realtek: backport irq-realtek-rtl driver from 5.12 to 5.10
This patch backports "irq-realtek-rtl" driver to Kernel 5.10 from 5.12. "MACH_REALTEK_RTL" is used as a platform name in upstream, but "RTL838X" is used in OpenWrt, so update the dependency by the additional patch. Signed-off-by: INAGAKI Hiroshi <musashino.open@gmail.com>
This commit is contained in:
		 INAGAKI Hiroshi
					INAGAKI Hiroshi
				
			
				
					committed by
					
						 Adrian Schmutzler
						Adrian Schmutzler
					
				
			
			
				
	
			
			
			 Adrian Schmutzler
						Adrian Schmutzler
					
				
			
						parent
						
							b2bd0199a8
						
					
				
				
					commit
					2cd00b5147
				
			| @@ -0,0 +1,84 @@ | ||||
| From 4a2b92a5d3519fc2c1edda4d4aa0e05bff41e8de Mon Sep 17 00:00:00 2001 | ||||
| From: Bert Vermeulen <bert@biot.com> | ||||
| Date: Fri, 22 Jan 2021 21:42:23 +0100 | ||||
| Subject: dt-bindings: interrupt-controller: Add Realtek RTL838x/RTL839x | ||||
|  support | ||||
|  | ||||
| Document the binding for the Realtek RTL838x/RTL839x interrupt controller. | ||||
|  | ||||
| Reviewed-by: Rob Herring <robh@kernel.org> | ||||
| Signed-off-by: Bert Vermeulen <bert@biot.com> | ||||
| [maz: Add a commit message, as the author couldn't be bothered...] | ||||
| Signed-off-by: Marc Zyngier <maz@kernel.org> | ||||
| Link: https://lore.kernel.org/r/20210122204224.509124-2-bert@biot.com | ||||
| --- | ||||
|  .../interrupt-controller/realtek,rtl-intc.yaml     | 57 ++++++++++++++++++++++ | ||||
|  1 file changed, 57 insertions(+) | ||||
|  create mode 100644 Documentation/devicetree/bindings/interrupt-controller/realtek,rtl-intc.yaml | ||||
|  | ||||
| diff --git a/Documentation/devicetree/bindings/interrupt-controller/realtek,rtl-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/realtek,rtl-intc.yaml | ||||
| new file mode 100644 | ||||
| index 0000000000000..9e76fff20323c | ||||
| --- /dev/null | ||||
| +++ b/Documentation/devicetree/bindings/interrupt-controller/realtek,rtl-intc.yaml | ||||
| @@ -0,0 +1,57 @@ | ||||
| +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||||
| +%YAML 1.2 | ||||
| +--- | ||||
| +$id: http://devicetree.org/schemas/interrupt-controller/realtek,rtl-intc.yaml# | ||||
| +$schema: http://devicetree.org/meta-schemas/core.yaml# | ||||
| + | ||||
| +title: Realtek RTL SoC interrupt controller devicetree bindings | ||||
| + | ||||
| +maintainers: | ||||
| +  - Birger Koblitz <mail@birger-koblitz.de> | ||||
| +  - Bert Vermeulen <bert@biot.com> | ||||
| +  - John Crispin <john@phrozen.org> | ||||
| + | ||||
| +properties: | ||||
| +  compatible: | ||||
| +    const: realtek,rtl-intc | ||||
| + | ||||
| +  "#interrupt-cells": | ||||
| +    const: 1 | ||||
| + | ||||
| +  reg: | ||||
| +    maxItems: 1 | ||||
| + | ||||
| +  interrupts: | ||||
| +    maxItems: 1 | ||||
| + | ||||
| +  interrupt-controller: true | ||||
| + | ||||
| +  "#address-cells": | ||||
| +    const: 0 | ||||
| + | ||||
| +  interrupt-map: | ||||
| +    description: Describes mapping from SoC interrupts to CPU interrupts | ||||
| + | ||||
| +required: | ||||
| +  - compatible | ||||
| +  - reg | ||||
| +  - "#interrupt-cells" | ||||
| +  - interrupt-controller | ||||
| +  - "#address-cells" | ||||
| +  - interrupt-map | ||||
| + | ||||
| +additionalProperties: false | ||||
| + | ||||
| +examples: | ||||
| +  - | | ||||
| +    intc: interrupt-controller@3000 { | ||||
| +      compatible = "realtek,rtl-intc"; | ||||
| +      #interrupt-cells = <1>; | ||||
| +      interrupt-controller; | ||||
| +      reg = <0x3000 0x20>; | ||||
| +      #address-cells = <0>; | ||||
| +      interrupt-map = | ||||
| +              <31 &cpuintc 2>, | ||||
| +              <30 &cpuintc 1>, | ||||
| +              <29 &cpuintc 5>; | ||||
| +    }; | ||||
| --  | ||||
| cgit 1.2.3-1.el7 | ||||
|  | ||||
| @@ -0,0 +1,211 @@ | ||||
| From 9f3a0f34b84ad1b9a8f2bdae44b66f16685b2143 Mon Sep 17 00:00:00 2001 | ||||
| From: Bert Vermeulen <bert@biot.com> | ||||
| Date: Fri, 22 Jan 2021 21:42:24 +0100 | ||||
| Subject: irqchip: Add support for Realtek RTL838x/RTL839x interrupt controller | ||||
|  | ||||
| This is a standard IRQ driver with only status and mask registers. | ||||
|  | ||||
| The mapping from SoC interrupts (18-31) to MIPS core interrupts is | ||||
| done via an interrupt-map in device tree. | ||||
|  | ||||
| Signed-off-by: Bert Vermeulen <bert@biot.com> | ||||
| Signed-off-by: Birger Koblitz <mail@birger-koblitz.de> | ||||
| Acked-by: John Crispin <john@phrozen.org> | ||||
| Signed-off-by: Marc Zyngier <maz@kernel.org> | ||||
| Link: https://lore.kernel.org/r/20210122204224.509124-3-bert@biot.com | ||||
| --- | ||||
|  drivers/irqchip/Makefile          |   1 + | ||||
|  drivers/irqchip/irq-realtek-rtl.c | 180 ++++++++++++++++++++++++++++++++++++++ | ||||
|  2 files changed, 181 insertions(+) | ||||
|  create mode 100644 drivers/irqchip/irq-realtek-rtl.c | ||||
|  | ||||
| --- a/drivers/irqchip/Makefile | ||||
| +++ b/drivers/irqchip/Makefile | ||||
| @@ -114,3 +114,4 @@ obj-$(CONFIG_LOONGSON_PCH_PIC)		+= irq-l | ||||
|  obj-$(CONFIG_LOONGSON_PCH_MSI)		+= irq-loongson-pch-msi.o | ||||
|  obj-$(CONFIG_MST_IRQ)			+= irq-mst-intc.o | ||||
|  obj-$(CONFIG_SL28CPLD_INTC)		+= irq-sl28cpld.o | ||||
| +obj-$(CONFIG_MACH_REALTEK_RTL)		+= irq-realtek-rtl.o | ||||
| --- /dev/null | ||||
| +++ b/drivers/irqchip/irq-realtek-rtl.c | ||||
| @@ -0,0 +1,180 @@ | ||||
| +// SPDX-License-Identifier: GPL-2.0-only | ||||
| +/* | ||||
| + * Copyright (C) 2020 Birger Koblitz <mail@birger-koblitz.de> | ||||
| + * Copyright (C) 2020 Bert Vermeulen <bert@biot.com> | ||||
| + * Copyright (C) 2020 John Crispin <john@phrozen.org> | ||||
| + */ | ||||
| + | ||||
| +#include <linux/of_irq.h> | ||||
| +#include <linux/irqchip.h> | ||||
| +#include <linux/spinlock.h> | ||||
| +#include <linux/of_address.h> | ||||
| +#include <linux/irqchip/chained_irq.h> | ||||
| + | ||||
| +/* Global Interrupt Mask Register */ | ||||
| +#define RTL_ICTL_GIMR		0x00 | ||||
| +/* Global Interrupt Status Register */ | ||||
| +#define RTL_ICTL_GISR		0x04 | ||||
| +/* Interrupt Routing Registers */ | ||||
| +#define RTL_ICTL_IRR0		0x08 | ||||
| +#define RTL_ICTL_IRR1		0x0c | ||||
| +#define RTL_ICTL_IRR2		0x10 | ||||
| +#define RTL_ICTL_IRR3		0x14 | ||||
| + | ||||
| +#define REG(x)		(realtek_ictl_base + x) | ||||
| + | ||||
| +static DEFINE_RAW_SPINLOCK(irq_lock); | ||||
| +static void __iomem *realtek_ictl_base; | ||||
| + | ||||
| +static void realtek_ictl_unmask_irq(struct irq_data *i) | ||||
| +{ | ||||
| +	unsigned long flags; | ||||
| +	u32 value; | ||||
| + | ||||
| +	raw_spin_lock_irqsave(&irq_lock, flags); | ||||
| + | ||||
| +	value = readl(REG(RTL_ICTL_GIMR)); | ||||
| +	value |= BIT(i->hwirq); | ||||
| +	writel(value, REG(RTL_ICTL_GIMR)); | ||||
| + | ||||
| +	raw_spin_unlock_irqrestore(&irq_lock, flags); | ||||
| +} | ||||
| + | ||||
| +static void realtek_ictl_mask_irq(struct irq_data *i) | ||||
| +{ | ||||
| +	unsigned long flags; | ||||
| +	u32 value; | ||||
| + | ||||
| +	raw_spin_lock_irqsave(&irq_lock, flags); | ||||
| + | ||||
| +	value = readl(REG(RTL_ICTL_GIMR)); | ||||
| +	value &= ~BIT(i->hwirq); | ||||
| +	writel(value, REG(RTL_ICTL_GIMR)); | ||||
| + | ||||
| +	raw_spin_unlock_irqrestore(&irq_lock, flags); | ||||
| +} | ||||
| + | ||||
| +static struct irq_chip realtek_ictl_irq = { | ||||
| +	.name = "realtek-rtl-intc", | ||||
| +	.irq_mask = realtek_ictl_mask_irq, | ||||
| +	.irq_unmask = realtek_ictl_unmask_irq, | ||||
| +}; | ||||
| + | ||||
| +static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) | ||||
| +{ | ||||
| +	irq_set_chip_and_handler(hw, &realtek_ictl_irq, handle_level_irq); | ||||
| + | ||||
| +	return 0; | ||||
| +} | ||||
| + | ||||
| +static const struct irq_domain_ops irq_domain_ops = { | ||||
| +	.map = intc_map, | ||||
| +	.xlate = irq_domain_xlate_onecell, | ||||
| +}; | ||||
| + | ||||
| +static void realtek_irq_dispatch(struct irq_desc *desc) | ||||
| +{ | ||||
| +	struct irq_chip *chip = irq_desc_get_chip(desc); | ||||
| +	struct irq_domain *domain; | ||||
| +	unsigned int pending; | ||||
| + | ||||
| +	chained_irq_enter(chip, desc); | ||||
| +	pending = readl(REG(RTL_ICTL_GIMR)) & readl(REG(RTL_ICTL_GISR)); | ||||
| +	if (unlikely(!pending)) { | ||||
| +		spurious_interrupt(); | ||||
| +		goto out; | ||||
| +	} | ||||
| +	domain = irq_desc_get_handler_data(desc); | ||||
| +	generic_handle_irq(irq_find_mapping(domain, __ffs(pending))); | ||||
| + | ||||
| +out: | ||||
| +	chained_irq_exit(chip, desc); | ||||
| +} | ||||
| + | ||||
| +/* | ||||
| + * SoC interrupts are cascaded to MIPS CPU interrupts according to the | ||||
| + * interrupt-map in the device tree. Each SoC interrupt gets 4 bits for | ||||
| + * the CPU interrupt in an Interrupt Routing Register. Max 32 SoC interrupts | ||||
| + * thus go into 4 IRRs. | ||||
| + */ | ||||
| +static int __init map_interrupts(struct device_node *node, struct irq_domain *domain) | ||||
| +{ | ||||
| +	struct device_node *cpu_ictl; | ||||
| +	const __be32 *imap; | ||||
| +	u32 imaplen, soc_int, cpu_int, tmp, regs[4]; | ||||
| +	int ret, i, irr_regs[] = { | ||||
| +		RTL_ICTL_IRR3, | ||||
| +		RTL_ICTL_IRR2, | ||||
| +		RTL_ICTL_IRR1, | ||||
| +		RTL_ICTL_IRR0, | ||||
| +	}; | ||||
| +	u8 mips_irqs_set; | ||||
| + | ||||
| +	ret = of_property_read_u32(node, "#address-cells", &tmp); | ||||
| +	if (ret || tmp) | ||||
| +		return -EINVAL; | ||||
| + | ||||
| +	imap = of_get_property(node, "interrupt-map", &imaplen); | ||||
| +	if (!imap || imaplen % 3) | ||||
| +		return -EINVAL; | ||||
| + | ||||
| +	mips_irqs_set = 0; | ||||
| +	memset(regs, 0, sizeof(regs)); | ||||
| +	for (i = 0; i < imaplen; i += 3 * sizeof(u32)) { | ||||
| +		soc_int = be32_to_cpup(imap); | ||||
| +		if (soc_int > 31) | ||||
| +			return -EINVAL; | ||||
| + | ||||
| +		cpu_ictl = of_find_node_by_phandle(be32_to_cpup(imap + 1)); | ||||
| +		if (!cpu_ictl) | ||||
| +			return -EINVAL; | ||||
| +		ret = of_property_read_u32(cpu_ictl, "#interrupt-cells", &tmp); | ||||
| +		if (ret || tmp != 1) | ||||
| +			return -EINVAL; | ||||
| +		of_node_put(cpu_ictl); | ||||
| + | ||||
| +		cpu_int = be32_to_cpup(imap + 2); | ||||
| +		if (cpu_int > 7) | ||||
| +			return -EINVAL; | ||||
| + | ||||
| +		if (!(mips_irqs_set & BIT(cpu_int))) { | ||||
| +			irq_set_chained_handler_and_data(cpu_int, realtek_irq_dispatch, | ||||
| +							 domain); | ||||
| +			mips_irqs_set |= BIT(cpu_int); | ||||
| +		} | ||||
| + | ||||
| +		regs[(soc_int * 4) / 32] |= cpu_int << (soc_int * 4) % 32; | ||||
| +		imap += 3; | ||||
| +	} | ||||
| + | ||||
| +	for (i = 0; i < 4; i++) | ||||
| +		writel(regs[i], REG(irr_regs[i])); | ||||
| + | ||||
| +	return 0; | ||||
| +} | ||||
| + | ||||
| +static int __init realtek_rtl_of_init(struct device_node *node, struct device_node *parent) | ||||
| +{ | ||||
| +	struct irq_domain *domain; | ||||
| +	int ret; | ||||
| + | ||||
| +	realtek_ictl_base = of_iomap(node, 0); | ||||
| +	if (!realtek_ictl_base) | ||||
| +		return -ENXIO; | ||||
| + | ||||
| +	/* Disable all cascaded interrupts */ | ||||
| +	writel(0, REG(RTL_ICTL_GIMR)); | ||||
| + | ||||
| +	domain = irq_domain_add_simple(node, 32, 0, | ||||
| +				       &irq_domain_ops, NULL); | ||||
| + | ||||
| +	ret = map_interrupts(node, domain); | ||||
| +	if (ret) { | ||||
| +		pr_err("invalid interrupt map\n"); | ||||
| +		return ret; | ||||
| +	} | ||||
| + | ||||
| +	return 0; | ||||
| +} | ||||
| + | ||||
| +IRQCHIP_DECLARE(realtek_rtl_intc, "realtek,rtl-intc", realtek_rtl_of_init); | ||||
| @@ -0,0 +1,8 @@ | ||||
| --- a/drivers/irqchip/Makefile | ||||
| +++ b/drivers/irqchip/Makefile | ||||
| @@ -114,4 +114,4 @@ obj-$(CONFIG_LOONGSON_PCH_PIC)		+= irq-l | ||||
|  obj-$(CONFIG_LOONGSON_PCH_MSI)		+= irq-loongson-pch-msi.o | ||||
|  obj-$(CONFIG_MST_IRQ)			+= irq-mst-intc.o | ||||
|  obj-$(CONFIG_SL28CPLD_INTC)		+= irq-sl28cpld.o | ||||
| -obj-$(CONFIG_MACH_REALTEK_RTL)		+= irq-realtek-rtl.o | ||||
| +obj-$(CONFIG_RTL838X)			+= irq-realtek-rtl.o | ||||
		Reference in New Issue
	
	Block a user