diff options
author | Maxime Bizon <mbizon@freebox.fr> | 2011-11-04 14:09:34 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2011-12-07 17:03:04 -0500 |
commit | 6224892c819e96898534c107c72b80a1a8e75abf (patch) | |
tree | 4f9f2bc957b221f7dd6f6daea7d993c78813b9ad /arch/mips/bcm63xx | |
parent | 71a43927b3bfe1a42cbf7bb174b170f06fa00a1a (diff) |
MIPS: BCM63XX: Add external irq support for non 6348 CPUs.
Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/2899/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/bcm63xx')
-rw-r--r-- | arch/mips/bcm63xx/irq.c | 131 | ||||
-rw-r--r-- | arch/mips/bcm63xx/setup.c | 30 |
2 files changed, 127 insertions, 34 deletions
diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c index 11f8942b82dc..9f538846b3f7 100644 --- a/arch/mips/bcm63xx/irq.c +++ b/arch/mips/bcm63xx/irq.c | |||
@@ -34,6 +34,9 @@ static void __internal_irq_unmask_64(unsigned int irq) __maybe_unused; | |||
34 | #define is_ext_irq_cascaded 0 | 34 | #define is_ext_irq_cascaded 0 |
35 | #define ext_irq_start 0 | 35 | #define ext_irq_start 0 |
36 | #define ext_irq_end 0 | 36 | #define ext_irq_end 0 |
37 | #define ext_irq_count 4 | ||
38 | #define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6338 | ||
39 | #define ext_irq_cfg_reg2 0 | ||
37 | #endif | 40 | #endif |
38 | #ifdef CONFIG_BCM63XX_CPU_6345 | 41 | #ifdef CONFIG_BCM63XX_CPU_6345 |
39 | #define irq_stat_reg PERF_IRQSTAT_6345_REG | 42 | #define irq_stat_reg PERF_IRQSTAT_6345_REG |
@@ -42,6 +45,9 @@ static void __internal_irq_unmask_64(unsigned int irq) __maybe_unused; | |||
42 | #define is_ext_irq_cascaded 0 | 45 | #define is_ext_irq_cascaded 0 |
43 | #define ext_irq_start 0 | 46 | #define ext_irq_start 0 |
44 | #define ext_irq_end 0 | 47 | #define ext_irq_end 0 |
48 | #define ext_irq_count 0 | ||
49 | #define ext_irq_cfg_reg1 0 | ||
50 | #define ext_irq_cfg_reg2 0 | ||
45 | #endif | 51 | #endif |
46 | #ifdef CONFIG_BCM63XX_CPU_6348 | 52 | #ifdef CONFIG_BCM63XX_CPU_6348 |
47 | #define irq_stat_reg PERF_IRQSTAT_6348_REG | 53 | #define irq_stat_reg PERF_IRQSTAT_6348_REG |
@@ -50,6 +56,9 @@ static void __internal_irq_unmask_64(unsigned int irq) __maybe_unused; | |||
50 | #define is_ext_irq_cascaded 0 | 56 | #define is_ext_irq_cascaded 0 |
51 | #define ext_irq_start 0 | 57 | #define ext_irq_start 0 |
52 | #define ext_irq_end 0 | 58 | #define ext_irq_end 0 |
59 | #define ext_irq_count 4 | ||
60 | #define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6348 | ||
61 | #define ext_irq_cfg_reg2 0 | ||
53 | #endif | 62 | #endif |
54 | #ifdef CONFIG_BCM63XX_CPU_6358 | 63 | #ifdef CONFIG_BCM63XX_CPU_6358 |
55 | #define irq_stat_reg PERF_IRQSTAT_6358_REG | 64 | #define irq_stat_reg PERF_IRQSTAT_6358_REG |
@@ -58,6 +67,9 @@ static void __internal_irq_unmask_64(unsigned int irq) __maybe_unused; | |||
58 | #define is_ext_irq_cascaded 1 | 67 | #define is_ext_irq_cascaded 1 |
59 | #define ext_irq_start (BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE) | 68 | #define ext_irq_start (BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE) |
60 | #define ext_irq_end (BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE) | 69 | #define ext_irq_end (BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE) |
70 | #define ext_irq_count 4 | ||
71 | #define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6358 | ||
72 | #define ext_irq_cfg_reg2 0 | ||
61 | #endif | 73 | #endif |
62 | 74 | ||
63 | #if irq_bits == 32 | 75 | #if irq_bits == 32 |
@@ -81,7 +93,9 @@ static inline void bcm63xx_init_irq(void) | |||
81 | static u32 irq_stat_addr, irq_mask_addr; | 93 | static u32 irq_stat_addr, irq_mask_addr; |
82 | static void (*dispatch_internal)(void); | 94 | static void (*dispatch_internal)(void); |
83 | static int is_ext_irq_cascaded; | 95 | static int is_ext_irq_cascaded; |
96 | static unsigned int ext_irq_count; | ||
84 | static unsigned int ext_irq_start, ext_irq_end; | 97 | static unsigned int ext_irq_start, ext_irq_end; |
98 | static unsigned int ext_irq_cfg_reg1, ext_irq_cfg_reg2; | ||
85 | static void (*internal_irq_mask)(unsigned int irq); | 99 | static void (*internal_irq_mask)(unsigned int irq); |
86 | static void (*internal_irq_unmask)(unsigned int irq); | 100 | static void (*internal_irq_unmask)(unsigned int irq); |
87 | 101 | ||
@@ -107,14 +121,18 @@ static void bcm63xx_init_irq(void) | |||
107 | irq_stat_addr += PERF_IRQSTAT_6348_REG; | 121 | irq_stat_addr += PERF_IRQSTAT_6348_REG; |
108 | irq_mask_addr += PERF_IRQMASK_6348_REG; | 122 | irq_mask_addr += PERF_IRQMASK_6348_REG; |
109 | irq_bits = 32; | 123 | irq_bits = 32; |
124 | ext_irq_count = 4; | ||
125 | ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6348; | ||
110 | break; | 126 | break; |
111 | case BCM6358_CPU_ID: | 127 | case BCM6358_CPU_ID: |
112 | irq_stat_addr += PERF_IRQSTAT_6358_REG; | 128 | irq_stat_addr += PERF_IRQSTAT_6358_REG; |
113 | irq_mask_addr += PERF_IRQMASK_6358_REG; | 129 | irq_mask_addr += PERF_IRQMASK_6358_REG; |
114 | irq_bits = 32; | 130 | irq_bits = 32; |
131 | ext_irq_count = 4; | ||
115 | is_ext_irq_cascaded = 1; | 132 | is_ext_irq_cascaded = 1; |
116 | ext_irq_start = BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE; | 133 | ext_irq_start = BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE; |
117 | ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE; | 134 | ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE; |
135 | ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6358; | ||
118 | break; | 136 | break; |
119 | default: | 137 | default: |
120 | BUG(); | 138 | BUG(); |
@@ -132,6 +150,13 @@ static void bcm63xx_init_irq(void) | |||
132 | } | 150 | } |
133 | #endif /* ! BCMCPU_RUNTIME_DETECT */ | 151 | #endif /* ! BCMCPU_RUNTIME_DETECT */ |
134 | 152 | ||
153 | static inline u32 get_ext_irq_perf_reg(int irq) | ||
154 | { | ||
155 | if (irq < 4) | ||
156 | return ext_irq_cfg_reg1; | ||
157 | return ext_irq_cfg_reg2; | ||
158 | } | ||
159 | |||
135 | static inline void handle_internal(int intbit) | 160 | static inline void handle_internal(int intbit) |
136 | { | 161 | { |
137 | if (is_ext_irq_cascaded && | 162 | if (is_ext_irq_cascaded && |
@@ -273,11 +298,17 @@ static void bcm63xx_internal_irq_unmask(struct irq_data *d) | |||
273 | static void bcm63xx_external_irq_mask(struct irq_data *d) | 298 | static void bcm63xx_external_irq_mask(struct irq_data *d) |
274 | { | 299 | { |
275 | unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; | 300 | unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; |
276 | u32 reg; | 301 | u32 reg, regaddr; |
277 | 302 | ||
278 | reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); | 303 | regaddr = get_ext_irq_perf_reg(irq); |
279 | reg &= ~EXTIRQ_CFG_MASK(irq); | 304 | reg = bcm_perf_readl(regaddr); |
280 | bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); | 305 | |
306 | if (BCMCPU_IS_6348()) | ||
307 | reg &= ~EXTIRQ_CFG_MASK_6348(irq % 4); | ||
308 | else | ||
309 | reg &= ~EXTIRQ_CFG_MASK(irq % 4); | ||
310 | |||
311 | bcm_perf_writel(reg, regaddr); | ||
281 | if (is_ext_irq_cascaded) | 312 | if (is_ext_irq_cascaded) |
282 | internal_irq_mask(irq + ext_irq_start); | 313 | internal_irq_mask(irq + ext_irq_start); |
283 | } | 314 | } |
@@ -285,11 +316,18 @@ static void bcm63xx_external_irq_mask(struct irq_data *d) | |||
285 | static void bcm63xx_external_irq_unmask(struct irq_data *d) | 316 | static void bcm63xx_external_irq_unmask(struct irq_data *d) |
286 | { | 317 | { |
287 | unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; | 318 | unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; |
288 | u32 reg; | 319 | u32 reg, regaddr; |
320 | |||
321 | regaddr = get_ext_irq_perf_reg(irq); | ||
322 | reg = bcm_perf_readl(regaddr); | ||
323 | |||
324 | if (BCMCPU_IS_6348()) | ||
325 | reg |= EXTIRQ_CFG_MASK_6348(irq % 4); | ||
326 | else | ||
327 | reg |= EXTIRQ_CFG_MASK(irq % 4); | ||
328 | |||
329 | bcm_perf_writel(reg, regaddr); | ||
289 | 330 | ||
290 | reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); | ||
291 | reg |= EXTIRQ_CFG_MASK(irq); | ||
292 | bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); | ||
293 | if (is_ext_irq_cascaded) | 331 | if (is_ext_irq_cascaded) |
294 | internal_irq_unmask(irq + ext_irq_start); | 332 | internal_irq_unmask(irq + ext_irq_start); |
295 | } | 333 | } |
@@ -297,58 +335,93 @@ static void bcm63xx_external_irq_unmask(struct irq_data *d) | |||
297 | static void bcm63xx_external_irq_clear(struct irq_data *d) | 335 | static void bcm63xx_external_irq_clear(struct irq_data *d) |
298 | { | 336 | { |
299 | unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; | 337 | unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; |
300 | u32 reg; | 338 | u32 reg, regaddr; |
339 | |||
340 | regaddr = get_ext_irq_perf_reg(irq); | ||
341 | reg = bcm_perf_readl(regaddr); | ||
301 | 342 | ||
302 | reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); | 343 | if (BCMCPU_IS_6348()) |
303 | reg |= EXTIRQ_CFG_CLEAR(irq); | 344 | reg |= EXTIRQ_CFG_CLEAR_6348(irq % 4); |
304 | bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); | 345 | else |
346 | reg |= EXTIRQ_CFG_CLEAR(irq % 4); | ||
347 | |||
348 | bcm_perf_writel(reg, regaddr); | ||
305 | } | 349 | } |
306 | 350 | ||
307 | static int bcm63xx_external_irq_set_type(struct irq_data *d, | 351 | static int bcm63xx_external_irq_set_type(struct irq_data *d, |
308 | unsigned int flow_type) | 352 | unsigned int flow_type) |
309 | { | 353 | { |
310 | unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; | 354 | unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; |
311 | u32 reg; | 355 | u32 reg, regaddr; |
356 | int levelsense, sense, bothedge; | ||
312 | 357 | ||
313 | flow_type &= IRQ_TYPE_SENSE_MASK; | 358 | flow_type &= IRQ_TYPE_SENSE_MASK; |
314 | 359 | ||
315 | if (flow_type == IRQ_TYPE_NONE) | 360 | if (flow_type == IRQ_TYPE_NONE) |
316 | flow_type = IRQ_TYPE_LEVEL_LOW; | 361 | flow_type = IRQ_TYPE_LEVEL_LOW; |
317 | 362 | ||
318 | reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); | 363 | levelsense = sense = bothedge = 0; |
319 | switch (flow_type) { | 364 | switch (flow_type) { |
320 | case IRQ_TYPE_EDGE_BOTH: | 365 | case IRQ_TYPE_EDGE_BOTH: |
321 | reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); | 366 | bothedge = 1; |
322 | reg |= EXTIRQ_CFG_BOTHEDGE(irq); | ||
323 | break; | 367 | break; |
324 | 368 | ||
325 | case IRQ_TYPE_EDGE_RISING: | 369 | case IRQ_TYPE_EDGE_RISING: |
326 | reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); | 370 | sense = 1; |
327 | reg |= EXTIRQ_CFG_SENSE(irq); | ||
328 | reg &= ~EXTIRQ_CFG_BOTHEDGE(irq); | ||
329 | break; | 371 | break; |
330 | 372 | ||
331 | case IRQ_TYPE_EDGE_FALLING: | 373 | case IRQ_TYPE_EDGE_FALLING: |
332 | reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); | ||
333 | reg &= ~EXTIRQ_CFG_SENSE(irq); | ||
334 | reg &= ~EXTIRQ_CFG_BOTHEDGE(irq); | ||
335 | break; | 374 | break; |
336 | 375 | ||
337 | case IRQ_TYPE_LEVEL_HIGH: | 376 | case IRQ_TYPE_LEVEL_HIGH: |
338 | reg |= EXTIRQ_CFG_LEVELSENSE(irq); | 377 | levelsense = 1; |
339 | reg |= EXTIRQ_CFG_SENSE(irq); | 378 | sense = 1; |
340 | break; | 379 | break; |
341 | 380 | ||
342 | case IRQ_TYPE_LEVEL_LOW: | 381 | case IRQ_TYPE_LEVEL_LOW: |
343 | reg |= EXTIRQ_CFG_LEVELSENSE(irq); | 382 | levelsense = 1; |
344 | reg &= ~EXTIRQ_CFG_SENSE(irq); | ||
345 | break; | 383 | break; |
346 | 384 | ||
347 | default: | 385 | default: |
348 | printk(KERN_ERR "bogus flow type combination given !\n"); | 386 | printk(KERN_ERR "bogus flow type combination given !\n"); |
349 | return -EINVAL; | 387 | return -EINVAL; |
350 | } | 388 | } |
351 | bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); | 389 | |
390 | regaddr = get_ext_irq_perf_reg(irq); | ||
391 | reg = bcm_perf_readl(regaddr); | ||
392 | irq %= 4; | ||
393 | |||
394 | if (BCMCPU_IS_6348()) { | ||
395 | if (levelsense) | ||
396 | reg |= EXTIRQ_CFG_LEVELSENSE_6348(irq); | ||
397 | else | ||
398 | reg &= ~EXTIRQ_CFG_LEVELSENSE_6348(irq); | ||
399 | if (sense) | ||
400 | reg |= EXTIRQ_CFG_SENSE_6348(irq); | ||
401 | else | ||
402 | reg &= ~EXTIRQ_CFG_SENSE_6348(irq); | ||
403 | if (bothedge) | ||
404 | reg |= EXTIRQ_CFG_BOTHEDGE_6348(irq); | ||
405 | else | ||
406 | reg &= ~EXTIRQ_CFG_BOTHEDGE_6348(irq); | ||
407 | } | ||
408 | |||
409 | if (BCMCPU_IS_6338() || BCMCPU_IS_6358()) { | ||
410 | if (levelsense) | ||
411 | reg |= EXTIRQ_CFG_LEVELSENSE(irq); | ||
412 | else | ||
413 | reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); | ||
414 | if (sense) | ||
415 | reg |= EXTIRQ_CFG_SENSE(irq); | ||
416 | else | ||
417 | reg &= ~EXTIRQ_CFG_SENSE(irq); | ||
418 | if (bothedge) | ||
419 | reg |= EXTIRQ_CFG_BOTHEDGE(irq); | ||
420 | else | ||
421 | reg &= ~EXTIRQ_CFG_BOTHEDGE(irq); | ||
422 | } | ||
423 | |||
424 | bcm_perf_writel(reg, regaddr); | ||
352 | 425 | ||
353 | irqd_set_trigger_type(d, flow_type); | 426 | irqd_set_trigger_type(d, flow_type); |
354 | if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) | 427 | if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) |
@@ -397,12 +470,12 @@ void __init arch_init_irq(void) | |||
397 | irq_set_chip_and_handler(i, &bcm63xx_internal_irq_chip, | 470 | irq_set_chip_and_handler(i, &bcm63xx_internal_irq_chip, |
398 | handle_level_irq); | 471 | handle_level_irq); |
399 | 472 | ||
400 | for (i = IRQ_EXTERNAL_BASE; i < IRQ_EXTERNAL_BASE + 4; ++i) | 473 | for (i = IRQ_EXTERNAL_BASE; i < IRQ_EXTERNAL_BASE + ext_irq_count; ++i) |
401 | irq_set_chip_and_handler(i, &bcm63xx_external_irq_chip, | 474 | irq_set_chip_and_handler(i, &bcm63xx_external_irq_chip, |
402 | handle_edge_irq); | 475 | handle_edge_irq); |
403 | 476 | ||
404 | if (!is_ext_irq_cascaded) { | 477 | if (!is_ext_irq_cascaded) { |
405 | for (i = 3; i < 7; ++i) | 478 | for (i = 3; i < 3 + ext_irq_count; ++i) |
406 | setup_irq(MIPS_CPU_IRQ_BASE + i, &cpu_ext_cascade_action); | 479 | setup_irq(MIPS_CPU_IRQ_BASE + i, &cpu_ext_cascade_action); |
407 | } | 480 | } |
408 | 481 | ||
diff --git a/arch/mips/bcm63xx/setup.c b/arch/mips/bcm63xx/setup.c index 04a349928643..d209f85d87bb 100644 --- a/arch/mips/bcm63xx/setup.c +++ b/arch/mips/bcm63xx/setup.c | |||
@@ -63,13 +63,33 @@ static void bcm6348_a1_reboot(void) | |||
63 | 63 | ||
64 | void bcm63xx_machine_reboot(void) | 64 | void bcm63xx_machine_reboot(void) |
65 | { | 65 | { |
66 | u32 reg; | 66 | u32 reg, perf_regs[2] = { 0, 0 }; |
67 | unsigned int i; | ||
67 | 68 | ||
68 | /* mask and clear all external irq */ | 69 | /* mask and clear all external irq */ |
69 | reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); | 70 | switch (bcm63xx_get_cpu_id()) { |
70 | reg &= ~EXTIRQ_CFG_MASK_ALL; | 71 | case BCM6338_CPU_ID: |
71 | reg |= EXTIRQ_CFG_CLEAR_ALL; | 72 | perf_regs[0] = PERF_EXTIRQ_CFG_REG_6338; |
72 | bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); | 73 | break; |
74 | case BCM6348_CPU_ID: | ||
75 | perf_regs[0] = PERF_EXTIRQ_CFG_REG_6348; | ||
76 | break; | ||
77 | case BCM6358_CPU_ID: | ||
78 | perf_regs[0] = PERF_EXTIRQ_CFG_REG_6358; | ||
79 | break; | ||
80 | } | ||
81 | |||
82 | for (i = 0; i < 2; i++) { | ||
83 | reg = bcm_perf_readl(perf_regs[i]); | ||
84 | if (BCMCPU_IS_6348()) { | ||
85 | reg &= ~EXTIRQ_CFG_MASK_ALL_6348; | ||
86 | reg |= EXTIRQ_CFG_CLEAR_ALL_6348; | ||
87 | } else { | ||
88 | reg &= ~EXTIRQ_CFG_MASK_ALL; | ||
89 | reg |= EXTIRQ_CFG_CLEAR_ALL; | ||
90 | } | ||
91 | bcm_perf_writel(reg, perf_regs[i]); | ||
92 | } | ||
73 | 93 | ||
74 | if (BCMCPU_IS_6348() && (bcm63xx_get_cpu_rev() == 0xa1)) | 94 | if (BCMCPU_IS_6348() && (bcm63xx_get_cpu_rev() == 0xa1)) |
75 | bcm6348_a1_reboot(); | 95 | bcm6348_a1_reboot(); |