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