summaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/Kconfig26
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/atcspi200_spi.c87
-rw-r--r--drivers/spi/atmel_spi.c14
-rw-r--r--drivers/spi/designware_spi.c130
-rw-r--r--drivers/spi/mpc8xx_spi.c2
-rw-r--r--drivers/spi/omap3_spi.c31
-rw-r--r--drivers/spi/renesas_rpc_spi.c465
-rw-r--r--drivers/spi/sh_qspi.c119
-rw-r--r--drivers/spi/stm32_qspi.c1
10 files changed, 663 insertions, 213 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 235a8c7d73a..ec92b84ed28 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -23,6 +23,13 @@ config ALTERA_SPI
IP core. Please find details on the "Embedded Peripherals IP
User Guide" of Altera.
+config ATCSPI200_SPI
+ bool "Andestech ATCSPI200 SPI driver"
+ help
+ Enable the Andestech ATCSPI200 SPI driver. This driver can be
+ used to access the SPI flash on AE3XX and AE250 platforms embedding
+ this Andestech IP core.
+
config ATH79_SPI
bool "Atheros SPI driver"
depends on ARCH_ATH79
@@ -34,7 +41,7 @@ config ATH79_SPI
config ATMEL_SPI
bool "Atmel SPI driver"
- depends on ARCH_AT91
+ default y if ARCH_AT91
help
This enables driver for the Atmel SPI Controller, present on
many AT91 (ARM) chips. This driver can be used to access
@@ -107,6 +114,14 @@ config PIC32_SPI
to access the SPI NOR flash, MMC-over-SPI on platforms based on
Microchip PIC32 family devices.
+config RENESAS_RPC_SPI
+ bool "Renesas RPC SPI driver"
+ depends on RCAR_GEN3
+ help
+ Enable the Renesas RPC SPI driver, used to access SPI NOR flash
+ on Renesas RCar Gen3 SoCs. This uses driver model and requires a
+ device tree binding to operate.
+
config ROCKCHIP_SPI
bool "Rockchip SPI driver"
help
@@ -232,13 +247,6 @@ config FSL_QSPI
used to access the SPI NOR flash on platforms embedding this
Freescale IP core.
-config ATCSPI200_SPI
- bool "Andestech ATCSPI200 SPI driver"
- help
- Enable the Andestech ATCSPI200 SPI driver. This driver can be
- used to access the SPI flash on AE3XX and AE250 platforms embedding
- this Andestech IP core.
-
config DAVINCI_SPI
bool "Davinci & Keystone SPI driver"
depends on ARCH_DAVINCI || ARCH_KEYSTONE
@@ -276,7 +284,7 @@ config LPC32XX_SSP
config MPC8XX_SPI
bool "MPC8XX SPI Driver"
- depends on 8xx
+ depends on MPC8xx
help
Enable support for SPI on MPC8XX
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 4b6000fd9a0..176bfa05cf2 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_MXS_SPI) += mxs_spi.o
obj-$(CONFIG_ATCSPI200_SPI) += atcspi200_spi.o
obj-$(CONFIG_OMAP3_SPI) += omap3_spi.o
obj-$(CONFIG_PIC32_SPI) += pic32_spi.o
+obj-$(CONFIG_RENESAS_RPC_SPI) += renesas_rpc_spi.o
obj-$(CONFIG_ROCKCHIP_SPI) += rk_spi.o
obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o
obj-$(CONFIG_SH_SPI) += sh_spi.o
diff --git a/drivers/spi/atcspi200_spi.c b/drivers/spi/atcspi200_spi.c
index 5b2e9d6264b..bc08914b9eb 100644
--- a/drivers/spi/atcspi200_spi.c
+++ b/drivers/spi/atcspi200_spi.c
@@ -75,9 +75,6 @@ struct atcspi200_spi_regs {
};
struct nds_spi_slave {
-#ifndef CONFIG_DM_SPI
- struct spi_slave slave;
-#endif
volatile struct atcspi200_spi_regs *regs;
int to;
unsigned int freq;
@@ -286,89 +283,6 @@ static int __atcspi200_spi_xfer(struct nds_spi_slave *ns,
return ret;
}
-#ifndef CONFIG_DM_SPI
-#define to_nds_spi_slave(s) container_of(s, struct nds_spi_slave, slave)
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
- unsigned int max_hz, unsigned int mode)
-{
- struct nds_spi_slave *ns;
-
- if (!spi_cs_is_valid(bus, cs))
- return NULL;
-
- ns = spi_alloc_slave(struct nds_spi_slave, bus, cs);
- if (!ns)
- return NULL;
-
- switch (bus) {
- case SPI0_BUS:
- ns->regs = (struct atcspi200_spi_regs *)SPI0_BASE;
- break;
-
- case SPI1_BUS:
- ns->regs = (struct atcspi200_spi_regs *)SPI1_BASE;
- break;
-
- default:
- return NULL;
- }
-
- ns->freq= max_hz;
- ns->mode = mode;
- ns->to = SPI_TIMEOUT;
- ns->max_transfer_length = MAX_TRANSFER_LEN;
- ns->slave.max_write_size = MAX_TRANSFER_LEN;
-
- return &ns->slave;
-}
-
-void spi_free_slave(struct spi_slave *slave)
-{
- struct nds_spi_slave *ns = to_nds_spi_slave(slave);
- free(ns);
-}
-
-void spi_init(void)
-{
- /* do nothing */
-}
-
-int spi_claim_bus(struct spi_slave *slave)
-{
- struct nds_spi_slave *ns = to_nds_spi_slave(slave);
- return __atcspi200_spi_claim_bus(ns);
-}
-
-void spi_release_bus(struct spi_slave *slave)
-{
- struct nds_spi_slave *ns = to_nds_spi_slave(slave);
- __atcspi200_spi_release_bus(ns);
-}
-
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out,
- void *data_in, unsigned long flags)
-{
- struct nds_spi_slave *ns = to_nds_spi_slave(slave);
- return __atcspi200_spi_xfer(ns, bitlen, data_out, data_in, flags);
-}
-
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
- return bus == 0 && cs < NSPI_MAX_CS_NUM;
-}
-
-void spi_cs_activate(struct spi_slave *slave)
-{
- struct nds_spi_slave *ns = to_nds_spi_slave(slave);
- __atcspi200_spi_start(ns);
-}
-
-void spi_cs_deactivate(struct spi_slave *slave)
-{
- struct nds_spi_slave *ns = to_nds_spi_slave(slave);
- __atcspi200_spi_stop(ns);
-}
-#else
static int atcspi200_spi_set_speed(struct udevice *bus, uint max_hz)
{
struct nds_spi_slave *ns = dev_get_priv(bus);
@@ -496,4 +410,3 @@ U_BOOT_DRIVER(atcspi200_spi) = {
.priv_auto_alloc_size = sizeof(struct nds_spi_slave),
.probe = atcspi200_spi_probe,
};
-#endif
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 8010ab434c0..3cdfd366ab8 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -236,7 +236,9 @@ struct atmel_spi_priv {
unsigned int freq; /* Default frequency */
unsigned int mode;
ulong bus_clk_rate;
+#ifdef CONFIG_DM_GPIO
struct gpio_desc cs_gpios[MAX_CS_COUNT];
+#endif
};
static int atmel_spi_claim_bus(struct udevice *dev)
@@ -291,6 +293,7 @@ static int atmel_spi_release_bus(struct udevice *dev)
static void atmel_spi_cs_activate(struct udevice *dev)
{
+#ifdef CONFIG_DM_GPIO
struct udevice *bus = dev_get_parent(dev);
struct atmel_spi_priv *priv = dev_get_priv(bus);
struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
@@ -300,10 +303,12 @@ static void atmel_spi_cs_activate(struct udevice *dev)
return;
dm_gpio_set_value(&priv->cs_gpios[cs], 0);
+#endif
}
static void atmel_spi_cs_deactivate(struct udevice *dev)
{
+#ifdef CONFIG_DM_GPIO
struct udevice *bus = dev_get_parent(dev);
struct atmel_spi_priv *priv = dev_get_priv(bus);
struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
@@ -313,6 +318,7 @@ static void atmel_spi_cs_deactivate(struct udevice *dev)
return;
dm_gpio_set_value(&priv->cs_gpios[cs], 1);
+#endif
}
static int atmel_spi_xfer(struct udevice *dev, unsigned int bitlen,
@@ -462,8 +468,7 @@ static int atmel_spi_enable_clk(struct udevice *bus)
static int atmel_spi_probe(struct udevice *bus)
{
struct atmel_spi_platdata *bus_plat = dev_get_platdata(bus);
- struct atmel_spi_priv *priv = dev_get_priv(bus);
- int i, ret;
+ int ret;
ret = atmel_spi_enable_clk(bus);
if (ret)
@@ -471,6 +476,10 @@ static int atmel_spi_probe(struct udevice *bus)
bus_plat->regs = (struct at91_spi *)devfdt_get_addr(bus);
+#ifdef CONFIG_DM_GPIO
+ struct atmel_spi_priv *priv = dev_get_priv(bus);
+ int i;
+
ret = gpio_request_list_by_name(bus, "cs-gpios", priv->cs_gpios,
ARRAY_SIZE(priv->cs_gpios), 0);
if (ret < 0) {
@@ -485,6 +494,7 @@ static int atmel_spi_probe(struct udevice *bus)
dm_gpio_set_dir_flags(&priv->cs_gpios[i],
GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
}
+#endif
writel(ATMEL_SPI_CR_SWRST, &bus_plat->regs->cr);
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index c501aeea166..0e93b62eee1 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -10,6 +10,7 @@
* SPDX-License-Identifier: GPL-2.0
*/
+#include <asm-generic/gpio.h>
#include <common.h>
#include <clk.h>
#include <dm.h>
@@ -18,6 +19,7 @@
#include <spi.h>
#include <fdtdec.h>
#include <linux/compat.h>
+#include <linux/iopoll.h>
#include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -97,6 +99,8 @@ struct dw_spi_priv {
struct clk clk;
unsigned long bus_clk_rate;
+ struct gpio_desc cs_gpio; /* External chip-select gpio */
+
int bits_per_word;
u8 cs; /* chip select pin */
u8 tmode; /* TR/TO/RO/EEPROM */
@@ -110,24 +114,40 @@ struct dw_spi_priv {
void *rx_end;
};
-static inline u32 dw_readl(struct dw_spi_priv *priv, u32 offset)
+static inline u32 dw_read(struct dw_spi_priv *priv, u32 offset)
{
return __raw_readl(priv->regs + offset);
}
-static inline void dw_writel(struct dw_spi_priv *priv, u32 offset, u32 val)
+static inline void dw_write(struct dw_spi_priv *priv, u32 offset, u32 val)
{
__raw_writel(val, priv->regs + offset);
}
-static inline u16 dw_readw(struct dw_spi_priv *priv, u32 offset)
+static int request_gpio_cs(struct udevice *bus)
{
- return __raw_readw(priv->regs + offset);
-}
+#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_SPL_BUILD)
+ struct dw_spi_priv *priv = dev_get_priv(bus);
+ int ret;
-static inline void dw_writew(struct dw_spi_priv *priv, u32 offset, u16 val)
-{
- __raw_writew(val, priv->regs + offset);
+ /* External chip select gpio line is optional */
+ ret = gpio_request_by_name(bus, "cs-gpio", 0, &priv->cs_gpio, 0);
+ if (ret == -ENOENT)
+ return 0;
+
+ if (ret < 0) {
+ printf("Error: %d: Can't get %s gpio!\n", ret, bus->name);
+ return ret;
+ }
+
+ if (dm_gpio_is_valid(&priv->cs_gpio)) {
+ dm_gpio_set_dir_flags(&priv->cs_gpio,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+ }
+
+ debug("%s: used external gpio for CS management\n", __func__);
+#endif
+ return 0;
}
static int dw_spi_ofdata_to_platdata(struct udevice *bus)
@@ -144,19 +164,19 @@ static int dw_spi_ofdata_to_platdata(struct udevice *bus)
debug("%s: regs=%p max-frequency=%d\n", __func__, plat->regs,
plat->frequency);
- return 0;
+ return request_gpio_cs(bus);
}
static inline void spi_enable_chip(struct dw_spi_priv *priv, int enable)
{
- dw_writel(priv, DW_SPI_SSIENR, (enable ? 1 : 0));
+ dw_write(priv, DW_SPI_SSIENR, (enable ? 1 : 0));
}
/* Restart the controller, disable all interrupts, clean rx fifo */
static void spi_hw_init(struct dw_spi_priv *priv)
{
spi_enable_chip(priv, 0);
- dw_writel(priv, DW_SPI_IMR, 0xff);
+ dw_write(priv, DW_SPI_IMR, 0xff);
spi_enable_chip(priv, 1);
/*
@@ -167,13 +187,13 @@ static void spi_hw_init(struct dw_spi_priv *priv)
u32 fifo;
for (fifo = 1; fifo < 256; fifo++) {
- dw_writew(priv, DW_SPI_TXFLTR, fifo);
- if (fifo != dw_readw(priv, DW_SPI_TXFLTR))
+ dw_write(priv, DW_SPI_TXFLTR, fifo);
+ if (fifo != dw_read(priv, DW_SPI_TXFLTR))
break;
}
priv->fifo_len = (fifo == 1) ? 0 : fifo;
- dw_writew(priv, DW_SPI_TXFLTR, 0);
+ dw_write(priv, DW_SPI_TXFLTR, 0);
}
debug("%s: fifo_len=%d\n", __func__, priv->fifo_len);
}
@@ -242,7 +262,7 @@ static inline u32 tx_max(struct dw_spi_priv *priv)
u32 tx_left, tx_room, rxtx_gap;
tx_left = (priv->tx_end - priv->tx) / (priv->bits_per_word >> 3);
- tx_room = priv->fifo_len - dw_readw(priv, DW_SPI_TXFLR);
+ tx_room = priv->fifo_len - dw_read(priv, DW_SPI_TXFLR);
/*
* Another concern is about the tx/rx mismatch, we
@@ -263,7 +283,7 @@ static inline u32 rx_max(struct dw_spi_priv *priv)
{
u32 rx_left = (priv->rx_end - priv->rx) / (priv->bits_per_word >> 3);
- return min_t(u32, rx_left, dw_readw(priv, DW_SPI_RXFLR));
+ return min_t(u32, rx_left, dw_read(priv, DW_SPI_RXFLR));
}
static void dw_writer(struct dw_spi_priv *priv)
@@ -279,34 +299,22 @@ static void dw_writer(struct dw_spi_priv *priv)
else
txw = *(u16 *)(priv->tx);
}
- dw_writew(priv, DW_SPI_DR, txw);
+ dw_write(priv, DW_SPI_DR, txw);
debug("%s: tx=0x%02x\n", __func__, txw);
priv->tx += priv->bits_per_word >> 3;
}
}
-static int dw_reader(struct dw_spi_priv *priv)
+static void dw_reader(struct dw_spi_priv *priv)
{
- unsigned start = get_timer(0);
- u32 max;
+ u32 max = rx_max(priv);
u16 rxw;
- /* Wait for rx data to be ready */
- while (rx_max(priv) == 0) {
- if (get_timer(start) > RX_TIMEOUT)
- return -ETIMEDOUT;
- }
-
- max = rx_max(priv);
-
while (max--) {
- rxw = dw_readw(priv, DW_SPI_DR);
+ rxw = dw_read(priv, DW_SPI_DR);
debug("%s: rx=0x%02x\n", __func__, rxw);
- /*
- * Care about rx only if the transfer's original "rx" is
- * not null
- */
+ /* Care about rx if the transfer's original "rx" is not null */
if (priv->rx_end - priv->len) {
if (priv->bits_per_word == 8)
*(u8 *)(priv->rx) = rxw;
@@ -315,24 +323,30 @@ static int dw_reader(struct dw_spi_priv *priv)
}
priv->rx += priv->bits_per_word >> 3;
}
-
- return 0;
}
static int poll_transfer(struct dw_spi_priv *priv)
{
- int ret;
-
do {
dw_writer(priv);
- ret = dw_reader(priv);
- if (ret < 0)
- return ret;
+ dw_reader(priv);
} while (priv->rx_end > priv->rx);
return 0;
}
+static void external_cs_manage(struct udevice *dev, bool on)
+{
+#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_SPL_BUILD)
+ struct dw_spi_priv *priv = dev_get_priv(dev->parent);
+
+ if (!dm_gpio_is_valid(&priv->cs_gpio))
+ return;
+
+ dm_gpio_set_value(&priv->cs_gpio, on ? 1 : 0);
+#endif
+}
+
static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
@@ -342,6 +356,7 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
u8 *rx = din;
int ret = 0;
u32 cr0 = 0;
+ u32 val;
u32 cs;
/* spi core configured to do 8 bit transfers */
@@ -350,6 +365,10 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
return -1;
}
+ /* Start the transaction if necessary. */
+ if (flags & SPI_XFER_BEGIN)
+ external_cs_manage(dev, false);
+
cr0 = (priv->bits_per_word - 1) | (priv->type << SPI_FRF_OFFSET) |
(priv->mode << SPI_MODE_OFFSET) |
(priv->tmode << SPI_TMOD_OFFSET);
@@ -359,7 +378,11 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
else if (rx)
priv->tmode = SPI_TMOD_RO;
else
- priv->tmode = SPI_TMOD_TO;
+ /*
+ * In transmit only mode (SPI_TMOD_TO) input FIFO never gets
+ * any data which breaks our logic in poll_transfer() above.
+ */
+ priv->tmode = SPI_TMOD_TR;
cr0 &= ~SPI_TMOD_MASK;
cr0 |= (priv->tmode << SPI_TMOD_OFFSET);
@@ -377,8 +400,8 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
debug("%s: cr0=%08x\n", __func__, cr0);
/* Reprogram cr0 only if changed */
- if (dw_readw(priv, DW_SPI_CTRL0) != cr0)
- dw_writew(priv, DW_SPI_CTRL0, cr0);
+ if (dw_read(priv, DW_SPI_CTRL0) != cr0)
+ dw_write(priv, DW_SPI_CTRL0, cr0);
/*
* Configure the desired SS (slave select 0...3) in the controller
@@ -386,7 +409,7 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
* automatically. So no cs_activate() etc is needed in this driver.
*/
cs = spi_chip_select(dev);
- dw_writel(priv, DW_SPI_SER, 1 << cs);
+ dw_write(priv, DW_SPI_SER, 1 << cs);
/* Enable controller after writing control registers */
spi_enable_chip(priv, 1);
@@ -394,6 +417,23 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
/* Start transfer in a polling loop */
ret = poll_transfer(priv);
+ /*
+ * Wait for current transmit operation to complete.
+ * Otherwise if some data still exists in Tx FIFO it can be
+ * silently flushed, i.e. dropped on disabling of the controller,
+ * which happens when writing 0 to DW_SPI_SSIENR which happens
+ * in the beginning of new transfer.
+ */
+ if (readl_poll_timeout(priv->regs + DW_SPI_SR, val,
+ !(val & SR_TF_EMPT) || (val & SR_BUSY),
+ RX_TIMEOUT * 1000)) {
+ ret = -ETIMEDOUT;
+ }
+
+ /* Stop the transaction if necessary */
+ if (flags & SPI_XFER_END)
+ external_cs_manage(dev, true);
+
return ret;
}
@@ -412,7 +452,7 @@ static int dw_spi_set_speed(struct udevice *bus, uint speed)
/* clk_div doesn't support odd number */
clk_div = priv->bus_clk_rate / speed;
clk_div = (clk_div + 1) & 0xfffe;
- dw_writel(priv, DW_SPI_BAUDR, clk_div);
+ dw_write(priv, DW_SPI_BAUDR, clk_div);
/* Enable controller after writing control registers */
spi_enable_chip(priv, 1);
diff --git a/drivers/spi/mpc8xx_spi.c b/drivers/spi/mpc8xx_spi.c
index b5bd558526b..eb035e9510c 100644
--- a/drivers/spi/mpc8xx_spi.c
+++ b/drivers/spi/mpc8xx_spi.c
@@ -19,7 +19,7 @@
#include <common.h>
#include <mpc8xx.h>
-#include <commproc.h>
+#include <asm/cpm_8xx.h>
#include <linux/ctype.h>
#include <malloc.h>
#include <post.h>
diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c
index 1da4542af0d..1ac691a68e7 100644
--- a/drivers/spi/omap3_spi.c
+++ b/drivers/spi/omap3_spi.c
@@ -456,9 +456,6 @@ static void _omap3_spi_claim_bus(struct omap3_spi_priv *priv)
conf |= OMAP3_MCSPI_MODULCTRL_SINGLE;
writel(conf, &priv->regs->modulctrl);
-
- _omap3_spi_set_mode(priv);
- _omap3_spi_set_speed(priv);
}
#ifndef CONFIG_DM_SPI
@@ -594,8 +591,6 @@ static int omap3_spi_claim_bus(struct udevice *dev)
struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
priv->cs = slave_plat->cs;
- priv->mode = slave_plat->mode;
- priv->freq = slave_plat->max_hz;
_omap3_spi_claim_bus(priv);
return 0;
@@ -635,8 +630,10 @@ static int omap3_spi_probe(struct udevice *dev)
(struct omap2_mcspi_platform_config*)dev_get_driver_data(dev);
priv->regs = (struct mcspi *)(devfdt_get_addr(dev) + data->regs_offset);
- priv->pin_dir = fdtdec_get_uint(blob, node, "ti,pindir-d0-out-d1-in",
- MCSPI_PINDIR_D0_IN_D1_OUT);
+ if (fdtdec_get_bool(blob, node, "ti,pindir-d0-out-d1-in"))
+ priv->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN;
+ else
+ priv->pin_dir = MCSPI_PINDIR_D0_IN_D1_OUT;
priv->wordlen = SPI_DEFAULT_WORDLEN;
return 0;
}
@@ -650,13 +647,29 @@ static int omap3_spi_xfer(struct udevice *dev, unsigned int bitlen,
return _spi_xfer(priv, bitlen, dout, din, flags);
}
-static int omap3_spi_set_speed(struct udevice *bus, unsigned int speed)
+static int omap3_spi_set_speed(struct udevice *dev, unsigned int speed)
{
+ struct udevice *bus = dev->parent;
+ struct omap3_spi_priv *priv = dev_get_priv(bus);
+ struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
+
+ priv->cs = slave_plat->cs;
+ priv->freq = slave_plat->max_hz;
+ _omap3_spi_set_speed(priv);
+
return 0;
}
-static int omap3_spi_set_mode(struct udevice *bus, uint mode)
+static int omap3_spi_set_mode(struct udevice *dev, uint mode)
{
+ struct udevice *bus = dev->parent;
+ struct omap3_spi_priv *priv = dev_get_priv(bus);
+ struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
+
+ priv->cs = slave_plat->cs;
+ priv->mode = slave_plat->mode;
+ _omap3_spi_set_mode(priv);
+
return 0;
}
diff --git a/drivers/spi/renesas_rpc_spi.c b/drivers/spi/renesas_rpc_spi.c
new file mode 100644
index 00000000000..e54f24c5d89
--- /dev/null
+++ b/drivers/spi/renesas_rpc_spi.c
@@ -0,0 +1,465 @@
+/*
+ * Renesas RCar Gen3 RPC QSPI driver
+ *
+ * Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/of_access.h>
+#include <dt-structs.h>
+#include <errno.h>
+#include <linux/errno.h>
+#include <spi.h>
+#include <wait_bit.h>
+
+#define RPC_CMNCR 0x0000 /* R/W */
+#define RPC_CMNCR_MD BIT(31)
+#define RPC_CMNCR_SFDE BIT(24)
+#define RPC_CMNCR_MOIIO3(val) (((val) & 0x3) << 22)
+#define RPC_CMNCR_MOIIO2(val) (((val) & 0x3) << 20)
+#define RPC_CMNCR_MOIIO1(val) (((val) & 0x3) << 18)
+#define RPC_CMNCR_MOIIO0(val) (((val) & 0x3) << 16)
+#define RPC_CMNCR_MOIIO_HIZ (RPC_CMNCR_MOIIO0(3) | RPC_CMNCR_MOIIO1(3) | \
+ RPC_CMNCR_MOIIO2(3) | RPC_CMNCR_MOIIO3(3))
+#define RPC_CMNCR_IO3FV(val) (((val) & 0x3) << 14)
+#define RPC_CMNCR_IO2FV(val) (((val) & 0x3) << 12)
+#define RPC_CMNCR_IO0FV(val) (((val) & 0x3) << 8)
+#define RPC_CMNCR_IOFV_HIZ (RPC_CMNCR_IO0FV(3) | RPC_CMNCR_IO2FV(3) | \
+ RPC_CMNCR_IO3FV(3))
+#define RPC_CMNCR_CPHAT BIT(6)
+#define RPC_CMNCR_CPHAR BIT(5)
+#define RPC_CMNCR_SSLP BIT(4)
+#define RPC_CMNCR_CPOL BIT(3)
+#define RPC_CMNCR_BSZ(val) (((val) & 0x3) << 0)
+
+#define RPC_SSLDR 0x0004 /* R/W */
+#define RPC_SSLDR_SPNDL(d) (((d) & 0x7) << 16)
+#define RPC_SSLDR_SLNDL(d) (((d) & 0x7) << 8)
+#define RPC_SSLDR_SCKDL(d) (((d) & 0x7) << 0)
+
+#define RPC_DRCR 0x000C /* R/W */
+#define RPC_DRCR_SSLN BIT(24)
+#define RPC_DRCR_RBURST(v) (((v) & 0x1F) << 16)
+#define RPC_DRCR_RCF BIT(9)
+#define RPC_DRCR_RBE BIT(8)
+#define RPC_DRCR_SSLE BIT(0)
+
+#define RPC_DRCMR 0x0010 /* R/W */
+#define RPC_DRCMR_CMD(c) (((c) & 0xFF) << 16)
+#define RPC_DRCMR_OCMD(c) (((c) & 0xFF) << 0)
+
+#define RPC_DREAR 0x0014 /* R/W */
+#define RPC_DREAR_EAV(v) (((v) & 0xFF) << 16)
+#define RPC_DREAR_EAC(v) (((v) & 0x7) << 0)
+
+#define RPC_DROPR 0x0018 /* R/W */
+#define RPC_DROPR_OPD3(o) (((o) & 0xFF) << 24)
+#define RPC_DROPR_OPD2(o) (((o) & 0xFF) << 16)
+#define RPC_DROPR_OPD1(o) (((o) & 0xFF) << 8)
+#define RPC_DROPR_OPD0(o) (((o) & 0xFF) << 0)
+
+#define RPC_DRENR 0x001C /* R/W */
+#define RPC_DRENR_CDB(o) (u32)((((o) & 0x3) << 30))
+#define RPC_DRENR_OCDB(o) (((o) & 0x3) << 28)
+#define RPC_DRENR_ADB(o) (((o) & 0x3) << 24)
+#define RPC_DRENR_OPDB(o) (((o) & 0x3) << 20)
+#define RPC_DRENR_SPIDB(o) (((o) & 0x3) << 16)
+#define RPC_DRENR_DME BIT(15)
+#define RPC_DRENR_CDE BIT(14)
+#define RPC_DRENR_OCDE BIT(12)
+#define RPC_DRENR_ADE(v) (((v) & 0xF) << 8)
+#define RPC_DRENR_OPDE(v) (((v) & 0xF) << 4)
+
+#define RPC_SMCR 0x0020 /* R/W */
+#define RPC_SMCR_SSLKP BIT(8)
+#define RPC_SMCR_SPIRE BIT(2)
+#define RPC_SMCR_SPIWE BIT(1)
+#define RPC_SMCR_SPIE BIT(0)
+
+#define RPC_SMCMR 0x0024 /* R/W */
+#define RPC_SMCMR_CMD(c) (((c) & 0xFF) << 16)
+#define RPC_SMCMR_OCMD(c) (((c) & 0xFF) << 0)
+
+#define RPC_SMADR 0x0028 /* R/W */
+#define RPC_SMOPR 0x002C /* R/W */
+#define RPC_SMOPR_OPD0(o) (((o) & 0xFF) << 0)
+#define RPC_SMOPR_OPD1(o) (((o) & 0xFF) << 8)
+#define RPC_SMOPR_OPD2(o) (((o) & 0xFF) << 16)
+#define RPC_SMOPR_OPD3(o) (((o) & 0xFF) << 24)
+
+#define RPC_SMENR 0x0030 /* R/W */
+#define RPC_SMENR_CDB(o) (((o) & 0x3) << 30)
+#define RPC_SMENR_OCDB(o) (((o) & 0x3) << 28)
+#define RPC_SMENR_ADB(o) (((o) & 0x3) << 24)
+#define RPC_SMENR_OPDB(o) (((o) & 0x3) << 20)
+#define RPC_SMENR_SPIDB(o) (((o) & 0x3) << 16)
+#define RPC_SMENR_DME BIT(15)
+#define RPC_SMENR_CDE BIT(14)
+#define RPC_SMENR_OCDE BIT(12)
+#define RPC_SMENR_ADE(v) (((v) & 0xF) << 8)
+#define RPC_SMENR_OPDE(v) (((v) & 0xF) << 4)
+#define RPC_SMENR_SPIDE(v) (((v) & 0xF) << 0)
+
+#define RPC_SMRDR0 0x0038 /* R */
+#define RPC_SMRDR1 0x003C /* R */
+#define RPC_SMWDR0 0x0040 /* R/W */
+#define RPC_SMWDR1 0x0044 /* R/W */
+#define RPC_CMNSR 0x0048 /* R */
+#define RPC_CMNSR_SSLF BIT(1)
+#define RPC_CMNSR_TEND BIT(0)
+
+#define RPC_DRDMCR 0x0058 /* R/W */
+#define RPC_DRDMCR_DMCYC(v) (((v) & 0xF) << 0)
+
+#define RPC_DRDRENR 0x005C /* R/W */
+#define RPC_DRDRENR_HYPE (0x5 << 12)
+#define RPC_DRDRENR_ADDRE BIT(8)
+#define RPC_DRDRENR_OPDRE BIT(4)
+#define RPC_DRDRENR_DRDRE BIT(0)
+
+#define RPC_SMDMCR 0x0060 /* R/W */
+#define RPC_SMDMCR_DMCYC(v) (((v) & 0xF) << 0)
+
+#define RPC_SMDRENR 0x0064 /* R/W */
+#define RPC_SMDRENR_HYPE (0x5 << 12)
+#define RPC_SMDRENR_ADDRE BIT(8)
+#define RPC_SMDRENR_OPDRE BIT(4)
+#define RPC_SMDRENR_SPIDRE BIT(0)
+
+#define RPC_PHYCNT 0x007C /* R/W */
+#define RPC_PHYCNT_CAL BIT(31)
+#define PRC_PHYCNT_OCTA_AA BIT(22)
+#define PRC_PHYCNT_OCTA_SA BIT(23)
+#define PRC_PHYCNT_EXDS BIT(21)
+#define RPC_PHYCNT_OCT BIT(20)
+#define RPC_PHYCNT_STRTIM(v) (((v) & 0x7) << 15)
+#define RPC_PHYCNT_WBUF2 BIT(4)
+#define RPC_PHYCNT_WBUF BIT(2)
+#define RPC_PHYCNT_MEM(v) (((v) & 0x3) << 0)
+
+#define RPC_PHYINT 0x0088 /* R/W */
+#define RPC_PHYINT_RSTEN BIT(18)
+#define RPC_PHYINT_WPEN BIT(17)
+#define RPC_PHYINT_INTEN BIT(16)
+#define RPC_PHYINT_RST BIT(2)
+#define RPC_PHYINT_WP BIT(1)
+#define RPC_PHYINT_INT BIT(0)
+
+#define RPC_WBUF 0x8000 /* R/W size=4/8/16/32/64Bytes */
+#define RPC_WBUF_SIZE 0x100
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct rpc_spi_platdata {
+ fdt_addr_t regs;
+ fdt_addr_t extr;
+ s32 freq; /* Default clock freq, -1 for none */
+};
+
+struct rpc_spi_priv {
+ fdt_addr_t regs;
+ fdt_addr_t extr;
+ struct clk clk;
+
+ u8 cmdcopy[8];
+ u32 cmdlen;
+ bool cmdstarted;
+};
+
+static int rpc_spi_wait_sslf(struct udevice *dev)
+{
+ struct rpc_spi_priv *priv = dev_get_priv(dev->parent);
+
+ return wait_for_bit_le32((void *)priv->regs + RPC_CMNSR, RPC_CMNSR_SSLF,
+ false, 1000, false);
+}
+
+static int rpc_spi_wait_tend(struct udevice *dev)
+{
+ struct rpc_spi_priv *priv = dev_get_priv(dev->parent);
+
+ return wait_for_bit_le32((void *)priv->regs + RPC_CMNSR, RPC_CMNSR_TEND,
+ true, 1000, false);
+}
+
+static void rpc_spi_flush_read_cache(struct udevice *dev)
+{
+ struct udevice *bus = dev->parent;
+ struct rpc_spi_priv *priv = dev_get_priv(bus);
+
+ /* Flush read cache */
+ writel(RPC_DRCR_SSLN | RPC_DRCR_RBURST(0x1f) |
+ RPC_DRCR_RCF | RPC_DRCR_RBE | RPC_DRCR_SSLE,
+ priv->regs + RPC_DRCR);
+ readl(priv->regs + RPC_DRCR);
+
+}
+
+static int rpc_spi_claim_bus(struct udevice *dev, bool manual)
+{
+ struct udevice *bus = dev->parent;
+ struct rpc_spi_priv *priv = dev_get_priv(bus);
+
+ /*
+ * NOTE: The 0x260 are undocumented bits, but they must be set.
+ * NOTE: On H3 ES1.x (not supported in mainline U-Boot), the
+ * RPC_PHYCNT_STRTIM shall be 0, while on newer parts, the
+ * RPC_PHYCNT_STRTIM shall be 6.
+ */
+ writel(RPC_PHYCNT_CAL | RPC_PHYCNT_STRTIM(6) | 0x260,
+ priv->regs + RPC_PHYCNT);
+ writel((manual ? RPC_CMNCR_MD : 0) | RPC_CMNCR_SFDE |
+ RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ | RPC_CMNCR_BSZ(0),
+ priv->regs + RPC_CMNCR);
+
+ writel(RPC_SSLDR_SPNDL(7) | RPC_SSLDR_SLNDL(7) |
+ RPC_SSLDR_SCKDL(7), priv->regs + RPC_SSLDR);
+
+ rpc_spi_flush_read_cache(dev);
+
+ return 0;
+}
+
+static int rpc_spi_release_bus(struct udevice *dev)
+{
+ struct udevice *bus = dev->parent;
+ struct rpc_spi_priv *priv = dev_get_priv(bus);
+
+ /* NOTE: The 0x260 are undocumented bits, but they must be set. */
+ writel(RPC_PHYCNT_STRTIM(6) | 0x260, priv->regs + RPC_PHYCNT);
+
+ rpc_spi_flush_read_cache(dev);
+
+ return 0;
+}
+
+static int rpc_spi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct udevice *bus = dev->parent;
+ struct rpc_spi_priv *priv = dev_get_priv(bus);
+ u32 wlen = dout ? (bitlen / 8) : 0;
+ u32 rlen = din ? (bitlen / 8) : 0;
+ u32 wloop = DIV_ROUND_UP(wlen, 4);
+ u32 smenr, smcr, offset;
+ int ret = 0;
+
+ if (!priv->cmdstarted) {
+ if (!wlen || rlen)
+ BUG();
+
+ memcpy(priv->cmdcopy, dout, wlen);
+ priv->cmdlen = wlen;
+
+ /* Command transfer start */
+ priv->cmdstarted = true;
+ if (!(flags & SPI_XFER_END))
+ return 0;
+ }
+
+ offset = (priv->cmdcopy[1] << 16) | (priv->cmdcopy[2] << 8) |
+ (priv->cmdcopy[3] << 0);
+
+ smenr = 0;
+
+ if (wlen || (!rlen && !wlen) || flags == SPI_XFER_ONCE) {
+ if (wlen && flags == SPI_XFER_END)
+ smenr = RPC_SMENR_SPIDE(0xf);
+
+ rpc_spi_claim_bus(dev, true);
+
+ writel(0, priv->regs + RPC_SMCR);
+
+ if (priv->cmdlen >= 1) { /* Command(1) */
+ writel(RPC_SMCMR_CMD(priv->cmdcopy[0]),
+ priv->regs + RPC_SMCMR);
+ smenr |= RPC_SMENR_CDE;
+ } else {
+ writel(0, priv->regs + RPC_SMCMR);
+ }
+
+ if (priv->cmdlen >= 4) { /* Address(3) */
+ writel(offset, priv->regs + RPC_SMADR);
+ smenr |= RPC_SMENR_ADE(7);
+ } else {
+ writel(0, priv->regs + RPC_SMADR);
+ }
+
+ if (priv->cmdlen >= 5) { /* Dummy(n) */
+ writel(8 * (priv->cmdlen - 4) - 1,
+ priv->regs + RPC_SMDMCR);
+ smenr |= RPC_SMENR_DME;
+ } else {
+ writel(0, priv->regs + RPC_SMDMCR);
+ }
+
+ writel(0, priv->regs + RPC_SMOPR);
+
+ writel(0, priv->regs + RPC_SMDRENR);
+
+ if (wlen && flags == SPI_XFER_END) {
+ u32 *datout = (u32 *)dout;
+
+ while (wloop--) {
+ smcr = RPC_SMCR_SPIWE | RPC_SMCR_SPIE;
+ if (wloop >= 1)
+ smcr |= RPC_SMCR_SSLKP;
+ writel(smenr, priv->regs + RPC_SMENR);
+ writel(*datout, priv->regs + RPC_SMWDR0);
+ writel(smcr, priv->regs + RPC_SMCR);
+ ret = rpc_spi_wait_tend(dev);
+ if (ret)
+ goto err;
+ datout++;
+ smenr = RPC_SMENR_SPIDE(0xf);
+ }
+
+ ret = rpc_spi_wait_sslf(dev);
+
+ } else {
+ writel(smenr, priv->regs + RPC_SMENR);
+ writel(RPC_SMCR_SPIE, priv->regs + RPC_SMCR);
+ ret = rpc_spi_wait_tend(dev);
+ }
+ } else { /* Read data only, using DRx ext access */
+ rpc_spi_claim_bus(dev, false);
+
+ if (priv->cmdlen >= 1) { /* Command(1) */
+ writel(RPC_DRCMR_CMD(priv->cmdcopy[0]),
+ priv->regs + RPC_DRCMR);
+ smenr |= RPC_DRENR_CDE;
+ } else {
+ writel(0, priv->regs + RPC_DRCMR);
+ }
+
+ if (priv->cmdlen >= 4) /* Address(3) */
+ smenr |= RPC_DRENR_ADE(7);
+
+ if (priv->cmdlen >= 5) { /* Dummy(n) */
+ writel(8 * (priv->cmdlen - 4) - 1,
+ priv->regs + RPC_DRDMCR);
+ smenr |= RPC_DRENR_DME;
+ } else {
+ writel(0, priv->regs + RPC_DRDMCR);
+ }
+
+ writel(0, priv->regs + RPC_DROPR);
+
+ writel(smenr, priv->regs + RPC_DRENR);
+
+ if (rlen)
+ memcpy_fromio(din, (void *)(priv->extr + offset), rlen);
+ else
+ readl(priv->extr); /* Dummy read */
+ }
+
+err:
+ priv->cmdstarted = false;
+
+ rpc_spi_release_bus(dev);
+
+ return ret;
+}
+
+static int rpc_spi_set_speed(struct udevice *bus, uint speed)
+{
+ /* This is a SPI NOR controller, do nothing. */
+ return 0;
+}
+
+static int rpc_spi_set_mode(struct udevice *bus, uint mode)
+{
+ /* This is a SPI NOR controller, do nothing. */
+ return 0;
+}
+
+static int rpc_spi_bind(struct udevice *parent)
+{
+ const void *fdt = gd->fdt_blob;
+ ofnode node;
+ int ret, off;
+
+ /*
+ * Check if there are any SPI NOR child nodes, if so, bind as
+ * this controller will be operated in SPI mode.
+ */
+ dev_for_each_subnode(node, parent) {
+ off = ofnode_to_offset(node);
+
+ ret = fdt_node_check_compatible(fdt, off, "spi-flash");
+ if (!ret)
+ return 0;
+
+ ret = fdt_node_check_compatible(fdt, off, "jedec,spi-nor");
+ if (!ret)
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+static int rpc_spi_probe(struct udevice *dev)
+{
+ struct rpc_spi_platdata *plat = dev_get_platdata(dev);
+ struct rpc_spi_priv *priv = dev_get_priv(dev);
+
+ priv->regs = plat->regs;
+ priv->extr = plat->extr;
+
+ clk_enable(&priv->clk);
+
+ return 0;
+}
+
+static int rpc_spi_ofdata_to_platdata(struct udevice *bus)
+{
+ struct rpc_spi_platdata *plat = dev_get_platdata(bus);
+ struct rpc_spi_priv *priv = dev_get_priv(bus);
+ int ret;
+
+ plat->regs = dev_read_addr_index(bus, 0);
+ plat->extr = dev_read_addr_index(bus, 1);
+
+ ret = clk_get_by_index(bus, 0, &priv->clk);
+ if (ret < 0) {
+ printf("%s: Could not get clock for %s: %d\n",
+ __func__, bus->name, ret);
+ return ret;
+ }
+
+ plat->freq = dev_read_u32_default(bus, "spi-max-freq", 50000000);
+
+ return 0;
+}
+
+static const struct dm_spi_ops rpc_spi_ops = {
+ .xfer = rpc_spi_xfer,
+ .set_speed = rpc_spi_set_speed,
+ .set_mode = rpc_spi_set_mode,
+};
+
+static const struct udevice_id rpc_spi_ids[] = {
+ { .compatible = "renesas,rpc-r8a7795" },
+ { .compatible = "renesas,rpc-r8a7796" },
+ { .compatible = "renesas,rpc-r8a77965" },
+ { .compatible = "renesas,rpc-r8a77970" },
+ { .compatible = "renesas,rpc-r8a77995" },
+ { }
+};
+
+U_BOOT_DRIVER(rpc_spi) = {
+ .name = "rpc_spi",
+ .id = UCLASS_SPI,
+ .of_match = rpc_spi_ids,
+ .ops = &rpc_spi_ops,
+ .ofdata_to_platdata = rpc_spi_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct rpc_spi_platdata),
+ .priv_auto_alloc_size = sizeof(struct rpc_spi_priv),
+ .bind = rpc_spi_bind,
+ .probe = rpc_spi_probe,
+};
diff --git a/drivers/spi/sh_qspi.c b/drivers/spi/sh_qspi.c
index 75999c812d5..5075be3cd13 100644
--- a/drivers/spi/sh_qspi.c
+++ b/drivers/spi/sh_qspi.c
@@ -11,6 +11,7 @@
#include <console.h>
#include <malloc.h>
#include <spi.h>
+#include <wait_bit.h>
#include <asm/arch/rmobile.h>
#include <asm/io.h>
@@ -35,33 +36,35 @@
SPCMD_BRDV0
#define SPBFCR_TXRST BIT(7)
#define SPBFCR_RXRST BIT(6)
+#define SPBFCR_TXTRG 0x30
+#define SPBFCR_RXTRG 0x07
/* SH QSPI register set */
struct sh_qspi_regs {
- unsigned char spcr;
- unsigned char sslp;
- unsigned char sppcr;
- unsigned char spsr;
- unsigned long spdr;
- unsigned char spscr;
- unsigned char spssr;
- unsigned char spbr;
- unsigned char spdcr;
- unsigned char spckd;
- unsigned char sslnd;
- unsigned char spnd;
- unsigned char dummy0;
- unsigned short spcmd0;
- unsigned short spcmd1;
- unsigned short spcmd2;
- unsigned short spcmd3;
- unsigned char spbfcr;
- unsigned char dummy1;
- unsigned short spbdcr;
- unsigned long spbmul0;
- unsigned long spbmul1;
- unsigned long spbmul2;
- unsigned long spbmul3;
+ u8 spcr;
+ u8 sslp;
+ u8 sppcr;
+ u8 spsr;
+ u32 spdr;
+ u8 spscr;
+ u8 spssr;
+ u8 spbr;
+ u8 spdcr;
+ u8 spckd;
+ u8 sslnd;
+ u8 spnd;
+ u8 dummy0;
+ u16 spcmd0;
+ u16 spcmd1;
+ u16 spcmd2;
+ u16 spcmd3;
+ u8 spbfcr;
+ u8 dummy1;
+ u16 spbdcr;
+ u32 spbmul0;
+ u32 spbmul1;
+ u32 spbmul2;
+ u32 spbmul3;
};
struct sh_qspi_slave {
@@ -200,11 +203,11 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
void *din, unsigned long flags)
{
struct sh_qspi_slave *ss = to_sh_qspi(slave);
- unsigned long nbyte;
- int ret = 0;
- unsigned char dtdata = 0, drdata;
- unsigned char *tdata = &dtdata, *rdata = &drdata;
- unsigned long *spbmul0 = &ss->regs->spbmul0;
+ u32 nbyte, chunk;
+ int i, ret = 0;
+ u8 dtdata = 0, drdata;
+ u8 *tdata = &dtdata, *rdata = &drdata;
+ u32 *spbmul0 = &ss->regs->spbmul0;
if (dout == NULL && din == NULL) {
if (flags & SPI_XFER_END)
@@ -230,46 +233,44 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
writel(nbyte, spbmul0);
if (dout != NULL)
- tdata = (unsigned char *)dout;
+ tdata = (u8 *)dout;
if (din != NULL)
rdata = din;
while (nbyte > 0) {
- while (!(readb(&ss->regs->spsr) & SPSR_SPTEF)) {
- if (ctrlc()) {
- puts("abort\n");
- return 1;
- }
- udelay(10);
+ /*
+ * Check if there is 32 Byte chunk and if there is, transfer
+ * it in one burst, otherwise transfer on byte-by-byte basis.
+ */
+ chunk = (nbyte >= 32) ? 32 : 1;
+
+ clrsetbits_8(&ss->regs->spbfcr, SPBFCR_TXTRG | SPBFCR_RXTRG,
+ chunk == 32 ? SPBFCR_TXTRG | SPBFCR_RXTRG : 0);
+
+ ret = wait_for_bit_8(&ss->regs->spsr, SPSR_SPTEF,
+ true, 1000, true);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < chunk; i++) {
+ writeb(*tdata, &ss->regs->spdr);
+ if (dout != NULL)
+ tdata++;
}
- writeb(*tdata, (unsigned char *)(&ss->regs->spdr));
+ ret = wait_for_bit_8(&ss->regs->spsr, SPSR_SPRFF,
+ true, 1000, true);
+ if (ret)
+ return ret;
- while ((readw(&ss->regs->spbdcr) != SPBDCR_RXBC0)) {
- if (ctrlc()) {
- puts("abort\n");
- return 1;
- }
- udelay(1);
+ for (i = 0; i < chunk; i++) {
+ *rdata = readb(&ss->regs->spdr);
+ if (din != NULL)
+ rdata++;
}
- while (!(readb(&ss->regs->spsr) & SPSR_SPRFF)) {
- if (ctrlc()) {
- puts("abort\n");
- return 1;
- }
- udelay(10);
- }
-
- *rdata = readb((unsigned char *)(&ss->regs->spdr));
-
- if (dout != NULL)
- tdata++;
- if (din != NULL)
- rdata++;
-
- nbyte--;
+ nbyte -= chunk;
}
if (flags & SPI_XFER_END)
diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c
index ef2b64ec5fb..558708a4a7b 100644
--- a/drivers/spi/stm32_qspi.c
+++ b/drivers/spi/stm32_qspi.c
@@ -16,7 +16,6 @@
#include <dm.h>
#include <errno.h>
#include <asm/arch/stm32.h>
-#include <asm/arch/stm32_defs.h>
#include <clk.h>
DECLARE_GLOBAL_DATA_PTR;