[06/11] mtd: nand: Move Samsung specific init/detection logic in nand_samsung.c

Message ID 20220714075131.411548-6-michael@amarulasolutions.com
State New
Headers show
Series
  • [01/11] mtd: nand: Get rid of busw parameter
Related show

Commit Message

Michael Trimarchi July 14, 2022, 7:51 a.m. UTC
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

Dario Binacchi July 14, 2022, 1:29 p.m. UTC | #1
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
>
Michael Trimarchi July 14, 2022, 1:50 p.m. UTC | #2
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

Patch

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;
 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);