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

From: Chao Fu B44548@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@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(®s->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(®s->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); +}

From: Chao Fu B44548@freescale.com
Add DSPI and QSPI bus definition in SOC level. Sf probe command parameter bus will decide which module will work.
Add register base definition.
Signed-off-by: Chao Fu B44548@freescale.com --- arch/arm/include/asm/arch-vf610/imx-regs.h | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/arm/include/asm/arch-vf610/imx-regs.h b/arch/arm/include/asm/arch-vf610/imx-regs.h index bd6f680..3076975 100644 --- a/arch/arm/include/asm/arch-vf610/imx-regs.h +++ b/arch/arm/include/asm/arch-vf610/imx-regs.h @@ -95,6 +95,8 @@ #define FEC_QUIRK_ENET_MAC #define I2C_QUIRK_REG
+#define SPI_BUS_FSL_QSPI0 0 + /* MSCM interrupt rounter */ #define MSCM_IRSPRC_CP0_EN 1 #define MSCM_IRSPRC_NUM 112

From: Chao Fu B44548@freescale.com
Add spi device info for vf610-twr board. Enable fsl-spi-interface for compatibility of fsl-dspi and fsl-qspi.
Signed-off-by: Chao Fu B44548@freescale.com --- board/freescale/vf610twr/vf610twr.c | 24 ++++++++++++++++++++++++ include/configs/vf610twr.h | 2 ++ 2 files changed, 26 insertions(+)
diff --git a/board/freescale/vf610twr/vf610twr.c b/board/freescale/vf610twr/vf610twr.c index 54a9f2c..356fcdc 100644 --- a/board/freescale/vf610twr/vf610twr.c +++ b/board/freescale/vf610twr/vf610twr.c @@ -402,6 +402,30 @@ int board_phy_config(struct phy_device *phydev) return 0; }
+int board_spi_find_bus(unsigned int bus, unsigned int cs) +{ + switch(bus) { + case SPI_BUS_FSL_QSPI0: + break; + default: + return -1; + } + + switch(bus) { + case SPI_BUS_FSL_QSPI0: + if(cs == 0) + return 0; + default: + return -1; + } +} + +void board_print_spi_device(void) +{ + printf("VF610-TWR spi flash info:\n"); + printf("S25FL128S is on spi bus 0 cs 0\n"); +} + int board_early_init_f(void) { clock_init(); diff --git a/include/configs/vf610twr.h b/include/configs/vf610twr.h index 0342550..05e2dcc 100644 --- a/include/configs/vf610twr.h +++ b/include/configs/vf610twr.h @@ -68,6 +68,8 @@ #define CONFIG_PHYLIB #define CONFIG_PHY_MICREL
+#define CONFIG_FSL_SPI_INTERFACE + /* QSPI Configs*/ #define CONFIG_FSL_QSPI

Hi,
On 1 July 2014 03:18, Chao Fu b44548@freescale.com wrote:
From: Chao Fu B44548@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.
We are in the process of enabling driver model for SPI and SPI flash. Work in progress is at u-boot-dm.git branch 'working'.
It probably makes sense to build on that rather than introduce new infrastructure. Please let me know what you think.
Regards, Simon
participants (2)
-
Chao Fu
-
Simon Glass