• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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