xref: /rk3399_ARM-atf/drivers/arm/gic/v2/gicv2_main.c (revision cbd3f3706d4217ee3669deeb52b158e84eb97f56)
1464ce2bbSSoby Mathew /*
2311b1773SSoby Mathew  * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
3464ce2bbSSoby Mathew  *
482cb2c1aSdp-arm  * SPDX-License-Identifier: BSD-3-Clause
5464ce2bbSSoby Mathew  */
6464ce2bbSSoby Mathew 
7464ce2bbSSoby Mathew #include <arch.h>
8464ce2bbSSoby Mathew #include <arch_helpers.h>
9464ce2bbSSoby Mathew #include <assert.h>
10464ce2bbSSoby Mathew #include <debug.h>
11464ce2bbSSoby Mathew #include <gic_common.h>
12464ce2bbSSoby Mathew #include <gicv2.h>
13e9ec3cecSSoby Mathew #include "../common/gic_common_private.h"
14464ce2bbSSoby Mathew #include "gicv2_private.h"
15464ce2bbSSoby Mathew 
16464ce2bbSSoby Mathew static const gicv2_driver_data_t *driver_data;
17464ce2bbSSoby Mathew 
18464ce2bbSSoby Mathew /*******************************************************************************
19464ce2bbSSoby Mathew  * Enable secure interrupts and use FIQs to route them. Disable legacy bypass
20464ce2bbSSoby Mathew  * and set the priority mask register to allow all interrupts to trickle in.
21464ce2bbSSoby Mathew  ******************************************************************************/
22464ce2bbSSoby Mathew void gicv2_cpuif_enable(void)
23464ce2bbSSoby Mathew {
24464ce2bbSSoby Mathew 	unsigned int val;
25464ce2bbSSoby Mathew 
26464ce2bbSSoby Mathew 	assert(driver_data);
27464ce2bbSSoby Mathew 	assert(driver_data->gicc_base);
28464ce2bbSSoby Mathew 
29464ce2bbSSoby Mathew 	/*
30464ce2bbSSoby Mathew 	 * Enable the Group 0 interrupts, FIQEn and disable Group 0/1
31464ce2bbSSoby Mathew 	 * bypass.
32464ce2bbSSoby Mathew 	 */
33464ce2bbSSoby Mathew 	val = CTLR_ENABLE_G0_BIT | FIQ_EN_BIT | FIQ_BYP_DIS_GRP0;
34464ce2bbSSoby Mathew 	val |= IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1;
35464ce2bbSSoby Mathew 
36464ce2bbSSoby Mathew 	/* Program the idle priority in the PMR */
37464ce2bbSSoby Mathew 	gicc_write_pmr(driver_data->gicc_base, GIC_PRI_MASK);
38464ce2bbSSoby Mathew 	gicc_write_ctlr(driver_data->gicc_base, val);
39464ce2bbSSoby Mathew }
40464ce2bbSSoby Mathew 
41464ce2bbSSoby Mathew /*******************************************************************************
42464ce2bbSSoby Mathew  * Place the cpu interface in a state where it can never make a cpu exit wfi as
43464ce2bbSSoby Mathew  * as result of an asserted interrupt. This is critical for powering down a cpu
44464ce2bbSSoby Mathew  ******************************************************************************/
45464ce2bbSSoby Mathew void gicv2_cpuif_disable(void)
46464ce2bbSSoby Mathew {
47464ce2bbSSoby Mathew 	unsigned int val;
48464ce2bbSSoby Mathew 
49464ce2bbSSoby Mathew 	assert(driver_data);
50464ce2bbSSoby Mathew 	assert(driver_data->gicc_base);
51464ce2bbSSoby Mathew 
52464ce2bbSSoby Mathew 	/* Disable secure, non-secure interrupts and disable their bypass */
53464ce2bbSSoby Mathew 	val = gicc_read_ctlr(driver_data->gicc_base);
54464ce2bbSSoby Mathew 	val &= ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT);
55464ce2bbSSoby Mathew 	val |= FIQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP0;
56464ce2bbSSoby Mathew 	val |= IRQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP1;
57464ce2bbSSoby Mathew 	gicc_write_ctlr(driver_data->gicc_base, val);
58464ce2bbSSoby Mathew }
59464ce2bbSSoby Mathew 
60464ce2bbSSoby Mathew /*******************************************************************************
61464ce2bbSSoby Mathew  * Per cpu gic distributor setup which will be done by all cpus after a cold
62464ce2bbSSoby Mathew  * boot/hotplug. This marks out the secure SPIs and PPIs & enables them.
63464ce2bbSSoby Mathew  ******************************************************************************/
64464ce2bbSSoby Mathew void gicv2_pcpu_distif_init(void)
65464ce2bbSSoby Mathew {
66464ce2bbSSoby Mathew 	assert(driver_data);
67464ce2bbSSoby Mathew 	assert(driver_data->gicd_base);
68464ce2bbSSoby Mathew 	assert(driver_data->g0_interrupt_array);
69464ce2bbSSoby Mathew 
70464ce2bbSSoby Mathew 	gicv2_secure_ppi_sgi_setup(driver_data->gicd_base,
71464ce2bbSSoby Mathew 					driver_data->g0_interrupt_num,
72464ce2bbSSoby Mathew 					driver_data->g0_interrupt_array);
73464ce2bbSSoby Mathew }
74464ce2bbSSoby Mathew 
75464ce2bbSSoby Mathew /*******************************************************************************
76464ce2bbSSoby Mathew  * Global gic distributor init which will be done by the primary cpu after a
77464ce2bbSSoby Mathew  * cold boot. It marks out the secure SPIs, PPIs & SGIs and enables them. It
78464ce2bbSSoby Mathew  * then enables the secure GIC distributor interface.
79464ce2bbSSoby Mathew  ******************************************************************************/
80464ce2bbSSoby Mathew void gicv2_distif_init(void)
81464ce2bbSSoby Mathew {
82464ce2bbSSoby Mathew 	unsigned int ctlr;
83464ce2bbSSoby Mathew 
84464ce2bbSSoby Mathew 	assert(driver_data);
85464ce2bbSSoby Mathew 	assert(driver_data->gicd_base);
86464ce2bbSSoby Mathew 	assert(driver_data->g0_interrupt_array);
87464ce2bbSSoby Mathew 
88464ce2bbSSoby Mathew 	/* Disable the distributor before going further */
89464ce2bbSSoby Mathew 	ctlr = gicd_read_ctlr(driver_data->gicd_base);
90464ce2bbSSoby Mathew 	gicd_write_ctlr(driver_data->gicd_base,
91464ce2bbSSoby Mathew 			ctlr & ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT));
92464ce2bbSSoby Mathew 
93464ce2bbSSoby Mathew 	/* Set the default attribute of all SPIs */
94464ce2bbSSoby Mathew 	gicv2_spis_configure_defaults(driver_data->gicd_base);
95464ce2bbSSoby Mathew 
96464ce2bbSSoby Mathew 	/* Configure the G0 SPIs */
97464ce2bbSSoby Mathew 	gicv2_secure_spis_configure(driver_data->gicd_base,
98464ce2bbSSoby Mathew 					driver_data->g0_interrupt_num,
99464ce2bbSSoby Mathew 					driver_data->g0_interrupt_array);
100464ce2bbSSoby Mathew 
101464ce2bbSSoby Mathew 	/* Re-enable the secure SPIs now that they have been configured */
102464ce2bbSSoby Mathew 	gicd_write_ctlr(driver_data->gicd_base, ctlr | CTLR_ENABLE_G0_BIT);
103464ce2bbSSoby Mathew }
104464ce2bbSSoby Mathew 
105464ce2bbSSoby Mathew /*******************************************************************************
106464ce2bbSSoby Mathew  * Initialize the ARM GICv2 driver with the provided platform inputs
107464ce2bbSSoby Mathew  ******************************************************************************/
108464ce2bbSSoby Mathew void gicv2_driver_init(const gicv2_driver_data_t *plat_driver_data)
109464ce2bbSSoby Mathew {
110464ce2bbSSoby Mathew 	unsigned int gic_version;
111464ce2bbSSoby Mathew 	assert(plat_driver_data);
112464ce2bbSSoby Mathew 	assert(plat_driver_data->gicd_base);
113464ce2bbSSoby Mathew 	assert(plat_driver_data->gicc_base);
114464ce2bbSSoby Mathew 
115464ce2bbSSoby Mathew 	/*
116464ce2bbSSoby Mathew 	 * The platform should provide a list of atleast one type of
117464ce2bbSSoby Mathew 	 * interrupts
118464ce2bbSSoby Mathew 	 */
119464ce2bbSSoby Mathew 	assert(plat_driver_data->g0_interrupt_array);
120464ce2bbSSoby Mathew 
121464ce2bbSSoby Mathew 	/*
122464ce2bbSSoby Mathew 	 * If there are no interrupts of a particular type, then the number of
123464ce2bbSSoby Mathew 	 * interrupts of that type should be 0 and vice-versa.
124464ce2bbSSoby Mathew 	 */
125464ce2bbSSoby Mathew 	assert(plat_driver_data->g0_interrupt_array ?
126464ce2bbSSoby Mathew 	       plat_driver_data->g0_interrupt_num :
127464ce2bbSSoby Mathew 	       plat_driver_data->g0_interrupt_num == 0);
128464ce2bbSSoby Mathew 
129464ce2bbSSoby Mathew 	/* Ensure that this is a GICv2 system */
130464ce2bbSSoby Mathew 	gic_version = gicd_read_pidr2(plat_driver_data->gicd_base);
131464ce2bbSSoby Mathew 	gic_version = (gic_version >> PIDR2_ARCH_REV_SHIFT)
132464ce2bbSSoby Mathew 					& PIDR2_ARCH_REV_MASK;
133464ce2bbSSoby Mathew 	assert(gic_version == ARCH_REV_GICV2);
134464ce2bbSSoby Mathew 
135464ce2bbSSoby Mathew 	driver_data = plat_driver_data;
136464ce2bbSSoby Mathew 
137311b1773SSoby Mathew 	/*
138311b1773SSoby Mathew 	 * The GIC driver data is initialized by the primary CPU with caches
139311b1773SSoby Mathew 	 * enabled. When the secondary CPU boots up, it initializes the
140311b1773SSoby Mathew 	 * GICC/GICR interface with the caches disabled. Hence flush the
141311b1773SSoby Mathew 	 * driver_data to ensure coherency. This is not required if the
142311b1773SSoby Mathew 	 * platform has HW_ASSISTED_COHERENCY enabled.
143311b1773SSoby Mathew 	 */
144311b1773SSoby Mathew #if !HW_ASSISTED_COHERENCY
145311b1773SSoby Mathew 	flush_dcache_range((uintptr_t) &driver_data, sizeof(driver_data));
146311b1773SSoby Mathew 	flush_dcache_range((uintptr_t) driver_data, sizeof(*driver_data));
147311b1773SSoby Mathew #endif
148464ce2bbSSoby Mathew 	INFO("ARM GICv2 driver initialized\n");
149464ce2bbSSoby Mathew }
150464ce2bbSSoby Mathew 
151464ce2bbSSoby Mathew /******************************************************************************
152464ce2bbSSoby Mathew  * This function returns whether FIQ is enabled in the GIC CPU interface.
153464ce2bbSSoby Mathew  *****************************************************************************/
154464ce2bbSSoby Mathew unsigned int gicv2_is_fiq_enabled(void)
155464ce2bbSSoby Mathew {
156464ce2bbSSoby Mathew 	unsigned int gicc_ctlr;
157464ce2bbSSoby Mathew 
158464ce2bbSSoby Mathew 	assert(driver_data);
159464ce2bbSSoby Mathew 	assert(driver_data->gicc_base);
160464ce2bbSSoby Mathew 
161464ce2bbSSoby Mathew 	gicc_ctlr = gicc_read_ctlr(driver_data->gicc_base);
162464ce2bbSSoby Mathew 	return (gicc_ctlr >> FIQ_EN_SHIFT) & 0x1;
163464ce2bbSSoby Mathew }
164464ce2bbSSoby Mathew 
165464ce2bbSSoby Mathew /*******************************************************************************
166464ce2bbSSoby Mathew  * This function returns the type of the highest priority pending interrupt at
167464ce2bbSSoby Mathew  * the GIC cpu interface. The return values can be one of the following :
168464ce2bbSSoby Mathew  *   PENDING_G1_INTID   : The interrupt type is non secure Group 1.
169464ce2bbSSoby Mathew  *   0 - 1019           : The interrupt type is secure Group 0.
170464ce2bbSSoby Mathew  *   GIC_SPURIOUS_INTERRUPT : there is no pending interrupt with
171464ce2bbSSoby Mathew  *                            sufficient priority to be signaled
172464ce2bbSSoby Mathew  ******************************************************************************/
173464ce2bbSSoby Mathew unsigned int gicv2_get_pending_interrupt_type(void)
174464ce2bbSSoby Mathew {
175464ce2bbSSoby Mathew 	assert(driver_data);
176464ce2bbSSoby Mathew 	assert(driver_data->gicc_base);
177464ce2bbSSoby Mathew 
178464ce2bbSSoby Mathew 	return gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK;
179464ce2bbSSoby Mathew }
180464ce2bbSSoby Mathew 
181464ce2bbSSoby Mathew /*******************************************************************************
182464ce2bbSSoby Mathew  * This function returns the id of the highest priority pending interrupt at
183464ce2bbSSoby Mathew  * the GIC cpu interface. GIC_SPURIOUS_INTERRUPT is returned when there is no
184464ce2bbSSoby Mathew  * interrupt pending.
185464ce2bbSSoby Mathew  ******************************************************************************/
186464ce2bbSSoby Mathew unsigned int gicv2_get_pending_interrupt_id(void)
187464ce2bbSSoby Mathew {
188464ce2bbSSoby Mathew 	unsigned int id;
189464ce2bbSSoby Mathew 
190464ce2bbSSoby Mathew 	assert(driver_data);
191464ce2bbSSoby Mathew 	assert(driver_data->gicc_base);
192464ce2bbSSoby Mathew 
193464ce2bbSSoby Mathew 	id = gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK;
194464ce2bbSSoby Mathew 
195464ce2bbSSoby Mathew 	/*
196464ce2bbSSoby Mathew 	 * Find out which non-secure interrupt it is under the assumption that
197464ce2bbSSoby Mathew 	 * the GICC_CTLR.AckCtl bit is 0.
198464ce2bbSSoby Mathew 	 */
199464ce2bbSSoby Mathew 	if (id == PENDING_G1_INTID)
200464ce2bbSSoby Mathew 		id = gicc_read_ahppir(driver_data->gicc_base) & INT_ID_MASK;
201464ce2bbSSoby Mathew 
202464ce2bbSSoby Mathew 	return id;
203464ce2bbSSoby Mathew }
204464ce2bbSSoby Mathew 
205464ce2bbSSoby Mathew /*******************************************************************************
206464ce2bbSSoby Mathew  * This functions reads the GIC cpu interface Interrupt Acknowledge register
207464ce2bbSSoby Mathew  * to start handling the pending secure 0 interrupt. It returns the
208464ce2bbSSoby Mathew  * contents of the IAR.
209464ce2bbSSoby Mathew  ******************************************************************************/
210464ce2bbSSoby Mathew unsigned int gicv2_acknowledge_interrupt(void)
211464ce2bbSSoby Mathew {
212464ce2bbSSoby Mathew 	assert(driver_data);
213464ce2bbSSoby Mathew 	assert(driver_data->gicc_base);
214464ce2bbSSoby Mathew 
215464ce2bbSSoby Mathew 	return gicc_read_IAR(driver_data->gicc_base);
216464ce2bbSSoby Mathew }
217464ce2bbSSoby Mathew 
218464ce2bbSSoby Mathew /*******************************************************************************
219464ce2bbSSoby Mathew  * This functions writes the GIC cpu interface End Of Interrupt register with
220464ce2bbSSoby Mathew  * the passed value to finish handling the active secure group 0 interrupt.
221464ce2bbSSoby Mathew  ******************************************************************************/
222464ce2bbSSoby Mathew void gicv2_end_of_interrupt(unsigned int id)
223464ce2bbSSoby Mathew {
224464ce2bbSSoby Mathew 	assert(driver_data);
225464ce2bbSSoby Mathew 	assert(driver_data->gicc_base);
226464ce2bbSSoby Mathew 
227464ce2bbSSoby Mathew 	gicc_write_EOIR(driver_data->gicc_base, id);
228464ce2bbSSoby Mathew }
229464ce2bbSSoby Mathew 
230464ce2bbSSoby Mathew /*******************************************************************************
231464ce2bbSSoby Mathew  * This function returns the type of the interrupt id depending upon the group
232464ce2bbSSoby Mathew  * this interrupt has been configured under by the interrupt controller i.e.
233464ce2bbSSoby Mathew  * group0 secure or group1 non secure. It returns zero for Group 0 secure and
234464ce2bbSSoby Mathew  * one for Group 1 non secure interrupt.
235464ce2bbSSoby Mathew  ******************************************************************************/
236464ce2bbSSoby Mathew unsigned int gicv2_get_interrupt_group(unsigned int id)
237464ce2bbSSoby Mathew {
238464ce2bbSSoby Mathew 	assert(driver_data);
239464ce2bbSSoby Mathew 	assert(driver_data->gicd_base);
240464ce2bbSSoby Mathew 
241464ce2bbSSoby Mathew 	return gicd_get_igroupr(driver_data->gicd_base, id);
242464ce2bbSSoby Mathew }
243eb68ea9bSJeenu Viswambharan 
244eb68ea9bSJeenu Viswambharan /*******************************************************************************
245eb68ea9bSJeenu Viswambharan  * This function returns the priority of the interrupt the processor is
246eb68ea9bSJeenu Viswambharan  * currently servicing.
247eb68ea9bSJeenu Viswambharan  ******************************************************************************/
248eb68ea9bSJeenu Viswambharan unsigned int gicv2_get_running_priority(void)
249eb68ea9bSJeenu Viswambharan {
250eb68ea9bSJeenu Viswambharan 	assert(driver_data);
251eb68ea9bSJeenu Viswambharan 	assert(driver_data->gicc_base);
252eb68ea9bSJeenu Viswambharan 
253eb68ea9bSJeenu Viswambharan 	return gicc_read_rpr(driver_data->gicc_base);
254eb68ea9bSJeenu Viswambharan }
255fa9db423SJeenu Viswambharan 
256fa9db423SJeenu Viswambharan /*******************************************************************************
257fa9db423SJeenu Viswambharan  * This function sets the GICv2 target mask pattern for the current PE. The PE
258fa9db423SJeenu Viswambharan  * target mask is used to translate linear PE index (returned by platform core
259fa9db423SJeenu Viswambharan  * position) to a bit mask used when targeting interrupts to a PE, viz. when
260fa9db423SJeenu Viswambharan  * raising SGIs and routing SPIs.
261fa9db423SJeenu Viswambharan  ******************************************************************************/
262fa9db423SJeenu Viswambharan void gicv2_set_pe_target_mask(unsigned int proc_num)
263fa9db423SJeenu Viswambharan {
264fa9db423SJeenu Viswambharan 	assert(driver_data);
265fa9db423SJeenu Viswambharan 	assert(driver_data->gicd_base);
266fa9db423SJeenu Viswambharan 	assert(driver_data->target_masks);
267fa9db423SJeenu Viswambharan 	assert(proc_num < GICV2_MAX_TARGET_PE);
268fa9db423SJeenu Viswambharan 	assert(proc_num < driver_data->target_masks_num);
269fa9db423SJeenu Viswambharan 
270fa9db423SJeenu Viswambharan 	/* Return if the target mask is already populated */
271fa9db423SJeenu Viswambharan 	if (driver_data->target_masks[proc_num])
272fa9db423SJeenu Viswambharan 		return;
273fa9db423SJeenu Viswambharan 
274fa9db423SJeenu Viswambharan 	/* Read target register corresponding to this CPU */
275fa9db423SJeenu Viswambharan 	driver_data->target_masks[proc_num] =
276fa9db423SJeenu Viswambharan 		gicv2_get_cpuif_id(driver_data->gicd_base);
277fa9db423SJeenu Viswambharan }
278*cbd3f370SJeenu Viswambharan 
279*cbd3f370SJeenu Viswambharan /*******************************************************************************
280*cbd3f370SJeenu Viswambharan  * This function returns the active status of the interrupt (either because the
281*cbd3f370SJeenu Viswambharan  * state is active, or active and pending).
282*cbd3f370SJeenu Viswambharan  ******************************************************************************/
283*cbd3f370SJeenu Viswambharan unsigned int gicv2_get_interrupt_active(unsigned int id)
284*cbd3f370SJeenu Viswambharan {
285*cbd3f370SJeenu Viswambharan 	assert(driver_data);
286*cbd3f370SJeenu Viswambharan 	assert(driver_data->gicd_base);
287*cbd3f370SJeenu Viswambharan 	assert(id <= MAX_SPI_ID);
288*cbd3f370SJeenu Viswambharan 
289*cbd3f370SJeenu Viswambharan 	return gicd_get_isactiver(driver_data->gicd_base, id);
290*cbd3f370SJeenu Viswambharan }
291