1 /*
2 * Copyright (c) 2015 MediaTek Inc.
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8 #include <lk/reg.h>
9 #include <platform/mt_typedefs.h>
10 #include <platform/mt_reg_base.h>
11 #include <platform/mt_irq.h>
12 #include <mt_gic.h>
13 #include <sync_write.h>
14 #include <lk/debug.h>
15
16 #define GICD_CTLR_RWP (1 << 31)
17 #define GICD_CTLR_ARE (1 << 4)
18 #define GICD_CTLR_ENGRP1S (1 << 2)
19 #define GICD_CTLR_ENGRP1NS (1 << 1)
20 #define GICR_WAKER_ProcessorSleep (1 << 1)
21 #define GICR_WAKER_ChildrenAsleep (1 << 2)
22
23 extern uint32_t mt_interrupt_needed_for_secure(void);
24 extern uint64_t mt_irq_get_affinity(void);
25
mt_gic_icc_primask_write(uint32_t reg)26 static void mt_gic_icc_primask_write(uint32_t reg) {
27 __asm__ volatile("MCR p15, 0, %0, c4, c6, 0" :: "r" (reg));
28 }
29
mt_gic_icc_primask_read(void)30 static uint32_t mt_gic_icc_primask_read(void) {
31 uint32_t reg;
32
33 __asm__ volatile("MRC p15, 0, %0, c4, c6, 0" : "=r" (reg));
34
35 return reg;
36 }
37
mt_gic_icc_igrpen1_write(uint32_t reg)38 static void mt_gic_icc_igrpen1_write(uint32_t reg) {
39 __asm__ volatile("MCR p15, 0, %0, c12, c12, 7" :: "r" (reg));
40 }
41
mt_gic_icc_igrpen1_read(void)42 static uint32_t mt_gic_icc_igrpen1_read(void) {
43 uint32_t reg;
44
45 __asm__ volatile("MRC p15, 0, %0, c12, c12, 7" : "=r" (reg));
46
47 return reg;
48 }
49
mt_gic_icc_iar1_read(void)50 static uint32_t mt_gic_icc_iar1_read(void) {
51 uint32_t reg;
52
53 __asm__ volatile("MRC p15, 0, %0, c12, c12, 0" : "=r" (reg));
54
55 return reg;
56 }
57
mt_gic_icc_msre_write(void)58 static void mt_gic_icc_msre_write(void) {
59 uint32_t reg;
60
61 #define MON_MODE "#22"
62 #define SVC_MODE "#19"
63
64 /*
65 * switch to monitor mode and mark ICC_MSRE.
66 */
67 __asm__ volatile("CPS " MON_MODE "\n"
68 "MRC p15, 6, %0, c12, c12, 5\n"
69 "ORR %0, %0, #9\n"
70 "MCR p15, 6, %0, c12, c12, 5\n"
71 "CPS " SVC_MODE "\n" : "=r" (reg));
72
73 dsb();
74 }
75
mt_gic_icc_sre_write(uint32_t reg)76 static void mt_gic_icc_sre_write(uint32_t reg) {
77 __asm__ volatile("MCR p15, 0, %0, c12, c12, 5" :: "r" (reg));
78 dsb();
79 }
80
mt_gic_icc_sre_read(void)81 static uint32_t mt_gic_icc_sre_read(void) {
82 uint32_t reg;
83
84 __asm__ volatile("MRC p15, 0, %0, c12, c12, 5" : "=r" (reg));
85
86 return reg;
87 }
88
mt_gic_icc_eoir1_write(uint32_t reg)89 static void mt_gic_icc_eoir1_write(uint32_t reg) {
90 __asm__ volatile("MCR p15, 0, %0, c12, c12, 1" :: "r" (reg));
91 }
92
mt_mpidr_read(void)93 uint32_t mt_mpidr_read(void) {
94 uint32_t reg;
95
96 __asm__ volatile("MRC p15, 0, %0, c0, c0, 5" : "=r" (reg));
97
98 return reg;
99 }
100
mt_gic_cpu_init(void)101 static void mt_gic_cpu_init(void) {
102 mt_gic_icc_sre_write(0x01);
103 mt_gic_icc_primask_write(0xF0);
104 mt_gic_icc_igrpen1_write(0x01);
105 dsb();
106 }
107
mt_gic_redist_init(void)108 static void mt_gic_redist_init(void) {
109 unsigned int value;
110
111 /* Wake up this CPU redistributor */
112 value = DRV_Reg32(GIC_REDIS_BASE + GIC_REDIS_WAKER);
113 value &= ~GICR_WAKER_ProcessorSleep;
114 DRV_WriteReg32(GIC_REDIS_BASE + GIC_REDIS_WAKER, value);
115
116 while (DRV_Reg32(GIC_REDIS_BASE + GIC_REDIS_WAKER) & GICR_WAKER_ChildrenAsleep);
117 }
118
mt_git_dist_rwp(void)119 static void mt_git_dist_rwp(void) {
120 /*
121 * check GICD_CTLR.RWP for done check
122 */
123 while (DRV_Reg32(GIC_DIST_BASE + GIC_DIST_CTRL) & GICD_CTLR_RWP) {
124
125 }
126 }
127
mt_gic_dist_init(void)128 static void mt_gic_dist_init(void) {
129 unsigned int i;
130 uint64_t affinity;
131
132 affinity = mt_irq_get_affinity();
133
134 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_CTRL, GICD_CTLR_ARE);
135
136 mt_git_dist_rwp();
137
138 /*
139 * Set all global interrupts to be level triggered, active low.
140 */
141 for (i = 32; i < (MT_NR_SPI + 32); i += 16) {
142 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_CONFIG + i * 4 / 16, 0);
143 }
144
145 /*
146 * Set all global interrupts to this CPU only.
147 */
148 for (i = 0; i < MT_NR_SPI; i++) {
149 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ROUTE + i * 8, (affinity & 0xFFFFFFFF));
150 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ROUTE + i * 8 + 4, (affinity >> 32));
151 }
152
153 /*
154 * Set all interrupts to G1S. Leave the PPI and SGIs alone
155 * as they are set by redistributor registers.
156 */
157 for (i = 0; i < NR_IRQ_LINE; i += 32)
158 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_IGRPMODR + i / 8, 0xFFFFFFFF);
159
160 /*
161 * Set priority on all interrupts.
162 */
163 for (i = 0; i < NR_IRQ_LINE; i += 4) {
164 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_PRI + i * 4 / 4, 0xA0A0A0A0);
165 }
166
167 /*
168 * Disable all interrupts.
169 */
170 for (i = 0; i < NR_IRQ_LINE; i += 32) {
171 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR + i * 4 / 32, 0xFFFFFFFF);
172 }
173
174 /*
175 * Clear all active status
176 */
177 for (i = 0; i < NR_IRQ_LINE; i += 32) {
178 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ACTIVE_CLEAR + i * 4 / 32, 0xFFFFFFFF);
179 }
180
181 /*
182 * Clear all pending status
183 */
184 for (i = 0; i < NR_IRQ_LINE; i += 32) {
185 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_PENDING_CLEAR + i * 4 / 32, 0xFFFFFFFF);
186 }
187
188
189 dsb();
190 mt_git_dist_rwp();
191 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_CTRL, GICD_CTLR_ARE | GICD_CTLR_ENGRP1S | GICD_CTLR_ENGRP1NS);
192 mt_git_dist_rwp();
193 }
194
platform_init_interrupts(void)195 void platform_init_interrupts(void) {
196 uint32_t sec;
197
198 sec = mt_interrupt_needed_for_secure();
199
200 if (sec)
201 mt_gic_icc_msre_write();
202
203 mt_gic_dist_init();
204
205 if (sec)
206 mt_gic_redist_init();
207
208 mt_gic_cpu_init();
209 }
210
platform_deinit_interrupts(void)211 void platform_deinit_interrupts(void) {
212 unsigned int irq;
213
214 for (irq = 0; irq < NR_IRQ_LINE; irq += 32) {
215 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR + irq * 4 / 32, 0xFFFFFFFF);
216 }
217
218 dsb();
219
220 while ((irq = mt_gic_icc_iar1_read()) != 1023 ) {
221 mt_gic_icc_eoir1_write(irq);
222 }
223 }
224
mt_irq_get(void)225 uint32_t mt_irq_get(void) {
226 return mt_gic_icc_iar1_read();
227 }
228
mt_irq_set_polarity(unsigned int irq,unsigned int polarity)229 void mt_irq_set_polarity(unsigned int irq, unsigned int polarity) {
230 unsigned int offset;
231 unsigned int reg_index;
232 unsigned int value;
233
234 // peripheral device's IRQ line is using GIC's SPI, and line ID >= GIC_PRIVATE_SIGNALS
235 if (irq < GIC_PRIVATE_SIGNALS) {
236 return;
237 }
238
239 offset = (irq - GIC_PRIVATE_SIGNALS) & 0x1F;
240 reg_index = (irq - GIC_PRIVATE_SIGNALS) >> 5;
241 if (polarity == 0) {
242 value = DRV_Reg32(INT_POL_CTL0 + (reg_index * 4));
243 value |= (1 << offset); // always invert the incoming IRQ's polarity
244 DRV_WriteReg32((INT_POL_CTL0 + (reg_index * 4)), value);
245 } else {
246 value = DRV_Reg32(INT_POL_CTL0 + (reg_index * 4));
247 value &= ~(0x1 << offset);
248 DRV_WriteReg32(INT_POL_CTL0 + (reg_index * 4), value);
249 }
250 }
251
mt_irq_set_sens(unsigned int irq,unsigned int sens)252 void mt_irq_set_sens(unsigned int irq, unsigned int sens) {
253 unsigned int config;
254
255 if (sens == MT65xx_EDGE_SENSITIVE) {
256 config = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4);
257 config |= (0x2 << (irq % 16) * 2);
258 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4, config);
259 } else {
260 config = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4);
261 config &= ~(0x2 << (irq % 16) * 2);
262 DRV_WriteReg32( GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4, config);
263 }
264 dsb();
265 }
266
267 /*
268 * mt_irq_mask: mask one IRQ
269 * @irq: IRQ line of the IRQ to mask
270 */
mt_irq_mask(unsigned int irq)271 void mt_irq_mask(unsigned int irq) {
272 unsigned int mask = 1 << (irq % 32);
273
274 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR + irq / 32 * 4, mask);
275 dsb();
276 }
277
278 /*
279 * mt_irq_unmask: unmask one IRQ
280 * @irq: IRQ line of the IRQ to unmask
281 */
mt_irq_unmask(unsigned int irq)282 void mt_irq_unmask(unsigned int irq) {
283 unsigned int mask = 1 << (irq % 32);
284
285 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ENABLE_SET + irq / 32 * 4, mask);
286 dsb();
287 }
288
289 /*
290 * mt_irq_ack: ack IRQ
291 * @irq: IRQ line of the IRQ to mask
292 */
mt_irq_ack(unsigned int irq)293 void mt_irq_ack(unsigned int irq) {
294 mt_gic_icc_eoir1_write(irq);
295 dsb();
296 }
297
298 /*
299 * mt_irq_mask_all: mask all IRQ lines. (This is ONLY used for the sleep driver)
300 * @mask: pointer to struct mtk_irq_mask for storing the original mask value.
301 * Return 0 for success; return negative values for failure.
302 */
mt_irq_mask_all(struct mtk_irq_mask * mask)303 int mt_irq_mask_all(struct mtk_irq_mask *mask) {
304 unsigned int i;
305
306 if (mask) {
307 for (i = 0; i < IRQ_REGS; i++) {
308 mask->mask[i] = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_ENABLE_SET + i * 4);
309 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR + i * 4, 0xFFFFFFFF);
310 }
311
312 dsb();
313
314 mask->header = IRQ_MASK_HEADER;
315 mask->footer = IRQ_MASK_FOOTER;
316
317 return 0;
318 } else {
319 return -1;
320 }
321 }
322
323 /*
324 * mt_irq_mask_restore: restore all IRQ lines' masks. (This is ONLY used for the sleep driver)
325 * @mask: pointer to struct mtk_irq_mask for storing the original mask value.
326 * Return 0 for success; return negative values for failure.
327 */
mt_irq_mask_restore(struct mtk_irq_mask * mask)328 int mt_irq_mask_restore(struct mtk_irq_mask *mask) {
329 unsigned int i;
330
331 if (!mask) {
332 return -1;
333 }
334 if (mask->header != IRQ_MASK_HEADER) {
335 return -1;
336 }
337 if (mask->footer != IRQ_MASK_FOOTER) {
338 return -1;
339 }
340
341 for (i = 0; i < IRQ_REGS; i++) {
342 DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ENABLE_SET + i * 4, mask->mask[i]);
343 }
344
345 dsb();
346
347
348 return 0;
349 }
350
mt_irq_register_dump(void)351 void mt_irq_register_dump(void) {
352 int i;
353 uint32_t reg, reg2;
354
355 dprintf(CRITICAL, "%s(): do irq register dump\n", __func__);
356
357 reg = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_CTRL);
358 dprintf(CRITICAL, "GICD_CTLR: 0x%08x\n", reg);
359
360 for (i = 0; i < MT_NR_SPI; i++) {
361 reg = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_ROUTE + i * 8);
362 reg2 = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_ROUTE + i * 8 + 4);
363 dprintf(CRITICAL, "GICD_IROUTER[%d]: 0x%08x, 0x%08x\n", i, reg, reg2);
364 }
365
366 for (i = 0; i < NR_IRQ_LINE; i += 32) {
367 reg = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_IGRPMODR + i / 8);
368 dprintf(CRITICAL, "GICD_IGRPMODR[%d]: 0x%08x\n", i >> 5, reg);
369 }
370
371 for (i = 0; i < NR_IRQ_LINE; i += 4) {
372 reg = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_PRI + i * 4 / 4);
373 dprintf(CRITICAL, "GICD_IPRIORITYR[%d]: 0x%08x\n", i >> 2, reg);
374 }
375
376 for (i = 32; i < (MT_NR_SPI + 32); i += 16) {
377 reg = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_CONFIG + i * 4 / 16);
378 dprintf(CRITICAL, "DIST_ICFGR[%d]: 0x%08x\n", (i >> 4) - 2, reg);
379 }
380
381 for (i = 0; i < IRQ_REGS; i++) {
382 reg = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_ENABLE_SET + i * 4);
383 dprintf(CRITICAL, "GICD_ISENABLER[%d]: 0x%08x\n", i, reg);
384 }
385
386 for (i = 0; i < IRQ_REGS; i++) {
387 reg = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_PENDING_SET + i * 4);
388 dprintf(CRITICAL, "GICD_ISPENDR[%d]: 0x%08x\n", i, reg);
389 }
390
391 for (i = 0; i < IRQ_REGS; i++) {
392 reg = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_ACTIVE_SET + i * 4);
393 dprintf(CRITICAL, "GICD_ISACTIVER[%d]: 0x%08x\n", i, reg);
394 }
395
396 reg = mt_gic_icc_sre_read();
397 dprintf(CRITICAL, "ICC_SRE: 0x%08x\n", reg);
398
399 reg = mt_gic_icc_primask_read();
400 dprintf(CRITICAL, "ICC_PMR: 0x%08x\n", reg);
401
402 reg = mt_gic_icc_igrpen1_read();
403 dprintf(CRITICAL, "ICC_IGRPEN1: 0x%08x\n", reg);
404
405 reg = mt_gic_icc_iar1_read();
406 dprintf(CRITICAL, "ICC_IAR1: 0x%08x\n", reg);
407
408 reg = mt_mpidr_read();
409 dprintf(CRITICAL, "MPIDR: 0x%08x\n", reg);
410 }
411