1 /*
2 * Copyright (c) 2008, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google, Inc. nor the names of its contributors
15 * may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <arch/arm.h>
33 #include <lk/reg.h>
34 #include <kernel/thread.h>
35 #include <platform/interrupts.h>
36 #include <sync_write.h>
37 #include <platform/mt_typedefs.h>
38 #include <platform/mt_reg_base.h>
39 #include <platform/mt_gpt.h>
40 #include <platform/mt_irq.h>
41
42 #include <lk/debug.h>
43
44 #define GIC_ICDISER0 (GIC_DIST_BASE + 0x100)
45 #define GIC_ICDISER1 (GIC_DIST_BASE + 0x104)
46 #define GIC_ICDISER2 (GIC_DIST_BASE + 0x108)
47 #define GIC_ICDISER3 (GIC_DIST_BASE + 0x10C)
48 #define GIC_ICDISER4 (GIC_DIST_BASE + 0x110)
49 #define GIC_ICDISER5 (GIC_DIST_BASE + 0x114)
50 #define GIC_ICDISER6 (GIC_DIST_BASE + 0x118)
51 #define GIC_ICDISER7 (GIC_DIST_BASE + 0x11C)
52
53 #define GIC_ICDICER0 (GIC_DIST_BASE + 0x180)
54 #define GIC_ICDICER1 (GIC_DIST_BASE + 0x184)
55 #define GIC_ICDICER2 (GIC_DIST_BASE + 0x188)
56 #define GIC_ICDICER3 (GIC_DIST_BASE + 0x18C)
57 #define GIC_ICDICER4 (GIC_DIST_BASE + 0x190)
58 #define GIC_ICDICER5 (GIC_DIST_BASE + 0x194)
59 #define GIC_ICDICER6 (GIC_DIST_BASE + 0x198)
60 #define GIC_ICDICER7 (GIC_DIST_BASE + 0x19C)
61
62 #define INT_POL_CTL0 (MCUCFG_BASE + 0x620)
63
mt_gic_cpu_init(void)64 static void mt_gic_cpu_init(void) {
65 DRV_WriteReg32(GIC_CPU_BASE + GIC_CPU_PRIMASK, 0xF0);
66 DRV_WriteReg32(GIC_CPU_BASE + GIC_CPU_CTRL, 0x1);
67 dsb();
68 }
69
mt_gic_dist_init(void)70 static void mt_gic_dist_init(void) {
71 unsigned int i;
72 #ifndef MTK_FORCE_CLUSTER1
73 unsigned int cpumask = 1 << 0;
74 #else
75 unsigned int cpumask = 1 << 4;
76 #endif
77
78 cpumask |= cpumask << 8;
79 cpumask |= cpumask << 16;
80
81 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_CTRL, 0);
82
83 /*
84 * Set all global interrupts to be level triggered, active low.
85 */
86 for (i = 32; i < (MT_NR_SPI + 32); i += 16) {
87 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_CONFIG + i * 4 / 16, 0);
88 }
89
90 /*
91 * Set all global interrupts to this CPU only.
92 */
93 for (i = 32; i < (MT_NR_SPI + 32); i += 4) {
94 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_TARGET + i * 4 / 4, cpumask);
95 }
96
97 /*
98 * Set priority on all interrupts.
99 */
100 for (i = 0; i < NR_IRQ_LINE; i += 4) {
101 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_PRI + i * 4 / 4, 0xA0A0A0A0);
102 }
103
104 /*
105 * Disable all interrupts.
106 */
107 for (i = 0; i < NR_IRQ_LINE; i += 32) {
108 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR + i * 4 / 32, 0xFFFFFFFF);
109 }
110
111 dsb();
112
113 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_CTRL, 1);
114 }
115
platform_init_interrupts(void)116 void platform_init_interrupts(void) {
117 mt_gic_dist_init();
118 mt_gic_cpu_init();
119 }
120
platform_deinit_interrupts(void)121 void platform_deinit_interrupts(void) {
122 unsigned int irq;
123
124 DRV_WriteReg32(GIC_ICDICER0, 0xFFFFFFFF);
125 DRV_WriteReg32(GIC_ICDICER1, 0xFFFFFFFF);
126 DRV_WriteReg32(GIC_ICDICER2, 0xFFFFFFFF);
127 DRV_WriteReg32(GIC_ICDICER3, 0xFFFFFFFF);
128 DRV_WriteReg32(GIC_ICDICER4, 0xFFFFFFFF);
129 DRV_WriteReg32(GIC_ICDICER5, 0xFFFFFFFF);
130 DRV_WriteReg32(GIC_ICDICER6, 0xFFFFFFFF);
131 DRV_WriteReg32(GIC_ICDICER7, 0xFFFFFFFF);
132 dsb();
133
134 while ((irq = DRV_Reg32(GIC_CPU_BASE + GIC_CPU_INTACK)) != 1023 ) {
135 DRV_WriteReg32(GIC_CPU_BASE + GIC_CPU_EOI, irq);
136 }
137 }
138
139 extern void lk_scheduler(void);
140 //extern void lk_usb_scheduler(void);
141 extern void lk_nand_irq_handler(unsigned int irq);
142 //extern void lk_msdc_irq_handler(unsigned int irq);
143 #ifdef DUMMY_AP
144 extern void dummy_ap_irq_handler(unsigned int irq);
145 #endif
146
platform_irq(struct arm_iframe * frame)147 enum handler_return platform_irq(struct arm_iframe *frame) {
148 unsigned int irq = DRV_Reg32(GIC_CPU_BASE + GIC_CPU_INTACK);
149
150 if (irq == MT_GPT_IRQ_ID)
151 lk_scheduler();
152 // else if(irq == MT_USB0_IRQ_ID)
153 // lk_usb_scheduler();
154 #ifndef MTK_EMMC_SUPPORT
155 // else if(irq == MT_NFI_IRQ_ID)
156 // lk_nand_irq_handler(irq);
157 #endif
158 // else if(irq == MT_MSDC0_IRQ_ID || irq == MT_MSDC1_IRQ_ID)
159 // lk_msdc_irq_handler(irq);
160
161 #ifdef DUMMY_AP
162 dummy_ap_irq_handler(irq);
163 #endif
164
165 //return INT_NO_RESCHEDULE;
166 return INT_RESCHEDULE;
167 }
168
platform_fiq(struct arm_iframe * frame)169 void platform_fiq(struct arm_iframe *frame) {
170
171 }
172
mt_irq_set_polarity(unsigned int irq,unsigned int polarity)173 void mt_irq_set_polarity(unsigned int irq, unsigned int polarity) {
174 unsigned int offset;
175 unsigned int reg_index;
176 unsigned int value;
177
178 // peripheral device's IRQ line is using GIC's SPI, and line ID >= GIC_PRIVATE_SIGNALS
179 if (irq < GIC_PRIVATE_SIGNALS) {
180 return;
181 }
182
183 offset = (irq - GIC_PRIVATE_SIGNALS) & 0x1F;
184 reg_index = (irq - GIC_PRIVATE_SIGNALS) >> 5;
185 if (polarity == 0) {
186 value = DRV_Reg32(INT_POL_CTL0 + (reg_index * 4));
187 value |= (1 << offset); // always invert the incoming IRQ's polarity
188 DRV_WriteReg32((INT_POL_CTL0 + (reg_index * 4)), value);
189 } else {
190 value = DRV_Reg32(INT_POL_CTL0 + (reg_index * 4));
191 value &= ~(0x1 << offset);
192 DRV_WriteReg32(INT_POL_CTL0 + (reg_index * 4), value);
193 }
194 }
195
mt_irq_set_sens(unsigned int irq,unsigned int sens)196 void mt_irq_set_sens(unsigned int irq, unsigned int sens) {
197 unsigned int config;
198
199 if (sens == MT65xx_EDGE_SENSITIVE) {
200 config = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4);
201 config |= (0x2 << (irq % 16) * 2);
202 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4, config);
203 } else {
204 config = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4);
205 config &= ~(0x2 << (irq % 16) * 2);
206 DRV_WriteReg32( GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4, config);
207 }
208 dsb();
209 }
210
211 /*
212 * mt_irq_mask: mask one IRQ
213 * @irq: IRQ line of the IRQ to mask
214 */
mt_irq_mask(unsigned int irq)215 void mt_irq_mask(unsigned int irq) {
216 unsigned int mask = 1 << (irq % 32);
217
218 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR + irq / 32 * 4, mask);
219 dsb();
220 }
221
222 /*
223 * mt_irq_unmask: unmask one IRQ
224 * @irq: IRQ line of the IRQ to unmask
225 */
mt_irq_unmask(unsigned int irq)226 void mt_irq_unmask(unsigned int irq) {
227 unsigned int mask = 1 << (irq % 32);
228
229 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ENABLE_SET + irq / 32 * 4, mask);
230 dsb();
231 }
232
233 /*
234 * mt_irq_mask: mask one IRQ
235 * @irq: IRQ line of the IRQ to mask
236 */
mt_irq_ack(unsigned int irq)237 void mt_irq_ack(unsigned int irq) {
238 DRV_WriteReg32(GIC_CPU_BASE + GIC_CPU_EOI, irq);
239 dsb();
240 }
241
242 /*
243 * mt_irq_mask_all: mask all IRQ lines. (This is ONLY used for the sleep driver)
244 * @mask: pointer to struct mtk_irq_mask for storing the original mask value.
245 * Return 0 for success; return negative values for failure.
246 */
mt_irq_mask_all(struct mtk_irq_mask * mask)247 int mt_irq_mask_all(struct mtk_irq_mask *mask) {
248 if (mask) {
249
250 mask->mask0 = DRV_Reg32(GIC_ICDISER0);
251 mask->mask1 = DRV_Reg32(GIC_ICDISER1);
252 mask->mask2 = DRV_Reg32(GIC_ICDISER2);
253 mask->mask3 = DRV_Reg32(GIC_ICDISER3);
254 mask->mask4 = DRV_Reg32(GIC_ICDISER4);
255 mask->mask5 = DRV_Reg32(GIC_ICDISER5);
256 mask->mask6 = DRV_Reg32(GIC_ICDISER6);
257 mask->mask7 = DRV_Reg32(GIC_ICDISER7);
258
259 DRV_WriteReg32(GIC_ICDICER0, 0xFFFFFFFF);
260 DRV_WriteReg32(GIC_ICDICER1, 0xFFFFFFFF);
261 DRV_WriteReg32(GIC_ICDICER2, 0xFFFFFFFF);
262 DRV_WriteReg32(GIC_ICDICER3, 0xFFFFFFFF);
263 DRV_WriteReg32(GIC_ICDICER4, 0xFFFFFFFF);
264 DRV_WriteReg32(GIC_ICDICER5, 0xFFFFFFFF);
265 DRV_WriteReg32(GIC_ICDICER6, 0xFFFFFFFF);
266 DRV_WriteReg32(GIC_ICDICER7, 0xFFFFFFFF);
267
268 dsb();
269
270 mask->header = IRQ_MASK_HEADER;
271 mask->footer = IRQ_MASK_FOOTER;
272
273 return 0;
274 } else {
275 return -1;
276 }
277 }
278
279 /*
280 * mt_irq_mask_restore: restore all IRQ lines' masks. (This is ONLY used for the sleep driver)
281 * @mask: pointer to struct mtk_irq_mask for storing the original mask value.
282 * Return 0 for success; return negative values for failure.
283 */
mt_irq_mask_restore(struct mtk_irq_mask * mask)284 int mt_irq_mask_restore(struct mtk_irq_mask *mask) {
285 if (!mask) {
286 return -1;
287 }
288 if (mask->header != IRQ_MASK_HEADER) {
289 return -1;
290 }
291 if (mask->footer != IRQ_MASK_FOOTER) {
292 return -1;
293 }
294
295 DRV_WriteReg32(GIC_ICDISER0,mask->mask0);
296 DRV_WriteReg32(GIC_ICDISER1,mask->mask1);
297 DRV_WriteReg32(GIC_ICDISER2,mask->mask2);
298 DRV_WriteReg32(GIC_ICDISER3,mask->mask3);
299 DRV_WriteReg32(GIC_ICDISER4,mask->mask4);
300 DRV_WriteReg32(GIC_ICDISER5,mask->mask5);
301 DRV_WriteReg32(GIC_ICDISER6,mask->mask6);
302 DRV_WriteReg32(GIC_ICDISER7,mask->mask7);
303
304 dsb();
305
306
307 return 0;
308 }
309