[PATCH v2 2/2] spi: cadence-qspi: Add direct mode support
Vignesh Raghavendra
vigneshr at ti.com
Fri Jan 17 14:02:12 CET 2020
On 17/01/20 6:21 pm, Simon Goldschmidt wrote:
> On Tue, Nov 19, 2019 at 11:12 AM Vignesh Raghavendra <vigneshr at 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/
Regards
Vignesh
> Regards,
> Simon
>
>>
>> Signed-off-by: Vignesh Raghavendra <vigneshr at 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
More information about the U-Boot
mailing list