diff options
author | Jonas Bonn <jonas@southpole.se> | 2011-06-04 15:18:56 -0400 |
---|---|---|
committer | Jonas Bonn <jonas@southpole.se> | 2011-07-22 12:46:33 -0400 |
commit | 816ebaa8b6ea8f97515a40e25076f297d0304611 (patch) | |
tree | 773c1c5b042dd535e6d40bf064370a036cfe18f3 /arch/openrisc | |
parent | b731fbbd246e3aba59701bd6112a14ba02bf1c1c (diff) |
OpenRISC: IRQ
This patch adds support for the OpenRISC PIC.
Signed-off-by: Jonas Bonn <jonas@southpole.se>
Cc: tglx@linutronix.de
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/openrisc')
-rw-r--r-- | arch/openrisc/include/asm/irq.h | 27 | ||||
-rw-r--r-- | arch/openrisc/include/asm/irqflags.h | 29 | ||||
-rw-r--r-- | arch/openrisc/kernel/irq.c | 172 |
3 files changed, 228 insertions, 0 deletions
diff --git a/arch/openrisc/include/asm/irq.h b/arch/openrisc/include/asm/irq.h new file mode 100644 index 000000000000..eb612b1865d2 --- /dev/null +++ b/arch/openrisc/include/asm/irq.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * OpenRISC Linux | ||
3 | * | ||
4 | * Linux architectural port borrowing liberally from similar works of | ||
5 | * others. All original copyrights apply as per the original source | ||
6 | * declaration. | ||
7 | * | ||
8 | * OpenRISC implementation: | ||
9 | * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com> | ||
10 | * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> | ||
11 | * et al. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | */ | ||
18 | |||
19 | #ifndef __ASM_OPENRISC_IRQ_H__ | ||
20 | #define __ASM_OPENRISC_IRQ_H__ | ||
21 | |||
22 | #define NR_IRQS 32 | ||
23 | #include <asm-generic/irq.h> | ||
24 | |||
25 | #define NO_IRQ (-1) | ||
26 | |||
27 | #endif /* __ASM_OPENRISC_IRQ_H__ */ | ||
diff --git a/arch/openrisc/include/asm/irqflags.h b/arch/openrisc/include/asm/irqflags.h new file mode 100644 index 000000000000..dc86c653d70b --- /dev/null +++ b/arch/openrisc/include/asm/irqflags.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * OpenRISC Linux | ||
3 | * | ||
4 | * Linux architectural port borrowing liberally from similar works of | ||
5 | * others. All original copyrights apply as per the original source | ||
6 | * declaration. | ||
7 | * | ||
8 | * OpenRISC implementation: | ||
9 | * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com> | ||
10 | * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> | ||
11 | * et al. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | */ | ||
18 | |||
19 | #ifndef ___ASM_OPENRISC_IRQFLAGS_H | ||
20 | #define ___ASM_OPENRISC_IRQFLAGS_H | ||
21 | |||
22 | #include <asm/spr_defs.h> | ||
23 | |||
24 | #define ARCH_IRQ_DISABLED 0x00 | ||
25 | #define ARCH_IRQ_ENABLED (SPR_SR_IEE|SPR_SR_TEE) | ||
26 | |||
27 | #include <asm-generic/irqflags.h> | ||
28 | |||
29 | #endif /* ___ASM_OPENRISC_IRQFLAGS_H */ | ||
diff --git a/arch/openrisc/kernel/irq.c b/arch/openrisc/kernel/irq.c new file mode 100644 index 000000000000..59b302338331 --- /dev/null +++ b/arch/openrisc/kernel/irq.c | |||
@@ -0,0 +1,172 @@ | |||
1 | /* | ||
2 | * OpenRISC irq.c | ||
3 | * | ||
4 | * Linux architectural port borrowing liberally from similar works of | ||
5 | * others. All original copyrights apply as per the original source | ||
6 | * declaration. | ||
7 | * | ||
8 | * Modifications for the OpenRISC architecture: | ||
9 | * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version | ||
14 | * 2 of the License, or (at your option) any later version. | ||
15 | */ | ||
16 | |||
17 | #include <linux/ptrace.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/of.h> | ||
22 | #include <linux/ftrace.h> | ||
23 | #include <linux/irq.h> | ||
24 | #include <linux/seq_file.h> | ||
25 | #include <linux/kernel_stat.h> | ||
26 | |||
27 | #include <linux/irqflags.h> | ||
28 | |||
29 | /* read interrupt enabled status */ | ||
30 | unsigned long arch_local_save_flags(void) | ||
31 | { | ||
32 | return mfspr(SPR_SR) & (SPR_SR_IEE|SPR_SR_TEE); | ||
33 | } | ||
34 | EXPORT_SYMBOL(arch_local_save_flags); | ||
35 | |||
36 | /* set interrupt enabled status */ | ||
37 | void arch_local_irq_restore(unsigned long flags) | ||
38 | { | ||
39 | mtspr(SPR_SR, ((mfspr(SPR_SR) & ~(SPR_SR_IEE|SPR_SR_TEE)) | flags)); | ||
40 | } | ||
41 | EXPORT_SYMBOL(arch_local_irq_restore); | ||
42 | |||
43 | |||
44 | /* OR1K PIC implementation */ | ||
45 | |||
46 | /* We're a couple of cycles faster than the generic implementations with | ||
47 | * these 'fast' versions. | ||
48 | */ | ||
49 | |||
50 | static void or1k_pic_mask(struct irq_data *data) | ||
51 | { | ||
52 | mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->irq)); | ||
53 | } | ||
54 | |||
55 | static void or1k_pic_unmask(struct irq_data *data) | ||
56 | { | ||
57 | mtspr(SPR_PICMR, mfspr(SPR_PICMR) | (1UL << data->irq)); | ||
58 | } | ||
59 | |||
60 | static void or1k_pic_ack(struct irq_data *data) | ||
61 | { | ||
62 | /* EDGE-triggered interrupts need to be ack'ed in order to clear | ||
63 | * the latch. | ||
64 | * LEVER-triggered interrupts do not need to be ack'ed; however, | ||
65 | * ack'ing the interrupt has no ill-effect and is quicker than | ||
66 | * trying to figure out what type it is... | ||
67 | */ | ||
68 | |||
69 | /* The OpenRISC 1000 spec says to write a 1 to the bit to ack the | ||
70 | * interrupt, but the OR1200 does this backwards and requires a 0 | ||
71 | * to be written... | ||
72 | */ | ||
73 | |||
74 | #ifdef CONFIG_OR1K_1200 | ||
75 | /* There are two oddities with the OR1200 PIC implementation: | ||
76 | * i) LEVEL-triggered interrupts are latched and need to be cleared | ||
77 | * ii) the interrupt latch is cleared by writing a 0 to the bit, | ||
78 | * as opposed to a 1 as mandated by the spec | ||
79 | */ | ||
80 | |||
81 | mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->irq)); | ||
82 | #else | ||
83 | WARN(1, "Interrupt handling possibily broken\n"); | ||
84 | mtspr(SPR_PICSR, (1UL << irq)); | ||
85 | #endif | ||
86 | } | ||
87 | |||
88 | static void or1k_pic_mask_ack(struct irq_data *data) | ||
89 | { | ||
90 | /* Comments for pic_ack apply here, too */ | ||
91 | |||
92 | #ifdef CONFIG_OR1K_1200 | ||
93 | mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->irq)); | ||
94 | #else | ||
95 | WARN(1, "Interrupt handling possibily broken\n"); | ||
96 | mtspr(SPR_PICSR, (1UL << irq)); | ||
97 | #endif | ||
98 | } | ||
99 | |||
100 | static int or1k_pic_set_type(struct irq_data *data, unsigned int flow_type) | ||
101 | { | ||
102 | /* There's nothing to do in the PIC configuration when changing | ||
103 | * flow type. Level and edge-triggered interrupts are both | ||
104 | * supported, but it's PIC-implementation specific which type | ||
105 | * is handled. */ | ||
106 | |||
107 | return irq_setup_alt_chip(data, flow_type); | ||
108 | } | ||
109 | |||
110 | static inline int pic_get_irq(int first) | ||
111 | { | ||
112 | int irq; | ||
113 | |||
114 | irq = ffs(mfspr(SPR_PICSR) >> first); | ||
115 | |||
116 | return irq ? irq + first - 1 : NO_IRQ; | ||
117 | } | ||
118 | |||
119 | static void __init or1k_irq_init(void) | ||
120 | { | ||
121 | struct irq_chip_generic *gc; | ||
122 | struct irq_chip_type *ct; | ||
123 | |||
124 | /* Disable all interrupts until explicitly requested */ | ||
125 | mtspr(SPR_PICMR, (0UL)); | ||
126 | |||
127 | gc = irq_alloc_generic_chip("or1k-PIC", 1, 0, 0, handle_level_irq); | ||
128 | ct = gc->chip_types; | ||
129 | |||
130 | ct->chip.irq_unmask = or1k_pic_unmask; | ||
131 | ct->chip.irq_mask = or1k_pic_mask; | ||
132 | ct->chip.irq_ack = or1k_pic_ack; | ||
133 | ct->chip.irq_mask_ack = or1k_pic_mask_ack; | ||
134 | ct->chip.irq_set_type = or1k_pic_set_type; | ||
135 | |||
136 | /* The OR1K PIC can handle both level and edge trigged | ||
137 | * interrupts in roughly the same manner | ||
138 | */ | ||
139 | #if 0 | ||
140 | /* FIXME: chip.type??? */ | ||
141 | ct->chip.type = IRQ_TYPE_EDGE_BOTH | IRQ_TYPE_LEVEL_MASK; | ||
142 | #endif | ||
143 | |||
144 | irq_setup_generic_chip(gc, IRQ_MSK(NR_IRQS), 0, | ||
145 | IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); | ||
146 | } | ||
147 | |||
148 | void __init init_IRQ(void) | ||
149 | { | ||
150 | or1k_irq_init(); | ||
151 | } | ||
152 | |||
153 | void __irq_entry do_IRQ(struct pt_regs *regs) | ||
154 | { | ||
155 | int irq = -1; | ||
156 | struct pt_regs *old_regs = set_irq_regs(regs); | ||
157 | |||
158 | irq_enter(); | ||
159 | |||
160 | while ((irq = pic_get_irq(irq + 1)) != NO_IRQ) | ||
161 | generic_handle_irq(irq); | ||
162 | |||
163 | irq_exit(); | ||
164 | set_irq_regs(old_regs); | ||
165 | } | ||
166 | |||
167 | unsigned int irq_create_of_mapping(struct device_node *controller, | ||
168 | const u32 *intspec, unsigned int intsize) | ||
169 | { | ||
170 | return intspec[0]; | ||
171 | } | ||
172 | EXPORT_SYMBOL_GPL(irq_create_of_mapping); | ||