blob: 49299e751a0d6fa93494c9f8646b24bc78d69701 [file] [log] [blame]
Amol Jadidb1edb32011-07-18 14:24:46 -07001/*
2 * Copyright (c) 2008, Google Inc.
3 * All rights reserved.
4 *
Aparna Mallavarapu18de8f02014-06-16 20:03:31 +05305 * Copyright (c) 2009-2011,2014, The Linux Foundation. All rights reserved.
Amol Jadidb1edb32011-07-18 14:24:46 -07006 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google, Inc. nor the names of its contributors
17 * may be used to endorse or promote products derived from this
18 * software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include <reg.h>
Sridhar Parasuram1ed164d2014-09-25 18:04:34 -070035#include <bits.h>
Amol Jadidb1edb32011-07-18 14:24:46 -070036#include <debug.h>
37#include <arch/arm.h>
38#include <kernel/thread.h>
39#include <platform/irqs.h>
40#include <qgic.h>
41
42static struct ihandler handler[NR_IRQS];
43
Aparna Mallavarapu18de8f02014-06-16 20:03:31 +053044static uint8_t qgic_get_cpumask()
45{
46 uint32_t mask=0, i;
47
48 /* Fetch the CPU MASK from the SGI/PPI reg */
49 for (i=0; i < 32; i += 4) {
50 mask = readl(GIC_DIST_TARGET + i);
51 mask |= mask >> 16;
52 mask |= mask >> 8;
53 if (mask)
54 break;
55 }
56
57 if (!mask)
58 dprintf(CRITICAL, "GIC CPU mask not found\n");
59
60 return mask;
61}
62
Amol Jadidb1edb32011-07-18 14:24:46 -070063/* Intialize distributor */
64static void qgic_dist_init(void)
65{
66 uint32_t i;
67 uint32_t num_irq = 0;
Aparna Mallavarapu18de8f02014-06-16 20:03:31 +053068 uint32_t cpumask;
69
70 cpumask = qgic_get_cpumask();
Amol Jadidb1edb32011-07-18 14:24:46 -070071
72 cpumask |= cpumask << 8;
73 cpumask |= cpumask << 16;
74
75 /* Disabling GIC */
76 writel(0, GIC_DIST_CTRL);
77
78 /*
79 * Find out how many interrupts are supported.
80 */
81 num_irq = readl(GIC_DIST_CTR) & 0x1f;
82 num_irq = (num_irq + 1) * 32;
83
84 /* Set each interrupt line to use N-N software model
85 * and edge sensitive, active high
86 */
Ajay Dudanib01e5062011-12-03 23:23:42 -080087 for (i = 32; i < num_irq; i += 16)
88 writel(0xffffffff, GIC_DIST_CONFIG + i * 4 / 16);
Amol Jadidb1edb32011-07-18 14:24:46 -070089
90 writel(0xffffffff, GIC_DIST_CONFIG + 4);
91
92 /* Set up interrupts for this CPU */
93 for (i = 32; i < num_irq; i += 4)
94 writel(cpumask, GIC_DIST_TARGET + i * 4 / 4);
95
Ajay Dudanib01e5062011-12-03 23:23:42 -080096 /* Set priority of all interrupts */
Amol Jadidb1edb32011-07-18 14:24:46 -070097
98 /*
99 * In bootloader we dont care about priority so
100 * setting up equal priorities for all
101 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800102 for (i = 0; i < num_irq; i += 4)
103 writel(0xa0a0a0a0, GIC_DIST_PRI + i * 4 / 4);
Amol Jadidb1edb32011-07-18 14:24:46 -0700104
Ajay Dudanib01e5062011-12-03 23:23:42 -0800105 /* Disabling interrupts */
106 for (i = 0; i < num_irq; i += 32)
107 writel(0xffffffff, GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
Amol Jadidb1edb32011-07-18 14:24:46 -0700108
109 writel(0x0000ffff, GIC_DIST_ENABLE_SET);
110
Ajay Dudanib01e5062011-12-03 23:23:42 -0800111 /*Enabling GIC */
Amol Jadidb1edb32011-07-18 14:24:46 -0700112 writel(1, GIC_DIST_CTRL);
113}
114
115/* Intialize cpu specific controller */
116static void qgic_cpu_init(void)
117{
118 writel(0xf0, GIC_CPU_PRIMASK);
119 writel(1, GIC_CPU_CTRL);
120}
121
122/* Initialize QGIC. Called from platform specific init code */
123void qgic_init(void)
124{
125 qgic_dist_init();
126 qgic_cpu_init();
127}
128
129/* IRQ handler */
Channagoud Kadabi81ba1102011-10-01 16:37:59 +0530130enum handler_return gic_platform_irq(struct arm_iframe *frame)
Amol Jadidb1edb32011-07-18 14:24:46 -0700131{
132 uint32_t num;
133 enum handler_return ret;
134
135 num = readl(GIC_CPU_INTACK);
Lijuan Gaoc19e19f2014-07-17 18:38:53 +0800136 if (num >= NR_IRQS)
Amol Jadidb1edb32011-07-18 14:24:46 -0700137 return 0;
138
139 ret = handler[num].func(handler[num].arg);
140 writel(num, GIC_CPU_EOI);
141
142 return ret;
143}
144
145/* FIQ handler */
Channagoud Kadabi81ba1102011-10-01 16:37:59 +0530146void gic_platform_fiq(struct arm_iframe *frame)
Amol Jadidb1edb32011-07-18 14:24:46 -0700147{
148 PANIC_UNIMPLEMENTED;
149}
150
151/* Mask interrupt */
Channagoud Kadabi81ba1102011-10-01 16:37:59 +0530152status_t gic_mask_interrupt(unsigned int vector)
Amol Jadidb1edb32011-07-18 14:24:46 -0700153{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800154 uint32_t reg = GIC_DIST_ENABLE_CLEAR + (vector / 32) * 4;
Amol Jadidb1edb32011-07-18 14:24:46 -0700155 uint32_t bit = 1 << (vector & 31);
156
157 writel(bit, reg);
158
159 return 0;
160}
161
162/* Un-mask interrupt */
Channagoud Kadabi81ba1102011-10-01 16:37:59 +0530163status_t gic_unmask_interrupt(unsigned int vector)
Amol Jadidb1edb32011-07-18 14:24:46 -0700164{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800165 uint32_t reg = GIC_DIST_ENABLE_SET + (vector / 32) * 4;
Amol Jadidb1edb32011-07-18 14:24:46 -0700166 uint32_t bit = 1 << (vector & 31);
167
168 writel(bit, reg);
169
170 return 0;
171}
172
173/* Register interrupt handler */
Channagoud Kadabi81ba1102011-10-01 16:37:59 +0530174void gic_register_int_handler(unsigned int vector, int_handler func, void *arg)
Amol Jadidb1edb32011-07-18 14:24:46 -0700175{
176 ASSERT(vector < NR_IRQS);
177
178 enter_critical_section();
179 handler[vector].func = func;
180 handler[vector].arg = arg;
181 exit_critical_section();
182}
Sridhar Parasuram1ed164d2014-09-25 18:04:34 -0700183
184void qgic_change_interrupt_cfg(uint32_t spi_number, uint8_t type)
185{
186 uint32_t register_number, register_address, bit_number, value;
187 register_number = spi_number >> 4; // r = n DIV 16
188 bit_number = (spi_number % 16) << 1; // b = (n MOD 16) * 2
189 value = readl(GIC_DIST_CONFIG + (register_number << 2));
190 // there are two bits per register to indicate the level
191 if (type == INTERRUPT_LVL_N_TO_N)
192 value &= ~(BIT(bit_number)|BIT(bit_number+1)); // 0x0 0x0
193 else if (type == INTERRUPT_LVL_1_TO_N)
194 value = (value & ~BIT(bit_number+1)) | BIT(bit_number); // 0x0 0x1
195 else if (type == INTERRUPT_EDGE_N_TO_N)
196 value = BIT(bit_number+1) | (value & ~BIT(bit_number));// 0x1 0x0
197 else if (type == INTERRUPT_EDGE_1_TO_N)
198 value |= (BIT(bit_number)|BIT(bit_number+1)); // 0x1 0x1
199 else
200 dprintf(CRITICAL, "Invalid interrupt type change requested\n");
201 register_address = GIC_DIST_CONFIG + (register_number << 2);
202 writel(value, register_address);
203}