diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2024-11-20 15:40:54 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2024-11-20 15:40:54 -0800 |
commit | 14d0e1a09fe97a7524ff36baa695900cb0c10c23 (patch) | |
tree | accca02adb7453b2cec02cb9435b2678c243d6aa /drivers/misc | |
parent | 9c39d5ab450f7181775957000f4aff33bfef9f7b (diff) | |
parent | b77587ac51d2fe4b9d5751662ddc083d19153662 (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/Kconfig | 24 | ||||
-rw-r--r-- | drivers/misc/Makefile | 3 | ||||
-rw-r--r-- | drivers/misc/lan966x_pci.c | 215 | ||||
-rw-r--r-- | drivers/misc/lan966x_pci.dtso | 177 |
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)>; + }; + }; + }; + }; + }; + }; +}; |