On Fri, Jan 17, 2020 at 2:01 PM Vignesh Raghavendra <vigne...@ti.com> wrote: > > > > On 17/01/20 6:21 pm, Simon Goldschmidt wrote: > > On Tue, Nov 19, 2019 at 11:12 AM Vignesh Raghavendra <vigne...@ti.com> > > wrote: > >> > >> Add support for Direct Access Controller mode of Cadence QSPI. This > >> allows MMIO access to SPI NOR flash providing better read performance. > >> Direct mode is only exercised if AHB window size is greater than 8MB. > >> Support for flash address remapping is also not supported at the moment > >> and can be added in future. > >> > >> For better performance, driver uses DMA to copy data from flash in > >> direct mode using dma_memcpy(). > > > > This v2 doesn't compile for socfpa as dma_memcpy() isn't available. Since > > direct > > mode isn't used on that platform (due to your 8MB check), dma_memcpy() is > > not > > required, but still it doesn't link as this is a runtime decision. > > > > Could you try with latest master and make sure it has [1] and [2] > applied? Thanks! > > [1]http://patchwork.ozlabs.org/patch/1195557/ > [2]http://patchwork.ozlabs.org/patch/1195556/
Right, Tom merged that yesterday. Compiles now, sorry for the noise. Regards, Simon > > Regards > Vignesh > > > Regards, > > Simon > > > >> > >> Signed-off-by: Vignesh Raghavendra <vigne...@ti.com> > >> --- > >> v2: Add DMA support and update commit message > >> > >> drivers/spi/cadence_qspi.c | 40 ++++++++++++--------- > >> drivers/spi/cadence_qspi.h | 19 +++++----- > >> drivers/spi/cadence_qspi_apb.c | 65 +++++++++++++++++++++++++++++----- > >> 3 files changed, 91 insertions(+), 33 deletions(-) > >> > >> diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c > >> index 673a2e9a6c4c..6c98cbf39ae4 100644 > >> --- a/drivers/spi/cadence_qspi.c > >> +++ b/drivers/spi/cadence_qspi.c > >> @@ -12,12 +12,13 @@ > >> #include <spi.h> > >> #include <spi-mem.h> > >> #include <linux/errno.h> > >> +#include <linux/sizes.h> > >> #include "cadence_qspi.h" > >> > >> #define CQSPI_STIG_READ 0 > >> #define CQSPI_STIG_WRITE 1 > >> -#define CQSPI_INDIRECT_READ 2 > >> -#define CQSPI_INDIRECT_WRITE 3 > >> +#define CQSPI_READ 2 > >> +#define CQSPI_WRITE 3 > >> > >> static int cadence_spi_write_speed(struct udevice *bus, uint hz) > >> { > >> @@ -189,6 +190,7 @@ static int cadence_spi_remove(struct udevice *dev) > >> > >> static int cadence_spi_set_mode(struct udevice *bus, uint mode) > >> { > >> + struct cadence_spi_platdata *plat = bus->platdata; > >> struct cadence_spi_priv *priv = dev_get_priv(bus); > >> > >> /* Disable QSPI */ > >> @@ -197,6 +199,10 @@ static int cadence_spi_set_mode(struct udevice *bus, > >> uint mode) > >> /* Set SPI mode */ > >> cadence_qspi_apb_set_clk_mode(priv->regbase, mode); > >> > >> + /* Enable Direct Access Controller */ > >> + if (plat->use_dac_mode) > >> + cadence_qspi_apb_dac_mode_enable(priv->regbase); > >> + > >> /* Enable QSPI */ > >> cadence_qspi_apb_controller_enable(priv->regbase); > >> > >> @@ -221,12 +227,12 @@ static int cadence_spi_mem_exec_op(struct spi_slave > >> *spi, > >> if (!op->addr.nbytes) > >> mode = CQSPI_STIG_READ; > >> else > >> - mode = CQSPI_INDIRECT_READ; > >> + mode = CQSPI_READ; > >> } else { > >> if (!op->addr.nbytes || !op->data.buf.out) > >> mode = CQSPI_STIG_WRITE; > >> else > >> - mode = CQSPI_INDIRECT_WRITE; > >> + mode = CQSPI_WRITE; > >> } > >> > >> switch (mode) { > >> @@ -236,19 +242,15 @@ static int cadence_spi_mem_exec_op(struct spi_slave > >> *spi, > >> case CQSPI_STIG_WRITE: > >> err = cadence_qspi_apb_command_write(base, op); > >> break; > >> - case CQSPI_INDIRECT_READ: > >> - err = cadence_qspi_apb_indirect_read_setup(plat, op); > >> - if (!err) { > >> - err = cadence_qspi_apb_indirect_read_execute > >> - (plat, op->data.nbytes, op->data.buf.in); > >> - } > >> + case CQSPI_READ: > >> + err = cadence_qspi_apb_read_setup(plat, op); > >> + if (!err) > >> + err = cadence_qspi_apb_read_execute(plat, op); > >> break; > >> - case CQSPI_INDIRECT_WRITE: > >> - err = cadence_qspi_apb_indirect_write_setup(plat, op); > >> - if (!err) { > >> - err = cadence_qspi_apb_indirect_write_execute > >> - (plat, op->data.nbytes, op->data.buf.out); > >> - } > >> + case CQSPI_WRITE: > >> + err = cadence_qspi_apb_write_setup(plat, op); > >> + if (!err) > >> + err = cadence_qspi_apb_write_execute(plat, op); > >> break; > >> default: > >> err = -1; > >> @@ -264,13 +266,17 @@ static int cadence_spi_ofdata_to_platdata(struct > >> udevice *bus) > >> ofnode subnode; > >> > >> plat->regbase = (void *)devfdt_get_addr_index(bus, 0); > >> - plat->ahbbase = (void *)devfdt_get_addr_index(bus, 1); > >> + plat->ahbbase = (void *)devfdt_get_addr_size_index(bus, 1, > >> + &plat->ahbsize); > >> plat->is_decoded_cs = dev_read_bool(bus, "cdns,is-decoded-cs"); > >> plat->fifo_depth = dev_read_u32_default(bus, "cdns,fifo-depth", > >> 128); > >> plat->fifo_width = dev_read_u32_default(bus, "cdns,fifo-width", 4); > >> plat->trigger_address = dev_read_u32_default(bus, > >> > >> "cdns,trigger-address", > >> 0); > >> + /* Use DAC mode only when MMIO window is at least 8M wide */ > >> + if (plat->ahbsize >= SZ_8M) > >> + plat->use_dac_mode = true; > >> > >> /* All other paramters are embedded in the child node */ > >> subnode = dev_read_first_subnode(bus); > >> diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h > >> index e655b027d788..619f0bed8efd 100644 > >> --- a/drivers/spi/cadence_qspi.h > >> +++ b/drivers/spi/cadence_qspi.h > >> @@ -23,6 +23,8 @@ struct cadence_spi_platdata { > >> u32 fifo_depth; > >> u32 fifo_width; > >> u32 trigger_address; > >> + fdt_addr_t ahbsize; > >> + bool use_dac_mode; > >> > >> /* Flash parameters */ > >> u32 page_size; > >> @@ -52,20 +54,21 @@ struct cadence_spi_priv { > >> void cadence_qspi_apb_controller_init(struct cadence_spi_platdata *plat); > >> void cadence_qspi_apb_controller_enable(void *reg_base_addr); > >> void cadence_qspi_apb_controller_disable(void *reg_base_addr); > >> +void cadence_qspi_apb_dac_mode_enable(void *reg_base); > >> > >> int cadence_qspi_apb_command_read(void *reg_base_addr, > >> const struct spi_mem_op *op); > >> int cadence_qspi_apb_command_write(void *reg_base_addr, > >> const struct spi_mem_op *op); > >> > >> -int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata > >> *plat, > >> - const struct spi_mem_op *op); > >> -int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata > >> *plat, > >> - unsigned int rxlen, u8 *rxbuf); > >> -int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata > >> *plat, > >> - const struct spi_mem_op *op); > >> -int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata > >> *plat, > >> - unsigned int txlen, const u8 *txbuf); > >> +int cadence_qspi_apb_read_setup(struct cadence_spi_platdata *plat, > >> + const struct spi_mem_op *op); > >> +int cadence_qspi_apb_read_execute(struct cadence_spi_platdata *plat, > >> + const struct spi_mem_op *op); > >> +int cadence_qspi_apb_write_setup(struct cadence_spi_platdata *plat, > >> + const struct spi_mem_op *op); > >> +int cadence_qspi_apb_write_execute(struct cadence_spi_platdata *plat, > >> + const struct spi_mem_op *op); > >> > >> void cadence_qspi_apb_chipselect(void *reg_base, > >> unsigned int chip_select, unsigned int decoder_enable); > >> diff --git a/drivers/spi/cadence_qspi_apb.c > >> b/drivers/spi/cadence_qspi_apb.c > >> index 8dd0495dfcf4..a0e14f93e020 100644 > >> --- a/drivers/spi/cadence_qspi_apb.c > >> +++ b/drivers/spi/cadence_qspi_apb.c > >> @@ -27,6 +27,7 @@ > >> > >> #include <common.h> > >> #include <asm/io.h> > >> +#include <dma.h> > >> #include <linux/errno.h> > >> #include <wait_bit.h> > >> #include <spi.h> > >> @@ -189,6 +190,15 @@ void cadence_qspi_apb_controller_disable(void > >> *reg_base) > >> writel(reg, reg_base + CQSPI_REG_CONFIG); > >> } > >> > >> +void cadence_qspi_apb_dac_mode_enable(void *reg_base) > >> +{ > >> + unsigned int reg; > >> + > >> + reg = readl(reg_base + CQSPI_REG_CONFIG); > >> + reg |= CQSPI_REG_CONFIG_DIRECT; > >> + writel(reg, reg_base + CQSPI_REG_CONFIG); > >> +} > >> + > >> /* Return 1 if idle, otherwise return 0 (busy). */ > >> static unsigned int cadence_qspi_wait_idle(void *reg_base) > >> { > >> @@ -512,8 +522,8 @@ int cadence_qspi_apb_command_write(void *reg_base, > >> const struct spi_mem_op *op) > >> } > >> > >> /* Opcode + Address (3/4 bytes) + dummy bytes (0-4 bytes) */ > >> -int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata > >> *plat, > >> - const struct spi_mem_op *op) > >> +int cadence_qspi_apb_read_setup(struct cadence_spi_platdata *plat, > >> + const struct spi_mem_op *op) > >> { > >> unsigned int reg; > >> unsigned int rd_reg; > >> @@ -577,8 +587,9 @@ static int cadence_qspi_wait_for_data(struct > >> cadence_spi_platdata *plat) > >> return -ETIMEDOUT; > >> } > >> > >> -int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata > >> *plat, > >> - unsigned int n_rx, u8 *rxbuf) > >> +static int > >> +cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat, > >> + unsigned int n_rx, u8 *rxbuf) > >> { > >> unsigned int remaining = n_rx; > >> unsigned int bytes_to_read = 0; > >> @@ -639,9 +650,29 @@ failrd: > >> return ret; > >> } > >> > >> +int cadence_qspi_apb_read_execute(struct cadence_spi_platdata *plat, > >> + const struct spi_mem_op *op) > >> +{ > >> + u32 from = op->addr.val; > >> + void *buf = op->data.buf.in; > >> + size_t len = op->data.nbytes; > >> + > >> + if (plat->use_dac_mode && (from + len < plat->ahbsize)) { > >> + if (len < 256 || > >> + dma_memcpy(buf, plat->ahbbase + from, len) < 0) { > >> + memcpy_fromio(buf, plat->ahbbase + from, len); > >> + } > >> + if (!cadence_qspi_wait_idle(plat->regbase)) > >> + return -EIO; > >> + return 0; > >> + } > >> + > >> + return cadence_qspi_apb_indirect_read_execute(plat, len, buf); > >> +} > >> + > >> /* Opcode + Address (3/4 bytes) */ > >> -int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata > >> *plat, > >> - const struct spi_mem_op *op) > >> +int cadence_qspi_apb_write_setup(struct cadence_spi_platdata *plat, > >> + const struct spi_mem_op *op) > >> { > >> unsigned int reg; > >> > >> @@ -662,8 +693,9 @@ int cadence_qspi_apb_indirect_write_setup(struct > >> cadence_spi_platdata *plat, > >> return 0; > >> } > >> > >> -int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata > >> *plat, > >> - unsigned int n_tx, const u8 *txbuf) > >> +static int > >> +cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat, > >> + unsigned int n_tx, const u8 *txbuf) > >> { > >> unsigned int page_size = plat->page_size; > >> unsigned int remaining = n_tx; > >> @@ -735,6 +767,23 @@ failwr: > >> return ret; > >> } > >> > >> +int cadence_qspi_apb_write_execute(struct cadence_spi_platdata *plat, > >> + const struct spi_mem_op *op) > >> +{ > >> + u32 to = op->addr.val; > >> + const void *buf = op->data.buf.out; > >> + size_t len = op->data.nbytes; > >> + > >> + if (plat->use_dac_mode && (to + len < plat->ahbsize)) { > >> + memcpy_toio(plat->ahbbase + to, buf, len); > >> + if (!cadence_qspi_wait_idle(plat->regbase)) > >> + return -EIO; > >> + return 0; > >> + } > >> + > >> + return cadence_qspi_apb_indirect_write_execute(plat, len, buf); > >> +} > >> + > >> void cadence_qspi_apb_enter_xip(void *reg_base, char xip_dummy) > >> { > >> unsigned int reg; > >> -- > >> 2.24.0 > >> > > -- > Regards > Vignesh