blob: 786eefc1db49c6a63794e0511d7997cea56e74ed [file] [log] [blame]
Varun Wadekarb316e242015-05-19 16:48:04 +05301/*
2 * Copyright (c) 2015, 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_helpers.h>
32#include <assert.h>
Varun Wadekard3a41502015-06-16 11:23:00 +053033#include <arm_gic.h>
Varun Wadekarb316e242015-05-19 16:48:04 +053034#include <bl_common.h>
35#include <debug.h>
36#include <gic_v2.h>
37#include <interrupt_mgmt.h>
38#include <platform.h>
39#include <stdint.h>
40#include <tegra_private.h>
41#include <tegra_def.h>
42
Varun Wadekard3a41502015-06-16 11:23:00 +053043/* Value used to initialize Non-Secure IRQ priorities four at a time */
44#define GICD_IPRIORITYR_DEF_VAL \
45 (GIC_HIGHEST_NS_PRIORITY | \
46 (GIC_HIGHEST_NS_PRIORITY << 8) | \
47 (GIC_HIGHEST_NS_PRIORITY << 16) | \
48 (GIC_HIGHEST_NS_PRIORITY << 24))
49
Varun Wadekarb7b45752015-12-28 14:55:41 -080050static const unsigned int *g_irq_sec_ptr;
51static unsigned int g_num_irqs;
52
Varun Wadekarb316e242015-05-19 16:48:04 +053053/*******************************************************************************
54 * Place the cpu interface in a state where it can never make a cpu exit wfi as
55 * as result of an asserted interrupt. This is critical for powering down a cpu
56 ******************************************************************************/
57void tegra_gic_cpuif_deactivate(void)
58{
59 unsigned int val;
60
61 /* Disable secure, non-secure interrupts and disable their bypass */
62 val = gicc_read_ctlr(TEGRA_GICC_BASE);
63 val &= ~(ENABLE_GRP0 | ENABLE_GRP1);
64 val |= FIQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP0;
65 val |= IRQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP1;
66 gicc_write_ctlr(TEGRA_GICC_BASE, val);
67}
68
69/*******************************************************************************
70 * Enable secure interrupts and set the priority mask register to allow all
71 * interrupts to trickle in.
72 ******************************************************************************/
73static void tegra_gic_cpuif_setup(unsigned int gicc_base)
74{
Varun Wadekard3a41502015-06-16 11:23:00 +053075 unsigned int val;
76
77 val = ENABLE_GRP0 | ENABLE_GRP1 | FIQ_EN | FIQ_BYP_DIS_GRP0;
78 val |= IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1;
79
80 gicc_write_ctlr(gicc_base, val);
Varun Wadekarb316e242015-05-19 16:48:04 +053081 gicc_write_pmr(gicc_base, GIC_PRI_MASK);
82}
83
84/*******************************************************************************
Varun Wadekard3a41502015-06-16 11:23:00 +053085 * Per cpu gic distributor setup which will be done by all cpus after a cold
86 * boot/hotplug. This marks out the secure interrupts & enables them.
87 ******************************************************************************/
88static void tegra_gic_pcpu_distif_setup(unsigned int gicd_base)
89{
90 unsigned int index, sec_ppi_sgi_mask = 0;
91
92 assert(gicd_base);
93
94 /* Setup PPI priorities doing four at a time */
95 for (index = 0; index < 32; index += 4) {
96 gicd_write_ipriorityr(gicd_base, index,
97 GICD_IPRIORITYR_DEF_VAL);
98 }
99
100 /*
101 * Invert the bitmask to create a mask for non-secure PPIs and
102 * SGIs. Program the GICD_IGROUPR0 with this bit mask. This write will
103 * update the GICR_IGROUPR0 as well in case we are running on a GICv3
104 * system. This is critical if GICD_CTLR.ARE_NS=1.
105 */
106 gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask);
107}
108
109/*******************************************************************************
Varun Wadekarb316e242015-05-19 16:48:04 +0530110 * Global gic distributor setup which will be done by the primary cpu after a
111 * cold boot. It marks out the non secure SPIs, PPIs & SGIs and enables them.
112 * It then enables the secure GIC distributor interface.
113 ******************************************************************************/
114static void tegra_gic_distif_setup(unsigned int gicd_base)
115{
Varun Wadekarb7b45752015-12-28 14:55:41 -0800116 unsigned int index, num_ints, irq_num;
117 uint8_t target_cpus;
118 uint32_t val;
Varun Wadekarb316e242015-05-19 16:48:04 +0530119
120 /*
121 * Mark out non-secure interrupts. Calculate number of
122 * IGROUPR registers to consider. Will be equal to the
123 * number of IT_LINES
124 */
125 num_ints = gicd_read_typer(gicd_base) & IT_LINES_NO_MASK;
Varun Wadekard3a41502015-06-16 11:23:00 +0530126 num_ints = (num_ints + 1) << 5;
127 for (index = MIN_SPI_ID; index < num_ints; index += 32)
128 gicd_write_igroupr(gicd_base, index, ~0);
129
130 /* Setup SPI priorities doing four at a time */
131 for (index = MIN_SPI_ID; index < num_ints; index += 4) {
132 gicd_write_ipriorityr(gicd_base, index,
133 GICD_IPRIORITYR_DEF_VAL);
134 }
135
Varun Wadekarb7b45752015-12-28 14:55:41 -0800136 /* Configure SPI secure interrupts now */
137 if (g_irq_sec_ptr) {
138
139 /* Read the target CPU mask */
140 target_cpus = TEGRA_SEC_IRQ_TARGET_MASK & GIC_TARGET_CPU_MASK;
141
142 for (index = 0; index < g_num_irqs; index++) {
143 irq_num = g_irq_sec_ptr[index];
144
145 if (irq_num >= MIN_SPI_ID) {
146
147 /* Configure as a secure interrupt */
148 gicd_clr_igroupr(gicd_base, irq_num);
149
150 /* Configure SPI priority */
151 mmio_write_8(gicd_base + GICD_IPRIORITYR +
152 irq_num,
153 GIC_HIGHEST_SEC_PRIORITY &
154 GIC_PRI_MASK);
155
156 /* Configure as level triggered */
157 val = gicd_read_icfgr(gicd_base, irq_num);
158 val |= (3 << ((irq_num & 0xF) << 1));
159 gicd_write_icfgr(gicd_base, irq_num, val);
160
161 /* Route SPI to the target CPUs */
162 gicd_set_itargetsr(gicd_base, irq_num,
163 target_cpus);
164
165 /* Enable this interrupt */
166 gicd_set_isenabler(gicd_base, irq_num);
167 }
168 }
169 }
170
Varun Wadekard3a41502015-06-16 11:23:00 +0530171 /*
172 * Configure the SGI and PPI. This is done in a separated function
173 * because each CPU is responsible for initializing its own private
174 * interrupts.
175 */
176 tegra_gic_pcpu_distif_setup(gicd_base);
Varun Wadekarb316e242015-05-19 16:48:04 +0530177
178 /* enable distributor */
179 gicd_write_ctlr(gicd_base, ENABLE_GRP0 | ENABLE_GRP1);
180}
181
Varun Wadekarb7b45752015-12-28 14:55:41 -0800182void tegra_gic_setup(const unsigned int *irq_sec_ptr, unsigned int num_irqs)
Varun Wadekarb316e242015-05-19 16:48:04 +0530183{
Varun Wadekarb7b45752015-12-28 14:55:41 -0800184 g_irq_sec_ptr = irq_sec_ptr;
185 g_num_irqs = num_irqs;
186
Varun Wadekarb316e242015-05-19 16:48:04 +0530187 tegra_gic_cpuif_setup(TEGRA_GICC_BASE);
188 tegra_gic_distif_setup(TEGRA_GICD_BASE);
189}
Varun Wadekard3a41502015-06-16 11:23:00 +0530190
191/*******************************************************************************
192 * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
193 * The interrupt controller knows which pin/line it uses to signal a type of
194 * interrupt. This function provides a common implementation of
195 * plat_interrupt_type_to_line() in an ARM GIC environment for optional re-use
196 * across platforms. It lets the interrupt management framework determine
197 * for a type of interrupt and security state, which line should be used in the
198 * SCR_EL3 to control its routing to EL3. The interrupt line is represented as
199 * the bit position of the IRQ or FIQ bit in the SCR_EL3.
200 ******************************************************************************/
201uint32_t tegra_gic_interrupt_type_to_line(uint32_t type,
202 uint32_t security_state)
203{
204 assert(type == INTR_TYPE_S_EL1 ||
205 type == INTR_TYPE_EL3 ||
206 type == INTR_TYPE_NS);
207
208 assert(sec_state_is_valid(security_state));
209
210 /*
211 * We ignore the security state parameter under the assumption that
212 * both normal and secure worlds are using ARM GICv2. This parameter
213 * will be used when the secure world starts using GICv3.
214 */
215#if ARM_GIC_ARCH == 2
216 return gicv2_interrupt_type_to_line(TEGRA_GICC_BASE, type);
217#else
218#error "Invalid ARM GIC architecture version specified for platform port"
219#endif /* ARM_GIC_ARCH */
220}
221
222#if ARM_GIC_ARCH == 2
223/*******************************************************************************
224 * This function returns the type of the highest priority pending interrupt at
225 * the GIC cpu interface. INTR_TYPE_INVAL is returned when there is no
226 * interrupt pending.
227 ******************************************************************************/
228uint32_t tegra_gic_get_pending_interrupt_type(void)
229{
230 uint32_t id;
231
232 id = gicc_read_hppir(TEGRA_GICC_BASE) & INT_ID_MASK;
233
234 /* Assume that all secure interrupts are S-EL1 interrupts */
235 if (id < 1022)
236 return INTR_TYPE_S_EL1;
237
238 if (id == GIC_SPURIOUS_INTERRUPT)
239 return INTR_TYPE_INVAL;
240
241 return INTR_TYPE_NS;
242}
243
244/*******************************************************************************
245 * This function returns the id of the highest priority pending interrupt at
246 * the GIC cpu interface. INTR_ID_UNAVAILABLE is returned when there is no
247 * interrupt pending.
248 ******************************************************************************/
249uint32_t tegra_gic_get_pending_interrupt_id(void)
250{
251 uint32_t id;
252
253 id = gicc_read_hppir(TEGRA_GICC_BASE) & INT_ID_MASK;
254
255 if (id < 1022)
256 return id;
257
258 if (id == 1023)
259 return INTR_ID_UNAVAILABLE;
260
261 /*
262 * Find out which non-secure interrupt it is under the assumption that
263 * the GICC_CTLR.AckCtl bit is 0.
264 */
265 return gicc_read_ahppir(TEGRA_GICC_BASE) & INT_ID_MASK;
266}
267
268/*******************************************************************************
269 * This functions reads the GIC cpu interface Interrupt Acknowledge register
270 * to start handling the pending interrupt. It returns the contents of the IAR.
271 ******************************************************************************/
272uint32_t tegra_gic_acknowledge_interrupt(void)
273{
274 return gicc_read_IAR(TEGRA_GICC_BASE);
275}
276
277/*******************************************************************************
278 * This functions writes the GIC cpu interface End Of Interrupt register with
279 * the passed value to finish handling the active interrupt
280 ******************************************************************************/
281void tegra_gic_end_of_interrupt(uint32_t id)
282{
283 gicc_write_EOIR(TEGRA_GICC_BASE, id);
284}
285
286/*******************************************************************************
287 * This function returns the type of the interrupt id depending upon the group
288 * this interrupt has been configured under by the interrupt controller i.e.
289 * group0 or group1.
290 ******************************************************************************/
291uint32_t tegra_gic_get_interrupt_type(uint32_t id)
292{
293 uint32_t group;
294
295 group = gicd_get_igroupr(TEGRA_GICD_BASE, id);
296
297 /* Assume that all secure interrupts are S-EL1 interrupts */
298 if (group == GRP0)
299 return INTR_TYPE_S_EL1;
300 else
301 return INTR_TYPE_NS;
302}
303
304#else
305#error "Invalid ARM GIC architecture version specified for platform port"
306#endif /* ARM_GIC_ARCH */
307
308uint32_t plat_ic_get_pending_interrupt_id(void)
309{
310 return tegra_gic_get_pending_interrupt_id();
311}
312
313uint32_t plat_ic_get_pending_interrupt_type(void)
314{
315 return tegra_gic_get_pending_interrupt_type();
316}
317
318uint32_t plat_ic_acknowledge_interrupt(void)
319{
320 return tegra_gic_acknowledge_interrupt();
321}
322
323uint32_t plat_ic_get_interrupt_type(uint32_t id)
324{
325 return tegra_gic_get_interrupt_type(id);
326}
327
328void plat_ic_end_of_interrupt(uint32_t id)
329{
330 tegra_gic_end_of_interrupt(id);
331}
332
333uint32_t plat_interrupt_type_to_line(uint32_t type,
334 uint32_t security_state)
335{
336 return tegra_gic_interrupt_type_to_line(type, security_state);
337}