Hi Peng, On 16 January 2015 at 22:59, Peng Fan <peng....@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. > > Thanks. > > 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.
Not sure where this driver is going - I'm happy to pick it up if you work things out with Jagan. For now I'll just make a few comments, in case they are useful. > > Signed-off-by: Peng Fan <peng....@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 Shouldn't need these #ifdefs around header files. > +#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; Should these be structure pointers? > + 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; Do you need cs in here? The per-child platform data has it if you base it on u-boot-dm/i2c-working (which is what I suggest). > + u32 sf_addr; > + int flash_num; > + u8 cur_seqid; > + u32 freq; > +}; > +#else Will there still be non-driver-model users of this driver? Can we convert them over? > +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) s/q/priv/ or something a bit longer than one character. > +{ > + 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++) { What is 11? > + 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) > + ; Should check for timeout here? > + > + /* 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; I think the device is there but it is wrong, so these should be -EINVAL Also better to avoid printf() and use debug(), for code size reasons I think. > + } > + > + /* 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 > > Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot