mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 13:14:02 +02:00
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:
parent
99542d244f
commit
15e9362f61
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user