All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/2] Realtek RTL838x/RTL839x interrupt controller driver
@ 2021-01-22 20:42 Bert Vermeulen
  2021-01-22 20:42 ` [PATCH v4 1/2] dt-bindings: interrupt-controller: Add Realtek RTL838x/RTL839x support Bert Vermeulen
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Bert Vermeulen @ 2021-01-22 20:42 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Birger Koblitz,
	Bert Vermeulen, John Crispin, linux-kernel, devicetree

v4:
- Disable cascaded interrupts before mapping, not after.
- Set chained handlers as interrupt mappings are read, instead of beforehand.
- Removed timer interrupt clear.

v3:
- Fixed syntax and maxItems problems in DT bindings.

v2:
- Addressed all comments by Marc Zyngier.
- Moved interrupt routing symbols to device tree interrupt-map. Parsing
  is done similar to the renesas,rza1-irqc driver.


Bert Vermeulen (2):
  dt-bindings: interrupt-controller: Add Realtek RTL838x/RTL839x support
  irqchip: Add support for Realtek RTL838x/RTL839x interrupt controller

 .../realtek,rtl-intc.yaml                     |  57 ++++++
 drivers/irqchip/Makefile                      |   1 +
 drivers/irqchip/irq-realtek-rtl.c             | 180 ++++++++++++++++++
 3 files changed, 238 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/realtek,rtl-intc.yaml
 create mode 100644 drivers/irqchip/irq-realtek-rtl.c

-- 
2.25.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v4 1/2] dt-bindings: interrupt-controller: Add Realtek RTL838x/RTL839x support
  2021-01-22 20:42 [PATCH v4 0/2] Realtek RTL838x/RTL839x interrupt controller driver Bert Vermeulen
@ 2021-01-22 20:42 ` Bert Vermeulen
  2021-02-04 16:02   ` [irqchip: irq/irqchip-next] " irqchip-bot for Bert Vermeulen
  2021-01-22 20:42 ` [PATCH v4 2/2] irqchip: Add support for Realtek RTL838x/RTL839x interrupt controller Bert Vermeulen
  2021-02-04 15:56 ` [PATCH v4 0/2] Realtek RTL838x/RTL839x interrupt controller driver Marc Zyngier
  2 siblings, 1 reply; 7+ messages in thread
From: Bert Vermeulen @ 2021-01-22 20:42 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Birger Koblitz,
	Bert Vermeulen, John Crispin, linux-kernel, devicetree
  Cc: Rob Herring

Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Bert Vermeulen <bert@biot.com>
---
 .../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 000000000000..9e76fff20323
--- /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>;
+    };
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v4 2/2] irqchip: Add support for Realtek RTL838x/RTL839x interrupt controller
  2021-01-22 20:42 [PATCH v4 0/2] Realtek RTL838x/RTL839x interrupt controller driver Bert Vermeulen
  2021-01-22 20:42 ` [PATCH v4 1/2] dt-bindings: interrupt-controller: Add Realtek RTL838x/RTL839x support Bert Vermeulen
@ 2021-01-22 20:42 ` Bert Vermeulen
  2021-02-04  8:41   ` John Crispin
  2021-02-04 16:02   ` [irqchip: irq/irqchip-next] " irqchip-bot for Bert Vermeulen
  2021-02-04 15:56 ` [PATCH v4 0/2] Realtek RTL838x/RTL839x interrupt controller driver Marc Zyngier
  2 siblings, 2 replies; 7+ messages in thread
From: Bert Vermeulen @ 2021-01-22 20:42 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Birger Koblitz,
	Bert Vermeulen, John Crispin, linux-kernel, devicetree

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>
---
 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

diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 0ac93bfaec61..4fc1086bed7e 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -113,3 +113,4 @@ obj-$(CONFIG_LOONGSON_PCH_PIC)		+= irq-loongson-pch-pic.o
 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
diff --git a/drivers/irqchip/irq-realtek-rtl.c b/drivers/irqchip/irq-realtek-rtl.c
new file mode 100644
index 000000000000..b57c67dfab5b
--- /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);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v4 2/2] irqchip: Add support for Realtek RTL838x/RTL839x interrupt controller
  2021-01-22 20:42 ` [PATCH v4 2/2] irqchip: Add support for Realtek RTL838x/RTL839x interrupt controller Bert Vermeulen
@ 2021-02-04  8:41   ` John Crispin
  2021-02-04 16:02   ` [irqchip: irq/irqchip-next] " irqchip-bot for Bert Vermeulen
  1 sibling, 0 replies; 7+ messages in thread
From: John Crispin @ 2021-02-04  8:41 UTC (permalink / raw)
  To: Bert Vermeulen, Thomas Gleixner, Marc Zyngier, Rob Herring,
	Birger Koblitz, linux-kernel, devicetree


On 22.01.21 21:42, Bert Vermeulen wrote:
> 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>

Thanks !

> ---
>   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
>
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index 0ac93bfaec61..4fc1086bed7e 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -113,3 +113,4 @@ obj-$(CONFIG_LOONGSON_PCH_PIC)		+= irq-loongson-pch-pic.o
>   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
> diff --git a/drivers/irqchip/irq-realtek-rtl.c b/drivers/irqchip/irq-realtek-rtl.c
> new file mode 100644
> index 000000000000..b57c67dfab5b
> --- /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);

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v4 0/2] Realtek RTL838x/RTL839x interrupt controller driver
  2021-01-22 20:42 [PATCH v4 0/2] Realtek RTL838x/RTL839x interrupt controller driver Bert Vermeulen
  2021-01-22 20:42 ` [PATCH v4 1/2] dt-bindings: interrupt-controller: Add Realtek RTL838x/RTL839x support Bert Vermeulen
  2021-01-22 20:42 ` [PATCH v4 2/2] irqchip: Add support for Realtek RTL838x/RTL839x interrupt controller Bert Vermeulen
@ 2021-02-04 15:56 ` Marc Zyngier
  2 siblings, 0 replies; 7+ messages in thread
From: Marc Zyngier @ 2021-02-04 15:56 UTC (permalink / raw)
  To: Thomas Gleixner, Birger Koblitz, devicetree, John Crispin,
	linux-kernel, Bert Vermeulen, Rob Herring

On Fri, 22 Jan 2021 21:42:22 +0100, Bert Vermeulen wrote:
> v4:
> - Disable cascaded interrupts before mapping, not after.
> - Set chained handlers as interrupt mappings are read, instead of beforehand.
> - Removed timer interrupt clear.
> 
> v3:
> - Fixed syntax and maxItems problems in DT bindings.
> 
> [...]

Applied to irq/irqchip-next, thanks!

[1/2] dt-bindings: interrupt-controller: Add Realtek RTL838x/RTL839x support
      commit: 4a2b92a5d3519fc2c1edda4d4aa0e05bff41e8de
[2/2] irqchip: Add support for Realtek RTL838x/RTL839x interrupt controller
      commit: 9f3a0f34b84ad1b9a8f2bdae44b66f16685b2143

Cheers,

	M.
-- 
Without deviation from the norm, progress is not possible.



^ permalink raw reply	[flat|nested] 7+ messages in thread

* [irqchip: irq/irqchip-next] irqchip: Add support for Realtek RTL838x/RTL839x interrupt controller
  2021-01-22 20:42 ` [PATCH v4 2/2] irqchip: Add support for Realtek RTL838x/RTL839x interrupt controller Bert Vermeulen
  2021-02-04  8:41   ` John Crispin
@ 2021-02-04 16:02   ` irqchip-bot for Bert Vermeulen
  1 sibling, 0 replies; 7+ messages in thread
From: irqchip-bot for Bert Vermeulen @ 2021-02-04 16:02 UTC (permalink / raw)
  To: linux-kernel
  Cc: Bert Vermeulen, Birger Koblitz, John Crispin, Marc Zyngier, tglx

The following commit has been merged into the irq/irqchip-next branch of irqchip:

Commit-ID:     9f3a0f34b84ad1b9a8f2bdae44b66f16685b2143
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms/9f3a0f34b84ad1b9a8f2bdae44b66f16685b2143
Author:        Bert Vermeulen <bert@biot.com>
AuthorDate:    Fri, 22 Jan 2021 21:42:24 +01:00
Committer:     Marc Zyngier <maz@kernel.org>
CommitterDate: Thu, 04 Feb 2021 10:36:15 

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

diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 2a1994d..c59b95a 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -112,3 +112,4 @@ obj-$(CONFIG_LOONGSON_PCH_PIC)		+= irq-loongson-pch-pic.o
 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
diff --git a/drivers/irqchip/irq-realtek-rtl.c b/drivers/irqchip/irq-realtek-rtl.c
new file mode 100644
index 0000000..b57c67d
--- /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);

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [irqchip: irq/irqchip-next] dt-bindings: interrupt-controller: Add Realtek RTL838x/RTL839x support
  2021-01-22 20:42 ` [PATCH v4 1/2] dt-bindings: interrupt-controller: Add Realtek RTL838x/RTL839x support Bert Vermeulen
@ 2021-02-04 16:02   ` irqchip-bot for Bert Vermeulen
  0 siblings, 0 replies; 7+ messages in thread
From: irqchip-bot for Bert Vermeulen @ 2021-02-04 16:02 UTC (permalink / raw)
  To: linux-kernel; +Cc: Rob Herring, Bert Vermeulen, Marc Zyngier, tglx

The following commit has been merged into the irq/irqchip-next branch of irqchip:

Commit-ID:     4a2b92a5d3519fc2c1edda4d4aa0e05bff41e8de
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms/4a2b92a5d3519fc2c1edda4d4aa0e05bff41e8de
Author:        Bert Vermeulen <bert@biot.com>
AuthorDate:    Fri, 22 Jan 2021 21:42:23 +01:00
Committer:     Marc Zyngier <maz@kernel.org>
CommitterDate: Thu, 04 Feb 2021 10:36:15 

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
---
 Documentation/devicetree/bindings/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 0000000..9e76fff
--- /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>;
+    };

^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-02-04 16:06 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-22 20:42 [PATCH v4 0/2] Realtek RTL838x/RTL839x interrupt controller driver Bert Vermeulen
2021-01-22 20:42 ` [PATCH v4 1/2] dt-bindings: interrupt-controller: Add Realtek RTL838x/RTL839x support Bert Vermeulen
2021-02-04 16:02   ` [irqchip: irq/irqchip-next] " irqchip-bot for Bert Vermeulen
2021-01-22 20:42 ` [PATCH v4 2/2] irqchip: Add support for Realtek RTL838x/RTL839x interrupt controller Bert Vermeulen
2021-02-04  8:41   ` John Crispin
2021-02-04 16:02   ` [irqchip: irq/irqchip-next] " irqchip-bot for Bert Vermeulen
2021-02-04 15:56 ` [PATCH v4 0/2] Realtek RTL838x/RTL839x interrupt controller driver Marc Zyngier

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.