Re: [PATCH v2 4/5] spi: bcm-mspi: Make BCMA optional to support non-BCMA chips

From: Jonas Gorski
Date: Wed Apr 08 2015 - 15:27:57 EST


Hi,

On Wed, Apr 8, 2015 at 8:04 PM, Jonathan Richardson
<jonathar@xxxxxxxxxxxx> wrote:
> 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"

You say "DT is now mandatory", but I don't see you depending on OF.
Does it compile with OF disabled?

> + 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

What happens if SPI_BCMA_MSPI and SPI_BCM_MSPI are both set? What
happens if they disagree, i.e. one is y, the other m?

> 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;

You could make this part a bit more readable by not reordering existing members.

> 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);
> +};

Why not keep these and let them call mspi->mspi_read() resp.
mspi->mspi_write()? It would reduce the amount of changes quite a bit.

>
> 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;

return NULL;

> + }
> +
> + 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

Won't this break when being build as a module? I think you need

#if IS_ENABLED(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");

devm_ioremap_resource will already complain for you.

> + 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

likewise.

> +
> 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);

Why are you removing the registration of the flash device? Won't this
break bcm53xx's flash registration?

> -
> -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;

Unrelated change.

>
> 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>");
> --


Regards
Jonas
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/