xref: /rk3399_ARM-atf/drivers/arm/gic/v2/gicv2_main.c (revision d77a1ec5213a6618bf1a52ea591506e995b29392)
1464ce2bbSSoby Mathew /*
2ab80cf35SMadhukar Pappireddy  * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved.
3dcb31ff7SFlorian Lugou  * Portions copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved.
4464ce2bbSSoby Mathew  *
582cb2c1aSdp-arm  * SPDX-License-Identifier: BSD-3-Clause
6464ce2bbSSoby Mathew  */
7464ce2bbSSoby Mathew 
809d40e0eSAntonio Nino Diaz #include <assert.h>
909d40e0eSAntonio Nino Diaz #include <stdbool.h>
1009d40e0eSAntonio Nino Diaz 
11464ce2bbSSoby Mathew #include <arch.h>
12464ce2bbSSoby Mathew #include <arch_helpers.h>
1309d40e0eSAntonio Nino Diaz #include <common/debug.h>
1409d40e0eSAntonio Nino Diaz #include <common/interrupt_props.h>
1509d40e0eSAntonio Nino Diaz #include <drivers/arm/gic_common.h>
1609d40e0eSAntonio Nino Diaz #include <drivers/arm/gicv2.h>
1709d40e0eSAntonio Nino Diaz #include <lib/spinlock.h>
183fea9c8bSAntonio Nino Diaz 
19e9ec3cecSSoby Mathew #include "../common/gic_common_private.h"
20464ce2bbSSoby Mathew #include "gicv2_private.h"
21464ce2bbSSoby Mathew 
22464ce2bbSSoby Mathew static const gicv2_driver_data_t *driver_data;
23464ce2bbSSoby Mathew 
2474dce7faSJeenu Viswambharan /*
2574dce7faSJeenu Viswambharan  * Spinlock to guard registers needing read-modify-write. APIs protected by this
2674dce7faSJeenu Viswambharan  * spinlock are used either at boot time (when only a single CPU is active), or
2774dce7faSJeenu Viswambharan  * when the system is fully coherent.
2874dce7faSJeenu Viswambharan  */
297fabe1a8SRoberto Vargas static spinlock_t gic_lock;
3074dce7faSJeenu Viswambharan 
31464ce2bbSSoby Mathew /*******************************************************************************
32464ce2bbSSoby Mathew  * Enable secure interrupts and use FIQs to route them. Disable legacy bypass
33464ce2bbSSoby Mathew  * and set the priority mask register to allow all interrupts to trickle in.
34464ce2bbSSoby Mathew  ******************************************************************************/
gicv2_cpuif_enable(void)35464ce2bbSSoby Mathew void gicv2_cpuif_enable(void)
36464ce2bbSSoby Mathew {
37464ce2bbSSoby Mathew 	unsigned int val;
38464ce2bbSSoby Mathew 
393fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
403fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicc_base != 0U);
41464ce2bbSSoby Mathew 
42464ce2bbSSoby Mathew 	/*
43464ce2bbSSoby Mathew 	 * Enable the Group 0 interrupts, FIQEn and disable Group 0/1
44464ce2bbSSoby Mathew 	 * bypass.
45464ce2bbSSoby Mathew 	 */
46464ce2bbSSoby Mathew 	val = CTLR_ENABLE_G0_BIT | FIQ_EN_BIT | FIQ_BYP_DIS_GRP0;
47464ce2bbSSoby Mathew 	val |= IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1;
48464ce2bbSSoby Mathew 
49464ce2bbSSoby Mathew 	/* Program the idle priority in the PMR */
50464ce2bbSSoby Mathew 	gicc_write_pmr(driver_data->gicc_base, GIC_PRI_MASK);
51464ce2bbSSoby Mathew 	gicc_write_ctlr(driver_data->gicc_base, val);
52464ce2bbSSoby Mathew }
53464ce2bbSSoby Mathew 
54464ce2bbSSoby Mathew /*******************************************************************************
55464ce2bbSSoby Mathew  * Place the cpu interface in a state where it can never make a cpu exit wfi as
56464ce2bbSSoby Mathew  * as result of an asserted interrupt. This is critical for powering down a cpu
57464ce2bbSSoby Mathew  ******************************************************************************/
gicv2_cpuif_disable(void)58464ce2bbSSoby Mathew void gicv2_cpuif_disable(void)
59464ce2bbSSoby Mathew {
60464ce2bbSSoby Mathew 	unsigned int val;
61464ce2bbSSoby Mathew 
623fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
633fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicc_base != 0U);
64464ce2bbSSoby Mathew 
65464ce2bbSSoby Mathew 	/* Disable secure, non-secure interrupts and disable their bypass */
66464ce2bbSSoby Mathew 	val = gicc_read_ctlr(driver_data->gicc_base);
67464ce2bbSSoby Mathew 	val &= ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT);
68464ce2bbSSoby Mathew 	val |= FIQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP0;
69464ce2bbSSoby Mathew 	val |= IRQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP1;
70464ce2bbSSoby Mathew 	gicc_write_ctlr(driver_data->gicc_base, val);
71464ce2bbSSoby Mathew }
72464ce2bbSSoby Mathew 
73464ce2bbSSoby Mathew /*******************************************************************************
74464ce2bbSSoby Mathew  * Per cpu gic distributor setup which will be done by all cpus after a cold
75464ce2bbSSoby Mathew  * boot/hotplug. This marks out the secure SPIs and PPIs & enables them.
76464ce2bbSSoby Mathew  ******************************************************************************/
gicv2_pcpu_distif_init(void)77464ce2bbSSoby Mathew void gicv2_pcpu_distif_init(void)
78464ce2bbSSoby Mathew {
79385f1dbbSJeenu Viswambharan 	unsigned int ctlr;
80385f1dbbSJeenu Viswambharan 
813fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
823fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicd_base != 0U);
83464ce2bbSSoby Mathew 
84c639e8ebSJeenu Viswambharan 	gicv2_secure_ppi_sgi_setup_props(driver_data->gicd_base,
85c639e8ebSJeenu Viswambharan 			driver_data->interrupt_props,
86c639e8ebSJeenu Viswambharan 			driver_data->interrupt_props_num);
87385f1dbbSJeenu Viswambharan 
88385f1dbbSJeenu Viswambharan 	/* Enable G0 interrupts if not already */
89385f1dbbSJeenu Viswambharan 	ctlr = gicd_read_ctlr(driver_data->gicd_base);
903fea9c8bSAntonio Nino Diaz 	if ((ctlr & CTLR_ENABLE_G0_BIT) == 0U) {
91385f1dbbSJeenu Viswambharan 		gicd_write_ctlr(driver_data->gicd_base,
92385f1dbbSJeenu Viswambharan 				ctlr | CTLR_ENABLE_G0_BIT);
93385f1dbbSJeenu Viswambharan 	}
94c639e8ebSJeenu Viswambharan }
95464ce2bbSSoby Mathew 
96464ce2bbSSoby Mathew /*******************************************************************************
97464ce2bbSSoby Mathew  * Global gic distributor init which will be done by the primary cpu after a
98464ce2bbSSoby Mathew  * cold boot. It marks out the secure SPIs, PPIs & SGIs and enables them. It
99464ce2bbSSoby Mathew  * then enables the secure GIC distributor interface.
100464ce2bbSSoby Mathew  ******************************************************************************/
gicv2_distif_init(void)101464ce2bbSSoby Mathew void gicv2_distif_init(void)
102464ce2bbSSoby Mathew {
103464ce2bbSSoby Mathew 	unsigned int ctlr;
104464ce2bbSSoby Mathew 
1053fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
1063fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicd_base != 0U);
107464ce2bbSSoby Mathew 
108464ce2bbSSoby Mathew 	/* Disable the distributor before going further */
109464ce2bbSSoby Mathew 	ctlr = gicd_read_ctlr(driver_data->gicd_base);
110464ce2bbSSoby Mathew 	gicd_write_ctlr(driver_data->gicd_base,
111464ce2bbSSoby Mathew 			ctlr & ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT));
112464ce2bbSSoby Mathew 
113464ce2bbSSoby Mathew 	/* Set the default attribute of all SPIs */
114464ce2bbSSoby Mathew 	gicv2_spis_configure_defaults(driver_data->gicd_base);
115464ce2bbSSoby Mathew 
116c639e8ebSJeenu Viswambharan 	gicv2_secure_spis_configure_props(driver_data->gicd_base,
117c639e8ebSJeenu Viswambharan 			driver_data->interrupt_props,
118c639e8ebSJeenu Viswambharan 			driver_data->interrupt_props_num);
119dcf01a0aSDan Handley 
120464ce2bbSSoby Mathew 
121464ce2bbSSoby Mathew 	/* Re-enable the secure SPIs now that they have been configured */
122464ce2bbSSoby Mathew 	gicd_write_ctlr(driver_data->gicd_base, ctlr | CTLR_ENABLE_G0_BIT);
123464ce2bbSSoby Mathew }
124464ce2bbSSoby Mathew 
125464ce2bbSSoby Mathew /*******************************************************************************
126464ce2bbSSoby Mathew  * Initialize the ARM GICv2 driver with the provided platform inputs
127464ce2bbSSoby Mathew  ******************************************************************************/
gicv2_driver_init(const gicv2_driver_data_t * plat_driver_data)128464ce2bbSSoby Mathew void gicv2_driver_init(const gicv2_driver_data_t *plat_driver_data)
129464ce2bbSSoby Mathew {
130464ce2bbSSoby Mathew 	unsigned int gic_version;
1313fea9c8bSAntonio Nino Diaz 
1323fea9c8bSAntonio Nino Diaz 	assert(plat_driver_data != NULL);
1333fea9c8bSAntonio Nino Diaz 	assert(plat_driver_data->gicd_base != 0U);
1343fea9c8bSAntonio Nino Diaz 	assert(plat_driver_data->gicc_base != 0U);
135464ce2bbSSoby Mathew 
1369d6d800dSSamuel Holland 	assert(plat_driver_data->interrupt_props_num > 0 ?
1379d6d800dSSamuel Holland 			plat_driver_data->interrupt_props != NULL : 1);
138464ce2bbSSoby Mathew 
139464ce2bbSSoby Mathew 	/* Ensure that this is a GICv2 system */
140464ce2bbSSoby Mathew 	gic_version = gicd_read_pidr2(plat_driver_data->gicd_base);
141464ce2bbSSoby Mathew 	gic_version = (gic_version >> PIDR2_ARCH_REV_SHIFT)
142464ce2bbSSoby Mathew 					& PIDR2_ARCH_REV_MASK;
14364deed19SEtienne Carriere 
14464deed19SEtienne Carriere 	/*
14564deed19SEtienne Carriere 	 * GICv1 with security extension complies with trusted firmware
14664deed19SEtienne Carriere 	 * GICv2 driver as far as virtualization and few tricky power
14764deed19SEtienne Carriere 	 * features are not used. GICv2 features that are not supported
14864deed19SEtienne Carriere 	 * by GICv1 with Security Extensions are:
14964deed19SEtienne Carriere 	 * - virtual interrupt support.
15064deed19SEtienne Carriere 	 * - wake up events.
15164deed19SEtienne Carriere 	 * - writeable GIC state register (for power sequences)
15264deed19SEtienne Carriere 	 * - interrupt priority drop.
15364deed19SEtienne Carriere 	 * - interrupt signal bypass.
15464deed19SEtienne Carriere 	 */
1553fea9c8bSAntonio Nino Diaz 	assert((gic_version == ARCH_REV_GICV2) ||
1563fea9c8bSAntonio Nino Diaz 	       (gic_version == ARCH_REV_GICV1));
157464ce2bbSSoby Mathew 
158464ce2bbSSoby Mathew 	driver_data = plat_driver_data;
159464ce2bbSSoby Mathew 
160311b1773SSoby Mathew 	/*
161311b1773SSoby Mathew 	 * The GIC driver data is initialized by the primary CPU with caches
162311b1773SSoby Mathew 	 * enabled. When the secondary CPU boots up, it initializes the
163311b1773SSoby Mathew 	 * GICC/GICR interface with the caches disabled. Hence flush the
164311b1773SSoby Mathew 	 * driver_data to ensure coherency. This is not required if the
1659262eb54SAndrew F. Davis 	 * platform has HW_ASSISTED_COHERENCY or WARMBOOT_ENABLE_DCACHE_EARLY
1669262eb54SAndrew F. Davis 	 * enabled.
167311b1773SSoby Mathew 	 */
1689262eb54SAndrew F. Davis #if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
169311b1773SSoby Mathew 	flush_dcache_range((uintptr_t) &driver_data, sizeof(driver_data));
170311b1773SSoby Mathew 	flush_dcache_range((uintptr_t) driver_data, sizeof(*driver_data));
171311b1773SSoby Mathew #endif
172464ce2bbSSoby Mathew 	INFO("ARM GICv2 driver initialized\n");
173464ce2bbSSoby Mathew }
174464ce2bbSSoby Mathew 
175464ce2bbSSoby Mathew /******************************************************************************
176464ce2bbSSoby Mathew  * This function returns whether FIQ is enabled in the GIC CPU interface.
177464ce2bbSSoby Mathew  *****************************************************************************/
gicv2_is_fiq_enabled(void)178464ce2bbSSoby Mathew unsigned int gicv2_is_fiq_enabled(void)
179464ce2bbSSoby Mathew {
180464ce2bbSSoby Mathew 	unsigned int gicc_ctlr;
181464ce2bbSSoby Mathew 
1823fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
1833fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicc_base != 0U);
184464ce2bbSSoby Mathew 
185464ce2bbSSoby Mathew 	gicc_ctlr = gicc_read_ctlr(driver_data->gicc_base);
1863fea9c8bSAntonio Nino Diaz 	return (gicc_ctlr >> FIQ_EN_SHIFT) & 0x1U;
187464ce2bbSSoby Mathew }
188464ce2bbSSoby Mathew 
189464ce2bbSSoby Mathew /*******************************************************************************
190464ce2bbSSoby Mathew  * This function returns the type of the highest priority pending interrupt at
191464ce2bbSSoby Mathew  * the GIC cpu interface. The return values can be one of the following :
192464ce2bbSSoby Mathew  *   PENDING_G1_INTID   : The interrupt type is non secure Group 1.
193464ce2bbSSoby Mathew  *   0 - 1019           : The interrupt type is secure Group 0.
194464ce2bbSSoby Mathew  *   GIC_SPURIOUS_INTERRUPT : there is no pending interrupt with
195464ce2bbSSoby Mathew  *                            sufficient priority to be signaled
196464ce2bbSSoby Mathew  ******************************************************************************/
gicv2_get_pending_interrupt_type(void)197464ce2bbSSoby Mathew unsigned int gicv2_get_pending_interrupt_type(void)
198464ce2bbSSoby Mathew {
1993fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
2003fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicc_base != 0U);
201464ce2bbSSoby Mathew 
202464ce2bbSSoby Mathew 	return gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK;
203464ce2bbSSoby Mathew }
204464ce2bbSSoby Mathew 
205464ce2bbSSoby Mathew /*******************************************************************************
206464ce2bbSSoby Mathew  * This function returns the id of the highest priority pending interrupt at
207464ce2bbSSoby Mathew  * the GIC cpu interface. GIC_SPURIOUS_INTERRUPT is returned when there is no
208464ce2bbSSoby Mathew  * interrupt pending.
209464ce2bbSSoby Mathew  ******************************************************************************/
gicv2_get_pending_interrupt_id(void)210464ce2bbSSoby Mathew unsigned int gicv2_get_pending_interrupt_id(void)
211464ce2bbSSoby Mathew {
212464ce2bbSSoby Mathew 	unsigned int id;
213464ce2bbSSoby Mathew 
2143fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
2153fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicc_base != 0U);
216464ce2bbSSoby Mathew 
217464ce2bbSSoby Mathew 	id = gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK;
218464ce2bbSSoby Mathew 
219464ce2bbSSoby Mathew 	/*
220464ce2bbSSoby Mathew 	 * Find out which non-secure interrupt it is under the assumption that
221464ce2bbSSoby Mathew 	 * the GICC_CTLR.AckCtl bit is 0.
222464ce2bbSSoby Mathew 	 */
223*03c6bb0eSMaheedhar Bollapalli 	if (id == PENDING_G1_INTID) {
224464ce2bbSSoby Mathew 		id = gicc_read_ahppir(driver_data->gicc_base) & INT_ID_MASK;
225*03c6bb0eSMaheedhar Bollapalli 	}
226464ce2bbSSoby Mathew 	return id;
227464ce2bbSSoby Mathew }
228464ce2bbSSoby Mathew 
229464ce2bbSSoby Mathew /*******************************************************************************
230464ce2bbSSoby Mathew  * This functions reads the GIC cpu interface Interrupt Acknowledge register
231464ce2bbSSoby Mathew  * to start handling the pending secure 0 interrupt. It returns the
232464ce2bbSSoby Mathew  * contents of the IAR.
233464ce2bbSSoby Mathew  ******************************************************************************/
gicv2_acknowledge_interrupt(void)234464ce2bbSSoby Mathew unsigned int gicv2_acknowledge_interrupt(void)
235464ce2bbSSoby Mathew {
2363fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
2373fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicc_base != 0U);
238464ce2bbSSoby Mathew 
239464ce2bbSSoby Mathew 	return gicc_read_IAR(driver_data->gicc_base);
240464ce2bbSSoby Mathew }
241464ce2bbSSoby Mathew 
242464ce2bbSSoby Mathew /*******************************************************************************
243464ce2bbSSoby Mathew  * This functions writes the GIC cpu interface End Of Interrupt register with
244464ce2bbSSoby Mathew  * the passed value to finish handling the active secure group 0 interrupt.
245464ce2bbSSoby Mathew  ******************************************************************************/
gicv2_end_of_interrupt(unsigned int id)246464ce2bbSSoby Mathew void gicv2_end_of_interrupt(unsigned int id)
247464ce2bbSSoby Mathew {
2483fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
2493fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicc_base != 0U);
250464ce2bbSSoby Mathew 
2515eb16c47SSandeep Tripathy 	/*
2525eb16c47SSandeep Tripathy 	 * Ensure the write to peripheral registers are *complete* before the write
2535eb16c47SSandeep Tripathy 	 * to GIC_EOIR.
2545eb16c47SSandeep Tripathy 	 *
2551b491eeaSElyes Haouas 	 * Note: The completion guarantee depends on various factors of system design
2565eb16c47SSandeep Tripathy 	 * and the barrier is the best core can do by which execution of further
2575eb16c47SSandeep Tripathy 	 * instructions waits till the barrier is alive.
2585eb16c47SSandeep Tripathy 	 */
2595eb16c47SSandeep Tripathy 	dsbishst();
260464ce2bbSSoby Mathew 	gicc_write_EOIR(driver_data->gicc_base, id);
261464ce2bbSSoby Mathew }
262464ce2bbSSoby Mathew 
263464ce2bbSSoby Mathew /*******************************************************************************
264464ce2bbSSoby Mathew  * This function returns the type of the interrupt id depending upon the group
265464ce2bbSSoby Mathew  * this interrupt has been configured under by the interrupt controller i.e.
266464ce2bbSSoby Mathew  * group0 secure or group1 non secure. It returns zero for Group 0 secure and
267464ce2bbSSoby Mathew  * one for Group 1 non secure interrupt.
268464ce2bbSSoby Mathew  ******************************************************************************/
gicv2_get_interrupt_group(unsigned int id)269464ce2bbSSoby Mathew unsigned int gicv2_get_interrupt_group(unsigned int id)
270464ce2bbSSoby Mathew {
2713fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
2723fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicd_base != 0U);
273464ce2bbSSoby Mathew 
274464ce2bbSSoby Mathew 	return gicd_get_igroupr(driver_data->gicd_base, id);
275464ce2bbSSoby Mathew }
276eb68ea9bSJeenu Viswambharan 
277eb68ea9bSJeenu Viswambharan /*******************************************************************************
278eb68ea9bSJeenu Viswambharan  * This function returns the priority of the interrupt the processor is
279eb68ea9bSJeenu Viswambharan  * currently servicing.
280eb68ea9bSJeenu Viswambharan  ******************************************************************************/
gicv2_get_running_priority(void)281eb68ea9bSJeenu Viswambharan unsigned int gicv2_get_running_priority(void)
282eb68ea9bSJeenu Viswambharan {
2833fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
2843fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicc_base != 0U);
285eb68ea9bSJeenu Viswambharan 
286eb68ea9bSJeenu Viswambharan 	return gicc_read_rpr(driver_data->gicc_base);
287eb68ea9bSJeenu Viswambharan }
288fa9db423SJeenu Viswambharan 
289fa9db423SJeenu Viswambharan /*******************************************************************************
290fa9db423SJeenu Viswambharan  * This function sets the GICv2 target mask pattern for the current PE. The PE
291fa9db423SJeenu Viswambharan  * target mask is used to translate linear PE index (returned by platform core
29273308618SAntonio Nino Diaz  * position) to a bit mask used when targeting interrupts to a PE (for example
29373308618SAntonio Nino Diaz  * when raising SGIs and routing SPIs).
294fa9db423SJeenu Viswambharan  ******************************************************************************/
gicv2_set_pe_target_mask(unsigned int proc_num)295fa9db423SJeenu Viswambharan void gicv2_set_pe_target_mask(unsigned int proc_num)
296fa9db423SJeenu Viswambharan {
2973fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
2983fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicd_base != 0U);
2993fea9c8bSAntonio Nino Diaz 	assert(driver_data->target_masks != NULL);
30020d38497Sjohpow01 	assert(proc_num < GICV2_MAX_TARGET_PE);
30120d38497Sjohpow01 	assert(proc_num < driver_data->target_masks_num);
302fa9db423SJeenu Viswambharan 
303fa9db423SJeenu Viswambharan 	/* Return if the target mask is already populated */
304*03c6bb0eSMaheedhar Bollapalli 	if (driver_data->target_masks[proc_num] != 0U) {
305fa9db423SJeenu Viswambharan 		return;
306*03c6bb0eSMaheedhar Bollapalli 	}
307058efeefSJeenu Viswambharan 	/*
308058efeefSJeenu Viswambharan 	 * Update target register corresponding to this CPU and flush for it to
309058efeefSJeenu Viswambharan 	 * be visible to other CPUs.
310058efeefSJeenu Viswambharan 	 */
3113fea9c8bSAntonio Nino Diaz 	if (driver_data->target_masks[proc_num] == 0U) {
312fa9db423SJeenu Viswambharan 		driver_data->target_masks[proc_num] =
313fa9db423SJeenu Viswambharan 			gicv2_get_cpuif_id(driver_data->gicd_base);
3149262eb54SAndrew F. Davis #if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
315058efeefSJeenu Viswambharan 		/*
316058efeefSJeenu Viswambharan 		 * PEs only update their own masks. Primary updates it with
317058efeefSJeenu Viswambharan 		 * caches on. But because secondaries does it with caches off,
318058efeefSJeenu Viswambharan 		 * all updates go to memory directly, and there's no danger of
319058efeefSJeenu Viswambharan 		 * secondaries overwriting each others' mask, despite
320058efeefSJeenu Viswambharan 		 * target_masks[] not being cache line aligned.
321058efeefSJeenu Viswambharan 		 */
322058efeefSJeenu Viswambharan 		flush_dcache_range((uintptr_t)
323058efeefSJeenu Viswambharan 				&driver_data->target_masks[proc_num],
324058efeefSJeenu Viswambharan 				sizeof(driver_data->target_masks[proc_num]));
325058efeefSJeenu Viswambharan #endif
326058efeefSJeenu Viswambharan 	}
327fa9db423SJeenu Viswambharan }
328cbd3f370SJeenu Viswambharan 
329cbd3f370SJeenu Viswambharan /*******************************************************************************
330cbd3f370SJeenu Viswambharan  * This function returns the active status of the interrupt (either because the
331cbd3f370SJeenu Viswambharan  * state is active, or active and pending).
332cbd3f370SJeenu Viswambharan  ******************************************************************************/
gicv2_get_interrupt_active(unsigned int id)333cbd3f370SJeenu Viswambharan unsigned int gicv2_get_interrupt_active(unsigned int id)
334cbd3f370SJeenu Viswambharan {
3353fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
3363fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicd_base != 0U);
337cbd3f370SJeenu Viswambharan 	assert(id <= MAX_SPI_ID);
338cbd3f370SJeenu Viswambharan 
339cbd3f370SJeenu Viswambharan 	return gicd_get_isactiver(driver_data->gicd_base, id);
340cbd3f370SJeenu Viswambharan }
341979225f4SJeenu Viswambharan 
342979225f4SJeenu Viswambharan /*******************************************************************************
343979225f4SJeenu Viswambharan  * This function enables the interrupt identified by id.
344979225f4SJeenu Viswambharan  ******************************************************************************/
gicv2_enable_interrupt(unsigned int id)345979225f4SJeenu Viswambharan void gicv2_enable_interrupt(unsigned int id)
346979225f4SJeenu Viswambharan {
3473fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
3483fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicd_base != 0U);
349979225f4SJeenu Viswambharan 	assert(id <= MAX_SPI_ID);
350979225f4SJeenu Viswambharan 
351979225f4SJeenu Viswambharan 	/*
352979225f4SJeenu Viswambharan 	 * Ensure that any shared variable updates depending on out of band
353979225f4SJeenu Viswambharan 	 * interrupt trigger are observed before enabling interrupt.
354979225f4SJeenu Viswambharan 	 */
355979225f4SJeenu Viswambharan 	dsbishst();
356979225f4SJeenu Viswambharan 	gicd_set_isenabler(driver_data->gicd_base, id);
357979225f4SJeenu Viswambharan }
358979225f4SJeenu Viswambharan 
359979225f4SJeenu Viswambharan /*******************************************************************************
360979225f4SJeenu Viswambharan  * This function disables the interrupt identified by id.
361979225f4SJeenu Viswambharan  ******************************************************************************/
gicv2_disable_interrupt(unsigned int id)362979225f4SJeenu Viswambharan void gicv2_disable_interrupt(unsigned int id)
363979225f4SJeenu Viswambharan {
3643fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
3653fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicd_base != 0U);
366979225f4SJeenu Viswambharan 	assert(id <= MAX_SPI_ID);
367979225f4SJeenu Viswambharan 
368979225f4SJeenu Viswambharan 	/*
369979225f4SJeenu Viswambharan 	 * Disable interrupt, and ensure that any shared variable updates
370979225f4SJeenu Viswambharan 	 * depending on out of band interrupt trigger are observed afterwards.
371979225f4SJeenu Viswambharan 	 */
372979225f4SJeenu Viswambharan 	gicd_set_icenabler(driver_data->gicd_base, id);
373979225f4SJeenu Viswambharan 	dsbishst();
374979225f4SJeenu Viswambharan }
375f3a86600SJeenu Viswambharan 
376f3a86600SJeenu Viswambharan /*******************************************************************************
377f3a86600SJeenu Viswambharan  * This function sets the interrupt priority as supplied for the given interrupt
378f3a86600SJeenu Viswambharan  * id.
379f3a86600SJeenu Viswambharan  ******************************************************************************/
gicv2_set_interrupt_priority(unsigned int id,unsigned int priority)380f3a86600SJeenu Viswambharan void gicv2_set_interrupt_priority(unsigned int id, unsigned int priority)
381f3a86600SJeenu Viswambharan {
3823fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
3833fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicd_base != 0U);
384f3a86600SJeenu Viswambharan 	assert(id <= MAX_SPI_ID);
385f3a86600SJeenu Viswambharan 
386f3a86600SJeenu Viswambharan 	gicd_set_ipriorityr(driver_data->gicd_base, id, priority);
387f3a86600SJeenu Viswambharan }
38874dce7faSJeenu Viswambharan 
38974dce7faSJeenu Viswambharan /*******************************************************************************
39074dce7faSJeenu Viswambharan  * This function assigns group for the interrupt identified by id. The group can
39174dce7faSJeenu Viswambharan  * be any of GICV2_INTR_GROUP*
39274dce7faSJeenu Viswambharan  ******************************************************************************/
gicv2_set_interrupt_group(unsigned int id,unsigned int group)393ab80cf35SMadhukar Pappireddy void gicv2_set_interrupt_group(unsigned int id, unsigned int group)
39474dce7faSJeenu Viswambharan {
3953fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
3963fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicd_base != 0U);
39774dce7faSJeenu Viswambharan 	assert(id <= MAX_SPI_ID);
39874dce7faSJeenu Viswambharan 
39974dce7faSJeenu Viswambharan 	/* Serialize read-modify-write to Distributor registers */
40074dce7faSJeenu Viswambharan 	spin_lock(&gic_lock);
401ab80cf35SMadhukar Pappireddy 	switch (group) {
40274dce7faSJeenu Viswambharan 	case GICV2_INTR_GROUP1:
40374dce7faSJeenu Viswambharan 		gicd_set_igroupr(driver_data->gicd_base, id);
40474dce7faSJeenu Viswambharan 		break;
40574dce7faSJeenu Viswambharan 	case GICV2_INTR_GROUP0:
40674dce7faSJeenu Viswambharan 		gicd_clr_igroupr(driver_data->gicd_base, id);
40774dce7faSJeenu Viswambharan 		break;
40874dce7faSJeenu Viswambharan 	default:
4093fea9c8bSAntonio Nino Diaz 		assert(false);
4105aa7498aSJonathan Wright 		break;
41174dce7faSJeenu Viswambharan 	}
41274dce7faSJeenu Viswambharan 	spin_unlock(&gic_lock);
41374dce7faSJeenu Viswambharan }
4148db978b5SJeenu Viswambharan 
4158db978b5SJeenu Viswambharan /*******************************************************************************
4168db978b5SJeenu Viswambharan  * This function raises the specified SGI to requested targets.
4178db978b5SJeenu Viswambharan  *
4188db978b5SJeenu Viswambharan  * The proc_num parameter must be the linear index of the target PE in the
4198db978b5SJeenu Viswambharan  * system.
4208db978b5SJeenu Viswambharan  ******************************************************************************/
gicv2_raise_sgi(int sgi_num,bool ns,int proc_num)421dcb31ff7SFlorian Lugou void gicv2_raise_sgi(int sgi_num, bool ns, int proc_num)
4228db978b5SJeenu Viswambharan {
4238db978b5SJeenu Viswambharan 	unsigned int sgir_val, target;
4248db978b5SJeenu Viswambharan 
4253fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
42620d38497Sjohpow01 	assert(proc_num >= 0);
42720d38497Sjohpow01 	assert(proc_num < (int)GICV2_MAX_TARGET_PE);
4283fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicd_base != 0U);
4298db978b5SJeenu Viswambharan 
4308db978b5SJeenu Viswambharan 	/*
4318db978b5SJeenu Viswambharan 	 * Target masks array must have been supplied, and the core position
4328db978b5SJeenu Viswambharan 	 * should be valid.
4338db978b5SJeenu Viswambharan 	 */
4343fea9c8bSAntonio Nino Diaz 	assert(driver_data->target_masks != NULL);
43520d38497Sjohpow01 	assert(proc_num < (int)driver_data->target_masks_num);
4368db978b5SJeenu Viswambharan 
4378db978b5SJeenu Viswambharan 	/* Don't raise SGI if the mask hasn't been populated */
4388db978b5SJeenu Viswambharan 	target = driver_data->target_masks[proc_num];
4393fea9c8bSAntonio Nino Diaz 	assert(target != 0U);
4408db978b5SJeenu Viswambharan 
441dcb31ff7SFlorian Lugou 	sgir_val = GICV2_SGIR_VALUE(SGIR_TGT_SPECIFIC, target, ns, sgi_num);
4428db978b5SJeenu Viswambharan 
4438db978b5SJeenu Viswambharan 	/*
4448db978b5SJeenu Viswambharan 	 * Ensure that any shared variable updates depending on out of band
4458db978b5SJeenu Viswambharan 	 * interrupt trigger are observed before raising SGI.
4468db978b5SJeenu Viswambharan 	 */
4478db978b5SJeenu Viswambharan 	dsbishst();
4488db978b5SJeenu Viswambharan 	gicd_write_sgir(driver_data->gicd_base, sgir_val);
4498db978b5SJeenu Viswambharan }
450fc529feeSJeenu Viswambharan 
451fc529feeSJeenu Viswambharan /*******************************************************************************
452fc529feeSJeenu Viswambharan  * This function sets the interrupt routing for the given SPI interrupt id.
453fc529feeSJeenu Viswambharan  * The interrupt routing is specified in routing mode. The proc_num parameter is
454fc529feeSJeenu Viswambharan  * linear index of the PE to target SPI. When proc_num < 0, the SPI may target
455fc529feeSJeenu Viswambharan  * all PEs.
456fc529feeSJeenu Viswambharan  ******************************************************************************/
gicv2_set_spi_routing(unsigned int id,int proc_num)457fc529feeSJeenu Viswambharan void gicv2_set_spi_routing(unsigned int id, int proc_num)
458fc529feeSJeenu Viswambharan {
4593fea9c8bSAntonio Nino Diaz 	unsigned int target;
460fc529feeSJeenu Viswambharan 
4613fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
4623fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicd_base != 0U);
463fc529feeSJeenu Viswambharan 
4643fea9c8bSAntonio Nino Diaz 	assert((id >= MIN_SPI_ID) && (id <= MAX_SPI_ID));
465fc529feeSJeenu Viswambharan 
466fc529feeSJeenu Viswambharan 	/*
467fc529feeSJeenu Viswambharan 	 * Target masks array must have been supplied, and the core position
468fc529feeSJeenu Viswambharan 	 * should be valid.
469fc529feeSJeenu Viswambharan 	 */
4703fea9c8bSAntonio Nino Diaz 	assert(driver_data->target_masks != NULL);
47120d38497Sjohpow01 	assert(proc_num < (int)GICV2_MAX_TARGET_PE);
47220d38497Sjohpow01 	assert(driver_data->target_masks_num < INT_MAX);
47320d38497Sjohpow01 	assert(proc_num < (int)driver_data->target_masks_num);
474fc529feeSJeenu Viswambharan 
475fc529feeSJeenu Viswambharan 	if (proc_num < 0) {
476fc529feeSJeenu Viswambharan 		/* Target all PEs */
477fc529feeSJeenu Viswambharan 		target = GIC_TARGET_CPU_MASK;
478fc529feeSJeenu Viswambharan 	} else {
479fc529feeSJeenu Viswambharan 		/* Don't route interrupt if the mask hasn't been populated */
480fc529feeSJeenu Viswambharan 		target = driver_data->target_masks[proc_num];
4813fea9c8bSAntonio Nino Diaz 		assert(target != 0U);
482fc529feeSJeenu Viswambharan 	}
483fc529feeSJeenu Viswambharan 
484fc529feeSJeenu Viswambharan 	gicd_set_itargetsr(driver_data->gicd_base, id, target);
485fc529feeSJeenu Viswambharan }
486a2816a16SJeenu Viswambharan 
487a2816a16SJeenu Viswambharan /*******************************************************************************
488a2816a16SJeenu Viswambharan  * This function clears the pending status of an interrupt identified by id.
489a2816a16SJeenu Viswambharan  ******************************************************************************/
gicv2_clear_interrupt_pending(unsigned int id)490a2816a16SJeenu Viswambharan void gicv2_clear_interrupt_pending(unsigned int id)
491a2816a16SJeenu Viswambharan {
4923fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
4933fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicd_base != 0U);
494a2816a16SJeenu Viswambharan 
495a2816a16SJeenu Viswambharan 	/* SGIs can't be cleared pending */
496a2816a16SJeenu Viswambharan 	assert(id >= MIN_PPI_ID);
497a2816a16SJeenu Viswambharan 
498a2816a16SJeenu Viswambharan 	/*
499a2816a16SJeenu Viswambharan 	 * Clear pending interrupt, and ensure that any shared variable updates
500a2816a16SJeenu Viswambharan 	 * depending on out of band interrupt trigger are observed afterwards.
501a2816a16SJeenu Viswambharan 	 */
502a2816a16SJeenu Viswambharan 	gicd_set_icpendr(driver_data->gicd_base, id);
503a2816a16SJeenu Viswambharan 	dsbishst();
504a2816a16SJeenu Viswambharan }
505a2816a16SJeenu Viswambharan 
506a2816a16SJeenu Viswambharan /*******************************************************************************
507a2816a16SJeenu Viswambharan  * This function sets the pending status of an interrupt identified by id.
508a2816a16SJeenu Viswambharan  ******************************************************************************/
gicv2_set_interrupt_pending(unsigned int id)509a2816a16SJeenu Viswambharan void gicv2_set_interrupt_pending(unsigned int id)
510a2816a16SJeenu Viswambharan {
5113fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
5123fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicd_base != 0U);
513a2816a16SJeenu Viswambharan 
514a2816a16SJeenu Viswambharan 	/* SGIs can't be cleared pending */
515a2816a16SJeenu Viswambharan 	assert(id >= MIN_PPI_ID);
516a2816a16SJeenu Viswambharan 
517a2816a16SJeenu Viswambharan 	/*
518a2816a16SJeenu Viswambharan 	 * Ensure that any shared variable updates depending on out of band
519a2816a16SJeenu Viswambharan 	 * interrupt trigger are observed before setting interrupt pending.
520a2816a16SJeenu Viswambharan 	 */
521a2816a16SJeenu Viswambharan 	dsbishst();
522a2816a16SJeenu Viswambharan 	gicd_set_ispendr(driver_data->gicd_base, id);
523a2816a16SJeenu Viswambharan }
524d55a4450SJeenu Viswambharan 
525d55a4450SJeenu Viswambharan /*******************************************************************************
526d55a4450SJeenu Viswambharan  * This function sets the PMR register with the supplied value. Returns the
527d55a4450SJeenu Viswambharan  * original PMR.
528d55a4450SJeenu Viswambharan  ******************************************************************************/
gicv2_set_pmr(unsigned int mask)529d55a4450SJeenu Viswambharan unsigned int gicv2_set_pmr(unsigned int mask)
530d55a4450SJeenu Viswambharan {
531d55a4450SJeenu Viswambharan 	unsigned int old_mask;
532d55a4450SJeenu Viswambharan 
5333fea9c8bSAntonio Nino Diaz 	assert(driver_data != NULL);
5343fea9c8bSAntonio Nino Diaz 	assert(driver_data->gicc_base != 0U);
535d55a4450SJeenu Viswambharan 
536d55a4450SJeenu Viswambharan 	old_mask = gicc_read_pmr(driver_data->gicc_base);
537d55a4450SJeenu Viswambharan 
538d55a4450SJeenu Viswambharan 	/*
539d55a4450SJeenu Viswambharan 	 * Order memory updates w.r.t. PMR write, and ensure they're visible
540d55a4450SJeenu Viswambharan 	 * before potential out of band interrupt trigger because of PMR update.
541d55a4450SJeenu Viswambharan 	 */
542d55a4450SJeenu Viswambharan 	dmbishst();
543d55a4450SJeenu Viswambharan 	gicc_write_pmr(driver_data->gicc_base, mask);
544d55a4450SJeenu Viswambharan 	dsbishst();
545d55a4450SJeenu Viswambharan 
546d55a4450SJeenu Viswambharan 	return old_mask;
547d55a4450SJeenu Viswambharan }
5484acd900dSMarcin Wojtas 
5494acd900dSMarcin Wojtas /*******************************************************************************
5504acd900dSMarcin Wojtas  * This function updates single interrupt configuration to be level/edge
5514acd900dSMarcin Wojtas  * triggered
5524acd900dSMarcin Wojtas  ******************************************************************************/
gicv2_interrupt_set_cfg(unsigned int id,unsigned int cfg)5534acd900dSMarcin Wojtas void gicv2_interrupt_set_cfg(unsigned int id, unsigned int cfg)
5544acd900dSMarcin Wojtas {
5554acd900dSMarcin Wojtas 	gicd_set_icfgr(driver_data->gicd_base, id, cfg);
5564acd900dSMarcin Wojtas }
557