From mboxrd@z Thu Jan 1 00:00:00 1970 From: Peng Fan Date: Mon, 19 Jan 2015 15:48:04 +0800 Subject: [U-Boot] [RFC PATCH] dm:spi:fsl_qspi add DM support In-Reply-To: References: <1421474363-30453-1-git-send-email-Peng.Fan@freescale.com> Message-ID: <54BCB6B4.6030702@freescale.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de Hi Jagan, On 1/19/2015 2:47 PM, Jagan Teki wrote: > Hi Peng, > > On 17 January 2015 at 11:29, Peng Fan 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 >> --- >> 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 >> #include "fsl_qspi.h" >> >> +#ifdef CONFIG_DM_SPI >> +#include >> +#include >> +#include >> +#include >> +#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(®s->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(®s->mcr); >> + qspi_write32(®s->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(®s->tbdr, tmp); >> + txbuf += 4; >> + } >> + >> + if (t2) { >> + tmp = 0; >> + memcpy(&tmp, txbuf, t2); >> + tmp = qspi_endian_xchg(tmp); >> + qspi_write32(®s->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(®s->sr) & QSPI_SR_BUSY_MASK) >> + ; >> + >> + /* save the reg */ >> + reg = qspi_read32(®s->mcr); >> + >> + qspi_write32(®s->sfar, q->amba_base + q->sf_addr); >> + qspi_write32(®s->rbct, QSPI_RBCT_WMRK_MASK | QSPI_RBCT_RXBRD_USEIPS); >> + qspi_write32(®s->mcr, reg | QSPI_MCR_CLR_RXF_MASK); >> + >> + /* trigger the LUT now */ >> + seqid = fsl_qspi_get_seqid(q, cmd); >> + qspi_write32(®s->ipcr, (seqid << QSPI_IPCR_SEQID_SHIFT) | len); >> + >> + /* Wait until completed */ >> + while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) >> + ; >> + >> + /* restore the MCR */ >> + qspi_write32(®s->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(®s->mcr, QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK); >> + >> + smpr_val = qspi_read32(®s->smpr); >> + qspi_write32(®s->smpr, smpr_val & ~(QSPI_SMPR_FSDLY_MASK | >> + QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK)); >> + qspi_write32(®s->mcr, QSPI_MCR_RESERVED_MASK); >> + >> + /* flash size is still using macro definition. */ >> + if (qspi->flash_num == 2) { >> + qspi_write32(®s->sfa1ad, qspi->amba_base + >> + FSL_QSPI_FLASH_SIZE); >> + qspi_write32(®s->sfa2ad, qspi->amba_base + >> + FSL_QSPI_FLASH_SIZE); >> + qspi_write32(®s->sfb1ad, qspi->amba_base + >> + FSL_QSPI_FLASH_SIZE * 2); >> + qspi_write32(®s->sfb2ad, qspi->amba_base + >> + FSL_QSPI_FLASH_SIZE * 2); >> + } else if (qspi->flash_num == 4) { >> + qspi_write32(®s->sfa1ad, qspi->amba_base + >> + FSL_QSPI_FLASH_SIZE); >> + qspi_write32(®s->sfa2ad, qspi->amba_base + >> + FSL_QSPI_FLASH_SIZE * 2); >> + qspi_write32(®s->sfb1ad, qspi->amba_base + >> + FSL_QSPI_FLASH_SIZE * 3); >> + qspi_write32(®s->sfb2ad, qspi->amba_base + >> + FSL_QSPI_FLASH_SIZE * 4); >> + } else { >> + qspi_write32(®s->sfa1ad, qspi->amba_base + >> + FSL_QSPI_FLASH_SIZE); >> + qspi_write32(®s->sfa2ad, qspi->amba_base + >> + FSL_QSPI_FLASH_SIZE); >> + qspi_write32(®s->sfb1ad, qspi->amba_base + >> + FSL_QSPI_FLASH_SIZE); >> + qspi_write32(®s->sfb2ad, qspi->amba_base + >> + FSL_QSPI_FLASH_SIZE); >> + } >> + >> + qspi_set_lut(qspi); >> + >> + smpr_val = qspi_read32(®s->smpr); >> + smpr_val &= ~QSPI_SMPR_DDRSMP_MASK; >> + qspi_write32(®s->smpr, smpr_val); >> + qspi_write32(®s->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!