diff options
Diffstat (limited to 'drivers')
51 files changed, 11740 insertions, 5275 deletions
diff --git a/drivers/bus/omap-gpmc.c b/drivers/bus/omap-gpmc.c index 8fd7a91740..cd5b6d5e03 100644 --- a/drivers/bus/omap-gpmc.c +++ b/drivers/bus/omap-gpmc.c @@ -18,6 +18,7 @@ #include <of_mtd.h> #include <linux/clk.h> #include <linux/err.h> +#include <linux/mtd/rawnand.h> #include <mach/gpmc_nand.h> #include <mach/gpmc.h> diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index db9c287b45..36dbe9f825 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -10,13 +10,11 @@ config MTD_WRITE config MTD_OOB_DEVICE bool - select NAND_READ_OOB if NAND default y prompt "Create a device for reading the OOB data" config MTD_RAW_DEVICE bool - select NAND_READ_OOB if NAND default n prompt "mtdraw device to read/write both data+oob" diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c index 1625d938ea..1b1ed53a61 100644 --- a/drivers/mtd/core.c +++ b/drivers/mtd/core.c @@ -15,6 +15,7 @@ #include <common.h> #include <linux/mtd/nand.h> #include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> #include <mtd/mtd-peb.h> #include <mtd/ubi-user.h> #include <cmdlinepart.h> @@ -199,7 +200,7 @@ static int mtd_op_erase(struct cdev *cdev, loff_t count, loff_t offset) erase.mtd = mtd; addr = offset; - if (!mtd->block_isbad) { + if (!mtd->_block_isbad) { erase.addr = addr; erase.len = count; return mtd_erase(mtd, &erase); @@ -210,7 +211,7 @@ static int mtd_op_erase(struct cdev *cdev, loff_t count, loff_t offset) while (count > 0) { dev_dbg(cdev->dev, "erase 0x%08llx len: 0x%08llx\n", addr, erase.len); - if (mtd->allow_erasebad || (mtd->master && mtd->master->allow_erasebad)) + if (mtd->allow_erasebad || (mtd->parent && mtd->parent->allow_erasebad)) ret = 0; else ret = mtd_block_isbad(mtd, addr); @@ -236,7 +237,7 @@ static int mtd_op_protect(struct cdev *cdev, size_t count, loff_t offset, int pr { struct mtd_info *mtd = cdev->priv; - if (!mtd->unlock || !mtd->lock) + if (!mtd->_unlock || !mtd->_lock) return -ENOSYS; if (prot) @@ -252,9 +253,7 @@ int mtd_ioctl(struct cdev *cdev, int request, void *buf) int ret = 0; struct mtd_info *mtd = cdev->priv; struct mtd_info_user *user = buf; -#if (defined(CONFIG_NAND_ECC_HW) || defined(CONFIG_NAND_ECC_SOFT)) struct mtd_ecc_stats *ecc = buf; -#endif struct region_info_user *reg = buf; #ifdef CONFIG_MTD_WRITE struct erase_info_user *ei = buf; @@ -292,14 +291,12 @@ int mtd_ioctl(struct cdev *cdev, int request, void *buf) user->ecctype = -1; user->eccsize = 0; break; -#if (defined(CONFIG_NAND_ECC_HW) || defined(CONFIG_NAND_ECC_SOFT)) case ECCGETSTATS: ecc->corrected = mtd->ecc_stats.corrected; ecc->failed = mtd->ecc_stats.failed; ecc->badblocks = mtd->ecc_stats.badblocks; ecc->bbtblocks = mtd->ecc_stats.bbtblocks; break; -#endif case MEMGETREGIONINFO: if (cdev->mtd) { unsigned long size = cdev->size; @@ -318,35 +315,35 @@ int mtd_ioctl(struct cdev *cdev, int request, void *buf) int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { - if (!mtd->lock) + if (!mtd->_lock) return -EOPNOTSUPP; if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs) return -EINVAL; if (!len) return 0; - return mtd->lock(mtd, ofs, len); + return mtd->_lock(mtd, ofs, len); } int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { - if (!mtd->unlock) + if (!mtd->_unlock) return -EOPNOTSUPP; if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs) return -EINVAL; if (!len) return 0; - return mtd->unlock(mtd, ofs, len); + return mtd->_unlock(mtd, ofs, len); } int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs) { - if (!mtd->block_isbad) + if (!mtd->_block_isbad) return 0; if (ofs < 0 || ofs > mtd->size) return -EINVAL; - return mtd->block_isbad(mtd, ofs); + return mtd->_block_isbad(mtd, ofs); } int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs) @@ -356,8 +353,8 @@ int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs) if (ofs < 0 || ofs >= mtd->size) return -EINVAL; - if (mtd->block_markbad) - ret = mtd->block_markbad(mtd, ofs); + if (mtd->_block_markbad) + ret = mtd->_block_markbad(mtd, ofs); else ret = -ENOSYS; @@ -368,8 +365,8 @@ int mtd_block_markgood(struct mtd_info *mtd, loff_t ofs) { int ret; - if (mtd->block_markgood) - ret = mtd->block_markgood(mtd, ofs); + if (mtd->_block_markgood) + ret = mtd->_block_markgood(mtd, ofs); else ret = -ENOSYS; @@ -377,42 +374,66 @@ int mtd_block_markgood(struct mtd_info *mtd, loff_t ofs) } int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, - u_char *buf) + u_char *buf) { - int ret_code; - *retlen = 0; + struct mtd_oob_ops ops = { + .len = len, + .datbuf = buf, + }; + int ret; if (from < 0 || from >= mtd->size || len > mtd->size - from) return -EINVAL; if (!len) return 0; - /* - * In the absence of an error, drivers return a non-negative integer - * representing the maximum number of bitflips that were corrected on - * any one ecc region (if applicable; zero otherwise). - */ - ret_code = mtd->read(mtd, from, len, retlen, buf); - if (unlikely(ret_code < 0)) - return ret_code; - if (mtd->ecc_strength == 0) - return 0; /* device lacks ecc */ - return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0; + ret = mtd_read_oob(mtd, from, &ops); + *retlen = ops.retlen; + + return ret; +} + +int mtd_write_oob(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops) +{ + int ret; + + ops->retlen = ops->oobretlen = 0; + + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + + /* Check the validity of a potential fallback on mtd->_write */ + if (!mtd->_write_oob && (!mtd->_write || ops->oobbuf)) + return -EOPNOTSUPP; + + if (mtd->_write_oob) + ret = mtd->_write_oob(mtd, to, ops); + else + ret = mtd->_write(mtd, to, ops->len, &ops->retlen, + ops->datbuf); + + return ret; } int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, - const u_char *buf) + const u_char *buf) { - *retlen = 0; + struct mtd_oob_ops ops = { + .len = len, + .datbuf = (u8 *)buf, + }; + int ret; if (to < 0 || to >= mtd->size || len > mtd->size - to) return -EINVAL; - if (!mtd->write || !(mtd->flags & MTD_WRITEABLE)) - return -EROFS; if (!len) return 0; - return mtd->write(mtd, to, len, retlen, buf); + ret = mtd_write_oob(mtd, to, &ops); + *retlen = ops.retlen; + + return ret; } int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) @@ -422,12 +443,10 @@ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; - if (!instr->len) { - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); + if (!instr->len) return 0; - } - return mtd->erase(mtd, instr); + + return mtd->_erase(mtd, instr); } int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) @@ -435,15 +454,23 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) int ret_code; ops->retlen = ops->oobretlen = 0; - if (!mtd->read_oob) + + /* Check the validity of a potential fallback on mtd->_read */ + if (!mtd->_read_oob && (!mtd->_read || ops->oobbuf)) return -EOPNOTSUPP; + /* * In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics * similar to mtd->_read(), returning a non-negative integer * representing max bitflips. In other cases, mtd->_read_oob() may * return -EUCLEAN. In all cases, perform similar logic to mtd_read(). */ - ret_code = mtd->read_oob(mtd, from, ops); + if (mtd->_read_oob) + ret_code = mtd->_read_oob(mtd, from, ops); + else + ret_code = mtd->_read(mtd, from, ops->len, &ops->retlen, + ops->datbuf); + if (unlikely(ret_code < 0)) return ret_code; if (mtd->ecc_strength == 0) @@ -570,7 +597,7 @@ static int mtd_part_compare(struct list_head *a, struct list_head *b) static int mtd_detect(struct device_d *dev) { - struct mtd_info *mtd = container_of(dev, struct mtd_info, class_dev); + struct mtd_info *mtd = container_of(dev, struct mtd_info, dev); int bufsize = 512; void *buf; int ret = 0, i; @@ -619,15 +646,13 @@ int add_mtd_device(struct mtd_info *mtd, const char *devname, int device_id) if (!devname) devname = "mtd"; - dev_set_name(&mtd->class_dev, devname); - mtd->class_dev.id = device_id; - if (mtd->parent) - mtd->class_dev.parent = mtd->parent; + dev_set_name(&mtd->dev, devname); + mtd->dev.id = device_id; if (IS_ENABLED(CONFIG_MTD_UBI)) - mtd->class_dev.detect = mtd_detect; + mtd->dev.detect = mtd_detect; - ret = register_device(&mtd->class_dev); + ret = register_device(&mtd->dev); if (ret) return ret; @@ -637,49 +662,51 @@ int add_mtd_device(struct mtd_info *mtd, const char *devname, int device_id) mtd->cdev.name = xstrdup(devname); else mtd->cdev.name = basprintf("%s%d", devname, - mtd->class_dev.id); + mtd->dev.id); INIT_LIST_HEAD(&mtd->partitions); mtd->cdev.priv = mtd; - mtd->cdev.dev = &mtd->class_dev; + mtd->cdev.dev = &mtd->dev; mtd->cdev.mtd = mtd; if (IS_ENABLED(CONFIG_PARAMETER)) { - dev_add_param_uint64_ro(&mtd->class_dev, "size", &mtd->size, "%llu"); - dev_add_param_uint32_ro(&mtd->class_dev, "erasesize", &mtd->erasesize, "%u"); - dev_add_param_uint32_ro(&mtd->class_dev, "writesize", &mtd->writesize, "%u"); - dev_add_param_uint32_ro(&mtd->class_dev, "oobsize", &mtd->oobsize, "%u"); + dev_add_param_uint64_ro(&mtd->dev, "size", &mtd->size, "%llu"); + dev_add_param_uint32_ro(&mtd->dev, "erasesize", &mtd->erasesize, "%u"); + dev_add_param_uint32_ro(&mtd->dev, "writesize", &mtd->writesize, "%u"); + dev_add_param_uint32_ro(&mtd->dev, "oobsize", &mtd->oobsize, "%u"); } ret = devfs_create(&mtd->cdev); if (ret) goto err; - if (mtd->master && !(mtd->cdev.flags & DEVFS_PARTITION_FIXED)) { + if (mtd->parent && !(mtd->cdev.flags & DEVFS_PARTITION_FIXED)) { struct mtd_info *mtdpart; - list_for_each_entry(mtdpart, &mtd->master->partitions, partitions_entry) { + list_for_each_entry(mtdpart, &mtd->parent->partitions, partitions_entry) { if (mtdpart->master_offset + mtdpart->size <= mtd->master_offset) continue; if (mtd->master_offset + mtd->size <= mtdpart->master_offset) continue; - dev_err(&mtd->class_dev, "New partition %s conflicts with %s\n", + dev_err(&mtd->dev, "New partition %s conflicts with %s\n", mtd->name, mtdpart->name); goto err1; } - list_add_sort(&mtd->partitions_entry, &mtd->master->partitions, mtd_part_compare); + list_add_sort(&mtd->partitions_entry, &mtd->parent->partitions, mtd_part_compare); } if (mtd_can_have_bb(mtd)) mtd->cdev_bb = mtd_add_bb(mtd, NULL); - if (mtd->parent && !mtd->master) { - dev_add_param_string(&mtd->class_dev, "partitions", mtd_partition_set, mtd_partition_get, &mtd->partition_string, mtd); - of_parse_partitions(&mtd->cdev, mtd->parent->device_node); - if (IS_ENABLED(CONFIG_OFDEVICE) && mtd->parent->device_node) { - mtd->of_path = xstrdup(mtd->parent->device_node->full_name); + if (!mtd->parent) { + struct device_node *np = mtd_get_of_node(mtd); + + dev_add_param_string(&mtd->dev, "partitions", mtd_partition_set, mtd_partition_get, &mtd->partition_string, mtd); + if (IS_ENABLED(CONFIG_OFDEVICE) && np) { + of_parse_partitions(&mtd->cdev, np); + mtd->of_path = xstrdup(np->full_name); ret = of_partitions_register_fixup(&mtd->cdev); if (ret) goto err1; @@ -695,7 +722,7 @@ err1: devfs_remove(&mtd->cdev); err: free(mtd->cdev.name); - unregister_device(&mtd->class_dev); + unregister_device(&mtd->dev); return ret; } @@ -711,10 +738,10 @@ int del_mtd_device (struct mtd_info *mtd) devfs_remove(&mtd->cdev); if (mtd->cdev_bb) mtd_del_bb(mtd); - unregister_device(&mtd->class_dev); + unregister_device(&mtd->dev); free(mtd->param_size.value); free(mtd->cdev.name); - if (mtd->master) + if (mtd->parent) list_del(&mtd->partitions_entry); return 0; @@ -746,3 +773,562 @@ const char *mtd_type_str(struct mtd_info *mtd) return "unknown"; } } + +/** + * mtd_ooblayout_ecc - Get the OOB region definition of a specific ECC section + * @mtd: MTD device structure + * @section: ECC section. Depending on the layout you may have all the ECC + * bytes stored in a single contiguous section, or one section + * per ECC chunk (and sometime several sections for a single ECC + * ECC chunk) + * @oobecc: OOB region struct filled with the appropriate ECC position + * information + * + * This function returns ECC section information in the OOB area. If you want + * to get all the ECC bytes information, then you should call + * mtd_ooblayout_ecc(mtd, section++, oobecc) until it returns -ERANGE. + * + * Returns zero on success, a negative error code otherwise. + */ +int mtd_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobecc) +{ + memset(oobecc, 0, sizeof(*oobecc)); + + if (section < 0) + return -EINVAL; + + if (!mtd->ooblayout || !mtd->ooblayout->ecc) + return -ENOTSUPP; + + return mtd->ooblayout->ecc(mtd, section, oobecc); +} +EXPORT_SYMBOL_GPL(mtd_ooblayout_ecc); + +/** + * mtd_ooblayout_free - Get the OOB region definition of a specific free + * section + * @mtd: MTD device structure + * @section: Free section you are interested in. Depending on the layout + * you may have all the free bytes stored in a single contiguous + * section, or one section per ECC chunk plus an extra section + * for the remaining bytes (or other funky layout). + * @oobfree: OOB region struct filled with the appropriate free position + * information + * + * This function returns free bytes position in the OOB area. If you want + * to get all the free bytes information, then you should call + * mtd_ooblayout_free(mtd, section++, oobfree) until it returns -ERANGE. + * + * Returns zero on success, a negative error code otherwise. + */ +int mtd_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobfree) +{ + memset(oobfree, 0, sizeof(*oobfree)); + + if (section < 0) + return -EINVAL; + + if (!mtd->ooblayout || !mtd->ooblayout->free) + return -ENOTSUPP; + + return mtd->ooblayout->free(mtd, section, oobfree); +} +EXPORT_SYMBOL_GPL(mtd_ooblayout_free); + +/** + * mtd_ooblayout_find_region - Find the region attached to a specific byte + * @mtd: mtd info structure + * @byte: the byte we are searching for + * @sectionp: pointer where the section id will be stored + * @oobregion: used to retrieve the ECC position + * @iter: iterator function. Should be either mtd_ooblayout_free or + * mtd_ooblayout_ecc depending on the region type you're searching for + * + * This function returns the section id and oobregion information of a + * specific byte. For example, say you want to know where the 4th ECC byte is + * stored, you'll use: + * + * mtd_ooblayout_find_region(mtd, 3, §ion, &oobregion, mtd_ooblayout_ecc); + * + * Returns zero on success, a negative error code otherwise. + */ +static int mtd_ooblayout_find_region(struct mtd_info *mtd, int byte, + int *sectionp, struct mtd_oob_region *oobregion, + int (*iter)(struct mtd_info *, + int section, + struct mtd_oob_region *oobregion)) +{ + int pos = 0, ret, section = 0; + + memset(oobregion, 0, sizeof(*oobregion)); + + while (1) { + ret = iter(mtd, section, oobregion); + if (ret) + return ret; + + if (pos + oobregion->length > byte) + break; + + pos += oobregion->length; + section++; + } + + /* + * Adjust region info to make it start at the beginning at the + * 'start' ECC byte. + */ + oobregion->offset += byte - pos; + oobregion->length -= byte - pos; + *sectionp = section; + + return 0; +} + +/** + * mtd_ooblayout_find_eccregion - Find the ECC region attached to a specific + * ECC byte + * @mtd: mtd info structure + * @eccbyte: the byte we are searching for + * @sectionp: pointer where the section id will be stored + * @oobregion: OOB region information + * + * Works like mtd_ooblayout_find_region() except it searches for a specific ECC + * byte. + * + * Returns zero on success, a negative error code otherwise. + */ +int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte, + int *section, + struct mtd_oob_region *oobregion) +{ + return mtd_ooblayout_find_region(mtd, eccbyte, section, oobregion, + mtd_ooblayout_ecc); +} +EXPORT_SYMBOL_GPL(mtd_ooblayout_find_eccregion); + +/** + * mtd_ooblayout_get_bytes - Extract OOB bytes from the oob buffer + * @mtd: mtd info structure + * @buf: destination buffer to store OOB bytes + * @oobbuf: OOB buffer + * @start: first byte to retrieve + * @nbytes: number of bytes to retrieve + * @iter: section iterator + * + * Extract bytes attached to a specific category (ECC or free) + * from the OOB buffer and copy them into buf. + * + * Returns zero on success, a negative error code otherwise. + */ +static int mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf, + const u8 *oobbuf, int start, int nbytes, + int (*iter)(struct mtd_info *, + int section, + struct mtd_oob_region *oobregion)) +{ + struct mtd_oob_region oobregion; + int section, ret; + + ret = mtd_ooblayout_find_region(mtd, start, §ion, + &oobregion, iter); + + while (!ret) { + int cnt; + + cnt = min_t(int, nbytes, oobregion.length); + memcpy(buf, oobbuf + oobregion.offset, cnt); + buf += cnt; + nbytes -= cnt; + + if (!nbytes) + break; + + ret = iter(mtd, ++section, &oobregion); + } + + return ret; +} + +/** + * mtd_ooblayout_set_bytes - put OOB bytes into the oob buffer + * @mtd: mtd info structure + * @buf: source buffer to get OOB bytes from + * @oobbuf: OOB buffer + * @start: first OOB byte to set + * @nbytes: number of OOB bytes to set + * @iter: section iterator + * + * Fill the OOB buffer with data provided in buf. The category (ECC or free) + * is selected by passing the appropriate iterator. + * + * Returns zero on success, a negative error code otherwise. + */ +static int mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf, + u8 *oobbuf, int start, int nbytes, + int (*iter)(struct mtd_info *, + int section, + struct mtd_oob_region *oobregion)) +{ + struct mtd_oob_region oobregion; + int section, ret; + + ret = mtd_ooblayout_find_region(mtd, start, §ion, + &oobregion, iter); + + while (!ret) { + int cnt; + + cnt = min_t(int, nbytes, oobregion.length); + memcpy(oobbuf + oobregion.offset, buf, cnt); + buf += cnt; + nbytes -= cnt; + + if (!nbytes) + break; + + ret = iter(mtd, ++section, &oobregion); + } + + return ret; +} + +/** + * mtd_ooblayout_count_bytes - count the number of bytes in a OOB category + * @mtd: mtd info structure + * @iter: category iterator + * + * Count the number of bytes in a given category. + * + * Returns a positive value on success, a negative error code otherwise. + */ +static int mtd_ooblayout_count_bytes(struct mtd_info *mtd, + int (*iter)(struct mtd_info *, + int section, + struct mtd_oob_region *oobregion)) +{ + struct mtd_oob_region oobregion; + int section = 0, ret, nbytes = 0; + + while (1) { + ret = iter(mtd, section++, &oobregion); + if (ret) { + if (ret == -ERANGE) + ret = nbytes; + break; + } + + nbytes += oobregion.length; + } + + return ret; +} + +/** + * mtd_ooblayout_get_eccbytes - extract ECC bytes from the oob buffer + * @mtd: mtd info structure + * @eccbuf: destination buffer to store ECC bytes + * @oobbuf: OOB buffer + * @start: first ECC byte to retrieve + * @nbytes: number of ECC bytes to retrieve + * + * Works like mtd_ooblayout_get_bytes(), except it acts on ECC bytes. + * + * Returns zero on success, a negative error code otherwise. + */ +int mtd_ooblayout_get_eccbytes(struct mtd_info *mtd, u8 *eccbuf, + const u8 *oobbuf, int start, int nbytes) +{ + return mtd_ooblayout_get_bytes(mtd, eccbuf, oobbuf, start, nbytes, + mtd_ooblayout_ecc); +} +EXPORT_SYMBOL_GPL(mtd_ooblayout_get_eccbytes); + +/** + * mtd_ooblayout_set_eccbytes - set ECC bytes into the oob buffer + * @mtd: mtd info structure + * @eccbuf: source buffer to get ECC bytes from + * @oobbuf: OOB buffer + * @start: first ECC byte to set + * @nbytes: number of ECC bytes to set + * + * Works like mtd_ooblayout_set_bytes(), except it acts on ECC bytes. + * + * Returns zero on success, a negative error code otherwise. + */ +int mtd_ooblayout_set_eccbytes(struct mtd_info *mtd, const u8 *eccbuf, + u8 *oobbuf, int start, int nbytes) +{ + return mtd_ooblayout_set_bytes(mtd, eccbuf, oobbuf, start, nbytes, + mtd_ooblayout_ecc); +} +EXPORT_SYMBOL_GPL(mtd_ooblayout_set_eccbytes); + +/** + * mtd_ooblayout_get_databytes - extract data bytes from the oob buffer + * @mtd: mtd info structure + * @databuf: destination buffer to store ECC bytes + * @oobbuf: OOB buffer + * @start: first ECC byte to retrieve + * @nbytes: number of ECC bytes to retrieve + * + * Works like mtd_ooblayout_get_bytes(), except it acts on free bytes. + * + * Returns zero on success, a negative error code otherwise. + */ +int mtd_ooblayout_get_databytes(struct mtd_info *mtd, u8 *databuf, + const u8 *oobbuf, int start, int nbytes) +{ + return mtd_ooblayout_get_bytes(mtd, databuf, oobbuf, start, nbytes, + mtd_ooblayout_free); +} +EXPORT_SYMBOL_GPL(mtd_ooblayout_get_databytes); + +/** + * mtd_ooblayout_set_databytes - set data bytes into the oob buffer + * @mtd: mtd info structure + * @databuf: source buffer to get data bytes from + * @oobbuf: OOB buffer + * @start: first ECC byte to set + * @nbytes: number of ECC bytes to set + * + * Works like mtd_ooblayout_set_bytes(), except it acts on free bytes. + * + * Returns zero on success, a negative error code otherwise. + */ +int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf, + u8 *oobbuf, int start, int nbytes) +{ + return mtd_ooblayout_set_bytes(mtd, databuf, oobbuf, start, nbytes, + mtd_ooblayout_free); +} +EXPORT_SYMBOL_GPL(mtd_ooblayout_set_databytes); + +/** + * mtd_ooblayout_count_freebytes - count the number of free bytes in OOB + * @mtd: mtd info structure + * + * Works like mtd_ooblayout_count_bytes(), except it count free bytes. + * + * Returns zero on success, a negative error code otherwise. + */ +int mtd_ooblayout_count_freebytes(struct mtd_info *mtd) +{ + return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_free); +} +EXPORT_SYMBOL_GPL(mtd_ooblayout_count_freebytes); + +/** + * mtd_ooblayout_count_eccbytes - count the number of ECC bytes in OOB + * @mtd: mtd info structure + * + * Works like mtd_ooblayout_count_bytes(), except it count ECC bytes. + * + * Returns zero on success, a negative error code otherwise. + */ +int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd) +{ + return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_ecc); +} +EXPORT_SYMBOL_GPL(mtd_ooblayout_count_eccbytes); + + +/** + * mtd_ecclayout_ecc - Default ooblayout_ecc iterator implementation + * @mtd: MTD device structure + * @section: ECC section. Depending on the layout you may have all the ECC + * bytes stored in a single contiguous section, or one section + * per ECC chunk (and sometime several sections for a single ECC + * ECC chunk) + * @oobecc: OOB region struct filled with the appropriate ECC position + * information + * + * This function is just a wrapper around the mtd->ecclayout field and is + * here to ease the transition to the mtd_ooblayout_ops approach. + * All it does is convert the layout->eccpos information into proper oob + * region definitions. + * + * Returns zero on success, a negative error code otherwise. + */ +static int mtd_ecclayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobecc) +{ + int eccbyte = 0, cursection = 0, length = 0, eccpos = 0; + + if (!mtd->ecclayout) + return -ENOTSUPP; + + /* + * This logic allows us to reuse the ->ecclayout information and + * expose them as ECC regions (as done for the OOB free regions). + * + * TODO: this should be dropped as soon as we get rid of the + * ->ecclayout field. + */ + for (eccbyte = 0; eccbyte < mtd->ecclayout->eccbytes; eccbyte++) { + eccpos = mtd->ecclayout->eccpos[eccbyte]; + + if (eccbyte < mtd->ecclayout->eccbytes - 1) { + int neccpos = mtd->ecclayout->eccpos[eccbyte + 1]; + + if (eccpos + 1 == neccpos) { + length++; + continue; + } + } + + if (section == cursection) + break; + + length = 0; + cursection++; + } + + if (cursection != section || eccbyte >= mtd->ecclayout->eccbytes) + return -ERANGE; + + oobecc->length = length + 1; + oobecc->offset = eccpos - length; + + return 0; +} + +/** + * mtd_ecclayout_ecc - Default ooblayout_free iterator implementation + * @mtd: MTD device structure + * @section: Free section. Depending on the layout you may have all the free + * bytes stored in a single contiguous section, or one section + * per ECC chunk (and sometime several sections for a single ECC + * ECC chunk) + * @oobfree: OOB region struct filled with the appropriate free position + * information + * + * This function is just a wrapper around the mtd->ecclayout field and is + * here to ease the transition to the mtd_ooblayout_ops approach. + * All it does is convert the layout->oobfree information into proper oob + * region definitions. + * + * Returns zero on success, a negative error code otherwise. + */ +static int mtd_ecclayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobfree) +{ + struct nand_ecclayout *layout = mtd->ecclayout; + + if (!layout) + return -ENOTSUPP; + + if (section >= MTD_MAX_OOBFREE_ENTRIES_LARGE || + !layout->oobfree[section].length) + return -ERANGE; + + oobfree->offset = layout->oobfree[section].offset; + oobfree->length = layout->oobfree[section].length; + + return 0; +} + +static const struct mtd_ooblayout_ops mtd_ecclayout_wrapper_ops = { + .ecc = mtd_ecclayout_ecc, + .free = mtd_ecclayout_free, +}; + +/** + * mtd_set_ecclayout - Attach an ecclayout to an MTD device + * @mtd: MTD device structure + * @ecclayout: The ecclayout to attach to the device + * + * Returns zero on success, a negative error code otherwise. + */ +void mtd_set_ecclayout(struct mtd_info *mtd, struct nand_ecclayout *ecclayout) +{ + if (!mtd || !ecclayout) + return; + + mtd->ecclayout = ecclayout; + mtd_set_ooblayout(mtd, &mtd_ecclayout_wrapper_ops); +} +EXPORT_SYMBOL_GPL(mtd_set_ecclayout); + +void mtd_print_oob_info(struct mtd_info *mtd) +{ + struct mtd_oob_region region; + int ret, i = 0, j, rowsize; + unsigned char *oob; + + if (!mtd->ooblayout) + return; + + oob = malloc(mtd->oobsize); + if (!oob) + return; + + memset(oob, ' ', mtd->oobsize); + + printf("---- ECC regions ----\n"); + while (1) { + ret = mtd->ooblayout->ecc(mtd, i, ®ion); + if (ret) + break; + printf("ecc: offset: %4d length: %4d\n", + region.offset, region.length); + i++; + + for (j = 0; j < region.length; j++) { + unsigned char *p = oob + region.offset + j; + + if (*p != ' ') + printf("oob offset %d already set to '%c'\n", + region.offset + j, *p); + *p = 'e'; + } + } + + i = 0; + + printf("---- free regions ----\n"); + while (1) { + ret = mtd->ooblayout->free(mtd, i, ®ion); + if (ret) + break; + + printf("free: offset: %4d length: %4d\n", + region.offset, region.length); + i++; + + for (j = 0; j < region.length; j++) { + unsigned char *p = oob + region.offset + j; + + if (*p != ' ') + printf("oob offset %d already set to '%c'\n", + region.offset + j, *p); + *p = 'f'; + } + } + + j = 0; + rowsize = 16; + + printf("---- OOB area ----\n"); + while (1) { + printf("%-4d", j); + + for (i = 0; i < rowsize; i++) { + if (i + j >= mtd->oobsize) + break; + if (i == rowsize / 2) + printf(" "); + printf(" %c", oob[j + i]); + } + + printf("\n"); + j += rowsize; + + if (j >= mtd->oobsize) + break; + } + + free(oob); +} diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index a40ba25632..cb0bb5cfec 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -852,7 +852,6 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info) doc_dbg("doc_erase(from=%lld, len=%lld\n", info->addr, info->len); doc_set_device_id(docg3, docg3->device_id); - info->state = MTD_ERASE_PENDING; calc_block_sector(info->addr + info->len, &block0, &block1, &page, &ofs, docg3->reliable); ret = -EINVAL; @@ -864,7 +863,6 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info) docg3->reliable); doc_set_reliable_mode(docg3); for (len = info->len; !ret && len > 0; len -= mtd->erasesize) { - info->state = MTD_ERASING; ret = doc_erase_block(docg3, block0, block1); block0 += 2; block1 += 2; @@ -873,11 +871,9 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info) if (ret) goto reset_err; - info->state = MTD_ERASE_DONE; return 0; reset_err: - info->state = MTD_ERASE_FAILED; return ret; } @@ -1073,13 +1069,13 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) mtd->erasesize /= 2; mtd->writesize = DOC_LAYOUT_PAGE_SIZE; mtd->oobsize = DOC_LAYOUT_OOB_SIZE; - mtd->read = doc_read; - mtd->read_oob = doc_read_oob; - mtd->block_isbad = doc_block_isbad; + mtd->_read = doc_read; + mtd->_read_oob = doc_read_oob; + mtd->_block_isbad = doc_block_isbad; #ifdef CONFIG_MTD_WRITE - mtd->erase = doc_erase; - mtd->write = doc_write; - mtd->write_oob = doc_write_oob; + mtd->_erase = doc_erase; + mtd->_write = doc_write; + mtd->_write_oob = doc_write_oob; #endif } @@ -1176,7 +1172,7 @@ static int __init docg3_probe(struct device_d *dev) continue; } docg3_floors[floor] = mtd; - mtd->parent = dev; + mtd->dev.parent = dev; ret = add_mtd_device(mtd, NULL, DEVICE_ID_DYNAMIC); if (ret) goto err_probe; diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 09a8714247..8845ec3a3e 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -239,7 +239,7 @@ static int m25p_probe(struct device_d *dev) nor->priv = flash; flash->mtd.priv = nor; - flash->mtd.parent = &spi->dev; + flash->mtd.dev.parent = &spi->dev; flash->spimem = spimem; if (spi->mode & SPI_RX_QUAD) diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 7980a91e19..9d4105f82b 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -213,10 +213,6 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) } } - /* Inform MTD subsystem that erase is complete */ - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); - return 0; } @@ -631,12 +627,12 @@ add_dataflash_otp(struct spi_device *spi, char *name, device->writesize = pagesize; device->type = MTD_DATAFLASH; device->flags = MTD_WRITEABLE; - device->erase = dataflash_erase; - device->read = dataflash_read; - device->write = dataflash_write; + device->_erase = dataflash_erase; + device->_read = dataflash_read; + device->_write = dataflash_write; device->priv = priv; - device->parent = &spi->dev; + device->dev.parent = &spi->dev; if (revision >= 'c') otp_tag = otp_setup(device, revision); diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c index acaf002258..9cc8194b5d 100644 --- a/drivers/mtd/devices/mtdram.c +++ b/drivers/mtd/devices/mtdram.c @@ -28,8 +28,6 @@ struct mtdram_priv_data { static int ram_erase(struct mtd_info *mtd, struct erase_info *instr) { memset((char *)mtd->priv + instr->addr, 0xff, instr->len); - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); return 0; } @@ -88,12 +86,12 @@ static int mtdram_probe(struct device_d *dev) mtd->flags = MTD_CAP_RAM; mtd->size = size; - mtd->read = ram_read; - mtd->write = ram_write; - mtd->erase = ram_erase; + mtd->_read = ram_read; + mtd->_write = ram_write; + mtd->_erase = ram_erase; mtd->erasesize = 1; - mtd->parent = dev; + mtd->dev.parent = dev; ret = add_mtd_device(mtd, mtd->name, device_id); return ret; diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index fa430712d0..3032c5a16d 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -383,13 +383,11 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) erase->addr = 0; offset += subdev->size; } - instr->state = erase->state; + kfree(erase); if (err) return err; - if (instr->callback) - instr->callback(instr); return 0; } @@ -579,16 +577,16 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd.subpage_sft = subdev[0]->subpage_sft; concat->mtd.oobsize = subdev[0]->oobsize; concat->mtd.oobavail = subdev[0]->oobavail; - if (subdev[0]->read_oob) - concat->mtd.read_oob = concat_read_oob; - if (subdev[0]->write_oob) - concat->mtd.write_oob = concat_write_oob; - if (subdev[0]->block_isbad) - concat->mtd.block_isbad = concat_block_isbad; - if (subdev[0]->block_markbad) - concat->mtd.block_markbad = concat_block_markbad; - if (subdev[0]->block_markgood) - concat->mtd.block_markgood = concat_block_markgood; + if (subdev[0]->_read_oob) + concat->mtd._read_oob = concat_read_oob; + if (subdev[0]->_write_oob) + concat->mtd._write_oob = concat_write_oob; + if (subdev[0]->_block_isbad) + concat->mtd._block_isbad = concat_block_isbad; + if (subdev[0]->_block_markbad) + concat->mtd._block_markbad = concat_block_markbad; + if (subdev[0]->_block_markgood) + concat->mtd._block_markgood = concat_block_markgood; concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks; @@ -625,8 +623,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c if (concat->mtd.writesize != subdev[i]->writesize || concat->mtd.subpage_sft != subdev[i]->subpage_sft || concat->mtd.oobsize != subdev[i]->oobsize || - !concat->mtd.read_oob != !subdev[i]->read_oob || - !concat->mtd.write_oob != !subdev[i]->write_oob) { + !concat->mtd._read_oob != !subdev[i]->_read_oob || + !concat->mtd._write_oob != !subdev[i]->_write_oob) { kfree(concat); printk("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name); @@ -641,11 +639,11 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->num_subdev = num_devs; concat->mtd.name = xstrdup(name); - concat->mtd.erase = concat_erase; - concat->mtd.read = concat_read; - concat->mtd.write = concat_write; - concat->mtd.lock = concat_lock; - concat->mtd.unlock = concat_unlock; + concat->mtd._erase = concat_erase; + concat->mtd._read = concat_read; + concat->mtd._write = concat_write; + concat->mtd._lock = concat_lock; + concat->mtd._unlock = concat_unlock; /* * Combine the erase block size info of the subdevices: diff --git a/drivers/mtd/mtdoob.c b/drivers/mtd/mtdoob.c index 4aef844485..04e064b227 100644 --- a/drivers/mtd/mtdoob.c +++ b/drivers/mtd/mtdoob.c @@ -72,7 +72,7 @@ static int add_mtdoob_device(struct mtd_info *mtd, const char *devname, void **p { struct mtdoob *mtdoob; - if (mtd->master || mtd->oobsize == 0) + if (mtd->parent || mtd->oobsize == 0) return 0; mtdoob = xzalloc(sizeof(*mtdoob)); @@ -80,7 +80,7 @@ static int add_mtdoob_device(struct mtd_info *mtd, const char *devname, void **p mtdoob->cdev.size = mtd_div_by_wb(mtd->size, mtd) * mtd->oobsize; mtdoob->cdev.name = basprintf("%s.oob", mtd->cdev.name); mtdoob->cdev.priv = mtdoob; - mtdoob->cdev.dev = &mtd->class_dev; + mtdoob->cdev.dev = &mtd->dev; mtdoob->mtd = mtd; *priv = mtdoob; devfs_create(&mtdoob->cdev); @@ -92,7 +92,7 @@ static int del_mtdoob_device(struct mtd_info *mtd, void **priv) { struct mtdoob *mtdoob; - if (mtd->master || mtd->oobsize == 0) + if (mtd->parent || mtd->oobsize == 0) return 0; mtdoob = *priv; diff --git a/drivers/mtd/mtdraw.c b/drivers/mtd/mtdraw.c index b71619244b..57630647b7 100644 --- a/drivers/mtd/mtdraw.c +++ b/drivers/mtd/mtdraw.c @@ -247,12 +247,11 @@ static int mtdraw_erase(struct cdev *cdev, loff_t count, loff_t offset) count = mtdraw_raw_to_mtd_offset(mtdraw, count); memset(&erase, 0, sizeof(erase)); - erase.mtd = mtd; erase.addr = offset; erase.len = mtd->erasesize; while (count > 0) { - dev_dbg(&mtd->class_dev, "erase 0x%08llx len: 0x%08llx\n", + dev_dbg(&mtd->dev, "erase 0x%08llx len: 0x%08llx\n", erase.addr, erase.len); if (!mtd->allow_erasebad) @@ -261,7 +260,7 @@ static int mtdraw_erase(struct cdev *cdev, loff_t count, loff_t offset) ret = 0; if (ret > 0) { - dev_info(&mtd->class_dev, "Skipping bad block at 0x%08llx\n", + dev_info(&mtd->dev, "Skipping bad block at 0x%08llx\n", erase.addr); } else { ret = mtd_erase(mtd, &erase); @@ -297,7 +296,7 @@ static int add_mtdraw_device(struct mtd_info *mtd, const char *devname, void **p { struct mtdraw *mtdraw; - if (mtd->master || mtd->oobsize == 0) + if (mtd->parent || mtd->oobsize == 0) return 0; mtdraw = xzalloc(sizeof(*mtdraw)); @@ -309,7 +308,7 @@ static int add_mtdraw_device(struct mtd_info *mtd, const char *devname, void **p mtdraw->cdev.size = (loff_t)mtd_div_by_wb(mtd->size, mtd) * mtdraw->rps; mtdraw->cdev.name = basprintf("%s.raw", mtd->cdev.name); mtdraw->cdev.priv = mtdraw; - mtdraw->cdev.dev = &mtd->class_dev; + mtdraw->cdev.dev = &mtd->dev; mtdraw->cdev.mtd = mtd; *priv = mtdraw; devfs_create(&mtdraw->cdev); @@ -321,7 +320,7 @@ static int del_mtdraw_device(struct mtd_info *mtd, void **priv) { struct mtdraw *mtdraw; - if (mtd->master || mtd->oobsize == 0) + if (mtd->parent || mtd->oobsize == 0) return 0; mtdraw = *priv; diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index b81e72d6b7..6a162f81f6 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -1,6 +1,5 @@ menuconfig NAND bool "NAND support" - select MTD_NAND_IDS help This enables support for accessing all type of NAND flash devices. For further information see @@ -8,55 +7,11 @@ menuconfig NAND if NAND -config NAND_ECC_SOFT - bool - default y - prompt "Support software ecc" - -config NAND_ECC_BCH +config MTD_NAND_ECC_SW_BCH select BCH bool prompt "Support software BCH ecc" -config NAND_ECC_HW - bool - default y - prompt "Support hardware ecc" - -config NAND_ECC_HW_OOB_FIRST - bool - prompt "Support hardware ecc (oob first)" - -config NAND_ECC_HW_SYNDROME - bool - default y - prompt "Support syndrome hardware ecc controllers" - -config NAND_ECC_HW_NONE - bool - default y - prompt "Support skipping ecc support" - -config NAND_INFO - bool - default y - prompt "Nand vendor/size information" - help - Show informational strings about the vendor and nand flash type - during startup - -config NAND_READ_OOB - bool - -config NAND_BBT - bool - select NAND_READ_OOB - default y - prompt "support bad block tables" - help - Say y here to include support for bad block tables. This speeds - up the process of checking for bad blocks - config NAND_ALLOW_ERASE_BAD bool depends on MTD_WRITE @@ -119,7 +74,6 @@ config NAND_ATMEL_PMECC bool prompt "PMECC support" depends on NAND_ATMEL || COMPILE_TEST - select NAND_ECC_HW help Support for PMECC present on the SoC sam9x5 and sam9n12 @@ -130,16 +84,13 @@ config NAND_S3C24XX help Add support for processor's NAND device controller. -config MTD_NAND_ECC_SMC +config MTD_NAND_ECC_SW_HAMMING_SMC bool "NAND ECC Smart Media byte order" default n help Software ECC according to the Smart Media Specification. The original Linux implementation had byte 0 and 1 swapped. -config MTD_NAND_IDS - tristate - config MTD_NAND_NOMADIK tristate "ST Nomadik 8815 NAND support" depends on ARCH_NOMADIK diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 274bc29ee7..f6e5b41e94 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -1,10 +1,14 @@ # Generic NAND options obj-$(CONFIG_NAND) += nand_ecc.o -obj-$(CONFIG_NAND_ECC_BCH) += nand_bch.o -obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o +obj-$(CONFIG_MTD_NAND_ECC_SW_BCH) += nand_bch.o +obj-$(CONFIG_NAND) += nand_ids.o obj-$(CONFIG_NAND) += nand_base.o nand-bb.o nand_timings.o -obj-$(CONFIG_NAND_BBT) += nand_bbt.o +obj-$(CONFIG_NAND) += nand_legacy.o nand_onfi.o nand_amd.o +obj-$(CONFIG_NAND) += nand_esmt.o nand_hynix.o nand_macronix.o +obj-$(CONFIG_NAND) += nand_micron.o nand_samsung.o nand_toshiba.o +obj-$(CONFIG_NAND) += nand_jedec.o core.o bbt.o +obj-$(CONFIG_NAND) += nand_bbt.o obj-$(CONFIG_MTD_NAND_NOMADIK) += nomadik_nand.o obj-$(CONFIG_NAND_IMX) += nand_imx.o @@ -18,4 +22,3 @@ pbl-$(CONFIG_NAND_S3C24XX) += nand_s3c24xx.o obj-$(CONFIG_NAND_MXS) += nand_mxs.o obj-$(CONFIG_MTD_NAND_DENALI) += nand_denali.o obj-$(CONFIG_MTD_NAND_DENALI_DT) += nand_denali_dt.o - diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index f3875a5648..db13f5b7e4 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -33,6 +33,7 @@ #include <of_mtd.h> #include <linux/mtd/mtd.h> +#include <linux/mtd/rawnand.h> #include <linux/mtd/nand.h> #include <linux/err.h> @@ -102,10 +103,10 @@ struct atmel_nand_host { int *pmecc_mu; int *pmecc_dmu; int *pmecc_delta; + struct nand_ecclayout *ecclayout; + void *ecc_code; }; -static struct nand_ecclayout atmel_pmecc_oobinfo; - /* * Enable NAND. */ @@ -127,9 +128,8 @@ static void atmel_nand_disable(struct atmel_nand_host *host) /* * Hardware specific access to control-lines */ -static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +static void atmel_nand_cmd_ctrl(struct nand_chip *nand_chip, int cmd, unsigned int ctrl) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; if (ctrl & NAND_CTRL_CHANGE) { @@ -150,9 +150,8 @@ static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl /* * Read the Device Ready pin. */ -static int atmel_nand_device_ready(struct mtd_info *mtd) +static int atmel_nand_device_ready(struct nand_chip *nand_chip) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; return gpio_get_value(host->board->rdy_pin); @@ -161,32 +160,24 @@ static int atmel_nand_device_ready(struct mtd_info *mtd) /* * Minimal-overhead PIO for data access. */ -static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) +static void atmel_read_buf(struct nand_chip *nand_chip, u8 *buf, int len) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - - readsb(nand_chip->IO_ADDR_R, buf, len); + readsb(nand_chip->legacy.IO_ADDR_R, buf, len); } -static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) +static void atmel_read_buf16(struct nand_chip *nand_chip, u8 *buf, int len) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - - readsw(nand_chip->IO_ADDR_R, buf, len / 2); + readsw(nand_chip->legacy.IO_ADDR_R, buf, len / 2); } -static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +static void atmel_write_buf(struct nand_chip *nand_chip, const u8 *buf, int len) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - - writesb(nand_chip->IO_ADDR_W, buf, len); + writesb(nand_chip->legacy.IO_ADDR_W, buf, len); } -static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) +static void atmel_write_buf16(struct nand_chip *nand_chip, const u8 *buf, int len) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - - writesw(nand_chip->IO_ADDR_W, buf, len / 2); + writesw(nand_chip->legacy.IO_ADDR_W, buf, len / 2); } /* @@ -208,22 +199,6 @@ static int pmecc_get_ecc_bytes(int cap, int sector_size) return (m * cap + 7) / 8; } -static void pmecc_config_ecc_layout(struct nand_ecclayout *layout, - int oobsize, int ecc_len) -{ - int i; - - layout->eccbytes = ecc_len; - - /* ECC will occupy the last ecc_len bytes continuously */ - for (i = 0; i < ecc_len; i++) - layout->eccpos[i] = oobsize - ecc_len + i; - - layout->oobfree[0].offset = 2; - layout->oobfree[0].length = - oobsize - ecc_len - layout->oobfree[0].offset; -} - static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host) { int table_size; @@ -545,7 +520,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; int i = 0; - int byte_pos, bit_pos, sector_size, pos; + int byte_pos, bit_pos, sector_size; uint32_t tmp; uint8_t err_byte; @@ -562,20 +537,12 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, if (byte_pos < sector_size) { err_byte = *(buf + byte_pos); *(buf + byte_pos) ^= (1 << bit_pos); - - pos = sector_num * host->board->pmecc_sector_size + byte_pos; - dev_info(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", - pos, bit_pos, err_byte, *(buf + byte_pos)); } else { /* Bit flip in OOB area */ tmp = sector_num * host->pmecc_bytes_per_sector + (byte_pos - sector_size); err_byte = ecc[tmp]; ecc[tmp] ^= (1 << bit_pos); - - pos = tmp + nand_chip->ecc.layout->eccpos[0]; - dev_info(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", - pos, bit_pos, err_byte, ecc[tmp]); } i++; @@ -585,17 +552,21 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, return; } -static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, - u8 *ecc) +static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf) { struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; - int i, err_nbr, eccbytes; + int i, err_nbr, ret, max_bitflips = 0; uint8_t *buf_pos; + uint8_t *ecc_code = host->ecc_code; + + ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, nand_chip->oob_poi, 0, + nand_chip->ecc.total); + if (ret) + return ret; - eccbytes = nand_chip->ecc.bytes; - for (i = 0; i < eccbytes; i++) - if (ecc[i] != 0xff) + for (i = 0; i < nand_chip->ecc.bytes * nand_chip->ecc.steps; i++) + if (ecc_code[i] != 0xff) goto normal_check; /* Erased page, return OK */ return 0; @@ -614,26 +585,25 @@ normal_check: if (err_nbr == -1) { dev_err(host->dev, "PMECC: Too many errors\n"); mtd->ecc_stats.failed++; - return -EIO; + return -EBADMSG; } else { - pmecc_correct_data(mtd, buf_pos, ecc, i, + pmecc_correct_data(mtd, buf_pos, ecc_code, i, host->pmecc_bytes_per_sector, err_nbr); mtd->ecc_stats.corrected += err_nbr; + max_bitflips = max(max_bitflips, err_nbr); } } pmecc_stat >>= 1; } - return 0; + return max_bitflips; } -static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) +static int atmel_nand_pmecc_read_page(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct atmel_nand_host *host = chip->priv; - int eccsize = chip->ecc.size; - uint8_t *oob = chip->oob_poi; - uint32_t *eccpos = chip->ecc.layout->eccpos; uint32_t stat; int ret; @@ -645,8 +615,10 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE); pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA); - chip->read_buf(mtd, buf, eccsize); - chip->read_buf(mtd, oob, mtd->oobsize); + nand_read_page_op(chip, page, 0, NULL, 0); + + chip->legacy.read_buf(chip, buf, mtd->writesize); + chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); ret = wait_on_timeout(PMECC_MAX_TIMEOUT_MS, !(pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)); @@ -657,20 +629,23 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, stat = pmecc_readl_relaxed(host->ecc, ISR); if (stat != 0) - if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0) - return -EIO; + return pmecc_correction(mtd, stat, buf); return 0; } -static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, - int oob_required) +static int atmel_nand_pmecc_write_page(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct atmel_nand_host *host = chip->priv; - uint32_t *eccpos = chip->ecc.layout->eccpos; + uint8_t *ecc_calc = host->ecc_code; int i, j, ret; + ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0); + if (ret) + return ret; + pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); @@ -680,7 +655,7 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE); pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA); - chip->write_buf(mtd, (u8 *)buf, mtd->writesize); + chip->legacy.write_buf(chip, (u8 *)buf, mtd->writesize); ret = wait_on_timeout(PMECC_MAX_TIMEOUT_MS, !(pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)); @@ -694,13 +669,22 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, int pos; pos = i * host->pmecc_bytes_per_sector + j; - chip->oob_poi[eccpos[pos]] = - pmecc_readb_ecc_relaxed(host->ecc, i, j); + ecc_calc[pos] = pmecc_readb_ecc_relaxed(host->ecc, i, j); } } - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); - return 0; + ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, + chip->oob_poi, 0, chip->ecc.total); + if (ret) + return ret; + + chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize); + + ret = nand_write_data_op(chip, chip->oob_poi, mtd->oobsize, false); + if (ret) + return ret; + + return nand_prog_page_end_op(chip); } static void atmel_pmecc_core_init(struct mtd_info *mtd) @@ -708,7 +692,7 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd) struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; uint32_t val = 0; - struct nand_ecclayout *ecc_layout; + int eccbytes; pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); @@ -755,11 +739,10 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd) | PMECC_CFG_AUTO_DISABLE); pmecc_writel(host->ecc, CFG, val); - ecc_layout = nand_chip->ecc.layout; + eccbytes = host->pmecc_sector_number * host->pmecc_bytes_per_sector; pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1); - pmecc_writel(host->ecc, SADDR, ecc_layout->eccpos[0]); - pmecc_writel(host->ecc, EADDR, - ecc_layout->eccpos[ecc_layout->eccbytes - 1]); + pmecc_writel(host->ecc, SADDR, mtd->oobsize - eccbytes); + pmecc_writel(host->ecc, EADDR, mtd->oobsize - 1); /* See datasheet about PMECC Clock Control Register */ pmecc_writel(host->ecc, CLK, 2); pmecc_writel(host->ecc, IDR, 0xff); @@ -862,7 +845,7 @@ static int __init atmel_pmecc_nand_init_params(struct device_d *dev, { struct resource *iores; struct nand_chip *nand_chip = &host->nand_chip; - struct mtd_info *mtd = &nand_chip->mtd; + struct mtd_info *mtd = nand_to_mtd(nand_chip); int cap, sector_size, err_no; int ret; @@ -911,9 +894,6 @@ static int __init atmel_pmecc_nand_init_params(struct device_d *dev, host->board->pmecc_lookup_table_offset = 0; } - /* ECC is calculated for the whole page (1 step) */ - nand_chip->ecc.size = mtd->writesize; - /* set ECC page size and oob layout */ switch (mtd->writesize) { case 2048: @@ -929,17 +909,16 @@ static int __init atmel_pmecc_nand_init_params(struct device_d *dev, host->pmecc_index_of = host->pmecc_rom_base + host->board->pmecc_lookup_table_offset; - nand_chip->ecc.steps = 1; - nand_chip->ecc.bytes = host->pmecc_bytes_per_sector * - host->pmecc_sector_number; + nand_chip->ecc.steps = host->pmecc_sector_number; + nand_chip->ecc.bytes = host->pmecc_bytes_per_sector; + nand_chip->ecc.size = sector_size; + nand_chip->ecc.strength = cap; + if (nand_chip->ecc.bytes > mtd->oobsize - 2) { dev_err(host->dev, "No room for ECC bytes\n"); return -EINVAL; } - pmecc_config_ecc_layout(&atmel_pmecc_oobinfo, - mtd->oobsize, - nand_chip->ecc.bytes); - nand_chip->ecc.layout = &atmel_pmecc_oobinfo; + mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); break; case 512: case 1024: @@ -979,10 +958,9 @@ static int __init atmel_pmecc_nand_init_params(struct device_d *dev, * dat: raw data (unused) * ecc_code: buffer for ECC */ -static int atmel_nand_calculate(struct mtd_info *mtd, +static int atmel_nand_calculate(struct nand_chip *nand_chip, const u_char *dat, unsigned char *ecc_code) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; unsigned int ecc_value; @@ -1008,34 +986,22 @@ static int atmel_nand_calculate(struct mtd_info *mtd, * chip: nand chip info structure * buf: buffer to store read data */ -static int atmel_nand_read_page(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) +static int atmel_nand_read_page(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { - int eccsize = chip->ecc.size; + struct mtd_info *mtd = nand_to_mtd(chip); + struct atmel_nand_host *host = chip->priv; int eccbytes = chip->ecc.bytes; - uint32_t *eccpos = chip->ecc.layout->eccpos; + uint32_t *eccpos = host->ecclayout->eccpos; uint8_t *p = buf; uint8_t *oob = chip->oob_poi; uint8_t *ecc_pos; int stat; - /* - * Errata: ALE is incorrectly wired up to the ECC controller - * on the AP7000, so it will include the address cycles in the - * ECC calculation. - * - * Workaround: Reset the parity registers before reading the - * actual data. - */ -#if 0 - if (cpu_is_at32ap7000()) { - struct atmel_nand_host *host = chip->priv; - ecc_writel(host->ecc, CR, ATMEL_ECC_RST); - } -#endif + nand_read_page_op(chip, page, 0, NULL, 0); /* read the page */ - chip->read_buf(mtd, p, eccsize); + chip->legacy.read_buf(chip, p, mtd->writesize); /* move to ECC position if needed */ if (eccpos[0] != 0) { @@ -1045,16 +1011,16 @@ static int atmel_nand_read_page(struct mtd_info *mtd, * NAND_CMD_RNDOUT. * anyway, for small pages, the eccpos[0] == 0 */ - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, + chip->legacy.cmdfunc(chip, NAND_CMD_RNDOUT, mtd->writesize + eccpos[0], -1); } /* the ECC controller needs to read the ECC just after the data */ ecc_pos = oob + eccpos[0]; - chip->read_buf(mtd, ecc_pos, eccbytes); + chip->legacy.read_buf(chip, ecc_pos, eccbytes); /* check if there's an error */ - stat = chip->ecc.correct(mtd, p, oob, NULL); + stat = chip->ecc.correct(chip, p, oob, NULL); if (stat < 0) mtd->ecc_stats.failed++; @@ -1062,10 +1028,10 @@ static int atmel_nand_read_page(struct mtd_info *mtd, mtd->ecc_stats.corrected += stat; /* get back to oob start (end of page) */ - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); + chip->legacy.cmdfunc(chip, NAND_CMD_RNDOUT, mtd->writesize, -1); /* read the oob */ - chip->read_buf(mtd, oob, mtd->oobsize); + chip->legacy.read_buf(chip, oob, mtd->oobsize); return 0; } @@ -1082,10 +1048,9 @@ static int atmel_nand_read_page(struct mtd_info *mtd, * * Detect and correct a 1 bit error for a page */ -static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, +static int atmel_nand_correct(struct nand_chip *nand_chip, u_char *dat, u_char *read_ecc, u_char *isnull) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); struct atmel_nand_host *host = nand_chip->priv; unsigned int ecc_status; unsigned int ecc_word, ecc_bit; @@ -1149,15 +1114,8 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, /* * Enable HW ECC : unused on most chips */ -static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) +static void atmel_nand_hwctl(struct nand_chip *nand_chip, int mode) { -#if 0 - if (cpu_is_at32ap7000()) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct atmel_nand_host *host = nand_chip->priv; - ecc_writel(host->ecc, CR, ATMEL_ECC_RST); - } -#endif } static int atmel_nand_of_init(struct atmel_nand_host *host, struct device_node *np) @@ -1251,7 +1209,7 @@ static int atmel_hw_nand_init_params(struct device_d *dev, { struct resource *iores; struct nand_chip *nand_chip = &host->nand_chip; - struct mtd_info *mtd = &nand_chip->mtd; + struct mtd_info *mtd = nand_to_mtd(nand_chip); iores = dev_request_mem_resource(dev, 1); if (IS_ERR(iores)) @@ -1268,19 +1226,23 @@ static int atmel_hw_nand_init_params(struct device_d *dev, /* set ECC page size and oob layout */ switch (mtd->writesize) { case 512: - nand_chip->ecc.layout = &atmel_oobinfo_small; + host->ecclayout = &atmel_oobinfo_small; + mtd_set_ecclayout(mtd, host->ecclayout); ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); break; case 1024: - nand_chip->ecc.layout = &atmel_oobinfo_large; + host->ecclayout = &atmel_oobinfo_large; + mtd_set_ecclayout(mtd, host->ecclayout); ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056); break; case 2048: - nand_chip->ecc.layout = &atmel_oobinfo_large; + host->ecclayout = &atmel_oobinfo_large; + mtd_set_ecclayout(mtd, host->ecclayout); ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112); break; case 4096: - nand_chip->ecc.layout = &atmel_oobinfo_large; + host->ecclayout = &atmel_oobinfo_large; + mtd_set_ecclayout(mtd, host->ecclayout); ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224); break; default: @@ -1328,7 +1290,7 @@ static int __init atmel_nand_probe(struct device_d *dev) host->io_base = IOMEM(iores->start); nand_chip = &host->nand_chip; - mtd = &nand_chip->mtd; + mtd = nand_to_mtd(nand_chip); host->board = pdata; host->dev = dev; @@ -1341,12 +1303,12 @@ static int __init atmel_nand_probe(struct device_d *dev) } nand_chip->priv = host; /* link the private data structures */ - mtd->parent = dev; + mtd->dev.parent = dev; /* Set address of NAND IO lines */ - nand_chip->IO_ADDR_R = host->io_base; - nand_chip->IO_ADDR_W = host->io_base; - nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl; + nand_chip->legacy.IO_ADDR_R = host->io_base; + nand_chip->legacy.IO_ADDR_W = host->io_base; + nand_chip->legacy.cmd_ctrl = atmel_nand_cmd_ctrl; if (gpio_is_valid(host->board->rdy_pin)) { res = gpio_request(host->board->rdy_pin, "nand_rdy"); @@ -1364,7 +1326,7 @@ static int __init atmel_nand_probe(struct device_d *dev) goto err_no_card; } - nand_chip->dev_ready = atmel_nand_device_ready; + nand_chip->legacy.dev_ready = atmel_nand_device_ready; } if (gpio_is_valid(host->board->enable_pin)) { @@ -1394,7 +1356,7 @@ static int __init atmel_nand_probe(struct device_d *dev) nand_chip->ecc.mode = NAND_ECC_HW; } - nand_chip->chip_delay = 40; /* 40us command delay time */ + nand_chip->legacy.chip_delay = 40; /* 40us command delay time */ if (IS_ENABLED(CONFIG_NAND_ECC_BCH) && pdata->ecc_mode == NAND_ECC_SOFT_BCH) { @@ -1403,11 +1365,11 @@ static int __init atmel_nand_probe(struct device_d *dev) if (host->board->bus_width_16) { /* 16-bit bus width */ nand_chip->options |= NAND_BUSWIDTH_16; - nand_chip->read_buf = atmel_read_buf16; - nand_chip->write_buf = atmel_write_buf16; + nand_chip->legacy.read_buf = atmel_read_buf16; + nand_chip->legacy.write_buf = atmel_write_buf16; } else { - nand_chip->read_buf = atmel_read_buf; - nand_chip->write_buf = atmel_write_buf; + nand_chip->legacy.read_buf = atmel_read_buf; + nand_chip->legacy.write_buf = atmel_write_buf; } atmel_nand_enable(host); @@ -1442,11 +1404,13 @@ static int __init atmel_nand_probe(struct device_d *dev) /* first scan to find the device and get the page size */ - if (nand_scan_ident(mtd, 1, NULL)) { + if (nand_scan_ident(nand_chip, 1, NULL)) { res = -ENXIO; goto err_scan_ident; } + host->ecc_code = xmalloc(mtd->oobsize); + if (IS_ENABLED(CONFIG_NAND_ECC_HW) && nand_chip->ecc.mode == NAND_ECC_HW) { if (IS_ENABLED(CONFIG_NAND_ATMEL_PMECC) && pdata->has_pmecc) @@ -1459,7 +1423,7 @@ static int __init atmel_nand_probe(struct device_d *dev) } /* second phase scan */ - if (nand_scan_tail(mtd)) { + if (nand_scan_tail(nand_chip)) { res = -ENXIO; goto err_scan_tail; } @@ -1469,7 +1433,6 @@ static int __init atmel_nand_probe(struct device_d *dev) if (!res) return res; - nand_release(mtd); err_scan_tail: err_hw_ecc: err_scan_ident: diff --git a/drivers/mtd/nand/bbt.c b/drivers/mtd/nand/bbt.c new file mode 100644 index 0000000000..172ab5ffbc --- /dev/null +++ b/drivers/mtd/nand/bbt.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017 Free Electrons + * + * Authors: + * Boris Brezillon <boris.brezillon@free-electrons.com> + * Peter Pan <peterpandong@micron.com> + */ + +#define pr_fmt(fmt) "nand-bbt: " fmt + +#include <common.h> +#include <linux/mtd/nand.h> +#include <linux/slab.h> + +/** + * nanddev_bbt_init() - Initialize the BBT (Bad Block Table) + * @nand: NAND device + * + * Initialize the in-memory BBT. + * + * Return: 0 in case of success, a negative error code otherwise. + */ +int nanddev_bbt_init(struct nand_device *nand) +{ + unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS); + unsigned int nblocks = nanddev_neraseblocks(nand); + unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block, + BITS_PER_LONG); + + nand->bbt.cache = kcalloc(nwords, sizeof(*nand->bbt.cache), + GFP_KERNEL); + if (!nand->bbt.cache) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL_GPL(nanddev_bbt_init); + +/** + * nanddev_bbt_cleanup() - Cleanup the BBT (Bad Block Table) + * @nand: NAND device + * + * Undoes what has been done in nanddev_bbt_init() + */ +void nanddev_bbt_cleanup(struct nand_device *nand) +{ + kfree(nand->bbt.cache); +} +EXPORT_SYMBOL_GPL(nanddev_bbt_cleanup); + +/** + * nanddev_bbt_update() - Update a BBT + * @nand: nand device + * + * Update the BBT. Currently a NOP function since on-flash bbt is not yet + * supported. + * + * Return: 0 in case of success, a negative error code otherwise. + */ +int nanddev_bbt_update(struct nand_device *nand) +{ + return 0; +} +EXPORT_SYMBOL_GPL(nanddev_bbt_update); + +/** + * nanddev_bbt_get_block_status() - Return the status of an eraseblock + * @nand: nand device + * @entry: the BBT entry + * + * Return: a positive number nand_bbt_block_status status or -%ERANGE if @entry + * is bigger than the BBT size. + */ +int nanddev_bbt_get_block_status(const struct nand_device *nand, + unsigned int entry) +{ + unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS); + unsigned long *pos = nand->bbt.cache + + ((entry * bits_per_block) / BITS_PER_LONG); + unsigned int offs = (entry * bits_per_block) % BITS_PER_LONG; + unsigned long status; + + if (entry >= nanddev_neraseblocks(nand)) + return -ERANGE; + + status = pos[0] >> offs; + if (bits_per_block + offs > BITS_PER_LONG) + status |= pos[1] << (BITS_PER_LONG - offs); + + return status & GENMASK(bits_per_block - 1, 0); +} +EXPORT_SYMBOL_GPL(nanddev_bbt_get_block_status); + +/** + * nanddev_bbt_set_block_status() - Update the status of an eraseblock in the + * in-memory BBT + * @nand: nand device + * @entry: the BBT entry to update + * @status: the new status + * + * Update an entry of the in-memory BBT. If you want to push the updated BBT + * the NAND you should call nanddev_bbt_update(). + * + * Return: 0 in case of success or -%ERANGE if @entry is bigger than the BBT + * size. + */ +int nanddev_bbt_set_block_status(struct nand_device *nand, unsigned int entry, + enum nand_bbt_block_status status) +{ + unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS); + unsigned long *pos = nand->bbt.cache + + ((entry * bits_per_block) / BITS_PER_LONG); + unsigned int offs = (entry * bits_per_block) % BITS_PER_LONG; + unsigned long val = status & GENMASK(bits_per_block - 1, 0); + + if (entry >= nanddev_neraseblocks(nand)) + return -ERANGE; + + pos[0] &= ~GENMASK(offs + bits_per_block - 1, offs); + pos[0] |= val << offs; + + if (bits_per_block + offs > BITS_PER_LONG) { + unsigned int rbits = bits_per_block + offs - BITS_PER_LONG; + + pos[1] &= ~GENMASK(rbits - 1, 0); + pos[1] |= val >> rbits; + } + + return 0; +} +EXPORT_SYMBOL_GPL(nanddev_bbt_set_block_status); diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c new file mode 100644 index 0000000000..ba22662e2f --- /dev/null +++ b/drivers/mtd/nand/core.c @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017 Free Electrons + * + * Authors: + * Boris Brezillon <boris.brezillon@free-electrons.com> + * Peter Pan <peterpandong@micron.com> + */ + +#define pr_fmt(fmt) "nand: " fmt + +#include <common.h> +#include <linux/mtd/nand.h> + +/** + * nanddev_isbad() - Check if a block is bad + * @nand: NAND device + * @pos: position pointing to the block we want to check + * + * Return: true if the block is bad, false otherwise. + */ +bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos) +{ + if (nanddev_bbt_is_initialized(nand)) { + unsigned int entry; + int status; + + entry = nanddev_bbt_pos_to_entry(nand, pos); + status = nanddev_bbt_get_block_status(nand, entry); + /* Lazy block status retrieval */ + if (status == NAND_BBT_BLOCK_STATUS_UNKNOWN) { + if (nand->ops->isbad(nand, pos)) + status = NAND_BBT_BLOCK_FACTORY_BAD; + else + status = NAND_BBT_BLOCK_GOOD; + + nanddev_bbt_set_block_status(nand, entry, status); + } + + if (status == NAND_BBT_BLOCK_WORN || + status == NAND_BBT_BLOCK_FACTORY_BAD) + return true; + + return false; + } + + return nand->ops->isbad(nand, pos); +} +EXPORT_SYMBOL_GPL(nanddev_isbad); + +/** + * nanddev_markbad() - Mark a block as bad + * @nand: NAND device + * @pos: position of the block to mark bad + * + * Mark a block bad. This function is updating the BBT if available and + * calls the low-level markbad hook (nand->ops->markbad()). + * + * Return: 0 in case of success, a negative error code otherwise. + */ +int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos) +{ + struct mtd_info *mtd = nanddev_to_mtd(nand); + unsigned int entry; + int ret = 0; + + if (nanddev_isbad(nand, pos)) + return 0; + + ret = nand->ops->markbad(nand, pos); + if (ret) + pr_warn("failed to write BBM to block @%llx (err = %d)\n", + nanddev_pos_to_offs(nand, pos), ret); + + if (!nanddev_bbt_is_initialized(nand)) + goto out; + + entry = nanddev_bbt_pos_to_entry(nand, pos); + ret = nanddev_bbt_set_block_status(nand, entry, NAND_BBT_BLOCK_WORN); + if (ret) + goto out; + + ret = nanddev_bbt_update(nand); + +out: + if (!ret) + mtd->ecc_stats.badblocks++; + + return ret; +} +EXPORT_SYMBOL_GPL(nanddev_markbad); + +/** + * nanddev_isreserved() - Check whether an eraseblock is reserved or not + * @nand: NAND device + * @pos: NAND position to test + * + * Checks whether the eraseblock pointed by @pos is reserved or not. + * + * Return: true if the eraseblock is reserved, false otherwise. + */ +bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos) +{ + unsigned int entry; + int status; + + if (!nanddev_bbt_is_initialized(nand)) + return false; + + /* Return info from the table */ + entry = nanddev_bbt_pos_to_entry(nand, pos); + status = nanddev_bbt_get_block_status(nand, entry); + return status == NAND_BBT_BLOCK_RESERVED; +} +EXPORT_SYMBOL_GPL(nanddev_isreserved); + +/** + * nanddev_erase() - Erase a NAND portion + * @nand: NAND device + * @pos: position of the block to erase + * + * Erases the block if it's not bad. + * + * Return: 0 in case of success, a negative error code otherwise. + */ +int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos) +{ + if (nanddev_isbad(nand, pos) || nanddev_isreserved(nand, pos)) { + pr_warn("attempt to erase a bad/reserved block @%llx\n", + nanddev_pos_to_offs(nand, pos)); + return -EIO; + } + + return nand->ops->erase(nand, pos); +} +EXPORT_SYMBOL_GPL(nanddev_erase); + +/** + * nanddev_mtd_erase() - Generic mtd->_erase() implementation for NAND devices + * @mtd: MTD device + * @einfo: erase request + * + * This is a simple mtd->_erase() implementation iterating over all blocks + * concerned by @einfo and calling nand->ops->erase() on each of them. + * + * Note that mtd->_erase should not be directly assigned to this helper, + * because there's no locking here. NAND specialized layers should instead + * implement there own wrapper around nanddev_mtd_erase() taking the + * appropriate lock before calling nanddev_mtd_erase(). + * + * Return: 0 in case of success, a negative error code otherwise. + */ +int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo) +{ + struct nand_device *nand = mtd_to_nanddev(mtd); + struct nand_pos pos, last; + int ret; + + nanddev_offs_to_pos(nand, einfo->addr, &pos); + nanddev_offs_to_pos(nand, einfo->addr + einfo->len - 1, &last); + while (nanddev_pos_cmp(&pos, &last) <= 0) { + ret = nanddev_erase(nand, &pos); + if (ret) { + einfo->fail_addr = nanddev_pos_to_offs(nand, &pos); + + return ret; + } + + nanddev_pos_next_eraseblock(nand, &pos); + } + + return 0; +} +EXPORT_SYMBOL_GPL(nanddev_mtd_erase); + +/** + * nanddev_mtd_max_bad_blocks() - Get the maximum number of bad eraseblock on + * a specific region of the NAND device + * @mtd: MTD device + * @offs: offset of the NAND region + * @len: length of the NAND region + * + * Default implementation for mtd->_max_bad_blocks(). Only works if + * nand->memorg.max_bad_eraseblocks_per_lun is > 0. + * + * Return: a positive number encoding the maximum number of eraseblocks on a + * portion of memory, a negative error code otherwise. + */ +int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len) +{ + struct nand_device *nand = mtd_to_nanddev(mtd); + struct nand_pos pos, end; + unsigned int max_bb = 0; + + if (!nand->memorg.max_bad_eraseblocks_per_lun) + return -ENOTSUPP; + + nanddev_offs_to_pos(nand, offs, &pos); + nanddev_offs_to_pos(nand, offs + len, &end); + + for (nanddev_offs_to_pos(nand, offs, &pos); + nanddev_pos_cmp(&pos, &end) < 0; + nanddev_pos_next_lun(nand, &pos)) + max_bb += nand->memorg.max_bad_eraseblocks_per_lun; + + return max_bb; +} +EXPORT_SYMBOL_GPL(nanddev_mtd_max_bad_blocks); + +/** + * nanddev_init() - Initialize a NAND device + * @nand: NAND device + * @ops: NAND device operations + * @owner: NAND device owner + * + * Initializes a NAND device object. Consistency checks are done on @ops and + * @nand->memorg. Also takes care of initializing the BBT. + * + * Return: 0 in case of success, a negative error code otherwise. + */ +int nanddev_init(struct nand_device *nand, const struct nand_ops *ops, + struct module *owner) +{ + struct mtd_info *mtd = nanddev_to_mtd(nand); + struct nand_memory_organization *memorg = nanddev_get_memorg(nand); + + if (!nand || !ops) + return -EINVAL; + + if (!ops->erase || !ops->markbad || !ops->isbad) + return -EINVAL; + + if (!memorg->bits_per_cell || !memorg->pagesize || + !memorg->pages_per_eraseblock || !memorg->eraseblocks_per_lun || + !memorg->planes_per_lun || !memorg->luns_per_target || + !memorg->ntargets) + return -EINVAL; + + nand->rowconv.eraseblock_addr_shift = + fls(memorg->pages_per_eraseblock - 1); + nand->rowconv.lun_addr_shift = fls(memorg->eraseblocks_per_lun - 1) + + nand->rowconv.eraseblock_addr_shift; + + nand->ops = ops; + + mtd->type = memorg->bits_per_cell == 1 ? + MTD_NANDFLASH : MTD_MLCNANDFLASH; + mtd->flags = MTD_CAP_NANDFLASH; + mtd->erasesize = memorg->pagesize * memorg->pages_per_eraseblock; + mtd->writesize = memorg->pagesize; + mtd->writebufsize = memorg->pagesize; + mtd->oobsize = memorg->oobsize; + mtd->size = nanddev_size(nand); + mtd->owner = owner; + + return nanddev_bbt_init(nand); +} +EXPORT_SYMBOL_GPL(nanddev_init); + +/** + * nanddev_cleanup() - Release resources allocated in nanddev_init() + * @nand: NAND device + * + * Basically undoes what has been done in nanddev_init(). + */ +void nanddev_cleanup(struct nand_device *nand) +{ + if (nanddev_bbt_is_initialized(nand)) + nanddev_bbt_cleanup(nand); +} +EXPORT_SYMBOL_GPL(nanddev_cleanup); + +MODULE_DESCRIPTION("Generic NAND framework"); +MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 7698b59720..f9c209d58d 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -1,499 +1,393 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * NAND Flash Controller Device Driver * Copyright (c) 2009 - 2010, Intel Corporation and its suppliers. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * */ #ifndef __DENALI_H__ #define __DENALI_H__ -#include <linux/mtd/nand.h> -#include <linux/spinlock.h> +#include <linux/list.h> +#include <linux/mtd/rawnand.h> +#include <linux/types.h> #define DEVICE_RESET 0x0 -#define DEVICE_RESET__BANK0 0x0001 -#define DEVICE_RESET__BANK1 0x0002 -#define DEVICE_RESET__BANK2 0x0004 -#define DEVICE_RESET__BANK3 0x0008 +#define DEVICE_RESET__BANK(bank) BIT(bank) #define TRANSFER_SPARE_REG 0x10 -#define TRANSFER_SPARE_REG__FLAG 0x0001 +#define TRANSFER_SPARE_REG__FLAG BIT(0) #define LOAD_WAIT_CNT 0x20 -#define LOAD_WAIT_CNT__VALUE 0xffff +#define LOAD_WAIT_CNT__VALUE GENMASK(15, 0) #define PROGRAM_WAIT_CNT 0x30 -#define PROGRAM_WAIT_CNT__VALUE 0xffff +#define PROGRAM_WAIT_CNT__VALUE GENMASK(15, 0) #define ERASE_WAIT_CNT 0x40 -#define ERASE_WAIT_CNT__VALUE 0xffff +#define ERASE_WAIT_CNT__VALUE GENMASK(15, 0) #define INT_MON_CYCCNT 0x50 -#define INT_MON_CYCCNT__VALUE 0xffff +#define INT_MON_CYCCNT__VALUE GENMASK(15, 0) #define RB_PIN_ENABLED 0x60 -#define RB_PIN_ENABLED__BANK0 0x0001 -#define RB_PIN_ENABLED__BANK1 0x0002 -#define RB_PIN_ENABLED__BANK2 0x0004 -#define RB_PIN_ENABLED__BANK3 0x0008 +#define RB_PIN_ENABLED__BANK(bank) BIT(bank) #define MULTIPLANE_OPERATION 0x70 -#define MULTIPLANE_OPERATION__FLAG 0x0001 +#define MULTIPLANE_OPERATION__FLAG BIT(0) #define MULTIPLANE_READ_ENABLE 0x80 -#define MULTIPLANE_READ_ENABLE__FLAG 0x0001 +#define MULTIPLANE_READ_ENABLE__FLAG BIT(0) #define COPYBACK_DISABLE 0x90 -#define COPYBACK_DISABLE__FLAG 0x0001 +#define COPYBACK_DISABLE__FLAG BIT(0) #define CACHE_WRITE_ENABLE 0xa0 -#define CACHE_WRITE_ENABLE__FLAG 0x0001 +#define CACHE_WRITE_ENABLE__FLAG BIT(0) #define CACHE_READ_ENABLE 0xb0 -#define CACHE_READ_ENABLE__FLAG 0x0001 +#define CACHE_READ_ENABLE__FLAG BIT(0) #define PREFETCH_MODE 0xc0 -#define PREFETCH_MODE__PREFETCH_EN 0x0001 -#define PREFETCH_MODE__PREFETCH_BURST_LENGTH 0xfff0 +#define PREFETCH_MODE__PREFETCH_EN BIT(0) +#define PREFETCH_MODE__PREFETCH_BURST_LENGTH GENMASK(15, 4) #define CHIP_ENABLE_DONT_CARE 0xd0 -#define CHIP_EN_DONT_CARE__FLAG 0x01 +#define CHIP_EN_DONT_CARE__FLAG BIT(0) #define ECC_ENABLE 0xe0 -#define ECC_ENABLE__FLAG 0x0001 +#define ECC_ENABLE__FLAG BIT(0) #define GLOBAL_INT_ENABLE 0xf0 -#define GLOBAL_INT_EN_FLAG 0x01 +#define GLOBAL_INT_EN_FLAG BIT(0) -#define WE_2_RE 0x100 -#define WE_2_RE__VALUE 0x003f +#define TWHR2_AND_WE_2_RE 0x100 +#define TWHR2_AND_WE_2_RE__WE_2_RE GENMASK(5, 0) +#define TWHR2_AND_WE_2_RE__TWHR2 GENMASK(13, 8) -#define ADDR_2_DATA 0x110 -#define ADDR_2_DATA__VALUE 0x003f +#define TCWAW_AND_ADDR_2_DATA 0x110 +/* The width of ADDR_2_DATA is 6 bit for old IP, 7 bit for new IP */ +#define TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA GENMASK(6, 0) +#define TCWAW_AND_ADDR_2_DATA__TCWAW GENMASK(13, 8) #define RE_2_WE 0x120 -#define RE_2_WE__VALUE 0x003f +#define RE_2_WE__VALUE GENMASK(5, 0) #define ACC_CLKS 0x130 -#define ACC_CLKS__VALUE 0x000f +#define ACC_CLKS__VALUE GENMASK(3, 0) #define NUMBER_OF_PLANES 0x140 -#define NUMBER_OF_PLANES__VALUE 0x0007 +#define NUMBER_OF_PLANES__VALUE GENMASK(2, 0) #define PAGES_PER_BLOCK 0x150 -#define PAGES_PER_BLOCK__VALUE 0xffff +#define PAGES_PER_BLOCK__VALUE GENMASK(15, 0) #define DEVICE_WIDTH 0x160 -#define DEVICE_WIDTH__VALUE 0x0003 +#define DEVICE_WIDTH__VALUE GENMASK(1, 0) #define DEVICE_MAIN_AREA_SIZE 0x170 -#define DEVICE_MAIN_AREA_SIZE__VALUE 0xffff +#define DEVICE_MAIN_AREA_SIZE__VALUE GENMASK(15, 0) #define DEVICE_SPARE_AREA_SIZE 0x180 -#define DEVICE_SPARE_AREA_SIZE__VALUE 0xffff +#define DEVICE_SPARE_AREA_SIZE__VALUE GENMASK(15, 0) #define TWO_ROW_ADDR_CYCLES 0x190 -#define TWO_ROW_ADDR_CYCLES__FLAG 0x0001 +#define TWO_ROW_ADDR_CYCLES__FLAG BIT(0) #define MULTIPLANE_ADDR_RESTRICT 0x1a0 -#define MULTIPLANE_ADDR_RESTRICT__FLAG 0x0001 +#define MULTIPLANE_ADDR_RESTRICT__FLAG BIT(0) #define ECC_CORRECTION 0x1b0 -#define ECC_CORRECTION__VALUE 0x001f +#define ECC_CORRECTION__VALUE GENMASK(4, 0) +#define ECC_CORRECTION__ERASE_THRESHOLD GENMASK(31, 16) #define READ_MODE 0x1c0 -#define READ_MODE__VALUE 0x000f +#define READ_MODE__VALUE GENMASK(3, 0) #define WRITE_MODE 0x1d0 -#define WRITE_MODE__VALUE 0x000f +#define WRITE_MODE__VALUE GENMASK(3, 0) #define COPYBACK_MODE 0x1e0 -#define COPYBACK_MODE__VALUE 0x000f +#define COPYBACK_MODE__VALUE GENMASK(3, 0) #define RDWR_EN_LO_CNT 0x1f0 -#define RDWR_EN_LO_CNT__VALUE 0x001f +#define RDWR_EN_LO_CNT__VALUE GENMASK(4, 0) #define RDWR_EN_HI_CNT 0x200 -#define RDWR_EN_HI_CNT__VALUE 0x001f +#define RDWR_EN_HI_CNT__VALUE GENMASK(4, 0) #define MAX_RD_DELAY 0x210 -#define MAX_RD_DELAY__VALUE 0x000f +#define MAX_RD_DELAY__VALUE GENMASK(3, 0) #define CS_SETUP_CNT 0x220 -#define CS_SETUP_CNT__VALUE 0x001f +#define CS_SETUP_CNT__VALUE GENMASK(4, 0) +#define CS_SETUP_CNT__TWB GENMASK(17, 12) #define SPARE_AREA_SKIP_BYTES 0x230 -#define SPARE_AREA_SKIP_BYTES__VALUE 0x003f +#define SPARE_AREA_SKIP_BYTES__VALUE GENMASK(5, 0) #define SPARE_AREA_MARKER 0x240 -#define SPARE_AREA_MARKER__VALUE 0xffff +#define SPARE_AREA_MARKER__VALUE GENMASK(15, 0) #define DEVICES_CONNECTED 0x250 -#define DEVICES_CONNECTED__VALUE 0x0007 +#define DEVICES_CONNECTED__VALUE GENMASK(2, 0) #define DIE_MASK 0x260 -#define DIE_MASK__VALUE 0x00ff +#define DIE_MASK__VALUE GENMASK(7, 0) #define FIRST_BLOCK_OF_NEXT_PLANE 0x270 -#define FIRST_BLOCK_OF_NEXT_PLANE__VALUE 0xffff +#define FIRST_BLOCK_OF_NEXT_PLANE__VALUE GENMASK(15, 0) #define WRITE_PROTECT 0x280 -#define WRITE_PROTECT__FLAG 0x0001 +#define WRITE_PROTECT__FLAG BIT(0) #define RE_2_RE 0x290 -#define RE_2_RE__VALUE 0x003f +#define RE_2_RE__VALUE GENMASK(5, 0) #define MANUFACTURER_ID 0x300 -#define MANUFACTURER_ID__VALUE 0x00ff +#define MANUFACTURER_ID__VALUE GENMASK(7, 0) #define DEVICE_ID 0x310 -#define DEVICE_ID__VALUE 0x00ff +#define DEVICE_ID__VALUE GENMASK(7, 0) #define DEVICE_PARAM_0 0x320 -#define DEVICE_PARAM_0__VALUE 0x00ff +#define DEVICE_PARAM_0__VALUE GENMASK(7, 0) #define DEVICE_PARAM_1 0x330 -#define DEVICE_PARAM_1__VALUE 0x00ff +#define DEVICE_PARAM_1__VALUE GENMASK(7, 0) #define DEVICE_PARAM_2 0x340 -#define DEVICE_PARAM_2__VALUE 0x00ff +#define DEVICE_PARAM_2__VALUE GENMASK(7, 0) #define LOGICAL_PAGE_DATA_SIZE 0x350 -#define LOGICAL_PAGE_DATA_SIZE__VALUE 0xffff +#define LOGICAL_PAGE_DATA_SIZE__VALUE GENMASK(15, 0) #define LOGICAL_PAGE_SPARE_SIZE 0x360 -#define LOGICAL_PAGE_SPARE_SIZE__VALUE 0xffff +#define LOGICAL_PAGE_SPARE_SIZE__VALUE GENMASK(15, 0) #define REVISION 0x370 -#define REVISION__VALUE 0xffff +#define REVISION__VALUE GENMASK(15, 0) #define ONFI_DEVICE_FEATURES 0x380 -#define ONFI_DEVICE_FEATURES__VALUE 0x003f +#define ONFI_DEVICE_FEATURES__VALUE GENMASK(5, 0) #define ONFI_OPTIONAL_COMMANDS 0x390 -#define ONFI_OPTIONAL_COMMANDS__VALUE 0x003f +#define ONFI_OPTIONAL_COMMANDS__VALUE GENMASK(5, 0) #define ONFI_TIMING_MODE 0x3a0 -#define ONFI_TIMING_MODE__VALUE 0x003f +#define ONFI_TIMING_MODE__VALUE GENMASK(5, 0) #define ONFI_PGM_CACHE_TIMING_MODE 0x3b0 -#define ONFI_PGM_CACHE_TIMING_MODE__VALUE 0x003f +#define ONFI_PGM_CACHE_TIMING_MODE__VALUE GENMASK(5, 0) #define ONFI_DEVICE_NO_OF_LUNS 0x3c0 -#define ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS 0x00ff -#define ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE 0x0100 +#define ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS GENMASK(7, 0) +#define ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE BIT(8) #define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L 0x3d0 -#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L__VALUE 0xffff +#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L__VALUE GENMASK(15, 0) #define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U 0x3e0 -#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U__VALUE 0xffff - -#define FEATURES 0x3f0 -#define FEATURES__N_BANKS 0x0003 -#define FEATURES__ECC_MAX_ERR 0x003c -#define FEATURES__DMA 0x0040 -#define FEATURES__CMD_DMA 0x0080 -#define FEATURES__PARTITION 0x0100 -#define FEATURES__XDMA_SIDEBAND 0x0200 -#define FEATURES__GPREG 0x0400 -#define FEATURES__INDEX_ADDR 0x0800 +#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U__VALUE GENMASK(15, 0) + +#define FEATURES 0x3f0 +#define FEATURES__N_BANKS GENMASK(1, 0) +#define FEATURES__ECC_MAX_ERR GENMASK(5, 2) +#define FEATURES__DMA BIT(6) +#define FEATURES__CMD_DMA BIT(7) +#define FEATURES__PARTITION BIT(8) +#define FEATURES__XDMA_SIDEBAND BIT(9) +#define FEATURES__GPREG BIT(10) +#define FEATURES__INDEX_ADDR BIT(11) #define TRANSFER_MODE 0x400 -#define TRANSFER_MODE__VALUE 0x0003 - -#define INTR_STATUS(__bank) (0x410 + ((__bank) * 0x50)) -#define INTR_EN(__bank) (0x420 + ((__bank) * 0x50)) - -/* - * Some versions of the IP have the ECC fixup handled in hardware. In this - * configuration we only get interrupted when the error is uncorrectable. - * Unfortunately this bit replaces INTR_STATUS__ECC_TRANSACTION_DONE from the - * old IP. - * taken from patch by Jamie Iles <jamie at jamieiles.com> - * support hardware with internal ECC fixup - */ -#define INTR_STATUS__ECC_UNCOR_ERR 0x0001 - -#define INTR_STATUS__ECC_TRANSACTION_DONE 0x0001 -#define INTR_STATUS__ECC_ERR 0x0002 -#define INTR_STATUS__DMA_CMD_COMP 0x0004 -#define INTR_STATUS__TIME_OUT 0x0008 -#define INTR_STATUS__PROGRAM_FAIL 0x0010 -#define INTR_STATUS__ERASE_FAIL 0x0020 -#define INTR_STATUS__LOAD_COMP 0x0040 -#define INTR_STATUS__PROGRAM_COMP 0x0080 -#define INTR_STATUS__ERASE_COMP 0x0100 -#define INTR_STATUS__PIPE_CPYBCK_CMD_COMP 0x0200 -#define INTR_STATUS__LOCKED_BLK 0x0400 -#define INTR_STATUS__UNSUP_CMD 0x0800 -#define INTR_STATUS__INT_ACT 0x1000 -#define INTR_STATUS__RST_COMP 0x2000 -#define INTR_STATUS__PIPE_CMD_ERR 0x4000 -#define INTR_STATUS__PAGE_XFER_INC 0x8000 - -#define INTR_EN__ECC_TRANSACTION_DONE 0x0001 -#define INTR_EN__ECC_ERR 0x0002 -#define INTR_EN__DMA_CMD_COMP 0x0004 -#define INTR_EN__TIME_OUT 0x0008 -#define INTR_EN__PROGRAM_FAIL 0x0010 -#define INTR_EN__ERASE_FAIL 0x0020 -#define INTR_EN__LOAD_COMP 0x0040 -#define INTR_EN__PROGRAM_COMP 0x0080 -#define INTR_EN__ERASE_COMP 0x0100 -#define INTR_EN__PIPE_CPYBCK_CMD_COMP 0x0200 -#define INTR_EN__LOCKED_BLK 0x0400 -#define INTR_EN__UNSUP_CMD 0x0800 -#define INTR_EN__INT_ACT 0x1000 -#define INTR_EN__RST_COMP 0x2000 -#define INTR_EN__PIPE_CMD_ERR 0x4000 -#define INTR_EN__PAGE_XFER_INC 0x8000 - -#define PAGE_CNT(__bank) (0x430 + ((__bank) * 0x50)) -#define ERR_PAGE_ADDR(__bank) (0x440 + ((__bank) * 0x50)) -#define ERR_BLOCK_ADDR(__bank) (0x450 + ((__bank) * 0x50)) - -#define DATA_INTR 0x550 -#define DATA_INTR__WRITE_SPACE_AV 0x0001 -#define DATA_INTR__READ_DATA_AV 0x0002 - -#define DATA_INTR_EN 0x560 -#define DATA_INTR_EN__WRITE_SPACE_AV 0x0001 -#define DATA_INTR_EN__READ_DATA_AV 0x0002 - -#define GPREG_0 0x570 -#define GPREG_0__VALUE 0xffff - -#define GPREG_1 0x580 -#define GPREG_1__VALUE 0xffff - -#define GPREG_2 0x590 -#define GPREG_2__VALUE 0xffff - -#define GPREG_3 0x5a0 -#define GPREG_3__VALUE 0xffff +#define TRANSFER_MODE__VALUE GENMASK(1, 0) + +#define INTR_STATUS(bank) (0x410 + (bank) * 0x50) +#define INTR_EN(bank) (0x420 + (bank) * 0x50) +/* bit[1:0] is used differently depending on IP version */ +#define INTR__ECC_UNCOR_ERR BIT(0) /* new IP */ +#define INTR__ECC_TRANSACTION_DONE BIT(0) /* old IP */ +#define INTR__ECC_ERR BIT(1) /* old IP */ +#define INTR__DMA_CMD_COMP BIT(2) +#define INTR__TIME_OUT BIT(3) +#define INTR__PROGRAM_FAIL BIT(4) +#define INTR__ERASE_FAIL BIT(5) +#define INTR__LOAD_COMP BIT(6) +#define INTR__PROGRAM_COMP BIT(7) +#define INTR__ERASE_COMP BIT(8) +#define INTR__PIPE_CPYBCK_CMD_COMP BIT(9) +#define INTR__LOCKED_BLK BIT(10) +#define INTR__UNSUP_CMD BIT(11) +#define INTR__INT_ACT BIT(12) +#define INTR__RST_COMP BIT(13) +#define INTR__PIPE_CMD_ERR BIT(14) +#define INTR__PAGE_XFER_INC BIT(15) +#define INTR__ERASED_PAGE BIT(16) + +#define PAGE_CNT(bank) (0x430 + (bank) * 0x50) +#define ERR_PAGE_ADDR(bank) (0x440 + (bank) * 0x50) +#define ERR_BLOCK_ADDR(bank) (0x450 + (bank) * 0x50) #define ECC_THRESHOLD 0x600 -#define ECC_THRESHOLD__VALUE 0x03ff +#define ECC_THRESHOLD__VALUE GENMASK(9, 0) #define ECC_ERROR_BLOCK_ADDRESS 0x610 -#define ECC_ERROR_BLOCK_ADDRESS__VALUE 0xffff +#define ECC_ERROR_BLOCK_ADDRESS__VALUE GENMASK(15, 0) #define ECC_ERROR_PAGE_ADDRESS 0x620 -#define ECC_ERROR_PAGE_ADDRESS__VALUE 0x0fff -#define ECC_ERROR_PAGE_ADDRESS__BANK 0xf000 +#define ECC_ERROR_PAGE_ADDRESS__VALUE GENMASK(11, 0) +#define ECC_ERROR_PAGE_ADDRESS__BANK GENMASK(15, 12) #define ECC_ERROR_ADDRESS 0x630 -#define ECC_ERROR_ADDRESS__OFFSET 0x0fff -#define ECC_ERROR_ADDRESS__SECTOR_NR 0xf000 +#define ECC_ERROR_ADDRESS__OFFSET GENMASK(11, 0) +#define ECC_ERROR_ADDRESS__SECTOR GENMASK(15, 12) #define ERR_CORRECTION_INFO 0x640 -#define ERR_CORRECTION_INFO__BYTEMASK 0x00ff -#define ERR_CORRECTION_INFO__DEVICE_NR 0x0f00 -#define ERR_CORRECTION_INFO__ERROR_TYPE 0x4000 -#define ERR_CORRECTION_INFO__LAST_ERR_INFO 0x8000 +#define ERR_CORRECTION_INFO__BYTE GENMASK(7, 0) +#define ERR_CORRECTION_INFO__DEVICE GENMASK(11, 8) +#define ERR_CORRECTION_INFO__UNCOR BIT(14) +#define ERR_CORRECTION_INFO__LAST_ERR BIT(15) + +#define ECC_COR_INFO(bank) (0x650 + (bank) / 2 * 0x10) +#define ECC_COR_INFO__SHIFT(bank) ((bank) % 2 * 8) +#define ECC_COR_INFO__MAX_ERRORS GENMASK(6, 0) +#define ECC_COR_INFO__UNCOR_ERR BIT(7) + +#define CFG_DATA_BLOCK_SIZE 0x6b0 + +#define CFG_LAST_DATA_BLOCK_SIZE 0x6c0 + +#define CFG_NUM_DATA_BLOCKS 0x6d0 + +#define CFG_META_DATA_SIZE 0x6e0 #define DMA_ENABLE 0x700 -#define DMA_ENABLE__FLAG 0x0001 +#define DMA_ENABLE__FLAG BIT(0) #define IGNORE_ECC_DONE 0x710 -#define IGNORE_ECC_DONE__FLAG 0x0001 +#define IGNORE_ECC_DONE__FLAG BIT(0) #define DMA_INTR 0x720 -#define DMA_INTR__TARGET_ERROR 0x0001 -#define DMA_INTR__DESC_COMP_CHANNEL0 0x0002 -#define DMA_INTR__DESC_COMP_CHANNEL1 0x0004 -#define DMA_INTR__DESC_COMP_CHANNEL2 0x0008 -#define DMA_INTR__DESC_COMP_CHANNEL3 0x0010 -#define DMA_INTR__MEMCOPY_DESC_COMP 0x0020 - #define DMA_INTR_EN 0x730 -#define DMA_INTR_EN__TARGET_ERROR 0x0001 -#define DMA_INTR_EN__DESC_COMP_CHANNEL0 0x0002 -#define DMA_INTR_EN__DESC_COMP_CHANNEL1 0x0004 -#define DMA_INTR_EN__DESC_COMP_CHANNEL2 0x0008 -#define DMA_INTR_EN__DESC_COMP_CHANNEL3 0x0010 -#define DMA_INTR_EN__MEMCOPY_DESC_COMP 0x0020 +#define DMA_INTR__TARGET_ERROR BIT(0) +#define DMA_INTR__DESC_COMP_CHANNEL0 BIT(1) +#define DMA_INTR__DESC_COMP_CHANNEL1 BIT(2) +#define DMA_INTR__DESC_COMP_CHANNEL2 BIT(3) +#define DMA_INTR__DESC_COMP_CHANNEL3 BIT(4) +#define DMA_INTR__MEMCOPY_DESC_COMP BIT(5) #define TARGET_ERR_ADDR_LO 0x740 -#define TARGET_ERR_ADDR_LO__VALUE 0xffff +#define TARGET_ERR_ADDR_LO__VALUE GENMASK(15, 0) #define TARGET_ERR_ADDR_HI 0x750 -#define TARGET_ERR_ADDR_HI__VALUE 0xffff +#define TARGET_ERR_ADDR_HI__VALUE GENMASK(15, 0) #define CHNL_ACTIVE 0x760 -#define CHNL_ACTIVE__CHANNEL0 0x0001 -#define CHNL_ACTIVE__CHANNEL1 0x0002 -#define CHNL_ACTIVE__CHANNEL2 0x0004 -#define CHNL_ACTIVE__CHANNEL3 0x0008 - -#define FLASH_BURST_LENGTH 0x770 -#define CHIP_INTERLEAVE_ENABLE_AND_ALLOW_INT_READS 0X780 -#define NO_OF_BLOCKS_PER_LUN 0X790 -#define LUN_STATUS_CMD 0X7A0 - -#define ACTIVE_SRC_ID 0x800 -#define ACTIVE_SRC_ID__VALUE 0x00ff - -#define PTN_INTR 0x810 -#define PTN_INTR__CONFIG_ERROR 0x0001 -#define PTN_INTR__ACCESS_ERROR_BANK0 0x0002 -#define PTN_INTR__ACCESS_ERROR_BANK1 0x0004 -#define PTN_INTR__ACCESS_ERROR_BANK2 0x0008 -#define PTN_INTR__ACCESS_ERROR_BANK3 0x0010 -#define PTN_INTR__REG_ACCESS_ERROR 0x0020 - -#define PTN_INTR_EN 0x820 -#define PTN_INTR_EN__CONFIG_ERROR 0x0001 -#define PTN_INTR_EN__ACCESS_ERROR_BANK0 0x0002 -#define PTN_INTR_EN__ACCESS_ERROR_BANK1 0x0004 -#define PTN_INTR_EN__ACCESS_ERROR_BANK2 0x0008 -#define PTN_INTR_EN__ACCESS_ERROR_BANK3 0x0010 -#define PTN_INTR_EN__REG_ACCESS_ERROR 0x0020 - -#define PERM_SRC_ID(__bank) (0x830 + ((__bank) * 0x40)) -#define PERM_SRC_ID__SRCID 0x00ff -#define PERM_SRC_ID__DIRECT_ACCESS_ACTIVE 0x0800 -#define PERM_SRC_ID__WRITE_ACTIVE 0x2000 -#define PERM_SRC_ID__READ_ACTIVE 0x4000 -#define PERM_SRC_ID__PARTITION_VALID 0x8000 - -#define MIN_BLK_ADDR(__bank) (0x840 + ((__bank) * 0x40)) -#define MIN_BLK_ADDR__VALUE 0xffff - -#define MAX_BLK_ADDR(__bank) (0x850 + ((__bank) * 0x40)) -#define MAX_BLK_ADDR__VALUE 0xffff - -#define MIN_MAX_BANK(__bank) (0x860 + ((__bank) * 0x40)) -#define MIN_MAX_BANK__MIN_VALUE 0x0003 -#define MIN_MAX_BANK__MAX_VALUE 0x000c - - -/* ffsdefs.h */ -#define CLEAR 0 /*use this to clear a field instead of "fail"*/ -#define SET 1 /*use this to set a field instead of "pass"*/ -#define FAIL 1 /*failed flag*/ -#define PASS 0 /*success flag*/ -#define ERR -1 /*error flag*/ - -/* lld.h */ -#define GOOD_BLOCK 0 -#define DEFECTIVE_BLOCK 1 -#define READ_ERROR 2 - -#define CLK_X 5 -#define CLK_MULTI 4 - -/* spectraswconfig.h */ -#define CMD_DMA 0 - -#define SPECTRA_PARTITION_ID 0 -/**** Block Table and Reserved Block Parameters *****/ -#define SPECTRA_START_BLOCK 3 -#define NUM_FREE_BLOCKS_GATE 30 - -/* KBV - Updated to LNW scratch register address */ -#define SCRATCH_REG_ADDR CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR -#define SCRATCH_REG_SIZE 64 - -#define GLOB_HWCTL_DEFAULT_BLKS 2048 - -#define SUPPORT_15BITECC 1 -#define SUPPORT_8BITECC 1 - -#define CUSTOM_CONF_PARAMS 0 - -#define ONFI_BLOOM_TIME 1 -#define MODE5_WORKAROUND 0 - - -#define MODE_00 0x00000000 -#define MODE_01 0x04000000 -#define MODE_10 0x08000000 -#define MODE_11 0x0C000000 - - -#define DATA_TRANSFER_MODE 0 -#define PROTECTION_PER_BLOCK 1 -#define LOAD_WAIT_COUNT 2 -#define PROGRAM_WAIT_COUNT 3 -#define ERASE_WAIT_COUNT 4 -#define INT_MONITOR_CYCLE_COUNT 5 -#define READ_BUSY_PIN_ENABLED 6 -#define MULTIPLANE_OPERATION_SUPPORT 7 -#define PRE_FETCH_MODE 8 -#define CE_DONT_CARE_SUPPORT 9 -#define COPYBACK_SUPPORT 10 -#define CACHE_WRITE_SUPPORT 11 -#define CACHE_READ_SUPPORT 12 -#define NUM_PAGES_IN_BLOCK 13 -#define ECC_ENABLE_SELECT 14 -#define WRITE_ENABLE_2_READ_ENABLE 15 -#define ADDRESS_2_DATA 16 -#define READ_ENABLE_2_WRITE_ENABLE 17 -#define TWO_ROW_ADDRESS_CYCLES 18 -#define MULTIPLANE_ADDRESS_RESTRICT 19 -#define ACC_CLOCKS 20 -#define READ_WRITE_ENABLE_LOW_COUNT 21 -#define READ_WRITE_ENABLE_HIGH_COUNT 22 - -#define ECC_SECTOR_SIZE 512 - -struct nand_buf { - int head; - int tail; - uint8_t *buf; - dma_addr_t dma_buf; +#define CHNL_ACTIVE__CHANNEL0 BIT(0) +#define CHNL_ACTIVE__CHANNEL1 BIT(1) +#define CHNL_ACTIVE__CHANNEL2 BIT(2) +#define CHNL_ACTIVE__CHANNEL3 BIT(3) + +/** + * struct denali_chip_sel - per-CS data of Denali NAND + * + * @bank: bank id of the controller this CS is connected to + * @hwhr2_and_we_2_re: value of timing register HWHR2_AND_WE_2_RE + * @tcwaw_and_addr_2_data: value of timing register TCWAW_AND_ADDR_2_DATA + * @re_2_we: value of timing register RE_2_WE + * @acc_clks: value of timing register ACC_CLKS + * @rdwr_en_lo_cnt: value of timing register RDWR_EN_LO_CNT + * @rdwr_en_hi_cnt: value of timing register RDWR_EN_HI_CNT + * @cs_setup_cnt: value of timing register CS_SETUP_CNT + * @re_2_re: value of timing register RE_2_RE + */ +struct denali_chip_sel { + int bank; + u32 hwhr2_and_we_2_re; + u32 tcwaw_and_addr_2_data; + u32 re_2_we; + u32 acc_clks; + u32 rdwr_en_lo_cnt; + u32 rdwr_en_hi_cnt; + u32 cs_setup_cnt; + u32 re_2_re; }; -#define INTEL_CE4100 1 -#define INTEL_MRST 2 -#define DT 3 +/** + * struct denali_chip - per-chip data of Denali NAND + * + * @chip: base NAND chip structure + * @node: node to be used to associate this chip with the controller + * @nsels: the number of CS lines of this chip + * @sels: the array of per-cs data + */ +struct denali_chip { + struct nand_chip chip; + struct list_head node; + unsigned int nsels; + struct denali_chip_sel sels[]; +}; -struct denali_nand_info { - struct nand_chip nand; - int flash_bank; /* currently selected chip */ - int status; - int platform; - struct nand_buf buf; +/** + * struct denali_controller - Denali NAND controller data + * + * @controller: base NAND controller structure + * @dev: device + * @chips: the list of chips attached to this controller + * @clk_rate: frequency of core clock + * @clk_x_rate: frequency of bus interface clock + * @reg: base of Register Interface + * @host: base of Host Data/Command interface + * @irq: interrupt number + * @irq_mask: interrupt bits the controller is waiting for + * @irq_status: interrupt bits of events that have happened + * @irq_lock: lock to protect @irq_mask and @irq_status + * @dma_avail: set if DMA engine is available + * @devs_per_cs: number of devices connected in parallel + * @oob_skip_bytes: number of bytes in OOB skipped by the ECC engine + * @active_bank: active bank id + * @nbanks: the number of banks supported by this controller + * @revision: IP revision + * @caps: controller capabilities that cannot be detected run-time + * @ecc_caps: ECC engine capabilities + * @host_read: callback for read access of Host Data/Command Interface + * @host_write: callback for write access of Host Data/Command Interface + * @setup_dma: callback for setup of the Data DMA + */ +struct denali_controller { + struct nand_controller controller; struct device_d *dev; - int total_used_banks; - uint32_t block; /* stored for future use */ - uint32_t page; - void __iomem *flash_reg; /* Mapped io reg base address */ - void __iomem *flash_mem; /* Mapped io reg base address */ - - /* elements used by ISR */ - //struct completion complete; - spinlock_t irq_lock; - uint32_t irq_status; - int irq_debug_array[32]; - int idx; + struct list_head chips; + unsigned long clk_rate; + unsigned long clk_x_rate; + void __iomem *reg; + void __iomem *host; int irq; - - uint32_t devnum; /* represent how many nands connected */ - uint32_t fwblks; /* represent how many blocks FW used */ - uint32_t totalblks; - uint32_t blksperchip; - uint32_t bbtskipbytes; - uint32_t max_banks; - bool have_hw_ecc_fixup; + u32 irq_mask; + u32 irq_status; + spinlock_t irq_lock; + bool dma_avail; + int devs_per_cs; + int oob_skip_bytes; + int active_bank; + int nbanks; + unsigned int revision; + unsigned int caps; + const struct nand_ecc_caps *ecc_caps; + u32 (*host_read)(struct denali_controller *denali, u32 addr); + void (*host_write)(struct denali_controller *denali, u32 addr, + u32 data); + void (*setup_dma)(struct denali_controller *denali, dma_addr_t dma_addr, + int page, bool write); }; -extern int denali_init(struct denali_nand_info *denali); -extern void denali_remove(struct denali_nand_info *denali); +#define DENALI_CAP_HW_ECC_FIXUP BIT(0) +#define DENALI_CAP_DMA_64BIT BIT(1) + +int denali_calc_ecc_bytes(int step_size, int strength); +int denali_chip_init(struct denali_controller *denali, + struct denali_chip *dchip); +int denali_init(struct denali_controller *denali); +void denali_remove(struct denali_controller *denali); #endif /* __DENALI_H__ */ diff --git a/drivers/mtd/nand/internals.h b/drivers/mtd/nand/internals.h new file mode 100644 index 0000000000..7716470a56 --- /dev/null +++ b/drivers/mtd/nand/internals.h @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018 - Bootlin + * + * Author: Boris Brezillon <boris.brezillon@bootlin.com> + * + * Header containing internal definitions to be used only by core files. + * NAND controller drivers should not include this file. + */ + +#ifndef __LINUX_RAWNAND_INTERNALS +#define __LINUX_RAWNAND_INTERNALS + +#include <linux/mtd/rawnand.h> + +/* + * NAND Flash Manufacturer ID Codes + */ +#define NAND_MFR_AMD 0x01 +#define NAND_MFR_ATO 0x9b +#define NAND_MFR_EON 0x92 +#define NAND_MFR_ESMT 0xc8 +#define NAND_MFR_FUJITSU 0x04 +#define NAND_MFR_HYNIX 0xad +#define NAND_MFR_INTEL 0x89 +#define NAND_MFR_MACRONIX 0xc2 +#define NAND_MFR_MICRON 0x2c +#define NAND_MFR_NATIONAL 0x8f +#define NAND_MFR_RENESAS 0x07 +#define NAND_MFR_SAMSUNG 0xec +#define NAND_MFR_SANDISK 0x45 +#define NAND_MFR_STMICRO 0x20 +/* Kioxia is new name of Toshiba memory. */ +#define NAND_MFR_TOSHIBA 0x98 +#define NAND_MFR_WINBOND 0xef + +/** + * struct nand_manufacturer_ops - NAND Manufacturer operations + * @detect: detect the NAND memory organization and capabilities + * @init: initialize all vendor specific fields (like the ->read_retry() + * implementation) if any. + * @cleanup: the ->init() function may have allocated resources, ->cleanup() + * is here to let vendor specific code release those resources. + * @fixup_onfi_param_page: apply vendor specific fixups to the ONFI parameter + * page. This is called after the checksum is verified. + */ +struct nand_manufacturer_ops { + void (*detect)(struct nand_chip *chip); + int (*init)(struct nand_chip *chip); + void (*cleanup)(struct nand_chip *chip); + void (*fixup_onfi_param_page)(struct nand_chip *chip, + struct nand_onfi_params *p); +}; + +/** + * struct nand_manufacturer_desc - NAND Flash Manufacturer descriptor + * @name: Manufacturer name + * @id: manufacturer ID code of device. + * @ops: manufacturer operations + */ +struct nand_manufacturer_desc { + int id; + char *name; + const struct nand_manufacturer_ops *ops; +}; + + +extern struct nand_flash_dev nand_flash_ids[]; + +extern const struct nand_manufacturer_ops amd_nand_manuf_ops; +extern const struct nand_manufacturer_ops esmt_nand_manuf_ops; +extern const struct nand_manufacturer_ops hynix_nand_manuf_ops; +extern const struct nand_manufacturer_ops macronix_nand_manuf_ops; +extern const struct nand_manufacturer_ops micron_nand_manuf_ops; +extern const struct nand_manufacturer_ops samsung_nand_manuf_ops; +extern const struct nand_manufacturer_ops toshiba_nand_manuf_ops; + +/* MLC pairing schemes */ +extern const struct mtd_pairing_scheme dist3_pairing_scheme; + +/* Core functions */ +const struct nand_manufacturer_desc *nand_get_manufacturer_desc(u8 id); +int nand_bbm_get_next_page(struct nand_chip *chip, int page); +int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs); +int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, + int allowbbt); +void onfi_fill_interface_config(struct nand_chip *chip, + struct nand_interface_config *iface, + enum nand_interface_type type, + unsigned int timing_mode); +unsigned int +onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings); +int nand_choose_best_sdr_timings(struct nand_chip *chip, + struct nand_interface_config *iface, + struct nand_sdr_timings *spec_timings); +const struct nand_interface_config *nand_get_reset_interface_config(void); +int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param); +int nand_set_features(struct nand_chip *chip, int addr, u8 *subfeature_param); +int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf, + int oob_required, int page); +int nand_write_page_raw_notsupp(struct nand_chip *chip, const u8 *buf, + int oob_required, int page); +int nand_exit_status_op(struct nand_chip *chip); +int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf, + unsigned int len); +void nand_decode_ext_id(struct nand_chip *chip); +void panic_nand_wait(struct nand_chip *chip, unsigned long timeo); +void sanitize_string(uint8_t *s, size_t len); + +static inline bool nand_has_exec_op(struct nand_chip *chip) +{ + if (!chip->controller || !chip->controller->ops || + !chip->controller->ops->exec_op) + return false; + + return true; +} + +static inline int nand_check_op(struct nand_chip *chip, + const struct nand_operation *op) +{ + if (!nand_has_exec_op(chip)) + return 0; + + return chip->controller->ops->exec_op(chip, op, true); +} + +static inline int nand_exec_op(struct nand_chip *chip, + const struct nand_operation *op) +{ + if (!nand_has_exec_op(chip)) + return -ENOTSUPP; + + if (WARN_ON(op->cs >= nanddev_ntargets(&chip->base))) + return -EINVAL; + + return chip->controller->ops->exec_op(chip, op, false); +} + +static inline bool nand_controller_can_setup_interface(struct nand_chip *chip) +{ + if (!chip->controller || !chip->controller->ops || + !chip->controller->ops->setup_interface) + return false; + + if (chip->options & NAND_KEEP_TIMINGS) + return false; + + return true; +} + +/* BBT functions */ +int nand_markbad_bbt(struct nand_chip *chip, loff_t offs); +int nand_markgood_bbt(struct nand_chip *chip, loff_t offs); +int nand_isreserved_bbt(struct nand_chip *chip, loff_t offs); +int nand_isbad_bbt(struct nand_chip *chip, loff_t offs, int allowbbt); + +/* Legacy */ +void nand_legacy_set_defaults(struct nand_chip *chip); +void nand_legacy_adjust_cmdfunc(struct nand_chip *chip); +int nand_legacy_check_hooks(struct nand_chip *chip); + +/* ONFI functions */ +u16 onfi_crc16(u16 crc, u8 const *p, size_t len); +int nand_onfi_detect(struct nand_chip *chip); + +/* JEDEC functions */ +int nand_jedec_detect(struct nand_chip *chip); + +#endif /* __LINUX_RAWNAND_INTERNALS */ diff --git a/drivers/mtd/nand/nand.h b/drivers/mtd/nand/nand.h deleted file mode 100644 index eb6652c14f..0000000000 --- a/drivers/mtd/nand/nand.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef __NAND_H -#define __NAND_H - -int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, - int page, int sndcmd); -int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, - int page); -int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs); -int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, - int allowbbt); -int nand_block_isbad(struct mtd_info *mtd, loff_t offs); -int nand_block_markbad(struct mtd_info *mtd, loff_t ofs); -void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len); -void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len); -void single_erase_cmd(struct mtd_info *mtd, int page); -void multi_erase_cmd(struct mtd_info *mtd, int page); -void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf); -int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t offset, int data_len, const uint8_t *buf, - int oob_required, int page, int cached, int raw); -int nand_erase(struct mtd_info *mtd, struct erase_info *instr); -int nand_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const uint8_t *buf); -int nand_write_oob(struct mtd_info *mtd, loff_t to, - struct mtd_oob_ops *ops); - -void nand_init_ecc_hw(struct nand_chip *chip); -void nand_init_ecc_soft(struct nand_chip *chip); -void nand_init_ecc_hw_syndrome(struct nand_chip *chip); - -#endif /* __NAND_H */ diff --git a/drivers/mtd/nand/nand_amd.c b/drivers/mtd/nand/nand_amd.c new file mode 100644 index 0000000000..c3d4dae3cd --- /dev/null +++ b/drivers/mtd/nand/nand_amd.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2017 Free Electrons + * Copyright (C) 2017 NextThing Co + * + * Author: Boris Brezillon <boris.brezillon@free-electrons.com> + */ + +#include "internals.h" + +static void amd_nand_decode_id(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; + + memorg = nanddev_get_memorg(&chip->base); + + nand_decode_ext_id(chip); + + /* + * 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 (chip->id.data[4] != 0x00 && chip->id.data[5] == 0x00 && + chip->id.data[6] == 0x00 && chip->id.data[7] == 0x00 && + memorg->pagesize == 512) { + memorg->pages_per_eraseblock = 256; + memorg->pages_per_eraseblock <<= ((chip->id.data[3] & 0x03) << 1); + mtd->erasesize = memorg->pages_per_eraseblock * + memorg->pagesize; + } +} + +static int amd_nand_init(struct nand_chip *chip) +{ + if (nand_is_slc(chip)) + /* + * According to the datasheet of some Cypress SLC NANDs, + * the bad block markers can be in the first, second or last + * page of a block. So let's check all three locations. + */ + chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE | + NAND_BBM_LASTPAGE; + + return 0; +} + +const struct nand_manufacturer_ops amd_nand_manuf_ops = { + .detect = amd_nand_decode_id, + .init = amd_nand_init, +}; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 3f4c787f49..e9c3d7e7c8 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1,6 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * drivers/mtd/nand.c - * * Overview: * This is the generic MTD driver for NAND flash devices. It should be * capable of working with almost all NAND chips currently available. @@ -22,14 +21,9 @@ * Check, if mtd->ecctype should be set to MTD_ECC_HW * if we have HW ECC support. * BBT table is not serialized, has to be fixed - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ -#define pr_fmt(fmt) "nand: " fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <common.h> #include <errno.h> @@ -45,69 +39,180 @@ #include <module.h> #include <of_mtd.h> +#include "internals.h" + /* Define default oob placement schemes for large and small page devices */ -static struct nand_ecclayout nand_oob_8 = { - .eccbytes = 3, - .eccpos = {0, 1, 2}, - .oobfree = { - {.offset = 3, - .length = 2}, - {.offset = 6, - .length = 2} } -}; +static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_ecc_ctrl *ecc = &chip->ecc; -static struct nand_ecclayout nand_oob_16 = { - .eccbytes = 6, - .eccpos = {0, 1, 2, 3, 6, 7}, - .oobfree = { - {.offset = 8, - . length = 8} } -}; + if (section > 1) + return -ERANGE; -static struct nand_ecclayout nand_oob_64 = { - .eccbytes = 24, - .eccpos = { - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63}, - .oobfree = { - {.offset = 2, - .length = 38} } + if (!section) { + oobregion->offset = 0; + if (mtd->oobsize == 16) + oobregion->length = 4; + else + oobregion->length = 3; + } else { + if (mtd->oobsize == 8) + return -ERANGE; + + oobregion->offset = 6; + oobregion->length = ecc->total - 4; + } + + return 0; +} + +static int nand_ooblayout_free_sp(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + if (section > 1) + return -ERANGE; + + if (mtd->oobsize == 16) { + if (section) + return -ERANGE; + + oobregion->length = 8; + oobregion->offset = 8; + } else { + oobregion->length = 2; + if (!section) + oobregion->offset = 3; + else + oobregion->offset = 6; + } + + return 0; +} + +const struct mtd_ooblayout_ops nand_ooblayout_sp_ops = { + .ecc = nand_ooblayout_ecc_sp, + .free = nand_ooblayout_free_sp, }; +EXPORT_SYMBOL_GPL(nand_ooblayout_sp_ops); + +static int nand_ooblayout_ecc_lp(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_ecc_ctrl *ecc = &chip->ecc; -static struct nand_ecclayout nand_oob_128 = { - .eccbytes = 48, - .eccpos = { - 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127}, - .oobfree = { - {.offset = 2, - .length = 78} } + if (section || !ecc->total) + return -ERANGE; + + oobregion->length = ecc->total; + oobregion->offset = mtd->oobsize - oobregion->length; + + return 0; +} + +static int nand_ooblayout_free_lp(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_ecc_ctrl *ecc = &chip->ecc; + + if (section) + return -ERANGE; + + oobregion->length = mtd->oobsize - ecc->total - 2; + oobregion->offset = 2; + + return 0; +} + +const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = { + .ecc = nand_ooblayout_ecc_lp, + .free = nand_ooblayout_free_lp, }; +EXPORT_SYMBOL_GPL(nand_ooblayout_lp_ops); + +/* + * Support the old "large page" layout used for 1-bit Hamming ECC where ECC + * are placed at a fixed offset. + */ +static int nand_ooblayout_ecc_lp_hamming(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_ecc_ctrl *ecc = &chip->ecc; + + if (section) + return -ERANGE; + + switch (mtd->oobsize) { + case 64: + oobregion->offset = 40; + break; + case 128: + oobregion->offset = 80; + break; + default: + return -EINVAL; + } -static int nand_get_device(struct mtd_info *mtd, int new_state); + oobregion->length = ecc->total; + if (oobregion->offset + oobregion->length > mtd->oobsize) + return -ERANGE; -static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, - struct mtd_oob_ops *ops); + return 0; +} -static int check_offs_len(struct mtd_info *mtd, - loff_t ofs, uint64_t len) +static int nand_ooblayout_free_lp_hamming(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) { struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_ecc_ctrl *ecc = &chip->ecc; + int ecc_offset = 0; + + if (section < 0 || section > 1) + return -ERANGE; + + switch (mtd->oobsize) { + case 64: + ecc_offset = 40; + break; + case 128: + ecc_offset = 80; + break; + default: + return -EINVAL; + } + + if (section == 0) { + oobregion->offset = 2; + oobregion->length = ecc_offset - 2; + } else { + oobregion->offset = ecc_offset + ecc->total; + oobregion->length = mtd->oobsize - oobregion->offset; + } + + return 0; +} + +static const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = { + .ecc = nand_ooblayout_ecc_lp_hamming, + .free = nand_ooblayout_free_lp_hamming, +}; + +static int check_offs_len(struct nand_chip *chip, loff_t ofs, uint64_t len) +{ int ret = 0; /* Start address must align on block boundary */ - if (ofs & ((1 << chip->phys_erase_shift) - 1)) { + if (ofs & ((1ULL << chip->phys_erase_shift) - 1)) { pr_debug("%s: unaligned address\n", __func__); ret = -EINVAL; } /* Length must align on block boundary */ - if (len & ((1 << chip->phys_erase_shift) - 1)) { + if (len & ((1ULL << chip->phys_erase_shift) - 1)) { pr_debug("%s: length not block aligned\n", __func__); ret = -EINVAL; } @@ -116,233 +221,348 @@ static int check_offs_len(struct mtd_info *mtd, } /** - * nand_release_device - [GENERIC] release chip - * @mtd: MTD device structure + * nand_extract_bits - Copy unaligned bits from one buffer to another one + * @dst: destination buffer + * @dst_off: bit offset at which the writing starts + * @src: source buffer + * @src_off: bit offset at which the reading starts + * @nbits: number of bits to copy from @src to @dst * - * Release chip lock and wake up anyone waiting on the device. + * Copy bits from one memory region to another (overlap authorized). */ -static void nand_release_device(struct mtd_info *mtd) +void nand_extract_bits(u8 *dst, unsigned int dst_off, const u8 *src, + unsigned int src_off, unsigned int nbits) { - struct nand_chip *chip = mtd_to_nand(mtd); + unsigned int tmp, n; - /* Release the controller and the chip */ - chip->controller->active = NULL; - chip->state = FL_READY; + dst += dst_off / 8; + dst_off %= 8; + src += src_off / 8; + src_off %= 8; + + while (nbits) { + n = min3(8 - dst_off, 8 - src_off, nbits); + + tmp = (*src >> src_off) & GENMASK(n - 1, 0); + *dst &= ~GENMASK(n - 1 + dst_off, dst_off); + *dst |= tmp << dst_off; + + dst_off += n; + if (dst_off >= 8) { + dst++; + dst_off -= 8; + } + + src_off += n; + if (src_off >= 8) { + src++; + src_off -= 8; + } + + nbits -= n; + } } +EXPORT_SYMBOL_GPL(nand_extract_bits); /** - * nand_read_byte - [DEFAULT] read one byte from the chip - * @mtd: MTD device structure + * nand_select_target() - Select a NAND target (A.K.A. die) + * @chip: NAND chip object + * @cs: the CS line to select. Note that this CS id is always from the chip + * PoV, not the controller one * - * Default read function for 8bit buswidth + * Select a NAND target so that further operations executed on @chip go to the + * selected NAND target. */ -static uint8_t nand_read_byte(struct mtd_info *mtd) +void nand_select_target(struct nand_chip *chip, unsigned int cs) { - struct nand_chip *chip = mtd_to_nand(mtd); - return readb(chip->IO_ADDR_R); + /* + * cs should always lie between 0 and nanddev_ntargets(), when that's + * not the case it's a bug and the caller should be fixed. + */ + if (WARN_ON(cs > nanddev_ntargets(&chip->base))) + return; + + chip->cur_cs = cs; + + if (chip->legacy.select_chip) + chip->legacy.select_chip(chip, cs); } +EXPORT_SYMBOL_GPL(nand_select_target); /** - * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip - * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip - * @mtd: MTD device structure - * - * Default read function for 16bit buswidth with endianness conversion. + * nand_deselect_target() - Deselect the currently selected target + * @chip: NAND chip object * + * Deselect the currently selected NAND target. The result of operations + * executed on @chip after the target has been deselected is undefined. */ -static uint8_t nand_read_byte16(struct mtd_info *mtd) +void nand_deselect_target(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); - return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R)); + if (chip->legacy.select_chip) + chip->legacy.select_chip(chip, -1); + + chip->cur_cs = -1; } +EXPORT_SYMBOL_GPL(nand_deselect_target); /** - * nand_read_word - [DEFAULT] read one word from the chip - * @mtd: MTD device structure + * nand_release_device - [GENERIC] release chip + * @chip: NAND chip object * - * Default read function for 16bit buswidth without endianness conversion. + * Release chip lock and wake up anyone waiting on the device. */ -static u16 nand_read_word(struct mtd_info *mtd) +static void nand_release_device(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); - return readw(chip->IO_ADDR_R); + /* Release the controller and the chip */ + mutex_unlock(&chip->controller->lock); + mutex_unlock(&chip->lock); } /** - * nand_select_chip - [DEFAULT] control CE line - * @mtd: MTD device structure - * @chipnr: chipnumber to select, -1 for deselect + * nand_bbm_get_next_page - Get the next page for bad block markers + * @chip: NAND chip object + * @page: First page to start checking for bad block marker usage * - * Default select function for 1 chip devices. + * Returns an integer that corresponds to the page offset within a block, for + * a page that is used to store bad block markers. If no more pages are + * available, -EINVAL is returned. */ -static void nand_select_chip(struct mtd_info *mtd, int chipnr) +int nand_bbm_get_next_page(struct nand_chip *chip, int page) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); + int last_page = ((mtd->erasesize - mtd->writesize) >> + chip->page_shift) & chip->pagemask; + unsigned int bbm_flags = NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE + | NAND_BBM_LASTPAGE; - switch (chipnr) { - case -1: - chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); - break; - case 0: - break; + if (page == 0 && !(chip->options & bbm_flags)) + return 0; + if (page == 0 && chip->options & NAND_BBM_FIRSTPAGE) + return 0; + if (page <= 1 && chip->options & NAND_BBM_SECONDPAGE) + return 1; + if (page <= last_page && chip->options & NAND_BBM_LASTPAGE) + return last_page; - default: - BUG(); - } + return -EINVAL; } /** - * nand_write_buf - [DEFAULT] write buffer to chip - * @mtd: MTD device structure - * @buf: data buffer - * @len: number of bytes to write + * nand_block_bad - [DEFAULT] Read bad block marker from the chip + * @chip: NAND chip object + * @ofs: offset from device start * - * Default write function for 8bit buswidth. + * Check, if the block is bad. */ -static __maybe_unused void nand_write_buf(struct mtd_info *mtd, - const uint8_t *buf, int len) +static int nand_block_bad(struct nand_chip *chip, loff_t ofs) { - int i; - struct nand_chip *chip = mtd_to_nand(mtd); + int first_page, page_offset; + int res; + u8 bad; - for (i = 0; i < len; i++) - writeb(buf[i], chip->IO_ADDR_W); + first_page = (int)(ofs >> chip->page_shift) & chip->pagemask; + page_offset = nand_bbm_get_next_page(chip, 0); + + while (page_offset >= 0) { + res = chip->ecc.read_oob(chip, first_page + page_offset); + if (res < 0) + return res; + + bad = chip->oob_poi[chip->badblockpos]; + + if (likely(chip->badblockbits == 8)) + res = bad != 0xFF; + else + res = hweight8(bad) < chip->badblockbits; + if (res) + return res; + + page_offset = nand_bbm_get_next_page(chip, page_offset + 1); + } + + return 0; +} + +static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs) +{ + if (chip->options & NAND_NO_BBM_QUIRK) + return 0; + + if (chip->legacy.block_bad) + return chip->legacy.block_bad(chip, ofs); + + return nand_block_bad(chip, ofs); } /** - * nand_read_buf - [DEFAULT] read chip data into buffer - * @mtd: MTD device structure - * @buf: buffer to store date - * @len: number of bytes to read + * nand_get_device - [GENERIC] Get chip for selected access + * @chip: NAND chip structure + * + * Lock the device and its controller for exclusive access * - * Default read function for 8bit buswidth. + * Return: -EBUSY if the chip has been suspended, 0 otherwise */ -static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static int nand_get_device(struct nand_chip *chip) { - int i; - struct nand_chip *chip = mtd_to_nand(mtd); + mutex_lock(&chip->lock); + if (chip->suspended) { + mutex_unlock(&chip->lock); + return -EBUSY; + } + mutex_lock(&chip->controller->lock); - for (i = 0; i < len; i++) - buf[i] = readb(chip->IO_ADDR_R); + return 0; } /** - * nand_write_buf16 - [DEFAULT] write buffer to chip - * @mtd: MTD device structure - * @buf: data buffer - * @len: number of bytes to write + * nand_check_wp - [GENERIC] check if the chip is write protected + * @chip: NAND chip object * - * Default write function for 16bit buswidth. + * Check, if the device is write protected. The function expects, that the + * device is already selected. */ -static __maybe_unused void nand_write_buf16(struct mtd_info *mtd, - const uint8_t *buf, int len) +static int nand_check_wp(struct nand_chip *chip) { - int i; - struct nand_chip *chip = mtd_to_nand(mtd); - u16 *p = (u16 *) buf; - len >>= 1; + u8 status; + int ret; - for (i = 0; i < len; i++) - writew(p[i], chip->IO_ADDR_W); + /* Broken xD cards report WP despite being writable */ + if (chip->options & NAND_BROKEN_XD) + return 0; + + /* Check the WP bit */ + ret = nand_status_op(chip, &status); + if (ret) + return ret; + return status & NAND_STATUS_WP ? 0 : 1; } /** - * nand_read_buf16 - [DEFAULT] read chip data into buffer - * @mtd: MTD device structure - * @buf: buffer to store date - * @len: number of bytes to read - * - * Default read function for 16bit buswidth. + * nand_fill_oob - [INTERN] Transfer client buffer to oob + * @chip: NAND chip object + * @oob: oob data buffer + * @len: oob data write length + * @ops: oob ops structure */ -static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) +static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, + struct mtd_oob_ops *ops) { - int i; - struct nand_chip *chip = mtd_to_nand(mtd); - u16 *p = (u16 *) buf; - len >>= 1; + struct mtd_info *mtd = nand_to_mtd(chip); + int ret; - for (i = 0; i < len; i++) - p[i] = readw(chip->IO_ADDR_R); + /* + * Initialise to all 0xFF, to avoid the possibility of left over OOB + * data from a previous OOB read. + */ + memset(chip->oob_poi, 0xff, mtd->oobsize); + + switch (ops->mode) { + + case MTD_OPS_PLACE_OOB: + case MTD_OPS_RAW: + memcpy(chip->oob_poi + ops->ooboffs, oob, len); + return oob + len; + + case MTD_OPS_AUTO_OOB: + ret = mtd_ooblayout_set_databytes(mtd, oob, chip->oob_poi, + ops->ooboffs, len); + BUG_ON(ret); + return oob + len; + + default: + BUG(); + } + return NULL; } /** - * nand_block_bad - [DEFAULT] Read bad block marker from the chip - * @mtd: MTD device structure - * @ofs: offset from device start - * @getchip: 0, if the chip is already selected + * nand_do_write_oob - [MTD Interface] NAND write out-of-band + * @chip: NAND chip object + * @to: offset to write to + * @ops: oob operation description structure * - * Check, if the block is bad. + * NAND write out-of-band. */ -static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) +static int nand_do_write_oob(struct nand_chip *chip, loff_t to, + struct mtd_oob_ops *ops) { - int page, chipnr, res = 0, i = 0; - struct nand_chip *chip = mtd_to_nand(mtd); - u16 bad; + struct mtd_info *mtd = nand_to_mtd(chip); + int chipnr, page, status, len, ret; - if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) - ofs += mtd->erasesize - mtd->writesize; + pr_debug("%s: to = 0x%08x, len = %i\n", + __func__, (unsigned int)to, (int)ops->ooblen); - page = (int)(ofs >> chip->page_shift) & chip->pagemask; + len = mtd_oobavail(mtd, ops); - if (getchip) { - chipnr = (int)(ofs >> chip->chip_shift); + /* Do not allow write past end of page */ + if ((ops->ooboffs + ops->ooblen) > len) { + pr_debug("%s: attempt to write past end of page\n", + __func__); + return -EINVAL; + } - nand_get_device(mtd, FL_READING); + chipnr = (int)(to >> chip->chip_shift); - /* Select the NAND device */ - chip->select_chip(mtd, chipnr); - } + /* + * Reset the chip. Some chips (like the Toshiba TC5832DC found in one + * of my DiskOnChip 2000 test units) will clear the whole data page too + * if we don't do this. I have no clue why, but I seem to have 'fixed' + * it in the doc2000 driver in August 1999. dwmw2. + */ + ret = nand_reset(chip, chipnr); + if (ret) + return ret; - do { - if (chip->options & NAND_BUSWIDTH_16) { - chip->cmdfunc(mtd, NAND_CMD_READOOB, - chip->badblockpos & 0xFE, page); - bad = cpu_to_le16(chip->read_word(mtd)); - if (chip->badblockpos & 0x1) - bad >>= 8; - else - bad &= 0xFF; - } else { - chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, - page); - bad = chip->read_byte(mtd); - } + nand_select_target(chip, chipnr); - if (likely(chip->badblockbits == 8)) - res = bad != 0xFF; - else - res = hweight8(bad) < chip->badblockbits; - ofs += mtd->writesize; - page = (int)(ofs >> chip->page_shift) & chip->pagemask; - i++; - } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE)); + /* Shift to get page */ + page = (int)(to >> chip->page_shift); - if (getchip) { - chip->select_chip(mtd, -1); - nand_release_device(mtd); + /* Check, if it is write protected */ + if (nand_check_wp(chip)) { + nand_deselect_target(chip); + return -EROFS; } - return res; + /* Invalidate the page cache, if we write to the cached page */ + if (page == chip->pagecache.page) + chip->pagecache.page = -1; + + nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops); + + if (ops->mode == MTD_OPS_RAW) + status = chip->ecc.write_oob_raw(chip, page & chip->pagemask); + else + status = chip->ecc.write_oob(chip, page & chip->pagemask); + + nand_deselect_target(chip); + + if (status) + return status; + + ops->oobretlen = ops->ooblen; + + return 0; } /** * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker - * @mtd: MTD device structure + * @chip: NAND chip object * @ofs: offset from device start * * This is the default implementation, which can be overridden by a hardware * specific driver. It provides the details for writing a bad block marker to a * block. */ -static __maybe_unused int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) +static int nand_default_block_markbad(struct nand_chip *chip, loff_t ofs) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_oob_ops ops; uint8_t buf[2] = { 0, 0 }; - int ret = 0, res, i = 0; + int ret = 0, res, page_offset; - ops.datbuf = NULL; + memset(&ops, 0, sizeof(ops)); ops.oobbuf = buf; ops.ooboffs = chip->badblockpos; if (chip->options & NAND_BUSWIDTH_16) { @@ -353,41 +573,57 @@ static __maybe_unused int nand_default_block_markbad(struct mtd_info *mtd, loff_ } ops.mode = MTD_OPS_PLACE_OOB; - /* Write to first/last page(s) if necessary */ - if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) - ofs += mtd->erasesize - mtd->writesize; - do { - res = nand_do_write_oob(mtd, ofs, &ops); + page_offset = nand_bbm_get_next_page(chip, 0); + + while (page_offset >= 0) { + res = nand_do_write_oob(chip, + ofs + (page_offset * mtd->writesize), + &ops); + if (!ret) ret = res; - i++; - ofs += mtd->writesize; - } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); + page_offset = nand_bbm_get_next_page(chip, page_offset + 1); + } return ret; } /** + * nand_markbad_bbm - mark a block by updating the BBM + * @chip: NAND chip object + * @ofs: offset of the block to mark bad + */ +int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs) +{ + if (chip->legacy.block_markbad) + return chip->legacy.block_markbad(chip, ofs); + + return nand_default_block_markbad(chip, ofs); +} + +/** * nand_block_markbad_lowlevel - mark a block bad - * @mtd: MTD device structure + * @chip: NAND chip object * @ofs: offset from device start * * This function performs the generic NAND bad block marking steps (i.e., bad * block table(s) and/or marker(s)). We only allow the hardware driver to - * specify how to write bad block markers to OOB (chip->block_markbad). + * specify how to write bad block markers to OOB (chip->legacy.block_markbad). * * We try operations in the following order: + * * (1) erase the affected block, to allow OOB marker to be written cleanly * (2) write bad block marker to OOB area of affected block (unless flag * NAND_BBT_NO_OOB_BBM is present) * (3) update the BBT + * * Note that we retain the first error encountered in (2) or (3), finish the * procedures, and dump the error in the end. - */ -static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs) +*/ +static int nand_block_markbad_lowlevel(struct nand_chip *chip, loff_t ofs) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); int res, ret = 0; if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) { @@ -395,20 +631,22 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs) /* Attempt erase before marking OOB */ memset(&einfo, 0, sizeof(einfo)); - einfo.mtd = mtd; einfo.addr = ofs; - einfo.len = 1 << chip->phys_erase_shift; - nand_erase_nand(mtd, &einfo, 0); + einfo.len = 1ULL << chip->phys_erase_shift; + nand_erase_nand(chip, &einfo, 0); /* Write bad block marker to OOB */ - nand_get_device(mtd, FL_WRITING); - ret = chip->block_markbad(mtd, ofs); - nand_release_device(mtd); + ret = nand_get_device(chip); + if (ret) + return ret; + + ret = nand_markbad_bbm(chip, ofs); + nand_release_device(chip); } /* Mark block bad in BBT */ - if (IS_ENABLED(CONFIG_NAND_BBT) && chip->bbt) { - res = nand_markbad_bbt(mtd, ofs); + if (chip->bbt) { + res = nand_markbad_bbt(chip, ofs); if (!ret) ret = res; } @@ -429,9 +667,9 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs) * (2) check bad block marker * (3) update the BBT */ -static int nand_block_markgood_lowlevel(struct mtd_info *mtd, loff_t ofs) +static int nand_block_markgood_lowlevel(struct nand_chip *chip, loff_t ofs) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); bool allow_erasebad; int ret; @@ -445,21 +683,13 @@ static int nand_block_markgood_lowlevel(struct mtd_info *mtd, loff_t ofs) einfo.mtd = mtd; einfo.addr = ofs; einfo.len = 1 << chip->phys_erase_shift; - nand_erase_nand(mtd, &einfo, 0); + nand_erase_nand(chip, &einfo, 0); mtd->allow_erasebad = allow_erasebad; - - /* - * Verify erase succeded. We need to select chip again, - * as nand_erase_nand deselected it. - */ - ret = chip->block_bad(mtd, ofs, 1); - if (ret) - return ret; } /* Mark block good in BBT */ if (IS_ENABLED(CONFIG_NAND_BBT) && chip->bbt) { - ret = nand_markgood_bbt(mtd, ofs); + ret = nand_markgood_bbt(chip, ofs); if (ret) return ret; } @@ -471,515 +701,1800 @@ static int nand_block_markgood_lowlevel(struct mtd_info *mtd, loff_t ofs) } /** - * nand_check_wp - [GENERIC] check if the chip is write protected - * @mtd: MTD device structure + * nand_block_checkbad - [GENERIC] Check if a block is marked bad + * @chip: NAND chip object + * @ofs: offset from device start + * @allowbbt: 1, if its allowed to access the bbt area * - * Check, if the device is write protected. The function expects, that the - * device is already selected. + * Check, if the block is bad. Either by reading the bad block table or + * calling of the scan function. */ -static int nand_check_wp(struct mtd_info *mtd) +static int nand_block_checkbad(struct nand_chip *chip, loff_t ofs, int allowbbt) { - struct nand_chip *chip = mtd_to_nand(mtd); + /* Return info from the table */ + if (chip->bbt) + return nand_isbad_bbt(chip, ofs, allowbbt); - /* Broken xD cards report WP despite being writable */ - if (chip->options & NAND_BROKEN_XD) + return nand_isbad_bbm(chip, ofs); +} + +/** + * nand_soft_waitrdy - Poll STATUS reg until RDY bit is set to 1 + * @chip: NAND chip structure + * @timeout_ms: Timeout in ms + * + * Poll the STATUS register using ->exec_op() until the RDY bit becomes 1. + * If that does not happen whitin the specified timeout, -ETIMEDOUT is + * returned. + * + * This helper is intended to be used when the controller does not have access + * to the NAND R/B pin. + * + * Be aware that calling this helper from an ->exec_op() implementation means + * ->exec_op() must be re-entrant. + * + * Return 0 if the NAND chip is ready, a negative error otherwise. + */ +int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms) +{ + const struct nand_sdr_timings *timings; + u8 status = 0; + int ret; + uint64_t start; + + if (!nand_has_exec_op(chip)) + return -ENOTSUPP; + + /* Wait tWB before polling the STATUS reg. */ + timings = nand_get_sdr_timings(nand_get_interface_config(chip)); + ndelay(PSEC_TO_NSEC(timings->tWB_max)); + + ret = nand_status_op(chip, NULL); + if (ret) + return ret; + + start = get_time_ns(); + do { + ret = nand_read_data_op(chip, &status, sizeof(status), true, + false); + if (ret) + break; + + if (status & NAND_STATUS_READY) + break; + + /* + * Typical lowest execution time for a tR on most NANDs is 10us, + * use this as polling delay before doing something smarter (ie. + * deriving a delay from the timeout value, timeout_ms/ratio). + */ + udelay(10); + } while (!is_timeout(start, timeout_ms * MSECOND)); + + /* + * We have to exit READ_STATUS mode in order to read real data on the + * bus in case the WAITRDY instruction is preceding a DATA_IN + * instruction. + */ + nand_exit_status_op(chip); + + if (ret) + return ret; + + return status & NAND_STATUS_READY ? 0 : -ETIMEDOUT; +}; +EXPORT_SYMBOL_GPL(nand_soft_waitrdy); + +static bool nand_supports_get_features(struct nand_chip *chip, int addr) +{ + return (chip->parameters.supports_set_get_features && + test_bit(addr, chip->parameters.get_feature_list)); +} + +bool nand_supports_set_features(struct nand_chip *chip, int addr) +{ + return (chip->parameters.supports_set_get_features && + test_bit(addr, chip->parameters.set_feature_list)); +} + +/** + * nand_reset_interface - Reset data interface and timings + * @chip: The NAND chip + * @chipnr: Internal die id + * + * Reset the Data interface and timings to ONFI mode 0. + * + * Returns 0 for success or negative error code otherwise. + */ +static int nand_reset_interface(struct nand_chip *chip, int chipnr) +{ + const struct nand_controller_ops *ops = chip->controller->ops; + int ret; + + if (!nand_controller_can_setup_interface(chip)) return 0; - /* Check the WP bit */ - chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); - return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; + /* + * The ONFI specification says: + * " + * To transition from NV-DDR or NV-DDR2 to the SDR data + * interface, the host shall use the Reset (FFh) command + * using SDR timing mode 0. A device in any timing mode is + * required to recognize Reset (FFh) command issued in SDR + * timing mode 0. + * " + * + * Configure the data interface in SDR mode and set the + * timings to timing mode 0. + */ + + chip->current_interface_config = nand_get_reset_interface_config(); + ret = ops->setup_interface(chip, chipnr, + chip->current_interface_config); + if (ret) + pr_err("Failed to configure data interface to SDR timing mode 0\n"); + + return ret; } /** - * nand_block_checkbad - [GENERIC] Check if a block is marked bad - * @mtd: MTD device structure - * @ofs: offset from device start - * @getchip: 0, if the chip is already selected - * @allowbbt: 1, if its allowed to access the bbt area + * nand_setup_interface - Setup the best data interface and timings + * @chip: The NAND chip + * @chipnr: Internal die id * - * Check, if the block is bad. Either by reading the bad block table or - * calling of the scan function. + * Configure what has been reported to be the best data interface and NAND + * timings supported by the chip and the driver. + * + * Returns 0 for success or negative error code otherwise. */ -static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, - int allowbbt) +static int nand_setup_interface(struct nand_chip *chip, int chipnr) { - struct nand_chip *chip = mtd_to_nand(mtd); + const struct nand_controller_ops *ops = chip->controller->ops; + u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { }; + int ret; - if (IS_ENABLED(CONFIG_NAND_BBT) && chip->bbt) { - /* Return info from the table */ - return nand_isbad_bbt(mtd, ofs, allowbbt); + if (!nand_controller_can_setup_interface(chip)) + return 0; + + /* + * A nand_reset_interface() put both the NAND chip and the NAND + * controller in timings mode 0. If the default mode for this chip is + * also 0, no need to proceed to the change again. Plus, at probe time, + * nand_setup_interface() uses ->set/get_features() which would + * fail anyway as the parameter page is not available yet. + */ + if (!chip->best_interface_config) + return 0; + + tmode_param[0] = chip->best_interface_config->timings.mode; + + /* Change the mode on the chip side (if supported by the NAND chip) */ + if (nand_supports_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) { + nand_select_target(chip, chipnr); + ret = nand_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE, + tmode_param); + nand_deselect_target(chip); + if (ret) + return ret; + } + + /* Change the mode on the controller side */ + ret = ops->setup_interface(chip, chipnr, chip->best_interface_config); + if (ret) + return ret; + + /* Check the mode has been accepted by the chip, if supported */ + if (!nand_supports_get_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) + goto update_interface_config; + + memset(tmode_param, 0, ONFI_SUBFEATURE_PARAM_LEN); + nand_select_target(chip, chipnr); + ret = nand_get_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE, + tmode_param); + nand_deselect_target(chip); + if (ret) + goto err_reset_chip; + + if (tmode_param[0] != chip->best_interface_config->timings.mode) { + pr_warn("timing mode %d not acknowledged by the NAND chip\n", + chip->best_interface_config->timings.mode); + goto err_reset_chip; } - return chip->block_bad(mtd, ofs, getchip); +update_interface_config: + chip->current_interface_config = chip->best_interface_config; + + return 0; + +err_reset_chip: + /* + * Fallback to mode 0 if the chip explicitly did not ack the chosen + * timing mode. + */ + nand_reset_interface(chip, chipnr); + nand_select_target(chip, chipnr); + nand_reset_op(chip); + nand_deselect_target(chip); + + return ret; } -/* Wait for the ready pin, after a command. The timeout is caught later. */ -void nand_wait_ready(struct mtd_info *mtd) +/** + * nand_choose_best_sdr_timings - Pick up the best SDR timings that both the + * NAND controller and the NAND chip support + * @chip: the NAND chip + * @iface: the interface configuration (can eventually be updated) + * @spec_timings: specific timings, when not fitting the ONFI specification + * + * If specific timings are provided, use them. Otherwise, retrieve supported + * timing modes from ONFI information. + */ +int nand_choose_best_sdr_timings(struct nand_chip *chip, + struct nand_interface_config *iface, + struct nand_sdr_timings *spec_timings) { - struct nand_chip *chip = mtd_to_nand(mtd); - uint64_t start = get_time_ns(); + const struct nand_controller_ops *ops = chip->controller->ops; + int best_mode = 0, mode, ret; - /* wait until command is processed or timeout occures */ - do { - if (chip->dev_ready(mtd)) + iface->type = NAND_SDR_IFACE; + + if (spec_timings) { + iface->timings.sdr = *spec_timings; + iface->timings.mode = onfi_find_closest_sdr_mode(spec_timings); + + /* Verify the controller supports the requested interface */ + ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY, + iface); + if (!ret) { + chip->best_interface_config = iface; + return ret; + } + + /* Fallback to slower modes */ + best_mode = iface->timings.mode; + } else if (chip->parameters.onfi) { + best_mode = fls(chip->parameters.onfi->async_timing_mode) - 1; + } + + for (mode = best_mode; mode >= 0; mode--) { + onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, mode); + + ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY, + iface); + if (!ret) break; - } while (!is_timeout(start, SECOND * 2)); + } + + chip->best_interface_config = iface; + + return 0; } /** - * nand_command - [DEFAULT] Send command to NAND device - * @mtd: MTD device structure - * @command: the command to be sent - * @column: the column address for this command, -1 if none - * @page_addr: the page address for this command, -1 if none - * - * Send command to NAND device. This function is used for small page devices - * (512 Bytes per page). - */ -static void nand_command(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) -{ - register struct nand_chip *chip = mtd_to_nand(mtd); - int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; - - /* Write out the command to the device */ - if (IS_ENABLED(CONFIG_MTD_WRITE) && command == NAND_CMD_SEQIN) { - int readcmd; - - if (column >= mtd->writesize) { - /* OOB area */ - column -= mtd->writesize; - readcmd = NAND_CMD_READOOB; - } else if (column < 256) { - /* First 256 bytes --> READ0 */ - readcmd = NAND_CMD_READ0; - } else { - column -= 256; - readcmd = NAND_CMD_READ1; - } - chip->cmd_ctrl(mtd, readcmd, ctrl); - ctrl &= ~NAND_CTRL_CHANGE; - } - chip->cmd_ctrl(mtd, command, ctrl); - - /* Address cycle, when necessary */ - ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; - /* Serially input address */ - if (column != -1) { - /* Adjust columns for 16 bit buswidth */ - if (chip->options & NAND_BUSWIDTH_16) - column >>= 1; - chip->cmd_ctrl(mtd, column, ctrl); - ctrl &= ~NAND_CTRL_CHANGE; - } - if (page_addr != -1) { - chip->cmd_ctrl(mtd, page_addr, ctrl); - ctrl &= ~NAND_CTRL_CHANGE; - chip->cmd_ctrl(mtd, page_addr >> 8, ctrl); - /* One more address cycle for devices > 32MiB */ - if (chip->chipsize > (32 << 20)) - chip->cmd_ctrl(mtd, page_addr >> 16, ctrl); - } - chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + * nand_choose_interface_config - find the best data interface and timings + * @chip: The NAND chip + * + * Find the best data interface and NAND timings supported by the chip + * and the driver. Eventually let the NAND manufacturer driver propose his own + * set of timings. + * + * After this function nand_chip->interface_config is initialized with the best + * timing mode available. + * + * Returns 0 for success or negative error code otherwise. + */ +static int nand_choose_interface_config(struct nand_chip *chip) +{ + struct nand_interface_config *iface; + int ret; + + if (!nand_controller_can_setup_interface(chip)) + return 0; + + iface = kzalloc(sizeof(*iface), GFP_KERNEL); + if (!iface) + return -ENOMEM; + + if (chip->ops.choose_interface_config) + ret = chip->ops.choose_interface_config(chip, iface); + else + ret = nand_choose_best_sdr_timings(chip, iface, NULL); + + if (ret) + kfree(iface); + + return ret; +} + +/** + * nand_fill_column_cycles - fill the column cycles of an address + * @chip: The NAND chip + * @addrs: Array of address cycles to fill + * @offset_in_page: The offset in the page + * + * Fills the first or the first two bytes of the @addrs field depending + * on the NAND bus width and the page size. + * + * Returns the number of cycles needed to encode the column, or a negative + * error code in case one of the arguments is invalid. + */ +static int nand_fill_column_cycles(struct nand_chip *chip, u8 *addrs, + unsigned int offset_in_page) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + /* Make sure the offset is less than the actual page size. */ + if (offset_in_page > mtd->writesize + mtd->oobsize) + return -EINVAL; /* - * Program and erase have their own busy handlers status and sequential - * in needs no delay + * On small page NANDs, there's a dedicated command to access the OOB + * area, and the column address is relative to the start of the OOB + * area, not the start of the page. Asjust the address accordingly. */ - switch (command) { + if (mtd->writesize <= 512 && offset_in_page >= mtd->writesize) + offset_in_page -= mtd->writesize; - case NAND_CMD_PAGEPROG: - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_SEQIN: - case NAND_CMD_STATUS: - return; - - case NAND_CMD_RESET: - if (chip->dev_ready) - break; - udelay(chip->chip_delay); - chip->cmd_ctrl(mtd, NAND_CMD_STATUS, - NAND_CTRL_CLE | NAND_CTRL_CHANGE); - chip->cmd_ctrl(mtd, - NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) - ; - return; + /* + * The offset in page is expressed in bytes, if the NAND bus is 16-bit + * wide, then it must be divided by 2. + */ + if (chip->options & NAND_BUSWIDTH_16) { + if (WARN_ON(offset_in_page % 2)) + return -EINVAL; - /* This applies to read commands */ - default: - /* - * If we don't have access to the busy pin, we apply the given - * command delay - */ - if (!chip->dev_ready) { - udelay(chip->chip_delay); - return; - } + offset_in_page /= 2; } + + addrs[0] = offset_in_page; + /* - * Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. + * Small page NANDs use 1 cycle for the columns, while large page NANDs + * need 2 */ - ndelay(100); + if (mtd->writesize <= 512) + return 1; + + addrs[1] = offset_in_page >> 8; + + return 2; +} + +static int nand_sp_exec_read_page_op(struct nand_chip *chip, unsigned int page, + unsigned int offset_in_page, void *buf, + unsigned int len) +{ + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(chip)); + struct mtd_info *mtd = nand_to_mtd(chip); + u8 addrs[4]; + struct nand_op_instr instrs[] = { + NAND_OP_CMD(NAND_CMD_READ0, 0), + NAND_OP_ADDR(3, addrs, PSEC_TO_NSEC(sdr->tWB_max)), + NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tR_max), + PSEC_TO_NSEC(sdr->tRR_min)), + NAND_OP_DATA_IN(len, buf, 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + int ret; + + /* Drop the DATA_IN instruction if len is set to 0. */ + if (!len) + op.ninstrs--; + + if (offset_in_page >= mtd->writesize) + instrs[0].ctx.cmd.opcode = NAND_CMD_READOOB; + else if (offset_in_page >= 256 && + !(chip->options & NAND_BUSWIDTH_16)) + instrs[0].ctx.cmd.opcode = NAND_CMD_READ1; + + ret = nand_fill_column_cycles(chip, addrs, offset_in_page); + if (ret < 0) + return ret; + + addrs[1] = page; + addrs[2] = page >> 8; - nand_wait_ready(mtd); + if (chip->options & NAND_ROW_ADDR_3) { + addrs[3] = page >> 16; + instrs[1].ctx.addr.naddrs++; + } + + return nand_exec_op(chip, &op); +} + +static int nand_lp_exec_read_page_op(struct nand_chip *chip, unsigned int page, + unsigned int offset_in_page, void *buf, + unsigned int len) +{ + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(chip)); + u8 addrs[5]; + struct nand_op_instr instrs[] = { + NAND_OP_CMD(NAND_CMD_READ0, 0), + NAND_OP_ADDR(4, addrs, 0), + NAND_OP_CMD(NAND_CMD_READSTART, PSEC_TO_NSEC(sdr->tWB_max)), + NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tR_max), + PSEC_TO_NSEC(sdr->tRR_min)), + NAND_OP_DATA_IN(len, buf, 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + int ret; + + /* Drop the DATA_IN instruction if len is set to 0. */ + if (!len) + op.ninstrs--; + + ret = nand_fill_column_cycles(chip, addrs, offset_in_page); + if (ret < 0) + return ret; + + addrs[2] = page; + addrs[3] = page >> 8; + + if (chip->options & NAND_ROW_ADDR_3) { + addrs[4] = page >> 16; + instrs[1].ctx.addr.naddrs++; + } + + return nand_exec_op(chip, &op); } /** - * nand_command_lp - [DEFAULT] Send command to NAND large page device - * @mtd: MTD device structure - * @command: the command to be sent - * @column: the column address for this command, -1 if none - * @page_addr: the page address for this command, -1 if none + * nand_read_page_op - Do a READ PAGE operation + * @chip: The NAND chip + * @page: page to read + * @offset_in_page: offset within the page + * @buf: buffer used to store the data + * @len: length of the buffer + * + * This function issues a READ PAGE operation. + * This function does not select/unselect the CS line. * - * Send command to NAND device. This is the version for the new large page - * devices. We don't have the separate regions as we have in the small page - * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. + * Returns 0 on success, a negative error code otherwise. */ -static void nand_command_lp(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) +int nand_read_page_op(struct nand_chip *chip, unsigned int page, + unsigned int offset_in_page, void *buf, unsigned int len) { - register struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); - /* Emulate NAND_CMD_READOOB */ - if (command == NAND_CMD_READOOB) { - column += mtd->writesize; - command = NAND_CMD_READ0; + if (len && !buf) + return -EINVAL; + + if (offset_in_page + len > mtd->writesize + mtd->oobsize) + return -EINVAL; + + if (nand_has_exec_op(chip)) { + if (mtd->writesize > 512) + return nand_lp_exec_read_page_op(chip, page, + offset_in_page, buf, + len); + + return nand_sp_exec_read_page_op(chip, page, offset_in_page, + buf, len); } - /* Command latch cycle */ - chip->cmd_ctrl(mtd, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + chip->legacy.cmdfunc(chip, NAND_CMD_READ0, offset_in_page, page); + if (len) + chip->legacy.read_buf(chip, buf, len); - if (column != -1 || page_addr != -1) { - int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE; + return 0; +} +EXPORT_SYMBOL_GPL(nand_read_page_op); - /* Serially input address */ - if (column != -1) { - /* Adjust columns for 16 bit buswidth */ - if (chip->options & NAND_BUSWIDTH_16) - column >>= 1; - chip->cmd_ctrl(mtd, column, ctrl); - ctrl &= ~NAND_CTRL_CHANGE; - chip->cmd_ctrl(mtd, column >> 8, ctrl); - } - if (page_addr != -1) { - chip->cmd_ctrl(mtd, page_addr, ctrl); - chip->cmd_ctrl(mtd, page_addr >> 8, - NAND_NCE | NAND_ALE); - /* One more address cycle for devices > 128MiB */ - if (chip->chipsize > (128 << 20)) - chip->cmd_ctrl(mtd, page_addr >> 16, - NAND_NCE | NAND_ALE); - } +/** + * nand_read_param_page_op - Do a READ PARAMETER PAGE operation + * @chip: The NAND chip + * @page: parameter page to read + * @buf: buffer used to store the data + * @len: length of the buffer + * + * This function issues a READ PARAMETER PAGE operation. + * This function does not select/unselect the CS line. + * + * Returns 0 on success, a negative error code otherwise. + */ +int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf, + unsigned int len) +{ + unsigned int i; + u8 *p = buf; + + if (len && !buf) + return -EINVAL; + + if (nand_has_exec_op(chip)) { + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(chip)); + struct nand_op_instr instrs[] = { + NAND_OP_CMD(NAND_CMD_PARAM, 0), + NAND_OP_ADDR(1, &page, PSEC_TO_NSEC(sdr->tWB_max)), + NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tR_max), + PSEC_TO_NSEC(sdr->tRR_min)), + NAND_OP_8BIT_DATA_IN(len, buf, 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + + /* Drop the DATA_IN instruction if len is set to 0. */ + if (!len) + op.ninstrs--; + + return nand_exec_op(chip, &op); } - chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - /* - * Program and erase have their own busy handlers status, sequential - * in, and deplete1 need no delay. - */ - switch (command) { - - case NAND_CMD_CACHEDPROG: - case NAND_CMD_PAGEPROG: - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_SEQIN: - case NAND_CMD_RNDIN: - case NAND_CMD_STATUS: - return; + chip->legacy.cmdfunc(chip, NAND_CMD_PARAM, page, -1); + for (i = 0; i < len; i++) + p[i] = chip->legacy.read_byte(chip); - case NAND_CMD_RESET: - if (chip->dev_ready) - break; - udelay(chip->chip_delay); - chip->cmd_ctrl(mtd, NAND_CMD_STATUS, - NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); - chip->cmd_ctrl(mtd, NAND_CMD_NONE, - NAND_NCE | NAND_CTRL_CHANGE); - while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) - ; - return; + return 0; +} - case NAND_CMD_RNDOUT: - /* No ready / busy check necessary */ - chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART, - NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); - chip->cmd_ctrl(mtd, NAND_CMD_NONE, - NAND_NCE | NAND_CTRL_CHANGE); - return; +/** + * nand_change_read_column_op - Do a CHANGE READ COLUMN operation + * @chip: The NAND chip + * @offset_in_page: offset within the page + * @buf: buffer used to store the data + * @len: length of the buffer + * @force_8bit: force 8-bit bus access + * + * This function issues a CHANGE READ COLUMN operation. + * This function does not select/unselect the CS line. + * + * Returns 0 on success, a negative error code otherwise. + */ +int nand_change_read_column_op(struct nand_chip *chip, + unsigned int offset_in_page, void *buf, + unsigned int len, bool force_8bit) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + if (len && !buf) + return -EINVAL; - case NAND_CMD_READ0: - chip->cmd_ctrl(mtd, NAND_CMD_READSTART, - NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); - chip->cmd_ctrl(mtd, NAND_CMD_NONE, - NAND_NCE | NAND_CTRL_CHANGE); + if (offset_in_page + len > mtd->writesize + mtd->oobsize) + return -EINVAL; - /* This applies to read commands */ - default: + /* Small page NANDs do not support column change. */ + if (mtd->writesize <= 512) + return -ENOTSUPP; + + if (nand_has_exec_op(chip)) { + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(chip)); + u8 addrs[2] = {}; + struct nand_op_instr instrs[] = { + NAND_OP_CMD(NAND_CMD_RNDOUT, 0), + NAND_OP_ADDR(2, addrs, 0), + NAND_OP_CMD(NAND_CMD_RNDOUTSTART, + PSEC_TO_NSEC(sdr->tCCS_min)), + NAND_OP_DATA_IN(len, buf, 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + int ret; + + ret = nand_fill_column_cycles(chip, addrs, offset_in_page); + if (ret < 0) + return ret; + + /* Drop the DATA_IN instruction if len is set to 0. */ + if (!len) + op.ninstrs--; + + instrs[3].ctx.data.force_8bit = force_8bit; + + return nand_exec_op(chip, &op); + } + + chip->legacy.cmdfunc(chip, NAND_CMD_RNDOUT, offset_in_page, -1); + if (len) + chip->legacy.read_buf(chip, buf, len); + + return 0; +} +EXPORT_SYMBOL_GPL(nand_change_read_column_op); + +/** + * nand_read_oob_op - Do a READ OOB operation + * @chip: The NAND chip + * @page: page to read + * @offset_in_oob: offset within the OOB area + * @buf: buffer used to store the data + * @len: length of the buffer + * + * This function issues a READ OOB operation. + * This function does not select/unselect the CS line. + * + * Returns 0 on success, a negative error code otherwise. + */ +int nand_read_oob_op(struct nand_chip *chip, unsigned int page, + unsigned int offset_in_oob, void *buf, unsigned int len) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + if (len && !buf) + return -EINVAL; + + if (offset_in_oob + len > mtd->oobsize) + return -EINVAL; + + if (nand_has_exec_op(chip)) + return nand_read_page_op(chip, page, + mtd->writesize + offset_in_oob, + buf, len); + + chip->legacy.cmdfunc(chip, NAND_CMD_READOOB, offset_in_oob, page); + if (len) + chip->legacy.read_buf(chip, buf, len); + + return 0; +} +EXPORT_SYMBOL_GPL(nand_read_oob_op); + +static int nand_exec_prog_page_op(struct nand_chip *chip, unsigned int page, + unsigned int offset_in_page, const void *buf, + unsigned int len, bool prog) +{ + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(chip)); + struct mtd_info *mtd = nand_to_mtd(chip); + u8 addrs[5] = {}; + struct nand_op_instr instrs[] = { /* - * If we don't have access to the busy pin, we apply the given - * command delay. + * The first instruction will be dropped if we're dealing + * with a large page NAND and adjusted if we're dealing + * with a small page NAND and the page offset is > 255. */ - if (!chip->dev_ready) { - udelay(chip->chip_delay); - return; - } + NAND_OP_CMD(NAND_CMD_READ0, 0), + NAND_OP_CMD(NAND_CMD_SEQIN, 0), + NAND_OP_ADDR(0, addrs, PSEC_TO_NSEC(sdr->tADL_min)), + NAND_OP_DATA_OUT(len, buf, 0), + NAND_OP_CMD(NAND_CMD_PAGEPROG, PSEC_TO_NSEC(sdr->tWB_max)), + NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tPROG_max), 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + int naddrs = nand_fill_column_cycles(chip, addrs, offset_in_page); + int ret; + u8 status; + + if (naddrs < 0) + return naddrs; + + addrs[naddrs++] = page; + addrs[naddrs++] = page >> 8; + if (chip->options & NAND_ROW_ADDR_3) + addrs[naddrs++] = page >> 16; + + instrs[2].ctx.addr.naddrs = naddrs; + + /* Drop the last two instructions if we're not programming the page. */ + if (!prog) { + op.ninstrs -= 2; + /* Also drop the DATA_OUT instruction if empty. */ + if (!len) + op.ninstrs--; } - /* - * Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. - */ - ndelay(100); + if (mtd->writesize <= 512) { + /* + * Small pages need some more tweaking: we have to adjust the + * first instruction depending on the page offset we're trying + * to access. + */ + if (offset_in_page >= mtd->writesize) + instrs[0].ctx.cmd.opcode = NAND_CMD_READOOB; + else if (offset_in_page >= 256 && + !(chip->options & NAND_BUSWIDTH_16)) + instrs[0].ctx.cmd.opcode = NAND_CMD_READ1; + } else { + /* + * Drop the first command if we're dealing with a large page + * NAND. + */ + op.instrs++; + op.ninstrs--; + } + + ret = nand_exec_op(chip, &op); + if (!prog || ret) + return ret; + + ret = nand_status_op(chip, &status); + if (ret) + return ret; - nand_wait_ready(mtd); + return status; } /** - * nand_get_device - [GENERIC] Get chip for selected access - * @mtd: MTD device structure - * @new_state: the state which is requested + * nand_prog_page_begin_op - starts a PROG PAGE operation + * @chip: The NAND chip + * @page: page to write + * @offset_in_page: offset within the page + * @buf: buffer containing the data to write to the page + * @len: length of the buffer + * + * This function issues the first half of a PROG PAGE operation. + * This function does not select/unselect the CS line. * - * Get the device and lock it for exclusive access + * Returns 0 on success, a negative error code otherwise. */ -static int -nand_get_device(struct mtd_info *mtd, int new_state) +int nand_prog_page_begin_op(struct nand_chip *chip, unsigned int page, + unsigned int offset_in_page, const void *buf, + unsigned int len) { - struct nand_chip *chip = mtd_to_nand(mtd); -retry: + struct mtd_info *mtd = nand_to_mtd(chip); - /* Hardware controller shared among independent devices */ - if (!chip->controller->active) - chip->controller->active = chip; + if (len && !buf) + return -EINVAL; - if (chip->controller->active == chip && chip->state == FL_READY) { - chip->state = new_state; - return 0; + if (offset_in_page + len > mtd->writesize + mtd->oobsize) + return -EINVAL; + + if (nand_has_exec_op(chip)) + return nand_exec_prog_page_op(chip, page, offset_in_page, buf, + len, false); + + chip->legacy.cmdfunc(chip, NAND_CMD_SEQIN, offset_in_page, page); + + if (buf) + chip->legacy.write_buf(chip, buf, len); + + return 0; +} +EXPORT_SYMBOL_GPL(nand_prog_page_begin_op); + +/** + * nand_prog_page_end_op - ends a PROG PAGE operation + * @chip: The NAND chip + * + * This function issues the second half of a PROG PAGE operation. + * This function does not select/unselect the CS line. + * + * Returns 0 on success, a negative error code otherwise. + */ +int nand_prog_page_end_op(struct nand_chip *chip) +{ + int ret; + u8 status; + + if (nand_has_exec_op(chip)) { + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(chip)); + struct nand_op_instr instrs[] = { + NAND_OP_CMD(NAND_CMD_PAGEPROG, + PSEC_TO_NSEC(sdr->tWB_max)), + NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tPROG_max), 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + + ret = nand_exec_op(chip, &op); + if (ret) + return ret; + + ret = nand_status_op(chip, &status); + if (ret) + return ret; + } else { + chip->legacy.cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1); + ret = chip->legacy.waitfunc(chip); + if (ret < 0) + return ret; + + status = ret; } - if (new_state == FL_PM_SUSPENDED) { - if (chip->controller->active->state == FL_PM_SUSPENDED) { - chip->state = FL_PM_SUSPENDED; - return 0; - } + + if (status & NAND_STATUS_FAIL) + return -EIO; + + return 0; +} +EXPORT_SYMBOL_GPL(nand_prog_page_end_op); + +/** + * nand_prog_page_op - Do a full PROG PAGE operation + * @chip: The NAND chip + * @page: page to write + * @offset_in_page: offset within the page + * @buf: buffer containing the data to write to the page + * @len: length of the buffer + * + * This function issues a full PROG PAGE operation. + * This function does not select/unselect the CS line. + * + * Returns 0 on success, a negative error code otherwise. + */ +int nand_prog_page_op(struct nand_chip *chip, unsigned int page, + unsigned int offset_in_page, const void *buf, + unsigned int len) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + int status; + + if (!len || !buf) + return -EINVAL; + + if (offset_in_page + len > mtd->writesize + mtd->oobsize) + return -EINVAL; + + if (nand_has_exec_op(chip)) { + status = nand_exec_prog_page_op(chip, page, offset_in_page, buf, + len, true); + } else { + chip->legacy.cmdfunc(chip, NAND_CMD_SEQIN, offset_in_page, + page); + chip->legacy.write_buf(chip, buf, len); + chip->legacy.cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1); + status = chip->legacy.waitfunc(chip); + } + + if (status & NAND_STATUS_FAIL) + return -EIO; + + return 0; +} +EXPORT_SYMBOL_GPL(nand_prog_page_op); + +/** + * nand_change_write_column_op - Do a CHANGE WRITE COLUMN operation + * @chip: The NAND chip + * @offset_in_page: offset within the page + * @buf: buffer containing the data to send to the NAND + * @len: length of the buffer + * @force_8bit: force 8-bit bus access + * + * This function issues a CHANGE WRITE COLUMN operation. + * This function does not select/unselect the CS line. + * + * Returns 0 on success, a negative error code otherwise. + */ +int nand_change_write_column_op(struct nand_chip *chip, + unsigned int offset_in_page, + const void *buf, unsigned int len, + bool force_8bit) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + if (len && !buf) + return -EINVAL; + + if (offset_in_page + len > mtd->writesize + mtd->oobsize) + return -EINVAL; + + /* Small page NANDs do not support column change. */ + if (mtd->writesize <= 512) + return -ENOTSUPP; + + if (nand_has_exec_op(chip)) { + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(chip)); + u8 addrs[2]; + struct nand_op_instr instrs[] = { + NAND_OP_CMD(NAND_CMD_RNDIN, 0), + NAND_OP_ADDR(2, addrs, PSEC_TO_NSEC(sdr->tCCS_min)), + NAND_OP_DATA_OUT(len, buf, 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + int ret; + + ret = nand_fill_column_cycles(chip, addrs, offset_in_page); + if (ret < 0) + return ret; + + instrs[2].ctx.data.force_8bit = force_8bit; + + /* Drop the DATA_OUT instruction if len is set to 0. */ + if (!len) + op.ninstrs--; + + return nand_exec_op(chip, &op); + } + + chip->legacy.cmdfunc(chip, NAND_CMD_RNDIN, offset_in_page, -1); + if (len) + chip->legacy.write_buf(chip, buf, len); + + return 0; +} +EXPORT_SYMBOL_GPL(nand_change_write_column_op); + +/** + * nand_readid_op - Do a READID operation + * @chip: The NAND chip + * @addr: address cycle to pass after the READID command + * @buf: buffer used to store the ID + * @len: length of the buffer + * + * This function sends a READID command and reads back the ID returned by the + * NAND. + * This function does not select/unselect the CS line. + * + * Returns 0 on success, a negative error code otherwise. + */ +int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf, + unsigned int len) +{ + unsigned int i; + u8 *id = buf; + + if (len && !buf) + return -EINVAL; + + if (nand_has_exec_op(chip)) { + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(chip)); + struct nand_op_instr instrs[] = { + NAND_OP_CMD(NAND_CMD_READID, 0), + NAND_OP_ADDR(1, &addr, PSEC_TO_NSEC(sdr->tADL_min)), + NAND_OP_8BIT_DATA_IN(len, buf, 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + + /* Drop the DATA_IN instruction if len is set to 0. */ + if (!len) + op.ninstrs--; + + return nand_exec_op(chip, &op); + } + + chip->legacy.cmdfunc(chip, NAND_CMD_READID, addr, -1); + + for (i = 0; i < len; i++) + id[i] = chip->legacy.read_byte(chip); + + return 0; +} +EXPORT_SYMBOL_GPL(nand_readid_op); + +/** + * nand_status_op - Do a STATUS operation + * @chip: The NAND chip + * @status: out variable to store the NAND status + * + * This function sends a STATUS command and reads back the status returned by + * the NAND. + * This function does not select/unselect the CS line. + * + * Returns 0 on success, a negative error code otherwise. + */ +int nand_status_op(struct nand_chip *chip, u8 *status) +{ + if (nand_has_exec_op(chip)) { + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(chip)); + struct nand_op_instr instrs[] = { + NAND_OP_CMD(NAND_CMD_STATUS, + PSEC_TO_NSEC(sdr->tADL_min)), + NAND_OP_8BIT_DATA_IN(1, status, 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + + if (!status) + op.ninstrs--; + + return nand_exec_op(chip, &op); } - goto retry; + + chip->legacy.cmdfunc(chip, NAND_CMD_STATUS, -1, -1); + if (status) + *status = chip->legacy.read_byte(chip); + + return 0; } +EXPORT_SYMBOL_GPL(nand_status_op); /** - * nand_wait - [DEFAULT] wait until the command is done - * @mtd: MTD device structure - * @chip: NAND chip structure + * nand_exit_status_op - Exit a STATUS operation + * @chip: The NAND chip + * + * This function sends a READ0 command to cancel the effect of the STATUS + * command to avoid reading only the status until a new read command is sent. * - * Wait for command done. This applies to erase and program only - * Erase can take up to 400ms and program up to 20ms according to - * general NAND and SmartMedia specs + * This function does not select/unselect the CS line. + * + * Returns 0 on success, a negative error code otherwise. */ -static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) +int nand_exit_status_op(struct nand_chip *chip) { + if (nand_has_exec_op(chip)) { + struct nand_op_instr instrs[] = { + NAND_OP_CMD(NAND_CMD_READ0, 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); - uint64_t start = get_time_ns(); - uint64_t timeo; - int status, state = chip->state; + return nand_exec_op(chip, &op); + } - if (state == FL_ERASING) - timeo = 400 * MSECOND; + chip->legacy.cmdfunc(chip, NAND_CMD_READ0, -1, -1); + + return 0; +} + +/** + * nand_erase_op - Do an erase operation + * @chip: The NAND chip + * @eraseblock: block to erase + * + * This function sends an ERASE command and waits for the NAND to be ready + * before returning. + * This function does not select/unselect the CS line. + * + * Returns 0 on success, a negative error code otherwise. + */ +int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock) +{ + unsigned int page = eraseblock << + (chip->phys_erase_shift - chip->page_shift); + int ret; + u8 status; + + if (nand_has_exec_op(chip)) { + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(chip)); + u8 addrs[3] = { page, page >> 8, page >> 16 }; + struct nand_op_instr instrs[] = { + NAND_OP_CMD(NAND_CMD_ERASE1, 0), + NAND_OP_ADDR(2, addrs, 0), + NAND_OP_CMD(NAND_CMD_ERASE2, + PSEC_TO_MSEC(sdr->tWB_max)), + NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tBERS_max), 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + + if (chip->options & NAND_ROW_ADDR_3) + instrs[1].ctx.addr.naddrs++; + + ret = nand_exec_op(chip, &op); + if (ret) + return ret; + + ret = nand_status_op(chip, &status); + if (ret) + return ret; + } else { + chip->legacy.cmdfunc(chip, NAND_CMD_ERASE1, -1, page); + chip->legacy.cmdfunc(chip, NAND_CMD_ERASE2, -1, -1); + + ret = chip->legacy.waitfunc(chip); + if (ret < 0) + return ret; + + status = ret; + } + + if (status & NAND_STATUS_FAIL) + return -EIO; + + return 0; +} +EXPORT_SYMBOL_GPL(nand_erase_op); + +/** + * nand_set_features_op - Do a SET FEATURES operation + * @chip: The NAND chip + * @feature: feature id + * @data: 4 bytes of data + * + * This function sends a SET FEATURES command and waits for the NAND to be + * ready before returning. + * This function does not select/unselect the CS line. + * + * Returns 0 on success, a negative error code otherwise. + */ +static int nand_set_features_op(struct nand_chip *chip, u8 feature, + const void *data) +{ + const u8 *params = data; + int i, ret; + + if (nand_has_exec_op(chip)) { + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(chip)); + struct nand_op_instr instrs[] = { + NAND_OP_CMD(NAND_CMD_SET_FEATURES, 0), + NAND_OP_ADDR(1, &feature, PSEC_TO_NSEC(sdr->tADL_min)), + NAND_OP_8BIT_DATA_OUT(ONFI_SUBFEATURE_PARAM_LEN, data, + PSEC_TO_NSEC(sdr->tWB_max)), + NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tFEAT_max), 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + + return nand_exec_op(chip, &op); + } + + chip->legacy.cmdfunc(chip, NAND_CMD_SET_FEATURES, feature, -1); + for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) + chip->legacy.write_byte(chip, params[i]); + + ret = chip->legacy.waitfunc(chip); + if (ret < 0) + return ret; + + if (ret & NAND_STATUS_FAIL) + return -EIO; + + return 0; +} + +/** + * nand_get_features_op - Do a GET FEATURES operation + * @chip: The NAND chip + * @feature: feature id + * @data: 4 bytes of data + * + * This function sends a GET FEATURES command and waits for the NAND to be + * ready before returning. + * This function does not select/unselect the CS line. + * + * Returns 0 on success, a negative error code otherwise. + */ +static int nand_get_features_op(struct nand_chip *chip, u8 feature, + void *data) +{ + u8 *params = data; + int i; + + if (nand_has_exec_op(chip)) { + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(chip)); + struct nand_op_instr instrs[] = { + NAND_OP_CMD(NAND_CMD_GET_FEATURES, 0), + NAND_OP_ADDR(1, &feature, PSEC_TO_NSEC(sdr->tWB_max)), + NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tFEAT_max), + PSEC_TO_NSEC(sdr->tRR_min)), + NAND_OP_8BIT_DATA_IN(ONFI_SUBFEATURE_PARAM_LEN, + data, 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + + return nand_exec_op(chip, &op); + } + + chip->legacy.cmdfunc(chip, NAND_CMD_GET_FEATURES, feature, -1); + for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) + params[i] = chip->legacy.read_byte(chip); + + return 0; +} + +static int nand_wait_rdy_op(struct nand_chip *chip, unsigned int timeout_ms, + unsigned int delay_ns) +{ + if (nand_has_exec_op(chip)) { + struct nand_op_instr instrs[] = { + NAND_OP_WAIT_RDY(PSEC_TO_MSEC(timeout_ms), + PSEC_TO_NSEC(delay_ns)), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + + return nand_exec_op(chip, &op); + } + + /* Apply delay or wait for ready/busy pin */ + if (!chip->legacy.dev_ready) + udelay(chip->legacy.chip_delay); else - timeo = 20 * MSECOND; + nand_wait_ready(chip); - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ - ndelay(100); + return 0; +} - chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); +/** + * nand_reset_op - Do a reset operation + * @chip: The NAND chip + * + * This function sends a RESET command and waits for the NAND to be ready + * before returning. + * This function does not select/unselect the CS line. + * + * Returns 0 on success, a negative error code otherwise. + */ +int nand_reset_op(struct nand_chip *chip) +{ + if (nand_has_exec_op(chip)) { + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(chip)); + struct nand_op_instr instrs[] = { + NAND_OP_CMD(NAND_CMD_RESET, PSEC_TO_NSEC(sdr->tWB_max)), + NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tRST_max), 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + + return nand_exec_op(chip, &op); + } - while (!is_timeout(start, timeo)) { - if (chip->dev_ready) { - if (chip->dev_ready(mtd)) - break; - } else { - if (chip->read_byte(mtd) & NAND_STATUS_READY) - break; - } + chip->legacy.cmdfunc(chip, NAND_CMD_RESET, -1, -1); + + return 0; +} +EXPORT_SYMBOL_GPL(nand_reset_op); + +/** + * nand_read_data_op - Read data from the NAND + * @chip: The NAND chip + * @buf: buffer used to store the data + * @len: length of the buffer + * @force_8bit: force 8-bit bus access + * @check_only: do not actually run the command, only checks if the + * controller driver supports it + * + * This function does a raw data read on the bus. Usually used after launching + * another NAND operation like nand_read_page_op(). + * This function does not select/unselect the CS line. + * + * Returns 0 on success, a negative error code otherwise. + */ +int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len, + bool force_8bit, bool check_only) +{ + if (!len || !buf) + return -EINVAL; + + if (nand_has_exec_op(chip)) { + struct nand_op_instr instrs[] = { + NAND_OP_DATA_IN(len, buf, 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + + instrs[0].ctx.data.force_8bit = force_8bit; + + if (check_only) + return nand_check_op(chip, &op); + + return nand_exec_op(chip, &op); } - status = (int)chip->read_byte(mtd); - return status; + if (check_only) + return 0; + + if (force_8bit) { + u8 *p = buf; + unsigned int i; + + for (i = 0; i < len; i++) + p[i] = chip->legacy.read_byte(chip); + } else { + chip->legacy.read_buf(chip, buf, len); + } + + return 0; } +EXPORT_SYMBOL_GPL(nand_read_data_op); /** - * __nand_unlock - [REPLACEABLE] unlocks specified locked blocks - * @mtd: mtd info - * @ofs: offset to start unlock from - * @len: length to unlock - * @invert: when = 0, unlock the range of blocks within the lower and - * upper boundary address - * when = 1, unlock the range of blocks outside the boundaries - * of the lower and upper boundary address + * nand_write_data_op - Write data from the NAND + * @chip: The NAND chip + * @buf: buffer containing the data to send on the bus + * @len: length of the buffer + * @force_8bit: force 8-bit bus access * - * Returs unlock status. + * This function does a raw data write on the bus. Usually used after launching + * another NAND operation like nand_write_page_begin_op(). + * This function does not select/unselect the CS line. + * + * Returns 0 on success, a negative error code otherwise. */ -static int __nand_unlock(struct mtd_info *mtd, loff_t ofs, - uint64_t len, int invert) +int nand_write_data_op(struct nand_chip *chip, const void *buf, + unsigned int len, bool force_8bit) { - int ret = 0; - int status, page; - struct nand_chip *chip = mtd_to_nand(mtd); + if (!len || !buf) + return -EINVAL; - /* Submit address of first page to unlock */ - page = ofs >> chip->page_shift; - chip->cmdfunc(mtd, NAND_CMD_UNLOCK1, -1, page & chip->pagemask); - - /* Submit address of last page to unlock */ - page = (ofs + len) >> chip->page_shift; - chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, - (page | invert) & chip->pagemask); - - /* Call wait ready function */ - status = chip->waitfunc(mtd, chip); - /* See if device thinks it succeeded */ - if (status & NAND_STATUS_FAIL) { - pr_debug("%s: error status = 0x%08x\n", - __func__, status); - ret = -EIO; + if (nand_has_exec_op(chip)) { + struct nand_op_instr instrs[] = { + NAND_OP_DATA_OUT(len, buf, 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + + instrs[0].ctx.data.force_8bit = force_8bit; + + return nand_exec_op(chip, &op); } - return ret; + if (force_8bit) { + const u8 *p = buf; + unsigned int i; + + for (i = 0; i < len; i++) + chip->legacy.write_byte(chip, p[i]); + } else { + chip->legacy.write_buf(chip, buf, len); + } + + return 0; } +EXPORT_SYMBOL_GPL(nand_write_data_op); + +/** + * struct nand_op_parser_ctx - Context used by the parser + * @instrs: array of all the instructions that must be addressed + * @ninstrs: length of the @instrs array + * @subop: Sub-operation to be passed to the NAND controller + * + * This structure is used by the core to split NAND operations into + * sub-operations that can be handled by the NAND controller. + */ +struct nand_op_parser_ctx { + const struct nand_op_instr *instrs; + unsigned int ninstrs; + struct nand_subop subop; +}; /** - * nand_unlock - [REPLACEABLE] unlocks specified locked blocks - * @mtd: mtd info - * @ofs: offset to start unlock from - * @len: length to unlock + * nand_op_parser_must_split_instr - Checks if an instruction must be split + * @pat: the parser pattern element that matches @instr + * @instr: pointer to the instruction to check + * @start_offset: this is an in/out parameter. If @instr has already been + * split, then @start_offset is the offset from which to start + * (either an address cycle or an offset in the data buffer). + * Conversely, if the function returns true (ie. instr must be + * split), this parameter is updated to point to the first + * data/address cycle that has not been taken care of. * - * Returns unlock status. + * Some NAND controllers are limited and cannot send X address cycles with a + * unique operation, or cannot read/write more than Y bytes at the same time. + * In this case, split the instruction that does not fit in a single + * controller-operation into two or more chunks. + * + * Returns true if the instruction must be split, false otherwise. + * The @start_offset parameter is also updated to the offset at which the next + * bundle of instruction must start (if an address or a data instruction). */ -int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +static bool +nand_op_parser_must_split_instr(const struct nand_op_parser_pattern_elem *pat, + const struct nand_op_instr *instr, + unsigned int *start_offset) { - int ret = 0; - int chipnr; - struct nand_chip *chip = mtd_to_nand(mtd); + switch (pat->type) { + case NAND_OP_ADDR_INSTR: + if (!pat->ctx.addr.maxcycles) + break; - pr_debug("%s: start = 0x%012llx, len = %llu\n", - __func__, (unsigned long long)ofs, len); + if (instr->ctx.addr.naddrs - *start_offset > + pat->ctx.addr.maxcycles) { + *start_offset += pat->ctx.addr.maxcycles; + return true; + } + break; - if (check_offs_len(mtd, ofs, len)) - ret = -EINVAL; + case NAND_OP_DATA_IN_INSTR: + case NAND_OP_DATA_OUT_INSTR: + if (!pat->ctx.data.maxlen) + break; - /* Align to last block address if size addresses end of the device */ - if (ofs + len == mtd->size) - len -= mtd->erasesize; + if (instr->ctx.data.len - *start_offset > + pat->ctx.data.maxlen) { + *start_offset += pat->ctx.data.maxlen; + return true; + } + break; - nand_get_device(mtd, FL_UNLOCKING); + default: + break; + } - /* Shift to get chip number */ - chipnr = ofs >> chip->chip_shift; + return false; +} - chip->select_chip(mtd, chipnr); +/** + * nand_op_parser_match_pat - Checks if a pattern matches the instructions + * remaining in the parser context + * @pat: the pattern to test + * @ctx: the parser context structure to match with the pattern @pat + * + * Check if @pat matches the set or a sub-set of instructions remaining in @ctx. + * Returns true if this is the case, false ortherwise. When true is returned, + * @ctx->subop is updated with the set of instructions to be passed to the + * controller driver. + */ +static bool +nand_op_parser_match_pat(const struct nand_op_parser_pattern *pat, + struct nand_op_parser_ctx *ctx) +{ + unsigned int instr_offset = ctx->subop.first_instr_start_off; + const struct nand_op_instr *end = ctx->instrs + ctx->ninstrs; + const struct nand_op_instr *instr = ctx->subop.instrs; + unsigned int i, ninstrs; + + for (i = 0, ninstrs = 0; i < pat->nelems && instr < end; i++) { + /* + * The pattern instruction does not match the operation + * instruction. If the instruction is marked optional in the + * pattern definition, we skip the pattern element and continue + * to the next one. If the element is mandatory, there's no + * match and we can return false directly. + */ + if (instr->type != pat->elems[i].type) { + if (!pat->elems[i].optional) + return false; + + continue; + } + + /* + * Now check the pattern element constraints. If the pattern is + * not able to handle the whole instruction in a single step, + * we have to split it. + * The last_instr_end_off value comes back updated to point to + * the position where we have to split the instruction (the + * start of the next subop chunk). + */ + if (nand_op_parser_must_split_instr(&pat->elems[i], instr, + &instr_offset)) { + ninstrs++; + i++; + break; + } + + instr++; + ninstrs++; + instr_offset = 0; + } /* - * Reset the chip. - * If we want to check the WP through READ STATUS and check the bit 7 - * we must reset the chip - * some operation can also clear the bit 7 of status register - * eg. erase/program a locked block + * This can happen if all instructions of a pattern are optional. + * Still, if there's not at least one instruction handled by this + * pattern, this is not a match, and we should try the next one (if + * any). */ - chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + if (!ninstrs) + return false; - /* Check, if it is write protected */ - if (nand_check_wp(mtd)) { - pr_debug("%s: device is write protected!\n", - __func__); - ret = -EIO; - goto out; + /* + * We had a match on the pattern head, but the pattern may be longer + * than the instructions we're asked to execute. We need to make sure + * there's no mandatory elements in the pattern tail. + */ + for (; i < pat->nelems; i++) { + if (!pat->elems[i].optional) + return false; } - ret = __nand_unlock(mtd, ofs, len, 0); + /* + * We have a match: update the subop structure accordingly and return + * true. + */ + ctx->subop.ninstrs = ninstrs; + ctx->subop.last_instr_end_off = instr_offset; -out: - chip->select_chip(mtd, -1); - nand_release_device(mtd); + return true; +} - return ret; +#if IS_ENABLED(CONFIG_DYNAMIC_DEBUG) || defined(DEBUG) +static void nand_op_parser_trace(const struct nand_op_parser_ctx *ctx) +{ + const struct nand_op_instr *instr; + char *prefix = " "; + unsigned int i; + + pr_debug("executing subop (CS%d):\n", ctx->subop.cs); + + for (i = 0; i < ctx->ninstrs; i++) { + instr = &ctx->instrs[i]; + + if (instr == &ctx->subop.instrs[0]) + prefix = " ->"; + + nand_op_trace(prefix, instr); + + if (instr == &ctx->subop.instrs[ctx->subop.ninstrs - 1]) + prefix = " "; + } +} +#else +static void nand_op_parser_trace(const struct nand_op_parser_ctx *ctx) +{ + /* NOP */ +} +#endif + +static int nand_op_parser_cmp_ctx(const struct nand_op_parser_ctx *a, + const struct nand_op_parser_ctx *b) +{ + if (a->subop.ninstrs < b->subop.ninstrs) + return -1; + else if (a->subop.ninstrs > b->subop.ninstrs) + return 1; + + if (a->subop.last_instr_end_off < b->subop.last_instr_end_off) + return -1; + else if (a->subop.last_instr_end_off > b->subop.last_instr_end_off) + return 1; + + return 0; } -EXPORT_SYMBOL(nand_unlock); /** - * nand_lock - [REPLACEABLE] locks all blocks present in the device - * @mtd: mtd info - * @ofs: offset to start unlock from - * @len: length to unlock + * nand_op_parser_exec_op - exec_op parser + * @chip: the NAND chip + * @parser: patterns description provided by the controller driver + * @op: the NAND operation to address + * @check_only: when true, the function only checks if @op can be handled but + * does not execute the operation * - * This feature is not supported in many NAND parts. 'Micron' NAND parts do - * have this feature, but it allows only to lock all blocks, not for specified - * range for block. Implementing 'lock' feature by making use of 'unlock', for - * now. + * Helper function designed to ease integration of NAND controller drivers that + * only support a limited set of instruction sequences. The supported sequences + * are described in @parser, and the framework takes care of splitting @op into + * multiple sub-operations (if required) and pass them back to the ->exec() + * callback of the matching pattern if @check_only is set to false. * - * Returns lock status. + * NAND controller drivers should call this function from their own ->exec_op() + * implementation. + * + * Returns 0 on success, a negative error code otherwise. A failure can be + * caused by an unsupported operation (none of the supported patterns is able + * to handle the requested operation), or an error returned by one of the + * matching pattern->exec() hook. */ -int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +int nand_op_parser_exec_op(struct nand_chip *chip, + const struct nand_op_parser *parser, + const struct nand_operation *op, bool check_only) { - int ret = 0; - int chipnr, status, page; - struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_op_parser_ctx ctx = { + .subop.cs = op->cs, + .subop.instrs = op->instrs, + .instrs = op->instrs, + .ninstrs = op->ninstrs, + }; + unsigned int i; + + while (ctx.subop.instrs < op->instrs + op->ninstrs) { + const struct nand_op_parser_pattern *pattern; + struct nand_op_parser_ctx best_ctx; + int ret, best_pattern = -1; + + for (i = 0; i < parser->npatterns; i++) { + struct nand_op_parser_ctx test_ctx = ctx; + + pattern = &parser->patterns[i]; + if (!nand_op_parser_match_pat(pattern, &test_ctx)) + continue; + + if (best_pattern >= 0 && + nand_op_parser_cmp_ctx(&test_ctx, &best_ctx) <= 0) + continue; + + best_pattern = i; + best_ctx = test_ctx; + } - pr_debug("%s: start = 0x%012llx, len = %llu\n", - __func__, (unsigned long long)ofs, len); + if (best_pattern < 0) { + pr_debug("->exec_op() parser: pattern not found!\n"); + return -ENOTSUPP; + } - if (check_offs_len(mtd, ofs, len)) - ret = -EINVAL; + ctx = best_ctx; + nand_op_parser_trace(&ctx); + + if (!check_only) { + pattern = &parser->patterns[best_pattern]; + ret = pattern->exec(chip, &ctx.subop); + if (ret) + return ret; + } - nand_get_device(mtd, FL_LOCKING); + /* + * Update the context structure by pointing to the start of the + * next subop. + */ + ctx.subop.instrs = ctx.subop.instrs + ctx.subop.ninstrs; + if (ctx.subop.last_instr_end_off) + ctx.subop.instrs -= 1; + + ctx.subop.first_instr_start_off = ctx.subop.last_instr_end_off; + } - /* Shift to get chip number */ - chipnr = ofs >> chip->chip_shift; + return 0; +} +EXPORT_SYMBOL_GPL(nand_op_parser_exec_op); + +static bool nand_instr_is_data(const struct nand_op_instr *instr) +{ + return instr && (instr->type == NAND_OP_DATA_IN_INSTR || + instr->type == NAND_OP_DATA_OUT_INSTR); +} + +static bool nand_subop_instr_is_valid(const struct nand_subop *subop, + unsigned int instr_idx) +{ + return subop && instr_idx < subop->ninstrs; +} + +static unsigned int nand_subop_get_start_off(const struct nand_subop *subop, + unsigned int instr_idx) +{ + if (instr_idx) + return 0; + + return subop->first_instr_start_off; +} + +/** + * nand_subop_get_addr_start_off - Get the start offset in an address array + * @subop: The entire sub-operation + * @instr_idx: Index of the instruction inside the sub-operation + * + * During driver development, one could be tempted to directly use the + * ->addr.addrs field of address instructions. This is wrong as address + * instructions might be split. + * + * Given an address instruction, returns the offset of the first cycle to issue. + */ +unsigned int nand_subop_get_addr_start_off(const struct nand_subop *subop, + unsigned int instr_idx) +{ + if (WARN_ON(!nand_subop_instr_is_valid(subop, instr_idx) || + subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR)) + return 0; + + return nand_subop_get_start_off(subop, instr_idx); +} +EXPORT_SYMBOL_GPL(nand_subop_get_addr_start_off); + +/** + * nand_subop_get_num_addr_cyc - Get the remaining address cycles to assert + * @subop: The entire sub-operation + * @instr_idx: Index of the instruction inside the sub-operation + * + * During driver development, one could be tempted to directly use the + * ->addr->naddrs field of a data instruction. This is wrong as instructions + * might be split. + * + * Given an address instruction, returns the number of address cycle to issue. + */ +unsigned int nand_subop_get_num_addr_cyc(const struct nand_subop *subop, + unsigned int instr_idx) +{ + int start_off, end_off; + + if (WARN_ON(!nand_subop_instr_is_valid(subop, instr_idx) || + subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR)) + return 0; + + start_off = nand_subop_get_addr_start_off(subop, instr_idx); + + if (instr_idx == subop->ninstrs - 1 && + subop->last_instr_end_off) + end_off = subop->last_instr_end_off; + else + end_off = subop->instrs[instr_idx].ctx.addr.naddrs; + + return end_off - start_off; +} +EXPORT_SYMBOL_GPL(nand_subop_get_num_addr_cyc); + +/** + * nand_subop_get_data_start_off - Get the start offset in a data array + * @subop: The entire sub-operation + * @instr_idx: Index of the instruction inside the sub-operation + * + * During driver development, one could be tempted to directly use the + * ->data->buf.{in,out} field of data instructions. This is wrong as data + * instructions might be split. + * + * Given a data instruction, returns the offset to start from. + */ +unsigned int nand_subop_get_data_start_off(const struct nand_subop *subop, + unsigned int instr_idx) +{ + if (WARN_ON(!nand_subop_instr_is_valid(subop, instr_idx) || + !nand_instr_is_data(&subop->instrs[instr_idx]))) + return 0; + + return nand_subop_get_start_off(subop, instr_idx); +} +EXPORT_SYMBOL_GPL(nand_subop_get_data_start_off); + +/** + * nand_subop_get_data_len - Get the number of bytes to retrieve + * @subop: The entire sub-operation + * @instr_idx: Index of the instruction inside the sub-operation + * + * During driver development, one could be tempted to directly use the + * ->data->len field of a data instruction. This is wrong as data instructions + * might be split. + * + * Returns the length of the chunk of data to send/receive. + */ +unsigned int nand_subop_get_data_len(const struct nand_subop *subop, + unsigned int instr_idx) +{ + int start_off = 0, end_off; + + if (WARN_ON(!nand_subop_instr_is_valid(subop, instr_idx) || + !nand_instr_is_data(&subop->instrs[instr_idx]))) + return 0; + + start_off = nand_subop_get_data_start_off(subop, instr_idx); + + if (instr_idx == subop->ninstrs - 1 && + subop->last_instr_end_off) + end_off = subop->last_instr_end_off; + else + end_off = subop->instrs[instr_idx].ctx.data.len; + + return end_off - start_off; +} +EXPORT_SYMBOL_GPL(nand_subop_get_data_len); + +/** + * nand_reset - Reset and initialize a NAND device + * @chip: The NAND chip + * @chipnr: Internal die id + * + * Save the timings data structure, then apply SDR timings mode 0 (see + * nand_reset_interface for details), do the reset operation, and apply + * back the previous timings. + * + * Returns 0 on success, a negative error code otherwise. + */ +int nand_reset(struct nand_chip *chip, int chipnr) +{ + int ret; - chip->select_chip(mtd, chipnr); + ret = nand_reset_interface(chip, chipnr); + if (ret) + return ret; /* - * Reset the chip. - * If we want to check the WP through READ STATUS and check the bit 7 - * we must reset the chip - * some operation can also clear the bit 7 of status register - * eg. erase/program a locked block + * The CS line has to be released before we can apply the new NAND + * interface settings, hence this weird nand_select_target() + * nand_deselect_target() dance. */ - chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + nand_select_target(chip, chipnr); + ret = nand_reset_op(chip); + nand_deselect_target(chip); + if (ret) + return ret; - /* Check, if it is write protected */ - if (nand_check_wp(mtd)) { - pr_debug("%s: device is write protected!\n", - __func__); - status = MTD_ERASE_FAILED; - ret = -EIO; - goto out; - } + ret = nand_setup_interface(chip, chipnr); + if (ret) + return ret; - /* Submit address of first page to lock */ - page = ofs >> chip->page_shift; - chip->cmdfunc(mtd, NAND_CMD_LOCK, -1, page & chip->pagemask); + return 0; +} +EXPORT_SYMBOL_GPL(nand_reset); - /* Call wait ready function */ - status = chip->waitfunc(mtd, chip); - /* See if device thinks it succeeded */ - if (status & NAND_STATUS_FAIL) { - pr_debug("%s: error status = 0x%08x\n", - __func__, status); - ret = -EIO; - goto out; - } +/** + * nand_get_features - wrapper to perform a GET_FEATURE + * @chip: NAND chip info structure + * @addr: feature address + * @subfeature_param: the subfeature parameters, a four bytes array + * + * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the + * operation cannot be handled. + */ +int nand_get_features(struct nand_chip *chip, int addr, + u8 *subfeature_param) +{ + if (!nand_supports_get_features(chip, addr)) + return -ENOTSUPP; - ret = __nand_unlock(mtd, ofs, len, 0x1); + if (chip->legacy.get_features) + return chip->legacy.get_features(chip, addr, subfeature_param); -out: - chip->select_chip(mtd, -1); - nand_release_device(mtd); + return nand_get_features_op(chip, addr, subfeature_param); +} - return ret; +/** + * nand_set_features - wrapper to perform a SET_FEATURE + * @chip: NAND chip info structure + * @addr: feature address + * @subfeature_param: the subfeature parameters, a four bytes array + * + * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the + * operation cannot be handled. + */ +int nand_set_features(struct nand_chip *chip, int addr, + u8 *subfeature_param) +{ + if (!nand_supports_set_features(chip, addr)) + return -ENOTSUPP; + + if (chip->legacy.set_features) + return chip->legacy.set_features(chip, addr, subfeature_param); + + return nand_set_features_op(chip, addr, subfeature_param); } -EXPORT_SYMBOL(nand_lock); /** * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data @@ -1016,7 +2531,10 @@ int nand_check_erased_buf(void *buf, int len, int bitflips_threshold) for (; len >= sizeof(long); len -= sizeof(long), bitmap += sizeof(long)) { - weight = hweight_long(*((unsigned long *)bitmap)); + unsigned long d = *((unsigned long *)bitmap); + if (d == ~0UL) + continue; + weight = hweight_long(d); bitflips += BITS_PER_LONG - weight; if (unlikely(bitflips > bitflips_threshold)) return -EBADMSG; @@ -1110,8 +2628,22 @@ int nand_check_erased_ecc_chunk(void *data, int datalen, EXPORT_SYMBOL(nand_check_erased_ecc_chunk); /** + * nand_read_page_raw_notsupp - dummy read raw page function + * @chip: nand chip info structure + * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi + * @page: page number to read + * + * Returns -ENOTSUPP unconditionally. + */ +int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf, + int oob_required, int page) +{ + return -ENOTSUPP; +} + +/** * nand_read_page_raw - [INTERN] read raw page data without ecc - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data * @oob_required: caller requires OOB data read to chip->oob_poi @@ -1119,18 +2651,70 @@ EXPORT_SYMBOL(nand_check_erased_ecc_chunk); * * Not for syndrome calculating ECC controllers, which use a special oob layout. */ -static __maybe_unused int nand_read_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) +int nand_read_page_raw(struct nand_chip *chip, uint8_t *buf, int oob_required, + int page) { - chip->read_buf(mtd, buf, mtd->writesize); - if (oob_required) - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + struct mtd_info *mtd = nand_to_mtd(chip); + int ret; + + ret = nand_read_page_op(chip, page, 0, buf, mtd->writesize); + if (ret) + return ret; + + if (oob_required) { + ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, + false, false); + if (ret) + return ret; + } + return 0; } +EXPORT_SYMBOL(nand_read_page_raw); + +/** + * nand_monolithic_read_page_raw - Monolithic page read in raw mode + * @chip: NAND chip info structure + * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi + * @page: page number to read + * + * This is a raw page read, ie. without any error detection/correction. + * Monolithic means we are requesting all the relevant data (main plus + * eventually OOB) to be loaded in the NAND cache and sent over the + * bus (from the NAND chip to the NAND controller) in a single + * operation. This is an alternative to nand_read_page_raw(), which + * first reads the main data, and if the OOB data is requested too, + * then reads more data on the bus. + */ +int nand_monolithic_read_page_raw(struct nand_chip *chip, u8 *buf, + int oob_required, int page) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + unsigned int size = mtd->writesize; + u8 *read_buf = buf; + int ret; + + if (oob_required) { + size += mtd->oobsize; + + if (buf != chip->data_buf) + read_buf = nand_get_data_buf(chip); + } + + ret = nand_read_page_op(chip, page, 0, read_buf, size); + if (ret) + return ret; + + if (buf != chip->data_buf) + memcpy(buf, read_buf, mtd->writesize); + + return 0; +} +EXPORT_SYMBOL(nand_monolithic_read_page_raw); /** * nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data * @oob_required: caller requires OOB data read to chip->oob_poi @@ -1138,68 +2722,89 @@ static __maybe_unused int nand_read_page_raw(struct mtd_info *mtd, * * We need a special oob layout and handling even when OOB isn't used. */ -static __maybe_unused int nand_read_page_raw_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, +static int nand_read_page_raw_syndrome(struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; uint8_t *oob = chip->oob_poi; - int steps, size; + int steps, size, ret; + + ret = nand_read_page_op(chip, page, 0, NULL, 0); + if (ret) + return ret; for (steps = chip->ecc.steps; steps > 0; steps--) { - chip->read_buf(mtd, buf, eccsize); + ret = nand_read_data_op(chip, buf, eccsize, false, false); + if (ret) + return ret; + buf += eccsize; if (chip->ecc.prepad) { - chip->read_buf(mtd, oob, chip->ecc.prepad); + ret = nand_read_data_op(chip, oob, chip->ecc.prepad, + false, false); + if (ret) + return ret; + oob += chip->ecc.prepad; } - chip->read_buf(mtd, oob, eccbytes); + ret = nand_read_data_op(chip, oob, eccbytes, false, false); + if (ret) + return ret; + oob += eccbytes; if (chip->ecc.postpad) { - chip->read_buf(mtd, oob, chip->ecc.postpad); + ret = nand_read_data_op(chip, oob, chip->ecc.postpad, + false, false); + if (ret) + return ret; + oob += chip->ecc.postpad; } } size = mtd->oobsize - (oob - chip->oob_poi); - if (size) - chip->read_buf(mtd, oob, size); + if (size) { + ret = nand_read_data_op(chip, oob, size, false, false); + if (ret) + return ret; + } return 0; } /** * nand_read_page_swecc - [REPLACEABLE] software ECC based page read function - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data * @oob_required: caller requires OOB data read to chip->oob_poi * @page: page number to read */ -static __maybe_unused int nand_read_page_swecc(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, - int page) +static int nand_read_page_swecc(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { - int i, eccsize = chip->ecc.size; + struct mtd_info *mtd = nand_to_mtd(chip); + int i, eccsize = chip->ecc.size, ret; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; uint8_t *p = buf; - uint8_t *ecc_calc = chip->buffers->ecccalc; - uint8_t *ecc_code = chip->buffers->ecccode; - uint32_t *eccpos = chip->ecc.layout->eccpos; + uint8_t *ecc_calc = chip->ecc.calc_buf; + uint8_t *ecc_code = chip->ecc.code_buf; unsigned int max_bitflips = 0; - chip->ecc.read_page_raw(mtd, chip, buf, 1, page); + chip->ecc.read_page_raw(chip, buf, 1, page); for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) - chip->ecc.calculate(mtd, p, &ecc_calc[i]); + chip->ecc.calculate(chip, p, &ecc_calc[i]); - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; + ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, + chip->ecc.total); + if (ret) + return ret; eccsteps = chip->ecc.steps; p = buf; @@ -1207,7 +2812,7 @@ static __maybe_unused int nand_read_page_swecc(struct mtd_info *mtd, for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { int stat; - stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + stat = chip->ecc.correct(chip, p, &ecc_code[i], &ecc_calc[i]); if (stat < 0) { mtd->ecc_stats.failed++; } else { @@ -1220,34 +2825,30 @@ static __maybe_unused int nand_read_page_swecc(struct mtd_info *mtd, /** * nand_read_subpage - [REPLACEABLE] ECC based sub-page read function - * @mtd: mtd info structure * @chip: nand chip info structure * @data_offs: offset of requested data within the page * @readlen: data length * @bufpoi: buffer to store read data + * @page: page number to read */ -static __maybe_unused int nand_read_subpage(struct mtd_info *mtd, - struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, - uint8_t *bufpoi, int page) +static int nand_read_subpage(struct nand_chip *chip, uint32_t data_offs, + uint32_t readlen, uint8_t *bufpoi, int page) { - int start_step, end_step, num_steps; - uint32_t *eccpos = chip->ecc.layout->eccpos; + struct mtd_info *mtd = nand_to_mtd(chip); + int start_step, end_step, num_steps, ret; uint8_t *p; int data_col_addr, i, gaps = 0; int datafrag_len, eccfrag_len, aligned_len, aligned_pos; int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; - int index = 0; + int index, section = 0; unsigned int max_bitflips = 0; - - /* - * Currently we have no users in barebox, so disable this for now - */ - return -ENOTSUPP; + struct mtd_oob_region oobregion = { }; /* Column address within the page aligned to ECC size (256bytes) */ start_step = data_offs / chip->ecc.size; end_step = (data_offs + readlen - 1) / chip->ecc.size; num_steps = end_step - start_step + 1; + index = start_step * chip->ecc.bytes; /* Data size aligned to ECC ecc.size */ datafrag_len = num_steps * chip->ecc.size; @@ -1255,58 +2856,74 @@ static __maybe_unused int nand_read_subpage(struct mtd_info *mtd, data_col_addr = start_step * chip->ecc.size; /* If we read not a page aligned data */ - if (data_col_addr != 0) - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1); - p = bufpoi + data_col_addr; - chip->read_buf(mtd, p, datafrag_len); + ret = nand_read_page_op(chip, page, data_col_addr, p, datafrag_len); + if (ret) + return ret; /* Calculate ECC */ for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) - chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]); + chip->ecc.calculate(chip, p, &chip->ecc.calc_buf[i]); /* * The performance is faster if we position offsets according to * ecc.pos. Let's make sure that there are no gaps in ECC positions. */ - for (i = 0; i < eccfrag_len - 1; i++) { - if (eccpos[i + start_step * chip->ecc.bytes] + 1 != - eccpos[i + start_step * chip->ecc.bytes + 1]) { - gaps = 1; - break; - } - } + ret = mtd_ooblayout_find_eccregion(mtd, index, §ion, &oobregion); + if (ret) + return ret; + + if (oobregion.length < eccfrag_len) + gaps = 1; + if (gaps) { - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + ret = nand_change_read_column_op(chip, mtd->writesize, + chip->oob_poi, mtd->oobsize, + false); + if (ret) + return ret; } else { /* * Send the command to read the particular ECC bytes take care * about buswidth alignment in read_buf. */ - index = start_step * chip->ecc.bytes; - - aligned_pos = eccpos[index] & ~(busw - 1); + aligned_pos = oobregion.offset & ~(busw - 1); aligned_len = eccfrag_len; - if (eccpos[index] & (busw - 1)) + if (oobregion.offset & (busw - 1)) aligned_len++; - if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1)) + if ((oobregion.offset + (num_steps * chip->ecc.bytes)) & + (busw - 1)) aligned_len++; - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, - mtd->writesize + aligned_pos, -1); - chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len); + ret = nand_change_read_column_op(chip, + mtd->writesize + aligned_pos, + &chip->oob_poi[aligned_pos], + aligned_len, false); + if (ret) + return ret; } - for (i = 0; i < eccfrag_len; i++) - chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + index]]; + ret = mtd_ooblayout_get_eccbytes(mtd, chip->ecc.code_buf, + chip->oob_poi, index, eccfrag_len); + if (ret) + return ret; p = bufpoi + data_col_addr; for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) { int stat; - stat = chip->ecc.correct(mtd, p, - &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); + stat = chip->ecc.correct(chip, p, &chip->ecc.code_buf[i], + &chip->ecc.calc_buf[i]); + if (stat == -EBADMSG && + (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { + /* check for empty pages with bitflips */ + stat = nand_check_erased_ecc_chunk(p, chip->ecc.size, + &chip->ecc.code_buf[i], + chip->ecc.bytes, + NULL, 0, + chip->ecc.strength); + } + if (stat < 0) { mtd->ecc_stats.failed++; } else { @@ -1319,7 +2936,6 @@ static __maybe_unused int nand_read_subpage(struct mtd_info *mtd, /** * nand_read_page_hwecc - [REPLACEABLE] hardware ECC based page read function - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data * @oob_required: caller requires OOB data read to chip->oob_poi @@ -1327,27 +2943,41 @@ static __maybe_unused int nand_read_subpage(struct mtd_info *mtd, * * Not for syndrome calculating ECC controllers which need a special oob layout. */ -static __maybe_unused int nand_read_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) +static int nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { - int i, eccsize = chip->ecc.size; + struct mtd_info *mtd = nand_to_mtd(chip); + int i, eccsize = chip->ecc.size, ret; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; uint8_t *p = buf; - uint8_t *ecc_calc = chip->buffers->ecccalc; - uint8_t *ecc_code = chip->buffers->ecccode; - uint32_t *eccpos = chip->ecc.layout->eccpos; + uint8_t *ecc_calc = chip->ecc.calc_buf; + uint8_t *ecc_code = chip->ecc.code_buf; unsigned int max_bitflips = 0; + ret = nand_read_page_op(chip, page, 0, NULL, 0); + if (ret) + return ret; + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - chip->ecc.hwctl(mtd, NAND_ECC_READ); - chip->read_buf(mtd, p, eccsize); - chip->ecc.calculate(mtd, p, &ecc_calc[i]); + chip->ecc.hwctl(chip, NAND_ECC_READ); + + ret = nand_read_data_op(chip, p, eccsize, false, false); + if (ret) + return ret; + + chip->ecc.calculate(chip, p, &ecc_calc[i]); } - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; + ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, false, + false); + if (ret) + return ret; + + ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, + chip->ecc.total); + if (ret) + return ret; eccsteps = chip->ecc.steps; p = buf; @@ -1355,59 +2985,16 @@ static __maybe_unused int nand_read_page_hwecc(struct mtd_info *mtd, for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { int stat; - stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); - if (stat < 0) { - mtd->ecc_stats.failed++; - } else { - mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); + stat = chip->ecc.correct(chip, p, &ecc_code[i], &ecc_calc[i]); + if (stat == -EBADMSG && + (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { + /* check for empty pages with bitflips */ + stat = nand_check_erased_ecc_chunk(p, eccsize, + &ecc_code[i], eccbytes, + NULL, 0, + chip->ecc.strength); } - } - return max_bitflips; -} -/** - * nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @oob_required: caller requires OOB data read to chip->oob_poi - * @page: page number to read - * - * Hardware ECC for large page chips, require OOB to be read first. For this - * ECC mode, the write_page method is re-used from ECC_HW. These methods - * read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with - * multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from - * the data area, by overwriting the NAND manufacturer bad block markings. - */ -static __maybe_unused int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint8_t *p = buf; - uint8_t *ecc_code = chip->buffers->ecccode; - uint32_t *eccpos = chip->ecc.layout->eccpos; - uint8_t *ecc_calc = chip->buffers->ecccalc; - unsigned int max_bitflips = 0; - - /* Read the OOB area first */ - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); - - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - int stat; - - chip->ecc.hwctl(mtd, NAND_ECC_READ); - chip->read_buf(mtd, p, eccsize); - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - - stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL); if (stat < 0) { mtd->ecc_stats.failed++; } else { @@ -1420,7 +3007,6 @@ static __maybe_unused int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, /** * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data * @oob_required: caller requires OOB data read to chip->oob_poi @@ -1429,57 +3015,91 @@ static __maybe_unused int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, * The hw generator calculates the error syndrome automatically. Therefore we * need a special oob layout and handling. */ -static __maybe_unused int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int nand_read_page_syndrome(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { - int i, eccsize = chip->ecc.size; + struct mtd_info *mtd = nand_to_mtd(chip); + int ret, i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; + int eccpadbytes = eccbytes + chip->ecc.prepad + chip->ecc.postpad; uint8_t *p = buf; uint8_t *oob = chip->oob_poi; unsigned int max_bitflips = 0; + ret = nand_read_page_op(chip, page, 0, NULL, 0); + if (ret) + return ret; + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { int stat; - chip->ecc.hwctl(mtd, NAND_ECC_READ); - chip->read_buf(mtd, p, eccsize); + chip->ecc.hwctl(chip, NAND_ECC_READ); + + ret = nand_read_data_op(chip, p, eccsize, false, false); + if (ret) + return ret; if (chip->ecc.prepad) { - chip->read_buf(mtd, oob, chip->ecc.prepad); + ret = nand_read_data_op(chip, oob, chip->ecc.prepad, + false, false); + if (ret) + return ret; + oob += chip->ecc.prepad; } - chip->ecc.hwctl(mtd, NAND_ECC_READSYN); - chip->read_buf(mtd, oob, eccbytes); - stat = chip->ecc.correct(mtd, p, oob, NULL); + chip->ecc.hwctl(chip, NAND_ECC_READSYN); - if (stat < 0) { - mtd->ecc_stats.failed++; - } else { - mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); - } + ret = nand_read_data_op(chip, oob, eccbytes, false, false); + if (ret) + return ret; + + stat = chip->ecc.correct(chip, p, oob, NULL); oob += eccbytes; if (chip->ecc.postpad) { - chip->read_buf(mtd, oob, chip->ecc.postpad); + ret = nand_read_data_op(chip, oob, chip->ecc.postpad, + false, false); + if (ret) + return ret; + oob += chip->ecc.postpad; } + + if (stat == -EBADMSG && + (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { + /* check for empty pages with bitflips */ + stat = nand_check_erased_ecc_chunk(p, chip->ecc.size, + oob - eccpadbytes, + eccpadbytes, + NULL, 0, + chip->ecc.strength); + } + + if (stat < 0) { + mtd->ecc_stats.failed++; + } else { + mtd->ecc_stats.corrected += stat; + max_bitflips = max_t(unsigned int, max_bitflips, stat); + } } /* Calculate remaining oob bytes */ i = mtd->oobsize - (oob - chip->oob_poi); - if (i) - chip->read_buf(mtd, oob, i); + if (i) { + ret = nand_read_data_op(chip, oob, i, false, false); + if (ret) + return ret; + } return max_bitflips; } /** * nand_transfer_oob - [INTERN] Transfer oob to client buffer - * @chip: nand chip structure + * @chip: NAND chip object * @oob: oob destination address * @ops: oob ops structure * @len: size of oob to transfer @@ -1487,6 +3107,9 @@ static __maybe_unused int nand_read_page_syndrome(struct mtd_info *mtd, struct static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, struct mtd_oob_ops *ops, size_t len) { + struct mtd_info *mtd = nand_to_mtd(chip); + int ret; + switch (ops->mode) { case MTD_OPS_PLACE_OOB: @@ -1494,31 +3117,12 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, memcpy(oob, chip->oob_poi + ops->ooboffs, len); return oob + len; - case MTD_OPS_AUTO_OOB: { - struct nand_oobfree *free = chip->ecc.layout->oobfree; - uint32_t boffs = 0, roffs = ops->ooboffs; - size_t bytes = 0; - - for (; free->length && len; free++, len -= bytes) { - /* Read request not from offset 0? */ - if (unlikely(roffs)) { - if (roffs >= free->length) { - roffs -= free->length; - continue; - } - boffs = free->offset + roffs; - bytes = min_t(size_t, len, - (free->length - roffs)); - roffs = 0; - } else { - bytes = min_t(size_t, len, free->length); - boffs = free->offset; - } - memcpy(oob, chip->oob_poi + boffs, bytes); - oob += bytes; - } - return oob; - } + case MTD_OPS_AUTO_OOB: + ret = mtd_ooblayout_get_databytes(mtd, oob, chip->oob_poi, + ops->ooboffs, len); + BUG_ON(ret); + return oob + len; + default: BUG(); } @@ -1526,32 +3130,64 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, } /** + * nand_setup_read_retry - [INTERN] Set the READ RETRY mode + * @chip: NAND chip object + * @retry_mode: the retry mode to use + * + * Some vendors supply a special command to shift the Vt threshold, to be used + * when there are too many bitflips in a page (i.e., ECC error). After setting + * a new threshold, the host should retry reading the page. + */ +static int nand_setup_read_retry(struct nand_chip *chip, int retry_mode) +{ + pr_debug("setting READ RETRY mode %d\n", retry_mode); + + if (retry_mode >= chip->read_retries) + return -EINVAL; + + if (!chip->ops.setup_read_retry) + return -EOPNOTSUPP; + + return chip->ops.setup_read_retry(chip, retry_mode); +} + +static void nand_wait_readrdy(struct nand_chip *chip) +{ + const struct nand_sdr_timings *sdr; + + if (!(chip->options & NAND_NEED_READRDY)) + return; + + sdr = nand_get_sdr_timings(nand_get_interface_config(chip)); + WARN_ON(nand_wait_rdy_op(chip, PSEC_TO_MSEC(sdr->tR_max), 0)); +} + +/** * nand_do_read_ops - [INTERN] Read data with ECC - * @mtd: MTD device structure + * @chip: NAND chip object * @from: offset to read from * @ops: oob ops structure * * Internal function. Called with chip held. */ -static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, +static int nand_do_read_ops(struct nand_chip *chip, loff_t from, struct mtd_oob_ops *ops) { int chipnr, page, realpage, col, bytes, aligned, oob_required; - struct nand_chip *chip = mtd_to_nand(mtd); - struct mtd_ecc_stats stats; + struct mtd_info *mtd = nand_to_mtd(chip); int ret = 0; uint32_t readlen = ops->len; uint32_t oobreadlen = ops->ooblen; - uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ? - mtd->oobavail : mtd->oobsize; + uint32_t max_oobsize = mtd_oobavail(mtd, ops); uint8_t *bufpoi, *oob, *buf; + int use_bounce_buf; unsigned int max_bitflips = 0; - - stats = mtd->ecc_stats; + int retry_mode = 0; + bool ecc_fail = false; chipnr = (int)(from >> chip->chip_shift); - chip->select_chip(mtd, chipnr); + nand_select_target(chip, chipnr); realpage = (int)(from >> chip->page_shift); page = realpage & chip->pagemask; @@ -1563,81 +3199,115 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, oob_required = oob ? 1 : 0; while (1) { + struct mtd_ecc_stats ecc_stats = mtd->ecc_stats; + bytes = min(mtd->writesize - col, readlen); aligned = (bytes == mtd->writesize); + if (!aligned) + use_bounce_buf = 1; + else if (chip->options & NAND_USES_DMA) + use_bounce_buf = !IS_ALIGNED((unsigned long)buf, + chip->buf_align); + else + use_bounce_buf = 0; + /* Is the current page in the buffer? */ - if (realpage != chip->pagebuf || oob) { - bufpoi = aligned ? buf : chip->buffers->databuf; + if (realpage != chip->pagecache.page || oob) { + bufpoi = use_bounce_buf ? chip->data_buf : buf; - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + if (use_bounce_buf && aligned) + pr_debug("%s: using read bounce buffer for buf@%p\n", + __func__, buf); +read_retry: /* * Now read the page into the buffer. Absent an error, * the read methods return max bitflips per ecc step. */ if (unlikely(ops->mode == MTD_OPS_RAW)) - ret = chip->ecc.read_page_raw(mtd, chip, bufpoi, + ret = chip->ecc.read_page_raw(chip, bufpoi, oob_required, page); else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) && !oob) - ret = chip->ecc.read_subpage(mtd, chip, - col, bytes, bufpoi, page); + ret = chip->ecc.read_subpage(chip, col, bytes, + bufpoi, page); else - ret = chip->ecc.read_page(mtd, chip, bufpoi, + ret = chip->ecc.read_page(chip, bufpoi, oob_required, page); if (ret < 0) { - if (!aligned) + if (use_bounce_buf) /* Invalidate page cache */ - chip->pagebuf = -1; + chip->pagecache.page = -1; break; } - max_bitflips = max_t(unsigned int, max_bitflips, ret); - - /* Transfer not aligned data */ - if (!aligned) { + /* + * Copy back the data in the initial buffer when reading + * partial pages or when a bounce buffer is required. + */ + if (use_bounce_buf) { if (!NAND_HAS_SUBPAGE_READ(chip) && !oob && - !(mtd->ecc_stats.failed - stats.failed) && + !(mtd->ecc_stats.failed - ecc_stats.failed) && (ops->mode != MTD_OPS_RAW)) { - chip->pagebuf = realpage; - chip->pagebuf_bitflips = ret; + chip->pagecache.page = realpage; + chip->pagecache.bitflips = ret; } else { /* Invalidate page cache */ - chip->pagebuf = -1; + chip->pagecache.page = -1; } - memcpy(buf, chip->buffers->databuf + col, bytes); + memcpy(buf, bufpoi + col, bytes); } - buf += bytes; - if (unlikely(oob)) { int toread = min(oobreadlen, max_oobsize); if (toread) { - oob = nand_transfer_oob(chip, - oob, ops, toread); + oob = nand_transfer_oob(chip, oob, ops, + toread); oobreadlen -= toread; } } - if (chip->options & NAND_NEED_READRDY) { - /* Apply delay or wait for ready/busy pin */ - if (!chip->dev_ready) - udelay(chip->chip_delay); - else - nand_wait_ready(mtd); + nand_wait_readrdy(chip); + + if (mtd->ecc_stats.failed - ecc_stats.failed) { + if (retry_mode + 1 < chip->read_retries) { + retry_mode++; + ret = nand_setup_read_retry(chip, + retry_mode); + if (ret < 0) + break; + + /* Reset ecc_stats; retry */ + mtd->ecc_stats = ecc_stats; + goto read_retry; + } else { + /* No more retry modes; real failure */ + ecc_fail = true; + } } + + buf += bytes; + max_bitflips = max_t(unsigned int, max_bitflips, ret); } else { - memcpy(buf, chip->buffers->databuf + col, bytes); + memcpy(buf, chip->data_buf + col, bytes); buf += bytes; max_bitflips = max_t(unsigned int, max_bitflips, - chip->pagebuf_bitflips); + chip->pagecache.bitflips); } readlen -= bytes; + /* Reset to retry mode 0 */ + if (retry_mode) { + ret = nand_setup_read_retry(chip, 0); + if (ret < 0) + break; + retry_mode = 0; + } + if (!readlen) break; @@ -1650,11 +3320,11 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /* Check, if we cross a chip boundary */ if (!page) { chipnr++; - chip->select_chip(mtd, -1); - chip->select_chip(mtd, chipnr); + nand_deselect_target(chip); + nand_select_target(chip, chipnr); } } - chip->select_chip(mtd, -1); + nand_deselect_target(chip); ops->retlen = ops->len - (size_t) readlen; if (oob) @@ -1663,142 +3333,107 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, if (ret < 0) return ret; - if (mtd->ecc_stats.failed - stats.failed) + if (ecc_fail) return -EBADMSG; return max_bitflips; } /** - * nand_read - [MTD Interface] MTD compatibility function for nand_do_read_ecc - * @mtd: MTD device structure - * @from: offset to read from - * @len: number of bytes to read - * @retlen: pointer to variable to store the number of read bytes - * @buf: the databuffer to put data - * - * Get hold of the chip and call nand_do_read. - */ -static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, uint8_t *buf) -{ - struct mtd_oob_ops ops; - int ret; - - nand_get_device(mtd, FL_READING); - ops.len = len; - ops.datbuf = buf; - ops.ooblen = 0; - ops.oobbuf = NULL; - ops.mode = MTD_OPS_PLACE_OOB; - ret = nand_do_read_ops(mtd, from, &ops); - *retlen = ops.retlen; - nand_release_device(mtd); - return ret; -} - -/** * nand_read_oob_std - [REPLACEABLE] the most common OOB data read function - * @mtd: mtd info structure * @chip: nand chip info structure * @page: page number to read */ -static __maybe_unused int nand_read_oob_std(struct mtd_info *mtd, - struct nand_chip *chip, int page) +int nand_read_oob_std(struct nand_chip *chip, int page) { - if (!IS_ENABLED(CONFIG_NAND_READ_OOB)) - return -ENOTSUPP; + struct mtd_info *mtd = nand_to_mtd(chip); - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - return 0; + return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize); } +EXPORT_SYMBOL(nand_read_oob_std); /** * nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC * with syndromes - * @mtd: mtd info structure * @chip: nand chip info structure * @page: page number to read */ -static __maybe_unused int nand_read_oob_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, int page) +static int nand_read_oob_syndrome(struct nand_chip *chip, int page) { - uint8_t *buf = chip->oob_poi; + struct mtd_info *mtd = nand_to_mtd(chip); int length = mtd->oobsize; int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; int eccsize = chip->ecc.size; - uint8_t *bufpoi = buf; - int i, toread, sndrnd = 0, pos; + uint8_t *bufpoi = chip->oob_poi; + int i, toread, sndrnd = 0, pos, ret; - if (!IS_ENABLED(CONFIG_NAND_READ_OOB)) - return -ENOTSUPP; + ret = nand_read_page_op(chip, page, chip->ecc.size, NULL, 0); + if (ret) + return ret; - chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page); for (i = 0; i < chip->ecc.steps; i++) { if (sndrnd) { + int ret; + pos = eccsize + i * (eccsize + chunk); if (mtd->writesize > 512) - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, pos, -1); + ret = nand_change_read_column_op(chip, pos, + NULL, 0, + false); else - chip->cmdfunc(mtd, NAND_CMD_READ0, pos, page); + ret = nand_read_page_op(chip, page, pos, NULL, + 0); + + if (ret) + return ret; } else sndrnd = 1; toread = min_t(int, length, chunk); - chip->read_buf(mtd, bufpoi, toread); + + ret = nand_read_data_op(chip, bufpoi, toread, false, false); + if (ret) + return ret; + bufpoi += toread; length -= toread; } - if (length > 0) - chip->read_buf(mtd, bufpoi, length); + if (length > 0) { + ret = nand_read_data_op(chip, bufpoi, length, false, false); + if (ret) + return ret; + } return 0; } /** * nand_write_oob_std - [REPLACEABLE] the most common OOB data write function - * @mtd: mtd info structure * @chip: nand chip info structure * @page: page number to write */ -static __maybe_unused int nand_write_oob_std(struct mtd_info *mtd, - struct nand_chip *chip, int page) +int nand_write_oob_std(struct nand_chip *chip, int page) { - int status = 0; - const uint8_t *buf = chip->oob_poi; - int length = mtd->oobsize; + struct mtd_info *mtd = nand_to_mtd(chip); - if (!IS_ENABLED(CONFIG_NAND_READ_OOB) || !IS_ENABLED(CONFIG_MTD_WRITE)) - return -ENOTSUPP; - - chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); - chip->write_buf(mtd, buf, length); - /* Send command to program the OOB data */ - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - - status = chip->waitfunc(mtd, chip); - - return status & NAND_STATUS_FAIL ? -EIO : 0; + return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi, + mtd->oobsize); } +EXPORT_SYMBOL(nand_write_oob_std); /** * nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC * with syndrome - only for large page flash - * @mtd: mtd info structure * @chip: nand chip info structure * @page: page number to write */ -static __maybe_unused int nand_write_oob_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, int page) +static int nand_write_oob_syndrome(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; int eccsize = chip->ecc.size, length = mtd->oobsize; - int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps; + int ret, i, len, pos, sndcmd = 0, steps = chip->ecc.steps; const uint8_t *bufpoi = chip->oob_poi; - if (!IS_ENABLED(CONFIG_NAND_READ_OOB) || !IS_ENABLED(CONFIG_MTD_WRITE)) - return -ENOTSUPP; - /* * data-ecc-data-ecc ... ecc-oob * or @@ -1810,7 +3445,10 @@ static __maybe_unused int nand_write_oob_syndrome(struct mtd_info *mtd, } else pos = eccsize; - chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); + ret = nand_prog_page_begin_op(chip, page, pos, NULL, 0); + if (ret) + return ret; + for (i = 0; i < steps; i++) { if (sndcmd) { if (mtd->writesize <= 512) { @@ -1819,79 +3457,71 @@ static __maybe_unused int nand_write_oob_syndrome(struct mtd_info *mtd, len = eccsize; while (len > 0) { int num = min_t(int, len, 4); - chip->write_buf(mtd, (uint8_t *)&fill, - num); + + ret = nand_write_data_op(chip, &fill, + num, false); + if (ret) + return ret; + len -= num; } } else { pos = eccsize + i * (eccsize + chunk); - chip->cmdfunc(mtd, NAND_CMD_RNDIN, pos, -1); + ret = nand_change_write_column_op(chip, pos, + NULL, 0, + false); + if (ret) + return ret; } } else sndcmd = 1; len = min_t(int, length, chunk); - chip->write_buf(mtd, bufpoi, len); + + ret = nand_write_data_op(chip, bufpoi, len, false); + if (ret) + return ret; + bufpoi += len; length -= len; } - if (length > 0) - chip->write_buf(mtd, bufpoi, length); - - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - status = chip->waitfunc(mtd, chip); + if (length > 0) { + ret = nand_write_data_op(chip, bufpoi, length, false); + if (ret) + return ret; + } - return status & NAND_STATUS_FAIL ? -EIO : 0; + return nand_prog_page_end_op(chip); } /** * nand_do_read_oob - [INTERN] NAND read out-of-band - * @mtd: MTD device structure + * @chip: NAND chip object * @from: offset to read from * @ops: oob operations description structure * * NAND read out-of-band data from the spare area. */ -static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, +static int nand_do_read_oob(struct nand_chip *chip, loff_t from, struct mtd_oob_ops *ops) { + struct mtd_info *mtd = nand_to_mtd(chip); + unsigned int max_bitflips = 0; int page, realpage, chipnr; - struct nand_chip *chip = mtd_to_nand(mtd); struct mtd_ecc_stats stats; int readlen = ops->ooblen; int len; uint8_t *buf = ops->oobbuf; int ret = 0; - if (!IS_ENABLED(CONFIG_NAND_READ_OOB)) - return -ENOTSUPP; - pr_debug("%s: from = 0x%08Lx, len = %i\n", __func__, (unsigned long long)from, readlen); stats = mtd->ecc_stats; - if (ops->mode == MTD_OPS_AUTO_OOB) - len = chip->ecc.layout->oobavail; - else - len = mtd->oobsize; - - if (unlikely(ops->ooboffs >= len)) { - pr_debug("%s: attempt to start read outside oob\n", - __func__); - return -EINVAL; - } - - /* Do not allow reads past end of device */ - if (unlikely(from >= mtd->size || - ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) - - (from >> chip->page_shift)) * len)) { - pr_debug("%s: attempt to read beyond end of device\n", - __func__); - return -EINVAL; - } + len = mtd_oobavail(mtd, ops); chipnr = (int)(from >> chip->chip_shift); - chip->select_chip(mtd, chipnr); + nand_select_target(chip, chipnr); /* Shift to get page */ realpage = (int)(from >> chip->page_shift); @@ -1899,9 +3529,9 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, while (1) { if (ops->mode == MTD_OPS_RAW) - ret = chip->ecc.read_oob_raw(mtd, chip, page); + ret = chip->ecc.read_oob_raw(chip, page); else - ret = chip->ecc.read_oob(mtd, chip, page); + ret = chip->ecc.read_oob(chip, page); if (ret < 0) break; @@ -1909,13 +3539,9 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, len = min(len, readlen); buf = nand_transfer_oob(chip, buf, ops, len); - if (chip->options & NAND_NEED_READRDY) { - /* Apply delay or wait for ready/busy pin */ - if (!chip->dev_ready) - udelay(chip->chip_delay); - else - nand_wait_ready(mtd); - } + nand_wait_readrdy(chip); + + max_bitflips = max_t(unsigned int, max_bitflips, ret); readlen -= len; if (!readlen) @@ -1928,11 +3554,11 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, /* Check, if we cross a chip boundary */ if (!page) { chipnr++; - chip->select_chip(mtd, -1); - chip->select_chip(mtd, chipnr); + nand_deselect_target(chip); + nand_select_target(chip, chipnr); } } - chip->select_chip(mtd, -1); + nand_deselect_target(chip); ops->oobretlen = ops->ooblen - readlen; @@ -1942,7 +3568,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, if (mtd->ecc_stats.failed - stats.failed) return -EBADMSG; - return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; + return max_bitflips; } /** @@ -1956,466 +3582,479 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, static int nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { - int ret = -ENOTSUPP; - - if (!IS_ENABLED(CONFIG_NAND_READ_OOB)) - return -ENOTSUPP; + struct nand_chip *chip = mtd_to_nand(mtd); + int ret; ops->retlen = 0; - /* Do not allow reads past end of device */ - if (ops->datbuf && (from + ops->len) > mtd->size) { - pr_debug("%s: attempt to read beyond end of device\n", - __func__); - return -EINVAL; - } - - nand_get_device(mtd, FL_READING); - - switch (ops->mode) { - case MTD_OPS_PLACE_OOB: - case MTD_OPS_AUTO_OOB: - case MTD_OPS_RAW: - break; + if (ops->mode != MTD_OPS_PLACE_OOB && + ops->mode != MTD_OPS_AUTO_OOB && + ops->mode != MTD_OPS_RAW) + return -ENOTSUPP; - default: - goto out; - } + ret = nand_get_device(chip); + if (ret) + return ret; if (!ops->datbuf) - ret = nand_do_read_oob(mtd, from, ops); + ret = nand_do_read_oob(chip, from, ops); else - ret = nand_do_read_ops(mtd, from, ops); + ret = nand_do_read_ops(chip, from, ops); -out: - nand_release_device(mtd); + nand_release_device(chip); return ret; } +/** + * nand_write_page_raw_notsupp - dummy raw page write function + * @chip: nand chip info structure + * @buf: data buffer + * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write + * + * Returns -ENOTSUPP unconditionally. + */ +int nand_write_page_raw_notsupp(struct nand_chip *chip, const u8 *buf, + int oob_required, int page) +{ + return -ENOTSUPP; +} /** * nand_write_page_raw - [INTERN] raw page write function - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write * * Not for syndrome calculating ECC controllers, which use a special oob layout. */ -static __maybe_unused int nand_write_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required) +int nand_write_page_raw(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { - if (!IS_ENABLED(CONFIG_MTD_WRITE)) - return -ENOTSUPP; + struct mtd_info *mtd = nand_to_mtd(chip); + int ret; + + ret = nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize); + if (ret) + return ret; + + if (oob_required) { + ret = nand_write_data_op(chip, chip->oob_poi, mtd->oobsize, + false); + if (ret) + return ret; + } - chip->write_buf(mtd, buf, mtd->writesize); - if (oob_required) - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + return nand_prog_page_end_op(chip); +} +EXPORT_SYMBOL(nand_write_page_raw); - return 0; +/** + * nand_monolithic_write_page_raw - Monolithic page write in raw mode + * @chip: NAND chip info structure + * @buf: data buffer to write + * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write + * + * This is a raw page write, ie. without any error detection/correction. + * Monolithic means we are requesting all the relevant data (main plus + * eventually OOB) to be sent over the bus and effectively programmed + * into the NAND chip arrays in a single operation. This is an + * alternative to nand_write_page_raw(), which first sends the main + * data, then eventually send the OOB data by latching more data + * cycles on the NAND bus, and finally sends the program command to + * synchronyze the NAND chip cache. + */ +int nand_monolithic_write_page_raw(struct nand_chip *chip, const u8 *buf, + int oob_required, int page) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + unsigned int size = mtd->writesize; + u8 *write_buf = (u8 *)buf; + + if (oob_required) { + size += mtd->oobsize; + + if (buf != chip->data_buf) { + write_buf = nand_get_data_buf(chip); + memcpy(write_buf, buf, mtd->writesize); + } + } + + return nand_prog_page_op(chip, page, 0, write_buf, size); } +EXPORT_SYMBOL(nand_monolithic_write_page_raw); /** * nand_write_page_raw_syndrome - [INTERN] raw page write function - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write * * We need a special oob layout and handling even when ECC isn't checked. */ -static __maybe_unused int nand_write_page_raw_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf, int oob_required) +static int nand_write_page_raw_syndrome(struct nand_chip *chip, + const uint8_t *buf, int oob_required, + int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; uint8_t *oob = chip->oob_poi; - int steps, size; + int steps, size, ret; - if (!IS_ENABLED(CONFIG_MTD_WRITE)) - return -ENOTSUPP; + ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0); + if (ret) + return ret; for (steps = chip->ecc.steps; steps > 0; steps--) { - chip->write_buf(mtd, buf, eccsize); + ret = nand_write_data_op(chip, buf, eccsize, false); + if (ret) + return ret; + buf += eccsize; if (chip->ecc.prepad) { - chip->write_buf(mtd, oob, chip->ecc.prepad); + ret = nand_write_data_op(chip, oob, chip->ecc.prepad, + false); + if (ret) + return ret; + oob += chip->ecc.prepad; } - chip->read_buf(mtd, oob, eccbytes); + ret = nand_write_data_op(chip, oob, eccbytes, false); + if (ret) + return ret; + oob += eccbytes; if (chip->ecc.postpad) { - chip->write_buf(mtd, oob, chip->ecc.postpad); + ret = nand_write_data_op(chip, oob, chip->ecc.postpad, + false); + if (ret) + return ret; + oob += chip->ecc.postpad; } } size = mtd->oobsize - (oob - chip->oob_poi); - if (size) - chip->write_buf(mtd, oob, size); + if (size) { + ret = nand_write_data_op(chip, oob, size, false); + if (ret) + return ret; + } - return 0; + return nand_prog_page_end_op(chip); } /** * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write */ -static __maybe_unused int nand_write_page_swecc(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required) +static int nand_write_page_swecc(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { - int i, eccsize = chip->ecc.size; + struct mtd_info *mtd = nand_to_mtd(chip); + int i, eccsize = chip->ecc.size, ret; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; - uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_calc = chip->ecc.calc_buf; const uint8_t *p = buf; - uint32_t *eccpos = chip->ecc.layout->eccpos; - - if (!IS_ENABLED(CONFIG_MTD_WRITE)) - return -ENOTSUPP; /* Software ECC calculation */ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) - chip->ecc.calculate(mtd, p, &ecc_calc[i]); + chip->ecc.calculate(chip, p, &ecc_calc[i]); - for (i = 0; i < chip->ecc.total; i++) - chip->oob_poi[eccpos[i]] = ecc_calc[i]; + ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0, + chip->ecc.total); + if (ret) + return ret; - return chip->ecc.write_page_raw(mtd, chip, buf, 1); + return chip->ecc.write_page_raw(chip, buf, 1, page); } /** * nand_write_page_hwecc - [REPLACEABLE] hardware ECC based page write function - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write */ -static __maybe_unused int nand_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required) +static int nand_write_page_hwecc(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { - int i, eccsize = chip->ecc.size; + struct mtd_info *mtd = nand_to_mtd(chip); + int i, eccsize = chip->ecc.size, ret; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; - uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_calc = chip->ecc.calc_buf; const uint8_t *p = buf; - uint32_t *eccpos = chip->ecc.layout->eccpos; - if (!IS_ENABLED(CONFIG_MTD_WRITE)) - return -ENOTSUPP; + ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0); + if (ret) + return ret; for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - chip->ecc.hwctl(mtd, NAND_ECC_WRITE); - chip->write_buf(mtd, p, eccsize); - chip->ecc.calculate(mtd, p, &ecc_calc[i]); + chip->ecc.hwctl(chip, NAND_ECC_WRITE); + + ret = nand_write_data_op(chip, p, eccsize, false); + if (ret) + return ret; + + chip->ecc.calculate(chip, p, &ecc_calc[i]); } - for (i = 0; i < chip->ecc.total; i++) - chip->oob_poi[eccpos[i]] = ecc_calc[i]; + ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0, + chip->ecc.total); + if (ret) + return ret; - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + ret = nand_write_data_op(chip, chip->oob_poi, mtd->oobsize, false); + if (ret) + return ret; - return 0; + return nand_prog_page_end_op(chip); } /** - * nand_write_subpage_hwecc - [REPLACABLE] hardware ECC based subpage write - * @mtd: mtd info structure + * nand_write_subpage_hwecc - [REPLACEABLE] hardware ECC based subpage write * @chip: nand chip info structure - * @column: column address of subpage within the page + * @offset: column address of subpage within the page * @data_len: data length + * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write */ -static __maybe_unused int nand_write_subpage_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, uint32_t offset, - uint32_t data_len, const uint8_t *data_buf, - int oob_required) +static int nand_write_subpage_hwecc(struct nand_chip *chip, uint32_t offset, + uint32_t data_len, const uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); uint8_t *oob_buf = chip->oob_poi; - uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_calc = chip->ecc.calc_buf; int ecc_size = chip->ecc.size; int ecc_bytes = chip->ecc.bytes; int ecc_steps = chip->ecc.steps; - uint32_t *eccpos = chip->ecc.layout->eccpos; uint32_t start_step = offset / ecc_size; uint32_t end_step = (offset + data_len - 1) / ecc_size; int oob_bytes = mtd->oobsize / ecc_steps; - int step, i; + int step, ret; - if (!IS_ENABLED(CONFIG_MTD_WRITE)) - return -ENOTSUPP; + ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0); + if (ret) + return ret; for (step = 0; step < ecc_steps; step++) { /* configure controller for WRITE access */ - chip->ecc.hwctl(mtd, NAND_ECC_WRITE); + chip->ecc.hwctl(chip, NAND_ECC_WRITE); /* write data (untouched subpages already masked by 0xFF) */ - chip->write_buf(mtd, data_buf, ecc_size); + ret = nand_write_data_op(chip, buf, ecc_size, false); + if (ret) + return ret; /* mask ECC of un-touched subpages by padding 0xFF */ if ((step < start_step) || (step > end_step)) memset(ecc_calc, 0xff, ecc_bytes); else - chip->ecc.calculate(mtd, data_buf, ecc_calc); + chip->ecc.calculate(chip, buf, ecc_calc); /* mask OOB of un-touched subpages by padding 0xFF */ /* if oob_required, preserve OOB metadata of written subpage */ if (!oob_required || (step < start_step) || (step > end_step)) memset(oob_buf, 0xff, oob_bytes); - data_buf += ecc_size; + buf += ecc_size; ecc_calc += ecc_bytes; oob_buf += oob_bytes; } /* copy calculated ECC for whole page to chip->buffer->oob */ /* this include masked-value(0xFF) for unwritten subpages */ - ecc_calc = chip->buffers->ecccalc; - for (i = 0; i < chip->ecc.total; i++) - chip->oob_poi[eccpos[i]] = ecc_calc[i]; + ecc_calc = chip->ecc.calc_buf; + ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0, + chip->ecc.total); + if (ret) + return ret; /* write OOB buffer to NAND device */ - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + ret = nand_write_data_op(chip, chip->oob_poi, mtd->oobsize, false); + if (ret) + return ret; - return 0; + return nand_prog_page_end_op(chip); } /** * nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write * * The hw generator calculates the error syndrome automatically. Therefore we * need a special oob layout and handling. */ -static __maybe_unused int nand_write_page_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf, int oob_required) +static int nand_write_page_syndrome(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; const uint8_t *p = buf; uint8_t *oob = chip->oob_poi; + int ret; - if (!IS_ENABLED(CONFIG_MTD_WRITE)) - return -ENOTSUPP; + ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0); + if (ret) + return ret; for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + chip->ecc.hwctl(chip, NAND_ECC_WRITE); - chip->ecc.hwctl(mtd, NAND_ECC_WRITE); - chip->write_buf(mtd, p, eccsize); + ret = nand_write_data_op(chip, p, eccsize, false); + if (ret) + return ret; if (chip->ecc.prepad) { - chip->write_buf(mtd, oob, chip->ecc.prepad); + ret = nand_write_data_op(chip, oob, chip->ecc.prepad, + false); + if (ret) + return ret; + oob += chip->ecc.prepad; } - chip->ecc.calculate(mtd, p, oob); - chip->write_buf(mtd, oob, eccbytes); + chip->ecc.calculate(chip, p, oob); + + ret = nand_write_data_op(chip, oob, eccbytes, false); + if (ret) + return ret; + oob += eccbytes; if (chip->ecc.postpad) { - chip->write_buf(mtd, oob, chip->ecc.postpad); + ret = nand_write_data_op(chip, oob, chip->ecc.postpad, + false); + if (ret) + return ret; + oob += chip->ecc.postpad; } } /* Calculate remaining oob bytes */ i = mtd->oobsize - (oob - chip->oob_poi); - if (i) - chip->write_buf(mtd, oob, i); + if (i) { + ret = nand_write_data_op(chip, oob, i, false); + if (ret) + return ret; + } - return 0; + return nand_prog_page_end_op(chip); } /** - * nand_write_page - [REPLACEABLE] write one page - * @mtd: MTD device structure + * nand_write_page - write one page * @chip: NAND chip descriptor * @offset: address offset within the page * @data_len: length of actual data to be written * @buf: the data to write * @oob_required: must write chip->oob_poi to OOB * @page: page number to write - * @cached: cached programming * @raw: use _raw version of write_page */ -static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t offset, int data_len, const uint8_t *buf, - int oob_required, int page, int cached, int raw) +static int nand_write_page(struct nand_chip *chip, uint32_t offset, + int data_len, const uint8_t *buf, int oob_required, + int page, int raw) { + struct mtd_info *mtd = nand_to_mtd(chip); int status, subpage; - if (!IS_ENABLED(CONFIG_MTD_WRITE)) - return -ENOTSUPP; - if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && chip->ecc.write_subpage) subpage = offset || (data_len < mtd->writesize); else subpage = 0; - chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); - if (unlikely(raw)) - status = chip->ecc.write_page_raw(mtd, chip, buf, - oob_required); + status = chip->ecc.write_page_raw(chip, buf, oob_required, + page); else if (subpage) - status = chip->ecc.write_subpage(mtd, chip, offset, data_len, - buf, oob_required); + status = chip->ecc.write_subpage(chip, offset, data_len, buf, + oob_required, page); else - status = chip->ecc.write_page(mtd, chip, buf, oob_required); + status = chip->ecc.write_page(chip, buf, oob_required, page); if (status < 0) return status; - /* - * Cached progamming disabled for now. Not sure if it's worth the - * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s). - */ - cached = 0; - - if (!cached || !NAND_HAS_CACHEPROG(chip)) { - - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - status = chip->waitfunc(mtd, chip); - /* - * See if operation failed and additional status checks are - * available. - */ - if ((status & NAND_STATUS_FAIL) && (chip->errstat)) - status = chip->errstat(mtd, chip, FL_WRITING, status, - page); - - if (status & NAND_STATUS_FAIL) - return -EIO; - } else { - chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1); - status = chip->waitfunc(mtd, chip); - } - return 0; } -/** - * nand_fill_oob - [INTERN] Transfer client buffer to oob - * @mtd: MTD device structure - * @oob: oob data buffer - * @len: oob data write length - * @ops: oob ops structure - */ -static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len, - struct mtd_oob_ops *ops) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - - /* - * Initialise to all 0xFF, to avoid the possibility of left over OOB - * data from a previous OOB read. - */ - memset(chip->oob_poi, 0xff, mtd->oobsize); - - switch (ops->mode) { - - case MTD_OPS_PLACE_OOB: - case MTD_OPS_RAW: - memcpy(chip->oob_poi + ops->ooboffs, oob, len); - return oob + len; - - case MTD_OPS_AUTO_OOB: { - struct nand_oobfree *free = chip->ecc.layout->oobfree; - uint32_t boffs = 0, woffs = ops->ooboffs; - size_t bytes = 0; - - for (; free->length && len; free++, len -= bytes) { - /* Write request not from offset 0? */ - if (unlikely(woffs)) { - if (woffs >= free->length) { - woffs -= free->length; - continue; - } - boffs = free->offset + woffs; - bytes = min_t(size_t, len, - (free->length - woffs)); - woffs = 0; - } else { - bytes = min_t(size_t, len, free->length); - boffs = free->offset; - } - memcpy(chip->oob_poi + boffs, oob, bytes); - oob += bytes; - } - return oob; - } - default: - BUG(); - } - return NULL; -} - #define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0) /** * nand_do_write_ops - [INTERN] NAND write with ECC - * @mtd: MTD device structure + * @chip: NAND chip object * @to: offset to write to * @ops: oob operations description structure * * NAND write with ECC. */ -static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, +static int nand_do_write_ops(struct nand_chip *chip, loff_t to, struct mtd_oob_ops *ops) { - int chipnr, realpage, page, blockmask, column; - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); + int chipnr, realpage, page, column; uint32_t writelen = ops->len; uint32_t oobwritelen = ops->ooblen; - uint32_t oobmaxlen = ops->mode == MTD_OPS_AUTO_OOB ? - mtd->oobavail : mtd->oobsize; + uint32_t oobmaxlen = mtd_oobavail(mtd, ops); uint8_t *oob = ops->oobbuf; uint8_t *buf = ops->datbuf; int ret; int oob_required = oob ? 1 : 0; - if (!IS_ENABLED(CONFIG_MTD_WRITE)) - return -ENOTSUPP; - ops->retlen = 0; if (!writelen) return 0; + /* Reject writes, which are not page aligned */ + if (NOTALIGNED(to) || NOTALIGNED(ops->len)) { + pr_notice("%s: attempt to write non page aligned data\n", + __func__); + return -EINVAL; + } + column = to & (mtd->writesize - 1); chipnr = (int)(to >> chip->chip_shift); - chip->select_chip(mtd, chipnr); + nand_select_target(chip, chipnr); /* Check, if it is write protected */ - if (nand_check_wp(mtd)) { + if (nand_check_wp(chip)) { ret = -EIO; goto err_out; } realpage = (int)(to >> chip->page_shift); page = realpage & chip->pagemask; - blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; /* Invalidate the page cache, when we write to the cached page */ - if (to <= (chip->pagebuf << chip->page_shift) && - (chip->pagebuf << chip->page_shift) < (to + ops->len)) - chip->pagebuf = -1; + if (to <= ((loff_t)chip->pagecache.page << chip->page_shift) && + ((loff_t)chip->pagecache.page << chip->page_shift) < (to + ops->len)) + chip->pagecache.page = -1; /* Don't allow multipage oob writes with offset */ if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) { @@ -2425,35 +4064,46 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, while (1) { int bytes = mtd->writesize; - int cached = writelen > bytes && page != blockmask; uint8_t *wbuf = buf; + int use_bounce_buf; + int part_pagewr = (column || writelen < mtd->writesize); + + if (part_pagewr) + use_bounce_buf = 1; + else if (chip->options & NAND_USES_DMA) + use_bounce_buf = !IS_ALIGNED((unsigned long)buf, + chip->buf_align); + else + use_bounce_buf = 0; - /* Partial page write? */ - if (unlikely(column || writelen < (mtd->writesize - 1))) { - cached = 0; - bytes = min_t(int, bytes - column, (int) writelen); - chip->pagebuf = -1; - memset(chip->buffers->databuf, 0xff, mtd->writesize); - memcpy(&chip->buffers->databuf[column], buf, bytes); - wbuf = chip->buffers->databuf; + /* + * Copy the data from the initial buffer when doing partial page + * writes or when a bounce buffer is required. + */ + if (use_bounce_buf) { + pr_debug("%s: using write bounce buffer for buf@%p\n", + __func__, buf); + if (part_pagewr) + bytes = min_t(int, bytes - column, writelen); + wbuf = nand_get_data_buf(chip); + memset(wbuf, 0xff, mtd->writesize); + memcpy(&wbuf[column], buf, bytes); } if (unlikely(oob)) { size_t len = min(oobwritelen, oobmaxlen); - oob = nand_fill_oob(mtd, oob, len, ops); + oob = nand_fill_oob(chip, oob, len, ops); oobwritelen -= len; } else { /* We still need to erase leftover OOB data */ memset(chip->oob_poi, 0xff, mtd->oobsize); } - if (oob || !mtd_buf_all_ff(wbuf, mtd->writesize)) { - ret = chip->write_page(mtd, chip, column, bytes, wbuf, - oob_required, page, cached, - (ops->mode == MTD_OPS_RAW)); - if (ret) - break; - } + ret = nand_write_page(chip, column, bytes, wbuf, + oob_required, page, + (ops->mode == MTD_OPS_RAW)); + if (ret) + break; writelen -= bytes; if (!writelen) @@ -2467,8 +4117,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, /* Check, if we cross a chip boundary */ if (!page) { chipnr++; - chip->select_chip(mtd, -1); - chip->select_chip(mtd, chipnr); + nand_deselect_target(chip); + nand_select_target(chip, chipnr); } } @@ -2477,130 +4127,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, ops->oobretlen = ops->ooblen; err_out: - chip->select_chip(mtd, -1); - return ret; -} - -/** - * nand_write - [MTD Interface] NAND write with ECC - * @mtd: MTD device structure - * @to: offset to write to - * @len: number of bytes to write - * @retlen: pointer to variable to store the number of written bytes - * @buf: the data to write - * - * NAND write with ECC. - */ -static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const uint8_t *buf) -{ - struct mtd_oob_ops ops; - int ret; - - if (!IS_ENABLED(CONFIG_MTD_WRITE)) - return -ENOTSUPP; - - nand_get_device(mtd, FL_WRITING); - ops.len = len; - ops.datbuf = (uint8_t *)buf; - ops.oobbuf = NULL; - ops.mode = MTD_OPS_PLACE_OOB; - ret = nand_do_write_ops(mtd, to, &ops); - *retlen = ops.retlen; - nand_release_device(mtd); + nand_deselect_target(chip); return ret; } /** - * nand_do_write_oob - [MTD Interface] NAND write out-of-band - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operation description structure - * - * NAND write out-of-band. - */ -static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, - struct mtd_oob_ops *ops) -{ - int chipnr, page, status, len; - struct nand_chip *chip = mtd_to_nand(mtd); - - if (!IS_ENABLED(CONFIG_MTD_WRITE)) - return -ENOTSUPP; - - pr_debug("%s: to = 0x%08x, len = %i\n", - __func__, (unsigned int)to, (int)ops->ooblen); - - if (ops->mode == MTD_OPS_AUTO_OOB) - len = chip->ecc.layout->oobavail; - else - len = mtd->oobsize; - - /* Do not allow write past end of page */ - if ((ops->ooboffs + ops->ooblen) > len) { - pr_debug("%s: attempt to write past end of page\n", - __func__); - return -EINVAL; - } - - if (unlikely(ops->ooboffs >= len)) { - pr_debug("%s: attempt to start write outside oob\n", - __func__); - return -EINVAL; - } - - /* Do not allow write past end of device */ - if (unlikely(to >= mtd->size || - ops->ooboffs + ops->ooblen > - ((mtd->size >> chip->page_shift) - - (to >> chip->page_shift)) * len)) { - pr_debug("%s: attempt to write beyond end of device\n", - __func__); - return -EINVAL; - } - - chipnr = (int)(to >> chip->chip_shift); - chip->select_chip(mtd, chipnr); - - /* Shift to get page */ - page = (int)(to >> chip->page_shift); - - /* - * Reset the chip. Some chips (like the Toshiba TC5832DC found in one - * of my DiskOnChip 2000 test units) will clear the whole data page too - * if we don't do this. I have no clue why, but I seem to have 'fixed' - * it in the doc2000 driver in August 1999. dwmw2. - */ - chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); - - /* Check, if it is write protected */ - if (nand_check_wp(mtd)) { - chip->select_chip(mtd, -1); - return -EROFS; - } - - /* Invalidate the page cache, if we write to the cached page */ - if (page == chip->pagebuf) - chip->pagebuf = -1; - - nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops); - - if (ops->mode == MTD_OPS_RAW) - status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask); - else - status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); - - chip->select_chip(mtd, -1); - - if (status) - return status; - - ops->oobretlen = ops->ooblen; - - return 0; -} - -/** * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band * @mtd: MTD device structure * @to: offset to write to @@ -2609,21 +4140,14 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, static int nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { - int ret = -ENOTSUPP; - - if (!IS_ENABLED(CONFIG_MTD_WRITE)) - return -ENOTSUPP; + struct nand_chip *chip = mtd_to_nand(mtd); + int ret; ops->retlen = 0; - /* Do not allow writes past end of device */ - if (ops->datbuf && (to + ops->len) > mtd->size) { - pr_debug("%s: attempt to write beyond end of device\n", - __func__); - return -EINVAL; - } - - nand_get_device(mtd, FL_WRITING); + ret = nand_get_device(chip); + if (ret) + return ret; switch (ops->mode) { case MTD_OPS_PLACE_OOB: @@ -2636,35 +4160,16 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, } if (!ops->datbuf) - ret = nand_do_write_oob(mtd, to, ops); + ret = nand_do_write_oob(chip, to, ops); else - ret = nand_do_write_ops(mtd, to, ops); + ret = nand_do_write_ops(chip, to, ops); out: - nand_release_device(mtd); + nand_release_device(chip); return ret; } /** - * single_erase_cmd - [GENERIC] NAND standard block erase command function - * @mtd: MTD device structure - * @page: the page address of the block which will be erased - * - * Standard erase command for NAND chips. - */ -static void single_erase_cmd(struct mtd_info *mtd, int page) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - - if (!IS_ENABLED(CONFIG_MTD_WRITE)) - return; - - /* Send commands to erase a block */ - chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); - chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); -} - -/** * nand_erase - [MTD Interface] erase block(s) * @mtd: MTD device structure * @instr: erase instruction @@ -2673,39 +4178,36 @@ static void single_erase_cmd(struct mtd_info *mtd, int page) */ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) { - if (!IS_ENABLED(CONFIG_MTD_WRITE)) - return -ENOTSUPP; - - return nand_erase_nand(mtd, instr, 0); + return nand_erase_nand(mtd_to_nand(mtd), instr, 0); } /** * nand_erase_nand - [INTERN] erase block(s) - * @mtd: MTD device structure + * @chip: NAND chip object * @instr: erase instruction * @allowbbt: allow erasing the bbt area * * Erase one ore more blocks. */ -int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, +int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, int allowbbt) { - int page, status, pages_per_block, ret, chipnr; - struct nand_chip *chip = mtd_to_nand(mtd); - loff_t len; + struct mtd_info *mtd = nand_to_mtd(chip); - if (!IS_ENABLED(CONFIG_MTD_WRITE)) - return -ENOTSUPP; + int page, pages_per_block, ret, chipnr; + loff_t len; pr_debug("%s: start = 0x%012llx, len = %llu\n", __func__, (unsigned long long)instr->addr, (unsigned long long)instr->len); - if (check_offs_len(mtd, instr->addr, instr->len)) + if (check_offs_len(chip, instr->addr, instr->len)) return -EINVAL; /* Grab the lock and see if the device is available */ - nand_get_device(mtd, FL_ERASING); + ret = nand_get_device(chip); + if (ret) + return ret; /* Shift to get first page */ page = (int)(instr->addr >> chip->page_shift); @@ -2715,29 +4217,27 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); /* Select the NAND device */ - chip->select_chip(mtd, chipnr); + nand_select_target(chip, chipnr); /* Check, if it is write protected */ - if (nand_check_wp(mtd)) { + if (nand_check_wp(chip)) { pr_debug("%s: device is write protected!\n", __func__); - instr->state = MTD_ERASE_FAILED; + ret = -EIO; goto erase_exit; } /* Loop through the pages */ len = instr->len; - instr->state = MTD_ERASING; - while (len) { /* Check if we have a bad block, we do not erase bad blocks! */ if (!mtd->allow_erasebad && - nand_block_checkbad(mtd, ((loff_t) page) << - chip->page_shift, 0, allowbbt)) { + nand_block_checkbad(chip, ((loff_t) page) << + chip->page_shift, allowbbt)) { pr_warn("%s: attempt to erase a bad block at page 0x%08x\n", __func__, page); - instr->state = MTD_ERASE_FAILED; + ret = -EIO; goto erase_exit; } @@ -2745,56 +4245,38 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, * Invalidate the page cache, if we erase the block which * contains the current cached page. */ - if (page <= chip->pagebuf && chip->pagebuf < + if (page <= chip->pagecache.page && chip->pagecache.page < (page + pages_per_block)) - chip->pagebuf = -1; - - chip->erase_cmd(mtd, page & chip->pagemask); - - status = chip->waitfunc(mtd, chip); + chip->pagecache.page = -1; - /* - * See if operation failed and additional status checks are - * available - */ - if ((status & NAND_STATUS_FAIL) && (chip->errstat)) - status = chip->errstat(mtd, chip, FL_ERASING, - status, page); - - /* See if block erase succeeded */ - if (status & NAND_STATUS_FAIL) { + ret = nand_erase_op(chip, (page & chip->pagemask) >> + (chip->phys_erase_shift - chip->page_shift)); + if (ret) { pr_debug("%s: failed erase, page 0x%08x\n", __func__, page); - instr->state = MTD_ERASE_FAILED; instr->fail_addr = ((loff_t)page << chip->page_shift); goto erase_exit; } /* Increment page address and decrement length */ - len -= (1 << chip->phys_erase_shift); + len -= (1ULL << chip->phys_erase_shift); page += pages_per_block; /* Check, if we cross a chip boundary */ if (len && !(page & chip->pagemask)) { chipnr++; - chip->select_chip(mtd, -1); - chip->select_chip(mtd, chipnr); + nand_deselect_target(chip); + nand_select_target(chip, chipnr); } } - instr->state = MTD_ERASE_DONE; + ret = 0; erase_exit: - ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; - /* Deselect and wake up anyone waiting on the device */ - chip->select_chip(mtd, -1); - nand_release_device(mtd); - - /* Do call back function */ - if (!ret) - mtd_erase_callback(instr); + nand_deselect_target(chip); + nand_release_device(chip); /* Return more or less happy */ return ret; @@ -2808,12 +4290,14 @@ erase_exit: */ static void nand_sync(struct mtd_info *mtd) { + struct nand_chip *chip = mtd_to_nand(mtd); + pr_debug("%s: called\n", __func__); /* Grab the lock and see if the device is available */ - nand_get_device(mtd, FL_SYNCING); + WARN_ON(nand_get_device(chip)); /* Release it and go back */ - nand_release_device(mtd); + nand_release_device(chip); } /** @@ -2823,7 +4307,23 @@ static void nand_sync(struct mtd_info *mtd) */ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) { - return nand_block_checkbad(mtd, offs, 1, 0); + struct nand_chip *chip = mtd_to_nand(mtd); + int chipnr = (int)(offs >> chip->chip_shift); + int ret; + + /* Select the NAND device */ + ret = nand_get_device(chip); + if (ret) + return ret; + + nand_select_target(chip, chipnr); + + ret = nand_block_checkbad(chip, offs, 0); + + nand_deselect_target(chip); + nand_release_device(chip); + + return ret; } /** @@ -2835,9 +4335,6 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) { int ret; - if (!IS_ENABLED(CONFIG_MTD_WRITE)) - return -ENOTSUPP; - ret = nand_block_isbad(mtd, ofs); if (ret) { /* If it was bad already, return success and do nothing */ @@ -2846,11 +4343,11 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) return ret; } - return nand_block_markbad_lowlevel(mtd, ofs); + return nand_block_markbad_lowlevel(mtd_to_nand(mtd), ofs); } /** - * nand_block_markgood - [MTD Interface] Mark block at the given offset as good + * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad * @mtd: MTD device structure * @ofs: offset relative to mtd start */ @@ -2858,118 +4355,66 @@ static int nand_block_markgood(struct mtd_info *mtd, loff_t ofs) { int ret; - if (!IS_ENABLED(CONFIG_MTD_WRITE)) - return -ENOTSUPP; - ret = nand_block_isbad(mtd, ofs); if (ret < 0) return ret; - /* If it was good already, return success and do nothing */ if (!ret) + /* If it was good already, return success and do nothing */ return 0; - return nand_block_markgood_lowlevel(mtd, ofs); + return nand_block_markgood_lowlevel(mtd_to_nand(mtd), ofs); } /** - * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand + * nand_lock - [MTD Interface] Lock the NAND flash * @mtd: MTD device structure - * @chip: nand chip info structure - * @addr: feature address. - * @subfeature_param: the subfeature parameters, a four bytes array. + * @ofs: offset byte address + * @len: number of bytes to lock (must be a multiple of block/page size) */ -static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, - int addr, uint8_t *subfeature_param) +static int nand_lock(struct mtd_info *mtd, loff_t ofs, size_t len) { - int status; + struct nand_chip *chip = mtd_to_nand(mtd); - if (!chip->onfi_version || - !(le16_to_cpu(chip->onfi_params.opt_cmd) - & ONFI_OPT_CMD_SET_GET_FEATURES)) - return -EINVAL; + if (!chip->ops.lock_area) + return -ENOTSUPP; - chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1); - chip->write_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN); - status = chip->waitfunc(mtd, chip); - if (status & NAND_STATUS_FAIL) - return -EIO; - return 0; + return chip->ops.lock_area(chip, ofs, len); } /** - * nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand + * nand_unlock - [MTD Interface] Unlock the NAND flash * @mtd: MTD device structure - * @chip: nand chip info structure - * @addr: feature address. - * @subfeature_param: the subfeature parameters, a four bytes array. + * @ofs: offset byte address + * @len: number of bytes to unlock (must be a multiple of block/page size) */ -static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip, - int addr, uint8_t *subfeature_param) +static int nand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) { - if (!chip->onfi_version || - !(le16_to_cpu(chip->onfi_params.opt_cmd) - & ONFI_OPT_CMD_SET_GET_FEATURES)) - return -EINVAL; + struct nand_chip *chip = mtd_to_nand(mtd); - /* clear the sub feature parameters */ - memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN); + if (!chip->ops.unlock_area) + return -ENOTSUPP; - chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1); - chip->read_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN); - return 0; + return chip->ops.unlock_area(chip, ofs, len); } /* Set default functions */ -static void nand_set_defaults(struct nand_chip *chip, int busw) -{ - /* check for proper chip_delay setup, set 20us if not */ - if (!chip->chip_delay) - chip->chip_delay = 20; - - /* check, if a user supplied command function given */ - if (chip->cmdfunc == NULL) - chip->cmdfunc = nand_command; - - /* check, if a user supplied wait function given */ - if (chip->waitfunc == NULL) - chip->waitfunc = nand_wait; - - if (!chip->select_chip) - chip->select_chip = nand_select_chip; - - /* set for ONFI nand */ - if (!chip->onfi_set_features) - chip->onfi_set_features = nand_onfi_set_features; - if (!chip->onfi_get_features) - chip->onfi_get_features = nand_onfi_get_features; - - if (!chip->read_byte) - chip->read_byte = busw ? nand_read_byte16 : nand_read_byte; - if (!chip->read_word) - chip->read_word = nand_read_word; - if (!chip->block_bad) - chip->block_bad = nand_block_bad; -#ifdef CONFIG_MTD_WRITE - if (!chip->block_markbad) - chip->block_markbad = nand_default_block_markbad; - if (!chip->write_buf) - chip->write_buf = busw ? nand_write_buf16 : nand_write_buf; -#endif - if (!chip->read_buf) - chip->read_buf = busw ? nand_read_buf16 : nand_read_buf; -#ifdef CONFIG_NAND_BBT - if (!chip->scan_bbt) - chip->scan_bbt = nand_default_bbt; -#endif +static void nand_set_defaults(struct nand_chip *chip) +{ + /* If no controller is provided, use the dummy, legacy one. */ if (!chip->controller) { - chip->controller = &chip->hwcontrol; + chip->controller = &chip->legacy.dummy_controller; + nand_controller_init(chip->controller); } + nand_legacy_set_defaults(chip); + + if (!chip->buf_align) + chip->buf_align = 1; } /* Sanitize ONFI strings so we can safely print them */ -static void sanitize_string(uint8_t *s, size_t len) +void sanitize_string(uint8_t *s, size_t len) { ssize_t i; @@ -2986,86 +4431,6 @@ static void sanitize_string(uint8_t *s, size_t len) strim(s); } -static u16 onfi_crc16(u16 crc, u8 const *p, size_t len) -{ - int i; - while (len--) { - crc ^= *p++ << 8; - for (i = 0; i < 8; i++) - crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0); - } - - return crc; -} - -/* - * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. - */ -static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, - int *busw) -{ - struct nand_onfi_params *p = &chip->onfi_params; - int i, j; - int val; - - /* Try ONFI for unknown chip or LP */ - chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); - if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || - chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') - return 0; - - chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); - for (i = 0; i < 3; i++) { - for (j = 0; j < sizeof(*p); j++) - ((uint8_t *)p)[j] = chip->read_byte(mtd); - if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == - le16_to_cpu(p->crc)) { - break; - } - } - - if (i == 3) { - pr_err("Could not find valid ONFI parameter page; aborting\n"); - return 0; - } - - /* Check version */ - val = le16_to_cpu(p->revision); - if (val & (1 << 5)) - chip->onfi_version = 23; - else if (val & (1 << 4)) - chip->onfi_version = 22; - else if (val & (1 << 3)) - chip->onfi_version = 21; - else if (val & (1 << 2)) - chip->onfi_version = 20; - else if (val & (1 << 1)) - chip->onfi_version = 10; - - if (!chip->onfi_version) { - pr_info("%s: unsupported ONFI version: %d\n", __func__, val); - return 0; - } - - sanitize_string(p->manufacturer, sizeof(p->manufacturer)); - sanitize_string(p->model, sizeof(p->model)); - if (!mtd->name) - mtd->name = p->model; - mtd->writesize = le32_to_cpu(p->byte_per_page); - mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; - mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); - chip->chipsize = le32_to_cpu(p->blocks_per_lun); - chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; - chip->bits_per_cell = p->bits_per_cell; - - *busw = 0; - if (le16_to_cpu(p->features) & 1) - *busw = NAND_BUSWIDTH_16; - - pr_info("ONFI flash detected\n"); - return 1; -} - /* * nand_id_has_period - Check if an ID string has a given wraparound period * @id_data: the ID string @@ -3140,160 +4505,60 @@ static int nand_get_bits_per_cell(u8 cellinfo) * 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) +void nand_decode_ext_id(struct nand_chip *chip) { - int extid, id_len; + struct nand_memory_organization *memorg; + struct mtd_info *mtd = nand_to_mtd(chip); + int extid; + u8 *id_data = chip->id.data; + + memorg = nanddev_get_memorg(&chip->base); + /* The 3rd id byte holds MLC / multichip data */ - chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]); + memorg->bits_per_cell = nand_get_bits_per_cell(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 && - !nand_is_slc(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: - 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 && - !nand_is_slc(chip)) { - 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; - /* - * 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 && - nand_is_slc(chip) && - (id_data[5] & 0x7) == 0x6 /* 24nm */ && - !(id_data[4] & 0x80) /* !BENAND */) { - mtd->oobsize = 32 * mtd->writesize >> 9; - } - } + /* Calc pagesize */ + memorg->pagesize = 1024 << (extid & 0x03); + mtd->writesize = memorg->pagesize; + extid >>= 2; + /* Calc oobsize */ + memorg->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9); + mtd->oobsize = memorg->oobsize; + extid >>= 2; + /* Calc blocksize. Blocksize is multiples of 64KiB */ + memorg->pages_per_eraseblock = ((64 * 1024) << (extid & 0x03)) / + memorg->pagesize; + mtd->erasesize = (64 * 1024) << (extid & 0x03); + extid >>= 2; + /* Get buswidth information */ + if (extid & 0x1) + chip->options |= NAND_BUSWIDTH_16; } +EXPORT_SYMBOL_GPL(nand_decode_ext_id); /* * 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) +static void nand_decode_id(struct nand_chip *chip, struct nand_flash_dev *type) { - int maf_id = id_data[0]; + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; + + memorg = nanddev_get_memorg(&chip->base); + memorg->pages_per_eraseblock = type->erasesize / type->pagesize; mtd->erasesize = type->erasesize; - mtd->writesize = type->pagesize; - mtd->oobsize = mtd->writesize / 32; - *busw = type->options & NAND_BUSWIDTH_16; + memorg->pagesize = type->pagesize; + mtd->writesize = memorg->pagesize; + memorg->oobsize = memorg->pagesize / 32; + mtd->oobsize = memorg->oobsize; /* All legacy ID NAND are small-page, SLC */ - chip->bits_per_cell = 1; - - /* - * 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); - } + memorg->bits_per_cell = 1; } /* @@ -3301,36 +4566,15 @@ static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip, * 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]) +static void nand_decode_bbm_options(struct nand_chip *chip) { - int maf_id = id_data[0]; + struct mtd_info *mtd = nand_to_mtd(chip); /* Set the bad block position */ if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16)) - chip->badblockpos = NAND_LARGE_BADBLOCK_POS; + chip->badblockpos = NAND_BBM_POS_LARGE; 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 (!nand_is_slc(chip) && - (maf_id == NAND_MFR_SAMSUNG || - 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_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; + chip->badblockpos = NAND_BBM_POS_SMALL; } static inline bool is_full_id_nand(struct nand_flash_dev *type) @@ -3338,19 +4582,36 @@ static inline bool is_full_id_nand(struct nand_flash_dev *type) return type->id_len; } -static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, - struct nand_flash_dev *type, u8 *id_data, int *busw) +static bool find_full_id_nand(struct nand_chip *chip, + struct nand_flash_dev *type) { + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; + u8 *id_data = chip->id.data; + + memorg = nanddev_get_memorg(&chip->base); + if (!strncmp(type->id, id_data, type->id_len)) { - mtd->writesize = type->pagesize; + memorg->pagesize = type->pagesize; + mtd->writesize = memorg->pagesize; + memorg->pages_per_eraseblock = type->erasesize / + type->pagesize; mtd->erasesize = type->erasesize; - mtd->oobsize = type->oobsize; - - chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]); - chip->chipsize = (uint64_t)type->chipsize << 20; + memorg->oobsize = type->oobsize; + mtd->oobsize = memorg->oobsize; + + memorg->bits_per_cell = nand_get_bits_per_cell(id_data[2]); + memorg->eraseblocks_per_lun = + DIV_ROUND_DOWN_ULL((u64)type->chipsize << 20, + memorg->pagesize * + memorg->pages_per_eraseblock); chip->options |= type->options; + chip->base.eccreq.strength = NAND_ECC_STRENGTH(type); + chip->base.eccreq.step_size = NAND_ECC_STEP(type); - *busw = type->options & NAND_BUSWIDTH_16; + chip->parameters.model = strdup(type->name); + if (!chip->parameters.model) + return false; return true; } @@ -3358,32 +4619,105 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, } /* + * Manufacturer detection. Only used when the NAND is not ONFI or JEDEC + * compliant and does not have a full-id or legacy-id entry in the nand_ids + * table. + */ +static void nand_manufacturer_detect(struct nand_chip *chip) +{ + /* + * Try manufacturer detection if available and use + * nand_decode_ext_id() otherwise. + */ + if (chip->manufacturer.desc && chip->manufacturer.desc->ops && + chip->manufacturer.desc->ops->detect) { + struct nand_memory_organization *memorg; + + memorg = nanddev_get_memorg(&chip->base); + + /* The 3rd id byte holds MLC / multichip data */ + memorg->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]); + chip->manufacturer.desc->ops->detect(chip); + } else { + nand_decode_ext_id(chip); + } +} + +/* + * Manufacturer initialization. This function is called for all NANDs including + * ONFI and JEDEC compliant ones. + * Manufacturer drivers should put all their specific initialization code in + * their ->init() hook. + */ +static int nand_manufacturer_init(struct nand_chip *chip) +{ + if (!chip->manufacturer.desc || !chip->manufacturer.desc->ops || + !chip->manufacturer.desc->ops->init) + return 0; + + return chip->manufacturer.desc->ops->init(chip); +} + +/* + * Manufacturer cleanup. This function is called for all NANDs including + * ONFI and JEDEC compliant ones. + * Manufacturer drivers should put all their specific cleanup code in their + * ->cleanup() hook. + */ +static void nand_manufacturer_cleanup(struct nand_chip *chip) +{ + /* Release manufacturer private data */ + if (chip->manufacturer.desc && chip->manufacturer.desc->ops && + chip->manufacturer.desc->ops->cleanup) + chip->manufacturer.desc->ops->cleanup(chip); +} + +static const char * +nand_manufacturer_name(const struct nand_manufacturer_desc *manufacturer_desc) +{ + return manufacturer_desc ? manufacturer_desc->name : "Unknown"; +} + +/* * 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, - struct nand_chip *chip, - int busw, - int *maf_id, int *dev_id, - struct nand_flash_dev *type) +static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) { - int i, maf_idx; - u8 id_data[8]; + const struct nand_manufacturer_desc *manufacturer_desc; + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; + int busw, ret; + u8 *id_data = chip->id.data; + u8 maf_id, dev_id; + u64 targetsize; - /* Select the device */ - chip->select_chip(mtd, 0); + /* + * Let's start by initializing memorg fields that might be left + * unassigned by the ID-based detection logic. + */ + memorg = nanddev_get_memorg(&chip->base); + memorg->planes_per_lun = 1; + memorg->luns_per_target = 1; /* * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) * after power-up. */ - chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + ret = nand_reset(chip, 0); + if (ret) + return ret; + + /* Select the device */ + nand_select_target(chip, 0); /* Send the command for reading device ID */ - chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + ret = nand_readid_op(chip, 0, id_data, 2); + if (ret) + return ret; /* Read manufacturer and device IDs */ - *maf_id = chip->read_byte(mtd); - *dev_id = chip->read_byte(mtd); + maf_id = id_data[0]; + dev_id = id_data[1]; /* * Try again to make sure, as some systems the bus-hold or other @@ -3392,434 +4726,984 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, * not match, ignore the device completely. */ - 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); + ret = nand_readid_op(chip, 0, id_data, sizeof(chip->id.data)); + if (ret) + return ret; - if (id_data[0] != *maf_id || id_data[1] != *dev_id) { - pr_info("%s: second ID read did not match " - "%02x,%02x against %02x,%02x\n", __func__, - *maf_id, *dev_id, id_data[0], id_data[1]); - return ERR_PTR(-ENODEV); + if (id_data[0] != maf_id || id_data[1] != dev_id) { + pr_info("second ID read did not match %02x,%02x against %02x,%02x\n", + maf_id, dev_id, id_data[0], id_data[1]); + return -ENODEV; } + chip->id.len = nand_id_len(id_data, ARRAY_SIZE(chip->id.data)); + + /* Try to identify manufacturer */ + manufacturer_desc = nand_get_manufacturer_desc(maf_id); + chip->manufacturer.desc = manufacturer_desc; + if (!type) type = nand_flash_ids; + /* + * Save the NAND_BUSWIDTH_16 flag before letting auto-detection logic + * override it. + * This is required to make sure initial NAND bus width set by the + * NAND controller driver is coherent with the real NAND bus width + * (extracted by auto-detection code). + */ + busw = chip->options & NAND_BUSWIDTH_16; + + /* + * The flag is only set (never cleared), reset it to its default value + * before starting auto-detection. + */ + chip->options &= ~NAND_BUSWIDTH_16; + for (; type->name != NULL; type++) { if (is_full_id_nand(type)) { - if (find_full_id_nand(mtd, chip, type, id_data, &busw)) + if (find_full_id_nand(chip, type)) goto ident_done; - } else if (*dev_id == type->dev_id) { - break; + } else if (dev_id == type->dev_id) { + break; } } - chip->onfi_version = 0; if (!type->name || !type->pagesize) { - /* Check is chip is ONFI compliant */ - if (nand_flash_detect_onfi(mtd, chip, &busw)) + /* Check if the chip is ONFI compliant */ + ret = nand_onfi_detect(chip); + if (ret < 0) + return ret; + else if (ret) + goto ident_done; + + /* Check if the chip is JEDEC compliant */ + ret = nand_jedec_detect(chip); + if (ret < 0) + return ret; + else if (ret) goto ident_done; } if (!type->name) - return ERR_PTR(-ENODEV); + return -ENODEV; - if (!mtd->name) - mtd->name = type->name; + chip->parameters.model = strdup(type->name); + if (!chip->parameters.model) + return -ENOMEM; - chip->chipsize = (uint64_t)type->chipsize << 20; + if (!type->pagesize) + nand_manufacturer_detect(chip); + else + nand_decode_id(chip, type); - if (!type->pagesize && chip->init_size) { - /* 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); - } else { - nand_decode_id(mtd, chip, type, id_data, &busw); - } /* 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: + memorg->eraseblocks_per_lun = + DIV_ROUND_DOWN_ULL((u64)type->chipsize << 20, + memorg->pagesize * + memorg->pages_per_eraseblock); - /* Try to identify manufacturer */ - for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { - if (nand_manuf_ids[maf_idx].id == *maf_id) - break; - } +ident_done: + if (!mtd->name) + mtd->name = strdup(chip->parameters.model); if (chip->options & NAND_BUSWIDTH_AUTO) { - WARN_ON(chip->options & NAND_BUSWIDTH_16); - chip->options |= busw; - nand_set_defaults(chip, busw); + WARN_ON(busw & NAND_BUSWIDTH_16); + nand_set_defaults(chip); } else if (busw != (chip->options & NAND_BUSWIDTH_16)) { /* * Check, if buswidth is correct. Hardware drivers should set * chip correct! */ - pr_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); - pr_warn("NAND bus width %d instead %d bit\n", - (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, - busw ? 16 : 8); - return ERR_PTR(-EINVAL); + pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", + maf_id, dev_id); + pr_info("%s %s\n", nand_manufacturer_name(manufacturer_desc), + mtd->name); + pr_warn("bus width %d instead of %d bits\n", busw ? 16 : 8, + (chip->options & NAND_BUSWIDTH_16) ? 16 : 8); + ret = -EINVAL; + + goto free_detect_allocation; } - nand_decode_bbm_options(mtd, chip, id_data); + nand_decode_bbm_options(chip); /* Calculate the address shift from the page size */ chip->page_shift = ffs(mtd->writesize) - 1; /* Convert chipsize to number of pages per chip -1 */ - chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; + targetsize = nanddev_target_size(&chip->base); + chip->pagemask = (targetsize >> chip->page_shift) - 1; chip->bbt_erase_shift = chip->phys_erase_shift = ffs(mtd->erasesize) - 1; - if (chip->chipsize & 0xffffffff) - chip->chip_shift = ffs((unsigned)chip->chipsize) - 1; + if (targetsize & 0xffffffff) + chip->chip_shift = ffs((unsigned)targetsize) - 1; else { - chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)); + chip->chip_shift = ffs((unsigned)(targetsize >> 32)); chip->chip_shift += 32 - 1; } + if (chip->chip_shift - chip->page_shift > 16) + chip->options |= NAND_ROW_ADDR_3; + chip->badblockbits = 8; - chip->erase_cmd = single_erase_cmd; - /* Do not replace user supplied command function! */ - if (mtd->writesize > 512 && chip->cmdfunc == nand_command) - chip->cmdfunc = nand_command_lp; + nand_legacy_adjust_cmdfunc(chip); + + pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", + maf_id, dev_id); + pr_info("%s %s\n", nand_manufacturer_name(manufacturer_desc), + chip->parameters.model); + pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n", + (int)(targetsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC", + mtd->erasesize >> 10, mtd->writesize, mtd->oobsize); + return 0; - pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s)," - " %dMiB, page size: %d, OOB size: %d\n", - *maf_id, *dev_id, nand_manuf_ids[maf_idx].name, - chip->onfi_version ? chip->onfi_params.model : type->name, - (int)(chip->chipsize >> 20), mtd->writesize, mtd->oobsize); +free_detect_allocation: + kfree(chip->parameters.model); - return type; + return ret; } -/** - * nand_of_parse_node - parse generic NAND properties - * @mtd: MTD device structure - * @np: Device node to read information from - * - * This parses device tree properties generic to NAND controllers and fills in - * the various fields in struct nand_chip. - */ -void nand_of_parse_node(struct mtd_info *mtd, struct device_node *np) +static const char * const nand_ecc_algos[] = { + [NAND_ECC_HAMMING] = "hamming", + [NAND_ECC_BCH] = "bch", + [NAND_ECC_RS] = "rs", +}; + +static enum nand_ecc_algo of_get_nand_ecc_algo(struct device_node *np) { - struct nand_chip *chip = mtd_to_nand(mtd); - int ecc_strength, ecc_size; + enum nand_ecc_algo ecc_algo; + const char *pm; + int err; + + err = of_property_read_string(np, "nand-ecc-algo", &pm); + if (!err) { + for (ecc_algo = NAND_ECC_HAMMING; + ecc_algo < ARRAY_SIZE(nand_ecc_algos); + ecc_algo++) { + if (!strcasecmp(pm, nand_ecc_algos[ecc_algo])) + return ecc_algo; + } + } - if (!IS_ENABLED(CONFIG_OFDEVICE)) - return; + /* + * For backward compatibility we also read "nand-ecc-mode" checking + * for some obsoleted values that were specifying ECC algorithm. + */ + err = of_property_read_string(np, "nand-ecc-mode", &pm); + if (!err) { + if (!strcasecmp(pm, "soft")) + return NAND_ECC_HAMMING; + else if (!strcasecmp(pm, "soft_bch")) + return NAND_ECC_BCH; + } + + return NAND_ECC_UNKNOWN; +} - ecc_strength = of_get_nand_ecc_strength(np); - ecc_size = of_get_nand_ecc_step_size(np); +static int nand_dt_init(struct nand_chip *chip) +{ + struct device_node *dn = nand_get_flash_node(chip); + enum nand_ecc_algo ecc_algo; + int ecc_mode, ecc_strength, ecc_step; + + if (!dn) + return 0; + + if (of_get_nand_bus_width(dn) == 16) + chip->options |= NAND_BUSWIDTH_16; + + if (of_property_read_bool(dn, "nand-is-boot-medium")) + chip->options |= NAND_IS_BOOT_MEDIUM; + + if (of_get_nand_on_flash_bbt(dn)) + chip->bbt_options |= NAND_BBT_USE_FLASH; + + ecc_mode = of_get_nand_ecc_mode(dn); + ecc_algo = of_get_nand_ecc_algo(dn); + ecc_strength = of_get_nand_ecc_strength(dn); + ecc_step = of_get_nand_ecc_step_size(dn); + + if (ecc_mode >= 0) + chip->ecc.mode = ecc_mode; + + if (ecc_algo != NAND_ECC_UNKNOWN) + chip->ecc.algo = ecc_algo; if (ecc_strength >= 0) chip->ecc.strength = ecc_strength; - if (ecc_size >= 0) - chip->ecc.size = ecc_size; + if (ecc_step > 0) + chip->ecc.size = ecc_step; + + if (of_property_read_bool(dn, "nand-ecc-maximize")) + chip->ecc.options |= NAND_ECC_MAXIMIZE; + + return 0; } /** - * nand_scan_ident - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure + * nand_scan_ident - Scan for the NAND device + * @chip: NAND chip object * @maxchips: number of chips to scan for * @table: alternative NAND ID table * * This is the first phase of the normal nand_scan() function. It reads the * flash ID and sets up MTD fields accordingly. * - * The mtd->owner field must be set to the module of the caller. + * This helper used to be called directly from controller drivers that needed + * to tweak some ECC-related parameters before nand_scan_tail(). This separation + * prevented dynamic allocations during this phase which was unconvenient and + * as been banned for the benefit of the ->init_ecc()/cleanup_ecc() hooks. */ -int nand_scan_ident(struct mtd_info *mtd, int maxchips, +int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, struct nand_flash_dev *table) { - int i, busw, nand_maf_id, nand_dev_id; - struct nand_chip *chip = mtd_to_nand(mtd); - struct nand_flash_dev *type; + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; + int nand_maf_id, nand_dev_id; + unsigned int i; + int ret; + + memorg = nanddev_get_memorg(&chip->base); + + /* Assume all dies are deselected when we enter nand_scan_ident(). */ + chip->cur_cs = -1; + + mutex_init(&chip->lock); + + /* Enforce the right timings for reset/detection */ + chip->current_interface_config = nand_get_reset_interface_config(); + + if (IS_ENABLED(CONFIG_OFTREE)) { + ret = nand_dt_init(chip); + if (ret) + return ret; + } + + if (!mtd->name && mtd->dev.parent) + mtd->name = strdup(dev_name(mtd->dev.parent)); - /* Get buswidth to select the correct functions */ - busw = chip->options & NAND_BUSWIDTH_16; /* Set the default functions */ - nand_set_defaults(chip, busw); + nand_set_defaults(chip); - /* Read the flash type */ - type = nand_get_flash_type(mtd, chip, busw, - &nand_maf_id, &nand_dev_id, table); + ret = nand_legacy_check_hooks(chip); + if (ret) + return ret; + + memorg->ntargets = maxchips; - if (IS_ERR(type)) { + /* Read the flash type */ + ret = nand_detect(chip, table); + if (ret) { if (!(chip->options & NAND_SCAN_SILENT_NODEV)) pr_warn("No NAND device found\n"); - chip->select_chip(mtd, -1); - return PTR_ERR(type); + nand_deselect_target(chip); + return ret; } - chip->select_chip(mtd, -1); + nand_maf_id = chip->id.data[0]; + nand_dev_id = chip->id.data[1]; + + nand_deselect_target(chip); /* Check for a chip array */ for (i = 1; i < maxchips; i++) { - chip->select_chip(mtd, i); + u8 id[2]; + /* See comment in nand_get_flash_type for reset */ - chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + ret = nand_reset(chip, i); + if (ret) + break; + + nand_select_target(chip, i); /* Send the command for reading device ID */ - chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + ret = nand_readid_op(chip, 0, id, sizeof(id)); + if (ret) + break; /* Read manufacturer and device IDs */ - if (nand_maf_id != chip->read_byte(mtd) || - nand_dev_id != chip->read_byte(mtd)) { - chip->select_chip(mtd, -1); + if (nand_maf_id != id[0] || nand_dev_id != id[1]) { + nand_deselect_target(chip); break; } - chip->select_chip(mtd, -1); + nand_deselect_target(chip); } if (i > 1) - pr_info("%d NAND chips detected\n", i); + pr_info("%d chips detected\n", i); /* Store the number of chips and calc total size for mtd */ - chip->numchips = i; - mtd->size = i * chip->chipsize; + memorg->ntargets = i; + mtd->size = i * nanddev_target_size(&chip->base); return 0; } -EXPORT_SYMBOL(nand_scan_ident); +static void nand_scan_ident_cleanup(struct nand_chip *chip) +{ + kfree(chip->parameters.model); + kfree(chip->parameters.onfi); +} + +static int nand_set_ecc_soft_ops(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; + + if (WARN_ON(ecc->mode != NAND_ECC_SOFT)) + return -EINVAL; + + switch (ecc->algo) { + case NAND_ECC_HAMMING: + ecc->calculate = nand_calculate_ecc; + ecc->correct = nand_correct_data; + ecc->read_page = nand_read_page_swecc; + ecc->read_subpage = nand_read_subpage; + ecc->write_page = nand_write_page_swecc; + if (!ecc->read_page_raw) + ecc->read_page_raw = nand_read_page_raw; + if (!ecc->write_page_raw) + ecc->write_page_raw = nand_write_page_raw; + ecc->read_oob = nand_read_oob_std; + ecc->write_oob = nand_write_oob_std; + if (!ecc->size) + ecc->size = 256; + ecc->bytes = 3; + ecc->strength = 1; + + if (IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)) + ecc->options |= NAND_ECC_SOFT_HAMMING_SM_ORDER; + + return 0; + case NAND_ECC_BCH: + if (!mtd_nand_has_bch()) { + WARN(1, "CONFIG_MTD_NAND_ECC_SW_BCH not enabled\n"); + return -EINVAL; + } + ecc->calculate = nand_bch_calculate_ecc; + ecc->correct = nand_bch_correct_data; + ecc->read_page = nand_read_page_swecc; + ecc->read_subpage = nand_read_subpage; + ecc->write_page = nand_write_page_swecc; + if (!ecc->read_page_raw) + ecc->read_page_raw = nand_read_page_raw; + if (!ecc->write_page_raw) + ecc->write_page_raw = nand_write_page_raw; + ecc->read_oob = nand_read_oob_std; + ecc->write_oob = nand_write_oob_std; + + /* + * Board driver should supply ecc.size and ecc.strength + * values to select how many bits are correctable. + * Otherwise, default to 4 bits for large page devices. + */ + if (!ecc->size && (mtd->oobsize >= 64)) { + ecc->size = 512; + ecc->strength = 4; + } + + /* + * if no ecc placement scheme was provided pickup the default + * large page one. + */ + if (!mtd->ooblayout) { + /* handle large page devices only */ + if (mtd->oobsize < 64) { + WARN(1, "OOB layout is required when using software BCH on small pages\n"); + return -EINVAL; + } + + mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); + + } + + /* + * We can only maximize ECC config when the default layout is + * used, otherwise we don't know how many bytes can really be + * used. + */ + if (mtd->ooblayout == &nand_ooblayout_lp_ops && + ecc->options & NAND_ECC_MAXIMIZE) { + int steps, bytes; + + /* Always prefer 1k blocks over 512bytes ones */ + ecc->size = 1024; + steps = mtd->writesize / ecc->size; + + /* Reserve 2 bytes for the BBM */ + bytes = (mtd->oobsize - 2) / steps; + ecc->strength = bytes * 8 / fls(8 * ecc->size); + } + + /* See nand_bch_init() for details. */ + ecc->bytes = 0; + ecc->priv = nand_bch_init(mtd); + if (!ecc->priv) { + WARN(1, "BCH ECC initialization failed!\n"); + return -EINVAL; + } + return 0; + default: + WARN(1, "Unsupported ECC algorithm!\n"); + return -EINVAL; + } +} /** - * nand_scan_tail - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure + * nand_check_ecc_caps - check the sanity of preset ECC settings + * @chip: nand chip info structure + * @caps: ECC caps info structure + * @oobavail: OOB size that the ECC engine can use + * + * When ECC step size and strength are already set, check if they are supported + * by the controller and the calculated ECC bytes fit within the chip's OOB. + * On success, the calculated ECC bytes is set. + */ +static int +nand_check_ecc_caps(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + const struct nand_ecc_step_info *stepinfo; + int preset_step = chip->ecc.size; + int preset_strength = chip->ecc.strength; + int ecc_bytes, nsteps = mtd->writesize / preset_step; + int i, j; + + for (i = 0; i < caps->nstepinfos; i++) { + stepinfo = &caps->stepinfos[i]; + + if (stepinfo->stepsize != preset_step) + continue; + + for (j = 0; j < stepinfo->nstrengths; j++) { + if (stepinfo->strengths[j] != preset_strength) + continue; + + ecc_bytes = caps->calc_ecc_bytes(preset_step, + preset_strength); + if (WARN_ONCE(ecc_bytes < 0, "%s: eccbytes < 0\n", __func__)) + return ecc_bytes; + + if (ecc_bytes * nsteps > oobavail) { + pr_err("ECC (step, strength) = (%d, %d) does not fit in OOB", + preset_step, preset_strength); + return -ENOSPC; + } + + chip->ecc.bytes = ecc_bytes; + + return 0; + } + } + + pr_err("ECC (step, strength) = (%d, %d) not supported on this controller", + preset_step, preset_strength); + + return -ENOTSUPP; +} + +/** + * nand_match_ecc_req - meet the chip's requirement with least ECC bytes + * @chip: nand chip info structure + * @caps: ECC engine caps info structure + * @oobavail: OOB size that the ECC engine can use + * + * If a chip's ECC requirement is provided, try to meet it with the least + * number of ECC bytes (i.e. with the largest number of OOB-free bytes). + * On success, the chosen ECC settings are set. + */ +static int +nand_match_ecc_req(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + const struct nand_ecc_step_info *stepinfo; + int req_step = chip->base.eccreq.step_size; + int req_strength = chip->base.eccreq.strength; + int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total; + int best_step, best_strength, best_ecc_bytes; + int best_ecc_bytes_total = INT_MAX; + int i, j; + + /* No information provided by the NAND chip */ + if (!req_step || !req_strength) + return -ENOTSUPP; + + /* number of correctable bits the chip requires in a page */ + req_corr = mtd->writesize / req_step * req_strength; + + for (i = 0; i < caps->nstepinfos; i++) { + stepinfo = &caps->stepinfos[i]; + step_size = stepinfo->stepsize; + + for (j = 0; j < stepinfo->nstrengths; j++) { + strength = stepinfo->strengths[j]; + + /* + * If both step size and strength are smaller than the + * chip's requirement, it is not easy to compare the + * resulted reliability. + */ + if (step_size < req_step && strength < req_strength) + continue; + + if (mtd->writesize % step_size) + continue; + + nsteps = mtd->writesize / step_size; + + ecc_bytes = caps->calc_ecc_bytes(step_size, strength); + if (WARN_ONCE(ecc_bytes < 0, "%s: eccbytes < 0\n", __func__)) + continue; + ecc_bytes_total = ecc_bytes * nsteps; + + if (ecc_bytes_total > oobavail || + strength * nsteps < req_corr) + continue; + + /* + * We assume the best is to meet the chip's requrement + * with the least number of ECC bytes. + */ + if (ecc_bytes_total < best_ecc_bytes_total) { + best_ecc_bytes_total = ecc_bytes_total; + best_step = step_size; + best_strength = strength; + best_ecc_bytes = ecc_bytes; + } + } + } + + if (best_ecc_bytes_total == INT_MAX) + return -ENOTSUPP; + + chip->ecc.size = best_step; + chip->ecc.strength = best_strength; + chip->ecc.bytes = best_ecc_bytes; + + return 0; +} + +/** + * nand_maximize_ecc - choose the max ECC strength available + * @chip: nand chip info structure + * @caps: ECC engine caps info structure + * @oobavail: OOB size that the ECC engine can use + * + * Choose the max ECC strength that is supported on the controller, and can fit + * within the chip's OOB. On success, the chosen ECC settings are set. + */ +static int +nand_maximize_ecc(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + const struct nand_ecc_step_info *stepinfo; + int step_size, strength, nsteps, ecc_bytes, corr; + int best_corr = 0; + int best_step = 0; + int best_strength, best_ecc_bytes; + int i, j; + + for (i = 0; i < caps->nstepinfos; i++) { + stepinfo = &caps->stepinfos[i]; + step_size = stepinfo->stepsize; + + /* If chip->ecc.size is already set, respect it */ + if (chip->ecc.size && step_size != chip->ecc.size) + continue; + + for (j = 0; j < stepinfo->nstrengths; j++) { + strength = stepinfo->strengths[j]; + + if (mtd->writesize % step_size) + continue; + + nsteps = mtd->writesize / step_size; + + ecc_bytes = caps->calc_ecc_bytes(step_size, strength); + if (WARN_ONCE(ecc_bytes < 0, "%s: eccbytes < 0\n", __func__)) + continue; + + if (ecc_bytes * nsteps > oobavail) + continue; + + corr = strength * nsteps; + + /* + * If the number of correctable bits is the same, + * bigger step_size has more reliability. + */ + if (corr > best_corr || + (corr == best_corr && step_size > best_step)) { + best_corr = corr; + best_step = step_size; + best_strength = strength; + best_ecc_bytes = ecc_bytes; + } + } + } + + if (!best_corr) + return -ENOTSUPP; + + chip->ecc.size = best_step; + chip->ecc.strength = best_strength; + chip->ecc.bytes = best_ecc_bytes; + + return 0; +} + +/** + * nand_ecc_choose_conf - Set the ECC strength and ECC step size + * @chip: nand chip info structure + * @caps: ECC engine caps info structure + * @oobavail: OOB size that the ECC engine can use + * + * Choose the ECC configuration according to following logic + * + * 1. If both ECC step size and ECC strength are already set (usually by DT) + * then check if it is supported by this controller. + * 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength. + * 3. Otherwise, try to match the ECC step size and ECC strength closest + * to the chip's requirement. If available OOB size can't fit the chip + * requirement then fallback to the maximum ECC step size and ECC strength. + * + * On success, the chosen ECC settings are set. + */ +int nand_ecc_choose_conf(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + if (WARN_ON(oobavail < 0 || oobavail > mtd->oobsize)) + return -EINVAL; + + if (chip->ecc.size && chip->ecc.strength) + return nand_check_ecc_caps(chip, caps, oobavail); + + if (chip->ecc.options & NAND_ECC_MAXIMIZE) + return nand_maximize_ecc(chip, caps, oobavail); + + if (!nand_match_ecc_req(chip, caps, oobavail)) + return 0; + + return nand_maximize_ecc(chip, caps, oobavail); +} +EXPORT_SYMBOL_GPL(nand_ecc_choose_conf); + +/* + * Check if the chip configuration meet the datasheet requirements. + + * If our configuration corrects A bits per B bytes and the minimum + * required correction level is X bits per Y bytes, then we must ensure + * both of the following are true: + * + * (1) A / B >= X / Y + * (2) A >= X + * + * Requirement (1) ensures we can correct for the required bitflip density. + * Requirement (2) ensures we can correct even when all bitflips are clumped + * in the same sector. + */ +static bool nand_ecc_strength_good(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; + int corr, ds_corr; + + if (ecc->size == 0 || chip->base.eccreq.step_size == 0) + /* Not enough information */ + return true; + + /* + * We get the number of corrected bits per page to compare + * the correction density. + */ + corr = (mtd->writesize * ecc->strength) / ecc->size; + ds_corr = (mtd->writesize * chip->base.eccreq.strength) / + chip->base.eccreq.step_size; + + return corr >= ds_corr && ecc->strength >= chip->base.eccreq.strength; +} + +static int rawnand_erase(struct nand_device *nand, const struct nand_pos *pos) +{ + struct nand_chip *chip = container_of(nand, struct nand_chip, + base); + unsigned int eb = nanddev_pos_to_row(nand, pos); + int ret; + + eb >>= nand->rowconv.eraseblock_addr_shift; + + nand_select_target(chip, pos->target); + ret = nand_erase_op(chip, eb); + nand_deselect_target(chip); + + return ret; +} + +static int rawnand_markbad(struct nand_device *nand, + const struct nand_pos *pos) +{ + struct nand_chip *chip = container_of(nand, struct nand_chip, + base); + + return nand_markbad_bbm(chip, nanddev_pos_to_offs(nand, pos)); +} + +static bool rawnand_isbad(struct nand_device *nand, const struct nand_pos *pos) +{ + struct nand_chip *chip = container_of(nand, struct nand_chip, + base); + int ret; + + nand_select_target(chip, pos->target); + ret = nand_isbad_bbm(chip, nanddev_pos_to_offs(nand, pos)); + nand_deselect_target(chip); + + return ret; +} + +static const struct nand_ops rawnand_ops = { + .erase = rawnand_erase, + .markbad = rawnand_markbad, + .isbad = rawnand_isbad, +}; + +/** + * nand_scan_tail - Scan for the NAND device + * @chip: NAND chip object * * This is the second phase of the normal nand_scan() function. It fills out * all the uninitialized function pointers with the defaults and scans for a * bad block table if appropriate. */ -int nand_scan_tail(struct mtd_info *mtd) +int nand_scan_tail(struct nand_chip *chip) { - int i; - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; + int ret, i; /* New bad blocks should be marked in OOB, flash-based BBT, or both */ - BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) && - !(chip->bbt_options & NAND_BBT_USE_FLASH)); + if (WARN_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) && + !(chip->bbt_options & NAND_BBT_USE_FLASH))) { + return -EINVAL; + } - if (!(chip->options & NAND_OWN_BUFFERS)) - chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL); - if (!chip->buffers) + chip->data_buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); + if (!chip->data_buf) return -ENOMEM; + /* + * FIXME: some NAND manufacturer drivers expect the first die to be + * selected when manufacturer->init() is called. They should be fixed + * to explictly select the relevant die when interacting with the NAND + * chip. + */ + nand_select_target(chip, 0); + ret = nand_manufacturer_init(chip); + nand_deselect_target(chip); + if (ret) + goto err_free_buf; + /* Set the internal oob buffer location, just after the page data */ - chip->oob_poi = chip->buffers->databuf + mtd->writesize; + chip->oob_poi = chip->data_buf + mtd->writesize; /* * If no default placement scheme is given, select an appropriate one. */ - if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) { + if (!mtd->ooblayout && + !(ecc->mode == NAND_ECC_SOFT && ecc->algo == NAND_ECC_BCH)) { switch (mtd->oobsize) { case 8: - chip->ecc.layout = &nand_oob_8; - break; case 16: - chip->ecc.layout = &nand_oob_16; + mtd_set_ooblayout(mtd, &nand_ooblayout_sp_ops); break; case 64: - chip->ecc.layout = &nand_oob_64; - break; case 128: - chip->ecc.layout = &nand_oob_128; + mtd_set_ooblayout(mtd, &nand_ooblayout_lp_hamming_ops); break; default: - pr_warn("No oob scheme defined for oobsize %d\n", - mtd->oobsize); - BUG(); + /* + * Expose the whole OOB area to users if ECC_NONE + * is passed. We could do that for all kind of + * ->oobsize, but we must keep the old large/small + * page with ECC layout when ->oobsize <= 128 for + * compatibility reasons. + */ + if (ecc->mode == NAND_ECC_NONE) { + mtd_set_ooblayout(mtd, + &nand_ooblayout_lp_ops); + break; + } + + WARN(1, "No oob scheme defined for oobsize %d\n", + mtd->oobsize); + ret = -EINVAL; + goto err_nand_manuf_cleanup; } } - if (!chip->write_page) - chip->write_page = nand_write_page; - /* * Check ECC mode, default to software if 3byte/512byte hardware ECC is * selected and we have 256 byte pagesize fallback to software ECC */ - switch (chip->ecc.mode) { -#ifdef CONFIG_NAND_ECC_HW_OOB_FIRST - case NAND_ECC_HW_OOB_FIRST: - /* Similar to NAND_ECC_HW, but a separate read_page handle */ - if (!chip->ecc.calculate || !chip->ecc.correct || - !chip->ecc.hwctl) { - pr_warn("No ECC functions supplied; hardware ECC not possible\n"); - BUG(); - } - if (!chip->ecc.read_page) - chip->ecc.read_page = nand_read_page_hwecc_oob_first; - if (!chip->ecc.write_page) - chip->ecc.write_page = nand_write_page_hwecc; - if (!chip->ecc.read_page_raw) - chip->ecc.read_page_raw = nand_read_page_raw; - if (!chip->ecc.write_page_raw) - chip->ecc.write_page_raw = nand_write_page_raw; - if (!chip->ecc.read_oob) - chip->ecc.read_oob = nand_read_oob_std; - if (!chip->ecc.write_oob) - chip->ecc.write_oob = nand_write_oob_std; - if (!chip->ecc.read_subpage) - chip->ecc.read_subpage = nand_read_subpage; - if (!chip->ecc.write_subpage) - chip->ecc.write_subpage = nand_write_subpage_hwecc; - break; -#endif -#ifdef CONFIG_NAND_ECC_HW + switch (ecc->mode) { case NAND_ECC_HW: /* Use standard hwecc read page function? */ - if (!chip->ecc.read_page) - chip->ecc.read_page = nand_read_page_hwecc; - if (!chip->ecc.write_page) - chip->ecc.write_page = nand_write_page_hwecc; - if (!chip->ecc.read_page_raw) - chip->ecc.read_page_raw = nand_read_page_raw; - if (!chip->ecc.write_page_raw) - chip->ecc.write_page_raw = nand_write_page_raw; - if (!chip->ecc.read_oob) - chip->ecc.read_oob = nand_read_oob_std; - if (!chip->ecc.write_oob) - chip->ecc.write_oob = nand_write_oob_std; - if (!chip->ecc.read_subpage) - chip->ecc.read_subpage = nand_read_subpage; - if (!chip->ecc.write_subpage) - chip->ecc.write_subpage = nand_write_subpage_hwecc; - break; -#endif -#ifdef CONFIG_NAND_ECC_HW_SYNDROME + if (!ecc->read_page) + ecc->read_page = nand_read_page_hwecc; + if (!ecc->write_page) + ecc->write_page = nand_write_page_hwecc; + if (!ecc->read_page_raw) + ecc->read_page_raw = nand_read_page_raw; + if (!ecc->write_page_raw) + ecc->write_page_raw = nand_write_page_raw; + if (!ecc->read_oob) + ecc->read_oob = nand_read_oob_std; + if (!ecc->write_oob) + ecc->write_oob = nand_write_oob_std; + if (!ecc->read_subpage) + ecc->read_subpage = nand_read_subpage; + if (!ecc->write_subpage && ecc->hwctl && ecc->calculate) + ecc->write_subpage = nand_write_subpage_hwecc; case NAND_ECC_HW_SYNDROME: + if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) && + (!ecc->read_page || + ecc->read_page == nand_read_page_hwecc || + !ecc->write_page || + ecc->write_page == nand_write_page_hwecc)) { + WARN(1, "No ECC functions supplied; hardware ECC not possible\n"); + ret = -EINVAL; + goto err_nand_manuf_cleanup; + } /* Use standard syndrome read/write page function? */ - if (!chip->ecc.read_page) - chip->ecc.read_page = nand_read_page_syndrome; - if (!chip->ecc.write_page) - chip->ecc.write_page = nand_write_page_syndrome; - if (!chip->ecc.read_page_raw) - chip->ecc.read_page_raw = nand_read_page_raw_syndrome; - if (!chip->ecc.write_page_raw) - chip->ecc.write_page_raw = nand_write_page_raw_syndrome; - if (!chip->ecc.read_oob) - chip->ecc.read_oob = nand_read_oob_syndrome; - if (!chip->ecc.write_oob) - chip->ecc.write_oob = nand_write_oob_syndrome; - break; -#endif -#ifdef CONFIG_NAND_ECC_SOFT - case NAND_ECC_SOFT: - chip->ecc.calculate = nand_calculate_ecc; - chip->ecc.correct = nand_correct_data; - chip->ecc.read_page = nand_read_page_swecc; - chip->ecc.read_subpage = nand_read_subpage; - chip->ecc.write_page = nand_write_page_swecc; - chip->ecc.read_page_raw = nand_read_page_raw; - chip->ecc.write_page_raw = nand_write_page_raw; - chip->ecc.read_oob = nand_read_oob_std; - chip->ecc.write_oob = nand_write_oob_std; - if (!chip->ecc.size) - chip->ecc.size = 256; - chip->ecc.bytes = 3; - chip->ecc.strength = 1; - break; -#endif -#ifdef CONFIG_NAND_ECC_BCH - case NAND_ECC_SOFT_BCH: - if (!mtd_nand_has_bch()) { - pr_warn("CONFIG_MTD_ECC_BCH not enabled\n"); - BUG(); + if (!ecc->read_page) + ecc->read_page = nand_read_page_syndrome; + if (!ecc->write_page) + ecc->write_page = nand_write_page_syndrome; + if (!ecc->read_page_raw) + ecc->read_page_raw = nand_read_page_raw_syndrome; + if (!ecc->write_page_raw) + ecc->write_page_raw = nand_write_page_raw_syndrome; + if (!ecc->read_oob) + ecc->read_oob = nand_read_oob_syndrome; + if (!ecc->write_oob) + ecc->write_oob = nand_write_oob_syndrome; + + if (mtd->writesize >= ecc->size) { + if (!ecc->strength) { + WARN(1, "Driver must set ecc.strength when using hardware ECC\n"); + ret = -EINVAL; + goto err_nand_manuf_cleanup; + } + break; } - chip->ecc.calculate = nand_bch_calculate_ecc; - chip->ecc.correct = nand_bch_correct_data; - chip->ecc.read_page = nand_read_page_swecc; - chip->ecc.read_subpage = nand_read_subpage; - chip->ecc.write_page = nand_write_page_swecc; - chip->ecc.read_page_raw = nand_read_page_raw; - chip->ecc.write_page_raw = nand_write_page_raw; - chip->ecc.read_oob = nand_read_oob_std; - chip->ecc.write_oob = nand_write_oob_std; - /* - * Board driver should supply ecc.size and ecc.strength values - * to select how many bits are correctable. Otherwise, default - * to 4 bits for large page devices. - */ - if (!chip->ecc.size && (mtd->oobsize >= 64)) { - chip->ecc.size = 512; - chip->ecc.strength = 4; + pr_warn("%d byte HW ECC not possible on %d byte page size, fallback to SW ECC\n", + ecc->size, mtd->writesize); + ecc->mode = NAND_ECC_SOFT; + ecc->algo = NAND_ECC_HAMMING; + case NAND_ECC_SOFT: + ret = nand_set_ecc_soft_ops(chip); + if (ret) { + ret = -EINVAL; + goto err_nand_manuf_cleanup; } + break; - /* See nand_bch_init() for details. */ - chip->ecc.bytes = 0; - chip->ecc.priv = nand_bch_init(mtd); - if (!chip->ecc.priv) { - pr_warn("BCH ECC initialization failed!\n"); - BUG(); + case NAND_ECC_ON_DIE: + if (!ecc->read_page || !ecc->write_page) { + WARN(1, "No ECC functions supplied; on-die ECC not possible\n"); + ret = -EINVAL; + goto err_nand_manuf_cleanup; } + if (!ecc->read_oob) + ecc->read_oob = nand_read_oob_std; + if (!ecc->write_oob) + ecc->write_oob = nand_write_oob_std; break; -#endif -#ifdef CONFIG_NAND_ECC_NONE + case NAND_ECC_NONE: pr_warn("NAND_ECC_NONE selected by board driver. This is not recommended!\n"); - chip->ecc.read_page = nand_read_page_raw; - chip->ecc.write_page = nand_write_page_raw; - chip->ecc.read_oob = nand_read_oob_std; - chip->ecc.read_page_raw = nand_read_page_raw; - chip->ecc.write_page_raw = nand_write_page_raw; - chip->ecc.write_oob = nand_write_oob_std; - chip->ecc.size = mtd->writesize; - chip->ecc.bytes = 0; - chip->ecc.strength = 0; + ecc->read_page = nand_read_page_raw; + ecc->write_page = nand_write_page_raw; + ecc->read_oob = nand_read_oob_std; + ecc->read_page_raw = nand_read_page_raw; + ecc->write_page_raw = nand_write_page_raw; + ecc->write_oob = nand_write_oob_std; + ecc->size = mtd->writesize; + ecc->bytes = 0; + ecc->strength = 0; break; -#endif + default: - pr_warn("Invalid NAND_ECC_MODE %d\n", chip->ecc.mode); - BUG(); + WARN(1, "Invalid NAND_ECC_MODE %d\n", ecc->mode); + ret = -EINVAL; + goto err_nand_manuf_cleanup; + } + + if (ecc->correct || ecc->calculate) { + ecc->calc_buf = kmalloc(mtd->oobsize, GFP_KERNEL); + ecc->code_buf = kmalloc(mtd->oobsize, GFP_KERNEL); + if (!ecc->calc_buf || !ecc->code_buf) { + ret = -ENOMEM; + goto err_nand_manuf_cleanup; + } } /* For many systems, the standard OOB write also works for raw */ - if (!chip->ecc.read_oob_raw) - chip->ecc.read_oob_raw = chip->ecc.read_oob; - if (!chip->ecc.write_oob_raw) - chip->ecc.write_oob_raw = chip->ecc.write_oob; + if (!ecc->read_oob_raw) + ecc->read_oob_raw = ecc->read_oob; + if (!ecc->write_oob_raw) + ecc->write_oob_raw = ecc->write_oob; - /* - * The number of bytes available for a client to place data into - * the out of band area. - */ - chip->ecc.layout->oobavail = 0; - for (i = 0; chip->ecc.layout->oobfree[i].length - && i < ARRAY_SIZE(chip->ecc.layout->oobfree); i++) - chip->ecc.layout->oobavail += - chip->ecc.layout->oobfree[i].length; - mtd->oobavail = chip->ecc.layout->oobavail; + /* propagate ecc info to mtd_info */ + mtd->ecc_strength = ecc->strength; + mtd->ecc_step_size = ecc->size; /* * Set the number of read / write steps for one page depending on ECC * mode. */ - chip->ecc.steps = mtd->writesize / chip->ecc.size; - if (chip->ecc.steps * chip->ecc.size != mtd->writesize) { - pr_warn("Invalid ECC parameters\n"); - BUG(); + ecc->steps = mtd->writesize / ecc->size; + if (ecc->steps * ecc->size != mtd->writesize) { + WARN(1, "Invalid ECC parameters\n"); + ret = -EINVAL; + goto err_nand_manuf_cleanup; + } + ecc->total = ecc->steps * ecc->bytes; + if (ecc->total > mtd->oobsize) { + WARN(1, "Total number of ECC bytes exceeded oobsize\n"); + ret = -EINVAL; + goto err_nand_manuf_cleanup; } - chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; + + /* + * The number of bytes available for a client to place data into + * the out of band area. + */ + ret = mtd_ooblayout_count_freebytes(mtd); + if (ret < 0) + ret = 0; + + mtd->oobavail = ret; + + /* ECC sanity check: warn if it's too weak */ + if (!nand_ecc_strength_good(chip)) + pr_warn("WARNING: %s: the ECC used on your system (%db/%dB) is too weak compared to the one required by the NAND chip (%db/%dB)\n", + mtd->name, chip->ecc.strength, chip->ecc.size, + chip->base.eccreq.strength, + chip->base.eccreq.step_size); /* Allow subpage writes up to ecc.steps. Not possible for MLC flash */ if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) { - switch (chip->ecc.steps) { + switch (ecc->steps) { case 2: mtd->subpage_sft = 1; break; @@ -3832,36 +5716,39 @@ int nand_scan_tail(struct mtd_info *mtd) } chip->subpagesize = mtd->writesize >> mtd->subpage_sft; - /* Initialize state */ - chip->state = FL_READY; - /* Invalidate the pagebuffer reference */ - chip->pagebuf = -1; + chip->pagecache.page = -1; /* Large page NAND with SOFT_ECC should support subpage reads */ - if ((chip->ecc.mode == NAND_ECC_SOFT) && (chip->page_shift > 9)) - chip->options |= NAND_SUBPAGE_READ; + switch (ecc->mode) { + case NAND_ECC_SOFT: + if (chip->page_shift > 9) + chip->options |= NAND_SUBPAGE_READ; + break; + + default: + break; + } + + ret = nanddev_init(&chip->base, &rawnand_ops, mtd->owner); + if (ret) + goto err_nand_manuf_cleanup; + + /* Adjust the MTD_CAP_ flags when NAND_ROM is set. */ + if (chip->options & NAND_ROM) + mtd->flags = MTD_CAP_ROM; /* Fill in remaining MTD driver data */ - mtd->type = MTD_NANDFLASH; - mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM : - MTD_CAP_NANDFLASH; - mtd->erase = nand_erase; - mtd->read = nand_read; - mtd->write = nand_write; - mtd->read_oob = nand_read_oob; - mtd->write_oob = nand_write_oob; - mtd->sync = nand_sync; - mtd->lock = NULL; - mtd->unlock = NULL; - mtd->block_isbad = nand_block_isbad; - mtd->block_markbad = nand_block_markbad; - mtd->block_markgood = nand_block_markgood; - mtd->writebufsize = mtd->writesize; + mtd->_erase = nand_erase; + mtd->_read_oob = nand_read_oob; + mtd->_write_oob = nand_write_oob; + mtd->_sync = nand_sync; + mtd->_lock = nand_lock; + mtd->_unlock = nand_unlock; + mtd->_block_isbad = nand_block_isbad; + mtd->_block_markbad = nand_block_markbad; + mtd->_block_markgood = nand_block_markgood; - /* propagate ecc info to mtd_info */ - mtd->ecclayout = chip->ecc.layout; - mtd->ecc_strength = chip->ecc.strength; /* * Initialize bitflip_threshold to its default prior scan_bbt() call. * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be @@ -3870,82 +5757,139 @@ int nand_scan_tail(struct mtd_info *mtd) if (!mtd->bitflip_threshold) mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4); + /* Find the fastest data interface for this chip */ + ret = nand_choose_interface_config(chip); + if (ret) + goto err_nanddev_cleanup; + + /* Enter fastest possible mode on all dies. */ + for (i = 0; i < nanddev_ntargets(&chip->base); i++) { + ret = nand_setup_interface(chip, i); + if (ret) + goto err_free_interface_config; + } + /* Check, if we should skip the bad block table scan */ if (chip->options & NAND_SKIP_BBTSCAN) return 0; - if (!IS_ENABLED(CONFIG_NAND_BBT)) - return 0; - /* Build bad block table */ - return chip->scan_bbt(mtd); + ret = nand_create_bbt(chip); + if (ret) + goto err_free_interface_config; + + return 0; + +err_free_interface_config: + kfree(chip->best_interface_config); + +err_nanddev_cleanup: + nanddev_cleanup(&chip->base); + +err_nand_manuf_cleanup: + nand_manufacturer_cleanup(chip); + +err_free_buf: + kfree(chip->data_buf); + kfree(ecc->code_buf); + kfree(ecc->calc_buf); + + return ret; +} + +static int nand_attach(struct nand_chip *chip) +{ + if (chip->controller->ops && chip->controller->ops->attach_chip) + return chip->controller->ops->attach_chip(chip); + + return 0; +} + +static void nand_detach(struct nand_chip *chip) +{ + if (chip->controller->ops && chip->controller->ops->detach_chip) + chip->controller->ops->detach_chip(chip); } -EXPORT_SYMBOL(nand_scan_tail); /** - * nand_scan - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: number of chips to scan for + * nand_scan_with_ids - [NAND Interface] Scan for the NAND device + * @chip: NAND chip object + * @maxchips: number of chips to scan for. + * @ids: optional flash IDs table * * 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. The mtd->owner field must be set to the module of the - * caller. + * appropriate values. */ -int nand_scan(struct mtd_info *mtd, int maxchips) +int nand_scan_with_ids(struct nand_chip *chip, unsigned int maxchips, + struct nand_flash_dev *ids) { int ret; - ret = nand_scan_ident(mtd, maxchips, NULL); - if (!ret) - ret = nand_scan_tail(mtd); + if (!maxchips) + return -EINVAL; + + ret = nand_scan_ident(chip, maxchips, ids); + if (ret) + return ret; + + ret = nand_attach(chip); + if (ret) + goto cleanup_ident; + + ret = nand_scan_tail(chip); + if (ret) + goto detach_chip; + + return 0; + +detach_chip: + nand_detach(chip); +cleanup_ident: + nand_scan_ident_cleanup(chip); + return ret; } -EXPORT_SYMBOL(nand_scan); +EXPORT_SYMBOL(nand_scan_with_ids); /** - * nand_release - [NAND Interface] Free resources held by the NAND device - * @mtd: MTD device structure + * nand_cleanup - [NAND Interface] Free resources held by the NAND device + * @chip: NAND chip object */ -void nand_release(struct mtd_info *mtd) +void nand_cleanup(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); - - if (chip->ecc.mode == NAND_ECC_SOFT_BCH) + if (chip->ecc.mode == NAND_ECC_SOFT && + chip->ecc.algo == NAND_ECC_BCH) nand_bch_free((struct nand_bch_control *)chip->ecc.priv); - del_mtd_device(mtd); + nanddev_cleanup(&chip->base); /* Free bad block table memory */ kfree(chip->bbt); - if (!(chip->options & NAND_OWN_BUFFERS)) - kfree(chip->buffers); + kfree(chip->data_buf); + kfree(chip->ecc.code_buf); + kfree(chip->ecc.calc_buf); /* Free bad block descriptor memory */ if (chip->badblock_pattern && chip->badblock_pattern->options & NAND_BBT_DYNAMICSTRUCT) kfree(chip->badblock_pattern); -} -EXPORT_SYMBOL_GPL(nand_release); - -static int mtd_set_erasebad(struct param_d *param, void *priv) -{ - struct mtd_info *mtd = priv; - if (!mtd->p_allow_erasebad) { - mtd->allow_erasebad = false; - return 0; - } + /* Free the data interface */ + kfree(chip->best_interface_config); - if (!mtd->allow_erasebad) - dev_warn(&mtd->class_dev, - "Allowing to erase bad blocks. This may be dangerous!\n"); + /* Free manufacturer priv data. */ + nand_manufacturer_cleanup(chip); - mtd->allow_erasebad = true; + /* Free controller specific allocations after chip identification */ + nand_detach(chip); - return 0; + /* Free identification phase allocations */ + nand_scan_ident_cleanup(chip); } +EXPORT_SYMBOL_GPL(nand_cleanup); + enum bbt_type { BBT_TYPE_NONE = 0, BBT_TYPE_FLASHBASED, @@ -3977,6 +5921,24 @@ static int mtd_get_bbt_type(struct param_d *p, void *priv) return 0; } +static int mtd_set_erasebad(struct param_d *param, void *priv) +{ + struct mtd_info *mtd = priv; + + if (!mtd->p_allow_erasebad) { + mtd->allow_erasebad = false; + return 0; + } + + if (!mtd->allow_erasebad) + dev_warn(&mtd->dev, + "Allowing to erase bad blocks. This may be dangerous!\n"); + + mtd->allow_erasebad = true; + + return 0; +} + int add_mtd_nand_device(struct mtd_info *mtd, char *devname) { struct nand_chip *chip = mtd_to_nand(mtd); @@ -3987,17 +5949,21 @@ int add_mtd_nand_device(struct mtd_info *mtd, char *devname) return ret; if (IS_ENABLED(CONFIG_NAND_ALLOW_ERASE_BAD)) - dev_add_param_bool(&mtd->class_dev, "erasebad", mtd_set_erasebad, + dev_add_param_bool(&mtd->dev, "erasebad", mtd_set_erasebad, NULL, &mtd->p_allow_erasebad, mtd); - dev_add_param_enum(&mtd->class_dev, "bbt", NULL, mtd_get_bbt_type, + dev_add_param_enum(&mtd->dev, "bbt", NULL, mtd_get_bbt_type, &chip->bbt_type, bbt_type_strings, - ARRAY_SIZE(bbt_type_strings), - mtd); + ARRAY_SIZE(bbt_type_strings), mtd); - dev_add_param_uint32_ro(&mtd->class_dev, "ecc.bytes", &chip->ecc.bytes, "%u"); - dev_add_param_uint32_ro(&mtd->class_dev, "ecc.strength", &chip->ecc.strength, "%u"); - dev_add_param_uint32_ro(&mtd->class_dev, "ecc.size", &chip->ecc.size, "%u"); + dev_add_param_uint32_ro(&mtd->dev, "ecc.bytes", &chip->ecc.bytes, "%u"); + dev_add_param_uint32_ro(&mtd->dev, "ecc.strength", &chip->ecc.strength, "%u"); + dev_add_param_uint32_ro(&mtd->dev, "ecc.size", &chip->ecc.size, "%u"); return ret; } + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>"); +MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); +MODULE_DESCRIPTION("Generic NAND flash driver code"); diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index ed4104629a..f582799636 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -1,15 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * drivers/mtd/nand_bbt.c - * * Overview: * Bad block table support for the NAND driver * * Copyright © 2004 Thomas Gleixner (tglx@linutronix.de) * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Description: * * When nand_scan_bbt is called, then it tries to find the bad block table @@ -56,18 +51,16 @@ * Following assumptions are made: * - bbts start at a page boundary, if autolocated on a block boundary * - the space necessary for a bbt in FLASH does not exceed a block boundary - * */ -#include <common.h> #include <linux/types.h> #include <linux/mtd/mtd.h> -#include <linux/mtd/nand.h> -#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/bbm.h> #include <linux/bitops.h> -#include <clock.h> -#include <errno.h> -#include <malloc.h> +#include <linux/export.h> +#include <linux/string.h> + +#include "internals.h" #define BBT_BLOCK_GOOD 0x00 #define BBT_BLOCK_WORN 0x01 @@ -164,7 +157,7 @@ static u32 add_marker_len(struct nand_bbt_descr *td) /** * read_bbt - [GENERIC] Read the bad block table starting from page - * @mtd: MTD device structure + * @this: NAND chip object * @buf: temporary buffer * @page: the starting page * @num: the number of bbt descriptors to read @@ -173,11 +166,11 @@ static u32 add_marker_len(struct nand_bbt_descr *td) * * Read the bad block table starting from page. */ -static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, - struct nand_bbt_descr *td, int offs) +static int read_bbt(struct nand_chip *this, uint8_t *buf, int page, int num, + struct nand_bbt_descr *td, int offs) { + struct mtd_info *mtd = nand_to_mtd(this); int res, ret = 0, i, j, act = 0; - struct nand_chip *this = mtd_to_nand(mtd); size_t retlen, len, totlen; loff_t from; int bits = td->options & NAND_BBT_NRBITS_MSK; @@ -232,7 +225,11 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, mtd->ecc_stats.bbtblocks++; continue; } - pr_debug("nand_read_bbt: bad block at 0x%012llx\n", + /* + * Leave it for now, if it's matured we can + * move this message to pr_debug. + */ + pr_info("nand_read_bbt: bad block at 0x%012llx\n", (loff_t)(offs + act) << this->bbt_erase_shift); /* Factory marked bad or worn out? */ @@ -253,7 +250,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, /** * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page - * @mtd: MTD device structure + * @this: NAND chip object * @buf: temporary buffer * @td: descriptor for the bad block table * @chip: read the table for a specific chip, -1 read all chips; applies only if @@ -262,24 +259,26 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, * Read the bad block table for all chips starting at a given page. We assume * that the bbt bits are in consecutive order. */ -static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip) +static int read_abs_bbt(struct nand_chip *this, uint8_t *buf, + struct nand_bbt_descr *td, int chip) { - struct nand_chip *this = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(this); + u64 targetsize = nanddev_target_size(&this->base); int res = 0, i; if (td->options & NAND_BBT_PERCHIP) { int offs = 0; - for (i = 0; i < this->numchips; i++) { + for (i = 0; i < nanddev_ntargets(&this->base); i++) { if (chip == -1 || chip == i) - res = read_bbt(mtd, buf, td->pages[i], - this->chipsize >> this->bbt_erase_shift, + res = read_bbt(this, buf, td->pages[i], + targetsize >> this->bbt_erase_shift, td, offs); if (res) return res; - offs += this->chipsize >> this->bbt_erase_shift; + offs += targetsize >> this->bbt_erase_shift; } } else { - res = read_bbt(mtd, buf, td->pages[0], + res = read_bbt(this, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, td, 0); if (res) return res; @@ -288,9 +287,10 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc } /* BBT marker is in the first page, no OOB */ -static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, - struct nand_bbt_descr *td) +static int scan_read_data(struct nand_chip *this, uint8_t *buf, loff_t offs, + struct nand_bbt_descr *td) { + struct mtd_info *mtd = nand_to_mtd(this); size_t retlen; size_t len; @@ -303,7 +303,7 @@ static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, /** * scan_read_oob - [GENERIC] Scan data+OOB region to buffer - * @mtd: MTD device structure + * @this: NAND chip object * @buf: temporary buffer * @offs: offset at which to scan * @len: length of data region to read @@ -312,9 +312,10 @@ static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, * page,OOB,page,OOB,... in buf. Completes transfer and returns the "strongest" * ECC condition (error or bitflip). May quit on the first (non-ECC) error. */ -static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, +static int scan_read_oob(struct nand_chip *this, uint8_t *buf, loff_t offs, size_t len) { + struct mtd_info *mtd = nand_to_mtd(this); struct mtd_oob_ops ops; int res, ret = 0; @@ -342,19 +343,20 @@ static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, return ret; } -static int scan_read(struct mtd_info *mtd, uint8_t *buf, loff_t offs, - size_t len, struct nand_bbt_descr *td) +static int scan_read(struct nand_chip *this, uint8_t *buf, loff_t offs, + size_t len, struct nand_bbt_descr *td) { if (td->options & NAND_BBT_NO_OOB) - return scan_read_data(mtd, buf, offs, td); + return scan_read_data(this, buf, offs, td); else - return scan_read_oob(mtd, buf, offs, len); + return scan_read_oob(this, buf, offs, len); } /* Scan write data with oob to flash */ -static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, +static int scan_write_bbt(struct nand_chip *this, loff_t offs, size_t len, uint8_t *buf, uint8_t *oob) { + struct mtd_info *mtd = nand_to_mtd(this); struct mtd_oob_ops ops; ops.mode = MTD_OPS_PLACE_OOB; @@ -367,8 +369,9 @@ static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, return mtd_write_oob(mtd, offs, &ops); } -static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) +static u32 bbt_get_ver_offs(struct nand_chip *this, struct nand_bbt_descr *td) { + struct mtd_info *mtd = nand_to_mtd(this); u32 ver_offs = td->veroffs; if (!(td->options & NAND_BBT_NO_OOB)) @@ -378,7 +381,7 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) /** * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page - * @mtd: MTD device structure + * @this: NAND chip object * @buf: temporary buffer * @td: descriptor for the bad block table * @md: descriptor for the bad block table mirror @@ -386,36 +389,38 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) * Read the bad block table(s) for all chips starting at a given page. We * assume that the bbt bits are in consecutive order. */ -static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, +static void read_abs_bbts(struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) { - struct nand_chip *this = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(this); /* Read the primary version, if available */ if (td->options & NAND_BBT_VERSION) { - scan_read(mtd, buf, (loff_t)td->pages[0] << this->page_shift, - mtd->writesize, td); - td->version[0] = buf[bbt_get_ver_offs(mtd, td)]; + scan_read(this, buf, (loff_t)td->pages[0] << this->page_shift, + mtd->writesize, td); + td->version[0] = buf[bbt_get_ver_offs(this, td)]; pr_info("Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); } /* Read the mirror version, if available */ if (md && (md->options & NAND_BBT_VERSION)) { - scan_read(mtd, buf, (loff_t)md->pages[0] << this->page_shift, - mtd->writesize, md); - md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; + scan_read(this, buf, (loff_t)md->pages[0] << this->page_shift, + mtd->writesize, md); + md->version[0] = buf[bbt_get_ver_offs(this, md)]; pr_info("Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); } } /* Scan a given block partially */ -static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, - loff_t offs, uint8_t *buf, int numpages) +static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd, + loff_t offs, uint8_t *buf) { + struct mtd_info *mtd = nand_to_mtd(this); + struct mtd_oob_ops ops; - int j, ret; + int ret, page_offset; ops.ooblen = mtd->oobsize; ops.oobbuf = buf; @@ -423,12 +428,15 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, ops.datbuf = NULL; ops.mode = MTD_OPS_PLACE_OOB; - for (j = 0; j < numpages; j++) { + page_offset = nand_bbm_get_next_page(this, 0); + + while (page_offset >= 0) { /* * Read the full oob until read_oob is fixed to handle single * byte reads for 16 bit buswidth. */ - ret = mtd_read_oob(mtd, offs, &ops); + ret = mtd_read_oob(mtd, offs + (page_offset * mtd->writesize), + &ops); /* Ignore ECC errors when checking for BBM */ if (ret && !mtd_is_bitflip_or_eccerr(ret)) return ret; @@ -436,14 +444,15 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, if (check_short_pattern(buf, bd)) return 1; - offs += mtd->writesize; + page_offset = nand_bbm_get_next_page(this, page_offset + 1); } + return 0; } /** * create_bbt - [GENERIC] Create a bad block table by scanning the device - * @mtd: MTD device structure + * @this: NAND chip object * @buf: temporary buffer * @bd: descriptor for the good/bad block search pattern * @chip: create the table for a specific chip, -1 read all chips; applies only @@ -452,46 +461,38 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, * Create a bad block table by scanning the device for the given good/bad block * identify pattern. */ -static int create_bbt(struct mtd_info *mtd, uint8_t *buf, - struct nand_bbt_descr *bd, int chip) +static int create_bbt(struct nand_chip *this, uint8_t *buf, + struct nand_bbt_descr *bd, int chip) { - struct nand_chip *this = mtd_to_nand(mtd); - int i, numblocks, numpages; - int startblock; + u64 targetsize = nanddev_target_size(&this->base); + struct mtd_info *mtd = nand_to_mtd(this); + int i, numblocks, startblock; loff_t from; pr_info("Scanning device for bad blocks\n"); - if (bd->options & NAND_BBT_SCAN2NDPAGE) - numpages = 2; - else - numpages = 1; - if (chip == -1) { numblocks = mtd->size >> this->bbt_erase_shift; startblock = 0; from = 0; } else { - if (chip >= this->numchips) { + if (chip >= nanddev_ntargets(&this->base)) { pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n", - chip + 1, this->numchips); + chip + 1, nanddev_ntargets(&this->base)); return -EINVAL; } - numblocks = this->chipsize >> this->bbt_erase_shift; + numblocks = targetsize >> this->bbt_erase_shift; startblock = chip * numblocks; numblocks += startblock; from = (loff_t)startblock << this->bbt_erase_shift; } - if (this->bbt_options & NAND_BBT_SCANLASTPAGE) - from += mtd->erasesize - (mtd->writesize * numpages); - for (i = startblock; i < numblocks; i++) { int ret; BUG_ON(bd->options & NAND_BBT_NO_OOB); - ret = scan_block_fast(mtd, bd, from, buf, numpages); + ret = scan_block_fast(this, bd, from, buf); if (ret < 0) return ret; @@ -509,7 +510,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, /** * search_bbt - [GENERIC] scan the device for a specific bad block table - * @mtd: MTD device structure + * @this: NAND chip object * @buf: temporary buffer * @td: descriptor for the bad block table * @@ -522,9 +523,11 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, * * The bbt ident pattern resides in the oob area of the first page in a block. */ -static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) +static int search_bbt(struct nand_chip *this, uint8_t *buf, + struct nand_bbt_descr *td) { - struct nand_chip *this = mtd_to_nand(mtd); + u64 targetsize = nanddev_target_size(&this->base); + struct mtd_info *mtd = nand_to_mtd(this); int i, chips; int startblock, block, dir; int scanlen = mtd->writesize + mtd->oobsize; @@ -542,8 +545,8 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { - chips = this->numchips; - bbtblocks = this->chipsize >> this->bbt_erase_shift; + chips = nanddev_ntargets(&this->base); + bbtblocks = targetsize >> this->bbt_erase_shift; startblock &= bbtblocks - 1; } else { chips = 1; @@ -561,17 +564,17 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr loff_t offs = (loff_t)actblock << this->bbt_erase_shift; /* Read first page */ - scan_read(mtd, buf, offs, mtd->writesize, td); + scan_read(this, buf, offs, mtd->writesize, td); if (!check_pattern(buf, scanlen, mtd->writesize, td)) { td->pages[i] = actblock << blocktopage; if (td->options & NAND_BBT_VERSION) { - offs = bbt_get_ver_offs(mtd, td); + offs = bbt_get_ver_offs(this, td); td->version[i] = buf[offs]; } break; } } - startblock += this->chipsize >> this->bbt_erase_shift; + startblock += targetsize >> this->bbt_erase_shift; } /* Check, if we found a bbt for each requested chip */ for (i = 0; i < chips; i++) { @@ -586,23 +589,23 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr /** * search_read_bbts - [GENERIC] scan the device for bad block table(s) - * @mtd: MTD device structure + * @this: NAND chip object * @buf: temporary buffer * @td: descriptor for the bad block table * @md: descriptor for the bad block table mirror * * Search and read the bad block table(s). */ -static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf, +static void search_read_bbts(struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) { /* Search the primary table */ - search_bbt(mtd, buf, td); + search_bbt(this, buf, td); /* Search the mirror table */ if (md) - search_bbt(mtd, buf, md); + search_bbt(this, buf, md); } /** @@ -621,6 +624,7 @@ static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf, static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chip) { + u64 targetsize = nanddev_target_size(&this->base); int startblock, dir, page, numblocks, i; /* @@ -632,9 +636,9 @@ static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td, return td->pages[chip] >> (this->bbt_erase_shift - this->page_shift); - numblocks = (int)(this->chipsize >> this->bbt_erase_shift); + numblocks = (int)(targetsize >> this->bbt_erase_shift); if (!(td->options & NAND_BBT_PERCHIP)) - numblocks *= this->numchips; + numblocks *= nanddev_ntargets(&this->base); /* * Automatic placement of the bad block table. Search direction @@ -670,7 +674,7 @@ static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td, /** * mark_bbt_block_bad - Mark one of the block reserved for BBT bad - * @mtd: the MTD device + * @this: the NAND device * @td: the BBT description * @chip: the CHIP selector * @block: the BBT block to mark @@ -680,18 +684,17 @@ static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td, * block as bad using a bad block marker and invalidating the associated * td->pages[] entry. */ -static void mark_bbt_block_bad(struct mtd_info *mtd, +static void mark_bbt_block_bad(struct nand_chip *this, struct nand_bbt_descr *td, int chip, int block) { - struct nand_chip *this = mtd_to_nand(mtd); loff_t to; int res; bbt_mark_entry(this, block, BBT_BLOCK_WORN); to = (loff_t)block << this->bbt_erase_shift; - res = this->block_markbad(mtd, to); + res = nand_markbad_bbm(this, to); if (res) pr_warn("nand_bbt: error %d while marking block %d bad\n", res, block); @@ -701,7 +704,7 @@ static void mark_bbt_block_bad(struct mtd_info *mtd, /** * write_bbt - [GENERIC] (Re)write the bad block table - * @mtd: MTD device structure + * @this: NAND chip object * @buf: temporary buffer * @td: descriptor for the bad block table * @md: descriptor for the bad block table mirror @@ -709,11 +712,12 @@ static void mark_bbt_block_bad(struct mtd_info *mtd, * * (Re)write the bad block table. */ -static int write_bbt(struct mtd_info *mtd, uint8_t *buf, +static int write_bbt(struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) { - struct nand_chip *this = mtd_to_nand(mtd); + u64 targetsize = nanddev_target_size(&this->base); + struct mtd_info *mtd = nand_to_mtd(this); struct erase_info einfo; int i, res, chip = 0; int bits, page, offs, numblocks, sft, sftmsk; @@ -733,10 +737,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, rcode = 0xff; /* Write bad block table per chip rather than per device? */ if (td->options & NAND_BBT_PERCHIP) { - numblocks = (int)(this->chipsize >> this->bbt_erase_shift); + numblocks = (int)(targetsize >> this->bbt_erase_shift); /* Full device write or specific chip? */ if (chipsel == -1) { - nrchips = this->numchips; + nrchips = nanddev_ntargets(&this->base); } else { nrchips = chipsel + 1; chip = chipsel; @@ -787,7 +791,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, /* Must we save the block contents? */ if (td->options & NAND_BBT_SAVECONTENT) { /* Make it block aligned */ - to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1)); + to &= ~(((loff_t)1 << this->bbt_erase_shift) - 1); len = 1 << this->bbt_erase_shift; res = mtd_read(mtd, to, len, &retlen, buf); if (res < 0) { @@ -853,24 +857,23 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, } memset(&einfo, 0, sizeof(einfo)); - einfo.mtd = mtd; einfo.addr = to; einfo.len = 1 << this->bbt_erase_shift; - res = nand_erase_nand(mtd, &einfo, 1); + res = nand_erase_nand(this, &einfo, 1); if (res < 0) { pr_warn("nand_bbt: error while erasing BBT block %d\n", res); - mark_bbt_block_bad(mtd, td, chip, block); + mark_bbt_block_bad(this, td, chip, block); continue; } - res = scan_write_bbt(mtd, to, len, buf, - td->options & NAND_BBT_NO_OOB ? NULL : - &buf[len]); + res = scan_write_bbt(this, to, len, buf, + td->options & NAND_BBT_NO_OOB ? + NULL : &buf[len]); if (res < 0) { pr_warn("nand_bbt: error while writing BBT block %d\n", res); - mark_bbt_block_bad(mtd, td, chip, block); + mark_bbt_block_bad(this, td, chip, block); continue; } @@ -889,22 +892,23 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, /** * nand_memory_bbt - [GENERIC] create a memory based bad block table - * @mtd: MTD device structure + * @this: NAND chip object * @bd: descriptor for the good/bad block search pattern * * The function creates a memory based bbt by scanning the device for * manufacturer / software marked good / bad blocks. */ -static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) +static inline int nand_memory_bbt(struct nand_chip *this, + struct nand_bbt_descr *bd) { - struct nand_chip *this = mtd_to_nand(mtd); + u8 *pagebuf = nand_get_data_buf(this); - return create_bbt(mtd, this->buffers->databuf, bd, -1); + return create_bbt(this, pagebuf, bd, -1); } /** * check_create - [GENERIC] create and write bbt(s) if necessary - * @mtd: MTD device structure + * @this: the NAND device * @buf: temporary buffer * @bd: descriptor for the good/bad block search pattern * @@ -913,17 +917,17 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b * for the chip/device. Update is necessary if one of the tables is missing or * the version nr. of one table is less than the other. */ -static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) +static int check_create(struct nand_chip *this, uint8_t *buf, + struct nand_bbt_descr *bd) { int i, chips, writeops, create, chipsel, res, res2; - struct nand_chip *this = mtd_to_nand(mtd); struct nand_bbt_descr *td = this->bbt_td; struct nand_bbt_descr *md = this->bbt_md; struct nand_bbt_descr *rd, *rd2; /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) - chips = this->numchips; + chips = nanddev_ntargets(&this->base); else chips = 1; @@ -973,7 +977,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc /* Create the table in memory by scanning the chip(s) */ if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY)) - create_bbt(mtd, buf, bd, chipsel); + create_bbt(this, buf, bd, chipsel); td->version[i] = 1; if (md) @@ -982,7 +986,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc /* Read back first? */ if (rd) { - res = read_abs_bbt(mtd, buf, rd, chipsel); + res = read_abs_bbt(this, buf, rd, chipsel); if (mtd_is_eccerr(res)) { /* Mark table as invalid */ rd->pages[i] = -1; @@ -993,7 +997,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc } /* If they weren't versioned, read both */ if (rd2) { - res2 = read_abs_bbt(mtd, buf, rd2, chipsel); + res2 = read_abs_bbt(this, buf, rd2, chipsel); if (mtd_is_eccerr(res2)) { /* Mark table as invalid */ rd2->pages[i] = -1; @@ -1015,14 +1019,14 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc /* Write the bad block table to the device? */ if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { - res = write_bbt(mtd, buf, td, md, chipsel); + res = write_bbt(this, buf, td, md, chipsel); if (res < 0) return res; } /* Write the mirror bad block table to the device? */ if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { - res = write_bbt(mtd, buf, md, td, chipsel); + res = write_bbt(this, buf, md, td, chipsel); if (res < 0) return res; } @@ -1031,23 +1035,79 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc } /** + * nand_update_bbt - update bad block table(s) + * @this: the NAND device + * @offs: the offset of the newly marked block + * + * The function updates the bad block table(s). + */ +int nand_update_bbt(struct nand_chip *this, loff_t offs) +{ + struct mtd_info *mtd = nand_to_mtd(this); + int len, res = 0; + int chip, chipsel; + uint8_t *buf; + struct nand_bbt_descr *td = this->bbt_td; + struct nand_bbt_descr *md = this->bbt_md; + + if (!this->bbt || !td) + return -EINVAL; + + /* Allocate a temporary buffer for one eraseblock incl. oob */ + len = (1 << this->bbt_erase_shift); + len += (len >> this->page_shift) * mtd->oobsize; + buf = kmalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* Do we have a bbt per chip? */ + if (td->options & NAND_BBT_PERCHIP) { + chip = (int)(offs >> this->chip_shift); + chipsel = chip; + } else { + chip = 0; + chipsel = -1; + } + + td->version[chip]++; + if (md) + md->version[chip]++; + + /* Write the bad block table to the device? */ + if (td->options & NAND_BBT_WRITE) { + res = write_bbt(this, buf, td, md, chipsel); + if (res < 0) + goto out; + } + /* Write the mirror bad block table to the device? */ + if (md && (md->options & NAND_BBT_WRITE)) { + res = write_bbt(this, buf, md, td, chipsel); + } + + out: + kfree(buf); + return res; +} + +/** * mark_bbt_regions - [GENERIC] mark the bad block table regions - * @mtd: MTD device structure + * @this: the NAND device * @td: bad block table descriptor * * The bad block table regions are marked as "bad" to prevent accidental * erasures / writes. The regions are identified by the mark 0x02. */ -static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) +static void mark_bbt_region(struct nand_chip *this, struct nand_bbt_descr *td) { - struct nand_chip *this = mtd_to_nand(mtd); + u64 targetsize = nanddev_target_size(&this->base); + struct mtd_info *mtd = nand_to_mtd(this); int i, j, chips, block, nrblocks, update; uint8_t oldval; /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { - chips = this->numchips; - nrblocks = (int)(this->chipsize >> this->bbt_erase_shift); + chips = nanddev_ntargets(&this->base); + nrblocks = (int)(targetsize >> this->bbt_erase_shift); } else { chips = 1; nrblocks = (int)(mtd->size >> this->bbt_erase_shift); @@ -1063,7 +1123,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) bbt_mark_entry(this, block, BBT_BLOCK_RESERVED); if ((oldval != BBT_BLOCK_RESERVED) && td->reserved_block_code) - nand_update_bbt(mtd, (loff_t)block << + nand_update_bbt(this, (loff_t)block << this->bbt_erase_shift); continue; } @@ -1085,22 +1145,23 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) * bbts. This should only happen once. */ if (update && td->reserved_block_code) - nand_update_bbt(mtd, (loff_t)(block - 1) << + nand_update_bbt(this, (loff_t)(block - 1) << this->bbt_erase_shift); } } /** * verify_bbt_descr - verify the bad block description - * @mtd: MTD device structure + * @this: the NAND device * @bd: the table to verify * * This functions performs a few sanity checks on the bad block description * table. */ -static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) +static void verify_bbt_descr(struct nand_chip *this, struct nand_bbt_descr *bd) { - struct nand_chip *this = mtd_to_nand(mtd); + u64 targetsize = nanddev_target_size(&this->base); + struct mtd_info *mtd = nand_to_mtd(this); u32 pattern_len; u32 bits; u32 table_size; @@ -1128,7 +1189,7 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) } if (bd->options & NAND_BBT_PERCHIP) - table_size = this->chipsize >> this->bbt_erase_shift; + table_size = targetsize >> this->bbt_erase_shift; else table_size = mtd->size >> this->bbt_erase_shift; table_size >>= 3; @@ -1140,7 +1201,7 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) /** * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) - * @mtd: MTD device structure + * @this: the NAND device * @bd: descriptor for the good/bad block search pattern * * The function checks, if a bad block table(s) is/are already available. If @@ -1150,15 +1211,15 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) * The bad block table memory is allocated here. It must be freed by calling * the nand_free_bbt function. */ -static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) +static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd) { - struct nand_chip *this = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(this); int len, res; uint8_t *buf; struct nand_bbt_descr *td = this->bbt_td; struct nand_bbt_descr *md = this->bbt_md; - len = mtd->size >> (this->bbt_erase_shift + 2); + len = (mtd->size >> (this->bbt_erase_shift + 2)) ? : 1; /* * Allocate memory (2bit per block) and clear the memory bad block * table. @@ -1168,18 +1229,18 @@ static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) return -ENOMEM; /* - * If no primary table decriptor is given, scan the device to build a + * If no primary table descriptor is given, scan the device to build a * memory based bad block table. */ if (!td) { - if ((res = nand_memory_bbt(mtd, bd))) { + if ((res = nand_memory_bbt(this, bd))) { pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n"); - goto err; + goto err_free_bbt; } return 0; } - verify_bbt_descr(mtd, td); - verify_bbt_descr(mtd, md); + verify_bbt_descr(this, td); + verify_bbt_descr(this, md); /* Allocate a temporary buffer for one eraseblock incl. oob */ len = (1 << this->bbt_erase_shift); @@ -1187,90 +1248,37 @@ static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) buf = vmalloc(len); if (!buf) { res = -ENOMEM; - goto err; + goto err_free_bbt; } /* Is the bbt at a given page? */ if (td->options & NAND_BBT_ABSPAGE) { - read_abs_bbts(mtd, buf, td, md); + read_abs_bbts(this, buf, td, md); } else { /* Search the bad block table using a pattern in oob */ - search_read_bbts(mtd, buf, td, md); + search_read_bbts(this, buf, td, md); } - res = check_create(mtd, buf, bd); + res = check_create(this, buf, bd); if (res) - goto err; + goto err_free_buf; /* Prevent the bbt regions from erasing / writing */ - mark_bbt_region(mtd, td); + mark_bbt_region(this, td); if (md) - mark_bbt_region(mtd, md); + mark_bbt_region(this, md); vfree(buf); return 0; -err: +err_free_buf: + vfree(buf); +err_free_bbt: kfree(this->bbt); this->bbt = NULL; return res; } -/** - * nand_update_bbt - update bad block table(s) - * @mtd: MTD device structure - * @offs: the offset of the newly marked block - * - * The function updates the bad block table(s). - */ -int nand_update_bbt(struct mtd_info *mtd, loff_t offs) -{ - struct nand_chip *this = mtd_to_nand(mtd); - int len, res = 0; - int chip, chipsel; - uint8_t *buf; - struct nand_bbt_descr *td = this->bbt_td; - struct nand_bbt_descr *md = this->bbt_md; - - if (!this->bbt || !td) - return -EINVAL; - - /* Allocate a temporary buffer for one eraseblock incl. oob */ - len = (1 << this->bbt_erase_shift); - len += (len >> this->page_shift) * mtd->oobsize; - buf = kmalloc(len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - /* Do we have a bbt per chip? */ - if (td->options & NAND_BBT_PERCHIP) { - chip = (int)(offs >> this->chip_shift); - chipsel = chip; - } else { - chip = 0; - chipsel = -1; - } - - td->version[chip]++; - if (md) - md->version[chip]++; - - /* Write the bad block table to the device? */ - if (td->options & NAND_BBT_WRITE) { - res = write_bbt(mtd, buf, td, md, chipsel); - if (res < 0) - goto out; - } - /* Write the mirror bad block table to the device? */ - if (md && (md->options & NAND_BBT_WRITE)) { - res = write_bbt(mtd, buf, md, td, chipsel); - } - - out: - kfree(buf); - return res; -} - /* * Define some generic bad / good block scan pattern which are used * while scanning a device for factory marked good / bad blocks. @@ -1351,15 +1359,14 @@ static int nand_create_badblock_pattern(struct nand_chip *this) } /** - * nand_default_bbt - [NAND Interface] Select a default bad block table for the device - * @mtd: MTD device structure + * nand_create_bbt - [NAND Interface] Select a default bad block table for the device + * @this: NAND chip object * * This function selects the default bad block table support for the device and * calls the nand_scan_bbt function. */ -int nand_default_bbt(struct mtd_info *mtd) +int nand_create_bbt(struct nand_chip *this) { - struct nand_chip *this = mtd_to_nand(mtd); int ret; /* Is a flash based bad block table requested? */ @@ -1385,20 +1392,32 @@ int nand_default_bbt(struct mtd_info *mtd) return ret; } - return nand_scan_bbt(mtd, this->badblock_pattern); + return nand_scan_bbt(this, this->badblock_pattern); +} +EXPORT_SYMBOL(nand_create_bbt); + +/** + * nand_isreserved_bbt - [NAND Interface] Check if a block is reserved + * @this: NAND chip object + * @offs: offset in the device + */ +int nand_isreserved_bbt(struct nand_chip *this, loff_t offs) +{ + int block; + + block = (int)(offs >> this->bbt_erase_shift); + return bbt_get_entry(this, block) == BBT_BLOCK_RESERVED; } /** * nand_isbad_bbt - [NAND Interface] Check if a block is bad - * @mtd: MTD device structure + * @this: NAND chip object * @offs: offset in the device * @allowbbt: allow access to bad block table region */ -int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) +int nand_isbad_bbt(struct nand_chip *this, loff_t offs, int allowbbt) { - struct nand_chip *this = mtd_to_nand(mtd); - int block; - uint8_t res; + int block, res; block = (int)(offs >> this->bbt_erase_shift); res = bbt_get_entry(this, block); @@ -1406,7 +1425,7 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", (unsigned int)offs, block, res); - switch ((int)res) { + switch (res) { case BBT_BLOCK_GOOD: return 0; case BBT_BLOCK_WORN: @@ -1417,9 +1436,8 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) return 1; } -static int nand_mark_bbt(struct mtd_info *mtd, loff_t offs, uint8_t mark) +static int nand_mark_bbt(struct nand_chip *this, loff_t offs, uint8_t mark) { - struct nand_chip *this = mtd_to_nand(mtd); int block, ret = 0; block = (int)(offs >> this->bbt_erase_shift); @@ -1429,7 +1447,7 @@ static int nand_mark_bbt(struct mtd_info *mtd, loff_t offs, uint8_t mark) /* Update flash-based bad block table */ if (this->bbt_options & NAND_BBT_USE_FLASH) - ret = nand_update_bbt(mtd, offs); + ret = nand_update_bbt(this, offs); return ret; } @@ -1439,9 +1457,9 @@ static int nand_mark_bbt(struct mtd_info *mtd, loff_t offs, uint8_t mark) * @mtd: MTD device structure * @offs: offset of the bad block */ -int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs) +int nand_markbad_bbt(struct nand_chip *this, loff_t offs) { - return nand_mark_bbt(mtd, offs, BBT_BLOCK_WORN); + return nand_mark_bbt(this, offs, BBT_BLOCK_WORN); } /** @@ -1449,11 +1467,7 @@ int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs) * @mtd: MTD device structure * @offs: offset of the good block */ -int nand_markgood_bbt(struct mtd_info *mtd, loff_t offs) +int nand_markgood_bbt(struct nand_chip *this, loff_t offs) { - return nand_mark_bbt(mtd, offs, BBT_BLOCK_GOOD); + return nand_mark_bbt(this, offs, BBT_BLOCK_GOOD); } - -EXPORT_SYMBOL(nand_scan_bbt); -EXPORT_SYMBOL(nand_default_bbt); -EXPORT_SYMBOL_GPL(nand_update_bbt); diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c index b94ecdf8d9..0d636d9608 100644 --- a/drivers/mtd/nand/nand_bch.c +++ b/drivers/mtd/nand/nand_bch.c @@ -1,19 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * This file provides ECC correction for more than 1 bit per block of data, * using binary BCH codes. It relies on the generic BCH library lib/bch.c. * * Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com> - * - * This file 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 or (at your option) any - * later version. - * - * This file 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 <common.h> @@ -22,6 +12,7 @@ #include <linux/kernel.h> #include <linux/bitops.h> #include <linux/mtd/mtd.h> +#include <linux/mtd/rawnand.h> #include <linux/mtd/nand.h> #include <linux/mtd/nand_bch.h> #include <linux/bch.h> @@ -29,27 +20,24 @@ /** * struct nand_bch_control - private NAND BCH control structure * @bch: BCH control structure - * @ecclayout: private ecc layout for this BCH configuration * @errloc: error location array * @eccmask: XOR ecc mask, allows erased pages to be decoded as valid */ struct nand_bch_control { struct bch_control *bch; - struct nand_ecclayout ecclayout; unsigned int *errloc; unsigned char *eccmask; }; /** * nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block - * @mtd: MTD block structure + * @chip: NAND chip object * @buf: input buffer with raw data * @code: output buffer with ECC */ -int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf, +int nand_bch_calculate_ecc(struct nand_chip *chip, const unsigned char *buf, unsigned char *code) { - const struct nand_chip *chip = mtd_to_nand(mtd); struct nand_bch_control *nbc = chip->ecc.priv; unsigned int i; @@ -66,17 +54,16 @@ EXPORT_SYMBOL(nand_bch_calculate_ecc); /** * nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s) - * @mtd: MTD block structure + * @chip: NAND chip object * @buf: raw data read from the chip * @read_ecc: ECC from the chip * @calc_ecc: the ECC calculated from raw data * * Detect and correct bit errors for a data byte block */ -int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, +int nand_bch_correct_data(struct nand_chip *chip, unsigned char *buf, unsigned char *read_ecc, unsigned char *calc_ecc) { - const struct nand_chip *chip = mtd_to_nand(mtd); struct nand_bch_control *nbc = chip->ecc.priv; unsigned int *errloc = nbc->errloc; int i, count; @@ -94,8 +81,8 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, errloc[i]); } } else if (count < 0) { - printk(KERN_ERR "ecc unrecoverable error\n"); - count = -1; + pr_err("ecc unrecoverable error\n"); + count = -EBADMSG; } return count; } @@ -121,7 +108,6 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd) { struct nand_chip *nand = mtd_to_nand(mtd); unsigned int m, t, eccsteps, i; - struct nand_ecclayout *layout = nand->ecc.layout; struct nand_bch_control *nbc = NULL; unsigned char *erased_page; unsigned int eccsize = nand->ecc.size; @@ -134,7 +120,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd) } if (!eccsize || !eccbytes) { - printk(KERN_WARNING "ecc parameters not supplied\n"); + pr_warn("ecc parameters not supplied\n"); goto fail; } @@ -151,55 +137,42 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd) /* verify that eccbytes has the expected value */ if (nbc->bch->ecc_bytes != eccbytes) { - printk(KERN_WARNING "invalid eccbytes %u, should be %u\n", - eccbytes, nbc->bch->ecc_bytes); + pr_warn("invalid eccbytes %u, should be %u\n", + eccbytes, nbc->bch->ecc_bytes); goto fail; } eccsteps = mtd->writesize/eccsize; - /* if no ecc placement scheme was provided, build one */ - if (!layout) { - - /* handle large page devices only */ - if (mtd->oobsize < 64) { - printk(KERN_WARNING "must provide an oob scheme for " - "oobsize %d\n", mtd->oobsize); - goto fail; - } - - layout = &nbc->ecclayout; - layout->eccbytes = eccsteps*eccbytes; - - /* reserve 2 bytes for bad block marker */ - if (layout->eccbytes+2 > mtd->oobsize) { - printk(KERN_WARNING "no suitable oob scheme available " - "for oobsize %d eccbytes %u\n", mtd->oobsize, - eccbytes); - goto fail; - } - /* put ecc bytes at oob tail */ - for (i = 0; i < layout->eccbytes; i++) - layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i; - - layout->oobfree[0].offset = 2; - layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes; - - nand->ecc.layout = layout; + /* Check that we have an oob layout description. */ + if (!mtd->ooblayout) { + pr_warn("missing oob scheme"); + goto fail; } /* sanity checks */ if (8*(eccsize+eccbytes) >= (1 << m)) { - printk(KERN_WARNING "eccsize %u is too large\n", eccsize); + pr_warn("eccsize %u is too large\n", eccsize); goto fail; } - if (layout->eccbytes != (eccsteps*eccbytes)) { - printk(KERN_WARNING "invalid ecc layout\n"); + + /* + * ecc->steps and ecc->total might be used by mtd->ooblayout->ecc(), + * which is called by mtd_ooblayout_count_eccbytes(). + * Make sure they are properly initialized before calling + * mtd_ooblayout_count_eccbytes(). + * FIXME: we should probably rework the sequencing in nand_scan_tail() + * to avoid setting those fields twice. + */ + nand->ecc.steps = eccsteps; + nand->ecc.total = eccsteps * eccbytes; + if (mtd_ooblayout_count_eccbytes(mtd) != (eccsteps*eccbytes)) { + pr_warn("invalid ecc layout\n"); goto fail; } - nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL); - nbc->errloc = kmalloc(t*sizeof(*nbc->errloc), GFP_KERNEL); + nbc->eccmask = kzalloc(eccbytes, GFP_KERNEL); + nbc->errloc = kmalloc_array(t, sizeof(*nbc->errloc), GFP_KERNEL); if (!nbc->eccmask || !nbc->errloc) goto fail; /* @@ -210,7 +183,6 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd) goto fail; memset(erased_page, 0xff, eccsize); - memset(nbc->eccmask, 0, eccbytes); encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask); kfree(erased_page); diff --git a/drivers/mtd/nand/nand_denali.c b/drivers/mtd/nand/nand_denali.c index 8995845649..1d7d1b62a8 100644 --- a/drivers/mtd/nand/nand_denali.c +++ b/drivers/mtd/nand/nand_denali.c @@ -1,29 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 /* * NAND Flash Controller Device Driver * Copyright © 2009-2010, Intel Corporation and its suppliers. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * + * Copyright (c) 2017-2019 Socionext Inc. + * Reworked by Masahiro Yamada <yamada.masahiro@socionext.com> */ - #include <common.h> #include <dma.h> #include <driver.h> #include <malloc.h> #include <init.h> #include <linux/mtd/mtd.h> +#include <linux/mtd/rawnand.h> #include <linux/mtd/nand.h> +#include <linux/spinlock.h> +#include <linux/bitfield.h> #include <io.h> #include <clock.h> #include <of_mtd.h> @@ -31,1527 +23,1320 @@ #include <asm/io.h> #include "denali.h" -#define NAND_DEFAULT_TIMINGS -1 - -static int onfi_timing_mode = CONFIG_MTD_NAND_DENALI_TIMING_MODE; - #define DENALI_NAND_NAME "denali-nand" -/* - * We define a macro here that combines all interrupts this driver uses into - * a single constant value, for convenience. - */ -#define DENALI_IRQ_ALL (INTR_STATUS__DMA_CMD_COMP | \ - INTR_STATUS__ECC_TRANSACTION_DONE | \ - INTR_STATUS__ECC_ERR | \ - INTR_STATUS__PROGRAM_FAIL | \ - INTR_STATUS__LOAD_COMP | \ - INTR_STATUS__PROGRAM_COMP | \ - INTR_STATUS__TIME_OUT | \ - INTR_STATUS__ERASE_FAIL | \ - INTR_STATUS__RST_COMP | \ - INTR_STATUS__ERASE_COMP | \ - INTR_STATUS__ECC_UNCOR_ERR) -/* And here we use a variable for interrupt mask, bcs we want to - * change the irq mask during init. That is, we want to enable R/B - * interrupt during init, but not at other times */ -static uint32_t denali_irq_mask = DENALI_IRQ_ALL; +/* for Indexed Addressing */ +#define DENALI_INDEXED_CTRL 0x00 +#define DENALI_INDEXED_DATA 0x10 +#define DENALI_MAP00 (0 << 26) /* direct access to buffer */ +#define DENALI_MAP01 (1 << 26) /* read/write pages in PIO */ +#define DENALI_MAP10 (2 << 26) /* high-level control plane */ +#define DENALI_MAP11 (3 << 26) /* direct controller access */ -/* - * indicates whether or not the internal value for the flash bank is - * valid or not - */ -#define CHIP_SELECT_INVALID -1 +/* MAP11 access cycle type */ +#define DENALI_MAP11_CMD ((DENALI_MAP11) | 0) /* command cycle */ +#define DENALI_MAP11_ADDR ((DENALI_MAP11) | 1) /* address cycle */ +#define DENALI_MAP11_DATA ((DENALI_MAP11) | 2) /* data cycle */ -#define SUPPORT_8BITECC 1 +#define DENALI_BANK(denali) ((denali)->active_bank << 24) -/* - * This macro divides two integers and rounds fractional values up - * to the nearest integer value. - */ -#define CEIL_DIV(X, Y) (((X)%(Y)) ? ((X)/(Y)+1) : ((X)/(Y))) +#define DENALI_INVALID_BANK -1 -/* - * this macro allows us to convert from an MTD structure to our own - * device context (denali) structure. - */ -static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd) +static struct denali_chip *to_denali_chip(struct nand_chip *chip) { - struct nand_chip *nand = mtd_to_nand(mtd); - - return container_of(nand, struct denali_nand_info, nand); + return container_of(chip, struct denali_chip, chip); } -/* - * These constants are defined by the driver to enable common driver - * configuration options. - */ -#define SPARE_ACCESS 0x41 -#define MAIN_ACCESS 0x42 -#define MAIN_SPARE_ACCESS 0x43 -#define PIPELINE_ACCESS 0x2000 - -#define DENALI_READ 0 -#define DENALI_WRITE 0x100 - -/* types of device accesses. We can issue commands and get status */ -#define COMMAND_CYCLE 0 -#define ADDR_CYCLE 1 -#define STATUS_CYCLE 2 - -/* - * this is a helper macro that allows us to - * format the bank into the proper bits for the controller - */ -#define BANK(x) ((x) << 24) - -/* forward declarations */ -static void clear_interrupts(struct denali_nand_info *denali); -static uint32_t wait_for_irq(struct denali_nand_info *denali, - uint32_t irq_mask); -static void denali_irq_enable(struct denali_nand_info *denali, - uint32_t int_mask); -static uint32_t read_interrupt_status(struct denali_nand_info *denali); +static struct denali_controller *to_denali_controller(struct nand_chip *chip) +{ + return container_of(chip->controller, struct denali_controller, + controller); +} /* - * Certain operations for the denali NAND controller use an indexed mode to - * read/write data. The operation is performed by writing the address value - * of the command to the device memory followed by the data. This function - * abstracts this common operation. + * Direct Addressing - the slave address forms the control information (command + * type, bank, block, and page address). The slave data is the actual data to + * be transferred. This mode requires 28 bits of address region allocated. */ -static void index_addr(struct denali_nand_info *denali, - uint32_t address, uint32_t data) +static u32 denali_direct_read(struct denali_controller *denali, u32 addr) { - iowrite32(address, denali->flash_mem); - iowrite32(data, denali->flash_mem + 0x10); + return ioread32(denali->host + addr); } -/* Perform an indexed read of the device */ -static void index_addr_read_data(struct denali_nand_info *denali, - uint32_t address, uint32_t *pdata) +static void denali_direct_write(struct denali_controller *denali, u32 addr, + u32 data) { - iowrite32(address, denali->flash_mem); - *pdata = ioread32(denali->flash_mem + 0x10); + iowrite32(data, denali->host + addr); } /* - * We need to buffer some data for some of the NAND core routines. - * The operations manage buffering that data. + * Indexed Addressing - address translation module intervenes in passing the + * control information. This mode reduces the required address range. The + * control information and transferred data are latched by the registers in + * the translation module. */ -static void reset_buf(struct denali_nand_info *denali) +static u32 denali_indexed_read(struct denali_controller *denali, u32 addr) { - denali->buf.head = denali->buf.tail = 0; + iowrite32(addr, denali->host + DENALI_INDEXED_CTRL); + return ioread32(denali->host + DENALI_INDEXED_DATA); } -static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte) +static void denali_indexed_write(struct denali_controller *denali, u32 addr, + u32 data) { - denali->buf.buf[denali->buf.tail++] = byte; + iowrite32(addr, denali->host + DENALI_INDEXED_CTRL); + iowrite32(data, denali->host + DENALI_INDEXED_DATA); } -/* reads the status of the device */ -static void read_status(struct denali_nand_info *denali) +static void denali_enable_irq(struct denali_controller *denali) { - uint32_t cmd; - - /* initialize the data buffer to store status */ - reset_buf(denali); + int i; - cmd = ioread32(denali->flash_reg + WRITE_PROTECT); - if (cmd) - write_byte_to_buf(denali, NAND_STATUS_WP); - else - write_byte_to_buf(denali, 0); + for (i = 0; i < denali->nbanks; i++) + iowrite32(U32_MAX, denali->reg + INTR_EN(i)); + iowrite32(GLOBAL_INT_EN_FLAG, denali->reg + GLOBAL_INT_ENABLE); } -/* resets a specific device connected to the core */ -static void reset_bank(struct denali_nand_info *denali) +static void denali_clear_irq(struct denali_controller *denali, + int bank, u32 irq_status) { - iowrite32(1 << denali->flash_bank, denali->flash_reg + DEVICE_RESET); - - /* wait for completion */ - while (ioread32(denali->flash_reg + DEVICE_RESET) & (1 << denali->flash_bank)) - cpu_relax(); + /* write one to clear bits */ + iowrite32(irq_status, denali->reg + INTR_STATUS(bank)); } -/* Reset the flash controller */ -static uint16_t denali_nand_reset(struct denali_nand_info *denali) +static void denali_clear_irq_all(struct denali_controller *denali) { int i; - for (i = 0; i < denali->max_banks; i++) - iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT, - denali->flash_reg + INTR_STATUS(i)); - - for (i = 0; i < denali->max_banks; i++) { - iowrite32(1 << i, denali->flash_reg + DEVICE_RESET); - while (!(ioread32(denali->flash_reg + INTR_STATUS(i)) & - (INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT))) - cpu_relax(); - if (ioread32(denali->flash_reg + INTR_STATUS(i)) & - INTR_STATUS__TIME_OUT) - dev_dbg(denali->dev, - "NAND Reset operation timed out on bank %d\n", i); - } - - for (i = 0; i < denali->max_banks; i++) - iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT, - denali->flash_reg + INTR_STATUS(i)); - - return PASS; + for (i = 0; i < denali->nbanks; i++) + denali_clear_irq(denali, i, U32_MAX); } -/* - * this routine calculates the ONFI timing values for a given mode and - * programs the clocking register accordingly. The mode is determined by - * the get_onfi_nand_para routine. - */ -static void nand_onfi_timing_set(struct denali_nand_info *denali, - uint16_t mode) +static int denali_isr(struct denali_controller *denali) { - uint16_t Trea[6] = {40, 30, 25, 20, 20, 16}; - uint16_t Trp[6] = {50, 25, 17, 15, 12, 10}; - uint16_t Treh[6] = {30, 15, 15, 10, 10, 7}; - uint16_t Trc[6] = {100, 50, 35, 30, 25, 20}; - uint16_t Trhoh[6] = {0, 15, 15, 15, 15, 15}; - uint16_t Trloh[6] = {0, 0, 0, 0, 5, 5}; - uint16_t Tcea[6] = {100, 45, 30, 25, 25, 25}; - uint16_t Tadl[6] = {200, 100, 100, 100, 70, 70}; - uint16_t Trhw[6] = {200, 100, 100, 100, 100, 100}; - uint16_t Trhz[6] = {200, 100, 100, 100, 100, 100}; - uint16_t Twhr[6] = {120, 80, 80, 60, 60, 60}; - uint16_t Tcs[6] = {70, 35, 25, 25, 20, 15}; - - uint16_t data_invalid_rhoh, data_invalid_rloh, data_invalid; - uint16_t dv_window = 0; - uint16_t en_lo, en_hi; - uint16_t acc_clks; - uint16_t addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt; - - en_lo = CEIL_DIV(Trp[mode], CLK_X); - en_hi = CEIL_DIV(Treh[mode], CLK_X); -#if ONFI_BLOOM_TIME - if ((en_hi * CLK_X) < (Treh[mode] + 2)) - en_hi++; -#endif - - if ((en_lo + en_hi) * CLK_X < Trc[mode]) - en_lo += CEIL_DIV((Trc[mode] - (en_lo + en_hi) * CLK_X), CLK_X); - - if ((en_lo + en_hi) < CLK_MULTI) - en_lo += CLK_MULTI - en_lo - en_hi; - - while (dv_window < 8) { - data_invalid_rhoh = en_lo * CLK_X + Trhoh[mode]; - - data_invalid_rloh = (en_lo + en_hi) * CLK_X + Trloh[mode]; - - data_invalid = data_invalid_rhoh < data_invalid_rloh ? - data_invalid_rhoh : data_invalid_rloh; - - dv_window = data_invalid - Trea[mode]; - - if (dv_window < 8) - en_lo++; - } + u32 irq_status; + int i; + + spin_lock(&denali->irq_lock); - acc_clks = CEIL_DIV(Trea[mode], CLK_X); + for (i = 0; i < denali->nbanks; i++) { + irq_status = ioread32(denali->reg + INTR_STATUS(i)); - while (acc_clks * CLK_X - Trea[mode] < 3) - acc_clks++; + denali_clear_irq(denali, i, irq_status); - if (data_invalid - acc_clks * CLK_X < 2) - dev_warn(denali->dev, "%s, Line %d: Warning!\n", - __FILE__, __LINE__); + if (i != denali->active_bank) + continue; - addr_2_data = CEIL_DIV(Tadl[mode], CLK_X); - re_2_we = CEIL_DIV(Trhw[mode], CLK_X); - re_2_re = CEIL_DIV(Trhz[mode], CLK_X); - we_2_re = CEIL_DIV(Twhr[mode], CLK_X); - cs_cnt = CEIL_DIV((Tcs[mode] - Trp[mode]), CLK_X); - if (cs_cnt == 0) - cs_cnt = 1; + denali->irq_status |= irq_status; - if (Tcea[mode]) { - while (cs_cnt * CLK_X + Trea[mode] < Tcea[mode]) - cs_cnt++; + if (denali->irq_status & denali->irq_mask) + return denali->irq_status; } -#if MODE5_WORKAROUND - if (mode == 5) - acc_clks = 5; -#endif - - /* Sighting 3462430: Temporary hack for MT29F128G08CJABAWP:B */ - if (ioread32(denali->flash_reg + MANUFACTURER_ID) == 0 && - ioread32(denali->flash_reg + DEVICE_ID) == 0x88) - acc_clks = 6; - - iowrite32(acc_clks, denali->flash_reg + ACC_CLKS); - iowrite32(re_2_we, denali->flash_reg + RE_2_WE); - iowrite32(re_2_re, denali->flash_reg + RE_2_RE); - iowrite32(we_2_re, denali->flash_reg + WE_2_RE); - iowrite32(addr_2_data, denali->flash_reg + ADDR_2_DATA); - iowrite32(en_lo, denali->flash_reg + RDWR_EN_LO_CNT); - iowrite32(en_hi, denali->flash_reg + RDWR_EN_HI_CNT); - iowrite32(cs_cnt, denali->flash_reg + CS_SETUP_CNT); + spin_unlock(&denali->irq_lock); + + return 0; } -/* queries the NAND device to see what ONFI modes it supports. */ -static uint16_t get_onfi_nand_para(struct denali_nand_info *denali) +static void denali_reset_irq(struct denali_controller *denali) { - int i; + unsigned long flags; - /* - * we needn't to do a reset here because driver has already - * reset all the banks before - */ - if (!(ioread32(denali->flash_reg + ONFI_TIMING_MODE) & - ONFI_TIMING_MODE__VALUE)) - return FAIL; - - for (i = 5; i > 0; i--) { - if (ioread32(denali->flash_reg + ONFI_TIMING_MODE) & - (0x01 << i)) - break; - } + spin_lock_irqsave(&denali->irq_lock, flags); + denali->irq_status = 0; + denali->irq_mask = 0; + spin_unlock_irqrestore(&denali->irq_lock, flags); +} - nand_onfi_timing_set(denali, i); +static u32 denali_wait_for_irq(struct denali_controller *denali, u32 irq_mask) +{ + unsigned long flags; + u32 irq_status; + uint64_t start; - /* - * By now, all the ONFI devices we know support the page cache - * rw feature. So here we enable the pipeline_rw_ahead feature - */ - /* iowrite32(1, denali->flash_reg + CACHE_WRITE_ENABLE); */ - /* iowrite32(1, denali->flash_reg + CACHE_READ_ENABLE); */ + spin_lock_irqsave(&denali->irq_lock, flags); - return PASS; -} + irq_status = denali->irq_status; -static void get_samsung_nand_para(struct denali_nand_info *denali, - uint8_t device_id) -{ - if (device_id == 0xd3) { /* Samsung K9WAG08U1A */ - /* Set timing register values according to datasheet */ - iowrite32(5, denali->flash_reg + ACC_CLKS); - iowrite32(20, denali->flash_reg + RE_2_WE); - iowrite32(12, denali->flash_reg + WE_2_RE); - iowrite32(14, denali->flash_reg + ADDR_2_DATA); - iowrite32(3, denali->flash_reg + RDWR_EN_LO_CNT); - iowrite32(2, denali->flash_reg + RDWR_EN_HI_CNT); - iowrite32(2, denali->flash_reg + CS_SETUP_CNT); + if (irq_mask & irq_status) { + /* return immediately if the IRQ has already happened. */ + spin_unlock_irqrestore(&denali->irq_lock, flags); + return irq_status; } -} -static void get_toshiba_nand_para(struct denali_nand_info *denali) -{ - uint32_t tmp; + denali->irq_mask = irq_mask; + spin_unlock_irqrestore(&denali->irq_lock, flags); - /* - * Workaround to fix a controller bug which reports a wrong - * spare area size for some kind of Toshiba NAND device - */ - if ((ioread32(denali->flash_reg + DEVICE_MAIN_AREA_SIZE) == 4096) && - (ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64)) { - iowrite32(216, denali->flash_reg + DEVICE_SPARE_AREA_SIZE); - tmp = ioread32(denali->flash_reg + DEVICES_CONNECTED) * - ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE); - iowrite32(tmp, - denali->flash_reg + LOGICAL_PAGE_SPARE_SIZE); -#if SUPPORT_15BITECC - iowrite32(15, denali->flash_reg + ECC_CORRECTION); -#elif SUPPORT_8BITECC - iowrite32(8, denali->flash_reg + ECC_CORRECTION); -#endif + start = get_time_ns(); + while (1) { + irq_status = denali_isr(denali); + if (irq_mask & irq_status) + return irq_status; + + if (is_timeout(start, SECOND)) { + dev_err(denali->dev, "timeout while waiting for irq 0x%x\n", + irq_mask); + return 0; + } } } -static void get_hynix_nand_para(struct denali_nand_info *denali, - uint8_t device_id) +static void denali_select_target(struct nand_chip *chip, int cs) { - uint32_t main_size, spare_size; - - switch (device_id) { - case 0xD5: /* Hynix H27UAG8T2A, H27UBG8U5A or H27UCG8VFA */ - case 0xD7: /* Hynix H27UDG8VEM, H27UCG8UDM or H27UCG8V5A */ - iowrite32(128, denali->flash_reg + PAGES_PER_BLOCK); - iowrite32(4096, denali->flash_reg + DEVICE_MAIN_AREA_SIZE); - iowrite32(224, denali->flash_reg + DEVICE_SPARE_AREA_SIZE); - main_size = 4096 * - ioread32(denali->flash_reg + DEVICES_CONNECTED); - spare_size = 224 * - ioread32(denali->flash_reg + DEVICES_CONNECTED); - iowrite32(main_size, - denali->flash_reg + LOGICAL_PAGE_DATA_SIZE); - iowrite32(spare_size, - denali->flash_reg + LOGICAL_PAGE_SPARE_SIZE); - iowrite32(0, denali->flash_reg + DEVICE_WIDTH); -#if SUPPORT_15BITECC - iowrite32(15, denali->flash_reg + ECC_CORRECTION); -#elif SUPPORT_8BITECC - iowrite32(8, denali->flash_reg + ECC_CORRECTION); -#endif - break; - default: - dev_warn(denali->dev, - "Spectra: Unknown Hynix NAND (Device ID: 0x%x).\n" - "Will use default parameter values instead.\n", - device_id); - } + struct denali_controller *denali = to_denali_controller(chip); + struct denali_chip_sel *sel = &to_denali_chip(chip)->sels[cs]; + struct mtd_info *mtd = nand_to_mtd(chip); + + denali->active_bank = sel->bank; + + iowrite32(1 << (chip->phys_erase_shift - chip->page_shift), + denali->reg + PAGES_PER_BLOCK); + iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0, + denali->reg + DEVICE_WIDTH); + iowrite32(mtd->writesize, denali->reg + DEVICE_MAIN_AREA_SIZE); + iowrite32(mtd->oobsize, denali->reg + DEVICE_SPARE_AREA_SIZE); + iowrite32(chip->options & NAND_ROW_ADDR_3 ? + 0 : TWO_ROW_ADDR_CYCLES__FLAG, + denali->reg + TWO_ROW_ADDR_CYCLES); + iowrite32(FIELD_PREP(ECC_CORRECTION__ERASE_THRESHOLD, 1) | + FIELD_PREP(ECC_CORRECTION__VALUE, chip->ecc.strength), + denali->reg + ECC_CORRECTION); + iowrite32(chip->ecc.size, denali->reg + CFG_DATA_BLOCK_SIZE); + iowrite32(chip->ecc.size, denali->reg + CFG_LAST_DATA_BLOCK_SIZE); + iowrite32(chip->ecc.steps, denali->reg + CFG_NUM_DATA_BLOCKS); + + if (chip->options & NAND_KEEP_TIMINGS) + return; + + /* update timing registers unless NAND_KEEP_TIMINGS is set */ + iowrite32(sel->hwhr2_and_we_2_re, denali->reg + TWHR2_AND_WE_2_RE); + iowrite32(sel->tcwaw_and_addr_2_data, + denali->reg + TCWAW_AND_ADDR_2_DATA); + iowrite32(sel->re_2_we, denali->reg + RE_2_WE); + iowrite32(sel->acc_clks, denali->reg + ACC_CLKS); + iowrite32(sel->rdwr_en_lo_cnt, denali->reg + RDWR_EN_LO_CNT); + iowrite32(sel->rdwr_en_hi_cnt, denali->reg + RDWR_EN_HI_CNT); + iowrite32(sel->cs_setup_cnt, denali->reg + CS_SETUP_CNT); + iowrite32(sel->re_2_re, denali->reg + RE_2_RE); } -/* - * determines how many NAND chips are connected to the controller. Note for - * Intel CE4100 devices we don't support more than one device. - */ -static void find_valid_banks(struct denali_nand_info *denali) +static int denali_change_column(struct nand_chip *chip, unsigned int offset, + void *buf, unsigned int len, bool write) { - uint32_t id[denali->max_banks]; - int i; + if (write) + return nand_change_write_column_op(chip, offset, buf, len, + false); + else + return nand_change_read_column_op(chip, offset, buf, len, + false); +} - denali->total_used_banks = 1; - for (i = 0; i < denali->max_banks; i++) { - index_addr(denali, MODE_11 | (i << 24) | 0, 0x90); - index_addr(denali, MODE_11 | (i << 24) | 1, 0); - index_addr_read_data(denali, MODE_11 | (i << 24) | 2, &id[i]); +static int denali_payload_xfer(struct nand_chip *chip, void *buf, bool write) +{ + struct denali_controller *denali = to_denali_controller(chip); + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; + int writesize = mtd->writesize; + int oob_skip = denali->oob_skip_bytes; + int ret, i, pos, len; + + for (i = 0; i < ecc->steps; i++) { + pos = i * (ecc->size + ecc->bytes); + len = ecc->size; + + if (pos >= writesize) { + pos += oob_skip; + } else if (pos + len > writesize) { + /* This chunk overwraps the BBM area. Must be split */ + ret = denali_change_column(chip, pos, buf, + writesize - pos, write); + if (ret) + return ret; + + buf += writesize - pos; + len -= writesize - pos; + pos = writesize + oob_skip; + } - dev_dbg(denali->dev, - "Return 1st ID for bank[%d]: %x\n", i, id[i]); + ret = denali_change_column(chip, pos, buf, len, write); + if (ret) + return ret; - if (i == 0) { - if (!(id[i] & 0x0ff)) - break; /* WTF? */ - } else { - if ((id[i] & 0x0ff) == (id[0] & 0x0ff)) - denali->total_used_banks++; - else - break; - } + buf += len; } - if (denali->platform == INTEL_CE4100) { - /* - * Platform limitations of the CE4100 device limit - * users to a single chip solution for NAND. - * Multichip support is not enabled. - */ - if (denali->total_used_banks != 1) { - dev_err(denali->dev, - "Sorry, Intel CE4100 only supports a single NAND device.\n"); - BUG(); - } - } - dev_dbg(denali->dev, - "denali->total_used_banks: %d\n", denali->total_used_banks); + return 0; } -/* - * Use the configuration feature register to determine the maximum number of - * banks that the hardware supports. - */ -static void detect_max_banks(struct denali_nand_info *denali) +static int denali_oob_xfer(struct nand_chip *chip, void *buf, bool write) { - uint32_t features = ioread32(denali->flash_reg + FEATURES); + struct denali_controller *denali = to_denali_controller(chip); + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; + int writesize = mtd->writesize; + int oobsize = mtd->oobsize; + int oob_skip = denali->oob_skip_bytes; + int ret, i, pos, len; + + /* BBM at the beginning of the OOB area */ + ret = denali_change_column(chip, writesize, buf, oob_skip, write); + if (ret) + return ret; + + buf += oob_skip; + + for (i = 0; i < ecc->steps; i++) { + pos = ecc->size + i * (ecc->size + ecc->bytes); + + if (i == ecc->steps - 1) + /* The last chunk includes OOB free */ + len = writesize + oobsize - pos - oob_skip; + else + len = ecc->bytes; + + if (pos >= writesize) { + pos += oob_skip; + } else if (pos + len > writesize) { + /* This chunk overwraps the BBM area. Must be split */ + ret = denali_change_column(chip, pos, buf, + writesize - pos, write); + if (ret) + return ret; + + buf += writesize - pos; + len -= writesize - pos; + pos = writesize + oob_skip; + } - denali->max_banks = 2 << (features & FEATURES__N_BANKS); -} + ret = denali_change_column(chip, pos, buf, len, write); + if (ret) + return ret; -static void detect_partition_feature(struct denali_nand_info *denali) -{ - /* - * For MRST platform, denali->fwblks represent the - * number of blocks firmware is taken, - * FW is in protect partition and MTD driver has no - * permission to access it. So let driver know how many - * blocks it can't touch. - */ - if (ioread32(denali->flash_reg + FEATURES) & FEATURES__PARTITION) { - if ((ioread32(denali->flash_reg + PERM_SRC_ID(1)) & - PERM_SRC_ID__SRCID) == SPECTRA_PARTITION_ID) { - denali->fwblks = - ((ioread32(denali->flash_reg + MIN_MAX_BANK(1)) & - MIN_MAX_BANK__MIN_VALUE) * - denali->blksperchip) - + - (ioread32(denali->flash_reg + MIN_BLK_ADDR(1)) & - MIN_BLK_ADDR__VALUE); - } else { - denali->fwblks = SPECTRA_START_BLOCK; - } - } else { - denali->fwblks = SPECTRA_START_BLOCK; + buf += len; } + + return 0; } -static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) +static int denali_read_raw(struct nand_chip *chip, void *buf, void *oob_buf, + int page) { - uint16_t status = PASS; - uint32_t id_bytes[8], addr; - uint8_t maf_id, device_id; - int i; + int ret; - /* - * Use read id method to get device ID and other params. - * For some NAND chips, controller can't report the correct - * device ID by reading from DEVICE_ID register - */ - addr = MODE_11 | BANK(denali->flash_bank); - index_addr(denali, addr | 0, 0x90); - index_addr(denali, addr | 1, 0); - for (i = 0; i < 8; i++) - index_addr_read_data(denali, addr | 2, &id_bytes[i]); - maf_id = id_bytes[0]; - device_id = id_bytes[1]; - - if (ioread32(denali->flash_reg + ONFI_DEVICE_NO_OF_LUNS) & - ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE) { /* ONFI 1.0 NAND */ - if (FAIL == get_onfi_nand_para(denali)) - return FAIL; - } else if (maf_id == 0xEC) { /* Samsung NAND */ - get_samsung_nand_para(denali, device_id); - } else if (maf_id == 0x98) { /* Toshiba NAND */ - get_toshiba_nand_para(denali); - } else if (maf_id == 0xAD) { /* Hynix NAND */ - get_hynix_nand_para(denali, device_id); - } + if (!buf && !oob_buf) + return -EINVAL; - dev_dbg(denali->dev, - "Dump timing register values:\n" - "acc_clks: %d, re_2_we: %d, re_2_re: %d\n" - "we_2_re: %d, addr_2_data: %d, rdwr_en_lo_cnt: %d\n" - "rdwr_en_hi_cnt: %d, cs_setup_cnt: %d\n", - ioread32(denali->flash_reg + ACC_CLKS), - ioread32(denali->flash_reg + RE_2_WE), - ioread32(denali->flash_reg + RE_2_RE), - ioread32(denali->flash_reg + WE_2_RE), - ioread32(denali->flash_reg + ADDR_2_DATA), - ioread32(denali->flash_reg + RDWR_EN_LO_CNT), - ioread32(denali->flash_reg + RDWR_EN_HI_CNT), - ioread32(denali->flash_reg + CS_SETUP_CNT)); - - find_valid_banks(denali); - - detect_partition_feature(denali); + ret = nand_read_page_op(chip, page, 0, NULL, 0); + if (ret) + return ret; - /* - * If the user specified to override the default timings - * with a specific ONFI mode, we apply those changes here. - */ - if (onfi_timing_mode != NAND_DEFAULT_TIMINGS) - nand_onfi_timing_set(denali, onfi_timing_mode); + if (buf) { + ret = denali_payload_xfer(chip, buf, false); + if (ret) + return ret; + } - return status; -} + if (oob_buf) { + ret = denali_oob_xfer(chip, oob_buf, false); + if (ret) + return ret; + } -static void denali_set_intr_modes(struct denali_nand_info *denali, - uint16_t INT_ENABLE) -{ - if (INT_ENABLE) - iowrite32(1, denali->flash_reg + GLOBAL_INT_ENABLE); - else - iowrite32(0, denali->flash_reg + GLOBAL_INT_ENABLE); + return 0; } -/* - * validation function to verify that the controlling software is making - * a valid request - */ -static inline bool is_flash_bank_valid(int flash_bank) +static int denali_write_raw(struct nand_chip *chip, const void *buf, + const void *oob_buf, int page) { - return flash_bank >= 0 && flash_bank < 4; -} - + int ret; -static void denali_irq_init(struct denali_nand_info *denali) -{ - uint32_t int_mask; - int i; + if (!buf && !oob_buf) + return -EINVAL; - /* Disable global interrupts */ - denali_set_intr_modes(denali, false); + ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0); + if (ret) + return ret; - int_mask = DENALI_IRQ_ALL; + if (buf) { + ret = denali_payload_xfer(chip, (void *)buf, true); + if (ret) + return ret; + } - /* Clear all status bits */ - for (i = 0; i < denali->max_banks; ++i) - iowrite32(0xFFFF, denali->flash_reg + INTR_STATUS(i)); + if (oob_buf) { + ret = denali_oob_xfer(chip, (void *)oob_buf, true); + if (ret) + return ret; + } - denali_irq_enable(denali, int_mask); + return nand_prog_page_end_op(chip); } - -static void denali_irq_cleanup(int irqnum, struct denali_nand_info *denali) +static int denali_read_page_raw(struct nand_chip *chip, u8 *buf, + int oob_required, int page) { - denali_set_intr_modes(denali, false); + return denali_read_raw(chip, buf, oob_required ? chip->oob_poi : NULL, + page); } -static void denali_irq_enable(struct denali_nand_info *denali, - uint32_t int_mask) +static int denali_write_page_raw(struct nand_chip *chip, const u8 *buf, + int oob_required, int page) { - int i; - - for (i = 0; i < denali->max_banks; ++i) - iowrite32(int_mask, denali->flash_reg + INTR_EN(i)); + return denali_write_raw(chip, buf, oob_required ? chip->oob_poi : NULL, + page); } -/* Interrupts are cleared by writing a 1 to the appropriate status bit */ -static inline void clear_interrupt(struct denali_nand_info *denali, - uint32_t irq_mask) +static int denali_read_oob(struct nand_chip *chip, int page) { - uint32_t intr_status_reg; - - intr_status_reg = INTR_STATUS(denali->flash_bank); - - iowrite32(irq_mask, denali->flash_reg + intr_status_reg); + return denali_read_raw(chip, NULL, chip->oob_poi, page); } -static void clear_interrupts(struct denali_nand_info *denali) +static int denali_write_oob(struct nand_chip *chip, int page) { - uint32_t status; - - status = read_interrupt_status(denali); - clear_interrupt(denali, status); - - denali->irq_status = 0x0; + return denali_write_raw(chip, NULL, chip->oob_poi, page); } -static uint32_t read_interrupt_status(struct denali_nand_info *denali) +static int denali_check_erased_page(struct nand_chip *chip, u8 *buf, + unsigned long uncor_ecc_flags, + unsigned int max_bitflips) { - uint32_t intr_status_reg; + struct denali_controller *denali = to_denali_controller(chip); + struct mtd_ecc_stats *ecc_stats = &nand_to_mtd(chip)->ecc_stats; + struct nand_ecc_ctrl *ecc = &chip->ecc; + u8 *ecc_code = chip->oob_poi + denali->oob_skip_bytes; + int i, stat; + + for (i = 0; i < ecc->steps; i++) { + if (!(uncor_ecc_flags & BIT(i))) + continue; + + stat = nand_check_erased_ecc_chunk(buf, ecc->size, ecc_code, + ecc->bytes, NULL, 0, + ecc->strength); + if (stat < 0) { + ecc_stats->failed++; + } else { + ecc_stats->corrected += stat; + max_bitflips = max_t(unsigned int, max_bitflips, stat); + } - intr_status_reg = INTR_STATUS(denali->flash_bank); + buf += ecc->size; + ecc_code += ecc->bytes; + } - return ioread32(denali->flash_reg + intr_status_reg); + return max_bitflips; } -static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) +static int denali_hw_ecc_fixup(struct nand_chip *chip, + unsigned long *uncor_ecc_flags) { - uint32_t intr_status = 0; - uint64_t start; - - if (!is_flash_bank_valid(denali->flash_bank)) { - dev_dbg(denali->dev, "No valid chip selected (%d)\n", - denali->flash_bank); - return 0; - } - - start = get_time_ns(); - - while (!is_timeout(start, 1000 * MSECOND)) { - intr_status = read_interrupt_status(denali); + struct denali_controller *denali = to_denali_controller(chip); + struct mtd_ecc_stats *ecc_stats = &nand_to_mtd(chip)->ecc_stats; + int bank = denali->active_bank; + u32 ecc_cor; + unsigned int max_bitflips; - if (intr_status != 0) - clear_interrupt(denali, intr_status); + ecc_cor = ioread32(denali->reg + ECC_COR_INFO(bank)); + ecc_cor >>= ECC_COR_INFO__SHIFT(bank); - if (intr_status & irq_mask) - return intr_status; + if (ecc_cor & ECC_COR_INFO__UNCOR_ERR) { + /* + * This flag is set when uncorrectable error occurs at least in + * one ECC sector. We can not know "how many sectors", or + * "which sector(s)". We need erase-page check for all sectors. + */ + *uncor_ecc_flags = GENMASK(chip->ecc.steps - 1, 0); + return 0; } - /* timeout */ - dev_dbg(denali->dev, "timeout occurred, status = 0x%x, mask = 0x%x\n", - intr_status, irq_mask); + max_bitflips = FIELD_GET(ECC_COR_INFO__MAX_ERRORS, ecc_cor); - return 0; -} - -/* - * This helper function setups the registers for ECC and whether or not - * the spare area will be transferred. - */ -static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, - bool transfer_spare) -{ - int ecc_en_flag, transfer_spare_flag; - - /* set ECC, transfer spare bits if needed */ - ecc_en_flag = ecc_en ? ECC_ENABLE__FLAG : 0; - transfer_spare_flag = transfer_spare ? TRANSFER_SPARE_REG__FLAG : 0; + /* + * The register holds the maximum of per-sector corrected bitflips. + * This is suitable for the return value of the ->read_page() callback. + * Unfortunately, we can not know the total number of corrected bits in + * the page. Increase the stats by max_bitflips. (compromised solution) + */ + ecc_stats->corrected += max_bitflips; - /* Enable spare area/ECC per user's request. */ - iowrite32(ecc_en_flag, denali->flash_reg + ECC_ENABLE); - iowrite32(transfer_spare_flag, denali->flash_reg + TRANSFER_SPARE_REG); + return max_bitflips; } -/* - * sends a pipeline command operation to the controller. See the Denali NAND - * controller's user guide for more information (section 4.2.3.6). - */ -static int denali_send_pipeline_cmd(struct denali_nand_info *denali, - bool ecc_en, bool transfer_spare, - int access_type, int op) +static int denali_sw_ecc_fixup(struct nand_chip *chip, + unsigned long *uncor_ecc_flags, u8 *buf) { - int status = PASS; - uint32_t page_count = 1; - uint32_t addr, cmd, irq_status, irq_mask; - - if (op == DENALI_READ) - irq_mask = INTR_STATUS__LOAD_COMP; - else if (op == DENALI_WRITE) - irq_mask = 0; - else - BUG(); - - setup_ecc_for_xfer(denali, ecc_en, transfer_spare); - - clear_interrupts(denali); - - addr = BANK(denali->flash_bank) | denali->page; - - if (op == DENALI_WRITE && access_type != SPARE_ACCESS) { - cmd = MODE_01 | addr; - iowrite32(cmd, denali->flash_mem); - } else if (op == DENALI_WRITE && access_type == SPARE_ACCESS) { - /* read spare area */ - cmd = MODE_10 | addr; - index_addr(denali, cmd, access_type); - - cmd = MODE_01 | addr; - iowrite32(cmd, denali->flash_mem); - } else if (op == DENALI_READ) { - /* setup page read request for access type */ - cmd = MODE_10 | addr; - index_addr(denali, cmd, access_type); - - /* - * page 33 of the NAND controller spec indicates we should not - * use the pipeline commands in Spare area only mode. - * So we don't. - */ - if (access_type == SPARE_ACCESS) { - cmd = MODE_01 | addr; - iowrite32(cmd, denali->flash_mem); - } else { - index_addr(denali, cmd, - PIPELINE_ACCESS | op | page_count); - + struct denali_controller *denali = to_denali_controller(chip); + struct mtd_ecc_stats *ecc_stats = &nand_to_mtd(chip)->ecc_stats; + unsigned int ecc_size = chip->ecc.size; + unsigned int bitflips = 0; + unsigned int max_bitflips = 0; + u32 err_addr, err_cor_info; + unsigned int err_byte, err_sector, err_device; + u8 err_cor_value; + unsigned int prev_sector = 0; + u32 irq_status; + + denali_reset_irq(denali); + + do { + err_addr = ioread32(denali->reg + ECC_ERROR_ADDRESS); + err_sector = FIELD_GET(ECC_ERROR_ADDRESS__SECTOR, err_addr); + err_byte = FIELD_GET(ECC_ERROR_ADDRESS__OFFSET, err_addr); + + err_cor_info = ioread32(denali->reg + ERR_CORRECTION_INFO); + err_cor_value = FIELD_GET(ERR_CORRECTION_INFO__BYTE, + err_cor_info); + err_device = FIELD_GET(ERR_CORRECTION_INFO__DEVICE, + err_cor_info); + + /* reset the bitflip counter when crossing ECC sector */ + if (err_sector != prev_sector) + bitflips = 0; + + if (err_cor_info & ERR_CORRECTION_INFO__UNCOR) { /* - * wait for command to be accepted - * can always use status0 bit as the - * mask is identical for each bank. + * Check later if this is a real ECC error, or + * an erased sector. */ - irq_status = wait_for_irq(denali, irq_mask); + *uncor_ecc_flags |= BIT(err_sector); + } else if (err_byte < ecc_size) { + /* + * If err_byte is larger than ecc_size, means error + * happened in OOB, so we ignore it. It's no need for + * us to correct it err_device is represented the NAND + * error bits are happened in if there are more than + * one NAND connected. + */ + int offset; + unsigned int flips_in_byte; - if (irq_status == 0) { - dev_err(denali->dev, - "cmd, page, addr on timeout (0x%x, 0x%x, 0x%x)\n", - cmd, denali->page, addr); - status = FAIL; - } else { - cmd = MODE_01 | addr; - iowrite32(cmd, denali->flash_mem); - } + offset = (err_sector * ecc_size + err_byte) * + denali->devs_per_cs + err_device; + + /* correct the ECC error */ + flips_in_byte = hweight8(buf[offset] ^ err_cor_value); + buf[offset] ^= err_cor_value; + ecc_stats->corrected += flips_in_byte; + bitflips += flips_in_byte; + + max_bitflips = max(max_bitflips, bitflips); } - } - return status; -} -/* helper function that simply writes a buffer to the flash */ -static int write_data_to_flash_mem(struct denali_nand_info *denali, - const uint8_t *buf, int len) -{ - uint32_t *buf32; - int i; + prev_sector = err_sector; + } while (!(err_cor_info & ERR_CORRECTION_INFO__LAST_ERR)); /* - * verify that the len is a multiple of 4. - * see comment in read_data_from_flash_mem() + * Once handle all ECC errors, controller will trigger an + * ECC_TRANSACTION_DONE interrupt. */ - BUG_ON((len % 4) != 0); + irq_status = denali_wait_for_irq(denali, INTR__ECC_TRANSACTION_DONE); + if (!(irq_status & INTR__ECC_TRANSACTION_DONE)) + return -EIO; - /* write the data to the flash memory */ - buf32 = (uint32_t *)buf; - for (i = 0; i < len / 4; i++) - iowrite32(*buf32++, denali->flash_mem + 0x10); - return i * 4; /* intent is to return the number of bytes read */ + return max_bitflips; } -/* helper function that simply reads a buffer from the flash */ -static int read_data_from_flash_mem(struct denali_nand_info *denali, - uint8_t *buf, int len) +static void denali_setup_dma64(struct denali_controller *denali, + dma_addr_t dma_addr, int page, bool write) { - uint32_t *buf32; - int i; + u32 mode; + const int page_count = 1; + + mode = DENALI_MAP10 | DENALI_BANK(denali) | page; + + /* DMA is a three step process */ /* - * we assume that len will be a multiple of 4, if not it would be nice - * to know about it ASAP rather than have random failures... - * This assumption is based on the fact that this function is designed - * to be used to read flash pages, which are typically multiples of 4. + * 1. setup transfer type, interrupt when complete, + * burst len = 64 bytes, the number of pages */ - BUG_ON((len % 4) != 0); + denali->host_write(denali, mode, + 0x01002000 | (64 << 16) | + (write ? BIT(8) : 0) | page_count); + + /* 2. set memory low address */ + denali->host_write(denali, mode, lower_32_bits(dma_addr)); - /* transfer the data from the flash */ - buf32 = (uint32_t *)buf; - for (i = 0; i < len / 4; i++) - *buf32++ = ioread32(denali->flash_mem + 0x10); - return i * 4; /* intent is to return the number of bytes read */ + /* 3. set memory high address */ + denali->host_write(denali, mode, upper_32_bits(dma_addr)); } -/* writes OOB data to the device */ -static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) +static void denali_setup_dma32(struct denali_controller *denali, + dma_addr_t dma_addr, int page, bool write) { - struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t irq_status; - uint32_t irq_mask = INTR_STATUS__PROGRAM_COMP | - INTR_STATUS__PROGRAM_FAIL; - int status = 0; + u32 mode; + const int page_count = 1; - denali->page = page; + mode = DENALI_MAP10 | DENALI_BANK(denali); - if (denali_send_pipeline_cmd(denali, false, false, SPARE_ACCESS, - DENALI_WRITE) == PASS) { - write_data_to_flash_mem(denali, buf, mtd->oobsize); + /* DMA is a four step process */ - /* wait for operation to complete */ - irq_status = wait_for_irq(denali, irq_mask); + /* 1. setup transfer type and # of pages */ + denali->host_write(denali, mode | page, + 0x2000 | (write ? BIT(8) : 0) | page_count); - if (irq_status == 0) { - dev_err(denali->dev, "OOB write failed\n"); - status = -EIO; - } + /* 2. set memory high address bits 23:8 */ + denali->host_write(denali, mode | ((dma_addr >> 16) << 8), 0x2200); - /* set the device back to MAIN_ACCESS */ - { - uint32_t addr; - uint32_t cmd; - addr = BANK(denali->flash_bank) | denali->page; - cmd = MODE_10 | addr; - index_addr(denali, (uint32_t)cmd, MAIN_ACCESS); - } + /* 3. set memory low address bits 23:8 */ + denali->host_write(denali, mode | ((dma_addr & 0xffff) << 8), 0x2300); - } else { - dev_err(denali->dev, "unable to send pipeline command\n"); - status = -EIO; - } - return status; + /* 4. interrupt when complete, burst len = 64 bytes */ + denali->host_write(denali, mode | 0x14000, 0x2400); } -/* reads OOB data from the device */ -static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) +static int denali_pio_read(struct denali_controller *denali, u32 *buf, + size_t size, int page) { - struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t irq_mask = INTR_STATUS__LOAD_COMP; - uint32_t irq_status, addr, cmd; + u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page; + u32 irq_status, ecc_err_mask; + int i; - denali->page = page; + if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) + ecc_err_mask = INTR__ECC_UNCOR_ERR; + else + ecc_err_mask = INTR__ECC_ERR; - if (denali_send_pipeline_cmd(denali, false, true, SPARE_ACCESS, - DENALI_READ) == PASS) { - read_data_from_flash_mem(denali, buf, mtd->oobsize); + denali_reset_irq(denali); - /* - * wait for command to be accepted - * can always use status0 bit as the - * mask is identical for each bank. - */ - irq_status = wait_for_irq(denali, irq_mask); + for (i = 0; i < size / 4; i++) + buf[i] = denali->host_read(denali, addr); - if (irq_status == 0) - dev_err(denali->dev, "page on OOB timeout %d\n", - denali->page); + irq_status = denali_wait_for_irq(denali, INTR__PAGE_XFER_INC); + if (!(irq_status & INTR__PAGE_XFER_INC)) + return -EIO; - /* - * We set the device back to MAIN_ACCESS here as I observed - * instability with the controller if you do a block erase - * and the last transaction was a SPARE_ACCESS. Block erase - * is reliable (according to the MTD test infrastructure) - * if you are in MAIN_ACCESS. - */ - addr = BANK(denali->flash_bank) | denali->page; - cmd = MODE_10 | addr; - index_addr(denali, cmd, MAIN_ACCESS); - } + if (irq_status & INTR__ERASED_PAGE) + memset(buf, 0xff, size); + + return irq_status & ecc_err_mask ? -EBADMSG : 0; } -/* - * this function examines buffers to see if they contain data that - * indicate that the buffer is part of an erased region of flash. - */ -static bool is_erased(uint8_t *buf, int len) +static int denali_pio_write(struct denali_controller *denali, const u32 *buf, + size_t size, int page) { + u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page; + u32 irq_status; int i; - for (i = 0; i < len; i++) - if (buf[i] != 0xFF) - return false; - return true; + denali_reset_irq(denali); + + for (i = 0; i < size / 4; i++) + denali->host_write(denali, addr, buf[i]); + + irq_status = denali_wait_for_irq(denali, + INTR__PROGRAM_COMP | + INTR__PROGRAM_FAIL); + if (!(irq_status & INTR__PROGRAM_COMP)) + return -EIO; + + return 0; } -#define ECC_SECTOR_SIZE 512 -#define ECC_SECTOR(x) (((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12) -#define ECC_BYTE(x) (((x) & ECC_ERROR_ADDRESS__OFFSET)) -#define ECC_CORRECTION_VALUE(x) ((x) & ERR_CORRECTION_INFO__BYTEMASK) -#define ECC_ERROR_CORRECTABLE(x) (!((x) & ERR_CORRECTION_INFO__ERROR_TYPE)) -#define ECC_ERR_DEVICE(x) (((x) & ERR_CORRECTION_INFO__DEVICE_NR) >> 8) -#define ECC_LAST_ERR(x) ((x) & ERR_CORRECTION_INFO__LAST_ERR_INFO) +static int denali_pio_xfer(struct denali_controller *denali, void *buf, + size_t size, int page, bool write) +{ + if (write) + return denali_pio_write(denali, buf, size, page); + else + return denali_pio_read(denali, buf, size, page); +} -static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, - uint32_t irq_status, unsigned int *max_bitflips) +static int denali_dma_xfer(struct denali_controller *denali, void *buf, + size_t size, int page, bool write) { - bool check_erased_page = false; - unsigned int bitflips = 0; + dma_addr_t dma_addr; + u32 irq_mask, irq_status, ecc_err_mask; + enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + int ret = 0; - if (denali->have_hw_ecc_fixup && - (irq_status & INTR_STATUS__ECC_UNCOR_ERR)) { - clear_interrupts(denali); - denali_set_intr_modes(denali, true); - check_erased_page = true; - } else if (irq_status & INTR_STATUS__ECC_ERR) { - /* read the ECC errors. we'll ignore them for now */ - uint32_t err_address, err_correction_info, err_byte, - err_sector, err_device, err_correction_value; - denali_set_intr_modes(denali, false); - - do { - err_address = ioread32(denali->flash_reg + - ECC_ERROR_ADDRESS); - err_sector = ECC_SECTOR(err_address); - err_byte = ECC_BYTE(err_address); - - err_correction_info = ioread32(denali->flash_reg + - ERR_CORRECTION_INFO); - err_correction_value = - ECC_CORRECTION_VALUE(err_correction_info); - err_device = ECC_ERR_DEVICE(err_correction_info); - - if (ECC_ERROR_CORRECTABLE(err_correction_info)) { - /* - * If err_byte is larger than ECC_SECTOR_SIZE, - * means error happened in OOB, so we ignore - * it. It's no need for us to correct it - * err_device is represented the NAND error - * bits are happened in if there are more - * than one NAND connected. - */ - if (err_byte < ECC_SECTOR_SIZE) { - int offset; - - offset = (err_sector * - ECC_SECTOR_SIZE + - err_byte) * - denali->devnum + - err_device; - /* correct the ECC error */ - buf[offset] ^= err_correction_value; - denali->nand.mtd.ecc_stats.corrected++; - bitflips++; - } - } else { - /* - * if the error is not correctable, need to - * look at the page to see if it is an erased - * page. if so, then it's not a real ECC error - */ - check_erased_page = true; - } - } while (!ECC_LAST_ERR(err_correction_info)); + dma_addr = dma_map_single(denali->dev, buf, size, dir); + if (dma_mapping_error(denali->dev, dma_addr)) { + dev_dbg(denali->dev, "Failed to DMA-map buffer. Trying PIO.\n"); + return denali_pio_xfer(denali, buf, size, page, write); + } + + if (write) { /* - * Once handle all ecc errors, controller will trigger - * a ECC_TRANSACTION_DONE interrupt, so here just wait - * for a while for this interrupt + * INTR__PROGRAM_COMP is never asserted for the DMA transfer. + * We can use INTR__DMA_CMD_COMP instead. This flag is asserted + * when the page program is completed. */ - while (!(read_interrupt_status(denali) & - INTR_STATUS__ECC_TRANSACTION_DONE)) - cpu_relax(); - clear_interrupts(denali); - denali_set_intr_modes(denali, true); + irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL; + ecc_err_mask = 0; + } else if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) { + irq_mask = INTR__DMA_CMD_COMP; + ecc_err_mask = INTR__ECC_UNCOR_ERR; + } else { + irq_mask = INTR__DMA_CMD_COMP; + ecc_err_mask = INTR__ECC_ERR; } - *max_bitflips = bitflips; - return check_erased_page; -} -/* programs the controller to either enable/disable DMA transfers */ -static void denali_enable_dma(struct denali_nand_info *denali, bool en) -{ - iowrite32(en ? DMA_ENABLE__FLAG : 0, denali->flash_reg + DMA_ENABLE); - ioread32(denali->flash_reg + DMA_ENABLE); + iowrite32(DMA_ENABLE__FLAG, denali->reg + DMA_ENABLE); + /* + * The ->setup_dma() hook kicks DMA by using the data/command + * interface, which belongs to a different AXI port from the + * register interface. Read back the register to avoid a race. + */ + ioread32(denali->reg + DMA_ENABLE); + + denali_reset_irq(denali); + denali->setup_dma(denali, dma_addr, page, write); + + irq_status = denali_wait_for_irq(denali, irq_mask); + if (!(irq_status & INTR__DMA_CMD_COMP)) + ret = -EIO; + else if (irq_status & ecc_err_mask) + ret = -EBADMSG; + + iowrite32(0, denali->reg + DMA_ENABLE); + + dma_unmap_single(denali->dev, dma_addr, size, dir); + + if (irq_status & INTR__ERASED_PAGE) + memset(buf, 0xff, size); + + return ret; } -/* setups the HW to perform the data DMA */ -static void denali_setup_dma(struct denali_nand_info *denali, int op) +static int denali_page_xfer(struct nand_chip *chip, void *buf, size_t size, + int page, bool write) { - uint32_t mode; - const int page_count = 1; - uint32_t addr = (unsigned long)denali->buf.buf; + struct denali_controller *denali = to_denali_controller(chip); - mode = MODE_10 | BANK(denali->flash_bank); + denali_select_target(chip, chip->cur_cs); - /* DMA is a four step process */ + if (denali->dma_avail) + return denali_dma_xfer(denali, buf, size, page, write); + else + return denali_pio_xfer(denali, buf, size, page, write); +} - /* 1. setup transfer type and # of pages */ - index_addr(denali, mode | denali->page, 0x2000 | op | page_count); +static int denali_read_page(struct nand_chip *chip, u8 *buf, + int oob_required, int page) +{ + struct denali_controller *denali = to_denali_controller(chip); + struct mtd_info *mtd = nand_to_mtd(chip); + unsigned long uncor_ecc_flags = 0; + int stat = 0; + int ret; + + ret = denali_page_xfer(chip, buf, mtd->writesize, page, false); + if (ret && ret != -EBADMSG) + return ret; + + if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) + stat = denali_hw_ecc_fixup(chip, &uncor_ecc_flags); + else if (ret == -EBADMSG) + stat = denali_sw_ecc_fixup(chip, &uncor_ecc_flags, buf); + + if (stat < 0) + return stat; + + if (uncor_ecc_flags) { + ret = denali_read_oob(chip, page); + if (ret) + return ret; + + stat = denali_check_erased_page(chip, buf, + uncor_ecc_flags, stat); + } - /* 2. set memory high address bits 23:8 */ - index_addr(denali, mode | ((addr >> 16) << 8), 0x2200); + return stat; +} - /* 3. set memory low address bits 23:8 */ - index_addr(denali, mode | ((addr & 0xffff) << 8), 0x2300); +static int denali_write_page(struct nand_chip *chip, const u8 *buf, + int oob_required, int page) +{ + struct mtd_info *mtd = nand_to_mtd(chip); - /* 4. interrupt when complete, burst len = 64 bytes */ - index_addr(denali, mode | 0x14000, 0x2400); + return denali_page_xfer(chip, (void *)buf, mtd->writesize, page, true); } -/* - * writes a page. user specifies type, and this function handles the - * configuration details. - */ -static int write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, bool raw_xfer) +static int denali_setup_interface(struct nand_chip *chip, int chipnr, + const struct nand_interface_config *conf) { - struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = (unsigned long)denali->buf.buf; - size_t size = mtd->writesize + mtd->oobsize; - uint32_t irq_status; - uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP | - INTR_STATUS__PROGRAM_FAIL; + static const unsigned int data_setup_on_host = 10000; + struct denali_controller *denali = to_denali_controller(chip); + struct denali_chip_sel *sel; + const struct nand_sdr_timings *timings; + unsigned long t_x, mult_x; + int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data; + int rdwr_en_lo, rdwr_en_hi, rdwr_en_lo_hi, cs_setup; + int addr_2_data_mask; + u32 tmp; + + timings = nand_get_sdr_timings(conf); + if (IS_ERR(timings)) + return PTR_ERR(timings); + + /* clk_x period in picoseconds */ + t_x = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate); + if (!t_x) + return -EINVAL; /* - * if it is a raw xfer, we want to disable ecc and send the spare area. - * !raw_xfer - enable ecc - * raw_xfer - transfer spare + * The bus interface clock, clk_x, is phase aligned with the core clock. + * The clk_x is an integral multiple N of the core clk. The value N is + * configured at IP delivery time, and its available value is 4, 5, 6. */ - setup_ecc_for_xfer(denali, !raw_xfer, raw_xfer); + mult_x = DIV_ROUND_CLOSEST_ULL(denali->clk_x_rate, denali->clk_rate); + if (mult_x < 4 || mult_x > 6) + return -EINVAL; - /* copy buffer into DMA buffer */ - memcpy(denali->buf.buf, buf, mtd->writesize); + if (chipnr == NAND_DATA_IFACE_CHECK_ONLY) + return 0; - if (raw_xfer) { - /* transfer the data to the spare area */ - memcpy(denali->buf.buf + mtd->writesize, - chip->oob_poi, - mtd->oobsize); - } + sel = &to_denali_chip(chip)->sels[chipnr]; - dma_sync_single_for_device(addr, size, DMA_TO_DEVICE); + /* tRWH -> RE_2_WE */ + re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_x); + re_2_we = min_t(int, re_2_we, RE_2_WE__VALUE); - clear_interrupts(denali); - denali_enable_dma(denali, true); + tmp = ioread32(denali->reg + RE_2_WE); + tmp &= ~RE_2_WE__VALUE; + tmp |= FIELD_PREP(RE_2_WE__VALUE, re_2_we); + sel->re_2_we = tmp; - denali_setup_dma(denali, DENALI_WRITE); + /* tRHZ -> RE_2_RE */ + re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_x); + re_2_re = min_t(int, re_2_re, RE_2_RE__VALUE); - /* wait for operation to complete */ - irq_status = wait_for_irq(denali, irq_mask); + tmp = ioread32(denali->reg + RE_2_RE); + tmp &= ~RE_2_RE__VALUE; + tmp |= FIELD_PREP(RE_2_RE__VALUE, re_2_re); + sel->re_2_re = tmp; - if (irq_status == 0) { - dev_err(denali->dev, "timeout on write_page (type = %d)\n", - raw_xfer); - denali->status = NAND_STATUS_FAIL; - } + /* + * tCCS, tWHR -> WE_2_RE + * + * With WE_2_RE properly set, the Denali controller automatically takes + * care of the delay; the driver need not set NAND_WAIT_TCCS. + */ + we_2_re = DIV_ROUND_UP(max(timings->tCCS_min, timings->tWHR_min), t_x); + we_2_re = min_t(int, we_2_re, TWHR2_AND_WE_2_RE__WE_2_RE); - denali_enable_dma(denali, false); - dma_sync_single_for_cpu(addr, size, DMA_TO_DEVICE); + tmp = ioread32(denali->reg + TWHR2_AND_WE_2_RE); + tmp &= ~TWHR2_AND_WE_2_RE__WE_2_RE; + tmp |= FIELD_PREP(TWHR2_AND_WE_2_RE__WE_2_RE, we_2_re); + sel->hwhr2_and_we_2_re = tmp; - return 0; -} + /* tADL -> ADDR_2_DATA */ -/* NAND core entry points */ + /* for older versions, ADDR_2_DATA is only 6 bit wide */ + addr_2_data_mask = TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA; + if (denali->revision < 0x0501) + addr_2_data_mask >>= 1; + + addr_2_data = DIV_ROUND_UP(timings->tADL_min, t_x); + addr_2_data = min_t(int, addr_2_data, addr_2_data_mask); + + tmp = ioread32(denali->reg + TCWAW_AND_ADDR_2_DATA); + tmp &= ~TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA; + tmp |= FIELD_PREP(TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA, addr_2_data); + sel->tcwaw_and_addr_2_data = tmp; + + /* tREH, tWH -> RDWR_EN_HI_CNT */ + rdwr_en_hi = DIV_ROUND_UP(max(timings->tREH_min, timings->tWH_min), + t_x); + rdwr_en_hi = min_t(int, rdwr_en_hi, RDWR_EN_HI_CNT__VALUE); + + tmp = ioread32(denali->reg + RDWR_EN_HI_CNT); + tmp &= ~RDWR_EN_HI_CNT__VALUE; + tmp |= FIELD_PREP(RDWR_EN_HI_CNT__VALUE, rdwr_en_hi); + sel->rdwr_en_hi_cnt = tmp; -/* - * this is the callback that the NAND core calls to write a page. Since - * writing a page with ECC or without is similar, all the work is done - * by write_page above. - */ -static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) -{ /* - * for regular page writes, we let HW handle all the ECC - * data written to the device. + * tREA -> ACC_CLKS + * tRP, tWP, tRHOH, tRC, tWC -> RDWR_EN_LO_CNT */ - return write_page(mtd, chip, buf, false); -} -/* - * This is the callback that the NAND core calls to write a page without ECC. - * raw access is similar to ECC page writes, so all the work is done in the - * write_page() function above. - */ -static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) -{ /* - * for raw page writes, we want to disable ECC and simply write - * whatever data is in the buffer. + * Determine the minimum of acc_clks to meet the setup timing when + * capturing the incoming data. + * + * The delay on the chip side is well-defined as tREA, but we need to + * take additional delay into account. This includes a certain degree + * of unknowledge, such as signal propagation delays on the PCB and + * in the SoC, load capacity of the I/O pins, etc. */ - return write_page(mtd, chip, buf, true); + acc_clks = DIV_ROUND_UP(timings->tREA_max + data_setup_on_host, t_x); + + /* Determine the minimum of rdwr_en_lo_cnt from RE#/WE# pulse width */ + rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min), t_x); + + /* Extend rdwr_en_lo to meet the data hold timing */ + rdwr_en_lo = max_t(int, rdwr_en_lo, + acc_clks - timings->tRHOH_min / t_x); + + /* Extend rdwr_en_lo to meet the requirement for RE#/WE# cycle time */ + rdwr_en_lo_hi = DIV_ROUND_UP(max(timings->tRC_min, timings->tWC_min), + t_x); + rdwr_en_lo = max(rdwr_en_lo, rdwr_en_lo_hi - rdwr_en_hi); + rdwr_en_lo = min_t(int, rdwr_en_lo, RDWR_EN_LO_CNT__VALUE); + + /* Center the data latch timing for extra safety */ + acc_clks = (acc_clks + rdwr_en_lo + + DIV_ROUND_UP(timings->tRHOH_min, t_x)) / 2; + acc_clks = min_t(int, acc_clks, ACC_CLKS__VALUE); + + tmp = ioread32(denali->reg + ACC_CLKS); + tmp &= ~ACC_CLKS__VALUE; + tmp |= FIELD_PREP(ACC_CLKS__VALUE, acc_clks); + sel->acc_clks = tmp; + + tmp = ioread32(denali->reg + RDWR_EN_LO_CNT); + tmp &= ~RDWR_EN_LO_CNT__VALUE; + tmp |= FIELD_PREP(RDWR_EN_LO_CNT__VALUE, rdwr_en_lo); + sel->rdwr_en_lo_cnt = tmp; + + /* tCS, tCEA -> CS_SETUP_CNT */ + cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_x) - rdwr_en_lo, + (int)DIV_ROUND_UP(timings->tCEA_max, t_x) - acc_clks, + 0); + cs_setup = min_t(int, cs_setup, CS_SETUP_CNT__VALUE); + + tmp = ioread32(denali->reg + CS_SETUP_CNT); + tmp &= ~CS_SETUP_CNT__VALUE; + tmp |= FIELD_PREP(CS_SETUP_CNT__VALUE, cs_setup); + sel->cs_setup_cnt = tmp; + + return 0; } -static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +int denali_calc_ecc_bytes(int step_size, int strength) { - return write_oob_data(mtd, chip->oob_poi, page); + /* BCH code. Denali requires ecc.bytes to be multiple of 2 */ + return DIV_ROUND_UP(strength * fls(step_size * 8), 16) * 2; } +EXPORT_SYMBOL(denali_calc_ecc_bytes); -static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int denali_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) { - read_oob_data(mtd, chip->oob_poi, page); + struct nand_chip *chip = mtd_to_nand(mtd); + struct denali_controller *denali = to_denali_controller(chip); + + if (section > 0) + return -ERANGE; + + oobregion->offset = denali->oob_skip_bytes; + oobregion->length = chip->ecc.total; return 0; } -static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int denali_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) { - unsigned int max_bitflips = 0; - struct denali_nand_info *denali = mtd_to_denali(mtd); - - dma_addr_t addr = (unsigned long)denali->buf.buf; - size_t size = mtd->writesize + mtd->oobsize; - - uint32_t irq_status; - uint32_t irq_mask = denali->have_hw_ecc_fixup ? - (INTR_STATUS__DMA_CMD_COMP) : - (INTR_STATUS__ECC_TRANSACTION_DONE | INTR_STATUS__ECC_ERR); - bool check_erased_page = false; - - if (page != denali->page) { - dev_err(denali->dev, - "IN %s: page %d is not equal to denali->page %d", - __func__, page, denali->page); - BUG(); - } + struct nand_chip *chip = mtd_to_nand(mtd); + struct denali_controller *denali = to_denali_controller(chip); - setup_ecc_for_xfer(denali, true, false); + if (section > 0) + return -ERANGE; - denali_enable_dma(denali, true); - dma_sync_single_for_device(addr, size, DMA_FROM_DEVICE); + oobregion->offset = chip->ecc.total + denali->oob_skip_bytes; + oobregion->length = mtd->oobsize - oobregion->offset; - clear_interrupts(denali); - denali_setup_dma(denali, DENALI_READ); + return 0; +} - /* wait for operation to complete */ - irq_status = wait_for_irq(denali, irq_mask); +static const struct mtd_ooblayout_ops denali_ooblayout_ops = { + .ecc = denali_ooblayout_ecc, + .free = denali_ooblayout_free, +}; - dma_sync_single_for_cpu(addr, size, DMA_FROM_DEVICE); +static int denali_multidev_fixup(struct nand_chip *chip) +{ + struct denali_controller *denali = to_denali_controller(chip); + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; - memcpy(buf, denali->buf.buf, mtd->writesize); + memorg = nanddev_get_memorg(&chip->base); - check_erased_page = handle_ecc(denali, buf, irq_status, &max_bitflips); - denali_enable_dma(denali, false); + /* + * Support for multi device: + * When the IP configuration is x16 capable and two x8 chips are + * connected in parallel, DEVICES_CONNECTED should be set to 2. + * In this case, the core framework knows nothing about this fact, + * so we should tell it the _logical_ pagesize and anything necessary. + */ + denali->devs_per_cs = ioread32(denali->reg + DEVICES_CONNECTED); - if (check_erased_page) { - if (denali->have_hw_ecc_fixup) { - /* When we have hw ecc fixup, don't check oob. - * That code below looks jacked up anyway. I mean, - * look at it, wtf? */ - if (!is_erased(buf, mtd->writesize)) - mtd->ecc_stats.failed++; - } else { - read_oob_data(&denali->nand.mtd, chip->oob_poi, - denali->page); - - /* check ECC failures that may have occurred on - * erased pages */ - if (check_erased_page) { - if (!is_erased(buf, mtd->writesize)) - mtd->ecc_stats.failed++; - if (!is_erased(buf, mtd->oobsize)) - mtd->ecc_stats.failed++; - } - } + /* + * On some SoCs, DEVICES_CONNECTED is not auto-detected. + * For those, DEVICES_CONNECTED is left to 0. Set 1 if it is the case. + */ + if (denali->devs_per_cs == 0) { + denali->devs_per_cs = 1; + iowrite32(1, denali->reg + DEVICES_CONNECTED); } - return max_bitflips; -} -static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = (unsigned long)denali->buf.buf; - size_t size = mtd->writesize + mtd->oobsize; - uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP; - - if (page != denali->page) { - dev_err(denali->dev, - "IN %s: page %d is not equal to denali->page %d", - __func__, page, denali->page); - BUG(); + if (denali->devs_per_cs == 1) + return 0; + + if (denali->devs_per_cs != 2) { + dev_err(denali->dev, "unsupported number of devices %d\n", + denali->devs_per_cs); + return -EINVAL; } - setup_ecc_for_xfer(denali, false, true); - denali_enable_dma(denali, true); + /* 2 chips in parallel */ + memorg->pagesize <<= 1; + memorg->oobsize <<= 1; + mtd->size <<= 1; + mtd->erasesize <<= 1; + mtd->writesize <<= 1; + mtd->oobsize <<= 1; + chip->page_shift += 1; + chip->phys_erase_shift += 1; + chip->bbt_erase_shift += 1; + chip->chip_shift += 1; + chip->pagemask <<= 1; + chip->ecc.size <<= 1; + chip->ecc.bytes <<= 1; + chip->ecc.strength <<= 1; + denali->oob_skip_bytes <<= 1; - dma_sync_single_for_device(addr, size, DMA_FROM_DEVICE); + return 0; +} - clear_interrupts(denali); - denali_setup_dma(denali, DENALI_READ); +static int denali_attach_chip(struct nand_chip *chip) +{ + struct denali_controller *denali = to_denali_controller(chip); + struct mtd_info *mtd = nand_to_mtd(chip); + int ret; + + ret = nand_ecc_choose_conf(chip, denali->ecc_caps, + mtd->oobsize - denali->oob_skip_bytes); + if (ret) { + printk("%s: %d\n", __func__, ret); + dev_err(denali->dev, "Failed to setup ECC settings.\n"); + return ret; + } - /* wait for operation to complete */ - wait_for_irq(denali, irq_mask); + dev_dbg(denali->dev, + "chosen ECC settings: step=%d, strength=%d, bytes=%d\n", + chip->ecc.size, chip->ecc.strength, chip->ecc.bytes); - dma_sync_single_for_cpu(addr, size, DMA_FROM_DEVICE); + ret = denali_multidev_fixup(chip); + if (ret) + return ret; - denali_enable_dma(denali, false); + return 0; +} - memcpy(buf, denali->buf.buf, mtd->writesize); - memcpy(chip->oob_poi, denali->buf.buf + mtd->writesize, mtd->oobsize); +static void denali_exec_in8(struct denali_controller *denali, u32 type, + u8 *buf, unsigned int len) +{ + int i; - return 0; + for (i = 0; i < len; i++) + buf[i] = denali->host_read(denali, type | DENALI_BANK(denali)); } -static uint8_t denali_read_byte(struct mtd_info *mtd) +static void denali_exec_in16(struct denali_controller *denali, u32 type, + u8 *buf, unsigned int len) { - struct denali_nand_info *denali = mtd_to_denali(mtd); - uint8_t result = 0xff; + u32 data; + int i; - if (denali->buf.head < denali->buf.tail) - result = denali->buf.buf[denali->buf.head++]; + for (i = 0; i < len; i += 2) { + data = denali->host_read(denali, type | DENALI_BANK(denali)); + /* bit 31:24 and 15:8 are used for DDR */ + buf[i] = data; + buf[i + 1] = data >> 16; + } +} - return result; +static void denali_exec_in(struct denali_controller *denali, u32 type, + u8 *buf, unsigned int len, bool width16) +{ + if (width16) + denali_exec_in16(denali, type, buf, len); + else + denali_exec_in8(denali, type, buf, len); } -static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static void denali_exec_out8(struct denali_controller *denali, u32 type, + const u8 *buf, unsigned int len) { int i; + for (i = 0; i < len; i++) - buf[i] = denali_read_byte(mtd); + denali->host_write(denali, type | DENALI_BANK(denali), buf[i]); } -static void denali_select_chip(struct mtd_info *mtd, int chip) +static void denali_exec_out16(struct denali_controller *denali, u32 type, + const u8 *buf, unsigned int len) { - struct denali_nand_info *denali = mtd_to_denali(mtd); + int i; - denali->flash_bank = chip; + for (i = 0; i < len; i += 2) + denali->host_write(denali, type | DENALI_BANK(denali), + buf[i + 1] << 16 | buf[i]); } -static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) +static void denali_exec_out(struct denali_controller *denali, u32 type, + const u8 *buf, unsigned int len, bool width16) { - struct denali_nand_info *denali = mtd_to_denali(mtd); - int status = denali->status; + if (width16) + denali_exec_out16(denali, type, buf, len); + else + denali_exec_out8(denali, type, buf, len); +} - denali->status = 0; +static int denali_exec_waitrdy(struct denali_controller *denali) +{ + u32 irq_stat; - return status; + /* R/B# pin transitioned from low to high? */ + irq_stat = denali_wait_for_irq(denali, INTR__INT_ACT); + + /* Just in case nand_operation has multiple NAND_OP_WAITRDY_INSTR. */ + denali_reset_irq(denali); + + return irq_stat & INTR__INT_ACT ? 0 : -EIO; } -static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, - int page) +static int denali_exec_instr(struct nand_chip *chip, + const struct nand_op_instr *instr) { - struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t addr, id; - uint32_t pages_per_block; - uint32_t block; - int i; + struct denali_controller *denali = to_denali_controller(chip); - switch (cmd) { - case NAND_CMD_PAGEPROG: - break; - case NAND_CMD_STATUS: - read_status(denali); - break; - case NAND_CMD_READID: - reset_buf(denali); - /* - * sometimes ManufactureId read from register is not right - * e.g. some of Micron MT29F32G08QAA MLC NAND chips - * So here we send READID cmd to NAND insteand - */ - addr = MODE_11 | BANK(denali->flash_bank); - index_addr(denali, addr | 0, 0x90); - index_addr(denali, addr | 1, col); - for (i = 0; i < 8; i++) { - index_addr_read_data(denali, addr | 2, &id); - write_byte_to_buf(denali, id); - } - break; - case NAND_CMD_PARAM: - reset_buf(denali); - - /* turn on R/B interrupt */ - denali_set_intr_modes(denali, false); - denali_irq_mask = DENALI_IRQ_ALL | INTR_STATUS__INT_ACT; - clear_interrupts(denali); - denali_irq_enable(denali, denali_irq_mask); - denali_set_intr_modes(denali, true); - - addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); - index_addr(denali, (uint32_t)addr | 0, cmd); - index_addr(denali, (uint32_t)addr | 1, col & 0xFF); - /* Wait tR time... */ - udelay(25); - /* And then wait for R/B interrupt */ - wait_for_irq(denali, INTR_STATUS__INT_ACT); - - /* turn off R/B interrupt now */ - denali_irq_mask = DENALI_IRQ_ALL; - denali_set_intr_modes(denali, false); - denali_irq_enable(denali, denali_irq_mask); - denali_set_intr_modes(denali, true); - - for (i = 0; i < 256; i++) { - index_addr_read_data(denali, - (uint32_t)addr | 2, - &id); - write_byte_to_buf(denali, id); - } - break; - case NAND_CMD_READ0: - case NAND_CMD_SEQIN: - denali->page = page; - break; - case NAND_CMD_RESET: - reset_bank(denali); - break; - case NAND_CMD_READOOB: - /* TODO: Read OOB data */ - break; - case NAND_CMD_UNLOCK1: - pages_per_block = mtd->erasesize / mtd->writesize; - block = page / pages_per_block; - addr = (uint32_t)MODE_10 | (block * pages_per_block); - index_addr(denali, addr, 0x10); - break; - case NAND_CMD_UNLOCK2: - pages_per_block = mtd->erasesize / mtd->writesize; - block = (page+pages_per_block-1) / pages_per_block; - addr = (uint32_t)MODE_10 | (block * pages_per_block); - index_addr(denali, addr, 0x11); - break; - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - addr = MODE_10 | BANK(denali->flash_bank) | page; - index_addr(denali, addr, 0x1); - break; + switch (instr->type) { + case NAND_OP_CMD_INSTR: + denali_exec_out8(denali, DENALI_MAP11_CMD, + &instr->ctx.cmd.opcode, 1); + return 0; + case NAND_OP_ADDR_INSTR: + denali_exec_out8(denali, DENALI_MAP11_ADDR, + instr->ctx.addr.addrs, + instr->ctx.addr.naddrs); + return 0; + case NAND_OP_DATA_IN_INSTR: + denali_exec_in(denali, DENALI_MAP11_DATA, + instr->ctx.data.buf.in, + instr->ctx.data.len, + !instr->ctx.data.force_8bit && + chip->options & NAND_BUSWIDTH_16); + return 0; + case NAND_OP_DATA_OUT_INSTR: + denali_exec_out(denali, DENALI_MAP11_DATA, + instr->ctx.data.buf.out, + instr->ctx.data.len, + !instr->ctx.data.force_8bit && + chip->options & NAND_BUSWIDTH_16); + return 0; + case NAND_OP_WAITRDY_INSTR: + return denali_exec_waitrdy(denali); default: - pr_err(": unsupported command received 0x%x\n", cmd); - break; + WARN_ONCE(1, "unsupported NAND instruction type: %d\n", + instr->type); + + return -EINVAL; } } -/* end NAND core entry points */ -/* Initialization code to bring the device up to a known good state */ -static void denali_hw_init(struct denali_nand_info *denali) +static int denali_exec_op(struct nand_chip *chip, + const struct nand_operation *op, bool check_only) { + int i, ret; + + if (check_only) + return 0; + + denali_select_target(chip, op->cs); + /* - * tell driver how many bit controller will skip before - * writing ECC code in OOB, this register may be already - * set by firmware. So we read this value out. - * if this value is 0, just let it be. + * Some commands contain NAND_OP_WAITRDY_INSTR. + * irq must be cleared here to catch the R/B# interrupt there. */ - denali->bbtskipbytes = ioread32(denali->flash_reg + - SPARE_AREA_SKIP_BYTES); - detect_max_banks(denali); - denali_nand_reset(denali); - iowrite32(0x0F, denali->flash_reg + RB_PIN_ENABLED); - iowrite32(CHIP_EN_DONT_CARE__FLAG, - denali->flash_reg + CHIP_ENABLE_DONT_CARE); - - iowrite32(0xffff, denali->flash_reg + SPARE_AREA_MARKER); - - /* Should set value for these registers when init */ - iowrite32(0, denali->flash_reg + TWO_ROW_ADDR_CYCLES); - iowrite32(1, denali->flash_reg + ECC_ENABLE); - denali_nand_timing_set(denali); - denali_irq_init(denali); -} + denali_reset_irq(to_denali_controller(chip)); -/* - * Althogh controller spec said SLC ECC is forceb to be 4bit, - * but denali controller in MRST only support 15bit and 8bit ECC - * correction - */ -#define ECC_8BITS 14 -static struct nand_ecclayout nand_8bit_oob = { - .eccbytes = 14, -}; + for (i = 0; i < op->ninstrs; i++) { + ret = denali_exec_instr(chip, &op->instrs[i]); + if (ret) + return ret; + } -#define ECC_15BITS 26 -static struct nand_ecclayout nand_15bit_oob = { - .eccbytes = 26, + return 0; +} + +static const struct nand_controller_ops denali_controller_ops = { + .attach_chip = denali_attach_chip, + .exec_op = denali_exec_op, + .setup_interface = denali_setup_interface, }; -/* initialize driver data structures */ -static void denali_drv_init(struct denali_nand_info *denali) +int denali_chip_init(struct denali_controller *denali, + struct denali_chip *dchip) { - denali->idx = 0; + struct nand_chip *chip = &dchip->chip; + struct mtd_info *mtd = nand_to_mtd(chip); + struct denali_chip *dchip2; + int i, j, ret; - /* indicate that MTD has not selected a valid bank yet */ - denali->flash_bank = CHIP_SELECT_INVALID; + chip->controller = &denali->controller; - /* initialize our irq_status variable to indicate no interrupts */ - denali->irq_status = 0; -} + /* sanity checks for bank numbers */ + for (i = 0; i < dchip->nsels; i++) { + unsigned int bank = dchip->sels[i].bank; -int denali_init(struct denali_nand_info *denali) -{ - struct nand_chip *nand = &denali->nand; - struct mtd_info *mtd = &nand->mtd; - int ret = 0; - uint32_t val; - - if (denali->platform == INTEL_CE4100) { - /* - * Due to a silicon limitation, we can only support - * ONFI timing mode 1 and below. - */ - if (onfi_timing_mode < -1 || onfi_timing_mode > 1) { - pr_err("Intel CE4100 only supports ONFI timing mode 1 or below\n"); + if (bank >= denali->nbanks) { + dev_err(denali->dev, "unsupported bank %d\n", bank); return -EINVAL; } - } - /* allocate a temporary buffer for nand_scan_ident() */ - denali->buf.buf = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (!denali->buf.buf) - return -ENOMEM; - - mtd->parent = denali->dev; - denali_hw_init(denali); - denali_drv_init(denali); + for (j = 0; j < i; j++) { + if (bank == dchip->sels[j].bank) { + dev_err(denali->dev, + "bank %d is assigned twice in the same chip\n", + bank); + return -EINVAL; + } + } - denali_set_intr_modes(denali, true); - mtd->name = "denali-nand"; + list_for_each_entry(dchip2, &denali->chips, node) { + for (j = 0; j < dchip2->nsels; j++) { + if (bank == dchip2->sels[j].bank) { + dev_err(denali->dev, + "bank %d is already used\n", + bank); + return -EINVAL; + } + } + } + } - /* register the driver with the NAND core subsystem */ - nand->read_buf = denali_read_buf; - nand->select_chip = denali_select_chip; - nand->cmdfunc = denali_cmdfunc; - nand->read_byte = denali_read_byte; - nand->waitfunc = denali_waitfunc; + mtd->dev.parent = denali->dev; /* - * scan for NAND devices attached to the controller - * this is the first stage in a two step process to register - * with the nand subsystem + * Fallback to the default name if DT did not give "label" property. + * Use "label" property if multiple chips are connected. */ - if (nand_scan_ident(mtd, denali->max_banks, NULL)) { - ret = -ENXIO; - goto failed_req_irq; + if (!mtd->name && list_empty(&denali->chips)) + mtd->name = "denali-nand"; + + if (denali->dma_avail) { + chip->options |= NAND_USES_DMA; + chip->buf_align = 16; } - /* allocate the right size buffer now */ - kfree(denali->buf.buf); - denali->buf.buf = kzalloc(mtd->writesize + mtd->oobsize, - GFP_KERNEL); - if (!denali->buf.buf) { - ret = -ENOMEM; - goto failed_req_irq; + /* clk rate info is needed for setup_interface */ + if (!denali->clk_rate || !denali->clk_x_rate) + chip->options |= NAND_KEEP_TIMINGS; + + chip->bbt_options |= NAND_BBT_USE_FLASH; + chip->bbt_options |= NAND_BBT_NO_OOB; + chip->options |= NAND_NO_SUBPAGE_WRITE; + chip->ecc.mode = NAND_ECC_HW_SYNDROME; + chip->ecc.read_page = denali_read_page; + chip->ecc.write_page = denali_write_page; + chip->ecc.read_page_raw = denali_read_page_raw; + chip->ecc.write_page_raw = denali_write_page_raw; + chip->ecc.read_oob = denali_read_oob; + chip->ecc.write_oob = denali_write_oob; + + mtd_set_ooblayout(mtd, &denali_ooblayout_ops); + + ret = nand_scan(chip, dchip->nsels); + if (ret) + return ret; + + ret = add_mtd_nand_device(mtd, "nand"); + if (ret) { + dev_err(denali->dev, "Failed to register MTD: %d\n", ret); + goto cleanup_nand; } - /* - * support for multi nand - * MTD known nothing about multi nand, so we should tell it - * the real pagesize and anything necessery - */ - denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED); - nand->chipsize <<= (denali->devnum - 1); - nand->page_shift += (denali->devnum - 1); - nand->pagemask = (nand->chipsize >> nand->page_shift) - 1; - nand->bbt_erase_shift += (denali->devnum - 1); - nand->phys_erase_shift = nand->bbt_erase_shift; - nand->chip_shift += (denali->devnum - 1); - mtd->writesize <<= (denali->devnum - 1); - mtd->oobsize <<= (denali->devnum - 1); - mtd->erasesize <<= (denali->devnum - 1); - mtd->size = nand->numchips * nand->chipsize; - denali->bbtskipbytes *= denali->devnum; + list_add_tail(&dchip->node, &denali->chips); + + return 0; + +cleanup_nand: + nand_cleanup(chip); + + return ret; +} +EXPORT_SYMBOL_GPL(denali_chip_init); + +int denali_init(struct denali_controller *denali) +{ + u32 features = ioread32(denali->reg + FEATURES); + + nand_controller_init(&denali->controller); + denali->controller.ops = &denali_controller_ops; + spin_lock_init(&denali->irq_lock); + INIT_LIST_HEAD(&denali->chips); + denali->active_bank = DENALI_INVALID_BANK; /* - * second stage of the NAND scan - * this stage requires information regarding ECC and - * bad block management. + * The REVISION register may not be reliable. Platforms are allowed to + * override it. */ + if (!denali->revision) + denali->revision = swab16(ioread32(denali->reg + REVISION)); - /* Bad block table description is set by nand framework, - see nand_bbt.c */ + denali->nbanks = 1 << FIELD_GET(FEATURES__N_BANKS, features); - nand->bbt_options |= NAND_BBT_USE_FLASH; - nand->ecc.mode = NAND_ECC_HW_SYNDROME; - if (denali->have_hw_ecc_fixup) { - /* We have OOB support, so allow scan of BBT - and leave the OOB alone */ - nand->bbt_options |= NAND_BBT_NO_OOB; - } else { - /* skip the scan for now until we have OOB read and write support */ - nand->options |= NAND_SKIP_BBTSCAN; + /* the encoding changed from rev 5.0 to 5.1 */ + if (denali->revision < 0x0501) + denali->nbanks <<= 1; + + if (features & FEATURES__DMA) + denali->dma_avail = true; + + if (denali->dma_avail) { + int dma_bit = denali->caps & DENALI_CAP_DMA_64BIT ? 64 : 32; + + dma_set_mask(denali->dev, DMA_BIT_MASK(dma_bit)); } - /* no subpage writes on denali */ - nand->options |= NAND_NO_SUBPAGE_WRITE; + if (denali->dma_avail) { + if (denali->caps & DENALI_CAP_DMA_64BIT) + denali->setup_dma = denali_setup_dma64; + else + denali->setup_dma = denali_setup_dma32; + } - /* - * Denali Controller only support 15bit and 8bit ECC in MRST, - * so just let controller do 15bit ECC for MLC and 8bit ECC for - * SLC if possible. - * */ - if (!nand_is_slc(&denali->nand) && - (mtd->oobsize > (denali->bbtskipbytes + - ECC_15BITS * (mtd->writesize / - ECC_SECTOR_SIZE)))) { - /* if MLC OOB size is large enough, use 15bit ECC*/ - nand->ecc.strength = 15; - nand->ecc.layout = &nand_15bit_oob; - nand->ecc.bytes = ECC_15BITS; - iowrite32(15, denali->flash_reg + ECC_CORRECTION); - } else if (mtd->oobsize < (denali->bbtskipbytes + - ECC_8BITS * (mtd->writesize / - ECC_SECTOR_SIZE))) { - pr_err("Your NAND chip OOB is not large enough to contain 8bit ECC correction codes"); - goto failed_req_irq; + if (features & FEATURES__INDEX_ADDR) { + denali->host_read = denali_indexed_read; + denali->host_write = denali_indexed_write; } else { - nand->ecc.strength = 8; - nand->ecc.layout = &nand_8bit_oob; - nand->ecc.bytes = ECC_8BITS; - iowrite32(8, denali->flash_reg + ECC_CORRECTION); + denali->host_read = denali_direct_read; + denali->host_write = denali_direct_write; } - nand->ecc.bytes *= denali->devnum; - nand->ecc.strength *= denali->devnum; - nand->ecc.layout->eccbytes *= - mtd->writesize / ECC_SECTOR_SIZE; - nand->ecc.layout->oobfree[0].offset = - denali->bbtskipbytes + nand->ecc.layout->eccbytes; - nand->ecc.layout->oobfree[0].length = - mtd->oobsize - nand->ecc.layout->eccbytes - - denali->bbtskipbytes; - /* - * Let driver know the total blocks number and how many blocks - * contained by each nand chip. blksperchip will help driver to - * know how many blocks is taken by FW. + * Set how many bytes should be skipped before writing data in OOB. + * If a platform requests a non-zero value, set it to the register. + * Otherwise, read the value out, expecting it has already been set up + * by firmware. */ - denali->totalblks = mtd->size >> nand->phys_erase_shift; - denali->blksperchip = denali->totalblks / nand->numchips; - - /* override the default read operations */ - nand->ecc.size = ECC_SECTOR_SIZE * denali->devnum; - nand->ecc.read_page = denali_read_page; - nand->ecc.read_page_raw = denali_read_page_raw; - nand->ecc.write_page = denali_write_page; - nand->ecc.write_page_raw = denali_write_page_raw; - nand->ecc.read_oob = denali_read_oob; - nand->ecc.write_oob = denali_write_oob; - - /* Occasionally the controller is in SPARE or MAIN+SPARE - mode upon startup, and we want it to be MAIN only */ - val = ioread32(denali->flash_reg + TRANSFER_MODE); - if (val != 0) { - int i; - dev_dbg(denali->dev, - "setting TRANSFER_MODE (%08x) back to MAIN only\n", val); - /* put all banks in MAIN mode, no SPARE */ - iowrite32(0, denali->flash_reg + TRANSFER_SPARE_REG); - for (i = 0; i < 4; i++) - index_addr(denali, MODE_10 | BANK(i) | 1, - MAIN_ACCESS); - } + if (denali->oob_skip_bytes) + iowrite32(denali->oob_skip_bytes, + denali->reg + SPARE_AREA_SKIP_BYTES); + else + denali->oob_skip_bytes = ioread32(denali->reg + + SPARE_AREA_SKIP_BYTES); - if (nand_scan_tail(mtd)) { - ret = -ENXIO; - goto failed_req_irq; - } + iowrite32(0, denali->reg + TRANSFER_SPARE_REG); + iowrite32(GENMASK(denali->nbanks - 1, 0), denali->reg + RB_PIN_ENABLED); + iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE); + iowrite32(ECC_ENABLE__FLAG, denali->reg + ECC_ENABLE); + iowrite32(0xffff, denali->reg + SPARE_AREA_MARKER); + iowrite32(WRITE_PROTECT__FLAG, denali->reg + WRITE_PROTECT); - return add_mtd_nand_device(mtd, "nand"); + denali_clear_irq_all(denali); -failed_req_irq: - denali_irq_cleanup(denali->irq, denali); + denali_enable_irq(denali); - return ret; + return 0; } EXPORT_SYMBOL(denali_init); - -MODULE_AUTHOR("Intel Corporation"); -MODULE_DESCRIPTION(""); -MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Driver core for Denali NAND controller"); +MODULE_AUTHOR("Intel Corporation and its suppliers"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mtd/nand/nand_denali_dt.c b/drivers/mtd/nand/nand_denali_dt.c index e3024549cd..877c40714a 100644 --- a/drivers/mtd/nand/nand_denali_dt.c +++ b/drivers/mtd/nand/nand_denali_dt.c @@ -24,58 +24,128 @@ #include <errno.h> #include <linux/clk.h> +#include <linux/spinlock.h> #include "denali.h" struct denali_dt { - struct denali_nand_info denali; - struct clk *clk; + struct denali_controller denali; + struct clk *clk; /* core clock */ + struct clk *clk_x; /* bus interface clock */ + struct clk *clk_ecc; /* ECC circuit clock */ }; +struct denali_dt_data { + unsigned int revision; + unsigned int caps; + unsigned int oob_skip_bytes; + const struct nand_ecc_caps *ecc_caps; +}; + +NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes, + 512, 8, 15); +static const struct denali_dt_data denali_socfpga_data = { + .caps = DENALI_CAP_HW_ECC_FIXUP, + .oob_skip_bytes = 2, + .ecc_caps = &denali_socfpga_ecc_caps, +}; + +static int denali_dt_chip_init(struct denali_controller *denali, + struct device_node *chip_np) +{ + struct denali_chip *dchip; + u32 bank; + int nsels, i, ret; + + nsels = of_property_count_elems_of_size(chip_np, "reg", sizeof(u32)); + if (nsels < 0) + return nsels; + + dchip = xzalloc(sizeof(*dchip) + sizeof(struct denali_chip_sel) *nsels); + + dchip->nsels = nsels; + + for (i = 0; i < nsels; i++) { + ret = of_property_read_u32_index(chip_np, "reg", i, &bank); + if (ret) + return ret; + + dchip->sels[i].bank = bank; + + nand_set_flash_node(&dchip->chip, chip_np); + } + + return denali_chip_init(denali, dchip); +} static int denali_dt_probe(struct device_d *ofdev) { struct resource *iores; struct denali_dt *dt; - struct denali_nand_info *denali; + struct denali_controller *denali; + struct denali_dt_data *data; + struct device_node *np; int ret; if (!IS_ENABLED(CONFIG_OFDEVICE)) return 1; + ret = dev_get_drvdata(ofdev, (const void **)&data); + if (ret) + return ret; + dt = kzalloc(sizeof(*dt), GFP_KERNEL); if (!dt) return -ENOMEM; denali = &dt->denali; - denali->platform = DT; denali->dev = ofdev; iores = dev_request_mem_resource(ofdev, 0); if (IS_ERR(iores)) return PTR_ERR(iores); - denali->flash_mem = IOMEM(iores->start); + denali->host = IOMEM(iores->start); iores = dev_request_mem_resource(ofdev, 1); if (IS_ERR(iores)) return PTR_ERR(iores); - denali->flash_reg = IOMEM(iores->start); + denali->reg = IOMEM(iores->start); - dt->clk = clk_get(ofdev, NULL); - if (IS_ERR(dt->clk)) { - dev_err(ofdev, "no clk available\n"); + dt->clk = clk_get(ofdev, "nand"); + if (IS_ERR(dt->clk)) return PTR_ERR(dt->clk); - } + + dt->clk_x = clk_get(ofdev, "nand_x"); + if (IS_ERR(dt->clk_x)) + return PTR_ERR(dt->clk_x); + + dt->clk_ecc = clk_get(ofdev, "ecc"); + if (IS_ERR(dt->clk_ecc)) + return PTR_ERR(dt->clk_ecc); + clk_enable(dt->clk); + clk_enable(dt->clk_x); + clk_enable(dt->clk_ecc); + + denali->clk_rate = clk_get_rate(dt->clk); + denali->clk_x_rate = clk_get_rate(dt->clk_x); - denali->have_hw_ecc_fixup = of_property_read_bool(ofdev->device_node, - "have-hw-ecc-fixup"); + denali->revision = data->revision; + denali->caps = data->caps; + denali->oob_skip_bytes = data->oob_skip_bytes; + denali->ecc_caps = data->ecc_caps; ret = denali_init(denali); if (ret) goto out_disable_clk; + for_each_child_of_node(ofdev->device_node, np) { + ret = denali_dt_chip_init(denali, np); + if (ret) + goto out_disable_clk; + } + return 0; out_disable_clk: @@ -86,7 +156,8 @@ out_disable_clk: static __maybe_unused struct of_device_id denali_nand_compatible[] = { { - .compatible = "altr,socfpga-denali-nand" + .compatible = "altr,socfpga-denali-nand", + .data = &denali_socfpga_data, }, { /* sentinel */ } diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index fd6ad7edc8..58fb335bb4 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c @@ -1,194 +1,483 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * This file contains an ECC algorithm from Toshiba that detects and - * corrects 1 bit errors in a 256 byte block of data. + * This file contains an ECC algorithm that detects and corrects 1 bit + * errors in a 256 byte block of data. * - * drivers/mtd/nand/nand_ecc.c + * Copyright © 2008 Koninklijke Philips Electronics NV. + * Author: Frans Meulenbroeks * - * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) - * Toshiba America Electronics Components, Inc. + * Completely replaces the previous ECC implementation which was written by: + * Steven J. Hill (sjhill@realitydiluted.com) + * Thomas Gleixner (tglx@linutronix.de) * - * Copyright (C) 2006 Thomas Gleixner <tglx@linutronix.de> - * - * $Id: nand_ecc.c,v 1.15 2005/11/07 11:14:30 gleixner Exp $ - * - * This file 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 or (at your option) any - * later version. - * - * This file 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. - * - * As a special exception, if other files instantiate templates or use - * macros or inline functions from these files, or you compile these - * files and link them with other works to produce a work based on these - * files, these files do not by themselves cause the resulting work to be - * covered by the GNU General Public License. However the source code for - * these files must still be made available in accordance with section (3) - * of the GNU General Public License. - * - * This exception does not invalidate any other reasons why a work based on - * this file might be covered by the GNU General Public License. + * Information on how this algorithm works and how it was developed + * can be found in Documentation/driver-api/mtd/nand_ecc.rst */ #include <linux/types.h> -#include <common.h> -#include <errno.h> +#include <linux/kernel.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/rawnand.h> #include <linux/mtd/nand_ecc.h> +#include <asm/byteorder.h> + +/* + * invparity is a 256 byte table that contains the odd parity + * for each byte. So if the number of bits in a byte is even, + * the array element is 1, and when the number of bits is odd + * the array eleemnt is 0. + */ +static const char invparity[256] = { + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 +}; + +/* + * bitsperbyte contains the number of bits per byte + * this is only used for testing and repairing parity + * (a precalculated value slightly improves performance) + */ +static const char bitsperbyte[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, +}; /* - * Pre-calculated 256-way 1 byte column parity + * addressbits is a lookup table to filter out the bits from the xor-ed + * ECC data that identify the faulty location. + * this is only used for repairing parity + * see the comments in nand_correct_data for more details */ -static const u_char nand_ecc_precalc_table[] = { - 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, - 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, - 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, - 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, - 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, - 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, - 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, - 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, - 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, - 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, - 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, - 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, - 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, - 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, - 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, - 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 +static const char addressbits[256] = { + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, + 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, + 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, + 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, + 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, + 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, + 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, + 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, + 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, + 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, + 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, + 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, + 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, + 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, + 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, + 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, + 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, + 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, + 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f, + 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, + 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f, + 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, + 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, + 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, + 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, + 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, + 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f, + 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, + 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f }; /** - * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block - * @mtd: MTD block structure - * @dat: raw data - * @ecc_code: buffer for ECC + * __nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte + * block + * @buf: input buffer with raw data + * @eccsize: data bytes per ECC step (256 or 512) + * @code: output buffer with ECC + * @sm_order: Smart Media byte ordering */ -int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) +void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize, + unsigned char *code, bool sm_order) { - uint8_t idx, reg1, reg2, reg3, tmp1, tmp2; int i; + const uint32_t *bp = (uint32_t *)buf; + /* 256 or 512 bytes/ecc */ + const uint32_t eccsize_mult = eccsize >> 8; + uint32_t cur; /* current value in buffer */ + /* rp0..rp15..rp17 are the various accumulated parities (per byte) */ + uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7; + uint32_t rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15, rp16; + uint32_t rp17 = 0; + uint32_t par; /* the cumulative parity for all data */ + uint32_t tmppar; /* the cumulative parity for this iteration; + for rp12, rp14 and rp16 at the end of the + loop */ - /* Initialize variables */ - reg1 = reg2 = reg3 = 0; + par = 0; + rp4 = 0; + rp6 = 0; + rp8 = 0; + rp10 = 0; + rp12 = 0; + rp14 = 0; + rp16 = 0; - /* Build up column parity */ - for(i = 0; i < 256; i++) { - /* Get CP0 - CP5 from table */ - idx = nand_ecc_precalc_table[*dat++]; - reg1 ^= (idx & 0x3f); + /* + * The loop is unrolled a number of times; + * This avoids if statements to decide on which rp value to update + * Also we process the data by longwords. + * Note: passing unaligned data might give a performance penalty. + * It is assumed that the buffers are aligned. + * tmppar is the cumulative sum of this iteration. + * needed for calculating rp12, rp14, rp16 and par + * also used as a performance improvement for rp6, rp8 and rp10 + */ + for (i = 0; i < eccsize_mult << 2; i++) { + cur = *bp++; + tmppar = cur; + rp4 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp6 ^= tmppar; + cur = *bp++; + tmppar ^= cur; + rp4 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp8 ^= tmppar; - /* All bit XOR = 1 ? */ - if (idx & 0x40) { - reg3 ^= (uint8_t) i; - reg2 ^= ~((uint8_t) i); - } + cur = *bp++; + tmppar ^= cur; + rp4 ^= cur; + rp6 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp6 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp4 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp10 ^= tmppar; + + cur = *bp++; + tmppar ^= cur; + rp4 ^= cur; + rp6 ^= cur; + rp8 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp6 ^= cur; + rp8 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp4 ^= cur; + rp8 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp8 ^= cur; + + cur = *bp++; + tmppar ^= cur; + rp4 ^= cur; + rp6 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp6 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp4 ^= cur; + cur = *bp++; + tmppar ^= cur; + + par ^= tmppar; + if ((i & 0x1) == 0) + rp12 ^= tmppar; + if ((i & 0x2) == 0) + rp14 ^= tmppar; + if (eccsize_mult == 2 && (i & 0x4) == 0) + rp16 ^= tmppar; } - /* Create non-inverted ECC code from line parity */ - tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */ - tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */ - tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */ - tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */ - tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */ - tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */ - tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */ - tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */ - - tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */ - tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */ - tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */ - tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */ - tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */ - tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */ - tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */ - tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */ - - /* Calculate final ECC code */ -#ifdef CONFIG_MTD_NAND_ECC_SMC - ecc_code[0] = ~tmp2; - ecc_code[1] = ~tmp1; + /* + * handle the fact that we use longword operations + * we'll bring rp4..rp14..rp16 back to single byte entities by + * shifting and xoring first fold the upper and lower 16 bits, + * then the upper and lower 8 bits. + */ + rp4 ^= (rp4 >> 16); + rp4 ^= (rp4 >> 8); + rp4 &= 0xff; + rp6 ^= (rp6 >> 16); + rp6 ^= (rp6 >> 8); + rp6 &= 0xff; + rp8 ^= (rp8 >> 16); + rp8 ^= (rp8 >> 8); + rp8 &= 0xff; + rp10 ^= (rp10 >> 16); + rp10 ^= (rp10 >> 8); + rp10 &= 0xff; + rp12 ^= (rp12 >> 16); + rp12 ^= (rp12 >> 8); + rp12 &= 0xff; + rp14 ^= (rp14 >> 16); + rp14 ^= (rp14 >> 8); + rp14 &= 0xff; + if (eccsize_mult == 2) { + rp16 ^= (rp16 >> 16); + rp16 ^= (rp16 >> 8); + rp16 &= 0xff; + } + + /* + * we also need to calculate the row parity for rp0..rp3 + * This is present in par, because par is now + * rp3 rp3 rp2 rp2 in little endian and + * rp2 rp2 rp3 rp3 in big endian + * as well as + * rp1 rp0 rp1 rp0 in little endian and + * rp0 rp1 rp0 rp1 in big endian + * First calculate rp2 and rp3 + */ +#ifdef __BIG_ENDIAN + rp2 = (par >> 16); + rp2 ^= (rp2 >> 8); + rp2 &= 0xff; + rp3 = par & 0xffff; + rp3 ^= (rp3 >> 8); + rp3 &= 0xff; #else - ecc_code[0] = ~tmp1; - ecc_code[1] = ~tmp2; + rp3 = (par >> 16); + rp3 ^= (rp3 >> 8); + rp3 &= 0xff; + rp2 = par & 0xffff; + rp2 ^= (rp2 >> 8); + rp2 &= 0xff; #endif - ecc_code[2] = ((~reg1) << 2) | 0x03; - return 0; + /* reduce par to 16 bits then calculate rp1 and rp0 */ + par ^= (par >> 16); +#ifdef __BIG_ENDIAN + rp0 = (par >> 8) & 0xff; + rp1 = (par & 0xff); +#else + rp1 = (par >> 8) & 0xff; + rp0 = (par & 0xff); +#endif + + /* finally reduce par to 8 bits */ + par ^= (par >> 8); + par &= 0xff; + + /* + * and calculate rp5..rp15..rp17 + * note that par = rp4 ^ rp5 and due to the commutative property + * of the ^ operator we can say: + * rp5 = (par ^ rp4); + * The & 0xff seems superfluous, but benchmarking learned that + * leaving it out gives slightly worse results. No idea why, probably + * it has to do with the way the pipeline in pentium is organized. + */ + rp5 = (par ^ rp4) & 0xff; + rp7 = (par ^ rp6) & 0xff; + rp9 = (par ^ rp8) & 0xff; + rp11 = (par ^ rp10) & 0xff; + rp13 = (par ^ rp12) & 0xff; + rp15 = (par ^ rp14) & 0xff; + if (eccsize_mult == 2) + rp17 = (par ^ rp16) & 0xff; + + /* + * Finally calculate the ECC bits. + * Again here it might seem that there are performance optimisations + * possible, but benchmarks showed that on the system this is developed + * the code below is the fastest + */ + if (sm_order) { + code[0] = (invparity[rp7] << 7) | (invparity[rp6] << 6) | + (invparity[rp5] << 5) | (invparity[rp4] << 4) | + (invparity[rp3] << 3) | (invparity[rp2] << 2) | + (invparity[rp1] << 1) | (invparity[rp0]); + code[1] = (invparity[rp15] << 7) | (invparity[rp14] << 6) | + (invparity[rp13] << 5) | (invparity[rp12] << 4) | + (invparity[rp11] << 3) | (invparity[rp10] << 2) | + (invparity[rp9] << 1) | (invparity[rp8]); + } else { + code[1] = (invparity[rp7] << 7) | (invparity[rp6] << 6) | + (invparity[rp5] << 5) | (invparity[rp4] << 4) | + (invparity[rp3] << 3) | (invparity[rp2] << 2) | + (invparity[rp1] << 1) | (invparity[rp0]); + code[0] = (invparity[rp15] << 7) | (invparity[rp14] << 6) | + (invparity[rp13] << 5) | (invparity[rp12] << 4) | + (invparity[rp11] << 3) | (invparity[rp10] << 2) | + (invparity[rp9] << 1) | (invparity[rp8]); + } + + if (eccsize_mult == 1) + code[2] = + (invparity[par & 0xf0] << 7) | + (invparity[par & 0x0f] << 6) | + (invparity[par & 0xcc] << 5) | + (invparity[par & 0x33] << 4) | + (invparity[par & 0xaa] << 3) | + (invparity[par & 0x55] << 2) | + 3; + else + code[2] = + (invparity[par & 0xf0] << 7) | + (invparity[par & 0x0f] << 6) | + (invparity[par & 0xcc] << 5) | + (invparity[par & 0x33] << 4) | + (invparity[par & 0xaa] << 3) | + (invparity[par & 0x55] << 2) | + (invparity[rp17] << 1) | + (invparity[rp16] << 0); } -EXPORT_SYMBOL(nand_calculate_ecc); +EXPORT_SYMBOL(__nand_calculate_ecc); -static inline int countbits(uint32_t byte) +/** + * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte + * block + * @chip: NAND chip object + * @buf: input buffer with raw data + * @code: output buffer with ECC + */ +int nand_calculate_ecc(struct nand_chip *chip, const unsigned char *buf, + unsigned char *code) { - int res = 0; + bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER; + + __nand_calculate_ecc(buf, chip->ecc.size, code, sm_order); - for (;byte; byte >>= 1) - res += byte & 0x01; - return res; + return 0; } +EXPORT_SYMBOL(nand_calculate_ecc); /** - * nand_correct_data - [NAND Interface] Detect and correct bit error(s) - * @mtd: MTD block structure - * @dat: raw data read from the chip + * __nand_correct_data - [NAND Interface] Detect and correct bit error(s) + * @buf: raw data read from the chip * @read_ecc: ECC from the chip * @calc_ecc: the ECC calculated from raw data + * @eccsize: data bytes per ECC step (256 or 512) + * @sm_order: Smart Media byte order * - * Detect and correct a 1 bit error for 256 byte block + * Detect and correct a 1 bit error for eccsize byte block */ -int nand_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) +int __nand_correct_data(unsigned char *buf, + unsigned char *read_ecc, unsigned char *calc_ecc, + unsigned int eccsize, bool sm_order) { - uint8_t s0, s1, s2; + unsigned char b0, b1, b2, bit_addr; + unsigned int byte_addr; + /* 256 or 512 bytes/ecc */ + const uint32_t eccsize_mult = eccsize >> 8; -#ifdef CONFIG_MTD_NAND_ECC_SMC - s0 = calc_ecc[0] ^ read_ecc[0]; - s1 = calc_ecc[1] ^ read_ecc[1]; - s2 = calc_ecc[2] ^ read_ecc[2]; -#else - s1 = calc_ecc[0] ^ read_ecc[0]; - s0 = calc_ecc[1] ^ read_ecc[1]; - s2 = calc_ecc[2] ^ read_ecc[2]; -#endif - if ((s0 | s1 | s2) == 0) - return 0; - - /* Check for a single bit error */ - if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && - ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && - ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { - - uint32_t byteoffs, bitnum; + /* + * b0 to b2 indicate which bit is faulty (if any) + * we might need the xor result more than once, + * so keep them in a local var + */ + if (sm_order) { + b0 = read_ecc[0] ^ calc_ecc[0]; + b1 = read_ecc[1] ^ calc_ecc[1]; + } else { + b0 = read_ecc[1] ^ calc_ecc[1]; + b1 = read_ecc[0] ^ calc_ecc[0]; + } - byteoffs = (s1 << 0) & 0x80; - byteoffs |= (s1 << 1) & 0x40; - byteoffs |= (s1 << 2) & 0x20; - byteoffs |= (s1 << 3) & 0x10; + b2 = read_ecc[2] ^ calc_ecc[2]; - byteoffs |= (s0 >> 4) & 0x08; - byteoffs |= (s0 >> 3) & 0x04; - byteoffs |= (s0 >> 2) & 0x02; - byteoffs |= (s0 >> 1) & 0x01; + /* check if there are any bitfaults */ - bitnum = (s2 >> 5) & 0x04; - bitnum |= (s2 >> 4) & 0x02; - bitnum |= (s2 >> 3) & 0x01; + /* repeated if statements are slightly more efficient than switch ... */ + /* ordered in order of likelihood */ - dat[byteoffs] ^= (1 << bitnum); + if ((b0 | b1 | b2) == 0) + return 0; /* no error */ + if ((((b0 ^ (b0 >> 1)) & 0x55) == 0x55) && + (((b1 ^ (b1 >> 1)) & 0x55) == 0x55) && + ((eccsize_mult == 1 && ((b2 ^ (b2 >> 1)) & 0x54) == 0x54) || + (eccsize_mult == 2 && ((b2 ^ (b2 >> 1)) & 0x55) == 0x55))) { + /* single bit error */ + /* + * rp17/rp15/13/11/9/7/5/3/1 indicate which byte is the faulty + * byte, cp 5/3/1 indicate the faulty bit. + * A lookup table (called addressbits) is used to filter + * the bits from the byte they are in. + * A marginal optimisation is possible by having three + * different lookup tables. + * One as we have now (for b0), one for b2 + * (that would avoid the >> 1), and one for b1 (with all values + * << 4). However it was felt that introducing two more tables + * hardly justify the gain. + * + * The b2 shift is there to get rid of the lowest two bits. + * We could also do addressbits[b2] >> 1 but for the + * performance it does not make any difference + */ + if (eccsize_mult == 1) + byte_addr = (addressbits[b1] << 4) + addressbits[b0]; + else + byte_addr = (addressbits[b2 & 0x3] << 8) + + (addressbits[b1] << 4) + addressbits[b0]; + bit_addr = addressbits[b2 >> 2]; + /* flip the bit */ + buf[byte_addr] ^= (1 << bit_addr); return 1; - } - if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) - return 1; + } + /* count nr of bits; use table lookup, faster than calculating it */ + if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1) + return 1; /* error in ECC data; no action needed */ + pr_err("%s: uncorrectable ECC error\n", __func__); return -EBADMSG; } +EXPORT_SYMBOL(__nand_correct_data); + +/** + * nand_correct_data - [NAND Interface] Detect and correct bit error(s) + * @chip: NAND chip object + * @buf: raw data read from the chip + * @read_ecc: ECC from the chip + * @calc_ecc: the ECC calculated from raw data + * + * Detect and correct a 1 bit error for 256/512 byte block + */ +int nand_correct_data(struct nand_chip *chip, unsigned char *buf, + unsigned char *read_ecc, unsigned char *calc_ecc) +{ + bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER; + + return __nand_correct_data(buf, read_ecc, calc_ecc, chip->ecc.size, + sm_order); +} EXPORT_SYMBOL(nand_correct_data); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>"); +MODULE_AUTHOR("Frans Meulenbroeks <fransmeulenbroeks@gmail.com>"); MODULE_DESCRIPTION("Generic NAND ECC support"); diff --git a/drivers/mtd/nand/nand_esmt.c b/drivers/mtd/nand/nand_esmt.c new file mode 100644 index 0000000000..3338c68aaa --- /dev/null +++ b/drivers/mtd/nand/nand_esmt.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Toradex AG + * + * Author: Marcel Ziswiler <marcel.ziswiler@toradex.com> + */ + +#include <linux/mtd/rawnand.h> +#include "internals.h" + +static void esmt_nand_decode_id(struct nand_chip *chip) +{ + nand_decode_ext_id(chip); + + /* Extract ECC requirements from 5th id byte. */ + if (chip->id.len >= 5 && nand_is_slc(chip)) { + chip->base.eccreq.step_size = 512; + switch (chip->id.data[4] & 0x3) { + case 0x0: + chip->base.eccreq.strength = 4; + break; + case 0x1: + chip->base.eccreq.strength = 2; + break; + case 0x2: + chip->base.eccreq.strength = 1; + break; + default: + WARN(1, "Could not get ECC info"); + chip->base.eccreq.step_size = 0; + break; + } + } +} + +static int esmt_nand_init(struct nand_chip *chip) +{ + if (nand_is_slc(chip)) + /* + * It is known that some ESMT SLC NANDs have been shipped + * with the factory bad block markers in the first or last page + * of the block, instead of the first or second page. To be on + * the safe side, let's check all three locations. + */ + chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE | + NAND_BBM_LASTPAGE; + + return 0; +} + +const struct nand_manufacturer_ops esmt_nand_manuf_ops = { + .detect = esmt_nand_decode_id, + .init = esmt_nand_init, +}; diff --git a/drivers/mtd/nand/nand_hynix.c b/drivers/mtd/nand/nand_hynix.c new file mode 100644 index 0000000000..0422ed53aa --- /dev/null +++ b/drivers/mtd/nand/nand_hynix.c @@ -0,0 +1,716 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2017 Free Electrons + * Copyright (C) 2017 NextThing Co + * + * Author: Boris Brezillon <boris.brezillon@free-electrons.com> + */ + +#include <linux/sizes.h> + +#include "internals.h" + +#define NAND_HYNIX_CMD_SET_PARAMS 0x36 +#define NAND_HYNIX_CMD_APPLY_PARAMS 0x16 + +#define NAND_HYNIX_1XNM_RR_REPEAT 8 + +/** + * struct hynix_read_retry - read-retry data + * @nregs: number of register to set when applying a new read-retry mode + * @regs: register offsets (NAND chip dependent) + * @values: array of values to set in registers. The array size is equal to + * (nregs * nmodes) + */ +struct hynix_read_retry { + int nregs; + const u8 *regs; + u8 values[]; +}; + +/** + * struct hynix_nand - private Hynix NAND struct + * @nand_technology: manufacturing process expressed in picometer + * @read_retry: read-retry information + */ +struct hynix_nand { + const struct hynix_read_retry *read_retry; +}; + +/** + * struct hynix_read_retry_otp - structure describing how the read-retry OTP + * area + * @nregs: number of hynix private registers to set before reading the reading + * the OTP area + * @regs: registers that should be configured + * @values: values that should be set in regs + * @page: the address to pass to the READ_PAGE command. Depends on the NAND + * chip + * @size: size of the read-retry OTP section + */ +struct hynix_read_retry_otp { + int nregs; + const u8 *regs; + const u8 *values; + int page; + int size; +}; + +static bool hynix_nand_has_valid_jedecid(struct nand_chip *chip) +{ + u8 jedecid[5] = { }; + int ret; + + ret = nand_readid_op(chip, 0x40, jedecid, sizeof(jedecid)); + if (ret) + return false; + + return !strncmp("JEDEC", jedecid, sizeof(jedecid)); +} + +static int hynix_nand_cmd_op(struct nand_chip *chip, u8 cmd) +{ + if (nand_has_exec_op(chip)) { + struct nand_op_instr instrs[] = { + NAND_OP_CMD(cmd, 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + + return nand_exec_op(chip, &op); + } + + chip->legacy.cmdfunc(chip, cmd, -1, -1); + + return 0; +} + +static int hynix_nand_reg_write_op(struct nand_chip *chip, u8 addr, u8 val) +{ + u16 column = ((u16)addr << 8) | addr; + + if (nand_has_exec_op(chip)) { + struct nand_op_instr instrs[] = { + NAND_OP_ADDR(1, &addr, 0), + NAND_OP_8BIT_DATA_OUT(1, &val, 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + + return nand_exec_op(chip, &op); + } + + chip->legacy.cmdfunc(chip, NAND_CMD_NONE, column, -1); + chip->legacy.write_byte(chip, val); + + return 0; +} + +static int hynix_nand_setup_read_retry(struct nand_chip *chip, int retry_mode) +{ + struct hynix_nand *hynix = nand_get_manufacturer_data(chip); + const u8 *values; + int i, ret; + + values = hynix->read_retry->values + + (retry_mode * hynix->read_retry->nregs); + + /* Enter 'Set Hynix Parameters' mode */ + ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_SET_PARAMS); + if (ret) + return ret; + + /* + * Configure the NAND in the requested read-retry mode. + * This is done by setting pre-defined values in internal NAND + * registers. + * + * The set of registers is NAND specific, and the values are either + * predefined or extracted from an OTP area on the NAND (values are + * probably tweaked at production in this case). + */ + for (i = 0; i < hynix->read_retry->nregs; i++) { + ret = hynix_nand_reg_write_op(chip, hynix->read_retry->regs[i], + values[i]); + if (ret) + return ret; + } + + /* Apply the new settings. */ + return hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_APPLY_PARAMS); +} + +/** + * hynix_get_majority - get the value that is occurring the most in a given + * set of values + * @in: the array of values to test + * @repeat: the size of the in array + * @out: pointer used to store the output value + * + * This function implements the 'majority check' logic that is supposed to + * overcome the unreliability of MLC NANDs when reading the OTP area storing + * the read-retry parameters. + * + * It's based on a pretty simple assumption: if we repeat the same value + * several times and then take the one that is occurring the most, we should + * find the correct value. + * Let's hope this dummy algorithm prevents us from losing the read-retry + * parameters. + */ +static int hynix_get_majority(const u8 *in, int repeat, u8 *out) +{ + int i, j, half = repeat / 2; + + /* + * We only test the first half of the in array because we must ensure + * that the value is at least occurring repeat / 2 times. + * + * This loop is suboptimal since we may count the occurrences of the + * same value several time, but we are doing that on small sets, which + * makes it acceptable. + */ + for (i = 0; i < half; i++) { + int cnt = 0; + u8 val = in[i]; + + /* Count all values that are matching the one at index i. */ + for (j = i + 1; j < repeat; j++) { + if (in[j] == val) + cnt++; + } + + /* We found a value occurring more than repeat / 2. */ + if (cnt > half) { + *out = val; + return 0; + } + } + + return -EIO; +} + +static int hynix_read_rr_otp(struct nand_chip *chip, + const struct hynix_read_retry_otp *info, + void *buf) +{ + int i, ret; + + ret = nand_reset_op(chip); + if (ret) + return ret; + + ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_SET_PARAMS); + if (ret) + return ret; + + for (i = 0; i < info->nregs; i++) { + ret = hynix_nand_reg_write_op(chip, info->regs[i], + info->values[i]); + if (ret) + return ret; + } + + ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_APPLY_PARAMS); + if (ret) + return ret; + + /* Sequence to enter OTP mode? */ + ret = hynix_nand_cmd_op(chip, 0x17); + if (ret) + return ret; + + ret = hynix_nand_cmd_op(chip, 0x4); + if (ret) + return ret; + + ret = hynix_nand_cmd_op(chip, 0x19); + if (ret) + return ret; + + /* Now read the page */ + ret = nand_read_page_op(chip, info->page, 0, buf, info->size); + if (ret) + return ret; + + /* Put everything back to normal */ + ret = nand_reset_op(chip); + if (ret) + return ret; + + ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_SET_PARAMS); + if (ret) + return ret; + + ret = hynix_nand_reg_write_op(chip, 0x38, 0); + if (ret) + return ret; + + ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_APPLY_PARAMS); + if (ret) + return ret; + + return nand_read_page_op(chip, 0, 0, NULL, 0); +} + +#define NAND_HYNIX_1XNM_RR_COUNT_OFFS 0 +#define NAND_HYNIX_1XNM_RR_REG_COUNT_OFFS 8 +#define NAND_HYNIX_1XNM_RR_SET_OFFS(x, setsize, inv) \ + (16 + ((((x) * 2) + ((inv) ? 1 : 0)) * (setsize))) + +static int hynix_mlc_1xnm_rr_value(const u8 *buf, int nmodes, int nregs, + int mode, int reg, bool inv, u8 *val) +{ + u8 tmp[NAND_HYNIX_1XNM_RR_REPEAT]; + int val_offs = (mode * nregs) + reg; + int set_size = nmodes * nregs; + int i, ret; + + for (i = 0; i < NAND_HYNIX_1XNM_RR_REPEAT; i++) { + int set_offs = NAND_HYNIX_1XNM_RR_SET_OFFS(i, set_size, inv); + + tmp[i] = buf[val_offs + set_offs]; + } + + ret = hynix_get_majority(tmp, NAND_HYNIX_1XNM_RR_REPEAT, val); + if (ret) + return ret; + + if (inv) + *val = ~*val; + + return 0; +} + +static u8 hynix_1xnm_mlc_read_retry_regs[] = { + 0xcc, 0xbf, 0xaa, 0xab, 0xcd, 0xad, 0xae, 0xaf +}; + +static int hynix_mlc_1xnm_rr_init(struct nand_chip *chip, + const struct hynix_read_retry_otp *info) +{ + struct hynix_nand *hynix = nand_get_manufacturer_data(chip); + struct hynix_read_retry *rr = NULL; + int ret, i, j; + u8 nregs, nmodes; + u8 *buf; + + buf = kmalloc(info->size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = hynix_read_rr_otp(chip, info, buf); + if (ret) + goto out; + + ret = hynix_get_majority(buf, NAND_HYNIX_1XNM_RR_REPEAT, + &nmodes); + if (ret) + goto out; + + ret = hynix_get_majority(buf + NAND_HYNIX_1XNM_RR_REPEAT, + NAND_HYNIX_1XNM_RR_REPEAT, + &nregs); + if (ret) + goto out; + + rr = kzalloc(sizeof(*rr) + (nregs * nmodes), GFP_KERNEL); + if (!rr) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < nmodes; i++) { + for (j = 0; j < nregs; j++) { + u8 *val = rr->values + (i * nregs); + + ret = hynix_mlc_1xnm_rr_value(buf, nmodes, nregs, i, j, + false, val); + if (!ret) + continue; + + ret = hynix_mlc_1xnm_rr_value(buf, nmodes, nregs, i, j, + true, val); + if (ret) + goto out; + } + } + + rr->nregs = nregs; + rr->regs = hynix_1xnm_mlc_read_retry_regs; + hynix->read_retry = rr; + chip->ops.setup_read_retry = hynix_nand_setup_read_retry; + chip->read_retries = nmodes; + +out: + kfree(buf); + + if (ret) + kfree(rr); + + return ret; +} + +static const u8 hynix_mlc_1xnm_rr_otp_regs[] = { 0x38 }; +static const u8 hynix_mlc_1xnm_rr_otp_values[] = { 0x52 }; + +static const struct hynix_read_retry_otp hynix_mlc_1xnm_rr_otps[] = { + { + .nregs = ARRAY_SIZE(hynix_mlc_1xnm_rr_otp_regs), + .regs = hynix_mlc_1xnm_rr_otp_regs, + .values = hynix_mlc_1xnm_rr_otp_values, + .page = 0x21f, + .size = 784 + }, + { + .nregs = ARRAY_SIZE(hynix_mlc_1xnm_rr_otp_regs), + .regs = hynix_mlc_1xnm_rr_otp_regs, + .values = hynix_mlc_1xnm_rr_otp_values, + .page = 0x200, + .size = 528, + }, +}; + +static int hynix_nand_rr_init(struct nand_chip *chip) +{ + int i, ret = 0; + bool valid_jedecid; + + valid_jedecid = hynix_nand_has_valid_jedecid(chip); + + /* + * We only support read-retry for 1xnm NANDs, and those NANDs all + * expose a valid JEDEC ID. + */ + if (valid_jedecid) { + u8 nand_tech = chip->id.data[5] >> 4; + + /* 1xnm technology */ + if (nand_tech == 4) { + for (i = 0; i < ARRAY_SIZE(hynix_mlc_1xnm_rr_otps); + i++) { + /* + * FIXME: Hynix recommend to copy the + * read-retry OTP area into a normal page. + */ + ret = hynix_mlc_1xnm_rr_init(chip, + hynix_mlc_1xnm_rr_otps); + if (!ret) + break; + } + } + } + + if (ret) + pr_warn("failed to initialize read-retry infrastructure"); + + return 0; +} + +static void hynix_nand_extract_oobsize(struct nand_chip *chip, + bool valid_jedecid) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; + u8 oobsize; + + memorg = nanddev_get_memorg(&chip->base); + + oobsize = ((chip->id.data[3] >> 2) & 0x3) | + ((chip->id.data[3] >> 4) & 0x4); + + if (valid_jedecid) { + switch (oobsize) { + case 0: + memorg->oobsize = 2048; + break; + case 1: + memorg->oobsize = 1664; + break; + case 2: + memorg->oobsize = 1024; + break; + case 3: + memorg->oobsize = 640; + break; + default: + /* + * We should never reach this case, but if that + * happens, this probably means Hynix decided to use + * a different extended ID format, and we should find + * a way to support it. + */ + WARN(1, "Invalid OOB size"); + break; + } + } else { + switch (oobsize) { + case 0: + memorg->oobsize = 128; + break; + case 1: + memorg->oobsize = 224; + break; + case 2: + memorg->oobsize = 448; + break; + case 3: + memorg->oobsize = 64; + break; + case 4: + memorg->oobsize = 32; + break; + case 5: + memorg->oobsize = 16; + break; + case 6: + memorg->oobsize = 640; + break; + default: + /* + * We should never reach this case, but if that + * happens, this probably means Hynix decided to use + * a different extended ID format, and we should find + * a way to support it. + */ + WARN(1, "Invalid OOB size"); + break; + } + + /* + * The datasheet of H27UCG8T2BTR mentions that the "Redundant + * Area Size" is encoded "per 8KB" (page size). This chip uses + * a page size of 16KiB. The datasheet mentions an OOB size of + * 1.280 bytes, but the OOB size encoded in the ID bytes (using + * the existing logic above) is 640 bytes. + * Update the OOB size for this chip by taking the value + * determined above and scaling it to the actual page size (so + * the actual OOB size for this chip is: 640 * 16k / 8k). + */ + if (chip->id.data[1] == 0xde) + memorg->oobsize *= memorg->pagesize / SZ_8K; + } + + mtd->oobsize = memorg->oobsize; +} + +static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip, + bool valid_jedecid) +{ + u8 ecc_level = (chip->id.data[4] >> 4) & 0x7; + + if (valid_jedecid) { + /* Reference: H27UCG8T2E datasheet */ + chip->base.eccreq.step_size = 1024; + + switch (ecc_level) { + case 0: + chip->base.eccreq.step_size = 0; + chip->base.eccreq.strength = 0; + break; + case 1: + chip->base.eccreq.strength = 4; + break; + case 2: + chip->base.eccreq.strength = 24; + break; + case 3: + chip->base.eccreq.strength = 32; + break; + case 4: + chip->base.eccreq.strength = 40; + break; + case 5: + chip->base.eccreq.strength = 50; + break; + case 6: + chip->base.eccreq.strength = 60; + break; + default: + /* + * We should never reach this case, but if that + * happens, this probably means Hynix decided to use + * a different extended ID format, and we should find + * a way to support it. + */ + WARN(1, "Invalid ECC requirements"); + } + } else { + /* + * The ECC requirements field meaning depends on the + * NAND technology. + */ + u8 nand_tech = chip->id.data[5] & 0x7; + + if (nand_tech < 3) { + /* > 26nm, reference: H27UBG8T2A datasheet */ + if (ecc_level < 5) { + chip->base.eccreq.step_size = 512; + chip->base.eccreq.strength = 1 << ecc_level; + } else if (ecc_level < 7) { + if (ecc_level == 5) + chip->base.eccreq.step_size = 2048; + else + chip->base.eccreq.step_size = 1024; + chip->base.eccreq.strength = 24; + } else { + /* + * We should never reach this case, but if that + * happens, this probably means Hynix decided + * to use a different extended ID format, and + * we should find a way to support it. + */ + WARN(1, "Invalid ECC requirements"); + } + } else { + /* <= 26nm, reference: H27UBG8T2B datasheet */ + if (!ecc_level) { + chip->base.eccreq.step_size = 0; + chip->base.eccreq.strength = 0; + } else if (ecc_level < 5) { + chip->base.eccreq.step_size = 512; + chip->base.eccreq.strength = 1 << (ecc_level - 1); + } else { + chip->base.eccreq.step_size = 1024; + chip->base.eccreq.strength = 24 + + (8 * (ecc_level - 5)); + } + } + } +} + +static void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip, + bool valid_jedecid) +{ + u8 nand_tech; + + /* We need scrambling on all TLC NANDs*/ + if (nanddev_bits_per_cell(&chip->base) > 2) + chip->options |= NAND_NEED_SCRAMBLING; + + /* And on MLC NANDs with sub-3xnm process */ + if (valid_jedecid) { + nand_tech = chip->id.data[5] >> 4; + + /* < 3xnm */ + if (nand_tech > 0) + chip->options |= NAND_NEED_SCRAMBLING; + } else { + nand_tech = chip->id.data[5] & 0x7; + + /* < 32nm */ + if (nand_tech > 2) + chip->options |= NAND_NEED_SCRAMBLING; + } +} + +static void hynix_nand_decode_id(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; + bool valid_jedecid; + u8 tmp; + + memorg = nanddev_get_memorg(&chip->base); + + /* + * Exclude all SLC NANDs from this advanced detection scheme. + * According to the ranges defined in several datasheets, it might + * appear that even SLC NANDs could fall in this extended ID scheme. + * If that the case rework the test to let SLC NANDs go through the + * detection process. + */ + if (chip->id.len < 6 || nand_is_slc(chip)) { + nand_decode_ext_id(chip); + return; + } + + /* Extract pagesize */ + memorg->pagesize = 2048 << (chip->id.data[3] & 0x03); + mtd->writesize = memorg->pagesize; + + tmp = (chip->id.data[3] >> 4) & 0x3; + /* + * When bit7 is set that means we start counting at 1MiB, otherwise + * we start counting at 128KiB and shift this value the content of + * ID[3][4:5]. + * The only exception is when ID[3][4:5] == 3 and ID[3][7] == 0, in + * this case the erasesize is set to 768KiB. + */ + if (chip->id.data[3] & 0x80) { + memorg->pages_per_eraseblock = (SZ_1M << tmp) / + memorg->pagesize; + mtd->erasesize = SZ_1M << tmp; + } else if (tmp == 3) { + memorg->pages_per_eraseblock = (SZ_512K + SZ_256K) / + memorg->pagesize; + mtd->erasesize = SZ_512K + SZ_256K; + } else { + memorg->pages_per_eraseblock = (SZ_128K << tmp) / + memorg->pagesize; + mtd->erasesize = SZ_128K << tmp; + } + + /* + * Modern Toggle DDR NANDs have a valid JEDECID even though they are + * not exposing a valid JEDEC parameter table. + * These NANDs use a different NAND ID scheme. + */ + valid_jedecid = hynix_nand_has_valid_jedecid(chip); + + hynix_nand_extract_oobsize(chip, valid_jedecid); + hynix_nand_extract_ecc_requirements(chip, valid_jedecid); + hynix_nand_extract_scrambling_requirements(chip, valid_jedecid); +} + +static void hynix_nand_cleanup(struct nand_chip *chip) +{ + struct hynix_nand *hynix = nand_get_manufacturer_data(chip); + + if (!hynix) + return; + + kfree(hynix->read_retry); + kfree(hynix); + nand_set_manufacturer_data(chip, NULL); +} + +static int +h27ucg8t2atrbc_choose_interface_config(struct nand_chip *chip, + struct nand_interface_config *iface) +{ + onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 4); + + return nand_choose_best_sdr_timings(chip, iface, NULL); +} + +static int hynix_nand_init(struct nand_chip *chip) +{ + struct hynix_nand *hynix; + int ret; + + if (!nand_is_slc(chip)) + chip->options |= NAND_BBM_LASTPAGE; + else + chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; + + hynix = kzalloc(sizeof(*hynix), GFP_KERNEL); + if (!hynix) + return -ENOMEM; + + nand_set_manufacturer_data(chip, hynix); + + if (!strncmp("H27UCG8T2ATR-BC", chip->parameters.model, + sizeof("H27UCG8T2ATR-BC") - 1)) + chip->ops.choose_interface_config = + h27ucg8t2atrbc_choose_interface_config; + + ret = hynix_nand_rr_init(chip); + if (ret) + hynix_nand_cleanup(chip); + + return ret; +} + +const struct nand_manufacturer_ops hynix_nand_manuf_ops = { + .detect = hynix_nand_decode_id, + .init = hynix_nand_init, + .cleanup = hynix_nand_cleanup, +}; diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 863e8d49ab..b9945791a9 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -1,24 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * drivers/mtd/nandids.c - * * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ -#include <common.h> + #include <linux/sizes.h> -#include <linux/mtd/nand.h> -#ifdef CONFIG_NAND_INFO -#define __STR(str) str -#else -#define __STR(str) "" -#endif +#include "internals.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 @@ -37,49 +26,65 @@ struct nand_flash_dev nand_flash_ids[] = { * listed by full ID. We list them first so that we can easily identify * the most specific match. */ - {__STR("TC58NVG2S0F 4G 3.3V 8-bit"), + {"TC58NVG0S3E 1G 3.3V 8-bit", + { .id = {0x98, 0xd1, 0x90, 0x15, 0x76, 0x14, 0x01, 0x00} }, + SZ_2K, SZ_128, SZ_128K, 0, 8, 64, NAND_ECC_INFO(1, SZ_512), }, + {"TC58NVG2S0F 4G 3.3V 8-bit", { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} }, - SZ_4K, SZ_512, SZ_256K, 0, 8, 224}, - {__STR("TC58NVG3S0F 8G 3.3V 8-bit"), + SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) }, + {"TC58NVG2S0H 4G 3.3V 8-bit", + { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x16, 0x08, 0x00} }, + SZ_4K, SZ_512, SZ_256K, 0, 8, 256, NAND_ECC_INFO(8, SZ_512) }, + {"TC58NVG3S0F 8G 3.3V 8-bit", { .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} }, - SZ_4K, SZ_1K, SZ_256K, 0, 8, 232}, - {__STR("TC58NVG5D2 32G 3.3V 8-bit"), + SZ_4K, SZ_1K, SZ_256K, 0, 8, 232, NAND_ECC_INFO(4, SZ_512) }, + {"TC58NVG5D2 32G 3.3V 8-bit", { .id = {0x98, 0xd7, 0x94, 0x32, 0x76, 0x56, 0x09, 0x00} }, - SZ_8K, SZ_4K, SZ_1M, 0, 8, 640}, - {__STR("TC58NVG6D2 64G 3.3V 8-bit"), + SZ_8K, SZ_4K, SZ_1M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) }, + {"TC58NVG6D2 64G 3.3V 8-bit", { .id = {0x98, 0xde, 0x94, 0x82, 0x76, 0x56, 0x04, 0x20} }, - SZ_8K, SZ_8K, SZ_2M, 0, 8, 640}, - - LEGACY_ID_NAND(__STR("NAND 4MiB 5V 8-bit"), 0x6B, 4, SZ_8K, SP_OPTIONS), - LEGACY_ID_NAND(__STR("NAND 4MiB 3,3V 8-bit"), 0xE3, 4, SZ_8K, SP_OPTIONS), - LEGACY_ID_NAND(__STR("NAND 4MiB 3,3V 8-bit"), 0xE5, 4, SZ_8K, SP_OPTIONS), - LEGACY_ID_NAND(__STR("NAND 8MiB 3,3V 8-bit"), 0xD6, 8, SZ_8K, SP_OPTIONS), - LEGACY_ID_NAND(__STR("NAND 8MiB 3,3V 8-bit"), 0xE6, 8, SZ_8K, SP_OPTIONS), - - LEGACY_ID_NAND(__STR("NAND 16MiB 1,8V 8-bit"), 0x33, 16, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND(__STR("NAND 16MiB 3,3V 8-bit"), 0x73, 16, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND(__STR("NAND 16MiB 1,8V 16-bit"), 0x43, 16, SZ_16K, SP_OPTIONS16), - LEGACY_ID_NAND(__STR("NAND 16MiB 3,3V 16-bit"), 0x53, 16, SZ_16K, SP_OPTIONS16), - - LEGACY_ID_NAND(__STR("NAND 32MiB 1,8V 8-bit"), 0x35, 32, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND(__STR("NAND 32MiB 3,3V 8-bit"), 0x75, 32, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND(__STR("NAND 32MiB 1,8V 16-bit"), 0x45, 32, SZ_16K, SP_OPTIONS16), - LEGACY_ID_NAND(__STR("NAND 32MiB 3,3V 16-bit"), 0x55, 32, SZ_16K, SP_OPTIONS16), - - LEGACY_ID_NAND(__STR("NAND 64MiB 1,8V 8-bit"), 0x36, 64, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND(__STR("NAND 64MiB 3,3V 8-bit"), 0x76, 64, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND(__STR("NAND 64MiB 1,8V 16-bit"), 0x46, 64, SZ_16K, SP_OPTIONS16), - LEGACY_ID_NAND(__STR("NAND 64MiB 3,3V 16-bit"), 0x56, 64, SZ_16K, SP_OPTIONS16), - - LEGACY_ID_NAND(__STR("NAND 128MiB 1,8V 8-bit"), 0x78, 128, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND(__STR("NAND 128MiB 1,8V 8-bit"), 0x39, 128, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND(__STR("NAND 128MiB 3,3V 8-bit"), 0x79, 128, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND(__STR("NAND 128MiB 1,8V 16-bit"), 0x72, 128, SZ_16K, SP_OPTIONS16), - LEGACY_ID_NAND(__STR("NAND 128MiB 1,8V 16-bit"), 0x49, 128, SZ_16K, SP_OPTIONS16), - LEGACY_ID_NAND(__STR("NAND 128MiB 3,3V 16-bit"), 0x74, 128, SZ_16K, SP_OPTIONS16), - LEGACY_ID_NAND(__STR("NAND 128MiB 3,3V 16-bit"), 0x59, 128, SZ_16K, SP_OPTIONS16), - - LEGACY_ID_NAND(__STR("NAND 256MiB 3,3V 8-bit"), 0x71, 256, SZ_16K, SP_OPTIONS), + SZ_8K, SZ_8K, SZ_2M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) }, + {"SDTNRGAMA 64G 3.3V 8-bit", + { .id = {0x45, 0xde, 0x94, 0x93, 0x76, 0x50} }, + SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) }, + {"H27UCG8T2ATR-BC 64G 3.3V 8-bit", + { .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} }, + SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640, + NAND_ECC_INFO(40, SZ_1K) }, + {"TH58NVG2S3HBAI4 4G 3.3V 8-bit", + { .id = {0x98, 0xdc, 0x91, 0x15, 0x76} }, + SZ_2K, SZ_512, SZ_128K, 0, 5, 128, NAND_ECC_INFO(8, SZ_512) }, + + LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE5, 4, SZ_8K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xD6, 8, SZ_8K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xE6, 8, SZ_8K, SP_OPTIONS), + + LEGACY_ID_NAND("NAND 16MiB 1,8V 8-bit", 0x33, 16, SZ_16K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 16MiB 3,3V 8-bit", 0x73, 16, SZ_16K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 16MiB 1,8V 16-bit", 0x43, 16, SZ_16K, SP_OPTIONS16), + LEGACY_ID_NAND("NAND 16MiB 3,3V 16-bit", 0x53, 16, SZ_16K, SP_OPTIONS16), + + LEGACY_ID_NAND("NAND 32MiB 1,8V 8-bit", 0x35, 32, SZ_16K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 32MiB 3,3V 8-bit", 0x75, 32, SZ_16K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 32MiB 1,8V 16-bit", 0x45, 32, SZ_16K, SP_OPTIONS16), + LEGACY_ID_NAND("NAND 32MiB 3,3V 16-bit", 0x55, 32, SZ_16K, SP_OPTIONS16), + + LEGACY_ID_NAND("NAND 64MiB 1,8V 8-bit", 0x36, 64, SZ_16K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 64MiB 3,3V 8-bit", 0x76, 64, SZ_16K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 64MiB 1,8V 16-bit", 0x46, 64, SZ_16K, SP_OPTIONS16), + LEGACY_ID_NAND("NAND 64MiB 3,3V 16-bit", 0x56, 64, SZ_16K, SP_OPTIONS16), + + LEGACY_ID_NAND("NAND 128MiB 1,8V 8-bit", 0x78, 128, SZ_16K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 128MiB 1,8V 8-bit", 0x39, 128, SZ_16K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 128MiB 3,3V 8-bit", 0x79, 128, SZ_16K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 128MiB 1,8V 16-bit", 0x72, 128, SZ_16K, SP_OPTIONS16), + LEGACY_ID_NAND("NAND 128MiB 1,8V 16-bit", 0x49, 128, SZ_16K, SP_OPTIONS16), + LEGACY_ID_NAND("NAND 128MiB 3,3V 16-bit", 0x74, 128, SZ_16K, SP_OPTIONS16), + LEGACY_ID_NAND("NAND 128MiB 3,3V 16-bit", 0x59, 128, SZ_16K, SP_OPTIONS16), + + LEGACY_ID_NAND("NAND 256MiB 3,3V 8-bit", 0x71, 256, SZ_16K, SP_OPTIONS), /* * These are the new chips with large page size. Their page size and @@ -87,101 +92,116 @@ struct nand_flash_dev nand_flash_ids[] = { */ /* 512 Megabit */ - EXTENDED_ID_NAND(__STR("NAND 64MiB 1,8V 8-bit"), 0xA2, 64, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 64MiB 1,8V 8-bit"), 0xA0, 64, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 64MiB 3,3V 8-bit"), 0xF2, 64, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 64MiB 3,3V 8-bit"), 0xD0, 64, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 64MiB 3,3V 8-bit"), 0xF0, 64, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 64MiB 1,8V 16-bit"), 0xB2, 64, LP_OPTIONS16), - EXTENDED_ID_NAND(__STR("NAND 64MiB 1,8V 16-bit"), 0xB0, 64, LP_OPTIONS16), - EXTENDED_ID_NAND(__STR("NAND 64MiB 3,3V 16-bit"), 0xC2, 64, LP_OPTIONS16), - EXTENDED_ID_NAND(__STR("NAND 64MiB 3,3V 16-bit"), 0xC0, 64, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 64MiB 1,8V 8-bit", 0xA2, 64, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 64MiB 1,8V 8-bit", 0xA0, 64, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit", 0xF2, 64, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit", 0xD0, 64, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit", 0xF0, 64, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 64MiB 1,8V 16-bit", 0xB2, 64, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 64MiB 1,8V 16-bit", 0xB0, 64, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 64MiB 3,3V 16-bit", 0xC2, 64, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 64MiB 3,3V 16-bit", 0xC0, 64, LP_OPTIONS16), /* 1 Gigabit */ - EXTENDED_ID_NAND(__STR("NAND 128MiB 1,8V 8-bit"), 0xA1, 128, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 128MiB 3,3V 8-bit"), 0xF1, 128, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 128MiB 3,3V 8-bit"), 0xD1, 128, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 128MiB 1,8V 16-bit"), 0xB1, 128, LP_OPTIONS16), - EXTENDED_ID_NAND(__STR("NAND 128MiB 3,3V 16-bit"), 0xC1, 128, LP_OPTIONS16), - EXTENDED_ID_NAND(__STR("NAND 128MiB 1,8V 16-bit"), 0xAD, 128, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 128MiB 1,8V 8-bit", 0xA1, 128, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 128MiB 3,3V 8-bit", 0xF1, 128, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 128MiB 3,3V 8-bit", 0xD1, 128, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 128MiB 1,8V 16-bit", 0xB1, 128, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 128MiB 3,3V 16-bit", 0xC1, 128, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 128MiB 1,8V 16-bit", 0xAD, 128, LP_OPTIONS16), /* 2 Gigabit */ - EXTENDED_ID_NAND(__STR("NAND 256MiB 1,8V 8-bit"), 0xAA, 256, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 256MiB 3,3V 8-bit"), 0xDA, 256, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 256MiB 1,8V 16-bit"), 0xBA, 256, LP_OPTIONS16), - EXTENDED_ID_NAND(__STR("NAND 256MiB 3,3V 16-bit"), 0xCA, 256, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 256MiB 1,8V 8-bit", 0xAA, 256, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 256MiB 3,3V 8-bit", 0xDA, 256, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 256MiB 1,8V 16-bit", 0xBA, 256, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 256MiB 3,3V 16-bit", 0xCA, 256, LP_OPTIONS16), /* 4 Gigabit */ - EXTENDED_ID_NAND(__STR("NAND 512MiB 1,8V 8-bit"), 0xAC, 512, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 512MiB 3,3V 8-bit"), 0xDC, 512, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 512MiB 1,8V 16-bit"), 0xBC, 512, LP_OPTIONS16), - EXTENDED_ID_NAND(__STR("NAND 512MiB 3,3V 16-bit"), 0xCC, 512, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 512MiB 1,8V 8-bit", 0xAC, 512, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 512MiB 3,3V 8-bit", 0xDC, 512, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 512MiB 1,8V 16-bit", 0xBC, 512, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 512MiB 3,3V 16-bit", 0xCC, 512, LP_OPTIONS16), /* 8 Gigabit */ - EXTENDED_ID_NAND(__STR("NAND 1GiB 1,8V 8-bit"), 0xA3, 1024, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 1GiB 3,3V 8-bit"), 0xD3, 1024, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 1GiB 1,8V 16-bit"), 0xB3, 1024, LP_OPTIONS16), - EXTENDED_ID_NAND(__STR("NAND 1GiB 3,3V 16-bit"), 0xC3, 1024, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 1GiB 1,8V 8-bit", 0xA3, 1024, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 1GiB 3,3V 8-bit", 0xD3, 1024, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 1GiB 1,8V 16-bit", 0xB3, 1024, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 1GiB 3,3V 16-bit", 0xC3, 1024, LP_OPTIONS16), /* 16 Gigabit */ - EXTENDED_ID_NAND(__STR("NAND 2GiB 1,8V 8-bit"), 0xA5, 2048, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 2GiB 3,3V 8-bit"), 0xD5, 2048, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 2GiB 1,8V 16-bit"), 0xB5, 2048, LP_OPTIONS16), - EXTENDED_ID_NAND(__STR("NAND 2GiB 3,3V 16-bit"), 0xC5, 2048, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 2GiB 1,8V 8-bit", 0xA5, 2048, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 2GiB 3,3V 8-bit", 0xD5, 2048, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 2GiB 1,8V 16-bit", 0xB5, 2048, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 2GiB 3,3V 16-bit", 0xC5, 2048, LP_OPTIONS16), /* 32 Gigabit */ - EXTENDED_ID_NAND(__STR("NAND 4GiB 1,8V 8-bit"), 0xA7, 4096, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 4GiB 3,3V 8-bit"), 0xD7, 4096, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 4GiB 1,8V 16-bit"), 0xB7, 4096, LP_OPTIONS16), - EXTENDED_ID_NAND(__STR("NAND 4GiB 3,3V 16-bit"), 0xC7, 4096, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 4GiB 1,8V 8-bit", 0xA7, 4096, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 4GiB 3,3V 8-bit", 0xD7, 4096, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 4GiB 1,8V 16-bit", 0xB7, 4096, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 4GiB 3,3V 16-bit", 0xC7, 4096, LP_OPTIONS16), /* 64 Gigabit */ - EXTENDED_ID_NAND(__STR("NAND 8GiB 1,8V 8-bit"), 0xAE, 8192, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 8GiB 3,3V 8-bit"), 0xDE, 8192, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 8GiB 1,8V 16-bit"), 0xBE, 8192, LP_OPTIONS16), - EXTENDED_ID_NAND(__STR("NAND 8GiB 3,3V 16-bit"), 0xCE, 8192, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 8GiB 1,8V 8-bit", 0xAE, 8192, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 8GiB 3,3V 8-bit", 0xDE, 8192, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 8GiB 1,8V 16-bit", 0xBE, 8192, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 8GiB 3,3V 16-bit", 0xCE, 8192, LP_OPTIONS16), /* 128 Gigabit */ - EXTENDED_ID_NAND(__STR("NAND 16GiB 1,8V 8-bit"), 0x1A, 16384, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 16GiB 3,3V 8-bit"), 0x3A, 16384, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 16GiB 1,8V 16-bit"), 0x2A, 16384, LP_OPTIONS16), - EXTENDED_ID_NAND(__STR("NAND 16GiB 3,3V 16-bit"), 0x4A, 16384, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 16GiB 1,8V 8-bit", 0x1A, 16384, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 16GiB 3,3V 8-bit", 0x3A, 16384, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 16GiB 1,8V 16-bit", 0x2A, 16384, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 16GiB 3,3V 16-bit", 0x4A, 16384, LP_OPTIONS16), /* 256 Gigabit */ - EXTENDED_ID_NAND(__STR("NAND 32GiB 1,8V 8-bit"), 0x1C, 32768, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 32GiB 3,3V 8-bit"), 0x3C, 32768, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 32GiB 1,8V 16-bit"), 0x2C, 32768, LP_OPTIONS16), - EXTENDED_ID_NAND(__STR("NAND 32GiB 3,3V 16-bit"), 0x4C, 32768, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 32GiB 1,8V 8-bit", 0x1C, 32768, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 32GiB 3,3V 8-bit", 0x3C, 32768, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 32GiB 1,8V 16-bit", 0x2C, 32768, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 32GiB 3,3V 16-bit", 0x4C, 32768, LP_OPTIONS16), /* 512 Gigabit */ - EXTENDED_ID_NAND(__STR("NAND 64GiB 1,8V 8-bit"), 0x1E, 65536, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 64GiB 3,3V 8-bit"), 0x3E, 65536, LP_OPTIONS), - EXTENDED_ID_NAND(__STR("NAND 64GiB 1,8V 16-bit"), 0x2E, 65536, LP_OPTIONS16), - EXTENDED_ID_NAND(__STR("NAND 64GiB 3,3V 16-bit"), 0x4E, 65536, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 64GiB 1,8V 8-bit", 0x1E, 65536, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 64GiB 3,3V 8-bit", 0x3E, 65536, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 64GiB 1,8V 16-bit", 0x2E, 65536, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 64GiB 3,3V 16-bit", 0x4E, 65536, LP_OPTIONS16), {NULL} }; /* Manufacturer IDs */ -struct nand_manufacturers nand_manuf_ids[] = { - {NAND_MFR_TOSHIBA, "Toshiba"}, - {NAND_MFR_SAMSUNG, "Samsung"}, +static const struct nand_manufacturer_desc nand_manufacturer_descs[] = { + {NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops}, + {NAND_MFR_ATO, "ATO"}, + {NAND_MFR_EON, "Eon"}, + {NAND_MFR_ESMT, "ESMT", &esmt_nand_manuf_ops}, {NAND_MFR_FUJITSU, "Fujitsu"}, + {NAND_MFR_HYNIX, "Hynix", &hynix_nand_manuf_ops}, + {NAND_MFR_INTEL, "Intel"}, + {NAND_MFR_MACRONIX, "Macronix", ¯onix_nand_manuf_ops}, + {NAND_MFR_MICRON, "Micron", µn_nand_manuf_ops}, {NAND_MFR_NATIONAL, "National"}, {NAND_MFR_RENESAS, "Renesas"}, + {NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops}, + {NAND_MFR_SANDISK, "SanDisk"}, {NAND_MFR_STMICRO, "ST Micro"}, - {NAND_MFR_HYNIX, "Hynix"}, - {NAND_MFR_MICRON, "Micron"}, - {NAND_MFR_AMD, "AMD/Spansion"}, - {NAND_MFR_MACRONIX, "Macronix"}, - {NAND_MFR_EON, "Eon"}, + {NAND_MFR_TOSHIBA, "Toshiba", &toshiba_nand_manuf_ops}, {NAND_MFR_WINBOND, "Winbond"}, - {0x0, "Unknown"} }; -EXPORT_SYMBOL(nand_manuf_ids); -EXPORT_SYMBOL(nand_flash_ids); +/** + * nand_get_manufacturer_desc - Get manufacturer information from the + * manufacturer ID + * @id: manufacturer ID + * + * Returns a nand_manufacturer_desc object if the manufacturer is defined + * in the NAND manufacturers database, NULL otherwise. + */ +const struct nand_manufacturer_desc *nand_get_manufacturer_desc(u8 id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(nand_manufacturer_descs); i++) + if (nand_manufacturer_descs[i].id == id) + return &nand_manufacturer_descs[i]; -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); -MODULE_DESCRIPTION("Nand device & manufacturer IDs"); + return NULL; +} diff --git a/drivers/mtd/nand/nand_imx.c b/drivers/mtd/nand/nand_imx.c index f9d3c2e34a..3d4082fe18 100644 --- a/drivers/mtd/nand/nand_imx.c +++ b/drivers/mtd/nand/nand_imx.c @@ -24,6 +24,7 @@ #include <init.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> +#include <linux/mtd/rawnand.h> #include <linux/clk.h> #include <mach/generic.h> #include <mach/imx-nand.h> @@ -57,7 +58,7 @@ struct imx_nand_host { int data_width; int flash_bbt; - void (*preset)(struct mtd_info *); + void (*preset)(struct nand_chip *); void (*send_cmd)(struct imx_nand_host *, uint16_t); void (*send_addr)(struct imx_nand_host *, uint16_t); void (*send_page)(struct imx_nand_host *, unsigned int); @@ -65,7 +66,7 @@ struct imx_nand_host { void (*send_read_param)(struct imx_nand_host *); uint16_t (*get_dev_status)(struct imx_nand_host *); int (*check_int)(struct imx_nand_host *); - int (*correct)(struct mtd_info *mtd); + int (*correct)(struct nand_chip *); void (*enable_hwecc)(struct nand_chip *, bool enable); }; @@ -429,7 +430,7 @@ static u16 get_dev_status_v1_v2(struct imx_nand_host *host) * * @return 0 if device is busy else 1 */ -static int imx_nand_dev_ready(struct mtd_info *mtd) +static int imx_nand_dev_ready(struct nand_chip *chip) { /* * NFC handles R/B internally.Therefore,this function @@ -475,10 +476,10 @@ static void imx_nand_enable_hwecc_v3(struct nand_chip *chip, bool enable) writel(config2, NFC_V3_CONFIG2); } -static int imx_nand_correct_data_v1(struct mtd_info *mtd) +static int imx_nand_correct_data_v1(struct nand_chip *chip) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct imx_nand_host *host = nand_chip->priv; + struct mtd_info *mtd = nand_to_mtd(chip); + struct imx_nand_host *host = chip->priv; if (host->eccstatus_v1 < 0) return host->eccstatus_v1; @@ -491,10 +492,10 @@ static int imx_nand_correct_data_v1(struct mtd_info *mtd) return 0; } -static int imx_nand_correct_data_v2_v3(struct mtd_info *mtd) +static int imx_nand_correct_data_v2_v3(struct nand_chip *chip) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct imx_nand_host *host = nand_chip->priv; + struct mtd_info *mtd = nand_to_mtd(chip); + struct imx_nand_host *host = chip->priv; u32 ecc_stat, err; int no_subpages; u8 ecc_bit_mask, err_limit, max_bitflips = 0; @@ -521,7 +522,7 @@ static int imx_nand_correct_data_v2_v3(struct mtd_info *mtd) return max_bitflips; } -static int imx_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, +static int imx_nand_calculate_ecc(struct nand_chip *chip, const u_char * dat, u_char * ecc_code) { return 0; @@ -534,17 +535,16 @@ static int imx_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, * * @return data read from the NAND Flash */ -static u_char imx_nand_read_byte(struct mtd_info *mtd) +static u_char imx_nand_read_byte(struct nand_chip *chip) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct imx_nand_host *host = nand_chip->priv; + struct imx_nand_host *host = chip->priv; u_char ret; /* Check for status request */ if (host->status_request) return host->get_dev_status(host) & 0xFF; - if (nand_chip->options & NAND_BUSWIDTH_16) { + if (chip->options & NAND_BUSWIDTH_16) { /* only take the lower byte of each word */ BUG_ON(host->buf_start & 1); ret = *(uint16_t *)(host->data_buf + host->buf_start); @@ -565,10 +565,9 @@ static u_char imx_nand_read_byte(struct mtd_info *mtd) * * @return data read from the NAND Flash */ -static u16 imx_nand_read_word(struct mtd_info *mtd) +static u16 imx_nand_read_word(struct nand_chip *chip) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct imx_nand_host *host = nand_chip->priv; + struct imx_nand_host *host = chip->priv; uint16_t ret; ret = *(uint16_t *)(host->data_buf + host->buf_start); @@ -586,11 +585,11 @@ static u16 imx_nand_read_word(struct mtd_info *mtd) * @param buf data to be written to NAND Flash * @param len number of bytes to be written */ -static void imx_nand_write_buf(struct mtd_info *mtd, +static void imx_nand_write_buf(struct nand_chip *chip, const u_char *buf, int len) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct imx_nand_host *host = nand_chip->priv; + struct mtd_info *mtd = nand_to_mtd(chip); + struct imx_nand_host *host = chip->priv; u16 col = host->buf_start; int n = mtd->oobsize + mtd->writesize - col; @@ -610,10 +609,10 @@ static void imx_nand_write_buf(struct mtd_info *mtd, * @param buf data to be read from NAND Flash * @param len number of bytes to be read */ -static void imx_nand_read_buf(struct mtd_info *mtd, u_char * buf, int len) +static void imx_nand_read_buf(struct nand_chip *chip, u_char * buf, int len) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct imx_nand_host *host = nand_chip->priv; + struct mtd_info *mtd = nand_to_mtd(chip); + struct imx_nand_host *host = chip->priv; u16 col = host->buf_start; int n = mtd->oobsize + mtd->writesize - col; @@ -631,10 +630,10 @@ static void imx_nand_read_buf(struct mtd_info *mtd, u_char * buf, int len) /* * Function to transfer data to/from spare area. */ -static void copy_spare(struct mtd_info *mtd, int bfrom, void *buf) +static void copy_spare(struct nand_chip *chip, int bfrom, void *buf) { - struct nand_chip *this = mtd_to_nand(mtd); - struct imx_nand_host *host = this->priv; + struct mtd_info *mtd = nand_to_mtd(chip); + struct imx_nand_host *host = chip->priv; u16 i, j; u16 n = mtd->writesize >> 9; u8 *d = buf; @@ -665,14 +664,14 @@ static void copy_spare(struct mtd_info *mtd, int bfrom, void *buf) * @param mtd MTD structure for the NAND Flash * @param chip val indicating select or deselect */ -static void imx_nand_select_chip(struct mtd_info *mtd, int chip) +static void imx_nand_select_chip(struct nand_chip *_chip, int chip) { } -static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) +static void mxc_do_addr_cycle(struct nand_chip *chip, int column, int page_addr) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct imx_nand_host *host = nand_chip->priv; + struct mtd_info *mtd = nand_to_mtd(chip); + struct imx_nand_host *host = chip->priv; /* * Write out column address, if necessary @@ -735,10 +734,9 @@ static int get_eccsize(struct mtd_info *mtd) return 8; } -static void preset_v1(struct mtd_info *mtd) +static void preset_v1(struct nand_chip *chip) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct imx_nand_host *host = nand_chip->priv; + struct imx_nand_host *host = chip->priv; uint16_t config1 = 0; host->eccsize = 1; @@ -757,14 +755,14 @@ static void preset_v1(struct mtd_info *mtd) writew(0x4, host->regs + NFC_V1_V2_WRPROT); } -static void preset_v2(struct mtd_info *mtd) +static void preset_v2(struct nand_chip *chip) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct imx_nand_host *host = nand_chip->priv; + struct mtd_info *mtd = nand_to_mtd(chip); + struct imx_nand_host *host = chip->priv; uint16_t config1 = 0; int mode; - mode = onfi_get_async_timing_mode(nand_chip); + mode = onfi_get_async_timing_mode(chip); if (mode != ONFI_TIMING_MODE_UNKNOWN && !IS_ERR(host->clk)) { const struct nand_sdr_timings *timings; @@ -817,9 +815,9 @@ static void preset_v2(struct mtd_info *mtd) writew(0x4, host->regs + NFC_V1_V2_WRPROT); } -static void preset_v3(struct mtd_info *mtd) +static void preset_v3(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct imx_nand_host *host = chip->priv; uint32_t config2, config3; int i, addr_phases; @@ -887,24 +885,23 @@ static void preset_v3(struct mtd_info *mtd) writel(0, NFC_V3_DELAY_LINE); } -static int imx_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t offset, int data_len, const uint8_t *buf, - int oob_required, int page, int cached, int raw) +static int imx_nand_write_page(struct nand_chip *chip, + const uint8_t *buf, bool ecc, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct imx_nand_host *host = chip->priv; int status; - host->enable_hwecc(chip, !raw); + host->enable_hwecc(chip, ecc); - chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); + chip->legacy.cmdfunc(chip, NAND_CMD_SEQIN, 0x00, page); memcpy32(host->main_area0, buf, mtd->writesize); - if (oob_required) - copy_spare(mtd, 0, chip->oob_poi); + copy_spare(chip, 0, chip->oob_poi); host->send_page(host, NFC_INPUT); - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - status = chip->waitfunc(mtd, chip); + chip->legacy.cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1); + status = chip->legacy.waitfunc(chip); if (status & NAND_STATUS_FAIL) return -EIO; @@ -912,39 +909,54 @@ static int imx_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, return 0; } -static void imx_nand_do_read_page(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required) +static int imx_nand_write_page_ecc(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { + return imx_nand_write_page(chip, buf, true, page); +} + +static int imx_nand_write_page_raw(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) +{ + return imx_nand_write_page(chip, buf, false, page); +} + +static void imx_nand_do_read_page(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) +{ + struct mtd_info *mtd = nand_to_mtd(chip); struct imx_nand_host *host = chip->priv; + nand_read_page_op(chip, page, 0, NULL, 0); + host->send_page(host, NFC_OUTPUT); memcpy32(buf, host->main_area0, mtd->writesize); if (oob_required) - copy_spare(mtd, 1, chip->oob_poi); + copy_spare(chip, 1, chip->oob_poi); } -static int imx_nand_read_page(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) +static int imx_nand_read_page(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { struct imx_nand_host *host = chip->priv; host->enable_hwecc(chip, true); - imx_nand_do_read_page(mtd, chip, buf, oob_required); + imx_nand_do_read_page(chip, buf, oob_required, page); - return host->correct(mtd); + return host->correct(chip); } -static int imx_nand_read_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) +static int imx_nand_read_page_raw(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { struct imx_nand_host *host = chip->priv; host->enable_hwecc(chip, false); - imx_nand_do_read_page(mtd, chip, buf, oob_required); + imx_nand_do_read_page(chip, buf, oob_required, page); return 0; } @@ -958,11 +970,11 @@ static int imx_nand_read_page_raw(struct mtd_info *mtd, * @param column column offset for the page read * @param page_addr page to be read from NAND Flash */ -static void imx_nand_command(struct mtd_info *mtd, unsigned command, +static void imx_nand_command(struct nand_chip *chip, unsigned command, int column, int page_addr) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct imx_nand_host *host = nand_chip->priv; + struct mtd_info *mtd = nand_to_mtd(chip); + struct imx_nand_host *host = chip->priv; dev_dbg(host->dev, "imx_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", @@ -978,7 +990,7 @@ static void imx_nand_command(struct mtd_info *mtd, unsigned command, */ switch (command) { case NAND_CMD_RESET: - host->preset(mtd); + host->preset(chip); host->send_cmd(host, command); break; @@ -986,7 +998,7 @@ static void imx_nand_command(struct mtd_info *mtd, unsigned command, host->buf_start = 0; host->status_request = 1; host->send_cmd(host, command); - mxc_do_addr_cycle(mtd, column, page_addr); + mxc_do_addr_cycle(chip, column, page_addr); break; case NAND_CMD_READ0: @@ -997,7 +1009,7 @@ static void imx_nand_command(struct mtd_info *mtd, unsigned command, host->buf_start = column + mtd->writesize; host->send_cmd(host, NAND_CMD_READ0); - mxc_do_addr_cycle(mtd, column, page_addr); + mxc_do_addr_cycle(chip, column, page_addr); if (host->pagesize_2k) /* send read confirm command */ @@ -1026,7 +1038,7 @@ static void imx_nand_command(struct mtd_info *mtd, unsigned command, * whole page including OOB together. */ /* call ourself to read a page */ - imx_nand_command(mtd, NAND_CMD_READ0, 0, + imx_nand_command(chip, NAND_CMD_READ0, 0, page_addr); } host->buf_start = column; @@ -1042,25 +1054,25 @@ static void imx_nand_command(struct mtd_info *mtd, unsigned command, host->send_cmd(host, NAND_CMD_READ0); } host->send_cmd(host, command); - mxc_do_addr_cycle(mtd, column, page_addr); + mxc_do_addr_cycle(chip, column, page_addr); break; case NAND_CMD_PAGEPROG: host->send_cmd(host, command); - mxc_do_addr_cycle(mtd, column, page_addr); + mxc_do_addr_cycle(chip, column, page_addr); break; case NAND_CMD_READID: host->send_cmd(host, command); - mxc_do_addr_cycle(mtd, column, page_addr); + mxc_do_addr_cycle(chip, column, page_addr); host->send_read_id(host); host->buf_start = 0; break; case NAND_CMD_PARAM: host->send_cmd(host, command); - mxc_do_addr_cycle(mtd, column, page_addr); + mxc_do_addr_cycle(chip, column, page_addr); host->send_read_param(host); host->buf_start = 0; break; @@ -1068,7 +1080,7 @@ static void imx_nand_command(struct mtd_info *mtd, unsigned command, case NAND_CMD_ERASE1: case NAND_CMD_ERASE2: host->send_cmd(host, command); - mxc_do_addr_cycle(mtd, column, page_addr); + mxc_do_addr_cycle(chip, column, page_addr); break; } } @@ -1150,8 +1162,9 @@ static int __init mxcnd_probe_dt(struct imx_nand_host *host) * on the flash BBT. * */ -static int checkbad(struct mtd_info *mtd, loff_t ofs) +static int checkbad(struct nand_chip *chip, loff_t ofs) { + struct mtd_info *mtd = nand_to_mtd(chip); int ret; uint8_t buf[mtd->writesize + mtd->oobsize]; struct mtd_oob_ops ops; @@ -1173,9 +1186,9 @@ static int checkbad(struct mtd_info *mtd, loff_t ofs) return 0; } -static int imxnd_create_bbt(struct mtd_info *mtd) +static int imxnd_create_bbt(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); int len, i, numblocks, ret; loff_t from = 0; uint8_t *bbt; @@ -1190,13 +1203,13 @@ static int imxnd_create_bbt(struct mtd_info *mtd) numblocks = mtd->size >> (chip->bbt_erase_shift - 1); for (i = 0; i < numblocks;) { - ret = checkbad(mtd, from); + ret = checkbad(chip, from); if (ret < 0) goto out; if (ret) { bbt[i >> 3] |= 0x03 << (i & 0x6); - dev_info(mtd->parent, "Bad eraseblock %d at 0x%08x\n", + dev_info(mtd->dev.parent, "Bad eraseblock %d at 0x%08x\n", i >> 1, (unsigned int)from); } @@ -1210,11 +1223,11 @@ static int imxnd_create_bbt(struct mtd_info *mtd) free(chip->bbt); chip->bbt = bbt; - ret = nand_update_bbt(mtd, 0); + ret = nand_update_bbt(chip, 0); if (ret) return ret; - ret = nand_default_bbt(mtd); + ret = nand_create_bbt(chip); if (ret) return ret; @@ -1345,22 +1358,23 @@ static int __init imxnd_probe(struct device_d *dev) /* structures must be linked */ this = &host->nand; - mtd = &this->mtd; - mtd->parent = dev; + mtd = nand_to_mtd(this); + mtd->dev.parent = dev; mtd->name = "imx_nand"; /* 50 us command delay time */ - this->chip_delay = 5; + this->legacy.chip_delay = 5; this->priv = host; - this->dev_ready = imx_nand_dev_ready; - this->cmdfunc = imx_nand_command; - this->select_chip = imx_nand_select_chip; - this->read_byte = imx_nand_read_byte; - this->read_word = imx_nand_read_word; - this->write_buf = imx_nand_write_buf; - this->read_buf = imx_nand_read_buf; - this->write_page = imx_nand_write_page; + this->legacy.dev_ready = imx_nand_dev_ready; + this->legacy.cmdfunc = imx_nand_command; + this->legacy.select_chip = imx_nand_select_chip; + this->legacy.read_byte = imx_nand_read_byte; + this->legacy.read_word = imx_nand_read_word; + this->legacy.write_buf = imx_nand_write_buf; + this->legacy.read_buf = imx_nand_read_buf; + this->ecc.write_page = imx_nand_write_page_ecc; + this->ecc.write_page_raw = imx_nand_write_page_raw; if (host->hw_ecc) { this->ecc.calculate = imx_nand_calculate_ecc; @@ -1381,12 +1395,12 @@ static int __init imxnd_probe(struct device_d *dev) this->ecc.mode = NAND_ECC_SOFT; } - this->ecc.layout = oob_smallpage; + mtd_set_ecclayout(mtd, oob_smallpage); /* NAND bus width determines access functions used by upper layer */ if (host->data_width == 2) { this->options |= NAND_BUSWIDTH_16; - this->ecc.layout = &nandv1_hw_eccoob_smallpage; + mtd_set_ecclayout(mtd, &nandv1_hw_eccoob_smallpage); imx_nand_set_layout(0, 16); } @@ -1398,13 +1412,13 @@ static int __init imxnd_probe(struct device_d *dev) } /* first scan to find the device and get the page size */ - if (nand_scan_ident(mtd, 1, NULL)) { + if (nand_scan_ident(this, 1, NULL)) { err = -ENXIO; goto escan; } /* Call preset again, with correct writesize this time */ - host->preset(mtd); + host->preset(this); imx_nand_set_layout(mtd->writesize, host->data_width == 2 ? 16 : 8); @@ -1414,9 +1428,9 @@ static int __init imxnd_probe(struct device_d *dev) "You will loose factory bad block markers!\n"); if (mtd->writesize == 2048) - this->ecc.layout = oob_largepage; + mtd_set_ecclayout(mtd, oob_largepage); else - this->ecc.layout = oob_4kpage; + mtd_set_ecclayout(mtd, oob_4kpage); host->pagesize_2k = 1; if (nfc_is_v21()) writew(NFC_V2_SPAS_SPARESIZE(64), host->regs + NFC_V2_SPAS); @@ -1432,14 +1446,14 @@ static int __init imxnd_probe(struct device_d *dev) this->ecc.strength = host->eccsize; /* second phase scan */ - if (nand_scan_tail(mtd)) { + if (nand_scan_tail(this)) { err = -ENXIO; goto escan; } if (host->flash_bbt && this->bbt_td->pages[0] == -1 && this->bbt_md->pages[0] == -1) { dev_info(dev, "no BBT found. creating one\n"); - err = imxnd_create_bbt(mtd); + err = imxnd_create_bbt(this); if (err) dev_warn(dev, "Failed to create bbt: %s\n", strerror(-err)); diff --git a/drivers/mtd/nand/nand_jedec.c b/drivers/mtd/nand/nand_jedec.c new file mode 100644 index 0000000000..5632d2c73f --- /dev/null +++ b/drivers/mtd/nand/nand_jedec.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) + * 2002-2006 Thomas Gleixner (tglx@linutronix.de) + * + * Credits: + * David Woodhouse for adding multichip support + * + * Aleph One Ltd. and Toby Churchill Ltd. for supporting the + * rework for 2K page size chips + * + * This file contains all ONFI helpers. + */ + +#include <common.h> +#include <linux/slab.h> + +#include "internals.h" + +#define JEDEC_PARAM_PAGES 3 + +/* + * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise. + */ +int nand_jedec_detect(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; + struct nand_jedec_params *p; + struct jedec_ecc_info *ecc; + bool use_datain = false; + int jedec_version = 0; + char id[5]; + int i, val, ret; + u16 crc; + + memorg = nanddev_get_memorg(&chip->base); + + /* Try JEDEC for unknown chip or LP */ + ret = nand_readid_op(chip, 0x40, id, sizeof(id)); + if (ret || strncmp(id, "JEDEC", sizeof(id))) + return 0; + + /* JEDEC chip: allocate a buffer to hold its parameter page */ + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + + if (!nand_has_exec_op(chip) || + !nand_read_data_op(chip, p, sizeof(*p), true, true)) + use_datain = true; + + for (i = 0; i < JEDEC_PARAM_PAGES; i++) { + if (!i) + ret = nand_read_param_page_op(chip, 0x40, p, + sizeof(*p)); + else if (use_datain) + ret = nand_read_data_op(chip, p, sizeof(*p), true, + false); + else + ret = nand_change_read_column_op(chip, sizeof(*p) * i, + p, sizeof(*p), true); + if (ret) { + ret = 0; + goto free_jedec_param_page; + } + + crc = onfi_crc16(ONFI_CRC_BASE, (u8 *)p, 510); + if (crc == le16_to_cpu(p->crc)) + break; + } + + if (i == JEDEC_PARAM_PAGES) { + pr_err("Could not find valid JEDEC parameter page; aborting\n"); + goto free_jedec_param_page; + } + + /* Check version */ + val = le16_to_cpu(p->revision); + if (val & (1 << 2)) + jedec_version = 10; + else if (val & (1 << 1)) + jedec_version = 1; /* vendor specific version */ + + if (!jedec_version) { + pr_info("unsupported JEDEC version: %d\n", val); + goto free_jedec_param_page; + } + + sanitize_string(p->manufacturer, sizeof(p->manufacturer)); + sanitize_string(p->model, sizeof(p->model)); + chip->parameters.model = strdup(p->model); + if (!chip->parameters.model) { + ret = -ENOMEM; + goto free_jedec_param_page; + } + + memorg->pagesize = le32_to_cpu(p->byte_per_page); + mtd->writesize = memorg->pagesize; + + /* Please reference to the comment for nand_flash_detect_onfi. */ + memorg->pages_per_eraseblock = + 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1); + mtd->erasesize = memorg->pages_per_eraseblock * memorg->pagesize; + + memorg->oobsize = le16_to_cpu(p->spare_bytes_per_page); + mtd->oobsize = memorg->oobsize; + + memorg->luns_per_target = p->lun_count; + memorg->planes_per_lun = 1 << p->multi_plane_addr; + + /* Please reference to the comment for nand_flash_detect_onfi. */ + memorg->eraseblocks_per_lun = + 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1); + memorg->bits_per_cell = p->bits_per_cell; + + if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS) + chip->options |= NAND_BUSWIDTH_16; + + /* ECC info */ + ecc = &p->ecc_info[0]; + + if (ecc->codeword_size >= 9) { + chip->base.eccreq.strength = ecc->ecc_bits; + chip->base.eccreq.step_size = 1 << ecc->codeword_size; + } else { + pr_warn("Invalid codeword size\n"); + } + + ret = 1; + +free_jedec_param_page: + kfree(p); + return ret; +} diff --git a/drivers/mtd/nand/nand_legacy.c b/drivers/mtd/nand/nand_legacy.c new file mode 100644 index 0000000000..0fcafe38f9 --- /dev/null +++ b/drivers/mtd/nand/nand_legacy.c @@ -0,0 +1,629 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) + * 2002-2006 Thomas Gleixner (tglx@linutronix.de) + * + * Credits: + * David Woodhouse for adding multichip support + * + * Aleph One Ltd. and Toby Churchill Ltd. for supporting the + * rework for 2K page size chips + * + * This file contains all legacy helpers/code that should be removed + * at some point. + */ + +#include <common.h> +#include <errno.h> +#include <clock.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_bch.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/err.h> +#include <asm/byteorder.h> +#include <io.h> +#include <malloc.h> +#include <module.h> + +#include "internals.h" + +/** + * nand_read_byte - [DEFAULT] read one byte from the chip + * @chip: NAND chip object + * + * Default read function for 8bit buswidth + */ +static uint8_t nand_read_byte(struct nand_chip *chip) +{ + return readb(chip->legacy.IO_ADDR_R); +} + +/** + * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip + * @chip: NAND chip object + * + * Default read function for 16bit buswidth with endianness conversion. + * + */ +static uint8_t nand_read_byte16(struct nand_chip *chip) +{ + return (uint8_t) cpu_to_le16(readw(chip->legacy.IO_ADDR_R)); +} + +/** + * nand_select_chip - [DEFAULT] control CE line + * @chip: NAND chip object + * @chipnr: chipnumber to select, -1 for deselect + * + * Default select function for 1 chip devices. + */ +static void nand_select_chip(struct nand_chip *chip, int chipnr) +{ + switch (chipnr) { + case -1: + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + 0 | NAND_CTRL_CHANGE); + break; + case 0: + break; + + default: + BUG(); + } +} + +/** + * nand_write_byte - [DEFAULT] write single byte to chip + * @chip: NAND chip object + * @byte: value to write + * + * Default function to write a byte to I/O[7:0] + */ +static void nand_write_byte(struct nand_chip *chip, uint8_t byte) +{ + chip->legacy.write_buf(chip, &byte, 1); +} + +/** + * nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16 + * @chip: NAND chip object + * @byte: value to write + * + * Default function to write a byte to I/O[7:0] on a 16-bit wide chip. + */ +static void nand_write_byte16(struct nand_chip *chip, uint8_t byte) +{ + uint16_t word = byte; + + /* + * It's not entirely clear what should happen to I/O[15:8] when writing + * a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads: + * + * When the host supports a 16-bit bus width, only data is + * transferred at the 16-bit width. All address and command line + * transfers shall use only the lower 8-bits of the data bus. During + * command transfers, the host may place any value on the upper + * 8-bits of the data bus. During address transfers, the host shall + * set the upper 8-bits of the data bus to 00h. + * + * One user of the write_byte callback is nand_set_features. The + * four parameters are specified to be written to I/O[7:0], but this is + * neither an address nor a command transfer. Let's assume a 0 on the + * upper I/O lines is OK. + */ + chip->legacy.write_buf(chip, (uint8_t *)&word, 2); +} + +/** + * nand_write_buf - [DEFAULT] write buffer to chip + * @chip: NAND chip object + * @buf: data buffer + * @len: number of bytes to write + * + * Default write function for 8bit buswidth. + */ +static void nand_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) +{ + int i; + + for (i = 0; i < len; i++) + writeb(buf[i], chip->legacy.IO_ADDR_W); +} + +/** + * nand_read_buf - [DEFAULT] read chip data into buffer + * @chip: NAND chip object + * @buf: buffer to store date + * @len: number of bytes to read + * + * Default read function for 8bit buswidth. + */ +static void nand_read_buf(struct nand_chip *chip, uint8_t *buf, int len) +{ + int i; + + for (i = 0; i < len; i++) + buf[i] = readb(chip->legacy.IO_ADDR_R); +} + +/** + * nand_write_buf16 - [DEFAULT] write buffer to chip + * @chip: NAND chip object + * @buf: data buffer + * @len: number of bytes to write + * + * Default write function for 16bit buswidth. + */ +static void nand_write_buf16(struct nand_chip *chip, const uint8_t *buf, + int len) +{ + int i; + u16 *p = (u16 *) buf; + len >>= 1; + + for (i = 0; i < len; i++) + writew(p[i], chip->legacy.IO_ADDR_W); +} + +/** + * nand_read_buf16 - [DEFAULT] read chip data into buffer + * @chip: NAND chip object + * @buf: buffer to store date + * @len: number of bytes to read + * + * Default read function for 16bit buswidth. + */ +static void nand_read_buf16(struct nand_chip *chip, uint8_t *buf, int len) +{ + int i; + u16 *p = (u16 *) buf; + len >>= 1; + + for (i = 0; i < len; i++) + p[i] = readw(chip->legacy.IO_ADDR_R); +} + +/** + * nand_wait_ready - [GENERIC] Wait for the ready pin after commands. + * @chip: NAND chip object + * + * Wait for the ready pin after a command, and warn if a timeout occurs. + */ +void nand_wait_ready(struct nand_chip *chip) +{ + uint64_t start = get_time_ns(); + + /* Wait until command is processed or timeout occurs */ + do { + if (chip->legacy.dev_ready(chip)) + return; + } while (!is_timeout(start, 400 * MSECOND)); + + if (!chip->legacy.dev_ready(chip)) + pr_warn("timeout while waiting for chip to become ready\n"); +} +EXPORT_SYMBOL_GPL(nand_wait_ready); + +/** + * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands. + * @chip: NAND chip object + * @timeo: Timeout in ms + * + * Wait for status ready (i.e. command done) or timeout. + */ +static void nand_wait_status_ready(struct nand_chip *chip, unsigned long timeo) +{ + uint64_t start = get_time_ns(); + int ret; + + do { + u8 status; + + ret = nand_read_data_op(chip, &status, sizeof(status), true, + false); + if (ret) + return; + + if (status & NAND_STATUS_READY) + break; + } while (!is_timeout(start, timeo * MSECOND)); +}; + +/** + * nand_command - [DEFAULT] Send command to NAND device + * @chip: NAND chip object + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none + * + * Send command to NAND device. This function is used for small page devices + * (512 Bytes per page). + */ +static void nand_command(struct nand_chip *chip, unsigned int command, + int column, int page_addr) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; + + /* Write out the command to the device */ + if (command == NAND_CMD_SEQIN) { + int readcmd; + + if (column >= mtd->writesize) { + /* OOB area */ + column -= mtd->writesize; + readcmd = NAND_CMD_READOOB; + } else if (column < 256) { + /* First 256 bytes --> READ0 */ + readcmd = NAND_CMD_READ0; + } else { + column -= 256; + readcmd = NAND_CMD_READ1; + } + chip->legacy.cmd_ctrl(chip, readcmd, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + } + if (command != NAND_CMD_NONE) + chip->legacy.cmd_ctrl(chip, command, ctrl); + + /* Address cycle, when necessary */ + ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; + /* Serially input address */ + if (column != -1) { + /* Adjust columns for 16 bit buswidth */ + if (chip->options & NAND_BUSWIDTH_16 && + !nand_opcode_8bits(command)) + column >>= 1; + chip->legacy.cmd_ctrl(chip, column, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + } + if (page_addr != -1) { + chip->legacy.cmd_ctrl(chip, page_addr, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + chip->legacy.cmd_ctrl(chip, page_addr >> 8, ctrl); + if (chip->options & NAND_ROW_ADDR_3) + chip->legacy.cmd_ctrl(chip, page_addr >> 16, ctrl); + } + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + + /* + * Program and erase have their own busy handlers status and sequential + * in needs no delay + */ + switch (command) { + + case NAND_CMD_NONE: + case NAND_CMD_PAGEPROG: + case NAND_CMD_ERASE1: + case NAND_CMD_ERASE2: + case NAND_CMD_SEQIN: + case NAND_CMD_STATUS: + case NAND_CMD_READID: + case NAND_CMD_SET_FEATURES: + return; + + case NAND_CMD_RESET: + if (chip->legacy.dev_ready) + break; + udelay(chip->legacy.chip_delay); + chip->legacy.cmd_ctrl(chip, NAND_CMD_STATUS, + NAND_CTRL_CLE | NAND_CTRL_CHANGE); + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + /* EZ-NAND can take upto 250ms as per ONFi v4.0 */ + nand_wait_status_ready(chip, 250); + return; + + /* This applies to read commands */ + case NAND_CMD_READ0: + /* + * READ0 is sometimes used to exit GET STATUS mode. When this + * is the case no address cycles are requested, and we can use + * this information to detect that we should not wait for the + * device to be ready. + */ + if (column == -1 && page_addr == -1) + return; + default: + /* + * If we don't have access to the busy pin, we apply the given + * command delay + */ + if (!chip->legacy.dev_ready) { + udelay(chip->legacy.chip_delay); + return; + } + } + /* + * Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. + */ + ndelay(100); + + nand_wait_ready(chip); +} + +static void nand_ccs_delay(struct nand_chip *chip) +{ + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(chip)); + + /* + * The controller already takes care of waiting for tCCS when the RNDIN + * or RNDOUT command is sent, return directly. + */ + if (!(chip->options & NAND_WAIT_TCCS)) + return; + + /* + * Wait tCCS_min if it is correctly defined, otherwise wait 500ns + * (which should be safe for all NANDs). + */ + if (nand_controller_can_setup_interface(chip)) + ndelay(sdr->tCCS_min / 1000); + else + ndelay(500); +} + +/** + * nand_command_lp - [DEFAULT] Send command to NAND large page device + * @chip: NAND chip object + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none + * + * Send command to NAND device. This is the version for the new large page + * devices. We don't have the separate regions as we have in the small page + * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. + */ +static void nand_command_lp(struct nand_chip *chip, unsigned int command, + int column, int page_addr) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + /* Emulate NAND_CMD_READOOB */ + if (command == NAND_CMD_READOOB) { + column += mtd->writesize; + command = NAND_CMD_READ0; + } + + /* Command latch cycle */ + if (command != NAND_CMD_NONE) + chip->legacy.cmd_ctrl(chip, command, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + + if (column != -1 || page_addr != -1) { + int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE; + + /* Serially input address */ + if (column != -1) { + /* Adjust columns for 16 bit buswidth */ + if (chip->options & NAND_BUSWIDTH_16 && + !nand_opcode_8bits(command)) + column >>= 1; + chip->legacy.cmd_ctrl(chip, column, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + + /* Only output a single addr cycle for 8bits opcodes. */ + if (!nand_opcode_8bits(command)) + chip->legacy.cmd_ctrl(chip, column >> 8, ctrl); + } + if (page_addr != -1) { + chip->legacy.cmd_ctrl(chip, page_addr, ctrl); + chip->legacy.cmd_ctrl(chip, page_addr >> 8, + NAND_NCE | NAND_ALE); + if (chip->options & NAND_ROW_ADDR_3) + chip->legacy.cmd_ctrl(chip, page_addr >> 16, + NAND_NCE | NAND_ALE); + } + } + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + + /* + * Program and erase have their own busy handlers status, sequential + * in and status need no delay. + */ + switch (command) { + + case NAND_CMD_NONE: + case NAND_CMD_CACHEDPROG: + case NAND_CMD_PAGEPROG: + case NAND_CMD_ERASE1: + case NAND_CMD_ERASE2: + case NAND_CMD_SEQIN: + case NAND_CMD_STATUS: + case NAND_CMD_READID: + case NAND_CMD_SET_FEATURES: + return; + + case NAND_CMD_RNDIN: + nand_ccs_delay(chip); + return; + + case NAND_CMD_RESET: + if (chip->legacy.dev_ready) + break; + udelay(chip->legacy.chip_delay); + chip->legacy.cmd_ctrl(chip, NAND_CMD_STATUS, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + /* EZ-NAND can take upto 250ms as per ONFi v4.0 */ + nand_wait_status_ready(chip, 250); + return; + + case NAND_CMD_RNDOUT: + /* No ready / busy check necessary */ + chip->legacy.cmd_ctrl(chip, NAND_CMD_RNDOUTSTART, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + + nand_ccs_delay(chip); + return; + + case NAND_CMD_READ0: + /* + * READ0 is sometimes used to exit GET STATUS mode. When this + * is the case no address cycles are requested, and we can use + * this information to detect that READSTART should not be + * issued. + */ + if (column == -1 && page_addr == -1) + return; + + chip->legacy.cmd_ctrl(chip, NAND_CMD_READSTART, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + default: + /* + * If we don't have access to the busy pin, we apply the given + * command delay. + */ + if (!chip->legacy.dev_ready) { + udelay(chip->legacy.chip_delay); + return; + } + } + + /* + * Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. + */ + ndelay(100); + + nand_wait_ready(chip); +} + +/** + * nand_get_set_features_notsupp - set/get features stub returning -ENOTSUPP + * @chip: nand chip info structure + * @addr: feature address. + * @subfeature_param: the subfeature parameters, a four bytes array. + * + * Should be used by NAND controller drivers that do not support the SET/GET + * FEATURES operations. + */ +int nand_get_set_features_notsupp(struct nand_chip *chip, int addr, + u8 *subfeature_param) +{ + return -ENOTSUPP; +} +EXPORT_SYMBOL(nand_get_set_features_notsupp); + +/** + * nand_wait - [DEFAULT] wait until the command is done + * @chip: NAND chip structure + * + * Wait for command done. This applies to erase and program only. + */ +static int nand_wait(struct nand_chip *chip) +{ + + u8 status; + int ret; + uint64_t start = get_time_ns(); + + /* + * Apply this short delay always to ensure that we do wait tWB in any + * case on any machine. + */ + ndelay(100); + + ret = nand_status_op(chip, NULL); + if (ret) + return ret; + + do { + if (chip->legacy.dev_ready) { + if (chip->legacy.dev_ready(chip)) + break; + } else { + ret = nand_read_data_op(chip, &status, + sizeof(status), true, + false); + if (ret) + return ret; + + if (status & NAND_STATUS_READY) + break; + } + } while (!is_timeout(start, 400 * MSECOND)); + + ret = nand_read_data_op(chip, &status, sizeof(status), true, false); + if (ret) + return ret; + + /* This can happen if in case of timeout or buggy dev_ready */ + WARN_ON(!(status & NAND_STATUS_READY)); + return status; +} + +void nand_legacy_set_defaults(struct nand_chip *chip) +{ + unsigned int busw = chip->options & NAND_BUSWIDTH_16; + + if (nand_has_exec_op(chip)) + return; + + /* check for proper chip_delay setup, set 20us if not */ + if (!chip->legacy.chip_delay) + chip->legacy.chip_delay = 20; + + /* check, if a user supplied command function given */ + if (!chip->legacy.cmdfunc) + chip->legacy.cmdfunc = nand_command; + + /* check, if a user supplied wait function given */ + if (chip->legacy.waitfunc == NULL) + chip->legacy.waitfunc = nand_wait; + + if (!chip->legacy.select_chip) + chip->legacy.select_chip = nand_select_chip; + + /* If called twice, pointers that depend on busw may need to be reset */ + if (!chip->legacy.read_byte || chip->legacy.read_byte == nand_read_byte) + chip->legacy.read_byte = busw ? nand_read_byte16 : nand_read_byte; + if (!chip->legacy.write_buf || chip->legacy.write_buf == nand_write_buf) + chip->legacy.write_buf = busw ? nand_write_buf16 : nand_write_buf; + if (!chip->legacy.write_byte || chip->legacy.write_byte == nand_write_byte) + chip->legacy.write_byte = busw ? nand_write_byte16 : nand_write_byte; + if (!chip->legacy.read_buf || chip->legacy.read_buf == nand_read_buf) + chip->legacy.read_buf = busw ? nand_read_buf16 : nand_read_buf; +} + +void nand_legacy_adjust_cmdfunc(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + /* Do not replace user supplied command function! */ + if (mtd->writesize > 512 && chip->legacy.cmdfunc == nand_command) + chip->legacy.cmdfunc = nand_command_lp; +} + +int nand_legacy_check_hooks(struct nand_chip *chip) +{ + /* + * ->legacy.cmdfunc() is legacy and will only be used if ->exec_op() is + * not populated. + */ + if (nand_has_exec_op(chip)) + return 0; + + /* + * Default functions assigned for ->legacy.cmdfunc() and + * ->legacy.select_chip() both expect ->legacy.cmd_ctrl() to be + * populated. + */ + if ((!chip->legacy.cmdfunc || !chip->legacy.select_chip) && + !chip->legacy.cmd_ctrl) { + pr_err("->legacy.cmd_ctrl() should be provided\n"); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/mtd/nand/nand_macronix.c b/drivers/mtd/nand/nand_macronix.c new file mode 100644 index 0000000000..bfedc789fb --- /dev/null +++ b/drivers/mtd/nand/nand_macronix.c @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2017 Free Electrons + * Copyright (C) 2017 NextThing Co + * + * Author: Boris Brezillon <boris.brezillon@free-electrons.com> + */ + +#include <linux/bitmap.h> +#include "internals.h" + +#define MACRONIX_READ_RETRY_BIT BIT(0) +#define MACRONIX_NUM_READ_RETRY_MODES 6 + +#define ONFI_FEATURE_ADDR_MXIC_PROTECTION 0xA0 +#define MXIC_BLOCK_PROTECTION_ALL_LOCK 0x38 +#define MXIC_BLOCK_PROTECTION_ALL_UNLOCK 0x0 + +#define ONFI_FEATURE_ADDR_MXIC_RANDOMIZER 0xB0 +#define MACRONIX_RANDOMIZER_BIT BIT(1) +#define MACRONIX_RANDOMIZER_ENPGM BIT(0) +#define MACRONIX_RANDOMIZER_RANDEN BIT(1) +#define MACRONIX_RANDOMIZER_RANDOPT BIT(2) +#define MACRONIX_RANDOMIZER_MODE_ENTER \ + (MACRONIX_RANDOMIZER_ENPGM | \ + MACRONIX_RANDOMIZER_RANDEN | \ + MACRONIX_RANDOMIZER_RANDOPT) +#define MACRONIX_RANDOMIZER_MODE_EXIT \ + (MACRONIX_RANDOMIZER_RANDEN | \ + MACRONIX_RANDOMIZER_RANDOPT) + +#define MXIC_CMD_POWER_DOWN 0xB9 + +struct nand_onfi_vendor_macronix { + u8 reserved; + u8 reliability_func; +} __packed; + +static int macronix_nand_setup_read_retry(struct nand_chip *chip, int mode) +{ + u8 feature[ONFI_SUBFEATURE_PARAM_LEN]; + + if (!chip->parameters.supports_set_get_features || + !test_bit(ONFI_FEATURE_ADDR_READ_RETRY, + chip->parameters.set_feature_list)) + return -ENOTSUPP; + + feature[0] = mode; + return nand_set_features(chip, ONFI_FEATURE_ADDR_READ_RETRY, feature); +} + +static int macronix_nand_randomizer_check_enable(struct nand_chip *chip) +{ + u8 feature[ONFI_SUBFEATURE_PARAM_LEN]; + int ret; + + ret = nand_get_features(chip, ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, + feature); + if (ret < 0) + return ret; + + if (feature[0]) + return feature[0]; + + feature[0] = MACRONIX_RANDOMIZER_MODE_ENTER; + ret = nand_set_features(chip, ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, + feature); + if (ret < 0) + return ret; + + /* RANDEN and RANDOPT OTP bits are programmed */ + feature[0] = 0x0; + ret = nand_prog_page_op(chip, 0, 0, feature, 1); + if (ret < 0) + return ret; + + ret = nand_get_features(chip, ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, + feature); + if (ret < 0) + return ret; + + feature[0] &= MACRONIX_RANDOMIZER_MODE_EXIT; + ret = nand_set_features(chip, ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, + feature); + if (ret < 0) + return ret; + + return 0; +} + +static void macronix_nand_onfi_init(struct nand_chip *chip) +{ + struct nand_parameters *p = &chip->parameters; + struct nand_onfi_vendor_macronix *mxic; + struct device_node *dn = nand_get_flash_node(chip); + int rand_otp = 0; + int ret; + + if (!p->onfi) + return; + + if (of_find_property(dn, "mxic,enable-randomizer-otp", NULL)) + rand_otp = 1; + + mxic = (struct nand_onfi_vendor_macronix *)p->onfi->vendor; + /* Subpage write is prohibited in randomizer operatoin */ + if (rand_otp && chip->options & NAND_NO_SUBPAGE_WRITE && + mxic->reliability_func & MACRONIX_RANDOMIZER_BIT) { + if (p->supports_set_get_features) { + bitmap_set(p->set_feature_list, + ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, 1); + bitmap_set(p->get_feature_list, + ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, 1); + ret = macronix_nand_randomizer_check_enable(chip); + if (ret < 0) { + bitmap_clear(p->set_feature_list, + ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, + 1); + bitmap_clear(p->get_feature_list, + ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, + 1); + pr_info("Macronix NAND randomizer failed\n"); + } else { + pr_info("Macronix NAND randomizer enabled\n"); + } + } + } + + if ((mxic->reliability_func & MACRONIX_READ_RETRY_BIT) == 0) + return; + + chip->read_retries = MACRONIX_NUM_READ_RETRY_MODES; + chip->ops.setup_read_retry = macronix_nand_setup_read_retry; + + if (p->supports_set_get_features) { + bitmap_set(p->set_feature_list, + ONFI_FEATURE_ADDR_READ_RETRY, 1); + bitmap_set(p->get_feature_list, + ONFI_FEATURE_ADDR_READ_RETRY, 1); + } +} + +/* + * Macronix AC series does not support using SET/GET_FEATURES to change + * the timings unlike what is declared in the parameter page. Unflag + * this feature to avoid unnecessary downturns. + */ +static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip) +{ + int i; + static const char * const broken_get_timings[] = { + "MX30LF1G18AC", + "MX30LF1G28AC", + "MX30LF2G18AC", + "MX30LF2G28AC", + "MX30LF4G18AC", + "MX30LF4G28AC", + "MX60LF8G18AC", + "MX30UF1G18AC", + "MX30UF1G16AC", + "MX30UF2G18AC", + "MX30UF2G16AC", + "MX30UF4G18AC", + "MX30UF4G16AC", + "MX30UF4G28AC", + }; + + if (!chip->parameters.supports_set_get_features) + return; + + i = match_string(broken_get_timings, ARRAY_SIZE(broken_get_timings), + chip->parameters.model); + if (i < 0) + return; + + bitmap_clear(chip->parameters.get_feature_list, + ONFI_FEATURE_ADDR_TIMING_MODE, 1); + bitmap_clear(chip->parameters.set_feature_list, + ONFI_FEATURE_ADDR_TIMING_MODE, 1); +} + +/* + * Macronix NAND supports Block Protection by Protectoin(PT) pin; + * active high at power-on which protects the entire chip even the #WP is + * disabled. Lock/unlock protection area can be partition according to + * protection bits, i.e. upper 1/2 locked, upper 1/4 locked and so on. + */ +static int mxic_nand_lock(struct nand_chip *chip, loff_t ofs, uint64_t len) +{ + u8 feature[ONFI_SUBFEATURE_PARAM_LEN]; + int ret; + + feature[0] = MXIC_BLOCK_PROTECTION_ALL_LOCK; + nand_select_target(chip, 0); + ret = nand_set_features(chip, ONFI_FEATURE_ADDR_MXIC_PROTECTION, + feature); + nand_deselect_target(chip); + if (ret) + pr_err("%s all blocks failed\n", __func__); + + return ret; +} + +static int mxic_nand_unlock(struct nand_chip *chip, loff_t ofs, uint64_t len) +{ + u8 feature[ONFI_SUBFEATURE_PARAM_LEN]; + int ret; + + feature[0] = MXIC_BLOCK_PROTECTION_ALL_UNLOCK; + nand_select_target(chip, 0); + ret = nand_set_features(chip, ONFI_FEATURE_ADDR_MXIC_PROTECTION, + feature); + nand_deselect_target(chip); + if (ret) + pr_err("%s all blocks failed\n", __func__); + + return ret; +} + +static void macronix_nand_block_protection_support(struct nand_chip *chip) +{ + u8 feature[ONFI_SUBFEATURE_PARAM_LEN]; + int ret; + + bitmap_set(chip->parameters.get_feature_list, + ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1); + + feature[0] = MXIC_BLOCK_PROTECTION_ALL_UNLOCK; + nand_select_target(chip, 0); + ret = nand_get_features(chip, ONFI_FEATURE_ADDR_MXIC_PROTECTION, + feature); + nand_deselect_target(chip); + if (ret || feature[0] != MXIC_BLOCK_PROTECTION_ALL_LOCK) { + if (ret) + pr_err("Block protection check failed\n"); + + bitmap_clear(chip->parameters.get_feature_list, + ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1); + return; + } + + bitmap_set(chip->parameters.set_feature_list, + ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1); + + chip->ops.lock_area = mxic_nand_lock; + chip->ops.unlock_area = mxic_nand_unlock; +} + +static int nand_power_down_op(struct nand_chip *chip) +{ + int ret; + + if (nand_has_exec_op(chip)) { + struct nand_op_instr instrs[] = { + NAND_OP_CMD(MXIC_CMD_POWER_DOWN, 0), + }; + + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + + ret = nand_exec_op(chip, &op); + if (ret) + return ret; + + } else { + chip->legacy.cmdfunc(chip, MXIC_CMD_POWER_DOWN, -1, -1); + } + + return 0; +} + +static int mxic_nand_suspend(struct nand_chip *chip) +{ + int ret; + + nand_select_target(chip, 0); + ret = nand_power_down_op(chip); + if (ret < 0) + pr_err("Suspending MXIC NAND chip failed (%d)\n", ret); + nand_deselect_target(chip); + + return ret; +} + +static void mxic_nand_resume(struct nand_chip *chip) +{ + /* + * Toggle #CS pin to resume NAND device and don't care + * of the others CLE, #WE, #RE pins status. + * A NAND controller ensure it is able to assert/de-assert #CS + * by sending any byte over the NAND bus. + * i.e., + * NAND power down command or reset command w/o R/B# status checking. + */ + nand_select_target(chip, 0); + nand_power_down_op(chip); + /* The minimum of a recovery time tRDP is 35 us */ + udelay(35); + nand_deselect_target(chip); +} + +static void macronix_nand_deep_power_down_support(struct nand_chip *chip) +{ + int i; + static const char * const deep_power_down_dev[] = { + "MX30UF1G28AD", + "MX30UF2G28AD", + "MX30UF4G28AD", + }; + + i = match_string(deep_power_down_dev, ARRAY_SIZE(deep_power_down_dev), + chip->parameters.model); + if (i < 0) + return; + + chip->ops.suspend = mxic_nand_suspend; + chip->ops.resume = mxic_nand_resume; +} + +static int macronix_nand_init(struct nand_chip *chip) +{ + if (nand_is_slc(chip)) + chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; + + macronix_nand_fix_broken_get_timings(chip); + macronix_nand_onfi_init(chip); + macronix_nand_block_protection_support(chip); + macronix_nand_deep_power_down_support(chip); + + return 0; +} + +const struct nand_manufacturer_ops macronix_nand_manuf_ops = { + .init = macronix_nand_init, +}; diff --git a/drivers/mtd/nand/nand_micron.c b/drivers/mtd/nand/nand_micron.c new file mode 100644 index 0000000000..d59be7ca7b --- /dev/null +++ b/drivers/mtd/nand/nand_micron.c @@ -0,0 +1,595 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2017 Free Electrons + * Copyright (C) 2017 NextThing Co + * + * Author: Boris Brezillon <boris.brezillon@free-electrons.com> + */ + +#include <common.h> +#include <linux/slab.h> + +#include "internals.h" + +/* + * Special Micron status bit 3 indicates that the block has been + * corrected by on-die ECC and should be rewritten. + */ +#define NAND_ECC_STATUS_WRITE_RECOMMENDED BIT(3) + +/* + * On chips with 8-bit ECC and additional bit can be used to distinguish + * cases where a errors were corrected without needing a rewrite + * + * Bit 4 Bit 3 Bit 0 Description + * ----- ----- ----- ----------- + * 0 0 0 No Errors + * 0 0 1 Multiple uncorrected errors + * 0 1 0 4 - 6 errors corrected, recommend rewrite + * 0 1 1 Reserved + * 1 0 0 1 - 3 errors corrected + * 1 0 1 Reserved + * 1 1 0 7 - 8 errors corrected, recommend rewrite + */ +#define NAND_ECC_STATUS_MASK (BIT(4) | BIT(3) | BIT(0)) +#define NAND_ECC_STATUS_UNCORRECTABLE BIT(0) +#define NAND_ECC_STATUS_4_6_CORRECTED BIT(3) +#define NAND_ECC_STATUS_1_3_CORRECTED BIT(4) +#define NAND_ECC_STATUS_7_8_CORRECTED (BIT(4) | BIT(3)) + +struct nand_onfi_vendor_micron { + u8 two_plane_read; + u8 read_cache; + u8 read_unique_id; + u8 dq_imped; + u8 dq_imped_num_settings; + u8 dq_imped_feat_addr; + u8 rb_pulldown_strength; + u8 rb_pulldown_strength_feat_addr; + u8 rb_pulldown_strength_num_settings; + u8 otp_mode; + u8 otp_page_start; + u8 otp_data_prot_addr; + u8 otp_num_pages; + u8 otp_feat_addr; + u8 read_retry_options; + u8 reserved[72]; + u8 param_revision; +} __packed; + +struct micron_on_die_ecc { + bool forced; + bool enabled; + void *rawbuf; +}; + +struct micron_nand { + struct micron_on_die_ecc ecc; +}; + +static int micron_nand_setup_read_retry(struct nand_chip *chip, int retry_mode) +{ + u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode}; + + return nand_set_features(chip, ONFI_FEATURE_ADDR_READ_RETRY, feature); +} + +/* + * Configure chip properties from Micron vendor-specific ONFI table + */ +static int micron_nand_onfi_init(struct nand_chip *chip) +{ + struct nand_parameters *p = &chip->parameters; + + if (p->onfi) { + struct nand_onfi_vendor_micron *micron = (void *)p->onfi->vendor; + + chip->read_retries = micron->read_retry_options; + chip->ops.setup_read_retry = micron_nand_setup_read_retry; + } + + if (p->supports_set_get_features) { + set_bit(ONFI_FEATURE_ADDR_READ_RETRY, p->set_feature_list); + set_bit(ONFI_FEATURE_ON_DIE_ECC, p->set_feature_list); + set_bit(ONFI_FEATURE_ADDR_READ_RETRY, p->get_feature_list); + set_bit(ONFI_FEATURE_ON_DIE_ECC, p->get_feature_list); + } + + return 0; +} + +static int micron_nand_on_die_4_ooblayout_ecc(struct mtd_info *mtd, + int section, + struct mtd_oob_region *oobregion) +{ + if (section >= 4) + return -ERANGE; + + oobregion->offset = (section * 16) + 8; + oobregion->length = 8; + + return 0; +} + +static int micron_nand_on_die_4_ooblayout_free(struct mtd_info *mtd, + int section, + struct mtd_oob_region *oobregion) +{ + if (section >= 4) + return -ERANGE; + + oobregion->offset = (section * 16) + 2; + oobregion->length = 6; + + return 0; +} + +static const struct mtd_ooblayout_ops micron_nand_on_die_4_ooblayout_ops = { + .ecc = micron_nand_on_die_4_ooblayout_ecc, + .free = micron_nand_on_die_4_ooblayout_free, +}; + +static int micron_nand_on_die_8_ooblayout_ecc(struct mtd_info *mtd, + int section, + struct mtd_oob_region *oobregion) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + + if (section) + return -ERANGE; + + oobregion->offset = mtd->oobsize - chip->ecc.total; + oobregion->length = chip->ecc.total; + + return 0; +} + +static int micron_nand_on_die_8_ooblayout_free(struct mtd_info *mtd, + int section, + struct mtd_oob_region *oobregion) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + + if (section) + return -ERANGE; + + oobregion->offset = 2; + oobregion->length = mtd->oobsize - chip->ecc.total - 2; + + return 0; +} + +static const struct mtd_ooblayout_ops micron_nand_on_die_8_ooblayout_ops = { + .ecc = micron_nand_on_die_8_ooblayout_ecc, + .free = micron_nand_on_die_8_ooblayout_free, +}; + +static int micron_nand_on_die_ecc_setup(struct nand_chip *chip, bool enable) +{ + struct micron_nand *micron = nand_get_manufacturer_data(chip); + u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, }; + int ret; + + if (micron->ecc.forced) + return 0; + + if (micron->ecc.enabled == enable) + return 0; + + if (enable) + feature[0] |= ONFI_FEATURE_ON_DIE_ECC_EN; + + ret = nand_set_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature); + if (!ret) + micron->ecc.enabled = enable; + + return ret; +} + +static int micron_nand_on_die_ecc_status_4(struct nand_chip *chip, u8 status, + void *buf, int page, + int oob_required) +{ + struct micron_nand *micron = nand_get_manufacturer_data(chip); + struct mtd_info *mtd = nand_to_mtd(chip); + unsigned int step, max_bitflips = 0; + bool use_datain = false; + int ret; + + if (!(status & NAND_ECC_STATUS_WRITE_RECOMMENDED)) { + if (status & NAND_STATUS_FAIL) + mtd->ecc_stats.failed++; + + return 0; + } + + /* + * The internal ECC doesn't tell us the number of bitflips that have + * been corrected, but tells us if it recommends to rewrite the block. + * If it's the case, we need to read the page in raw mode and compare + * its content to the corrected version to extract the actual number of + * bitflips. + * But before we do that, we must make sure we have all OOB bytes read + * in non-raw mode, even if the user did not request those bytes. + */ + if (!oob_required) { + /* + * We first check which operation is supported by the controller + * before running it. This trick makes it possible to support + * all controllers, even the most constraints, without almost + * any performance hit. + * + * TODO: could be enhanced to avoid repeating the same check + * over and over in the fast path. + */ + if (!nand_has_exec_op(chip) || + !nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, false, + true)) + use_datain = true; + + if (use_datain) + ret = nand_read_data_op(chip, chip->oob_poi, + mtd->oobsize, false, false); + else + ret = nand_change_read_column_op(chip, mtd->writesize, + chip->oob_poi, + mtd->oobsize, false); + if (ret) + return ret; + } + + micron_nand_on_die_ecc_setup(chip, false); + + ret = nand_read_page_op(chip, page, 0, micron->ecc.rawbuf, + mtd->writesize + mtd->oobsize); + if (ret) + return ret; + + for (step = 0; step < chip->ecc.steps; step++) { + unsigned int offs, i, nbitflips = 0; + u8 *rawbuf, *corrbuf; + + offs = step * chip->ecc.size; + rawbuf = micron->ecc.rawbuf + offs; + corrbuf = buf + offs; + + for (i = 0; i < chip->ecc.size; i++) + nbitflips += hweight8(corrbuf[i] ^ rawbuf[i]); + + offs = (step * 16) + 4; + rawbuf = micron->ecc.rawbuf + mtd->writesize + offs; + corrbuf = chip->oob_poi + offs; + + for (i = 0; i < chip->ecc.bytes + 4; i++) + nbitflips += hweight8(corrbuf[i] ^ rawbuf[i]); + + if (WARN_ON(nbitflips > chip->ecc.strength)) + return -EINVAL; + + max_bitflips = max(nbitflips, max_bitflips); + mtd->ecc_stats.corrected += nbitflips; + } + + return max_bitflips; +} + +static int micron_nand_on_die_ecc_status_8(struct nand_chip *chip, u8 status) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + /* + * With 8/512 we have more information but still don't know precisely + * how many bit-flips were seen. + */ + switch (status & NAND_ECC_STATUS_MASK) { + case NAND_ECC_STATUS_UNCORRECTABLE: + mtd->ecc_stats.failed++; + return 0; + case NAND_ECC_STATUS_1_3_CORRECTED: + mtd->ecc_stats.corrected += 3; + return 3; + case NAND_ECC_STATUS_4_6_CORRECTED: + mtd->ecc_stats.corrected += 6; + /* rewrite recommended */ + return 6; + case NAND_ECC_STATUS_7_8_CORRECTED: + mtd->ecc_stats.corrected += 8; + /* rewrite recommended */ + return 8; + default: + return 0; + } +} + +static int +micron_nand_read_page_on_die_ecc(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + bool use_datain = false; + u8 status; + int ret, max_bitflips = 0; + + ret = micron_nand_on_die_ecc_setup(chip, true); + if (ret) + return ret; + + ret = nand_read_page_op(chip, page, 0, NULL, 0); + if (ret) + goto out; + + ret = nand_status_op(chip, &status); + if (ret) + goto out; + + /* + * We first check which operation is supported by the controller before + * running it. This trick makes it possible to support all controllers, + * even the most constraints, without almost any performance hit. + * + * TODO: could be enhanced to avoid repeating the same check over and + * over in the fast path. + */ + if (!nand_has_exec_op(chip) || + !nand_read_data_op(chip, buf, mtd->writesize, false, true)) + use_datain = true; + + if (use_datain) { + ret = nand_exit_status_op(chip); + if (ret) + goto out; + + ret = nand_read_data_op(chip, buf, mtd->writesize, false, + false); + if (!ret && oob_required) + ret = nand_read_data_op(chip, chip->oob_poi, + mtd->oobsize, false, false); + } else { + ret = nand_change_read_column_op(chip, 0, buf, mtd->writesize, + false); + if (!ret && oob_required) + ret = nand_change_read_column_op(chip, mtd->writesize, + chip->oob_poi, + mtd->oobsize, false); + } + + if (chip->ecc.strength == 4) + max_bitflips = micron_nand_on_die_ecc_status_4(chip, status, + buf, page, + oob_required); + else + max_bitflips = micron_nand_on_die_ecc_status_8(chip, status); + +out: + micron_nand_on_die_ecc_setup(chip, false); + + return ret ? ret : max_bitflips; +} + +static int +micron_nand_write_page_on_die_ecc(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) +{ + int ret; + + ret = micron_nand_on_die_ecc_setup(chip, true); + if (ret) + return ret; + + ret = nand_write_page_raw(chip, buf, oob_required, page); + micron_nand_on_die_ecc_setup(chip, false); + + return ret; +} + +enum { + /* The NAND flash doesn't support on-die ECC */ + MICRON_ON_DIE_UNSUPPORTED, + + /* + * The NAND flash supports on-die ECC and it can be + * enabled/disabled by a set features command. + */ + MICRON_ON_DIE_SUPPORTED, + + /* + * The NAND flash supports on-die ECC, and it cannot be + * disabled. + */ + MICRON_ON_DIE_MANDATORY, +}; + +#define MICRON_ID_INTERNAL_ECC_MASK GENMASK(1, 0) +#define MICRON_ID_ECC_ENABLED BIT(7) + +/* + * Try to detect if the NAND support on-die ECC. To do this, we enable + * the feature, and read back if it has been enabled as expected. We + * also check if it can be disabled, because some Micron NANDs do not + * allow disabling the on-die ECC and we don't support such NANDs for + * now. + * + * This function also has the side effect of disabling on-die ECC if + * it had been left enabled by the firmware/bootloader. + */ +static int micron_supports_on_die_ecc(struct nand_chip *chip) +{ + u8 id[5]; + int ret; + + if (!chip->parameters.onfi) + return MICRON_ON_DIE_UNSUPPORTED; + + if (nanddev_bits_per_cell(&chip->base) != 1) + return MICRON_ON_DIE_UNSUPPORTED; + + /* + * We only support on-die ECC of 4/512 or 8/512 + */ + if (chip->base.eccreq.strength != 4 && chip->base.eccreq.strength != 8) + return MICRON_ON_DIE_UNSUPPORTED; + + /* 0x2 means on-die ECC is available. */ + if (chip->id.len != 5 || + (chip->id.data[4] & MICRON_ID_INTERNAL_ECC_MASK) != 0x2) + return MICRON_ON_DIE_UNSUPPORTED; + + /* + * It seems that there are devices which do not support ECC officially. + * At least the MT29F2G08ABAGA / MT29F2G08ABBGA devices supports + * enabling the ECC feature but don't reflect that to the READ_ID table. + * So we have to guarantee that we disable the ECC feature directly + * after we did the READ_ID table command. Later we can evaluate the + * ECC_ENABLE support. + */ + ret = micron_nand_on_die_ecc_setup(chip, true); + if (ret) + return MICRON_ON_DIE_UNSUPPORTED; + + ret = nand_readid_op(chip, 0, id, sizeof(id)); + if (ret) + return MICRON_ON_DIE_UNSUPPORTED; + + ret = micron_nand_on_die_ecc_setup(chip, false); + if (ret) + return MICRON_ON_DIE_UNSUPPORTED; + + if (!(id[4] & MICRON_ID_ECC_ENABLED)) + return MICRON_ON_DIE_UNSUPPORTED; + + ret = nand_readid_op(chip, 0, id, sizeof(id)); + if (ret) + return MICRON_ON_DIE_UNSUPPORTED; + + if (id[4] & MICRON_ID_ECC_ENABLED) + return MICRON_ON_DIE_MANDATORY; + + /* + * We only support on-die ECC of 4/512 or 8/512 + */ + if (chip->base.eccreq.strength != 4 && chip->base.eccreq.strength != 8) + return MICRON_ON_DIE_UNSUPPORTED; + + return MICRON_ON_DIE_SUPPORTED; +} + +static int micron_nand_init(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct micron_nand *micron; + int ondie; + int ret; + + micron = kzalloc(sizeof(*micron), GFP_KERNEL); + if (!micron) + return -ENOMEM; + + nand_set_manufacturer_data(chip, micron); + + ret = micron_nand_onfi_init(chip); + if (ret) + goto err_free_manuf_data; + + chip->options |= NAND_BBM_FIRSTPAGE; + + if (mtd->writesize == 2048) + chip->options |= NAND_BBM_SECONDPAGE; + + ondie = micron_supports_on_die_ecc(chip); + + if (ondie == MICRON_ON_DIE_MANDATORY && + chip->ecc.mode != NAND_ECC_ON_DIE) { + pr_err("On-die ECC forcefully enabled, not supported\n"); + ret = -EINVAL; + goto err_free_manuf_data; + } + + if (chip->ecc.mode == NAND_ECC_ON_DIE) { + if (ondie == MICRON_ON_DIE_UNSUPPORTED) { + pr_err("On-die ECC selected but not supported\n"); + ret = -EINVAL; + goto err_free_manuf_data; + } + + if (ondie == MICRON_ON_DIE_MANDATORY) { + micron->ecc.forced = true; + micron->ecc.enabled = true; + } + + /* + * In case of 4bit on-die ECC, we need a buffer to store a + * page dumped in raw mode so that we can compare its content + * to the same page after ECC correction happened and extract + * the real number of bitflips from this comparison. + * That's not needed for 8-bit ECC, because the status expose + * a better approximation of the number of bitflips in a page. + */ + if (chip->base.eccreq.strength == 4) { + micron->ecc.rawbuf = kmalloc(mtd->writesize + + mtd->oobsize, + GFP_KERNEL); + if (!micron->ecc.rawbuf) { + ret = -ENOMEM; + goto err_free_manuf_data; + } + } + + if (chip->base.eccreq.strength == 4) + mtd_set_ooblayout(mtd, + µn_nand_on_die_4_ooblayout_ops); + else + mtd_set_ooblayout(mtd, + µn_nand_on_die_8_ooblayout_ops); + + chip->ecc.bytes = chip->base.eccreq.strength * 2; + chip->ecc.size = 512; + chip->ecc.strength = chip->base.eccreq.strength; + chip->ecc.algo = NAND_ECC_BCH; + chip->ecc.read_page = micron_nand_read_page_on_die_ecc; + chip->ecc.write_page = micron_nand_write_page_on_die_ecc; + + if (ondie == MICRON_ON_DIE_MANDATORY) { + chip->ecc.read_page_raw = nand_read_page_raw_notsupp; + chip->ecc.write_page_raw = nand_write_page_raw_notsupp; + } else { + if (!chip->ecc.read_page_raw) + chip->ecc.read_page_raw = nand_read_page_raw; + if (!chip->ecc.write_page_raw) + chip->ecc.write_page_raw = nand_write_page_raw; + } + } + + return 0; + +err_free_manuf_data: + kfree(micron->ecc.rawbuf); + kfree(micron); + + return ret; +} + +static void micron_nand_cleanup(struct nand_chip *chip) +{ + struct micron_nand *micron = nand_get_manufacturer_data(chip); + + kfree(micron->ecc.rawbuf); + kfree(micron); +} + +static void micron_fixup_onfi_param_page(struct nand_chip *chip, + struct nand_onfi_params *p) +{ + /* + * MT29F1G08ABAFAWP-ITE:F and possibly others report 00 00 for the + * revision number field of the ONFI parameter page. Assume ONFI + * version 1.0 if the revision number is 00 00. + */ + if (le16_to_cpu(p->revision) == 0) + p->revision = cpu_to_le16(ONFI_VERSION_1_0); +} + +const struct nand_manufacturer_ops micron_nand_manuf_ops = { + .init = micron_nand_init, + .cleanup = micron_nand_cleanup, + .fixup_onfi_param_page = micron_fixup_onfi_param_page, +}; diff --git a/drivers/mtd/nand/nand_mrvl_nfc.c b/drivers/mtd/nand/nand_mrvl_nfc.c index 15d052b5a4..1f3e152375 100644 --- a/drivers/mtd/nand/nand_mrvl_nfc.c +++ b/drivers/mtd/nand/nand_mrvl_nfc.c @@ -20,6 +20,7 @@ #include <init.h> #include <io.h> #include <linux/mtd/mtd.h> +#include <linux/mtd/rawnand.h> #include <linux/mtd/nand.h> #include <linux/types.h> #include <linux/clk.h> @@ -277,8 +278,10 @@ static struct nand_ecclayout ecc_layout_4KB_bch8bit = { #define NDTR1_tWHR(c) (min((c), 15) << 4) #define NDTR1_tAR(c) (min((c), 15) << 0) -#define mtd_info_to_host(mtd) ((struct mrvl_nand_host *) \ - (((struct nand_chip *)((mtd)->priv))->priv)) +static inline struct mrvl_nand_host *nand_to_host(struct nand_chip *chip) +{ + return container_of(chip, struct mrvl_nand_host, chip); +} static const struct mrvl_nand_variant pxa3xx_variant = { .hwflags = 0, @@ -341,7 +344,7 @@ static struct mrvl_nand_timing timings[] = { static void mrvl_nand_set_timing(struct mrvl_nand_host *host, bool use_default) { - struct mtd_info *mtd = &host->chip.mtd; + struct nand_chip *chip = &host->chip; unsigned long nand_clk = clk_get_rate(host->core_clk); struct mrvl_nand_timing *t; uint32_t ndtr0, ndtr1; @@ -350,8 +353,8 @@ static void mrvl_nand_set_timing(struct mrvl_nand_host *host, bool use_default) if (use_default) { id = 0; } else { - host->chip.cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); - host->chip.read_buf(mtd, (unsigned char *)&id, sizeof(id)); + chip->legacy.cmdfunc(chip, NAND_CMD_READID, 0x00, -1); + chip->legacy.read_buf(chip, (unsigned char *)&id, sizeof(id)); } for (t = &timings[0]; t->id; t++) if (t->id == id) @@ -370,9 +373,9 @@ static void mrvl_nand_set_timing(struct mrvl_nand_host *host, bool use_default) nand_writel(host, NDTR1CS0, ndtr1); } -static int mrvl_nand_ready(struct mtd_info *mtd) +static int mrvl_nand_ready(struct nand_chip *chip) { - struct mrvl_nand_host *host = mtd_info_to_host(mtd); + struct mrvl_nand_host *host = nand_to_host(chip); u32 ndcr; ndcr = nand_readl(host, NDSR); @@ -396,14 +399,14 @@ static int mrvl_nand_ready(struct mtd_info *mtd) * Thus, this function is only called when we want *all* blocks to look good, * so it *always* return success. */ -static int mrvl_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) +static int mrvl_nand_block_bad(struct nand_chip *chip, loff_t ofs) { return 0; } -static void mrvl_nand_select_chip(struct mtd_info *mtd, int chipnr) +static void mrvl_nand_select_chip(struct nand_chip *chip, int chipnr) { - struct mrvl_nand_host *host = mtd_info_to_host(mtd); + struct mrvl_nand_host *host = nand_to_host(chip); if (chipnr <= 0 || chipnr >= 3 || chipnr == host->cs) return; @@ -417,9 +420,12 @@ static void mrvl_nand_select_chip(struct mtd_info *mtd, int chipnr) */ static unsigned int mrvl_datasize(struct mrvl_nand_host *host) { + struct nand_chip *chip = &host->chip; + struct mtd_info *mtd = nand_to_mtd(chip); + unsigned int datasize; - datasize = host->chip.mtd.writesize; + datasize = mtd->writesize; if (host->use_spare) { datasize += host->spare_size; if (!host->use_ecc) @@ -470,7 +476,7 @@ static void mrvl_nand_start(struct mrvl_nand_host *host) nand_writel(host, NDSR, NDSR_MASK); nand_writel(host, NDCR, ndcr | NDCR_ND_RUN); - if (wait_on_timeout(host->chip.chip_delay * USECOND, + if (wait_on_timeout(host->chip.legacy.chip_delay * USECOND, nand_readl(host, NDSR) & NDSR_WRCMDREQ)) { dev_err(host->dev, "Waiting for command request failed\n"); } else { @@ -529,6 +535,9 @@ static void set_command_address(struct mrvl_nand_host *host, static void prepare_start_command(struct mrvl_nand_host *host, int command) { + struct nand_chip *chip = &host->chip; + struct mtd_info *mtd = nand_to_mtd(chip); + /* reset data and oob column point to handle data */ host->buf_start = 0; host->buf_count = 0; @@ -571,7 +580,7 @@ static void prepare_start_command(struct mrvl_nand_host *host, int command) if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB || command == NAND_CMD_SEQIN) { - host->buf_count = host->chip.mtd.writesize + host->chip.mtd.oobsize; + host->buf_count = mtd->writesize + mtd->oobsize; memset(host->data_buff, 0xFF, host->buf_count); } @@ -588,10 +597,10 @@ static void prepare_start_command(struct mrvl_nand_host *host, int command) static int prepare_set_command(struct mrvl_nand_host *host, int command, int ext_cmd_type, uint16_t column, int page_addr) { + struct nand_chip *chip = &host->chip; + struct mtd_info *mtd = nand_to_mtd(chip); int addr_cycle, exec_cmd; - struct mtd_info *mtd; - mtd = &host->chip.mtd; exec_cmd = 1; if (host->cs != 0) @@ -717,7 +726,7 @@ static void mrvl_data_stage(struct mrvl_nand_host *host) if (!host->data_size) return; - wait_on_timeout(host->chip.chip_delay * USECOND, + wait_on_timeout(host->chip.legacy.chip_delay * USECOND, nand_readl(host, NDSR) & mask); if (!(nand_readl(host, NDSR) & mask)) { dev_err(host->dev, "Timeout waiting for data ndsr=0x%08x\n", @@ -750,7 +759,7 @@ static void mrvl_nand_wait_cmd_done(struct mrvl_nand_host *host, mask = NDSR_CS0_CMDD; else mask = NDSR_CS1_CMDD; - wait_on_timeout(host->chip.chip_delay * USECOND, + wait_on_timeout(host->chip.legacy.chip_delay * USECOND, (nand_readl(host, NDSR) & mask) == mask); if ((nand_readl(host, NDSR) & mask) != mask) { dev_err(host->dev, "Waiting end of command %dth %d timeout, ndsr=0x%08x ndcr=0x%08x\n", @@ -759,10 +768,10 @@ static void mrvl_nand_wait_cmd_done(struct mrvl_nand_host *host, } } -static void mrvl_nand_cmdfunc(struct mtd_info *mtd, unsigned command, +static void mrvl_nand_cmdfunc(struct nand_chip *chip, unsigned command, int column, int page_addr) { - struct mrvl_nand_host *host = mtd_info_to_host(mtd); + struct mrvl_nand_host *host = nand_to_host(chip); /* * if this is a x16 device ,then convert the input @@ -790,10 +799,13 @@ static void mrvl_nand_cmdfunc(struct mtd_info *mtd, unsigned command, * * Returns 0 */ -static int mrvl_nand_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required) +static int mrvl_nand_write_page_hwecc(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { - struct mrvl_nand_host *host = mtd_info_to_host(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); + struct mrvl_nand_host *host = nand_to_host(chip); + + nand_prog_page_begin_op(chip, page, 0, NULL, 0); memcpy(host->data_buff, buf, mtd->writesize); if (oob_required) @@ -803,19 +815,22 @@ static int mrvl_nand_write_page_hwecc(struct mtd_info *mtd, memset(host->data_buff + mtd->writesize, 0xff, mtd->oobsize); dev_dbg(host->dev, "%s(buf=%p, oob_required=%d) => 0\n", __func__, buf, oob_required); - return 0; + + return nand_prog_page_end_op(chip); } -static int mrvl_nand_read_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, - int page) +static int mrvl_nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { - struct mrvl_nand_host *host = mtd_info_to_host(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); + struct mrvl_nand_host *host = nand_to_host(chip); u32 ndsr; int ret = 0; - chip->read_buf(mtd, buf, mtd->writesize); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + nand_read_page_op(chip, page, 0, NULL, 0); + + chip->legacy.read_buf(chip, buf, mtd->writesize); + chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); ndsr = nand_readl(host, NDSR); if (ndsr & NDSR_UNCORERR) { @@ -837,9 +852,9 @@ static int mrvl_nand_read_page_hwecc(struct mtd_info *mtd, return ret; } -static void mrvl_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static void mrvl_nand_read_buf(struct nand_chip *chip, uint8_t *buf, int len) { - struct mrvl_nand_host *host = mtd_info_to_host(mtd); + struct mrvl_nand_host *host = nand_to_host(chip); int xfer; xfer = min_t(int, len, host->buf_count); @@ -848,26 +863,26 @@ static void mrvl_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) host->buf_count -= xfer; } -static uint8_t mrvl_nand_read_byte(struct mtd_info *mtd) +static uint8_t mrvl_nand_read_byte(struct nand_chip *chip) { uint8_t ret; - mrvl_nand_read_buf(mtd, (uint8_t *)&ret, sizeof(ret)); + mrvl_nand_read_buf(chip, (uint8_t *)&ret, sizeof(ret)); return ret; } -static u16 mrvl_nand_read_word(struct mtd_info *mtd) +static u16 mrvl_nand_read_word(struct nand_chip *chip) { u16 ret; - mrvl_nand_read_buf(mtd, (uint8_t *)&ret, sizeof(ret)); + mrvl_nand_read_buf(chip, (uint8_t *)&ret, sizeof(ret)); return ret; } -static void mrvl_nand_write_buf(struct mtd_info *mtd, +static void mrvl_nand_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) { - struct mrvl_nand_host *host = mtd_info_to_host(mtd); + struct mrvl_nand_host *host = nand_to_host(chip); memcpy(host->data_buff + host->buf_start, buf, len); host->buf_start += len; @@ -877,7 +892,7 @@ static void mrvl_nand_write_buf(struct mtd_info *mtd, static void mrvl_nand_config_flash(struct mrvl_nand_host *host) { struct nand_chip *chip = &host->chip; - struct mtd_info *mtd = &host->chip.mtd; + struct mtd_info *mtd = nand_to_mtd(chip); uint32_t ndcr = host->reg_ndcr; /* calculate flash information */ @@ -911,6 +926,9 @@ static void mrvl_nand_config_flash(struct mrvl_nand_host *host) static int pxa_ecc_strength1(struct mrvl_nand_host *host, struct nand_ecc_ctrl *ecc, int ecc_stepsize, int page_size) { + struct nand_chip *chip = &host->chip; + struct mtd_info *mtd = nand_to_mtd(chip); + if (ecc_stepsize == 512 && page_size == 2048) { host->chunk_size = 2048; host->spare_size = 40; @@ -919,7 +937,7 @@ static int pxa_ecc_strength1(struct mrvl_nand_host *host, ecc->mode = NAND_ECC_HW; ecc->size = 512; ecc->strength = 1; - ecc->layout = &ecc_layout_2KB_hwecc; + mtd_set_ecclayout(mtd, &ecc_layout_2KB_hwecc); return 0; } @@ -930,7 +948,7 @@ static int pxa_ecc_strength1(struct mrvl_nand_host *host, host->ecc_bch = 0; ecc->mode = NAND_ECC_HW; ecc->size = 512; - ecc->layout = &ecc_layout_512B_hwecc; + mtd_set_ecclayout(mtd, &ecc_layout_512B_hwecc); ecc->strength = 1; return 0; } @@ -941,6 +959,9 @@ static int pxa_ecc_strength1(struct mrvl_nand_host *host, static int pxa_ecc_strength4(struct mrvl_nand_host *host, struct nand_ecc_ctrl *ecc, int ecc_stepsize, int page_size) { + struct nand_chip *chip = &host->chip; + struct mtd_info *mtd = nand_to_mtd(chip); + if (!(host->hwflags & HWFLAGS_ECC_BCH)) return -ENODEV; @@ -955,7 +976,7 @@ static int pxa_ecc_strength4(struct mrvl_nand_host *host, host->ecc_bch = 1; ecc->mode = NAND_ECC_HW; ecc->size = 2048; - ecc->layout = &ecc_layout_2KB_bch4bit; + mtd_set_ecclayout(mtd, &ecc_layout_2KB_bch4bit); ecc->strength = 16; return 0; } @@ -967,7 +988,7 @@ static int pxa_ecc_strength4(struct mrvl_nand_host *host, host->ecc_bch = 1; ecc->mode = NAND_ECC_HW; ecc->size = 2048; - ecc->layout = &ecc_layout_4KB_bch4bit; + mtd_set_ecclayout(mtd, &ecc_layout_4KB_bch4bit); ecc->strength = 16; return 0; } @@ -978,6 +999,9 @@ static int pxa_ecc_strength4(struct mrvl_nand_host *host, static int pxa_ecc_strength8(struct mrvl_nand_host *host, struct nand_ecc_ctrl *ecc, int ecc_stepsize, int page_size) { + struct nand_chip *chip = &host->chip; + struct mtd_info *mtd = nand_to_mtd(chip); + if (!(host->hwflags & HWFLAGS_ECC_BCH)) return -ENODEV; @@ -992,7 +1016,7 @@ static int pxa_ecc_strength8(struct mrvl_nand_host *host, host->ecc_bch = 1; ecc->mode = NAND_ECC_HW; ecc->size = 1024; - ecc->layout = &ecc_layout_4KB_bch8bit; + mtd_set_ecclayout(mtd, &ecc_layout_4KB_bch8bit); ecc->strength = 16; return 0; } @@ -1033,9 +1057,9 @@ static int pxa_ecc_init(struct mrvl_nand_host *host, return 0; } -static int mrvl_nand_scan(struct mtd_info *mtd) +static int mrvl_nand_scan(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct mrvl_nand_host *host = chip->priv; int ret; unsigned int ndcr; @@ -1053,9 +1077,9 @@ static int mrvl_nand_scan(struct mtd_info *mtd) nand_readl(host, NDECCCTRL) & ~NDECCCTRL_BCH_EN); mrvl_nand_set_timing(host, true); - if (nand_scan_ident(mtd, 1, NULL)) { + if (nand_scan_ident(chip, 1, NULL)) { host->reg_ndcr |= NDCR_DWIDTH_M | NDCR_DWIDTH_C; - if (nand_scan_ident(mtd, 1, NULL)) + if (nand_scan_ident(chip, 1, NULL)) return -ENODEV; } mrvl_nand_config_flash(host); @@ -1099,7 +1123,7 @@ static int mrvl_nand_scan(struct mtd_info *mtd) host->buf_size = mtd->writesize + mtd->oobsize; host->data_buff = xmalloc(host->buf_size); - return nand_scan_tail(mtd); + return nand_scan_tail(chip); } static struct mrvl_nand_host *alloc_nand_resource(struct device_d *dev) @@ -1114,24 +1138,24 @@ static struct mrvl_nand_host *alloc_nand_resource(struct device_d *dev) host = xzalloc(sizeof(*host)); host->num_cs = 1; host->cs = 0; - mtd = &host->chip.mtd; - mtd->parent = dev; + mtd = nand_to_mtd(&host->chip); + mtd->dev.parent = dev; mtd->name = "mrvl_nand"; chip = &host->chip; - chip->read_byte = mrvl_nand_read_byte; - chip->read_word = mrvl_nand_read_word; + chip->legacy.read_byte = mrvl_nand_read_byte; + chip->legacy.read_word = mrvl_nand_read_word; chip->ecc.read_page = mrvl_nand_read_page_hwecc; chip->ecc.write_page = mrvl_nand_write_page_hwecc; - chip->dev_ready = mrvl_nand_ready; - chip->select_chip = mrvl_nand_select_chip; - chip->block_bad = mrvl_nand_block_bad; - chip->read_buf = mrvl_nand_read_buf; - chip->write_buf = mrvl_nand_write_buf; + chip->legacy.dev_ready = mrvl_nand_ready; + chip->legacy.select_chip = mrvl_nand_select_chip; + chip->legacy.block_bad = mrvl_nand_block_bad; + chip->legacy.read_buf = mrvl_nand_read_buf; + chip->legacy.write_buf = mrvl_nand_write_buf; chip->options |= NAND_NO_SUBPAGE_WRITE; - chip->cmdfunc = mrvl_nand_cmdfunc; + chip->legacy.cmdfunc = mrvl_nand_cmdfunc; chip->priv = host; - chip->chip_delay = CHIP_DELAY_TIMEOUT_US; + chip->legacy.chip_delay = CHIP_DELAY_TIMEOUT_US; host->dev = dev; iores = dev_request_mem_resource(dev, 0); @@ -1201,6 +1225,8 @@ static int mrvl_nand_probe_dt(struct mrvl_nand_host *host) static int mrvl_nand_probe(struct device_d *dev) { struct mrvl_nand_host *host; + struct nand_chip *chip; + struct mtd_info *mtd; int ret; host = alloc_nand_resource(dev); @@ -1213,15 +1239,17 @@ static int mrvl_nand_probe(struct device_d *dev) if (ret) return ret; - host->chip.controller = &host->chip.hwcontrol; - ret = mrvl_nand_scan(&host->chip.mtd); + chip = &host->chip; + mtd = nand_to_mtd(chip); + + ret = mrvl_nand_scan(chip); if (ret) { dev_warn(dev, "failed to scan nand at cs %d\n", host->cs); return -ENODEV; } - ret = add_mtd_nand_device(&host->chip.mtd, "nand"); + ret = add_mtd_nand_device(mtd, "nand"); return ret; } diff --git a/drivers/mtd/nand/nand_mxs.c b/drivers/mtd/nand/nand_mxs.c index e2b6e21620..9f7ab14426 100644 --- a/drivers/mtd/nand/nand_mxs.c +++ b/drivers/mtd/nand/nand_mxs.c @@ -20,6 +20,7 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> +#include <linux/mtd/rawnand.h> #include <linux/mtd/nand_mxs.h> #include <linux/types.h> #include <linux/clk.h> @@ -235,8 +236,6 @@ struct mxs_nand_info { int bb_mark_bit_offset; }; -static struct nand_ecclayout fake_ecc_layout; - static inline int mxs_nand_is_imx6(struct mxs_nand_info *info) { return info->type == GPMI_IMX6; @@ -330,16 +329,14 @@ static uint32_t mxs_nand_get_mark_offset(struct mtd_info *mtd) return block_mark_bit_offset; } -static int mxs_nand_calc_geo(struct mtd_info *mtd) +static int mxs_nand_calc_geo(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct mxs_nand_info *nand_info = chip->priv; int ecc_chunk_count = mxs_nand_ecc_chunk_cnt(mtd->writesize); int gf_len = 13; /* length of Galois Field for non-DDR nand */ int max_ecc_strength; - nand_of_parse_node(mtd, mtd->parent->device_node); - max_ecc_strength = ((mtd->oobsize - MXS_NAND_METADATA_SIZE) * 8) / (gf_len * ecc_chunk_count); /* We need the minor even number. */ @@ -420,9 +417,8 @@ static int mxs_nand_wait_for_bch_complete(struct mxs_nand_info *nand_info) * ignore the chip enable bit and concentrate only on sending bytes to the NAND * Flash. */ -static void mxs_nand_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) +static void mxs_nand_cmd_ctrl(struct nand_chip *chip, int data, unsigned int ctrl) { - struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = chip->priv; struct mxs_dma_desc *d; uint32_t channel = nand_info->dma_channel_base + nand_info->cur_chip; @@ -496,9 +492,8 @@ static void mxs_nand_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) /* * Test if the NAND flash is ready. */ -static int mxs_nand_device_ready(struct mtd_info *mtd) +static int mxs_nand_device_ready(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = chip->priv; void __iomem *gpmi_regs = nand_info->io_base; uint32_t tmp; @@ -522,9 +517,8 @@ static int mxs_nand_device_ready(struct mtd_info *mtd) /* * Select the NAND chip. */ -static void mxs_nand_select_chip(struct mtd_info *mtd, int chipnum) +static void mxs_nand_select_chip(struct nand_chip *chip, int chipnum) { - struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = chip->priv; nand_info->cur_chip = chipnum; @@ -537,10 +531,9 @@ static void mxs_nand_select_chip(struct mtd_info *mtd, int chipnum) * swapping the block mark, or swapping it *back* -- but it doesn't matter * because the the operation is the same. */ -static void mxs_nand_swap_block_mark(struct mtd_info *mtd, +static void mxs_nand_swap_block_mark(struct nand_chip *chip, uint8_t *data_buf, uint8_t *oob_buf) { - struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = chip->priv; uint32_t bit_offset; @@ -579,9 +572,8 @@ static void mxs_nand_swap_block_mark(struct mtd_info *mtd, /* * Read data from NAND. */ -static void mxs_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int length) +static void mxs_nand_read_buf(struct nand_chip *chip, uint8_t *buf, int length) { - struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = chip->priv; struct mxs_dma_desc *d; uint32_t channel = nand_info->dma_channel_base + nand_info->cur_chip; @@ -656,10 +648,9 @@ rtn: /* * Write data to NAND. */ -static void mxs_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, +static void mxs_nand_write_buf(struct nand_chip *chip, const uint8_t *buf, int length) { - struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = chip->priv; struct mxs_dma_desc *d; uint32_t channel = nand_info->dma_channel_base + nand_info->cur_chip; @@ -707,16 +698,15 @@ static void mxs_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, /* * Read a single byte from NAND. */ -static uint8_t mxs_nand_read_byte(struct mtd_info *mtd) +static uint8_t mxs_nand_read_byte(struct nand_chip *chip) { uint8_t buf; - mxs_nand_read_buf(mtd, &buf, 1); + mxs_nand_read_buf(chip, &buf, 1); return buf; } -static void mxs_nand_config_bch(struct mtd_info *mtd, int readlen) +static void mxs_nand_config_bch(struct nand_chip *chip, int readlen) { - struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = chip->priv; int chunk_size; void __iomem *bch_regs = nand_info->bch_base; @@ -744,10 +734,11 @@ static void mxs_nand_config_bch(struct mtd_info *mtd, int readlen) /* * Read a page from NAND. */ -static int __mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, +static int __mxs_nand_ecc_read_page(struct nand_chip *chip, uint8_t *buf, int oob_required, int page, int readlen) { + struct mtd_info *mtd = nand_to_mtd(chip); struct mxs_nand_info *nand_info = chip->priv; struct mxs_dma_desc *d; uint32_t channel = nand_info->dma_channel_base + nand_info->cur_chip; @@ -756,13 +747,15 @@ static int __mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip unsigned int max_bitflips = 0; int i, ret, readtotal, nchunks; + nand_read_page_op(chip, page, 0, NULL, 0); + readlen = roundup(readlen, MXS_NAND_CHUNK_DATA_CHUNK_SIZE); nchunks = mxs_nand_ecc_chunk_cnt(readlen); readtotal = MXS_NAND_METADATA_SIZE; readtotal += MXS_NAND_CHUNK_DATA_CHUNK_SIZE * nchunks; readtotal += DIV_ROUND_UP(13 * chip->ecc.strength * nchunks, 8); - mxs_nand_config_bch(mtd, readtotal); + mxs_nand_config_bch(chip, readtotal); /* Compile the DMA descriptor - wait for ready. */ d = mxs_nand_get_dma_desc(nand_info); @@ -850,7 +843,7 @@ static int __mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip } /* Read DMA completed, now do the mark swapping. */ - mxs_nand_swap_block_mark(mtd, nand_info->data_buf, nand_info->oob_buf); + mxs_nand_swap_block_mark(chip, nand_info->data_buf, nand_info->oob_buf); memcpy(buf, nand_info->data_buf, readlen); @@ -931,19 +924,21 @@ static int __mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip rtn: mxs_nand_return_dma_descs(nand_info); - mxs_nand_config_bch(mtd, mtd->writesize + mtd->oobsize); + mxs_nand_config_bch(chip, mtd->writesize + mtd->oobsize); return ret ? ret : max_bitflips; } -static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, +static int mxs_nand_ecc_read_page(struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { - return __mxs_nand_ecc_read_page(mtd, chip, buf, oob_required, page, + struct mtd_info *mtd = nand_to_mtd(chip); + + return __mxs_nand_ecc_read_page(chip, buf, oob_required, page, mtd->writesize); } -static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, +static int gpmi_ecc_read_subpage(struct nand_chip *chip, uint32_t offs, uint32_t len, uint8_t *buf, int page) { /* @@ -956,26 +951,28 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, offs = 0; } - return __mxs_nand_ecc_read_page(mtd, chip, buf, 0, page, len); + return __mxs_nand_ecc_read_page(chip, buf, 0, page, len); } /* * Write a page to NAND. */ -static int mxs_nand_ecc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, - int oob_required) +static int mxs_nand_ecc_write_page(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct mxs_nand_info *nand_info = chip->priv; struct mxs_dma_desc *d; uint32_t channel = nand_info->dma_channel_base + nand_info->cur_chip; int ret = 0; + nand_prog_page_begin_op(chip, page, 0, NULL, 0); + memcpy(nand_info->data_buf, buf, mtd->writesize); memcpy(nand_info->oob_buf, chip->oob_poi, mtd->oobsize); /* Handle block mark swapping. */ - mxs_nand_swap_block_mark(mtd, nand_info->data_buf, nand_info->oob_buf); + mxs_nand_swap_block_mark(chip, nand_info->data_buf, nand_info->oob_buf); /* Compile the DMA descriptor - write data. */ d = mxs_nand_get_dma_desc(nand_info); @@ -1018,7 +1015,10 @@ static int mxs_nand_ecc_write_page(struct mtd_info *mtd, rtn: mxs_nand_return_dma_descs(nand_info); - return ret; + if (ret) + return ret; + + return nand_prog_page_end_op(chip); } /* @@ -1136,9 +1136,9 @@ static int mxs_nand_hook_block_markbad(struct mtd_info *mtd, loff_t ofs) * raw_oob_mode field so that, when control finally arrives here, we'll know * what to do. */ -static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int mxs_nand_ecc_read_oob(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct mxs_nand_info *nand_info = chip->priv; int column; @@ -1152,8 +1152,8 @@ static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, * If control arrives here, we're doing a "raw" read. Send the * command to read the conventional OOB and read it. */ - chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->legacy.cmdfunc(chip, NAND_CMD_READ0, mtd->writesize, page); + chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); } else { /* * If control arrives here, we're not doing a "raw" read. Fill @@ -1162,8 +1162,8 @@ static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, memset(chip->oob_poi, 0xff, mtd->oobsize); column = nand_info->version == GPMI_VERSION_TYPE_MX23 ? 0 : mtd->writesize; - chip->cmdfunc(mtd, NAND_CMD_READ0, column, page); - mxs_nand_read_buf(mtd, chip->oob_poi, 1); + chip->legacy.cmdfunc(chip, NAND_CMD_READ0, column, page); + mxs_nand_read_buf(chip, chip->oob_poi, 1); } return 0; @@ -1173,9 +1173,9 @@ static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, /* * Write OOB data to NAND. */ -static int mxs_nand_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int mxs_nand_ecc_write_oob(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct mxs_nand_info *nand_info = chip->priv; int column; uint8_t block_mark = 0; @@ -1196,12 +1196,12 @@ static int mxs_nand_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, column = nand_info->version == GPMI_VERSION_TYPE_MX23 ? 0 : mtd->writesize; /* Write the block mark. */ - chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page); - chip->write_buf(mtd, &block_mark, 1); - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + chip->legacy.cmdfunc(chip, NAND_CMD_SEQIN, column, page); + chip->legacy.write_buf(chip, &block_mark, 1); + chip->legacy.cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1); /* Check if it worked. */ - if (chip->waitfunc(mtd, chip) & NAND_STATUS_FAIL) + if (chip->legacy.waitfunc(chip) & NAND_STATUS_FAIL) return -EIO; return 0; @@ -1220,7 +1220,7 @@ static int mxs_nand_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, * Thus, this function is only called when we want *all* blocks to look good, * so it *always* return success. */ -static int mxs_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) +static int mxs_nand_block_bad(struct nand_chip *chip , loff_t ofs) { return 0; } @@ -1239,9 +1239,9 @@ static int mxs_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) * call to nand_scan(). Anything other than zero will cause this driver to * tear everything down and declare failure. */ -static int mxs_nand_scan_bbt(struct mtd_info *mtd) +static int mxs_nand_scan_bbt(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct mxs_nand_info *nand_info = chip->priv; void __iomem *bch_regs = nand_info->bch_base; int ret; @@ -1252,7 +1252,7 @@ static int mxs_nand_scan_bbt(struct mtd_info *mtd) if (ret) return ret; - mxs_nand_config_bch(mtd, mtd->writesize + mtd->oobsize); + mxs_nand_config_bch(chip, mtd->writesize + mtd->oobsize); /* Set *all* chip selects to use layout 0 */ writel(0, bch_regs + BCH_LAYOUTSELECT); @@ -1261,23 +1261,23 @@ static int mxs_nand_scan_bbt(struct mtd_info *mtd) writel(BCH_CTRL_COMPLETE_IRQ_EN, bch_regs + BCH_CTRL + STMP_OFFSET_REG_SET); /* Hook some operations at the MTD level. */ - if (mtd->read_oob != mxs_nand_hook_read_oob) { - nand_info->hooked_read_oob = mtd->read_oob; - mtd->read_oob = mxs_nand_hook_read_oob; + if (mtd->_read_oob != mxs_nand_hook_read_oob) { + nand_info->hooked_read_oob = mtd->_read_oob; + mtd->_read_oob = mxs_nand_hook_read_oob; } - if (mtd->write_oob != mxs_nand_hook_write_oob) { - nand_info->hooked_write_oob = mtd->write_oob; - mtd->write_oob = mxs_nand_hook_write_oob; + if (mtd->_write_oob != mxs_nand_hook_write_oob) { + nand_info->hooked_write_oob = mtd->_write_oob; + mtd->_write_oob = mxs_nand_hook_write_oob; } - if (mtd->block_markbad != mxs_nand_hook_block_markbad) { - nand_info->hooked_block_markbad = mtd->block_markbad; - mtd->block_markbad = mxs_nand_hook_block_markbad; + if (mtd->_block_markbad != mxs_nand_hook_block_markbad) { + nand_info->hooked_block_markbad = mtd->_block_markbad; + mtd->_block_markbad = mxs_nand_hook_block_markbad; } /* We use the reference implementation for bad block management. */ - return nand_default_bbt(mtd); + return nand_create_bbt(chip); } /* @@ -1478,11 +1478,11 @@ static int mxs_nand_compute_hardware_timing(struct mxs_nand_info *info, * If there are multiple chips, we need to relax the timings to allow * for signal distortion due to higher capacitance. */ - if (chip->numchips > 2) { + if (nanddev_ntargets(&chip->base) > 2) { target.data_setup_in_ns += 10; target.data_hold_in_ns += 10; target.address_setup_in_ns += 10; - } else if (chip->numchips > 1) { + } else if (nanddev_ntargets(&chip->base) > 1) { target.data_setup_in_ns += 5; target.data_hold_in_ns += 5; target.address_setup_in_ns += 5; @@ -2029,14 +2029,13 @@ static void mxs_nand_compute_edo_timing(struct mxs_nand_info *info, static int mxs_nand_enable_edo_mode(struct mxs_nand_info *info) { struct nand_chip *chip = &info->nand_chip; - struct mtd_info *mtd = &chip->mtd; uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {}; int ret, mode; if (!mxs_nand_is_imx6(info)) return -ENODEV; - if (!chip->onfi_version) + if (!chip->parameters.onfi) return -ENOENT; mode = onfi_get_async_timing_mode(chip); @@ -2049,27 +2048,26 @@ static int mxs_nand_enable_edo_mode(struct mxs_nand_info *info) else return -EINVAL; - chip->select_chip(mtd, 0); + chip->legacy.select_chip(chip, 0); - if (le16_to_cpu(chip->onfi_params.opt_cmd) - & ONFI_OPT_CMD_SET_GET_FEATURES) { + if (nand_supports_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) { /* [1] send SET FEATURE commond to NAND */ feature[0] = mode; - ret = chip->onfi_set_features(mtd, chip, + ret = chip->legacy.set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE, feature); if (ret) goto err_out; /* [2] send GET FEATURE command to double-check the timing mode */ - ret = chip->onfi_get_features(mtd, chip, + ret = chip->legacy.get_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE, feature); if (ret || feature[0] != mode) goto err_out; } - chip->select_chip(mtd, -1); + chip->legacy.select_chip(chip, -1); /* [3] set the main IO clock, 100MHz for mode 5, 80MHz for mode 4. */ clk_disable(info->clk); @@ -2081,7 +2079,7 @@ static int mxs_nand_enable_edo_mode(struct mxs_nand_info *info) return mode; err_out: - chip->select_chip(mtd, -1); + chip->legacy.select_chip(chip, -1); return -EINVAL; } @@ -2193,37 +2191,35 @@ static int mxs_nand_probe(struct device_d *dev) /* structures must be linked */ chip = &nand_info->nand_chip; - mtd = &nand_info->nand_chip.mtd; - mtd->parent = dev; + mtd = nand_to_mtd(chip); + mtd->dev.parent = dev; chip->priv = nand_info; - chip->cmd_ctrl = mxs_nand_cmd_ctrl; + chip->legacy.cmd_ctrl = mxs_nand_cmd_ctrl; - chip->dev_ready = mxs_nand_device_ready; - chip->select_chip = mxs_nand_select_chip; - chip->block_bad = mxs_nand_block_bad; - chip->scan_bbt = mxs_nand_scan_bbt; + chip->legacy.dev_ready = mxs_nand_device_ready; + chip->legacy.select_chip = mxs_nand_select_chip; + chip->legacy.block_bad = mxs_nand_block_bad; - chip->read_byte = mxs_nand_read_byte; + chip->legacy.read_byte = mxs_nand_read_byte; - chip->read_buf = mxs_nand_read_buf; - chip->write_buf = mxs_nand_write_buf; + chip->legacy.read_buf = mxs_nand_read_buf; + chip->legacy.write_buf = mxs_nand_write_buf; chip->ecc.read_page = mxs_nand_ecc_read_page; chip->ecc.write_page = mxs_nand_ecc_write_page; chip->ecc.read_oob = mxs_nand_ecc_read_oob; chip->ecc.write_oob = mxs_nand_ecc_write_oob; - chip->ecc.layout = &fake_ecc_layout; chip->ecc.mode = NAND_ECC_HW; /* first scan to find the device and get the page size */ - err = nand_scan_ident(mtd, 4, NULL); + err = nand_scan_ident(chip, 4, NULL); if (err) goto err2; - err = mxs_nand_calc_geo(mtd); + err = mxs_nand_calc_geo(chip); if (err) goto err2; @@ -2232,15 +2228,17 @@ static int mxs_nand_probe(struct device_d *dev) chip->options |= NAND_SUBPAGE_READ; } - chip->options |= NAND_NO_SUBPAGE_WRITE; + chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_SKIP_BBTSCAN; mxs_nand_setup_timing(nand_info); /* second phase scan */ - err = nand_scan_tail(mtd); + err = nand_scan_tail(chip); if (err) goto err2; + mxs_nand_scan_bbt(chip); + err = add_mtd_nand_device(mtd, "nand"); if (err) goto err2; diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c index 83fa93b617..e3d36a1cf4 100644 --- a/drivers/mtd/nand/nand_omap_gpmc.c +++ b/drivers/mtd/nand/nand_omap_gpmc.c @@ -66,6 +66,7 @@ #include <clock.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> +#include <linux/mtd/rawnand.h> #include <linux/mtd/nand_ecc.h> #include <io.h> #include <mach/gpmc.h> @@ -102,11 +103,11 @@ static const char *ecc_mode_strings[] = { "hamming_hw_romcode", "bch8_hw", "bch8_hw_romcode", + "bch16_hw", }; /** internal structure maintained for nand information */ struct gpmc_nand_info { - struct nand_hw_control controller; struct device_d *pdev; struct gpmc_nand_platform_data *pdata; struct nand_chip nand; @@ -141,9 +142,8 @@ static struct nand_bbt_descr bb_descrip_flashbased = { * * @return */ -static int omap_dev_ready(struct mtd_info *mtd) +static int omap_dev_ready(struct nand_chip *nand) { - struct nand_chip *nand = mtd_to_nand(mtd); struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); if (readl(oinfo->gpmc_base + GPMC_STATUS) & oinfo->wait_mon_mask) @@ -187,30 +187,29 @@ static void gpmc_nand_wp(struct gpmc_nand_info *oinfo, int mode) * * @return none */ -static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) +static void omap_hwcontrol(struct nand_chip *nand, int cmd, unsigned int ctrl) { - struct nand_chip *nand = mtd_to_nand(mtd); struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); switch (ctrl) { case NAND_CTRL_CHANGE | NAND_CTRL_CLE: - nand->IO_ADDR_W = oinfo->gpmc_command; - nand->IO_ADDR_R = oinfo->gpmc_data; + nand->legacy.IO_ADDR_W = oinfo->gpmc_command; + nand->legacy.IO_ADDR_R = oinfo->gpmc_data; break; case NAND_CTRL_CHANGE | NAND_CTRL_ALE: - nand->IO_ADDR_W = oinfo->gpmc_address; - nand->IO_ADDR_R = oinfo->gpmc_data; + nand->legacy.IO_ADDR_W = oinfo->gpmc_address; + nand->legacy.IO_ADDR_R = oinfo->gpmc_data; break; case NAND_CTRL_CHANGE | NAND_NCE: - nand->IO_ADDR_W = oinfo->gpmc_data; - nand->IO_ADDR_R = oinfo->gpmc_data; + nand->legacy.IO_ADDR_W = oinfo->gpmc_data; + nand->legacy.IO_ADDR_R = oinfo->gpmc_data; break; } if (cmd != NAND_CMD_NONE) - writeb(cmd, nand->IO_ADDR_W); + writeb(cmd, nand->legacy.IO_ADDR_W); return; } @@ -231,10 +230,9 @@ static unsigned int gen_true_ecc(u8 *ecc_buf) ((ecc_buf[2] & 0x0F) << 8); } -static int __omap_calculate_ecc(struct mtd_info *mtd, uint8_t *ecc_code, +static int __omap_calculate_ecc(struct nand_chip *nand, uint8_t *ecc_code, int sblock) { - struct nand_chip *nand = mtd_to_nand(mtd); struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); unsigned int reg, reg1, val; unsigned int val1 = 0x0, val2 = 0x0; @@ -324,16 +322,15 @@ static int __omap_calculate_ecc(struct mtd_info *mtd, uint8_t *ecc_code, return 0; } -static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, +static int omap_calculate_ecc(struct nand_chip *nand, const uint8_t *dat, uint8_t *ecc_code) { - return __omap_calculate_ecc(mtd, ecc_code, 0); + return __omap_calculate_ecc(nand, ecc_code, 0); } -static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat, +static int omap_correct_bch(struct nand_chip *nand, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc) { - struct nand_chip *nand = mtd_to_nand(mtd); struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); int j, actual_eccsize; const uint8_t *erased_ecc_vec; @@ -404,13 +401,12 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat, return bitflip_count; } -static int omap_correct_hamming(struct mtd_info *mtd, uint8_t *dat, +static int omap_correct_hamming(struct nand_chip *nand, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc) { unsigned int orig_ecc, new_ecc, res, hm; unsigned short parity_bits, byte; unsigned char bit; - struct nand_chip *nand = mtd_to_nand(mtd); struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && @@ -461,23 +457,21 @@ static int omap_correct_hamming(struct mtd_info *mtd, uint8_t *dat, * * @return 0 if data is OK or corrected, else returns -1 */ -static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat, +static int omap_correct_data(struct nand_chip *nand, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc) { - struct nand_chip *nand = mtd_to_nand(mtd); struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); if (oinfo->ecc_mode != OMAP_ECC_HAMMING_CODE_HW_ROMCODE) return -EINVAL; - return omap_correct_hamming(mtd, dat, read_ecc, calc_ecc); + return omap_correct_hamming(nand, dat, read_ecc, calc_ecc); return 0; } -static void omap_enable_hwecc(struct mtd_info *mtd, int mode) +static void omap_enable_hwecc(struct nand_chip *nand, int mode) { - struct nand_chip *nand = mtd_to_nand(mtd); struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); unsigned int bch_mod = 0, bch_wrapmode = 0, eccsize1 = 0, eccsize0 = 0; unsigned int ecc_conf_val = 0, ecc_size_conf_val = 0; @@ -556,7 +550,7 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode) oinfo->gpmc_base + GPMC_ECC_CONTROL); } -static int omap_gpmc_read_buf_manual(struct mtd_info *mtd, struct nand_chip *chip, +static int omap_gpmc_read_buf_manual(struct nand_chip *chip, void *buf, int bytes, int result_reg) { struct gpmc_nand_info *oinfo = chip->priv; @@ -568,7 +562,7 @@ static int omap_gpmc_read_buf_manual(struct mtd_info *mtd, struct nand_chip *chi writel(GPMC_ECC_CONTROL_ECCPOINTER(result_reg), oinfo->gpmc_base + GPMC_ECC_CONTROL); - chip->read_buf(mtd, buf, bytes); + chip->legacy.read_buf(chip, buf, bytes); return bytes; } @@ -579,9 +573,8 @@ static int omap_gpmc_read_buf_manual(struct mtd_info *mtd, struct nand_chip *chi * @buf: buffer to store date * @len: number of bytes to read */ -static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len) +static void omap_read_buf_pref(struct nand_chip *nand_chip, u_char *buf, int len) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); struct gpmc_nand_info *info = nand_chip->priv; u32 r_count = 0; u32 *p = (u32 *)buf; @@ -619,10 +612,9 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len) * @buf: data buffer * @len: number of bytes to write */ -static void omap_write_buf_pref(struct mtd_info *mtd, +static void omap_write_buf_pref(struct nand_chip *nand_chip, const u_char *buf, int len) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); struct gpmc_nand_info *info = nand_chip->priv; u32 w_count = 0; @@ -632,7 +624,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd, /* take care of subpage writes */ while (len % 4 != 0) { - writeb(*buf, info->nand.IO_ADDR_W); + writeb(*buf, info->nand.legacy.IO_ADDR_W); buf1++; p32 = (u32 *)buf1; len--; @@ -642,7 +634,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd, gpmc_prefetch_enable(info->gpmc_cs, PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1); - while (len >= 0) { + while (len) { w_count = readl(info->gpmc_base + GPMC_PREFETCH_STATUS); w_count = GPMC_PREFETCH_STATUS_FIFO_CNT(w_count); w_count = w_count >> 2; @@ -684,21 +676,22 @@ static void omap_write_buf_pref(struct mtd_info *mtd, * generation), so we use the otherwise unused ECC_RESULTx_5 to * generate dummy eccs for the unprotected oob area. */ -static int omap_gpmc_read_page_bch_rom_mode(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) +static int omap_gpmc_read_page_bch_rom_mode(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct gpmc_nand_info *oinfo = chip->priv; int dev_width = chip->options & NAND_BUSWIDTH_16 ? GPMC_ECC_CONFIG_ECC16B : 0; uint8_t *p = buf; - uint8_t *ecc_calc = chip->buffers->ecccalc; - uint8_t *ecc_code = chip->buffers->ecccode; - uint32_t *eccpos = chip->ecc.layout->eccpos; + uint8_t *ecc_calc = chip->ecc.calc_buf; + uint8_t *ecc_code = chip->ecc.code_buf; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; int eccsize = chip->ecc.size; unsigned int max_bitflips = 0; - int stat, i, j; + int stat, i, j, ret; + nand_read_page_op(chip, page, 0, NULL, 0); writel(GPMC_ECC_SIZE_CONFIG_ECCSIZE1(0) | GPMC_ECC_SIZE_CONFIG_ECCSIZE0(64), @@ -720,27 +713,29 @@ static int omap_gpmc_read_page_bch_rom_mode(struct mtd_info *mtd, oinfo->gpmc_base + GPMC_ECC_CONTROL); for (i = 0; i < 32; i++) - p += omap_gpmc_read_buf_manual(mtd, chip, p, 64, (i >> 3) + 1); + p += omap_gpmc_read_buf_manual(chip, p, 64, (i >> 3) + 1); p = chip->oob_poi; - p += omap_gpmc_read_buf_manual(mtd, chip, p, 2, 5); + p += omap_gpmc_read_buf_manual(chip, p, 2, 5); for (i = 0; i < 4; i++) { - p += omap_gpmc_read_buf_manual(mtd, chip, p, 13, i + 1); - p += omap_gpmc_read_buf_manual(mtd, chip, p, 1, 5); + p += omap_gpmc_read_buf_manual(chip, p, 13, i + 1); + p += omap_gpmc_read_buf_manual(chip, p, 1, 5); } - p += omap_gpmc_read_buf_manual(mtd, chip, p, 6, 5); + p += omap_gpmc_read_buf_manual(chip, p, 6, 5); - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; + ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, + chip->ecc.total); + if (ret) + return ret; p = buf; for (i = 0, j = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize, j++) { - __omap_calculate_ecc(mtd, &ecc_calc[i - j], j + 1); - stat = omap_correct_bch(mtd, p, &ecc_code[i], &ecc_calc[i - j]); + __omap_calculate_ecc(chip, &ecc_calc[i - j], j + 1); + stat = omap_correct_bch(chip, p, &ecc_code[i], &ecc_calc[i - j]); if (stat < 0) { mtd->ecc_stats.failed++; } else { @@ -954,51 +949,59 @@ static int omap_elm_correct_data(struct nand_chip *chip, u_char *data, return (err) ? err : stat; } -static int gpmc_read_page_hwecc_elm(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, +static int gpmc_read_page_hwecc_elm(struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { - int i; + struct mtd_info *mtd = nand_to_mtd(chip); + int i, ret; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; - uint8_t *ecc_calc = chip->buffers->ecccalc; - uint8_t *ecc_code = chip->buffers->ecccode; - uint32_t *eccpos = chip->ecc.layout->eccpos; + uint8_t *ecc_calc = chip->ecc.calc_buf; + uint8_t *ecc_code = chip->ecc.code_buf; - chip->ecc.hwctl(mtd, NAND_ECC_READ); - chip->read_buf(mtd, buf, mtd->writesize); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->ecc.hwctl(chip, NAND_ECC_READ); - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; + nand_read_page_op(chip, page, 0, NULL, 0); + + chip->legacy.read_buf(chip, buf, mtd->writesize); + chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); + + ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, + chip->ecc.total); + if (ret) + return ret; eccsteps = chip->ecc.steps; for (i = 0; eccsteps; eccsteps--, i++) - __omap_calculate_ecc(mtd, &ecc_calc[i * eccbytes], i); + __omap_calculate_ecc(chip, &ecc_calc[i * eccbytes], i); return omap_elm_correct_data(chip, buf, ecc_code, ecc_calc); } -static int gpmc_read_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, +static int gpmc_read_page_hwecc(struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { - int i, eccsize = chip->ecc.size; + struct mtd_info *mtd = nand_to_mtd(chip); + int i, ret, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; uint8_t *p = buf; - uint8_t *ecc_calc = chip->buffers->ecccalc; - uint8_t *ecc_code = chip->buffers->ecccode; - uint32_t *eccpos = chip->ecc.layout->eccpos; + uint8_t *ecc_calc = chip->ecc.calc_buf; + uint8_t *ecc_code = chip->ecc.code_buf; unsigned int max_bitflips = 0; - chip->ecc.hwctl(mtd, NAND_ECC_READ); - chip->read_buf(mtd, p, mtd->writesize); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->ecc.hwctl(chip, NAND_ECC_READ); + + nand_read_page_op(chip, page, 0, NULL, 0); - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; + chip->legacy.read_buf(chip, p, mtd->writesize); + chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); + + ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, + chip->ecc.total); + if (ret) + return ret; eccsteps = chip->ecc.steps; p = buf; @@ -1006,8 +1009,8 @@ static int gpmc_read_page_hwecc(struct mtd_info *mtd, for (i = 0 ; eccsteps; eccsteps--, i++, p += eccsize) { int stat; - __omap_calculate_ecc(mtd, &ecc_calc[i * eccbytes], i); - stat = omap_correct_bch(mtd, p, &ecc_code[i * eccbytes], &ecc_calc[i * eccbytes]); + __omap_calculate_ecc(chip, &ecc_calc[i * eccbytes], i); + stat = omap_correct_bch(chip, p, &ecc_code[i * eccbytes], &ecc_calc[i * eccbytes]); if (stat < 0) { mtd->ecc_stats.failed++; } else { @@ -1022,7 +1025,7 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo, enum gpmc_ecc_mode mode) { struct nand_chip *nand = &oinfo->nand; - struct mtd_info *minfo = &nand->mtd; + struct mtd_info *minfo = nand_to_mtd(nand); int offset, err; int i, j; @@ -1037,7 +1040,7 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo, offset = 1; if (mode != OMAP_ECC_SOFT) { - nand->ecc.layout = &omap_oobinfo; + mtd_set_ecclayout(minfo, &omap_oobinfo); nand->ecc.calculate = omap_calculate_ecc; nand->ecc.hwctl = omap_enable_hwecc; nand->ecc.correct = omap_correct_data; @@ -1125,7 +1128,7 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo, break; case OMAP_ECC_SOFT: - nand->ecc.layout = NULL; + minfo->ecclayout = NULL; nand->ecc.mode = NAND_ECC_SOFT; oinfo->nand.ecc.strength = 1; break; @@ -1136,7 +1139,7 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo, oinfo->ecc_mode = mode; /* second phase scan */ - if (nand_scan_tail(minfo)) + if (nand_scan_tail(nand)) return -ENXIO; nand->options |= NAND_SKIP_BBTSCAN; @@ -1199,8 +1202,8 @@ static int gpmc_nand_probe(struct device_d *pdev) nand = &oinfo->nand; nand->priv = (void *)oinfo; - minfo = &nand->mtd; - minfo->parent = pdev; + minfo = nand_to_mtd(nand); + minfo->dev.parent = pdev; if (pdata->cs >= GPMC_NUM_CS) { dev_dbg(pdev, "Invalid CS!\n"); @@ -1238,7 +1241,7 @@ static int gpmc_nand_probe(struct device_d *pdev) } /* Same data register for in and out */ - nand->IO_ADDR_W = nand->IO_ADDR_R = (void *)oinfo->gpmc_data; + nand->legacy.IO_ADDR_W = nand->legacy.IO_ADDR_R = (void *)oinfo->gpmc_data; /* * If RDY/BSY line is connected to OMAP then use the omap ready * function and the generic nand_wait function which reads the @@ -1257,26 +1260,20 @@ static int gpmc_nand_probe(struct device_d *pdev) /* Set up the wait monitoring mask * This is GPMC_STATUS reg relevant */ oinfo->wait_mon_mask = (0x1 << (pdata->wait_mon_pin - 1)) << 8; - nand->dev_ready = omap_dev_ready; - nand->chip_delay = 0; + nand->legacy.dev_ready = omap_dev_ready; + nand->legacy.chip_delay = 0; } else { /* use the default nand_wait function */ - nand->chip_delay = 50; + nand->legacy.chip_delay = 50; } /* Use default cmdfunc */ /* nand cmd control */ - nand->cmd_ctrl = omap_hwcontrol; + nand->legacy.cmd_ctrl = omap_hwcontrol; /* Dont do a bbt scan at the start */ nand->options |= NAND_SKIP_BBTSCAN; - nand->options |= NAND_OWN_BUFFERS; - nand->buffers = xzalloc(sizeof(*nand->buffers)); - - /* State my controller */ - nand->controller = &oinfo->controller; - /* All information is ready.. now lets call setup, if present */ if (pdata->nand_setup) { err = pdata->nand_setup(pdata); @@ -1296,16 +1293,16 @@ static int gpmc_nand_probe(struct device_d *pdev) mdelay(1); /* first scan to find the device and get the page size */ - if (nand_scan_ident(minfo, 1, NULL)) { + if (nand_scan_ident(nand, 1, NULL)) { err = -ENXIO; goto out_release_mem; } gpmc_set_buswidth(nand, nand->options & NAND_BUSWIDTH_16); - nand->read_buf = omap_read_buf_pref; + nand->legacy.read_buf = omap_read_buf_pref; if (IS_ENABLED(CONFIG_MTD_WRITE)) - nand->write_buf = omap_write_buf_pref; + nand->legacy.write_buf = omap_write_buf_pref; nand->options |= NAND_SKIP_BBTSCAN; diff --git a/drivers/mtd/nand/nand_onfi.c b/drivers/mtd/nand/nand_onfi.c new file mode 100644 index 0000000000..5f4c5c3437 --- /dev/null +++ b/drivers/mtd/nand/nand_onfi.c @@ -0,0 +1,326 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) + * 2002-2006 Thomas Gleixner (tglx@linutronix.de) + * + * Credits: + * David Woodhouse for adding multichip support + * + * Aleph One Ltd. and Toby Churchill Ltd. for supporting the + * rework for 2K page size chips + * + * This file contains all ONFI helpers. + */ + +#include <common.h> +#include <linux/bitmap.h> + +#include "internals.h" + +#define ONFI_PARAM_PAGES 3 + +u16 onfi_crc16(u16 crc, u8 const *p, size_t len) +{ + int i; + while (len--) { + crc ^= *p++ << 8; + for (i = 0; i < 8; i++) + crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0); + } + + return crc; +} + +/* Parse the Extended Parameter Page. */ +static int nand_flash_detect_ext_param_page(struct nand_chip *chip, + struct nand_onfi_params *p) +{ + struct onfi_ext_param_page *ep; + struct onfi_ext_section *s; + struct onfi_ext_ecc_info *ecc; + uint8_t *cursor; + int ret; + int len; + int i; + + len = le16_to_cpu(p->ext_param_page_length) * 16; + ep = kmalloc(len, GFP_KERNEL); + if (!ep) + return -ENOMEM; + + /* + * Use the Change Read Column command to skip the ONFI param pages and + * ensure we read at the right location. + */ + ret = nand_change_read_column_op(chip, + sizeof(*p) * p->num_of_param_pages, + ep, len, true); + if (ret) + goto ext_out; + + ret = -EINVAL; + if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2) + != le16_to_cpu(ep->crc))) { + pr_debug("fail in the CRC.\n"); + goto ext_out; + } + + /* + * Check the signature. + * Do not strictly follow the ONFI spec, maybe changed in future. + */ + if (strncmp(ep->sig, "EPPS", 4)) { + pr_debug("The signature is invalid.\n"); + goto ext_out; + } + + /* find the ECC section. */ + cursor = (uint8_t *)(ep + 1); + for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) { + s = ep->sections + i; + if (s->type == ONFI_SECTION_TYPE_2) + break; + cursor += s->length * 16; + } + if (i == ONFI_EXT_SECTION_MAX) { + pr_debug("We can not find the ECC section.\n"); + goto ext_out; + } + + /* get the info we want. */ + ecc = (struct onfi_ext_ecc_info *)cursor; + + if (!ecc->codeword_size) { + pr_debug("Invalid codeword size\n"); + goto ext_out; + } + + chip->base.eccreq.strength = ecc->ecc_bits; + chip->base.eccreq.step_size = 1 << ecc->codeword_size; + ret = 0; + +ext_out: + kfree(ep); + return ret; +} + +/* + * Recover data with bit-wise majority + */ +static void nand_bit_wise_majority(const void **srcbufs, + unsigned int nsrcbufs, + void *dstbuf, + unsigned int bufsize) +{ + int i, j, k; + + for (i = 0; i < bufsize; i++) { + u8 val = 0; + + for (j = 0; j < 8; j++) { + unsigned int cnt = 0; + + for (k = 0; k < nsrcbufs; k++) { + const u8 *srcbuf = srcbufs[k]; + + if (srcbuf[i] & BIT(j)) + cnt++; + } + + if (cnt > nsrcbufs / 2) + val |= BIT(j); + } + + ((u8 *)dstbuf)[i] = val; + } +} + +/* + * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. + */ +int nand_onfi_detect(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; + struct nand_onfi_params *p = NULL, *pbuf; + struct onfi_params *onfi; + bool use_datain = false; + int onfi_version = 0; + char id[4]; + int i, ret, val; + u16 crc; + + memorg = nanddev_get_memorg(&chip->base); + + /* Try ONFI for unknown chip or LP */ + ret = nand_readid_op(chip, 0x20, id, sizeof(id)); + if (ret || strncmp(id, "ONFI", 4)) + return 0; + + /* ONFI chip: allocate a buffer to hold its parameter page */ + pbuf = kzalloc((sizeof(*pbuf) * ONFI_PARAM_PAGES), GFP_KERNEL); + if (!pbuf) + return -ENOMEM; + + if (!nand_has_exec_op(chip) || + !nand_read_data_op(chip, &pbuf[0], sizeof(*pbuf), true, true)) + use_datain = true; + + for (i = 0; i < ONFI_PARAM_PAGES; i++) { + if (!i) + ret = nand_read_param_page_op(chip, 0, &pbuf[i], + sizeof(*pbuf)); + else if (use_datain) + ret = nand_read_data_op(chip, &pbuf[i], sizeof(*pbuf), + true, false); + else + ret = nand_change_read_column_op(chip, sizeof(*pbuf) * i, + &pbuf[i], sizeof(*pbuf), + true); + if (ret) { + ret = 0; + goto free_onfi_param_page; + } + + crc = onfi_crc16(ONFI_CRC_BASE, (u8 *)&pbuf[i], 254); + if (crc == le16_to_cpu(pbuf[i].crc)) { + p = &pbuf[i]; + break; + } + } + + if (i == ONFI_PARAM_PAGES) { + const void *srcbufs[ONFI_PARAM_PAGES]; + unsigned int j; + + for (j = 0; j < ONFI_PARAM_PAGES; j++) + srcbufs[j] = pbuf + j; + + pr_warn("Could not find a valid ONFI parameter page, trying bit-wise majority to recover it\n"); + nand_bit_wise_majority(srcbufs, ONFI_PARAM_PAGES, pbuf, + sizeof(*pbuf)); + + crc = onfi_crc16(ONFI_CRC_BASE, (u8 *)pbuf, 254); + if (crc != le16_to_cpu(pbuf->crc)) { + pr_err("ONFI parameter recovery failed, aborting\n"); + goto free_onfi_param_page; + } + p = pbuf; + } + + if (chip->manufacturer.desc && chip->manufacturer.desc->ops && + chip->manufacturer.desc->ops->fixup_onfi_param_page) + chip->manufacturer.desc->ops->fixup_onfi_param_page(chip, p); + + /* Check version */ + val = le16_to_cpu(p->revision); + if (val & ONFI_VERSION_2_3) + onfi_version = 23; + else if (val & ONFI_VERSION_2_2) + onfi_version = 22; + else if (val & ONFI_VERSION_2_1) + onfi_version = 21; + else if (val & ONFI_VERSION_2_0) + onfi_version = 20; + else if (val & ONFI_VERSION_1_0) + onfi_version = 10; + + if (!onfi_version) { + pr_info("unsupported ONFI version: %d\n", val); + goto free_onfi_param_page; + } + + sanitize_string(p->manufacturer, sizeof(p->manufacturer)); + sanitize_string(p->model, sizeof(p->model)); + chip->parameters.model = strdup(p->model); + if (!chip->parameters.model) { + ret = -ENOMEM; + goto free_onfi_param_page; + } + + memorg->pagesize = le32_to_cpu(p->byte_per_page); + mtd->writesize = memorg->pagesize; + + /* + * pages_per_block and blocks_per_lun may not be a power-of-2 size + * (don't ask me who thought of this...). MTD assumes that these + * dimensions will be power-of-2, so just truncate the remaining area. + */ + memorg->pages_per_eraseblock = + 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1); + mtd->erasesize = memorg->pages_per_eraseblock * memorg->pagesize; + + memorg->oobsize = le16_to_cpu(p->spare_bytes_per_page); + mtd->oobsize = memorg->oobsize; + + memorg->luns_per_target = p->lun_count; + memorg->planes_per_lun = 1 << p->interleaved_bits; + + /* See erasesize comment */ + memorg->eraseblocks_per_lun = + 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1); + memorg->max_bad_eraseblocks_per_lun = le32_to_cpu(p->blocks_per_lun); + memorg->bits_per_cell = p->bits_per_cell; + + if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS) + chip->options |= NAND_BUSWIDTH_16; + + if (p->ecc_bits != 0xff) { + chip->base.eccreq.strength = p->ecc_bits; + chip->base.eccreq.step_size = 512; + } else if (onfi_version >= 21 && + (le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) { + + /* + * The nand_flash_detect_ext_param_page() uses the + * Change Read Column command which maybe not supported + * by the chip->legacy.cmdfunc. So try to update the + * chip->legacy.cmdfunc now. We do not replace user supplied + * command function. + */ + nand_legacy_adjust_cmdfunc(chip); + + /* The Extended Parameter Page is supported since ONFI 2.1. */ + if (nand_flash_detect_ext_param_page(chip, p)) + pr_warn("Failed to detect ONFI extended param page\n"); + } else { + pr_warn("Could not retrieve ONFI ECC requirements\n"); + } + + /* Save some parameters from the parameter page for future use */ + if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES) { + chip->parameters.supports_set_get_features = true; + bitmap_set(chip->parameters.get_feature_list, + ONFI_FEATURE_ADDR_TIMING_MODE, 1); + bitmap_set(chip->parameters.set_feature_list, + ONFI_FEATURE_ADDR_TIMING_MODE, 1); + } + + onfi = kzalloc(sizeof(*onfi), GFP_KERNEL); + if (!onfi) { + ret = -ENOMEM; + goto free_model; + } + + onfi->version = onfi_version; + onfi->tPROG = le16_to_cpu(p->t_prog); + onfi->tBERS = le16_to_cpu(p->t_bers); + onfi->tR = le16_to_cpu(p->t_r); + onfi->tCCS = le16_to_cpu(p->t_ccs); + onfi->async_timing_mode = le16_to_cpu(p->async_timing_mode); + onfi->vendor_revision = le16_to_cpu(p->vendor_revision); + memcpy(onfi->vendor, p->vendor, sizeof(p->vendor)); + chip->parameters.onfi = onfi; + + /* Identification done, free the full ONFI parameter page and exit */ + kfree(pbuf); + + return 1; + +free_model: + kfree(chip->parameters.model); +free_onfi_param_page: + kfree(pbuf); + + return ret; +} diff --git a/drivers/mtd/nand/nand_orion.c b/drivers/mtd/nand/nand_orion.c index c8b89cd03c..3899a67b56 100644 --- a/drivers/mtd/nand/nand_orion.c +++ b/drivers/mtd/nand/nand_orion.c @@ -18,6 +18,7 @@ #include <errno.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> +#include <linux/mtd/rawnand.h> #include <linux/clk.h> struct orion_nand { @@ -27,9 +28,8 @@ struct orion_nand { u8 cle; /* address line number connected to CLE */ }; -static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +static void orion_nand_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl) { - struct nand_chip *chip = mtd_to_nand(mtd); struct orion_nand *priv = chip->priv; u32 offs; @@ -46,13 +46,12 @@ static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl if (chip->options & NAND_BUSWIDTH_16) offs <<= 1; - writeb(cmd, chip->IO_ADDR_W + offs); + writeb(cmd, chip->legacy.IO_ADDR_W + offs); } -static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static void orion_nand_read_buf(struct nand_chip *chip, uint8_t *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); - void __iomem *io_base = chip->IO_ADDR_R; + void __iomem *io_base = chip->legacy.IO_ADDR_R; uint64_t *buf64; int i = 0; @@ -90,8 +89,8 @@ static int orion_nand_probe(struct device_d *dev) u32 val = 0; priv = xzalloc(sizeof(struct orion_nand)); - mtd = &priv->chip.mtd; chip = &priv->chip; + mtd = nand_to_mtd(chip); iores = dev_request_mem_resource(dev, 0); if (IS_ERR(iores)) @@ -114,13 +113,13 @@ static int orion_nand_probe(struct device_d *dev) width = 8; if (!of_property_read_u32(dev_node, "chip-delay", &val)) - chip->chip_delay = (u8)val; + chip->legacy.chip_delay = (u8)val; - mtd->parent = dev; + mtd->dev.parent = dev; chip->priv = priv; - chip->IO_ADDR_R = chip->IO_ADDR_W = io_base; - chip->cmd_ctrl = orion_nand_cmd_ctrl; - chip->read_buf = orion_nand_read_buf; + chip->legacy.IO_ADDR_R = chip->legacy.IO_ADDR_W = io_base; + chip->legacy.cmd_ctrl = orion_nand_cmd_ctrl; + chip->legacy.read_buf = orion_nand_read_buf; chip->ecc.mode = NAND_ECC_SOFT; WARN(width > 16, "%d bit bus width out of range", width); @@ -132,7 +131,7 @@ static int orion_nand_probe(struct device_d *dev) if (!IS_ERR(clk)) clk_enable(clk); - if (nand_scan(mtd, 1)) { + if (nand_scan(chip, 1)) { ret = -ENXIO; goto no_dev; } diff --git a/drivers/mtd/nand/nand_s3c24xx.c b/drivers/mtd/nand/nand_s3c24xx.c index 9fbc0f90d3..59bd6c9fed 100644 --- a/drivers/mtd/nand/nand_s3c24xx.c +++ b/drivers/mtd/nand/nand_s3c24xx.c @@ -26,6 +26,7 @@ #include <malloc.h> #include <init.h> #include <linux/mtd/mtd.h> +#include <linux/mtd/rawnand.h> #include <linux/mtd/nand.h> #include <mach/s3c-generic.h> #include <mach/s3c-iomap.h> @@ -200,10 +201,9 @@ static void __nand_boot_init disable_nand_controller(void __iomem *host) * * This is a special block read variant for the S3C2440 CPU. */ -static void s3c2440_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static void s3c2440_nand_read_buf(struct nand_chip *chip, uint8_t *buf, int len) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct s3c24x0_nand_host *host = nand_chip->priv; + struct s3c24x0_nand_host *host = chip->priv; readsl(host->base + NFDATA, buf, len >> 2); @@ -224,11 +224,10 @@ static void s3c2440_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) * * This is a special block write variant for the S3C2440 CPU. */ -static void s3c2440_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, +static void s3c2440_nand_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct s3c24x0_nand_host *host = nand_chip->priv; + struct s3c24x0_nand_host *host = chip->priv; writesl(host->base + NFDATA, buf, len >> 2); @@ -252,7 +251,7 @@ static void s3c2440_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, * * @note: This routine works always on a 24 bit ECC */ -static int s3c2410_nand_correct_data(struct mtd_info *mtd, uint8_t *dat, +static int s3c2410_nand_correct_data(struct nand_chip *chip, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc) { unsigned int diff0, diff1, diff2; @@ -313,10 +312,9 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, uint8_t *dat, return -1; } -static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode) +static void s3c2410_nand_enable_hwecc(struct nand_chip *chip, int mode) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct s3c24x0_nand_host *host = nand_chip->priv; + struct s3c24x0_nand_host *host = chip->priv; #ifdef CONFIG_CPU_S3C2410 writel(readl(host->base + NFCONF) | NFCONF_INITECC , host->base + NFCONF); @@ -326,10 +324,9 @@ static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode) #endif } -static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, uint8_t *ecc_code) +static int s3c2410_nand_calculate_ecc(struct nand_chip *chip, const uint8_t *dat, uint8_t *ecc_code) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct s3c24x0_nand_host *host = nand_chip->priv; + struct s3c24x0_nand_host *host = chip->priv; #ifdef CONFIG_CPU_S3C2410 ecc_code[0] = readb(host->base + NFECC); @@ -346,30 +343,27 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, return 0; } -static void s3c24x0_nand_select_chip(struct mtd_info *mtd, int chip) +static void s3c24x0_nand_select_chip(struct nand_chip *chip, int num) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct s3c24x0_nand_host *host = nand_chip->priv; + struct s3c24x0_nand_host *host = chip->priv; - if (chip == -1) + if (num == -1) disable_cs(host->base); else enable_cs(host->base); } -static int s3c24x0_nand_devready(struct mtd_info *mtd) +static int s3c24x0_nand_devready(struct nand_chip *chip) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct s3c24x0_nand_host *host = nand_chip->priv; + struct s3c24x0_nand_host *host = chip->priv; return readw(host->base + NFSTAT) & NFSTAT_BUSY; } -static void s3c24x0_nand_hwcontrol(struct mtd_info *mtd, int cmd, +static void s3c24x0_nand_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct s3c24x0_nand_host *host = nand_chip->priv; + struct s3c24x0_nand_host *host = chip->priv; if (cmd == NAND_CMD_NONE) return; @@ -427,24 +421,24 @@ static int s3c24x0_nand_probe(struct device_d *dev) /* structures must be linked */ chip = &host->nand; - mtd = &chip->mtd; - mtd->parent = dev; + mtd = nand_to_mtd(chip); + mtd->dev.parent = dev; /* init the default settings */ /* 50 us command delay time */ - chip->chip_delay = 50; + chip->legacy.chip_delay = 50; chip->priv = host; - chip->IO_ADDR_R = chip->IO_ADDR_W = host->base + NFDATA; + chip->legacy.IO_ADDR_R = chip->legacy.IO_ADDR_W = host->base + NFDATA; #ifdef CONFIG_CPU_S3C2440 - chip->read_buf = s3c2440_nand_read_buf; - chip->write_buf = s3c2440_nand_write_buf; + chip->legacy.read_buf = s3c2440_nand_read_buf; + chip->legacy.write_buf = s3c2440_nand_write_buf; #endif - chip->cmd_ctrl = s3c24x0_nand_hwcontrol; - chip->dev_ready = s3c24x0_nand_devready; - chip->select_chip = s3c24x0_nand_select_chip; + chip->legacy.cmd_ctrl = s3c24x0_nand_hwcontrol; + chip->legacy.dev_ready = s3c24x0_nand_devready; + chip->legacy.select_chip = s3c24x0_nand_select_chip; /* we are using the hardware ECC feature of this device */ chip->ecc.calculate = s3c2410_nand_calculate_ecc; @@ -469,7 +463,7 @@ static int s3c24x0_nand_probe(struct device_d *dev) { /* small page (512 bytes per page) */ chip->ecc.size = 512; - chip->ecc.layout = &nand_hw_eccoob; + mtd_set_ecclayout(mtd, &nand_hw_eccoob); } if (pdata->flash_bbt) { @@ -482,7 +476,7 @@ static int s3c24x0_nand_probe(struct device_d *dev) goto on_error; /* Scan to find existence of the device */ - ret = nand_scan(mtd, 1); + ret = nand_scan(chip, 1); if (ret != 0) { ret = -ENXIO; goto on_error; diff --git a/drivers/mtd/nand/nand_samsung.c b/drivers/mtd/nand/nand_samsung.c new file mode 100644 index 0000000000..3a4a19e808 --- /dev/null +++ b/drivers/mtd/nand/nand_samsung.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2017 Free Electrons + * Copyright (C) 2017 NextThing Co + * + * Author: Boris Brezillon <boris.brezillon@free-electrons.com> + */ + +#include "internals.h" + +static void samsung_nand_decode_id(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; + + memorg = nanddev_get_memorg(&chip->base); + + /* 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 */ + memorg->pagesize = 2048 << (extid & 0x03); + mtd->writesize = memorg->pagesize; + + extid >>= 2; + + /* Get oobsize */ + switch (((extid >> 2) & 0x4) | (extid & 0x3)) { + case 1: + memorg->oobsize = 128; + break; + case 2: + memorg->oobsize = 218; + break; + case 3: + memorg->oobsize = 400; + break; + case 4: + memorg->oobsize = 436; + break; + case 5: + memorg->oobsize = 512; + break; + case 6: + memorg->oobsize = 640; + break; + default: + /* + * We should never reach this case, but if that + * happens, this probably means Samsung decided to use + * a different extended ID format, and we should find + * a way to support it. + */ + WARN(1, "Invalid OOB size value"); + break; + } + + mtd->oobsize = memorg->oobsize; + + /* Get blocksize */ + extid >>= 2; + memorg->pages_per_eraseblock = (128 * 1024) << + (((extid >> 1) & 0x04) | + (extid & 0x03)) / + memorg->pagesize; + mtd->erasesize = (128 * 1024) << + (((extid >> 1) & 0x04) | (extid & 0x03)); + + /* Extract ECC requirements from 5th id byte*/ + extid = (chip->id.data[4] >> 4) & 0x07; + if (extid < 5) { + chip->base.eccreq.step_size = 512; + chip->base.eccreq.strength = 1 << extid; + } else { + chip->base.eccreq.step_size = 1024; + switch (extid) { + case 5: + chip->base.eccreq.strength = 24; + break; + case 6: + chip->base.eccreq.strength = 40; + break; + case 7: + chip->base.eccreq.strength = 60; + break; + default: + WARN(1, "Could not decode ECC info"); + chip->base.eccreq.step_size = 0; + } + } + } else { + nand_decode_ext_id(chip); + + if (nand_is_slc(chip)) { + switch (chip->id.data[1]) { + /* K9F4G08U0D-S[I|C]B0(T00) */ + case 0xDC: + chip->base.eccreq.step_size = 512; + chip->base.eccreq.strength = 1; + break; + + /* K9F1G08U0E 21nm chips do not support subpage write */ + case 0xF1: + if (chip->id.len > 4 && + (chip->id.data[4] & GENMASK(1, 0)) == 0x1) + chip->options |= NAND_NO_SUBPAGE_WRITE; + break; + default: + break; + } + } + } +} + +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->options |= NAND_BBM_LASTPAGE; + else + chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; + + return 0; +} + +const struct nand_manufacturer_ops samsung_nand_manuf_ops = { + .detect = samsung_nand_decode_id, + .init = samsung_nand_init, +}; diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c index 7a939510b7..1338133e81 100644 --- a/drivers/mtd/nand/nand_timings.c +++ b/drivers/mtd/nand/nand_timings.c @@ -1,242 +1,391 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Free Electrons * * 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 version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> #include <linux/err.h> -#include <linux/mtd/nand.h> +#include <linux/export.h> + +#include "internals.h" + +#define ONFI_DYN_TIMING_MAX U16_MAX -static const struct nand_sdr_timings onfi_sdr_timings[] = { +/* + * For non-ONFI chips we use the highest possible value for tPROG and tBERS. + * tR and tCCS will take the default values precised in the ONFI specification + * for timing mode 0, respectively 200us and 500ns. + * + * These four values are tweaked to be more accurate in the case of ONFI chips. + */ +static const struct nand_interface_config onfi_sdr_timings[] = { /* Mode 0 */ { - .tADL_min = 200000, - .tALH_min = 20000, - .tALS_min = 50000, - .tAR_min = 25000, - .tCEA_max = 100000, - .tCEH_min = 20000, - .tCH_min = 20000, - .tCHZ_max = 100000, - .tCLH_min = 20000, - .tCLR_min = 20000, - .tCLS_min = 50000, - .tCOH_min = 0, - .tCS_min = 70000, - .tDH_min = 20000, - .tDS_min = 40000, - .tFEAT_max = 1000000, - .tIR_min = 10000, - .tITC_max = 1000000, - .tRC_min = 100000, - .tREA_max = 40000, - .tREH_min = 30000, - .tRHOH_min = 0, - .tRHW_min = 200000, - .tRHZ_max = 200000, - .tRLOH_min = 0, - .tRP_min = 50000, - .tRST_max = 250000000000, - .tWB_max = 200000, - .tRR_min = 40000, - .tWC_min = 100000, - .tWH_min = 30000, - .tWHR_min = 120000, - .tWP_min = 50000, - .tWW_min = 100000, + .type = NAND_SDR_IFACE, + .timings.mode = 0, + .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, + .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, + .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, + .tADL_min = 400000, + .tALH_min = 20000, + .tALS_min = 50000, + .tAR_min = 25000, + .tCEA_max = 100000, + .tCEH_min = 20000, + .tCH_min = 20000, + .tCHZ_max = 100000, + .tCLH_min = 20000, + .tCLR_min = 20000, + .tCLS_min = 50000, + .tCOH_min = 0, + .tCS_min = 70000, + .tDH_min = 20000, + .tDS_min = 40000, + .tFEAT_max = 1000000, + .tIR_min = 10000, + .tITC_max = 1000000, + .tRC_min = 100000, + .tREA_max = 40000, + .tREH_min = 30000, + .tRHOH_min = 0, + .tRHW_min = 200000, + .tRHZ_max = 200000, + .tRLOH_min = 0, + .tRP_min = 50000, + .tRR_min = 40000, + .tRST_max = 250000000000ULL, + .tWB_max = 200000, + .tWC_min = 100000, + .tWH_min = 30000, + .tWHR_min = 120000, + .tWP_min = 50000, + .tWW_min = 100000, + }, }, /* Mode 1 */ { - .tADL_min = 100000, - .tALH_min = 10000, - .tALS_min = 25000, - .tAR_min = 10000, - .tCEA_max = 45000, - .tCEH_min = 20000, - .tCH_min = 10000, - .tCHZ_max = 50000, - .tCLH_min = 10000, - .tCLR_min = 10000, - .tCLS_min = 25000, - .tCOH_min = 15000, - .tCS_min = 35000, - .tDH_min = 10000, - .tDS_min = 20000, - .tFEAT_max = 1000000, - .tIR_min = 0, - .tITC_max = 1000000, - .tRC_min = 50000, - .tREA_max = 30000, - .tREH_min = 15000, - .tRHOH_min = 15000, - .tRHW_min = 100000, - .tRHZ_max = 100000, - .tRLOH_min = 0, - .tRP_min = 25000, - .tRR_min = 20000, - .tRST_max = 500000000, - .tWB_max = 100000, - .tWC_min = 45000, - .tWH_min = 15000, - .tWHR_min = 80000, - .tWP_min = 25000, - .tWW_min = 100000, + .type = NAND_SDR_IFACE, + .timings.mode = 1, + .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, + .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, + .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, + .tADL_min = 400000, + .tALH_min = 10000, + .tALS_min = 25000, + .tAR_min = 10000, + .tCEA_max = 45000, + .tCEH_min = 20000, + .tCH_min = 10000, + .tCHZ_max = 50000, + .tCLH_min = 10000, + .tCLR_min = 10000, + .tCLS_min = 25000, + .tCOH_min = 15000, + .tCS_min = 35000, + .tDH_min = 10000, + .tDS_min = 20000, + .tFEAT_max = 1000000, + .tIR_min = 0, + .tITC_max = 1000000, + .tRC_min = 50000, + .tREA_max = 30000, + .tREH_min = 15000, + .tRHOH_min = 15000, + .tRHW_min = 100000, + .tRHZ_max = 100000, + .tRLOH_min = 0, + .tRP_min = 25000, + .tRR_min = 20000, + .tRST_max = 500000000, + .tWB_max = 100000, + .tWC_min = 45000, + .tWH_min = 15000, + .tWHR_min = 80000, + .tWP_min = 25000, + .tWW_min = 100000, + }, }, /* Mode 2 */ { - .tADL_min = 100000, - .tALH_min = 10000, - .tALS_min = 15000, - .tAR_min = 10000, - .tCEA_max = 30000, - .tCEH_min = 20000, - .tCH_min = 10000, - .tCHZ_max = 50000, - .tCLH_min = 10000, - .tCLR_min = 10000, - .tCLS_min = 15000, - .tCOH_min = 15000, - .tCS_min = 25000, - .tDH_min = 5000, - .tDS_min = 15000, - .tFEAT_max = 1000000, - .tIR_min = 0, - .tITC_max = 1000000, - .tRC_min = 35000, - .tREA_max = 25000, - .tREH_min = 15000, - .tRHOH_min = 15000, - .tRHW_min = 100000, - .tRHZ_max = 100000, - .tRLOH_min = 0, - .tRR_min = 20000, - .tRST_max = 500000000, - .tWB_max = 100000, - .tRP_min = 17000, - .tWC_min = 35000, - .tWH_min = 15000, - .tWHR_min = 80000, - .tWP_min = 17000, - .tWW_min = 100000, + .type = NAND_SDR_IFACE, + .timings.mode = 2, + .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, + .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, + .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, + .tADL_min = 400000, + .tALH_min = 10000, + .tALS_min = 15000, + .tAR_min = 10000, + .tCEA_max = 30000, + .tCEH_min = 20000, + .tCH_min = 10000, + .tCHZ_max = 50000, + .tCLH_min = 10000, + .tCLR_min = 10000, + .tCLS_min = 15000, + .tCOH_min = 15000, + .tCS_min = 25000, + .tDH_min = 5000, + .tDS_min = 15000, + .tFEAT_max = 1000000, + .tIR_min = 0, + .tITC_max = 1000000, + .tRC_min = 35000, + .tREA_max = 25000, + .tREH_min = 15000, + .tRHOH_min = 15000, + .tRHW_min = 100000, + .tRHZ_max = 100000, + .tRLOH_min = 0, + .tRR_min = 20000, + .tRST_max = 500000000, + .tWB_max = 100000, + .tRP_min = 17000, + .tWC_min = 35000, + .tWH_min = 15000, + .tWHR_min = 80000, + .tWP_min = 17000, + .tWW_min = 100000, + }, }, /* Mode 3 */ { - .tADL_min = 100000, - .tALH_min = 5000, - .tALS_min = 10000, - .tAR_min = 10000, - .tCEA_max = 25000, - .tCEH_min = 20000, - .tCH_min = 5000, - .tCHZ_max = 50000, - .tCLH_min = 5000, - .tCLR_min = 10000, - .tCLS_min = 10000, - .tCOH_min = 15000, - .tCS_min = 25000, - .tDH_min = 5000, - .tDS_min = 10000, - .tFEAT_max = 1000000, - .tIR_min = 0, - .tITC_max = 1000000, - .tRC_min = 30000, - .tREA_max = 20000, - .tREH_min = 10000, - .tRHOH_min = 15000, - .tRHW_min = 100000, - .tRHZ_max = 100000, - .tRLOH_min = 0, - .tRP_min = 15000, - .tRR_min = 20000, - .tRST_max = 500000000, - .tWB_max = 100000, - .tWC_min = 30000, - .tWH_min = 10000, - .tWHR_min = 80000, - .tWP_min = 15000, - .tWW_min = 100000, + .type = NAND_SDR_IFACE, + .timings.mode = 3, + .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, + .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, + .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, + .tADL_min = 400000, + .tALH_min = 5000, + .tALS_min = 10000, + .tAR_min = 10000, + .tCEA_max = 25000, + .tCEH_min = 20000, + .tCH_min = 5000, + .tCHZ_max = 50000, + .tCLH_min = 5000, + .tCLR_min = 10000, + .tCLS_min = 10000, + .tCOH_min = 15000, + .tCS_min = 25000, + .tDH_min = 5000, + .tDS_min = 10000, + .tFEAT_max = 1000000, + .tIR_min = 0, + .tITC_max = 1000000, + .tRC_min = 30000, + .tREA_max = 20000, + .tREH_min = 10000, + .tRHOH_min = 15000, + .tRHW_min = 100000, + .tRHZ_max = 100000, + .tRLOH_min = 0, + .tRP_min = 15000, + .tRR_min = 20000, + .tRST_max = 500000000, + .tWB_max = 100000, + .tWC_min = 30000, + .tWH_min = 10000, + .tWHR_min = 80000, + .tWP_min = 15000, + .tWW_min = 100000, + }, }, /* Mode 4 */ { - .tADL_min = 70000, - .tALH_min = 5000, - .tALS_min = 10000, - .tAR_min = 10000, - .tCEA_max = 25000, - .tCEH_min = 20000, - .tCH_min = 5000, - .tCHZ_max = 30000, - .tCLH_min = 5000, - .tCLR_min = 10000, - .tCLS_min = 10000, - .tCOH_min = 15000, - .tCS_min = 20000, - .tDH_min = 5000, - .tDS_min = 10000, - .tFEAT_max = 1000000, - .tIR_min = 0, - .tITC_max = 1000000, - .tRC_min = 25000, - .tREA_max = 20000, - .tREH_min = 10000, - .tRHOH_min = 15000, - .tRHW_min = 100000, - .tRHZ_max = 100000, - .tRLOH_min = 5000, - .tRP_min = 12000, - .tRR_min = 20000, - .tRST_max = 500000000, - .tWB_max = 100000, - .tWC_min = 25000, - .tWH_min = 10000, - .tWHR_min = 80000, - .tWP_min = 12000, - .tWW_min = 100000, + .type = NAND_SDR_IFACE, + .timings.mode = 4, + .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, + .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, + .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, + .tADL_min = 400000, + .tALH_min = 5000, + .tALS_min = 10000, + .tAR_min = 10000, + .tCEA_max = 25000, + .tCEH_min = 20000, + .tCH_min = 5000, + .tCHZ_max = 30000, + .tCLH_min = 5000, + .tCLR_min = 10000, + .tCLS_min = 10000, + .tCOH_min = 15000, + .tCS_min = 20000, + .tDH_min = 5000, + .tDS_min = 10000, + .tFEAT_max = 1000000, + .tIR_min = 0, + .tITC_max = 1000000, + .tRC_min = 25000, + .tREA_max = 20000, + .tREH_min = 10000, + .tRHOH_min = 15000, + .tRHW_min = 100000, + .tRHZ_max = 100000, + .tRLOH_min = 5000, + .tRP_min = 12000, + .tRR_min = 20000, + .tRST_max = 500000000, + .tWB_max = 100000, + .tWC_min = 25000, + .tWH_min = 10000, + .tWHR_min = 80000, + .tWP_min = 12000, + .tWW_min = 100000, + }, }, /* Mode 5 */ { - .tADL_min = 70000, - .tALH_min = 5000, - .tALS_min = 10000, - .tAR_min = 10000, - .tCEA_max = 25000, - .tCEH_min = 20000, - .tCH_min = 5000, - .tCHZ_max = 30000, - .tCLH_min = 5000, - .tCLR_min = 10000, - .tCLS_min = 10000, - .tCOH_min = 15000, - .tCS_min = 15000, - .tDH_min = 5000, - .tDS_min = 7000, - .tFEAT_max = 1000000, - .tIR_min = 0, - .tITC_max = 1000000, - .tRC_min = 20000, - .tREA_max = 16000, - .tREH_min = 7000, - .tRHOH_min = 15000, - .tRHW_min = 100000, - .tRHZ_max = 100000, - .tRLOH_min = 5000, - .tRP_min = 10000, - .tRR_min = 20000, - .tRST_max = 500000000, - .tWB_max = 100000, - .tWC_min = 20000, - .tWH_min = 7000, - .tWHR_min = 80000, - .tWP_min = 10000, - .tWW_min = 100000, + .type = NAND_SDR_IFACE, + .timings.mode = 5, + .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, + .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, + .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, + .tADL_min = 400000, + .tALH_min = 5000, + .tALS_min = 10000, + .tAR_min = 10000, + .tCEA_max = 25000, + .tCEH_min = 20000, + .tCH_min = 5000, + .tCHZ_max = 30000, + .tCLH_min = 5000, + .tCLR_min = 10000, + .tCLS_min = 10000, + .tCOH_min = 15000, + .tCS_min = 15000, + .tDH_min = 5000, + .tDS_min = 7000, + .tFEAT_max = 1000000, + .tIR_min = 0, + .tITC_max = 1000000, + .tRC_min = 20000, + .tREA_max = 16000, + .tREH_min = 7000, + .tRHOH_min = 15000, + .tRHW_min = 100000, + .tRHZ_max = 100000, + .tRLOH_min = 5000, + .tRP_min = 10000, + .tRR_min = 20000, + .tRST_max = 500000000, + .tWB_max = 100000, + .tWC_min = 20000, + .tWH_min = 7000, + .tWHR_min = 80000, + .tWP_min = 10000, + .tWW_min = 100000, + }, }, }; +/* All NAND chips share the same reset data interface: SDR mode 0 */ +const struct nand_interface_config *nand_get_reset_interface_config(void) +{ + return &onfi_sdr_timings[0]; +} + +/** + * onfi_find_closest_sdr_mode - Derive the closest ONFI SDR timing mode given a + * set of timings + * @spec_timings: the timings to challenge + */ +unsigned int +onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings) +{ + const struct nand_sdr_timings *onfi_timings; + int mode; + + for (mode = ARRAY_SIZE(onfi_sdr_timings) - 1; mode > 0; mode--) { + onfi_timings = &onfi_sdr_timings[mode].timings.sdr; + + if (spec_timings->tCCS_min <= onfi_timings->tCCS_min && + spec_timings->tADL_min <= onfi_timings->tADL_min && + spec_timings->tALH_min <= onfi_timings->tALH_min && + spec_timings->tALS_min <= onfi_timings->tALS_min && + spec_timings->tAR_min <= onfi_timings->tAR_min && + spec_timings->tCEH_min <= onfi_timings->tCEH_min && + spec_timings->tCH_min <= onfi_timings->tCH_min && + spec_timings->tCLH_min <= onfi_timings->tCLH_min && + spec_timings->tCLR_min <= onfi_timings->tCLR_min && + spec_timings->tCLS_min <= onfi_timings->tCLS_min && + spec_timings->tCOH_min <= onfi_timings->tCOH_min && + spec_timings->tCS_min <= onfi_timings->tCS_min && + spec_timings->tDH_min <= onfi_timings->tDH_min && + spec_timings->tDS_min <= onfi_timings->tDS_min && + spec_timings->tIR_min <= onfi_timings->tIR_min && + spec_timings->tRC_min <= onfi_timings->tRC_min && + spec_timings->tREH_min <= onfi_timings->tREH_min && + spec_timings->tRHOH_min <= onfi_timings->tRHOH_min && + spec_timings->tRHW_min <= onfi_timings->tRHW_min && + spec_timings->tRLOH_min <= onfi_timings->tRLOH_min && + spec_timings->tRP_min <= onfi_timings->tRP_min && + spec_timings->tRR_min <= onfi_timings->tRR_min && + spec_timings->tWC_min <= onfi_timings->tWC_min && + spec_timings->tWH_min <= onfi_timings->tWH_min && + spec_timings->tWHR_min <= onfi_timings->tWHR_min && + spec_timings->tWP_min <= onfi_timings->tWP_min && + spec_timings->tWW_min <= onfi_timings->tWW_min) + return mode; + } + + return 0; +} + +/** + * onfi_fill_interface_config - Initialize an interface config from a given + * ONFI mode + * @chip: The NAND chip + * @iface: The interface configuration to fill + * @type: The interface type + * @timing_mode: The ONFI timing mode + */ +void onfi_fill_interface_config(struct nand_chip *chip, + struct nand_interface_config *iface, + enum nand_interface_type type, + unsigned int timing_mode) +{ + struct onfi_params *onfi = chip->parameters.onfi; + + if (WARN_ON(type != NAND_SDR_IFACE)) + return; + + if (WARN_ON(timing_mode >= ARRAY_SIZE(onfi_sdr_timings))) + return; + + *iface = onfi_sdr_timings[timing_mode]; + + /* + * Initialize timings that cannot be deduced from timing mode: + * tPROG, tBERS, tR and tCCS. + * These information are part of the ONFI parameter page. + */ + if (onfi) { + struct nand_sdr_timings *timings = &iface->timings.sdr; + + /* microseconds -> picoseconds */ + timings->tPROG_max = 1000000ULL * onfi->tPROG; + timings->tBERS_max = 1000000ULL * onfi->tBERS; + timings->tR_max = 1000000ULL * onfi->tR; + + /* nanoseconds -> picoseconds */ + timings->tCCS_min = 1000UL * onfi->tCCS; + } +} + /** * onfi_async_timing_mode_to_sdr_timings - [NAND Interface] Retrieve NAND * timings according to the given ONFI timing mode @@ -246,6 +395,5 @@ const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode) { if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings)) return ERR_PTR(-EINVAL); - - return &onfi_sdr_timings[mode]; + return &onfi_sdr_timings[mode].timings.sdr; } diff --git a/drivers/mtd/nand/nand_toshiba.c b/drivers/mtd/nand/nand_toshiba.c new file mode 100644 index 0000000000..21a5dbc7e0 --- /dev/null +++ b/drivers/mtd/nand/nand_toshiba.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2017 Free Electrons + * Copyright (C) 2017 NextThing Co + * + * Author: Boris Brezillon <boris.brezillon@free-electrons.com> + */ + +#include "internals.h" + +/* Bit for detecting BENAND */ +#define TOSHIBA_NAND_ID4_IS_BENAND BIT(7) + +/* Recommended to rewrite for BENAND */ +#define TOSHIBA_NAND_STATUS_REWRITE_RECOMMENDED BIT(3) + +/* ECC Status Read Command for BENAND */ +#define TOSHIBA_NAND_CMD_ECC_STATUS_READ 0x7A + +/* ECC Status Mask for BENAND */ +#define TOSHIBA_NAND_ECC_STATUS_MASK 0x0F + +/* Uncorrectable Error for BENAND */ +#define TOSHIBA_NAND_ECC_STATUS_UNCORR 0x0F + +/* Max ECC Steps for BENAND */ +#define TOSHIBA_NAND_MAX_ECC_STEPS 8 + +static int toshiba_nand_benand_read_eccstatus_op(struct nand_chip *chip, + u8 *buf) +{ + u8 *ecc_status = buf; + + if (nand_has_exec_op(chip)) { + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(nand_get_interface_config(chip)); + struct nand_op_instr instrs[] = { + NAND_OP_CMD(TOSHIBA_NAND_CMD_ECC_STATUS_READ, + PSEC_TO_NSEC(sdr->tADL_min)), + NAND_OP_8BIT_DATA_IN(chip->ecc.steps, ecc_status, 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + + return nand_exec_op(chip, &op); + } + + return -ENOTSUPP; +} + +static int toshiba_nand_benand_eccstatus(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + int ret; + unsigned int max_bitflips = 0; + u8 status, ecc_status[TOSHIBA_NAND_MAX_ECC_STEPS]; + + /* Check Status */ + ret = toshiba_nand_benand_read_eccstatus_op(chip, ecc_status); + if (!ret) { + unsigned int i, bitflips = 0; + + for (i = 0; i < chip->ecc.steps; i++) { + bitflips = ecc_status[i] & TOSHIBA_NAND_ECC_STATUS_MASK; + if (bitflips == TOSHIBA_NAND_ECC_STATUS_UNCORR) { + mtd->ecc_stats.failed++; + } else { + mtd->ecc_stats.corrected += bitflips; + max_bitflips = max(max_bitflips, bitflips); + } + } + + return max_bitflips; + } + + /* + * Fallback to regular status check if + * toshiba_nand_benand_read_eccstatus_op() failed. + */ + ret = nand_status_op(chip, &status); + if (ret) + return ret; + + if (status & NAND_STATUS_FAIL) { + /* uncorrected */ + mtd->ecc_stats.failed++; + } else if (status & TOSHIBA_NAND_STATUS_REWRITE_RECOMMENDED) { + /* corrected */ + max_bitflips = mtd->bitflip_threshold; + mtd->ecc_stats.corrected += max_bitflips; + } + + return max_bitflips; +} + +static int +toshiba_nand_read_page_benand(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) +{ + int ret; + + ret = nand_read_page_raw(chip, buf, oob_required, page); + if (ret) + return ret; + + return toshiba_nand_benand_eccstatus(chip); +} + +static int +toshiba_nand_read_subpage_benand(struct nand_chip *chip, uint32_t data_offs, + uint32_t readlen, uint8_t *bufpoi, int page) +{ + int ret; + + ret = nand_read_page_op(chip, page, data_offs, + bufpoi + data_offs, readlen); + if (ret) + return ret; + + return toshiba_nand_benand_eccstatus(chip); +} + +static void toshiba_nand_benand_init(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + /* + * On BENAND, the entire OOB region can be used by the MTD user. + * The calculated ECC bytes are stored into other isolated + * area which is not accessible to users. + * This is why chip->ecc.bytes = 0. + */ + chip->ecc.bytes = 0; + chip->ecc.size = 512; + chip->ecc.strength = 8; + chip->ecc.read_page = toshiba_nand_read_page_benand; + chip->ecc.read_subpage = toshiba_nand_read_subpage_benand; + chip->ecc.write_page = nand_write_page_raw; + chip->ecc.read_page_raw = nand_read_page_raw_notsupp; + chip->ecc.write_page_raw = nand_write_page_raw_notsupp; + + chip->options |= NAND_SUBPAGE_READ; + + mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); +} + +static void toshiba_nand_decode_id(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; + + memorg = nanddev_get_memorg(&chip->base); + + nand_decode_ext_id(chip); + + /* + * 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 (chip->id.len >= 6 && nand_is_slc(chip) && + (chip->id.data[5] & 0x7) == 0x6 /* 24nm */ && + !(chip->id.data[4] & TOSHIBA_NAND_ID4_IS_BENAND) /* !BENAND */) { + memorg->oobsize = 32 * memorg->pagesize >> 9; + mtd->oobsize = memorg->oobsize; + } + + /* + * Extract ECC requirements from 6th id byte. + * For Toshiba SLC, ecc requrements are as follows: + * - 43nm: 1 bit ECC for each 512Byte is required. + * - 32nm: 4 bit ECC for each 512Byte is required. + * - 24nm: 8 bit ECC for each 512Byte is required. + */ + if (chip->id.len >= 6 && nand_is_slc(chip)) { + chip->base.eccreq.step_size = 512; + switch (chip->id.data[5] & 0x7) { + case 0x4: + chip->base.eccreq.strength = 1; + break; + case 0x5: + chip->base.eccreq.strength = 4; + break; + case 0x6: + chip->base.eccreq.strength = 8; + break; + default: + WARN(1, "Could not get ECC info"); + chip->base.eccreq.step_size = 0; + break; + } + } +} + +static int +tc58nvg0s3e_choose_interface_config(struct nand_chip *chip, + struct nand_interface_config *iface) +{ + onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 2); + + return nand_choose_best_sdr_timings(chip, iface, NULL); +} + +static int +th58nvg2s3hbai4_choose_interface_config(struct nand_chip *chip, + struct nand_interface_config *iface) +{ + struct nand_sdr_timings *sdr = &iface->timings.sdr; + + /* Start with timings from the closest timing mode, mode 4. */ + onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 4); + + /* Patch timings that differ from mode 4. */ + sdr->tALS_min = 12000; + sdr->tCHZ_max = 20000; + sdr->tCLS_min = 12000; + sdr->tCOH_min = 0; + sdr->tDS_min = 12000; + sdr->tRHOH_min = 25000; + sdr->tRHW_min = 30000; + sdr->tRHZ_max = 60000; + sdr->tWHR_min = 60000; + + /* Patch timings not part of onfi timing mode. */ + sdr->tPROG_max = 700000000; + sdr->tBERS_max = 5000000000; + + return nand_choose_best_sdr_timings(chip, iface, sdr); +} + +static int tc58nvg0s3e_init(struct nand_chip *chip) +{ + chip->ops.choose_interface_config = + &tc58nvg0s3e_choose_interface_config; + + return 0; +} + +static int th58nvg2s3hbai4_init(struct nand_chip *chip) +{ + chip->ops.choose_interface_config = + &th58nvg2s3hbai4_choose_interface_config; + + return 0; +} + +static int toshiba_nand_init(struct nand_chip *chip) +{ + if (nand_is_slc(chip)) + chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; + + /* Check that chip is BENAND and ECC mode is on-die */ + if (nand_is_slc(chip) && chip->ecc.mode == NAND_ECC_ON_DIE && + chip->id.data[4] & TOSHIBA_NAND_ID4_IS_BENAND) + toshiba_nand_benand_init(chip); + + if (!strcmp("TC58TEG5DCLTA00", chip->parameters.model)) + return -EINVAL; /* MLC, not yet supported in barebox */ + if (!strncmp("TC58NVG0S3E", chip->parameters.model, + sizeof("TC58NVG0S3E") - 1)) + tc58nvg0s3e_init(chip); + if (!strncmp("TH58NVG2S3HBAI4", chip->parameters.model, + sizeof("TH58NVG2S3HBAI4") - 1)) + th58nvg2s3hbai4_init(chip); + + return 0; +} + +const struct nand_manufacturer_ops toshiba_nand_manuf_ops = { + .detect = toshiba_nand_decode_id, + .init = toshiba_nand_init, +}; diff --git a/drivers/mtd/nand/nomadik_nand.c b/drivers/mtd/nand/nomadik_nand.c index 31bc2efc40..b5ef39223e 100644 --- a/drivers/mtd/nand/nomadik_nand.c +++ b/drivers/mtd/nand/nomadik_nand.c @@ -30,6 +30,7 @@ #include <linux/types.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> +#include <linux/mtd/rawnand.h> #include <io.h> #include <mach/nand.h> @@ -58,7 +59,7 @@ static inline int parity(int b) /* uses low 8 bits: returns 0 or all-1 */ * I haven't managed to get the desired data out of it; so do it in sw. * There is problably some errata involved, but currently miss the info. */ -static int nomadik_ecc512_calc(struct mtd_info *mtd, const u_char *data, +static int nomadik_ecc512_calc(struct nand_chip *nand, const u_char *data, u_char *ecc) { int gpar = 0; @@ -101,10 +102,9 @@ static int nomadik_ecc512_calc(struct mtd_info *mtd, const u_char *data, return 0; } -static int nomadik_ecc512_correct(struct mtd_info *mtd, uint8_t *dat, +static int nomadik_ecc512_correct(struct nand_chip *chip, uint8_t *dat, uint8_t *r_ecc, uint8_t *c_ecc) { - struct nand_chip *chip = mtd_to_nand(mtd); uint32_t r, c, d, diff; /*read, calculated, xor of them */ if (!memcmp(r_ecc, c_ecc, chip->ecc.bytes)) @@ -149,14 +149,13 @@ static struct nand_ecclayout nomadik_ecc_layout = { .oobfree = { {0x08, 0x08}, {0x18, 0x08}, {0x28, 0x08}, {0x38, 0x08} }, }; -static void nomadik_ecc_control(struct mtd_info *mtd, int mode) +static void nomadik_ecc_control(struct nand_chip *nand, int mode) { /* No need to enable hw ecc, it's on by default */ } -static void nomadik_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +static void nomadik_cmd_ctrl(struct nand_chip *nand, int cmd, unsigned int ctrl) { - struct nand_chip *nand = mtd_to_nand(mtd); struct nomadik_nand_host *host = nand->priv; if (cmd == NAND_CMD_NONE) @@ -198,17 +197,18 @@ static int nomadik_nand_probe(struct device_d *dev) /* Link all private pointers */ nand = &host->nand; - mtd = &nand->mtd; + mtd = nand_to_mtd(nand); nand->priv = host; - mtd->parent = dev; + mtd->dev.parent = dev; - nand->IO_ADDR_W = nand->IO_ADDR_R = dev_request_mem_region_by_name(dev, "nand_data"); - if (IS_ERR(nand->IO_ADDR_W)) - return PTR_ERR(nand->IO_ADDR_W); - nand->cmd_ctrl = nomadik_cmd_ctrl; + nand->legacy.IO_ADDR_W = nand->legacy.IO_ADDR_R = + dev_request_mem_region_by_name(dev, "nand_data"); + if (IS_ERR(nand->legacy.IO_ADDR_W)) + return PTR_ERR(nand->legacy.IO_ADDR_W); + nand->legacy.cmd_ctrl = nomadik_cmd_ctrl; nand->ecc.mode = NAND_ECC_HW; - nand->ecc.layout = &nomadik_ecc_layout; + mtd_set_ecclayout(mtd, &nomadik_ecc_layout); nand->ecc.calculate = nomadik_ecc512_calc; nand->ecc.correct = nomadik_ecc512_correct; nand->ecc.hwctl = nomadik_ecc_control; @@ -221,7 +221,7 @@ static int nomadik_nand_probe(struct device_d *dev) /* * Scan to find existance of the device */ - if (nand_scan(mtd, 1)) { + if (nand_scan(nand, 1)) { ret = -ENXIO; goto err; } diff --git a/drivers/mtd/nor/cfi_flash.c b/drivers/mtd/nor/cfi_flash.c index 430f926e8c..225b03ec3d 100644 --- a/drivers/mtd/nor/cfi_flash.c +++ b/drivers/mtd/nor/cfi_flash.c @@ -920,13 +920,8 @@ static int cfi_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) int ret; ret = cfi_erase(info, instr->len, instr->addr); - if (ret) { - instr->state = MTD_ERASE_FAILED; + if (ret) return -EIO; - } - - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); return 0; } @@ -937,11 +932,11 @@ static void cfi_init_mtd(struct flash_info *info) u32 erasesize; int i; - mtd->read = cfi_mtd_read; - mtd->write = cfi_mtd_write; - mtd->erase = cfi_mtd_erase; - mtd->lock = cfi_mtd_lock; - mtd->unlock = cfi_mtd_unlock; + mtd->_read = cfi_mtd_read; + mtd->_write = cfi_mtd_write; + mtd->_erase = cfi_mtd_erase; + mtd->_lock = cfi_mtd_lock; + mtd->_unlock = cfi_mtd_unlock; mtd->size = info->size; erasesize = 0; @@ -959,7 +954,7 @@ static void cfi_init_mtd(struct flash_info *info) mtd->numeraseregions = info->numeraseregions; mtd->flags = MTD_CAP_NORFLASH; mtd->type = MTD_NORFLASH; - mtd->parent = info->dev; + mtd->dev.parent = info->dev; } static int cfi_probe_one(struct flash_info *info, int num) @@ -1035,7 +1030,7 @@ static int cfi_probe(struct device_d *dev) mtd = &priv->infos[0].mtd; } - mtd->parent = dev; + mtd->dev.parent = dev; ret = add_mtd_device(mtd, "nor", DEVICE_ID_DYNAMIC); if (ret) diff --git a/drivers/mtd/partition.c b/drivers/mtd/partition.c index 013697732d..a426c8bfcf 100644 --- a/drivers/mtd/partition.c +++ b/drivers/mtd/partition.c @@ -13,7 +13,7 @@ static int mtd_part_read(struct mtd_info *mtd, loff_t from, size_t len, len = 0; else if (from + len > mtd->size) len = mtd->size - from; - res = mtd->master->read(mtd->master, from + mtd->master_offset, + res = mtd->parent->_read(mtd->parent, from + mtd->master_offset, len, retlen, buf); return res; } @@ -28,7 +28,7 @@ static int mtd_part_read_oob(struct mtd_info *mtd, loff_t from, if (ops->datbuf && from + ops->len > mtd->size) return -EINVAL; - res = mtd->master->read_oob(mtd->master, from + mtd->master_offset, ops); + res = mtd->parent->_read_oob(mtd->parent, from + mtd->master_offset, ops); if (unlikely(res)) { if (mtd_is_bitflip(res)) mtd->ecc_stats.corrected++; @@ -47,7 +47,7 @@ static int mtd_part_write(struct mtd_info *mtd, loff_t to, size_t len, len = 0; else if (to + len > mtd->size) len = mtd->size - to; - return mtd->master->write(mtd->master, to + mtd->master_offset, + return mtd->parent->_write(mtd->parent, to + mtd->master_offset, len, retlen, buf); } @@ -58,7 +58,7 @@ static int mtd_part_write_oob(struct mtd_info *mtd, loff_t to, return -EINVAL; if (ops->datbuf && to + ops->len > mtd->size) return -EINVAL; - return mtd->master->write_oob(mtd->master, to + mtd->master_offset, ops); + return mtd->parent->_write_oob(mtd->parent, to + mtd->master_offset, ops); } static int mtd_part_erase(struct mtd_info *mtd, struct erase_info *instr) @@ -70,7 +70,7 @@ static int mtd_part_erase(struct mtd_info *mtd, struct erase_info *instr) if (instr->addr >= mtd->size) return -EINVAL; instr->addr += mtd->master_offset; - ret = mtd->master->erase(mtd->master, instr); + ret = mtd->parent->_erase(mtd->parent, instr); if (ret) { if (instr->fail_addr != 0xffffffff) instr->fail_addr -= mtd->master_offset; @@ -81,7 +81,7 @@ static int mtd_part_erase(struct mtd_info *mtd, struct erase_info *instr) static int mtd_part_lock(struct mtd_info *mtd, loff_t offset, size_t len) { - if (!mtd->master->lock) + if (!mtd->parent->_lock) return -ENOSYS; if (!(mtd->flags & MTD_WRITEABLE)) @@ -92,12 +92,12 @@ static int mtd_part_lock(struct mtd_info *mtd, loff_t offset, size_t len) offset += mtd->master_offset; - return mtd->master->lock(mtd->master, offset, len); + return mtd->parent->_lock(mtd->parent, offset, len); } static int mtd_part_unlock(struct mtd_info *mtd, loff_t offset, size_t len) { - if (!mtd->master->unlock) + if (!mtd->parent->_unlock) return -ENOSYS; if (!(mtd->flags & MTD_WRITEABLE)) @@ -108,7 +108,7 @@ static int mtd_part_unlock(struct mtd_info *mtd, loff_t offset, size_t len) offset += mtd->master_offset; - return mtd->master->unlock(mtd->master, offset, len); + return mtd->parent->_unlock(mtd->parent, offset, len); } static int mtd_part_block_isbad(struct mtd_info *mtd, loff_t ofs) @@ -116,7 +116,7 @@ static int mtd_part_block_isbad(struct mtd_info *mtd, loff_t ofs) if (ofs >= mtd->size) return -EINVAL; ofs += mtd->master_offset; - return mtd_block_isbad(mtd->master, ofs); + return mtd_block_isbad(mtd->parent, ofs); } static int mtd_part_block_markbad(struct mtd_info *mtd, loff_t ofs) @@ -128,7 +128,7 @@ static int mtd_part_block_markbad(struct mtd_info *mtd, loff_t ofs) if (ofs >= mtd->size) return -EINVAL; ofs += mtd->master_offset; - res = mtd->master->block_markbad(mtd->master, ofs); + res = mtd->parent->_block_markbad(mtd->parent, ofs); if (!res) mtd->ecc_stats.badblocks++; return res; @@ -143,7 +143,7 @@ static int mtd_part_block_markgood(struct mtd_info *mtd, loff_t ofs) if (ofs >= mtd->size) return -EINVAL; ofs += mtd->master_offset; - res = mtd->master->block_markgood(mtd->master, ofs); + res = mtd->parent->_block_markgood(mtd->parent, ofs); if (!res) mtd->ecc_stats.badblocks--; return res; @@ -159,13 +159,15 @@ struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset, part->type = mtd->type; part->flags = mtd->flags; - part->parent = &mtd->class_dev; + part->dev.parent = &mtd->dev; part->writesize = mtd->writesize; part->writebufsize = mtd->writebufsize; part->oobsize = mtd->oobsize; part->oobavail = mtd->oobavail; part->bitflip_threshold = mtd->bitflip_threshold; part->ecclayout = mtd->ecclayout; + part->ecc_step_size = mtd->ecc_step_size; + part->ooblayout = mtd->ooblayout; part->ecc_strength = mtd->ecc_strength; part->subpage_sft = mtd->subpage_sft; part->cdev.flags = flags; @@ -196,27 +198,27 @@ struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset, part->erasesize = mtd->erasesize; } - part->read = mtd_part_read; + part->_read = mtd_part_read; if (IS_ENABLED(CONFIG_MTD_WRITE)) { - part->write = mtd_part_write; - part->erase = mtd_part_erase; - part->lock = mtd_part_lock; - part->unlock = mtd_part_unlock; - part->block_markbad = mtd->block_markbad ? mtd_part_block_markbad : NULL; - part->block_markgood = mtd->block_markgood ? mtd_part_block_markgood : NULL; + part->_write = mtd_part_write; + part->_erase = mtd_part_erase; + part->_lock = mtd_part_lock; + part->_unlock = mtd_part_unlock; + part->_block_markbad = mtd->_block_markbad ? mtd_part_block_markbad : NULL; + part->_block_markgood = mtd->_block_markgood ? mtd_part_block_markgood : NULL; } - if (mtd->write_oob) - part->write_oob = mtd_part_write_oob; - if (mtd->read_oob) - part->read_oob = mtd_part_read_oob; + if (mtd->_write_oob) + part->_write_oob = mtd_part_write_oob; + if (mtd->_read_oob) + part->_read_oob = mtd_part_read_oob; - part->block_isbad = mtd->block_isbad ? mtd_part_block_isbad : NULL; + part->_block_isbad = mtd->_block_isbad ? mtd_part_block_isbad : NULL; part->size = size; part->name = xstrdup(name); part->master_offset = offset; - part->master = mtd; + part->parent = mtd; if (!strncmp(mtd->cdev.name, name, strlen(mtd->cdev.name))) part->cdev.partname = xstrdup(name + strlen(mtd->cdev.name) + 1); @@ -225,7 +227,7 @@ struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset, if (ret) goto err; - part->cdev.master = &part->master->cdev; + part->cdev.master = &part->parent->cdev; return part; err: @@ -238,7 +240,7 @@ err: int mtd_del_partition(struct mtd_info *part) { - if (!part->master) + if (!part->parent) return -EINVAL; del_mtd_device(part); diff --git a/drivers/mtd/peb.c b/drivers/mtd/peb.c index b47d04b4c0..f3c51a61b4 100644 --- a/drivers/mtd/peb.c +++ b/drivers/mtd/peb.c @@ -237,7 +237,7 @@ retry: * enabled. A corresponding message will be printed * later, when it is has been scrubbed. */ - dev_dbg(&mtd->class_dev, "fixable bit-flip detected at PEB %d\n", pnum); + dev_dbg(&mtd->dev, "fixable bit-flip detected at PEB %d\n", pnum); if (len != read) return -EIO; return -EUCLEAN; @@ -246,7 +246,7 @@ retry: if (mtd_is_eccerr(err) && retries++ < MTD_IO_RETRIES) goto retry; - dev_err(&mtd->class_dev, "error %d%s while reading %d bytes from PEB %d:%d\n", + dev_err(&mtd->dev, "error %d%s while reading %d bytes from PEB %d:%d\n", err, errstr, len, pnum, offset); return err; } @@ -284,7 +284,7 @@ int mtd_peb_check_all_ff(struct mtd_info *mtd, int pnum, int offset, int len, err = mtd_peb_read(mtd, buf, pnum, offset, len); if (err && !mtd_is_bitflip(err)) { - dev_err(&mtd->class_dev, + dev_err(&mtd->dev, "error %d while reading %d bytes from PEB %d:%d\n", err, len, pnum, offset); goto out; @@ -293,7 +293,7 @@ int mtd_peb_check_all_ff(struct mtd_info *mtd, int pnum, int offset, int len, err = mtd_buf_all_ff(buf, len); if (err == 0) { if (warn) - dev_err(&mtd->class_dev, "all-ff check failed for PEB %d\n", + dev_err(&mtd->dev, "all-ff check failed for PEB %d\n", pnum); err = -EBADMSG; goto out; @@ -343,15 +343,15 @@ int mtd_peb_verify(struct mtd_info *mtd, const void *buf, int pnum, if (c == c1) continue; - dev_err(&mtd->class_dev, "self-check failed for PEB %d:%d, len %d\n", + dev_err(&mtd->dev, "self-check failed for PEB %d:%d, len %d\n", pnum, offset, len); - dev_info(&mtd->class_dev, "data differs at position %d\n", i); + dev_info(&mtd->dev, "data differs at position %d\n", i); dump_len = max_t(int, 128, len - i); #ifdef DEBUG - dev_info(&mtd->class_dev, "hex dump of the original buffer from %d to %d\n", + dev_info(&mtd->dev, "hex dump of the original buffer from %d to %d\n", i, i + dump_len); memory_display(buf + i, i, dump_len, 4, 0); - dev_info(&mtd->class_dev, "hex dump of the read buffer from %d to %d\n", + dev_info(&mtd->dev, "hex dump of the read buffer from %d to %d\n", i, i + dump_len); memory_display(buf1 + i, i, dump_len, 4, 0); dump_stack(); @@ -391,7 +391,7 @@ int mtd_peb_write(struct mtd_info *mtd, const void *buf, int pnum, int offset, size_t written; loff_t addr; - dev_dbg(&mtd->class_dev, "write %d bytes to PEB %d:%d\n", len, pnum, offset); + dev_dbg(&mtd->dev, "write %d bytes to PEB %d:%d\n", len, pnum, offset); if (!mtd_peb_valid(mtd, pnum)) return -EINVAL; @@ -405,7 +405,7 @@ int mtd_peb_write(struct mtd_info *mtd, const void *buf, int pnum, int offset, return -EINVAL; if (mtd_peb_emulate_write_failure()) { - dev_err(&mtd->class_dev, "Cannot write %d bytes to PEB %d:%d (emulated)\n", + dev_err(&mtd->dev, "Cannot write %d bytes to PEB %d:%d (emulated)\n", len, pnum, offset); return -EIO; } @@ -420,7 +420,7 @@ int mtd_peb_write(struct mtd_info *mtd, const void *buf, int pnum, int offset, addr = (loff_t)pnum * mtd->erasesize + offset; err = mtd_write(mtd, addr, len, &written, buf); if (err) { - dev_err(&mtd->class_dev, "error %d while writing %d bytes to PEB %d:%d, written %zu bytes\n", + dev_err(&mtd->dev, "error %d while writing %d bytes to PEB %d:%d, written %zu bytes\n", err, len, pnum, offset, written); } else { if (written != len) @@ -533,12 +533,11 @@ int mtd_peb_erase(struct mtd_info *mtd, int pnum) int ret; struct erase_info ei = {}; - dev_dbg(&mtd->class_dev, "erase PEB %d\n", pnum); + dev_dbg(&mtd->dev, "erase PEB %d\n", pnum); if (!mtd_peb_valid(mtd, pnum)) return -EINVAL; - ei.mtd = mtd; ei.addr = (loff_t)pnum * mtd->erasesize; ei.len = mtd->erasesize; @@ -553,7 +552,7 @@ int mtd_peb_erase(struct mtd_info *mtd, int pnum) } if (mtd_peb_emulate_erase_failure()) { - dev_err(&mtd->class_dev, "cannot erase PEB %d (emulated)", pnum); + dev_err(&mtd->dev, "cannot erase PEB %d (emulated)", pnum); return -EIO; } @@ -588,7 +587,7 @@ int mtd_peb_torture(struct mtd_info *mtd, int pnum) if (!peb_buf) return -ENOMEM; - dev_dbg(&mtd->class_dev, "run torture test for PEB %d\n", pnum); + dev_dbg(&mtd->dev, "run torture test for PEB %d\n", pnum); patt_count = ARRAY_SIZE(patterns); @@ -618,7 +617,7 @@ int mtd_peb_torture(struct mtd_info *mtd, int pnum) goto out; err = patt_count + 1; - dev_dbg(&mtd->class_dev, "PEB %d passed torture test, do not mark it as bad\n", + dev_dbg(&mtd->dev, "PEB %d passed torture test, do not mark it as bad\n", pnum); out: @@ -628,7 +627,7 @@ out: * has not passed because it happened on a freshly erased * physical eraseblock which means something is wrong with it. */ - dev_err(&mtd->class_dev, "read problems on freshly erased PEB %d, must be bad\n", + dev_err(&mtd->dev, "read problems on freshly erased PEB %d, must be bad\n", pnum); err = -EIO; @@ -703,7 +702,7 @@ int mtd_peb_create_bitflips(struct mtd_info *mtd, int pnum, int offset, ret = mtd_read_oob(mtd, offs, &ops); if (ret) { - dev_err(&mtd->class_dev, "Cannot read raw data at 0x%08llx\n", offs); + dev_err(&mtd->dev, "Cannot read raw data at 0x%08llx\n", offs); goto err; } } @@ -729,12 +728,12 @@ int mtd_peb_create_bitflips(struct mtd_info *mtd, int pnum, int offset, pos[offs] ^= 1 << bit; if (info) - dev_info(&mtd->class_dev, "Flipping bit %d @ %d\n", bit, offs); + dev_info(&mtd->dev, "Flipping bit %d @ %d\n", bit, offs); } ret = mtd_peb_erase(mtd, pnum); if (ret < 0) { - dev_err(&mtd->class_dev, "Cannot erase PEB %d\n", pnum); + dev_err(&mtd->dev, "Cannot erase PEB %d\n", pnum); goto err; } @@ -746,7 +745,7 @@ int mtd_peb_create_bitflips(struct mtd_info *mtd, int pnum, int offset, ret = mtd_write_oob(mtd, offs, &ops); if (ret) { - dev_err(&mtd->class_dev, "Cannot write page at 0x%08llx\n", offs); + dev_err(&mtd->dev, "Cannot write page at 0x%08llx\n", offs); goto err; } } @@ -754,7 +753,7 @@ int mtd_peb_create_bitflips(struct mtd_info *mtd, int pnum, int offset, ret = 0; err: if (ret) - dev_err(&mtd->class_dev, "Failed to create bitflips: %s\n", strerror(-ret)); + dev_err(&mtd->dev, "Failed to create bitflips: %s\n", strerror(-ret)); free(buf); free(oobbuf); diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c index 2372482ac1..ea53d2cd84 100644 --- a/drivers/mtd/spi-nor/cadence-quadspi.c +++ b/drivers/mtd/spi-nor/cadence-quadspi.c @@ -1120,7 +1120,7 @@ static int cqspi_setup_flash(struct device_d *dev, if (ret) return ret; - mtd->parent = nor->dev; + mtd->dev.parent = nor->dev; } else { nor->dev = dev; } diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 5cc4573178..350b82a6be 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -540,14 +540,10 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE); - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); - return ret; erase_err: spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE); - instr->state = MTD_ERASE_FAILED; return ret; } @@ -1441,20 +1437,20 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, mtd->writesize = 1; mtd->flags = MTD_CAP_NORFLASH; mtd->size = params.size; - mtd->erase = spi_nor_erase; - mtd->read = spi_nor_read; + mtd->_erase = spi_nor_erase; + mtd->_read = spi_nor_read; /* nor protection support for STmicro chips */ if (JEDEC_MFR(info) == CFI_MFR_ST) { - mtd->lock = spi_nor_lock; - mtd->unlock = spi_nor_unlock; + mtd->_lock = spi_nor_lock; + mtd->_unlock = spi_nor_unlock; } /* sst nor chips use AAI word program */ if (info->flags & SST_WRITE) - mtd->write = sst_write; + mtd->_write = sst_write; else - mtd->write = spi_nor_write; + mtd->_write = spi_nor_write; if (info->flags & USE_FSR) nor->flags |= SNOR_F_USE_FSR; diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index da409010f7..75fdee3692 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -159,7 +159,7 @@ static int uif_init(struct ubi_device *ubi, int *ref) dev_set_name(&ubi->dev, "%s.ubi", ubi->mtd->cdev.name); ubi->dev.id = DEVICE_ID_SINGLE; - ubi->dev.parent = &ubi->mtd->class_dev; + ubi->dev.parent = &ubi->mtd->dev; err = register_device(&ubi->dev); if (err) @@ -241,8 +241,8 @@ static int get_bad_peb_limit(const struct ubi_device *ubi, int max_beb_per1024) * is that all the bad eraseblocks of the chip are in * the MTD partition we are attaching (ubi->mtd). */ - if (ubi->mtd->master) - device_size = ubi->mtd->master->size; + if (ubi->mtd->parent) + device_size = ubi->mtd->parent->size; else device_size = ubi->mtd->size; diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c index 5b34e9b8d1..900be2f09b 100644 --- a/drivers/net/e1000/eeprom.c +++ b/drivers/net/e1000/eeprom.c @@ -1426,13 +1426,9 @@ static int e1000_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) if (ret < 0) goto fail; - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); - return 0; fail: - instr->state = MTD_ERASE_FAILED; return ret; } diff --git a/drivers/of/of_mtd.c b/drivers/of/of_mtd.c index 0956ee15d3..c531518c1d 100644 --- a/drivers/of/of_mtd.c +++ b/drivers/of/of_mtd.c @@ -9,6 +9,7 @@ #include <common.h> #include <of_mtd.h> #include <linux/mtd/nand.h> +#include <linux/mtd/rawnand.h> /** * It maps 'enum nand_ecc_modes_t' found in include/linux/mtd/nand.h @@ -16,10 +17,12 @@ * device driver can get nand ecc from device tree. */ static const char *nand_ecc_modes[] = { + [NAND_ECC_INVALID] = "invalid", [NAND_ECC_NONE] = "none", [NAND_ECC_SOFT] = "soft", [NAND_ECC_HW] = "hw", [NAND_ECC_HW_SYNDROME] = "hw_syndrome", + [NAND_ECC_ON_DIE] = "on-die", [NAND_ECC_HW_OOB_FIRST] = "hw_oob_first", [NAND_ECC_SOFT_BCH] = "soft_bch", }; |