1 /*
2 * Copyright (c) 2023 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
3 * Licensed under the Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 * http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9 * PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 */
12
13 #include <arch/tools.h>
14 #include <arch/mmu.h>
15 #include <arch/machine/smp.h>
16 #include <common/types.h>
17 #include <common/macro.h>
18 #include <mm/mm.h>
19
20 /* Maximum number of interrups a GIC can support */
21 #define GIC_MAX_INTS 1020
22
23 /* Number of interrupts in one register */
24 #define NUM_INTS_PER_REG 32
25
26 /* Offsets from gic.gicd_base */
27 #define GICD_CTLR (0x000)
28 #define GICD_TYPER (0x004)
29 #define GICD_IGROUPR(n) (0x080 + (n)*4)
30 #define GICD_ISENABLER(n) (0x100 + (n)*4)
31 #define GICD_ICENABLER(n) (0x180 + (n)*4)
32 #define GICD_ISPENDR(n) (0x200 + (n)*4)
33 #define GICD_ICPENDR(n) (0x280 + (n)*4)
34 #define GICD_IPRIORITYR(n) (0x400 + (n)*4)
35 #define GICD_ITARGETSR(n) (0x800 + (n)*4)
36 #define GICD_IGROUPMODR(n) (0xd00 + (n)*4)
37 #define GICD_SGIR (0xF00)
38
39 #define GICD_CTLR_ENABLEGRP1S (1 << 2)
40
read_icc_ctlr(void)41 static inline u32 read_icc_ctlr(void)
42 {
43 u64 val64 = 0;
44 asm volatile("mrs %0, "
45 "S3_0_C12_C12_4"
46 : "=r"(val64));
47 return val64;
48 }
49
write_icc_ctlr(u32 val)50 static inline void write_icc_ctlr(u32 val)
51 {
52 u64 val64 = val;
53 asm volatile("msr "
54 "S3_0_C12_C12_4"
55 ", %0"
56 :
57 : "r"(val64));
58 }
59
write_icc_pmr(u32 val)60 static inline void write_icc_pmr(u32 val)
61 {
62 u64 val64 = val;
63 asm volatile("msr "
64 "S3_0_C4_C6_0"
65 ", %0"
66 :
67 : "r"(val64));
68 }
69
write_icc_igrpen1(u32 val)70 static inline void write_icc_igrpen1(u32 val)
71 {
72 u64 val64 = val;
73 asm volatile("msr "
74 "S3_0_C12_C12_7"
75 ", %0"
76 :
77 : "r"(val64));
78 }
79
set32(vaddr_t addr,u32 set_mask)80 static inline void set32(vaddr_t addr, u32 set_mask)
81 {
82 put32(addr, get32(addr) | set_mask);
83 }
84
probe_max_it(vaddr_t gicd_base)85 static size_t probe_max_it(vaddr_t gicd_base)
86 {
87 int i;
88 u32 old_ctlr;
89 size_t ret = 0;
90 const size_t max_regs =
91 ((GIC_MAX_INTS + NUM_INTS_PER_REG - 1) / NUM_INTS_PER_REG) - 1;
92
93 /*
94 * Probe which interrupt number is the largest.
95 */
96 old_ctlr = read_icc_ctlr();
97 write_icc_ctlr(0);
98 for (i = max_regs; i >= 0; i--) {
99 u32 old_reg;
100 u32 reg;
101 int b;
102
103 old_reg = get32(gicd_base + GICD_ISENABLER(i));
104 put32(gicd_base + GICD_ISENABLER(i), 0xffffffff);
105 reg = get32(gicd_base + GICD_ISENABLER(i));
106 put32(gicd_base + GICD_ICENABLER(i), ~old_reg);
107 for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) {
108 if ((u32)BIT(b) & reg) {
109 ret = i * NUM_INTS_PER_REG + b;
110 goto out;
111 }
112 }
113 }
114 out:
115 write_icc_ctlr(old_ctlr);
116 return ret;
117 }
118
__plat_interrupt_init_percpu(vaddr_t gicd_base)119 void __plat_interrupt_init_percpu(vaddr_t gicd_base)
120 {
121 /* per-CPU interrupts config:
122 * ID0-ID7(SGI) for Non-secure interrupts
123 * ID8-ID15(SGI) for Secure interrupts.
124 * All PPI config as Non-secure interrupts.
125 */
126 put32(gicd_base + GICD_IGROUPR(0), 0xffff00ff);
127
128 /* Set the priority mask to permit Non-secure interrupts, and to
129 * allow the Non-secure world to adjust the priority mask itself
130 */
131 write_icc_pmr(0x80);
132 write_icc_igrpen1(1);
133 }
134
__plat_interrupt_init(vaddr_t gicd_base)135 void __plat_interrupt_init(vaddr_t gicd_base)
136 {
137 size_t n, max_it;
138
139 max_it = probe_max_it(gicd_base);
140
141 for (n = 0; n <= max_it / NUM_INTS_PER_REG; n++) {
142 /* Disable interrupts */
143 put32(gicd_base + GICD_ICENABLER(n), 0xffffffff);
144
145 /* Make interrupts non-pending */
146 put32(gicd_base + GICD_ICPENDR(n), 0xffffffff);
147
148 /* Mark interrupts non-secure */
149 if (n == 0) {
150 /* per-CPU inerrupts config:
151 * ID0-ID7(SGI) for Non-secure interrupts
152 * ID8-ID15(SGI) for Secure interrupts.
153 * All PPI config as Non-secure interrupts.
154 */
155 put32(gicd_base + GICD_IGROUPR(n), 0xffff00ff);
156 } else {
157 put32(gicd_base + GICD_IGROUPR(n), 0xffffffff);
158 }
159 }
160
161 write_icc_pmr(0x80);
162 write_icc_igrpen1(1);
163 set32(gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S);
164 }
165
plat_interrupt_init(void)166 void plat_interrupt_init(void)
167 {
168 vaddr_t gicd_base;
169
170 gicd_base = phys_to_virt(get_gicd_base());
171
172 if (smp_get_cpu_id() == 0) {
173 __plat_interrupt_init(gicd_base);
174 } else {
175 __plat_interrupt_init_percpu(gicd_base);
176 }
177 }
178
plat_send_ipi(u32 cpu,u32 ipi)179 void plat_send_ipi(u32 cpu, u32 ipi)
180 {
181 }
182
plat_enable_irqno(int irq)183 void plat_enable_irqno(int irq)
184 {
185 }
186
plat_disable_irqno(int irq)187 void plat_disable_irqno(int irq)
188 {
189 }
190
plat_ack_irq(int irq)191 void plat_ack_irq(int irq)
192 {
193 }
194
plat_handle_irq(void)195 void plat_handle_irq(void)
196 {
197 }
198