[PATCH v2 2/2] spi: cadence-qspi: Add direct mode support

Simon Goldschmidt simon.k.r.goldschmidt at gmail.com
Fri Jan 17 13:51:24 CET 2020


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.

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
>


More information about the U-Boot mailing list