blob: c3dc5f65e13324a2afb2849a2d331347a134d53e [file] [log] [blame]
Varun Wadekarb316e242015-05-19 16:48:04 +05301/*
2 * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
3 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Varun Wadekarb316e242015-05-19 16:48:04 +05305 */
6
7#include <arch_helpers.h>
Isla Mitchelle3631462017-07-14 10:46:32 +01008#include <assert.h>
Varun Wadekarb316e242015-05-19 16:48:04 +05309#include <bl_common.h>
10#include <debug.h>
Varun Wadekarb316e242015-05-19 16:48:04 +053011#include <interrupt_mgmt.h>
12#include <platform.h>
13#include <stdint.h>
Varun Wadekarb316e242015-05-19 16:48:04 +053014#include <tegra_def.h>
Isla Mitchelle3631462017-07-14 10:46:32 +010015#include <tegra_private.h>
Varun Wadekarb316e242015-05-19 16:48:04 +053016
Varun Wadekard3a41502015-06-16 11:23:00 +053017/* Value used to initialize Non-Secure IRQ priorities four at a time */
18#define GICD_IPRIORITYR_DEF_VAL \
19 (GIC_HIGHEST_NS_PRIORITY | \
20 (GIC_HIGHEST_NS_PRIORITY << 8) | \
21 (GIC_HIGHEST_NS_PRIORITY << 16) | \
22 (GIC_HIGHEST_NS_PRIORITY << 24))
23
Varun Wadekarc6c386d2016-05-20 16:21:22 -070024static const irq_sec_cfg_t *g_irq_sec_ptr;
Varun Wadekarca872932017-05-25 18:06:59 -070025static uint32_t g_num_irqs;
Varun Wadekarb7b45752015-12-28 14:55:41 -080026
Varun Wadekarb316e242015-05-19 16:48:04 +053027/*******************************************************************************
28 * Place the cpu interface in a state where it can never make a cpu exit wfi as
29 * as result of an asserted interrupt. This is critical for powering down a cpu
30 ******************************************************************************/
31void tegra_gic_cpuif_deactivate(void)
32{
Varun Wadekarca872932017-05-25 18:06:59 -070033 uint32_t val;
Varun Wadekarb316e242015-05-19 16:48:04 +053034
35 /* Disable secure, non-secure interrupts and disable their bypass */
36 val = gicc_read_ctlr(TEGRA_GICC_BASE);
37 val &= ~(ENABLE_GRP0 | ENABLE_GRP1);
38 val |= FIQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP0;
39 val |= IRQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP1;
40 gicc_write_ctlr(TEGRA_GICC_BASE, val);
41}
42
43/*******************************************************************************
44 * Enable secure interrupts and set the priority mask register to allow all
45 * interrupts to trickle in.
46 ******************************************************************************/
Varun Wadekarca872932017-05-25 18:06:59 -070047static void tegra_gic_cpuif_setup(uint32_t gicc_base)
Varun Wadekarb316e242015-05-19 16:48:04 +053048{
Varun Wadekarca872932017-05-25 18:06:59 -070049 uint32_t val;
Varun Wadekard3a41502015-06-16 11:23:00 +053050
51 val = ENABLE_GRP0 | ENABLE_GRP1 | FIQ_EN | FIQ_BYP_DIS_GRP0;
52 val |= IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1;
53
54 gicc_write_ctlr(gicc_base, val);
Varun Wadekarb316e242015-05-19 16:48:04 +053055 gicc_write_pmr(gicc_base, GIC_PRI_MASK);
56}
57
58/*******************************************************************************
Varun Wadekard3a41502015-06-16 11:23:00 +053059 * Per cpu gic distributor setup which will be done by all cpus after a cold
60 * boot/hotplug. This marks out the secure interrupts & enables them.
61 ******************************************************************************/
Varun Wadekarca872932017-05-25 18:06:59 -070062static void tegra_gic_pcpu_distif_setup(uint32_t gicd_base)
Varun Wadekard3a41502015-06-16 11:23:00 +053063{
Varun Wadekarca872932017-05-25 18:06:59 -070064 uint32_t index, sec_ppi_sgi_mask = 0;
Varun Wadekard3a41502015-06-16 11:23:00 +053065
Varun Wadekarca872932017-05-25 18:06:59 -070066 assert(gicd_base != 0U);
Varun Wadekard3a41502015-06-16 11:23:00 +053067
68 /* Setup PPI priorities doing four at a time */
Varun Wadekarca872932017-05-25 18:06:59 -070069 for (index = 0U; index < 32U; index += 4U) {
Varun Wadekard3a41502015-06-16 11:23:00 +053070 gicd_write_ipriorityr(gicd_base, index,
71 GICD_IPRIORITYR_DEF_VAL);
72 }
73
74 /*
75 * Invert the bitmask to create a mask for non-secure PPIs and
76 * SGIs. Program the GICD_IGROUPR0 with this bit mask. This write will
77 * update the GICR_IGROUPR0 as well in case we are running on a GICv3
78 * system. This is critical if GICD_CTLR.ARE_NS=1.
79 */
80 gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask);
81}
82
83/*******************************************************************************
Varun Wadekarb316e242015-05-19 16:48:04 +053084 * Global gic distributor setup which will be done by the primary cpu after a
85 * cold boot. It marks out the non secure SPIs, PPIs & SGIs and enables them.
86 * It then enables the secure GIC distributor interface.
87 ******************************************************************************/
Varun Wadekarca872932017-05-25 18:06:59 -070088static void tegra_gic_distif_setup(uint32_t gicd_base)
Varun Wadekarb316e242015-05-19 16:48:04 +053089{
Varun Wadekarca872932017-05-25 18:06:59 -070090 uint32_t index, num_ints, irq_num;
Varun Wadekarb7b45752015-12-28 14:55:41 -080091 uint8_t target_cpus;
92 uint32_t val;
Varun Wadekarb316e242015-05-19 16:48:04 +053093
94 /*
95 * Mark out non-secure interrupts. Calculate number of
96 * IGROUPR registers to consider. Will be equal to the
97 * number of IT_LINES
98 */
99 num_ints = gicd_read_typer(gicd_base) & IT_LINES_NO_MASK;
Varun Wadekarca872932017-05-25 18:06:59 -0700100 num_ints = (num_ints + 1U) << 5;
101 for (index = MIN_SPI_ID; index < num_ints; index += 32U) {
102 gicd_write_igroupr(gicd_base, index, 0xFFFFFFFFU);
103 }
Varun Wadekard3a41502015-06-16 11:23:00 +0530104
105 /* Setup SPI priorities doing four at a time */
Varun Wadekarca872932017-05-25 18:06:59 -0700106 for (index = MIN_SPI_ID; index < num_ints; index += 4U) {
Varun Wadekard3a41502015-06-16 11:23:00 +0530107 gicd_write_ipriorityr(gicd_base, index,
108 GICD_IPRIORITYR_DEF_VAL);
109 }
110
Varun Wadekarb7b45752015-12-28 14:55:41 -0800111 /* Configure SPI secure interrupts now */
Varun Wadekarca872932017-05-25 18:06:59 -0700112 if (g_irq_sec_ptr != NULL) {
Varun Wadekarb7b45752015-12-28 14:55:41 -0800113
Varun Wadekarca872932017-05-25 18:06:59 -0700114 for (index = 0U; index < g_num_irqs; index++) {
115 irq_num = g_irq_sec_ptr[index].irq;
116 target_cpus = (uint8_t)g_irq_sec_ptr[index].target_cpus;
Varun Wadekarb7b45752015-12-28 14:55:41 -0800117
118 if (irq_num >= MIN_SPI_ID) {
119
120 /* Configure as a secure interrupt */
121 gicd_clr_igroupr(gicd_base, irq_num);
122
123 /* Configure SPI priority */
Varun Wadekarca872932017-05-25 18:06:59 -0700124 mmio_write_8((uint64_t)gicd_base +
125 (uint64_t)GICD_IPRIORITYR +
126 (uint64_t)irq_num,
Varun Wadekarb7b45752015-12-28 14:55:41 -0800127 GIC_HIGHEST_SEC_PRIORITY &
128 GIC_PRI_MASK);
129
130 /* Configure as level triggered */
131 val = gicd_read_icfgr(gicd_base, irq_num);
Varun Wadekarca872932017-05-25 18:06:59 -0700132 val |= (3U << ((irq_num & 0xFU) << 1U));
Varun Wadekarb7b45752015-12-28 14:55:41 -0800133 gicd_write_icfgr(gicd_base, irq_num, val);
134
135 /* Route SPI to the target CPUs */
136 gicd_set_itargetsr(gicd_base, irq_num,
137 target_cpus);
138
139 /* Enable this interrupt */
140 gicd_set_isenabler(gicd_base, irq_num);
141 }
142 }
143 }
144
Varun Wadekard3a41502015-06-16 11:23:00 +0530145 /*
146 * Configure the SGI and PPI. This is done in a separated function
147 * because each CPU is responsible for initializing its own private
148 * interrupts.
149 */
150 tegra_gic_pcpu_distif_setup(gicd_base);
Varun Wadekarb316e242015-05-19 16:48:04 +0530151
152 /* enable distributor */
153 gicd_write_ctlr(gicd_base, ENABLE_GRP0 | ENABLE_GRP1);
154}
155
Varun Wadekarca872932017-05-25 18:06:59 -0700156void tegra_gic_setup(const irq_sec_cfg_t *irq_sec_ptr, uint32_t num_irqs)
Varun Wadekarb316e242015-05-19 16:48:04 +0530157{
Varun Wadekarb7b45752015-12-28 14:55:41 -0800158 g_irq_sec_ptr = irq_sec_ptr;
159 g_num_irqs = num_irqs;
160
Varun Wadekarb316e242015-05-19 16:48:04 +0530161 tegra_gic_cpuif_setup(TEGRA_GICC_BASE);
162 tegra_gic_distif_setup(TEGRA_GICD_BASE);
163}
Varun Wadekard3a41502015-06-16 11:23:00 +0530164
165/*******************************************************************************
166 * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
167 * The interrupt controller knows which pin/line it uses to signal a type of
168 * interrupt. This function provides a common implementation of
169 * plat_interrupt_type_to_line() in an ARM GIC environment for optional re-use
170 * across platforms. It lets the interrupt management framework determine
171 * for a type of interrupt and security state, which line should be used in the
172 * SCR_EL3 to control its routing to EL3. The interrupt line is represented as
173 * the bit position of the IRQ or FIQ bit in the SCR_EL3.
174 ******************************************************************************/
Varun Wadekarca872932017-05-25 18:06:59 -0700175static uint32_t tegra_gic_interrupt_type_to_line(uint32_t type,
Varun Wadekard3a41502015-06-16 11:23:00 +0530176 uint32_t security_state)
177{
Varun Wadekarca872932017-05-25 18:06:59 -0700178 assert((type == INTR_TYPE_S_EL1) ||
179 (type == INTR_TYPE_EL3) ||
180 (type == INTR_TYPE_NS));
Varun Wadekard3a41502015-06-16 11:23:00 +0530181
182 assert(sec_state_is_valid(security_state));
183
184 /*
185 * We ignore the security state parameter under the assumption that
186 * both normal and secure worlds are using ARM GICv2. This parameter
187 * will be used when the secure world starts using GICv3.
188 */
Varun Wadekard3a41502015-06-16 11:23:00 +0530189 return gicv2_interrupt_type_to_line(TEGRA_GICC_BASE, type);
Varun Wadekard3a41502015-06-16 11:23:00 +0530190}
191
Varun Wadekard3a41502015-06-16 11:23:00 +0530192/*******************************************************************************
193 * This function returns the type of the highest priority pending interrupt at
194 * the GIC cpu interface. INTR_TYPE_INVAL is returned when there is no
195 * interrupt pending.
196 ******************************************************************************/
Varun Wadekarca872932017-05-25 18:06:59 -0700197static uint32_t tegra_gic_get_pending_interrupt_type(void)
Varun Wadekard3a41502015-06-16 11:23:00 +0530198{
199 uint32_t id;
Varun Wadekarca872932017-05-25 18:06:59 -0700200 uint32_t index;
201 uint32_t ret = INTR_TYPE_NS;
Varun Wadekard3a41502015-06-16 11:23:00 +0530202
203 id = gicc_read_hppir(TEGRA_GICC_BASE) & INT_ID_MASK;
204
Varun Wadekarc6c386d2016-05-20 16:21:22 -0700205 /* get the interrupt type */
Varun Wadekarca872932017-05-25 18:06:59 -0700206 if (id < 1022U) {
207 for (index = 0U; index < g_num_irqs; index++) {
208 if (id == g_irq_sec_ptr[index].irq) {
209 ret = g_irq_sec_ptr[index].type;
210 break;
211 }
212 }
213 } else {
214 if (id == GIC_SPURIOUS_INTERRUPT) {
215 ret = INTR_TYPE_INVAL;
Varun Wadekarc6c386d2016-05-20 16:21:22 -0700216 }
217 }
Varun Wadekard3a41502015-06-16 11:23:00 +0530218
Varun Wadekarca872932017-05-25 18:06:59 -0700219 return ret;
Varun Wadekard3a41502015-06-16 11:23:00 +0530220}
221
222/*******************************************************************************
223 * This function returns the id of the highest priority pending interrupt at
224 * the GIC cpu interface. INTR_ID_UNAVAILABLE is returned when there is no
225 * interrupt pending.
226 ******************************************************************************/
Varun Wadekarca872932017-05-25 18:06:59 -0700227static uint32_t tegra_gic_get_pending_interrupt_id(void)
Varun Wadekard3a41502015-06-16 11:23:00 +0530228{
Varun Wadekarca872932017-05-25 18:06:59 -0700229 uint32_t id, ret;
Varun Wadekard3a41502015-06-16 11:23:00 +0530230
231 id = gicc_read_hppir(TEGRA_GICC_BASE) & INT_ID_MASK;
232
Antonio Nino Diazf94e40d2017-09-14 15:57:44 +0100233 if (id < 1022U) {
Varun Wadekarca872932017-05-25 18:06:59 -0700234 ret = id;
Antonio Nino Diazf94e40d2017-09-14 15:57:44 +0100235 } else if (id == 1023U) {
236 ret = 0xFFFFFFFFU; /* INTR_ID_UNAVAILABLE */
Varun Wadekarca872932017-05-25 18:06:59 -0700237 } else {
238 /*
239 * Find out which non-secure interrupt it is under the assumption that
240 * the GICC_CTLR.AckCtl bit is 0.
241 */
242 ret = gicc_read_ahppir(TEGRA_GICC_BASE) & INT_ID_MASK;
243 }
Varun Wadekard3a41502015-06-16 11:23:00 +0530244
Varun Wadekarca872932017-05-25 18:06:59 -0700245 return ret;
Varun Wadekard3a41502015-06-16 11:23:00 +0530246}
247
248/*******************************************************************************
249 * This functions reads the GIC cpu interface Interrupt Acknowledge register
250 * to start handling the pending interrupt. It returns the contents of the IAR.
251 ******************************************************************************/
Varun Wadekarca872932017-05-25 18:06:59 -0700252static uint32_t tegra_gic_acknowledge_interrupt(void)
Varun Wadekard3a41502015-06-16 11:23:00 +0530253{
254 return gicc_read_IAR(TEGRA_GICC_BASE);
255}
256
257/*******************************************************************************
258 * This functions writes the GIC cpu interface End Of Interrupt register with
259 * the passed value to finish handling the active interrupt
260 ******************************************************************************/
Varun Wadekarca872932017-05-25 18:06:59 -0700261static void tegra_gic_end_of_interrupt(uint32_t id)
Varun Wadekard3a41502015-06-16 11:23:00 +0530262{
263 gicc_write_EOIR(TEGRA_GICC_BASE, id);
264}
265
266/*******************************************************************************
267 * This function returns the type of the interrupt id depending upon the group
268 * this interrupt has been configured under by the interrupt controller i.e.
269 * group0 or group1.
270 ******************************************************************************/
Varun Wadekarca872932017-05-25 18:06:59 -0700271static uint32_t tegra_gic_get_interrupt_type(uint32_t id)
Varun Wadekard3a41502015-06-16 11:23:00 +0530272{
273 uint32_t group;
Varun Wadekarca872932017-05-25 18:06:59 -0700274 uint32_t index;
275 uint32_t ret = INTR_TYPE_NS;
Varun Wadekard3a41502015-06-16 11:23:00 +0530276
277 group = gicd_get_igroupr(TEGRA_GICD_BASE, id);
278
Varun Wadekarc6c386d2016-05-20 16:21:22 -0700279 /* get the interrupt type */
280 if (group == GRP0) {
Varun Wadekarca872932017-05-25 18:06:59 -0700281 for (index = 0U; index < g_num_irqs; index++) {
282 if (id == g_irq_sec_ptr[index].irq) {
283 ret = g_irq_sec_ptr[index].type;
284 break;
285 }
Varun Wadekarc6c386d2016-05-20 16:21:22 -0700286 }
287 }
288
Varun Wadekarca872932017-05-25 18:06:59 -0700289 return ret;
Varun Wadekard3a41502015-06-16 11:23:00 +0530290}
291
Varun Wadekard3a41502015-06-16 11:23:00 +0530292uint32_t plat_ic_get_pending_interrupt_id(void)
293{
294 return tegra_gic_get_pending_interrupt_id();
295}
296
297uint32_t plat_ic_get_pending_interrupt_type(void)
298{
299 return tegra_gic_get_pending_interrupt_type();
300}
301
302uint32_t plat_ic_acknowledge_interrupt(void)
303{
304 return tegra_gic_acknowledge_interrupt();
305}
306
307uint32_t plat_ic_get_interrupt_type(uint32_t id)
308{
309 return tegra_gic_get_interrupt_type(id);
310}
311
312void plat_ic_end_of_interrupt(uint32_t id)
313{
314 tegra_gic_end_of_interrupt(id);
315}
316
317uint32_t plat_interrupt_type_to_line(uint32_t type,
318 uint32_t security_state)
319{
320 return tegra_gic_interrupt_type_to_line(type, security_state);
321}