* [PATCH v3 0/5] arm64: Realtek RTD1195/RTD1295 IRQ mux
@ 2017-10-17 12:47 Andreas Färber
2017-10-17 12:47 ` [PATCH v3 1/5] dt-bindings: interrupt-controller: Add Realtek RTD1295 Andreas Färber
` (4 more replies)
0 siblings, 5 replies; 8+ messages in thread
From: Andreas Färber @ 2017-10-17 12:47 UTC (permalink / raw)
To: linux-arm-kernel
Hello,
This series adds two IRQ muxes for the Realtek RTD1295 and RTD1195 SoCs.
The implementation is based on register offsets seen in the vendor DT,
split up into two separate nodes, as well as code from QNAP's rtk119x and
Synology's RTD1293/96 GPL code dumps.
v3 does various cleanups, renames variables, reworks unmask vs. enable/disable
and adds an isr/scpu_int_en map as well as full RTD1195 support.
More experimental patches at:
https://github.com/afaerber/linux/commits/rtd1295-next
Have a lot of fun!
Cheers,
Andreas
v2 -> v3:
* Rebased, adding nodes to rtd129x.dtsi instead of rtd1295.dtsi
* Adopted {readl,writel}_relaxed() (Marc)
* Adopted spin_lock_irqsave() (Marc)
* Implemented RTD1195
* Implemented mapping for non-linear bits such as i2c3
v1 -> v2:
* Rebased, avoiding dependency on reset series for DT nodes
* Don't forward set_affinity to GIC (Marc)
* Added more spinlocks (Marc)
* Code cleanups
* Investigated quirk
* Fixed spinlock initialization (Andrew)
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Roc He <hepeng@zidoo.tv>
Cc: ??? <jiang.liqin@geniatech.com>
Cc: devicetree at vger.kernel.org
Cc: Andrew Lunn <andrew@lunn.ch>
Andreas F?rber (5):
dt-bindings: interrupt-controller: Add Realtek RTD1295
irqchip: Add Realtek RTD1295 mux driver
arm64: dts: realtek: Add irq mux to RTD129x
dt-bindings: interrupt-controller: Document RTD1195
irqchip: rtd119x: Add RTD1195 definitions
.../interrupt-controller/realtek,rtd119x-mux.txt | 25 ++
arch/arm64/boot/dts/realtek/rtd129x.dtsi | 22 ++
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-rtd119x-mux.c | 388 +++++++++++++++++++++
4 files changed, 436 insertions(+)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/realtek,rtd119x-mux.txt
create mode 100644 drivers/irqchip/irq-rtd119x-mux.c
--
2.13.6
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3 1/5] dt-bindings: interrupt-controller: Add Realtek RTD1295
2017-10-17 12:47 [PATCH v3 0/5] arm64: Realtek RTD1195/RTD1295 IRQ mux Andreas Färber
@ 2017-10-17 12:47 ` Andreas Färber
2017-10-17 12:47 ` [PATCH v3 2/5] irqchip: Add Realtek RTD1295 mux driver Andreas Färber
` (3 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Andreas Färber @ 2017-10-17 12:47 UTC (permalink / raw)
To: linux-arm-kernel
Add binding for Realtek RTD1295 IRQ mux.
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Andreas F?rber <afaerber@suse.de>
---
v2 -> v3:
* Renamed non-iso irq mux to "misc" for clarity
v1 -> v2:
* Dropped reference to common interrupt.txt bindings (Rob)
.../interrupt-controller/realtek,rtd119x-mux.txt | 23 ++++++++++++++++++++++
1 file changed, 23 insertions(+)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/realtek,rtd119x-mux.txt
diff --git a/Documentation/devicetree/bindings/interrupt-controller/realtek,rtd119x-mux.txt b/Documentation/devicetree/bindings/interrupt-controller/realtek,rtd119x-mux.txt
new file mode 100644
index 000000000000..f39ce341adbd
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/realtek,rtd119x-mux.txt
@@ -0,0 +1,23 @@
+Realtek RTD119x/129x IRQ Mux Controller
+=======================================
+
+Required properties:
+
+- compatible : Should be one of the following:
+ - "realtek,rtd1295-misc-irq-mux"
+ - "realtek,rtd1295-iso-irq-mux"
+- reg : Specifies base physical address and size of the registers.
+- interrupts : Specifies the interrupt line which is mux'ed.
+- interrupt-controller : Presence indicates the node as interrupt controller.
+- #interrupt-cells : Shall be 1. See common bindings in interrupt.txt.
+
+
+Example:
+
+ interrupt-controller at 98007000 {
+ compatible = "realtek,rtd1295-iso-irq-mux";
+ reg = <0x98007000 0x100>;
+ interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
--
2.13.6
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 2/5] irqchip: Add Realtek RTD1295 mux driver
2017-10-17 12:47 [PATCH v3 0/5] arm64: Realtek RTD1195/RTD1295 IRQ mux Andreas Färber
2017-10-17 12:47 ` [PATCH v3 1/5] dt-bindings: interrupt-controller: Add Realtek RTD1295 Andreas Färber
@ 2017-10-17 12:47 ` Andreas Färber
2017-10-17 13:56 ` Thomas Gleixner
2017-10-17 12:47 ` [PATCH v3 3/5] arm64: dts: realtek: Add irq mux to RTD129x Andreas Färber
` (2 subsequent siblings)
4 siblings, 1 reply; 8+ messages in thread
From: Andreas Färber @ 2017-10-17 12:47 UTC (permalink / raw)
To: linux-arm-kernel
This irq mux driver implements the RTD1295 SoC's non-linear mapping
between status and enable bits.
Based in part on QNAP's arch/arm/mach-rtk119x/rtk_irq_mux.c and
Synology's drivers/irqchip/irq-rtk.c code.
Signed-off-by: Andreas F?rber <afaerber@suse.de>
---
v2 -> v3:
* Adopted spin_lock_irq{save,restore}() (Marc)
* Adopted single-write masking (Marc)
* Adopted misc compatible string
* Introduced explicit bit mapping
* Adopted looped processing of pending interrupts (Marc)
* Replaced unmask implementation with UMSK_ISR write
* Introduced enable/disable ops and dropped no longer needed UART0 quirk
v1 -> v2:
* Renamed struct fields to avoid ambiguity (Marc)
* Refactored offset lookup to avoid per-compatible init functions
* Inserted white lines to clarify balanced locking (Marc)
* Dropped forwarding of set_affinity to GIC (Marc)
* Added spinlocks for consistency (Marc)
* Limited initialization quirk to iso mux
* Fixed spinlock initialization (Andrew)
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-rtd119x-mux.c | 291 ++++++++++++++++++++++++++++++++++++++
2 files changed, 292 insertions(+)
create mode 100644 drivers/irqchip/irq-rtd119x-mux.c
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 845abc107ad5..99a95428ac9d 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -79,3 +79,4 @@ obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o
obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o
obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o
obj-$(CONFIG_IRQ_UNIPHIER_AIDET) += irq-uniphier-aidet.o
+obj-$(CONFIG_ARCH_REALTEK) += irq-rtd119x-mux.o
diff --git a/drivers/irqchip/irq-rtd119x-mux.c b/drivers/irqchip/irq-rtd119x-mux.c
new file mode 100644
index 000000000000..ad6e2093fcd3
--- /dev/null
+++ b/drivers/irqchip/irq-rtd119x-mux.c
@@ -0,0 +1,291 @@
+/*
+ * Realtek RTD129x IRQ mux
+ *
+ * Copyright (c) 2017 Andreas F?rber
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <linux/io.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+
+struct rtd119x_irq_mux_info {
+ unsigned isr_offset;
+ unsigned umsk_isr_offset;
+ unsigned scpu_int_en_offset;
+ const u32 *isr_to_scpu_int_en_mask;
+};
+
+struct rtd119x_irq_mux_data {
+ void __iomem *reg_isr;
+ void __iomem *reg_umsk_isr;
+ void __iomem *reg_scpu_int_en;
+ const struct rtd119x_irq_mux_info *info;
+ int irq;
+ struct irq_domain *domain;
+ spinlock_t lock;
+};
+
+static void rtd119x_mux_irq_handle(struct irq_desc *desc)
+{
+ struct rtd119x_irq_mux_data *data = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ u32 scpu_int_en, isr, mask;
+ int ret, i;
+
+ chained_irq_enter(chip, desc);
+
+ scpu_int_en = readl_relaxed(data->reg_scpu_int_en);
+ isr = readl_relaxed(data->reg_isr);
+
+ for (i = 0; i < 32; i++) {
+ if (!(isr & BIT(i)))
+ continue;
+
+ mask = data->info->isr_to_scpu_int_en_mask[i];
+ if (!(scpu_int_en & mask))
+ continue;
+
+ ret = generic_handle_irq(irq_find_mapping(data->domain, i));
+ if (ret == 0)
+ writel_relaxed(BIT(i), data->reg_isr);
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static void rtd119x_mux_mask_irq(struct irq_data *data)
+{
+ struct rtd119x_irq_mux_data *mux_data = irq_data_get_irq_chip_data(data);
+
+ writel_relaxed(BIT(data->hwirq), mux_data->reg_isr);
+}
+
+static void rtd119x_mux_unmask_irq(struct irq_data *data)
+{
+ struct rtd119x_irq_mux_data *mux_data = irq_data_get_irq_chip_data(data);
+
+ writel_relaxed(BIT(data->hwirq), mux_data->reg_umsk_isr);
+}
+
+static void rtd119x_mux_enable_irq(struct irq_data *data)
+{
+ struct rtd119x_irq_mux_data *mux_data = irq_data_get_irq_chip_data(data);
+ unsigned long flags;
+ u32 scpu_int_en, mask;
+
+ mask = mux_data->info->isr_to_scpu_int_en_mask[data->hwirq];
+ if (!mask)
+ return;
+
+ spin_lock_irqsave(&mux_data->lock, flags);
+
+ scpu_int_en = readl_relaxed(mux_data->reg_scpu_int_en);
+ scpu_int_en |= mask;
+ writel_relaxed(scpu_int_en, mux_data->reg_scpu_int_en);
+
+ spin_unlock_irqrestore(&mux_data->lock, flags);
+}
+
+static void rtd119x_mux_disable_irq(struct irq_data *data)
+{
+ struct rtd119x_irq_mux_data *mux_data = irq_data_get_irq_chip_data(data);
+ unsigned long flags;
+ u32 scpu_int_en, mask;
+
+ mask = mux_data->info->isr_to_scpu_int_en_mask[data->hwirq];
+ if (!mask)
+ return;
+
+ spin_lock_irqsave(&mux_data->lock, flags);
+
+ scpu_int_en = readl_relaxed(mux_data->reg_scpu_int_en);
+ scpu_int_en &= ~mask;
+ writel_relaxed(scpu_int_en, mux_data->reg_scpu_int_en);
+
+ spin_unlock_irqrestore(&mux_data->lock, flags);
+}
+
+static int rtd119x_mux_set_affinity(struct irq_data *d,
+ const struct cpumask *mask_val, bool force)
+{
+ /* Forwarding the affinity to the parent would affect all 32 interrupts. */
+ return -EINVAL;
+}
+
+static struct irq_chip rtd119x_mux_irq_chip = {
+ .name = "rtd119x-mux",
+ .irq_mask = rtd119x_mux_mask_irq,
+ .irq_unmask = rtd119x_mux_unmask_irq,
+ .irq_enable = rtd119x_mux_enable_irq,
+ .irq_disable = rtd119x_mux_disable_irq,
+ .irq_set_affinity = rtd119x_mux_set_affinity,
+};
+
+static int rtd119x_mux_irq_domain_map(struct irq_domain *d,
+ unsigned int irq, irq_hw_number_t hw)
+{
+ struct rtd119x_irq_mux_data *data = d->host_data;
+
+ irq_set_chip_and_handler(irq, &rtd119x_mux_irq_chip, handle_level_irq);
+ irq_set_chip_data(irq, data);
+ irq_set_probe(irq);
+
+ return 0;
+}
+
+static struct irq_domain_ops rtd119x_mux_irq_domain_ops = {
+ .xlate = irq_domain_xlate_onecell,
+ .map = rtd119x_mux_irq_domain_map,
+};
+
+enum rtd129x_iso_isr_bits {
+ RTD1295_ISO_ISR_UR0_SHIFT = 2,
+ RTD1295_ISO_ISR_IRDA_SHIFT = 5,
+ RTD1295_ISO_ISR_I2C0_SHIFT = 8,
+ RTD1295_ISO_ISR_I2C1_SHIFT = 11,
+ RTD1295_ISO_ISR_RTC_HSEC_SHIFT,
+ RTD1295_ISO_ISR_RTC_ALARM_SHIFT,
+ RTD1295_ISO_ISR_GPIOA_SHIFT = 19,
+ RTD1295_ISO_ISR_GPIODA_SHIFT,
+ RTD1295_ISO_ISR_GPHY_DV_SHIFT = 29,
+ RTD1295_ISO_ISR_GPHY_AV_SHIFT,
+ RTD1295_ISO_ISR_I2C1_REQ_SHIFT,
+};
+
+static const u32 rtd129x_iso_isr_to_scpu_int_en_mask[32] = {
+ [RTD1295_ISO_ISR_UR0_SHIFT] = BIT(2),
+ [RTD1295_ISO_ISR_IRDA_SHIFT] = BIT(5),
+ [RTD1295_ISO_ISR_I2C0_SHIFT] = BIT(8),
+ [RTD1295_ISO_ISR_I2C1_SHIFT] = BIT(11),
+ [RTD1295_ISO_ISR_RTC_HSEC_SHIFT] = BIT(12),
+ [RTD1295_ISO_ISR_RTC_ALARM_SHIFT] = BIT(13),
+ [RTD1295_ISO_ISR_GPIOA_SHIFT] = BIT(19),
+ [RTD1295_ISO_ISR_GPIODA_SHIFT] = BIT(20),
+ [RTD1295_ISO_ISR_GPHY_DV_SHIFT] = BIT(29),
+ [RTD1295_ISO_ISR_GPHY_AV_SHIFT] = BIT(30),
+ [RTD1295_ISO_ISR_I2C1_REQ_SHIFT] = BIT(31),
+};
+
+enum rtd129x_misc_isr_bits {
+ RTD1295_ISR_UR1_SHIFT = 3,
+ RTD1295_ISR_UR1_TO_SHIFT = 5,
+ RTD1295_ISR_UR2_SHIFT = 8,
+ RTD1295_ISR_RTC_MIN_SHIFT = 10,
+ RTD1295_ISR_RTC_HOUR_SHIFT = 11,
+ RTD1295_ISR_RTC_DATA_SHIFT = 12,
+ RTD1295_ISR_UR2_TO_SHIFT = 13,
+ RTD1295_ISR_I2C5_SHIFT = 14,
+ RTD1295_ISR_I2C4_SHIFT = 15,
+ RTD1295_ISR_GPIOA_SHIFT = 19,
+ RTD1295_ISR_GPIODA_SHIFT = 20,
+ RTD1295_ISR_LSADC0_SHIFT = 21,
+ RTD1295_ISR_LSADC1_SHIFT = 22,
+ RTD1295_ISR_I2C3_SHIFT = 23,
+ RTD1295_ISR_SC0_SHIFT = 24,
+ RTD1295_ISR_I2C2_SHIFT = 26,
+ RTD1295_ISR_GSPI_SHIFT = 27,
+ RTD1295_ISR_FAN_SHIFT = 29,
+};
+
+static const u32 rtd129x_misc_isr_to_scpu_int_en_mask[32] = {
+ [RTD1295_ISR_UR1_SHIFT] = BIT(3),
+ [RTD1295_ISR_UR1_TO_SHIFT] = BIT(5),
+ [RTD1295_ISR_UR2_TO_SHIFT] = BIT(6),
+ [RTD1295_ISR_UR2_SHIFT] = BIT(7),
+ [RTD1295_ISR_RTC_MIN_SHIFT] = BIT(10),
+ [RTD1295_ISR_RTC_HOUR_SHIFT] = BIT(11),
+ [RTD1295_ISR_RTC_DATA_SHIFT] = BIT(12),
+ [RTD1295_ISR_I2C5_SHIFT] = BIT(14),
+ [RTD1295_ISR_I2C4_SHIFT] = BIT(15),
+ [RTD1295_ISR_GPIOA_SHIFT] = BIT(19),
+ [RTD1295_ISR_GPIODA_SHIFT] = BIT(20),
+ [RTD1295_ISR_LSADC0_SHIFT] = BIT(21),
+ [RTD1295_ISR_LSADC1_SHIFT] = BIT(22),
+ [RTD1295_ISR_SC0_SHIFT] = BIT(24),
+ [RTD1295_ISR_I2C2_SHIFT] = BIT(26),
+ [RTD1295_ISR_GSPI_SHIFT] = BIT(27),
+ [RTD1295_ISR_I2C3_SHIFT] = BIT(28),
+ [RTD1295_ISR_FAN_SHIFT] = BIT(29),
+};
+
+static const struct rtd119x_irq_mux_info rtd129x_iso_irq_mux_info = {
+ .isr_offset = 0x0,
+ .umsk_isr_offset = 0x4,
+ .scpu_int_en_offset = 0x40,
+ .isr_to_scpu_int_en_mask = rtd129x_iso_isr_to_scpu_int_en_mask,
+};
+
+static const struct rtd119x_irq_mux_info rtd129x_misc_irq_mux_info = {
+ .umsk_isr_offset = 0x8,
+ .isr_offset = 0xc,
+ .scpu_int_en_offset = 0x80,
+ .isr_to_scpu_int_en_mask = rtd129x_misc_isr_to_scpu_int_en_mask,
+};
+
+static const struct of_device_id rtd1295_irq_mux_dt_matches[] = {
+ {
+ .compatible = "realtek,rtd1295-iso-irq-mux",
+ .data = &rtd129x_iso_irq_mux_info,
+ }, {
+ .compatible = "realtek,rtd1295-misc-irq-mux",
+ .data = &rtd129x_misc_irq_mux_info,
+ }, {
+ }
+};
+
+static int __init rtd119x_irq_mux_init(struct device_node *node,
+ struct device_node *parent)
+{
+ struct rtd119x_irq_mux_data *data;
+ const struct of_device_id *match;
+ const struct rtd119x_irq_mux_info *info;
+ void __iomem *base;
+
+ match = of_match_node(rtd1295_irq_mux_dt_matches, node);
+ if (!match)
+ return -EINVAL;
+
+ info = match->data;
+ if (!info)
+ return -EINVAL;
+
+ base = of_iomap(node, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->info = info;
+ data->reg_isr = base + info->isr_offset;
+ data->reg_umsk_isr = base + info->umsk_isr_offset;
+ data->reg_scpu_int_en = base + info->scpu_int_en_offset;
+
+ data->irq = irq_of_parse_and_map(node, 0);
+ if (data->irq <= 0) {
+ kfree(data);
+ return -EINVAL;
+ }
+
+ spin_lock_init(&data->lock);
+
+ data->domain = irq_domain_add_linear(node, 32,
+ &rtd119x_mux_irq_domain_ops, data);
+ if (!data->domain) {
+ kfree(data);
+ return -ENOMEM;
+ }
+
+ irq_set_chained_handler_and_data(data->irq, rtd119x_mux_irq_handle, data);
+
+ return 0;
+}
+IRQCHIP_DECLARE(rtd1295_iso_mux, "realtek,rtd1295-iso-irq-mux", rtd119x_irq_mux_init);
+IRQCHIP_DECLARE(rtd1295_misc_mux, "realtek,rtd1295-misc-irq-mux", rtd119x_irq_mux_init);
--
2.13.6
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 3/5] arm64: dts: realtek: Add irq mux to RTD129x
2017-10-17 12:47 [PATCH v3 0/5] arm64: Realtek RTD1195/RTD1295 IRQ mux Andreas Färber
2017-10-17 12:47 ` [PATCH v3 1/5] dt-bindings: interrupt-controller: Add Realtek RTD1295 Andreas Färber
2017-10-17 12:47 ` [PATCH v3 2/5] irqchip: Add Realtek RTD1295 mux driver Andreas Färber
@ 2017-10-17 12:47 ` Andreas Färber
2017-10-17 12:47 ` [PATCH v3 4/5] dt-bindings: interrupt-controller: Document RTD1195 Andreas Färber
2017-10-17 12:47 ` [PATCH v3 5/5] irqchip: rtd119x: Add RTD1195 definitions Andreas Färber
4 siblings, 0 replies; 8+ messages in thread
From: Andreas Färber @ 2017-10-17 12:47 UTC (permalink / raw)
To: linux-arm-kernel
Update UART nodes with interrupts.
Signed-off-by: Andreas F?rber <afaerber@suse.de>
---
v2 -> v3:
* Added nodes to rtd129x.dtsi instead of rtd1295.dtsi
* Adopted misc compatible string
* Renamed node label from irq_mux to misc_irq_mux for clarity
v1 -> v2:
* Rebased
arch/arm64/boot/dts/realtek/rtd129x.dtsi | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/arch/arm64/boot/dts/realtek/rtd129x.dtsi b/arch/arm64/boot/dts/realtek/rtd129x.dtsi
index b9cb92466fc7..bd07194154a4 100644
--- a/arch/arm64/boot/dts/realtek/rtd129x.dtsi
+++ b/arch/arm64/boot/dts/realtek/rtd129x.dtsi
@@ -31,21 +31,41 @@
/* Exclude up to 2 GiB of RAM */
ranges = <0x80000000 0x80000000 0x80000000>;
+ iso_irq_mux: interrupt-controller at 98007000 {
+ compatible = "realtek,rtd1295-iso-irq-mux";
+ reg = <0x98007000 0x100>;
+ interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
uart0: serial at 98007800 {
compatible = "snps,dw-apb-uart";
reg = <0x98007800 0x400>;
reg-shift = <2>;
reg-io-width = <4>;
clock-frequency = <27000000>;
+ interrupt-parent = <&iso_irq_mux>;
+ interrupts = <2>;
status = "disabled";
};
+ misc_irq_mux: interrupt-controller at 9801b000 {
+ compatible = "realtek,rtd1295-misc-irq-mux";
+ reg = <0x9801b000 0x100>;
+ interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
uart1: serial at 9801b200 {
compatible = "snps,dw-apb-uart";
reg = <0x9801b200 0x100>;
reg-shift = <2>;
reg-io-width = <4>;
clock-frequency = <432000000>;
+ interrupt-parent = <&misc_irq_mux>;
+ interrupts = <3>, <5>;
status = "disabled";
};
@@ -55,6 +75,8 @@
reg-shift = <2>;
reg-io-width = <4>;
clock-frequency = <432000000>;
+ interrupt-parent = <&misc_irq_mux>;
+ interrupts = <8>, <13>;
status = "disabled";
};
--
2.13.6
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 4/5] dt-bindings: interrupt-controller: Document RTD1195
2017-10-17 12:47 [PATCH v3 0/5] arm64: Realtek RTD1195/RTD1295 IRQ mux Andreas Färber
` (2 preceding siblings ...)
2017-10-17 12:47 ` [PATCH v3 3/5] arm64: dts: realtek: Add irq mux to RTD129x Andreas Färber
@ 2017-10-17 12:47 ` Andreas Färber
2017-10-24 16:37 ` Rob Herring
2017-10-17 12:47 ` [PATCH v3 5/5] irqchip: rtd119x: Add RTD1195 definitions Andreas Färber
4 siblings, 1 reply; 8+ messages in thread
From: Andreas Färber @ 2017-10-17 12:47 UTC (permalink / raw)
To: linux-arm-kernel
Add compatible strings for Realtek RTD1195.
Signed-off-by: Andreas F?rber <afaerber@suse.de>
---
v3: New
Could be squashed into 1/5 if acked.
.../devicetree/bindings/interrupt-controller/realtek,rtd119x-mux.txt | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/realtek,rtd119x-mux.txt b/Documentation/devicetree/bindings/interrupt-controller/realtek,rtd119x-mux.txt
index f39ce341adbd..67be0653528b 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/realtek,rtd119x-mux.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/realtek,rtd119x-mux.txt
@@ -4,6 +4,8 @@ Realtek RTD119x/129x IRQ Mux Controller
Required properties:
- compatible : Should be one of the following:
+ - "realtek,rtd1195-misc-irq-mux"
+ - "realtek,rtd1195-iso-irq-mux"
- "realtek,rtd1295-misc-irq-mux"
- "realtek,rtd1295-iso-irq-mux"
- reg : Specifies base physical address and size of the registers.
--
2.13.6
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 5/5] irqchip: rtd119x: Add RTD1195 definitions
2017-10-17 12:47 [PATCH v3 0/5] arm64: Realtek RTD1195/RTD1295 IRQ mux Andreas Färber
` (3 preceding siblings ...)
2017-10-17 12:47 ` [PATCH v3 4/5] dt-bindings: interrupt-controller: Document RTD1195 Andreas Färber
@ 2017-10-17 12:47 ` Andreas Färber
4 siblings, 0 replies; 8+ messages in thread
From: Andreas Färber @ 2017-10-17 12:47 UTC (permalink / raw)
To: linux-arm-kernel
Add compatible strings and bit definitions for Realtek RTD1195 SoC.
Signed-off-by: Andreas F?rber <afaerber@suse.de>
---
v3: New
drivers/irqchip/irq-rtd119x-mux.c | 99 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 98 insertions(+), 1 deletion(-)
diff --git a/drivers/irqchip/irq-rtd119x-mux.c b/drivers/irqchip/irq-rtd119x-mux.c
index ad6e2093fcd3..84c592ad7421 100644
--- a/drivers/irqchip/irq-rtd119x-mux.c
+++ b/drivers/irqchip/irq-rtd119x-mux.c
@@ -1,5 +1,5 @@
/*
- * Realtek RTD129x IRQ mux
+ * Realtek RTD119x/RTD129x IRQ mux
*
* Copyright (c) 2017 Andreas F?rber
*
@@ -144,6 +144,81 @@ static struct irq_domain_ops rtd119x_mux_irq_domain_ops = {
.map = rtd119x_mux_irq_domain_map,
};
+enum rtd119x_iso_isr_bits {
+ RTD119X_ISO_ISR_TC3_SHIFT = 1,
+ RTD119X_ISO_ISR_UR0_SHIFT = 2,
+ RTD119X_ISO_ISR_IRDA_SHIFT = 5,
+ RTD119X_ISO_ISR_WDOG_NMI_SHIFT = 7,
+ RTD119X_ISO_ISR_I2C0_SHIFT = 8,
+ RTD119X_ISO_ISR_TC4_SHIFT = 9,
+ RTD119X_ISO_ISR_I2C6_SHIFT = 10,
+ RTD119X_ISO_ISR_RTC_HSEC_SHIFT = 12,
+ RTD119X_ISO_ISR_RTC_ALARM_SHIFT = 13,
+ RTD119X_ISO_ISR_VFD_WDONE_SHIFT = 14,
+ RTD119X_ISO_ISR_VFD_ARDKPADA_SHIFT = 15,
+ RTD119X_ISO_ISR_VFD_ARDKPADDA_SHIFT = 16,
+ RTD119X_ISO_ISR_VFD_ARDSWA_SHIFT = 17,
+ RTD119X_ISO_ISR_VFD_ARDSWDA_SHIFT = 18,
+ RTD119X_ISO_ISR_GPIOA_SHIFT = 19,
+ RTD119X_ISO_ISR_GPIODA_SHIFT = 20,
+ RTD119X_ISO_ISR_CEC_SHIFT = 22,
+};
+
+static const u32 rtd119x_iso_isr_to_scpu_int_en_mask[32] = {
+ [RTD119X_ISO_ISR_UR0_SHIFT] = BIT(2),
+ [RTD119X_ISO_ISR_IRDA_SHIFT] = BIT(5),
+ [RTD119X_ISO_ISR_I2C0_SHIFT] = BIT(8),
+ [RTD119X_ISO_ISR_I2C6_SHIFT] = BIT(10),
+ [RTD119X_ISO_ISR_RTC_HSEC_SHIFT] = BIT(12),
+ [RTD119X_ISO_ISR_RTC_ALARM_SHIFT] = BIT(13),
+ [RTD119X_ISO_ISR_VFD_WDONE_SHIFT] = BIT(14),
+ [RTD119X_ISO_ISR_VFD_ARDKPADA_SHIFT] = BIT(15),
+ [RTD119X_ISO_ISR_VFD_ARDKPADDA_SHIFT] = BIT(16),
+ [RTD119X_ISO_ISR_VFD_ARDSWA_SHIFT] = BIT(17),
+ [RTD119X_ISO_ISR_VFD_ARDSWDA_SHIFT] = BIT(18),
+ [RTD119X_ISO_ISR_GPIOA_SHIFT] = BIT(19),
+ [RTD119X_ISO_ISR_GPIODA_SHIFT] = BIT(20),
+ [RTD119X_ISO_ISR_CEC_SHIFT] = BIT(22),
+};
+
+enum rtd119x_misc_isr_bits {
+ RTD119X_MIS_ISR_WDOG_NMI_SHIFT = 2,
+ RTD119X_MIS_ISR_UR1_SHIFT,
+ RTD119X_MIS_ISR_I2C1_SHIFT,
+ RTD119X_MIS_ISR_UR1_TO_SHIFT,
+ RTD119X_MIS_ISR_TC0_SHIFT,
+ RTD119X_MIS_ISR_TC1_SHIFT,
+ RTD119X_MIS_ISR_RTC_HSEC_SHIFT = 9,
+ RTD119X_MIS_ISR_RTC_MIN_SHIFT,
+ RTD119X_MIS_ISR_RTC_HOUR_SHIFT,
+ RTD119X_MIS_ISR_RTC_DATE_SHIFT,
+ RTD119X_MIS_ISR_I2C5_SHIFT = 14,
+ RTD119X_MIS_ISR_I2C4_SHIFT,
+ RTD119X_MIS_ISR_GPIOA_SHIFT = 19,
+ RTD119X_MIS_ISR_GPIODA_SHIFT,
+ RTD119X_MIS_ISR_LSADC_SHIFT,
+ RTD119X_MIS_ISR_I2C3_SHIFT = 23,
+ RTD119X_MIS_ISR_I2C2_SHIFT = 26,
+ RTD119X_MIS_ISR_GSPI_SHIFT,
+};
+
+static const u32 rtd119x_misc_isr_to_scpu_int_en_mask[32] = {
+ [RTD119X_MIS_ISR_UR1_SHIFT] = BIT(3),
+ [RTD119X_MIS_ISR_I2C1_SHIFT] = BIT(4),
+ [RTD119X_MIS_ISR_UR1_TO_SHIFT] = BIT(5),
+ [RTD119X_MIS_ISR_RTC_MIN_SHIFT] = BIT(10),
+ [RTD119X_MIS_ISR_RTC_HOUR_SHIFT] = BIT(11),
+ [RTD119X_MIS_ISR_RTC_DATE_SHIFT] = BIT(12),
+ [RTD119X_MIS_ISR_I2C5_SHIFT] = BIT(14),
+ [RTD119X_MIS_ISR_I2C4_SHIFT] = BIT(15),
+ [RTD119X_MIS_ISR_GPIOA_SHIFT] = BIT(19),
+ [RTD119X_MIS_ISR_GPIODA_SHIFT] = BIT(20),
+ [RTD119X_MIS_ISR_LSADC_SHIFT] = BIT(21),
+ [RTD119X_MIS_ISR_I2C2_SHIFT] = BIT(26),
+ [RTD119X_MIS_ISR_GSPI_SHIFT] = BIT(27),
+ [RTD119X_MIS_ISR_I2C3_SHIFT] = BIT(28),
+};
+
enum rtd129x_iso_isr_bits {
RTD1295_ISO_ISR_UR0_SHIFT = 2,
RTD1295_ISO_ISR_IRDA_SHIFT = 5,
@@ -214,6 +289,13 @@ static const u32 rtd129x_misc_isr_to_scpu_int_en_mask[32] = {
[RTD1295_ISR_FAN_SHIFT] = BIT(29),
};
+static const struct rtd119x_irq_mux_info rtd119x_iso_irq_mux_info = {
+ .isr_offset = 0x0,
+ .umsk_isr_offset = 0x4,
+ .scpu_int_en_offset = 0x40,
+ .isr_to_scpu_int_en_mask = rtd119x_iso_isr_to_scpu_int_en_mask,
+};
+
static const struct rtd119x_irq_mux_info rtd129x_iso_irq_mux_info = {
.isr_offset = 0x0,
.umsk_isr_offset = 0x4,
@@ -221,6 +303,13 @@ static const struct rtd119x_irq_mux_info rtd129x_iso_irq_mux_info = {
.isr_to_scpu_int_en_mask = rtd129x_iso_isr_to_scpu_int_en_mask,
};
+static const struct rtd119x_irq_mux_info rtd119x_misc_irq_mux_info = {
+ .umsk_isr_offset = 0x8,
+ .isr_offset = 0xc,
+ .scpu_int_en_offset = 0x80,
+ .isr_to_scpu_int_en_mask = rtd119x_misc_isr_to_scpu_int_en_mask,
+};
+
static const struct rtd119x_irq_mux_info rtd129x_misc_irq_mux_info = {
.umsk_isr_offset = 0x8,
.isr_offset = 0xc,
@@ -230,9 +319,15 @@ static const struct rtd119x_irq_mux_info rtd129x_misc_irq_mux_info = {
static const struct of_device_id rtd1295_irq_mux_dt_matches[] = {
{
+ .compatible = "realtek,rtd1195-iso-irq-mux",
+ .data = &rtd119x_iso_irq_mux_info,
+ }, {
.compatible = "realtek,rtd1295-iso-irq-mux",
.data = &rtd129x_iso_irq_mux_info,
}, {
+ .compatible = "realtek,rtd1195-misc-irq-mux",
+ .data = &rtd119x_misc_irq_mux_info,
+ }, {
.compatible = "realtek,rtd1295-misc-irq-mux",
.data = &rtd129x_misc_irq_mux_info,
}, {
@@ -287,5 +382,7 @@ static int __init rtd119x_irq_mux_init(struct device_node *node,
return 0;
}
+IRQCHIP_DECLARE(rtd1195_iso_mux, "realtek,rtd1195-iso-irq-mux", rtd119x_irq_mux_init);
IRQCHIP_DECLARE(rtd1295_iso_mux, "realtek,rtd1295-iso-irq-mux", rtd119x_irq_mux_init);
+IRQCHIP_DECLARE(rtd1195_misc_mux, "realtek,rtd1195-misc-irq-mux", rtd119x_irq_mux_init);
IRQCHIP_DECLARE(rtd1295_misc_mux, "realtek,rtd1295-misc-irq-mux", rtd119x_irq_mux_init);
--
2.13.6
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 2/5] irqchip: Add Realtek RTD1295 mux driver
2017-10-17 12:47 ` [PATCH v3 2/5] irqchip: Add Realtek RTD1295 mux driver Andreas Färber
@ 2017-10-17 13:56 ` Thomas Gleixner
0 siblings, 0 replies; 8+ messages in thread
From: Thomas Gleixner @ 2017-10-17 13:56 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, 17 Oct 2017, Andreas F?rber wrote:
> +
> +struct rtd119x_irq_mux_info {
> + unsigned isr_offset;
> + unsigned umsk_isr_offset;
> + unsigned scpu_int_en_offset;
> + const u32 *isr_to_scpu_int_en_mask;
Please use 'unsigned int' instead of the shorthand 'unsigned' and while at
it make the struct definition tabular. That makes it way simpler to read.
struct rtd119x_irq_mux_info {
unsigned int isr_offset;
unsigned int umsk_isr_offset;
unsigned int scpu_int_en_offset;
const u32 *isr_to_scpu_int_en_mask;
> +};
> +
> +struct rtd119x_irq_mux_data {
> + void __iomem *reg_isr;
> + void __iomem *reg_umsk_isr;
> + void __iomem *reg_scpu_int_en;
> + const struct rtd119x_irq_mux_info *info;
> + int irq;
> + struct irq_domain *domain;
See above.
> + spinlock_t lock;
This wants to be a raw_spinlock_t because it's taken in interrupt disabled
context. Not an issue in mainline, but the RT patchset will barf.
> +};
> +
> +static void rtd119x_mux_irq_handle(struct irq_desc *desc)
> +{
> + struct rtd119x_irq_mux_data *data = irq_desc_get_handler_data(desc);
> + struct irq_chip *chip = irq_desc_get_chip(desc);
> + u32 scpu_int_en, isr, mask;
> + int ret, i;
> +
> + chained_irq_enter(chip, desc);
> +
> + scpu_int_en = readl_relaxed(data->reg_scpu_int_en);
> + isr = readl_relaxed(data->reg_isr);
> +
> + for (i = 0; i < 32; i++) {
> + if (!(isr & BIT(i)))
> + continue;
Not really performance optimal especially if the interrupt is at the end of
the bits. Such a loop should be optimized for a single interrupt because
that's the majority of events.
while (isr) {
i = __ffs(isr);
isr &= ~(1U << i);
Hmm?
> + mask = data->info->isr_to_scpu_int_en_mask[i];
> + if (!(scpu_int_en & mask))
> + continue;
So this catches the case where you get an unmasked interrupt and there is
another pending interrupt in ISR which is masked. See further down for
more comments on this.
> +
> + ret = generic_handle_irq(irq_find_mapping(data->domain, i));
> + if (ret == 0)
Please use the (!ret) shorthand as we normally do in the kernel or simply
get rid of ret completely.
if (!generic_handle_irq(irq_find_mapping(data->domain, i)))
Hmm?
> + writel_relaxed(BIT(i), data->reg_isr);
> + }
> +
> + chained_irq_exit(chip, desc);
> +}
> +static void rtd119x_mux_enable_irq(struct irq_data *data)
> +{
> + struct rtd119x_irq_mux_data *mux_data = irq_data_get_irq_chip_data(data);
> + unsigned long flags;
> + u32 scpu_int_en, mask;
> +
> + mask = mux_data->info->isr_to_scpu_int_en_mask[data->hwirq];
> + if (!mask)
> + return;
> +
> + spin_lock_irqsave(&mux_data->lock, flags);
> +
> + scpu_int_en = readl_relaxed(mux_data->reg_scpu_int_en);
> + scpu_int_en |= mask;
> + writel_relaxed(scpu_int_en, mux_data->reg_scpu_int_en);
So if you make that:
mux_data->scpu_int_en |= mask;
mux_data->scpu_isr_en |= BIT(data->hwirq);
writel_relaxed(mux_data->scpu_int_en, mux_data->reg_scpu_int_en);
Then you have two advantages:
1) You spare the read
2) Because you cache also the isr_en value you can make your demultiplex
routine smarter:
raw_spin_lock(&data->lock);
isr = readl_relaxed(data->reg_isr);
isr &= data->scpu_isr_en;
raw_spin_unlock(&data->lock);
while (isr) {
i = __ffs(isr);
isr &= ~BIT(i);
if (!generic_handle_irq(irq_find_mapping(data->domain, i)))
writel_relaxed(BIT(i), data->reg_isr);
}
See? It clears out the masked interrupts right away from ISR and it avoids
the extra indirection of reading the irq -> mask table potentially several
times in the loop.
> +static int rtd119x_mux_set_affinity(struct irq_data *d,
> + const struct cpumask *mask_val, bool force)
> +{
> + /* Forwarding the affinity to the parent would affect all 32 interrupts. */
> + return -EINVAL;
Why are you implementing that callback at all? The core checks it for NULL
already and returns an appropriate error code if something tries to set the
affinity of such an interrupt.
> +static struct irq_chip rtd119x_mux_irq_chip = {
> + .name = "rtd119x-mux",
> + .irq_mask = rtd119x_mux_mask_irq,
> + .irq_unmask = rtd119x_mux_unmask_irq,
> + .irq_enable = rtd119x_mux_enable_irq,
> + .irq_disable = rtd119x_mux_disable_irq,
> + .irq_set_affinity = rtd119x_mux_set_affinity,
> +};
> +enum rtd129x_iso_isr_bits {
> + RTD1295_ISO_ISR_UR0_SHIFT = 2,
> + RTD1295_ISO_ISR_IRDA_SHIFT = 5,
> + RTD1295_ISO_ISR_I2C0_SHIFT = 8,
> + RTD1295_ISO_ISR_I2C1_SHIFT = 11,
> + RTD1295_ISO_ISR_RTC_HSEC_SHIFT,
> + RTD1295_ISO_ISR_RTC_ALARM_SHIFT,
> + RTD1295_ISO_ISR_GPIOA_SHIFT = 19,
That's really hard to read.
> + RTD1295_ISO_ISR_UR0_SHIFT = 2,
> + RTD1295_ISO_ISR_IRDA_SHIFT = 5,
> + RTD1295_ISO_ISR_I2C0_SHIFT = 8,
> + RTD1295_ISO_ISR_I2C1_SHIFT = 11,
> + RTD1295_ISO_ISR_RTC_HSEC_SHIFT = 12,
> + RTD1295_ISO_ISR_RTC_ALARM_SHIFT = 13,
> + RTD1295_ISO_ISR_GPIOA_SHIFT = 19,
Can you see the difference?
> + RTD1295_ISO_ISR_GPIODA_SHIFT,
> + RTD1295_ISO_ISR_GPHY_DV_SHIFT = 29,
> + RTD1295_ISO_ISR_GPHY_AV_SHIFT,
> + RTD1295_ISO_ISR_I2C1_REQ_SHIFT,
> +};
> +static const struct rtd119x_irq_mux_info rtd129x_iso_irq_mux_info = {
> + .isr_offset = 0x0,
> + .umsk_isr_offset = 0x4,
> + .scpu_int_en_offset = 0x40,
> + .isr_to_scpu_int_en_mask = rtd129x_iso_isr_to_scpu_int_en_mask,
If you make the struct member and the function name less convoluted you
can keep the nice tabular mode.
> +};
> +
> +static const struct rtd119x_irq_mux_info rtd129x_misc_irq_mux_info = {
> + .umsk_isr_offset = 0x8,
> + .isr_offset = 0xc,
> + .scpu_int_en_offset = 0x80,
> + .isr_to_scpu_int_en_mask = rtd129x_misc_isr_to_scpu_int_en_mask,
> +};
> +
> +static const struct of_device_id rtd1295_irq_mux_dt_matches[] = {
> + {
> + .compatible = "realtek,rtd1295-iso-irq-mux",
> + .data = &rtd129x_iso_irq_mux_info,
Tabular again, please
> + }, {
Please make that seperate lines
},
{
So it's visually clear.
> + .compatible = "realtek,rtd1295-misc-irq-mux",
> + .data = &rtd129x_misc_irq_mux_info,
> + }, {
> + }
> +};
> +
> +static int __init rtd119x_irq_mux_init(struct device_node *node,
> + struct device_node *parent)
> +{
> + struct rtd119x_irq_mux_data *data;
> + const struct of_device_id *match;
> + const struct rtd119x_irq_mux_info *info;
> + void __iomem *base;
> +
> + match = of_match_node(rtd1295_irq_mux_dt_matches, node);
> + if (!match)
> + return -EINVAL;
> +
> + info = match->data;
> + if (!info)
> + return -EINVAL;
> +
> + base = of_iomap(node, 0);
> + if (IS_ERR(base))
> + return PTR_ERR(base);
> +
> + data = kzalloc(sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + data->info = info;
> + data->reg_isr = base + info->isr_offset;
If you use tabular initialization then please for all struct members or
none. Inconsistent formatting disturbs the reading flow.
Thanks,
tglx
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3 4/5] dt-bindings: interrupt-controller: Document RTD1195
2017-10-17 12:47 ` [PATCH v3 4/5] dt-bindings: interrupt-controller: Document RTD1195 Andreas Färber
@ 2017-10-24 16:37 ` Rob Herring
0 siblings, 0 replies; 8+ messages in thread
From: Rob Herring @ 2017-10-24 16:37 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Oct 17, 2017 at 02:47:06PM +0200, Andreas F?rber wrote:
> Add compatible strings for Realtek RTD1195.
>
> Signed-off-by: Andreas F?rber <afaerber@suse.de>
> ---
> v3: New
>
> Could be squashed into 1/5 if acked.
Yes.
Acked-by: Rob Herring <robh@kernel.org>
>
> .../devicetree/bindings/interrupt-controller/realtek,rtd119x-mux.txt | 2 ++
> 1 file changed, 2 insertions(+)
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2017-10-24 16:37 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-10-17 12:47 [PATCH v3 0/5] arm64: Realtek RTD1195/RTD1295 IRQ mux Andreas Färber
2017-10-17 12:47 ` [PATCH v3 1/5] dt-bindings: interrupt-controller: Add Realtek RTD1295 Andreas Färber
2017-10-17 12:47 ` [PATCH v3 2/5] irqchip: Add Realtek RTD1295 mux driver Andreas Färber
2017-10-17 13:56 ` Thomas Gleixner
2017-10-17 12:47 ` [PATCH v3 3/5] arm64: dts: realtek: Add irq mux to RTD129x Andreas Färber
2017-10-17 12:47 ` [PATCH v3 4/5] dt-bindings: interrupt-controller: Document RTD1195 Andreas Färber
2017-10-24 16:37 ` Rob Herring
2017-10-17 12:47 ` [PATCH v3 5/5] irqchip: rtd119x: Add RTD1195 definitions Andreas Färber
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox