^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright 2016 Broadcom Limited
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "spi-bcm-qspi.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define INTR_BASE_BIT_SHIFT 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define INTR_COUNT 0x07
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct bcm_iproc_intc {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) struct bcm_qspi_soc_intc soc_intc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct platform_device *pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) void __iomem *int_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) void __iomem *int_status_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) spinlock_t soclock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) bool big_endian;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static u32 bcm_iproc_qspi_get_l2_int_status(struct bcm_qspi_soc_intc *soc_intc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct bcm_iproc_intc *priv =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) container_of(soc_intc, struct bcm_iproc_intc, soc_intc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) void __iomem *mmio = priv->int_status_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) u32 val = 0, sts = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) for (i = 0; i < INTR_COUNT; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (bcm_qspi_readl(priv->big_endian, mmio + (i * 4)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) val |= 1UL << i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (val & INTR_MSPI_DONE_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) sts |= MSPI_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) if (val & BSPI_LR_INTERRUPTS_ALL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) sts |= BSPI_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) if (val & BSPI_LR_INTERRUPTS_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) sts |= BSPI_ERR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) return sts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static void bcm_iproc_qspi_int_ack(struct bcm_qspi_soc_intc *soc_intc, int type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct bcm_iproc_intc *priv =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) container_of(soc_intc, struct bcm_iproc_intc, soc_intc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) void __iomem *mmio = priv->int_status_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) u32 mask = get_qspi_mask(type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) for (i = 0; i < INTR_COUNT; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (mask & (1UL << i))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) bcm_qspi_writel(priv->big_endian, 1, mmio + (i * 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static void bcm_iproc_qspi_int_set(struct bcm_qspi_soc_intc *soc_intc, int type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) bool en)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct bcm_iproc_intc *priv =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) container_of(soc_intc, struct bcm_iproc_intc, soc_intc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) void __iomem *mmio = priv->int_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) u32 mask = get_qspi_mask(type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) spin_lock_irqsave(&priv->soclock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) val = bcm_qspi_readl(priv->big_endian, mmio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (en)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) val = val | (mask << INTR_BASE_BIT_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) val = val & ~(mask << INTR_BASE_BIT_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) bcm_qspi_writel(priv->big_endian, val, mmio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) spin_unlock_irqrestore(&priv->soclock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) static int bcm_iproc_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) struct bcm_iproc_intc *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) struct bcm_qspi_soc_intc *soc_intc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (!priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) soc_intc = &priv->soc_intc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) priv->pdev = pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) spin_lock_init(&priv->soclock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr_regs");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) priv->int_reg = devm_ioremap_resource(dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (IS_ERR(priv->int_reg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return PTR_ERR(priv->int_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) "intr_status_reg");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) priv->int_status_reg = devm_ioremap_resource(dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (IS_ERR(priv->int_status_reg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) return PTR_ERR(priv->int_status_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) priv->big_endian = of_device_is_big_endian(dev->of_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) bcm_iproc_qspi_int_ack(soc_intc, MSPI_BSPI_DONE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) bcm_iproc_qspi_int_set(soc_intc, MSPI_BSPI_DONE, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) soc_intc->bcm_qspi_int_ack = bcm_iproc_qspi_int_ack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) soc_intc->bcm_qspi_int_set = bcm_iproc_qspi_int_set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) soc_intc->bcm_qspi_get_int_status = bcm_iproc_qspi_get_l2_int_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return bcm_qspi_probe(pdev, soc_intc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static int bcm_iproc_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) return bcm_qspi_remove(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) static const struct of_device_id bcm_iproc_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) { .compatible = "brcm,spi-nsp-qspi" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) { .compatible = "brcm,spi-ns2-qspi" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) MODULE_DEVICE_TABLE(of, bcm_iproc_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) static struct platform_driver bcm_iproc_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) .probe = bcm_iproc_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) .remove = bcm_iproc_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) .name = "bcm_iproc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) .pm = &bcm_qspi_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) .of_match_table = bcm_iproc_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) module_platform_driver(bcm_iproc_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) MODULE_LICENSE("GPL v2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) MODULE_AUTHOR("Kamal Dasu");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) MODULE_DESCRIPTION("SPI flash driver for Broadcom iProc SoCs");