From d2998286fc58e3ac6c75ed4d3a1e77b618bbf2ae Mon Sep 17 00:00:00 2001 From: Lad, Prabhakar Date: Sat, 30 Jul 2016 22:28:24 +0100 Subject: spi: zynq_spi: Fix infinite looping while xfer During spi transfer, for example: sspi 1:1.0 8 ff the rx_len values will be: rx_len = 0 rx_len = 4294967295 This caused a busy looping during xfer, this patch fixes it by adding a check while reading the rx fifo Signed-off-by: Lad, Prabhakar Cc: Michal Simek Cc: Siva Durga Prasad Paladugu Reviewed-by: Jagan Teki --- drivers/spi/zynq_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c index 09ae1be7e98..dd3de2792d4 100644 --- a/drivers/spi/zynq_spi.c +++ b/drivers/spi/zynq_spi.c @@ -230,7 +230,7 @@ static int zynq_spi_xfer(struct udevice *dev, unsigned int bitlen, /* Read the data from RX FIFO */ status = readl(®s->isr); - while (status & ZYNQ_SPI_IXR_RXNEMPTY_MASK) { + while ((status & ZYNQ_SPI_IXR_RXNEMPTY_MASK) && rx_len) { buf = readl(®s->rxdr); if (rx_buf) *rx_buf++ = buf; -- cgit v1.2.3 From 260368507a15de9503f509b175796935f65fbfc3 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Wed, 7 Sep 2016 15:18:22 +0530 Subject: spi: ti_qspi: use 128 bit transfer mode when writing to flash TI QSPI has four 32 bit data registers which can be used to transfer 16 bytes of data at once. The register group QSPI_SPI_DATA_REG_3, QSPI_SPI_DATA_REG_2, QSPI_SPI_DATA_REG_1 and QSPI_SPI_DATA_REG is treated as a single 128-bit word for shifting data in and out. The bit at QSPI_SPI_DATA_REG_3[31] position is the first bit to be shifted out in case of 128 bit transfer mode. Therefore the first byte to be written to flash should be at QSPI_SPI_DATA_REG_3[31-25] position. Instead of writing 1 byte at a time when interacting with SPI NOR flash, make use of all the four registers so that 16 bytes can be transferred in one go. With this patch, the flash write speed increases from ~250KBs/ to ~650KB/s on DRA74 EVM. Signed-off-by: Vignesh R Reviewed-by: Tom Rini Reviewed-by: Jagan Teki --- drivers/spi/ti_qspi.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c index bb72cb03ec2..1e2c432ede6 100644 --- a/drivers/spi/ti_qspi.c +++ b/drivers/spi/ti_qspi.c @@ -23,6 +23,9 @@ DECLARE_GLOBAL_DATA_PTR; #define QSPI_TIMEOUT 2000000 #define QSPI_FCLK 192000000 #define QSPI_DRA7XX_FCLK 76800000 +#define QSPI_WLEN_MAX_BITS 128 +#define QSPI_WLEN_MAX_BYTES (QSPI_WLEN_MAX_BITS >> 3) +#define QSPI_WLEN_MASK QSPI_WLEN(QSPI_WLEN_MAX_BITS) /* clock control */ #define QSPI_CLK_EN BIT(31) #define QSPI_CLK_DIV_MAX 0xffff @@ -230,13 +233,34 @@ static int __ti_qspi_xfer(struct ti_qspi_priv *priv, unsigned int bitlen, #ifdef CONFIG_AM43XX udelay(100); #endif - while (words--) { + while (words) { + u8 xfer_len = 0; + if (txp) { - debug("tx cmd %08x dc %08x data %02x\n", - priv->cmd | QSPI_WR_SNGL, priv->dc, *txp); - writel(*txp++, &priv->base->data); - writel(priv->cmd | QSPI_WR_SNGL, - &priv->base->cmd); + u32 cmd = priv->cmd; + + if (words >= QSPI_WLEN_MAX_BYTES) { + u32 *txbuf = (u32 *)txp; + u32 data; + + data = cpu_to_be32(*txbuf++); + writel(data, &priv->base->data3); + data = cpu_to_be32(*txbuf++); + writel(data, &priv->base->data2); + data = cpu_to_be32(*txbuf++); + writel(data, &priv->base->data1); + data = cpu_to_be32(*txbuf++); + writel(data, &priv->base->data); + cmd &= ~QSPI_WLEN_MASK; + cmd |= QSPI_WLEN(QSPI_WLEN_MAX_BITS); + xfer_len = QSPI_WLEN_MAX_BYTES; + } else { + writeb(*txp, &priv->base->data); + xfer_len = 1; + } + debug("tx cmd %08x dc %08x\n", + cmd | QSPI_WR_SNGL, priv->dc); + writel(cmd | QSPI_WR_SNGL, &priv->base->cmd); status = readl(&priv->base->status); timeout = QSPI_TIMEOUT; while ((status & QSPI_WC_BUSY) != QSPI_XFER_DONE) { @@ -246,6 +270,7 @@ static int __ti_qspi_xfer(struct ti_qspi_priv *priv, unsigned int bitlen, } status = readl(&priv->base->status); } + txp += xfer_len; debug("tx done, status %08x\n", status); } if (rxp) { @@ -262,9 +287,11 @@ static int __ti_qspi_xfer(struct ti_qspi_priv *priv, unsigned int bitlen, status = readl(&priv->base->status); } *rxp++ = readl(&priv->base->data); + xfer_len = 1; debug("rx done, status %08x, read %02x\n", status, *(rxp-1)); } + words -= xfer_len; } /* Terminate frame */ -- cgit v1.2.3 From 28b69f64886c89d463ebe380f87f858f7362be36 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Wed, 7 Sep 2016 15:18:23 +0530 Subject: spi: ti_qspi: Remove unnecessary udelay for AM437x This udelay() was added as an HACK and is no longer required. All read/write/erase operations work fine even without this delay. Hence, remove the udelay() call. Tested read/write/erase operation on AM437x SK. Also tested QSPI Boot. Signed-off-by: Vignesh R Reviewed-by: Tom Rini Reviewed-by: Jagan Teki --- drivers/spi/ti_qspi.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c index 1e2c432ede6..406e76b8a78 100644 --- a/drivers/spi/ti_qspi.c +++ b/drivers/spi/ti_qspi.c @@ -226,13 +226,6 @@ static int __ti_qspi_xfer(struct ti_qspi_priv *priv, unsigned int bitlen, priv->cmd |= QSPI_3_PIN; priv->cmd |= 0xfff; -/* FIXME: This delay is required for successfull - * completion of read/write/erase. Once its root - * caused, it will be remove from the driver. - */ -#ifdef CONFIG_AM43XX - udelay(100); -#endif while (words) { u8 xfer_len = 0; -- cgit v1.2.3 From 08fe9c294f2d699a4e8b6b18e31169a89552f967 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Mon, 8 Aug 2016 17:12:12 +0530 Subject: spi: Use mode for rx mode flags Make rx mode flags as generic to spi, earlier mode_rx is maintained separately because of some flash specific code. Cc: Simon Glass Cc: Bin Meng Cc: Michal Simek Cc: Siva Durga Prasad Paladugu Cc: Vignesh R Cc: Mugunthan V N Signed-off-by: Jagan Teki --- drivers/mtd/spi/spi_flash.c | 6 +++--- drivers/spi/cadence_qspi.c | 2 +- drivers/spi/ich.c | 6 ++---- drivers/spi/spi-uclass.c | 11 ++++------- drivers/spi/ti_qspi.c | 6 +++--- include/spi.h | 14 ++++---------- 6 files changed, 17 insertions(+), 28 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 5fd408c93cd..041b64f8b31 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -1172,11 +1172,11 @@ int spi_flash_scan(struct spi_flash *flash) /* Look for read commands */ flash->read_cmd = CMD_READ_ARRAY_FAST; - if (spi->mode_rx & SPI_RX_SLOW) + if (spi->mode & SPI_RX_SLOW) flash->read_cmd = CMD_READ_ARRAY_SLOW; - else if (spi->mode_rx & SPI_RX_QUAD && params->flags & RD_QUAD) + else if (spi->mode & SPI_RX_QUAD && params->flags & RD_QUAD) flash->read_cmd = CMD_READ_QUAD_OUTPUT_FAST; - else if (spi->mode_rx & SPI_RX_DUAL && params->flags & RD_DUAL) + else if (spi->mode & SPI_RX_DUAL && params->flags & RD_DUAL) flash->read_cmd = CMD_READ_DUAL_OUTPUT_FAST; /* Look for write commands */ diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c index a5244fff4d9..1d50f135c9d 100644 --- a/drivers/spi/cadence_qspi.c +++ b/drivers/spi/cadence_qspi.c @@ -251,7 +251,7 @@ static int cadence_spi_xfer(struct udevice *dev, unsigned int bitlen, break; case CQSPI_INDIRECT_READ: err = cadence_qspi_apb_indirect_read_setup(plat, - priv->cmd_len, dm_plat->mode_rx, cmd_buf); + priv->cmd_len, dm_plat->mode, cmd_buf); if (!err) { err = cadence_qspi_apb_indirect_read_execute (plat, data_bytes, din); diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c index 00b2fed7b74..caf0103dc38 100644 --- a/drivers/spi/ich.c +++ b/drivers/spi/ich.c @@ -649,10 +649,8 @@ static int ich_spi_child_pre_probe(struct udevice *dev) * ICH 7 SPI controller only supports array read command * and byte program command for SST flash */ - if (plat->ich_version == ICHV_7) { - slave->mode_rx = SPI_RX_SLOW; - slave->mode = SPI_TX_BYTE; - } + if (plat->ich_version == ICHV_7) + slave->mode = SPI_RX_SLOW | SPI_TX_BYTE; return 0; } diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index 247abfa72ba..d9c49e4e8c2 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -164,7 +164,6 @@ static int spi_child_pre_probe(struct udevice *dev) slave->max_hz = plat->max_hz; slave->mode = plat->mode; - slave->mode_rx = plat->mode_rx; slave->wordlen = SPI_DEFAULT_WORDLEN; return 0; @@ -381,7 +380,7 @@ void spi_free_slave(struct spi_slave *slave) int spi_slave_ofdata_to_platdata(const void *blob, int node, struct dm_spi_slave_platdata *plat) { - int mode = 0, mode_rx = 0; + int mode = 0; int value; plat->cs = fdtdec_get_int(blob, node, "reg", -1); @@ -413,24 +412,22 @@ int spi_slave_ofdata_to_platdata(const void *blob, int node, break; } - plat->mode = mode; - value = fdtdec_get_uint(blob, node, "spi-rx-bus-width", 1); switch (value) { case 1: break; case 2: - mode_rx |= SPI_RX_DUAL; + mode |= SPI_RX_DUAL; break; case 4: - mode_rx |= SPI_RX_QUAD; + mode |= SPI_RX_QUAD; break; default: error("spi-rx-bus-width %d not supported\n", value); break; } - plat->mode_rx = mode_rx; + plat->mode = mode; return 0; } diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c index 406e76b8a78..52520dff632 100644 --- a/drivers/spi/ti_qspi.c +++ b/drivers/spi/ti_qspi.c @@ -356,7 +356,7 @@ static void ti_spi_setup_spi_register(struct ti_qspi_priv *priv) QSPI_SETUP0_NUM_D_BYTES_8_BITS | QSPI_SETUP0_READ_QUAD | QSPI_CMD_WRITE | QSPI_NUM_DUMMY_BITS); - slave->mode_rx = SPI_RX_QUAD; + slave->mode |= SPI_RX_QUAD; #else memval |= QSPI_CMD_READ | QSPI_SETUP0_NUM_A_BYTES | QSPI_SETUP0_NUM_D_BYTES_NO_BITS | @@ -442,7 +442,7 @@ static void __ti_qspi_setup_memorymap(struct ti_qspi_priv *priv, bool enable) { u32 memval; - u32 mode = slave->mode_rx & (SPI_RX_QUAD | SPI_RX_DUAL); + u32 mode = slave->mode & (SPI_RX_QUAD | SPI_RX_DUAL); if (!enable) { writel(0, &priv->base->setup0); @@ -456,7 +456,7 @@ static void __ti_qspi_setup_memorymap(struct ti_qspi_priv *priv, memval |= QSPI_CMD_READ_QUAD; memval |= QSPI_SETUP0_NUM_D_BYTES_8_BITS; memval |= QSPI_SETUP0_READ_QUAD; - slave->mode_rx = SPI_RX_QUAD; + slave->mode |= SPI_RX_QUAD; break; case SPI_RX_DUAL: memval |= QSPI_CMD_READ_DUAL; diff --git a/include/spi.h b/include/spi.h index ca96fa4b31b..b262e061a8b 100644 --- a/include/spi.h +++ b/include/spi.h @@ -26,12 +26,10 @@ #define SPI_TX_BYTE BIT(8) /* transmit with 1 wire byte */ #define SPI_TX_DUAL BIT(9) /* transmit with 2 wires */ #define SPI_TX_QUAD BIT(10) /* transmit with 4 wires */ - -/* SPI mode_rx flags */ -#define SPI_RX_SLOW BIT(0) /* receive with 1 wire slow */ -#define SPI_RX_FAST BIT(1) /* receive with 1 wire fast */ -#define SPI_RX_DUAL BIT(2) /* receive with 2 wires */ -#define SPI_RX_QUAD BIT(3) /* receive with 4 wires */ +#define SPI_RX_SLOW BIT(11) /* receive with 1 wire slow */ +#define SPI_RX_FAST BIT(12) /* receive with 1 wire fast */ +#define SPI_RX_DUAL BIT(13) /* receive with 2 wires */ +#define SPI_RX_QUAD BIT(14) /* receive with 4 wires */ /* SPI bus connection options - see enum spi_dual_flash */ #define SPI_CONN_DUAL_SHARED (1 << 0) @@ -61,13 +59,11 @@ struct dm_spi_bus { * @cs: Chip select number (0..n-1) * @max_hz: Maximum bus speed that this slave can tolerate * @mode: SPI mode to use for this device (see SPI mode flags) - * @mode_rx: SPI RX mode to use for this slave (see SPI mode_rx flags) */ struct dm_spi_slave_platdata { unsigned int cs; uint max_hz; uint mode; - u8 mode_rx; }; #endif /* CONFIG_DM_SPI */ @@ -94,7 +90,6 @@ struct dm_spi_slave_platdata { * bus (bus->seq) so does not need to be stored * @cs: ID of the chip select connected to the slave. * @mode: SPI mode to use for this slave (see SPI mode flags) - * @mode_rx: SPI RX mode to use for this slave (see SPI mode_rx flags) * @wordlen: Size of SPI word in number of bits * @max_write_size: If non-zero, the maximum number of bytes which can * be written at once, excluding command bytes. @@ -112,7 +107,6 @@ struct spi_slave { unsigned int cs; #endif uint mode; - u8 mode_rx; unsigned int wordlen; unsigned int max_write_size; void *memory_map; -- cgit v1.2.3 From 21b1dd18f1bedf9c725128bc2e84acb9958815fa Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Sat, 3 Sep 2016 12:58:33 +0530 Subject: spi: Kconfig: Move FSL_QSPI entry to non-dm place Since FSL_QSPI driver still supporting non-dm code better to move the Kconfig from DM undefined place. Cc: Stefano Babic Reviewed-by: Peng Fan Signed-off-by: Jagan Teki --- drivers/spi/Kconfig | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index aca385d5e59..5da66a6de0f 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -61,13 +61,6 @@ config FSL_DSPI this Freescale DSPI IP core. LS102xA and Colibri VF50/VF61 platforms use this driver. -config FSL_QSPI - bool "Freescale QSPI driver" - help - Enable the Freescale Quad-SPI (QSPI) driver. This driver can be - used to access the SPI NOR flash on platforms embedding this - Freescale IP core. - config ICH_SPI bool "Intel ICH SPI driver" help @@ -188,6 +181,13 @@ config FSL_ESPI access the SPI interface and SPI NOR flash on platforms embedding this Freescale eSPI IP core. +config FSL_QSPI + bool "Freescale QSPI driver" + help + Enable the Freescale Quad-SPI (QSPI) driver. This driver can be + used to access the SPI NOR flash on platforms embedding this + Freescale IP core. + config TI_QSPI bool "TI QSPI driver" help -- cgit v1.2.3