aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/ath25
diff options
context:
space:
mode:
authorSergey Ryazanov <ryazanov.s.a@gmail.com>2014-10-28 19:18:41 -0400
committerRalf Baechle <ralf@linux-mips.org>2014-11-24 01:45:27 -0500
commit1753e74ed8fa3235174d5baa3421cbf8d693a42d (patch)
treebb6b196bb76d05dfb2be056218643ed2c0513baa /arch/mips/ath25
parentba910345034aea52d292bdc26b9c6831ab7b54e8 (diff)
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>
Diffstat (limited to 'arch/mips/ath25')
-rw-r--r--arch/mips/ath25/ar2315.c114
-rw-r--r--arch/mips/ath25/ar2315.h2
-rw-r--r--arch/mips/ath25/ar2315_regs.h23
-rw-r--r--arch/mips/ath25/ar5312.c112
-rw-r--r--arch/mips/ath25/ar5312.h2
-rw-r--r--arch/mips/ath25/ar5312_regs.h23
-rw-r--r--arch/mips/ath25/board.c9
-rw-r--r--arch/mips/ath25/devices.h4
8 files changed, 289 insertions, 0 deletions
diff --git a/arch/mips/ath25/ar2315.c b/arch/mips/ath25/ar2315.c
index 828943212f03..d92aa91ae75d 100644
--- a/arch/mips/ath25/ar2315.c
+++ b/arch/mips/ath25/ar2315.c
@@ -16,6 +16,9 @@
16 16
17#include <linux/init.h> 17#include <linux/init.h>
18#include <linux/kernel.h> 18#include <linux/kernel.h>
19#include <linux/bitops.h>
20#include <linux/irqdomain.h>
21#include <linux/interrupt.h>
19#include <linux/reboot.h> 22#include <linux/reboot.h>
20#include <asm/bootinfo.h> 23#include <asm/bootinfo.h>
21#include <asm/reboot.h> 24#include <asm/reboot.h>
@@ -26,6 +29,7 @@
26#include "ar2315_regs.h" 29#include "ar2315_regs.h"
27 30
28static void __iomem *ar2315_rst_base; 31static void __iomem *ar2315_rst_base;
32static struct irq_domain *ar2315_misc_irq_domain;
29 33
30static inline u32 ar2315_rst_reg_read(u32 reg) 34static inline u32 ar2315_rst_reg_read(u32 reg)
31{ 35{
@@ -46,6 +50,116 @@ static inline void ar2315_rst_reg_mask(u32 reg, u32 mask, u32 val)
46 ar2315_rst_reg_write(reg, ret); 50 ar2315_rst_reg_write(reg, ret);
47} 51}
48 52
53static 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
64static struct irqaction ar2315_ahb_err_interrupt = {
65 .handler = ar2315_ahb_err_handler,
66 .name = "ar2315-ahb-error",
67};
68
69static 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
93static void ar2315_misc_irq_unmask(struct irq_data *d)
94{
95 ar2315_rst_reg_mask(AR2315_IMR, 0, BIT(d->hwirq));
96}
97
98static void ar2315_misc_irq_mask(struct irq_data *d)
99{
100 ar2315_rst_reg_mask(AR2315_IMR, BIT(d->hwirq), 0);
101}
102
103static 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
109static 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
116static 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 */
128static 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
142void __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
49static void ar2315_restart(char *command) 163static void ar2315_restart(char *command)
50{ 164{
51 void (*mips_reset_vec)(void) = (void *)0xbfc00000; 165 void (*mips_reset_vec)(void) = (void *)0xbfc00000;
diff --git a/arch/mips/ath25/ar2315.h b/arch/mips/ath25/ar2315.h
index baeaf847223a..da5b843dd3a6 100644
--- a/arch/mips/ath25/ar2315.h
+++ b/arch/mips/ath25/ar2315.h
@@ -3,11 +3,13 @@
3 3
4#ifdef CONFIG_SOC_AR2315 4#ifdef CONFIG_SOC_AR2315
5 5
6void ar2315_arch_init_irq(void);
6void ar2315_plat_time_init(void); 7void ar2315_plat_time_init(void);
7void ar2315_plat_mem_setup(void); 8void ar2315_plat_mem_setup(void);
8 9
9#else 10#else
10 11
12static inline void ar2315_arch_init_irq(void) {}
11static inline void ar2315_plat_time_init(void) {} 13static inline void ar2315_plat_time_init(void) {}
12static inline void ar2315_plat_mem_setup(void) {} 14static inline void ar2315_plat_mem_setup(void) {}
13 15
diff --git a/arch/mips/ath25/ar2315_regs.h b/arch/mips/ath25/ar2315_regs.h
index c97d35127a5d..16e86149cb74 100644
--- a/arch/mips/ath25/ar2315_regs.h
+++ b/arch/mips/ath25/ar2315_regs.h
@@ -15,6 +15,29 @@
15#define __ASM_MACH_ATH25_AR2315_REGS_H 15#define __ASM_MACH_ATH25_AR2315_REGS_H
16 16
17/* 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
40/*
18 * Address map 41 * Address map
19 */ 42 */
20#define AR2315_SPI_READ_BASE 0x08000000 /* SPI flash */ 43#define AR2315_SPI_READ_BASE 0x08000000 /* SPI flash */
diff --git a/arch/mips/ath25/ar5312.c b/arch/mips/ath25/ar5312.c
index c2adaf2cd73a..b99a02a9e20e 100644
--- a/arch/mips/ath25/ar5312.c
+++ b/arch/mips/ath25/ar5312.c
@@ -16,6 +16,9 @@
16 16
17#include <linux/init.h> 17#include <linux/init.h>
18#include <linux/kernel.h> 18#include <linux/kernel.h>
19#include <linux/bitops.h>
20#include <linux/irqdomain.h>
21#include <linux/interrupt.h>
19#include <linux/reboot.h> 22#include <linux/reboot.h>
20#include <asm/bootinfo.h> 23#include <asm/bootinfo.h>
21#include <asm/reboot.h> 24#include <asm/reboot.h>
@@ -26,6 +29,7 @@
26#include "ar5312_regs.h" 29#include "ar5312_regs.h"
27 30
28static void __iomem *ar5312_rst_base; 31static void __iomem *ar5312_rst_base;
32static struct irq_domain *ar5312_misc_irq_domain;
29 33
30static inline u32 ar5312_rst_reg_read(u32 reg) 34static inline u32 ar5312_rst_reg_read(u32 reg)
31{ 35{
@@ -46,6 +50,114 @@ static inline void ar5312_rst_reg_mask(u32 reg, u32 mask, u32 val)
46 ar5312_rst_reg_write(reg, ret); 50 ar5312_rst_reg_write(reg, ret);
47} 51}
48 52
53static 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
67static struct irqaction ar5312_ahb_err_interrupt = {
68 .handler = ar5312_ahb_err_handler,
69 .name = "ar5312-ahb-error",
70};
71
72static 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 */
95static 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 */
101static 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
107static 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
113static 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
120static struct irq_domain_ops ar5312_misc_irq_domain_ops = {
121 .map = ar5312_misc_irq_map,
122};
123
124static 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
140void __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
49static void ar5312_restart(char *command) 161static void ar5312_restart(char *command)
50{ 162{
51 /* reset the system */ 163 /* reset the system */
diff --git a/arch/mips/ath25/ar5312.h b/arch/mips/ath25/ar5312.h
index 9e1e56e24eed..254f04f371b5 100644
--- a/arch/mips/ath25/ar5312.h
+++ b/arch/mips/ath25/ar5312.h
@@ -3,11 +3,13 @@
3 3
4#ifdef CONFIG_SOC_AR5312 4#ifdef CONFIG_SOC_AR5312
5 5
6void ar5312_arch_init_irq(void);
6void ar5312_plat_time_init(void); 7void ar5312_plat_time_init(void);
7void ar5312_plat_mem_setup(void); 8void ar5312_plat_mem_setup(void);
8 9
9#else 10#else
10 11
12static inline void ar5312_arch_init_irq(void) {}
11static inline void ar5312_plat_time_init(void) {} 13static inline void ar5312_plat_time_init(void) {}
12static inline void ar5312_plat_mem_setup(void) {} 14static inline void ar5312_plat_mem_setup(void) {}
13 15
diff --git a/arch/mips/ath25/ar5312_regs.h b/arch/mips/ath25/ar5312_regs.h
index ff1201119be0..4b947f967439 100644
--- a/arch/mips/ath25/ar5312_regs.h
+++ b/arch/mips/ath25/ar5312_regs.h
@@ -12,6 +12,29 @@
12#define __ASM_MACH_ATH25_AR5312_REGS_H 12#define __ASM_MACH_ATH25_AR5312_REGS_H
13 13
14/* 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
37/*
15 * Address Map 38 * Address Map
16 * 39 *
17 * The AR5312 supports 2 enet MACS, even though many reference boards only 40 * The AR5312 supports 2 enet MACS, even though many reference boards only
diff --git a/arch/mips/ath25/board.c b/arch/mips/ath25/board.c
index 6063bdf9066e..d4675e04a634 100644
--- a/arch/mips/ath25/board.c
+++ b/arch/mips/ath25/board.c
@@ -20,6 +20,8 @@
20#include "ar5312.h" 20#include "ar5312.h"
21#include "ar2315.h" 21#include "ar2315.h"
22 22
23void (*ath25_irq_dispatch)(void);
24
23static void ath25_halt(void) 25static void ath25_halt(void)
24{ 26{
25 local_irq_disable(); 27 local_irq_disable();
@@ -42,6 +44,7 @@ void __init plat_mem_setup(void)
42 44
43asmlinkage void plat_irq_dispatch(void) 45asmlinkage void plat_irq_dispatch(void)
44{ 46{
47 ath25_irq_dispatch();
45} 48}
46 49
47void __init plat_time_init(void) 50void __init plat_time_init(void)
@@ -61,4 +64,10 @@ void __init arch_init_irq(void)
61{ 64{
62 clear_c0_status(ST0_IM); 65 clear_c0_status(ST0_IM);
63 mips_cpu_irq_init(); 66 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();
64} 73}
diff --git a/arch/mips/ath25/devices.h b/arch/mips/ath25/devices.h
index e25a3262256d..2985586a0f2c 100644
--- a/arch/mips/ath25/devices.h
+++ b/arch/mips/ath25/devices.h
@@ -5,6 +5,10 @@
5 5
6#define ATH25_REG_MS(_val, _field) (((_val) & _field##_M) >> _field##_S) 6#define ATH25_REG_MS(_val, _field) (((_val) & _field##_M) >> _field##_S)
7 7
8#define ATH25_IRQ_CPU_CLOCK (MIPS_CPU_IRQ_BASE + 7) /* C0_CAUSE: 0x8000 */
9
10extern void (*ath25_irq_dispatch)(void);
11
8static inline bool is_ar2315(void) 12static inline bool is_ar2315(void)
9{ 13{
10 return (current_cpu_data.cputype == CPU_4KEC); 14 return (current_cpu_data.cputype == CPU_4KEC);