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