[U-Boot] [RFC PATCH] dm:spi:fsl_qspi add DM support

Peng Fan B51431 at freescale.com
Mon Jan 19 08:48:04 CET 2015


Hi Jagan,

On 1/19/2015 2:47 PM, Jagan Teki wrote:
> Hi Peng,
>
> On 17 January 2015 at 11:29, Peng Fan <Peng.Fan at freescale.com> wrote:
>> Hi Simon ,Jagan
>>
>> This patch is based on git://git.denx.de/u-boot-spi.git master branch,
>> since some fsl_qspi's new feature is still in this git repo and have
>> not been merged to mainline.
>> I saw Simon sent out a new patch that remove the per_child_auto_alloc_size
>> from the platforms' driver code and move it to spi uclass driver. In
>> this patch I do not remove it, since this is a RFC version, and Jagan's
>> spi git repo still has it. I can remove it in formal version if needed.
>> Please take your time to review and comment this patch.
> Appreciate for your work on adding dm on fsl-qspi.
> But, I'm sending v2 RFC for spi-nor stuff where your driver be part of that
> instead of drivers/spi - I'm planning to send it in this MW.
ok.
> My plan is we review this dm stuff but in anyway if the new spi-nor is been
> merged you'r driver needs to move on spi-nor with relevant changes.
>
> Comments?

ok. I can do some work to make the driver match the new spi-nor stuff. 
If you have anytime, you can review the dm stuff.
There are small issues about register configuration in this patch, and I 
am fixing it in my side. Anyway, I'll wait your v2 patch, and based on 
your spi-nor stuff to add the dm stuff for fsl_qspi driver.

>> This patch adds DM support for fsl_qspi driver, the DM part needs
>> device tree support.
>>
>> Partial of the original driver code is reused, such as the AHB part,
>> the LUT initialization and etc. The driver now supports new DM and original
>> driver by define "CONFIG_DM_SPI". Until device tree is integrated, the
>> original part can be discarded.
>>
>> The driver code file is now as following:
>>   "
>>
>>   Common code that needs both by DM or original driver code.
>>
>>   #if defined(CONFIG_DM_SPI)
>>
>>   DM part
>>
>>   #else
>>
>>   Original driver code
>>
>>   #endif
>> "
>>
>> In DM part, some reconstruction is done. A fsl_qspi_runcmd is included to
>> simplify the code, but not the original qspi_op_xxxxs. fsl_qspi_get_seqid
>> is included to get seqid, but not hardcoded in original qspi_op_xxxxs.
>>
>> Signed-off-by: Peng Fan <Peng.Fan at freescale.com>
>> ---
>>   drivers/spi/fsl_qspi.c | 420 +++++++++++++++++++++++++++++++++++++++++++++++--
>>   drivers/spi/fsl_qspi.h |   1 +
>>   2 files changed, 405 insertions(+), 16 deletions(-)
>>
>> diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
>> index 5e0b069..ee151b3 100644
>> --- a/drivers/spi/fsl_qspi.c
>> +++ b/drivers/spi/fsl_qspi.c
>> @@ -13,6 +13,13 @@
>>   #include <linux/sizes.h>
>>   #include "fsl_qspi.h"
>>
>> +#ifdef CONFIG_DM_SPI
>> +#include <dm.h>
>> +#include <fdtdec.h>
>> +#include <asm/errno.h>
>> +#include <spi_flash.h>
>> +#endif
>> +
>>   #define RX_BUFFER_SIZE         0x80
>>   #ifdef CONFIG_MX6SX
>>   #define TX_BUFFER_SIZE         0x200
>> @@ -71,27 +78,41 @@
>>   #define qspi_write32           out_be32
>>   #endif
>>
>> -static unsigned long spi_bases[] = {
>> -       QSPI0_BASE_ADDR,
>> -#ifdef CONFIG_MX6SX
>> -       QSPI1_BASE_ADDR,
>> -#endif
>> -};
>> +#ifdef CONFIG_DM_SPI
>> +DECLARE_GLOBAL_DATA_PTR;
>> +#define QUADSPI_AHBMAP_BANK_MAXSIZE    SZ_64M
>>
>> -static unsigned long amba_bases[] = {
>> -       QSPI0_AMBA_BASE,
>> -#ifdef CONFIG_MX6SX
>> -       QSPI1_AMBA_BASE,
>> -#endif
>> +struct fsl_qspi_platdata {
>> +       u32             max_hz;
>> +       u32             reg_base;
>> +       u32             amba_base;
>> +       u32             flash_num;
>>   };
>>
>>   struct fsl_qspi {
>> +       u32             reg_base;
>> +       u32             amba_base;
>> +       size_t          cmd_len;
>> +       u8              cmd_buf[32];
>> +       size_t          data_len;
>> +       int             qspi_is_init;
>> +       size_t          flash_size;
>> +       u32             bank_memmap_phy[4];
>> +       int             cs;
>> +       u32             sf_addr;
>> +       int             flash_num;
>> +       u8              cur_seqid;
>> +       u32             freq;
>> +};
>> +#else
>> +struct fsl_qspi {
>>          struct spi_slave slave;
>>          unsigned long reg_base;
>>          unsigned long amba_base;
>>          u32 sf_addr;
>>          u8 cur_seqid;
>>   };
>> +#endif
>>
>>   /* QSPI support swapping the flash read/write data
>>    * in hardware for LS102xA, but not for VF610 */
>> @@ -104,11 +125,6 @@ static inline u32 qspi_endian_xchg(u32 data)
>>   #endif
>>   }
>>
>> -static inline struct fsl_qspi *to_qspi_spi(struct spi_slave *slave)
>> -{
>> -       return container_of(slave, struct fsl_qspi, slave);
>> -}
>> -
>>   static void qspi_set_lut(struct fsl_qspi *qspi)
>>   {
>>          struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
>> @@ -367,6 +383,377 @@ static void qspi_init_ahb_read(struct fsl_qspi_regs *regs)
>>   }
>>   #endif
>>
>> +#ifdef CONFIG_DM_SPI
>> +/* Get the SEQID for the command */
>> +static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
>> +{
>> +       switch (cmd) {
>> +       case QSPI_CMD_FAST_READ:
>> +       case QSPI_CMD_FAST_READ_4B:
>> +               return SEQID_FAST_READ;
>> +       case QSPI_CMD_WREN:
>> +               return SEQID_WREN;
>> +       case QSPI_CMD_RDSR:
>> +               return SEQID_RDSR;
>> +       case QSPI_CMD_SE:
>> +               return SEQID_SE;
>> +       case QSPI_CMD_PP:
>> +       case QSPI_CMD_PP_4B:
>> +               return SEQID_PP;
>> +       case QSPI_CMD_RDID:
>> +               return SEQID_RDID;
>> +       case QSPI_CMD_BE_4K:
>> +               return SEQID_BE_4K;
>> +#ifdef CONFIG_SPI_FLASH_BAR
>> +       case QSPI_CMD_BRRD:
>> +               return SEQID_BRRD;
>> +       case QSPI_CMD_BRWR:
>> +               return SEQID_BRWR;
>> +       case QSPI_CMD_RDEAR:
>> +               return SEQID_RDEAR;
>> +       case QSPI_CMD_WREAR:
>> +               return SEQID_WREAR;
>> +#endif
>> +       default:
>> +               break;
>> +       }
>> +       return -1;
>> +}
>> +
>> +/* Read out the data from the QUADSPI_RBDR buffer registers. */
>> +static void fsl_qspi_ip_read(struct fsl_qspi *q, int len, u8 *rxbuf)
>> +{
>> +       struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)q->reg_base;
>> +       u32 tmp;
>> +       int i = 0;
>> +
>> +       while (len > 0) {
>> +               tmp = qspi_read32(&regs->rbdr[i]);
>> +               tmp = qspi_endian_xchg(tmp);
>> +
>> +               if (len >= 4) {
>> +                       memcpy(rxbuf, &tmp, 4);
>> +                       rxbuf += 4;
>> +               } else {
>> +                       memcpy(rxbuf, &tmp, len);
>> +                       break;
>> +               }
>> +
>> +               len -= 4;
>> +               i++;
>> +       }
>> +}
>> +
>> +/* Write data to the QUADSPI_TBDR buffer registers. */
>> +static void fsl_qspi_write_data(struct fsl_qspi *q, int len, u8 *txbuf)
>> +{
>> +       struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)q->reg_base;
>> +       u32 tmp;
>> +       u32 t1, t2;
>> +       int j;
>> +
>> +       tmp = qspi_read32(&regs->mcr);
>> +       qspi_write32(&regs->mcr, tmp | QSPI_MCR_CLR_RXF_MASK |
>> +                    QSPI_MCR_CLR_TXF_MASK);
>> +
>> +       /* fill the TX data to the FIFO */
>> +       t2 = len % 4;
>> +       t1 = len >> 2; /* 4 Bytes aligned */
>> +
>> +       for (j = 0; j < t1; j++) {
>> +               memcpy(&tmp, txbuf, 4);
>> +               tmp = qspi_endian_xchg(tmp);
>> +               qspi_write32(&regs->tbdr, tmp);
>> +               txbuf += 4;
>> +       }
>> +
>> +       if (t2) {
>> +               tmp = 0;
>> +               memcpy(&tmp, txbuf, t2);
>> +               tmp = qspi_endian_xchg(tmp);
>> +               qspi_write32(&regs->tbdr, tmp);
>> +       }
>> +}
>> +
>> +static int fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, int len)
>> +{
>> +       struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)q->reg_base;
>> +       int seqid;
>> +       u32 reg;
>> +
>> +       /* Wait previous cmd completed */
>> +       while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
>> +               ;
>> +
>> +       /* save the reg */
>> +       reg = qspi_read32(&regs->mcr);
>> +
>> +       qspi_write32(&regs->sfar, q->amba_base + q->sf_addr);
>> +       qspi_write32(&regs->rbct, QSPI_RBCT_WMRK_MASK | QSPI_RBCT_RXBRD_USEIPS);
>> +       qspi_write32(&regs->mcr, reg | QSPI_MCR_CLR_RXF_MASK);
>> +
>> +       /* trigger the LUT now */
>> +       seqid = fsl_qspi_get_seqid(q, cmd);
>> +       qspi_write32(&regs->ipcr, (seqid << QSPI_IPCR_SEQID_SHIFT) | len);
>> +
>> +       /* Wait until completed */
>> +       while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
>> +               ;
>> +
>> +       /* restore the MCR */
>> +       qspi_write32(&regs->mcr, reg);
>> +
>> +#ifdef CONFIG_SYS_FSL_QSPI_AHB
>> +       /* After switch BANK, AHB buffer should also be invalid. */
>> +       if ((QSPI_CMD_SE == cmd) || (QSPI_CMD_PP == cmd) ||
>> +           (QSPI_CMD_BE_4K == cmd) || (QSPI_CMD_WREAR == cmd) ||
>> +           (QSPI_CMD_BRWR == cmd))
>> +               qspi_ahb_invalid(q);
>> +#endif
>> +       return 0;
>> +}
>> +
>> +int fsl_qspi_init(struct fsl_qspi *qspi)
>> +{
>> +       struct fsl_qspi_regs *regs;
>> +       u32 smpr_val;
>> +
>> +       regs = (struct fsl_qspi_regs *)qspi->reg_base;
>> +
>> +       qspi_write32(&regs->mcr, QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK);
>> +
>> +       smpr_val = qspi_read32(&regs->smpr);
>> +       qspi_write32(&regs->smpr, smpr_val & ~(QSPI_SMPR_FSDLY_MASK |
>> +                    QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK));
>> +       qspi_write32(&regs->mcr, QSPI_MCR_RESERVED_MASK);
>> +
>> +       /* flash size is still using macro definition. */
>> +       if (qspi->flash_num == 2) {
>> +               qspi_write32(&regs->sfa1ad, qspi->amba_base +
>> +                            FSL_QSPI_FLASH_SIZE);
>> +               qspi_write32(&regs->sfa2ad, qspi->amba_base +
>> +                            FSL_QSPI_FLASH_SIZE);
>> +               qspi_write32(&regs->sfb1ad, qspi->amba_base +
>> +                            FSL_QSPI_FLASH_SIZE * 2);
>> +               qspi_write32(&regs->sfb2ad, qspi->amba_base +
>> +                            FSL_QSPI_FLASH_SIZE * 2);
>> +       } else if (qspi->flash_num == 4) {
>> +               qspi_write32(&regs->sfa1ad, qspi->amba_base +
>> +                            FSL_QSPI_FLASH_SIZE);
>> +               qspi_write32(&regs->sfa2ad, qspi->amba_base +
>> +                            FSL_QSPI_FLASH_SIZE * 2);
>> +               qspi_write32(&regs->sfb1ad, qspi->amba_base +
>> +                            FSL_QSPI_FLASH_SIZE * 3);
>> +               qspi_write32(&regs->sfb2ad, qspi->amba_base +
>> +                            FSL_QSPI_FLASH_SIZE * 4);
>> +       } else {
>> +               qspi_write32(&regs->sfa1ad, qspi->amba_base +
>> +                            FSL_QSPI_FLASH_SIZE);
>> +               qspi_write32(&regs->sfa2ad, qspi->amba_base +
>> +                            FSL_QSPI_FLASH_SIZE);
>> +               qspi_write32(&regs->sfb1ad, qspi->amba_base +
>> +                            FSL_QSPI_FLASH_SIZE);
>> +               qspi_write32(&regs->sfb2ad, qspi->amba_base +
>> +                            FSL_QSPI_FLASH_SIZE);
>> +       }
>> +
>> +       qspi_set_lut(qspi);
>> +
>> +       smpr_val = qspi_read32(&regs->smpr);
>> +       smpr_val &= ~QSPI_SMPR_DDRSMP_MASK;
>> +       qspi_write32(&regs->smpr, smpr_val);
>> +       qspi_write32(&regs->mcr, QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
>> +
>> +#ifdef CONFIG_SYS_FSL_QSPI_AHB
>> +       qspi_init_ahb_read(regs);
>> +#endif
>> +       return 0;
>> +}
>> +
>> +static int fsl_qspi_probe(struct udevice *bus)
>> +{
>> +       struct fsl_qspi_platdata *plat = bus->platdata;
>> +       struct fsl_qspi *priv = dev_get_priv(bus);
>> +
>> +       priv->reg_base = plat->reg_base;
>> +       priv->amba_base = plat->amba_base;
>> +       priv->flash_num = plat->flash_num;
>> +
>> +       if (!priv->qspi_is_init) {
>> +               /* Initialization */
>> +               fsl_qspi_init(priv);
>> +               priv->qspi_is_init = 1;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int fsl_qspi_child_pre_probe(struct udevice *dev)
>> +{
>> +       struct udevice *bus = dev_get_parent(dev);
>> +       struct fsl_qspi *priv = dev_get_priv(bus);
>> +       struct spi_slave *slave = dev_get_parentdata(dev);
>> +       int cs = spi_chip_select(dev);
>> +
>> +       slave->max_write_size = TX_BUFFER_SIZE;
>> +
>> +       priv->cs = cs;
>> +       priv->amba_base = priv->bank_memmap_phy[priv->cs];
>> +
>> +       return 0;
>> +}
>> +
>> +static int fsl_qspi_xfer(struct udevice *dev, unsigned int bitlen,
>> +                        const void *dout, void *din, unsigned long flags)
>> +{
>> +       struct udevice *bus = dev->parent;
>> +       struct fsl_qspi *q = dev_get_priv(bus);
>> +       u32 len = DIV_ROUND_UP(bitlen, 8);
>> +       int ret = 0;
>> +       u8 *buf;
>> +       static u32 addr;
>> +       static u8 opcode;
>> +
>> +       if (!opcode && (flags & SPI_XFER_BEGIN)) {
>> +               /* CMD PHASE */
>> +               buf = (u8 *)dout;
>> +               opcode = buf[0];
>> +               if (len > 1) {
>> +                       addr = buf[1] << 16 | buf[2] << 8 | buf[3];
>> +                       q->sf_addr = addr;
>> +               }
>> +
>> +               /* Only transfer CMD */
>> +               if (flags & SPI_XFER_END)
>> +                       ret = fsl_qspi_runcmd(q, opcode, 0);
>> +
>> +       } else if (opcode) {
>> +               /* Data phase */
>> +               if (din) {
>> +                       /* read*/
>> +                       buf = (u8 *)din;
>> +#ifdef CONFIG_SYS_FSL_QSPI_AHB
>> +                       if (QSPI_CMD_FAST_READ == opcode) {
>> +                               qspi_ahb_read(q, buf, len);
>> +                       } else {
>> +                               ret = fsl_qspi_runcmd(q, opcode, len);
>> +                               if (!ret)
>> +                                       fsl_qspi_ip_read(q, len, buf);
>> +                       }
>> +#else
>> +                       ret = fsl_qspi_runcmd(q, opcode, len);
>> +                       if (!ret)
>> +                               fsl_qspi_ip_read(q, len, buf);
>> +#endif
>> +               } else if (dout) {
>> +                       /* Write data, First prepare data */
>> +                       buf = (u8 *)dout;
>> +                       fsl_qspi_write_data(q, len, buf);
>> +                       /* Run page program cmd */
>> +                       ret = fsl_qspi_runcmd(q, opcode, len);
>> +               }
>> +       }
>> +
>> +       if (ret || (flags & SPI_XFER_END)) {
>> +               opcode = 0;
>> +               addr = 0;
>> +       }
>> +
>> +       return ret;
>> +}
>> +
>> +static int fsl_qspi_ofdata_to_platdata(struct udevice *bus)
>> +{
>> +       struct fsl_qspi_platdata *plat = bus->platdata;
>> +       const void *blob = gd->fdt_blob;
>> +       int node = bus->of_offset;
>> +       int subnode, flash_num = 0;
>> +       u32 data[4];
>> +       int ret;
>> +
>> +       ret = fdtdec_get_int_array(blob, node, "reg", data, ARRAY_SIZE(data));
>> +       if (ret) {
>> +               printf("Error: can't get base addresses (ret = %d)!\n", ret);
>> +               return -ENODEV;
>> +       }
>> +
>> +       /* Count flash numbers */
>> +       fdt_for_each_subnode(blob, subnode, node)
>> +               ++flash_num;
>> +
>> +       if (flash_num == 0) {
>> +               printf("Error: Missing flashes!\n");
>> +               return -ENODEV;
>> +       }
>> +
>> +       plat->reg_base = data[0];
>> +       plat->amba_base = data[2];
>> +       plat->flash_num = flash_num;
>> +
>> +       plat->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency",
>> +                                     50000000);
>> +
>> +       debug("%s: reg_base=0x%x amba_base=0x%x max-frequency=%d\n",
>> +             __func__, plat->reg_base, plat->amba_base, plat->max_hz);
>> +
>> +       return 0;
>> +}
>> +
>> +static int fsl_qspi_set_speed(struct udevice *bus, u32 speed)
>> +{
>> +       return 0;
>> +}
>> +
>> +static int fsl_qspi_set_mode(struct udevice *bus, u32 mode)
>> +{
>> +       return 0;
>> +}
>> +
>> +static const struct dm_spi_ops fsl_qspi_ops = {
>> +       .xfer           = fsl_qspi_xfer,
>> +       .set_speed      = fsl_qspi_set_speed,
>> +       .set_mode       = fsl_qspi_set_mode,
>> +};
>> +
>> +static const struct udevice_id fsl_qspi_ids[] = {
>> +       { .compatible = "fsl,vf610-qspi" },
>> +       { .compatible = "fsl,imx6sx-qspi" },
>> +       { }
>> +};
>> +
>> +U_BOOT_DRIVER(fsl_qspi) = {
>> +       .name = "fsl_qspi",
>> +       .id = UCLASS_SPI,
>> +       .of_match = fsl_qspi_ids,
>> +       .ops = &fsl_qspi_ops,
>> +       .ofdata_to_platdata = fsl_qspi_ofdata_to_platdata,
>> +       .platdata_auto_alloc_size = sizeof(struct fsl_qspi_platdata),
>> +       .priv_auto_alloc_size = sizeof(struct fsl_qspi),
>> +       .per_child_auto_alloc_size = sizeof(struct spi_slave),
>> +       .probe = fsl_qspi_probe,
>> +       .child_pre_probe = fsl_qspi_child_pre_probe,
>> +};
>> +
>> +#else
>> +static unsigned long spi_bases[] = {
>> +       QSPI0_BASE_ADDR,
>> +#ifdef CONFIG_MX6SX
>> +       QSPI1_BASE_ADDR,
>> +#endif
>> +};
>> +
>> +static unsigned long amba_bases[] = {
>> +       QSPI0_AMBA_BASE,
>> +#ifdef CONFIG_MX6SX
>> +       QSPI1_AMBA_BASE,
>> +#endif
>> +};
>> +
>> +static inline struct fsl_qspi *to_qspi_spi(struct spi_slave *slave)
>> +{
>> +       return container_of(slave, struct fsl_qspi, slave);
>> +}
>> +
>>   void spi_init()
>>   {
>>          /* do nothing */
>> @@ -782,3 +1169,4 @@ void spi_release_bus(struct spi_slave *slave)
>>   {
>>          /* Nothing to do */
>>   }
>> +#endif
>> diff --git a/drivers/spi/fsl_qspi.h b/drivers/spi/fsl_qspi.h
>> index 6cb3610..ef4d4b5 100644
>> --- a/drivers/spi/fsl_qspi.h
>> +++ b/drivers/spi/fsl_qspi.h
>> @@ -104,6 +104,7 @@ struct fsl_qspi_regs {
>>
>>   #define QSPI_RBCT_RXBRD_SHIFT          8
>>   #define QSPI_RBCT_RXBRD_USEIPS         (1 << QSPI_RBCT_RXBRD_SHIFT)
>> +#define QSPI_RBCT_WMRK_MASK            0x1F
>>
>>   #define QSPI_SR_BUSY_SHIFT             0
>>   #define QSPI_SR_BUSY_MASK              (1 << QSPI_SR_BUSY_SHIFT)
>> --
>> 1.8.4
>>
>>
> thanks!



More information about the U-Boot mailing list