[PATCH 2/2] mtd: spi-nor: cadence-quadspi: Add support for direct access mode

Vignesh R vigneshr at ti.com
Fri Dec 22 01:48:53 PST 2017


Hi Cyrille

On Wednesday 20 December 2017 08:43 PM, Cyrille Pitchen wrote:
> Hi Vignesh,
> 
> Le 07/12/2017 à 07:38, Vignesh R a écrit :
>> Cadence QSPI controller provides direct access mode through which flash
>> can be accessed in a memory-mapped IO mode. This enables read/write to
>> flash using memcpy*() functions. This mode provides higher throughput
>> for both read/write operations when compared to current indirect mode of
>> operation.
>> 
>> This patch therefore adds support to use QSPI in direct mode. If the
>> window reserved in SoC's memory map for MMIO access is less that of
>> flash size(like on most SoCFPGA variants), then the driver falls back
>> to indirect mode of operation.
>> 
>> On TI's 66AK2G SoC, with ARM running at 600MHz and QSPI at 96MHz
>> switching to direct mode improves read throughput from 3MB/s to 8MB/s.
>> 
>> Signed-off-by: Vignesh R <vigneshr at ti.com>
>> ---

[...]

>> +static int cqspi_direct_read_execute(struct spi_nor *nor, u8 *rxbuf,
>> +                                  loff_t from_addr, const size_t len)
>> +{
>> +     struct cqspi_flash_pdata *f_pdata = nor->priv;
>> +     struct cqspi_st *cqspi = f_pdata->cqspi;
>> +     u32 reg;
>> +
>> +     reg = readl(cqspi->iobase + CQSPI_REG_CONFIG);
>> +     reg |= CQSPI_REG_CONFIG_ENB_DIR_ACC_CTRL;
>> +     writel(reg, cqspi->iobase + CQSPI_REG_CONFIG);
> 
> I guess setting the ENB_DIR_ACC_CTRL bit could be set once for all when you
> set use_direct_mode to true, couldn't it?
> 
> It may improve the read performance even more. However not expecting much
> difference for Page Program operations.
> 
> Then you could call directly call mempcy_fromio() from cqspi_read().
> Not mandatory for me, since I also like the symmetry of the 2 functions:
> cqspi_direct_read_execute() / cqspi_indirect_read_execute().
> 

Right, actually I can unconditionally set ENB_DIR_ACC_CTRL once in
cqspi_controller_init(). Indirect accesses will still be forwarded to
indirect access controller even if direct access controller is kept
enabled. So, indirect ops users are not affected.
I will make the changes in v2.

> So it's up to you :)
> 
>> +     memcpy_fromio(rxbuf, cqspi->ahb_base + from_addr, len);
>> +
>> +     return 0;
>> +}
>> +
>>  static int cqspi_write_setup(struct spi_nor *nor)
>>  {
>>        unsigned int reg;
>> @@ -671,6 +689,21 @@ static int cqspi_indirect_write_execute(struct spi_nor *nor, loff_t to_addr,
>>        return ret;
>>  }
>>  
>> +static int cqspi_direct_write_execute(struct spi_nor *nor, loff_t to_addr,
>> +                                   const u8 *txbuf, const size_t len)
>> +{
>> +     struct cqspi_flash_pdata *f_pdata = nor->priv;
>> +     struct cqspi_st *cqspi = f_pdata->cqspi;
>> +     u32 reg;
>> +
>> +     reg = readl(cqspi->iobase + CQSPI_REG_CONFIG);
>> +     reg |= CQSPI_REG_CONFIG_ENB_DIR_ACC_CTRL;
>> +     writel(reg, cqspi->iobase + CQSPI_REG_CONFIG);
> 
> Same comment here.
> 
>> +     memcpy_toio(cqspi->ahb_base + to_addr, txbuf, len);
>> +
>> +     return 0;
>> +}
>> +
>>  static void cqspi_chipselect(struct spi_nor *nor)
>>  {
>>        struct cqspi_flash_pdata *f_pdata = nor->priv;
>> @@ -891,6 +924,7 @@ static int cqspi_set_protocol(struct spi_nor *nor, const int read)
>>  static ssize_t cqspi_write(struct spi_nor *nor, loff_t to,
>>                           size_t len, const u_char *buf)
>>  {
>> +     struct cqspi_flash_pdata *f_pdata = nor->priv;
>>        int ret;
>>  
>>        ret = cqspi_set_protocol(nor, 0);
>> @@ -901,7 +935,10 @@ static ssize_t cqspi_write(struct spi_nor *nor, loff_t to,
>>        if (ret)
>>                return ret;
>>  
>> -     ret = cqspi_indirect_write_execute(nor, to, buf, len);
>> +     if (f_pdata->use_direct_mode)
>> +             ret = cqspi_direct_write_execute(nor, to, buf, len);
>> +     else
>> +             ret = cqspi_indirect_write_execute(nor, to, buf, len);
>>        if (ret)
>>                return ret;
>>  
>> @@ -911,6 +948,7 @@ static ssize_t cqspi_write(struct spi_nor *nor, loff_t to,
>>  static ssize_t cqspi_read(struct spi_nor *nor, loff_t from,
>>                          size_t len, u_char *buf)
>>  {
>> +     struct cqspi_flash_pdata *f_pdata = nor->priv;
>>        int ret;
>>  
>>        ret = cqspi_set_protocol(nor, 1);
>> @@ -921,7 +959,10 @@ static ssize_t cqspi_read(struct spi_nor *nor, loff_t from,
>>        if (ret)
>>                return ret;
>>  
>> -     ret = cqspi_indirect_read_execute(nor, buf, from, len);
>> +     if (f_pdata->use_direct_mode)
>> +             ret = cqspi_direct_read_execute(nor, buf, from, len);
>> +     else
>> +             ret = cqspi_indirect_read_execute(nor, buf, from, len);
>>        if (ret)
>>                return ret;
>>  
>> @@ -1153,6 +1194,12 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
>>                        goto err;
>>  
>>                f_pdata->registered = true;
>> +
>> +             if (mtd->size <= cqspi->ahb_size) {
>> +                     f_pdata->use_direct_mode = true;
>> +                     dev_info(nor->dev, "using direct mode for %s\n",
>> +                              mtd->name);
> 
> Please use dev_dbg() here insted of dev_info(). IMHO, this kind of output
> is not really needed by regular users.
> 

Agreed, will update that.

> Otherwise, the series looks great!
> 

Thanks for the review! Will submit v2 shortly.


-- 
Regards
Vignesh



More information about the linux-arm-kernel mailing list