summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-11-20 15:40:54 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2024-11-20 15:40:54 -0800
commit14d0e1a09fe97a7524ff36baa695900cb0c10c23 (patch)
treeaccca02adb7453b2cec02cb9435b2678c243d6aa /drivers/misc
parent9c39d5ab450f7181775957000f4aff33bfef9f7b (diff)
parentb77587ac51d2fe4b9d5751662ddc083d19153662 (diff)
Merge tag 'soc-drivers-6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
Pull SoC driver updates from Arnd Bergmann: "Nothing particular important in the SoC driver updates, just the usual improvements to for drivers/soc and a couple of subsystems that don't fit anywhere else: - The largest set of updates is for Qualcomm SoC drivers, extending the set of supported features for additional SoCs in the QSEECOM, LLCC and socinfo drivers.a - The ti_sci firmware driver gains support for power managment - The drivers/reset subsystem sees a rework of the microchip sparx5 and amlogic reset drivers to support additional chips, plus a few minor updates on other platforms - The SCMI firmware interface driver gains support for two protocol extensions, allowing more flexible use of the shared memory area and new DT binding properties for configurability. - Mediatek SoC drivers gain support for power managment on the MT8188 SoC and a new driver for DVFS. - The AMD/Xilinx ZynqMP SoC drivers gain support for system reboot and a few bugfixes - The Hisilicon Kunpeng HCCS driver gains support for configuring lanes through sysfs Finally, there are cleanups and minor fixes for drivers/{soc, bus, memory}, including changing back the .remove_new callback to .remove, as well as a few other updates for freescale (powerpc) soc drivers, NXP i.MX soc drivers, cznic turris platform driver, memory controller drviers, TI OMAP SoC drivers, and Tegra firmware drivers" * tag 'soc-drivers-6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (116 commits) soc: fsl: cpm1: qmc: Set the ret error code on platform_get_irq() failure soc: fsl: rcpm: fix missing of_node_put() in copy_ippdexpcr1_setting() soc: fsl: cpm1: tsa: switch to for_each_available_child_of_node_scoped() platform: cznic: turris-omnia-mcu: Rename variable holding GPIO line names platform: cznic: turris-omnia-mcu: Document the driver private data structure firmware: turris-mox-rwtm: Document the driver private data structure bus: Switch back to struct platform_driver::remove() soc: qcom: ice: Remove the device_link field in qcom_ice drm/msm/adreno: Setup SMMU aparture for per-process page table firmware: qcom: scm: Introduce CP_SMMU_APERTURE_ID firmware: arm_scpi: Check the DVFS OPP count returned by the firmware soc: qcom: socinfo: add IPQ5424/IPQ5404 SoC ID dt-bindings: arm: qcom,ids: add SoC ID for IPQ5424/IPQ5404 soc: qcom: llcc: Flip the manual slice configuration condition dt-bindings: firmware: qcom,scm: Document sm8750 SCM firmware: qcom: uefisecapp: Allow X1E Devkit devices misc: lan966x_pci: Fix dtc warn 'Missing interrupt-parent' misc: lan966x_pci: Fix dtc warns 'missing or empty reg/ranges property' soc: qcom: llcc: Add LLCC configuration for the QCS8300 platform dt-bindings: cache: qcom,llcc: Document the QCS8300 LLCC ...
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/Kconfig24
-rw-r--r--drivers/misc/Makefile3
-rw-r--r--drivers/misc/lan966x_pci.c215
-rw-r--r--drivers/misc/lan966x_pci.dtso177
4 files changed, 419 insertions, 0 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 3fe7e2a9bd29..902c306bc972 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -610,6 +610,30 @@ config MARVELL_CN10K_DPI
To compile this driver as a module, choose M here: the module
will be called mrvl_cn10k_dpi.
+config MCHP_LAN966X_PCI
+ tristate "Microchip LAN966x PCIe Support"
+ depends on PCI
+ select OF
+ select OF_OVERLAY
+ select IRQ_DOMAIN
+ help
+ This enables the support for the LAN966x PCIe device.
+
+ This is used to drive the LAN966x PCIe device from the host system
+ to which it is connected. The driver uses a device tree overlay to
+ load other drivers to support for LAN966x internal components.
+
+ Even if this driver does not depend on those other drivers, in order
+ to have a fully functional board, the following drivers are needed:
+ - fixed-clock (COMMON_CLK)
+ - lan966x-oic (LAN966X_OIC)
+ - lan966x-cpu-syscon (MFD_SYSCON)
+ - lan966x-switch-reset (RESET_MCHP_SPARX5)
+ - lan966x-pinctrl (PINCTRL_OCELOT)
+ - lan966x-serdes (PHY_LAN966X_SERDES)
+ - lan966x-miim (MDIO_MSCC_MIIM)
+ - lan966x-switch (LAN966X_SWITCH)
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index a9f94525e181..885b22989580 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -71,4 +71,7 @@ obj-$(CONFIG_TPS6594_ESM) += tps6594-esm.o
obj-$(CONFIG_TPS6594_PFSM) += tps6594-pfsm.o
obj-$(CONFIG_NSM) += nsm.o
obj-$(CONFIG_MARVELL_CN10K_DPI) += mrvl_cn10k_dpi.o
+lan966x-pci-objs := lan966x_pci.o
+lan966x-pci-objs += lan966x_pci.dtbo.o
+obj-$(CONFIG_MCHP_LAN966X_PCI) += lan966x-pci.o
obj-y += keba/
diff --git a/drivers/misc/lan966x_pci.c b/drivers/misc/lan966x_pci.c
new file mode 100644
index 000000000000..9c79b58137e5
--- /dev/null
+++ b/drivers/misc/lan966x_pci.c
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip LAN966x PCI driver
+ *
+ * Copyright (c) 2024 Microchip Technology Inc. and its subsidiaries.
+ *
+ * Authors:
+ * Clément Léger <clement.leger@bootlin.com>
+ * Hervé Codina <herve.codina@bootlin.com>
+ */
+
+#include <linux/device.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+
+/* Embedded dtbo symbols created by cmd_wrap_S_dtb in scripts/Makefile.lib */
+extern char __dtbo_lan966x_pci_begin[];
+extern char __dtbo_lan966x_pci_end[];
+
+struct pci_dev_intr_ctrl {
+ struct pci_dev *pci_dev;
+ struct irq_domain *irq_domain;
+ int irq;
+};
+
+static int pci_dev_irq_domain_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_simple_irq);
+ return 0;
+}
+
+static const struct irq_domain_ops pci_dev_irq_domain_ops = {
+ .map = pci_dev_irq_domain_map,
+ .xlate = irq_domain_xlate_onecell,
+};
+
+static irqreturn_t pci_dev_irq_handler(int irq, void *data)
+{
+ struct pci_dev_intr_ctrl *intr_ctrl = data;
+ int ret;
+
+ ret = generic_handle_domain_irq(intr_ctrl->irq_domain, 0);
+ return ret ? IRQ_NONE : IRQ_HANDLED;
+}
+
+static struct pci_dev_intr_ctrl *pci_dev_create_intr_ctrl(struct pci_dev *pdev)
+{
+ struct pci_dev_intr_ctrl *intr_ctrl __free(kfree) = NULL;
+ struct fwnode_handle *fwnode;
+ int ret;
+
+ fwnode = dev_fwnode(&pdev->dev);
+ if (!fwnode)
+ return ERR_PTR(-ENODEV);
+
+ intr_ctrl = kmalloc(sizeof(*intr_ctrl), GFP_KERNEL);
+ if (!intr_ctrl)
+ return ERR_PTR(-ENOMEM);
+
+ intr_ctrl->pci_dev = pdev;
+
+ intr_ctrl->irq_domain = irq_domain_create_linear(fwnode, 1, &pci_dev_irq_domain_ops,
+ intr_ctrl);
+ if (!intr_ctrl->irq_domain) {
+ pci_err(pdev, "Failed to create irqdomain\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_INTX);
+ if (ret < 0) {
+ pci_err(pdev, "Unable alloc irq vector (%d)\n", ret);
+ goto err_remove_domain;
+ }
+ intr_ctrl->irq = pci_irq_vector(pdev, 0);
+ ret = request_irq(intr_ctrl->irq, pci_dev_irq_handler, IRQF_SHARED,
+ pci_name(pdev), intr_ctrl);
+ if (ret) {
+ pci_err(pdev, "Unable to request irq %d (%d)\n", intr_ctrl->irq, ret);
+ goto err_free_irq_vector;
+ }
+
+ return_ptr(intr_ctrl);
+
+err_free_irq_vector:
+ pci_free_irq_vectors(pdev);
+err_remove_domain:
+ irq_domain_remove(intr_ctrl->irq_domain);
+ return ERR_PTR(ret);
+}
+
+static void pci_dev_remove_intr_ctrl(struct pci_dev_intr_ctrl *intr_ctrl)
+{
+ free_irq(intr_ctrl->irq, intr_ctrl);
+ pci_free_irq_vectors(intr_ctrl->pci_dev);
+ irq_dispose_mapping(irq_find_mapping(intr_ctrl->irq_domain, 0));
+ irq_domain_remove(intr_ctrl->irq_domain);
+ kfree(intr_ctrl);
+}
+
+static void devm_pci_dev_remove_intr_ctrl(void *intr_ctrl)
+{
+ pci_dev_remove_intr_ctrl(intr_ctrl);
+}
+
+static int devm_pci_dev_create_intr_ctrl(struct pci_dev *pdev)
+{
+ struct pci_dev_intr_ctrl *intr_ctrl;
+
+ intr_ctrl = pci_dev_create_intr_ctrl(pdev);
+ if (IS_ERR(intr_ctrl))
+ return PTR_ERR(intr_ctrl);
+
+ return devm_add_action_or_reset(&pdev->dev, devm_pci_dev_remove_intr_ctrl, intr_ctrl);
+}
+
+struct lan966x_pci {
+ struct device *dev;
+ int ovcs_id;
+};
+
+static int lan966x_pci_load_overlay(struct lan966x_pci *data)
+{
+ u32 dtbo_size = __dtbo_lan966x_pci_end - __dtbo_lan966x_pci_begin;
+ void *dtbo_start = __dtbo_lan966x_pci_begin;
+
+ return of_overlay_fdt_apply(dtbo_start, dtbo_size, &data->ovcs_id, dev_of_node(data->dev));
+}
+
+static void lan966x_pci_unload_overlay(struct lan966x_pci *data)
+{
+ of_overlay_remove(&data->ovcs_id);
+}
+
+static int lan966x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct device *dev = &pdev->dev;
+ struct lan966x_pci *data;
+ int ret;
+
+ /*
+ * On ACPI system, fwnode can point to the ACPI node.
+ * This driver needs an of_node to be used as the device-tree overlay
+ * target. This of_node should be set by the PCI core if it succeeds in
+ * creating it (CONFIG_PCI_DYNAMIC_OF_NODES feature).
+ * Check here for the validity of this of_node.
+ */
+ if (!dev_of_node(dev))
+ return dev_err_probe(dev, -EINVAL, "Missing of_node for device\n");
+
+ /* Need to be done before devm_pci_dev_create_intr_ctrl.
+ * It allocates an IRQ and so pdev->irq is updated.
+ */
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ ret = devm_pci_dev_create_intr_ctrl(pdev);
+ if (ret)
+ return ret;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ pci_set_drvdata(pdev, data);
+ data->dev = dev;
+
+ ret = lan966x_pci_load_overlay(data);
+ if (ret)
+ return ret;
+
+ pci_set_master(pdev);
+
+ ret = of_platform_default_populate(dev_of_node(dev), NULL, dev);
+ if (ret)
+ goto err_unload_overlay;
+
+ return 0;
+
+err_unload_overlay:
+ lan966x_pci_unload_overlay(data);
+ return ret;
+}
+
+static void lan966x_pci_remove(struct pci_dev *pdev)
+{
+ struct lan966x_pci *data = pci_get_drvdata(pdev);
+
+ of_platform_depopulate(data->dev);
+
+ lan966x_pci_unload_overlay(data);
+}
+
+static struct pci_device_id lan966x_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_EFAR, 0x9660) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, lan966x_pci_ids);
+
+static struct pci_driver lan966x_pci_driver = {
+ .name = "mchp_lan966x_pci",
+ .id_table = lan966x_pci_ids,
+ .probe = lan966x_pci_probe,
+ .remove = lan966x_pci_remove,
+};
+module_pci_driver(lan966x_pci_driver);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("Microchip LAN966x PCI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/lan966x_pci.dtso b/drivers/misc/lan966x_pci.dtso
new file mode 100644
index 000000000000..7b196b0a0eb6
--- /dev/null
+++ b/drivers/misc/lan966x_pci.dtso
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 Microchip UNG
+ */
+
+#include <dt-bindings/clock/microchip,lan966x.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/mfd/atmel-flexcom.h>
+#include <dt-bindings/phy/phy-lan966x-serdes.h>
+
+/dts-v1/;
+/plugin/;
+
+/ {
+ fragment@0 {
+ target-path = "";
+
+ /*
+ * These properties allow to avoid a dtc warnings.
+ * The real interrupt controller is the PCI device itself. It
+ * is the node on which the device tree overlay will be applied.
+ * This node has those properties.
+ */
+ #interrupt-cells = <1>;
+ interrupt-controller;
+
+ __overlay__ {
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ cpu_clk: clock-600000000 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <600000000>; /* CPU clock = 600MHz */
+ };
+
+ ddr_clk: clock-30000000 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <30000000>; /* Fabric clock = 30MHz */
+ };
+
+ sys_clk: clock-15625000 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <15625000>; /* System clock = 15.625MHz */
+ };
+
+ pci-ep-bus@0 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ /*
+ * map @0xe2000000 (32MB) to BAR0 (CPU)
+ * map @0xe0000000 (16MB) to BAR1 (AMBA)
+ */
+ ranges = <0xe2000000 0x00 0x00 0x00 0x2000000
+ 0xe0000000 0x01 0x00 0x00 0x1000000>;
+
+ oic: oic@e00c0120 {
+ compatible = "microchip,lan966x-oic";
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ interrupts = <0>; /* PCI INTx assigned interrupt */
+ reg = <0xe00c0120 0x190>;
+ };
+
+ cpu_ctrl: syscon@e00c0000 {
+ compatible = "microchip,lan966x-cpu-syscon", "syscon";
+ reg = <0xe00c0000 0xa8>;
+ };
+
+ reset: reset@e200400c {
+ compatible = "microchip,lan966x-switch-reset";
+ reg = <0xe200400c 0x4>, <0xe00c0000 0xa8>;
+ reg-names = "gcb","cpu";
+ #reset-cells = <1>;
+ cpu-syscon = <&cpu_ctrl>;
+ };
+
+ gpio: pinctrl@e2004064 {
+ compatible = "microchip,lan966x-pinctrl";
+ reg = <0xe2004064 0xb4>,
+ <0xe2010024 0x138>;
+ resets = <&reset 0>;
+ reset-names = "switch";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&gpio 0 0 78>;
+ interrupt-parent = <&oic>;
+ interrupt-controller;
+ interrupts = <17 IRQ_TYPE_LEVEL_HIGH>;
+ #interrupt-cells = <2>;
+
+ tod_pins: tod_pins {
+ pins = "GPIO_36";
+ function = "ptpsync_1";
+ };
+
+ fc0_a_pins: fcb4-i2c-pins {
+ /* RXD, TXD */
+ pins = "GPIO_9", "GPIO_10";
+ function = "fc0_a";
+ };
+
+ };
+
+ serdes: serdes@e202c000 {
+ compatible = "microchip,lan966x-serdes";
+ reg = <0xe202c000 0x9c>,
+ <0xe2004010 0x4>;
+ #phy-cells = <2>;
+ };
+
+ mdio1: mdio@e200413c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "microchip,lan966x-miim";
+ reg = <0xe200413c 0x24>,
+ <0xe2010020 0x4>;
+
+ resets = <&reset 0>;
+ reset-names = "switch";
+
+ lan966x_phy0: ethernet-lan966x_phy@1 {
+ reg = <1>;
+ };
+
+ lan966x_phy1: ethernet-lan966x_phy@2 {
+ reg = <2>;
+ };
+ };
+
+ switch: switch@e0000000 {
+ compatible = "microchip,lan966x-switch";
+ reg = <0xe0000000 0x0100000>,
+ <0xe2000000 0x0800000>;
+ reg-names = "cpu", "gcb";
+
+ interrupt-parent = <&oic>;
+ interrupts = <12 IRQ_TYPE_LEVEL_HIGH>,
+ <9 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "xtr", "ana";
+
+ resets = <&reset 0>;
+ reset-names = "switch";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&tod_pins>;
+
+ ethernet-ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port0: port@0 {
+ phy-handle = <&lan966x_phy0>;
+
+ reg = <0>;
+ phy-mode = "gmii";
+ phys = <&serdes 0 CU(0)>;
+ };
+
+ port1: port@1 {
+ phy-handle = <&lan966x_phy1>;
+
+ reg = <1>;
+ phy-mode = "gmii";
+ phys = <&serdes 1 CU(1)>;
+ };
+ };
+ };
+ };
+ };
+ };
+};