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; } diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 5dd0b3cb5250..a7bc458edc5c 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -3641,14 +3641,15 @@ EXPORT_SYMBOL_GPL(spi_nor_scan); static int spi_nor_create_read_dirmap(struct spi_nor *nor) { struct spi_mem_dirmap_info info = { - .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0), - SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), - SPI_MEM_OP_DUMMY(nor->read_dummy, 0), - SPI_MEM_OP_DATA_IN(0, NULL, 0)), + .op_tmpl = &info.primary_op_tmpl, + .primary_op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0), + SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), + SPI_MEM_OP_DUMMY(nor->read_dummy, 0), + SPI_MEM_OP_DATA_IN(0, NULL, 0)), .offset = 0, .length = nor->params->size, }; - struct spi_mem_op *op = &info.op_tmpl; + struct spi_mem_op *op = info.op_tmpl; spi_nor_spimem_setup_op(nor, op, nor->read_proto); @@ -3672,14 +3673,15 @@ static int spi_nor_create_read_dirmap(struct spi_nor *nor) static int spi_nor_create_write_dirmap(struct spi_nor *nor) { struct spi_mem_dirmap_info info = { - .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0), - SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(0, NULL, 0)), + .op_tmpl = &info.primary_op_tmpl, + .primary_op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0), + SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(0, NULL, 0)), .offset = 0, .length = nor->params->size, }; - struct spi_mem_op *op = &info.op_tmpl; + struct spi_mem_op *op = info.op_tmpl; if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second) op->addr.nbytes = 0; diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c index 7b6c09f91fef..95bfde7c8e7f 100644 --- a/drivers/spi/spi-airoha-snfi.c +++ b/drivers/spi/spi-airoha-snfi.c @@ -546,7 +546,7 @@ static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc) if (desc->info.length > SPI_NAND_CACHE_SIZE) return -E2BIG; - if (!airoha_snand_supports_op(desc->mem, &desc->info.op_tmpl)) + if (!airoha_snand_supports_op(desc->mem, desc->info.op_tmpl)) return -EOPNOTSUPP; return 0; @@ -572,7 +572,7 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, * DUALIO and QUADIO opcodes are not supported by the spi controller, * replace them with supported opcodes. */ - opcode = desc->info.op_tmpl.cmd.opcode; + opcode = desc->info.op_tmpl->cmd.opcode; switch (opcode) { case SPI_NAND_OP_READ_FROM_CACHE_SINGLE: case SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST: @@ -761,7 +761,7 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, /* minimum oob size is 64 */ bytes = round_up(offs + len, 64); - opcode = desc->info.op_tmpl.cmd.opcode; + opcode = desc->info.op_tmpl->cmd.opcode; switch (opcode) { case SPI_NAND_OP_PROGRAM_LOAD_SINGLE: case SPI_NAND_OP_PROGRAM_LOAD_RAMDOM_SINGLE: diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c index 027caa2eeb5c..e9fd9f3b552b 100644 --- a/drivers/spi/spi-aspeed-smc.c +++ b/drivers/spi/spi-aspeed-smc.c @@ -697,7 +697,7 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc) { struct aspeed_spi *aspi = spi_controller_get_devdata(desc->mem->spi->controller); struct aspeed_spi_chip *chip = &aspi->chips[spi_get_chipselect(desc->mem->spi, 0)]; - struct spi_mem_op *op = &desc->info.op_tmpl; + struct spi_mem_op *op = desc->info.op_tmpl; u32 ctl_val; int ret = 0; @@ -769,7 +769,7 @@ static ssize_t aspeed_spi_dirmap_read(struct spi_mem_dirmap_desc *desc, if (chip->ahb_window_size < offset + len || chip->force_user_mode) { int ret; - ret = aspeed_spi_read_user(chip, &desc->info.op_tmpl, offset, len, buf); + ret = aspeed_spi_read_user(chip, desc->info.op_tmpl, offset, len, buf); if (ret < 0) return ret; } else { diff --git a/drivers/spi/spi-intel.c b/drivers/spi/spi-intel.c index 1775ad39e633..7494b921a743 100644 --- a/drivers/spi/spi-intel.c +++ b/drivers/spi/spi-intel.c @@ -814,7 +814,7 @@ static int intel_spi_dirmap_create(struct spi_mem_dirmap_desc *desc) struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller); const struct intel_spi_mem_op *iop; - iop = intel_spi_match_mem_op(ispi, &desc->info.op_tmpl); + iop = intel_spi_match_mem_op(ispi, desc->info.op_tmpl); if (!iop) return -EOPNOTSUPP; @@ -827,7 +827,7 @@ static ssize_t intel_spi_dirmap_read(struct spi_mem_dirmap_desc *desc, u64 offs, { struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller); const struct intel_spi_mem_op *iop = desc->priv; - struct spi_mem_op op = desc->info.op_tmpl; + struct spi_mem_op op = *desc->info.op_tmpl; int ret; /* Fill in the gaps */ @@ -844,7 +844,7 @@ static ssize_t intel_spi_dirmap_write(struct spi_mem_dirmap_desc *desc, u64 offs { struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller); const struct intel_spi_mem_op *iop = desc->priv; - struct spi_mem_op op = desc->info.op_tmpl; + struct spi_mem_op op = *desc->info.op_tmpl; int ret; op.addr.val = offs; diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 93266848c6df..a88b9f038356 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -654,7 +654,7 @@ EXPORT_SYMBOL_GPL(spi_mem_calc_op_duration); static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, void *buf) { - struct spi_mem_op op = desc->info.op_tmpl; + struct spi_mem_op op = *desc->info.op_tmpl; int ret; op.addr.val = desc->info.offset + offs; @@ -674,7 +674,7 @@ static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc, static ssize_t spi_mem_no_dirmap_write(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, const void *buf) { - struct spi_mem_op op = desc->info.op_tmpl; + struct spi_mem_op op = *desc->info.op_tmpl; int ret; op.addr.val = desc->info.offset + offs; @@ -713,19 +713,37 @@ spi_mem_dirmap_create(struct spi_mem *mem, int ret = -ENOTSUPP; /* Make sure the number of address cycles is between 1 and 8 bytes. */ - if (!info->op_tmpl.addr.nbytes || info->op_tmpl.addr.nbytes > 8) + if (!info->primary_op_tmpl.addr.nbytes || info->primary_op_tmpl.addr.nbytes > 8) return ERR_PTR(-EINVAL); /* data.dir should either be SPI_MEM_DATA_IN or SPI_MEM_DATA_OUT. */ - if (info->op_tmpl.data.dir == SPI_MEM_NO_DATA) + if (info->primary_op_tmpl.data.dir == SPI_MEM_NO_DATA) return ERR_PTR(-EINVAL); + /* Apply similar constraints to the secondary template */ + if (info->secondary_op_tmpl.cmd.opcode) { + if (!info->secondary_op_tmpl.addr.nbytes || + info->secondary_op_tmpl.addr.nbytes > 8) + return ERR_PTR(-EINVAL); + + if (info->secondary_op_tmpl.data.dir == SPI_MEM_NO_DATA) + return ERR_PTR(-EINVAL); + + if (!spi_mem_supports_op(mem, &info->secondary_op_tmpl)) + return ERR_PTR(-EOPNOTSUPP); + + if (ctlr->mem_ops && ctlr->mem_ops->dirmap_create && + !spi_mem_controller_is_capable(ctlr, secondary_op_tmpl)) + return ERR_PTR(-EOPNOTSUPP); + } + desc = kzalloc_obj(*desc); if (!desc) return ERR_PTR(-ENOMEM); desc->mem = mem; desc->info = *info; + desc->info.op_tmpl = &desc->info.primary_op_tmpl; if (ctlr->mem_ops && ctlr->mem_ops->dirmap_create) { ret = spi_mem_access_start(mem); if (ret) { @@ -740,7 +758,7 @@ spi_mem_dirmap_create(struct spi_mem *mem, if (ret) { desc->nodirmap = true; - if (!spi_mem_supports_op(desc->mem, &desc->info.op_tmpl)) + if (!spi_mem_supports_op(desc->mem, &desc->info.primary_op_tmpl)) ret = -EOPNOTSUPP; else ret = 0; @@ -864,7 +882,7 @@ ssize_t spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc, struct spi_controller *ctlr = desc->mem->spi->controller; ssize_t ret; - if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) + if (desc->info.op_tmpl->data.dir != SPI_MEM_DATA_IN) return -EINVAL; if (!len) @@ -910,7 +928,7 @@ ssize_t spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc, struct spi_controller *ctlr = desc->mem->spi->controller; ssize_t ret; - if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_OUT) + if (desc->info.op_tmpl->data.dir != SPI_MEM_DATA_OUT) return -EINVAL; if (!len) diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c index b0e7fc828a50..83b688e65284 100644 --- a/drivers/spi/spi-mxic.c +++ b/drivers/spi/spi-mxic.c @@ -403,20 +403,20 @@ static ssize_t mxic_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc, if (WARN_ON(offs + desc->info.offset + len > U32_MAX)) return -EINVAL; - writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl.data.swap16), + writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl->data.swap16), mxic->regs + HC_CFG); - writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len), + writel(mxic_spi_mem_prep_op_cfg(desc->info.op_tmpl, len), mxic->regs + LRD_CFG); writel(desc->info.offset + offs, mxic->regs + LRD_ADDR); len = min_t(size_t, len, mxic->linear.size); writel(len, mxic->regs + LRD_RANGE); - writel(LMODE_CMD0(desc->info.op_tmpl.cmd.opcode) | + writel(LMODE_CMD0(desc->info.op_tmpl->cmd.opcode) | LMODE_SLV_ACT(spi_get_chipselect(desc->mem->spi, 0)) | LMODE_EN, mxic->regs + LRD_CTRL); - if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl.data.ecc) { + if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl->data.ecc) { ret = mxic_ecc_process_data_pipelined(mxic->ecc.pipelined_engine, NAND_PAGE_READ, mxic->linear.dma + offs); @@ -448,20 +448,20 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc, if (WARN_ON(offs + desc->info.offset + len > U32_MAX)) return -EINVAL; - writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl.data.swap16), + writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl->data.swap16), mxic->regs + HC_CFG); - writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len), + writel(mxic_spi_mem_prep_op_cfg(desc->info.op_tmpl, len), mxic->regs + LWR_CFG); writel(desc->info.offset + offs, mxic->regs + LWR_ADDR); len = min_t(size_t, len, mxic->linear.size); writel(len, mxic->regs + LWR_RANGE); - writel(LMODE_CMD0(desc->info.op_tmpl.cmd.opcode) | + writel(LMODE_CMD0(desc->info.op_tmpl->cmd.opcode) | LMODE_SLV_ACT(spi_get_chipselect(desc->mem->spi, 0)) | LMODE_EN, mxic->regs + LWR_CTRL); - if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl.data.ecc) { + if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl->data.ecc) { ret = mxic_ecc_process_data_pipelined(mxic->ecc.pipelined_engine, NAND_PAGE_WRITE, mxic->linear.dma + offs); @@ -509,7 +509,7 @@ static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc) if (desc->info.offset + desc->info.length > U32_MAX) return -EINVAL; - if (!mxic_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl)) + if (!mxic_spi_mem_supports_op(desc->mem, desc->info.op_tmpl)) return -EOPNOTSUPP; return 0; diff --git a/drivers/spi/spi-npcm-fiu.c b/drivers/spi/spi-npcm-fiu.c index 6617751009c3..4b825044038b 100644 --- a/drivers/spi/spi-npcm-fiu.c +++ b/drivers/spi/spi-npcm-fiu.c @@ -299,11 +299,11 @@ static ssize_t npcm_fiu_direct_read(struct spi_mem_dirmap_desc *desc, for (i = 0 ; i < len ; i++) *(buf_rx + i) = ioread8(src + i); } else { - if (desc->info.op_tmpl.addr.buswidth != fiu->drd_op.addr.buswidth || - desc->info.op_tmpl.dummy.nbytes != fiu->drd_op.dummy.nbytes || - desc->info.op_tmpl.cmd.opcode != fiu->drd_op.cmd.opcode || - desc->info.op_tmpl.addr.nbytes != fiu->drd_op.addr.nbytes) - npcm_fiu_set_drd(fiu, &desc->info.op_tmpl); + if (desc->info.op_tmpl->addr.buswidth != fiu->drd_op.addr.buswidth || + desc->info.op_tmpl->dummy.nbytes != fiu->drd_op.dummy.nbytes || + desc->info.op_tmpl->cmd.opcode != fiu->drd_op.cmd.opcode || + desc->info.op_tmpl->addr.nbytes != fiu->drd_op.addr.nbytes) + npcm_fiu_set_drd(fiu, desc->info.op_tmpl); memcpy_fromio(buf_rx, src, len); } @@ -609,7 +609,7 @@ static int npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc) } if (!fiu->spix_mode && - desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) { + desc->info.op_tmpl->data.dir == SPI_MEM_DATA_OUT) { desc->nodirmap = true; return 0; } @@ -644,9 +644,9 @@ static int npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc) NPCM_FIU_CFG_FIU_FIX); } - if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) { + if (desc->info.op_tmpl->data.dir == SPI_MEM_DATA_IN) { if (!fiu->spix_mode) - npcm_fiu_set_drd(fiu, &desc->info.op_tmpl); + npcm_fiu_set_drd(fiu, desc->info.op_tmpl); else npcm_fiux_set_direct_rd(fiu); diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c index 6edc0c4db854..1ef7bd91b3b3 100644 --- a/drivers/spi/spi-rpc-if.c +++ b/drivers/spi/spi-rpc-if.c @@ -83,7 +83,7 @@ static ssize_t xspi_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc, if (offs + desc->info.offset + len > U32_MAX) return -EINVAL; - rpcif_spi_mem_prepare(desc->mem->spi, &desc->info.op_tmpl, &offs, &len); + rpcif_spi_mem_prepare(desc->mem->spi, desc->info.op_tmpl, &offs, &len); return xspi_dirmap_write(rpc->dev, offs, len, buf); } @@ -97,7 +97,7 @@ static ssize_t rpcif_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc, if (offs + desc->info.offset + len > U32_MAX) return -EINVAL; - rpcif_spi_mem_prepare(desc->mem->spi, &desc->info.op_tmpl, &offs, &len); + rpcif_spi_mem_prepare(desc->mem->spi, desc->info.op_tmpl, &offs, &len); return rpcif_dirmap_read(rpc->dev, offs, len, buf); } @@ -110,13 +110,13 @@ static int rpcif_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc) if (desc->info.offset + desc->info.length > U32_MAX) return -EINVAL; - if (!rpcif_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl)) + if (!rpcif_spi_mem_supports_op(desc->mem, desc->info.op_tmpl)) return -EOPNOTSUPP; if (!rpc->dirmap) return -EOPNOTSUPP; - if (!rpc->xspi && desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) + if (!rpc->xspi && desc->info.op_tmpl->data.dir != SPI_MEM_DATA_IN) return -EOPNOTSUPP; return 0; diff --git a/drivers/spi/spi-stm32-ospi.c b/drivers/spi/spi-stm32-ospi.c index 3757f6ba8fc6..fa0e8e83cb1b 100644 --- a/drivers/spi/spi-stm32-ospi.c +++ b/drivers/spi/spi-stm32-ospi.c @@ -601,11 +601,11 @@ static int stm32_ospi_dirmap_create(struct spi_mem_dirmap_desc *desc) { struct stm32_ospi *ospi = spi_controller_get_devdata(desc->mem->spi->controller); - if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) + if (desc->info.op_tmpl->data.dir == SPI_MEM_DATA_OUT) return -EOPNOTSUPP; /* Should never happen, as mm_base == null is an error probe exit condition */ - if (!ospi->mm_base && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) + if (!ospi->mm_base && desc->info.op_tmpl->data.dir == SPI_MEM_DATA_IN) return -EOPNOTSUPP; if (!ospi->mm_size) @@ -632,7 +632,7 @@ static ssize_t stm32_ospi_dirmap_read(struct spi_mem_dirmap_desc *desc, * spi_mem_op template with offs, len and *buf in order to get * all needed transfer information into struct spi_mem_op */ - memcpy(&op, &desc->info.op_tmpl, sizeof(struct spi_mem_op)); + memcpy(&op, desc->info.op_tmpl, sizeof(struct spi_mem_op)); dev_dbg(ospi->dev, "%s len = 0x%zx offs = 0x%llx buf = 0x%p\n", __func__, len, offs, buf); op.data.nbytes = len; diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index ea69fe25686f..b77daba6db83 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -505,11 +505,11 @@ static int stm32_qspi_dirmap_create(struct spi_mem_dirmap_desc *desc) { struct stm32_qspi *qspi = spi_controller_get_devdata(desc->mem->spi->controller); - if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) + if (desc->info.op_tmpl->data.dir == SPI_MEM_DATA_OUT) return -EOPNOTSUPP; /* should never happen, as mm_base == null is an error probe exit condition */ - if (!qspi->mm_base && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) + if (!qspi->mm_base && desc->info.op_tmpl->data.dir == SPI_MEM_DATA_IN) return -EOPNOTSUPP; if (!qspi->mm_size) @@ -535,7 +535,7 @@ static ssize_t stm32_qspi_dirmap_read(struct spi_mem_dirmap_desc *desc, * spi_mem_op template with offs, len and *buf in order to get * all needed transfer information into struct spi_mem_op */ - memcpy(&op, &desc->info.op_tmpl, sizeof(struct spi_mem_op)); + memcpy(&op, desc->info.op_tmpl, sizeof(struct spi_mem_op)); dev_dbg(qspi->dev, "%s len = 0x%zx offs = 0x%llx buf = 0x%p\n", __func__, len, offs, buf); op.data.nbytes = len; diff --git a/drivers/spi/spi-wpcm-fiu.c b/drivers/spi/spi-wpcm-fiu.c index 0e26ff178505..cd78e927953d 100644 --- a/drivers/spi/spi-wpcm-fiu.c +++ b/drivers/spi/spi-wpcm-fiu.c @@ -377,7 +377,7 @@ static int wpcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc) struct wpcm_fiu_spi *fiu = spi_controller_get_devdata(desc->mem->spi->controller); int cs = spi_get_chipselect(desc->mem->spi, 0); - if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) + if (desc->info.op_tmpl->data.dir != SPI_MEM_DATA_IN) return -EOPNOTSUPP; /* diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index 782984ba3a20..f53f5f0499b4 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -691,8 +691,6 @@ struct spinand_info { struct spinand_dirmap { struct spi_mem_dirmap_desc *wdesc; struct spi_mem_dirmap_desc *rdesc; - struct spi_mem_dirmap_desc *wdesc_ecc; - struct spi_mem_dirmap_desc *rdesc_ecc; }; /** @@ -869,6 +867,8 @@ static inline void spinand_set_of_node(struct spinand_device *spinand, nanddev_set_of_node(&spinand->base, np); } +bool spinand_op_is_odtr(const struct spi_mem_op *op); + int spinand_match_and_init(struct spinand_device *spinand, const struct spinand_info *table, unsigned int table_size, diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h index c8e207522223..722abd9aee3c 100644 --- a/include/linux/spi/spi-mem.h +++ b/include/linux/spi/spi-mem.h @@ -227,6 +227,8 @@ struct spi_mem_op { * struct spi_mem_dirmap_info - Direct mapping information * @op_tmpl: operation template that should be used by the direct mapping when * the memory device is accessed + * @secondary_op_tmpl: secondary template, may be used as an alternative to the + * primary template (decided by the upper layer) * @offset: absolute offset this direct mapping is pointing to * @length: length in byte of this direct mapping * @@ -237,7 +239,9 @@ struct spi_mem_op { * direction is directly encoded in the ->op_tmpl.data.dir field. */ struct spi_mem_dirmap_info { - struct spi_mem_op op_tmpl; + struct spi_mem_op *op_tmpl; + struct spi_mem_op primary_op_tmpl; + struct spi_mem_op secondary_op_tmpl; u64 offset; u64 length; }; @@ -381,12 +385,18 @@ struct spi_controller_mem_ops { * @swap16: Supports swapping bytes on a 16 bit boundary when configured in * Octal DTR * @per_op_freq: Supports per operation frequency switching + * @no_cs_assertion: The controller may automatically deassert the CS if there + * is a pause in the transfer (eg. internal bus contention or + * DMA arbitration on an interconnect). Features such as NAND + * continuous reads shall not be leveraged. */ struct spi_controller_mem_caps { bool dtr; bool ecc; bool swap16; bool per_op_freq; + bool secondary_op_tmpl; + bool no_cs_assertion; }; #define spi_mem_controller_is_capable(ctlr, cap) \