/* Software ecc 3/256, write all */
case NAND_ECC_SOFT:
for (; eccsteps; eccsteps--) {
- this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
+ this->ecc.calculate(mtd, &this->data_poi[datidx], ecc_code);
for (i = 0; i < 3; i++, eccidx++)
oob_buf[oob_config[eccidx]] = ecc_code[i];
- datidx += this->eccsize;
+ datidx += this->ecc.size;
}
- this->write_buf(mtd, this->data_poi, mtd->oobblock);
+ this->write_buf(mtd, this->data_poi, mtd->writesize);
break;
default:
- eccbytes = this->eccbytes;
+ eccbytes = this->ecc.bytes;
for (; eccsteps; eccsteps--) {
/* enable hardware ecc logic for write */
- this->enable_hwecc(mtd, NAND_ECC_WRITE);
- this->write_buf(mtd, &this->data_poi[datidx], this->eccsize);
- this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
+ this->ecc.hwctl(mtd, NAND_ECC_WRITE);
+ this->write_buf(mtd, &this->data_poi[datidx], this->ecc.size);
+ this->ecc.calculate(mtd, &this->data_poi[datidx], ecc_code);
for (i = 0; i < eccbytes; i++, eccidx++)
oob_buf[oob_config[eccidx]] = ecc_code[i];
/* If the hardware ecc provides syndromes then
page = realpage & this->pagemask;
/* Get raw starting column */
- col = from & (mtd->oobblock - 1);
+ col = from & (mtd->writesize - 1);
- end = mtd->oobblock;
+ end = mtd->writesize;
- ecc = this->eccsize;
- eccbytes = this->eccbytes;
+ ecc = this->ecc.size;
+ eccbytes = this->ecc.bytes;
if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))
compareecc = 0;
* tuple until we have a full page to write
*/
int cnt = 0;
- while (cnt < mtd->oobblock) {
+ while (cnt < mtd->writesize) {
if (vecs->iov_base != NULL && vecs->iov_len)
- this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++];
+ this->data_buf[cnt++] = ((uint8_t *) vecs->iov_base)[len++];
/* Check, if we have to switch to the next tuple */
if (len >= (int)vecs->iov_len) {
vecs++;
if (this->state == FL_PM_SUSPENDED)
nand_release_device(mtd);
else
- printk(KERN_ERR "resume() called for the chip which is not in suspended state\n");
-
+ printk(KERN_ERR "nand_resume() called for a chip which is not "
+ "in suspended state\n");
}
-/* module_text_address() isn't exported, and it's mostly a pointless
- test if this is a module _anyway_ -- they'd have to try _really_ hard
- to call us from in-kernel code if the core NAND support is modular. */
-#ifdef MODULE
-#define caller_is_module() (1)
-#else
-#define caller_is_module() module_text_address((unsigned long)__builtin_return_address(0))
-#endif
+/*
+ * Free allocated data structures
+ */
+static void nand_free_kmem(struct nand_chip *this)
+{
+ /* Buffer allocated by nand_scan ? */
+ if (this->options & NAND_OOBBUF_ALLOC)
+ kfree(this->oob_buf);
+ /* Buffer allocated by nand_scan ? */
+ if (this->options & NAND_DATABUF_ALLOC)
+ kfree(this->data_buf);
+ /* Controller allocated by nand_scan ? */
+ if (this->options & NAND_CONTROLLER_ALLOC)
+ kfree(this->controller);
+}
-/**
- * nand_scan - [NAND Interface] Scan for the NAND device
- * @mtd: MTD device structure
- * @maxchips: Number of chips to scan for
- *
- * This fills out all the uninitialized function pointers
- * with the defaults.
- * The flash ID is read and the mtd/chip structures are
- * filled with the appropriate values. Buffers are allocated if
- * they are not provided by the board driver
- * The mtd->owner field must be set to the module of the caller
- *
+/*
+ * Allocate buffers and data structures
*/
-int nand_scan(struct mtd_info *mtd, int maxchips)
+static int nand_allocate_kmem(struct mtd_info *mtd, struct nand_chip *this)
{
- int i, nand_maf_id, nand_dev_id, busw, maf_id;
- struct nand_chip *this = mtd->priv;
+ size_t len;
- /* Many callers got this wrong, so check for it for a while... */
- if (!mtd->owner && caller_is_module()) {
- printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n");
- BUG();
+ if (!this->oob_buf) {
+ len = mtd->oobsize <<
+ (this->phys_erase_shift - this->page_shift);
+ this->oob_buf = kmalloc(len, GFP_KERNEL);
+ if (!this->oob_buf)
+ goto outerr;
+ this->options |= NAND_OOBBUF_ALLOC;
}
- /* Get buswidth to select the correct functions */
- busw = this->options & NAND_BUSWIDTH_16;
+ if (!this->data_buf) {
- len = mtd->oobblock + mtd->oobsize;
++ len = mtd->writesize + mtd->oobsize;
+ this->data_buf = kmalloc(len, GFP_KERNEL);
+ if (!this->data_buf)
+ goto outerr;
+ this->options |= NAND_DATABUF_ALLOC;
+ }
+
+ if (!this->controller) {
+ this->controller = kzalloc(sizeof(struct nand_hw_control),
+ GFP_KERNEL);
+ if (!this->controller)
+ goto outerr;
+ this->options |= NAND_CONTROLLER_ALLOC;
+ }
+ return 0;
+
+ outerr:
+ printk(KERN_ERR "nand_scan(): Cannot allocate buffers\n");
+ nand_free_kmem(this);
+ return -ENOMEM;
+}
+/*
+ * Set default functions
+ */
+static void nand_set_defaults(struct nand_chip *this, int busw)
+{
/* check for proper chip_delay setup, set 20us if not */
if (!this->chip_delay)
this->chip_delay = 20;
this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
- nand_maf_id = this->read_byte(mtd);
- nand_dev_id = this->read_byte(mtd);
+ *maf_id = this->read_byte(mtd);
+ dev_id = this->read_byte(mtd);
- /* Print and store flash device information */
+ /* Lookup the flash id */
for (i = 0; nand_flash_ids[i].name != NULL; i++) {
+ if (dev_id == nand_flash_ids[i].id) {
+ type = &nand_flash_ids[i];
+ break;
+ }
+ }
- if (nand_dev_id != nand_flash_ids[i].id)
- continue;
-
- if (!mtd->name)
- mtd->name = nand_flash_ids[i].name;
- this->chipsize = nand_flash_ids[i].chipsize << 20;
-
- /* New devices have all the information in additional id bytes */
- if (!nand_flash_ids[i].pagesize) {
- int extid;
- /* The 3rd id byte contains non relevant data ATM */
- extid = this->read_byte(mtd);
- /* The 4th id byte is the important one */
- extid = this->read_byte(mtd);
- /* Calc pagesize */
- mtd->writesize = 1024 << (extid & 0x3);
- 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;
+ if (!type)
+ return ERR_PTR(-ENODEV);
+
+ this->chipsize = nand_flash_ids[i].chipsize << 20;
+
+ /* Newer devices have all the information in additional id bytes */
+ if (!nand_flash_ids[i].pagesize) {
+ int extid;
+ /* The 3rd id byte contains non relevant data ATM */
+ extid = this->read_byte(mtd);
+ /* The 4th id byte is the important one */
+ extid = this->read_byte(mtd);
+ /* Calc pagesize */
- mtd->oobblock = 1024 << (extid & 0x3);
++ mtd->writesize = 1024 << (extid & 0x3);
+ extid >>= 2;
+ /* Calc oobsize */
- mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock >> 9);
++ 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 {
- /* Old devices have this data hardcoded in the
- * device id table */
- mtd->erasesize = nand_flash_ids[i].erasesize;
- mtd->writesize = nand_flash_ids[i].pagesize;
- mtd->oobsize = mtd->writesize / 32;
- busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
- }
+ } else {
+ /*
+ * Old devices have this data hardcoded in the device id table
+ */
+ mtd->erasesize = nand_flash_ids[i].erasesize;
- mtd->oobblock = nand_flash_ids[i].pagesize;
- mtd->oobsize = mtd->oobblock / 32;
++ mtd->writesize = nand_flash_ids[i].pagesize;
++ mtd->oobsize = mtd->writesize / 32;
+ busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
+ }
- /* Try to identify manufacturer */
- for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) {
- if (nand_manuf_ids[maf_id].id == nand_maf_id)
- break;
- }
+ /* Try to identify manufacturer */
+ for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_id++) {
+ if (nand_manuf_ids[maf_idx].id == *maf_id)
+ break;
+ }
- /* Check, if buswidth is correct. Hardware drivers should set
- * this correct ! */
- if (busw != (this->options & NAND_BUSWIDTH_16)) {
- printk(KERN_INFO "NAND device: Manufacturer ID:"
- " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
- nand_manuf_ids[maf_id].name, mtd->name);
- printk(KERN_WARNING
- "NAND bus width %d instead %d bit\n",
- (this->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8);
- this->select_chip(mtd, -1);
- return 1;
- }
+ /*
+ * Check, if buswidth is correct. Hardware drivers should set
+ * this correct !
+ */
+ if (busw != (this->options & NAND_BUSWIDTH_16)) {
+ printk(KERN_INFO "NAND device: Manufacturer ID:"
+ " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
+ dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
+ printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
+ (this->options & NAND_BUSWIDTH_16) ? 16 : 8,
+ busw ? 16 : 8);
+ return ERR_PTR(-EINVAL);
+ }
- /* Calculate the address shift from the page size */
- this->page_shift = ffs(mtd->writesize) - 1;
- this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1;
- this->chip_shift = ffs(this->chipsize) - 1;
-
- /* Set the bad block position */
- this->badblockpos = mtd->writesize > 512 ? NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
-
- /* Get chip options, preserve non chip based options */
- this->options &= ~NAND_CHIPOPTIONS_MSK;
- this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;
- /* Set this as a default. Board drivers can override it, if necessary */
- this->options |= NAND_NO_AUTOINCR;
- /* Check if this is a not a samsung device. Do not clear the options
- * for chips which are not having an extended id.
- */
- if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
- this->options &= ~NAND_SAMSUNG_LP_OPTIONS;
+ /* Calculate the address shift from the page size */
- this->page_shift = ffs(mtd->oobblock) - 1;
++ this->page_shift = ffs(mtd->writesize) - 1;
+ /* Convert chipsize to number of pages per chip -1. */
+ this->pagemask = (this->chipsize >> this->page_shift) - 1;
- /* Check for AND chips with 4 page planes */
- if (this->options & NAND_4PAGE_ARRAY)
- this->erase_cmd = multi_erase_cmd;
- else
- this->erase_cmd = single_erase_cmd;
+ this->bbt_erase_shift = this->phys_erase_shift =
+ ffs(mtd->erasesize) - 1;
+ this->chip_shift = ffs(this->chipsize) - 1;
- /* Do not replace user supplied command function ! */
- if (mtd->writesize > 512 && this->cmdfunc == nand_command)
- this->cmdfunc = nand_command_lp;
+ /* Set the bad block position */
- this->badblockpos = mtd->oobblock > 512 ?
++ this->badblockpos = mtd->writesize > 512 ?
+ NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
- printk(KERN_INFO "NAND device: Manufacturer ID:"
- " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
- nand_manuf_ids[maf_id].name, nand_flash_ids[i].name);
- break;
+ /* Get chip options, preserve non chip based options */
+ this->options &= ~NAND_CHIPOPTIONS_MSK;
+ this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;
+
+ /*
+ * Set this as a default. Board drivers can override it, if necessary
+ */
+ this->options |= NAND_NO_AUTOINCR;
+
+ /* Check if this is a not a samsung device. Do not clear the
+ * options for chips which are not having an extended id.
+ */
+ if (*maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
+ this->options &= ~NAND_SAMSUNG_LP_OPTIONS;
+
+ /* Check for AND chips with 4 page planes */
+ if (this->options & NAND_4PAGE_ARRAY)
+ this->erase_cmd = multi_erase_cmd;
+ else
+ this->erase_cmd = single_erase_cmd;
+
+ /* Do not replace user supplied command function ! */
- if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
++ if (mtd->writesize > 512 && this->cmdfunc == nand_command)
+ this->cmdfunc = nand_command_lp;
+
+ printk(KERN_INFO "NAND device: Manufacturer ID:"
+ " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,
+ nand_manuf_ids[maf_idx].name, type->name);
+
+ return type;
+}
+
+/* module_text_address() isn't exported, and it's mostly a pointless
+ test if this is a module _anyway_ -- they'd have to try _really_ hard
+ to call us from in-kernel code if the core NAND support is modular. */
+#ifdef MODULE
+#define caller_is_module() (1)
+#else
+#define caller_is_module() \
+ module_text_address((unsigned long)__builtin_return_address(0))
+#endif
+
+/**
+ * nand_scan - [NAND Interface] Scan for the NAND device
+ * @mtd: MTD device structure
+ * @maxchips: Number of chips to scan for
+ *
+ * This fills out all the uninitialized function pointers
+ * with the defaults.
+ * The flash ID is read and the mtd/chip structures are
+ * filled with the appropriate values. Buffers are allocated if
+ * they are not provided by the board driver
+ * The mtd->owner field must be set to the module of the caller
+ *
+ */
+int nand_scan(struct mtd_info *mtd, int maxchips)
+{
+ int i, busw, nand_maf_id;
+ struct nand_chip *this = mtd->priv;
+ struct nand_flash_dev *type;
+
+ /* Many callers got this wrong, so check for it for a while... */
+ if (!mtd->owner && caller_is_module()) {
+ printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n");
+ BUG();
}
- if (!nand_flash_ids[i].name) {
+ /* Get buswidth to select the correct functions */
+ busw = this->options & NAND_BUSWIDTH_16;
+ /* Set the default functions */
+ nand_set_defaults(this, busw);
+
+ /* Read the flash type */
+ type = nand_get_flash_type(mtd, this, busw, &nand_maf_id);
+
+ if (IS_ERR(type)) {
printk(KERN_WARNING "No NAND device found!!!\n");
this->select_chip(mtd, -1);
- return 1;
+ return PTR_ERR(type);
}
+ /* Check for a chip array */
for (i = 1; i < maxchips; i++) {
this->select_chip(mtd, i);
-
/* Send the command for reading device ID */
this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
-
/* Read manufacturer and device IDs */
if (nand_maf_id != this->read_byte(mtd) ||
- nand_dev_id != this->read_byte(mtd))
+ type->id != this->read_byte(mtd))
break;
}
if (i > 1)
mtd->oobavail += this->autooob->oobfree[i][1];
/*
- * check ECC mode, default to software
- * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize
- * fallback to software ECC
+ * check ECC mode, default to software if 3byte/512byte hardware ECC is
+ * selected and we have 256 byte pagesize fallback to software ECC
*/
- this->eccsize = 256; /* set default eccsize */
- this->eccbytes = 3;
-
- switch (this->eccmode) {
- case NAND_ECC_HW12_2048:
- if (mtd->writesize < 2048) {
- printk(KERN_WARNING "2048 byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
- mtd->writesize);
- this->eccmode = NAND_ECC_SOFT;
- this->calculate_ecc = nand_calculate_ecc;
- this->correct_data = nand_correct_data;
- } else
- this->eccsize = 2048;
- break;
-
- case NAND_ECC_HW3_512:
- case NAND_ECC_HW6_512:
- case NAND_ECC_HW8_512:
- if (mtd->writesize == 256) {
- printk(KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n");
- this->eccmode = NAND_ECC_SOFT;
- this->calculate_ecc = nand_calculate_ecc;
- this->correct_data = nand_correct_data;
- } else
- this->eccsize = 512; /* set eccsize to 512 */
- break;
+ switch (this->ecc.mode) {
+ case NAND_ECC_HW:
+ case NAND_ECC_HW_SYNDROME:
+ if (!this->ecc.calculate || !this->ecc.correct ||
+ !this->ecc.hwctl) {
+ printk(KERN_WARNING "No ECC functions supplied, "
+ "Hardware ECC not possible\n");
+ BUG();
+ }
- if (mtd->oobblock >= this->ecc.size)
++ if (mtd->writesize >= this->ecc.size)
+ break;
+ printk(KERN_WARNING "%d byte HW ECC not possible on "
+ "%d byte page size, fallback to SW ECC\n",
- this->ecc.size, mtd->oobblock);
++ this->ecc.size, mtd->writesize);
+ this->ecc.mode = NAND_ECC_SOFT;
- case NAND_ECC_HW3_256:
+ case NAND_ECC_SOFT:
+ this->ecc.calculate = nand_calculate_ecc;
+ this->ecc.correct = nand_correct_data;
+ this->ecc.size = 256;
+ this->ecc.bytes = 3;
break;
case NAND_ECC_NONE:
- printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n");
- this->eccmode = NAND_ECC_NONE;
- break;
-
- case NAND_ECC_SOFT:
- this->calculate_ecc = nand_calculate_ecc;
- this->correct_data = nand_correct_data;
+ printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
+ "This is not recommended !!\n");
- this->ecc.size = mtd->oobblock;
++ this->ecc.size = mtd->writesize;
+ this->ecc.bytes = 0;
break;
-
default:
- printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
+ printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
+ this->ecc.mode);
BUG();
}
- /* Check hardware ecc function availability and adjust number of ecc bytes per
- * calculation step
+ /*
+ * Set the number of read / write steps for one page depending on ECC
+ * mode
*/
- this->ecc.steps = mtd->oobblock / this->ecc.size;
- if(this->ecc.steps * this->ecc.size != mtd->oobblock) {
- switch (this->eccmode) {
- case NAND_ECC_HW12_2048:
- this->eccbytes += 4;
- case NAND_ECC_HW8_512:
- this->eccbytes += 2;
- case NAND_ECC_HW6_512:
- this->eccbytes += 3;
- case NAND_ECC_HW3_512:
- case NAND_ECC_HW3_256:
- if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
- break;
- printk(KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
++ this->ecc.steps = mtd->writesize / this->ecc.size;
++ if(this->ecc.steps * this->ecc.size != mtd->writesize) {
+ printk(KERN_WARNING "Invalid ecc parameters\n");
BUG();
}