diff options
| author | Miquel Raynal <miquel.raynal@bootlin.com> | 2026-05-04 15:14:36 +0200 |
|---|---|---|
| committer | Miquel Raynal <miquel.raynal@bootlin.com> | 2026-05-04 15:14:36 +0200 |
| commit | 7a0d420e42a5f0e8451d142cf1154dda7183e146 (patch) | |
| tree | 7b24f86be388a476b38c574e0c61f037208fecee /drivers/mtd/nand | |
| parent | 7fd2df204f342fc17d1a0bfcd474b24232fb0f32 (diff) | |
| parent | 38fbe4b3f66e5b8e2f2ab8e7ca3d912e1e935fe2 (diff) | |
Merge tag 'mtd/spi-mem-cont-read-for-7.2' into nand/next
Aside from preparation changes in the SPI NAND core, the changes carried
here focus on the shared spi-mem layer which is enhanced in order to
bring two new features:
- The possibility to fill a primary and a secondary operation template
in the direct mapping structure in order to support continuous reads
in SPI NAND, which may require two different read operations.
- SPI controllers may indicate possible CS instabilities over long
transfers by setting a boolean. This capability is related to the
previous one, the need for it has arised while testing SPI NAND
continuous reads with the Cadence QSPI controller which cannot, under
certain conditions, keep the CS asserted for the length of
an eraseblock-large transfer.
Diffstat (limited to 'drivers/mtd/nand')
| -rw-r--r-- | drivers/mtd/nand/spi/core.c | 76 |
1 files changed, 29 insertions, 47 deletions
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 0b076790bd9d..786e3fb4874d 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -501,10 +501,13 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand, } } - if (req->mode == MTD_OPS_RAW) - rdesc = spinand->dirmaps[req->pos.plane].rdesc; + rdesc = spinand->dirmaps[req->pos.plane].rdesc; + + if (nand->ecc.engine->integration == NAND_ECC_ENGINE_INTEGRATION_PIPELINED && + req->mode != MTD_OPS_RAW) + rdesc->info.op_tmpl->data.ecc = true; else - rdesc = spinand->dirmaps[req->pos.plane].rdesc_ecc; + rdesc->info.op_tmpl->data.ecc = false; if (spinand->flags & SPINAND_HAS_READ_PLANE_SELECT_BIT) column |= req->pos.plane << fls(nanddev_page_size(nand)); @@ -593,10 +596,13 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand, req->ooblen); } - if (req->mode == MTD_OPS_RAW) - wdesc = spinand->dirmaps[req->pos.plane].wdesc; + wdesc = spinand->dirmaps[req->pos.plane].wdesc; + + if (nand->ecc.engine->integration == NAND_ECC_ENGINE_INTEGRATION_PIPELINED && + req->mode != MTD_OPS_RAW) + wdesc->info.op_tmpl->data.ecc = true; else - wdesc = spinand->dirmaps[req->pos.plane].wdesc_ecc; + wdesc->info.op_tmpl->data.ecc = false; if (spinand->flags & SPINAND_HAS_PROG_PLANE_SELECT_BIT) column |= req->pos.plane << fls(nanddev_page_size(nand)); @@ -892,6 +898,12 @@ static int spinand_mtd_continuous_page_read(struct mtd_info *mtd, loff_t from, * Each data read must be a multiple of 4-bytes and full pages should be read; * otherwise, the data output might get out of sequence from one read command * to another. + * + * Continuous reads never cross LUN boundaries. Some devices don't + * support crossing planes boundaries. Some devices don't even support + * crossing blocks boundaries. The common case being to read through UBI, + * we will very rarely read two consequent blocks or more, so let's only enable + * continuous reads when reading within the same erase block. */ nanddev_io_for_each_block(nand, NAND_PAGE_READ, from, ops, &iter) { ret = spinand_select_target(spinand, iter.req.pos.target); @@ -982,19 +994,6 @@ static bool spinand_use_cont_read(struct mtd_info *mtd, loff_t from, nanddev_offs_to_pos(nand, from, &start_pos); nanddev_offs_to_pos(nand, from + ops->len - 1, &end_pos); - /* - * Continuous reads never cross LUN boundaries. Some devices don't - * support crossing planes boundaries. Some devices don't even support - * crossing blocks boundaries. The common case being to read through UBI, - * we will very rarely read two consequent blocks or more, so it is safer - * and easier (can be improved) to only enable continuous reads when - * reading within the same erase block. - */ - if (start_pos.target != end_pos.target || - start_pos.plane != end_pos.plane || - start_pos.eraseblock != end_pos.eraseblock) - return false; - return start_pos.page < end_pos.page; } @@ -1252,12 +1251,18 @@ static int spinand_create_dirmap(struct spinand_device *spinand, struct nand_device *nand = spinand_to_nand(spinand); struct spi_mem_dirmap_info info = { 0 }; struct spi_mem_dirmap_desc *desc; + bool enable_ecc = false; + + if (nand->ecc.engine->integration == NAND_ECC_ENGINE_INTEGRATION_PIPELINED) + enable_ecc = true; /* The plane number is passed in MSB just above the column address */ info.offset = plane << fls(nand->memorg.pagesize); + /* Write descriptor */ info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); - info.op_tmpl = *spinand->op_templates->update_cache; + info.primary_op_tmpl = *spinand->op_templates->update_cache; + info.primary_op_tmpl.data.ecc = enable_ecc; desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, spinand->spimem, &info); if (IS_ERR(desc)) @@ -1265,38 +1270,15 @@ static int spinand_create_dirmap(struct spinand_device *spinand, spinand->dirmaps[plane].wdesc = desc; - info.op_tmpl = *spinand->op_templates->read_cache; + /* Read descriptor */ + info.primary_op_tmpl = *spinand->op_templates->read_cache; + info.primary_op_tmpl.data.ecc = enable_ecc; desc = spinand_create_rdesc(spinand, &info); if (IS_ERR(desc)) return PTR_ERR(desc); spinand->dirmaps[plane].rdesc = desc; - if (nand->ecc.engine->integration != NAND_ECC_ENGINE_INTEGRATION_PIPELINED) { - spinand->dirmaps[plane].wdesc_ecc = spinand->dirmaps[plane].wdesc; - spinand->dirmaps[plane].rdesc_ecc = spinand->dirmaps[plane].rdesc; - - return 0; - } - - info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); - info.op_tmpl = *spinand->op_templates->update_cache; - info.op_tmpl.data.ecc = true; - desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, - spinand->spimem, &info); - if (IS_ERR(desc)) - return PTR_ERR(desc); - - spinand->dirmaps[plane].wdesc_ecc = desc; - - info.op_tmpl = *spinand->op_templates->read_cache; - info.op_tmpl.data.ecc = true; - desc = spinand_create_rdesc(spinand, &info); - if (IS_ERR(desc)) - return PTR_ERR(desc); - - spinand->dirmaps[plane].rdesc_ecc = desc; - return 0; } @@ -1421,7 +1403,7 @@ static void spinand_manufacturer_cleanup(struct spinand_device *spinand) return spinand->manufacturer->ops->cleanup(spinand); } -static bool spinand_op_is_odtr(const struct spi_mem_op *op) +bool spinand_op_is_odtr(const struct spi_mem_op *op) { return op->cmd.dtr && op->cmd.buswidth == 8; } |
