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