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