[06/11] mtd: nand: Move Samsung specific init/detection logic in nand_samsung.c
Commit Message
Upstream commit c51d0ac59f24200dfdccc897ff7c3c9446c7599a
Move Samsung specific initialization and detection logic into
nand_samsung.c. This is part of the "separate vendor specific code from
core" cleanup process.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Acked-by: Richard Weinberger <richard@nod.at>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
---
drivers/mtd/nand/raw/Makefile | 3 +-
drivers/mtd/nand/raw/nand_base.c | 50 +---------------
drivers/mtd/nand/raw/nand_ids.c | 4 +-
drivers/mtd/nand/raw/nand_samsung.c | 90 +++++++++++++++++++++++++++++
include/linux/mtd/rawnand.h | 2 +
5 files changed, 99 insertions(+), 50 deletions(-)
create mode 100644 drivers/mtd/nand/raw/nand_samsung.c
Comments
Hi Michael,
On Thu, Jul 14, 2022 at 9:51 AM Michael Trimarchi
<michael@amarulasolutions.com> wrote:
>
> Upstream commit c51d0ac59f24200dfdccc897ff7c3c9446c7599a
>
> Move Samsung specific initialization and detection logic into
> nand_samsung.c. This is part of the "separate vendor specific code from
> core" cleanup process.
>
> Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
> Acked-by: Richard Weinberger <richard@nod.at>
> Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
> ---
> drivers/mtd/nand/raw/Makefile | 3 +-
> drivers/mtd/nand/raw/nand_base.c | 50 +---------------
> drivers/mtd/nand/raw/nand_ids.c | 4 +-
> drivers/mtd/nand/raw/nand_samsung.c | 90 +++++++++++++++++++++++++++++
> include/linux/mtd/rawnand.h | 2 +
> 5 files changed, 99 insertions(+), 50 deletions(-)
> create mode 100644 drivers/mtd/nand/raw/nand_samsung.c
>
> diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
> index 6ec3581d20..c023c3cb68 100644
> --- a/drivers/mtd/nand/raw/Makefile
> +++ b/drivers/mtd/nand/raw/Makefile
> @@ -14,7 +14,7 @@ obj-$(CONFIG_SPL_NAND_DENALI) += denali_spl.o
> obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o
> obj-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o
> obj-$(CONFIG_SPL_NAND_ECC) += nand_ecc.o
> -obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o
> +obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o nand_samsung.o
> obj-$(CONFIG_SPL_NAND_IDENT) += nand_ids.o nand_timings.o
> obj-$(CONFIG_SPL_NAND_INIT) += nand.o
> ifeq ($(CONFIG_SPL_ENV_SUPPORT),y)
> @@ -31,6 +31,7 @@ obj-y += nand_ids.o
> obj-y += nand_util.o
> obj-y += nand_ecc.o
> obj-y += nand_base.o
> +obj-y += nand_samsung.o
> obj-y += nand_timings.o
>
> endif # not spl
> diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
> index fa9ffb56fd..d4a91b5fcc 100644
> --- a/drivers/mtd/nand/raw/nand_base.c
> +++ b/drivers/mtd/nand/raw/nand_base.c
> @@ -4165,47 +4165,12 @@ void nand_decode_ext_id(struct nand_chip *chip)
> /*
> * Field definitions are in the following datasheets:
> * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
> - * New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44)
> * Hynix MLC (6 byte ID): Hynix H27UBG8T2B (p.22)
> *
> * Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung
> * ID to decide what to do.
> */
> - if (id_len == 6 && chip->id.data[0] == NAND_MFR_SAMSUNG &&
> - !nand_is_slc(chip) && chip->id.data[5] != 0x00) {
> - /* Calc pagesize */
> - mtd->writesize = 2048 << (extid & 0x03);
> - extid >>= 2;
> - /* Calc oobsize */
> - switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
> - case 1:
> - mtd->oobsize = 128;
> - break;
> - case 2:
> - mtd->oobsize = 218;
> - break;
> - case 3:
> - mtd->oobsize = 400;
> - break;
> - case 4:
> - mtd->oobsize = 436;
> - break;
> - case 5:
> - mtd->oobsize = 512;
> - break;
> - case 6:
> - mtd->oobsize = 640;
> - break;
> - case 7:
> - default: /* Other cases are "reserved" (unknown) */
> - mtd->oobsize = 1024;
> - break;
> - }
> - extid >>= 2;
> - /* Calc blocksize */
> - mtd->erasesize = (128 * 1024) <<
> - (((extid >> 1) & 0x04) | (extid & 0x03));
> - } else if (id_len == 6 && chip->id.data[0] == NAND_MFR_HYNIX &&
> + if (id_len == 6 && chip->id.data[0] == NAND_MFR_HYNIX &&
> !nand_is_slc(chip)) {
> unsigned int tmp;
>
> @@ -4367,13 +4332,10 @@ static void nand_decode_bbm_options(struct mtd_info *mtd,
> * Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba,
> * AMD/Spansion, and Macronix. All others scan only the first page.
> */
> - if (!nand_is_slc(chip) &&
> - (maf_id == NAND_MFR_SAMSUNG ||
> - maf_id == NAND_MFR_HYNIX))
> + if (!nand_is_slc(chip) && maf_id == NAND_MFR_HYNIX)
> chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
> else if ((nand_is_slc(chip) &&
> - (maf_id == NAND_MFR_SAMSUNG ||
> - maf_id == NAND_MFR_HYNIX ||
> + (maf_id == NAND_MFR_HYNIX ||
> maf_id == NAND_MFR_TOSHIBA ||
> maf_id == NAND_MFR_AMD ||
> maf_id == NAND_MFR_MACRONIX)) ||
> @@ -4542,12 +4504,6 @@ struct nand_flash_dev *nand_get_flash_type(struct nand_chip *chip,
> /* Get chip options */
> chip->options |= type->options;
>
> - /*
> - * Check if chip is not a Samsung device. Do not clear the
> - * options for chips which do not have an extended id.
> - */
> - if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
> - chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
Now it's always a chip, not Samsung.
Shouldn't that be so?
if (!type->pagesize)
chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
Regards,
Dario
> ident_done:
>
> if (chip->options & NAND_BUSWIDTH_AUTO) {
> diff --git a/drivers/mtd/nand/raw/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c
> index 2a50f0b214..f4126c3a5a 100644
> --- a/drivers/mtd/nand/raw/nand_ids.c
> +++ b/drivers/mtd/nand/raw/nand_ids.c
> @@ -10,7 +10,7 @@
> #include <linux/mtd/rawnand.h>
> #include <linux/sizes.h>
>
> -#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS
> +#define LP_OPTIONS 0
> #define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
>
> #define SP_OPTIONS NAND_NEED_READRDY
> @@ -189,7 +189,7 @@ struct nand_flash_dev nand_flash_ids[] = {
> /* Manufacturer IDs */
> struct nand_manufacturers nand_manuf_ids[] = {
> {NAND_MFR_TOSHIBA, "Toshiba"},
> - {NAND_MFR_SAMSUNG, "Samsung"},
> + {NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops},
> {NAND_MFR_FUJITSU, "Fujitsu"},
> {NAND_MFR_NATIONAL, "National"},
> {NAND_MFR_RENESAS, "Renesas"},
> diff --git a/drivers/mtd/nand/raw/nand_samsung.c b/drivers/mtd/nand/raw/nand_samsung.c
> new file mode 100644
> index 0000000000..3dfbbec382
> --- /dev/null
> +++ b/drivers/mtd/nand/raw/nand_samsung.c
> @@ -0,0 +1,90 @@
> +/*
> + * Copyright (C) 2017 Free Electrons
> + * Copyright (C) 2017 NextThing Co
> + *
> + * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/bug.h>
> +#include <linux/mtd/nand.h>
> +#include <linux/mtd/rawnand.h>
> +
> +static void samsung_nand_decode_id(struct nand_chip *chip)
> +{
> + struct mtd_info *mtd = nand_to_mtd(chip);
> +
> + /* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */
> + if (chip->id.len == 6 && !nand_is_slc(chip) &&
> + chip->id.data[5] != 0x00) {
> + u8 extid = chip->id.data[3];
> +
> + /* Get pagesize */
> + mtd->writesize = 2048 << (extid & 0x03);
> +
> + extid >>= 2;
> +
> + /* Get oobsize */
> + switch (((extid >> 2) & 0x4) | (extid & 0x3)) {
> + case 1:
> + mtd->oobsize = 128;
> + break;
> + case 2:
> + mtd->oobsize = 218;
> + break;
> + case 3:
> + mtd->oobsize = 400;
> + break;
> + case 4:
> + mtd->oobsize = 436;
> + break;
> + case 5:
> + mtd->oobsize = 512;
> + break;
> + case 6:
> + mtd->oobsize = 640;
> + break;
> + case 7:
> + default: /* Other cases are "reserved" (unknown) */
> + WARN(1, "Invalid OOB size value");
> + mtd->oobsize = 1024;
> + break;
> + }
> +
> + /* Get blocksize */
> + extid >>= 2;
> + mtd->erasesize = (128 * 1024) <<
> + (((extid >> 1) & 0x04) | (extid & 0x03));
> + } else {
> + nand_decode_ext_id(chip);
> + }
> +}
> +
> +static int samsung_nand_init(struct nand_chip *chip)
> +{
> + struct mtd_info *mtd = nand_to_mtd(chip);
> +
> + if (mtd->writesize > 512)
> + chip->options |= NAND_SAMSUNG_LP_OPTIONS;
> +
> + if (!nand_is_slc(chip))
> + chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
> + else
> + chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
> +
> + return 0;
> +}
> +
> +const struct nand_manufacturer_ops samsung_nand_manuf_ops = {
> + .detect = samsung_nand_decode_id,
> + .init = samsung_nand_init,
> +};
> diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
> index 8fb2a43296..d0312e924b 100644
> --- a/include/linux/mtd/rawnand.h
> +++ b/include/linux/mtd/rawnand.h
> @@ -1158,6 +1158,8 @@ struct nand_manufacturers {
> extern struct nand_flash_dev nand_flash_ids[];
> extern struct nand_manufacturers nand_manuf_ids[];
>
> +extern const struct nand_manufacturer_ops samsung_nand_manuf_ops;
> +
> int nand_default_bbt(struct mtd_info *mtd);
> int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
> int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs);
> --
> 2.34.1
>
Ciao
On Thu, Jul 14, 2022 at 3:29 PM Dario Binacchi
<dario.binacchi@amarulasolutions.com> wrote:
>
> Hi Michael,
>
> On Thu, Jul 14, 2022 at 9:51 AM Michael Trimarchi
> <michael@amarulasolutions.com> wrote:
> >
> > Upstream commit c51d0ac59f24200dfdccc897ff7c3c9446c7599a
> >
> > Move Samsung specific initialization and detection logic into
> > nand_samsung.c. This is part of the "separate vendor specific code from
> > core" cleanup process.
> >
> > Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
> > Acked-by: Richard Weinberger <richard@nod.at>
> > Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
> > ---
> > drivers/mtd/nand/raw/Makefile | 3 +-
> > drivers/mtd/nand/raw/nand_base.c | 50 +---------------
> > drivers/mtd/nand/raw/nand_ids.c | 4 +-
> > drivers/mtd/nand/raw/nand_samsung.c | 90 +++++++++++++++++++++++++++++
> > include/linux/mtd/rawnand.h | 2 +
> > 5 files changed, 99 insertions(+), 50 deletions(-)
> > create mode 100644 drivers/mtd/nand/raw/nand_samsung.c
> >
> > diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
> > index 6ec3581d20..c023c3cb68 100644
> > --- a/drivers/mtd/nand/raw/Makefile
> > +++ b/drivers/mtd/nand/raw/Makefile
> > @@ -14,7 +14,7 @@ obj-$(CONFIG_SPL_NAND_DENALI) += denali_spl.o
> > obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o
> > obj-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o
> > obj-$(CONFIG_SPL_NAND_ECC) += nand_ecc.o
> > -obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o
> > +obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o nand_samsung.o
> > obj-$(CONFIG_SPL_NAND_IDENT) += nand_ids.o nand_timings.o
> > obj-$(CONFIG_SPL_NAND_INIT) += nand.o
> > ifeq ($(CONFIG_SPL_ENV_SUPPORT),y)
> > @@ -31,6 +31,7 @@ obj-y += nand_ids.o
> > obj-y += nand_util.o
> > obj-y += nand_ecc.o
> > obj-y += nand_base.o
> > +obj-y += nand_samsung.o
> > obj-y += nand_timings.o
> >
> > endif # not spl
> > diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
> > index fa9ffb56fd..d4a91b5fcc 100644
> > --- a/drivers/mtd/nand/raw/nand_base.c
> > +++ b/drivers/mtd/nand/raw/nand_base.c
> > @@ -4165,47 +4165,12 @@ void nand_decode_ext_id(struct nand_chip *chip)
> > /*
> > * Field definitions are in the following datasheets:
> > * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
> > - * New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44)
> > * Hynix MLC (6 byte ID): Hynix H27UBG8T2B (p.22)
> > *
> > * Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung
> > * ID to decide what to do.
> > */
> > - if (id_len == 6 && chip->id.data[0] == NAND_MFR_SAMSUNG &&
> > - !nand_is_slc(chip) && chip->id.data[5] != 0x00) {
> > - /* Calc pagesize */
> > - mtd->writesize = 2048 << (extid & 0x03);
> > - extid >>= 2;
> > - /* Calc oobsize */
> > - switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
> > - case 1:
> > - mtd->oobsize = 128;
> > - break;
> > - case 2:
> > - mtd->oobsize = 218;
> > - break;
> > - case 3:
> > - mtd->oobsize = 400;
> > - break;
> > - case 4:
> > - mtd->oobsize = 436;
> > - break;
> > - case 5:
> > - mtd->oobsize = 512;
> > - break;
> > - case 6:
> > - mtd->oobsize = 640;
> > - break;
> > - case 7:
> > - default: /* Other cases are "reserved" (unknown) */
> > - mtd->oobsize = 1024;
> > - break;
> > - }
> > - extid >>= 2;
> > - /* Calc blocksize */
> > - mtd->erasesize = (128 * 1024) <<
> > - (((extid >> 1) & 0x04) | (extid & 0x03));
> > - } else if (id_len == 6 && chip->id.data[0] == NAND_MFR_HYNIX &&
> > + if (id_len == 6 && chip->id.data[0] == NAND_MFR_HYNIX &&
> > !nand_is_slc(chip)) {
> > unsigned int tmp;
> >
> > @@ -4367,13 +4332,10 @@ static void nand_decode_bbm_options(struct mtd_info *mtd,
> > * Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba,
> > * AMD/Spansion, and Macronix. All others scan only the first page.
> > */
> > - if (!nand_is_slc(chip) &&
> > - (maf_id == NAND_MFR_SAMSUNG ||
> > - maf_id == NAND_MFR_HYNIX))
> > + if (!nand_is_slc(chip) && maf_id == NAND_MFR_HYNIX)
> > chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
> > else if ((nand_is_slc(chip) &&
> > - (maf_id == NAND_MFR_SAMSUNG ||
> > - maf_id == NAND_MFR_HYNIX ||
> > + (maf_id == NAND_MFR_HYNIX ||
> > maf_id == NAND_MFR_TOSHIBA ||
> > maf_id == NAND_MFR_AMD ||
> > maf_id == NAND_MFR_MACRONIX)) ||
> > @@ -4542,12 +4504,6 @@ struct nand_flash_dev *nand_get_flash_type(struct nand_chip *chip,
> > /* Get chip options */
> > chip->options |= type->options;
> >
> > - /*
> > - * Check if chip is not a Samsung device. Do not clear the
>
> > - * options for chips which do not have an extended id.
> > - */
> > - if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
> > - chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
>
> Now it's always a chip, not Samsung.
> Shouldn't that be so?
> if (!type->pagesize)
> chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
>
LP_OPTIONS viene messo 0 sotto
MIchael
> Regards,
> Dario
>
> > ident_done:
> >
> > if (chip->options & NAND_BUSWIDTH_AUTO) {
> > diff --git a/drivers/mtd/nand/raw/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c
> > index 2a50f0b214..f4126c3a5a 100644
> > --- a/drivers/mtd/nand/raw/nand_ids.c
> > +++ b/drivers/mtd/nand/raw/nand_ids.c
> > @@ -10,7 +10,7 @@
> > #include <linux/mtd/rawnand.h>
> > #include <linux/sizes.h>
> >
> > -#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS
> > +#define LP_OPTIONS 0
> > #define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
> >
> > #define SP_OPTIONS NAND_NEED_READRDY
> > @@ -189,7 +189,7 @@ struct nand_flash_dev nand_flash_ids[] = {
> > /* Manufacturer IDs */
> > struct nand_manufacturers nand_manuf_ids[] = {
> > {NAND_MFR_TOSHIBA, "Toshiba"},
> > - {NAND_MFR_SAMSUNG, "Samsung"},
> > + {NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops},
> > {NAND_MFR_FUJITSU, "Fujitsu"},
> > {NAND_MFR_NATIONAL, "National"},
> > {NAND_MFR_RENESAS, "Renesas"},
> > diff --git a/drivers/mtd/nand/raw/nand_samsung.c b/drivers/mtd/nand/raw/nand_samsung.c
> > new file mode 100644
> > index 0000000000..3dfbbec382
> > --- /dev/null
> > +++ b/drivers/mtd/nand/raw/nand_samsung.c
> > @@ -0,0 +1,90 @@
> > +/*
> > + * Copyright (C) 2017 Free Electrons
> > + * Copyright (C) 2017 NextThing Co
> > + *
> > + * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + */
> > +
> > +#include <linux/bug.h>
> > +#include <linux/mtd/nand.h>
> > +#include <linux/mtd/rawnand.h>
> > +
> > +static void samsung_nand_decode_id(struct nand_chip *chip)
> > +{
> > + struct mtd_info *mtd = nand_to_mtd(chip);
> > +
> > + /* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */
> > + if (chip->id.len == 6 && !nand_is_slc(chip) &&
> > + chip->id.data[5] != 0x00) {
> > + u8 extid = chip->id.data[3];
> > +
> > + /* Get pagesize */
> > + mtd->writesize = 2048 << (extid & 0x03);
> > +
> > + extid >>= 2;
> > +
> > + /* Get oobsize */
> > + switch (((extid >> 2) & 0x4) | (extid & 0x3)) {
> > + case 1:
> > + mtd->oobsize = 128;
> > + break;
> > + case 2:
> > + mtd->oobsize = 218;
> > + break;
> > + case 3:
> > + mtd->oobsize = 400;
> > + break;
> > + case 4:
> > + mtd->oobsize = 436;
> > + break;
> > + case 5:
> > + mtd->oobsize = 512;
> > + break;
> > + case 6:
> > + mtd->oobsize = 640;
> > + break;
> > + case 7:
> > + default: /* Other cases are "reserved" (unknown) */
> > + WARN(1, "Invalid OOB size value");
> > + mtd->oobsize = 1024;
> > + break;
> > + }
> > +
> > + /* Get blocksize */
> > + extid >>= 2;
> > + mtd->erasesize = (128 * 1024) <<
> > + (((extid >> 1) & 0x04) | (extid & 0x03));
> > + } else {
> > + nand_decode_ext_id(chip);
> > + }
> > +}
> > +
> > +static int samsung_nand_init(struct nand_chip *chip)
> > +{
> > + struct mtd_info *mtd = nand_to_mtd(chip);
> > +
> > + if (mtd->writesize > 512)
> > + chip->options |= NAND_SAMSUNG_LP_OPTIONS;
> > +
> > + if (!nand_is_slc(chip))
> > + chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
> > + else
> > + chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
> > +
> > + return 0;
> > +}
> > +
> > +const struct nand_manufacturer_ops samsung_nand_manuf_ops = {
> > + .detect = samsung_nand_decode_id,
> > + .init = samsung_nand_init,
> > +};
> > diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
> > index 8fb2a43296..d0312e924b 100644
> > --- a/include/linux/mtd/rawnand.h
> > +++ b/include/linux/mtd/rawnand.h
> > @@ -1158,6 +1158,8 @@ struct nand_manufacturers {
> > extern struct nand_flash_dev nand_flash_ids[];
> > extern struct nand_manufacturers nand_manuf_ids[];
> >
> > +extern const struct nand_manufacturer_ops samsung_nand_manuf_ops;
> > +
> > int nand_default_bbt(struct mtd_info *mtd);
> > int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
> > int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs);
> > --
> > 2.34.1
> >
>
>
> --
>
> Dario Binacchi
>
> Embedded Linux Developer
>
> dario.binacchi@amarulasolutions.com
>
> __________________________________
>
>
> Amarula Solutions SRL
>
> Via Le Canevare 30, 31100 Treviso, Veneto, IT
>
> T. +39 042 243 5310
> info@amarulasolutions.com
>
> www.amarulasolutions.com
@@ -14,7 +14,7 @@ obj-$(CONFIG_SPL_NAND_DENALI) += denali_spl.o
obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o
obj-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o
obj-$(CONFIG_SPL_NAND_ECC) += nand_ecc.o
-obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o
+obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o nand_samsung.o
obj-$(CONFIG_SPL_NAND_IDENT) += nand_ids.o nand_timings.o
obj-$(CONFIG_SPL_NAND_INIT) += nand.o
ifeq ($(CONFIG_SPL_ENV_SUPPORT),y)
@@ -31,6 +31,7 @@ obj-y += nand_ids.o
obj-y += nand_util.o
obj-y += nand_ecc.o
obj-y += nand_base.o
+obj-y += nand_samsung.o
obj-y += nand_timings.o
endif # not spl
@@ -4165,47 +4165,12 @@ void nand_decode_ext_id(struct nand_chip *chip)
/*
* Field definitions are in the following datasheets:
* Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
- * New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44)
* Hynix MLC (6 byte ID): Hynix H27UBG8T2B (p.22)
*
* Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung
* ID to decide what to do.
*/
- if (id_len == 6 && chip->id.data[0] == NAND_MFR_SAMSUNG &&
- !nand_is_slc(chip) && chip->id.data[5] != 0x00) {
- /* Calc pagesize */
- mtd->writesize = 2048 << (extid & 0x03);
- extid >>= 2;
- /* Calc oobsize */
- switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
- case 1:
- mtd->oobsize = 128;
- break;
- case 2:
- mtd->oobsize = 218;
- break;
- case 3:
- mtd->oobsize = 400;
- break;
- case 4:
- mtd->oobsize = 436;
- break;
- case 5:
- mtd->oobsize = 512;
- break;
- case 6:
- mtd->oobsize = 640;
- break;
- case 7:
- default: /* Other cases are "reserved" (unknown) */
- mtd->oobsize = 1024;
- break;
- }
- extid >>= 2;
- /* Calc blocksize */
- mtd->erasesize = (128 * 1024) <<
- (((extid >> 1) & 0x04) | (extid & 0x03));
- } else if (id_len == 6 && chip->id.data[0] == NAND_MFR_HYNIX &&
+ if (id_len == 6 && chip->id.data[0] == NAND_MFR_HYNIX &&
!nand_is_slc(chip)) {
unsigned int tmp;
@@ -4367,13 +4332,10 @@ static void nand_decode_bbm_options(struct mtd_info *mtd,
* Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba,
* AMD/Spansion, and Macronix. All others scan only the first page.
*/
- if (!nand_is_slc(chip) &&
- (maf_id == NAND_MFR_SAMSUNG ||
- maf_id == NAND_MFR_HYNIX))
+ if (!nand_is_slc(chip) && maf_id == NAND_MFR_HYNIX)
chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
else if ((nand_is_slc(chip) &&
- (maf_id == NAND_MFR_SAMSUNG ||
- maf_id == NAND_MFR_HYNIX ||
+ (maf_id == NAND_MFR_HYNIX ||
maf_id == NAND_MFR_TOSHIBA ||
maf_id == NAND_MFR_AMD ||
maf_id == NAND_MFR_MACRONIX)) ||
@@ -4542,12 +4504,6 @@ struct nand_flash_dev *nand_get_flash_type(struct nand_chip *chip,
/* Get chip options */
chip->options |= type->options;
- /*
- * Check if chip is not a Samsung device. Do not clear the
- * options for chips which do not have an extended id.
- */
- if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
- chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
ident_done:
if (chip->options & NAND_BUSWIDTH_AUTO) {
@@ -10,7 +10,7 @@
#include <linux/mtd/rawnand.h>
#include <linux/sizes.h>
-#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS
+#define LP_OPTIONS 0
#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
#define SP_OPTIONS NAND_NEED_READRDY
@@ -189,7 +189,7 @@ struct nand_flash_dev nand_flash_ids[] = {
/* Manufacturer IDs */
struct nand_manufacturers nand_manuf_ids[] = {
{NAND_MFR_TOSHIBA, "Toshiba"},
- {NAND_MFR_SAMSUNG, "Samsung"},
+ {NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops},
{NAND_MFR_FUJITSU, "Fujitsu"},
{NAND_MFR_NATIONAL, "National"},
{NAND_MFR_RENESAS, "Renesas"},
new file mode 100644
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2017 Free Electrons
+ * Copyright (C) 2017 NextThing Co
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bug.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
+
+static void samsung_nand_decode_id(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
+ /* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */
+ if (chip->id.len == 6 && !nand_is_slc(chip) &&
+ chip->id.data[5] != 0x00) {
+ u8 extid = chip->id.data[3];
+
+ /* Get pagesize */
+ mtd->writesize = 2048 << (extid & 0x03);
+
+ extid >>= 2;
+
+ /* Get oobsize */
+ switch (((extid >> 2) & 0x4) | (extid & 0x3)) {
+ case 1:
+ mtd->oobsize = 128;
+ break;
+ case 2:
+ mtd->oobsize = 218;
+ break;
+ case 3:
+ mtd->oobsize = 400;
+ break;
+ case 4:
+ mtd->oobsize = 436;
+ break;
+ case 5:
+ mtd->oobsize = 512;
+ break;
+ case 6:
+ mtd->oobsize = 640;
+ break;
+ case 7:
+ default: /* Other cases are "reserved" (unknown) */
+ WARN(1, "Invalid OOB size value");
+ mtd->oobsize = 1024;
+ break;
+ }
+
+ /* Get blocksize */
+ extid >>= 2;
+ mtd->erasesize = (128 * 1024) <<
+ (((extid >> 1) & 0x04) | (extid & 0x03));
+ } else {
+ nand_decode_ext_id(chip);
+ }
+}
+
+static int samsung_nand_init(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
+ if (mtd->writesize > 512)
+ chip->options |= NAND_SAMSUNG_LP_OPTIONS;
+
+ if (!nand_is_slc(chip))
+ chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
+ else
+ chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+
+ return 0;
+}
+
+const struct nand_manufacturer_ops samsung_nand_manuf_ops = {
+ .detect = samsung_nand_decode_id,
+ .init = samsung_nand_init,
+};
@@ -1158,6 +1158,8 @@ struct nand_manufacturers {
extern struct nand_flash_dev nand_flash_ids[];
extern struct nand_manufacturers nand_manuf_ids[];
+extern const struct nand_manufacturer_ops samsung_nand_manuf_ops;
+
int nand_default_bbt(struct mtd_info *mtd);
int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs);