Skip to content

Commit 1753e74

Browse files
rsa9000ralfbaechle
authored andcommitted
MIPS: ath25: add interrupts handling routines
Add interrupts initialization and handling routines, also add AHB bus error interrupt handlers for both SoCs families. Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com> Cc: Linux MIPS <linux-mips@linux-mips.org> Patchwork: https://patchwork.linux-mips.org/patch/8240/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
1 parent ba91034 commit 1753e74

File tree

9 files changed

+290
-0
lines changed

9 files changed

+290
-0
lines changed

arch/mips/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ config ATH25
103103
select CSRC_R4K
104104
select DMA_NONCOHERENT
105105
select IRQ_CPU
106+
select IRQ_DOMAIN
106107
select SYS_HAS_CPU_MIPS32_R1
107108
select SYS_SUPPORTS_BIG_ENDIAN
108109
select SYS_SUPPORTS_32BIT_KERNEL

arch/mips/ath25/ar2315.c

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
#include <linux/init.h>
1818
#include <linux/kernel.h>
19+
#include <linux/bitops.h>
20+
#include <linux/irqdomain.h>
21+
#include <linux/interrupt.h>
1922
#include <linux/reboot.h>
2023
#include <asm/bootinfo.h>
2124
#include <asm/reboot.h>
@@ -26,6 +29,7 @@
2629
#include "ar2315_regs.h"
2730

2831
static void __iomem *ar2315_rst_base;
32+
static struct irq_domain *ar2315_misc_irq_domain;
2933

3034
static inline u32 ar2315_rst_reg_read(u32 reg)
3135
{
@@ -46,6 +50,116 @@ static inline void ar2315_rst_reg_mask(u32 reg, u32 mask, u32 val)
4650
ar2315_rst_reg_write(reg, ret);
4751
}
4852

53+
static irqreturn_t ar2315_ahb_err_handler(int cpl, void *dev_id)
54+
{
55+
ar2315_rst_reg_write(AR2315_AHB_ERR0, AR2315_AHB_ERROR_DET);
56+
ar2315_rst_reg_read(AR2315_AHB_ERR1);
57+
58+
pr_emerg("AHB fatal error\n");
59+
machine_restart("AHB error"); /* Catastrophic failure */
60+
61+
return IRQ_HANDLED;
62+
}
63+
64+
static struct irqaction ar2315_ahb_err_interrupt = {
65+
.handler = ar2315_ahb_err_handler,
66+
.name = "ar2315-ahb-error",
67+
};
68+
69+
static void ar2315_misc_irq_handler(unsigned irq, struct irq_desc *desc)
70+
{
71+
u32 pending = ar2315_rst_reg_read(AR2315_ISR) &
72+
ar2315_rst_reg_read(AR2315_IMR);
73+
unsigned nr, misc_irq = 0;
74+
75+
if (pending) {
76+
struct irq_domain *domain = irq_get_handler_data(irq);
77+
78+
nr = __ffs(pending);
79+
misc_irq = irq_find_mapping(domain, nr);
80+
}
81+
82+
if (misc_irq) {
83+
if (nr == AR2315_MISC_IRQ_GPIO)
84+
ar2315_rst_reg_write(AR2315_ISR, AR2315_ISR_GPIO);
85+
else if (nr == AR2315_MISC_IRQ_WATCHDOG)
86+
ar2315_rst_reg_write(AR2315_ISR, AR2315_ISR_WD);
87+
generic_handle_irq(misc_irq);
88+
} else {
89+
spurious_interrupt();
90+
}
91+
}
92+
93+
static void ar2315_misc_irq_unmask(struct irq_data *d)
94+
{
95+
ar2315_rst_reg_mask(AR2315_IMR, 0, BIT(d->hwirq));
96+
}
97+
98+
static void ar2315_misc_irq_mask(struct irq_data *d)
99+
{
100+
ar2315_rst_reg_mask(AR2315_IMR, BIT(d->hwirq), 0);
101+
}
102+
103+
static struct irq_chip ar2315_misc_irq_chip = {
104+
.name = "ar2315-misc",
105+
.irq_unmask = ar2315_misc_irq_unmask,
106+
.irq_mask = ar2315_misc_irq_mask,
107+
};
108+
109+
static int ar2315_misc_irq_map(struct irq_domain *d, unsigned irq,
110+
irq_hw_number_t hw)
111+
{
112+
irq_set_chip_and_handler(irq, &ar2315_misc_irq_chip, handle_level_irq);
113+
return 0;
114+
}
115+
116+
static struct irq_domain_ops ar2315_misc_irq_domain_ops = {
117+
.map = ar2315_misc_irq_map,
118+
};
119+
120+
/*
121+
* Called when an interrupt is received, this function
122+
* determines exactly which interrupt it was, and it
123+
* invokes the appropriate handler.
124+
*
125+
* Implicitly, we also define interrupt priority by
126+
* choosing which to dispatch first.
127+
*/
128+
static void ar2315_irq_dispatch(void)
129+
{
130+
u32 pending = read_c0_status() & read_c0_cause();
131+
132+
if (pending & CAUSEF_IP3)
133+
do_IRQ(AR2315_IRQ_WLAN0);
134+
else if (pending & CAUSEF_IP2)
135+
do_IRQ(AR2315_IRQ_MISC);
136+
else if (pending & CAUSEF_IP7)
137+
do_IRQ(ATH25_IRQ_CPU_CLOCK);
138+
else
139+
spurious_interrupt();
140+
}
141+
142+
void __init ar2315_arch_init_irq(void)
143+
{
144+
struct irq_domain *domain;
145+
unsigned irq;
146+
147+
ath25_irq_dispatch = ar2315_irq_dispatch;
148+
149+
domain = irq_domain_add_linear(NULL, AR2315_MISC_IRQ_COUNT,
150+
&ar2315_misc_irq_domain_ops, NULL);
151+
if (!domain)
152+
panic("Failed to add IRQ domain");
153+
154+
irq = irq_create_mapping(domain, AR2315_MISC_IRQ_AHB);
155+
setup_irq(irq, &ar2315_ahb_err_interrupt);
156+
157+
irq_set_chained_handler(AR2315_IRQ_MISC, ar2315_misc_irq_handler);
158+
irq_set_handler_data(AR2315_IRQ_MISC, domain);
159+
160+
ar2315_misc_irq_domain = domain;
161+
}
162+
49163
static void ar2315_restart(char *command)
50164
{
51165
void (*mips_reset_vec)(void) = (void *)0xbfc00000;

arch/mips/ath25/ar2315.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33

44
#ifdef CONFIG_SOC_AR2315
55

6+
void ar2315_arch_init_irq(void);
67
void ar2315_plat_time_init(void);
78
void ar2315_plat_mem_setup(void);
89

910
#else
1011

12+
static inline void ar2315_arch_init_irq(void) {}
1113
static inline void ar2315_plat_time_init(void) {}
1214
static inline void ar2315_plat_mem_setup(void) {}
1315

arch/mips/ath25/ar2315_regs.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,29 @@
1414
#ifndef __ASM_MACH_ATH25_AR2315_REGS_H
1515
#define __ASM_MACH_ATH25_AR2315_REGS_H
1616

17+
/*
18+
* IRQs
19+
*/
20+
#define AR2315_IRQ_MISC (MIPS_CPU_IRQ_BASE + 2) /* C0_CAUSE: 0x0400 */
21+
#define AR2315_IRQ_WLAN0 (MIPS_CPU_IRQ_BASE + 3) /* C0_CAUSE: 0x0800 */
22+
#define AR2315_IRQ_ENET0 (MIPS_CPU_IRQ_BASE + 4) /* C0_CAUSE: 0x1000 */
23+
#define AR2315_IRQ_LCBUS_PCI (MIPS_CPU_IRQ_BASE + 5) /* C0_CAUSE: 0x2000 */
24+
#define AR2315_IRQ_WLAN0_POLL (MIPS_CPU_IRQ_BASE + 6) /* C0_CAUSE: 0x4000 */
25+
26+
/*
27+
* Miscellaneous interrupts, which share IP2.
28+
*/
29+
#define AR2315_MISC_IRQ_UART0 0
30+
#define AR2315_MISC_IRQ_I2C_RSVD 1
31+
#define AR2315_MISC_IRQ_SPI 2
32+
#define AR2315_MISC_IRQ_AHB 3
33+
#define AR2315_MISC_IRQ_APB 4
34+
#define AR2315_MISC_IRQ_TIMER 5
35+
#define AR2315_MISC_IRQ_GPIO 6
36+
#define AR2315_MISC_IRQ_WATCHDOG 7
37+
#define AR2315_MISC_IRQ_IR_RSVD 8
38+
#define AR2315_MISC_IRQ_COUNT 9
39+
1740
/*
1841
* Address map
1942
*/

arch/mips/ath25/ar5312.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
#include <linux/init.h>
1818
#include <linux/kernel.h>
19+
#include <linux/bitops.h>
20+
#include <linux/irqdomain.h>
21+
#include <linux/interrupt.h>
1922
#include <linux/reboot.h>
2023
#include <asm/bootinfo.h>
2124
#include <asm/reboot.h>
@@ -26,6 +29,7 @@
2629
#include "ar5312_regs.h"
2730

2831
static void __iomem *ar5312_rst_base;
32+
static struct irq_domain *ar5312_misc_irq_domain;
2933

3034
static inline u32 ar5312_rst_reg_read(u32 reg)
3135
{
@@ -46,6 +50,114 @@ static inline void ar5312_rst_reg_mask(u32 reg, u32 mask, u32 val)
4650
ar5312_rst_reg_write(reg, ret);
4751
}
4852

53+
static irqreturn_t ar5312_ahb_err_handler(int cpl, void *dev_id)
54+
{
55+
u32 proc1 = ar5312_rst_reg_read(AR5312_PROC1);
56+
u32 proc_addr = ar5312_rst_reg_read(AR5312_PROCADDR); /* clears error */
57+
u32 dma1 = ar5312_rst_reg_read(AR5312_DMA1);
58+
u32 dma_addr = ar5312_rst_reg_read(AR5312_DMAADDR); /* clears error */
59+
60+
pr_emerg("AHB interrupt: PROCADDR=0x%8.8x PROC1=0x%8.8x DMAADDR=0x%8.8x DMA1=0x%8.8x\n",
61+
proc_addr, proc1, dma_addr, dma1);
62+
63+
machine_restart("AHB error"); /* Catastrophic failure */
64+
return IRQ_HANDLED;
65+
}
66+
67+
static struct irqaction ar5312_ahb_err_interrupt = {
68+
.handler = ar5312_ahb_err_handler,
69+
.name = "ar5312-ahb-error",
70+
};
71+
72+
static void ar5312_misc_irq_handler(unsigned irq, struct irq_desc *desc)
73+
{
74+
u32 pending = ar5312_rst_reg_read(AR5312_ISR) &
75+
ar5312_rst_reg_read(AR5312_IMR);
76+
unsigned nr, misc_irq = 0;
77+
78+
if (pending) {
79+
struct irq_domain *domain = irq_get_handler_data(irq);
80+
81+
nr = __ffs(pending);
82+
misc_irq = irq_find_mapping(domain, nr);
83+
}
84+
85+
if (misc_irq) {
86+
generic_handle_irq(misc_irq);
87+
if (nr == AR5312_MISC_IRQ_TIMER)
88+
ar5312_rst_reg_read(AR5312_TIMER);
89+
} else {
90+
spurious_interrupt();
91+
}
92+
}
93+
94+
/* Enable the specified AR5312_MISC_IRQ interrupt */
95+
static void ar5312_misc_irq_unmask(struct irq_data *d)
96+
{
97+
ar5312_rst_reg_mask(AR5312_IMR, 0, BIT(d->hwirq));
98+
}
99+
100+
/* Disable the specified AR5312_MISC_IRQ interrupt */
101+
static void ar5312_misc_irq_mask(struct irq_data *d)
102+
{
103+
ar5312_rst_reg_mask(AR5312_IMR, BIT(d->hwirq), 0);
104+
ar5312_rst_reg_read(AR5312_IMR); /* flush write buffer */
105+
}
106+
107+
static struct irq_chip ar5312_misc_irq_chip = {
108+
.name = "ar5312-misc",
109+
.irq_unmask = ar5312_misc_irq_unmask,
110+
.irq_mask = ar5312_misc_irq_mask,
111+
};
112+
113+
static int ar5312_misc_irq_map(struct irq_domain *d, unsigned irq,
114+
irq_hw_number_t hw)
115+
{
116+
irq_set_chip_and_handler(irq, &ar5312_misc_irq_chip, handle_level_irq);
117+
return 0;
118+
}
119+
120+
static struct irq_domain_ops ar5312_misc_irq_domain_ops = {
121+
.map = ar5312_misc_irq_map,
122+
};
123+
124+
static void ar5312_irq_dispatch(void)
125+
{
126+
u32 pending = read_c0_status() & read_c0_cause();
127+
128+
if (pending & CAUSEF_IP2)
129+
do_IRQ(AR5312_IRQ_WLAN0);
130+
else if (pending & CAUSEF_IP5)
131+
do_IRQ(AR5312_IRQ_WLAN1);
132+
else if (pending & CAUSEF_IP6)
133+
do_IRQ(AR5312_IRQ_MISC);
134+
else if (pending & CAUSEF_IP7)
135+
do_IRQ(ATH25_IRQ_CPU_CLOCK);
136+
else
137+
spurious_interrupt();
138+
}
139+
140+
void __init ar5312_arch_init_irq(void)
141+
{
142+
struct irq_domain *domain;
143+
unsigned irq;
144+
145+
ath25_irq_dispatch = ar5312_irq_dispatch;
146+
147+
domain = irq_domain_add_linear(NULL, AR5312_MISC_IRQ_COUNT,
148+
&ar5312_misc_irq_domain_ops, NULL);
149+
if (!domain)
150+
panic("Failed to add IRQ domain");
151+
152+
irq = irq_create_mapping(domain, AR5312_MISC_IRQ_AHB_PROC);
153+
setup_irq(irq, &ar5312_ahb_err_interrupt);
154+
155+
irq_set_chained_handler(AR5312_IRQ_MISC, ar5312_misc_irq_handler);
156+
irq_set_handler_data(AR5312_IRQ_MISC, domain);
157+
158+
ar5312_misc_irq_domain = domain;
159+
}
160+
49161
static void ar5312_restart(char *command)
50162
{
51163
/* reset the system */

arch/mips/ath25/ar5312.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33

44
#ifdef CONFIG_SOC_AR5312
55

6+
void ar5312_arch_init_irq(void);
67
void ar5312_plat_time_init(void);
78
void ar5312_plat_mem_setup(void);
89

910
#else
1011

12+
static inline void ar5312_arch_init_irq(void) {}
1113
static inline void ar5312_plat_time_init(void) {}
1214
static inline void ar5312_plat_mem_setup(void) {}
1315

arch/mips/ath25/ar5312_regs.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,29 @@
1111
#ifndef __ASM_MACH_ATH25_AR5312_REGS_H
1212
#define __ASM_MACH_ATH25_AR5312_REGS_H
1313

14+
/*
15+
* IRQs
16+
*/
17+
#define AR5312_IRQ_WLAN0 (MIPS_CPU_IRQ_BASE + 2) /* C0_CAUSE: 0x0400 */
18+
#define AR5312_IRQ_ENET0 (MIPS_CPU_IRQ_BASE + 3) /* C0_CAUSE: 0x0800 */
19+
#define AR5312_IRQ_ENET1 (MIPS_CPU_IRQ_BASE + 4) /* C0_CAUSE: 0x1000 */
20+
#define AR5312_IRQ_WLAN1 (MIPS_CPU_IRQ_BASE + 5) /* C0_CAUSE: 0x2000 */
21+
#define AR5312_IRQ_MISC (MIPS_CPU_IRQ_BASE + 6) /* C0_CAUSE: 0x4000 */
22+
23+
/*
24+
* Miscellaneous interrupts, which share IP6.
25+
*/
26+
#define AR5312_MISC_IRQ_TIMER 0
27+
#define AR5312_MISC_IRQ_AHB_PROC 1
28+
#define AR5312_MISC_IRQ_AHB_DMA 2
29+
#define AR5312_MISC_IRQ_GPIO 3
30+
#define AR5312_MISC_IRQ_UART0 4
31+
#define AR5312_MISC_IRQ_UART0_DMA 5
32+
#define AR5312_MISC_IRQ_WATCHDOG 6
33+
#define AR5312_MISC_IRQ_LOCAL 7
34+
#define AR5312_MISC_IRQ_SPI 8
35+
#define AR5312_MISC_IRQ_COUNT 9
36+
1437
/*
1538
* Address Map
1639
*

arch/mips/ath25/board.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include "ar5312.h"
2121
#include "ar2315.h"
2222

23+
void (*ath25_irq_dispatch)(void);
24+
2325
static void ath25_halt(void)
2426
{
2527
local_irq_disable();
@@ -42,6 +44,7 @@ void __init plat_mem_setup(void)
4244

4345
asmlinkage void plat_irq_dispatch(void)
4446
{
47+
ath25_irq_dispatch();
4548
}
4649

4750
void __init plat_time_init(void)
@@ -61,4 +64,10 @@ void __init arch_init_irq(void)
6164
{
6265
clear_c0_status(ST0_IM);
6366
mips_cpu_irq_init();
67+
68+
/* Initialize interrupt controllers */
69+
if (is_ar5312())
70+
ar5312_arch_init_irq();
71+
else
72+
ar2315_arch_init_irq();
6473
}

0 commit comments

Comments
 (0)