[U-Boot] [UBOOT PATCH v4 0/4] spi:xilinx_spi: Modify xilinx spi driver

This series of patches do the following: - This patch added support to get reg base address from DTS file - Added rxfifo() and txfifo() functions to add the modularity - Added support to read JEDEC-id twice at the boot time - Added live-tree support
Changes in v2: - Split single patch into the series of patches
Changes in v3: - Read reg in probe function - Removed xilinx_spi_ofdata_to_platdata function - Added fifo_depth read support in 2/3 and removed from 1/3
Changes in v4: - Moved static startup variable to private structure - Added live-tree support
Michal Simek (1): spi: xilinx: Read reg base address from DTS file
Vipul Kumar (3): spi: xilinx_spi: Modify transfer logic xilinx_spi_xfer() function spi: xilinx_spi: Added support to read JEDEC-id twice at the boot time spi: xilinx_spi: convert to livetree
drivers/spi/xilinx_spi.c | 152 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 110 insertions(+), 42 deletions(-)

From: Michal Simek michal.simek@xilinx.com
This patch added support to read register base address from DTS file.
Signed-off-by: Vipul Kumar vipul.kumar@xilinx.com --- Changes in v4: - No change --- drivers/spi/xilinx_spi.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index 8f0f32f..cc5ac51 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]; @@ -107,13 +103,12 @@ struct xilinx_spi_priv { unsigned int mode; };
-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]; + priv->regs = (struct xilinx_spi_regs *)devfdt_get_addr(bus);
writel(SPISSR_RESET_VALUE, ®s->srr);

This patch modify xilinx_spi_xfer() function and add rxfifo() and txfifo() functions to add the modularity so that these functions can be used by other functions within the same file.
This patch also added support to read fifo_size from dts.
Signed-off-by: Vipul Kumar vipul.kumar@xilinx.com Signed-off-by: Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com --- Changes in v4: - Added space before "return i" --- drivers/spi/xilinx_spi.c | 103 +++++++++++++++++++++++++++++++---------------- 1 file changed, 68 insertions(+), 35 deletions(-)
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index cc5ac51..11b7343 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -19,6 +19,7 @@ #include <malloc.h> #include <spi.h> #include <asm/io.h> +#include <wait_bit.h>
/* * [0]: http://www.xilinx.com/support/documentation @@ -77,6 +78,8 @@ #define CONFIG_XILINX_SPI_IDLE_VAL GENMASK(7, 0) #endif
+#define XILINX_SPISR_TIMEOUT 10000 /* in milliseconds */ + /* xilinx spi register set */ struct xilinx_spi_regs { u32 __space0__[7]; @@ -101,6 +104,7 @@ struct xilinx_spi_priv { struct xilinx_spi_regs *regs; unsigned int freq; unsigned int mode; + unsigned int fifo_depth; };
static int xilinx_spi_probe(struct udevice *bus) @@ -110,6 +114,9 @@ static int xilinx_spi_probe(struct udevice *bus)
priv->regs = (struct xilinx_spi_regs *)devfdt_get_addr(bus);
+ priv->fifo_depth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus), + "fifo-size", 0); + writel(SPISSR_RESET_VALUE, ®s->srr);
return 0; @@ -157,6 +164,47 @@ 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 int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { @@ -168,8 +216,10 @@ 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; + int ret;
debug("spi_xfer: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", bus->seq, slave_plat->cs, bitlen, bytes, flags); @@ -184,48 +234,31 @@ 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); + 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;
- /* write out and wait for processing (receive data) */ - writel(d & SPIDTR_8BIT_MASK, ®s->spidtr); - while (timeout && readl(®s->spisr) - & SPISR_RX_EMPTY) { - timeout--; - udelay(1); - } - - if (!timeout) { + ret = wait_for_bit_le32(®s->spisr, SPISR_TX_EMPTY, true, + XILINX_SPISR_TIMEOUT, false); + if (ret < 0) { printf("XILSPI error: Xfer timeout\n"); - return -1; + return ret; }
- /* 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:

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 ().
Signed-off-by: Vipul Kumar vipul.kumar@xilinx.com --- Changes in v4: - Moved static startup variable to private data structure - Link to AR: https://www.xilinx.com/support/answers/52626.html --- drivers/spi/xilinx_spi.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+)
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index 11b7343..f66ea15 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -105,6 +105,7 @@ struct xilinx_spi_priv { unsigned int freq; unsigned int mode; unsigned int fifo_depth; + u8 startup; };
static int xilinx_spi_probe(struct udevice *bus) @@ -205,6 +206,39 @@ static u32 xilinx_spi_read_rxfifo(struct udevice *bus, u8 *rxp, u32 rxbytes) 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; + 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 ( ; priv->startup < 2; priv->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 (priv->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) { @@ -237,6 +271,13 @@ static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen, if (flags & SPI_XFER_BEGIN) spi_cs_activate(dev, slave_plat->cs);
+ /* + * 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);

On Thu, Jun 28, 2018 at 1:14 PM, Vipul Kumar vipul.kumar@xilinx.com wrote:
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 ().
Signed-off-by: Vipul Kumar vipul.kumar@xilinx.com
Changes in v4:
- Moved static startup variable to private data structure
- Link to AR: https://www.xilinx.com/support/answers/52626.html
drivers/spi/xilinx_spi.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+)
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index 11b7343..f66ea15 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -105,6 +105,7 @@ struct xilinx_spi_priv { unsigned int freq; unsigned int mode; unsigned int fifo_depth;
u8 startup;
};
static int xilinx_spi_probe(struct udevice *bus) @@ -205,6 +206,39 @@ static u32 xilinx_spi_read_rxfifo(struct udevice *bus, u8 *rxp, u32 rxbytes) 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;
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 ( ; priv->startup < 2; priv->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 (priv->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) { @@ -237,6 +271,13 @@ static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen, if (flags & SPI_XFER_BEGIN) spi_cs_activate(dev, slave_plat->cs);
/*
* 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);
Can this be xilinx_spi_startup_block? otherwise it look like generic startup function for processor or soc.

Update the xilinx spi driver to support a live tree.
Signed-off-by: Vipul Kumar vipul.kumar@xilinx.com --- drivers/spi/xilinx_spi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index f66ea15..59ac851 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -113,10 +113,9 @@ 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 *)devfdt_get_addr(bus); + priv->regs = (struct xilinx_spi_regs *)dev_read_addr(bus);
- priv->fifo_depth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus), - "fifo-size", 0); + priv->fifo_depth = dev_read_u32_default(bus, "fifo-size", 0);
writel(SPISSR_RESET_VALUE, ®s->srr);
participants (2)
-
Jagan Teki
-
Vipul Kumar