[U-Boot] [PATCH 1/2] qspi:fsl implement AHB read
Jagan Teki
jagannadh.teki at gmail.com
Thu Jan 8 12:21:57 CET 2015
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?
>
>>
>>> 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!
--
Jagan.
More information about the U-Boot
mailing list