1 /*
2 * Copyright (c) 2020, MediaTek Inc. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <arch_helpers.h>
8 #include <common/debug.h>
9 #include <drivers/arm/gic_common.h>
10 #include <lib/mmio.h>
11
12 #include <mt_gic_v3.h>
13 #include <plat_mt_cirq.h>
14 #include <platform_def.h>
15
16 static struct cirq_events cirq_all_events = {
17 .spi_start = CIRQ_SPI_START,
18 };
19 static uint32_t already_cloned;
20 /*
21 * mt_irq_mask_restore: restore all interrupts
22 * @mask: pointer to struct mtk_irq_mask for storing the original mask value.
23 * Return 0 for success; return negative values for failure.
24 * (This is ONLY used for the idle current measurement by the factory mode.)
25 */
mt_irq_mask_restore(struct mtk_irq_mask * mask)26 int mt_irq_mask_restore(struct mtk_irq_mask *mask)
27 {
28 if (mask == NULL) {
29 return -1;
30 }
31 if (mask->header != IRQ_MASK_HEADER) {
32 return -1;
33 }
34 if (mask->footer != IRQ_MASK_FOOTER) {
35 return -1;
36 }
37
38 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x4),
39 mask->mask1);
40 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x8),
41 mask->mask2);
42 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0xc),
43 mask->mask3);
44 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x10),
45 mask->mask4);
46 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x14),
47 mask->mask5);
48 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x18),
49 mask->mask6);
50 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x1c),
51 mask->mask7);
52 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x20),
53 mask->mask8);
54 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x24),
55 mask->mask9);
56 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x28),
57 mask->mask10);
58 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x2c),
59 mask->mask11);
60 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x30),
61 mask->mask12);
62 /* make sure dist changes happen */
63 dsb();
64
65 return 0;
66 }
67
68 /*
69 * mt_irq_mask_all: disable all interrupts
70 * @mask: pointer to struct mtk_irq_mask for storing the original mask value.
71 * Return 0 for success; return negative values for failure.
72 * (This is ONLY used for the idle current measurement by the factory mode.)
73 */
mt_irq_mask_all(struct mtk_irq_mask * mask)74 int mt_irq_mask_all(struct mtk_irq_mask *mask)
75 {
76 if (mask != NULL) {
77 /* for SPI */
78 mask->mask1 = mmio_read_32((BASE_GICD_BASE +
79 GICD_ISENABLER + 0x4));
80 mask->mask2 = mmio_read_32((BASE_GICD_BASE +
81 GICD_ISENABLER + 0x8));
82 mask->mask3 = mmio_read_32((BASE_GICD_BASE +
83 GICD_ISENABLER + 0xc));
84 mask->mask4 = mmio_read_32((BASE_GICD_BASE +
85 GICD_ISENABLER + 0x10));
86 mask->mask5 = mmio_read_32((BASE_GICD_BASE +
87 GICD_ISENABLER + 0x14));
88 mask->mask6 = mmio_read_32((BASE_GICD_BASE +
89 GICD_ISENABLER + 0x18));
90 mask->mask7 = mmio_read_32((BASE_GICD_BASE +
91 GICD_ISENABLER + 0x1c));
92 mask->mask8 = mmio_read_32((BASE_GICD_BASE +
93 GICD_ISENABLER + 0x20));
94 mask->mask9 = mmio_read_32((BASE_GICD_BASE +
95 GICD_ISENABLER + 0x24));
96 mask->mask10 = mmio_read_32((BASE_GICD_BASE +
97 GICD_ISENABLER + 0x28));
98 mask->mask11 = mmio_read_32((BASE_GICD_BASE +
99 GICD_ISENABLER + 0x2c));
100 mask->mask12 = mmio_read_32((BASE_GICD_BASE +
101 GICD_ISENABLER + 0x30));
102
103 /* for SPI */
104 mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x4),
105 0xFFFFFFFF);
106 mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x8),
107 0xFFFFFFFF);
108 mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0xC),
109 0xFFFFFFFF);
110 mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x10),
111 0xFFFFFFFF);
112 mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x14),
113 0xFFFFFFFF);
114 mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x18),
115 0xFFFFFFFF);
116 mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x1C),
117 0xFFFFFFFF);
118 mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x20),
119 0xFFFFFFFF);
120 mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x24),
121 0xFFFFFFFF);
122 mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x28),
123 0xFFFFFFFF);
124 mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x2c),
125 0xFFFFFFFF);
126 mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x30),
127 0xFFFFFFFF);
128 /* make sure distributor changes happen */
129 dsb();
130
131 mask->header = IRQ_MASK_HEADER;
132 mask->footer = IRQ_MASK_FOOTER;
133
134 return 0;
135 } else {
136 return -1;
137 }
138 }
139
mt_irq_get_pol(uint32_t irq)140 static uint32_t mt_irq_get_pol(uint32_t irq)
141 {
142 #ifdef CIRQ_WITH_POLARITY
143 uint32_t reg;
144 uint32_t base = INT_POL_CTL0;
145
146 if (irq < 32U) {
147 return 0;
148 }
149
150 reg = ((irq - 32U) / 32U);
151
152 return mmio_read_32(base + reg * 4U);
153 #else
154 return 0;
155 #endif
156 }
157
mt_irq_get_sens(unsigned int irq)158 unsigned int mt_irq_get_sens(unsigned int irq)
159 {
160 unsigned int config;
161
162 /*
163 * 2'b10 edge
164 * 2'b01 level
165 */
166 config = mmio_read_32(MT_GIC_BASE + GICD_ICFGR + (irq / 16U) * 4U);
167 config = (config >> (irq % 16U) * 2U) & 0x3;
168
169 return config;
170 }
171
collect_all_wakeup_events(void)172 static void collect_all_wakeup_events(void)
173 {
174 unsigned int i;
175 uint32_t gic_irq;
176 uint32_t cirq;
177 uint32_t cirq_reg;
178 uint32_t cirq_offset;
179 uint32_t mask;
180 uint32_t pol_mask;
181 uint32_t irq_offset;
182 uint32_t irq_mask;
183
184 if ((cirq_all_events.wakeup_events == NULL) ||
185 cirq_all_events.num_of_events == 0U) {
186 return;
187 }
188
189 for (i = 0U; i < cirq_all_events.num_of_events; i++) {
190 if (cirq_all_events.wakeup_events[i] > 0U) {
191 gic_irq = cirq_all_events.wakeup_events[i];
192 cirq = gic_irq - cirq_all_events.spi_start - 32U;
193 cirq_reg = cirq / 32U;
194 cirq_offset = cirq % 32U;
195 mask = 0x1 << cirq_offset;
196 irq_offset = gic_irq % 32U;
197 irq_mask = 0x1 << irq_offset;
198 /*
199 * CIRQ default masks all
200 */
201 cirq_all_events.table[cirq_reg].mask |= mask;
202 /*
203 * CIRQ default pol is low
204 */
205 pol_mask = mt_irq_get_pol(
206 cirq_all_events.wakeup_events[i])
207 & irq_mask;
208 /*
209 * 0 means rising
210 */
211 if (pol_mask == 0U) {
212 cirq_all_events.table[cirq_reg].pol |= mask;
213 }
214 /*
215 * CIRQ could monitor edge/level trigger
216 * cirq register (0: edge, 1: level)
217 */
218 if (mt_irq_get_sens(cirq_all_events.wakeup_events[i])
219 == SENS_EDGE) {
220 cirq_all_events.table[cirq_reg].sen |= mask;
221 }
222
223 cirq_all_events.table[cirq_reg].used = 1U;
224 cirq_all_events.table[cirq_reg].reg_num = cirq_reg;
225 }
226 }
227 }
228
229 /*
230 * mt_cirq_set_pol: Set the polarity for the specified SYS_CIRQ number.
231 * @cirq_num: the SYS_CIRQ number to set
232 * @pol: polarity to set
233 * @return:
234 * 0: set pol success
235 * -1: cirq num is out of range
236 */
237 #ifdef CIRQ_WITH_POLARITY
mt_cirq_set_pol(uint32_t cirq_num,uint32_t pol)238 static int mt_cirq_set_pol(uint32_t cirq_num, uint32_t pol)
239 {
240 uint32_t base;
241 uint32_t bit = 1U << (cirq_num % 32U);
242
243 if (cirq_num >= CIRQ_IRQ_NUM) {
244 return -1;
245 }
246
247 if (pol == MT_CIRQ_POL_NEG) {
248 base = (cirq_num / 32U) * 4U + CIRQ_POL_CLR_BASE;
249 } else if (pol == MT_CIRQ_POL_POS) {
250 base = (cirq_num / 32U) * 4U + CIRQ_POL_SET_BASE;
251 } else {
252 return -1;
253 }
254
255 mmio_write_32(base, bit);
256 return 0;
257 }
258 #endif
259
260 /*
261 * mt_cirq_mask: Mask the specified SYS_CIRQ.
262 * @cirq_num: the SYS_CIRQ number to mask
263 * @return:
264 * 0: mask success
265 * -1: cirq num is out of range
266 */
mt_cirq_mask(uint32_t cirq_num)267 static int mt_cirq_mask(uint32_t cirq_num)
268 {
269 uint32_t bit = 1U << (cirq_num % 32U);
270
271 if (cirq_num >= CIRQ_IRQ_NUM) {
272 return -1;
273 }
274
275 mmio_write_32((cirq_num / 32U) * 4U + CIRQ_MASK_SET_BASE, bit);
276
277 return 0;
278 }
279
280 /*
281 * mt_cirq_unmask: Unmask the specified SYS_CIRQ.
282 * @cirq_num: the SYS_CIRQ number to unmask
283 * @return:
284 * 0: umask success
285 * -1: cirq num is out of range
286 */
mt_cirq_unmask(uint32_t cirq_num)287 static int mt_cirq_unmask(uint32_t cirq_num)
288 {
289 uint32_t bit = 1U << (cirq_num % 32U);
290
291 if (cirq_num >= CIRQ_IRQ_NUM) {
292 return -1;
293 }
294
295 mmio_write_32((cirq_num / 32U) * 4U + CIRQ_MASK_CLR_BASE, bit);
296
297 return 0;
298 }
299
mt_irq_get_en(uint32_t irq)300 uint32_t mt_irq_get_en(uint32_t irq)
301 {
302 uint32_t addr, st, val;
303
304 addr = BASE_GICD_BASE + GICD_ISENABLER + (irq / 32U) * 4U;
305 st = mmio_read_32(addr);
306
307 val = (st >> (irq % 32U)) & 1U;
308
309 return val;
310 }
311
__cirq_fast_clone(void)312 static void __cirq_fast_clone(void)
313 {
314 struct cirq_reg *reg;
315 unsigned int i;
316
317 for (i = 0U; i < CIRQ_REG_NUM ; ++i) {
318 uint32_t cirq_bit;
319
320 reg = &cirq_all_events.table[i];
321
322 if (reg->used == 0U) {
323 continue;
324 }
325
326 mmio_write_32(CIRQ_SENS_CLR_BASE + (reg->reg_num * 4U),
327 reg->sen);
328
329 for (cirq_bit = 0U; cirq_bit < 32U; ++cirq_bit) {
330 uint32_t val, cirq_id;
331 uint32_t gic_id;
332 #ifdef CIRQ_WITH_POLARITY
333 uint32_t gic_bit, pol;
334 #endif
335 uint32_t en;
336
337 val = ((1U << cirq_bit) & reg->mask);
338
339 if (val == 0U) {
340 continue;
341 }
342
343 cirq_id = (reg->reg_num << 5U) + cirq_bit;
344 gic_id = CIRQ_TO_IRQ_NUM(cirq_id);
345 #ifdef CIRQ_WITH_POLARITY
346 gic_bit = (0x1U << ((gic_id - 32U) % 32U));
347 pol = mt_irq_get_pol(gic_id) & gic_bit;
348 if (pol != 0U) {
349 mt_cirq_set_pol(cirq_id, MT_CIRQ_POL_NEG);
350 } else {
351 mt_cirq_set_pol(cirq_id, MT_CIRQ_POL_POS);
352 }
353 #endif
354 en = mt_irq_get_en(gic_id);
355 if (en == 1U) {
356 mt_cirq_unmask(cirq_id);
357 } else {
358 mt_cirq_mask(cirq_id);
359 }
360 }
361 }
362 }
363
cirq_fast_clone(void)364 static void cirq_fast_clone(void)
365 {
366 if (already_cloned == 0U) {
367 collect_all_wakeup_events();
368 already_cloned = 1U;
369 }
370 __cirq_fast_clone();
371 }
372
set_wakeup_sources(uint32_t * list,uint32_t num_of_events)373 void set_wakeup_sources(uint32_t *list, uint32_t num_of_events)
374 {
375 cirq_all_events.num_of_events = num_of_events;
376 cirq_all_events.wakeup_events = list;
377 }
378 /*
379 * mt_cirq_clone_gic: Copy the setting from GIC to SYS_CIRQ
380 */
mt_cirq_clone_gic(void)381 void mt_cirq_clone_gic(void)
382 {
383 cirq_fast_clone();
384 }
385
mt_irq_get_pending_vec(uint32_t start_irq)386 uint32_t mt_irq_get_pending_vec(uint32_t start_irq)
387 {
388 uint32_t base = 0U;
389 uint32_t pending_vec = 0U;
390 uint32_t reg = start_irq / 32U;
391 uint32_t LSB_num, MSB_num;
392 uint32_t LSB_vec, MSB_vec;
393
394 base = BASE_GICD_BASE;
395
396 /* if start_irq is not aligned 32, do some assembling */
397 MSB_num = start_irq % 32U;
398 if (MSB_num != 0U) {
399 LSB_num = 32U - MSB_num;
400 LSB_vec = mmio_read_32(base + GICD_ISPENDR +
401 reg * 4U) >> MSB_num;
402 MSB_vec = mmio_read_32(base + GICD_ISPENDR +
403 (reg + 1U) * 4U) << LSB_num;
404 pending_vec = MSB_vec | LSB_vec;
405 } else {
406 pending_vec = mmio_read_32(base + GICD_ISPENDR + reg * 4);
407 }
408
409 return pending_vec;
410 }
411
mt_cirq_get_mask_vec(unsigned int i)412 static int mt_cirq_get_mask_vec(unsigned int i)
413 {
414 return mmio_read_32((i * 4U) + CIRQ_MASK_BASE);
415 }
416
417 /*
418 * mt_cirq_ack_all: Ack all the interrupt on SYS_CIRQ
419 */
mt_cirq_ack_all(void)420 void mt_cirq_ack_all(void)
421 {
422 uint32_t ack_vec, pend_vec, mask_vec;
423 unsigned int i;
424
425 for (i = 0; i < CIRQ_CTRL_REG_NUM; i++) {
426 /*
427 * if a irq is pending & not masked, don't ack it
428 * , since cirq start irq might not be 32 aligned with gic,
429 * need an exotic API to get proper vector of pending irq
430 */
431 pend_vec = mt_irq_get_pending_vec(CIRQ_SPI_START
432 + (i + 1U) * 32U);
433 mask_vec = mt_cirq_get_mask_vec(i);
434 /* those should be acked are: "not (pending & not masked)",
435 */
436 ack_vec = (~pend_vec) | mask_vec;
437 mmio_write_32(CIRQ_ACK_BASE + (i * 4U), ack_vec);
438 }
439
440 /*
441 * make sure all cirq setting take effect
442 * before doing other things
443 */
444 dsb();
445 }
446 /*
447 * mt_cirq_enable: Enable SYS_CIRQ
448 */
mt_cirq_enable(void)449 void mt_cirq_enable(void)
450 {
451 uint32_t st;
452
453 /* level only */
454 mt_cirq_ack_all();
455
456 st = mmio_read_32(CIRQ_CON);
457 /*
458 * CIRQ could monitor edge/level trigger
459 */
460 st |= (CIRQ_CON_EN << CIRQ_CON_EN_BITS);
461
462 mmio_write_32(CIRQ_CON, (st & CIRQ_CON_BITS_MASK));
463 }
464
465 /*
466 * mt_cirq_disable: Disable SYS_CIRQ
467 */
mt_cirq_disable(void)468 void mt_cirq_disable(void)
469 {
470 uint32_t st;
471
472 st = mmio_read_32(CIRQ_CON);
473 st &= ~(CIRQ_CON_EN << CIRQ_CON_EN_BITS);
474 mmio_write_32(CIRQ_CON, (st & CIRQ_CON_BITS_MASK));
475 }
476
mt_irq_unmask_for_sleep_ex(uint32_t irq)477 void mt_irq_unmask_for_sleep_ex(uint32_t irq)
478 {
479 uint32_t mask;
480
481 mask = 1U << (irq % 32U);
482
483 mmio_write_32(BASE_GICD_BASE + GICD_ISENABLER +
484 ((irq / 32U) * 4U), mask);
485 }
486
mt_cirq_mask_all(void)487 void mt_cirq_mask_all(void)
488 {
489 unsigned int i;
490
491 for (i = 0U; i < CIRQ_CTRL_REG_NUM; i++) {
492 mmio_write_32(CIRQ_MASK_SET_BASE + (i * 4U), 0xFFFFFFFF);
493 }
494 dsb();
495 }
496
cirq_fast_sw_flush(void)497 static void cirq_fast_sw_flush(void)
498 {
499 struct cirq_reg *reg;
500 unsigned int i;
501
502 for (i = 0U; i < CIRQ_REG_NUM ; ++i) {
503 uint32_t cirq_bit;
504
505 reg = &cirq_all_events.table[i];
506
507 if (reg->used == 0U) {
508 continue;
509 }
510
511 reg->pending = mmio_read_32(CIRQ_STA_BASE +
512 (reg->reg_num << 2U));
513 reg->pending &= reg->mask;
514
515 for (cirq_bit = 0U; cirq_bit < 32U; ++cirq_bit) {
516 uint32_t val, cirq_id;
517
518 val = (1U << cirq_bit) & reg->pending;
519 if (val == 0U) {
520 continue;
521 }
522
523 cirq_id = (reg->reg_num << 5U) + cirq_bit;
524 mt_irq_set_pending(CIRQ_TO_IRQ_NUM(cirq_id));
525 if (CIRQ_TO_IRQ_NUM(cirq_id) == MD_WDT_IRQ_BIT_ID) {
526 INFO("Set MD_WDT_IRQ pending in %s\n",
527 __func__);
528 }
529 }
530 }
531 }
532
533 /*
534 * mt_cirq_disable: Flush interrupt from SYS_CIRQ to GIC
535 */
mt_cirq_flush(void)536 void mt_cirq_flush(void)
537 {
538 cirq_fast_sw_flush();
539 mt_cirq_mask_all();
540 mt_cirq_ack_all();
541 }
542
mt_cirq_sw_reset(void)543 void mt_cirq_sw_reset(void)
544 {
545 #ifdef CIRQ_NEED_SW_RESET
546 uint32_t st;
547
548 st = mmio_read_32(CIRQ_CON);
549 st |= (CIRQ_SW_RESET << CIRQ_CON_SW_RST_BITS);
550 mmio_write_32(CIRQ_CON, st);
551 #endif
552 }
553