[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, &regs->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(&regs->spicr) | SPICR_RXFIFO_RESEST |
> SPICR_TXFIFO_RESEST;
> +	writel(reg, &regs->spicr);
>  	writel(SPISSR_OFF, &regs->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(&regs->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, &regs->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(&regs->spisr) & SPISR_RX_EMPTY)) {
> +		d = readl(&regs->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(&regs->spicr) & ~SPICR_MASTER_INHIBIT;
> +		writel(reg, &regs->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(&regs->spisr) & SPISR_RX_EMPTY)) {
> -		readl(&regs->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, &regs->spidtr);
> -		while (timeout && readl(&regs->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(&regs->spicr) & ~SPICR_MASTER_INHIBIT;
> +		writel(reg, &regs->spicr);
> +		txbytes -= count;
> +		if (txp)
> +			txp += count;
> +
> +		timeout = 10000000;
> +		do {
>  			udelay(1);
> -		}
> +		} while (!(readl(&regs->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(&regs->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