Duo2 official release
[vuplus_openvuplus] / meta-bsp / vuduo2 / recipes / linux / linux-vuplus-3.3.8 / nand_base.patch
diff --git a/meta-bsp/vuduo2/recipes/linux/linux-vuplus-3.3.8/nand_base.patch b/meta-bsp/vuduo2/recipes/linux/linux-vuplus-3.3.8/nand_base.patch
new file mode 100644 (file)
index 0000000..6df72b8
--- /dev/null
@@ -0,0 +1,418 @@
+diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
+index 97a48c3..aaba655 100644
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -2934,246 +2934,6 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
+ }
+ /*
+- * nand_id_has_period - Check if an ID string has a given wraparound period
+- * @id_data: the ID string
+- * @arrlen: the length of the @id_data array
+- * @period: the period of repitition
+- *
+- * Check if an ID string is repeated within a given sequence of bytes at
+- * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a
+- * period of 2). This is a helper function for nand_id_len(). Returns non-zero
+- * if the repetition has a period of @period; otherwise, returns zero.
+- */
+-static int nand_id_has_period(u8 *id_data, int arrlen, int period)
+-{
+-      int i, j;
+-      for (i = 0; i < period; i++)
+-              for (j = i + period; j < arrlen; j += period)
+-                      if (id_data[i] != id_data[j])
+-                              return 0;
+-      return 1;
+-}
+-
+-/*
+- * nand_id_len - Get the length of an ID string returned by CMD_READID
+- * @id_data: the ID string
+- * @arrlen: the length of the @id_data array
+-
+- * Returns the length of the ID string, according to known wraparound/trailing
+- * zero patterns. If no pattern exists, returns the length of the array.
+- */
+-static int nand_id_len(u8 *id_data, int arrlen)
+-{
+-      int last_nonzero, period;
+-
+-      /* Find last non-zero byte */
+-      for (last_nonzero = arrlen - 1; last_nonzero >= 0; last_nonzero--)
+-              if (id_data[last_nonzero])
+-                      break;
+-
+-      /* All zeros */
+-      if (last_nonzero < 0)
+-              return 0;
+-
+-      /* Calculate wraparound period */
+-      for (period = 1; period < arrlen; period++)
+-              if (nand_id_has_period(id_data, arrlen, period))
+-                      break;
+-
+-      /* There's a repeated pattern */
+-      if (period < arrlen)
+-              return period;
+-
+-      /* There are trailing zeros */
+-      if (last_nonzero < arrlen - 1)
+-              return last_nonzero + 1;
+-
+-      /* No pattern detected */
+-      return arrlen;
+-}
+-
+-/*
+- * Many new NAND share similar device ID codes, which represent the size of the
+- * chip. The rest of the parameters must be decoded according to generic or
+- * manufacturer-specific "extended ID" decoding patterns.
+- */
+-static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
+-                              u8 id_data[8], int *busw)
+-{
+-      int extid, id_len;
+-      /* The 3rd id byte holds MLC / multichip data */
+-      chip->cellinfo = id_data[2];
+-      /* The 4th id byte is the important one */
+-      extid = id_data[3];
+-
+-      id_len = nand_id_len(id_data, 8);
+-
+-      /*
+-       * 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 && id_data[0] == NAND_MFR_SAMSUNG &&
+-                      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:
+-              default: /* Other cases are "reserved" (unknown) */
+-                      mtd->oobsize = 640;
+-                      break;
+-              }
+-              extid >>= 2;
+-              /* Calc blocksize */
+-              mtd->erasesize = (128 * 1024) <<
+-                      (((extid >> 1) & 0x04) | (extid & 0x03));
+-              *busw = 0;
+-      } else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX &&
+-                      (chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
+-              unsigned int tmp;
+-
+-              /* Calc pagesize */
+-              mtd->writesize = 2048 << (extid & 0x03);
+-              extid >>= 2;
+-              /* Calc oobsize */
+-              switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
+-              case 0:
+-                      mtd->oobsize = 128;
+-                      break;
+-              case 1:
+-                      mtd->oobsize = 224;
+-                      break;
+-              case 2:
+-                      mtd->oobsize = 448;
+-                      break;
+-              case 3:
+-                      mtd->oobsize = 64;
+-                      break;
+-              case 4:
+-                      mtd->oobsize = 32;
+-                      break;
+-              case 5:
+-                      mtd->oobsize = 16;
+-                      break;
+-              default:
+-                      mtd->oobsize = 640;
+-                      break;
+-              }
+-              extid >>= 2;
+-              /* Calc blocksize */
+-              tmp = ((extid >> 1) & 0x04) | (extid & 0x03);
+-              if (tmp < 0x03)
+-                      mtd->erasesize = (128 * 1024) << tmp;
+-              else if (tmp == 0x03)
+-                      mtd->erasesize = 768 * 1024;
+-              else
+-                      mtd->erasesize = (64 * 1024) << tmp;
+-              *busw = 0;
+-      } else {
+-              /* Calc pagesize */
+-              mtd->writesize = 1024 << (extid & 0x03);
+-              extid >>= 2;
+-              /* Calc oobsize */
+-              mtd->oobsize = (8 << (extid & 0x01)) *
+-                      (mtd->writesize >> 9);
+-              extid >>= 2;
+-              /* Calc blocksize. Blocksize is multiples of 64KiB */
+-              mtd->erasesize = (64 * 1024) << (extid & 0x03);
+-              extid >>= 2;
+-              /* Get buswidth information */
+-              *busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+-      }
+-}
+-
+-/*
+- * Old devices have chip data hardcoded in the device ID table. nand_decode_id
+- * decodes a matching ID table entry and assigns the MTD size parameters for
+- * the chip.
+- */
+-static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
+-                              struct nand_flash_dev *type, u8 id_data[8],
+-                              int *busw)
+-{
+-      int maf_id = id_data[0];
+-
+-      mtd->erasesize = type->erasesize;
+-      mtd->writesize = type->pagesize;
+-      mtd->oobsize = mtd->writesize / 32;
+-      *busw = type->options & NAND_BUSWIDTH_16;
+-
+-      /*
+-       * Check for Spansion/AMD ID + repeating 5th, 6th byte since
+-       * some Spansion chips have erasesize that conflicts with size
+-       * listed in nand_ids table.
+-       * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
+-       */
+-      if (maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && id_data[5] == 0x00
+-                      && id_data[6] == 0x00 && id_data[7] == 0x00
+-                      && mtd->writesize == 512) {
+-              mtd->erasesize = 128 * 1024;
+-              mtd->erasesize <<= ((id_data[3] & 0x03) << 1);
+-      }
+-}
+-
+-/*
+- * Set the bad block marker/indicator (BBM/BBI) patterns according to some
+- * heuristic patterns using various detected parameters (e.g., manufacturer,
+- * page size, cell-type information).
+- */
+-static void nand_decode_bbm_options(struct mtd_info *mtd,
+-                                  struct nand_chip *chip, u8 id_data[8])
+-{
+-      int maf_id = id_data[0];
+-
+-      /* Set the bad block position */
+-      if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16))
+-              chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
+-      else
+-              chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
+-
+-      /*
+-       * Bad block marker is stored in the last page of each block on Samsung
+-       * and Hynix MLC devices; stored in first two pages of each block on
+-       * Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba,
+-       * AMD/Spansion, and Macronix.  All others scan only the first page.
+-       */
+-      if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+-                      (maf_id == NAND_MFR_SAMSUNG ||
+-                       maf_id == NAND_MFR_HYNIX))
+-              chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
+-      else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+-                              (maf_id == NAND_MFR_SAMSUNG ||
+-                               maf_id == NAND_MFR_HYNIX ||
+-                               maf_id == NAND_MFR_TOSHIBA ||
+-                               maf_id == NAND_MFR_AMD ||
+-                               maf_id == NAND_MFR_MACRONIX)) ||
+-                      (mtd->writesize == 2048 &&
+-                       maf_id == NAND_MFR_MICRON))
+-              chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+-}
+-
+-/*
+  * Get the flash and manufacturer id and lookup if the type is supported.
+  */
+ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
+@@ -3184,6 +2944,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
+ {
+       int i, maf_idx;
+       u8 id_data[8];
++      int ret;
+       /* Select the device */
+       chip->select_chip(mtd, 0);
+@@ -3210,8 +2971,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
+       chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
+-      /* Read entire ID string */
+-      for (i = 0; i < 8; i++)
++      for (i = 0; i < 2; i++)
+               id_data[i] = chip->read_byte(mtd);
+       if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
+@@ -3231,10 +2991,18 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
+       chip->onfi_version = 0;
+       if (!type->name || !type->pagesize) {
+               /* Check is chip is ONFI compliant */
+-              if (nand_flash_detect_onfi(mtd, chip, &busw))
++              ret = nand_flash_detect_onfi(mtd, chip, &busw);
++              if (ret)
+                       goto ident_done;
+       }
++      chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
++
++      /* Read entire ID string */
++
++      for (i = 0; i < 8; i++)
++              id_data[i] = chip->read_byte(mtd);
++
+       if (!type->name)
+               return ERR_PTR(-ENODEV);
+@@ -3247,10 +3015,82 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
+               /* Set the pagesize, oobsize, erasesize by the driver */
+               busw = chip->init_size(mtd, chip, id_data);
+       } else if (!type->pagesize) {
+-              /* Decode parameters from extended ID */
+-              nand_decode_ext_id(mtd, chip, id_data, &busw);
++              int extid;
++              /* The 3rd id byte holds MLC / multichip data */
++              chip->cellinfo = id_data[2];
++              /* The 4th id byte is the important one */
++              extid = id_data[3];
++
++              /*
++               * Field definitions are in the following datasheets:
++               * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
++               * New style   (6 byte ID): Samsung K9GBG08U0M (p.40)
++               *
++               * Check for wraparound + Samsung ID + nonzero 6th byte
++               * to decide what to do.
++               */
++              if (id_data[0] == id_data[6] && id_data[1] == id_data[7] &&
++                              id_data[0] == NAND_MFR_SAMSUNG &&
++                              (chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
++                              id_data[5] != 0x00) {
++                      /* Calc pagesize */
++                      mtd->writesize = 2048 << (extid & 0x03);
++                      extid >>= 2;
++                      /* Calc oobsize */
++                      switch (extid & 0x03) {
++                      case 1:
++                              mtd->oobsize = 128;
++                              break;
++                      case 2:
++                              mtd->oobsize = 218;
++                              break;
++                      case 3:
++                              mtd->oobsize = 400;
++                              break;
++                      default:
++                              mtd->oobsize = 436;
++                              break;
++                      }
++                      extid >>= 2;
++                      /* Calc blocksize */
++                      mtd->erasesize = (128 * 1024) <<
++                              (((extid >> 1) & 0x04) | (extid & 0x03));
++                      busw = 0;
++              } else {
++                      /* Calc pagesize */
++                      mtd->writesize = 1024 << (extid & 0x03);
++                      extid >>= 2;
++                      /* Calc oobsize */
++                      mtd->oobsize = (8 << (extid & 0x01)) *
++                              (mtd->writesize >> 9);
++                      extid >>= 2;
++                      /* Calc blocksize. Blocksize is multiples of 64KiB */
++                      mtd->erasesize = (64 * 1024) << (extid & 0x03);
++                      extid >>= 2;
++                      /* Get buswidth information */
++                      busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
++              }
+       } else {
+-              nand_decode_id(mtd, chip, type, id_data, &busw);
++              /*
++               * Old devices have chip data hardcoded in the device id table.
++               */
++              mtd->erasesize = type->erasesize;
++              mtd->writesize = type->pagesize;
++              mtd->oobsize = mtd->writesize / 32;
++              busw = type->options & NAND_BUSWIDTH_16;
++
++              /*
++               * Check for Spansion/AMD ID + repeating 5th, 6th byte since
++               * some Spansion chips have erasesize that conflicts with size
++               * listed in nand_ids table.
++               * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
++               */
++              if (*maf_id == NAND_MFR_AMD && id_data[4] != 0x00 &&
++                              id_data[5] == 0x00 && id_data[6] == 0x00 &&
++                              id_data[7] == 0x00 && mtd->writesize == 512) {
++                      mtd->erasesize = 128 * 1024;
++                      mtd->erasesize <<= ((id_data[3] & 0x03) << 1);
++              }
+       }
+       /* Get chip options, preserve non chip based options */
+       chip->options &= ~NAND_CHIPOPTIONS_MSK;
+@@ -3284,8 +3124,6 @@ ident_done:
+               return ERR_PTR(-EINVAL);
+       }
+-      nand_decode_bbm_options(mtd, chip, id_data);
+-
+       /* Calculate the address shift from the page size */
+       chip->page_shift = ffs(mtd->writesize) - 1;
+       /* Convert chipsize to number of pages per chip -1 */
+@@ -3302,6 +3140,33 @@ ident_done:
+       chip->badblockbits = 8;
++      /* Set the bad block position */
++      if (mtd->writesize > 512 || (busw & NAND_BUSWIDTH_16))
++              chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
++      else
++              chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
++
++      /*
++       * Bad block marker is stored in the last page of each block
++       * on Samsung and Hynix MLC devices; stored in first two pages
++       * of each block on Micron devices with 2KiB pages and on
++       * SLC Samsung, Hynix, Toshiba, AMD/Spansion, and Macronix.
++       * All others scan only the first page.
++       */
++      if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
++                      (*maf_id == NAND_MFR_SAMSUNG ||
++                       *maf_id == NAND_MFR_HYNIX))
++              chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
++      else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
++                              (*maf_id == NAND_MFR_SAMSUNG ||
++                               *maf_id == NAND_MFR_HYNIX ||
++                               *maf_id == NAND_MFR_TOSHIBA ||
++                               *maf_id == NAND_MFR_AMD ||
++                               *maf_id == NAND_MFR_MACRONIX)) ||
++                      (mtd->writesize == 2048 &&
++                       *maf_id == NAND_MFR_MICRON))
++              chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
++
+       /* Check for AND chips with 4 page planes */
+       if (chip->options & NAND_4PAGE_ARRAY)
+               chip->erase_cmd = multi_erase_cmd;