[U-Boot] [PATCH RFC 1/3] spi:fsl_spi:Add compatibility for fsl-qspi and fsl-dspi modules driver

Chao Fu b44548 at freescale.com
Tue Jul 1 11:18:05 CEST 2014


From: Chao Fu <B44548 at freescale.com>

Freescale has some series of chips(e.g. vf610) contain two kinds of
SPI modules, DSPI and QSPI. U-boot spi current code can't compile and
enable the two modules at same time. So add fsl-spi-interface make two
spi driver code work together.

Usage:(e.g.)
	SPI bus defination can be find in SOC level:
        SPI_BUS_FSL_QSPI0                               0
        SPI_BUS_FSL_DSPI1                               1
        SPI_BUS_FSL_DSPI2                               2

	SPI devices info can be find in board level:
        AT45DB021 is on spi bus 1 cs 0
        S25FL064  is on spi bus 2 cs 0
        S25FL128S is on spi bus 0 cs 0

Before using any SPI bus and SPI flash, execute sf probe bus:cs in uboot cmdline
Such as use S25FL064, sf probe 2:0.
Then sf read xxxx/ sf write xxxx can be excuted.

Signed-off-by: Chao Fu <B44548 at freescale.com>
---
 drivers/spi/Makefile            |   1 +
 drivers/spi/fsl_qspi.c          |  33 ++---
 drivers/spi/fsl_spi_interface.c | 275 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 286 insertions(+), 23 deletions(-)
 create mode 100644 drivers/spi/fsl_spi_interface.c

diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index b587308..9c5d25c 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -40,4 +40,5 @@ obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o
 obj-$(CONFIG_TI_QSPI) += ti_qspi.o
 obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o
 obj-$(CONFIG_ZYNQ_SPI) += zynq_spi.o
+obj-$(CONFIG_FSL_SPI_INTERFACE) += fsl_spi_interface.o
 obj-$(CONFIG_FSL_QSPI) += fsl_qspi.o
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index ba20bef..328f154 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -51,14 +51,6 @@
 #define qspi_write32		out_be32
 #endif
 
-static unsigned long spi_bases[] = {
-	QSPI0_BASE_ADDR,
-};
-
-static unsigned long amba_bases[] = {
-	QSPI0_AMBA_BASE,
-};
-
 struct fsl_qspi {
 	struct spi_slave slave;
 	unsigned long reg_base;
@@ -67,6 +59,9 @@ struct fsl_qspi {
 	u8 cur_seqid;
 };
 
+unsigned long get_spi_bus_base(unsigned int bus);
+unsigned long get_qspi_amba_base(unsigned int bus);
+
 /* QSPI support swapping the flash read/write data
  * in hardware for LS102xA, but not for VF610 */
 static inline u32 qspi_endian_xchg(u32 data)
@@ -176,12 +171,7 @@ static void qspi_set_lut(struct fsl_qspi *qspi)
 	qspi_write32(&regs->lckcr, QSPI_LCKCR_LOCK);
 }
 
-void spi_init()
-{
-	/* do nothing */
-}
-
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+struct spi_slave *qspi_setup_slave(unsigned int bus, unsigned int cs,
 		unsigned int max_hz, unsigned int mode)
 {
 	struct fsl_qspi *qspi;
@@ -189,15 +179,12 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 	u32 reg_val, smpr_val;
 	u32 total_size, seq_id;
 
-	if (bus >= ARRAY_SIZE(spi_bases))
-		return NULL;
-
 	qspi = spi_alloc_slave(struct fsl_qspi, bus, cs);
 	if (!qspi)
 		return NULL;
 
-	qspi->reg_base = spi_bases[bus];
-	qspi->amba_base = amba_bases[bus];
+	qspi->reg_base = get_spi_bus_base(bus);
+	qspi->amba_base = get_qspi_amba_base(bus);
 
 	qspi->slave.max_write_size = TX_BUFFER_SIZE;
 
@@ -232,14 +219,14 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 	return &qspi->slave;
 }
 
-void spi_free_slave(struct spi_slave *slave)
+void qspi_free_slave(struct spi_slave *slave)
 {
 	struct fsl_qspi *qspi = to_qspi_spi(slave);
 
 	free(qspi);
 }
 
-int spi_claim_bus(struct spi_slave *slave)
+int qspi_claim_bus(struct spi_slave *slave)
 {
 	return 0;
 }
@@ -436,7 +423,7 @@ static void qspi_op_se(struct fsl_qspi *qspi)
 	qspi_write32(&regs->mcr, mcr_reg);
 }
 
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+int qspi_xfer(struct spi_slave *slave, unsigned int bitlen,
 		const void *dout, void *din, unsigned long flags)
 {
 	struct fsl_qspi *qspi = to_qspi_spi(slave);
@@ -476,7 +463,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 	return 0;
 }
 
-void spi_release_bus(struct spi_slave *slave)
+void qspi_release_bus(struct spi_slave *slave)
 {
 	/* Nothing to do */
 }
diff --git a/drivers/spi/fsl_spi_interface.c b/drivers/spi/fsl_spi_interface.c
new file mode 100644
index 0000000..4af6be1
--- /dev/null
+++ b/drivers/spi/fsl_spi_interface.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ *
+ * Freescale Muti Serial Peripheral Interface (QSPI and DSPI) driver support
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <spi.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+
+void dspi_init(void);
+int dspi_claim_bus(struct spi_slave *slave);
+int dspi_release_bus(struct spi_slave *slave);
+int dspi_cs_is_valid(unsigned int bus, unsigned int cs);
+struct spi_slave *dspi_setup_slave(unsigned int bus, unsigned int cs,
+				unsigned int max_hz, unsigned int mode);
+void dspi_free_slave(struct spi_slave *slave);
+void dspi_cs_activate(struct spi_slave *slave);
+void dspi_cs_deactivate(struct spi_slave *slave);
+int dspi_xfer(struct spi_slave *slave, unsigned int bitlen,
+	    const void *data_out, void *data_in, unsigned long flags);
+void qspi_init(void);
+int qspi_claim_bus(struct spi_slave *slave);
+int qspi_release_bus(struct spi_slave *slave);
+int qspi_cs_is_valid(unsigned int bus, unsigned int cs);
+struct spi_slave *qspi_setup_slave(unsigned int bus, unsigned int cs,
+				unsigned int max_hz, unsigned int mode);
+void qspi_free_slave(struct spi_slave *slave);
+void qspi_cs_activate(struct spi_slave *slave);
+void qspi_cs_deactivate(struct spi_slave *slave);
+int qspi_xfer(struct spi_slave *slave, unsigned int bitlen,
+	    const void *data_out, void *data_in, unsigned long flags);
+
+void board_print_spi_device(void);
+int board_spi_find_bus(unsigned int bus, unsigned int cs);
+
+struct fsl_spi_driver {
+	void (*init)(void);
+	int (*claim_bus)(struct spi_slave *slave);
+	int (*release_bus)(struct spi_slave *slave);
+	int (*cs_is_valid)(unsigned int bus, unsigned int cs);
+	struct spi_slave *(*setup_slave)(unsigned int bus, unsigned int cs,
+					unsigned int max_hz, unsigned int mode);
+	void (*free_slave)(struct spi_slave *slave);
+	void (*cs_activate)(struct spi_slave *slave);
+	void (*cs_deactivate)(struct spi_slave *slave);
+	int (*xfer)(struct spi_slave *slave, unsigned int bitlen,
+		    const void *data_out, void *data_in, unsigned long flags);
+};
+
+static struct fsl_spi_driver fsl_spi_drivers[] = {
+#ifdef CONFIG_FSL_DSPI
+	{
+		.init		= dspi_init,
+		.claim_bus	= dspi_claim_bus,
+		.cs_is_valid	= NULL,
+		.setup_slave	= dspi_setup_slave,
+		.free_slave	= dspi_free_slave,
+		.cs_activate	= NULL,
+		.cs_deactivate	= NULL,
+		.xfer		= dspi_xfer,
+	},
+#endif
+#ifdef CONFIG_FSL_QSPI
+	{
+		.init		= NULL,
+		.claim_bus	= qspi_claim_bus,
+		.cs_is_valid	= NULL,
+		.setup_slave	= qspi_setup_slave,
+		.free_slave	= qspi_free_slave,
+		.cs_activate	= NULL,
+		.cs_deactivate	= NULL,
+		.xfer		= qspi_xfer,
+	},
+#endif
+};
+
+enum fsl_spi_driver_sel {
+#ifdef CONFIG_FSL_DSPI
+	DSPI_DRIVER,
+#endif
+#ifdef CONFIG_FSL_QSPI
+	QSPI_DRIVER,
+#endif
+};
+
+struct fsl_spi_driver * find_fsl_spi_driver(unsigned int bus, unsigned int cs)
+{
+	unsigned int driver_sel;
+
+	if(board_spi_find_bus(bus, cs)) {
+		board_print_spi_device();
+		printf("can't find device on bus %d cs %d in board \n",
+								bus, cs);
+		return NULL;
+	}
+
+	switch (bus) {
+#ifdef CONFIG_FSL_DSPI
+#ifdef SPI_BUS_FSL_DSPI1
+		case SPI_BUS_FSL_DSPI1:
+#endif
+#ifdef SPI_BUS_FSL_DSPI2
+		case SPI_BUS_FSL_DSPI2:
+#endif
+#ifdef SPI_BUS_FSL_DSPI3
+		case SPI_BUS_FSL_DSPI3:
+#endif
+#ifdef SPI_BUS_FSL_DSPI4
+		case SPI_BUS_FSL_DSPI4:
+#endif
+			driver_sel = DSPI_DRIVER;
+			break;
+#endif
+#ifdef CONFIG_FSL_QSPI
+#ifdef SPI_BUS_FSL_QSPI0
+		case SPI_BUS_FSL_QSPI0:
+#endif
+#ifdef SPI_BUS_FSL_QSPI1
+		case SPI_BUS_FSL_QSPI1:
+#endif
+			driver_sel = QSPI_DRIVER;
+			break;
+#endif
+		default:
+			return NULL;
+	}
+
+	return &fsl_spi_drivers[driver_sel];
+}
+
+unsigned long get_spi_bus_base(unsigned int bus)
+{
+	switch (bus) {
+#ifdef SPI_BUS_FSL_DSPI1
+		case SPI_BUS_FSL_DSPI1:
+			return DSPI1_BASE_ADDR;
+#endif
+#ifdef SPI_BUS_FSL_DSPI2
+		case SPI_BUS_FSL_DSPI2:
+			return DSPI2_BASE_ADDR;
+#endif
+#ifdef SPI_BUS_FSL_DSPI3
+		case SPI_BUS_FSL_DSPI3:
+			return DSPI3_BASE_ADDR;
+#endif
+#ifdef SPI_BUS_FSL_DSPI4
+		case SPI_BUS_FSL_DSPI4:
+			return DSPI4_BASE_ADDR;
+#endif
+#ifdef SPI_BUS_FSL_QSPI0
+		case SPI_BUS_FSL_QSPI0:
+			return QSPI0_BASE_ADDR;
+#endif
+#ifdef SPI_BUS_FSL_QSPI1
+		case SPI_BUS_FSL_QSPI1:
+			return QSPI1_BASE_ADDR;
+#endif
+		default:
+			printf("FSL SPL:get bus base error %d", bus);
+			return 0;
+	}
+}
+
+unsigned long get_qspi_amba_base(unsigned int bus)
+{
+	switch (bus) {
+#ifdef SPI_BUS_FSL_QSPI0
+		case SPI_BUS_FSL_QSPI0:
+			return QSPI0_AMBA_BASE;
+#endif
+#ifdef SPI_BUS_FSL_QSPI1
+		case SPI_BUS_FSL_QSPI1:
+			return QSPI1_AMBA_BASE;
+#endif
+		default:
+			printf("FSL SPL:get qspi amba bus base error %d", bus);
+			return 0;
+	}
+
+	return 0;
+}
+
+void spi_init()
+{
+	int i;
+	struct fsl_spi_driver *driver;
+
+	for (i = 0; i < ARRAY_SIZE(fsl_spi_drivers); i++) {
+		driver = &fsl_spi_drivers[i];
+		if(driver && driver->init)
+			driver->init();
+	}
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+		unsigned int max_hz, unsigned int mode)
+{
+	struct fsl_spi_driver *driver = find_fsl_spi_driver(bus, cs);
+
+	if (!driver || !driver->setup_slave)
+		return NULL;
+
+	return driver->setup_slave(bus, cs, max_hz, mode);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+	struct fsl_spi_driver *driver = find_fsl_spi_driver(slave->bus,
+								slave->cs);
+
+	if (!driver)
+		return 1;
+	if (!driver->claim_bus)
+		return 0;
+
+	return driver->claim_bus(slave);
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+	struct fsl_spi_driver *driver = find_fsl_spi_driver(slave->bus,
+								slave->cs);
+
+	if (driver && driver->free_slave)
+		return driver->free_slave(slave);
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+		const void *dout, void *din, unsigned long flags)
+{
+	struct fsl_spi_driver *driver = find_fsl_spi_driver(slave->bus,
+								slave->cs);
+
+	if (!driver || !driver->xfer)
+		return -1;
+
+	/*if (dout && flags != SPI_XFER_END)
+		if(board_spi_parse_cmd((u8*)dout, slave->bus))
+			return 0;*/
+
+	return driver->xfer(slave, bitlen, dout, din, flags);
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+	struct fsl_spi_driver *driver = find_fsl_spi_driver(slave->bus,
+								slave->cs);
+
+	if (driver && driver->release_bus)
+		driver->release_bus(slave);
+}
+
+
+void spi_cs_activate(struct spi_slave *slave)
+{
+	struct fsl_spi_driver *driver = find_fsl_spi_driver(slave->bus,
+								slave->cs);
+
+	if (driver && driver->cs_activate)
+		driver->cs_activate(slave);
+}
+
+void spi_cs_deactivate(struct spi_slave *slave)
+{
+	struct fsl_spi_driver *driver = find_fsl_spi_driver(slave->bus,
+								slave->cs);
+
+	if (driver && driver->cs_deactivate)
+		driver->cs_deactivate(slave);
+}
-- 
1.8.4



More information about the U-Boot mailing list