mtd: nand: detect OOB size for Toshiba 24nm raw SLC
[deliverable/linux.git] / drivers / mtd / nand / nand_base.c
index dfcd0a565c5b3e8f66d9b24077ae3701f132ee36..158240d5649a7758e25336b8451649e3e8418b80 100644 (file)
@@ -211,11 +211,9 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr)
  */
 static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
-       int i;
        struct nand_chip *chip = mtd->priv;
 
-       for (i = 0; i < len; i++)
-               writeb(buf[i], chip->IO_ADDR_W);
+       iowrite8_rep(chip->IO_ADDR_W, buf, len);
 }
 
 /**
@@ -228,11 +226,9 @@ static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
  */
 static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-       int i;
        struct nand_chip *chip = mtd->priv;
 
-       for (i = 0; i < len; i++)
-               buf[i] = readb(chip->IO_ADDR_R);
+       ioread8_rep(chip->IO_ADDR_R, buf, len);
 }
 
 /**
@@ -245,14 +241,10 @@ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
  */
 static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
-       int i;
        struct nand_chip *chip = mtd->priv;
        u16 *p = (u16 *) buf;
-       len >>= 1;
-
-       for (i = 0; i < len; i++)
-               writew(p[i], chip->IO_ADDR_W);
 
+       iowrite16_rep(chip->IO_ADDR_W, p, len >> 1);
 }
 
 /**
@@ -265,13 +257,10 @@ static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
  */
 static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-       int i;
        struct nand_chip *chip = mtd->priv;
        u16 *p = (u16 *) buf;
-       len >>= 1;
 
-       for (i = 0; i < len; i++)
-               p[i] = readw(chip->IO_ADDR_R);
+       ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
 }
 
 /**
@@ -2720,7 +2709,9 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
 {
        int status;
 
-       if (!chip->onfi_version)
+       if (!chip->onfi_version ||
+           !(le16_to_cpu(chip->onfi_params.opt_cmd)
+             & ONFI_OPT_CMD_SET_GET_FEATURES))
                return -EINVAL;
 
        chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1);
@@ -2741,7 +2732,9 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
 static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
                        int addr, uint8_t *subfeature_param)
 {
-       if (!chip->onfi_version)
+       if (!chip->onfi_version ||
+           !(le16_to_cpu(chip->onfi_params.opt_cmd)
+             & ONFI_OPT_CMD_SET_GET_FEATURES))
                return -EINVAL;
 
        /* clear the sub feature parameters */
@@ -2793,7 +2786,9 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
 
        if (!chip->select_chip)
                chip->select_chip = nand_select_chip;
-       if (!chip->read_byte)
+
+       /* If called twice, pointers that depend on busw may need to be reset */
+       if (!chip->read_byte || chip->read_byte == nand_read_byte)
                chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
        if (!chip->read_word)
                chip->read_word = nand_read_word;
@@ -2801,9 +2796,9 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
                chip->block_bad = nand_block_bad;
        if (!chip->block_markbad)
                chip->block_markbad = nand_default_block_markbad;
-       if (!chip->write_buf)
+       if (!chip->write_buf || chip->write_buf == nand_write_buf)
                chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
-       if (!chip->read_buf)
+       if (!chip->read_buf || chip->read_buf == nand_read_buf)
                chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
        if (!chip->scan_bbt)
                chip->scan_bbt = nand_default_bbt;
@@ -3086,6 +3081,22 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
                extid >>= 2;
                /* Get buswidth information */
                *busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+
+               /*
+                * Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
+                * 512B page. For Toshiba SLC, we decode the 5th/6th byte as
+                * follows:
+                * - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
+                *                         110b -> 24nm
+                * - ID byte 5, bit[7]:    1 -> BENAND, 0 -> raw SLC
+                */
+               if (id_len >= 6 && id_data[0] == NAND_MFR_TOSHIBA &&
+                               !(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+                               (id_data[5] & 0x7) == 0x6 /* 24nm */ &&
+                               !(id_data[4] & 0x80) /* !BENAND */) {
+                       mtd->oobsize = 32 * mtd->writesize >> 9;
+               }
+
        }
 }
 
This page took 0.044316 seconds and 5 git commands to generate.