[U-Boot] [PATCH 1/2] qspi:fsl implement AHB read
Jagan Teki
jagannadh.teki at gmail.com
Thu Jan 8 19:34:43 CET 2015
On 8 January 2015 at 17:10, Peng Fan <Peng.Fan at freescale.com> wrote:
>
> 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!
>
>
Applied to u-boot-spi/master
thanks!
--
Jagan.
More information about the U-Boot
mailing list