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