• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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