| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 1 | /* |
| Boyan Karatotev | a4b3334 | 2025-06-19 16:24:29 +0100 | [diff] [blame] | 2 | * Copyright (c) 2018-2025, Arm Limited. All rights reserved. |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 3 | * |
| 4 | * SPDX-License-Identifier: BSD-3-Clause |
| 5 | */ |
| 6 | |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 7 | #include <stdbool.h> |
| 8 | |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 9 | #include <arch.h> |
| 10 | #include <arch_helpers.h> |
| 11 | #include <assert.h> |
| 12 | #include <debug.h> |
| Boyan Karatotev | a4b3334 | 2025-06-19 16:24:29 +0100 | [diff] [blame] | 13 | #include <drivers/arm/gic_v2v3_common.h> |
| Antonio Nino Diaz | 09a00ef | 2019-01-11 13:12:58 +0000 | [diff] [blame] | 14 | #include <drivers/arm/gic_v2.h> |
| 15 | #include <drivers/arm/gic_v3.h> |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 16 | #include <drivers/arm/gic_v5.h> |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 17 | |
| 18 | /* Record whether a GICv3 was detected on the system */ |
| 19 | static unsigned int gicv3_detected; |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 20 | static unsigned int gicv5_detected; |
| 21 | static bool gic_done_init; |
| 22 | |
| 23 | int arm_gic_get_version(void) |
| 24 | { |
| 25 | assert(gic_done_init); |
| 26 | |
| 27 | if (gicv3_detected) { |
| 28 | return 3; |
| 29 | } else if (gicv5_detected) { |
| 30 | return 5; |
| 31 | } else { |
| 32 | return 2; |
| 33 | } |
| 34 | } |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 35 | |
| 36 | void arm_gic_enable_interrupts_local(void) |
| 37 | { |
| 38 | if (gicv3_detected) |
| 39 | gicv3_enable_cpuif(); |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 40 | else if (gicv5_detected) |
| 41 | gicv5_enable_cpuif(); |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 42 | else |
| 43 | gicv2_enable_cpuif(); |
| 44 | } |
| 45 | |
| 46 | void arm_gic_setup_local(void) |
| 47 | { |
| 48 | if (gicv3_detected) { |
| 49 | gicv3_probe_redistif_addr(); |
| 50 | gicv3_setup_cpuif(); |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 51 | } else if (gicv5_detected) { |
| 52 | gicv5_setup_cpuif(); |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 53 | } else { |
| 54 | gicv2_probe_gic_cpu_id(); |
| 55 | gicv2_setup_cpuif(); |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | void arm_gic_disable_interrupts_local(void) |
| 60 | { |
| 61 | if (gicv3_detected) |
| 62 | gicv3_disable_cpuif(); |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 63 | else if (gicv5_detected) |
| 64 | gicv5_disable_cpuif(); |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 65 | else |
| 66 | gicv2_disable_cpuif(); |
| 67 | } |
| 68 | |
| 69 | void arm_gic_save_context_local(void) |
| 70 | { |
| 71 | if (gicv3_detected) |
| 72 | gicv3_save_cpuif_context(); |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 73 | else if (gicv5_detected) |
| 74 | gicv5_save_cpuif_context(); |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 75 | else |
| 76 | gicv2_save_cpuif_context(); |
| 77 | } |
| 78 | |
| 79 | void arm_gic_restore_context_local(void) |
| 80 | { |
| 81 | if (gicv3_detected) |
| 82 | gicv3_restore_cpuif_context(); |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 83 | else if (gicv5_detected) |
| 84 | gicv5_restore_cpuif_context(); |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 85 | else |
| 86 | gicv2_restore_cpuif_context(); |
| 87 | } |
| 88 | |
| 89 | void arm_gic_save_context_global(void) |
| 90 | { |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 91 | if (gicv3_detected) { |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 92 | gicv3_save_sgi_ppi_context(); |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 93 | } else if (gicv5_detected) { |
| 94 | /* NOP, done by EL3 */ |
| 95 | } else { |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 96 | gicv2_save_sgi_ppi_context(); |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 97 | } |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 98 | } |
| 99 | |
| 100 | void arm_gic_restore_context_global(void) |
| 101 | { |
| 102 | if (gicv3_detected) { |
| 103 | gicv3_setup_distif(); |
| 104 | gicv3_restore_sgi_ppi_context(); |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 105 | } else if (gicv5_detected) { |
| 106 | /* NOP, done by EL3 */ |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 107 | } else { |
| 108 | gicv2_setup_distif(); |
| 109 | gicv2_restore_sgi_ppi_context(); |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | void arm_gic_setup_global(void) |
| 114 | { |
| 115 | if (gicv3_detected) |
| 116 | gicv3_setup_distif(); |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 117 | else if (gicv5_detected) |
| 118 | gicv5_setup(); |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 119 | else |
| 120 | gicv2_setup_distif(); |
| 121 | } |
| 122 | |
| 123 | unsigned int arm_gic_get_intr_priority(unsigned int num) |
| 124 | { |
| 125 | if (gicv3_detected) |
| 126 | return gicv3_get_ipriorityr(num); |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 127 | /* TODO only used for SDEI, currently not supported/ported */ |
| 128 | else if (gicv5_detected) { |
| 129 | assert(0); |
| 130 | return 0; |
| 131 | } else |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 132 | return gicv2_gicd_get_ipriorityr(num); |
| 133 | } |
| 134 | |
| 135 | void arm_gic_set_intr_priority(unsigned int num, |
| 136 | unsigned int priority) |
| 137 | { |
| 138 | if (gicv3_detected) |
| 139 | gicv3_set_ipriorityr(num, priority); |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 140 | else if (gicv5_detected) |
| 141 | gicv5_set_priority(num, priority); |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 142 | else |
| 143 | gicv2_gicd_set_ipriorityr(num, priority); |
| 144 | } |
| 145 | |
| Boyan Karatotev | 6d144db | 2025-06-23 15:04:53 +0100 | [diff] [blame^] | 146 | uint32_t arm_gic_get_sgi_num(uint32_t seq_id, unsigned int core_pos) |
| 147 | { |
| 148 | if (gicv5_detected) { |
| 149 | return gicv5_get_sgi_num(seq_id, core_pos); |
| 150 | } else { |
| 151 | return gicv2v3_get_sgi_num(seq_id, core_pos); |
| 152 | } |
| 153 | } |
| 154 | |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 155 | void arm_gic_send_sgi(unsigned int sgi_id, unsigned int core_pos) |
| 156 | { |
| 157 | if (gicv3_detected) |
| 158 | gicv3_send_sgi(sgi_id, core_pos); |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 159 | else if (gicv5_detected) |
| 160 | gicv5_send_sgi(sgi_id, core_pos); |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 161 | else |
| 162 | gicv2_send_sgi(sgi_id, core_pos); |
| 163 | } |
| 164 | |
| 165 | void arm_gic_set_intr_target(unsigned int num, unsigned int core_pos) |
| 166 | { |
| 167 | if (gicv3_detected) |
| 168 | gicv3_set_intr_route(num, core_pos); |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 169 | else if (gicv5_detected) |
| 170 | gicv5_set_intr_route(num, core_pos); |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 171 | else |
| 172 | gicv2_set_itargetsr(num, core_pos); |
| 173 | } |
| 174 | |
| 175 | unsigned int arm_gic_intr_enabled(unsigned int num) |
| 176 | { |
| 177 | if (gicv3_detected) |
| 178 | return gicv3_get_isenabler(num) != 0; |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 179 | /* TODO only used for SDEI, currently not supported/ported */ |
| 180 | else if (gicv5_detected) { |
| 181 | assert(0); |
| 182 | return 0; |
| 183 | } else |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 184 | return gicv2_gicd_get_isenabler(num) != 0; |
| 185 | } |
| 186 | |
| 187 | void arm_gic_intr_enable(unsigned int num) |
| 188 | { |
| 189 | if (gicv3_detected) |
| 190 | gicv3_set_isenabler(num); |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 191 | else if (gicv5_detected) |
| 192 | gicv5_intr_enable(num); |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 193 | else |
| 194 | gicv2_gicd_set_isenabler(num); |
| 195 | } |
| 196 | |
| 197 | void arm_gic_intr_disable(unsigned int num) |
| 198 | { |
| 199 | if (gicv3_detected) |
| 200 | gicv3_set_icenabler(num); |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 201 | else if (gicv5_detected) |
| 202 | gicv5_intr_disable(num); |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 203 | else |
| 204 | gicv2_gicd_set_icenabler(num); |
| 205 | } |
| 206 | |
| 207 | unsigned int arm_gic_intr_ack(unsigned int *raw_iar) |
| 208 | { |
| 209 | assert(raw_iar); |
| 210 | |
| 211 | if (gicv3_detected) { |
| 212 | *raw_iar = gicv3_acknowledge_interrupt(); |
| 213 | return *raw_iar; |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 214 | } else if (gicv5_detected) { |
| 215 | *raw_iar = gicv5_acknowledge_interrupt(); |
| 216 | return *raw_iar; |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 217 | } else { |
| 218 | *raw_iar = gicv2_gicc_read_iar(); |
| 219 | return get_gicc_iar_intid(*raw_iar); |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | unsigned int arm_gic_is_intr_pending(unsigned int num) |
| 224 | { |
| 225 | if (gicv3_detected) |
| 226 | return gicv3_get_ispendr(num); |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 227 | else if (gicv5_detected) |
| 228 | return gicv5_is_intr_pending(num); |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 229 | else |
| 230 | return gicv2_gicd_get_ispendr(num); |
| 231 | } |
| 232 | |
| 233 | void arm_gic_intr_clear(unsigned int num) |
| 234 | { |
| 235 | if (gicv3_detected) |
| 236 | gicv3_set_icpendr(num); |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 237 | else if (gicv5_detected) |
| 238 | gicv5_intr_clear(num); |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 239 | else |
| 240 | gicv2_gicd_set_icpendr(num); |
| 241 | } |
| 242 | |
| 243 | void arm_gic_end_of_intr(unsigned int raw_iar) |
| 244 | { |
| 245 | if (gicv3_detected) |
| 246 | gicv3_end_of_interrupt(raw_iar); |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 247 | else if (gicv5_detected) |
| 248 | gicv5_end_of_interrupt(raw_iar); |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 249 | else |
| 250 | gicv2_gicc_write_eoir(raw_iar); |
| 251 | } |
| 252 | |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 253 | void arm_gic_probe(void) |
| 254 | { |
| 255 | if (is_gicv3_mode()) { |
| 256 | gicv3_detected = 1; |
| 257 | INFO("GICv3 mode detected\n"); |
| 258 | } else if (is_gicv5_mode()) { |
| 259 | gicv5_detected = 1; |
| 260 | INFO("GICv5 mode detected\n"); |
| 261 | } else { |
| 262 | INFO("GICv2 mode detected\n"); |
| 263 | } |
| 264 | |
| 265 | gic_done_init = true; |
| 266 | } |
| 267 | |
| 268 | /* to not change the API, pretend the IRS is a distributor */ |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 269 | void arm_gic_init(uintptr_t gicc_base, |
| 270 | uintptr_t gicd_base, |
| 271 | uintptr_t gicr_base) |
| 272 | { |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 273 | if (gicv3_detected) { |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 274 | gicv3_init(gicr_base, gicd_base); |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 275 | } else if (gicv5_detected) { |
| 276 | gicv5_init(gicd_base); |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 277 | } else { |
| 278 | gicv2_init(gicc_base, gicd_base); |
| 279 | } |
| Sandrine Bailleux | 3cd87d7 | 2018-10-09 11:12:55 +0200 | [diff] [blame] | 280 | } |
| Madhukar Pappireddy | c6a3abf | 2023-10-25 16:47:23 -0500 | [diff] [blame] | 281 | |
| 282 | bool arm_gic_is_espi_supported(void) |
| 283 | { |
| Boyan Karatotev | e5629bd | 2025-06-16 11:45:34 +0100 | [diff] [blame] | 284 | /* TODO only used for FFA, currently not supported/ported on GICv5 */ |
| Madhukar Pappireddy | c6a3abf | 2023-10-25 16:47:23 -0500 | [diff] [blame] | 285 | if (!gicv3_detected) { |
| 286 | return false; |
| 287 | } |
| 288 | |
| 289 | /* Check if extended SPI range is implemented. */ |
| Boyan Karatotev | aa48358 | 2025-06-20 09:07:44 +0100 | [diff] [blame] | 290 | if ((gicv3_get_gicd_typer() & TYPER_ESPI) != 0U) { |
| Madhukar Pappireddy | c6a3abf | 2023-10-25 16:47:23 -0500 | [diff] [blame] | 291 | return true; |
| 292 | } |
| 293 | |
| 294 | return false; |
| 295 | } |