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