spi: ma35d1-qspi: Add DTR support

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 <miquel.raynal@bootlin.com>
Link: https://patch.msgid.link/20260813-perso-ma35d1-upstream-qspi-v1-4-b217b9870eb1@bootlin.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Miquel Raynal 2026-08-13 10:00:24 +02:00 committed by Mark Brown
parent 99542d244f
commit 15e9362f61
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0

View File

@ -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;