2013-04-11 13:18:21

by Christian Ruppert

[permalink] [raw]
Subject: [PATCH] irqchip: Add TB10x interrupt controller driver

The SOC interrupt controller driver for the Abilis Systems TB10x series of
SOCs based on ARC700 CPUs.

Signed-off-by: Christian Ruppert <[email protected]>
Signed-off-by: Pierrick Hascoet <[email protected]>
---
.../interrupt-controller/abilis,tb10x_ictl.txt | 38 +++
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-tb10x.c | 254 ++++++++++++++++++++
3 files changed, 293 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x_ictl.txt
create mode 100644 drivers/irqchip/irq-tb10x.c

diff --git a/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x_ictl.txt b/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x_ictl.txt
new file mode 100644
index 0000000..bc292cd
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x_ictl.txt
@@ -0,0 +1,38 @@
+TB10x Top Level Interrupt Controller
+====================================
+
+The Abilis TB10x SOC contains a custom interrupt controller. It performs
+one-to-one mapping of external interrupt sources to CPU interrupts and
+provides support for reconfigurable trigger modes.
+
+Required properties
+-------------------
+
+- compatible: Should be "abilis,tb10x_ictl"
+- reg: specifies physical base address and size of register range.
+- interrupt-congroller: Identifies the node as an interrupt controller.
+- #interrupt cells: Specifies the number of cells used to encode an interrupt
+ source connected to this controller. The value shall be 2.
+- interrupt-parent: Specifies the parent interrupt controller.
+- interrupts: Specifies the list of interrupt lines which are handled by
+ the interrupt controller in the parent controller's notation. Interrupts
+ are mapped one-to-one to parent interrupts.
+
+Example
+-------
+
+intc: interrupt-controller { /* Parent interrupt controller */
+ interrupt-controller;
+ #interrupt-cells = <1>; /* For example below */
+ /* ... */
+};
+
+tb10x_ictl: pic@2000 { /* TB10x interrupt controller */
+ compatible = "abilis,tb10x_ictl";
+ reg = <0x2000 0x20>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupt-parent = <&intc>;
+ interrupts = <5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+ 20 21 22 23 24 25 26 27 28 29 30 31>;
+};
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 98e3b87..ab64cc2 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_METAG) += irq-metag-ext.o
obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi.o
obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
+obj-$(CONFIG_ARC_PLAT_TB10X) += irq-tb10x.o
obj-$(CONFIG_ARM_GIC) += irq-gic.o
obj-$(CONFIG_ARM_VIC) += irq-vic.o
obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o
diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c
new file mode 100644
index 0000000..542de1e
--- /dev/null
+++ b/drivers/irqchip/irq-tb10x.c
@@ -0,0 +1,254 @@
+/*
+ * Abilis Systems interrupt controller driver
+ *
+ * Copyright (C) Abilis Systems 2012
+ *
+ * Author: Christian Ruppert <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include "../../drivers/irqchip/irqchip.h"
+
+#define AB_IRQCTL_INT_ENABLE (0x00)
+#define AB_IRQCTL_INT_STATUS (0x04)
+#define AB_IRQCTL_SRC_MODE (0x08)
+#define AB_IRQCTL_SRC_POLARITY (0x0C)
+#define AB_IRQCTL_INT_MODE (0x10)
+#define AB_IRQCTL_INT_POLARITY (0x14)
+#define AB_IRQCTL_INT_FORCE (0x18)
+
+struct tb10x_ictl {
+ void *base;
+ struct irq_domain *domain;
+};
+
+static inline void ab_irqctl_writereg(struct tb10x_ictl *ictl, u32 reg,
+ u32 val)
+{
+ iowrite32(val, (u32 *)(ictl->base + reg));
+}
+
+static inline u32 ab_irqctl_readreg(struct tb10x_ictl *ictl, u32 reg)
+{
+ return ioread32((u32 *)(ictl->base + reg));
+}
+
+static int tb10x_irq_set_type(struct irq_data *data, unsigned int flow_type)
+{
+ struct tb10x_ictl *ictl = irq_data_get_irq_chip_data(data);
+ unsigned int irq = data->irq;
+ unsigned int hwirq = irqd_to_hwirq(data);
+ uint32_t im, mod, pol;
+
+ im = 1UL << hwirq;
+
+ mod = ab_irqctl_readreg(ictl, AB_IRQCTL_SRC_MODE) | im;
+ pol = ab_irqctl_readreg(ictl, AB_IRQCTL_SRC_POLARITY) | im;
+
+ switch (flow_type & IRQF_TRIGGER_MASK) {
+ case IRQ_TYPE_EDGE_FALLING:
+ pol ^= im;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ mod ^= im;
+ break;
+ case IRQ_TYPE_NONE:
+ flow_type = IRQ_TYPE_LEVEL_LOW;
+ case IRQ_TYPE_LEVEL_LOW:
+ mod ^= im;
+ pol ^= im;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ break;
+ default:
+ pr_err("%s: Cannot assign multiple trigger modes to IRQ %d.\n",
+ __func__, irq);
+ return -EBADR;
+ }
+
+ irqd_set_trigger_type(data, flow_type);
+
+ ab_irqctl_writereg(ictl, AB_IRQCTL_SRC_MODE, mod);
+ ab_irqctl_writereg(ictl, AB_IRQCTL_SRC_POLARITY, pol);
+ ab_irqctl_writereg(ictl, AB_IRQCTL_INT_STATUS, im);
+
+ if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+ __irq_set_handler_locked(irq, handle_level_irq);
+ else
+ __irq_set_handler_locked(irq, handle_edge_irq);
+
+ return IRQ_SET_MASK_OK;
+}
+
+static void tb10x_irq_unmask(struct irq_data *data)
+{
+ struct tb10x_ictl *ictl = irq_data_get_irq_chip_data(data);
+ unsigned int hwirq = irqd_to_hwirq(data);
+
+ ab_irqctl_writereg(ictl, AB_IRQCTL_INT_ENABLE,
+ ab_irqctl_readreg(ictl, AB_IRQCTL_INT_ENABLE) | (1 << hwirq));
+}
+
+static void tb10x_irq_mask(struct irq_data *data)
+{
+ struct tb10x_ictl *ictl = irq_data_get_irq_chip_data(data);
+ unsigned int hwirq = irqd_to_hwirq(data);
+
+ ab_irqctl_writereg(ictl, AB_IRQCTL_INT_ENABLE,
+ ab_irqctl_readreg(ictl, AB_IRQCTL_INT_ENABLE) & ~(1 << hwirq));
+}
+
+static void tb10x_irq_ack(struct irq_data *data)
+{
+ struct tb10x_ictl *ictl = irq_data_get_irq_chip_data(data);
+ unsigned int hwirq = irqd_to_hwirq(data);
+
+ ab_irqctl_writereg(ictl, AB_IRQCTL_INT_STATUS,
+ ab_irqctl_readreg(ictl, AB_IRQCTL_SRC_MODE)
+ & (1 << hwirq));
+}
+
+static struct irq_chip irq_tb10x_chip = {
+ .name = "TB10x-ICTL",
+ .irq_ack = tb10x_irq_ack,
+ .irq_mask = tb10x_irq_mask,
+ .irq_unmask = tb10x_irq_unmask,
+ .irq_set_type = tb10x_irq_set_type,
+};
+
+static int tb10x_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hw)
+{
+ irq_set_chip_data(irq, d->host_data);
+ irq_set_chip_and_handler(irq, &irq_tb10x_chip, handle_level_irq);
+
+ return 0;
+}
+
+static int tb10x_irq_xlate(struct irq_domain *d, struct device_node *node,
+ const u32 *intspec, unsigned int intsize,
+ unsigned long *out_hwirq, unsigned int *out_type)
+{
+ static const unsigned int tb10x_xlate_types[] = {
+ IRQ_TYPE_EDGE_RISING,
+ IRQ_TYPE_LEVEL_LOW,
+ IRQ_TYPE_LEVEL_HIGH,
+ IRQ_TYPE_EDGE_FALLING,
+ };
+
+ if (WARN_ON(intsize != 2))
+ return -EINVAL;
+
+ if (WARN_ON(intspec[1] >= ARRAY_SIZE(tb10x_xlate_types)))
+ return -EINVAL;
+
+ *out_hwirq = intspec[0];
+ *out_type = tb10x_xlate_types[intspec[1]];
+ return 0;
+}
+
+static struct irq_domain_ops irq_tb10x_domain_ops = {
+ .map = tb10x_irq_map,
+ .xlate = tb10x_irq_xlate,
+};
+
+static void tb10x_irq_cascade(unsigned int irq, struct irq_desc *desc)
+{
+ struct tb10x_ictl *ictl = irq_desc_get_handler_data(desc);
+
+ generic_handle_irq(irq_find_mapping(ictl->domain, irq));
+}
+
+static int __init of_tb10x_init_irq(struct device_node *ictl,
+ struct device_node *parent)
+{
+ int i;
+ int ret;
+ int nrirqs = of_irq_count(ictl);
+ struct resource mem;
+ struct tb10x_ictl *ic;
+
+ ic = kmalloc(sizeof(struct tb10x_ictl), GFP_KERNEL);
+ if (!ic)
+ return -ENOMEM;
+
+ ic->domain = irq_domain_add_tree(ictl, &irq_tb10x_domain_ops, ic);
+ if (!ic->domain) {
+ ret = -ENOMEM;
+ goto irq_domain_add_fail;
+ }
+
+ if (of_address_to_resource(ictl, 0, &mem)) {
+ pr_err("%s: No registers declared in DeviceTree.\n",
+ ictl->name);
+ ret = -EINVAL;
+ goto of_reg_get_fail;
+ }
+
+ if (!request_mem_region(mem.start, resource_size(&mem),
+ irq_tb10x_chip.name)) {
+ ret = -EBUSY;
+ goto reg_request_fail;
+ }
+
+ ic->base = ioremap(mem.start, resource_size(&mem));
+ if (!ic->base) {
+ ret = -EBUSY;
+ goto ioremap_fail;
+ }
+
+ for (i = 0; i < nrirqs; i++) {
+ unsigned int irq, hwirq;
+ struct irq_data *irq_data;
+
+ irq = irq_of_parse_and_map(ictl, i);
+ irq_data = irq_get_irq_data(irq);
+
+ if (!irq_data)
+ continue;
+
+ hwirq = irqd_to_hwirq(irq_data);
+
+ if (irq != hwirq)
+ panic("IRQ %d maps to hardware IRQ %d.\n", irq, hwirq);
+
+ irq_set_handler_data(irq, ic);
+ irq_set_chained_handler(irq, tb10x_irq_cascade);
+ }
+
+ ab_irqctl_writereg(ic, AB_IRQCTL_INT_ENABLE, 0);
+ ab_irqctl_writereg(ic, AB_IRQCTL_INT_MODE, 0);
+ ab_irqctl_writereg(ic, AB_IRQCTL_INT_POLARITY, 0);
+ ab_irqctl_writereg(ic, AB_IRQCTL_INT_STATUS, ~0UL);
+
+ return 0;
+
+ioremap_fail:
+ release_mem_region(mem.start, resource_size(&mem));
+reg_request_fail:
+of_reg_get_fail:
+ irq_domain_remove(ic->domain);
+irq_domain_add_fail:
+ kfree(ic);
+ return ret;
+}
+IRQCHIP_DECLARE(tb10x_intc, "abilis,tb10x_ictl", of_tb10x_init_irq);
--
1.7.1


2013-05-07 12:38:19

by Christian Ruppert

[permalink] [raw]
Subject: [PATCH REBASE] irqchip: Add TB10x interrupt controller driver

The SOC interrupt controller driver for the Abilis Systems TB10x series of
SOCs based on ARC700 CPUs.

This driver is required to boot the arch/arc/plat-tb10x platform already
present in linux-next. Please consider this patch for inclusion in 3.10.
This is the rebase of a previous version on linux-next.

Signed-off-by: Christian Ruppert <[email protected]>
Signed-off-by: Pierrick Hascoet <[email protected]>
---
.../interrupt-controller/abilis,tb10x_ictl.txt | 38 +++
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-tb10x.c | 254 ++++++++++++++++++++
3 files changed, 293 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x_ictl.txt
create mode 100644 drivers/irqchip/irq-tb10x.c

diff --git a/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x_ictl.txt b/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x_ictl.txt
new file mode 100644
index 0000000..bc292cd
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x_ictl.txt
@@ -0,0 +1,38 @@
+TB10x Top Level Interrupt Controller
+====================================
+
+The Abilis TB10x SOC contains a custom interrupt controller. It performs
+one-to-one mapping of external interrupt sources to CPU interrupts and
+provides support for reconfigurable trigger modes.
+
+Required properties
+-------------------
+
+- compatible: Should be "abilis,tb10x_ictl"
+- reg: specifies physical base address and size of register range.
+- interrupt-congroller: Identifies the node as an interrupt controller.
+- #interrupt cells: Specifies the number of cells used to encode an interrupt
+ source connected to this controller. The value shall be 2.
+- interrupt-parent: Specifies the parent interrupt controller.
+- interrupts: Specifies the list of interrupt lines which are handled by
+ the interrupt controller in the parent controller's notation. Interrupts
+ are mapped one-to-one to parent interrupts.
+
+Example
+-------
+
+intc: interrupt-controller { /* Parent interrupt controller */
+ interrupt-controller;
+ #interrupt-cells = <1>; /* For example below */
+ /* ... */
+};
+
+tb10x_ictl: pic@2000 { /* TB10x interrupt controller */
+ compatible = "abilis,tb10x_ictl";
+ reg = <0x2000 0x20>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupt-parent = <&intc>;
+ interrupts = <5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+ 20 21 22 23 24 25 26 27 28 29 30 31>;
+};
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 6a02eac..ad81a2c 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_METAG) += irq-metag-ext.o
obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o
obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
+obj-$(CONFIG_ARC_PLAT_TB10X) += irq-tb10x.o
obj-$(CONFIG_ARM_GIC) += irq-gic.o
obj-$(CONFIG_ARM_VIC) += irq-vic.o
obj-$(CONFIG_SIRF_IRQ) += irq-sirfsoc.o
diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c
new file mode 100644
index 0000000..542de1e
--- /dev/null
+++ b/drivers/irqchip/irq-tb10x.c
@@ -0,0 +1,254 @@
+/*
+ * Abilis Systems interrupt controller driver
+ *
+ * Copyright (C) Abilis Systems 2012
+ *
+ * Author: Christian Ruppert <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include "../../drivers/irqchip/irqchip.h"
+
+#define AB_IRQCTL_INT_ENABLE (0x00)
+#define AB_IRQCTL_INT_STATUS (0x04)
+#define AB_IRQCTL_SRC_MODE (0x08)
+#define AB_IRQCTL_SRC_POLARITY (0x0C)
+#define AB_IRQCTL_INT_MODE (0x10)
+#define AB_IRQCTL_INT_POLARITY (0x14)
+#define AB_IRQCTL_INT_FORCE (0x18)
+
+struct tb10x_ictl {
+ void *base;
+ struct irq_domain *domain;
+};
+
+static inline void ab_irqctl_writereg(struct tb10x_ictl *ictl, u32 reg,
+ u32 val)
+{
+ iowrite32(val, (u32 *)(ictl->base + reg));
+}
+
+static inline u32 ab_irqctl_readreg(struct tb10x_ictl *ictl, u32 reg)
+{
+ return ioread32((u32 *)(ictl->base + reg));
+}
+
+static int tb10x_irq_set_type(struct irq_data *data, unsigned int flow_type)
+{
+ struct tb10x_ictl *ictl = irq_data_get_irq_chip_data(data);
+ unsigned int irq = data->irq;
+ unsigned int hwirq = irqd_to_hwirq(data);
+ uint32_t im, mod, pol;
+
+ im = 1UL << hwirq;
+
+ mod = ab_irqctl_readreg(ictl, AB_IRQCTL_SRC_MODE) | im;
+ pol = ab_irqctl_readreg(ictl, AB_IRQCTL_SRC_POLARITY) | im;
+
+ switch (flow_type & IRQF_TRIGGER_MASK) {
+ case IRQ_TYPE_EDGE_FALLING:
+ pol ^= im;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ mod ^= im;
+ break;
+ case IRQ_TYPE_NONE:
+ flow_type = IRQ_TYPE_LEVEL_LOW;
+ case IRQ_TYPE_LEVEL_LOW:
+ mod ^= im;
+ pol ^= im;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ break;
+ default:
+ pr_err("%s: Cannot assign multiple trigger modes to IRQ %d.\n",
+ __func__, irq);
+ return -EBADR;
+ }
+
+ irqd_set_trigger_type(data, flow_type);
+
+ ab_irqctl_writereg(ictl, AB_IRQCTL_SRC_MODE, mod);
+ ab_irqctl_writereg(ictl, AB_IRQCTL_SRC_POLARITY, pol);
+ ab_irqctl_writereg(ictl, AB_IRQCTL_INT_STATUS, im);
+
+ if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+ __irq_set_handler_locked(irq, handle_level_irq);
+ else
+ __irq_set_handler_locked(irq, handle_edge_irq);
+
+ return IRQ_SET_MASK_OK;
+}
+
+static void tb10x_irq_unmask(struct irq_data *data)
+{
+ struct tb10x_ictl *ictl = irq_data_get_irq_chip_data(data);
+ unsigned int hwirq = irqd_to_hwirq(data);
+
+ ab_irqctl_writereg(ictl, AB_IRQCTL_INT_ENABLE,
+ ab_irqctl_readreg(ictl, AB_IRQCTL_INT_ENABLE) | (1 << hwirq));
+}
+
+static void tb10x_irq_mask(struct irq_data *data)
+{
+ struct tb10x_ictl *ictl = irq_data_get_irq_chip_data(data);
+ unsigned int hwirq = irqd_to_hwirq(data);
+
+ ab_irqctl_writereg(ictl, AB_IRQCTL_INT_ENABLE,
+ ab_irqctl_readreg(ictl, AB_IRQCTL_INT_ENABLE) & ~(1 << hwirq));
+}
+
+static void tb10x_irq_ack(struct irq_data *data)
+{
+ struct tb10x_ictl *ictl = irq_data_get_irq_chip_data(data);
+ unsigned int hwirq = irqd_to_hwirq(data);
+
+ ab_irqctl_writereg(ictl, AB_IRQCTL_INT_STATUS,
+ ab_irqctl_readreg(ictl, AB_IRQCTL_SRC_MODE)
+ & (1 << hwirq));
+}
+
+static struct irq_chip irq_tb10x_chip = {
+ .name = "TB10x-ICTL",
+ .irq_ack = tb10x_irq_ack,
+ .irq_mask = tb10x_irq_mask,
+ .irq_unmask = tb10x_irq_unmask,
+ .irq_set_type = tb10x_irq_set_type,
+};
+
+static int tb10x_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hw)
+{
+ irq_set_chip_data(irq, d->host_data);
+ irq_set_chip_and_handler(irq, &irq_tb10x_chip, handle_level_irq);
+
+ return 0;
+}
+
+static int tb10x_irq_xlate(struct irq_domain *d, struct device_node *node,
+ const u32 *intspec, unsigned int intsize,
+ unsigned long *out_hwirq, unsigned int *out_type)
+{
+ static const unsigned int tb10x_xlate_types[] = {
+ IRQ_TYPE_EDGE_RISING,
+ IRQ_TYPE_LEVEL_LOW,
+ IRQ_TYPE_LEVEL_HIGH,
+ IRQ_TYPE_EDGE_FALLING,
+ };
+
+ if (WARN_ON(intsize != 2))
+ return -EINVAL;
+
+ if (WARN_ON(intspec[1] >= ARRAY_SIZE(tb10x_xlate_types)))
+ return -EINVAL;
+
+ *out_hwirq = intspec[0];
+ *out_type = tb10x_xlate_types[intspec[1]];
+ return 0;
+}
+
+static struct irq_domain_ops irq_tb10x_domain_ops = {
+ .map = tb10x_irq_map,
+ .xlate = tb10x_irq_xlate,
+};
+
+static void tb10x_irq_cascade(unsigned int irq, struct irq_desc *desc)
+{
+ struct tb10x_ictl *ictl = irq_desc_get_handler_data(desc);
+
+ generic_handle_irq(irq_find_mapping(ictl->domain, irq));
+}
+
+static int __init of_tb10x_init_irq(struct device_node *ictl,
+ struct device_node *parent)
+{
+ int i;
+ int ret;
+ int nrirqs = of_irq_count(ictl);
+ struct resource mem;
+ struct tb10x_ictl *ic;
+
+ ic = kmalloc(sizeof(struct tb10x_ictl), GFP_KERNEL);
+ if (!ic)
+ return -ENOMEM;
+
+ ic->domain = irq_domain_add_tree(ictl, &irq_tb10x_domain_ops, ic);
+ if (!ic->domain) {
+ ret = -ENOMEM;
+ goto irq_domain_add_fail;
+ }
+
+ if (of_address_to_resource(ictl, 0, &mem)) {
+ pr_err("%s: No registers declared in DeviceTree.\n",
+ ictl->name);
+ ret = -EINVAL;
+ goto of_reg_get_fail;
+ }
+
+ if (!request_mem_region(mem.start, resource_size(&mem),
+ irq_tb10x_chip.name)) {
+ ret = -EBUSY;
+ goto reg_request_fail;
+ }
+
+ ic->base = ioremap(mem.start, resource_size(&mem));
+ if (!ic->base) {
+ ret = -EBUSY;
+ goto ioremap_fail;
+ }
+
+ for (i = 0; i < nrirqs; i++) {
+ unsigned int irq, hwirq;
+ struct irq_data *irq_data;
+
+ irq = irq_of_parse_and_map(ictl, i);
+ irq_data = irq_get_irq_data(irq);
+
+ if (!irq_data)
+ continue;
+
+ hwirq = irqd_to_hwirq(irq_data);
+
+ if (irq != hwirq)
+ panic("IRQ %d maps to hardware IRQ %d.\n", irq, hwirq);
+
+ irq_set_handler_data(irq, ic);
+ irq_set_chained_handler(irq, tb10x_irq_cascade);
+ }
+
+ ab_irqctl_writereg(ic, AB_IRQCTL_INT_ENABLE, 0);
+ ab_irqctl_writereg(ic, AB_IRQCTL_INT_MODE, 0);
+ ab_irqctl_writereg(ic, AB_IRQCTL_INT_POLARITY, 0);
+ ab_irqctl_writereg(ic, AB_IRQCTL_INT_STATUS, ~0UL);
+
+ return 0;
+
+ioremap_fail:
+ release_mem_region(mem.start, resource_size(&mem));
+reg_request_fail:
+of_reg_get_fail:
+ irq_domain_remove(ic->domain);
+irq_domain_add_fail:
+ kfree(ic);
+ return ret;
+}
+IRQCHIP_DECLARE(tb10x_intc, "abilis,tb10x_ictl", of_tb10x_init_irq);
--
1.7.1

2013-05-27 10:07:04

by Vineet Gupta

[permalink] [raw]
Subject: Re: [PATCH REBASE] irqchip: Add TB10x interrupt controller driver

On 05/07/2013 06:07 PM, Christian Ruppert wrote:
> The SOC interrupt controller driver for the Abilis Systems TB10x series of
> SOCs based on ARC700 CPUs.
>
> This driver is required to boot the arch/arc/plat-tb10x platform already
> present in linux-next. Please consider this patch for inclusion in 3.10.
> This is the rebase of a previous version on linux-next.
>
> Signed-off-by: Christian Ruppert <[email protected]>
> Signed-off-by: Pierrick Hascoet <[email protected]>

Looks good to me !

Reviewed-by: Vineet Gupta <[email protected]>

P.S. @tglx can you please review this at your earliest convenience and provide any
feedback to Chrisitian. This driver is essential to their platform and it would be
nice to have it in mainline in 3.11

Thx,
-Vineet

2013-05-27 12:26:51

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH REBASE] irqchip: Add TB10x interrupt controller driver

On Tue, 7 May 2013, Christian Ruppert wrote:
> +#include <linux/interrupt.h>
> +#include <linux/irqdomain.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +#include <linux/io.h>
> +#include <linux/slab.h>
> +#include "../../drivers/irqchip/irqchip.h"

#include "irqchip.h" perhaps?

> +#define AB_IRQCTL_INT_ENABLE (0x00)

What's the purpose of the parens? Decrease readability?

> +static void tb10x_irq_unmask(struct irq_data *data)
> +{
> + struct tb10x_ictl *ictl = irq_data_get_irq_chip_data(data);
> + unsigned int hwirq = irqd_to_hwirq(data);
> +
> + ab_irqctl_writereg(ictl, AB_IRQCTL_INT_ENABLE,
> + ab_irqctl_readreg(ictl, AB_IRQCTL_INT_ENABLE) | (1 << hwirq));

Another implementation of the generic interrupt chip functionality.

> +static int tb10x_irq_map(struct irq_domain *d, unsigned int irq,
> + irq_hw_number_t hw)
> +{
> + irq_set_chip_data(irq, d->host_data);
> + irq_set_chip_and_handler(irq, &irq_tb10x_chip, handle_level_irq);
> +
> + return 0;
> +}
> +
> +static int tb10x_irq_xlate(struct irq_domain *d, struct device_node *node,
> + const u32 *intspec, unsigned int intsize,
> + unsigned long *out_hwirq, unsigned int *out_type)
> +{
> + static const unsigned int tb10x_xlate_types[] = {
> + IRQ_TYPE_EDGE_RISING,
> + IRQ_TYPE_LEVEL_LOW,
> + IRQ_TYPE_LEVEL_HIGH,
> + IRQ_TYPE_EDGE_FALLING,

Why do you need to introduce another format for specifying the
interrupt type instead of using the IRQ_TYPE values and
irq_domain_xlate_twocell()?

> +static void tb10x_irq_cascade(unsigned int irq, struct irq_desc *desc)
> +{
> + struct tb10x_ictl *ictl = irq_desc_get_handler_data(desc);
> +
> + generic_handle_irq(irq_find_mapping(ictl->domain, irq));
> +}
> +
> +static int __init of_tb10x_init_irq(struct device_node *ictl,
> + struct device_node *parent)
> +{
> + int i;
> + int ret;
> + int nrirqs = of_irq_count(ictl);

One line for all those ints please

> + ic->domain = irq_domain_add_tree(ictl, &irq_tb10x_domain_ops, ic);

Why do you want a tree, if you require that the interrupts are mapped
1:1 to the hardware interrupt numbers? This doesn't make any sense at
all and makes the above cascade handler a pointless waste of cpu cycles.

Thanks,

tglx

2013-05-28 16:35:45

by Christian Ruppert

[permalink] [raw]
Subject: [PATCH V2] irqchip: Add TB10x interrupt controller driver

The SOC interrupt controller driver for the Abilis Systems TB10x series of
SOCs based on ARC700 CPUs.

Signed-off-by: Christian Ruppert <[email protected]>
Signed-off-by: Pierrick Hascoet <[email protected]>
---
.../interrupt-controller/abilis,tb10x_ictl.txt | 38 ++++
arch/arc/boot/dts/abilis_tb100.dtsi | 32 ++--
arch/arc/boot/dts/abilis_tb101.dtsi | 32 ++--
arch/arc/boot/dts/abilis_tb10x.dtsi | 30 ++--
arch/arc/plat-tb10x/Kconfig | 1 +
drivers/irqchip/Kconfig | 5 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-tb10x.c | 205 ++++++++++++++++++++
8 files changed, 291 insertions(+), 53 deletions(-)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x_ictl.txt
create mode 100644 drivers/irqchip/irq-tb10x.c

diff --git a/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x_ictl.txt b/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x_ictl.txt
new file mode 100644
index 0000000..bc292cd
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x_ictl.txt
@@ -0,0 +1,38 @@
+TB10x Top Level Interrupt Controller
+====================================
+
+The Abilis TB10x SOC contains a custom interrupt controller. It performs
+one-to-one mapping of external interrupt sources to CPU interrupts and
+provides support for reconfigurable trigger modes.
+
+Required properties
+-------------------
+
+- compatible: Should be "abilis,tb10x_ictl"
+- reg: specifies physical base address and size of register range.
+- interrupt-congroller: Identifies the node as an interrupt controller.
+- #interrupt cells: Specifies the number of cells used to encode an interrupt
+ source connected to this controller. The value shall be 2.
+- interrupt-parent: Specifies the parent interrupt controller.
+- interrupts: Specifies the list of interrupt lines which are handled by
+ the interrupt controller in the parent controller's notation. Interrupts
+ are mapped one-to-one to parent interrupts.
+
+Example
+-------
+
+intc: interrupt-controller { /* Parent interrupt controller */
+ interrupt-controller;
+ #interrupt-cells = <1>; /* For example below */
+ /* ... */
+};
+
+tb10x_ictl: pic@2000 { /* TB10x interrupt controller */
+ compatible = "abilis,tb10x_ictl";
+ reg = <0x2000 0x20>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupt-parent = <&intc>;
+ interrupts = <5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+ 20 21 22 23 24 25 26 27 28 29 30 31>;
+};
diff --git a/arch/arc/boot/dts/abilis_tb100.dtsi b/arch/arc/boot/dts/abilis_tb100.dtsi
index 941ad11..d9f8249 100644
--- a/arch/arc/boot/dts/abilis_tb100.dtsi
+++ b/arch/arc/boot/dts/abilis_tb100.dtsi
@@ -21,10 +21,6 @@

/include/ "abilis_tb10x.dtsi"

-/* interrupt specifiers
- * --------------------
- * 0: rising, 1: low, 2: high, 3: falling,
- */

/ {
clock-frequency = <500000000>; /* 500 MHZ */
@@ -173,7 +169,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF140000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -185,7 +181,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF141000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -197,7 +193,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF142000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -209,7 +205,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF143000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -221,7 +217,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF144000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -233,7 +229,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF145000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -245,7 +241,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF146000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -257,7 +253,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF147000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -269,7 +265,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF148000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -281,7 +277,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF149000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -293,7 +289,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14A000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -305,7 +301,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14B000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -317,7 +313,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14C000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -329,7 +325,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14D000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
diff --git a/arch/arc/boot/dts/abilis_tb101.dtsi b/arch/arc/boot/dts/abilis_tb101.dtsi
index fd25c21..da8ca79 100644
--- a/arch/arc/boot/dts/abilis_tb101.dtsi
+++ b/arch/arc/boot/dts/abilis_tb101.dtsi
@@ -21,10 +21,6 @@

/include/ "abilis_tb10x.dtsi"

-/* interrupt specifiers
- * --------------------
- * 0: rising, 1: low, 2: high, 3: falling,
- */

/ {
clock-frequency = <500000000>; /* 500 MHZ */
@@ -182,7 +178,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF140000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -194,7 +190,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF141000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -206,7 +202,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF142000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -218,7 +214,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF143000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -230,7 +226,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF144000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -242,7 +238,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF145000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -254,7 +250,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF146000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -266,7 +262,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF147000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -278,7 +274,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF148000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -290,7 +286,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF149000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -302,7 +298,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14A000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -314,7 +310,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14B000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -326,7 +322,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14C000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -338,7 +334,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14D000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
diff --git a/arch/arc/boot/dts/abilis_tb10x.dtsi b/arch/arc/boot/dts/abilis_tb10x.dtsi
index b97e305..f73e705 100644
--- a/arch/arc/boot/dts/abilis_tb10x.dtsi
+++ b/arch/arc/boot/dts/abilis_tb10x.dtsi
@@ -19,10 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

-/* interrupt specifiers
- * --------------------
- * 0: rising, 1: low, 2: high, 3: falling,
- */

/ {
compatible = "abilis,arc-tb10x";
@@ -91,7 +87,7 @@
compatible = "snps,dw-apb-uart";
reg = <0xFF100000 0x100>;
clock-frequency = <166666666>;
- interrupts = <25 1>;
+ interrupts = <25 8>;
reg-shift = <2>;
reg-io-width = <4>;
interrupt-parent = <&tb10x_ictl>;
@@ -100,7 +96,7 @@
compatible = "snps,dwmac-3.70a","snps,dwmac";
reg = <0xFE100000 0x1058>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <6 1>;
+ interrupts = <6 8>;
interrupt-names = "macirq";
clocks = <&ahb_clk>;
clock-names = "stmmaceth";
@@ -109,7 +105,7 @@
compatible = "snps,dma-spear1340";
reg = <0xFE000000 0x400>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <14 1>;
+ interrupts = <14 8>;
dma-channels = <6>;
dma-requests = <0>;
dma-masters = <1>;
@@ -128,7 +124,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF120000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};
i2c1: i2c@FF121000 {
@@ -137,7 +133,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF121000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};
i2c2: i2c@FF122000 {
@@ -146,7 +142,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF122000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};
i2c3: i2c@FF123000 {
@@ -155,7 +151,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF123000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};
i2c4: i2c@FF124000 {
@@ -164,7 +160,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF124000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};

@@ -176,7 +172,7 @@
num-cs = <1>;
reg = <0xFE010000 0x20>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <26 1>;
+ interrupts = <26 8>;
clocks = <&ahb_clk>;
};
spi1: spi@0xFE011000 {
@@ -187,7 +183,7 @@
num-cs = <2>;
reg = <0xFE011000 0x20>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <10 1>;
+ interrupts = <10 8>;
clocks = <&ahb_clk>;
};

@@ -195,7 +191,7 @@
compatible = "abilis,tb100-tsm";
reg = <0xff316000 0x400>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <17 1>;
+ interrupts = <17 8>;
output-clkdiv = <4>;
global-packet-delay = <0x21>;
port-packet-delay = <0>;
@@ -213,7 +209,7 @@
"cpuctrl",
"a6it_int_force";
interrupt-parent = <&tb10x_ictl>;
- interrupts = <20 1>, <19 1>;
+ interrupts = <20 2>, <19 2>;
interrupt-names = "cmd_irq", "event_irq";
};
tb10x_mdsc0: tb10x-mdscr@FF300000 {
@@ -239,7 +235,7 @@
compatible = "abilis,tb100-wfb";
reg = <0xff319000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <16 1>;
+ interrupts = <16 8>;
};
};
};
diff --git a/arch/arc/plat-tb10x/Kconfig b/arch/arc/plat-tb10x/Kconfig
index 1d34521..1ab386b 100644
--- a/arch/arc/plat-tb10x/Kconfig
+++ b/arch/arc/plat-tb10x/Kconfig
@@ -22,6 +22,7 @@ menuconfig ARC_PLAT_TB10X
select PINCTRL
select PINMUX
select ARCH_REQUIRE_GPIOLIB
+ select TB10X_IRQC
help
Support for platforms based on the TB10x home media gateway SOC by
Abilis Systems. TB10x is based on the ARC700 CPU architecture.
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 4a33351..8843f21 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -33,6 +33,11 @@ config RENESAS_IRQC
bool
select IRQ_DOMAIN

+config TB10X_IRQC
+ bool
+ select IRQ_DOMAIN
+ select GENERIC_IRQ_CHIP
+
config VERSATILE_FPGA_IRQ
bool
select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index cda4cb5..b45e4a4 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_METAG) += irq-metag-ext.o
obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o
obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
+obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o
obj-$(CONFIG_ARM_GIC) += irq-gic.o
obj-$(CONFIG_ARM_VIC) += irq-vic.o
obj-$(CONFIG_SIRF_IRQ) += irq-sirfsoc.o
diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c
new file mode 100644
index 0000000..06f7ce2
--- /dev/null
+++ b/drivers/irqchip/irq-tb10x.c
@@ -0,0 +1,205 @@
+/*
+ * Abilis Systems interrupt controller driver
+ *
+ * Copyright (C) Abilis Systems 2012
+ *
+ * Author: Christian Ruppert <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include "irqchip.h"
+
+#define AB_IRQCTL_INT_ENABLE 0x00
+#define AB_IRQCTL_INT_STATUS 0x04
+#define AB_IRQCTL_SRC_MODE 0x08
+#define AB_IRQCTL_SRC_POLARITY 0x0C
+#define AB_IRQCTL_INT_MODE 0x10
+#define AB_IRQCTL_INT_POLARITY 0x14
+#define AB_IRQCTL_INT_FORCE 0x18
+
+#define AB_IRQCTL_MAXIRQ 32
+#define TB10X_IRQCHIP_BASE NR_CPU_IRQS
+
+static inline void ab_irqctl_writereg(struct irq_chip_generic *gc, u32 reg,
+ u32 val)
+{
+ irq_reg_writel(val, (u32 *)(gc->reg_base + reg));
+}
+
+static inline u32 ab_irqctl_readreg(struct irq_chip_generic *gc, u32 reg)
+{
+ return irq_reg_readl((u32 *)(gc->reg_base + reg));
+}
+
+static int tb10x_irq_set_type(struct irq_data *data, unsigned int flow_type)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
+ unsigned int irq = data->irq;
+ unsigned int hwirq = irqd_to_hwirq(data);
+ uint32_t im, mod, pol;
+
+ im = BIT(hwirq);
+
+ irq_gc_lock(gc);
+
+ mod = ab_irqctl_readreg(gc, AB_IRQCTL_SRC_MODE) | im;
+ pol = ab_irqctl_readreg(gc, AB_IRQCTL_SRC_POLARITY) | im;
+
+ switch (flow_type & IRQF_TRIGGER_MASK) {
+ case IRQ_TYPE_EDGE_FALLING:
+ pol ^= im;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ mod ^= im;
+ break;
+ case IRQ_TYPE_NONE:
+ flow_type = IRQ_TYPE_LEVEL_LOW;
+ case IRQ_TYPE_LEVEL_LOW:
+ mod ^= im;
+ pol ^= im;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ break;
+ default:
+ irq_gc_unlock(gc);
+ pr_err("%s: Cannot assign multiple trigger modes to IRQ %d.\n",
+ __func__, irq);
+ return -EBADR;
+ }
+
+ irqd_set_trigger_type(data, flow_type);
+ irq_setup_alt_chip(data, flow_type);
+
+ ab_irqctl_writereg(gc, AB_IRQCTL_SRC_MODE, mod);
+ ab_irqctl_writereg(gc, AB_IRQCTL_SRC_POLARITY, pol);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_STATUS, im);
+
+ irq_gc_unlock(gc);
+
+ return IRQ_SET_MASK_OK;
+}
+
+static struct irq_domain_ops irq_tb10x_domain_ops = {
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static void tb10x_irq_cascade(unsigned int irq, struct irq_desc *desc)
+{
+ struct irq_domain *domain = irq_desc_get_handler_data(desc);
+
+ generic_handle_irq(irq_find_mapping(domain, irq));
+}
+
+static int __init of_tb10x_init_irq(struct device_node *ictl,
+ struct device_node *parent)
+{
+ int i, ret, nrirqs = of_irq_count(ictl);
+ u32 mask = 0;
+ struct resource mem;
+ struct irq_chip_generic *gc;
+ struct irq_domain *domain;
+ void __iomem *reg_base;
+
+ if (of_address_to_resource(ictl, 0, &mem)) {
+ pr_err("%s: No registers declared in DeviceTree.\n",
+ ictl->name);
+ return -EINVAL;
+ }
+
+ if (!request_mem_region(mem.start, resource_size(&mem),
+ ictl->name)) {
+ pr_err("%s: Request mem region failed.\n", ictl->name);
+ return -EBUSY;
+ }
+
+ reg_base = ioremap(mem.start, resource_size(&mem));
+ if (!reg_base) {
+ ret = -EBUSY;
+ pr_err("%s: ioremap failed.\n", ictl->name);
+ goto ioremap_fail;
+ }
+
+ gc = irq_alloc_generic_chip(ictl->name, 2, TB10X_IRQCHIP_BASE,
+ reg_base, handle_level_irq);
+ if (!gc) {
+ ret = -ENOMEM;
+ pr_err("%s: Could not allocate generic interrupt chip.\n",
+ ictl->name);
+ goto gc_alloc_fail;
+ }
+
+ gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types[0].chip.irq_set_type = tb10x_irq_set_type;
+ gc->chip_types[0].regs.mask = AB_IRQCTL_INT_ENABLE;
+
+ gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
+ gc->chip_types[1].chip.name = gc->chip_types[0].chip.name;
+ gc->chip_types[1].chip.irq_ack = irq_gc_ack_set_bit;
+ gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types[1].chip.irq_set_type = tb10x_irq_set_type;
+ gc->chip_types[1].regs.ack = AB_IRQCTL_INT_STATUS;
+ gc->chip_types[1].regs.mask = AB_IRQCTL_INT_ENABLE;
+ gc->chip_types[1].handler = handle_edge_irq;
+
+ domain = irq_domain_add_legacy(ictl, AB_IRQCTL_MAXIRQ,
+ TB10X_IRQCHIP_BASE, 0,
+ &irq_tb10x_domain_ops, gc);
+ if (!domain) {
+ ret = -ENOMEM;
+ pr_err("%s: Could not register interrupt domain.\n",
+ ictl->name);
+ goto irq_domain_add_fail;
+ }
+
+ for (i = 0; i < nrirqs; i++) {
+ unsigned int irq = irq_of_parse_and_map(ictl, i);
+
+ irq_set_handler_data(irq, domain);
+ irq_set_chained_handler(irq, tb10x_irq_cascade);
+
+ mask |= BIT(of_irq_to_resource(ictl, i, NULL));
+ }
+
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_ENABLE, 0);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_MODE, 0);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_POLARITY, 0);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_STATUS, ~0UL);
+
+ irq_setup_generic_chip(gc, mask, IRQ_GC_INIT_MASK_CACHE,
+ IRQ_NOREQUEST, IRQ_NOPROBE);
+
+ return 0;
+
+irq_domain_add_fail:
+ kfree(gc);
+gc_alloc_fail:
+ iounmap(gc->reg_base);
+ioremap_fail:
+ release_mem_region(mem.start, resource_size(&mem));
+ return ret;
+}
+IRQCHIP_DECLARE(tb10x_intc, "abilis,tb10x_ictl", of_tb10x_init_irq);
--
1.7.1

2013-05-30 21:20:01

by Grant Likely

[permalink] [raw]
Subject: Re: [PATCH V2] irqchip: Add TB10x interrupt controller driver

On Tue, 28 May 2013 18:34:07 +0200, Christian Ruppert <[email protected]> wrote:
> The SOC interrupt controller driver for the Abilis Systems TB10x series of
> SOCs based on ARC700 CPUs.
>
> Signed-off-by: Christian Ruppert <[email protected]>
> Signed-off-by: Pierrick Hascoet <[email protected]>
> ---
> .../interrupt-controller/abilis,tb10x_ictl.txt | 38 ++++
> arch/arc/boot/dts/abilis_tb100.dtsi | 32 ++--
> arch/arc/boot/dts/abilis_tb101.dtsi | 32 ++--
> arch/arc/boot/dts/abilis_tb10x.dtsi | 30 ++--
> arch/arc/plat-tb10x/Kconfig | 1 +
> drivers/irqchip/Kconfig | 5 +
> drivers/irqchip/Makefile | 1 +
> drivers/irqchip/irq-tb10x.c | 205 ++++++++++++++++++++
> 8 files changed, 291 insertions(+), 53 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x_ictl.txt
> create mode 100644 drivers/irqchip/irq-tb10x.c
>
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x_ictl.txt b/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x_ictl.txt
> new file mode 100644
> index 0000000..bc292cd
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x_ictl.txt
> @@ -0,0 +1,38 @@
> +TB10x Top Level Interrupt Controller
> +====================================
> +
> +The Abilis TB10x SOC contains a custom interrupt controller. It performs
> +one-to-one mapping of external interrupt sources to CPU interrupts and
> +provides support for reconfigurable trigger modes.
> +
> +Required properties
> +-------------------
> +
> +- compatible: Should be "abilis,tb10x_ictl"

Use '-' instead of underscore for compatible values. Otherwise the
binding looks fine.

> +- reg: specifies physical base address and size of register range.
> +- interrupt-congroller: Identifies the node as an interrupt controller.
> +- #interrupt cells: Specifies the number of cells used to encode an interrupt
> + source connected to this controller. The value shall be 2.
> +- interrupt-parent: Specifies the parent interrupt controller.
> +- interrupts: Specifies the list of interrupt lines which are handled by
> + the interrupt controller in the parent controller's notation. Interrupts
> + are mapped one-to-one to parent interrupts.
> +
> +Example
> +-------
> +
> +intc: interrupt-controller { /* Parent interrupt controller */
> + interrupt-controller;
> + #interrupt-cells = <1>; /* For example below */
> + /* ... */
> +};
> +
> +tb10x_ictl: pic@2000 { /* TB10x interrupt controller */
> + compatible = "abilis,tb10x_ictl";
> + reg = <0x2000 0x20>;
> + interrupt-controller;
> + #interrupt-cells = <2>;
> + interrupt-parent = <&intc>;
> + interrupts = <5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
> + 20 21 22 23 24 25 26 27 28 29 30 31>;
> +};

[...]
> +#define AB_IRQCTL_MAXIRQ 32
> +#define TB10X_IRQCHIP_BASE NR_CPU_IRQS
> +
> +static inline void ab_irqctl_writereg(struct irq_chip_generic *gc, u32 reg,
> + u32 val)
> +{
> + irq_reg_writel(val, (u32 *)(gc->reg_base + reg));

In most cases, if you have to use a cast, then the code is unsafe.
->reg_base is a void*, so the cast should be unnecessary.

> +}
> +
> +static inline u32 ab_irqctl_readreg(struct irq_chip_generic *gc, u32 reg)
> +{
> + return irq_reg_readl((u32 *)(gc->reg_base + reg));
> +}
> +
> +static int tb10x_irq_set_type(struct irq_data *data, unsigned int flow_type)
> +{
> + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
> + unsigned int irq = data->irq;

irq is used exactly once for a debug pr_err(). I'd drop it from here.

> + unsigned int hwirq = irqd_to_hwirq(data);
> + uint32_t im, mod, pol;
> +
> + im = BIT(hwirq);

data->mask should work here with Thomas' branch (see below)

> +
> + irq_gc_lock(gc);
> +
> + mod = ab_irqctl_readreg(gc, AB_IRQCTL_SRC_MODE) | im;
> + pol = ab_irqctl_readreg(gc, AB_IRQCTL_SRC_POLARITY) | im;
> +
> + switch (flow_type & IRQF_TRIGGER_MASK) {
> + case IRQ_TYPE_EDGE_FALLING:
> + pol ^= im;
> + break;
> + case IRQ_TYPE_LEVEL_HIGH:
> + mod ^= im;
> + break;
> + case IRQ_TYPE_NONE:
> + flow_type = IRQ_TYPE_LEVEL_LOW;
> + case IRQ_TYPE_LEVEL_LOW:
> + mod ^= im;
> + pol ^= im;
> + break;
> + case IRQ_TYPE_EDGE_RISING:
> + break;
> + default:
> + irq_gc_unlock(gc);
> + pr_err("%s: Cannot assign multiple trigger modes to IRQ %d.\n",
> + __func__, irq);
> + return -EBADR;
> + }
> +
> + irqd_set_trigger_type(data, flow_type);
> + irq_setup_alt_chip(data, flow_type);
> +
> + ab_irqctl_writereg(gc, AB_IRQCTL_SRC_MODE, mod);
> + ab_irqctl_writereg(gc, AB_IRQCTL_SRC_POLARITY, pol);
> + ab_irqctl_writereg(gc, AB_IRQCTL_INT_STATUS, im);
> +
> + irq_gc_unlock(gc);
> +
> + return IRQ_SET_MASK_OK;
> +}
> +
> +static struct irq_domain_ops irq_tb10x_domain_ops = {
> + .xlate = irq_domain_xlate_twocell,
> +};
> +
> +static void tb10x_irq_cascade(unsigned int irq, struct irq_desc *desc)
> +{
> + struct irq_domain *domain = irq_desc_get_handler_data(desc);
> +
> + generic_handle_irq(irq_find_mapping(domain, irq));
> +}
> +
> +static int __init of_tb10x_init_irq(struct device_node *ictl,
> + struct device_node *parent)
> +{
> + int i, ret, nrirqs = of_irq_count(ictl);
> + u32 mask = 0;
> + struct resource mem;
> + struct irq_chip_generic *gc;
> + struct irq_domain *domain;
> + void __iomem *reg_base;
> +
> + if (of_address_to_resource(ictl, 0, &mem)) {
> + pr_err("%s: No registers declared in DeviceTree.\n",
> + ictl->name);
> + return -EINVAL;
> + }
> +
> + if (!request_mem_region(mem.start, resource_size(&mem),
> + ictl->name)) {
> + pr_err("%s: Request mem region failed.\n", ictl->name);
> + return -EBUSY;
> + }
> +
> + reg_base = ioremap(mem.start, resource_size(&mem));
> + if (!reg_base) {
> + ret = -EBUSY;
> + pr_err("%s: ioremap failed.\n", ictl->name);
> + goto ioremap_fail;
> + }
> +
> + gc = irq_alloc_generic_chip(ictl->name, 2, TB10X_IRQCHIP_BASE,
> + reg_base, handle_level_irq);
> + if (!gc) {
> + ret = -ENOMEM;
> + pr_err("%s: Could not allocate generic interrupt chip.\n",
> + ictl->name);
> + goto gc_alloc_fail;
> + }

Thomas has merged patches to add irq_alloc_domain_generic_chips() which
you should be using here. It takes care of linking the generic chip into
the irq domain. You can find the patches in the irq/for-arm branch of
the tip tree:

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git

> +
> + gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK;
> + gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
> + gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
> + gc->chip_types[0].chip.irq_set_type = tb10x_irq_set_type;
> + gc->chip_types[0].regs.mask = AB_IRQCTL_INT_ENABLE;
> +
> + gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
> + gc->chip_types[1].chip.name = gc->chip_types[0].chip.name;
> + gc->chip_types[1].chip.irq_ack = irq_gc_ack_set_bit;
> + gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit;
> + gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit;
> + gc->chip_types[1].chip.irq_set_type = tb10x_irq_set_type;
> + gc->chip_types[1].regs.ack = AB_IRQCTL_INT_STATUS;
> + gc->chip_types[1].regs.mask = AB_IRQCTL_INT_ENABLE;
> + gc->chip_types[1].handler = handle_edge_irq;
> +
> + domain = irq_domain_add_legacy(ictl, AB_IRQCTL_MAXIRQ,
> + TB10X_IRQCHIP_BASE, 0,
> + &irq_tb10x_domain_ops, gc);
> + if (!domain) {
> + ret = -ENOMEM;
> + pr_err("%s: Could not register interrupt domain.\n",
> + ictl->name);
> + goto irq_domain_add_fail;
> + }
> +
> + for (i = 0; i < nrirqs; i++) {
> + unsigned int irq = irq_of_parse_and_map(ictl, i);
> +
> + irq_set_handler_data(irq, domain);
> + irq_set_chained_handler(irq, tb10x_irq_cascade);
> +
> + mask |= BIT(of_irq_to_resource(ictl, i, NULL));
> + }
> +
> + ab_irqctl_writereg(gc, AB_IRQCTL_INT_ENABLE, 0);
> + ab_irqctl_writereg(gc, AB_IRQCTL_INT_MODE, 0);
> + ab_irqctl_writereg(gc, AB_IRQCTL_INT_POLARITY, 0);
> + ab_irqctl_writereg(gc, AB_IRQCTL_INT_STATUS, ~0UL);
> +
> + irq_setup_generic_chip(gc, mask, IRQ_GC_INIT_MASK_CACHE,
> + IRQ_NOREQUEST, IRQ_NOPROBE);
> +
> + return 0;
> +
> +irq_domain_add_fail:
> + kfree(gc);
> +gc_alloc_fail:
> + iounmap(gc->reg_base);
> +ioremap_fail:
> + release_mem_region(mem.start, resource_size(&mem));
> + return ret;
> +}
> +IRQCHIP_DECLARE(tb10x_intc, "abilis,tb10x_ictl", of_tb10x_init_irq);
> --
> 1.7.1
>

--
Grant Likely, B.Sc, P.Eng.
Secret Lab Technologies, Ltd.

2013-05-31 15:33:51

by Christian Ruppert

[permalink] [raw]
Subject: [PATCH V3] irqchip: Add TB10x interrupt controller driver

The SOC interrupt controller driver for the Abilis Systems TB10x series of
SOCs based on ARC700 CPUs.

This patch depends on commits eb76bdd407d8a90e59a06cb0158886df390e5d1c and
712bc93df9e7f14b8a163148d2aa7c778e151627 from branch irq/for-arm of
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git.

Signed-off-by: Christian Ruppert <[email protected]>
Signed-off-by: Pierrick Hascoet <[email protected]>
---
.../interrupt-controller/abilis,tb10x-ictl.txt | 38 ++++
arch/arc/boot/dts/abilis_tb100.dtsi | 32 ++--
arch/arc/boot/dts/abilis_tb101.dtsi | 32 ++--
arch/arc/boot/dts/abilis_tb10x.dtsi | 32 ++--
arch/arc/plat-tb10x/Kconfig | 1 +
drivers/irqchip/Kconfig | 5 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-tb10x.c | 195 ++++++++++++++++++++
8 files changed, 282 insertions(+), 54 deletions(-)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x-ictl.txt
create mode 100644 drivers/irqchip/irq-tb10x.c

diff --git a/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x-ictl.txt b/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x-ictl.txt
new file mode 100644
index 0000000..9d52d5a
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x-ictl.txt
@@ -0,0 +1,38 @@
+TB10x Top Level Interrupt Controller
+====================================
+
+The Abilis TB10x SOC contains a custom interrupt controller. It performs
+one-to-one mapping of external interrupt sources to CPU interrupts and
+provides support for reconfigurable trigger modes.
+
+Required properties
+-------------------
+
+- compatible: Should be "abilis,tb10x-ictl"
+- reg: specifies physical base address and size of register range.
+- interrupt-congroller: Identifies the node as an interrupt controller.
+- #interrupt cells: Specifies the number of cells used to encode an interrupt
+ source connected to this controller. The value shall be 2.
+- interrupt-parent: Specifies the parent interrupt controller.
+- interrupts: Specifies the list of interrupt lines which are handled by
+ the interrupt controller in the parent controller's notation. Interrupts
+ are mapped one-to-one to parent interrupts.
+
+Example
+-------
+
+intc: interrupt-controller { /* Parent interrupt controller */
+ interrupt-controller;
+ #interrupt-cells = <1>; /* For example below */
+ /* ... */
+};
+
+tb10x_ictl: pic@2000 { /* TB10x interrupt controller */
+ compatible = "abilis,tb10x-ictl";
+ reg = <0x2000 0x20>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupt-parent = <&intc>;
+ interrupts = <5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+ 20 21 22 23 24 25 26 27 28 29 30 31>;
+};
diff --git a/arch/arc/boot/dts/abilis_tb100.dtsi b/arch/arc/boot/dts/abilis_tb100.dtsi
index 941ad11..d9f8249 100644
--- a/arch/arc/boot/dts/abilis_tb100.dtsi
+++ b/arch/arc/boot/dts/abilis_tb100.dtsi
@@ -21,10 +21,6 @@

/include/ "abilis_tb10x.dtsi"

-/* interrupt specifiers
- * --------------------
- * 0: rising, 1: low, 2: high, 3: falling,
- */

/ {
clock-frequency = <500000000>; /* 500 MHZ */
@@ -173,7 +169,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF140000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -185,7 +181,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF141000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -197,7 +193,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF142000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -209,7 +205,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF143000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -221,7 +217,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF144000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -233,7 +229,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF145000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -245,7 +241,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF146000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -257,7 +253,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF147000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -269,7 +265,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF148000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -281,7 +277,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF149000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -293,7 +289,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14A000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -305,7 +301,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14B000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -317,7 +313,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14C000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -329,7 +325,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14D000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
diff --git a/arch/arc/boot/dts/abilis_tb101.dtsi b/arch/arc/boot/dts/abilis_tb101.dtsi
index fd25c21..da8ca79 100644
--- a/arch/arc/boot/dts/abilis_tb101.dtsi
+++ b/arch/arc/boot/dts/abilis_tb101.dtsi
@@ -21,10 +21,6 @@

/include/ "abilis_tb10x.dtsi"

-/* interrupt specifiers
- * --------------------
- * 0: rising, 1: low, 2: high, 3: falling,
- */

/ {
clock-frequency = <500000000>; /* 500 MHZ */
@@ -182,7 +178,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF140000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -194,7 +190,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF141000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -206,7 +202,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF142000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -218,7 +214,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF143000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -230,7 +226,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF144000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -242,7 +238,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF145000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -254,7 +250,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF146000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -266,7 +262,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF147000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -278,7 +274,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF148000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -290,7 +286,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF149000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -302,7 +298,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14A000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -314,7 +310,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14B000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -326,7 +322,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14C000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -338,7 +334,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14D000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
diff --git a/arch/arc/boot/dts/abilis_tb10x.dtsi b/arch/arc/boot/dts/abilis_tb10x.dtsi
index b97e305..edf56f4 100644
--- a/arch/arc/boot/dts/abilis_tb10x.dtsi
+++ b/arch/arc/boot/dts/abilis_tb10x.dtsi
@@ -19,10 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

-/* interrupt specifiers
- * --------------------
- * 0: rising, 1: low, 2: high, 3: falling,
- */

/ {
compatible = "abilis,arc-tb10x";
@@ -78,7 +74,7 @@
#interrupt-cells = <1>;
};
tb10x_ictl: pic@fe002000 {
- compatible = "abilis,tb10x_ictl";
+ compatible = "abilis,tb10x-ictl";
reg = <0xFE002000 0x20>;
interrupt-controller;
#interrupt-cells = <2>;
@@ -91,7 +87,7 @@
compatible = "snps,dw-apb-uart";
reg = <0xFF100000 0x100>;
clock-frequency = <166666666>;
- interrupts = <25 1>;
+ interrupts = <25 8>;
reg-shift = <2>;
reg-io-width = <4>;
interrupt-parent = <&tb10x_ictl>;
@@ -100,7 +96,7 @@
compatible = "snps,dwmac-3.70a","snps,dwmac";
reg = <0xFE100000 0x1058>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <6 1>;
+ interrupts = <6 8>;
interrupt-names = "macirq";
clocks = <&ahb_clk>;
clock-names = "stmmaceth";
@@ -109,7 +105,7 @@
compatible = "snps,dma-spear1340";
reg = <0xFE000000 0x400>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <14 1>;
+ interrupts = <14 8>;
dma-channels = <6>;
dma-requests = <0>;
dma-masters = <1>;
@@ -128,7 +124,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF120000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};
i2c1: i2c@FF121000 {
@@ -137,7 +133,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF121000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};
i2c2: i2c@FF122000 {
@@ -146,7 +142,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF122000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};
i2c3: i2c@FF123000 {
@@ -155,7 +151,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF123000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};
i2c4: i2c@FF124000 {
@@ -164,7 +160,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF124000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};

@@ -176,7 +172,7 @@
num-cs = <1>;
reg = <0xFE010000 0x20>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <26 1>;
+ interrupts = <26 8>;
clocks = <&ahb_clk>;
};
spi1: spi@0xFE011000 {
@@ -187,7 +183,7 @@
num-cs = <2>;
reg = <0xFE011000 0x20>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <10 1>;
+ interrupts = <10 8>;
clocks = <&ahb_clk>;
};

@@ -195,7 +191,7 @@
compatible = "abilis,tb100-tsm";
reg = <0xff316000 0x400>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <17 1>;
+ interrupts = <17 8>;
output-clkdiv = <4>;
global-packet-delay = <0x21>;
port-packet-delay = <0>;
@@ -213,7 +209,7 @@
"cpuctrl",
"a6it_int_force";
interrupt-parent = <&tb10x_ictl>;
- interrupts = <20 1>, <19 1>;
+ interrupts = <20 2>, <19 2>;
interrupt-names = "cmd_irq", "event_irq";
};
tb10x_mdsc0: tb10x-mdscr@FF300000 {
@@ -239,7 +235,7 @@
compatible = "abilis,tb100-wfb";
reg = <0xff319000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <16 1>;
+ interrupts = <16 8>;
};
};
};
diff --git a/arch/arc/plat-tb10x/Kconfig b/arch/arc/plat-tb10x/Kconfig
index 1d34521..1ab386b 100644
--- a/arch/arc/plat-tb10x/Kconfig
+++ b/arch/arc/plat-tb10x/Kconfig
@@ -22,6 +22,7 @@ menuconfig ARC_PLAT_TB10X
select PINCTRL
select PINMUX
select ARCH_REQUIRE_GPIOLIB
+ select TB10X_IRQC
help
Support for platforms based on the TB10x home media gateway SOC by
Abilis Systems. TB10x is based on the ARC700 CPU architecture.
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 4a33351..8843f21 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -33,6 +33,11 @@ config RENESAS_IRQC
bool
select IRQ_DOMAIN

+config TB10X_IRQC
+ bool
+ select IRQ_DOMAIN
+ select GENERIC_IRQ_CHIP
+
config VERSATILE_FPGA_IRQ
bool
select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index cda4cb5..b45e4a4 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_METAG) += irq-metag-ext.o
obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o
obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
+obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o
obj-$(CONFIG_ARM_GIC) += irq-gic.o
obj-$(CONFIG_ARM_VIC) += irq-vic.o
obj-$(CONFIG_SIRF_IRQ) += irq-sirfsoc.o
diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c
new file mode 100644
index 0000000..7c44c99
--- /dev/null
+++ b/drivers/irqchip/irq-tb10x.c
@@ -0,0 +1,195 @@
+/*
+ * Abilis Systems interrupt controller driver
+ *
+ * Copyright (C) Abilis Systems 2012
+ *
+ * Author: Christian Ruppert <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include "irqchip.h"
+
+#define AB_IRQCTL_INT_ENABLE 0x00
+#define AB_IRQCTL_INT_STATUS 0x04
+#define AB_IRQCTL_SRC_MODE 0x08
+#define AB_IRQCTL_SRC_POLARITY 0x0C
+#define AB_IRQCTL_INT_MODE 0x10
+#define AB_IRQCTL_INT_POLARITY 0x14
+#define AB_IRQCTL_INT_FORCE 0x18
+
+#define AB_IRQCTL_MAXIRQ 32
+
+static inline void ab_irqctl_writereg(struct irq_chip_generic *gc, u32 reg,
+ u32 val)
+{
+ irq_reg_writel(val, gc->reg_base + reg);
+}
+
+static inline u32 ab_irqctl_readreg(struct irq_chip_generic *gc, u32 reg)
+{
+ return irq_reg_readl(gc->reg_base + reg);
+}
+
+static int tb10x_irq_set_type(struct irq_data *data, unsigned int flow_type)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
+ uint32_t im, mod, pol;
+
+ im = data->mask;
+
+ irq_gc_lock(gc);
+
+ mod = ab_irqctl_readreg(gc, AB_IRQCTL_SRC_MODE) | im;
+ pol = ab_irqctl_readreg(gc, AB_IRQCTL_SRC_POLARITY) | im;
+
+ switch (flow_type & IRQF_TRIGGER_MASK) {
+ case IRQ_TYPE_EDGE_FALLING:
+ pol ^= im;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ mod ^= im;
+ break;
+ case IRQ_TYPE_NONE:
+ flow_type = IRQ_TYPE_LEVEL_LOW;
+ case IRQ_TYPE_LEVEL_LOW:
+ mod ^= im;
+ pol ^= im;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ break;
+ default:
+ irq_gc_unlock(gc);
+ pr_err("%s: Cannot assign multiple trigger modes to IRQ %d.\n",
+ __func__, data->irq);
+ return -EBADR;
+ }
+
+ irqd_set_trigger_type(data, flow_type);
+ irq_setup_alt_chip(data, flow_type);
+
+ ab_irqctl_writereg(gc, AB_IRQCTL_SRC_MODE, mod);
+ ab_irqctl_writereg(gc, AB_IRQCTL_SRC_POLARITY, pol);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_STATUS, im);
+
+ irq_gc_unlock(gc);
+
+ return IRQ_SET_MASK_OK;
+}
+
+static void tb10x_irq_cascade(unsigned int irq, struct irq_desc *desc)
+{
+ struct irq_domain *domain = irq_desc_get_handler_data(desc);
+
+ generic_handle_irq(irq_find_mapping(domain, irq));
+}
+
+static int __init of_tb10x_init_irq(struct device_node *ictl,
+ struct device_node *parent)
+{
+ int i, ret, nrirqs = of_irq_count(ictl);
+ struct resource mem;
+ struct irq_chip_generic *gc;
+ struct irq_domain *domain;
+ void __iomem *reg_base;
+
+ if (of_address_to_resource(ictl, 0, &mem)) {
+ pr_err("%s: No registers declared in DeviceTree.\n",
+ ictl->name);
+ return -EINVAL;
+ }
+
+ if (!request_mem_region(mem.start, resource_size(&mem),
+ ictl->name)) {
+ pr_err("%s: Request mem region failed.\n", ictl->name);
+ return -EBUSY;
+ }
+
+ reg_base = ioremap(mem.start, resource_size(&mem));
+ if (!reg_base) {
+ ret = -EBUSY;
+ pr_err("%s: ioremap failed.\n", ictl->name);
+ goto ioremap_fail;
+ }
+
+ domain = irq_domain_add_linear(ictl, AB_IRQCTL_MAXIRQ,
+ &irq_generic_chip_ops, NULL);
+ if (!domain) {
+ ret = -ENOMEM;
+ pr_err("%s: Could not register interrupt domain.\n",
+ ictl->name);
+ goto irq_domain_add_fail;
+ }
+
+ ret = irq_alloc_domain_generic_chips(domain, AB_IRQCTL_MAXIRQ,
+ 2, ictl->name, handle_level_irq,
+ IRQ_NOREQUEST, IRQ_NOPROBE,
+ IRQ_GC_INIT_MASK_CACHE);
+ if (ret) {
+ pr_err("%s: Could not allocate generic interrupt chip.\n",
+ ictl->name);
+ goto gc_alloc_fail;
+ }
+
+ gc = domain->gc->gc[0];
+ gc->reg_base = reg_base;
+
+ gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types[0].chip.irq_set_type = tb10x_irq_set_type;
+ gc->chip_types[0].regs.mask = AB_IRQCTL_INT_ENABLE;
+
+ gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
+ gc->chip_types[1].chip.name = gc->chip_types[0].chip.name;
+ gc->chip_types[1].chip.irq_ack = irq_gc_ack_set_bit;
+ gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types[1].chip.irq_set_type = tb10x_irq_set_type;
+ gc->chip_types[1].regs.ack = AB_IRQCTL_INT_STATUS;
+ gc->chip_types[1].regs.mask = AB_IRQCTL_INT_ENABLE;
+ gc->chip_types[1].handler = handle_edge_irq;
+
+ for (i = 0; i < nrirqs; i++) {
+ unsigned int irq = irq_of_parse_and_map(ictl, i);
+
+ irq_set_handler_data(irq, domain);
+ irq_set_chained_handler(irq, tb10x_irq_cascade);
+ }
+
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_ENABLE, 0);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_MODE, 0);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_POLARITY, 0);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_STATUS, ~0UL);
+
+ return 0;
+
+gc_alloc_fail:
+ irq_domain_remove(domain);
+irq_domain_add_fail:
+ iounmap(reg_base);
+ioremap_fail:
+ release_mem_region(mem.start, resource_size(&mem));
+ return ret;
+}
+IRQCHIP_DECLARE(tb10x_intc, "abilis,tb10x-ictl", of_tb10x_init_irq);
--
1.7.1

2013-05-31 17:32:50

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH V3] irqchip: Add TB10x interrupt controller driver

On Fri, 31 May 2013, Christian Ruppert wrote:

> The SOC interrupt controller driver for the Abilis Systems TB10x series of
> SOCs based on ARC700 CPUs.
>
> This patch depends on commits eb76bdd407d8a90e59a06cb0158886df390e5d1c and
> 712bc93df9e7f14b8a163148d2aa7c778e151627 from branch irq/for-arm of
> git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git.

That branch can be pulled into ARC as well. It only contains the
changes, which are necessary for the irq domain support of the generic
irq chip.

> +static void tb10x_irq_cascade(unsigned int irq, struct irq_desc *desc)
> +{
> + struct irq_domain *domain = irq_desc_get_handler_data(desc);
> +
> + generic_handle_irq(irq_find_mapping(domain, irq));
> +}

...

> + for (i = 0; i < nrirqs; i++) {
> + unsigned int irq = irq_of_parse_and_map(ictl, i);
> +
> + irq_set_handler_data(irq, domain);
> + irq_set_chained_handler(irq, tb10x_irq_cascade);
> + }

I might be completely confused, but this does not make any sense at
all.

You allocate a linear domain and then map the interrupts in the
domain. The mapping function retrieves the hardware interrupt number
and creates a virtual interrupt number, installs the chip and the
handler for the interrupt and finally returns the virtual interrupt
number.

Now you take that virtual interrupt number and install
tb10x_irq_cascade as the handler. irq_set_chained_handler() will
startup (unmask) the interrupt right away.

In the cascade handler you take the virtual interrupt number, which
you get as argument, and find the mapping, i.e. the matching VIRTUAL
interrupt number for the VIRTUAL interrupt number and then call the
handler.

How is this supposed to work?

Thanks,

tglx

2013-05-31 22:18:26

by Grant Likely

[permalink] [raw]
Subject: Re: [PATCH V3] irqchip: Add TB10x interrupt controller driver

On Fri, 31 May 2013 19:32:34 +0200 (CEST), Thomas Gleixner <[email protected]> wrote:
> On Fri, 31 May 2013, Christian Ruppert wrote:
>
> > The SOC interrupt controller driver for the Abilis Systems TB10x series of
> > SOCs based on ARC700 CPUs.
> >
> > This patch depends on commits eb76bdd407d8a90e59a06cb0158886df390e5d1c and
> > 712bc93df9e7f14b8a163148d2aa7c778e151627 from branch irq/for-arm of
> > git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git.
>
> That branch can be pulled into ARC as well. It only contains the
> changes, which are necessary for the irq domain support of the generic
> irq chip.
>
> > +static void tb10x_irq_cascade(unsigned int irq, struct irq_desc *desc)
> > +{
> > + struct irq_domain *domain = irq_desc_get_handler_data(desc);
> > +
> > + generic_handle_irq(irq_find_mapping(domain, irq));
> > +}
>
> ...
>
> > + for (i = 0; i < nrirqs; i++) {
> > + unsigned int irq = irq_of_parse_and_map(ictl, i);
> > +
> > + irq_set_handler_data(irq, domain);
> > + irq_set_chained_handler(irq, tb10x_irq_cascade);
> > + }
>
> I might be completely confused, but this does not make any sense at
> all.
>
> You allocate a linear domain and then map the interrupts in the
> domain. The mapping function retrieves the hardware interrupt number
> and creates a virtual interrupt number, installs the chip and the
> handler for the interrupt and finally returns the virtual interrupt
> number.
>
> Now you take that virtual interrupt number and install
> tb10x_irq_cascade as the handler. irq_set_chained_handler() will
> startup (unmask) the interrupt right away.
>
> In the cascade handler you take the virtual interrupt number, which
> you get as argument, and find the mapping, i.e. the matching VIRTUAL
> interrupt number for the VIRTUAL interrupt number and then call the
> handler.
>
> How is this supposed to work?

I think what is going on here is that the tb10x interrupt controller
appears to be more of a front-end to another interrupt controller with
each input wired up 1:1 to the interrupt inputs of the other controller.
(I don't know why someone would design an interrupt controller that way,
but that's another issue). The loop above is mapping each of the
interrupt inputs on the parent controller so that each child controller
can be chained to it as an input. I can't think of how else it could be
set up with the current code if the drivers were kept separate.

Christian, what is the parent interrupt controller for this SoC? It
really feels like the tb10x-ictl belongs as part of the parent
controller. I went and looked at the parent node, and I saw this:

intc: interrupt-controller {
compatible = "snps,arc700-intc";
interrupt-controller;
#interrupt-cells = <1>;
};

I noticed the conspicuous absence of a reg property. Is this something
architectural? If I were working on this system I'd drop the
snps,arc700-intc node entirely and have a single abilis,tb10x-intc that
encapsulated the properties of both (you would of course want to share
handler functions for the 'normal' inputs without the custom features).
That would eliminate the goofyness of listing 27 separate interrupts in
the abilis,tb10x-ictl interrupts property.

g.

2013-06-01 11:02:24

by Christian Ruppert

[permalink] [raw]
Subject: Re: [PATCH V3] irqchip: Add TB10x interrupt controller driver

On Fri, May 31, 2013 at 11:18:14PM +0100, Grant Likely wrote:
> On Fri, 31 May 2013 19:32:34 +0200 (CEST), Thomas Gleixner <[email protected]> wrote:
> > On Fri, 31 May 2013, Christian Ruppert wrote:
> >
> > > The SOC interrupt controller driver for the Abilis Systems TB10x series of
> > > SOCs based on ARC700 CPUs.
> > >
> > > This patch depends on commits eb76bdd407d8a90e59a06cb0158886df390e5d1c and
> > > 712bc93df9e7f14b8a163148d2aa7c778e151627 from branch irq/for-arm of
> > > git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git.
> >
> > That branch can be pulled into ARC as well. It only contains the
> > changes, which are necessary for the irq domain support of the generic
> > irq chip.

Vineet, what do you think about this? For the moment I have pulled the
patch set into our local branch and to me it doesn't matter, we just
have to make sure to respect this dependency when merging everything
together.

> > > +static void tb10x_irq_cascade(unsigned int irq, struct irq_desc *desc)
> > > +{
> > > + struct irq_domain *domain = irq_desc_get_handler_data(desc);
> > > +
> > > + generic_handle_irq(irq_find_mapping(domain, irq));
> > > +}
> >
> > ...
> >
> > > + for (i = 0; i < nrirqs; i++) {
> > > + unsigned int irq = irq_of_parse_and_map(ictl, i);
> > > +
> > > + irq_set_handler_data(irq, domain);
> > > + irq_set_chained_handler(irq, tb10x_irq_cascade);
> > > + }
> >
> > I might be completely confused, but this does not make any sense at
> > all.
> >
> > You allocate a linear domain and then map the interrupts in the
> > domain. The mapping function retrieves the hardware interrupt number
> > and creates a virtual interrupt number, installs the chip and the
> > handler for the interrupt and finally returns the virtual interrupt
> > number.
> >
> > Now you take that virtual interrupt number and install
> > tb10x_irq_cascade as the handler. irq_set_chained_handler() will
> > startup (unmask) the interrupt right away.
> >
> > In the cascade handler you take the virtual interrupt number, which
> > you get as argument, and find the mapping, i.e. the matching VIRTUAL
> > interrupt number for the VIRTUAL interrupt number and then call the
> > handler.
> >
> > How is this supposed to work?
>
> I think what is going on here is that the tb10x interrupt controller
> appears to be more of a front-end to another interrupt controller with
> each input wired up 1:1 to the interrupt inputs of the other controller.

Exactly. The TB10x interrupt controller is a front-end for the ARC CPU
built-in interrupt controller.

> (I don't know why someone would design an interrupt controller that way,
> but that's another issue).

There are several technical reasons for this front-end. The one that
concerns us most in the kernel is that the TB10x front-end does the
translation from all kinds of interrupt trigger modes to the level
triggered interrupts natively understood by the ARC CPU built-in
controller.

> The loop above is mapping each of the
> interrupt inputs on the parent controller so that each child controller
> can be chained to it as an input. I can't think of how else it could be
> set up with the current code if the drivers were kept separate.

This is exactly the intention. I haven't found an easier way to do this
either but I'm open to suggestions. Btw, I have noticed that the parent
controller interrupts from this loop are not listed in /proc/interrupts.
I'm not sure if what is done in the loop is sufficient or if I should
add something else (the naive option of using request_irq doesn't work,
the kernel saying something in the lines of "irq XX triggered but noone
cares").

> Christian, what is the parent interrupt controller for this SoC? It
> really feels like the tb10x-ictl belongs as part of the parent
> controller. I went and looked at the parent node, and I saw this:
>
> intc: interrupt-controller {
> compatible = "snps,arc700-intc";
> interrupt-controller;
> #interrupt-cells = <1>;
> };
>
> I noticed the conspicuous absence of a reg property. Is this something
> architectural?

The parent controller is part of the CPU itself, see
arch/arc/kernel/irq.c. This controller is maintained by Vineet and IMHO
we should keep it separate from the TB10x one since it is implicitly
used in all ARC-based platforms whereas the TB10x controller is used in
Abilis chips only.

> If I were working on this system I'd drop the
> snps,arc700-intc node entirely and have a single abilis,tb10x-intc that
> encapsulated the properties of both (you would of course want to share
> handler functions for the 'normal' inputs without the custom features).
> That would eliminate the goofyness of listing 27 separate interrupts in
> the abilis,tb10x-ictl interrupts property.

To complicate things even further, some ARC CPU built-in peripherals
(e.g. timers) generate interrupts directly to the ARC built-in interrupt
controller (without going through the TB10x front-end), hence the
"goofy" list of interrupts in the TB10x DT node.

Greetings,
Christian

--
Christian Ruppert , <[email protected]>
/|
Tel: +41/(0)22 816 19-42 //| 3, Chemin du Pr?-Fleuri
_// | bilis Systems CH-1228 Plan-les-Ouates

2013-06-03 04:05:42

by Vineet Gupta

[permalink] [raw]
Subject: Re: [PATCH V3] irqchip: Add TB10x interrupt controller driver

On 06/01/2013 03:48 AM, Grant Likely wrote:
> On Fri, 31 May 2013 19:32:34 +0200 (CEST), Thomas Gleixner <[email protected]> wrote:
>> irq chip.
>>> +static void tb10x_irq_cascade(unsigned int irq, struct irq_desc *desc)
>>> +{
>>> + struct irq_domain *domain = irq_desc_get_handler_data(desc);
>>> +
>>> + generic_handle_irq(irq_find_mapping(domain, irq));
>>> +}
>> ...
>>
>>> + for (i = 0; i < nrirqs; i++) {
>>> + unsigned int irq = irq_of_parse_and_map(ictl, i);
>>> +
>>> + irq_set_handler_data(irq, domain);
>>> + irq_set_chained_handler(irq, tb10x_irq_cascade);
>>> + }
>> I might be completely confused, but this does not make any sense at
>> all.
>>
>> You allocate a linear domain and then map the interrupts in the
>> domain. The mapping function retrieves the hardware interrupt number
>> and creates a virtual interrupt number, installs the chip and the
>> handler for the interrupt and finally returns the virtual interrupt
>> number.
>>
>> Now you take that virtual interrupt number and install
>> tb10x_irq_cascade as the handler. irq_set_chained_handler() will
>> startup (unmask) the interrupt right away.
>>
>> In the cascade handler you take the virtual interrupt number, which
>> you get as argument, and find the mapping, i.e. the matching VIRTUAL
>> interrupt number for the VIRTUAL interrupt number and then call the
>> handler.
>>
>> How is this supposed to work?
> I think what is going on here is that the tb10x interrupt controller
> appears to be more of a front-end to another interrupt controller with
> each input wired up 1:1 to the interrupt inputs of the other controller.
> (I don't know why someone would design an interrupt controller that way,
> but that's another issue).

Actually ARC700 core has an integrated intc with 32 lines and ability to
mask/unmask each of the lines, priority/level per line etc. Simpler SoCs don't
need to have anymore.

> The loop above is mapping each of the
> interrupt inputs on the parent controller so that each child controller
> can be chained to it as an input. I can't think of how else it could be
> set up with the current code if the drivers were kept separate.
>
> Christian, what is the parent interrupt controller for this SoC? It
> really feels like the tb10x-ictl belongs as part of the parent
> controller. I went and looked at the parent node, and I saw this:
>
> intc: interrupt-controller {
> compatible = "snps,arc700-intc";
> interrupt-controller;
> #interrupt-cells = <1>;
> };
>
> I noticed the conspicuous absence of a reg property. Is this something
> architectural?

Indeed, the intc is not memory mapped. It is accessed via the separate AUX address
space (and separate r/w instructions) similar to x86 I/O address space.

> If I were working on this system I'd drop the
> snps,arc700-intc node entirely and have a single abilis,tb10x-intc that
> encapsulated the properties of both (you would of course want to share
> handler functions for the 'normal' inputs without the custom features).
> That would eliminate the goofyness of listing 27 separate interrupts in
> the abilis,tb10x-ictl interrupts property.

But how is this different from other systems with a primary in-core intc and a
cascaded external intc. How do they do it. I guess I need to read up more on this.

-Vineet

2013-06-03 05:35:22

by Vineet Gupta

[permalink] [raw]
Subject: Re: [PATCH V3] irqchip: Add TB10x interrupt controller driver (2)

On 06/01/2013 04:31 PM, Christian Ruppert wrote:
> On Fri, May 31, 2013 at 11:18:14PM +0100, Grant Likely wrote:
>> On Fri, 31 May 2013 19:32:34 +0200 (CEST), Thomas Gleixner <[email protected]> wrote:
>>> On Fri, 31 May 2013, Christian Ruppert wrote:
>>>
>>>> The SOC interrupt controller driver for the Abilis Systems TB10x series of
>>>> SOCs based on ARC700 CPUs.
>>>>
>>>> This patch depends on commits eb76bdd407d8a90e59a06cb0158886df390e5d1c and
>>>> 712bc93df9e7f14b8a163148d2aa7c778e151627 from branch irq/for-arm of
>>>> git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git.
>>> That branch can be pulled into ARC as well. It only contains the
>>> changes, which are necessary for the irq domain support of the generic
>>> irq chip.
> Vineet, what do you think about this? For the moment I have pulled the
> patch set into our local branch and to me it doesn't matter, we just
> have to make sure to respect this dependency when merging everything
> together.

Yes what you did is right. I don't have to back-merge any of this into my tree -
given that I'm not testing the v3 intc here. In 3.11 all respective changes will
go in via the respective trees anyways.

>
>> (I don't know why someone would design an interrupt controller that way,
>> but that's another issue).
> There are several technical reasons for this front-end. The one that
> concerns us most in the kernel is that the TB10x front-end does the
> translation from all kinds of interrupt trigger modes to the level
> triggered interrupts natively understood by the ARC CPU built-in
> controller.

As I mentioned in prev email, arc in-core intc always exists, providing
reasonable functionality so that simpler SoCs don't have to do that themselves.


>> The loop above is mapping each of the
>> interrupt inputs on the parent controller so that each child controller
>> can be chained to it as an input. I can't think of how else it could be
>> set up with the current code if the drivers were kept separate.
> This is exactly the intention. I haven't found an easier way to do this
> either but I'm open to suggestions.

But the child intc must only uplink to one parent intc IRQ line. In that case why
do we need to enumerate the rest of them in code. Is that a limitation of
framework or the parent intc (with it's legacy domain instantiation) is not doing
something correct.

> Btw, I have noticed that the parent
> controller interrupts from this loop are not listed in /proc/interrupts.
> I'm not sure if what is done in the loop is sufficient or if I should
> add something else (the naive option of using request_irq doesn't work,
> the kernel saying something in the lines of "irq XX triggered but noone
> cares").
>
>> Christian, what is the parent interrupt controller for this SoC? It
>> really feels like the tb10x-ictl belongs as part of the parent
>> controller. I went and looked at the parent node, and I saw this:
>>
>> intc: interrupt-controller {
>> compatible = "snps,arc700-intc";
>> interrupt-controller;
>> #interrupt-cells = <1>;
>> };
>>
>> I noticed the conspicuous absence of a reg property. Is this something
>> architectural?
> The parent controller is part of the CPU itself, see
> arch/arc/kernel/irq.c. This controller is maintained by Vineet and IMHO
> we should keep it separate from the TB10x one since it is implicitly
> used in all ARC-based platforms whereas the TB10x controller is used in
> Abilis chips only.

Ofcourse they have to separate. The question is, what do we need to do to avoid
clunkiness in code for the cascaded intc.

>> If I were working on this system I'd drop the
>> snps,arc700-intc node entirely and have a single abilis,tb10x-intc that
>> encapsulated the properties of both (you would of course want to share
>> handler functions for the 'normal' inputs without the custom features).
>> That would eliminate the goofyness of listing 27 separate interrupts in
>> the abilis,tb10x-ictl interrupts property.
> To complicate things even further, some ARC CPU built-in peripherals
> (e.g. timers) generate interrupts directly to the ARC built-in interrupt
> controller (without going through the TB10x front-end), hence the
> "goofy" list of interrupts in the TB10x DT node.

But I presume that this is common-place for cascaded intc setups - some
peripherals hooking up directly to topmost intc would be normal. But it seems I'm
not as educated in area as I really should be.

-Vineet

2013-06-03 08:00:52

by Christian Ruppert

[permalink] [raw]
Subject: Re: [PATCH V3] irqchip: Add TB10x interrupt controller driver (2)

On Mon, Jun 03, 2013 at 11:03:13AM +0530, Vineet Gupta wrote:
> On 06/01/2013 04:31 PM, Christian Ruppert wrote:
> > On Fri, May 31, 2013 at 11:18:14PM +0100, Grant Likely wrote:
> >> On Fri, 31 May 2013 19:32:34 +0200 (CEST), Thomas Gleixner <[email protected]> wrote:
> >>> On Fri, 31 May 2013, Christian Ruppert wrote:
> [...]
> >> The loop above is mapping each of the
> >> interrupt inputs on the parent controller so that each child controller
> >> can be chained to it as an input. I can't think of how else it could be
> >> set up with the current code if the drivers were kept separate.
> > This is exactly the intention. I haven't found an easier way to do this
> > either but I'm open to suggestions.
>
> But the child intc must only uplink to one parent intc IRQ line. In that
> case why do we need to enumerate the rest of them in code. Is that a
> limitation of framework or the parent intc (with it's legacy domain
> instantiation) is not doing something correct.

You are right, it would have been possible to "merge" several interrupt
sources onto the same ARC input. This is done (where required) further
down the interrupt controller hierarchy, however, and the way our
hardware is designed is that every input line of the tb10x-ictl controls
a separate output line. Every one of these output lines is connected to
a different ARC interrupt input. tb10x-ictl does not "merge" several
interrupts:

...
|
3 --+ 3
|
4 --+ 4
+-----+ |
5 --+.....+-----+ 5
|tb10x| | ARC770
6 --+.....+-----+ 6
|-ictl| |
7 --+.....+-----+ 7
| | |
8 --+.....+-----+ 8
| | |
... ...

> [...]
> >> If I were working on this system I'd drop the
> >> snps,arc700-intc node entirely and have a single abilis,tb10x-intc that
> >> encapsulated the properties of both (you would of course want to share
> >> handler functions for the 'normal' inputs without the custom features).
> >> That would eliminate the goofyness of listing 27 separate interrupts in
> >> the abilis,tb10x-ictl interrupts property.
> > To complicate things even further, some ARC CPU built-in peripherals
> > (e.g. timers) generate interrupts directly to the ARC built-in interrupt
> > controller (without going through the TB10x front-end), hence the
> > "goofy" list of interrupts in the TB10x DT node.
>
> But I presume that this is common-place for cascaded intc setups - some
> peripherals hooking up directly to topmost intc would be normal. But it
> seems I'm not as educated in area as I really should be.

Yep, that's completely normal. But it forces us to tell the driver which
ones of the interrupts it must manage and which ones it should ignore.

Greetings,
Christian

--
Christian Ruppert , <[email protected]>
/|
Tel: +41/(0)22 816 19-42 //| 3, Chemin du Pr?-Fleuri
_// | bilis Systems CH-1228 Plan-les-Ouates

2013-06-03 09:51:30

by Grant Likely

[permalink] [raw]
Subject: Re: [PATCH V3] irqchip: Add TB10x interrupt controller driver

On Mon, Jun 3, 2013 at 5:05 AM, Vineet Gupta <[email protected]> wrote:
> On 06/01/2013 03:48 AM, Grant Likely wrote:
>> If I were working on this system I'd drop the
>> snps,arc700-intc node entirely and have a single abilis,tb10x-intc that
>> encapsulated the properties of both (you would of course want to share
>> handler functions for the 'normal' inputs without the custom features).
>> That would eliminate the goofyness of listing 27 separate interrupts in
>> the abilis,tb10x-ictl interrupts property.
>
> But how is this different from other systems with a primary in-core intc and a
> cascaded external intc. How do they do it. I guess I need to read up more on this.

Usually cascaded irq controllers have multiple irqs multiplexed onto a
single irq on the parent controller. It's the 1:1 situation that makes
this controller odd.

g,

2013-06-13 08:27:17

by Christian Ruppert

[permalink] [raw]
Subject: Re: [PATCH V3] irqchip: Add TB10x interrupt controller driver

On Sat, Jun 01, 2013 at 01:01:33PM +0200, Christian Ruppert wrote:
> On Fri, May 31, 2013 at 11:18:14PM +0100, Grant Likely wrote:
> > On Fri, 31 May 2013 19:32:34 +0200 (CEST), Thomas Gleixner <[email protected]> wrote:
> > > On Fri, 31 May 2013, Christian Ruppert wrote:
> > >
> > > > The SOC interrupt controller driver for the Abilis Systems TB10x series of
> > > > SOCs based on ARC700 CPUs.
> > > >
> > > > This patch depends on commits eb76bdd407d8a90e59a06cb0158886df390e5d1c and
> > > > 712bc93df9e7f14b8a163148d2aa7c778e151627 from branch irq/for-arm of
> > > > git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git.
> > >
> > > That branch can be pulled into ARC as well. It only contains the
> > > changes, which are necessary for the irq domain support of the generic
> > > irq chip.
>
> Vineet, what do you think about this? For the moment I have pulled the
> patch set into our local branch and to me it doesn't matter, we just
> have to make sure to respect this dependency when merging everything
> together.
>
> > > > +static void tb10x_irq_cascade(unsigned int irq, struct irq_desc *desc)
> > > > +{
> > > > + struct irq_domain *domain = irq_desc_get_handler_data(desc);
> > > > +
> > > > + generic_handle_irq(irq_find_mapping(domain, irq));
> > > > +}
> > >
> > > ...
> > >
> > > > + for (i = 0; i < nrirqs; i++) {
> > > > + unsigned int irq = irq_of_parse_and_map(ictl, i);
> > > > +
> > > > + irq_set_handler_data(irq, domain);
> > > > + irq_set_chained_handler(irq, tb10x_irq_cascade);
> > > > + }
> > >
> > > I might be completely confused, but this does not make any sense at
> > > all.
> > >
> > > You allocate a linear domain and then map the interrupts in the
> > > domain. The mapping function retrieves the hardware interrupt number
> > > and creates a virtual interrupt number, installs the chip and the
> > > handler for the interrupt and finally returns the virtual interrupt
> > > number.
> > >
> > > Now you take that virtual interrupt number and install
> > > tb10x_irq_cascade as the handler. irq_set_chained_handler() will
> > > startup (unmask) the interrupt right away.
> > >
> > > In the cascade handler you take the virtual interrupt number, which
> > > you get as argument, and find the mapping, i.e. the matching VIRTUAL
> > > interrupt number for the VIRTUAL interrupt number and then call the
> > > handler.
> > >
> > > How is this supposed to work?
> >
> > I think what is going on here is that the tb10x interrupt controller
> > appears to be more of a front-end to another interrupt controller with
> > each input wired up 1:1 to the interrupt inputs of the other controller.
>
> Exactly. The TB10x interrupt controller is a front-end for the ARC CPU
> built-in interrupt controller.
>
> > (I don't know why someone would design an interrupt controller that way,
> > but that's another issue).
>
> There are several technical reasons for this front-end. The one that
> concerns us most in the kernel is that the TB10x front-end does the
> translation from all kinds of interrupt trigger modes to the level
> triggered interrupts natively understood by the ARC CPU built-in
> controller.
>
> > The loop above is mapping each of the
> > interrupt inputs on the parent controller so that each child controller
> > can be chained to it as an input. I can't think of how else it could be
> > set up with the current code if the drivers were kept separate.
>
> This is exactly the intention. I haven't found an easier way to do this
> either but I'm open to suggestions. Btw, I have noticed that the parent
> controller interrupts from this loop are not listed in /proc/interrupts.
> I'm not sure if what is done in the loop is sufficient or if I should
> add something else (the naive option of using request_irq doesn't work,
> the kernel saying something in the lines of "irq XX triggered but noone
> cares").
>
> > Christian, what is the parent interrupt controller for this SoC? It
> > really feels like the tb10x-ictl belongs as part of the parent
> > controller. I went and looked at the parent node, and I saw this:
> >
> > intc: interrupt-controller {
> > compatible = "snps,arc700-intc";
> > interrupt-controller;
> > #interrupt-cells = <1>;
> > };
> >
> > I noticed the conspicuous absence of a reg property. Is this something
> > architectural?
>
> The parent controller is part of the CPU itself, see
> arch/arc/kernel/irq.c. This controller is maintained by Vineet and IMHO
> we should keep it separate from the TB10x one since it is implicitly
> used in all ARC-based platforms whereas the TB10x controller is used in
> Abilis chips only.
>
> > If I were working on this system I'd drop the
> > snps,arc700-intc node entirely and have a single abilis,tb10x-intc that
> > encapsulated the properties of both (you would of course want to share
> > handler functions for the 'normal' inputs without the custom features).
> > That would eliminate the goofyness of listing 27 separate interrupts in
> > the abilis,tb10x-ictl interrupts property.
>
> To complicate things even further, some ARC CPU built-in peripherals
> (e.g. timers) generate interrupts directly to the ARC built-in interrupt
> controller (without going through the TB10x front-end), hence the
> "goofy" list of interrupts in the TB10x DT node.

Hello Thomas,

Any news about this one?

Greetings,
Christian

--
Christian Ruppert , <[email protected]>
/|
Tel: +41/(0)22 816 19-42 //| 3, Chemin du Pr?-Fleuri
_// | bilis Systems CH-1228 Plan-les-Ouates

2013-06-25 13:30:09

by Christian Ruppert

[permalink] [raw]
Subject: Re: [PATCH V3] irqchip: Add TB10x interrupt controller driver

On Mon, Jun 03, 2013 at 10:51:06AM +0100, Grant Likely wrote:
> On Mon, Jun 3, 2013 at 5:05 AM, Vineet Gupta <[email protected]> wrote:
> > On 06/01/2013 03:48 AM, Grant Likely wrote:
> >> If I were working on this system I'd drop the
> >> snps,arc700-intc node entirely and have a single abilis,tb10x-intc that
> >> encapsulated the properties of both (you would of course want to share
> >> handler functions for the 'normal' inputs without the custom features).
> >> That would eliminate the goofyness of listing 27 separate interrupts in
> >> the abilis,tb10x-ictl interrupts property.
> >
> > But how is this different from other systems with a primary in-core intc and a
> > cascaded external intc. How do they do it. I guess I need to read up more on this.
>
> Usually cascaded irq controllers have multiple irqs multiplexed onto a
> single irq on the parent controller. It's the 1:1 situation that makes
> this controller odd.

You're right, this might be a bit confusing. The controller was mainly
designed as a compatibility layer between ARC770 built-in interrupts and
the rest of the system.

Do you see a better way to drive this kind of hardware? Do you have any
other comments on the driver?

Without this driver, arch/arc/plat-tb10x and related drivers will not
work and it would thus be good to have this in the kernel as quickly as
possible if there are no more issues with it.

Greetings,
Christian

--
Christian Ruppert , <[email protected]>
/|
Tel: +41/(0)22 816 19-42 //| 3, Chemin du Pr?-Fleuri
_// | bilis Systems CH-1228 Plan-les-Ouates

2013-06-25 13:33:25

by Grant Likely

[permalink] [raw]
Subject: Re: [PATCH V3] irqchip: Add TB10x interrupt controller driver

On Tue, Jun 25, 2013 at 2:29 PM, Christian Ruppert
<[email protected]> wrote:
> On Mon, Jun 03, 2013 at 10:51:06AM +0100, Grant Likely wrote:
>> On Mon, Jun 3, 2013 at 5:05 AM, Vineet Gupta <[email protected]> wrote:
>> > On 06/01/2013 03:48 AM, Grant Likely wrote:
>> >> If I were working on this system I'd drop the
>> >> snps,arc700-intc node entirely and have a single abilis,tb10x-intc that
>> >> encapsulated the properties of both (you would of course want to share
>> >> handler functions for the 'normal' inputs without the custom features).
>> >> That would eliminate the goofyness of listing 27 separate interrupts in
>> >> the abilis,tb10x-ictl interrupts property.
>> >
>> > But how is this different from other systems with a primary in-core intc and a
>> > cascaded external intc. How do they do it. I guess I need to read up more on this.
>>
>> Usually cascaded irq controllers have multiple irqs multiplexed onto a
>> single irq on the parent controller. It's the 1:1 situation that makes
>> this controller odd.
>
> You're right, this might be a bit confusing. The controller was mainly
> designed as a compatibility layer between ARC770 built-in interrupts and
> the rest of the system.
>
> Do you see a better way to drive this kind of hardware? Do you have any
> other comments on the driver?
>
> Without this driver, arch/arc/plat-tb10x and related drivers will not
> work and it would thus be good to have this in the kernel as quickly as
> possible if there are no more issues with it.

No, I don't have any other issues with it. It is unconventional, but
the framework handles it fine the way you've set it up.

g.

2013-06-25 13:58:52

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH V3] irqchip: Add TB10x interrupt controller driver

On Fri, 31 May 2013, Christian Ruppert wrote:
> The SOC interrupt controller driver for the Abilis Systems TB10x series of
> SOCs based on ARC700 CPUs.
>
> This patch depends on commits eb76bdd407d8a90e59a06cb0158886df390e5d1c and
> 712bc93df9e7f14b8a163148d2aa7c778e151627 from branch irq/for-arm of
> git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git.

This should go below --- as it is not part of the changelog.

> Signed-off-by: Christian Ruppert <[email protected]>
> Signed-off-by: Pierrick Hascoet <[email protected]>

Why is Pierrick in the SOB chain?

> ---
> .../interrupt-controller/abilis,tb10x-ictl.txt | 38 ++++
> arch/arc/boot/dts/abilis_tb100.dtsi | 32 ++--
> arch/arc/boot/dts/abilis_tb101.dtsi | 32 ++--
> arch/arc/boot/dts/abilis_tb10x.dtsi | 32 ++--
> arch/arc/plat-tb10x/Kconfig | 1 +
> drivers/irqchip/Kconfig | 5 +
> drivers/irqchip/Makefile | 1 +
> drivers/irqchip/irq-tb10x.c | 195 ++++++++++++++++++++

I can pick it up, but I'm not so fond of carrying arch/arc patches
which might conflict with other stuff in the arc tree. Veenet, if I
should pick the whole thing up, I'd like to have an acked-by at least.

Thanks,

tglx

2013-06-25 14:12:16

by Christian Ruppert

[permalink] [raw]
Subject: Re: [PATCH V3] irqchip: Add TB10x interrupt controller driver

On Tue, Jun 25, 2013 at 03:58:43PM +0200, Thomas Gleixner wrote:
> On Fri, 31 May 2013, Christian Ruppert wrote:
> > The SOC interrupt controller driver for the Abilis Systems TB10x series of
> > SOCs based on ARC700 CPUs.
> >
> > This patch depends on commits eb76bdd407d8a90e59a06cb0158886df390e5d1c and
> > 712bc93df9e7f14b8a163148d2aa7c778e151627 from branch irq/for-arm of
> > git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git.
>
> This should go below --- as it is not part of the changelog.

OK, I will change that.

> > Signed-off-by: Christian Ruppert <[email protected]>
> > Signed-off-by: Pierrick Hascoet <[email protected]>
>
> Why is Pierrick in the SOB chain?

We work on the platform port together and review and test each others'
patches. It is planned submitting several of his patches as soon as
basic platform is in.

> > ---
> > .../interrupt-controller/abilis,tb10x-ictl.txt | 38 ++++
> > arch/arc/boot/dts/abilis_tb100.dtsi | 32 ++--
> > arch/arc/boot/dts/abilis_tb101.dtsi | 32 ++--
> > arch/arc/boot/dts/abilis_tb10x.dtsi | 32 ++--
> > arch/arc/plat-tb10x/Kconfig | 1 +
> > drivers/irqchip/Kconfig | 5 +
> > drivers/irqchip/Makefile | 1 +
> > drivers/irqchip/irq-tb10x.c | 195 ++++++++++++++++++++
>
> I can pick it up, but I'm not so fond of carrying arch/arc patches
> which might conflict with other stuff in the arc tree. Veenet, if I
> should pick the whole thing up, I'd like to have an acked-by at least.

Would you prefer if we separated everything in arch/arc from this patch
and push it through Vineet's channel?

Greetings,
Christian

--
Christian Ruppert , <[email protected]>
/|
Tel: +41/(0)22 816 19-42 //| 3, Chemin du Pr?-Fleuri
_// | bilis Systems CH-1228 Plan-les-Ouates

2013-06-25 14:37:35

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH V3] irqchip: Add TB10x interrupt controller driver

On Tue, 25 Jun 2013, Christian Ruppert wrote:
> On Tue, Jun 25, 2013 at 03:58:43PM +0200, Thomas Gleixner wrote:
> > On Fri, 31 May 2013, Christian Ruppert wrote:
> > > The SOC interrupt controller driver for the Abilis Systems TB10x series of
> > > SOCs based on ARC700 CPUs.
> > >
> > > This patch depends on commits eb76bdd407d8a90e59a06cb0158886df390e5d1c and
> > > 712bc93df9e7f14b8a163148d2aa7c778e151627 from branch irq/for-arm of
> > > git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git.
> >
> > This should go below --- as it is not part of the changelog.
>
> OK, I will change that.
>
> > > Signed-off-by: Christian Ruppert <[email protected]>
> > > Signed-off-by: Pierrick Hascoet <[email protected]>
> >
> > Why is Pierrick in the SOB chain?
>
> We work on the platform port together and review and test each others'
> patches. It is planned submitting several of his patches as soon as
> basic platform is in.
>
> > > ---
> > > .../interrupt-controller/abilis,tb10x-ictl.txt | 38 ++++
> > > arch/arc/boot/dts/abilis_tb100.dtsi | 32 ++--
> > > arch/arc/boot/dts/abilis_tb101.dtsi | 32 ++--
> > > arch/arc/boot/dts/abilis_tb10x.dtsi | 32 ++--
> > > arch/arc/plat-tb10x/Kconfig | 1 +
> > > drivers/irqchip/Kconfig | 5 +
> > > drivers/irqchip/Makefile | 1 +
> > > drivers/irqchip/irq-tb10x.c | 195 ++++++++++++++++++++
> >
> > I can pick it up, but I'm not so fond of carrying arch/arc patches
> > which might conflict with other stuff in the arc tree. Veenet, if I
> > should pick the whole thing up, I'd like to have an acked-by at least.
>
> Would you prefer if we separated everything in arch/arc from this patch
> and push it through Vineet's channel?

If it can be split w/o breaking the world, this would be the most
elegant solution.

Thanks,

tglx

2013-06-25 16:30:54

by Christian Ruppert

[permalink] [raw]
Subject: [PATCH V4] irqchip: Add TB10x interrupt controller driver

The SOC interrupt controller driver for the Abilis Systems TB10x series of
SOCs based on ARC700 CPUs.

Signed-off-by: Christian Ruppert <[email protected]>
Signed-off-by: Pierrick Hascoet <[email protected]>
---
This patch depends on commits eb76bdd407d8a90e59a06cb0158886df390e5d1c and
712bc93df9e7f14b8a163148d2aa7c778e151627 from branch irq/for-arm of
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git.

.../interrupt-controller/abilis,tb10x-ictl.txt | 38 ++++
drivers/irqchip/Kconfig | 5 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-tb10x.c | 195 ++++++++++++++++++++
4 files changed, 239 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x-ictl.txt
create mode 100644 drivers/irqchip/irq-tb10x.c

diff --git a/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x-ictl.txt b/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x-ictl.txt
new file mode 100644
index 0000000..9d52d5a
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x-ictl.txt
@@ -0,0 +1,38 @@
+TB10x Top Level Interrupt Controller
+====================================
+
+The Abilis TB10x SOC contains a custom interrupt controller. It performs
+one-to-one mapping of external interrupt sources to CPU interrupts and
+provides support for reconfigurable trigger modes.
+
+Required properties
+-------------------
+
+- compatible: Should be "abilis,tb10x-ictl"
+- reg: specifies physical base address and size of register range.
+- interrupt-congroller: Identifies the node as an interrupt controller.
+- #interrupt cells: Specifies the number of cells used to encode an interrupt
+ source connected to this controller. The value shall be 2.
+- interrupt-parent: Specifies the parent interrupt controller.
+- interrupts: Specifies the list of interrupt lines which are handled by
+ the interrupt controller in the parent controller's notation. Interrupts
+ are mapped one-to-one to parent interrupts.
+
+Example
+-------
+
+intc: interrupt-controller { /* Parent interrupt controller */
+ interrupt-controller;
+ #interrupt-cells = <1>; /* For example below */
+ /* ... */
+};
+
+tb10x_ictl: pic@2000 { /* TB10x interrupt controller */
+ compatible = "abilis,tb10x-ictl";
+ reg = <0x2000 0x20>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupt-parent = <&intc>;
+ interrupts = <5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+ 20 21 22 23 24 25 26 27 28 29 30 31>;
+};
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 4a33351..8843f21 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -33,6 +33,11 @@ config RENESAS_IRQC
bool
select IRQ_DOMAIN

+config TB10X_IRQC
+ bool
+ select IRQ_DOMAIN
+ select GENERIC_IRQ_CHIP
+
config VERSATILE_FPGA_IRQ
bool
select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index cda4cb5..b45e4a4 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_METAG) += irq-metag-ext.o
obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o
obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
+obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o
obj-$(CONFIG_ARM_GIC) += irq-gic.o
obj-$(CONFIG_ARM_VIC) += irq-vic.o
obj-$(CONFIG_SIRF_IRQ) += irq-sirfsoc.o
diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c
new file mode 100644
index 0000000..7c44c99
--- /dev/null
+++ b/drivers/irqchip/irq-tb10x.c
@@ -0,0 +1,195 @@
+/*
+ * Abilis Systems interrupt controller driver
+ *
+ * Copyright (C) Abilis Systems 2012
+ *
+ * Author: Christian Ruppert <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include "irqchip.h"
+
+#define AB_IRQCTL_INT_ENABLE 0x00
+#define AB_IRQCTL_INT_STATUS 0x04
+#define AB_IRQCTL_SRC_MODE 0x08
+#define AB_IRQCTL_SRC_POLARITY 0x0C
+#define AB_IRQCTL_INT_MODE 0x10
+#define AB_IRQCTL_INT_POLARITY 0x14
+#define AB_IRQCTL_INT_FORCE 0x18
+
+#define AB_IRQCTL_MAXIRQ 32
+
+static inline void ab_irqctl_writereg(struct irq_chip_generic *gc, u32 reg,
+ u32 val)
+{
+ irq_reg_writel(val, gc->reg_base + reg);
+}
+
+static inline u32 ab_irqctl_readreg(struct irq_chip_generic *gc, u32 reg)
+{
+ return irq_reg_readl(gc->reg_base + reg);
+}
+
+static int tb10x_irq_set_type(struct irq_data *data, unsigned int flow_type)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
+ uint32_t im, mod, pol;
+
+ im = data->mask;
+
+ irq_gc_lock(gc);
+
+ mod = ab_irqctl_readreg(gc, AB_IRQCTL_SRC_MODE) | im;
+ pol = ab_irqctl_readreg(gc, AB_IRQCTL_SRC_POLARITY) | im;
+
+ switch (flow_type & IRQF_TRIGGER_MASK) {
+ case IRQ_TYPE_EDGE_FALLING:
+ pol ^= im;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ mod ^= im;
+ break;
+ case IRQ_TYPE_NONE:
+ flow_type = IRQ_TYPE_LEVEL_LOW;
+ case IRQ_TYPE_LEVEL_LOW:
+ mod ^= im;
+ pol ^= im;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ break;
+ default:
+ irq_gc_unlock(gc);
+ pr_err("%s: Cannot assign multiple trigger modes to IRQ %d.\n",
+ __func__, data->irq);
+ return -EBADR;
+ }
+
+ irqd_set_trigger_type(data, flow_type);
+ irq_setup_alt_chip(data, flow_type);
+
+ ab_irqctl_writereg(gc, AB_IRQCTL_SRC_MODE, mod);
+ ab_irqctl_writereg(gc, AB_IRQCTL_SRC_POLARITY, pol);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_STATUS, im);
+
+ irq_gc_unlock(gc);
+
+ return IRQ_SET_MASK_OK;
+}
+
+static void tb10x_irq_cascade(unsigned int irq, struct irq_desc *desc)
+{
+ struct irq_domain *domain = irq_desc_get_handler_data(desc);
+
+ generic_handle_irq(irq_find_mapping(domain, irq));
+}
+
+static int __init of_tb10x_init_irq(struct device_node *ictl,
+ struct device_node *parent)
+{
+ int i, ret, nrirqs = of_irq_count(ictl);
+ struct resource mem;
+ struct irq_chip_generic *gc;
+ struct irq_domain *domain;
+ void __iomem *reg_base;
+
+ if (of_address_to_resource(ictl, 0, &mem)) {
+ pr_err("%s: No registers declared in DeviceTree.\n",
+ ictl->name);
+ return -EINVAL;
+ }
+
+ if (!request_mem_region(mem.start, resource_size(&mem),
+ ictl->name)) {
+ pr_err("%s: Request mem region failed.\n", ictl->name);
+ return -EBUSY;
+ }
+
+ reg_base = ioremap(mem.start, resource_size(&mem));
+ if (!reg_base) {
+ ret = -EBUSY;
+ pr_err("%s: ioremap failed.\n", ictl->name);
+ goto ioremap_fail;
+ }
+
+ domain = irq_domain_add_linear(ictl, AB_IRQCTL_MAXIRQ,
+ &irq_generic_chip_ops, NULL);
+ if (!domain) {
+ ret = -ENOMEM;
+ pr_err("%s: Could not register interrupt domain.\n",
+ ictl->name);
+ goto irq_domain_add_fail;
+ }
+
+ ret = irq_alloc_domain_generic_chips(domain, AB_IRQCTL_MAXIRQ,
+ 2, ictl->name, handle_level_irq,
+ IRQ_NOREQUEST, IRQ_NOPROBE,
+ IRQ_GC_INIT_MASK_CACHE);
+ if (ret) {
+ pr_err("%s: Could not allocate generic interrupt chip.\n",
+ ictl->name);
+ goto gc_alloc_fail;
+ }
+
+ gc = domain->gc->gc[0];
+ gc->reg_base = reg_base;
+
+ gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types[0].chip.irq_set_type = tb10x_irq_set_type;
+ gc->chip_types[0].regs.mask = AB_IRQCTL_INT_ENABLE;
+
+ gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
+ gc->chip_types[1].chip.name = gc->chip_types[0].chip.name;
+ gc->chip_types[1].chip.irq_ack = irq_gc_ack_set_bit;
+ gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types[1].chip.irq_set_type = tb10x_irq_set_type;
+ gc->chip_types[1].regs.ack = AB_IRQCTL_INT_STATUS;
+ gc->chip_types[1].regs.mask = AB_IRQCTL_INT_ENABLE;
+ gc->chip_types[1].handler = handle_edge_irq;
+
+ for (i = 0; i < nrirqs; i++) {
+ unsigned int irq = irq_of_parse_and_map(ictl, i);
+
+ irq_set_handler_data(irq, domain);
+ irq_set_chained_handler(irq, tb10x_irq_cascade);
+ }
+
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_ENABLE, 0);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_MODE, 0);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_POLARITY, 0);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_STATUS, ~0UL);
+
+ return 0;
+
+gc_alloc_fail:
+ irq_domain_remove(domain);
+irq_domain_add_fail:
+ iounmap(reg_base);
+ioremap_fail:
+ release_mem_region(mem.start, resource_size(&mem));
+ return ret;
+}
+IRQCHIP_DECLARE(tb10x_intc, "abilis,tb10x-ictl", of_tb10x_init_irq);
--
1.7.1

Subject: [tip:irq/core] irqchip: Add TB10x interrupt controller driver

Commit-ID: b06eb0173ef1d9366d14b4ca3e8e38dc72b03e8b
Gitweb: http://git.kernel.org/tip/b06eb0173ef1d9366d14b4ca3e8e38dc72b03e8b
Author: Christian Ruppert <[email protected]>
AuthorDate: Tue, 25 Jun 2013 18:29:57 +0200
Committer: Thomas Gleixner <[email protected]>
CommitDate: Tue, 25 Jun 2013 18:54:21 +0200

irqchip: Add TB10x interrupt controller driver

The SOC interrupt controller driver for the Abilis Systems TB10x series of
SOCs based on ARC700 CPUs.

Signed-off-by: Christian Ruppert <[email protected]>
Signed-off-by: Pierrick Hascoet <[email protected]>
Cc: Vineet Gupta <[email protected]>
Cc: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Rob Landley <[email protected]>
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Thomas Gleixner <[email protected]>
---
.../interrupt-controller/abilis,tb10x-ictl.txt | 38 ++++
drivers/irqchip/Kconfig | 5 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-tb10x.c | 195 +++++++++++++++++++++
4 files changed, 239 insertions(+)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x-ictl.txt b/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x-ictl.txt
new file mode 100644
index 0000000..9d52d5a
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x-ictl.txt
@@ -0,0 +1,38 @@
+TB10x Top Level Interrupt Controller
+====================================
+
+The Abilis TB10x SOC contains a custom interrupt controller. It performs
+one-to-one mapping of external interrupt sources to CPU interrupts and
+provides support for reconfigurable trigger modes.
+
+Required properties
+-------------------
+
+- compatible: Should be "abilis,tb10x-ictl"
+- reg: specifies physical base address and size of register range.
+- interrupt-congroller: Identifies the node as an interrupt controller.
+- #interrupt cells: Specifies the number of cells used to encode an interrupt
+ source connected to this controller. The value shall be 2.
+- interrupt-parent: Specifies the parent interrupt controller.
+- interrupts: Specifies the list of interrupt lines which are handled by
+ the interrupt controller in the parent controller's notation. Interrupts
+ are mapped one-to-one to parent interrupts.
+
+Example
+-------
+
+intc: interrupt-controller { /* Parent interrupt controller */
+ interrupt-controller;
+ #interrupt-cells = <1>; /* For example below */
+ /* ... */
+};
+
+tb10x_ictl: pic@2000 { /* TB10x interrupt controller */
+ compatible = "abilis,tb10x-ictl";
+ reg = <0x2000 0x20>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupt-parent = <&intc>;
+ interrupts = <5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+ 20 21 22 23 24 25 26 27 28 29 30 31>;
+};
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 68c3107..d4d1f4b 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -38,6 +38,11 @@ config RENESAS_IRQC
bool
select IRQ_DOMAIN

+config TB10X_IRQC
+ bool
+ select IRQ_DOMAIN
+ select GENERIC_IRQ_CHIP
+
config VERSATILE_FPGA_IRQ
bool
select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 55df3bd..8fe6ad5 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o
obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o
obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o
obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o
+obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o
diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c
new file mode 100644
index 0000000..7c44c99
--- /dev/null
+++ b/drivers/irqchip/irq-tb10x.c
@@ -0,0 +1,195 @@
+/*
+ * Abilis Systems interrupt controller driver
+ *
+ * Copyright (C) Abilis Systems 2012
+ *
+ * Author: Christian Ruppert <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include "irqchip.h"
+
+#define AB_IRQCTL_INT_ENABLE 0x00
+#define AB_IRQCTL_INT_STATUS 0x04
+#define AB_IRQCTL_SRC_MODE 0x08
+#define AB_IRQCTL_SRC_POLARITY 0x0C
+#define AB_IRQCTL_INT_MODE 0x10
+#define AB_IRQCTL_INT_POLARITY 0x14
+#define AB_IRQCTL_INT_FORCE 0x18
+
+#define AB_IRQCTL_MAXIRQ 32
+
+static inline void ab_irqctl_writereg(struct irq_chip_generic *gc, u32 reg,
+ u32 val)
+{
+ irq_reg_writel(val, gc->reg_base + reg);
+}
+
+static inline u32 ab_irqctl_readreg(struct irq_chip_generic *gc, u32 reg)
+{
+ return irq_reg_readl(gc->reg_base + reg);
+}
+
+static int tb10x_irq_set_type(struct irq_data *data, unsigned int flow_type)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
+ uint32_t im, mod, pol;
+
+ im = data->mask;
+
+ irq_gc_lock(gc);
+
+ mod = ab_irqctl_readreg(gc, AB_IRQCTL_SRC_MODE) | im;
+ pol = ab_irqctl_readreg(gc, AB_IRQCTL_SRC_POLARITY) | im;
+
+ switch (flow_type & IRQF_TRIGGER_MASK) {
+ case IRQ_TYPE_EDGE_FALLING:
+ pol ^= im;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ mod ^= im;
+ break;
+ case IRQ_TYPE_NONE:
+ flow_type = IRQ_TYPE_LEVEL_LOW;
+ case IRQ_TYPE_LEVEL_LOW:
+ mod ^= im;
+ pol ^= im;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ break;
+ default:
+ irq_gc_unlock(gc);
+ pr_err("%s: Cannot assign multiple trigger modes to IRQ %d.\n",
+ __func__, data->irq);
+ return -EBADR;
+ }
+
+ irqd_set_trigger_type(data, flow_type);
+ irq_setup_alt_chip(data, flow_type);
+
+ ab_irqctl_writereg(gc, AB_IRQCTL_SRC_MODE, mod);
+ ab_irqctl_writereg(gc, AB_IRQCTL_SRC_POLARITY, pol);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_STATUS, im);
+
+ irq_gc_unlock(gc);
+
+ return IRQ_SET_MASK_OK;
+}
+
+static void tb10x_irq_cascade(unsigned int irq, struct irq_desc *desc)
+{
+ struct irq_domain *domain = irq_desc_get_handler_data(desc);
+
+ generic_handle_irq(irq_find_mapping(domain, irq));
+}
+
+static int __init of_tb10x_init_irq(struct device_node *ictl,
+ struct device_node *parent)
+{
+ int i, ret, nrirqs = of_irq_count(ictl);
+ struct resource mem;
+ struct irq_chip_generic *gc;
+ struct irq_domain *domain;
+ void __iomem *reg_base;
+
+ if (of_address_to_resource(ictl, 0, &mem)) {
+ pr_err("%s: No registers declared in DeviceTree.\n",
+ ictl->name);
+ return -EINVAL;
+ }
+
+ if (!request_mem_region(mem.start, resource_size(&mem),
+ ictl->name)) {
+ pr_err("%s: Request mem region failed.\n", ictl->name);
+ return -EBUSY;
+ }
+
+ reg_base = ioremap(mem.start, resource_size(&mem));
+ if (!reg_base) {
+ ret = -EBUSY;
+ pr_err("%s: ioremap failed.\n", ictl->name);
+ goto ioremap_fail;
+ }
+
+ domain = irq_domain_add_linear(ictl, AB_IRQCTL_MAXIRQ,
+ &irq_generic_chip_ops, NULL);
+ if (!domain) {
+ ret = -ENOMEM;
+ pr_err("%s: Could not register interrupt domain.\n",
+ ictl->name);
+ goto irq_domain_add_fail;
+ }
+
+ ret = irq_alloc_domain_generic_chips(domain, AB_IRQCTL_MAXIRQ,
+ 2, ictl->name, handle_level_irq,
+ IRQ_NOREQUEST, IRQ_NOPROBE,
+ IRQ_GC_INIT_MASK_CACHE);
+ if (ret) {
+ pr_err("%s: Could not allocate generic interrupt chip.\n",
+ ictl->name);
+ goto gc_alloc_fail;
+ }
+
+ gc = domain->gc->gc[0];
+ gc->reg_base = reg_base;
+
+ gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types[0].chip.irq_set_type = tb10x_irq_set_type;
+ gc->chip_types[0].regs.mask = AB_IRQCTL_INT_ENABLE;
+
+ gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
+ gc->chip_types[1].chip.name = gc->chip_types[0].chip.name;
+ gc->chip_types[1].chip.irq_ack = irq_gc_ack_set_bit;
+ gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types[1].chip.irq_set_type = tb10x_irq_set_type;
+ gc->chip_types[1].regs.ack = AB_IRQCTL_INT_STATUS;
+ gc->chip_types[1].regs.mask = AB_IRQCTL_INT_ENABLE;
+ gc->chip_types[1].handler = handle_edge_irq;
+
+ for (i = 0; i < nrirqs; i++) {
+ unsigned int irq = irq_of_parse_and_map(ictl, i);
+
+ irq_set_handler_data(irq, domain);
+ irq_set_chained_handler(irq, tb10x_irq_cascade);
+ }
+
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_ENABLE, 0);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_MODE, 0);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_POLARITY, 0);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_STATUS, ~0UL);
+
+ return 0;
+
+gc_alloc_fail:
+ irq_domain_remove(domain);
+irq_domain_add_fail:
+ iounmap(reg_base);
+ioremap_fail:
+ release_mem_region(mem.start, resource_size(&mem));
+ return ret;
+}
+IRQCHIP_DECLARE(tb10x_intc, "abilis,tb10x-ictl", of_tb10x_init_irq);

2013-06-26 04:18:08

by Vineet Gupta

[permalink] [raw]
Subject: Re: [PATCH V3] irqchip: Add TB10x interrupt controller driver

Hi Thomas,

On 06/25/2013 08:07 PM, Thomas Gleixner wrote:
>
>>> I can pick it up, but I'm not so fond of carrying arch/arc patches
>>> which might conflict with other stuff in the arc tree. Veenet, if I
>>> should pick the whole thing up, I'd like to have an acked-by at least.
>> Would you prefer if we separated everything in arch/arc from this patch
>> and push it through Vineet's channel?
> If it can be split w/o breaking the world, this would be the most
> elegant solution.

I would have preferred it to be part of same patch, for bisectability if nothing
else. However your tree gets merged in pretty early in the cycle so I'll make sure
my pull request goes in after yours.

Anyways, thanks for merging the driver.

Chrisitian, please send over the forked out arch/arc bits for this to me
separately. The i2c DT changes seem to touch different files though so I don't see
merge issues as of now.

-Vineet

2013-06-26 04:24:04

by Vineet Gupta

[permalink] [raw]
Subject: Re: [PATCH V3] irqchip: Add TB10x interrupt controller driver

On 06/25/2013 07:41 PM, Christian Ruppert wrote:
>>> > > Signed-off-by: Christian Ruppert <[email protected]>
>>> > > Signed-off-by: Pierrick Hascoet <[email protected]>
>> >
>> > Why is Pierrick in the SOB chain?
> We work on the platform port together and review and test each others'
> patches. It is planned submitting several of his patches as soon as
> basic platform is in.

Which is fine, however the rule is, person sending the patch needs to do the last SOB.

2013-06-26 15:03:21

by Christian Ruppert

[permalink] [raw]
Subject: [PATCH] ARC: [TB10x] Updates for irqchip driver

Device tree and Kconfig updates for irqchip driver.

Signed-off-by: Christian Ruppert <[email protected]>
---
arch/arc/boot/dts/abilis_tb100.dtsi | 32 ++++++++++++++------------------
arch/arc/boot/dts/abilis_tb101.dtsi | 32 ++++++++++++++------------------
arch/arc/boot/dts/abilis_tb10x.dtsi | 32 ++++++++++++++------------------
arch/arc/plat-tb10x/Kconfig | 1 +
4 files changed, 43 insertions(+), 54 deletions(-)

diff --git a/arch/arc/boot/dts/abilis_tb100.dtsi b/arch/arc/boot/dts/abilis_tb100.dtsi
index 941ad11..d9f8249 100644
--- a/arch/arc/boot/dts/abilis_tb100.dtsi
+++ b/arch/arc/boot/dts/abilis_tb100.dtsi
@@ -21,10 +21,6 @@

/include/ "abilis_tb10x.dtsi"

-/* interrupt specifiers
- * --------------------
- * 0: rising, 1: low, 2: high, 3: falling,
- */

/ {
clock-frequency = <500000000>; /* 500 MHZ */
@@ -173,7 +169,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF140000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -185,7 +181,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF141000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -197,7 +193,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF142000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -209,7 +205,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF143000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -221,7 +217,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF144000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -233,7 +229,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF145000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -245,7 +241,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF146000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -257,7 +253,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF147000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -269,7 +265,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF148000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -281,7 +277,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF149000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -293,7 +289,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14A000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -305,7 +301,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14B000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -317,7 +313,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14C000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -329,7 +325,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14D000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
diff --git a/arch/arc/boot/dts/abilis_tb101.dtsi b/arch/arc/boot/dts/abilis_tb101.dtsi
index fd25c21..da8ca79 100644
--- a/arch/arc/boot/dts/abilis_tb101.dtsi
+++ b/arch/arc/boot/dts/abilis_tb101.dtsi
@@ -21,10 +21,6 @@

/include/ "abilis_tb10x.dtsi"

-/* interrupt specifiers
- * --------------------
- * 0: rising, 1: low, 2: high, 3: falling,
- */

/ {
clock-frequency = <500000000>; /* 500 MHZ */
@@ -182,7 +178,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF140000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -194,7 +190,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF141000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -206,7 +202,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF142000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -218,7 +214,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF143000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -230,7 +226,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF144000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -242,7 +238,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF145000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -254,7 +250,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF146000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -266,7 +262,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF147000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -278,7 +274,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF148000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -290,7 +286,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF149000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -302,7 +298,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14A000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -314,7 +310,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14B000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -326,7 +322,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14C000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -338,7 +334,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14D000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
diff --git a/arch/arc/boot/dts/abilis_tb10x.dtsi b/arch/arc/boot/dts/abilis_tb10x.dtsi
index b97e305..edf56f4 100644
--- a/arch/arc/boot/dts/abilis_tb10x.dtsi
+++ b/arch/arc/boot/dts/abilis_tb10x.dtsi
@@ -19,10 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

-/* interrupt specifiers
- * --------------------
- * 0: rising, 1: low, 2: high, 3: falling,
- */

/ {
compatible = "abilis,arc-tb10x";
@@ -78,7 +74,7 @@
#interrupt-cells = <1>;
};
tb10x_ictl: pic@fe002000 {
- compatible = "abilis,tb10x_ictl";
+ compatible = "abilis,tb10x-ictl";
reg = <0xFE002000 0x20>;
interrupt-controller;
#interrupt-cells = <2>;
@@ -91,7 +87,7 @@
compatible = "snps,dw-apb-uart";
reg = <0xFF100000 0x100>;
clock-frequency = <166666666>;
- interrupts = <25 1>;
+ interrupts = <25 8>;
reg-shift = <2>;
reg-io-width = <4>;
interrupt-parent = <&tb10x_ictl>;
@@ -100,7 +96,7 @@
compatible = "snps,dwmac-3.70a","snps,dwmac";
reg = <0xFE100000 0x1058>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <6 1>;
+ interrupts = <6 8>;
interrupt-names = "macirq";
clocks = <&ahb_clk>;
clock-names = "stmmaceth";
@@ -109,7 +105,7 @@
compatible = "snps,dma-spear1340";
reg = <0xFE000000 0x400>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <14 1>;
+ interrupts = <14 8>;
dma-channels = <6>;
dma-requests = <0>;
dma-masters = <1>;
@@ -128,7 +124,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF120000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};
i2c1: i2c@FF121000 {
@@ -137,7 +133,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF121000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};
i2c2: i2c@FF122000 {
@@ -146,7 +142,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF122000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};
i2c3: i2c@FF123000 {
@@ -155,7 +151,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF123000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};
i2c4: i2c@FF124000 {
@@ -164,7 +160,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF124000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};

@@ -176,7 +172,7 @@
num-cs = <1>;
reg = <0xFE010000 0x20>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <26 1>;
+ interrupts = <26 8>;
clocks = <&ahb_clk>;
};
spi1: spi@0xFE011000 {
@@ -187,7 +183,7 @@
num-cs = <2>;
reg = <0xFE011000 0x20>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <10 1>;
+ interrupts = <10 8>;
clocks = <&ahb_clk>;
};

@@ -195,7 +191,7 @@
compatible = "abilis,tb100-tsm";
reg = <0xff316000 0x400>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <17 1>;
+ interrupts = <17 8>;
output-clkdiv = <4>;
global-packet-delay = <0x21>;
port-packet-delay = <0>;
@@ -213,7 +209,7 @@
"cpuctrl",
"a6it_int_force";
interrupt-parent = <&tb10x_ictl>;
- interrupts = <20 1>, <19 1>;
+ interrupts = <20 2>, <19 2>;
interrupt-names = "cmd_irq", "event_irq";
};
tb10x_mdsc0: tb10x-mdscr@FF300000 {
@@ -239,7 +235,7 @@
compatible = "abilis,tb100-wfb";
reg = <0xff319000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <16 1>;
+ interrupts = <16 8>;
};
};
};
diff --git a/arch/arc/plat-tb10x/Kconfig b/arch/arc/plat-tb10x/Kconfig
index 1d34521..1ab386b 100644
--- a/arch/arc/plat-tb10x/Kconfig
+++ b/arch/arc/plat-tb10x/Kconfig
@@ -22,6 +22,7 @@ menuconfig ARC_PLAT_TB10X
select PINCTRL
select PINMUX
select ARCH_REQUIRE_GPIOLIB
+ select TB10X_IRQC
help
Support for platforms based on the TB10x home media gateway SOC by
Abilis Systems. TB10x is based on the ARC700 CPU architecture.
--
1.7.1

2013-06-27 02:33:35

by Vineet Gupta

[permalink] [raw]
Subject: Re: [PATCH] ARC: [TB10x] Updates for irqchip driver

On 06/26/2013 07:31 PM, Christian Ruppert wrote:
> Device tree and Kconfig updates for irqchip driver.
>
> Signed-off-by: Christian Ruppert <[email protected]>

Applied to ARC for-next

Thx,
-Vineet