[U-Boot] [UBOOT PATCH] spi: xilinx_spi: Modify xilinx spi driver
Vipul Kumar
vipulk at xilinx.com
Mon Jun 4 11:19:11 UTC 2018
Hi Jagan,
Do you have any comments on this? If not, could you please take it up.
Thanks,
Vipul
> -----Original Message-----
> From: Vipul Kumar [mailto:vipul.kumar at xilinx.com]
> Sent: Monday, May 28, 2018 6:06 PM
> To: u-boot at lists.denx.de
> Cc: michal.simek at xilinx.com; Siva Durga Prasad Paladugu
> <sivadur at xilinx.com>; Vipul Kumar <vipulk at xilinx.com>
> Subject: [UBOOT PATCH] spi: xilinx_spi: Modify xilinx spi driver
>
> This patch added support to get reg base address from DTS file and added
> rxfifo() and txfifo() functions to add the modularity.
>
> Also, this patch is for the startup block issue in the spi controller.
> SPI clock is passing through STARTUP block to FLASH. STARTUP block don't
> provide clock as soon as QSPI provides command. So, first command fails.
>
> This patch added support to read JEDEC id in xilinx_spi_xfer () before
> performing the spi operations.
>
> Signed-off-by: Vipul Kumar <vipul.kumar at xilinx.com>
> ---
> drivers/spi/xilinx_spi.c | 161 +++++++++++++++++++++++++++++++++++--
> ----------
> 1 file changed, 121 insertions(+), 40 deletions(-)
>
> diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index
> 8f0f32f..12097ce 100644
> --- a/drivers/spi/xilinx_spi.c
> +++ b/drivers/spi/xilinx_spi.c
> @@ -77,10 +77,6 @@
> #define CONFIG_XILINX_SPI_IDLE_VAL GENMASK(7, 0)
> #endif
>
> -#ifndef CONFIG_SYS_XILINX_SPI_LIST
> -#define CONFIG_SYS_XILINX_SPI_LIST { CONFIG_SYS_SPI_BASE }
> -#endif
> -
> /* xilinx spi register set */
> struct xilinx_spi_regs {
> u32 __space0__[7];
> @@ -105,16 +101,14 @@ struct xilinx_spi_priv {
> struct xilinx_spi_regs *regs;
> unsigned int freq;
> unsigned int mode;
> + unsigned int fifo_depth;
> };
>
> -static unsigned long xilinx_spi_base_list[] = CONFIG_SYS_XILINX_SPI_LIST;
> static int xilinx_spi_probe(struct udevice *bus) {
> struct xilinx_spi_priv *priv = dev_get_priv(bus);
> struct xilinx_spi_regs *regs = priv->regs;
>
> - priv->regs = (struct xilinx_spi_regs *)xilinx_spi_base_list[bus->seq];
> -
> writel(SPISSR_RESET_VALUE, ®s->srr);
>
> return 0;
> @@ -134,8 +128,12 @@ static void spi_cs_deactivate(struct udevice *dev)
> struct udevice *bus = dev_get_parent(dev);
> struct xilinx_spi_priv *priv = dev_get_priv(bus);
> struct xilinx_spi_regs *regs = priv->regs;
> + u32 reg;
>
> + reg = readl(®s->spicr) | SPICR_RXFIFO_RESEST |
> SPICR_TXFIFO_RESEST;
> + writel(reg, ®s->spicr);
> writel(SPISSR_OFF, ®s->spissr);
> +
> }
>
> static int xilinx_spi_claim_bus(struct udevice *dev) @@ -162,6 +160,80 @@
> static int xilinx_spi_release_bus(struct udevice *dev)
> return 0;
> }
>
> +static u32 xilinx_spi_fill_txfifo(struct udevice *bus, const u8 *txp,
> + u32 txbytes)
> +{
> + struct xilinx_spi_priv *priv = dev_get_priv(bus);
> + struct xilinx_spi_regs *regs = priv->regs;
> + unsigned char d;
> + u32 i = 0;
> +
> + while (txbytes && !(readl(®s->spisr) & SPISR_TX_FULL) &&
> + i < priv->fifo_depth) {
> + d = txp ? *txp++ : CONFIG_XILINX_SPI_IDLE_VAL;
> + debug("spi_xfer: tx:%x ", d);
> + /* write out and wait for processing (receive data) */
> + writel(d & SPIDTR_8BIT_MASK, ®s->spidtr);
> + txbytes--;
> + i++;
> + }
> + return i;
> +}
> +
> +static u32 xilinx_spi_read_rxfifo(struct udevice *bus, u8 *rxp, u32
> +rxbytes) {
> + struct xilinx_spi_priv *priv = dev_get_priv(bus);
> + struct xilinx_spi_regs *regs = priv->regs;
> + unsigned char d;
> + unsigned int i = 0;
> +
> + while (rxbytes && !(readl(®s->spisr) & SPISR_RX_EMPTY)) {
> + d = readl(®s->spidrr) & SPIDRR_8BIT_MASK;
> + if (rxp)
> + *rxp++ = d;
> + debug("spi_xfer: rx:%x\n", d);
> + rxbytes--;
> + i++;
> + }
> + debug("Rx_done\n");
> +
> + return i;
> +}
> +
> +static void xilinx_startup_block(struct udevice *dev, unsigned int bytes,
> + const void *dout, void *din)
> +{
> + struct udevice *bus = dev_get_parent(dev);
> + struct xilinx_spi_priv *priv = dev_get_priv(bus);
> + struct xilinx_spi_regs *regs = priv->regs;
> + struct dm_spi_slave_platdata *slave_plat =
> dev_get_parent_platdata(dev);
> + const unsigned char *txp = dout;
> + unsigned char *rxp = din;
> + static int startup;
> + u32 reg, count;
> + u32 txbytes = bytes;
> + u32 rxbytes = bytes;
> +
> + /*
> + * This loop runs two times. First time to send the command.
> + * Second time to transfer data. After transferring data,
> + * it sets txp to the initial value for the normal operation.
> + */
> + for ( ; startup < 2; startup++) {
> + count = xilinx_spi_fill_txfifo(bus, txp, txbytes);
> + reg = readl(®s->spicr) & ~SPICR_MASTER_INHIBIT;
> + writel(reg, ®s->spicr);
> + count = xilinx_spi_read_rxfifo(bus, rxp, rxbytes);
> + txp = din;
> +
> + if (startup) {
> + spi_cs_deactivate(dev);
> + spi_cs_activate(dev, slave_plat->cs);
> + txp = dout;
> + }
> + }
> +}
> +
> static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen,
> const void *dout, void *din, unsigned long flags) {
> @@ -173,8 +245,9 @@ static int xilinx_spi_xfer(struct udevice *dev,
> unsigned int bitlen,
> unsigned int bytes = bitlen / XILSPI_MAX_XFER_BITS;
> const unsigned char *txp = dout;
> unsigned char *rxp = din;
> - unsigned rxecount = 17; /* max. 16 elements in FIFO, leftover
> 1 */
> - unsigned global_timeout;
> + u32 txbytes = bytes;
> + u32 rxbytes = bytes;
> + u32 reg, count, timeout;
>
> debug("spi_xfer: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n",
> bus->seq, slave_plat->cs, bitlen, bytes, flags); @@ -189,48 +262,41
> @@ static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen,
> goto done;
> }
>
> - /* empty read buffer */
> - while (rxecount && !(readl(®s->spisr) & SPISR_RX_EMPTY)) {
> - readl(®s->spidrr);
> - rxecount--;
> - }
> -
> - if (!rxecount) {
> - printf("XILSPI error: Rx buffer not empty\n");
> - return -1;
> - }
> -
> if (flags & SPI_XFER_BEGIN)
> spi_cs_activate(dev, slave_plat->cs);
>
> - /* at least 1usec or greater, leftover 1 */
> - global_timeout = priv->freq > XILSPI_MAX_XFER_BITS * 1000000 ? 2 :
> - (XILSPI_MAX_XFER_BITS * 1000000 / priv->freq) + 1;
> -
> - while (bytes--) {
> - unsigned timeout = global_timeout;
> - /* get Tx element from data out buffer and count up */
> - unsigned char d = txp ? *txp++ :
> CONFIG_XILINX_SPI_IDLE_VAL;
> - debug("spi_xfer: tx:%x ", d);
> -
> - /* write out and wait for processing (receive data) */
> - writel(d & SPIDTR_8BIT_MASK, ®s->spidtr);
> - while (timeout && readl(®s->spisr)
> - & SPISR_RX_EMPTY) {
> - timeout--;
> + /*
> + * This is the work around for the startup block issue in
> + * the spi controller. SPI clock is passing through STARTUP
> + * block to FLASH. STARTUP block don't provide clock as soon
> + * as QSPI provides command. So first command fails.
> + */
> + xilinx_startup_block(dev, bytes, dout, din);
> +
> + while (txbytes && rxbytes) {
> + count = xilinx_spi_fill_txfifo(bus, txp, txbytes);
> + reg = readl(®s->spicr) & ~SPICR_MASTER_INHIBIT;
> + writel(reg, ®s->spicr);
> + txbytes -= count;
> + if (txp)
> + txp += count;
> +
> + timeout = 10000000;
> + do {
> udelay(1);
> - }
> + } while (!(readl(®s->spisr) & SPISR_TX_EMPTY) &&
> timeout--);
>
> if (!timeout) {
> printf("XILSPI error: Xfer timeout\n");
> return -1;
> }
>
> - /* read Rx element and push into data in buffer */
> - d = readl(®s->spidrr) & SPIDRR_8BIT_MASK;
> + debug("txbytes:0x%x,txp:0x%p\n", txbytes, txp);
> + count = xilinx_spi_read_rxfifo(bus, rxp, rxbytes);
> + rxbytes -= count;
> if (rxp)
> - *rxp++ = d;
> - debug("spi_xfer: rx:%x\n", d);
> + rxp += count;
> + debug("rxbytes:0x%x rxp:0x%p\n", rxbytes, rxp);
> }
>
> done:
> @@ -285,6 +351,20 @@ static const struct dm_spi_ops xilinx_spi_ops = {
> .set_mode = xilinx_spi_set_mode,
> };
>
> +static int xilinx_spi_ofdata_to_platdata(struct udevice *bus) {
> + struct xilinx_spi_priv *priv = dev_get_priv(bus);
> +
> + priv->regs = (struct xilinx_spi_regs *)devfdt_get_addr(bus);
> +
> + debug("%s: regs=%p\n", __func__, priv->regs);
> +
> + priv->fifo_depth = fdtdec_get_int(gd->fdt_blob,
> dev_of_offset(bus),
> + "fifo-size", 0);
> +
> + return 0;
> +}
> +
> static const struct udevice_id xilinx_spi_ids[] = {
> { .compatible = "xlnx,xps-spi-2.00.a" },
> { .compatible = "xlnx,xps-spi-2.00.b" }, @@ -296,6 +376,7 @@
> U_BOOT_DRIVER(xilinx_spi) = {
> .id = UCLASS_SPI,
> .of_match = xilinx_spi_ids,
> .ops = &xilinx_spi_ops,
> + .ofdata_to_platdata = xilinx_spi_ofdata_to_platdata,
> .priv_auto_alloc_size = sizeof(struct xilinx_spi_priv),
> .probe = xilinx_spi_probe,
> };
> --
> 2.7.4
More information about the U-Boot
mailing list