On Fri, Jan 17, 2020 at 2:20 PM Simon Goldschmidt <simon.k.r.goldschm...@gmail.com> wrote: > > 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.
Tested on socfpga_gen5 (due to the platform layout, this test only says it still works in indirect mode - direct mode is not activated on socfgpa): Tested-by: Simon Goldschmidt <simon.k.r.goldschm...@gmail.com> > > 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