xref: /rk3399_ARM-atf/drivers/arm/gic/v2/gicv2_helpers.c (revision 464ce2bbaa95a95f773a639c47e14bdffa21d75a)
1*464ce2bbSSoby Mathew /*
2*464ce2bbSSoby Mathew  * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
3*464ce2bbSSoby Mathew  *
4*464ce2bbSSoby Mathew  * Redistribution and use in source and binary forms, with or without
5*464ce2bbSSoby Mathew  * modification, are permitted provided that the following conditions are met:
6*464ce2bbSSoby Mathew  *
7*464ce2bbSSoby Mathew  * Redistributions of source code must retain the above copyright notice, this
8*464ce2bbSSoby Mathew  * list of conditions and the following disclaimer.
9*464ce2bbSSoby Mathew  *
10*464ce2bbSSoby Mathew  * Redistributions in binary form must reproduce the above copyright notice,
11*464ce2bbSSoby Mathew  * this list of conditions and the following disclaimer in the documentation
12*464ce2bbSSoby Mathew  * and/or other materials provided with the distribution.
13*464ce2bbSSoby Mathew  *
14*464ce2bbSSoby Mathew  * Neither the name of ARM nor the names of its contributors may be used
15*464ce2bbSSoby Mathew  * to endorse or promote products derived from this software without specific
16*464ce2bbSSoby Mathew  * prior written permission.
17*464ce2bbSSoby Mathew  *
18*464ce2bbSSoby Mathew  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19*464ce2bbSSoby Mathew  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*464ce2bbSSoby Mathew  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*464ce2bbSSoby Mathew  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22*464ce2bbSSoby Mathew  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23*464ce2bbSSoby Mathew  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24*464ce2bbSSoby Mathew  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25*464ce2bbSSoby Mathew  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26*464ce2bbSSoby Mathew  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27*464ce2bbSSoby Mathew  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28*464ce2bbSSoby Mathew  * POSSIBILITY OF SUCH DAMAGE.
29*464ce2bbSSoby Mathew  */
30*464ce2bbSSoby Mathew 
31*464ce2bbSSoby Mathew #include <arch.h>
32*464ce2bbSSoby Mathew #include <arch_helpers.h>
33*464ce2bbSSoby Mathew #include <assert.h>
34*464ce2bbSSoby Mathew #include <debug.h>
35*464ce2bbSSoby Mathew #include <gic_common.h>
36*464ce2bbSSoby Mathew #include "gicv2_private.h"
37*464ce2bbSSoby Mathew 
38*464ce2bbSSoby Mathew /*
39*464ce2bbSSoby Mathew  * Accessor to read the GIC Distributor ITARGETSR corresponding to the
40*464ce2bbSSoby Mathew  * interrupt `id`, 4 interrupt IDs at a time.
41*464ce2bbSSoby Mathew  */
42*464ce2bbSSoby Mathew unsigned int gicd_read_itargetsr(uintptr_t base, unsigned int id)
43*464ce2bbSSoby Mathew {
44*464ce2bbSSoby Mathew 	unsigned n = id >> ITARGETSR_SHIFT;
45*464ce2bbSSoby Mathew 	return mmio_read_32(base + GICD_ITARGETSR + (n << 2));
46*464ce2bbSSoby Mathew }
47*464ce2bbSSoby Mathew 
48*464ce2bbSSoby Mathew /*
49*464ce2bbSSoby Mathew  * Accessor to read the GIC Distributor CPENDSGIR corresponding to the
50*464ce2bbSSoby Mathew  * interrupt `id`, 4 interrupt IDs at a time.
51*464ce2bbSSoby Mathew  */
52*464ce2bbSSoby Mathew unsigned int gicd_read_cpendsgir(uintptr_t base, unsigned int id)
53*464ce2bbSSoby Mathew {
54*464ce2bbSSoby Mathew 	unsigned n = id >> CPENDSGIR_SHIFT;
55*464ce2bbSSoby Mathew 	return mmio_read_32(base + GICD_CPENDSGIR + (n << 2));
56*464ce2bbSSoby Mathew }
57*464ce2bbSSoby Mathew 
58*464ce2bbSSoby Mathew /*
59*464ce2bbSSoby Mathew  * Accessor to read the GIC Distributor SPENDSGIR corresponding to the
60*464ce2bbSSoby Mathew  * interrupt `id`, 4 interrupt IDs at a time.
61*464ce2bbSSoby Mathew  */
62*464ce2bbSSoby Mathew unsigned int gicd_read_spendsgir(uintptr_t base, unsigned int id)
63*464ce2bbSSoby Mathew {
64*464ce2bbSSoby Mathew 	unsigned n = id >> SPENDSGIR_SHIFT;
65*464ce2bbSSoby Mathew 	return mmio_read_32(base + GICD_SPENDSGIR + (n << 2));
66*464ce2bbSSoby Mathew }
67*464ce2bbSSoby Mathew 
68*464ce2bbSSoby Mathew /*
69*464ce2bbSSoby Mathew  * Accessor to write the GIC Distributor ITARGETSR corresponding to the
70*464ce2bbSSoby Mathew  * interrupt `id`, 4 interrupt IDs at a time.
71*464ce2bbSSoby Mathew  */
72*464ce2bbSSoby Mathew void gicd_write_itargetsr(uintptr_t base, unsigned int id, unsigned int val)
73*464ce2bbSSoby Mathew {
74*464ce2bbSSoby Mathew 	unsigned n = id >> ITARGETSR_SHIFT;
75*464ce2bbSSoby Mathew 	mmio_write_32(base + GICD_ITARGETSR + (n << 2), val);
76*464ce2bbSSoby Mathew }
77*464ce2bbSSoby Mathew 
78*464ce2bbSSoby Mathew /*
79*464ce2bbSSoby Mathew  * Accessor to write the GIC Distributor CPENDSGIR corresponding to the
80*464ce2bbSSoby Mathew  * interrupt `id`, 4 interrupt IDs at a time.
81*464ce2bbSSoby Mathew  */
82*464ce2bbSSoby Mathew void gicd_write_cpendsgir(uintptr_t base, unsigned int id, unsigned int val)
83*464ce2bbSSoby Mathew {
84*464ce2bbSSoby Mathew 	unsigned n = id >> CPENDSGIR_SHIFT;
85*464ce2bbSSoby Mathew 	mmio_write_32(base + GICD_CPENDSGIR + (n << 2), val);
86*464ce2bbSSoby Mathew }
87*464ce2bbSSoby Mathew 
88*464ce2bbSSoby Mathew /*
89*464ce2bbSSoby Mathew  * Accessor to write the GIC Distributor SPENDSGIR corresponding to the
90*464ce2bbSSoby Mathew  * interrupt `id`, 4 interrupt IDs at a time.
91*464ce2bbSSoby Mathew  */
92*464ce2bbSSoby Mathew void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val)
93*464ce2bbSSoby Mathew {
94*464ce2bbSSoby Mathew 	unsigned n = id >> SPENDSGIR_SHIFT;
95*464ce2bbSSoby Mathew 	mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val);
96*464ce2bbSSoby Mathew }
97*464ce2bbSSoby Mathew 
98*464ce2bbSSoby Mathew /*
99*464ce2bbSSoby Mathew  * Accessor to write the GIC Distributor ITARGETSR corresponding to the
100*464ce2bbSSoby Mathew  * interrupt `id`.
101*464ce2bbSSoby Mathew  */
102*464ce2bbSSoby Mathew void gicd_set_itargetsr(uintptr_t base, unsigned int id, unsigned int target)
103*464ce2bbSSoby Mathew {
104*464ce2bbSSoby Mathew 	unsigned byte_off = id & ((1 << ITARGETSR_SHIFT) - 1);
105*464ce2bbSSoby Mathew 	unsigned int reg_val = gicd_read_itargetsr(base, id);
106*464ce2bbSSoby Mathew 
107*464ce2bbSSoby Mathew 	gicd_write_itargetsr(base, id, reg_val | (target << (byte_off << 3)));
108*464ce2bbSSoby Mathew }
109*464ce2bbSSoby Mathew 
110*464ce2bbSSoby Mathew /*******************************************************************************
111*464ce2bbSSoby Mathew  * Get the current CPU bit mask from GICD_ITARGETSR0
112*464ce2bbSSoby Mathew  ******************************************************************************/
113*464ce2bbSSoby Mathew unsigned int gicv2_get_cpuif_id(uintptr_t base)
114*464ce2bbSSoby Mathew {
115*464ce2bbSSoby Mathew 	unsigned int val;
116*464ce2bbSSoby Mathew 
117*464ce2bbSSoby Mathew 	val = gicd_read_itargetsr(base, 0);
118*464ce2bbSSoby Mathew 	return val & GIC_TARGET_CPU_MASK;
119*464ce2bbSSoby Mathew }
120*464ce2bbSSoby Mathew 
121*464ce2bbSSoby Mathew /*******************************************************************************
122*464ce2bbSSoby Mathew  * Helper function to configure the default attributes of SPIs.
123*464ce2bbSSoby Mathew  ******************************************************************************/
124*464ce2bbSSoby Mathew void gicv2_spis_configure_defaults(uintptr_t gicd_base)
125*464ce2bbSSoby Mathew {
126*464ce2bbSSoby Mathew 	unsigned int index, num_ints;
127*464ce2bbSSoby Mathew 
128*464ce2bbSSoby Mathew 	num_ints = gicd_read_typer(gicd_base);
129*464ce2bbSSoby Mathew 	num_ints &= TYPER_IT_LINES_NO_MASK;
130*464ce2bbSSoby Mathew 	num_ints = (num_ints + 1) << 5;
131*464ce2bbSSoby Mathew 
132*464ce2bbSSoby Mathew 	/*
133*464ce2bbSSoby Mathew 	 * Treat all SPIs as G1NS by default. The number of interrupts is
134*464ce2bbSSoby Mathew 	 * calculated as 32 * (IT_LINES + 1). We do 32 at a time.
135*464ce2bbSSoby Mathew 	 */
136*464ce2bbSSoby Mathew 	for (index = MIN_SPI_ID; index < num_ints; index += 32)
137*464ce2bbSSoby Mathew 		gicd_write_igroupr(gicd_base, index, ~0U);
138*464ce2bbSSoby Mathew 
139*464ce2bbSSoby Mathew 	/* Setup the default SPI priorities doing four at a time */
140*464ce2bbSSoby Mathew 	for (index = MIN_SPI_ID; index < num_ints; index += 4)
141*464ce2bbSSoby Mathew 		gicd_write_ipriorityr(gicd_base,
142*464ce2bbSSoby Mathew 				      index,
143*464ce2bbSSoby Mathew 				      GICD_IPRIORITYR_DEF_VAL);
144*464ce2bbSSoby Mathew 
145*464ce2bbSSoby Mathew 	/* Treat all SPIs as level triggered by default, 16 at a time */
146*464ce2bbSSoby Mathew 	for (index = MIN_SPI_ID; index < num_ints; index += 16)
147*464ce2bbSSoby Mathew 		gicd_write_icfgr(gicd_base, index, 0);
148*464ce2bbSSoby Mathew }
149*464ce2bbSSoby Mathew 
150*464ce2bbSSoby Mathew /*******************************************************************************
151*464ce2bbSSoby Mathew  * Helper function to configure secure G0 SPIs.
152*464ce2bbSSoby Mathew  ******************************************************************************/
153*464ce2bbSSoby Mathew void gicv2_secure_spis_configure(uintptr_t gicd_base,
154*464ce2bbSSoby Mathew 				     unsigned int num_ints,
155*464ce2bbSSoby Mathew 				     const unsigned int *sec_intr_list)
156*464ce2bbSSoby Mathew {
157*464ce2bbSSoby Mathew 	unsigned int index, irq_num;
158*464ce2bbSSoby Mathew 
159*464ce2bbSSoby Mathew 	/* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
160*464ce2bbSSoby Mathew 	assert(num_ints ? (uintptr_t)sec_intr_list : 1);
161*464ce2bbSSoby Mathew 
162*464ce2bbSSoby Mathew 	for (index = 0; index < num_ints; index++) {
163*464ce2bbSSoby Mathew 		irq_num = sec_intr_list[index];
164*464ce2bbSSoby Mathew 		if (irq_num >= MIN_SPI_ID) {
165*464ce2bbSSoby Mathew 			/* Configure this interrupt as a secure interrupt */
166*464ce2bbSSoby Mathew 			gicd_clr_igroupr(gicd_base, irq_num);
167*464ce2bbSSoby Mathew 
168*464ce2bbSSoby Mathew 			/* Set the priority of this interrupt */
169*464ce2bbSSoby Mathew 			gicd_write_ipriorityr(gicd_base,
170*464ce2bbSSoby Mathew 					      irq_num,
171*464ce2bbSSoby Mathew 					      GIC_HIGHEST_SEC_PRIORITY);
172*464ce2bbSSoby Mathew 
173*464ce2bbSSoby Mathew 			/* Target the secure interrupts to primary CPU */
174*464ce2bbSSoby Mathew 			gicd_set_itargetsr(gicd_base, irq_num,
175*464ce2bbSSoby Mathew 					gicv2_get_cpuif_id(gicd_base));
176*464ce2bbSSoby Mathew 
177*464ce2bbSSoby Mathew 			/* Enable this interrupt */
178*464ce2bbSSoby Mathew 			gicd_set_isenabler(gicd_base, irq_num);
179*464ce2bbSSoby Mathew 		}
180*464ce2bbSSoby Mathew 	}
181*464ce2bbSSoby Mathew 
182*464ce2bbSSoby Mathew }
183*464ce2bbSSoby Mathew 
184*464ce2bbSSoby Mathew /*******************************************************************************
185*464ce2bbSSoby Mathew  * Helper function to configure secure G0 SGIs and PPIs.
186*464ce2bbSSoby Mathew  ******************************************************************************/
187*464ce2bbSSoby Mathew void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base,
188*464ce2bbSSoby Mathew 					unsigned int num_ints,
189*464ce2bbSSoby Mathew 					const unsigned int *sec_intr_list)
190*464ce2bbSSoby Mathew {
191*464ce2bbSSoby Mathew 	unsigned int index, irq_num, sec_ppi_sgi_mask = 0;
192*464ce2bbSSoby Mathew 
193*464ce2bbSSoby Mathew 	/* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
194*464ce2bbSSoby Mathew 	assert(num_ints ? (uintptr_t)sec_intr_list : 1);
195*464ce2bbSSoby Mathew 
196*464ce2bbSSoby Mathew 	/*
197*464ce2bbSSoby Mathew 	 * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
198*464ce2bbSSoby Mathew 	 * more scalable approach as it avoids clearing the enable bits in the
199*464ce2bbSSoby Mathew 	 * GICD_CTLR.
200*464ce2bbSSoby Mathew 	 */
201*464ce2bbSSoby Mathew 	gicd_write_icenabler(gicd_base, 0, ~0);
202*464ce2bbSSoby Mathew 
203*464ce2bbSSoby Mathew 	/* Setup the default PPI/SGI priorities doing four at a time */
204*464ce2bbSSoby Mathew 	for (index = 0; index < MIN_SPI_ID; index += 4)
205*464ce2bbSSoby Mathew 		gicd_write_ipriorityr(gicd_base,
206*464ce2bbSSoby Mathew 				      index,
207*464ce2bbSSoby Mathew 				      GICD_IPRIORITYR_DEF_VAL);
208*464ce2bbSSoby Mathew 
209*464ce2bbSSoby Mathew 	for (index = 0; index < num_ints; index++) {
210*464ce2bbSSoby Mathew 		irq_num = sec_intr_list[index];
211*464ce2bbSSoby Mathew 		if (irq_num < MIN_SPI_ID) {
212*464ce2bbSSoby Mathew 			/* We have an SGI or a PPI. They are Group0 at reset */
213*464ce2bbSSoby Mathew 			sec_ppi_sgi_mask |= 1U << irq_num;
214*464ce2bbSSoby Mathew 
215*464ce2bbSSoby Mathew 			/* Set the priority of this interrupt */
216*464ce2bbSSoby Mathew 			gicd_write_ipriorityr(gicd_base,
217*464ce2bbSSoby Mathew 					    irq_num,
218*464ce2bbSSoby Mathew 					    GIC_HIGHEST_SEC_PRIORITY);
219*464ce2bbSSoby Mathew 		}
220*464ce2bbSSoby Mathew 	}
221*464ce2bbSSoby Mathew 
222*464ce2bbSSoby Mathew 	/*
223*464ce2bbSSoby Mathew 	 * Invert the bitmask to create a mask for non-secure PPIs and
224*464ce2bbSSoby Mathew 	 * SGIs. Program the GICD_IGROUPR0 with this bit mask.
225*464ce2bbSSoby Mathew 	 */
226*464ce2bbSSoby Mathew 	gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask);
227*464ce2bbSSoby Mathew 
228*464ce2bbSSoby Mathew 	/* Enable the Group 0 SGIs and PPIs */
229*464ce2bbSSoby Mathew 	gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask);
230*464ce2bbSSoby Mathew }
231