diff options
Diffstat (limited to 'arch/sh/kernel/cpu/irq/ipr.c')
-rw-r--r-- | arch/sh/kernel/cpu/irq/ipr.c | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c new file mode 100644 index 000000000000..fdbd718ae5c6 --- /dev/null +++ b/arch/sh/kernel/cpu/irq/ipr.c | |||
@@ -0,0 +1,206 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/irq/ipr.c | ||
3 | * | ||
4 | * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi | ||
5 | * Copyright (C) 2000 Kazumoto Kojima | ||
6 | * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp> | ||
7 | * | ||
8 | * Interrupt handling for IPR-based IRQ. | ||
9 | * | ||
10 | * Supported system: | ||
11 | * On-chip supporting modules (TMU, RTC, etc.). | ||
12 | * On-chip supporting modules for SH7709/SH7709A/SH7729/SH7300. | ||
13 | * Hitachi SolutionEngine external I/O: | ||
14 | * MS7709SE01, MS7709ASE01, and MS7750SE01 | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/config.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/irq.h> | ||
21 | #include <linux/module.h> | ||
22 | |||
23 | #include <asm/system.h> | ||
24 | #include <asm/io.h> | ||
25 | #include <asm/machvec.h> | ||
26 | |||
27 | struct ipr_data { | ||
28 | unsigned int addr; /* Address of Interrupt Priority Register */ | ||
29 | int shift; /* Shifts of the 16-bit data */ | ||
30 | int priority; /* The priority */ | ||
31 | }; | ||
32 | static struct ipr_data ipr_data[NR_IRQS]; | ||
33 | |||
34 | static void enable_ipr_irq(unsigned int irq); | ||
35 | static void disable_ipr_irq(unsigned int irq); | ||
36 | |||
37 | /* shutdown is same as "disable" */ | ||
38 | #define shutdown_ipr_irq disable_ipr_irq | ||
39 | |||
40 | static void mask_and_ack_ipr(unsigned int); | ||
41 | static void end_ipr_irq(unsigned int irq); | ||
42 | |||
43 | static unsigned int startup_ipr_irq(unsigned int irq) | ||
44 | { | ||
45 | enable_ipr_irq(irq); | ||
46 | return 0; /* never anything pending */ | ||
47 | } | ||
48 | |||
49 | static struct hw_interrupt_type ipr_irq_type = { | ||
50 | .typename = "IPR-IRQ", | ||
51 | .startup = startup_ipr_irq, | ||
52 | .shutdown = shutdown_ipr_irq, | ||
53 | .enable = enable_ipr_irq, | ||
54 | .disable = disable_ipr_irq, | ||
55 | .ack = mask_and_ack_ipr, | ||
56 | .end = end_ipr_irq | ||
57 | }; | ||
58 | |||
59 | static void disable_ipr_irq(unsigned int irq) | ||
60 | { | ||
61 | unsigned long val, flags; | ||
62 | unsigned int addr = ipr_data[irq].addr; | ||
63 | unsigned short mask = 0xffff ^ (0x0f << ipr_data[irq].shift); | ||
64 | |||
65 | /* Set the priority in IPR to 0 */ | ||
66 | local_irq_save(flags); | ||
67 | val = ctrl_inw(addr); | ||
68 | val &= mask; | ||
69 | ctrl_outw(val, addr); | ||
70 | local_irq_restore(flags); | ||
71 | } | ||
72 | |||
73 | static void enable_ipr_irq(unsigned int irq) | ||
74 | { | ||
75 | unsigned long val, flags; | ||
76 | unsigned int addr = ipr_data[irq].addr; | ||
77 | int priority = ipr_data[irq].priority; | ||
78 | unsigned short value = (priority << ipr_data[irq].shift); | ||
79 | |||
80 | /* Set priority in IPR back to original value */ | ||
81 | local_irq_save(flags); | ||
82 | val = ctrl_inw(addr); | ||
83 | val |= value; | ||
84 | ctrl_outw(val, addr); | ||
85 | local_irq_restore(flags); | ||
86 | } | ||
87 | |||
88 | static void mask_and_ack_ipr(unsigned int irq) | ||
89 | { | ||
90 | disable_ipr_irq(irq); | ||
91 | |||
92 | #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ | ||
93 | defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) | ||
94 | /* This is needed when we use edge triggered setting */ | ||
95 | /* XXX: Is it really needed? */ | ||
96 | if (IRQ0_IRQ <= irq && irq <= IRQ5_IRQ) { | ||
97 | /* Clear external interrupt request */ | ||
98 | int a = ctrl_inb(INTC_IRR0); | ||
99 | a &= ~(1 << (irq - IRQ0_IRQ)); | ||
100 | ctrl_outb(a, INTC_IRR0); | ||
101 | } | ||
102 | #endif | ||
103 | } | ||
104 | |||
105 | static void end_ipr_irq(unsigned int irq) | ||
106 | { | ||
107 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
108 | enable_ipr_irq(irq); | ||
109 | } | ||
110 | |||
111 | void make_ipr_irq(unsigned int irq, unsigned int addr, int pos, | ||
112 | int priority, int maskpos) | ||
113 | { | ||
114 | disable_irq_nosync(irq); | ||
115 | ipr_data[irq].addr = addr; | ||
116 | ipr_data[irq].shift = pos*4; /* POSition (0-3) x 4 means shift */ | ||
117 | ipr_data[irq].priority = priority; | ||
118 | |||
119 | irq_desc[irq].handler = &ipr_irq_type; | ||
120 | disable_ipr_irq(irq); | ||
121 | } | ||
122 | |||
123 | void __init init_IRQ(void) | ||
124 | { | ||
125 | #ifndef CONFIG_CPU_SUBTYPE_SH7780 | ||
126 | make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY, 0); | ||
127 | make_ipr_irq(TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY, 0); | ||
128 | #if defined(CONFIG_SH_RTC) | ||
129 | make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY, 0); | ||
130 | #endif | ||
131 | |||
132 | #ifdef SCI_ERI_IRQ | ||
133 | make_ipr_irq(SCI_ERI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY, 0); | ||
134 | make_ipr_irq(SCI_RXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY, 0); | ||
135 | make_ipr_irq(SCI_TXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY, 0); | ||
136 | #endif | ||
137 | |||
138 | #ifdef SCIF1_ERI_IRQ | ||
139 | make_ipr_irq(SCIF1_ERI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY, 0); | ||
140 | make_ipr_irq(SCIF1_RXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY, 0); | ||
141 | make_ipr_irq(SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY, 0); | ||
142 | make_ipr_irq(SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY, 0); | ||
143 | #endif | ||
144 | |||
145 | #if defined(CONFIG_CPU_SUBTYPE_SH7300) | ||
146 | make_ipr_irq(SCIF0_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS, SCIF0_PRIORITY, 0); | ||
147 | make_ipr_irq(DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY, 0); | ||
148 | make_ipr_irq(DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY, 0); | ||
149 | make_ipr_irq(VIO_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY, 0); | ||
150 | #endif | ||
151 | |||
152 | #ifdef SCIF_ERI_IRQ | ||
153 | make_ipr_irq(SCIF_ERI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY, 0); | ||
154 | make_ipr_irq(SCIF_RXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY, 0); | ||
155 | make_ipr_irq(SCIF_BRI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY, 0); | ||
156 | make_ipr_irq(SCIF_TXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY, 0); | ||
157 | #endif | ||
158 | |||
159 | #ifdef IRDA_ERI_IRQ | ||
160 | make_ipr_irq(IRDA_ERI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY, 0); | ||
161 | make_ipr_irq(IRDA_RXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY, 0); | ||
162 | make_ipr_irq(IRDA_BRI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY, 0); | ||
163 | make_ipr_irq(IRDA_TXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY, 0); | ||
164 | #endif | ||
165 | |||
166 | #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ | ||
167 | defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) | ||
168 | /* | ||
169 | * Initialize the Interrupt Controller (INTC) | ||
170 | * registers to their power on values | ||
171 | */ | ||
172 | |||
173 | /* | ||
174 | * Enable external irq (INTC IRQ mode). | ||
175 | * You should set corresponding bits of PFC to "00" | ||
176 | * to enable these interrupts. | ||
177 | */ | ||
178 | make_ipr_irq(IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, IRQ0_PRIORITY, 0); | ||
179 | make_ipr_irq(IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, IRQ1_PRIORITY, 0); | ||
180 | make_ipr_irq(IRQ2_IRQ, IRQ2_IPR_ADDR, IRQ2_IPR_POS, IRQ2_PRIORITY, 0); | ||
181 | make_ipr_irq(IRQ3_IRQ, IRQ3_IPR_ADDR, IRQ3_IPR_POS, IRQ3_PRIORITY, 0); | ||
182 | make_ipr_irq(IRQ4_IRQ, IRQ4_IPR_ADDR, IRQ4_IPR_POS, IRQ4_PRIORITY, 0); | ||
183 | make_ipr_irq(IRQ5_IRQ, IRQ5_IPR_ADDR, IRQ5_IPR_POS, IRQ5_PRIORITY, 0); | ||
184 | #endif | ||
185 | #endif | ||
186 | |||
187 | #ifdef CONFIG_CPU_HAS_PINT_IRQ | ||
188 | init_IRQ_pint(); | ||
189 | #endif | ||
190 | |||
191 | #ifdef CONFIG_CPU_HAS_INTC2_IRQ | ||
192 | init_IRQ_intc2(); | ||
193 | #endif | ||
194 | /* Perform the machine specific initialisation */ | ||
195 | if (sh_mv.mv_init_irq != NULL) | ||
196 | sh_mv.mv_init_irq(); | ||
197 | } | ||
198 | |||
199 | #if !defined(CONFIG_CPU_HAS_PINT_IRQ) | ||
200 | int ipr_irq_demux(int irq) | ||
201 | { | ||
202 | return irq; | ||
203 | } | ||
204 | #endif | ||
205 | |||
206 | EXPORT_SYMBOL(make_ipr_irq); | ||