@@ -222,7 +222,6 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand,
{
struct spi_mem_op op = *spinand->op_templates.read_cache;
struct nand_device *nand = spinand_to_nand(spinand);
- struct mtd_info *mtd = nanddev_to_mtd(nand);
struct nand_page_io_req adjreq = *req;
unsigned int nbytes = 0;
void *buf = NULL;
@@ -276,17 +275,6 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand,
memcpy(req->databuf.in, spinand->databuf + req->dataoffs,
req->datalen);
- if (req->ooblen) {
- if (req->mode == MTD_OPS_AUTO_OOB)
- mtd_ooblayout_get_databytes(mtd, req->oobbuf.in,
- spinand->oobbuf,
- req->ooboffs,
- req->ooblen);
- else
- memcpy(req->oobbuf.in, spinand->oobbuf + req->ooboffs,
- req->ooblen);
- }
-
return 0;
}
@@ -295,16 +283,18 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand,
{
struct spi_mem_op op = *spinand->op_templates.write_cache;
struct nand_device *nand = spinand_to_nand(spinand);
- struct mtd_info *mtd = nanddev_to_mtd(nand);
struct nand_page_io_req adjreq = *req;
unsigned int nbytes = 0;
void *buf = NULL;
u16 column = 0;
int ret;
+ /*
+ * Only reset the data buffer, the OOB buffer is prepared by ECC engines
+ *->prepare/finish_io_req() callbacks.
+ */
memset(spinand->databuf, 0xff,
- nanddev_page_size(nand) +
- nanddev_per_page_oobsize(nand));
+ nanddev_page_size(nand));
if (req->datalen) {
memcpy(spinand->databuf + req->dataoffs, req->databuf.out,
@@ -317,15 +307,6 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand,
}
if (req->ooblen) {
- if (req->mode == MTD_OPS_AUTO_OOB)
- mtd_ooblayout_set_databytes(mtd, req->oobbuf.out,
- spinand->oobbuf,
- req->ooboffs,
- req->ooblen);
- else
- memcpy(spinand->oobbuf + req->ooboffs, req->oobbuf.out,
- req->ooblen);
-
adjreq.ooblen = nanddev_per_page_oobsize(nand);
adjreq.ooboffs = 0;
nbytes += nanddev_per_page_oobsize(nand);
@@ -457,12 +438,17 @@ static int spinand_lock_block(struct spinand_device *spinand, u8 lock)
}
static int spinand_read_page(struct spinand_device *spinand,
- const struct nand_page_io_req *req,
- bool ecc_enabled)
+ const struct nand_page_io_req *req)
{
+ struct nand_device *nand = spinand_to_nand(spinand);
u8 status;
int ret;
+ ret = nand_ecc_prepare_io_req(nand, (struct nand_page_io_req *)req,
+ spinand->oobbuf);
+ if (ret)
+ return ret;
+
ret = spinand_load_page_op(spinand, req);
if (ret)
return ret;
@@ -471,22 +457,28 @@ static int spinand_read_page(struct spinand_device *spinand,
if (ret < 0)
return ret;
+ spinand_ondie_ecc_save_status(nand, status);
+
ret = spinand_read_from_cache_op(spinand, req);
if (ret)
return ret;
- if (!ecc_enabled)
- return 0;
-
- return spinand_check_ecc_status(spinand, status);
+ return nand_ecc_finish_io_req(nand, (struct nand_page_io_req *)req,
+ spinand->oobbuf);
}
static int spinand_write_page(struct spinand_device *spinand,
const struct nand_page_io_req *req)
{
+ struct nand_device *nand = spinand_to_nand(spinand);
u8 status;
int ret;
+ ret = nand_ecc_prepare_io_req(nand, (struct nand_page_io_req *)req,
+ spinand->oobbuf);
+ if (ret)
+ return ret;
+
ret = spinand_write_enable_op(spinand);
if (ret)
return ret;
@@ -501,9 +493,10 @@ static int spinand_write_page(struct spinand_device *spinand,
ret = spinand_wait(spinand, &status);
if (!ret && (status & STATUS_PROG_FAILED))
- ret = -EIO;
+ return -EIO;
- return ret;
+ return nand_ecc_finish_io_req(nand, (struct nand_page_io_req *)req,
+ spinand->oobbuf);
}
static int spinand_mtd_read(struct mtd_info *mtd, loff_t from,
@@ -513,25 +506,24 @@ static int spinand_mtd_read(struct mtd_info *mtd, loff_t from,
struct nand_device *nand = mtd_to_nanddev(mtd);
unsigned int max_bitflips = 0;
struct nand_io_iter iter;
- bool enable_ecc = false;
+ bool disable_ecc = false;
bool ecc_failed = false;
int ret = 0;
- if (ops->mode != MTD_OPS_RAW && spinand->eccinfo.ooblayout)
- enable_ecc = true;
+ if (ops->mode == MTD_OPS_RAW || !spinand->eccinfo.ooblayout)
+ disable_ecc = true;
mutex_lock(&spinand->lock);
nanddev_io_for_each_page(nand, NAND_PAGE_READ, from, ops, &iter) {
+ if (disable_ecc)
+ iter.req.mode = MTD_OPS_RAW;
+
ret = spinand_select_target(spinand, iter.req.pos.target);
if (ret)
break;
- ret = spinand_ecc_enable(spinand, enable_ecc);
- if (ret)
- break;
-
- ret = spinand_read_page(spinand, &iter.req, enable_ecc);
+ ret = spinand_read_page(spinand, &iter.req);
if (ret < 0 && ret != -EBADMSG)
break;
@@ -562,20 +554,19 @@ static int spinand_mtd_write(struct mtd_info *mtd, loff_t to,
struct spinand_device *spinand = mtd_to_spinand(mtd);
struct nand_device *nand = mtd_to_nanddev(mtd);
struct nand_io_iter iter;
- bool enable_ecc = false;
+ bool disable_ecc = false;
int ret = 0;
- if (ops->mode != MTD_OPS_RAW && mtd->ooblayout)
- enable_ecc = true;
+ if (ops->mode == MTD_OPS_RAW || !mtd->ooblayout)
+ disable_ecc = true;
mutex_lock(&spinand->lock);
nanddev_io_for_each_page(nand, NAND_PAGE_WRITE, to, ops, &iter) {
- ret = spinand_select_target(spinand, iter.req.pos.target);
- if (ret)
- break;
+ if (disable_ecc)
+ iter.req.mode = MTD_OPS_RAW;
- ret = spinand_ecc_enable(spinand, enable_ecc);
+ ret = spinand_select_target(spinand, iter.req.pos.target);
if (ret)
break;
@@ -605,7 +596,7 @@ static bool spinand_isbad(struct nand_device *nand, const struct nand_pos *pos)
memset(spinand->oobbuf, 0, 2);
spinand_select_target(spinand, pos->target);
- spinand_read_page(spinand, &req, false);
+ spinand_read_page(spinand, &req);
if (spinand->oobbuf[0] != 0xff || spinand->oobbuf[1] != 0xff)
printk("would be bad, but fuck it\n");
// return true;
@@ -901,30 +892,6 @@ static int spinand_detect(struct spinand_device *spinand)
return 0;
}
-static int spinand_noecc_ooblayout_ecc(struct mtd_info *mtd, int section,
- struct mtd_oob_region *region)
-{
- return -ERANGE;
-}
-
-static int spinand_noecc_ooblayout_free(struct mtd_info *mtd, int section,
- struct mtd_oob_region *region)
-{
- if (section)
- return -ERANGE;
-
- /* Reserve 2 bytes for the BBM. */
- region->offset = 2;
- region->length = 62;
-
- return 0;
-}
-
-static const struct mtd_ooblayout_ops spinand_noecc_ooblayout = {
- .ecc = spinand_noecc_ooblayout_ecc,
- .free = spinand_noecc_ooblayout_free,
-};
-
static int spinand_init(struct spinand_device *spinand)
{
struct device *dev = &spinand->spimem->spi->dev;
@@ -994,6 +961,11 @@ static int spinand_init(struct spinand_device *spinand)
if (ret)
goto err_manuf_cleanup;
+ spinand_ecc_enable(spinand, false);
+ ret = nanddev_ecc_engine_init(nand);
+ if (ret)
+ goto err_cleanup_nanddev;
+
/*
* Right now, we don't support ECC, so let the whole oob
* area available for the user.
@@ -1006,19 +978,17 @@ static int spinand_init(struct spinand_device *spinand)
mtd->_erase = spinand_mtd_erase;
mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks;
- if (spinand->eccinfo.ooblayout)
- mtd_set_ooblayout(mtd, spinand->eccinfo.ooblayout);
- else
- mtd_set_ooblayout(mtd, &spinand_noecc_ooblayout);
-
ret = mtd_ooblayout_count_freebytes(mtd);
if (ret < 0)
- goto err_cleanup_nanddev;
+ goto err_cleanup_ecc_engine;
mtd->oobavail = ret;
return 0;
+err_cleanup_ecc_engine:
+ nanddev_ecc_engine_cleanup(nand);
+
err_cleanup_nanddev:
nanddev_cleanup(nand);
@@ -420,6 +420,5 @@ int spinand_match_and_init(struct spinand_device *dev,
int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
int spinand_select_target(struct spinand_device *spinand, unsigned int target);
int spinand_ecc_enable(struct spinand_device *spinand, bool enable);
-int spinand_check_ecc_status(struct spinand_device *spinand, u8 status);
#endif /* __LINUX_MTD_SPINAND_H */
Now that all the logic is available in the NAND core, let's use it from the SPI-NAND core. Right now there is no functional change as the default ECC engine for SPI-NANDs is set to 'on-die', but user can now use software correction if they want to by just setting the right properties in the DT. Also note that the OOB layout handling is removed from the SPI-NAND core as each ECC engine is supposed to handle it by it's own; users should not be aware of that. Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> --- drivers/mtd/nand/spi/core.c | 126 ++++++++++++++---------------------- include/linux/mtd/spinand.h | 1 - 2 files changed, 48 insertions(+), 79 deletions(-)