blob: 80e98ebeef0163269b8c2345aa7d48bc03b5bc4b [file] [log] [blame]
Aaron Durbin27ce0942014-09-11 16:07:02 -05001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2014 Google Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Aaron Durbin27ce0942014-09-11 16:07:02 -050014 */
15
16#include <arch/cpu.h>
17#include <arch/io.h>
18#include <console/console.h>
19#include <gic.h>
Furquan Shaikhfdb3a8d2015-10-15 15:50:30 -070020#include <stddef.h>
Aaron Durbin27ce0942014-09-11 16:07:02 -050021#include "gic.h"
22
23enum {
24 ENABLE_GRP0 = 0x1 << 0,
25 ENABLE_GRP1 = 0x1 << 1,
Joseph Lo589e63e2015-04-29 17:14:03 +080026 FIQ_BYP_DIS_GRP0 = 0x1 << 5,
27 IRQ_BYP_DIS_GRP0 = 0x1 << 6,
28 FIQ_BYP_DIS_GRP1 = 0x1 << 7,
29 IRQ_BYP_DIS_GRP1 = 0x1 << 8,
Aaron Durbin27ce0942014-09-11 16:07:02 -050030};
31
32struct gic {
33 struct gicd_mmio *gicd;
34 struct gicc_mmio *gicc;
35 size_t num_interrupts;
36 unsigned int version;
37 unsigned int security_extensions;
38};
39
40static struct gic *gic_get(void)
41{
42 static struct gic gic;
43
44 if (gic.gicd == NULL) {
45 uint32_t typer;
46
47 gic.gicd = gicd_base();
48 gic.gicc = gicc_base();
49 typer = read32(&gic.gicd->typer);
50 gic.num_interrupts = 32 * ((typer & 0x1f) + 1);
51 gic.security_extensions = !!(typer & (1 << 10));
52 gic.version = (read32(&gic.gicd->icpidr2) & 0xf0) >> 4;
53
54 printk(BIOS_DEBUG, "GICv%d - %zu ints %s GICD=%p GICC=%p\n",
55 gic.version, gic.num_interrupts,
56 gic.security_extensions ? "SecExtn" : "",
57 gic.gicd, gic.gicc);
58 }
59
60 return &gic;
61}
62
Furquan Shaikh1e2abe02015-04-13 19:57:54 -070063static inline uint32_t gic_read(uint32_t *base)
64{
65 return read32(base);
66}
67
Aaron Durbin27ce0942014-09-11 16:07:02 -050068static inline void gic_write(uint32_t *base, uint32_t val)
69{
Julius Werner2f37bd62015-02-19 14:51:15 -080070 write32(base, val);
Aaron Durbin27ce0942014-09-11 16:07:02 -050071}
72
73static void gic_write_regs(uint32_t *base, size_t num_regs, uint32_t val)
74{
75 size_t i;
76
77 for (i = 0; i < num_regs; i++)
78 gic_write(base++, val);
79}
80
81static void gic_write_banked_regs(uint32_t *base, size_t interrupts_per_reg,
82 uint32_t val)
83{
84 /* 1st 32 interrupts are banked per CPU. */
85 gic_write_regs(base, 32 / interrupts_per_reg, val);
86}
87
88void gic_init(void)
89{
90 struct gic *gic;
91 struct gicd_mmio *gicd;
92 struct gicc_mmio *gicc;
93 uint32_t cpu_mask;
94
95 gic = gic_get();
96 gicd = gic->gicd;
97 gicc = gic->gicc;
98
99 /* Enable Group 0 and Group 1 in GICD -- banked regs. */
100 gic_write(&gicd->ctlr, ENABLE_GRP0 | ENABLE_GRP1);
101
102 /* Enable Group 0 and Group 1 in GICC and enable all priroity levels. */
103 gic_write(&gicc->ctlr, ENABLE_GRP0 | ENABLE_GRP1);
104 gic_write(&gicc->pmr, 1 << 7);
105
106 cpu_mask = 1 << smp_processor_id();
107 cpu_mask |= cpu_mask << 8;
108 cpu_mask |= cpu_mask << 16;
109
110 /* Only write banked registers for secondary CPUs. */
111 if (smp_processor_id()) {
112 gic_write_banked_regs(&gicd->itargetsr[0], 4, cpu_mask);
113 /* Put interrupts into Group 1. */
114 gic_write_banked_regs(&gicd->igroupr[0], 32, ~0x0);
115 /* Allow Non-secure access to everything. */
116 gic_write_banked_regs(&gicd->nsacr[0], 16, ~0x0);
117 return;
118 }
119
120 /* All interrupts routed to processors that execute this function. */
121 gic_write_regs(&gicd->itargetsr[0], gic->num_interrupts / 4, cpu_mask);
122 /* Put all interrupts into Gropup 1. */
123 gic_write_regs(&gicd->igroupr[0], gic->num_interrupts / 32, ~0x0);
124 /* Allow Non-secure access to everything. */
125 gic_write_regs(&gicd->nsacr[0], gic->num_interrupts / 16, ~0x0);
126}
Furquan Shaikh1e2abe02015-04-13 19:57:54 -0700127
128void gic_disable(void)
129{
130 struct gic *gic;
131 struct gicc_mmio *gicc;
132
133 gic = gic_get();
134 gicc = gic->gicc;
135
136 /* Disable secure, non-secure interrupts. */
137 uint32_t val = gic_read(&gicc->ctlr);
138 val &= ~(ENABLE_GRP0 | ENABLE_GRP1);
Joseph Lo589e63e2015-04-29 17:14:03 +0800139 /*
140 * Enable the IRQ/FIQ BypassDisable bits to bypass the IRQs.
141 * So the CPU can wake up from power gating state when the GIC
142 * was disabled.
143 */
144 val |= FIQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP0 |
145 FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1;
Furquan Shaikh1e2abe02015-04-13 19:57:54 -0700146 gic_write(&gicc->ctlr, val);
147}
148
149void gic_enable(void)
150{
151 struct gic *gic;
152 struct gicc_mmio *gicc;
153
154 gic = gic_get();
155 gicc = gic->gicc;
156
157 /* Enable secure, non-secure interrupts. */
158 uint32_t val = gic_read(&gicc->ctlr);
159 val |= (ENABLE_GRP0 | ENABLE_GRP1);
160 gic_write(&gicc->ctlr, val);
161}