The Broadcom MSPI controller is used on various chips. The driver only supported BCM53xx chips with BCMA (an AMBA bus variant). It now supports both BCMA MSPI and non-BCMA MSPI. To do this the following changes were made: - A new config for non-BCMA chips has been added. - Common code between the BCMA and non BCMA version are shared. - Function pointers to set read/write functions to abstract bcma and non-bcma versions are provided. - DT is now mandatory. Hard coded SPI devices are removed and must be set in DT. - Remove function was unnecessary and removed. Signed-off-by: Jonathan Richardson <jonathar@xxxxxxxxxxxx> --- drivers/spi/Kconfig | 5 + drivers/spi/Makefile | 1 + drivers/spi/spi-bcm-mspi.c | 228 ++++++++++++++++++++++++++++++++------------ 3 files changed, 171 insertions(+), 63 deletions(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 766e08d..23f2357 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -120,6 +120,11 @@ config SPI_BCMA_MSPI help Enable support for the Broadcom BCMA MSPI controller. +config SPI_BCM_MSPI + tristate "Broadcom MSPI controller" + help + Enable support for the Broadcom MSPI controller. + config SPI_BCM63XX tristate "Broadcom BCM63xx SPI controller" depends on BCM63XX diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 6b58100..36872d2 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_SPI_ATH79) += spi-ath79.o obj-$(CONFIG_SPI_AU1550) += spi-au1550.o obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o obj-$(CONFIG_SPI_BCMA_MSPI) += spi-bcm-mspi.o +obj-$(CONFIG_SPI_BCM_MSPI) += spi-bcm-mspi.o obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o diff --git a/drivers/spi/spi-bcm-mspi.c b/drivers/spi/spi-bcm-mspi.c index 502227d..32bb1f0 100644 --- a/drivers/spi/spi-bcm-mspi.c +++ b/drivers/spi/spi-bcm-mspi.c @@ -11,11 +11,13 @@ * GNU General Public License for more details. */ #include <linux/kernel.h> +#include <linux/platform_device.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/delay.h> #include <linux/bcma/bcma.h> #include <linux/spi/spi.h> +#include <linux/of.h> #include "spi-bcm-mspi.h" @@ -25,22 +27,17 @@ #define BCM_MSPI_SPE_TIMEOUT_MS 80 struct bcm_mspi { +#ifdef CONFIG_SPI_BCMA_MSPI struct bcma_device *core; - struct spi_master *master; +#endif + void __iomem *base; + struct spi_master *master; size_t read_offset; -}; - -static inline u32 bcm_mspi_read(struct bcm_mspi *mspi, u16 offset) -{ - return bcma_read32(mspi->core, offset); -} -static inline void bcm_mspi_write(struct bcm_mspi *mspi, u16 offset, - u32 value) -{ - bcma_write32(mspi->core, offset, value); -} + void (*mspi_write)(struct bcm_mspi *mspi, u16 offset, u32 value); + u32 (*mspi_read)(struct bcm_mspi *mspi, u16 offset); +}; static inline unsigned int bcm_mspi_calc_timeout(size_t len) { @@ -56,7 +53,7 @@ static int bcm_mspi_wait(struct bcm_mspi *mspi, unsigned int timeout_ms) /* SPE bit has to be 0 before we read MSPI STATUS */ deadline = jiffies + BCM_MSPI_SPE_TIMEOUT_MS * HZ / 1000; do { - tmp = bcm_mspi_read(mspi, MSPI_SPCR2); + tmp = mspi->mspi_read(mspi, MSPI_SPCR2); if (!(tmp & MSPI_SPCR2_SPE)) break; udelay(5); @@ -68,9 +65,9 @@ static int bcm_mspi_wait(struct bcm_mspi *mspi, unsigned int timeout_ms) /* Check status */ deadline = jiffies + timeout_ms * HZ / 1000; do { - tmp = bcm_mspi_read(mspi, MSPI_STATUS); + tmp = mspi->mspi_read(mspi, MSPI_STATUS); if (tmp & MSPI_STATUS_SPIF) { - bcm_mspi_write(mspi, MSPI_STATUS, 0); + mspi->mspi_write(mspi, MSPI_STATUS, 0); return 0; } @@ -79,7 +76,7 @@ static int bcm_mspi_wait(struct bcm_mspi *mspi, unsigned int timeout_ms) } while (!time_after_eq(jiffies, deadline)); spi_timeout: - bcm_mspi_write(mspi, MSPI_STATUS, 0); + mspi->mspi_write(mspi, MSPI_STATUS, 0); pr_err("Timeout waiting for SPI to be ready!\n"); @@ -94,7 +91,7 @@ static void bcm_mspi_buf_write(struct bcm_mspi *mspi, u8 *w_buf, for (i = 0; i < len; i++) { /* Transmit Register File MSB */ - bcm_mspi_write(mspi, MSPI_TXRAM + 4 * (i * 2), + mspi->mspi_write(mspi, MSPI_TXRAM + 4 * (i * 2), (unsigned int)w_buf[i]); } @@ -105,28 +102,28 @@ static void bcm_mspi_buf_write(struct bcm_mspi *mspi, u8 *w_buf, tmp &= ~MSPI_CDRAM_CONT; tmp &= ~0x1; /* Command Register File */ - bcm_mspi_write(mspi, MSPI_CDRAM + 4 * i, tmp); + mspi->mspi_write(mspi, MSPI_CDRAM + 4 * i, tmp); } /* Set queue pointers */ - bcm_mspi_write(mspi, MSPI_NEWQP, 0); - bcm_mspi_write(mspi, MSPI_ENDQP, len - 1); + mspi->mspi_write(mspi, MSPI_NEWQP, 0); + mspi->mspi_write(mspi, MSPI_ENDQP, len - 1); if (cont) - bcm_mspi_write(mspi, MSPI_WRITE_LOCK, 1); + mspi->mspi_write(mspi, MSPI_WRITE_LOCK, 1); /* Start SPI transfer */ - tmp = bcm_mspi_read(mspi, MSPI_SPCR2); + tmp = mspi->mspi_read(mspi, MSPI_SPCR2); tmp |= MSPI_SPCR2_SPE; if (cont) tmp |= MSPI_SPCR2_CONT_AFTER_CMD; - bcm_mspi_write(mspi, MSPI_SPCR2, tmp); + mspi->mspi_write(mspi, MSPI_SPCR2, tmp); /* Wait for SPI to finish */ bcm_mspi_wait(mspi, bcm_mspi_calc_timeout(len)); if (!cont) - bcm_mspi_write(mspi, MSPI_WRITE_LOCK, 0); + mspi->mspi_write(mspi, MSPI_WRITE_LOCK, 0); mspi->read_offset = len; } @@ -144,34 +141,35 @@ static void bcm_mspi_buf_read(struct bcm_mspi *mspi, u8 *r_buf, tmp &= ~MSPI_CDRAM_CONT; tmp &= ~0x1; /* Command Register File */ - bcm_mspi_write(mspi, MSPI_CDRAM + 4 * i, tmp); + mspi->mspi_write(mspi, MSPI_CDRAM + 4 * i, tmp); } /* Set queue pointers */ - bcm_mspi_write(mspi, MSPI_NEWQP, 0); - bcm_mspi_write(mspi, MSPI_ENDQP, mspi->read_offset + len - 1); + mspi->mspi_write(mspi, MSPI_NEWQP, 0); + mspi->mspi_write(mspi, MSPI_ENDQP, + mspi->read_offset + len - 1); if (cont) - bcm_mspi_write(mspi, MSPI_WRITE_LOCK, 1); + mspi->mspi_write(mspi, MSPI_WRITE_LOCK, 1); /* Start SPI transfer */ - tmp = bcm_mspi_read(mspi, MSPI_SPCR2); + tmp = mspi->mspi_read(mspi, MSPI_SPCR2); tmp |= MSPI_SPCR2_SPE; if (cont) tmp |= MSPI_SPCR2_CONT_AFTER_CMD; - bcm_mspi_write(mspi, MSPI_SPCR2, tmp); + mspi->mspi_write(mspi, MSPI_SPCR2, tmp); /* Wait for SPI to finish */ bcm_mspi_wait(mspi, bcm_mspi_calc_timeout(len)); if (!cont) - bcm_mspi_write(mspi, MSPI_WRITE_LOCK, 0); + mspi->mspi_write(mspi, MSPI_WRITE_LOCK, 0); for (i = 0; i < len; ++i) { int offset = mspi->read_offset + i; /* Data stored in the transmit register file LSB */ - r_buf[i] = (u8)bcm_mspi_read(mspi, + r_buf[i] = (u8)mspi->mspi_read(mspi, MSPI_RXRAM + 4 * (1 + offset * 2)); } @@ -216,10 +214,104 @@ static int bcm_mspi_transfer_one(struct spi_master *master, return 0; } -static struct spi_board_info bcm_mspi_info = { - .modalias = "bcm53xxspiflash", +/* + * Allocate SPI master for both bcma and non bcma bus. The SPI device must be + * configured in DT. + */ +static struct bcm_mspi *bcm_mspi_init(struct device *dev) +{ + struct bcm_mspi *data; + struct spi_master *master; + + master = spi_alloc_master(dev, sizeof(*data)); + if (!master) { + dev_err(dev, "error allocating spi_master\n"); + return 0; + } + + data = spi_master_get_devdata(master); + data->master = master; + + /* SPI master will always use the SPI device(s) from DT. */ + master->dev.of_node = dev->of_node; + master->transfer_one = bcm_mspi_transfer_one; + + return data; +} + +#ifdef CONFIG_SPI_BCM_MSPI + +static const struct of_device_id bcm_mspi_dt[] = { + { .compatible = "brcm,mspi" }, + { }, +}; +MODULE_DEVICE_TABLE(of, bcm_mspi_dt); + +static inline u32 bcm_mspi_read(struct bcm_mspi *mspi, u16 offset) +{ + return readl(mspi->base + offset); +} + +static inline void bcm_mspi_write(struct bcm_mspi *mspi, u16 offset, + u32 value) +{ + writel(value, mspi->base + offset); +} + +/* + * Probe routine for non-bcma devices. + */ +static int bcm_mspi_probe(struct platform_device *pdev) +{ + struct bcm_mspi *data; + struct device *dev = &pdev->dev; + int err; + struct resource *res; + + dev_info(dev, "BCM MSPI probe\n"); + + data = bcm_mspi_init(dev); + if (!data) + return -ENOMEM; + + /* Map base memory address. */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->base = devm_ioremap_resource(dev, res); + if (IS_ERR(data->base)) { + dev_err(&pdev->dev, "unable to map I/O memory\n"); + err = PTR_ERR(data->base); + goto out; + } + + data->mspi_read = bcm_mspi_read; + data->mspi_write = bcm_mspi_write; + platform_set_drvdata(pdev, data); + + err = devm_spi_register_master(dev, data->master); + if (err) + goto out; + + return 0; + +out: + spi_master_put(data->master); + return err; +} + +static struct platform_driver bcm_mspi_driver = { + .driver = { + .name = "bcm-mspi", + .of_match_table = bcm_mspi_dt, + }, + .probe = bcm_mspi_probe, }; +module_platform_driver(bcm_mspi_driver); + +#endif + +#ifdef CONFIG_SPI_BCMA_MSPI + static const struct bcma_device_id bcm_mspi_bcma_tbl[] = { BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_QSPI, BCMA_ANY_REV, BCMA_ANY_CLASS), @@ -227,62 +319,70 @@ static const struct bcma_device_id bcm_mspi_bcma_tbl[] = { }; MODULE_DEVICE_TABLE(bcma, bcm_mspi_bcma_tbl); +static const struct of_device_id bcm_bcma_mspi_dt[] = { + { .compatible = "brcm,bcma-mspi" }, + { }, +}; +MODULE_DEVICE_TABLE(of, bcm_mspi_dt); + +static inline u32 bcm_bcma_mspi_read(struct bcm_mspi *mspi, u16 offset) +{ + return bcma_read32(mspi->core, offset); +} + +static inline void bcm_bcma_mspi_write(struct bcm_mspi *mspi, u16 offset, + u32 value) +{ + bcma_write32(mspi->core, offset, value); +} + +/* + * Probe routine for bcma devices. + */ static int bcm_mspi_bcma_probe(struct bcma_device *core) { struct bcm_mspi *data; - struct spi_master *master; int err; dev_info(&core->dev, "BCM MSPI BCMA probe\n"); if (core->bus->drv_cc.core->id.rev != 42) { - pr_err("SPI on SoC with unsupported ChipCommon rev\n"); + dev_err(&core->dev, + "SPI on SoC with unsupported ChipCommon rev\n"); return -ENOTSUPP; } - master = spi_alloc_master(&core->dev, sizeof(*data)); - if (!master) + data = bcm_mspi_init(&core->dev); + if (!data) return -ENOMEM; - data = spi_master_get_devdata(master); - data->master = master; + data->mspi_read = bcm_bcma_mspi_read; + data->mspi_write = bcm_bcma_mspi_write; data->core = core; - master->transfer_one = bcm_mspi_transfer_one; - bcma_set_drvdata(core, data); err = devm_spi_register_master(&core->dev, data->master); if (err) { - spi_master_put(master); - bcma_set_drvdata(core, NULL); - goto out; + spi_master_put(data->master); + return err; } - /* Broadcom SoCs (at least with the CC rev 42) use SPI for flash only */ - spi_new_device(master, &bcm_mspi_info); - -out: - return err; -} - -static void bcm_mspi_bcma_remove(struct bcma_device *core) -{ - struct bcm_mspi *mspi = bcma_get_drvdata(core); - - spi_unregister_master(mspi->master); + return 0; } static struct bcma_driver bcm_mspi_bcma_driver = { .name = KBUILD_MODNAME, + .drv = { + .of_match_table = bcm_bcma_mspi_dt, + }, .id_table = bcm_mspi_bcma_tbl, .probe = bcm_mspi_bcma_probe, - .remove = bcm_mspi_bcma_remove, }; -static int __init bcm_mspi_module_init(void) +static int __init bcm_mspi_bcma_module_init(void) { - int err = 0; + int err; err = bcma_driver_register(&bcm_mspi_bcma_driver); if (err) @@ -291,13 +391,15 @@ static int __init bcm_mspi_module_init(void) return err; } -static void __exit bcm_mspi_module_exit(void) +static void __exit bcm_mspi_bcma_module_exit(void) { bcma_driver_unregister(&bcm_mspi_bcma_driver); } -module_init(bcm_mspi_module_init); -module_exit(bcm_mspi_module_exit); +module_init(bcm_mspi_bcma_module_init); +module_exit(bcm_mspi_bcma_module_exit); + +#endif MODULE_DESCRIPTION("Broadcom MSPI SPI Controller driver"); MODULE_AUTHOR("Rafał Miłecki <zajec5@xxxxxxxxx>"); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html