diff mbox series

[U-Boot,v2,2/2] spi: cadence-qspi: Add direct mode support

Message ID 20191119101304.18488-3-vigneshr@ti.com
State Superseded
Delegated to: Jagannadha Sutradharudu Teki
Headers show
Series spi: cadence-qspi: Move to spi-mem APIs | expand

Commit Message

Raghavendra, Vignesh Nov. 19, 2019, 10:13 a.m. UTC
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().

Signed-off-by: Vignesh Raghavendra <vigneshr@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(-)

Comments

Simon Goldschmidt Jan. 17, 2020, 12:51 p.m. UTC | #1
On Tue, Nov 19, 2019 at 11:12 AM Vignesh Raghavendra <vigneshr@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@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
>
Raghavendra, Vignesh Jan. 17, 2020, 1:02 p.m. UTC | #2
On 17/01/20 6:21 pm, Simon Goldschmidt wrote:
> On Tue, Nov 19, 2019 at 11:12 AM Vignesh Raghavendra <vigneshr@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@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
>>
Simon Goldschmidt Jan. 17, 2020, 1:20 p.m. UTC | #3
On Fri, Jan 17, 2020 at 2:01 PM Vignesh Raghavendra <vigneshr@ti.com> wrote:
>
>
>
> On 17/01/20 6:21 pm, Simon Goldschmidt wrote:
> > On Tue, Nov 19, 2019 at 11:12 AM Vignesh Raghavendra <vigneshr@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 <vigneshr@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
Simon Goldschmidt Jan. 17, 2020, 3:52 p.m. UTC | #4
On Fri, Jan 17, 2020 at 2:20 PM Simon Goldschmidt
<simon.k.r.goldschmidt@gmail.com> wrote:
>
> On Fri, Jan 17, 2020 at 2:01 PM Vignesh Raghavendra <vigneshr@ti.com> wrote:
> >
> >
> >
> > On 17/01/20 6:21 pm, Simon Goldschmidt wrote:
> > > On Tue, Nov 19, 2019 at 11:12 AM Vignesh Raghavendra <vigneshr@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.goldschmidt@gmail.com>

>
> Regards,
> Simon
>
> >
> > Regards
> > Vignesh
> >
> > > Regards,
> > > Simon
> > >
> > >>
> > >> Signed-off-by: Vignesh Raghavendra <vigneshr@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
Jagan Teki Jan. 26, 2020, 4:43 p.m. UTC | #5
On Fri, Jan 17, 2020 at 9:23 PM Simon Goldschmidt
<simon.k.r.goldschmidt@gmail.com> wrote:
>
> On Fri, Jan 17, 2020 at 2:20 PM Simon Goldschmidt
> <simon.k.r.goldschmidt@gmail.com> wrote:
> >
> > On Fri, Jan 17, 2020 at 2:01 PM Vignesh Raghavendra <vigneshr@ti.com> wrote:
> > >
> > >
> > >
> > > On 17/01/20 6:21 pm, Simon Goldschmidt wrote:
> > > > On Tue, Nov 19, 2019 at 11:12 AM Vignesh Raghavendra <vigneshr@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.goldschmidt@gmail.com>
>
> >
> > Regards,
> > Simon
> >
> > >
> > > Regards
> > > Vignesh
> > >
> > > > Regards,
> > > > Simon
> > > >
> > > >>
> > > >> Signed-off-by: Vignesh Raghavendra <vigneshr@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
> > > >>
> > >

Not apply directly, look like rebase require on top of master?

Jagan.
Raghavendra, Vignesh Jan. 27, 2020, 5:12 a.m. UTC | #6
Hi Jagan,

On 26/01/20 10:13 pm, Jagan Teki wrote:
> On Fri, Jan 17, 2020 at 9:23 PM Simon Goldschmidt
> <simon.k.r.goldschmidt@gmail.com> wrote:
>>
>> On Fri, Jan 17, 2020 at 2:20 PM Simon Goldschmidt
>> <simon.k.r.goldschmidt@gmail.com> wrote:
>>>
>>> On Fri, Jan 17, 2020 at 2:01 PM Vignesh Raghavendra <vigneshr@ti.com> wrote:
[...]

>>>>>>  void cadence_qspi_apb_enter_xip(void *reg_base, char xip_dummy)
>>>>>>  {
>>>>>>         unsigned int reg;
>>>>>> --
>>>>>> 2.24.0
>>>>>>
>>>>
> 
> Not apply directly, look like rebase require on top of master?
> 

I have resent the series rebasing on top of latest master:
http://patchwork.ozlabs.org/project/uboot/list/?series=155385
Jagan Teki Jan. 27, 2020, 7:13 a.m. UTC | #7
On Mon, Jan 27, 2020 at 10:42 AM Vignesh Raghavendra <vigneshr@ti.com> wrote:
>
> Hi Jagan,
>
> On 26/01/20 10:13 pm, Jagan Teki wrote:
> > On Fri, Jan 17, 2020 at 9:23 PM Simon Goldschmidt
> > <simon.k.r.goldschmidt@gmail.com> wrote:
> >>
> >> On Fri, Jan 17, 2020 at 2:20 PM Simon Goldschmidt
> >> <simon.k.r.goldschmidt@gmail.com> wrote:
> >>>
> >>> On Fri, Jan 17, 2020 at 2:01 PM Vignesh Raghavendra <vigneshr@ti.com> wrote:
> [...]
>
> >>>>>>  void cadence_qspi_apb_enter_xip(void *reg_base, char xip_dummy)
> >>>>>>  {
> >>>>>>         unsigned int reg;
> >>>>>> --
> >>>>>> 2.24.0
> >>>>>>
> >>>>
> >
> > Not apply directly, look like rebase require on top of master?
> >
>
> I have resent the series rebasing on top of latest master:
> http://patchwork.ozlabs.org/project/uboot/list/?series=155385

Thanks.

Applied to u-boot-spi/master
diff mbox series

Patch

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;