[PATCH 4/5] spi: ma35d1-qspi: Add DTR support
Miquel Raynal <[email protected]>
| Newsgroups | org.kernel.vger.linux-spi,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <20260813-perso-ma35d1-upstream-qspi-v1-4-b217b9870eb1@bootlin.com> |
The controller has DTR support, a bit must be set for it. The behaviour is interesting though, as the speed won't improve when enabled. This is because there seems to be an internal divisor (/2) which keeps the rate equal when DTR is enabled. As a result, this commit also doubles the target bus speed, which in practice does not happen. This way, there is a real gain: Before: $ flash_speed /dev/mtd0 -dc10 eraseblock write speed is 1000 KiB/s [...] eraseblock read speed is 1199 KiB/s [...] After: $ flash_speed /dev/mtd0 -dc10 eraseblock write speed is 985 KiB/s [...] eraseblock read speed is 1540 KiB/s [...] Signed-off-by: Miquel Raynal <[email protected]> --- drivers/spi/spi-ma35d1-qspi.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-ma35d1-qspi.c b/drivers/spi/spi-ma35d1-qspi.c index 027a9433f2b1..9965a11573d8 100644 --- a/drivers/spi/spi-ma35d1-qspi.c +++ b/drivers/spi/spi-ma35d1-qspi.c @@ -31,6 +31,7 @@ #define NUVOTON_QSPI_RX_OFFSET 0x30 /* Data Receive Register, RO */ /* QSPI Control Register bit masks */ +#define NUVOTON_QSPI_CTL_DTREN_MASK BIT(23) /* DTR I/O Mode Enable */ #define NUVOTON_QSPI_CTL_QUADIOEN_MASK BIT(22) /* Quad I/O Mode Enable */ #define NUVOTON_QSPI_CTL_DUALIOEN_MASK BIT(21) /* Dual I/O Mode Enable */ #define NUVOTON_QSPI_CTL_DATDIR_MASK BIT(20) /* Data Port Direction Control */ @@ -131,7 +132,7 @@ static int nuvoton_qspi_reset_fifo(struct nuvoton_qspi *qspi) 1, NUVOTON_QSPI_TIMEOUT_US); } -static int nuvoton_qspi_set_speed(struct spi_device *spi, u32 speed_hz) +static int nuvoton_qspi_set_speed(struct spi_device *spi, u32 speed_hz, bool dtr) { struct nuvoton_qspi *qspi = spi_controller_get_devdata(spi->controller); unsigned long clk_rate; @@ -143,6 +144,10 @@ static int nuvoton_qspi_set_speed(struct spi_device *spi, u32 speed_hz) if (!speed_hz) return -EINVAL; + /* Experimentally, when enabling DTR the frequency is cut in half */ + if (dtr) + speed_hz *= 2; + if (qspi->speed_hz == speed_hz) return 0; @@ -215,16 +220,19 @@ static int nuvoton_qspi_setup_transfer(struct spi_device *spi, u8 bpw) static int nuvoton_qspi_configure_bus(struct spi_device *spi, unsigned int buswidth, enum spi_mem_data_dir dir, - u32 speed_hz) + u32 speed_hz, bool dtr) { struct nuvoton_qspi *qspi = spi_controller_get_devdata(spi->controller); u32 ctl = 0; int ret; - ret = nuvoton_qspi_set_speed(spi, speed_hz); + ret = nuvoton_qspi_set_speed(spi, speed_hz, dtr); if (ret) return ret; + if (dtr) + ctl |= NUVOTON_QSPI_CTL_DTREN_MASK; + if (buswidth == 4) ctl |= NUVOTON_QSPI_CTL_QUADIOEN_MASK; else if (buswidth == 2) @@ -234,6 +242,7 @@ static int nuvoton_qspi_configure_bus(struct spi_device *spi, ctl |= NUVOTON_QSPI_CTL_DATDIR_MASK; nuvoton_qspi_update_bits(qspi, NUVOTON_QSPI_CTL_OFFSET, + NUVOTON_QSPI_CTL_DTREN_MASK | NUVOTON_QSPI_CTL_QUADIOEN_MASK | NUVOTON_QSPI_CTL_DUALIOEN_MASK | NUVOTON_QSPI_CTL_DATDIR_MASK, ctl); @@ -470,7 +479,7 @@ static int nuvoton_qspi_mem_exec_op(struct spi_mem *mem, cmd[i] = op->cmd.opcode >> (8 * (op->cmd.nbytes - i - 1)); ret = nuvoton_qspi_configure_bus(spi, op->cmd.buswidth, SPI_MEM_DATA_OUT, - op->max_freq); + op->max_freq, op->cmd.dtr); if (ret) goto out_deassert_cs; @@ -483,7 +492,7 @@ static int nuvoton_qspi_mem_exec_op(struct spi_mem *mem, addr[i] = op->addr.val >> (8 * (op->addr.nbytes - i - 1)); ret = nuvoton_qspi_configure_bus(spi, op->addr.buswidth, SPI_MEM_DATA_OUT, - op->max_freq); + op->max_freq, op->addr.dtr); if (ret) goto out_deassert_cs; @@ -494,7 +503,7 @@ static int nuvoton_qspi_mem_exec_op(struct spi_mem *mem, if (op->dummy.nbytes) { ret = nuvoton_qspi_configure_bus(spi, op->dummy.buswidth, SPI_MEM_DATA_OUT, - op->max_freq); + op->max_freq, op->dummy.dtr); if (ret) goto out_deassert_cs; @@ -505,7 +514,7 @@ static int nuvoton_qspi_mem_exec_op(struct spi_mem *mem, if (op->data.nbytes) { ret = nuvoton_qspi_configure_bus(spi, op->data.buswidth, op->data.dir, - op->max_freq); + op->max_freq, op->data.dtr); if (ret) goto out_deassert_cs; @@ -531,6 +540,7 @@ static const struct spi_controller_mem_ops nuvoton_qspi_mem_ops = { static const struct spi_controller_mem_caps nuvoton_qspi_mem_caps = { .per_op_freq = true, + .dtr = true, }; static int nuvoton_qspi_transfer_one(struct spi_controller *ctlr, @@ -567,7 +577,8 @@ static int nuvoton_qspi_transfer_one(struct spi_controller *ctlr, buswidth = 2; } - ret = nuvoton_qspi_configure_bus(spi, buswidth, dir, xfer->speed_hz); + ret = nuvoton_qspi_configure_bus(spi, buswidth, dir, xfer->speed_hz, + xfer->dtr_mode); if (ret) return ret; -- 2.54.0