target: don't build jffs2 nor images by default
[openwrt/svn-archive/archive.git] / target / linux / lantiq / patches-3.7 / 0105-MIPS-lantiq-rework-external-irq-code.patch
1 From edd237c93d564e698e169a89d1b1b35248c5ef4a Mon Sep 17 00:00:00 2001
2 From: John Crispin <blogic@openwrt.org>
3 Date: Mon, 3 Dec 2012 21:44:30 +0100
4 Subject: [PATCH 105/123] MIPS: lantiq: rework external irq code
5
6 This code makes the irqs used by the EIU loadable from the DT. Additionally we
7 add a helper that allows the pinctrl layer to map external irqs to real irq
8 numbers.
9
10 Signed-off-by: John Crispin <blogic@openwrt.org>
11 ---
12 arch/mips/include/asm/mach-lantiq/lantiq.h | 1 +
13 arch/mips/lantiq/irq.c | 104 +++++++++++++++++++---------
14 2 files changed, 73 insertions(+), 32 deletions(-)
15
16 --- a/arch/mips/include/asm/mach-lantiq/lantiq.h
17 +++ b/arch/mips/include/asm/mach-lantiq/lantiq.h
18 @@ -34,6 +34,7 @@ extern spinlock_t ebu_lock;
19 extern void ltq_disable_irq(struct irq_data *data);
20 extern void ltq_mask_and_ack_irq(struct irq_data *data);
21 extern void ltq_enable_irq(struct irq_data *data);
22 +extern int ltq_eiu_get_irq(int exin);
23
24 /* clock handling */
25 extern int clk_activate(struct clk *clk);
26 --- a/arch/mips/lantiq/irq.c
27 +++ b/arch/mips/lantiq/irq.c
28 @@ -33,17 +33,10 @@
29 /* register definitions - external irqs */
30 #define LTQ_EIU_EXIN_C 0x0000
31 #define LTQ_EIU_EXIN_INIC 0x0004
32 +#define LTQ_EIU_EXIN_INC 0x0008
33 #define LTQ_EIU_EXIN_INEN 0x000C
34
35 -/* irq numbers used by the external interrupt unit (EIU) */
36 -#define LTQ_EIU_IR0 (INT_NUM_IM4_IRL0 + 30)
37 -#define LTQ_EIU_IR1 (INT_NUM_IM3_IRL0 + 31)
38 -#define LTQ_EIU_IR2 (INT_NUM_IM1_IRL0 + 26)
39 -#define LTQ_EIU_IR3 INT_NUM_IM1_IRL0
40 -#define LTQ_EIU_IR4 (INT_NUM_IM1_IRL0 + 1)
41 -#define LTQ_EIU_IR5 (INT_NUM_IM1_IRL0 + 2)
42 -#define LTQ_EIU_IR6 (INT_NUM_IM2_IRL0 + 30)
43 -#define XWAY_EXIN_COUNT 3
44 +/* number of external interrupts */
45 #define MAX_EIU 6
46
47 /* the performance counter */
48 @@ -72,20 +65,19 @@
49 int gic_present;
50 #endif
51
52 -static unsigned short ltq_eiu_irq[MAX_EIU] = {
53 - LTQ_EIU_IR0,
54 - LTQ_EIU_IR1,
55 - LTQ_EIU_IR2,
56 - LTQ_EIU_IR3,
57 - LTQ_EIU_IR4,
58 - LTQ_EIU_IR5,
59 -};
60 -
61 static int exin_avail;
62 +static struct resource ltq_eiu_irq[MAX_EIU];
63 static void __iomem *ltq_icu_membase[MAX_IM];
64 static void __iomem *ltq_eiu_membase;
65 static struct irq_domain *ltq_domain;
66
67 +int ltq_eiu_get_irq(int exin)
68 +{
69 + if (exin < exin_avail)
70 + return ltq_eiu_irq[exin].start;
71 + return -1;
72 +}
73 +
74 void ltq_disable_irq(struct irq_data *d)
75 {
76 u32 ier = LTQ_ICU_IM0_IER;
77 @@ -128,19 +120,64 @@ void ltq_enable_irq(struct irq_data *d)
78 ltq_icu_w32(im, ltq_icu_r32(im, ier) | BIT(offset), ier);
79 }
80
81 +static int ltq_eiu_settype(struct irq_data *d, unsigned int type)
82 +{
83 + int i;
84 +
85 + for (i = 0; i < MAX_EIU; i++) {
86 + if (d->hwirq == ltq_eiu_irq[i].start) {
87 + int val = 0;
88 + int edge = 0;
89 +
90 + switch (type) {
91 + case IRQF_TRIGGER_NONE:
92 + break;
93 + case IRQF_TRIGGER_RISING:
94 + val = 1;
95 + edge = 1;
96 + break;
97 + case IRQF_TRIGGER_FALLING:
98 + val = 2;
99 + edge = 1;
100 + break;
101 + case IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING:
102 + val = 3;
103 + edge = 1;
104 + break;
105 + case IRQF_TRIGGER_HIGH:
106 + val = 5;
107 + break;
108 + case IRQF_TRIGGER_LOW:
109 + val = 6;
110 + break;
111 + default:
112 + pr_err("invalid type %d for irq %ld\n", type, d->hwirq);
113 + return -EINVAL;
114 + }
115 +
116 + if (edge)
117 + irq_set_handler(d->hwirq, handle_edge_irq);
118 +
119 + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) |
120 + (val << (i * 4)), LTQ_EIU_EXIN_C);
121 + }
122 + }
123 +
124 + return 0;
125 +}
126 +
127 static unsigned int ltq_startup_eiu_irq(struct irq_data *d)
128 {
129 int i;
130
131 ltq_enable_irq(d);
132 for (i = 0; i < MAX_EIU; i++) {
133 - if (d->hwirq == ltq_eiu_irq[i]) {
134 - /* low level - we should really handle set_type */
135 - ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) |
136 - (0x6 << (i * 4)), LTQ_EIU_EXIN_C);
137 + if (d->hwirq == ltq_eiu_irq[i].start) {
138 + /* by default we are low level triggered */
139 + ltq_eiu_settype(d, IRQF_TRIGGER_LOW);
140 /* clear all pending */
141 - ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INIC) & ~BIT(i),
142 - LTQ_EIU_EXIN_INIC);
143 + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INC) & ~BIT(i),
144 + LTQ_EIU_EXIN_INC);
145 /* enable */
146 ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | BIT(i),
147 LTQ_EIU_EXIN_INEN);
148 @@ -157,7 +194,7 @@ static void ltq_shutdown_eiu_irq(struct
149
150 ltq_disable_irq(d);
151 for (i = 0; i < MAX_EIU; i++) {
152 - if (d->hwirq == ltq_eiu_irq[i]) {
153 + if (d->hwirq == ltq_eiu_irq[i].start) {
154 /* disable */
155 ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~BIT(i),
156 LTQ_EIU_EXIN_INEN);
157 @@ -186,6 +223,7 @@ static struct irq_chip ltq_eiu_type = {
158 .irq_ack = ltq_ack_irq,
159 .irq_mask = ltq_disable_irq,
160 .irq_mask_ack = ltq_mask_and_ack_irq,
161 + .irq_set_type = ltq_eiu_settype,
162 };
163
164 static void ltq_hw_irqdispatch(int module)
165 @@ -301,7 +339,7 @@ static int icu_map(struct irq_domain *d,
166 return 0;
167
168 for (i = 0; i < exin_avail; i++)
169 - if (hw == ltq_eiu_irq[i])
170 + if (hw == ltq_eiu_irq[i].start)
171 chip = &ltq_eiu_type;
172
173 irq_set_chip_and_handler(hw, chip, handle_level_irq);
174 @@ -323,7 +361,7 @@ int __init icu_of_init(struct device_nod
175 {
176 struct device_node *eiu_node;
177 struct resource res;
178 - int i;
179 + int i, ret;
180
181 for (i = 0; i < MAX_IM; i++) {
182 if (of_address_to_resource(node, i, &res))
183 @@ -340,17 +378,19 @@ int __init icu_of_init(struct device_nod
184 }
185
186 /* the external interrupts are optional and xway only */
187 - eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu");
188 + eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu-xway");
189 if (eiu_node && !of_address_to_resource(eiu_node, 0, &res)) {
190 /* find out how many external irq sources we have */
191 - const __be32 *count = of_get_property(node,
192 - "lantiq,count", NULL);
193 + exin_avail = of_irq_count(eiu_node);
194
195 - if (count)
196 - exin_avail = *count;
197 if (exin_avail > MAX_EIU)
198 exin_avail = MAX_EIU;
199
200 + ret = of_irq_to_resource_table(eiu_node,
201 + ltq_eiu_irq, exin_avail);
202 + if (ret != exin_avail)
203 + panic("failed to load external irq resources\n");
204 +
205 if (request_mem_region(res.start, resource_size(&res),
206 res.name) < 0)
207 pr_err("Failed to request eiu memory");