diff options
Diffstat (limited to 'target/linux/bcm27xx/patches-6.1/950-0872-mfd-Add-rp1-driver.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-6.1/950-0872-mfd-Add-rp1-driver.patch | 442 |
1 files changed, 0 insertions, 442 deletions
diff --git a/target/linux/bcm27xx/patches-6.1/950-0872-mfd-Add-rp1-driver.patch b/target/linux/bcm27xx/patches-6.1/950-0872-mfd-Add-rp1-driver.patch deleted file mode 100644 index c2044753f9..0000000000 --- a/target/linux/bcm27xx/patches-6.1/950-0872-mfd-Add-rp1-driver.patch +++ /dev/null @@ -1,442 +0,0 @@ -From 7196a12b94e90225686e6c34cdf65a583214f7a5 Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.com> -Date: Mon, 10 Oct 2022 14:21:50 +0100 -Subject: [PATCH] mfd: Add rp1 driver - -RP1 is a multifunction PCIe device that exposes a range of -peripherals. -Add the parent driver to manage these. - -Signed-off-by: Phil Elwell <phil@raspberrypi.com> ---- - drivers/mfd/Kconfig | 11 ++ - drivers/mfd/Makefile | 1 + - drivers/mfd/rp1.c | 367 +++++++++++++++++++++++++++++++++++ - include/linux/rp1_platform.h | 20 ++ - 4 files changed, 399 insertions(+) - create mode 100644 drivers/mfd/rp1.c - create mode 100644 include/linux/rp1_platform.h - ---- a/drivers/mfd/Kconfig -+++ b/drivers/mfd/Kconfig -@@ -2253,6 +2253,17 @@ config MFD_INTEL_M10_BMC - additional drivers must be enabled in order to use the functionality - of the device. - -+config MFD_RP1 -+ tristate "RP1 MFD driver" -+ depends on PCI -+ select MFD_CORE -+ help -+ Support for the RP1 peripheral chip. -+ -+ This driver provides support for the Raspberry Pi RP1 peripheral chip. -+ It is responsible for enabling the Device Tree node once the PCIe endpoint -+ has been configured, and handling interrupts. -+ - config MFD_RSMU_I2C - tristate "Renesas Synchronization Management Unit with I2C" - depends on I2C && OF ---- a/drivers/mfd/Makefile -+++ b/drivers/mfd/Makefile -@@ -273,6 +273,7 @@ obj-$(CONFIG_MFD_RPISENSE_CORE) += rpise - obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o - obj-$(CONFIG_MFD_SIMPLE_MFD_I2C) += simple-mfd-i2c.o - obj-$(CONFIG_MFD_INTEL_M10_BMC) += intel-m10-bmc.o -+obj-$(CONFIG_MFD_RP1) += rp1.o - - obj-$(CONFIG_MFD_ATC260X) += atc260x-core.o - obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o ---- /dev/null -+++ b/drivers/mfd/rp1.c -@@ -0,0 +1,367 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (c) 2018-22 Raspberry Pi Ltd. -+ * All rights reserved. -+ */ -+ -+#include <linux/clk.h> -+#include <linux/clkdev.h> -+#include <linux/clk-provider.h> -+#include <linux/completion.h> -+#include <linux/etherdevice.h> -+#include <linux/err.h> -+#include <linux/interrupt.h> -+#include <linux/io.h> -+#include <linux/irq.h> -+#include <linux/irqchip/chained_irq.h> -+#include <linux/irqdomain.h> -+#include <linux/mfd/core.h> -+#include <linux/mmc/host.h> -+#include <linux/module.h> -+#include <linux/msi.h> -+#include <linux/of_platform.h> -+#include <linux/pci.h> -+#include <linux/platform_device.h> -+#include <linux/rp1_platform.h> -+#include <linux/reset.h> -+#include <linux/slab.h> -+ -+#include <dt-bindings/mfd/rp1.h> -+ -+/* TO DO: -+ * 1. Occasional shutdown crash - RP1 being closed before its children? -+ * 2. DT mode interrupt handling. -+ */ -+ -+#define RP1_DRIVER_NAME "rp1" -+ -+#define PCI_VENDOR_ID_RPI 0x1de4 -+#define PCI_DEVICE_ID_RP1_C0 0x0001 -+#define PCI_DEVICE_REV_RP1_C0 2 -+ -+#define RP1_ACTUAL_IRQS RP1_INT_END -+#define RP1_IRQS RP1_ACTUAL_IRQS -+ -+#define RP1_SYSCLK_RATE 200000000 -+#define RP1_SYSCLK_FPGA_RATE 60000000 -+ -+// Don't want to include the whole sysinfo reg header -+#define SYSINFO_CHIP_ID_OFFSET 0x00000000 -+#define SYSINFO_PLATFORM_OFFSET 0x00000004 -+ -+#define REG_RW 0x000 -+#define REG_SET 0x800 -+#define REG_CLR 0xc00 -+ -+// MSIX CFG registers start at 0x8 -+#define MSIX_CFG(x) (0x8 + (4 * (x))) -+ -+#define MSIX_CFG_IACK_EN BIT(3) -+#define MSIX_CFG_IACK BIT(2) -+#define MSIX_CFG_TEST BIT(1) -+#define MSIX_CFG_ENABLE BIT(0) -+ -+#define INTSTATL 0x108 -+#define INTSTATH 0x10c -+ -+struct rp1_dev { -+ struct pci_dev *pdev; -+ struct device *dev; -+ resource_size_t bar_start; -+ resource_size_t bar_end; -+ struct clk *sys_clk; -+ struct irq_domain *domain; -+ struct irq_data *pcie_irqds[64]; -+ void __iomem *msix_cfg_regs; -+}; -+ -+static bool rp1_level_triggered_irq[RP1_ACTUAL_IRQS] = { 0 }; -+ -+static struct rp1_dev *g_rp1; -+static u32 g_chip_id, g_platform; -+ -+static void dump_bar(struct pci_dev *pdev, unsigned int bar) -+{ -+ dev_info(&pdev->dev, -+ "bar%d len 0x%llx, start 0x%llx, end 0x%llx, flags, 0x%lx\n", -+ bar, -+ pci_resource_len(pdev, bar), -+ pci_resource_start(pdev, bar), -+ pci_resource_end(pdev, bar), -+ pci_resource_flags(pdev, bar)); -+} -+ -+static void msix_cfg_set(struct rp1_dev *rp1, unsigned int hwirq, u32 value) -+{ -+ writel(value, rp1->msix_cfg_regs + REG_SET + MSIX_CFG(hwirq)); -+} -+ -+static void msix_cfg_clr(struct rp1_dev *rp1, unsigned int hwirq, u32 value) -+{ -+ writel(value, rp1->msix_cfg_regs + REG_CLR + MSIX_CFG(hwirq)); -+} -+ -+static void rp1_mask_irq(struct irq_data *irqd) -+{ -+ struct rp1_dev *rp1 = irqd->domain->host_data; -+ struct irq_data *pcie_irqd = rp1->pcie_irqds[irqd->hwirq]; -+ -+ pci_msi_mask_irq(pcie_irqd); -+} -+ -+static void rp1_unmask_irq(struct irq_data *irqd) -+{ -+ struct rp1_dev *rp1 = irqd->domain->host_data; -+ struct irq_data *pcie_irqd = rp1->pcie_irqds[irqd->hwirq]; -+ -+ pci_msi_unmask_irq(pcie_irqd); -+} -+ -+static int rp1_irq_set_type(struct irq_data *irqd, unsigned int type) -+{ -+ struct rp1_dev *rp1 = irqd->domain->host_data; -+ unsigned int hwirq = (unsigned int)irqd->hwirq; -+ int ret = 0; -+ -+ switch (type) { -+ case IRQ_TYPE_LEVEL_HIGH: -+ dev_dbg(rp1->dev, "MSIX IACK EN for irq %d\n", hwirq); -+ msix_cfg_set(rp1, hwirq, MSIX_CFG_IACK_EN); -+ rp1_level_triggered_irq[hwirq] = true; -+ break; -+ case IRQ_TYPE_EDGE_RISING: -+ msix_cfg_clr(rp1, hwirq, MSIX_CFG_IACK_EN); -+ rp1_level_triggered_irq[hwirq] = false; -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+static struct irq_chip rp1_irq_chip = { -+ .name = "rp1_irq_chip", -+ .irq_mask = rp1_mask_irq, -+ .irq_unmask = rp1_unmask_irq, -+ .irq_set_type = rp1_irq_set_type, -+}; -+ -+static void rp1_chained_handle_irq(struct irq_desc *desc) -+{ -+ struct irq_chip *chip = irq_desc_get_chip(desc); -+ struct rp1_dev *rp1 = desc->irq_data.chip_data; -+ unsigned int hwirq = desc->irq_data.hwirq & 0x3f; -+ int new_irq; -+ -+ rp1 = g_rp1; -+ -+ chained_irq_enter(chip, desc); -+ -+ new_irq = irq_linear_revmap(rp1->domain, hwirq); -+ generic_handle_irq(new_irq); -+ if (rp1_level_triggered_irq[hwirq]) -+ msix_cfg_set(rp1, hwirq, MSIX_CFG_IACK); -+ -+ chained_irq_exit(chip, desc); -+} -+ -+static int rp1_irq_xlate(struct irq_domain *d, struct device_node *node, -+ const u32 *intspec, unsigned int intsize, -+ unsigned long *out_hwirq, unsigned int *out_type) -+{ -+ struct rp1_dev *rp1 = d->host_data; -+ struct irq_data *pcie_irqd; -+ unsigned long hwirq; -+ int pcie_irq; -+ int ret; -+ -+ ret = irq_domain_xlate_twocell(d, node, intspec, intsize, -+ &hwirq, out_type); -+ if (!ret) { -+ pcie_irq = pci_irq_vector(rp1->pdev, hwirq); -+ pcie_irqd = irq_get_irq_data(pcie_irq); -+ rp1->pcie_irqds[hwirq] = pcie_irqd; -+ *out_hwirq = hwirq; -+ } -+ return ret; -+} -+ -+static int rp1_irq_activate(struct irq_domain *d, struct irq_data *irqd, -+ bool reserve) -+{ -+ struct rp1_dev *rp1 = d->host_data; -+ struct irq_data *pcie_irqd; -+ -+ pcie_irqd = rp1->pcie_irqds[irqd->hwirq]; -+ msix_cfg_set(rp1, (unsigned int)irqd->hwirq, MSIX_CFG_ENABLE); -+ return irq_domain_activate_irq(pcie_irqd, reserve); -+} -+ -+static void rp1_irq_deactivate(struct irq_domain *d, struct irq_data *irqd) -+{ -+ struct rp1_dev *rp1 = d->host_data; -+ struct irq_data *pcie_irqd; -+ -+ pcie_irqd = rp1->pcie_irqds[irqd->hwirq]; -+ msix_cfg_clr(rp1, (unsigned int)irqd->hwirq, MSIX_CFG_ENABLE); -+ return irq_domain_deactivate_irq(pcie_irqd); -+} -+ -+static const struct irq_domain_ops rp1_domain_ops = { -+ .xlate = rp1_irq_xlate, -+ .activate = rp1_irq_activate, -+ .deactivate = rp1_irq_deactivate, -+}; -+ -+static inline dma_addr_t rp1_io_to_phys(struct rp1_dev *rp1, unsigned int offset) -+{ -+ return rp1->bar_start + offset; -+} -+ -+static u32 rp1_reg_read(struct rp1_dev *rp1, unsigned int base_addr, u32 offset) -+{ -+ dma_addr_t phys = rp1_io_to_phys(rp1, base_addr); -+ void __iomem *regblock = ioremap(phys, 0x1000); -+ u32 value = readl(regblock + offset); -+ -+ iounmap(regblock); -+ return value; -+} -+ -+void rp1_get_platform(u32 *chip_id, u32 *platform) -+{ -+ if (chip_id) -+ *chip_id = g_chip_id; -+ if (platform) -+ *platform = g_platform; -+} -+EXPORT_SYMBOL_GPL(rp1_get_platform); -+ -+static int rp1_probe(struct pci_dev *pdev, const struct pci_device_id *id) -+{ -+ struct reset_control *reset; -+ struct platform_device *pcie_pdev; -+ struct device_node *rp1_node; -+ struct rp1_dev *rp1; -+ int err = 0; -+ int i; -+ -+ reset = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); -+ if (IS_ERR(reset)) -+ return PTR_ERR(reset); -+ reset_control_reset(reset); -+ -+ dump_bar(pdev, 0); -+ dump_bar(pdev, 1); -+ -+ if (pci_resource_len(pdev, 1) <= 0x10000) { -+ dev_err(&pdev->dev, -+ "Not initialised - is the firmware running?\n"); -+ return -EINVAL; -+ } -+ -+ /* enable pci device */ -+ err = pcim_enable_device(pdev); -+ if (err < 0) { -+ dev_err(&pdev->dev, "Enabling PCI device has failed: %d", -+ err); -+ return err; -+ } -+ -+ pci_set_master(pdev); -+ -+ err = pci_alloc_irq_vectors(pdev, RP1_IRQS, RP1_IRQS, -+ PCI_IRQ_MSIX); -+ if (err != RP1_IRQS) { -+ dev_err(&pdev->dev, "pci_alloc_irq_vectors failed - %d\n", err); -+ return err; -+ } -+ -+ rp1 = devm_kzalloc(&pdev->dev, sizeof(*rp1), GFP_KERNEL); -+ if (!rp1) -+ return -ENOMEM; -+ -+ rp1->pdev = pdev; -+ rp1->dev = &pdev->dev; -+ -+ pci_set_drvdata(pdev, rp1); -+ -+ rp1->bar_start = pci_resource_start(pdev, 1); -+ rp1->bar_end = pci_resource_end(pdev, 1); -+ -+ // Get chip id -+ g_chip_id = rp1_reg_read(rp1, RP1_SYSINFO_BASE, SYSINFO_CHIP_ID_OFFSET); -+ g_platform = rp1_reg_read(rp1, RP1_SYSINFO_BASE, SYSINFO_PLATFORM_OFFSET); -+ dev_info(&pdev->dev, "chip_id 0x%x%s\n", g_chip_id, -+ (g_platform & RP1_PLATFORM_FPGA) ? " FPGA" : ""); -+ if (g_chip_id != RP1_C0_CHIP_ID) { -+ dev_err(&pdev->dev, "wrong chip id (%x)\n", g_chip_id); -+ return -EINVAL; -+ } -+ -+ rp1_node = of_find_node_by_name(NULL, "rp1"); -+ if (!rp1_node) { -+ dev_err(&pdev->dev, "failed to find RP1 DT node\n"); -+ return -EINVAL; -+ } -+ -+ pcie_pdev = of_find_device_by_node(rp1_node->parent); -+ rp1->domain = irq_domain_add_linear(rp1_node, RP1_IRQS, -+ &rp1_domain_ops, rp1); -+ -+ g_rp1 = rp1; -+ -+ /* TODO can this go in the rp1 device tree entry? */ -+ rp1->msix_cfg_regs = ioremap(rp1_io_to_phys(rp1, RP1_PCIE_APBS_BASE), 0x1000); -+ -+ for (i = 0; i < RP1_IRQS; i++) { -+ int irq = irq_create_mapping(rp1->domain, i); -+ -+ if (irq < 0) { -+ dev_err(&pdev->dev, "failed to create irq mapping\n"); -+ return irq; -+ } -+ -+ irq_set_chip_data(irq, rp1); -+ irq_set_chip_and_handler(irq, &rp1_irq_chip, handle_level_irq); -+ irq_set_probe(irq); -+ irq_set_chained_handler(pci_irq_vector(pdev, i), -+ rp1_chained_handle_irq); -+ } -+ -+ if (rp1_node) -+ of_platform_populate(rp1_node, NULL, NULL, &pcie_pdev->dev); -+ -+ of_node_put(rp1_node); -+ -+ return 0; -+} -+ -+static void rp1_remove(struct pci_dev *pdev) -+{ -+ struct rp1_dev *rp1 = pci_get_drvdata(pdev); -+ -+ mfd_remove_devices(&pdev->dev); -+ -+ clk_unregister(rp1->sys_clk); -+} -+ -+static const struct pci_device_id dev_id_table[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_RPI, PCI_DEVICE_ID_RP1_C0), }, -+ { 0, } -+}; -+ -+static struct pci_driver rp1_driver = { -+ .name = RP1_DRIVER_NAME, -+ .id_table = dev_id_table, -+ .probe = rp1_probe, -+ .remove = rp1_remove, -+}; -+ -+module_pci_driver(rp1_driver); -+ -+MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.com>"); -+MODULE_DESCRIPTION("RP1 wrapper"); -+MODULE_LICENSE("GPL"); ---- /dev/null -+++ b/include/linux/rp1_platform.h -@@ -0,0 +1,20 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2021-2022 Raspberry Pi Ltd. -+ * All rights reserved. -+ */ -+ -+#ifndef _RP1_PLATFORM_H -+#define _RP1_PLATFORM_H -+ -+#include <vdso/bits.h> -+ -+#define RP1_B0_CHIP_ID 0x10001927 -+#define RP1_C0_CHIP_ID 0x20001927 -+ -+#define RP1_PLATFORM_ASIC BIT(1) -+#define RP1_PLATFORM_FPGA BIT(0) -+ -+void rp1_get_platform(u32 *chip_id, u32 *platform); -+ -+#endif |