aboutsummaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/Kconfig41
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/exynos_spi.c6
-rw-r--r--drivers/spi/fsl_dspi.c737
-rw-r--r--drivers/spi/fsl_qspi.c985
-rw-r--r--drivers/spi/ich.c522
-rw-r--r--drivers/spi/omap3_spi.c20
-rw-r--r--drivers/spi/spi-uclass.c8
-rw-r--r--drivers/spi/tegra114_spi.c3
-rw-r--r--drivers/spi/tegra20_sflash.c3
-rw-r--r--drivers/spi/tegra20_slink.c3
-rw-r--r--drivers/spi/zynq_spi.c3
12 files changed, 1728 insertions, 604 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 7ae2727..357a335 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -10,3 +10,44 @@ config DM_SPI
as 'parent data' to every slave on each bus. Slaves
typically use driver-private data instead of extending the
spi_slave structure.
+
+config SANDBOX_SPI
+ bool "Sandbox SPI driver"
+ depends on SANDBOX && DM
+ help
+ Enable SPI support for sandbox. This is an emulation of a real SPI
+ bus. Devices can be attached to the bus using the device tree
+ which specifies the driver to use. As an example, see this device
+ tree fragment from sandbox.dts. It shows that the SPI bus has a
+ single flash device on chip select 0 which is emulated by the driver
+ for "sandbox,spi-flash", which is in drivers/mtd/spi/sandbox.c.
+
+ spi@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ compatible = "sandbox,spi";
+ cs-gpios = <0>, <&gpio_a 0>;
+ flash@0 {
+ reg = <0>;
+ compatible = "spansion,m25p16", "sandbox,spi-flash";
+ spi-max-frequency = <40000000>;
+ sandbox,filename = "spi.bin";
+ };
+ };
+
+config DESIGNWARE_SPI
+ bool "Designware SPI driver"
+ depends on DM_SPI
+ help
+ Enable the Designware SPI driver. This driver can be used to
+ access the SPI NOR flash on platforms embedding this Designware
+ IP core.
+
+config CADENCE_QSPI
+ bool "Cadence QSPI driver"
+ depends on DM_SPI
+ help
+ Enable the Cadence Quad-SPI (QSPI) driver. This driver can be
+ used to access the SPI NOR flash on platforms embedding this
+ Cadence IP core.
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index ce6f1cc..e288692 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -50,3 +50,4 @@ obj-$(CONFIG_TI_QSPI) += ti_qspi.o
obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o
obj-$(CONFIG_ZYNQ_SPI) += zynq_spi.o
obj-$(CONFIG_FSL_QSPI) += fsl_qspi.o
+obj-$(CONFIG_FSL_DSPI) += fsl_dspi.o
diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c
index a46d8c1..67f6b2d 100644
--- a/drivers/spi/exynos_spi.c
+++ b/drivers/spi/exynos_spi.c
@@ -296,8 +296,9 @@ static int exynos_spi_probe(struct udevice *bus)
return 0;
}
-static int exynos_spi_claim_bus(struct udevice *bus)
+static int exynos_spi_claim_bus(struct udevice *dev)
{
+ struct udevice *bus = dev->parent;
struct exynos_spi_priv *priv = dev_get_priv(bus);
exynos_pinmux_config(priv->periph_id, PINMUX_FLAG_NONE);
@@ -308,8 +309,9 @@ static int exynos_spi_claim_bus(struct udevice *bus)
return 0;
}
-static int exynos_spi_release_bus(struct udevice *bus)
+static int exynos_spi_release_bus(struct udevice *dev)
{
+ struct udevice *bus = dev->parent;
struct exynos_spi_priv *priv = dev_get_priv(bus);
spi_flush_fifo(priv->regs);
diff --git a/drivers/spi/fsl_dspi.c b/drivers/spi/fsl_dspi.c
new file mode 100644
index 0000000..6476f91
--- /dev/null
+++ b/drivers/spi/fsl_dspi.c
@@ -0,0 +1,737 @@
+/*
+ * (C) Copyright 2000-2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (C) 2004-2009, 2015 Freescale Semiconductor, Inc.
+ * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
+ * Chao Fu (B44548@freescale.com)
+ * Haikun Wang (B53464@freescale.com)
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <dm.h>
+#include <errno.h>
+#include <common.h>
+#include <spi.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <fdtdec.h>
+#ifndef CONFIG_M68K
+#include <asm/arch/clock.h>
+#endif
+#include <fsl_dspi.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* fsl_dspi_platdata flags */
+#define DSPI_FLAG_REGMAP_ENDIAN_BIG (1 << 0)
+
+/* idle data value */
+#define DSPI_IDLE_VAL 0x0
+
+/* max chipselect signals number */
+#define FSL_DSPI_MAX_CHIPSELECT 6
+
+/* default SCK frequency, unit: HZ */
+#define FSL_DSPI_DEFAULT_SCK_FREQ 10000000
+
+/* tx/rx data wait timeout value, unit: us */
+#define DSPI_TXRX_WAIT_TIMEOUT 1000000
+
+/* CTAR register pre-configure value */
+#define DSPI_CTAR_DEFAULT_VALUE (DSPI_CTAR_TRSZ(7) | \
+ DSPI_CTAR_PCSSCK_1CLK | \
+ DSPI_CTAR_PASC(0) | \
+ DSPI_CTAR_PDT(0) | \
+ DSPI_CTAR_CSSCK(0) | \
+ DSPI_CTAR_ASC(0) | \
+ DSPI_CTAR_DT(0))
+
+/* CTAR register pre-configure mask */
+#define DSPI_CTAR_SET_MODE_MASK (DSPI_CTAR_TRSZ(15) | \
+ DSPI_CTAR_PCSSCK(3) | \
+ DSPI_CTAR_PASC(3) | \
+ DSPI_CTAR_PDT(3) | \
+ DSPI_CTAR_CSSCK(15) | \
+ DSPI_CTAR_ASC(15) | \
+ DSPI_CTAR_DT(15))
+
+/**
+ * struct fsl_dspi_platdata - platform data for Freescale DSPI
+ *
+ * @flags: Flags for DSPI DSPI_FLAG_...
+ * @speed_hz: Default SCK frequency
+ * @num_chipselect: Number of DSPI chipselect signals
+ * @regs_addr: Base address of DSPI registers
+ */
+struct fsl_dspi_platdata {
+ uint flags;
+ uint speed_hz;
+ uint num_chipselect;
+ fdt_addr_t regs_addr;
+};
+
+/**
+ * struct fsl_dspi_priv - private data for Freescale DSPI
+ *
+ * @flags: Flags for DSPI DSPI_FLAG_...
+ * @mode: SPI mode to use for slave device (see SPI mode flags)
+ * @mcr_val: MCR register configure value
+ * @bus_clk: DSPI input clk frequency
+ * @speed_hz: Default SCK frequency
+ * @charbit: How many bits in every transfer
+ * @num_chipselect: Number of DSPI chipselect signals
+ * @ctar_val: CTAR register configure value of per chipselect slave device
+ * @regs: Point to DSPI register structure for I/O access
+ */
+struct fsl_dspi_priv {
+ uint flags;
+ uint mode;
+ uint mcr_val;
+ uint bus_clk;
+ uint speed_hz;
+ uint charbit;
+ uint num_chipselect;
+ uint ctar_val[FSL_DSPI_MAX_CHIPSELECT];
+ struct dspi *regs;
+};
+
+#ifndef CONFIG_DM_SPI
+struct fsl_dspi {
+ struct spi_slave slave;
+ struct fsl_dspi_priv priv;
+};
+#endif
+
+__weak void cpu_dspi_port_conf(void)
+{
+}
+
+__weak int cpu_dspi_claim_bus(uint bus, uint cs)
+{
+ return 0;
+}
+
+__weak void cpu_dspi_release_bus(uint bus, uint cs)
+{
+}
+
+static uint dspi_read32(uint flags, uint *addr)
+{
+ return flags & DSPI_FLAG_REGMAP_ENDIAN_BIG ?
+ in_be32(addr) : in_le32(addr);
+}
+
+static void dspi_write32(uint flags, uint *addr, uint val)
+{
+ flags & DSPI_FLAG_REGMAP_ENDIAN_BIG ?
+ out_be32(addr, val) : out_le32(addr, val);
+}
+
+static void dspi_halt(struct fsl_dspi_priv *priv, u8 halt)
+{
+ uint mcr_val;
+
+ mcr_val = dspi_read32(priv->flags, &priv->regs->mcr);
+
+ if (halt)
+ mcr_val |= DSPI_MCR_HALT;
+ else
+ mcr_val &= ~DSPI_MCR_HALT;
+
+ dspi_write32(priv->flags, &priv->regs->mcr, mcr_val);
+}
+
+static void fsl_dspi_init_mcr(struct fsl_dspi_priv *priv, uint cfg_val)
+{
+ /* halt DSPI module */
+ dspi_halt(priv, 1);
+
+ dspi_write32(priv->flags, &priv->regs->mcr, cfg_val);
+
+ /* resume module */
+ dspi_halt(priv, 0);
+
+ priv->mcr_val = cfg_val;
+}
+
+static void fsl_dspi_cfg_cs_active_state(struct fsl_dspi_priv *priv,
+ uint cs, uint state)
+{
+ uint mcr_val;
+
+ dspi_halt(priv, 1);
+
+ mcr_val = dspi_read32(priv->flags, &priv->regs->mcr);
+ if (state & SPI_CS_HIGH)
+ /* CSx inactive state is low */
+ mcr_val &= ~DSPI_MCR_PCSIS(cs);
+ else
+ /* CSx inactive state is high */
+ mcr_val |= DSPI_MCR_PCSIS(cs);
+ dspi_write32(priv->flags, &priv->regs->mcr, mcr_val);
+
+ dspi_halt(priv, 0);
+}
+
+static int fsl_dspi_cfg_ctar_mode(struct fsl_dspi_priv *priv,
+ uint cs, uint mode)
+{
+ uint bus_setup;
+
+ bus_setup = dspi_read32(priv->flags, &priv->regs->ctar[0]);
+
+ bus_setup &= ~DSPI_CTAR_SET_MODE_MASK;
+ bus_setup |= priv->ctar_val[cs];
+ bus_setup &= ~(DSPI_CTAR_CPOL | DSPI_CTAR_CPHA | DSPI_CTAR_LSBFE);
+
+ if (mode & SPI_CPOL)
+ bus_setup |= DSPI_CTAR_CPOL;
+ if (mode & SPI_CPHA)
+ bus_setup |= DSPI_CTAR_CPHA;
+ if (mode & SPI_LSB_FIRST)
+ bus_setup |= DSPI_CTAR_LSBFE;
+
+ dspi_write32(priv->flags, &priv->regs->ctar[0], bus_setup);
+
+ priv->charbit =
+ ((dspi_read32(priv->flags, &priv->regs->ctar[0]) &
+ DSPI_CTAR_TRSZ(15)) == DSPI_CTAR_TRSZ(15)) ? 16 : 8;
+
+ return 0;
+}
+
+static void fsl_dspi_clr_fifo(struct fsl_dspi_priv *priv)
+{
+ uint mcr_val;
+
+ dspi_halt(priv, 1);
+ mcr_val = dspi_read32(priv->flags, &priv->regs->mcr);
+ /* flush RX and TX FIFO */
+ mcr_val |= (DSPI_MCR_CTXF | DSPI_MCR_CRXF);
+ dspi_write32(priv->flags, &priv->regs->mcr, mcr_val);
+ dspi_halt(priv, 0);
+}
+
+static void dspi_tx(struct fsl_dspi_priv *priv, u32 ctrl, u16 data)
+{
+ int timeout = DSPI_TXRX_WAIT_TIMEOUT;
+
+ /* wait for empty entries in TXFIFO or timeout */
+ while (DSPI_SR_TXCTR(dspi_read32(priv->flags, &priv->regs->sr)) >= 4 &&
+ timeout--)
+ udelay(1);
+
+ if (timeout >= 0)
+ dspi_write32(priv->flags, &priv->regs->tfr, (ctrl | data));
+ else
+ debug("dspi_tx: waiting timeout!\n");
+}
+
+static u16 dspi_rx(struct fsl_dspi_priv *priv)
+{
+ int timeout = DSPI_TXRX_WAIT_TIMEOUT;
+
+ /* wait for valid entries in RXFIFO or timeout */
+ while (DSPI_SR_RXCTR(dspi_read32(priv->flags, &priv->regs->sr)) == 0 &&
+ timeout--)
+ udelay(1);
+
+ if (timeout >= 0)
+ return (u16)DSPI_RFR_RXDATA(
+ dspi_read32(priv->flags, &priv->regs->rfr));
+ else {
+ debug("dspi_rx: waiting timeout!\n");
+ return (u16)(~0);
+ }
+}
+
+static int dspi_xfer(struct fsl_dspi_priv *priv, uint cs, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ u16 *spi_rd16 = NULL, *spi_wr16 = NULL;
+ u8 *spi_rd = NULL, *spi_wr = NULL;
+ static u32 ctrl;
+ uint len = bitlen >> 3;
+
+ if (priv->charbit == 16) {
+ bitlen >>= 1;
+ spi_wr16 = (u16 *)dout;
+ spi_rd16 = (u16 *)din;
+ } else {
+ spi_wr = (u8 *)dout;
+ spi_rd = (u8 *)din;
+ }
+
+ if ((flags & SPI_XFER_BEGIN) == SPI_XFER_BEGIN)
+ ctrl |= DSPI_TFR_CONT;
+
+ ctrl = ctrl & DSPI_TFR_CONT;
+ ctrl = ctrl | DSPI_TFR_CTAS(0) | DSPI_TFR_PCS(cs);
+
+ if (len > 1) {
+ int tmp_len = len - 1;
+ while (tmp_len--) {
+ if (dout != NULL) {
+ if (priv->charbit == 16)
+ dspi_tx(priv, ctrl, *spi_wr16++);
+ else
+ dspi_tx(priv, ctrl, *spi_wr++);
+ dspi_rx(priv);
+ }
+
+ if (din != NULL) {
+ dspi_tx(priv, ctrl, DSPI_IDLE_VAL);
+ if (priv->charbit == 16)
+ *spi_rd16++ = dspi_rx(priv);
+ else
+ *spi_rd++ = dspi_rx(priv);
+ }
+ }
+
+ len = 1; /* remaining byte */
+ }
+
+ if ((flags & SPI_XFER_END) == SPI_XFER_END)
+ ctrl &= ~DSPI_TFR_CONT;
+
+ if (len) {
+ if (dout != NULL) {
+ if (priv->charbit == 16)
+ dspi_tx(priv, ctrl, *spi_wr16);
+ else
+ dspi_tx(priv, ctrl, *spi_wr);
+ dspi_rx(priv);
+ }
+
+ if (din != NULL) {
+ dspi_tx(priv, ctrl, DSPI_IDLE_VAL);
+ if (priv->charbit == 16)
+ *spi_rd16 = dspi_rx(priv);
+ else
+ *spi_rd = dspi_rx(priv);
+ }
+ } else {
+ /* dummy read */
+ dspi_tx(priv, ctrl, DSPI_IDLE_VAL);
+ dspi_rx(priv);
+ }
+
+ return 0;
+}
+
+/**
+ * Calculate the divide value between input clk frequency and expected SCK frequency
+ * Formula: SCK = (clkrate/pbr) x ((1+dbr)/br)
+ * Dbr: use default value 0
+ *
+ * @pbr: return Baud Rate Prescaler value
+ * @br: return Baud Rate Scaler value
+ * @speed_hz: expected SCK frequency
+ * @clkrate: input clk frequency
+ */
+static int fsl_dspi_hz_to_spi_baud(int *pbr, int *br,
+ int speed_hz, uint clkrate)
+{
+ /* Valid baud rate pre-scaler values */
+ int pbr_tbl[4] = {2, 3, 5, 7};
+ int brs[16] = {2, 4, 6, 8,
+ 16, 32, 64, 128,
+ 256, 512, 1024, 2048,
+ 4096, 8192, 16384, 32768};
+ int temp, i = 0, j = 0;
+
+ temp = clkrate / speed_hz;
+
+ for (i = 0; i < ARRAY_SIZE(pbr_tbl); i++)
+ for (j = 0; j < ARRAY_SIZE(brs); j++) {
+ if (pbr_tbl[i] * brs[j] >= temp) {
+ *pbr = i;
+ *br = j;
+ return 0;
+ }
+ }
+
+ debug("Can not find valid baud rate,speed_hz is %d, ", speed_hz);
+ debug("clkrate is %d, we use the max prescaler value.\n", clkrate);
+
+ *pbr = ARRAY_SIZE(pbr_tbl) - 1;
+ *br = ARRAY_SIZE(brs) - 1;
+ return -EINVAL;
+}
+
+static int fsl_dspi_cfg_speed(struct fsl_dspi_priv *priv, uint speed)
+{
+ int ret;
+ uint bus_setup;
+ int best_i, best_j, bus_clk;
+
+ bus_clk = priv->bus_clk;
+
+ debug("DSPI set_speed: expected SCK speed %u, bus_clk %u.\n",
+ speed, bus_clk);
+
+ bus_setup = dspi_read32(priv->flags, &priv->regs->ctar[0]);
+ bus_setup &= ~(DSPI_CTAR_DBR | DSPI_CTAR_PBR(0x3) | DSPI_CTAR_BR(0xf));
+
+ ret = fsl_dspi_hz_to_spi_baud(&best_i, &best_j, speed, bus_clk);
+ if (ret) {
+ speed = priv->speed_hz;
+ debug("DSPI set_speed use default SCK rate %u.\n", speed);
+ fsl_dspi_hz_to_spi_baud(&best_i, &best_j, speed, bus_clk);
+ }
+
+ bus_setup |= (DSPI_CTAR_PBR(best_i) | DSPI_CTAR_BR(best_j));
+ dspi_write32(priv->flags, &priv->regs->ctar[0], bus_setup);
+
+ priv->speed_hz = speed;
+
+ return 0;
+}
+#ifndef CONFIG_DM_SPI
+void spi_init(void)
+{
+ /* Nothing to do */
+}
+
+void spi_init_f(void)
+{
+ /* Nothing to do */
+}
+
+void spi_init_r(void)
+{
+ /* Nothing to do */
+}
+
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+ if (((cs >= 0) && (cs < 8)) && ((bus >= 0) && (bus < 8)))
+ return 1;
+ else
+ return 0;
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
+{
+ struct fsl_dspi *dspi;
+ uint mcr_cfg_val;
+
+ dspi = spi_alloc_slave(struct fsl_dspi, bus, cs);
+ if (!dspi)
+ return NULL;
+
+ cpu_dspi_port_conf();
+
+#ifdef CONFIG_SYS_FSL_DSPI_BE
+ dspi->priv.flags |= DSPI_FLAG_REGMAP_ENDIAN_BIG;
+#endif
+
+ dspi->priv.regs = (struct dspi *)MMAP_DSPI;
+
+#ifdef CONFIG_M68K
+ dspi->priv.bus_clk = gd->bus_clk;
+#else
+ dspi->priv.bus_clk = mxc_get_clock(MXC_DSPI_CLK);
+#endif
+ dspi->priv.speed_hz = FSL_DSPI_DEFAULT_SCK_FREQ;
+
+ /* default: all CS signals inactive state is high */
+ mcr_cfg_val = DSPI_MCR_MSTR | DSPI_MCR_PCSIS_MASK |
+ DSPI_MCR_CRXF | DSPI_MCR_CTXF;
+ fsl_dspi_init_mcr(&dspi->priv, mcr_cfg_val);
+
+ for (i = 0; i < FSL_DSPI_MAX_CHIPSELECT; i++)
+ dspi->priv.ctar_val[i] = DSPI_CTAR_DEFAULT_VALUE;
+
+#ifdef CONFIG_SYS_DSPI_CTAR0
+ if (FSL_DSPI_MAX_CHIPSELECT > 0)
+ dspi->priv.ctar_val[0] = CONFIG_SYS_DSPI_CTAR0;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR1
+ if (FSL_DSPI_MAX_CHIPSELECT > 1)
+ dspi->priv.ctar_val[1] = CONFIG_SYS_DSPI_CTAR1;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR2
+ if (FSL_DSPI_MAX_CHIPSELECT > 2)
+ dspi->priv.ctar_val[2] = CONFIG_SYS_DSPI_CTAR2;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR3
+ if (FSL_DSPI_MAX_CHIPSELECT > 3)
+ dspi->priv.ctar_val[3] = CONFIG_SYS_DSPI_CTAR3;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR4
+ if (FSL_DSPI_MAX_CHIPSELECT > 4)
+ dspi->priv.ctar_val[4] = CONFIG_SYS_DSPI_CTAR4;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR5
+ if (FSL_DSPI_MAX_CHIPSELECT > 5)
+ dspi->priv.ctar_val[5] = CONFIG_SYS_DSPI_CTAR5;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR6
+ if (FSL_DSPI_MAX_CHIPSELECT > 6)
+ dspi->priv.ctar_val[6] = CONFIG_SYS_DSPI_CTAR6;
+#endif
+#ifdef CONFIG_SYS_DSPI_CTAR7
+ if (FSL_DSPI_MAX_CHIPSELECT > 7)
+ dspi->priv.ctar_val[7] = CONFIG_SYS_DSPI_CTAR7;
+#endif
+
+ fsl_dspi_cfg_speed(&dspi->priv, max_hz);
+
+ /* configure transfer mode */
+ fsl_dspi_cfg_ctar_mode(&dspi->priv, cs, mode);
+
+ /* configure active state of CSX */
+ fsl_dspi_cfg_cs_active_state(&dspi->priv, cs, mode);
+
+ return &dspi->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ free(slave);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+ uint sr_val;
+ struct fsl_dspi *dspi = (struct fsl_dspi *)slave;
+
+ cpu_dspi_claim_bus(slave->bus, slave->cs);
+
+ fsl_dspi_clr_fifo(&dspi->priv);
+
+ /* check module TX and RX status */
+ sr_val = dspi_read32(dspi->priv.flags, &dspi->priv.regs->sr);
+ if ((sr_val & DSPI_SR_TXRXS) != DSPI_SR_TXRXS) {
+ debug("DSPI RX/TX not ready!\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+ struct fsl_dspi *dspi = (struct fsl_dspi *)slave;
+
+ dspi_halt(&dspi->priv, 1);
+ cpu_dspi_release_bus(slave->bus.slave->cs);
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
+ void *din, unsigned long flags)
+{
+ struct fsl_dspi *dspi = (struct fsl_dspi *)slave;
+ return dspi_xfer(&dspi->priv, slave->cs, bitlen, dout, din, flags);
+}
+#else
+static int fsl_dspi_child_pre_probe(struct udevice *dev)
+{
+ struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
+ struct fsl_dspi_priv *priv = dev_get_priv(dev->parent);
+
+ if (slave_plat->cs >= priv->num_chipselect) {
+ debug("DSPI invalid chipselect number %d(max %d)!\n",
+ slave_plat->cs, priv->num_chipselect - 1);
+ return -EINVAL;
+ }
+
+ priv->ctar_val[slave_plat->cs] = DSPI_CTAR_DEFAULT_VALUE;
+
+ debug("DSPI pre_probe slave device on CS %u, max_hz %u, mode 0x%x.\n",
+ slave_plat->cs, slave_plat->max_hz, slave_plat->mode);
+
+ return 0;
+}
+
+static int fsl_dspi_probe(struct udevice *bus)
+{
+ struct fsl_dspi_platdata *plat = dev_get_platdata(bus);
+ struct fsl_dspi_priv *priv = dev_get_priv(bus);
+ struct dm_spi_bus *dm_spi_bus;
+ uint mcr_cfg_val;
+
+ dm_spi_bus = bus->uclass_priv;
+
+ /* cpu speical pin muxing configure */
+ cpu_dspi_port_conf();
+
+ /* get input clk frequency */
+ priv->regs = (struct dspi *)plat->regs_addr;
+ priv->flags = plat->flags;
+#ifdef CONFIG_M68K
+ priv->bus_clk = gd->bus_clk;
+#else
+ priv->bus_clk = mxc_get_clock(MXC_DSPI_CLK);
+#endif
+ priv->num_chipselect = plat->num_chipselect;
+ priv->speed_hz = plat->speed_hz;
+ /* frame data length in bits, default 8bits */
+ priv->charbit = 8;
+
+ dm_spi_bus->max_hz = plat->speed_hz;
+
+ /* default: all CS signals inactive state is high */
+ mcr_cfg_val = DSPI_MCR_MSTR | DSPI_MCR_PCSIS_MASK |
+ DSPI_MCR_CRXF | DSPI_MCR_CTXF;
+ fsl_dspi_init_mcr(priv, mcr_cfg_val);
+
+ debug("%s probe done, bus-num %d.\n", bus->name, bus->seq);
+
+ return 0;
+}
+
+static int fsl_dspi_claim_bus(struct udevice *dev)
+{
+ uint sr_val;
+ struct fsl_dspi_priv *priv;
+ struct udevice *bus = dev->parent;
+ struct dm_spi_slave_platdata *slave_plat =
+ dev_get_parent_platdata(dev);
+
+ priv = dev_get_priv(bus);
+
+ /* processor special prepartion work */
+ cpu_dspi_claim_bus(bus->seq, slave_plat->cs);
+
+ /* configure transfer mode */
+ fsl_dspi_cfg_ctar_mode(priv, slave_plat->cs, priv->mode);
+
+ /* configure active state of CSX */
+ fsl_dspi_cfg_cs_active_state(priv, slave_plat->cs,
+ priv->mode);
+
+ fsl_dspi_clr_fifo(priv);
+
+ /* check module TX and RX status */
+ sr_val = dspi_read32(priv->flags, &priv->regs->sr);
+ if ((sr_val & DSPI_SR_TXRXS) != DSPI_SR_TXRXS) {
+ debug("DSPI RX/TX not ready!\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int fsl_dspi_release_bus(struct udevice *dev)
+{
+ struct udevice *bus = dev->parent;
+ struct fsl_dspi_priv *priv = dev_get_priv(bus);
+ struct dm_spi_slave_platdata *slave_plat =
+ dev_get_parent_platdata(dev);
+
+ /* halt module */
+ dspi_halt(priv, 1);
+
+ /* processor special release work */
+ cpu_dspi_release_bus(bus->seq, slave_plat->cs);
+
+ return 0;
+}
+
+/**
+ * This function doesn't do anything except help with debugging
+ */
+static int fsl_dspi_bind(struct udevice *bus)
+{
+ debug("%s assigned req_seq %d.\n", bus->name, bus->req_seq);
+ return 0;
+}
+
+static int fsl_dspi_ofdata_to_platdata(struct udevice *bus)
+{
+ fdt_addr_t addr;
+ struct fsl_dspi_platdata *plat = bus->platdata;
+ const void *blob = gd->fdt_blob;
+ int node = bus->of_offset;
+
+ if (fdtdec_get_bool(blob, node, "big-endian"))
+ plat->flags |= DSPI_FLAG_REGMAP_ENDIAN_BIG;
+
+ plat->num_chipselect =
+ fdtdec_get_int(blob, node, "num-cs", FSL_DSPI_MAX_CHIPSELECT);
+
+ addr = fdtdec_get_addr(blob, node, "reg");
+ if (addr == FDT_ADDR_T_NONE) {
+ debug("DSPI: Can't get base address or size\n");
+ return -ENOMEM;
+ }
+ plat->regs_addr = addr;
+
+ plat->speed_hz = fdtdec_get_int(blob,
+ node, "spi-max-frequency", FSL_DSPI_DEFAULT_SCK_FREQ);
+
+ debug("DSPI: regs=0x%x, max-frequency=%d, endianess=%s, num-cs=%d\n",
+ plat->regs_addr, plat->speed_hz,
+ plat->flags & DSPI_FLAG_REGMAP_ENDIAN_BIG ? "be" : "le",
+ plat->num_chipselect);
+
+ return 0;
+}
+
+static int fsl_dspi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct fsl_dspi_priv *priv;
+ struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
+ struct udevice *bus;
+
+ bus = dev->parent;
+ priv = dev_get_priv(bus);
+
+ return dspi_xfer(priv, slave_plat->cs, bitlen, dout, din, flags);
+}
+
+static int fsl_dspi_set_speed(struct udevice *bus, uint speed)
+{
+ struct fsl_dspi_priv *priv = dev_get_priv(bus);
+
+ return fsl_dspi_cfg_speed(priv, speed);
+}
+
+static int fsl_dspi_set_mode(struct udevice *bus, uint mode)
+{
+ struct fsl_dspi_priv *priv = dev_get_priv(bus);
+
+ debug("DSPI set_mode: mode 0x%x.\n", mode);
+
+ /*
+ * We store some chipselect special configure value in priv->ctar_val,
+ * and we can't get the correct chipselect number here,
+ * so just store mode value.
+ * Do really configuration when claim_bus.
+ */
+ priv->mode = mode;
+
+ return 0;
+}
+
+static const struct dm_spi_ops fsl_dspi_ops = {
+ .claim_bus = fsl_dspi_claim_bus,
+ .release_bus = fsl_dspi_release_bus,
+ .xfer = fsl_dspi_xfer,
+ .set_speed = fsl_dspi_set_speed,
+ .set_mode = fsl_dspi_set_mode,
+};
+
+static const struct udevice_id fsl_dspi_ids[] = {
+ { .compatible = "fsl,vf610-dspi" },
+ { }
+};
+
+U_BOOT_DRIVER(fsl_dspi) = {
+ .name = "fsl_dspi",
+ .id = UCLASS_SPI,
+ .of_match = fsl_dspi_ids,
+ .ops = &fsl_dspi_ops,
+ .ofdata_to_platdata = fsl_dspi_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct fsl_dspi_platdata),
+ .priv_auto_alloc_size = sizeof(struct fsl_dspi_priv),
+ .probe = fsl_dspi_probe,
+ .child_pre_probe = fsl_dspi_child_pre_probe,
+ .bind = fsl_dspi_bind,
+};
+#endif
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index 5e0b069..868df5f 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2014 Freescale Semiconductor, Inc.
+ * Copyright 2013-2015 Freescale Semiconductor, Inc.
*
* Freescale Quad Serial Peripheral Interface (QSPI) driver
*
@@ -11,8 +11,12 @@
#include <spi.h>
#include <asm/io.h>
#include <linux/sizes.h>
+#include <dm.h>
+#include <errno.h>
#include "fsl_qspi.h"
+DECLARE_GLOBAL_DATA_PTR;
+
#define RX_BUFFER_SIZE 0x80
#ifdef CONFIG_MX6SX
#define TX_BUFFER_SIZE 0x200
@@ -63,35 +67,85 @@
#define QSPI_CMD_PP_4B 0x12 /* Page program (up to 256 bytes) */
#define QSPI_CMD_SE_4B 0xdc /* Sector erase (usually 64KiB) */
-#ifdef CONFIG_SYS_FSL_QSPI_LE
-#define qspi_read32 in_le32
-#define qspi_write32 out_le32
-#elif defined(CONFIG_SYS_FSL_QSPI_BE)
-#define qspi_read32 in_be32
-#define qspi_write32 out_be32
-#endif
+/* fsl_qspi_platdata flags */
+#define QSPI_FLAG_REGMAP_ENDIAN_BIG (1 << 0)
-static unsigned long spi_bases[] = {
- QSPI0_BASE_ADDR,
-#ifdef CONFIG_MX6SX
- QSPI1_BASE_ADDR,
-#endif
-};
+/* default SCK frequency, unit: HZ */
+#define FSL_QSPI_DEFAULT_SCK_FREQ 50000000
-static unsigned long amba_bases[] = {
- QSPI0_AMBA_BASE,
-#ifdef CONFIG_MX6SX
- QSPI1_AMBA_BASE,
+/* QSPI max chipselect signals number */
+#define FSL_QSPI_MAX_CHIPSELECT_NUM 4
+
+#ifdef CONFIG_DM_SPI
+/**
+ * struct fsl_qspi_platdata - platform data for Freescale QSPI
+ *
+ * @flags: Flags for QSPI QSPI_FLAG_...
+ * @speed_hz: Default SCK frequency
+ * @reg_base: Base address of QSPI registers
+ * @amba_base: Base address of QSPI memory mapping
+ * @amba_total_size: size of QSPI memory mapping
+ * @flash_num: Number of active slave devices
+ * @num_chipselect: Number of QSPI chipselect signals
+ */
+struct fsl_qspi_platdata {
+ u32 flags;
+ u32 speed_hz;
+ u32 reg_base;
+ u32 amba_base;
+ u32 amba_total_size;
+ u32 flash_num;
+ u32 num_chipselect;
+};
#endif
+
+/**
+ * struct fsl_qspi_priv - private data for Freescale QSPI
+ *
+ * @flags: Flags for QSPI QSPI_FLAG_...
+ * @bus_clk: QSPI input clk frequency
+ * @speed_hz: Default SCK frequency
+ * @cur_seqid: current LUT table sequence id
+ * @sf_addr: flash access offset
+ * @amba_base: Base address of QSPI memory mapping of every CS
+ * @amba_total_size: size of QSPI memory mapping
+ * @cur_amba_base: Base address of QSPI memory mapping of current CS
+ * @flash_num: Number of active slave devices
+ * @num_chipselect: Number of QSPI chipselect signals
+ * @regs: Point to QSPI register structure for I/O access
+ */
+struct fsl_qspi_priv {
+ u32 flags;
+ u32 bus_clk;
+ u32 speed_hz;
+ u32 cur_seqid;
+ u32 sf_addr;
+ u32 amba_base[FSL_QSPI_MAX_CHIPSELECT_NUM];
+ u32 amba_total_size;
+ u32 cur_amba_base;
+ u32 flash_num;
+ u32 num_chipselect;
+ struct fsl_qspi_regs *regs;
};
+#ifndef CONFIG_DM_SPI
struct fsl_qspi {
struct spi_slave slave;
- unsigned long reg_base;
- unsigned long amba_base;
- u32 sf_addr;
- u8 cur_seqid;
+ struct fsl_qspi_priv priv;
};
+#endif
+
+static u32 qspi_read32(u32 flags, u32 *addr)
+{
+ return flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ?
+ in_be32(addr) : in_le32(addr);
+}
+
+static void qspi_write32(u32 flags, u32 *addr, u32 val)
+{
+ flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ?
+ out_be32(addr, val) : out_le32(addr, val);
+}
/* QSPI support swapping the flash read/write data
* in hardware for LS102xA, but not for VF610 */
@@ -104,131 +158,135 @@ static inline u32 qspi_endian_xchg(u32 data)
#endif
}
-static inline struct fsl_qspi *to_qspi_spi(struct spi_slave *slave)
-{
- return container_of(slave, struct fsl_qspi, slave);
-}
-
-static void qspi_set_lut(struct fsl_qspi *qspi)
+static void qspi_set_lut(struct fsl_qspi_priv *priv)
{
- struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ struct fsl_qspi_regs *regs = priv->regs;
u32 lut_base;
/* Unlock the LUT */
- qspi_write32(&regs->lutkey, LUT_KEY_VALUE);
- qspi_write32(&regs->lckcr, QSPI_LCKCR_UNLOCK);
+ qspi_write32(priv->flags, &regs->lutkey, LUT_KEY_VALUE);
+ qspi_write32(priv->flags, &regs->lckcr, QSPI_LCKCR_UNLOCK);
/* Write Enable */
lut_base = SEQID_WREN * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_WREN) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_WREN) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD));
- qspi_write32(&regs->lut[lut_base + 1], 0);
- qspi_write32(&regs->lut[lut_base + 2], 0);
- qspi_write32(&regs->lut[lut_base + 3], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
/* Fast Read */
lut_base = SEQID_FAST_READ * 4;
#ifdef CONFIG_SPI_FLASH_BAR
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_FAST_READ) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
+ qspi_write32(priv->flags, &regs->lut[lut_base],
+ OPRND0(QSPI_CMD_FAST_READ) | PAD0(LUT_PAD1) |
+ INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
#else
if (FSL_QSPI_FLASH_SIZE <= SZ_16M)
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_FAST_READ) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
- PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+ qspi_write32(priv->flags, &regs->lut[lut_base],
+ OPRND0(QSPI_CMD_FAST_READ) | PAD0(LUT_PAD1) |
+ INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
else
- qspi_write32(&regs->lut[lut_base],
+ qspi_write32(priv->flags, &regs->lut[lut_base],
OPRND0(QSPI_CMD_FAST_READ_4B) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) |
OPRND1(ADDR32BIT) | PAD1(LUT_PAD1) |
INSTR1(LUT_ADDR));
#endif
- qspi_write32(&regs->lut[lut_base + 1], OPRND0(8) | PAD0(LUT_PAD1) |
- INSTR0(LUT_DUMMY) | OPRND1(RX_BUFFER_SIZE) | PAD1(LUT_PAD1) |
- INSTR1(LUT_READ));
- qspi_write32(&regs->lut[lut_base + 2], 0);
- qspi_write32(&regs->lut[lut_base + 3], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 1],
+ OPRND0(8) | PAD0(LUT_PAD1) | INSTR0(LUT_DUMMY) |
+ OPRND1(RX_BUFFER_SIZE) | PAD1(LUT_PAD1) |
+ INSTR1(LUT_READ));
+ qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
/* Read Status */
lut_base = SEQID_RDSR * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_RDSR) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_RDSR) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
PAD1(LUT_PAD1) | INSTR1(LUT_READ));
- qspi_write32(&regs->lut[lut_base + 1], 0);
- qspi_write32(&regs->lut[lut_base + 2], 0);
- qspi_write32(&regs->lut[lut_base + 3], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
/* Erase a sector */
lut_base = SEQID_SE * 4;
#ifdef CONFIG_SPI_FLASH_BAR
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_SE) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_SE) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
#else
if (FSL_QSPI_FLASH_SIZE <= SZ_16M)
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_SE) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
- PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+ qspi_write32(priv->flags, &regs->lut[lut_base],
+ OPRND0(QSPI_CMD_SE) | PAD0(LUT_PAD1) |
+ INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
else
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_SE_4B) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
- PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+ qspi_write32(priv->flags, &regs->lut[lut_base],
+ OPRND0(QSPI_CMD_SE_4B) | PAD0(LUT_PAD1) |
+ INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
#endif
- qspi_write32(&regs->lut[lut_base + 1], 0);
- qspi_write32(&regs->lut[lut_base + 2], 0);
- qspi_write32(&regs->lut[lut_base + 3], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
/* Erase the whole chip */
lut_base = SEQID_CHIP_ERASE * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_CHIP_ERASE) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD));
- qspi_write32(&regs->lut[lut_base + 1], 0);
- qspi_write32(&regs->lut[lut_base + 2], 0);
- qspi_write32(&regs->lut[lut_base + 3], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base],
+ OPRND0(QSPI_CMD_CHIP_ERASE) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD));
+ qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
/* Page Program */
lut_base = SEQID_PP * 4;
#ifdef CONFIG_SPI_FLASH_BAR
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_PP) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_PP) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
#else
if (FSL_QSPI_FLASH_SIZE <= SZ_16M)
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_PP) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
- PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+ qspi_write32(priv->flags, &regs->lut[lut_base],
+ OPRND0(QSPI_CMD_PP) | PAD0(LUT_PAD1) |
+ INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
else
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_PP_4B) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
- PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+ qspi_write32(priv->flags, &regs->lut[lut_base],
+ OPRND0(QSPI_CMD_PP_4B) | PAD0(LUT_PAD1) |
+ INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
+ PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
#endif
#ifdef CONFIG_MX6SX
/*
* To MX6SX, OPRND0(TX_BUFFER_SIZE) can not work correctly.
* So, Use IDATSZ in IPCR to determine the size and here set 0.
*/
- qspi_write32(&regs->lut[lut_base + 1], OPRND0(0) |
+ qspi_write32(priv->flags, &regs->lut[lut_base + 1], OPRND0(0) |
PAD0(LUT_PAD1) | INSTR0(LUT_WRITE));
#else
- qspi_write32(&regs->lut[lut_base + 1], OPRND0(TX_BUFFER_SIZE) |
- PAD0(LUT_PAD1) | INSTR0(LUT_WRITE));
+ qspi_write32(priv->flags, &regs->lut[lut_base + 1],
+ OPRND0(TX_BUFFER_SIZE) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_WRITE));
#endif
- qspi_write32(&regs->lut[lut_base + 2], 0);
- qspi_write32(&regs->lut[lut_base + 3], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
/* READ ID */
lut_base = SEQID_RDID * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_RDID) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_RDID) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(8) |
PAD1(LUT_PAD1) | INSTR1(LUT_READ));
- qspi_write32(&regs->lut[lut_base + 1], 0);
- qspi_write32(&regs->lut[lut_base + 2], 0);
- qspi_write32(&regs->lut[lut_base + 3], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
+ qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
/* SUB SECTOR 4K ERASE */
lut_base = SEQID_BE_4K * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_BE_4K) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_BE_4K) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
@@ -239,28 +297,28 @@ static void qspi_set_lut(struct fsl_qspi *qspi)
* initialization.
*/
lut_base = SEQID_BRRD * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_BRRD) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_BRRD) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
PAD1(LUT_PAD1) | INSTR1(LUT_READ));
lut_base = SEQID_BRWR * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_BRWR) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_BRWR) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
PAD1(LUT_PAD1) | INSTR1(LUT_WRITE));
lut_base = SEQID_RDEAR * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_RDEAR) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_RDEAR) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
PAD1(LUT_PAD1) | INSTR1(LUT_READ));
lut_base = SEQID_WREAR * 4;
- qspi_write32(&regs->lut[lut_base], OPRND0(QSPI_CMD_WREAR) |
+ qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_WREAR) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
PAD1(LUT_PAD1) | INSTR1(LUT_WRITE));
#endif
/* Lock the LUT */
- qspi_write32(&regs->lutkey, LUT_KEY_VALUE);
- qspi_write32(&regs->lckcr, QSPI_LCKCR_LOCK);
+ qspi_write32(priv->flags, &regs->lutkey, LUT_KEY_VALUE);
+ qspi_write32(priv->flags, &regs->lckcr, QSPI_LCKCR_LOCK);
}
#if defined(CONFIG_SYS_FSL_QSPI_AHB)
@@ -270,14 +328,14 @@ static void qspi_set_lut(struct fsl_qspi *qspi)
* the wrong data. The spec tells us reset the AHB domain and Serial Flash
* domain at the same time.
*/
-static inline void qspi_ahb_invalid(struct fsl_qspi *q)
+static inline void qspi_ahb_invalid(struct fsl_qspi_priv *priv)
{
- struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)q->reg_base;
+ struct fsl_qspi_regs *regs = priv->regs;
u32 reg;
- reg = qspi_read32(&regs->mcr);
+ reg = qspi_read32(priv->flags, &regs->mcr);
reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK;
- qspi_write32(&regs->mcr, reg);
+ qspi_write32(priv->flags, &regs->mcr, reg);
/*
* The minimum delay : 1 AHB + 2 SFCK clocks.
@@ -286,46 +344,48 @@ static inline void qspi_ahb_invalid(struct fsl_qspi *q)
udelay(1);
reg &= ~(QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK);
- qspi_write32(&regs->mcr, reg);
+ qspi_write32(priv->flags, &regs->mcr, reg);
}
/* Read out the data from the AHB buffer. */
-static inline void qspi_ahb_read(struct fsl_qspi *q, u8 *rxbuf, int len)
+static inline void qspi_ahb_read(struct fsl_qspi_priv *priv, u8 *rxbuf, int len)
{
- struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)q->reg_base;
+ struct fsl_qspi_regs *regs = priv->regs;
u32 mcr_reg;
- mcr_reg = qspi_read32(&regs->mcr);
+ mcr_reg = qspi_read32(priv->flags, &regs->mcr);
- qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ qspi_write32(priv->flags, &regs->mcr,
+ QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
/* Read out the data directly from the AHB buffer. */
- memcpy(rxbuf, (u8 *)(q->amba_base + q->sf_addr), len);
+ memcpy(rxbuf, (u8 *)(priv->cur_amba_base + priv->sf_addr), len);
- qspi_write32(&regs->mcr, mcr_reg);
+ qspi_write32(priv->flags, &regs->mcr, mcr_reg);
}
-static void qspi_enable_ddr_mode(struct fsl_qspi_regs *regs)
+static void qspi_enable_ddr_mode(struct fsl_qspi_priv *priv)
{
u32 reg, reg2;
+ struct fsl_qspi_regs *regs = priv->regs;
- reg = qspi_read32(&regs->mcr);
+ reg = qspi_read32(priv->flags, &regs->mcr);
/* Disable the module */
- qspi_write32(&regs->mcr, reg | QSPI_MCR_MDIS_MASK);
+ qspi_write32(priv->flags, &regs->mcr, reg | QSPI_MCR_MDIS_MASK);
/* Set the Sampling Register for DDR */
- reg2 = qspi_read32(&regs->smpr);
+ reg2 = qspi_read32(priv->flags, &regs->smpr);
reg2 &= ~QSPI_SMPR_DDRSMP_MASK;
reg2 |= (2 << QSPI_SMPR_DDRSMP_SHIFT);
- qspi_write32(&regs->smpr, reg2);
+ qspi_write32(priv->flags, &regs->smpr, reg2);
/* Enable the module again (enable the DDR too) */
reg |= QSPI_MCR_DDR_EN_MASK;
/* Enable bit 29 for imx6sx */
reg |= (1 << 29);
- qspi_write32(&regs->mcr, reg);
+ qspi_write32(priv->flags, &regs->mcr, reg);
}
/*
@@ -341,180 +401,103 @@ static void qspi_enable_ddr_mode(struct fsl_qspi_regs *regs)
* causes the controller to clear the buffer, and use the sequence pointed
* by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash.
*/
-static void qspi_init_ahb_read(struct fsl_qspi_regs *regs)
+static void qspi_init_ahb_read(struct fsl_qspi_priv *priv)
{
+ struct fsl_qspi_regs *regs = priv->regs;
+
/* AHB configuration for access buffer 0/1/2 .*/
- qspi_write32(&regs->buf0cr, QSPI_BUFXCR_INVALID_MSTRID);
- qspi_write32(&regs->buf1cr, QSPI_BUFXCR_INVALID_MSTRID);
- qspi_write32(&regs->buf2cr, QSPI_BUFXCR_INVALID_MSTRID);
- qspi_write32(&regs->buf3cr, QSPI_BUF3CR_ALLMST_MASK |
+ qspi_write32(priv->flags, &regs->buf0cr, QSPI_BUFXCR_INVALID_MSTRID);
+ qspi_write32(priv->flags, &regs->buf1cr, QSPI_BUFXCR_INVALID_MSTRID);
+ qspi_write32(priv->flags, &regs->buf2cr, QSPI_BUFXCR_INVALID_MSTRID);
+ qspi_write32(priv->flags, &regs->buf3cr, QSPI_BUF3CR_ALLMST_MASK |
(0x80 << QSPI_BUF3CR_ADATSZ_SHIFT));
/* We only use the buffer3 */
- qspi_write32(&regs->buf0ind, 0);
- qspi_write32(&regs->buf1ind, 0);
- qspi_write32(&regs->buf2ind, 0);
+ qspi_write32(priv->flags, &regs->buf0ind, 0);
+ qspi_write32(priv->flags, &regs->buf1ind, 0);
+ qspi_write32(priv->flags, &regs->buf2ind, 0);
/*
* Set the default lut sequence for AHB Read.
* Parallel mode is disabled.
*/
- qspi_write32(&regs->bfgencr,
+ qspi_write32(priv->flags, &regs->bfgencr,
SEQID_FAST_READ << QSPI_BFGENCR_SEQID_SHIFT);
/*Enable DDR Mode*/
- qspi_enable_ddr_mode(regs);
+ qspi_enable_ddr_mode(priv);
}
#endif
-void spi_init()
-{
- /* do nothing */
-}
-
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
- unsigned int max_hz, unsigned int mode)
-{
- struct fsl_qspi *qspi;
- struct fsl_qspi_regs *regs;
- u32 smpr_val;
- u32 total_size;
-
- if (bus >= ARRAY_SIZE(spi_bases))
- return NULL;
-
- if (cs >= FSL_QSPI_FLASH_NUM)
- return NULL;
-
- qspi = spi_alloc_slave(struct fsl_qspi, bus, cs);
- if (!qspi)
- return NULL;
-
- qspi->reg_base = spi_bases[bus];
- /*
- * According cs, use different amba_base to choose the
- * corresponding flash devices.
- *
- * If not, only one flash device is used even if passing
- * different cs using `sf probe`
- */
- qspi->amba_base = amba_bases[bus] + cs * FSL_QSPI_FLASH_SIZE;
-
- qspi->slave.max_write_size = TX_BUFFER_SIZE;
-
- regs = (struct fsl_qspi_regs *)qspi->reg_base;
- qspi_write32(&regs->mcr, QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK);
-
- smpr_val = qspi_read32(&regs->smpr);
- qspi_write32(&regs->smpr, smpr_val & ~(QSPI_SMPR_FSDLY_MASK |
- QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK));
- qspi_write32(&regs->mcr, QSPI_MCR_RESERVED_MASK);
-
- total_size = FSL_QSPI_FLASH_SIZE * FSL_QSPI_FLASH_NUM;
- /*
- * Any read access to non-implemented addresses will provide
- * undefined results.
- *
- * In case single die flash devices, TOP_ADDR_MEMA2 and
- * TOP_ADDR_MEMB2 should be initialized/programmed to
- * TOP_ADDR_MEMA1 and TOP_ADDR_MEMB1 respectively - in effect,
- * setting the size of these devices to 0. This would ensure
- * that the complete memory map is assigned to only one flash device.
- */
- qspi_write32(&regs->sfa1ad, FSL_QSPI_FLASH_SIZE | amba_bases[bus]);
- qspi_write32(&regs->sfa2ad, FSL_QSPI_FLASH_SIZE | amba_bases[bus]);
- qspi_write32(&regs->sfb1ad, total_size | amba_bases[bus]);
- qspi_write32(&regs->sfb2ad, total_size | amba_bases[bus]);
-
- qspi_set_lut(qspi);
-
- smpr_val = qspi_read32(&regs->smpr);
- smpr_val &= ~QSPI_SMPR_DDRSMP_MASK;
- qspi_write32(&regs->smpr, smpr_val);
- qspi_write32(&regs->mcr, QSPI_MCR_RESERVED_MASK);
-
-#ifdef CONFIG_SYS_FSL_QSPI_AHB
- qspi_init_ahb_read(regs);
-#endif
- return &qspi->slave;
-}
-
-void spi_free_slave(struct spi_slave *slave)
-{
- struct fsl_qspi *qspi = to_qspi_spi(slave);
-
- free(qspi);
-}
-
-int spi_claim_bus(struct spi_slave *slave)
-{
- return 0;
-}
-
#ifdef CONFIG_SPI_FLASH_BAR
/* Bank register read/write, EAR register read/write */
-static void qspi_op_rdbank(struct fsl_qspi *qspi, u8 *rxbuf, u32 len)
+static void qspi_op_rdbank(struct fsl_qspi_priv *priv, u8 *rxbuf, u32 len)
{
- struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ struct fsl_qspi_regs *regs = priv->regs;
u32 reg, mcr_reg, data, seqid;
- mcr_reg = qspi_read32(&regs->mcr);
- qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ mcr_reg = qspi_read32(priv->flags, &regs->mcr);
+ qspi_write32(priv->flags, &regs->mcr,
+ QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
- qspi_write32(&regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+ qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
- qspi_write32(&regs->sfar, qspi->amba_base);
+ qspi_write32(priv->flags, &regs->sfar, priv->cur_amba_base);
- if (qspi->cur_seqid == QSPI_CMD_BRRD)
+ if (priv->cur_seqid == QSPI_CMD_BRRD)
seqid = SEQID_BRRD;
else
seqid = SEQID_RDEAR;
- qspi_write32(&regs->ipcr, (seqid << QSPI_IPCR_SEQID_SHIFT) | len);
+ qspi_write32(priv->flags, &regs->ipcr,
+ (seqid << QSPI_IPCR_SEQID_SHIFT) | len);
/* Wait previous command complete */
- while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;
while (1) {
- reg = qspi_read32(&regs->rbsr);
+ reg = qspi_read32(priv->flags, &regs->rbsr);
if (reg & QSPI_RBSR_RDBFL_MASK) {
- data = qspi_read32(&regs->rbdr[0]);
+ data = qspi_read32(priv->flags, &regs->rbdr[0]);
data = qspi_endian_xchg(data);
memcpy(rxbuf, &data, len);
- qspi_write32(&regs->mcr, qspi_read32(&regs->mcr) |
+ qspi_write32(priv->flags, &regs->mcr,
+ qspi_read32(priv->flags, &regs->mcr) |
QSPI_MCR_CLR_RXF_MASK);
break;
}
}
- qspi_write32(&regs->mcr, mcr_reg);
+ qspi_write32(priv->flags, &regs->mcr, mcr_reg);
}
#endif
-static void qspi_op_rdid(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
+static void qspi_op_rdid(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len)
{
- struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ struct fsl_qspi_regs *regs = priv->regs;
u32 mcr_reg, rbsr_reg, data;
int i, size;
- mcr_reg = qspi_read32(&regs->mcr);
- qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
- qspi_write32(&regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+ mcr_reg = qspi_read32(priv->flags, &regs->mcr);
+ qspi_write32(priv->flags, &regs->mcr,
+ QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+ qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
- qspi_write32(&regs->sfar, qspi->amba_base);
+ qspi_write32(priv->flags, &regs->sfar, priv->cur_amba_base);
- qspi_write32(&regs->ipcr, (SEQID_RDID << QSPI_IPCR_SEQID_SHIFT) | 0);
- while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ qspi_write32(priv->flags, &regs->ipcr,
+ (SEQID_RDID << QSPI_IPCR_SEQID_SHIFT) | 0);
+ while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;
i = 0;
size = len;
while ((RX_BUFFER_SIZE >= size) && (size > 0)) {
- rbsr_reg = qspi_read32(&regs->rbsr);
+ rbsr_reg = qspi_read32(priv->flags, &regs->rbsr);
if (rbsr_reg & QSPI_RBSR_RDBFL_MASK) {
- data = qspi_read32(&regs->rbdr[i]);
+ data = qspi_read32(priv->flags, &regs->rbdr[i]);
data = qspi_endian_xchg(data);
memcpy(rxbuf, &data, 4);
rxbuf++;
@@ -523,34 +506,36 @@ static void qspi_op_rdid(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
}
}
- qspi_write32(&regs->mcr, mcr_reg);
+ qspi_write32(priv->flags, &regs->mcr, mcr_reg);
}
#ifndef CONFIG_SYS_FSL_QSPI_AHB
/* If not use AHB read, read data from ip interface */
-static void qspi_op_read(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
+static void qspi_op_read(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len)
{
- struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ struct fsl_qspi_regs *regs = priv->regs;
u32 mcr_reg, data;
int i, size;
u32 to_or_from;
- mcr_reg = qspi_read32(&regs->mcr);
- qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
- qspi_write32(&regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+ mcr_reg = qspi_read32(priv->flags, &regs->mcr);
+ qspi_write32(priv->flags, &regs->mcr,
+ QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+ qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
- to_or_from = qspi->sf_addr + qspi->amba_base;
+ to_or_from = priv->sf_addr + priv->cur_amba_base;
while (len > 0) {
- qspi_write32(&regs->sfar, to_or_from);
+ qspi_write32(priv->flags, &regs->sfar, to_or_from);
size = (len > RX_BUFFER_SIZE) ?
RX_BUFFER_SIZE : len;
- qspi_write32(&regs->ipcr,
- (SEQID_FAST_READ << QSPI_IPCR_SEQID_SHIFT) | size);
- while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ qspi_write32(priv->flags, &regs->ipcr,
+ (SEQID_FAST_READ << QSPI_IPCR_SEQID_SHIFT) |
+ size);
+ while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;
to_or_from += size;
@@ -558,66 +543,69 @@ static void qspi_op_read(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
i = 0;
while ((RX_BUFFER_SIZE >= size) && (size > 0)) {
- data = qspi_read32(&regs->rbdr[i]);
+ data = qspi_read32(priv->flags, &regs->rbdr[i]);
data = qspi_endian_xchg(data);
memcpy(rxbuf, &data, 4);
rxbuf++;
size -= 4;
i++;
}
- qspi_write32(&regs->mcr, qspi_read32(&regs->mcr) |
- QSPI_MCR_CLR_RXF_MASK);
+ qspi_write32(priv->flags, &regs->mcr,
+ qspi_read32(priv->flags, &regs->mcr) |
+ QSPI_MCR_CLR_RXF_MASK);
}
- qspi_write32(&regs->mcr, mcr_reg);
+ qspi_write32(priv->flags, &regs->mcr, mcr_reg);
}
#endif
-static void qspi_op_write(struct fsl_qspi *qspi, u8 *txbuf, u32 len)
+static void qspi_op_write(struct fsl_qspi_priv *priv, u8 *txbuf, u32 len)
{
- struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ struct fsl_qspi_regs *regs = priv->regs;
u32 mcr_reg, data, reg, status_reg, seqid;
int i, size, tx_size;
u32 to_or_from = 0;
- mcr_reg = qspi_read32(&regs->mcr);
- qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
- qspi_write32(&regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+ mcr_reg = qspi_read32(priv->flags, &regs->mcr);
+ qspi_write32(priv->flags, &regs->mcr,
+ QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+ qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
status_reg = 0;
while ((status_reg & FLASH_STATUS_WEL) != FLASH_STATUS_WEL) {
- qspi_write32(&regs->ipcr,
- (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0);
- while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ qspi_write32(priv->flags, &regs->ipcr,
+ (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0);
+ while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;
- qspi_write32(&regs->ipcr,
- (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 1);
- while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ qspi_write32(priv->flags, &regs->ipcr,
+ (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 1);
+ while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;
- reg = qspi_read32(&regs->rbsr);
+ reg = qspi_read32(priv->flags, &regs->rbsr);
if (reg & QSPI_RBSR_RDBFL_MASK) {
- status_reg = qspi_read32(&regs->rbdr[0]);
+ status_reg = qspi_read32(priv->flags, &regs->rbdr[0]);
status_reg = qspi_endian_xchg(status_reg);
}
- qspi_write32(&regs->mcr,
- qspi_read32(&regs->mcr) | QSPI_MCR_CLR_RXF_MASK);
+ qspi_write32(priv->flags, &regs->mcr,
+ qspi_read32(priv->flags, &regs->mcr) |
+ QSPI_MCR_CLR_RXF_MASK);
}
/* Default is page programming */
seqid = SEQID_PP;
#ifdef CONFIG_SPI_FLASH_BAR
- if (qspi->cur_seqid == QSPI_CMD_BRWR)
+ if (priv->cur_seqid == QSPI_CMD_BRWR)
seqid = SEQID_BRWR;
- else if (qspi->cur_seqid == QSPI_CMD_WREAR)
+ else if (priv->cur_seqid == QSPI_CMD_WREAR)
seqid = SEQID_WREAR;
#endif
- to_or_from = qspi->sf_addr + qspi->amba_base;
+ to_or_from = priv->sf_addr + priv->cur_amba_base;
- qspi_write32(&regs->sfar, to_or_from);
+ qspi_write32(priv->flags, &regs->sfar, to_or_from);
tx_size = (len > TX_BUFFER_SIZE) ?
TX_BUFFER_SIZE : len;
@@ -626,7 +614,7 @@ static void qspi_op_write(struct fsl_qspi *qspi, u8 *txbuf, u32 len)
for (i = 0; i < size; i++) {
memcpy(&data, txbuf, 4);
data = qspi_endian_xchg(data);
- qspi_write32(&regs->tbdr, data);
+ qspi_write32(priv->flags, &regs->tbdr, data);
txbuf += 4;
}
@@ -635,146 +623,273 @@ static void qspi_op_write(struct fsl_qspi *qspi, u8 *txbuf, u32 len)
data = 0;
memcpy(&data, txbuf, size);
data = qspi_endian_xchg(data);
- qspi_write32(&regs->tbdr, data);
+ qspi_write32(priv->flags, &regs->tbdr, data);
}
- qspi_write32(&regs->ipcr, (seqid << QSPI_IPCR_SEQID_SHIFT) | tx_size);
- while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ qspi_write32(priv->flags, &regs->ipcr,
+ (seqid << QSPI_IPCR_SEQID_SHIFT) | tx_size);
+ while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;
- qspi_write32(&regs->mcr, mcr_reg);
+ qspi_write32(priv->flags, &regs->mcr, mcr_reg);
}
-static void qspi_op_rdsr(struct fsl_qspi *qspi, u32 *rxbuf)
+static void qspi_op_rdsr(struct fsl_qspi_priv *priv, u32 *rxbuf)
{
- struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ struct fsl_qspi_regs *regs = priv->regs;
u32 mcr_reg, reg, data;
- mcr_reg = qspi_read32(&regs->mcr);
- qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
- qspi_write32(&regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+ mcr_reg = qspi_read32(priv->flags, &regs->mcr);
+ qspi_write32(priv->flags, &regs->mcr,
+ QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+ qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
- qspi_write32(&regs->sfar, qspi->amba_base);
+ qspi_write32(priv->flags, &regs->sfar, priv->cur_amba_base);
- qspi_write32(&regs->ipcr,
- (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 0);
- while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ qspi_write32(priv->flags, &regs->ipcr,
+ (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 0);
+ while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;
while (1) {
- reg = qspi_read32(&regs->rbsr);
+ reg = qspi_read32(priv->flags, &regs->rbsr);
if (reg & QSPI_RBSR_RDBFL_MASK) {
- data = qspi_read32(&regs->rbdr[0]);
+ data = qspi_read32(priv->flags, &regs->rbdr[0]);
data = qspi_endian_xchg(data);
memcpy(rxbuf, &data, 4);
- qspi_write32(&regs->mcr, qspi_read32(&regs->mcr) |
- QSPI_MCR_CLR_RXF_MASK);
+ qspi_write32(priv->flags, &regs->mcr,
+ qspi_read32(priv->flags, &regs->mcr) |
+ QSPI_MCR_CLR_RXF_MASK);
break;
}
}
- qspi_write32(&regs->mcr, mcr_reg);
+ qspi_write32(priv->flags, &regs->mcr, mcr_reg);
}
-static void qspi_op_erase(struct fsl_qspi *qspi)
+static void qspi_op_erase(struct fsl_qspi_priv *priv)
{
- struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ struct fsl_qspi_regs *regs = priv->regs;
u32 mcr_reg;
u32 to_or_from = 0;
- mcr_reg = qspi_read32(&regs->mcr);
- qspi_write32(&regs->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
- qspi_write32(&regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+ mcr_reg = qspi_read32(priv->flags, &regs->mcr);
+ qspi_write32(priv->flags, &regs->mcr,
+ QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
+ qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
- to_or_from = qspi->sf_addr + qspi->amba_base;
- qspi_write32(&regs->sfar, to_or_from);
+ to_or_from = priv->sf_addr + priv->cur_amba_base;
+ qspi_write32(priv->flags, &regs->sfar, to_or_from);
- qspi_write32(&regs->ipcr,
- (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0);
- while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ qspi_write32(priv->flags, &regs->ipcr,
+ (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0);
+ while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;
- if (qspi->cur_seqid == QSPI_CMD_SE) {
- qspi_write32(&regs->ipcr,
+ if (priv->cur_seqid == QSPI_CMD_SE) {
+ qspi_write32(priv->flags, &regs->ipcr,
(SEQID_SE << QSPI_IPCR_SEQID_SHIFT) | 0);
- } else if (qspi->cur_seqid == QSPI_CMD_BE_4K) {
- qspi_write32(&regs->ipcr,
+ } else if (priv->cur_seqid == QSPI_CMD_BE_4K) {
+ qspi_write32(priv->flags, &regs->ipcr,
(SEQID_BE_4K << QSPI_IPCR_SEQID_SHIFT) | 0);
}
- while (qspi_read32(&regs->sr) & QSPI_SR_BUSY_MASK)
+ while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;
- qspi_write32(&regs->mcr, mcr_reg);
+ qspi_write32(priv->flags, &regs->mcr, mcr_reg);
}
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+int qspi_xfer(struct fsl_qspi_priv *priv, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
- struct fsl_qspi *qspi = to_qspi_spi(slave);
u32 bytes = DIV_ROUND_UP(bitlen, 8);
static u32 wr_sfaddr;
u32 txbuf;
if (dout) {
if (flags & SPI_XFER_BEGIN) {
- qspi->cur_seqid = *(u8 *)dout;
+ priv->cur_seqid = *(u8 *)dout;
memcpy(&txbuf, dout, 4);
}
if (flags == SPI_XFER_END) {
- qspi->sf_addr = wr_sfaddr;
- qspi_op_write(qspi, (u8 *)dout, bytes);
+ priv->sf_addr = wr_sfaddr;
+ qspi_op_write(priv, (u8 *)dout, bytes);
return 0;
}
- if (qspi->cur_seqid == QSPI_CMD_FAST_READ) {
- qspi->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK;
- } else if ((qspi->cur_seqid == QSPI_CMD_SE) ||
- (qspi->cur_seqid == QSPI_CMD_BE_4K)) {
- qspi->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK;
- qspi_op_erase(qspi);
- } else if (qspi->cur_seqid == QSPI_CMD_PP)
+ if (priv->cur_seqid == QSPI_CMD_FAST_READ) {
+ priv->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK;
+ } else if ((priv->cur_seqid == QSPI_CMD_SE) ||
+ (priv->cur_seqid == QSPI_CMD_BE_4K)) {
+ priv->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK;
+ qspi_op_erase(priv);
+ } else if (priv->cur_seqid == QSPI_CMD_PP) {
wr_sfaddr = swab32(txbuf) & OFFSET_BITS_MASK;
+ } else if ((priv->cur_seqid == QSPI_CMD_BRWR) ||
+ (priv->cur_seqid == QSPI_CMD_WREAR)) {
#ifdef CONFIG_SPI_FLASH_BAR
- else if ((qspi->cur_seqid == QSPI_CMD_BRWR) ||
- (qspi->cur_seqid == QSPI_CMD_WREAR)) {
wr_sfaddr = 0;
- }
#endif
+ }
}
if (din) {
- if (qspi->cur_seqid == QSPI_CMD_FAST_READ) {
+ if (priv->cur_seqid == QSPI_CMD_FAST_READ) {
#ifdef CONFIG_SYS_FSL_QSPI_AHB
- qspi_ahb_read(qspi, din, bytes);
+ qspi_ahb_read(priv, din, bytes);
#else
- qspi_op_read(qspi, din, bytes);
+ qspi_op_read(priv, din, bytes);
#endif
- }
- else if (qspi->cur_seqid == QSPI_CMD_RDID)
- qspi_op_rdid(qspi, din, bytes);
- else if (qspi->cur_seqid == QSPI_CMD_RDSR)
- qspi_op_rdsr(qspi, din);
+ } else if (priv->cur_seqid == QSPI_CMD_RDID)
+ qspi_op_rdid(priv, din, bytes);
+ else if (priv->cur_seqid == QSPI_CMD_RDSR)
+ qspi_op_rdsr(priv, din);
#ifdef CONFIG_SPI_FLASH_BAR
- else if ((qspi->cur_seqid == QSPI_CMD_BRRD) ||
- (qspi->cur_seqid == QSPI_CMD_RDEAR)) {
- qspi->sf_addr = 0;
- qspi_op_rdbank(qspi, din, bytes);
+ else if ((priv->cur_seqid == QSPI_CMD_BRRD) ||
+ (priv->cur_seqid == QSPI_CMD_RDEAR)) {
+ priv->sf_addr = 0;
+ qspi_op_rdbank(priv, din, bytes);
}
#endif
}
#ifdef CONFIG_SYS_FSL_QSPI_AHB
- if ((qspi->cur_seqid == QSPI_CMD_SE) ||
- (qspi->cur_seqid == QSPI_CMD_PP) ||
- (qspi->cur_seqid == QSPI_CMD_BE_4K) ||
- (qspi->cur_seqid == QSPI_CMD_WREAR) ||
- (qspi->cur_seqid == QSPI_CMD_BRWR))
- qspi_ahb_invalid(qspi);
+ if ((priv->cur_seqid == QSPI_CMD_SE) ||
+ (priv->cur_seqid == QSPI_CMD_PP) ||
+ (priv->cur_seqid == QSPI_CMD_BE_4K) ||
+ (priv->cur_seqid == QSPI_CMD_WREAR) ||
+ (priv->cur_seqid == QSPI_CMD_BRWR))
+ qspi_ahb_invalid(priv);
+#endif
+
+ return 0;
+}
+
+void qspi_module_disable(struct fsl_qspi_priv *priv, u8 disable)
+{
+ u32 mcr_val;
+
+ mcr_val = qspi_read32(priv->flags, &priv->regs->mcr);
+ if (disable)
+ mcr_val |= QSPI_MCR_MDIS_MASK;
+ else
+ mcr_val &= ~QSPI_MCR_MDIS_MASK;
+ qspi_write32(priv->flags, &priv->regs->mcr, mcr_val);
+}
+
+void qspi_cfg_smpr(struct fsl_qspi_priv *priv, u32 clear_bits, u32 set_bits)
+{
+ u32 smpr_val;
+
+ smpr_val = qspi_read32(priv->flags, &priv->regs->smpr);
+ smpr_val &= ~clear_bits;
+ smpr_val |= set_bits;
+ qspi_write32(priv->flags, &priv->regs->smpr, smpr_val);
+}
+#ifndef CONFIG_DM_SPI
+static unsigned long spi_bases[] = {
+ QSPI0_BASE_ADDR,
+#ifdef CONFIG_MX6SX
+ QSPI1_BASE_ADDR,
+#endif
+};
+
+static unsigned long amba_bases[] = {
+ QSPI0_AMBA_BASE,
+#ifdef CONFIG_MX6SX
+ QSPI1_AMBA_BASE,
+#endif
+};
+
+static inline struct fsl_qspi *to_qspi_spi(struct spi_slave *slave)
+{
+ return container_of(slave, struct fsl_qspi, slave);
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
+{
+ struct fsl_qspi *qspi;
+ struct fsl_qspi_regs *regs;
+ u32 total_size;
+
+ if (bus >= ARRAY_SIZE(spi_bases))
+ return NULL;
+
+ if (cs >= FSL_QSPI_FLASH_NUM)
+ return NULL;
+
+ qspi = spi_alloc_slave(struct fsl_qspi, bus, cs);
+ if (!qspi)
+ return NULL;
+
+#ifdef CONFIG_SYS_FSL_QSPI_BE
+ qspi->priv.flags |= QSPI_FLAG_REGMAP_ENDIAN_BIG;
+#endif
+
+ regs = (struct fsl_qspi_regs *)spi_bases[bus];
+ qspi->priv.regs = regs;
+ /*
+ * According cs, use different amba_base to choose the
+ * corresponding flash devices.
+ *
+ * If not, only one flash device is used even if passing
+ * different cs using `sf probe`
+ */
+ qspi->priv.cur_amba_base = amba_bases[bus] + cs * FSL_QSPI_FLASH_SIZE;
+
+ qspi->slave.max_write_size = TX_BUFFER_SIZE;
+
+ qspi_write32(qspi->priv.flags, &regs->mcr,
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK);
+
+ qspi_cfg_smpr(&qspi->priv,
+ ~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_DDRSMP_MASK |
+ QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK), 0);
+
+ total_size = FSL_QSPI_FLASH_SIZE * FSL_QSPI_FLASH_NUM;
+ /*
+ * Any read access to non-implemented addresses will provide
+ * undefined results.
+ *
+ * In case single die flash devices, TOP_ADDR_MEMA2 and
+ * TOP_ADDR_MEMB2 should be initialized/programmed to
+ * TOP_ADDR_MEMA1 and TOP_ADDR_MEMB1 respectively - in effect,
+ * setting the size of these devices to 0. This would ensure
+ * that the complete memory map is assigned to only one flash device.
+ */
+ qspi_write32(qspi->priv.flags, &regs->sfa1ad,
+ FSL_QSPI_FLASH_SIZE | amba_bases[bus]);
+ qspi_write32(qspi->priv.flags, &regs->sfa2ad,
+ FSL_QSPI_FLASH_SIZE | amba_bases[bus]);
+ qspi_write32(qspi->priv.flags, &regs->sfb1ad,
+ total_size | amba_bases[bus]);
+ qspi_write32(qspi->priv.flags, &regs->sfb2ad,
+ total_size | amba_bases[bus]);
+
+ qspi_set_lut(&qspi->priv);
+
+#ifdef CONFIG_SYS_FSL_QSPI_AHB
+ qspi_init_ahb_read(&qspi->priv);
#endif
+ qspi_module_disable(&qspi->priv, 0);
+
+ return &qspi->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ struct fsl_qspi *qspi = to_qspi_spi(slave);
+
+ free(qspi);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
return 0;
}
@@ -782,3 +897,215 @@ void spi_release_bus(struct spi_slave *slave)
{
/* Nothing to do */
}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct fsl_qspi *qspi = to_qspi_spi(slave);
+
+ return qspi_xfer(&qspi->priv, bitlen, dout, din, flags);
+}
+
+void spi_init(void)
+{
+ /* Nothing to do */
+}
+#else
+static int fsl_qspi_child_pre_probe(struct udevice *dev)
+{
+ struct spi_slave *slave = dev_get_parentdata(dev);
+
+ slave->max_write_size = TX_BUFFER_SIZE;
+
+ return 0;
+}
+
+static int fsl_qspi_probe(struct udevice *bus)
+{
+ u32 total_size;
+ struct fsl_qspi_platdata *plat = dev_get_platdata(bus);
+ struct fsl_qspi_priv *priv = dev_get_priv(bus);
+ struct dm_spi_bus *dm_spi_bus;
+
+ dm_spi_bus = bus->uclass_priv;
+
+ dm_spi_bus->max_hz = plat->speed_hz;
+
+ priv->regs = (struct fsl_qspi_regs *)plat->reg_base;
+ priv->flags = plat->flags;
+
+ priv->speed_hz = plat->speed_hz;
+ priv->amba_base[0] = plat->amba_base;
+ priv->amba_total_size = plat->amba_total_size;
+ priv->flash_num = plat->flash_num;
+ priv->num_chipselect = plat->num_chipselect;
+
+ qspi_write32(priv->flags, &priv->regs->mcr,
+ QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK);
+
+ qspi_cfg_smpr(priv, ~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_DDRSMP_MASK |
+ QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK), 0);
+
+ total_size = FSL_QSPI_FLASH_SIZE * FSL_QSPI_FLASH_NUM;
+ /*
+ * Any read access to non-implemented addresses will provide
+ * undefined results.
+ *
+ * In case single die flash devices, TOP_ADDR_MEMA2 and
+ * TOP_ADDR_MEMB2 should be initialized/programmed to
+ * TOP_ADDR_MEMA1 and TOP_ADDR_MEMB1 respectively - in effect,
+ * setting the size of these devices to 0. This would ensure
+ * that the complete memory map is assigned to only one flash device.
+ */
+ qspi_write32(priv->flags, &priv->regs->sfa1ad,
+ FSL_QSPI_FLASH_SIZE | priv->amba_base[0]);
+ qspi_write32(priv->flags, &priv->regs->sfa2ad,
+ FSL_QSPI_FLASH_SIZE | priv->amba_base[0]);
+ qspi_write32(priv->flags, &priv->regs->sfb1ad,
+ total_size | priv->amba_base[0]);
+ qspi_write32(priv->flags, &priv->regs->sfb2ad,
+ total_size | priv->amba_base[0]);
+
+ qspi_set_lut(priv);
+
+#ifdef CONFIG_SYS_FSL_QSPI_AHB
+ qspi_init_ahb_read(priv);
+#endif
+
+ qspi_module_disable(priv, 0);
+
+ return 0;
+}
+
+static int fsl_qspi_ofdata_to_platdata(struct udevice *bus)
+{
+ struct reg_data {
+ u32 addr;
+ u32 size;
+ } regs_data[2];
+ struct fsl_qspi_platdata *plat = bus->platdata;
+ const void *blob = gd->fdt_blob;
+ int node = bus->of_offset;
+ int ret, flash_num = 0, subnode;
+
+ if (fdtdec_get_bool(blob, node, "big-endian"))
+ plat->flags |= QSPI_FLAG_REGMAP_ENDIAN_BIG;
+
+ ret = fdtdec_get_int_array(blob, node, "reg", (u32 *)regs_data,
+ sizeof(regs_data)/sizeof(u32));
+ if (ret) {
+ debug("Error: can't get base addresses (ret = %d)!\n", ret);
+ return -ENOMEM;
+ }
+
+ /* Count flash numbers */
+ fdt_for_each_subnode(blob, subnode, node)
+ ++flash_num;
+
+ if (flash_num == 0) {
+ debug("Error: Missing flashes!\n");
+ return -ENODEV;
+ }
+
+ plat->speed_hz = fdtdec_get_int(blob, node, "spi-max-frequency",
+ FSL_QSPI_DEFAULT_SCK_FREQ);
+ plat->num_chipselect = fdtdec_get_int(blob, node, "num-cs",
+ FSL_QSPI_MAX_CHIPSELECT_NUM);
+
+ plat->reg_base = regs_data[0].addr;
+ plat->amba_base = regs_data[1].addr;
+ plat->amba_total_size = regs_data[1].size;
+ plat->flash_num = flash_num;
+
+ debug("%s: regs=<0x%x> <0x%x, 0x%x>, max-frequency=%d, endianess=%s\n",
+ __func__,
+ plat->reg_base,
+ plat->amba_base,
+ plat->amba_total_size,
+ plat->speed_hz,
+ plat->flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ? "be" : "le"
+ );
+
+ return 0;
+}
+
+static int fsl_qspi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct fsl_qspi_priv *priv;
+ struct udevice *bus;
+
+ bus = dev->parent;
+ priv = dev_get_priv(bus);
+
+ return qspi_xfer(priv, bitlen, dout, din, flags);
+}
+
+static int fsl_qspi_claim_bus(struct udevice *dev)
+{
+ struct fsl_qspi_priv *priv;
+ struct udevice *bus;
+ struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
+
+ bus = dev->parent;
+ priv = dev_get_priv(bus);
+
+ priv->cur_amba_base =
+ priv->amba_base[0] + FSL_QSPI_FLASH_SIZE * slave_plat->cs;
+
+ qspi_module_disable(priv, 0);
+
+ return 0;
+}
+
+static int fsl_qspi_release_bus(struct udevice *dev)
+{
+ struct fsl_qspi_priv *priv;
+ struct udevice *bus;
+
+ bus = dev->parent;
+ priv = dev_get_priv(bus);
+
+ qspi_module_disable(priv, 1);
+
+ return 0;
+}
+
+static int fsl_qspi_set_speed(struct udevice *bus, uint speed)
+{
+ /* Nothing to do */
+ return 0;
+}
+
+static int fsl_qspi_set_mode(struct udevice *bus, uint mode)
+{
+ /* Nothing to do */
+ return 0;
+}
+
+static const struct dm_spi_ops fsl_qspi_ops = {
+ .claim_bus = fsl_qspi_claim_bus,
+ .release_bus = fsl_qspi_release_bus,
+ .xfer = fsl_qspi_xfer,
+ .set_speed = fsl_qspi_set_speed,
+ .set_mode = fsl_qspi_set_mode,
+};
+
+static const struct udevice_id fsl_qspi_ids[] = {
+ { .compatible = "fsl,vf610-qspi" },
+ { .compatible = "fsl,imx6sx-qspi" },
+ { }
+};
+
+U_BOOT_DRIVER(fsl_qspi) = {
+ .name = "fsl_qspi",
+ .id = UCLASS_SPI,
+ .of_match = fsl_qspi_ids,
+ .ops = &fsl_qspi_ops,
+ .ofdata_to_platdata = fsl_qspi_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct fsl_qspi_platdata),
+ .priv_auto_alloc_size = sizeof(struct fsl_qspi_priv),
+ .probe = fsl_qspi_probe,
+ .child_pre_probe = fsl_qspi_child_pre_probe,
+};
+#endif
diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c
index 194e882..50354fd 100644
--- a/drivers/spi/ich.c
+++ b/drivers/spi/ich.c
@@ -7,6 +7,7 @@
*/
#include <common.h>
+#include <dm.h>
#include <errno.h>
#include <malloc.h>
#include <spi.h>
@@ -19,154 +20,99 @@
#define SPI_OPCODE_WREN 0x06
#define SPI_OPCODE_FAST_READ 0x0b
-struct ich_ctlr {
+struct ich_spi_platdata {
pci_dev_t dev; /* PCI device number */
int ich_version; /* Controller version, 7 or 9 */
bool use_sbase; /* Use SBASE instead of RCB */
+};
+
+struct ich_spi_priv {
int ichspi_lock;
int locked;
- uint8_t *opmenu;
+ int opmenu;
int menubytes;
void *base; /* Base of register set */
- uint16_t *preop;
- uint16_t *optype;
- uint32_t *addr;
- uint8_t *data;
+ int preop;
+ int optype;
+ int addr;
+ int data;
unsigned databytes;
- uint8_t *status;
- uint16_t *control;
- uint32_t *bbar;
+ int status;
+ int control;
+ int bbar;
uint32_t *pr; /* only for ich9 */
- uint8_t *speed; /* pointer to speed control */
+ int speed; /* pointer to speed control */
ulong max_speed; /* Maximum bus speed in MHz */
+ ulong cur_speed; /* Current bus speed */
+ struct spi_trans trans; /* current transaction in progress */
};
-struct ich_ctlr ctlr;
-
-static inline struct ich_spi_slave *to_ich_spi(struct spi_slave *slave)
-{
- return container_of(slave, struct ich_spi_slave, slave);
-}
-
-static unsigned int ich_reg(const void *addr)
-{
- return (unsigned)(addr - ctlr.base) & 0xffff;
-}
-
-static u8 ich_readb(const void *addr)
+static u8 ich_readb(struct ich_spi_priv *priv, int reg)
{
- u8 value = readb(addr);
+ u8 value = readb(priv->base + reg);
- debug("read %2.2x from %4.4x\n", value, ich_reg(addr));
+ debug("read %2.2x from %4.4x\n", value, reg);
return value;
}
-static u16 ich_readw(const void *addr)
+static u16 ich_readw(struct ich_spi_priv *priv, int reg)
{
- u16 value = readw(addr);
+ u16 value = readw(priv->base + reg);
- debug("read %4.4x from %4.4x\n", value, ich_reg(addr));
+ debug("read %4.4x from %4.4x\n", value, reg);
return value;
}
-static u32 ich_readl(const void *addr)
+static u32 ich_readl(struct ich_spi_priv *priv, int reg)
{
- u32 value = readl(addr);
+ u32 value = readl(priv->base + reg);
- debug("read %8.8x from %4.4x\n", value, ich_reg(addr));
+ debug("read %8.8x from %4.4x\n", value, reg);
return value;
}
-static void ich_writeb(u8 value, void *addr)
+static void ich_writeb(struct ich_spi_priv *priv, u8 value, int reg)
{
- writeb(value, addr);
- debug("wrote %2.2x to %4.4x\n", value, ich_reg(addr));
+ writeb(value, priv->base + reg);
+ debug("wrote %2.2x to %4.4x\n", value, reg);
}
-static void ich_writew(u16 value, void *addr)
+static void ich_writew(struct ich_spi_priv *priv, u16 value, int reg)
{
- writew(value, addr);
- debug("wrote %4.4x to %4.4x\n", value, ich_reg(addr));
+ writew(value, priv->base + reg);
+ debug("wrote %4.4x to %4.4x\n", value, reg);
}
-static void ich_writel(u32 value, void *addr)
+static void ich_writel(struct ich_spi_priv *priv, u32 value, int reg)
{
- writel(value, addr);
- debug("wrote %8.8x to %4.4x\n", value, ich_reg(addr));
+ writel(value, priv->base + reg);
+ debug("wrote %8.8x to %4.4x\n", value, reg);
}
-static void write_reg(const void *value, void *dest, uint32_t size)
+static void write_reg(struct ich_spi_priv *priv, const void *value,
+ int dest_reg, uint32_t size)
{
- memcpy_toio(dest, value, size);
+ memcpy_toio(priv->base + dest_reg, value, size);
}
-static void read_reg(const void *src, void *value, uint32_t size)
+static void read_reg(struct ich_spi_priv *priv, int src_reg, void *value,
+ uint32_t size)
{
- memcpy_fromio(value, src, size);
+ memcpy_fromio(value, priv->base + src_reg, size);
}
-static void ich_set_bbar(struct ich_ctlr *ctlr, uint32_t minaddr)
+static void ich_set_bbar(struct ich_spi_priv *ctlr, uint32_t minaddr)
{
const uint32_t bbar_mask = 0x00ffff00;
uint32_t ichspi_bbar;
minaddr &= bbar_mask;
- ichspi_bbar = ich_readl(ctlr->bbar) & ~bbar_mask;
+ ichspi_bbar = ich_readl(ctlr, ctlr->bbar) & ~bbar_mask;
ichspi_bbar |= minaddr;
- ich_writel(ichspi_bbar, ctlr->bbar);
-}
-
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
- puts("spi_cs_is_valid used but not implemented\n");
- return 0;
-}
-
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
- unsigned int max_hz, unsigned int mode)
-{
- struct ich_spi_slave *ich;
-
- ich = spi_alloc_slave(struct ich_spi_slave, bus, cs);
- if (!ich) {
- puts("ICH SPI: Out of memory\n");
- return NULL;
- }
-
- /*
- * Yes this controller can only write a small number of bytes at
- * once! The limit is typically 64 bytes.
- */
- ich->slave.max_write_size = ctlr.databytes;
- ich->speed = max_hz;
-
- /*
- * ICH 7 SPI controller only supports array read command
- * and byte program command for SST flash
- */
- if (ctlr.ich_version == 7 || ctlr.use_sbase) {
- ich->slave.op_mode_rx = SPI_OPM_RX_AS;
- ich->slave.op_mode_tx = SPI_OPM_TX_BP;
- }
-
- return &ich->slave;
-}
-
-struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node,
- int spi_node)
-{
- /* We only support a single SPI at present */
- return spi_setup_slave(0, 0, 20000000, 0);
-}
-
-void spi_free_slave(struct spi_slave *slave)
-{
- struct ich_spi_slave *ich = to_ich_spi(slave);
-
- free(ich);
+ ich_writel(ctlr, ichspi_bbar, ctlr->bbar);
}
/*
@@ -185,7 +131,8 @@ static int get_ich_version(uint16_t device_id)
device_id <= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX) ||
(device_id >= PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MIN &&
device_id <= PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX) ||
- device_id == PCI_DEVICE_ID_INTEL_VALLEYVIEW_LPC)
+ device_id == PCI_DEVICE_ID_INTEL_VALLEYVIEW_LPC ||
+ device_id == PCI_DEVICE_ID_INTEL_LYNXPOINT_LPC)
return 9;
return 0;
@@ -208,7 +155,7 @@ static int ich9_can_do_33mhz(pci_dev_t dev)
return speed == 1;
}
-static int ich_find_spi_controller(struct ich_ctlr *ich)
+static int ich_find_spi_controller(struct ich_spi_platdata *ich)
{
int last_bus = pci_last_busno();
int bus;
@@ -241,131 +188,77 @@ static int ich_find_spi_controller(struct ich_ctlr *ich)
return -ENODEV;
}
-static int ich_init_controller(struct ich_ctlr *ctlr)
+static int ich_init_controller(struct ich_spi_platdata *plat,
+ struct ich_spi_priv *ctlr)
{
uint8_t *rcrb; /* Root Complex Register Block */
uint32_t rcba; /* Root Complex Base Address */
uint32_t sbase_addr;
uint8_t *sbase;
- pci_read_config_dword(ctlr->dev, 0xf0, &rcba);
+ pci_read_config_dword(plat->dev, 0xf0, &rcba);
/* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable. */
rcrb = (uint8_t *)(rcba & 0xffffc000);
/* SBASE is similar */
- pci_read_config_dword(ctlr->dev, 0x54, &sbase_addr);
+ pci_read_config_dword(plat->dev, 0x54, &sbase_addr);
sbase = (uint8_t *)(sbase_addr & 0xfffffe00);
- if (ctlr->ich_version == 7) {
+ if (plat->ich_version == 7) {
struct ich7_spi_regs *ich7_spi;
ich7_spi = (struct ich7_spi_regs *)(rcrb + 0x3020);
- ctlr->ichspi_lock = ich_readw(&ich7_spi->spis) & SPIS_LOCK;
- ctlr->opmenu = ich7_spi->opmenu;
+ ctlr->ichspi_lock = readw(&ich7_spi->spis) & SPIS_LOCK;
+ ctlr->opmenu = offsetof(struct ich7_spi_regs, opmenu);
ctlr->menubytes = sizeof(ich7_spi->opmenu);
- ctlr->optype = &ich7_spi->optype;
- ctlr->addr = &ich7_spi->spia;
- ctlr->data = (uint8_t *)ich7_spi->spid;
+ ctlr->optype = offsetof(struct ich7_spi_regs, optype);
+ ctlr->addr = offsetof(struct ich7_spi_regs, spia);
+ ctlr->data = offsetof(struct ich7_spi_regs, spid);
ctlr->databytes = sizeof(ich7_spi->spid);
- ctlr->status = (uint8_t *)&ich7_spi->spis;
- ctlr->control = &ich7_spi->spic;
- ctlr->bbar = &ich7_spi->bbar;
- ctlr->preop = &ich7_spi->preop;
+ ctlr->status = offsetof(struct ich7_spi_regs, spis);
+ ctlr->control = offsetof(struct ich7_spi_regs, spic);
+ ctlr->bbar = offsetof(struct ich7_spi_regs, bbar);
+ ctlr->preop = offsetof(struct ich7_spi_regs, preop);
ctlr->base = ich7_spi;
- } else if (ctlr->ich_version == 9) {
+ } else if (plat->ich_version == 9) {
struct ich9_spi_regs *ich9_spi;
- if (ctlr->use_sbase)
+ if (plat->use_sbase)
ich9_spi = (struct ich9_spi_regs *)sbase;
else
ich9_spi = (struct ich9_spi_regs *)(rcrb + 0x3800);
- ctlr->ichspi_lock = ich_readw(&ich9_spi->hsfs) & HSFS_FLOCKDN;
- ctlr->opmenu = ich9_spi->opmenu;
+ ctlr->ichspi_lock = readw(&ich9_spi->hsfs) & HSFS_FLOCKDN;
+ ctlr->opmenu = offsetof(struct ich9_spi_regs, opmenu);
ctlr->menubytes = sizeof(ich9_spi->opmenu);
- ctlr->optype = &ich9_spi->optype;
- ctlr->addr = &ich9_spi->faddr;
- ctlr->data = (uint8_t *)ich9_spi->fdata;
+ ctlr->optype = offsetof(struct ich9_spi_regs, optype);
+ ctlr->addr = offsetof(struct ich9_spi_regs, faddr);
+ ctlr->data = offsetof(struct ich9_spi_regs, fdata);
ctlr->databytes = sizeof(ich9_spi->fdata);
- ctlr->status = &ich9_spi->ssfs;
- ctlr->control = (uint16_t *)ich9_spi->ssfc;
- ctlr->speed = ich9_spi->ssfc + 2;
- ctlr->bbar = &ich9_spi->bbar;
- ctlr->preop = &ich9_spi->preop;
+ ctlr->status = offsetof(struct ich9_spi_regs, ssfs);
+ ctlr->control = offsetof(struct ich9_spi_regs, ssfc);
+ ctlr->speed = ctlr->control + 2;
+ ctlr->bbar = offsetof(struct ich9_spi_regs, bbar);
+ ctlr->preop = offsetof(struct ich9_spi_regs, preop);
ctlr->pr = &ich9_spi->pr[0];
ctlr->base = ich9_spi;
} else {
- debug("ICH SPI: Unrecognized ICH version %d.\n",
- ctlr->ich_version);
- return -1;
+ debug("ICH SPI: Unrecognised ICH version %d\n",
+ plat->ich_version);
+ return -EINVAL;
}
/* Work out the maximum speed we can support */
ctlr->max_speed = 20000000;
- if (ctlr->ich_version == 9 && ich9_can_do_33mhz(ctlr->dev))
+ if (plat->ich_version == 9 && ich9_can_do_33mhz(plat->dev))
ctlr->max_speed = 33000000;
debug("ICH SPI: Version %d detected at %p, speed %ld\n",
- ctlr->ich_version, ctlr->base, ctlr->max_speed);
+ plat->ich_version, ctlr->base, ctlr->max_speed);
ich_set_bbar(ctlr, 0);
return 0;
}
-void spi_init(void)
-{
- uint8_t bios_cntl;
-
- if (ich_find_spi_controller(&ctlr)) {
- printf("ICH SPI: Cannot find device\n");
- return;
- }
-
- if (ich_init_controller(&ctlr)) {
- printf("ICH SPI: Cannot setup controller\n");
- return;
- }
-
- /*
- * Disable the BIOS write protect so write commands are allowed. On
- * v9, deassert SMM BIOS Write Protect Disable.
- */
- if (ctlr.use_sbase) {
- struct ich9_spi_regs *ich9_spi;
-
- ich9_spi = (struct ich9_spi_regs *)ctlr.base;
- bios_cntl = ich_readb(&ich9_spi->bcr);
- bios_cntl &= ~(1 << 5); /* clear Enable InSMM_STS (EISS) */
- bios_cntl |= 1; /* Write Protect Disable (WPD) */
- ich_writeb(bios_cntl, &ich9_spi->bcr);
- } else {
- pci_read_config_byte(ctlr.dev, 0xdc, &bios_cntl);
- if (ctlr.ich_version == 9)
- bios_cntl &= ~(1 << 5);
- pci_write_config_byte(ctlr.dev, 0xdc, bios_cntl | 0x1);
- }
-}
-
-int spi_claim_bus(struct spi_slave *slave)
-{
- /* Handled by ICH automatically. */
- return 0;
-}
-
-void spi_release_bus(struct spi_slave *slave)
-{
- /* Handled by ICH automatically. */
-}
-
-void spi_cs_activate(struct spi_slave *slave)
-{
- /* Handled by ICH automatically. */
-}
-
-void spi_cs_deactivate(struct spi_slave *slave)
-{
- /* Handled by ICH automatically. */
-}
-
static inline void spi_use_out(struct spi_trans *trans, unsigned bytes)
{
trans->out += bytes;
@@ -411,19 +304,19 @@ static void spi_setup_type(struct spi_trans *trans, int data_bytes)
}
}
-static int spi_setup_opcode(struct spi_trans *trans)
+static int spi_setup_opcode(struct ich_spi_priv *ctlr, struct spi_trans *trans)
{
uint16_t optypes;
- uint8_t opmenu[ctlr.menubytes];
+ uint8_t opmenu[ctlr->menubytes];
trans->opcode = trans->out[0];
spi_use_out(trans, 1);
- if (!ctlr.ichspi_lock) {
+ if (!ctlr->ichspi_lock) {
/* The lock is off, so just use index 0. */
- ich_writeb(trans->opcode, ctlr.opmenu);
- optypes = ich_readw(ctlr.optype);
+ ich_writeb(ctlr, trans->opcode, ctlr->opmenu);
+ optypes = ich_readw(ctlr, ctlr->optype);
optypes = (optypes & 0xfffc) | (trans->type & 0x3);
- ich_writew(optypes, ctlr.optype);
+ ich_writew(ctlr, optypes, ctlr->optype);
return 0;
} else {
/* The lock is on. See if what we need is on the menu. */
@@ -434,20 +327,20 @@ static int spi_setup_opcode(struct spi_trans *trans)
if (trans->opcode == SPI_OPCODE_WREN)
return 0;
- read_reg(ctlr.opmenu, opmenu, sizeof(opmenu));
- for (opcode_index = 0; opcode_index < ctlr.menubytes;
+ read_reg(ctlr, ctlr->opmenu, opmenu, sizeof(opmenu));
+ for (opcode_index = 0; opcode_index < ctlr->menubytes;
opcode_index++) {
if (opmenu[opcode_index] == trans->opcode)
break;
}
- if (opcode_index == ctlr.menubytes) {
+ if (opcode_index == ctlr->menubytes) {
printf("ICH SPI: Opcode %x not found\n",
trans->opcode);
- return -1;
+ return -EINVAL;
}
- optypes = ich_readw(ctlr.optype);
+ optypes = ich_readw(ctlr, ctlr->optype);
optype = (optypes >> (opcode_index * 2)) & 0x3;
if (trans->type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS &&
optype == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS &&
@@ -458,7 +351,7 @@ static int spi_setup_opcode(struct spi_trans *trans)
if (optype != trans->type) {
printf("ICH SPI: Transaction doesn't fit type %d\n",
optype);
- return -1;
+ return -ENOSPC;
}
return opcode_index;
}
@@ -480,7 +373,7 @@ static int spi_setup_offset(struct spi_trans *trans)
return 1;
default:
printf("Unrecognized SPI transaction type %#x\n", trans->type);
- return -1;
+ return -EPROTO;
}
}
@@ -491,16 +384,19 @@ static int spi_setup_offset(struct spi_trans *trans)
*
* Return the last read status value on success or -1 on failure.
*/
-static int ich_status_poll(u16 bitmask, int wait_til_set)
+static int ich_status_poll(struct ich_spi_priv *ctlr, u16 bitmask,
+ int wait_til_set)
{
int timeout = 600000; /* This will result in 6s */
u16 status = 0;
while (timeout--) {
- status = ich_readw(ctlr.status);
+ status = ich_readw(ctlr, ctlr->status);
if (wait_til_set ^ ((status & bitmask) == 0)) {
- if (wait_til_set)
- ich_writew((status & bitmask), ctlr.status);
+ if (wait_til_set) {
+ ich_writew(ctlr, status & bitmask,
+ ctlr->status);
+ }
return status;
}
udelay(10);
@@ -508,30 +404,28 @@ static int ich_status_poll(u16 bitmask, int wait_til_set)
printf("ICH SPI: SCIP timeout, read %x, expected %x\n",
status, bitmask);
- return -1;
+ return -ETIMEDOUT;
}
-/*
-int spi_xfer(struct spi_slave *slave, const void *dout,
- unsigned int bitsout, void *din, unsigned int bitsin)
-*/
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
- void *din, unsigned long flags)
+static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
{
- struct ich_spi_slave *ich = to_ich_spi(slave);
+ struct udevice *bus = dev_get_parent(dev);
+ struct ich_spi_priv *ctlr = dev_get_priv(bus);
uint16_t control;
int16_t opcode_index;
int with_address;
int status;
int bytes = bitlen / 8;
- struct spi_trans *trans = &ich->trans;
+ struct spi_trans *trans = &ctlr->trans;
unsigned type = flags & (SPI_XFER_BEGIN | SPI_XFER_END);
int using_cmd = 0;
+ int ret;
/* Ee don't support writing partial bytes. */
if (bitlen % 8) {
debug("ICH SPI: Accessing partial bytes not supported\n");
- return -1;
+ return -EPROTONOSUPPORT;
}
/* An empty end transaction can be ignored */
@@ -545,7 +439,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
if (dout && type == SPI_XFER_BEGIN) {
if (bytes > ICH_MAX_CMD_LEN) {
debug("ICH SPI: Command length limit exceeded\n");
- return -1;
+ return -ENOSPC;
}
memcpy(trans->cmd, dout, bytes);
trans->cmd_len = bytes;
@@ -576,21 +470,22 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
/* There has to always at least be an opcode. */
if (!trans->bytesout) {
debug("ICH SPI: No opcode for transfer\n");
- return -1;
+ return -EPROTO;
}
- if (ich_status_poll(SPIS_SCIP, 0) == -1)
- return -1;
+ ret = ich_status_poll(ctlr, SPIS_SCIP, 0);
+ if (ret < 0)
+ return ret;
- ich_writew(SPIS_CDS | SPIS_FCERR, ctlr.status);
+ ich_writew(ctlr, SPIS_CDS | SPIS_FCERR, ctlr->status);
spi_setup_type(trans, using_cmd ? bytes : 0);
- opcode_index = spi_setup_opcode(trans);
+ opcode_index = spi_setup_opcode(ctlr, trans);
if (opcode_index < 0)
- return -1;
+ return -EINVAL;
with_address = spi_setup_offset(trans);
if (with_address < 0)
- return -1;
+ return -EINVAL;
if (trans->opcode == SPI_OPCODE_WREN) {
/*
@@ -598,20 +493,20 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
* in order to prevent the Management Engine from
* issuing a transaction between WREN and DATA.
*/
- if (!ctlr.ichspi_lock)
- ich_writew(trans->opcode, ctlr.preop);
+ if (!ctlr->ichspi_lock)
+ ich_writew(ctlr, trans->opcode, ctlr->preop);
return 0;
}
- if (ctlr.speed && ctlr.max_speed >= 33000000) {
+ if (ctlr->speed && ctlr->max_speed >= 33000000) {
int byte;
- byte = ich_readb(ctlr.speed);
- if (ich->speed >= 33000000)
+ byte = ich_readb(ctlr, ctlr->speed);
+ if (ctlr->cur_speed >= 33000000)
byte |= SSFC_SCF_33MHZ;
else
byte &= ~SSFC_SCF_33MHZ;
- ich_writeb(byte, ctlr.speed);
+ ich_writeb(ctlr, byte, ctlr->speed);
}
/* See if we have used up the command data */
@@ -622,35 +517,36 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
}
/* Preset control fields */
- control = ich_readw(ctlr.control);
+ control = ich_readw(ctlr, ctlr->control);
control &= ~SSFC_RESERVED;
control = SPIC_SCGO | ((opcode_index & 0x07) << 4);
/* Issue atomic preop cycle if needed */
- if (ich_readw(ctlr.preop))
+ if (ich_readw(ctlr, ctlr->preop))
control |= SPIC_ACS;
if (!trans->bytesout && !trans->bytesin) {
/* SPI addresses are 24 bit only */
- if (with_address)
- ich_writel(trans->offset & 0x00FFFFFF, ctlr.addr);
-
+ if (with_address) {
+ ich_writel(ctlr, trans->offset & 0x00FFFFFF,
+ ctlr->addr);
+ }
/*
* This is a 'no data' command (like Write Enable), its
* bitesout size was 1, decremented to zero while executing
* spi_setup_opcode() above. Tell the chip to send the
* command.
*/
- ich_writew(control, ctlr.control);
+ ich_writew(ctlr, control, ctlr->control);
/* wait for the result */
- status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1);
- if (status == -1)
- return -1;
+ status = ich_status_poll(ctlr, SPIS_CDS | SPIS_FCERR, 1);
+ if (status < 0)
+ return status;
if (status & SPIS_FCERR) {
debug("ICH SPI: Command transaction error\n");
- return -1;
+ return -EIO;
}
return 0;
@@ -663,9 +559,9 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
* and followed by other SPI commands, and this sequence is controlled
* by the SPI chip driver.
*/
- if (trans->bytesout > ctlr.databytes) {
+ if (trans->bytesout > ctlr->databytes) {
debug("ICH SPI: Too much to write. This should be prevented by the driver's max_write_size?\n");
- return -1;
+ return -EPROTO;
}
/*
@@ -676,41 +572,41 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
uint32_t data_length;
/* SPI addresses are 24 bit only */
- ich_writel(trans->offset & 0x00FFFFFF, ctlr.addr);
+ ich_writel(ctlr, trans->offset & 0x00FFFFFF, ctlr->addr);
if (trans->bytesout)
- data_length = min(trans->bytesout, ctlr.databytes);
+ data_length = min(trans->bytesout, ctlr->databytes);
else
- data_length = min(trans->bytesin, ctlr.databytes);
+ data_length = min(trans->bytesin, ctlr->databytes);
/* Program data into FDATA0 to N */
if (trans->bytesout) {
- write_reg(trans->out, ctlr.data, data_length);
+ write_reg(ctlr, trans->out, ctlr->data, data_length);
spi_use_out(trans, data_length);
if (with_address)
trans->offset += data_length;
}
/* Add proper control fields' values */
- control &= ~((ctlr.databytes - 1) << 8);
+ control &= ~((ctlr->databytes - 1) << 8);
control |= SPIC_DS;
control |= (data_length - 1) << 8;
/* write it */
- ich_writew(control, ctlr.control);
+ ich_writew(ctlr, control, ctlr->control);
/* Wait for Cycle Done Status or Flash Cycle Error. */
- status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1);
- if (status == -1)
- return -1;
+ status = ich_status_poll(ctlr, SPIS_CDS | SPIS_FCERR, 1);
+ if (status < 0)
+ return status;
if (status & SPIS_FCERR) {
debug("ICH SPI: Data transaction error\n");
- return -1;
+ return -EIO;
}
if (trans->bytesin) {
- read_reg(ctlr.data, trans->in, data_length);
+ read_reg(ctlr, ctlr->data, trans->in, data_length);
spi_use_in(trans, data_length);
if (with_address)
trans->offset += data_length;
@@ -718,7 +614,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
}
/* Clear atomic preop now that xfer is done */
- ich_writew(0, ctlr.preop);
+ ich_writew(ctlr, 0, ctlr->preop);
return 0;
}
@@ -730,15 +626,18 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
* don't actually take effect until the HSFS[FLOCKDN] bit is set, but that's
* done elsewhere.
*/
-int spi_write_protect_region(uint32_t lower_limit, uint32_t length, int hint)
+int spi_write_protect_region(struct udevice *dev, uint32_t lower_limit,
+ uint32_t length, int hint)
{
+ struct udevice *bus = dev->parent;
+ struct ich_spi_priv *ctlr = dev_get_priv(bus);
uint32_t tmplong;
uint32_t upper_limit;
- if (!ctlr.pr) {
+ if (!ctlr->pr) {
printf("%s: operation not supported on this chipset\n",
__func__);
- return -1;
+ return -ENOSYS;
}
if (length == 0 ||
@@ -746,7 +645,7 @@ int spi_write_protect_region(uint32_t lower_limit, uint32_t length, int hint)
hint < 0 || hint > 4) {
printf("%s(0x%x, 0x%x, %d): invalid args\n", __func__,
lower_limit, length, hint);
- return -1;
+ return -EPERM;
}
upper_limit = lower_limit + length - 1;
@@ -765,8 +664,121 @@ int spi_write_protect_region(uint32_t lower_limit, uint32_t length, int hint)
((lower_limit & 0x01fff000) >> 12);
printf("%s: writing 0x%08x to %p\n", __func__, tmplong,
- &ctlr.pr[hint]);
- ctlr.pr[hint] = tmplong;
+ &ctlr->pr[hint]);
+ ctlr->pr[hint] = tmplong;
+
+ return 0;
+}
+
+static int ich_spi_probe(struct udevice *bus)
+{
+ struct ich_spi_platdata *plat = dev_get_platdata(bus);
+ struct ich_spi_priv *priv = dev_get_priv(bus);
+ uint8_t bios_cntl;
+ int ret;
+
+ ret = ich_init_controller(plat, priv);
+ if (ret)
+ return ret;
+ /*
+ * Disable the BIOS write protect so write commands are allowed. On
+ * v9, deassert SMM BIOS Write Protect Disable.
+ */
+ if (plat->use_sbase) {
+ struct ich9_spi_regs *ich9_spi;
+
+ ich9_spi = priv->base;
+ bios_cntl = ich_readb(priv, ich9_spi->bcr);
+ bios_cntl &= ~(1 << 5); /* clear Enable InSMM_STS (EISS) */
+ bios_cntl |= 1; /* Write Protect Disable (WPD) */
+ ich_writeb(priv, bios_cntl, ich9_spi->bcr);
+ } else {
+ pci_read_config_byte(plat->dev, 0xdc, &bios_cntl);
+ if (plat->ich_version == 9)
+ bios_cntl &= ~(1 << 5);
+ pci_write_config_byte(plat->dev, 0xdc, bios_cntl | 0x1);
+ }
+
+ priv->cur_speed = priv->max_speed;
+
+ return 0;
+}
+
+static int ich_spi_ofdata_to_platdata(struct udevice *bus)
+{
+ struct ich_spi_platdata *plat = dev_get_platdata(bus);
+ int ret;
+
+ ret = ich_find_spi_controller(plat);
+ if (ret)
+ return ret;
return 0;
}
+
+static int ich_spi_set_speed(struct udevice *bus, uint speed)
+{
+ struct ich_spi_priv *priv = dev_get_priv(bus);
+
+ priv->cur_speed = speed;
+
+ return 0;
+}
+
+static int ich_spi_set_mode(struct udevice *bus, uint mode)
+{
+ debug("%s: mode=%d\n", __func__, mode);
+
+ return 0;
+}
+
+static int ich_spi_child_pre_probe(struct udevice *dev)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct ich_spi_platdata *plat = dev_get_platdata(bus);
+ struct ich_spi_priv *priv = dev_get_priv(bus);
+ struct spi_slave *slave = dev_get_parentdata(dev);
+
+ /*
+ * Yes this controller can only write a small number of bytes at
+ * once! The limit is typically 64 bytes.
+ */
+ slave->max_write_size = priv->databytes;
+ /*
+ * ICH 7 SPI controller only supports array read command
+ * and byte program command for SST flash
+ */
+ if (plat->ich_version == 7) {
+ slave->op_mode_rx = SPI_OPM_RX_AS;
+ slave->op_mode_tx = SPI_OPM_TX_BP;
+ }
+
+ return 0;
+}
+
+static const struct dm_spi_ops ich_spi_ops = {
+ .xfer = ich_spi_xfer,
+ .set_speed = ich_spi_set_speed,
+ .set_mode = ich_spi_set_mode,
+ /*
+ * cs_info is not needed, since we require all chip selects to be
+ * in the device tree explicitly
+ */
+};
+
+static const struct udevice_id ich_spi_ids[] = {
+ { .compatible = "intel,ich-spi" },
+ { }
+};
+
+U_BOOT_DRIVER(ich_spi) = {
+ .name = "ich_spi",
+ .id = UCLASS_SPI,
+ .of_match = ich_spi_ids,
+ .ops = &ich_spi_ops,
+ .ofdata_to_platdata = ich_spi_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct ich_spi_platdata),
+ .priv_auto_alloc_size = sizeof(struct ich_spi_priv),
+ .child_pre_probe = ich_spi_child_pre_probe,
+ .probe = ich_spi_probe,
+};
diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c
index 651e46e..85f9e85 100644
--- a/drivers/spi/omap3_spi.c
+++ b/drivers/spi/omap3_spi.c
@@ -20,7 +20,7 @@
#include <asm/io.h>
#include "omap3_spi.h"
-#define SPI_WAIT_TIMEOUT 3000000
+#define SPI_WAIT_TIMEOUT 10
static void spi_reset(struct omap3_spi_slave *ds)
{
@@ -227,7 +227,7 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp,
{
struct omap3_spi_slave *ds = to_omap3_spi(slave);
int i;
- int timeout = SPI_WAIT_TIMEOUT;
+ ulong start;
int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
/* Enable the channel */
@@ -241,9 +241,10 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp,
for (i = 0; i < len; i++) {
/* wait till TX register is empty (TXS == 1) */
+ start = get_timer(0);
while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
OMAP3_MCSPI_CHSTAT_TXS)) {
- if (--timeout <= 0) {
+ if (get_timer(start) > SPI_WAIT_TIMEOUT) {
printf("SPI TXS timed out, status=0x%08x\n",
readl(&ds->regs->channel[ds->slave.cs].chstat));
return -1;
@@ -280,7 +281,7 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp,
{
struct omap3_spi_slave *ds = to_omap3_spi(slave);
int i;
- int timeout = SPI_WAIT_TIMEOUT;
+ ulong start;
int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
/* Enable the channel */
@@ -295,10 +296,11 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp,
writel(0, &ds->regs->channel[ds->slave.cs].tx);
for (i = 0; i < len; i++) {
+ start = get_timer(0);
/* Wait till RX register contains data (RXS == 1) */
while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
OMAP3_MCSPI_CHSTAT_RXS)) {
- if (--timeout <= 0) {
+ if (get_timer(start) > SPI_WAIT_TIMEOUT) {
printf("SPI RXS timed out, status=0x%08x\n",
readl(&ds->regs->channel[ds->slave.cs].chstat));
return -1;
@@ -332,7 +334,7 @@ int omap3_spi_txrx(struct spi_slave *slave, unsigned int len,
const void *txp, void *rxp, unsigned long flags)
{
struct omap3_spi_slave *ds = to_omap3_spi(slave);
- int timeout = SPI_WAIT_TIMEOUT;
+ ulong start;
int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
int irqstatus = readl(&ds->regs->irqstatus);
int i=0;
@@ -350,9 +352,10 @@ int omap3_spi_txrx(struct spi_slave *slave, unsigned int len,
for (i=0; i < len; i++){
/* Write: wait for TX empty (TXS == 1)*/
irqstatus |= (1<< (4*(ds->slave.bus)));
+ start = get_timer(0);
while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
OMAP3_MCSPI_CHSTAT_TXS)) {
- if (--timeout <= 0) {
+ if (get_timer(start) > SPI_WAIT_TIMEOUT) {
printf("SPI TXS timed out, status=0x%08x\n",
readl(&ds->regs->channel[ds->slave.cs].chstat));
return -1;
@@ -368,9 +371,10 @@ int omap3_spi_txrx(struct spi_slave *slave, unsigned int len,
writel(((u8 *)txp)[i], tx);
/*Read: wait for RX containing data (RXS == 1)*/
+ start = get_timer(0);
while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
OMAP3_MCSPI_CHSTAT_RXS)) {
- if (--timeout <= 0) {
+ if (get_timer(start) > SPI_WAIT_TIMEOUT) {
printf("SPI RXS timed out, status=0x%08x\n",
readl(&ds->regs->channel[ds->slave.cs].chstat));
return -1;
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 63a6217..83fe8e0 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -50,7 +50,7 @@ int spi_claim_bus(struct spi_slave *slave)
struct udevice *dev = slave->dev;
struct udevice *bus = dev->parent;
struct dm_spi_ops *ops = spi_get_ops(bus);
- struct dm_spi_bus *spi = bus->uclass_priv;
+ struct dm_spi_bus *spi = dev_get_uclass_priv(bus);
int speed;
int ret;
@@ -67,7 +67,7 @@ int spi_claim_bus(struct spi_slave *slave)
if (ret)
return ret;
- return ops->claim_bus ? ops->claim_bus(bus) : 0;
+ return ops->claim_bus ? ops->claim_bus(dev) : 0;
}
void spi_release_bus(struct spi_slave *slave)
@@ -77,7 +77,7 @@ void spi_release_bus(struct spi_slave *slave)
struct dm_spi_ops *ops = spi_get_ops(bus);
if (ops->release_bus)
- ops->release_bus(bus);
+ ops->release_bus(dev);
}
int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
@@ -110,7 +110,7 @@ int spi_child_post_bind(struct udevice *dev)
int spi_post_probe(struct udevice *bus)
{
- struct dm_spi_bus *spi = bus->uclass_priv;
+ struct dm_spi_bus *spi = dev_get_uclass_priv(bus);
spi->max_hz = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
"spi-max-frequency", 0);
diff --git a/drivers/spi/tegra114_spi.c b/drivers/spi/tegra114_spi.c
index 53ff9ea..4bec663 100644
--- a/drivers/spi/tegra114_spi.c
+++ b/drivers/spi/tegra114_spi.c
@@ -153,8 +153,9 @@ static int tegra114_spi_probe(struct udevice *bus)
return 0;
}
-static int tegra114_spi_claim_bus(struct udevice *bus)
+static int tegra114_spi_claim_bus(struct udevice *dev)
{
+ struct udevice *bus = dev->parent;
struct tegra114_spi_priv *priv = dev_get_priv(bus);
struct spi_regs *regs = priv->regs;
diff --git a/drivers/spi/tegra20_sflash.c b/drivers/spi/tegra20_sflash.c
index 78c74cd..82c1b84 100644
--- a/drivers/spi/tegra20_sflash.c
+++ b/drivers/spi/tegra20_sflash.c
@@ -125,8 +125,9 @@ static int tegra20_sflash_probe(struct udevice *bus)
return 0;
}
-static int tegra20_sflash_claim_bus(struct udevice *bus)
+static int tegra20_sflash_claim_bus(struct udevice *dev)
{
+ struct udevice *bus = dev->parent;
struct tegra20_sflash_priv *priv = dev_get_priv(bus);
struct spi_regs *regs = priv->regs;
u32 reg;
diff --git a/drivers/spi/tegra20_slink.c b/drivers/spi/tegra20_slink.c
index 597d6ad..f6fb89b 100644
--- a/drivers/spi/tegra20_slink.c
+++ b/drivers/spi/tegra20_slink.c
@@ -141,8 +141,9 @@ static int tegra30_spi_probe(struct udevice *bus)
return 0;
}
-static int tegra30_spi_claim_bus(struct udevice *bus)
+static int tegra30_spi_claim_bus(struct udevice *dev)
{
+ struct udevice *bus = dev->parent;
struct tegra30_spi_priv *priv = dev_get_priv(bus);
struct spi_regs *regs = priv->regs;
u32 reg;
diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c
index 5da8759..e9129da 100644
--- a/drivers/spi/zynq_spi.c
+++ b/drivers/spi/zynq_spi.c
@@ -227,9 +227,6 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
debug("spi_xfer: bus:%i cs:%i bitlen:%i len:%i flags:%lx\n",
slave->bus, slave->cs, bitlen, len, flags);
- if (bitlen == 0)
- return -1;
-
if (bitlen % 8) {
debug("spi_xfer: Non byte aligned SPI transfer\n");
return -1;