summaryrefslogtreecommitdiff
path: root/target/linux/lantiq/patches-3.7/0105-MIPS-lantiq-rework-external-irq-code.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/lantiq/patches-3.7/0105-MIPS-lantiq-rework-external-irq-code.patch')
-rw-r--r--target/linux/lantiq/patches-3.7/0105-MIPS-lantiq-rework-external-irq-code.patch214
1 files changed, 214 insertions, 0 deletions
diff --git a/target/linux/lantiq/patches-3.7/0105-MIPS-lantiq-rework-external-irq-code.patch b/target/linux/lantiq/patches-3.7/0105-MIPS-lantiq-rework-external-irq-code.patch
new file mode 100644
index 0000000..88659c2
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0105-MIPS-lantiq-rework-external-irq-code.patch
@@ -0,0 +1,214 @@
+From edd237c93d564e698e169a89d1b1b35248c5ef4a Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 3 Dec 2012 21:44:30 +0100
+Subject: [PATCH 105/123] MIPS: lantiq: rework external irq code
+
+This code makes the irqs used by the EIU loadable from the DT. Additionally we
+add a helper that allows the pinctrl layer to map external irqs to real irq
+numbers.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/include/asm/mach-lantiq/lantiq.h | 1 +
+ arch/mips/lantiq/irq.c | 104 +++++++++++++++++++---------
+ 2 files changed, 73 insertions(+), 32 deletions(-)
+
+diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h
+index 76be7a0..f196cce 100644
+--- a/arch/mips/include/asm/mach-lantiq/lantiq.h
++++ b/arch/mips/include/asm/mach-lantiq/lantiq.h
+@@ -34,6 +34,7 @@ extern spinlock_t ebu_lock;
+ extern void ltq_disable_irq(struct irq_data *data);
+ extern void ltq_mask_and_ack_irq(struct irq_data *data);
+ extern void ltq_enable_irq(struct irq_data *data);
++extern int ltq_eiu_get_irq(int exin);
+
+ /* clock handling */
+ extern int clk_activate(struct clk *clk);
+diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
+index f36acd1..48407f6 100644
+--- a/arch/mips/lantiq/irq.c
++++ b/arch/mips/lantiq/irq.c
+@@ -33,17 +33,10 @@
+ /* register definitions - external irqs */
+ #define LTQ_EIU_EXIN_C 0x0000
+ #define LTQ_EIU_EXIN_INIC 0x0004
++#define LTQ_EIU_EXIN_INC 0x0008
+ #define LTQ_EIU_EXIN_INEN 0x000C
+
+-/* irq numbers used by the external interrupt unit (EIU) */
+-#define LTQ_EIU_IR0 (INT_NUM_IM4_IRL0 + 30)
+-#define LTQ_EIU_IR1 (INT_NUM_IM3_IRL0 + 31)
+-#define LTQ_EIU_IR2 (INT_NUM_IM1_IRL0 + 26)
+-#define LTQ_EIU_IR3 INT_NUM_IM1_IRL0
+-#define LTQ_EIU_IR4 (INT_NUM_IM1_IRL0 + 1)
+-#define LTQ_EIU_IR5 (INT_NUM_IM1_IRL0 + 2)
+-#define LTQ_EIU_IR6 (INT_NUM_IM2_IRL0 + 30)
+-#define XWAY_EXIN_COUNT 3
++/* number of external interrupts */
+ #define MAX_EIU 6
+
+ /* the performance counter */
+@@ -72,20 +65,19 @@
+ int gic_present;
+ #endif
+
+-static unsigned short ltq_eiu_irq[MAX_EIU] = {
+- LTQ_EIU_IR0,
+- LTQ_EIU_IR1,
+- LTQ_EIU_IR2,
+- LTQ_EIU_IR3,
+- LTQ_EIU_IR4,
+- LTQ_EIU_IR5,
+-};
+-
+ static int exin_avail;
++static struct resource ltq_eiu_irq[MAX_EIU];
+ static void __iomem *ltq_icu_membase[MAX_IM];
+ static void __iomem *ltq_eiu_membase;
+ static struct irq_domain *ltq_domain;
+
++int ltq_eiu_get_irq(int exin)
++{
++ if (exin < exin_avail)
++ return ltq_eiu_irq[exin].start;
++ return -1;
++}
++
+ void ltq_disable_irq(struct irq_data *d)
+ {
+ u32 ier = LTQ_ICU_IM0_IER;
+@@ -128,19 +120,64 @@ void ltq_enable_irq(struct irq_data *d)
+ ltq_icu_w32(im, ltq_icu_r32(im, ier) | BIT(offset), ier);
+ }
+
++static int ltq_eiu_settype(struct irq_data *d, unsigned int type)
++{
++ int i;
++
++ for (i = 0; i < MAX_EIU; i++) {
++ if (d->hwirq == ltq_eiu_irq[i].start) {
++ int val = 0;
++ int edge = 0;
++
++ switch (type) {
++ case IRQF_TRIGGER_NONE:
++ break;
++ case IRQF_TRIGGER_RISING:
++ val = 1;
++ edge = 1;
++ break;
++ case IRQF_TRIGGER_FALLING:
++ val = 2;
++ edge = 1;
++ break;
++ case IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING:
++ val = 3;
++ edge = 1;
++ break;
++ case IRQF_TRIGGER_HIGH:
++ val = 5;
++ break;
++ case IRQF_TRIGGER_LOW:
++ val = 6;
++ break;
++ default:
++ pr_err("invalid type %d for irq %ld\n", type, d->hwirq);
++ return -EINVAL;
++ }
++
++ if (edge)
++ irq_set_handler(d->hwirq, handle_edge_irq);
++
++ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) |
++ (val << (i * 4)), LTQ_EIU_EXIN_C);
++ }
++ }
++
++ return 0;
++}
++
+ static unsigned int ltq_startup_eiu_irq(struct irq_data *d)
+ {
+ int i;
+
+ ltq_enable_irq(d);
+ for (i = 0; i < MAX_EIU; i++) {
+- if (d->hwirq == ltq_eiu_irq[i]) {
+- /* low level - we should really handle set_type */
+- ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) |
+- (0x6 << (i * 4)), LTQ_EIU_EXIN_C);
++ if (d->hwirq == ltq_eiu_irq[i].start) {
++ /* by default we are low level triggered */
++ ltq_eiu_settype(d, IRQF_TRIGGER_LOW);
+ /* clear all pending */
+- ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INIC) & ~BIT(i),
+- LTQ_EIU_EXIN_INIC);
++ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INC) & ~BIT(i),
++ LTQ_EIU_EXIN_INC);
+ /* enable */
+ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | BIT(i),
+ LTQ_EIU_EXIN_INEN);
+@@ -157,7 +194,7 @@ static void ltq_shutdown_eiu_irq(struct irq_data *d)
+
+ ltq_disable_irq(d);
+ for (i = 0; i < MAX_EIU; i++) {
+- if (d->hwirq == ltq_eiu_irq[i]) {
++ if (d->hwirq == ltq_eiu_irq[i].start) {
+ /* disable */
+ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~BIT(i),
+ LTQ_EIU_EXIN_INEN);
+@@ -186,6 +223,7 @@ static struct irq_chip ltq_eiu_type = {
+ .irq_ack = ltq_ack_irq,
+ .irq_mask = ltq_disable_irq,
+ .irq_mask_ack = ltq_mask_and_ack_irq,
++ .irq_set_type = ltq_eiu_settype,
+ };
+
+ static void ltq_hw_irqdispatch(int module)
+@@ -301,7 +339,7 @@ static int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
+ return 0;
+
+ for (i = 0; i < exin_avail; i++)
+- if (hw == ltq_eiu_irq[i])
++ if (hw == ltq_eiu_irq[i].start)
+ chip = &ltq_eiu_type;
+
+ irq_set_chip_and_handler(hw, chip, handle_level_irq);
+@@ -323,7 +361,7 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
+ {
+ struct device_node *eiu_node;
+ struct resource res;
+- int i;
++ int i, ret;
+
+ for (i = 0; i < MAX_IM; i++) {
+ if (of_address_to_resource(node, i, &res))
+@@ -340,17 +378,19 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
+ }
+
+ /* the external interrupts are optional and xway only */
+- eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu");
++ eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu-xway");
+ if (eiu_node && !of_address_to_resource(eiu_node, 0, &res)) {
+ /* find out how many external irq sources we have */
+- const __be32 *count = of_get_property(node,
+- "lantiq,count", NULL);
++ exin_avail = of_irq_count(eiu_node);
+
+- if (count)
+- exin_avail = *count;
+ if (exin_avail > MAX_EIU)
+ exin_avail = MAX_EIU;
+
++ ret = of_irq_to_resource_table(eiu_node,
++ ltq_eiu_irq, exin_avail);
++ if (ret != exin_avail)
++ panic("failed to load external irq resources\n");
++
+ if (request_mem_region(res.start, resource_size(&res),
+ res.name) < 0)
+ pr_err("Failed to request eiu memory");
+--
+1.7.10.4
+