This makes code more generic. Also it allows check for DTR support and emit DTR operations only if it supported by the spi controller.
This is necessary for spinand DTR support. Signed-off-by: Mikhail Kshevetskiy <[email protected]> --- drivers/spi/atmel-quadspi.c | 5 +++ drivers/spi/cadence_qspi.c | 10 +++--- drivers/spi/nxp_xspi.c | 12 +++++--- drivers/spi/spi-mem.c | 61 ++++++++++++++++++++----------------- include/spi-mem.h | 19 ++++++++++-- include/spi.h | 1 + 6 files changed, 68 insertions(+), 40 deletions(-) diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c index b2b96e1c4b9..37d97c094f8 100644 --- a/drivers/spi/atmel-quadspi.c +++ b/drivers/spi/atmel-quadspi.c @@ -1286,11 +1286,16 @@ static const struct spi_controller_mem_ops atmel_qspi_mem_ops = { .exec_op = atmel_qspi_exec_op, }; +static const struct spi_controller_mem_ops atmel_qspi_mem_caps = { + .dtr = true, +}; + static const struct dm_spi_ops atmel_qspi_ops = { .claim_bus = atmel_qspi_claim_bus, .release_bus = atmel_qspi_release_bus, .xfer = atmel_qspi_xfer, .mem_ops = &atmel_qspi_mem_ops, + .mem_caps = &atmel_qspi_mem_caps, .set_speed = atmel_qspi_set_speed, .set_mode = atmel_qspi_set_mode, }; diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c index 984d4a39ded..8eec45270b0 100644 --- a/drivers/spi/cadence_qspi.c +++ b/drivers/spi/cadence_qspi.c @@ -398,10 +398,7 @@ static bool cadence_spi_mem_supports_op(struct spi_slave *slave, if (!(all_true || all_false)) return false; - if (all_true) - return spi_mem_dtr_supports_op(slave, op); - else - return spi_mem_default_supports_op(slave, op); + return spi_mem_default_supports_op(slave, op); } static int cadence_spi_of_to_plat(struct udevice *bus) @@ -467,10 +464,15 @@ static const struct spi_controller_mem_ops cadence_spi_mem_ops = { .supports_op = cadence_spi_mem_supports_op, }; +static const struct spi_controller_mem_caps cadence_spi_mem_caps = { + .dtr = true, +}; + static const struct dm_spi_ops cadence_spi_ops = { .set_speed = cadence_spi_set_speed, .set_mode = cadence_spi_set_mode, .mem_ops = &cadence_spi_mem_ops, + .mem_caps = &cadence_spi_mem_caps, /* * cs_info is not needed, since we require all chip selects to be * in the device tree explicitly diff --git a/drivers/spi/nxp_xspi.c b/drivers/spi/nxp_xspi.c index 200138f5adf..c3a5c56b138 100644 --- a/drivers/spi/nxp_xspi.c +++ b/drivers/spi/nxp_xspi.c @@ -326,10 +326,7 @@ static bool nxp_xspi_supports_op(struct spi_slave *slave, op->data.nbytes > x->devtype_data->txfifo) return false; - if (op->cmd.dtr) - return spi_mem_dtr_supports_op(slave, op); - else - return spi_mem_default_supports_op(slave, op); + return spi_mem_default_supports_op(slave, op); } static int xspi_update_lut(struct nxp_xspi *x, u32 seq_index, const u32 *lut_base, u32 num_of_seq) @@ -700,11 +697,16 @@ static const struct spi_controller_mem_ops nxp_xspi_mem_ops = { .exec_op = nxp_xspi_exec_op, }; +static const struct spi_controller_mem_caps nxp_xspi_mem_caps = { + .dtr = true, +}; + static const struct dm_spi_ops nxp_xspi_ops = { .claim_bus = nxp_xspi_claim_bus, .set_speed = nxp_xspi_set_speed, .set_mode = nxp_xspi_set_mode, - .mem_ops = &nxp_xspi_mem_ops, + .mem_ops = &nxp_xspi_mem_ops, + .mem_caps = &nxp_xspi_mem_caps, }; static int nxp_xspi_of_to_plat(struct udevice *bus) diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 3fd2353af94..1c23f3d8843 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -171,38 +171,43 @@ static bool spi_mem_check_buswidth(struct spi_slave *slave, return true; } -bool spi_mem_dtr_supports_op(struct spi_slave *slave, - const struct spi_mem_op *op) -{ - if (op->cmd.buswidth == 8 && op->cmd.nbytes % 2) - return false; - - if (op->addr.nbytes && op->addr.buswidth == 8 && op->addr.nbytes % 2) - return false; - - if (op->dummy.nbytes && op->dummy.buswidth == 8 && op->dummy.nbytes % 2) - return false; - - /* - * Transactions of odd length do not make sense for 8D-8D-8D mode - * because a byte is transferred in just half a cycle. - */ - if (op->data.dir != SPI_MEM_NO_DATA && op->data.dir != SPI_MEM_DATA_IN && - op->data.buswidth == 8 && op->data.nbytes % 2) - return false; - - return spi_mem_check_buswidth(slave, op); -} -EXPORT_SYMBOL_GPL(spi_mem_dtr_supports_op); - bool spi_mem_default_supports_op(struct spi_slave *slave, const struct spi_mem_op *op) { - if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr) - return false; + struct udevice *bus = slave->dev->parent; + struct dm_spi_ops *ops = spi_get_ops(bus); + bool op_is_dtr = + op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr; + + if (op_is_dtr) { + if (!spi_mem_controller_is_capable(ops, dtr)) + return false; + + if (op->data.swap16 && !spi_mem_controller_is_capable(ops, swap16)) + return false; + + /* Extra 8D-8D-8D limitations */ + if (op->cmd.dtr && op->cmd.buswidth == 8) { + if (op->cmd.nbytes != 2) + return false; + + if ((op->addr.nbytes % 2) || + (op->dummy.nbytes % 2) || + (op->data.nbytes % 2)) { + dev_err(bus, + "Even byte numbers not allowed in octal DTR operations\n"); + return false; + } + } + } else { + if (op->cmd.nbytes != 1) + return false; + } - if (op->cmd.nbytes != 1) - return false; + if (op->data.ecc) { + if (!spi_mem_controller_is_capable(ops, ecc)) + return false; + } return spi_mem_check_buswidth(slave, op); } diff --git a/include/spi-mem.h b/include/spi-mem.h index 36281a62f77..8c20feebfca 100644 --- a/include/spi-mem.h +++ b/include/spi-mem.h @@ -331,6 +331,22 @@ struct spi_controller_mem_ops { u64 offs, size_t len, const void *buf); }; +/** + * struct spi_controller_mem_caps - SPI memory controller capabilities + * @dtr: Supports DTR operations + * @ecc: Supports operations with error correction + * @swap16: Supports swapping bytes on a 16 bit boundary when configured in + * Octal DTR + */ +struct spi_controller_mem_caps { + bool dtr; + bool ecc; + bool swap16; +}; + +#define spi_mem_controller_is_capable(spi_ops, cap) \ + ((spi_ops)->mem_caps && (spi_ops)->mem_caps->cap) + #ifndef __UBOOT__ /** * struct spi_mem_driver - SPI memory driver @@ -395,9 +411,6 @@ int spi_mem_adjust_op_size(struct spi_slave *slave, struct spi_mem_op *op); u64 spi_mem_calc_op_duration(struct spi_mem_op *op); bool spi_mem_supports_op(struct spi_slave *slave, const struct spi_mem_op *op); -bool spi_mem_dtr_supports_op(struct spi_slave *slave, - const struct spi_mem_op *op); - bool spi_mem_default_supports_op(struct spi_slave *slave, const struct spi_mem_op *op); diff --git a/include/spi.h b/include/spi.h index 97096a77526..97e95529850 100644 --- a/include/spi.h +++ b/include/spi.h @@ -492,6 +492,7 @@ struct dm_spi_ops { * has native support for memory like operations. */ const struct spi_controller_mem_ops *mem_ops; + const struct spi_controller_mem_caps *mem_caps; /** * Set transfer speed. -- 2.53.0
