summaryrefslogtreecommitdiffstats
path: root/drivers/irqchip
diff options
context:
space:
mode:
authorKevin Cernekee <cernekee@gmail.com>2014-12-25 12:49:03 -0500
committerRalf Baechle <ralf@linux-mips.org>2015-04-01 11:21:37 -0400
commit5b5468cf1fe9d16e568b45685b31dd4c72588778 (patch)
treed26512b303418d969f55a0bcd93378386fa16c2e /drivers/irqchip
parentc9ae71e0f78fb72eedd674c788415cdf1eb34195 (diff)
IRQCHIP: bcm7120-l2: Refactor driver for arbitrary IRQEN/IRQSTAT offsets
Currently the driver assumes that REG_BASE+0x00 is the IRQ enable mask, and REG_BASE+0x04 is the IRQ status mask. This is true on BCM3384 and BCM7xxx, but it is not true for some of the controllers found on BCM63xx chips. So we will change a couple of key assumptions: - Don't assume that both the IRQEN and IRQSTAT registers will be covered by a single ioremap() operation. - Don't assume any particular ordering (IRQSTAT might show up before IRQEN on some chips). - For an L2 controller with >=64 IRQs, don't assume that every IRQEN/IRQSTAT pair will use the same register spacing. This patch changes the "plumbing" but doesn't yet provide a way for users to instantiate a controller with arbitrary IRQEN/IRQSTAT offsets. Signed-off-by: Kevin Cernekee <cernekee@gmail.com> Cc: f.fainelli@gmail.com Cc: jaedon.shin@gmail.com Cc: abrestic@chromium.org Cc: tglx@linutronix.de Cc: jason@lakedaemon.net Cc: jogo@openwrt.org Cc: computersforpeace@gmail.com Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/8841/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'drivers/irqchip')
-rw-r--r--drivers/irqchip/irq-bcm7120-l2.c41
1 files changed, 28 insertions, 13 deletions
diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c
index 8eec8e1201d9..e8441ee7454c 100644
--- a/drivers/irqchip/irq-bcm7120-l2.c
+++ b/drivers/irqchip/irq-bcm7120-l2.c
@@ -34,11 +34,15 @@
34#define IRQSTAT 0x04 34#define IRQSTAT 0x04
35 35
36#define MAX_WORDS 4 36#define MAX_WORDS 4
37#define MAX_MAPPINGS MAX_WORDS
37#define IRQS_PER_WORD 32 38#define IRQS_PER_WORD 32
38 39
39struct bcm7120_l2_intc_data { 40struct bcm7120_l2_intc_data {
40 unsigned int n_words; 41 unsigned int n_words;
41 void __iomem *base[MAX_WORDS]; 42 void __iomem *map_base[MAX_MAPPINGS];
43 void __iomem *pair_base[MAX_WORDS];
44 int en_offset[MAX_WORDS];
45 int stat_offset[MAX_WORDS];
42 struct irq_domain *domain; 46 struct irq_domain *domain;
43 bool can_wake; 47 bool can_wake;
44 u32 irq_fwd_mask[MAX_WORDS]; 48 u32 irq_fwd_mask[MAX_WORDS];
@@ -61,7 +65,8 @@ static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
61 int hwirq; 65 int hwirq;
62 66
63 irq_gc_lock(gc); 67 irq_gc_lock(gc);
64 pending = irq_reg_readl(gc, IRQSTAT) & gc->mask_cache; 68 pending = irq_reg_readl(gc, b->stat_offset[idx]) &
69 gc->mask_cache;
65 irq_gc_unlock(gc); 70 irq_gc_unlock(gc);
66 71
67 for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) { 72 for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) {
@@ -76,21 +81,24 @@ static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
76static void bcm7120_l2_intc_suspend(struct irq_data *d) 81static void bcm7120_l2_intc_suspend(struct irq_data *d)
77{ 82{
78 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 83 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
84 struct irq_chip_type *ct = irq_data_get_chip_type(d);
79 struct bcm7120_l2_intc_data *b = gc->private; 85 struct bcm7120_l2_intc_data *b = gc->private;
80 86
81 irq_gc_lock(gc); 87 irq_gc_lock(gc);
82 if (b->can_wake) 88 if (b->can_wake)
83 irq_reg_writel(gc, gc->mask_cache | gc->wake_active, IRQEN); 89 irq_reg_writel(gc, gc->mask_cache | gc->wake_active,
90 ct->regs.mask);
84 irq_gc_unlock(gc); 91 irq_gc_unlock(gc);
85} 92}
86 93
87static void bcm7120_l2_intc_resume(struct irq_data *d) 94static void bcm7120_l2_intc_resume(struct irq_data *d)
88{ 95{
89 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 96 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
97 struct irq_chip_type *ct = irq_data_get_chip_type(d);
90 98
91 /* Restore the saved mask */ 99 /* Restore the saved mask */
92 irq_gc_lock(gc); 100 irq_gc_lock(gc);
93 irq_reg_writel(gc, gc->mask_cache, IRQEN); 101 irq_reg_writel(gc, gc->mask_cache, ct->regs.mask);
94 irq_gc_unlock(gc); 102 irq_gc_unlock(gc);
95} 103}
96 104
@@ -137,9 +145,14 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn,
137 return -ENOMEM; 145 return -ENOMEM;
138 146
139 for (idx = 0; idx < MAX_WORDS; idx++) { 147 for (idx = 0; idx < MAX_WORDS; idx++) {
140 data->base[idx] = of_iomap(dn, idx); 148 data->map_base[idx] = of_iomap(dn, idx);
141 if (!data->base[idx]) 149 if (!data->map_base[idx])
142 break; 150 break;
151
152 data->pair_base[idx] = data->map_base[idx];
153 data->en_offset[idx] = IRQEN;
154 data->stat_offset[idx] = IRQSTAT;
155
143 data->n_words = idx + 1; 156 data->n_words = idx + 1;
144 } 157 }
145 if (!data->n_words) { 158 if (!data->n_words) {
@@ -157,7 +170,8 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn,
157 if (ret == 0 || ret == -EINVAL) { 170 if (ret == 0 || ret == -EINVAL) {
158 for (idx = 0; idx < data->n_words; idx++) 171 for (idx = 0; idx < data->n_words; idx++)
159 __raw_writel(data->irq_fwd_mask[idx], 172 __raw_writel(data->irq_fwd_mask[idx],
160 data->base[idx] + IRQEN); 173 data->pair_base[idx] +
174 data->en_offset[idx]);
161 } else { 175 } else {
162 /* property exists but has the wrong number of words */ 176 /* property exists but has the wrong number of words */
163 pr_err("invalid int-fwd-mask property\n"); 177 pr_err("invalid int-fwd-mask property\n");
@@ -215,11 +229,12 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn,
215 gc = irq_get_domain_generic_chip(data->domain, irq); 229 gc = irq_get_domain_generic_chip(data->domain, irq);
216 230
217 gc->unused = 0xffffffff & ~data->irq_map_mask[idx]; 231 gc->unused = 0xffffffff & ~data->irq_map_mask[idx];
218 gc->reg_base = data->base[idx];
219 gc->private = data; 232 gc->private = data;
220 ct = gc->chip_types; 233 ct = gc->chip_types;
221 234
222 ct->regs.mask = IRQEN; 235 gc->reg_base = data->pair_base[idx];
236 ct->regs.mask = data->en_offset[idx];
237
223 ct->chip.irq_mask = irq_gc_mask_clr_bit; 238 ct->chip.irq_mask = irq_gc_mask_clr_bit;
224 ct->chip.irq_unmask = irq_gc_mask_set_bit; 239 ct->chip.irq_unmask = irq_gc_mask_set_bit;
225 ct->chip.irq_ack = irq_gc_noop; 240 ct->chip.irq_ack = irq_gc_noop;
@@ -237,16 +252,16 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn,
237 } 252 }
238 253
239 pr_info("registered BCM7120 L2 intc (mem: 0x%p, parent IRQ(s): %d)\n", 254 pr_info("registered BCM7120 L2 intc (mem: 0x%p, parent IRQ(s): %d)\n",
240 data->base[0], num_parent_irqs); 255 data->map_base[0], num_parent_irqs);
241 256
242 return 0; 257 return 0;
243 258
244out_free_domain: 259out_free_domain:
245 irq_domain_remove(data->domain); 260 irq_domain_remove(data->domain);
246out_unmap: 261out_unmap:
247 for (idx = 0; idx < MAX_WORDS; idx++) { 262 for (idx = 0; idx < MAX_MAPPINGS; idx++) {
248 if (data->base[idx]) 263 if (data->map_base[idx])
249 iounmap(data->base[idx]); 264 iounmap(data->map_base[idx]);
250 } 265 }
251 kfree(data); 266 kfree(data);
252 return ret; 267 return ret;