[U-Boot] [PATCH 1/2] qspi:fsl implement AHB read
Peng Fan
Peng.Fan at freescale.com
Thu Jan 8 12:40:29 CET 2015
On 1/8/2015 7:21 PM, Jagan Teki wrote:
> On 8 January 2015 at 15:48, Peng Fan <Peng.Fan at freescale.com> wrote:
>> Hi, Jagan
>>
>> On 1/8/2015 2:20 PM, Jagan Teki wrote:
>>> On 8 January 2015 at 08:10, Peng Fan <Peng.Fan at freescale.com> wrote:
>>>> The QSPI controller in i.MX 6SoloX and Vybrid supports reading data using
>>>> IP register and AHB bus.
>>>>
>>>> The original driver only supports reading data from IP interface. The IC
>>>> team suggests to use AHB read which is faster then IP read. Using AHB
>>>> read,
>>>> we can directly memcpy, a "missed" access to the buffer will cause the
>>>> controller to clear the buffer and use the SEQID stored in bfgencr
>>>> register
>>>> to initiate a read from flash device.
>>> So for the read connections - controller is connected through IP and
>>> AHB interface
>>> is it? and I'm thinking these two are bus protocols which can use any
>>> peripheral unlike
>>> qspi.
>>
>> Yeah. fsl qspi controller is connected through IP and AHB interface.
>> register access through IP interface, Data access can use IP interface or
>> AHB interface. There is a memory mapped region for AHB data read. If want
>> to use AHB data read for QSPI, the controller should be configured by IP
>> interface, and then can use memcpy to read data. This patch adds the
>> configuration for using QSPI AHB read, this configuration is dedicated for
>> qspi.
> Yes - I understand.
>
> I'm thinking this ahb is a generic but not only specific to qspi the
> read of this
> interface should be generic somewhere in arch code so-that fsl_qspi will call
> those routines on based on the need. - does it make sense?
The AHB read function is just memcpy. This original code use
"qspi_op_read" to read data from IP interface. In this patch, if
configured CONFIG_FSL_QSPI_AHB_READ, use qsp_ahb_read. This function is
very simple, as following:
+mcr_reg = qspi_read32(®s->mcr);
+
+qspi_write32(®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+
+/* Read out the data directly from the AHB buffer. */
+memcpy(rxbuf, (u8 *)(q->amba_base + q->sf_addr), len);
+
+qspi_write32(®s->mcr, mcr_reg);
It's just a wrapper function to call memcpy and save/restore qspi mcr
register, nothing else. I think it's not needed to wrap memcpy and move
it to arch code, since it is simple and contains qspi register save and
restore.
>>>> Since AHB bus is 64 bit width, we can not set MCR register using 32bit.
>>>> In
>>>> order to minimize code change, redefine QSPI_MCR_END_CFD_LE to 64bit
>>>> Little
>>>> endian but not 32bit Little endia.
>>>>
>>>> Introduce a new configuration option CONFIG_SYS_FSL_QSPI_AHB. If want to
>>>> use AHB read, just define CONFIG_SYS_FSL_QSPI_AHB. If not, just ignore
>>>> it.
>>>> Actually if Vybrid is migrated to use AHB read, this option can be
>>>> removed and
>>>> IP read function can be discared. The reason to introduce this option
>>>> is that only i.MX SOC is tested in my side, no Vybrid platform for me.
>>> So, where did you define?
>>
>> The configuration is defined in board header file in mx6sxsabresd.h, using
>> #define CONFIG_SYS_FSL_QSPI_AHB.
> Yes I saw in 2/2
>
>>
>>>> In spi_setup_slave, the original piece code to set AHB is deleted, since
>>>> Vybrid platform does not use this to intiate AHB read. Instead, add
>>>> qspi_init_ahb_read function if defined CONFIG_SYS_FSL_QSPI_AHB.
>>>>
>>>> Signed-off-by: Peng Fan <Peng.Fan at freescale.com>
>>>> ---
>>>> drivers/spi/fsl_qspi.c | 137
>>>> +++++++++++++++++++++++++++++++++++++++++++++----
>>>> drivers/spi/fsl_qspi.h | 15 ++++++
>>>> 2 files changed, 142 insertions(+), 10 deletions(-)
>>>>
>>>> diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
>>>> index ad4f4ce..5e0b069 100644
>>>> --- a/drivers/spi/fsl_qspi.c
>>>> +++ b/drivers/spi/fsl_qspi.c
>>>> @@ -263,6 +263,110 @@ static void qspi_set_lut(struct fsl_qspi *qspi)
>>>> qspi_write32(®s->lckcr, QSPI_LCKCR_LOCK);
>>>> }
>>>>
>>>> +#if defined(CONFIG_SYS_FSL_QSPI_AHB)
>>>> +/*
>>>> + * If we have changed the content of the flash by writing or erasing,
>>>> + * we need to invalidate the AHB buffer. If we do not do so, we may read
>>>> out
>>>> + * the wrong data. The spec tells us reset the AHB domain and Serial
>>>> Flash
>>>> + * domain at the same time.
>>>> + */
>>>> +static inline void qspi_ahb_invalid(struct fsl_qspi *q)
>>>> +{
>>>> + struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)q->reg_base;
>>>> + u32 reg;
>>>> +
>>>> + reg = qspi_read32(®s->mcr);
>>>> + reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK;
>>>> + qspi_write32(®s->mcr, reg);
>>>> +
>>>> + /*
>>>> + * The minimum delay : 1 AHB + 2 SFCK clocks.
>>>> + * Delay 1 us is enough.
>>>> + */
>>>> + udelay(1);
>>>> +
>>>> + reg &= ~(QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK);
>>>> + qspi_write32(®s->mcr, reg);
>>>> +}
>>>> +
>>>> +/* Read out the data from the AHB buffer. */
>>>> +static inline void qspi_ahb_read(struct fsl_qspi *q, u8 *rxbuf, int len)
>>>> +{
>>>> + struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)q->reg_base;
>>>> + u32 mcr_reg;
>>>> +
>>>> + mcr_reg = qspi_read32(®s->mcr);
>>>> +
>>>> + qspi_write32(®s->mcr, QSPI_MCR_CLR_RXF_MASK |
>>>> QSPI_MCR_CLR_TXF_MASK |
>>>> + QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
>>>> +
>>>> + /* Read out the data directly from the AHB buffer. */
>>>> + memcpy(rxbuf, (u8 *)(q->amba_base + q->sf_addr), len);
>>>> +
>>>> + qspi_write32(®s->mcr, mcr_reg);
>>>> +}
>>>> +
>>>> +static void qspi_enable_ddr_mode(struct fsl_qspi_regs *regs)
>>>> +{
>>>> + u32 reg, reg2;
>>>> +
>>>> + reg = qspi_read32(®s->mcr);
>>>> + /* Disable the module */
>>>> + qspi_write32(®s->mcr, reg | QSPI_MCR_MDIS_MASK);
>>>> +
>>>> + /* Set the Sampling Register for DDR */
>>>> + reg2 = qspi_read32(®s->smpr);
>>>> + reg2 &= ~QSPI_SMPR_DDRSMP_MASK;
>>>> + reg2 |= (2 << QSPI_SMPR_DDRSMP_SHIFT);
>>>> + qspi_write32(®s->smpr, reg2);
>>>> +
>>>> + /* Enable the module again (enable the DDR too) */
>>>> + reg |= QSPI_MCR_DDR_EN_MASK;
>>>> + /* Enable bit 29 for imx6sx */
>>>> + reg |= (1 << 29);
>>>> +
>>>> + qspi_write32(®s->mcr, reg);
>>>> +}
>>>> +
>>>> +/*
>>>> + * There are two different ways to read out the data from the flash:
>>>> + * the "IP Command Read" and the "AHB Command Read".
>>>> + *
>>>> + * The IC guy suggests we use the "AHB Command Read" which is faster
>>>> + * then the "IP Command Read". (What's more is that there is a bug in
>>>> + * the "IP Command Read" in the Vybrid.)
>>>> + *
>>>> + * After we set up the registers for the "AHB Command Read", we can use
>>>> + * the memcpy to read the data directly. A "missed" access to the buffer
>>>> + * causes the controller to clear the buffer, and use the sequence
>>>> pointed
>>>> + * by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash.
>>>> + */
>>>> +static void qspi_init_ahb_read(struct fsl_qspi_regs *regs)
>>>> +{
>>>> + /* AHB configuration for access buffer 0/1/2 .*/
>>>> + qspi_write32(®s->buf0cr, QSPI_BUFXCR_INVALID_MSTRID);
>>>> + qspi_write32(®s->buf1cr, QSPI_BUFXCR_INVALID_MSTRID);
>>>> + qspi_write32(®s->buf2cr, QSPI_BUFXCR_INVALID_MSTRID);
>>>> + qspi_write32(®s->buf3cr, QSPI_BUF3CR_ALLMST_MASK |
>>>> + (0x80 << QSPI_BUF3CR_ADATSZ_SHIFT));
>>>> +
>>>> + /* We only use the buffer3 */
>>>> + qspi_write32(®s->buf0ind, 0);
>>>> + qspi_write32(®s->buf1ind, 0);
>>>> + qspi_write32(®s->buf2ind, 0);
>>>> +
>>>> + /*
>>>> + * Set the default lut sequence for AHB Read.
>>>> + * Parallel mode is disabled.
>>>> + */
>>>> + qspi_write32(®s->bfgencr,
>>>> + SEQID_FAST_READ << QSPI_BFGENCR_SEQID_SHIFT);
>>>> +
>>>> + /*Enable DDR Mode*/
>>>> + qspi_enable_ddr_mode(regs);
>>>> +}
>>>> +#endif
>>>> +
>>>> void spi_init()
>>>> {
>>>> /* do nothing */
>>>> @@ -273,8 +377,8 @@ struct spi_slave *spi_setup_slave(unsigned int bus,
>>>> unsigned int cs,
>>>> {
>>>> struct fsl_qspi *qspi;
>>>> struct fsl_qspi_regs *regs;
>>>> - u32 reg_val, smpr_val;
>>>> - u32 total_size, seq_id;
>>>> + u32 smpr_val;
>>>> + u32 total_size;
>>>>
>>>> if (bus >= ARRAY_SIZE(spi_bases))
>>>> return NULL;
>>>> @@ -329,13 +433,9 @@ struct spi_slave *spi_setup_slave(unsigned int bus,
>>>> unsigned int cs,
>>>> qspi_write32(®s->smpr, smpr_val);
>>>> qspi_write32(®s->mcr, QSPI_MCR_RESERVED_MASK);
>>>>
>>>> - seq_id = 0;
>>>> - reg_val = qspi_read32(®s->bfgencr);
>>>> - reg_val &= ~QSPI_BFGENCR_SEQID_MASK;
>>>> - reg_val |= (seq_id << QSPI_BFGENCR_SEQID_SHIFT);
>>>> - reg_val &= ~QSPI_BFGENCR_PAR_EN_MASK;
>>>> - qspi_write32(®s->bfgencr, reg_val);
>>>> -
>>>> +#ifdef CONFIG_SYS_FSL_QSPI_AHB
>>>> + qspi_init_ahb_read(regs);
>>>> +#endif
>>>> return &qspi->slave;
>>>> }
>>>>
>>>> @@ -426,6 +526,8 @@ static void qspi_op_rdid(struct fsl_qspi *qspi, u32
>>>> *rxbuf, u32 len)
>>>> qspi_write32(®s->mcr, mcr_reg);
>>>> }
>>>>
>>>> +#ifndef CONFIG_SYS_FSL_QSPI_AHB
>>>> +/* If not use AHB read, read data from ip interface */
>>>> static void qspi_op_read(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
>>>> {
>>>> struct fsl_qspi_regs *regs = (struct fsl_qspi_regs
>>>> *)qspi->reg_base;
>>>> @@ -469,6 +571,7 @@ static void qspi_op_read(struct fsl_qspi *qspi, u32
>>>> *rxbuf, u32 len)
>>>>
>>>> qspi_write32(®s->mcr, mcr_reg);
>>>> }
>>>> +#endif
>>>>
>>>> static void qspi_op_write(struct fsl_qspi *qspi, u8 *txbuf, u32 len)
>>>> {
>>>> @@ -643,8 +746,13 @@ int spi_xfer(struct spi_slave *slave, unsigned int
>>>> bitlen,
>>>> }
>>>>
>>>> if (din) {
>>>> - if (qspi->cur_seqid == QSPI_CMD_FAST_READ)
>>>> + if (qspi->cur_seqid == QSPI_CMD_FAST_READ) {
>>>> +#ifdef CONFIG_SYS_FSL_QSPI_AHB
>>>> + qspi_ahb_read(qspi, din, bytes);
>>>> +#else
>>>> qspi_op_read(qspi, din, bytes);
>>>> +#endif
>>>> + }
>>>> else if (qspi->cur_seqid == QSPI_CMD_RDID)
>>>> qspi_op_rdid(qspi, din, bytes);
>>>> else if (qspi->cur_seqid == QSPI_CMD_RDSR)
>>>> @@ -658,6 +766,15 @@ int spi_xfer(struct spi_slave *slave, unsigned int
>>>> bitlen,
>>>> #endif
>>>> }
>>>>
>>>> +#ifdef CONFIG_SYS_FSL_QSPI_AHB
>>>> + if ((qspi->cur_seqid == QSPI_CMD_SE) ||
>>>> + (qspi->cur_seqid == QSPI_CMD_PP) ||
>>>> + (qspi->cur_seqid == QSPI_CMD_BE_4K) ||
>>>> + (qspi->cur_seqid == QSPI_CMD_WREAR) ||
>>>> + (qspi->cur_seqid == QSPI_CMD_BRWR))
>>>> + qspi_ahb_invalid(qspi);
>>>> +#endif
>>>> +
>>>> return 0;
>>>> }
>>>>
>>>> diff --git a/drivers/spi/fsl_qspi.h b/drivers/spi/fsl_qspi.h
>>>> index db400e6..6cb3610 100644
>>>> --- a/drivers/spi/fsl_qspi.h
>>>> +++ b/drivers/spi/fsl_qspi.h
>>>> @@ -58,7 +58,12 @@ struct fsl_qspi_regs {
>>>>
>>>> #define QSPI_MCR_END_CFD_SHIFT 2
>>>> #define QSPI_MCR_END_CFD_MASK (3 << QSPI_MCR_END_CFD_SHIFT)
>>>> +#ifdef CONFIG_SYS_FSL_QSPI_AHB
>>>> +/* AHB needs 64bit operation */
>>>> +#define QSPI_MCR_END_CFD_LE (3 << QSPI_MCR_END_CFD_SHIFT)
>>>> +#else
>>>> #define QSPI_MCR_END_CFD_LE (1 << QSPI_MCR_END_CFD_SHIFT)
>>>> +#endif
>>>> #define QSPI_MCR_DDR_EN_SHIFT 7
>>>> #define QSPI_MCR_DDR_EN_MASK (1 << QSPI_MCR_DDR_EN_SHIFT)
>>>> #define QSPI_MCR_CLR_RXF_SHIFT 10
>>>> @@ -69,6 +74,10 @@ struct fsl_qspi_regs {
>>>> #define QSPI_MCR_MDIS_MASK (1 << QSPI_MCR_MDIS_SHIFT)
>>>> #define QSPI_MCR_RESERVED_SHIFT 16
>>>> #define QSPI_MCR_RESERVED_MASK (0xf << QSPI_MCR_RESERVED_SHIFT)
>>>> +#define QSPI_MCR_SWRSTHD_SHIFT 1
>>>> +#define QSPI_MCR_SWRSTHD_MASK (1 << QSPI_MCR_SWRSTHD_SHIFT)
>>>> +#define QSPI_MCR_SWRSTSD_SHIFT 0
>>>> +#define QSPI_MCR_SWRSTSD_MASK (1 << QSPI_MCR_SWRSTSD_SHIFT)
>>>>
>>>> #define QSPI_SMPR_HSENA_SHIFT 0
>>>> #define QSPI_SMPR_HSENA_MASK (1 << QSPI_SMPR_HSENA_SHIFT)
>>>> @@ -79,6 +88,12 @@ struct fsl_qspi_regs {
>>>> #define QSPI_SMPR_DDRSMP_SHIFT 16
>>>> #define QSPI_SMPR_DDRSMP_MASK (7 << QSPI_SMPR_DDRSMP_SHIFT)
>>>>
>>>> +#define QSPI_BUFXCR_INVALID_MSTRID 0xe
>>>> +#define QSPI_BUF3CR_ALLMST_SHIFT 31
>>>> +#define QSPI_BUF3CR_ALLMST_MASK (1 <<
>>>> QSPI_BUF3CR_ALLMST_SHIFT)
>>>> +#define QSPI_BUF3CR_ADATSZ_SHIFT 8
>>>> +#define QSPI_BUF3CR_ADATSZ_MASK (0xFF <<
>>>> QSPI_BUF3CR_ADATSZ_SHIFT)
>>>> +
>>>> #define QSPI_BFGENCR_SEQID_SHIFT 12
>>>> #define QSPI_BFGENCR_SEQID_MASK (0xf <<
>>>> QSPI_BFGENCR_SEQID_SHIFT)
>>>> #define QSPI_BFGENCR_PAR_EN_SHIFT 16
>>>> --
>>>> 1.8.4
> thanks!
More information about the U-Boot
mailing list