diff --git a/Documentation/devicetree/bindings/interrupt-controller/loongson,pch-lpc.yaml b/Documentation/devicetree/bindings/interrupt-controller/loongson,pch-lpc.yaml new file mode 100644 index 00000000000000..c00fbf31f47f05 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/loongson,pch-lpc.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/loongson,pch-lpc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Loongson PCH LPC Controller + +maintainers: + - Jiaxun Yang + +description: + This interrupt controller is found in the Loongson LS7A family of PCH for + accepting interrupts sent by LPC-connected peripherals and signalling PIC + via a single interrupt line when interrupts are available. + +properties: + compatible: + const: loongson,pch-lpc-1.0 + + reg: + maxItems: 1 + + interrupt-controller: true + + interrupts: + maxItems: 1 + + '#interrupt-cells': + const: 2 + +required: + - compatible + - reg + - interrupt-controller + - interrupts + - '#interrupt-cells' + +additionalProperties: false + +examples: + - | + #include + lpc: interrupt-controller@10002000 { + compatible = "loongson,pch-lpc-1.0"; + reg = <0x10002000 0x400>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&pic>; + interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; + }; +... diff --git a/arch/mips/boot/dts/loongson/ls7a-pch.dtsi b/arch/mips/boot/dts/loongson/ls7a-pch.dtsi index ee71045883e7e7..d41ca0b3d6511b 100644 --- a/arch/mips/boot/dts/loongson/ls7a-pch.dtsi +++ b/arch/mips/boot/dts/loongson/ls7a-pch.dtsi @@ -19,11 +19,13 @@ #interrupt-cells = <2>; }; - rtc0: rtc@100d0100 { - compatible = "loongson,ls7a-rtc"; - reg = <0 0x100d0100 0 0x78>; + lpc: interrupt-controller@10002000 { + compatible = "loongson,pch-lpc-1.0"; + reg = <0 0x10002000 0 0x1000>; + interrupt-controller; interrupt-parent = <&pic>; - interrupts = <52 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; + #interrupt-cells = <2>; }; ls7a_uart0: serial@10080000 { @@ -65,6 +67,13 @@ no-loopback-test; }; + rtc0: rtc@100d0100 { + compatible = "loongson,ls7a-rtc"; + reg = <0 0x100d0100 0 0x78>; + interrupt-parent = <&pic>; + interrupts = <52 IRQ_TYPE_LEVEL_HIGH>; + }; + pci@1a000000 { compatible = "loongson,ls7a-pci"; device_type = "pci"; @@ -199,7 +208,8 @@ <13 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "macirq", "eth_lpi"; interrupt-parent = <&pic>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; + phy-handle = <&phy0>; mdio { #address-cells = <1>; #size-cells = <0>; @@ -222,7 +232,8 @@ <15 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "macirq", "eth_lpi"; interrupt-parent = <&pic>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; + phy-handle = <&phy1>; mdio { #address-cells = <1>; #size-cells = <0>; diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index a61c6dc63c29cf..b478b3089d7787 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -758,7 +758,6 @@ config LOONGSON_PCH_MSI config LOONGSON_PCH_LPC bool "Loongson PCH LPC Controller" - depends on LOONGARCH depends on MACH_LOONGSON64 default MACH_LOONGSON64 select IRQ_DOMAIN_HIERARCHY diff --git a/drivers/irqchip/irq-loongson-pch-lpc.c b/drivers/irqchip/irq-loongson-pch-lpc.c index 912bf50a5c7ca7..cea34de994cef7 100644 --- a/drivers/irqchip/irq-loongson-pch-lpc.c +++ b/drivers/irqchip/irq-loongson-pch-lpc.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include "irq-loongson.h" @@ -171,13 +173,11 @@ static struct syscore_ops pch_lpc_syscore_ops = { .resume = pch_lpc_resume, }; -int __init pch_lpc_acpi_init(struct irq_domain *parent, - struct acpi_madt_lpc_pic *acpi_pchlpc) +static int __init pch_lpc_init(phys_addr_t addr, unsigned long size, + struct fwnode_handle *irq_handle, + int parent_irq) { - int parent_irq; struct pch_lpc *priv; - struct irq_fwspec fwspec; - struct fwnode_handle *irq_handle; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) @@ -185,7 +185,7 @@ int __init pch_lpc_acpi_init(struct irq_domain *parent, raw_spin_lock_init(&priv->lpc_lock); - priv->base = ioremap(acpi_pchlpc->address, acpi_pchlpc->size); + priv->base = ioremap(addr, size); if (!priv->base) goto free_priv; @@ -194,12 +194,6 @@ int __init pch_lpc_acpi_init(struct irq_domain *parent, goto iounmap_base; } - irq_handle = irq_domain_alloc_named_fwnode("lpcintc"); - if (!irq_handle) { - pr_err("Unable to allocate domain handle\n"); - goto iounmap_base; - } - /* * The LPC interrupt controller is a legacy i8259-compatible device, * which requires a static 1:1 mapping for IRQs 0-15. @@ -209,15 +203,10 @@ int __init pch_lpc_acpi_init(struct irq_domain *parent, &pch_lpc_domain_ops, priv); if (!priv->lpc_domain) { pr_err("Failed to create IRQ domain\n"); - goto free_irq_handle; + goto iounmap_base; } pch_lpc_reset(priv); - fwspec.fwnode = parent->fwnode; - fwspec.param[0] = acpi_pchlpc->cascade + GSI_MIN_PCH_IRQ; - fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH; - fwspec.param_count = 2; - parent_irq = irq_create_fwspec_mapping(&fwspec); irq_set_chained_handler_and_data(parent_irq, lpc_irq_dispatch, priv); pch_lpc_priv = priv; @@ -226,8 +215,6 @@ int __init pch_lpc_acpi_init(struct irq_domain *parent, return 0; -free_irq_handle: - irq_domain_free_fwnode(irq_handle); iounmap_base: iounmap(priv->base); free_priv: @@ -235,3 +222,62 @@ int __init pch_lpc_acpi_init(struct irq_domain *parent, return -ENOMEM; } + +#ifdef CONFIG_ACPI +int __init pch_lpc_acpi_init(struct irq_domain *parent, + struct acpi_madt_lpc_pic *acpi_pchlpc) +{ + int parent_irq; + struct pch_lpc *priv; + struct irq_fwspec fwspec; + struct fwnode_handle *irq_handle; + int ret; + + irq_handle = irq_domain_alloc_named_fwnode("lpcintc"); + if (!irq_handle) { + pr_err("Unable to allocate domain handle\n"); + return -ENOMEM; + } + + fwspec.fwnode = parent->fwnode; + fwspec.param[0] = acpi_pchlpc->cascade + GSI_MIN_PCH_IRQ; + fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH; + fwspec.param_count = 2; + parent_irq = irq_create_fwspec_mapping(&fwspec); + + ret = pch_lpc_init(acpi_pchlpc->address, acpi_pchlpc->size, + irq_handle, parent_irq); + if (ret) { + irq_domain_free_fwnode(irq_handle); + return ret; + } + + return 0; +} +#endif /* CONFIG_ACPI */ + +#ifdef CONFIG_OF +static int pch_lpc_of_init(struct device_node *node, + struct device_node *parent) +{ + int parent_irq; + struct fwnode_handle *irq_handle; + struct resource res; + + if (of_address_to_resource(node, 0, &res)) + return -EINVAL; + + parent_irq = irq_of_parse_and_map(node, 0); + if (!parent_irq) { + pr_err("Failed to get the parent IRQ for LPC IRQs\n"); + return -EINVAL; + } + + irq_handle = of_fwnode_handle(node); + + return pch_lpc_init(res.start, resource_size(&res), irq_handle, + parent_irq); +} + +IRQCHIP_DECLARE(pch_lpc, "loongson,pch-lpc-1.0", pch_lpc_of_init); +#endif /* CONFIG_OF */ diff --git a/kernel/softirq.c b/kernel/softirq.c index 77198911b8dd4b..cdc77d52c36b29 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -1184,5 +1184,5 @@ int __init __weak arch_early_irq_init(void) unsigned int __weak arch_dynirq_lower_bound(unsigned int from) { - return from; + return MAX(from, NR_IRQS_LEGACY); }