blob: 7abb5a1c11222f20fd93642ce765a82c9017dfaa [file] [log] [blame]
Channagoud Kadabie240b702014-06-19 12:14:44 -07001/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Fundation, Inc. nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30#include <reg.h>
31#include <bits.h>
32#include <arch/arm.h>
33#include <kernel/thread.h>
34#include <platform/irqs.h>
35#include <platform/iomap.h>
36#include <qgic.h>
37#include <debug.h>
38
39static struct ihandler handler[NR_IRQS];
40
41/* Intialize distributor */
42void qgic_dist_config(uint32_t num_irq)
43{
44 uint32_t i;
45
46 /* Set each interrupt line to use N-N software model
47 * and edge sensitive, active high
48 */
49 for (i = 32; i < num_irq; i += 16)
50 writel(0xffffffff, GIC_DIST_CONFIG + i * 4 / 16);
51
52 writel(0xffffffff, GIC_DIST_CONFIG + 4);
53
54 /* Set priority of all interrupts */
55
56 /*
57 * In bootloader we dont care about priority so
58 * setting up equal priorities for all
59 */
60 for (i = 0; i < num_irq; i += 4)
61 writel(0xa0a0a0a0, GIC_DIST_PRI + i * 4 / 4);
62
63 /* Disabling interrupts */
64 for (i = 0; i < num_irq; i += 32)
65 writel(0xffffffff, GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
66
67 writel(0x0000ffff, GIC_DIST_ENABLE_SET);
68}
69
70/* Initialize QGIC. Called from platform specific init code */
71void qgic_init(void)
72{
73 qgic_dist_init();
74 qgic_cpu_init();
75}
76
77/* IRQ handler */
78enum handler_return gic_platform_irq(struct arm_iframe *frame)
79{
80 uint32_t num;
81 enum handler_return ret;
82
83 /* Read the interrupt number to be served*/
84 num = qgic_read_iar();
85
86 if (num >= NR_IRQS)
87 return 0;
88
89 ret = handler[num].func(handler[num].arg);
90
91 /* End of interrupt */
92 qgic_write_eoi(num);
93
94 return ret;
95}
96
97/* FIQ handler */
98void gic_platform_fiq(struct arm_iframe *frame)
99{
100 PANIC_UNIMPLEMENTED;
101}
102
103/* Mask interrupt */
104status_t gic_mask_interrupt(unsigned int vector)
105{
106 uint32_t reg = GIC_DIST_ENABLE_CLEAR + (vector / 32) * 4;
107 uint32_t bit = 1 << (vector & 31);
108
109 writel(bit, reg);
110
111 return 0;
112}
113
114/* Un-mask interrupt */
115status_t gic_unmask_interrupt(unsigned int vector)
116{
117 uint32_t reg = GIC_DIST_ENABLE_SET + (vector / 32) * 4;
118 uint32_t bit = 1 << (vector & 31);
119
120 writel(bit, reg);
121
122 return 0;
123}
124
125/* Register interrupt handler */
126void gic_register_int_handler(unsigned int vector, int_handler func, void *arg)
127{
128 ASSERT(vector < NR_IRQS);
129
130 enter_critical_section();
131 handler[vector].func = func;
132 handler[vector].arg = arg;
133 exit_critical_section();
134}
135
136void qgic_change_interrupt_cfg(uint32_t spi_number, uint8_t type)
137{
138 uint32_t register_number, register_address, bit_number, value;
139 register_number = spi_number >> 4; // r = n DIV 16
140 bit_number = (spi_number % 16) << 1; // b = (n MOD 16) * 2
141 value = readl(GIC_DIST_CONFIG + (register_number << 2));
142 // there are two bits per register to indicate the level
143 if (type == INTERRUPT_LVL_N_TO_N)
144 value &= ~(BIT(bit_number)|BIT(bit_number+1)); // 0x0 0x0
145 else if (type == INTERRUPT_LVL_1_TO_N)
146 value = (value & ~BIT(bit_number+1)) | BIT(bit_number); // 0x0 0x1
147 else if (type == INTERRUPT_EDGE_N_TO_N)
148 value = BIT(bit_number+1) | (value & ~BIT(bit_number));// 0x1 0x0
149 else if (type == INTERRUPT_EDGE_1_TO_N)
150 value |= (BIT(bit_number)|BIT(bit_number+1)); // 0x1 0x1
151 else
152 dprintf(CRITICAL, "Invalid interrupt type change requested\n");
153 register_address = GIC_DIST_CONFIG + (register_number << 2);
154 writel(value, register_address);
155}