1 /* 2 * (C) Copyright 2017 Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <asm/gic.h> 9 #include <config.h> 10 #include "irq-internal.h" 11 12 #define gicd_readl(offset) readl((void *)GICD_BASE + (offset)) 13 #define gicc_readl(offset) readl((void *)GICC_BASE + (offset)) 14 #define gicd_writel(v, offset) writel(v, (void *)GICD_BASE + (offset)) 15 #define gicc_writel(v, offset) writel(v, (void *)GICC_BASE + (offset)) 16 17 /* 64-bit write */ 18 #define gicd_writeq(v, offset) writeq(v, (void *)GICD_BASE + (offset)) 19 20 #define IRQ_REG_X4(irq) (4 * ((irq) / 4)) 21 #define IRQ_REG_X16(irq) (4 * ((irq) / 16)) 22 #define IRQ_REG_X32(irq) (4 * ((irq) / 32)) 23 #define IRQ_REG_X4_OFFSET(irq) ((irq) % 4) 24 #define IRQ_REG_X16_OFFSET(irq) ((irq) % 16) 25 #define IRQ_REG_X32_OFFSET(irq) ((irq) % 32) 26 27 #define MPIDR_CPU_MASK 0xff 28 29 #define IROUTER_IRM_SHIFT 31 30 #define IROUTER_IRM_MASK 0x1 31 #define gicd_irouter_val_from_mpidr(mpidr, irm) \ 32 ((mpidr & ~(0xff << 24)) | \ 33 (irm & IROUTER_IRM_MASK) << IROUTER_IRM_SHIFT) 34 35 typedef enum INT_TRIG { 36 INT_LEVEL_TRIGGER, 37 INT_EDGE_TRIGGER 38 } eINT_TRIG; 39 40 struct gic_dist_data { 41 uint32_t ctlr; 42 uint32_t icfgr[DIV_ROUND_UP(1020, 16)]; 43 uint32_t itargetsr[DIV_ROUND_UP(1020, 4)]; 44 uint32_t ipriorityr[DIV_ROUND_UP(1020, 4)]; 45 uint32_t igroupr[DIV_ROUND_UP(1020, 32)]; 46 uint32_t ispendr[DIV_ROUND_UP(1020, 32)]; 47 uint32_t isenabler[DIV_ROUND_UP(1020, 32)]; 48 }; 49 50 struct gic_cpu_data { 51 uint32_t ctlr; 52 uint32_t pmr; 53 }; 54 55 static struct gic_dist_data gicd_save; 56 static struct gic_cpu_data gicc_save; 57 58 static inline void int_set_prio_filter(u32 priority) 59 { 60 gicc_writel(priority & 0xff, GICC_PMR); 61 } 62 63 static inline void int_enable_distributor(void) 64 { 65 u32 val; 66 67 val = gicd_readl(GICD_CTLR); 68 val |= 0x01; 69 gicd_writel(val, GICD_CTLR); 70 } 71 72 static inline void int_disable_distributor(void) 73 { 74 u32 val; 75 76 val = gicd_readl(GICD_CTLR); 77 val &= ~0x01; 78 gicd_writel(val, GICD_CTLR); 79 } 80 81 static inline void int_enable_secure_signal(void) 82 { 83 u32 val; 84 85 val = gicc_readl(GICC_CTLR); 86 val |= 0x01; 87 gicc_writel(val, GICC_CTLR); 88 } 89 90 static inline void int_disable_secure_signal(void) 91 { 92 u32 val; 93 94 val = gicc_readl(GICC_CTLR); 95 val &= ~0x01; 96 gicc_writel(val, GICC_CTLR); 97 } 98 99 static inline void int_enable_nosecure_signal(void) 100 { 101 u32 val; 102 103 val = gicc_readl(GICC_CTLR); 104 val |= 0x02; 105 gicc_writel(val, GICC_CTLR); 106 } 107 108 static inline void int_disable_nosecure_signal(void) 109 { 110 u32 val; 111 112 val = gicc_readl(GICC_CTLR); 113 val &= ~0x02; 114 gicc_writel(val, GICC_CTLR); 115 } 116 117 static int gic_irq_set_trigger(int irq, eINT_TRIG trig) 118 { 119 u32 val; 120 121 if (trig == INT_LEVEL_TRIGGER) { 122 val = gicd_readl(GICD_ICFGR + IRQ_REG_X16(irq)); 123 val &= ~(1 << (2 * IRQ_REG_X16_OFFSET(irq) + 1)); 124 gicd_writel(val, GICD_ICFGR + IRQ_REG_X16(irq)); 125 } else { 126 val = gicd_readl(GICD_ICFGR + IRQ_REG_X16(irq)); 127 val |= (1 << (2 * IRQ_REG_X16_OFFSET(irq) + 1)); 128 gicd_writel(val, GICD_ICFGR + IRQ_REG_X16(irq)); 129 } 130 131 return 0; 132 } 133 134 static int gic_irq_enable(int irq) 135 { 136 #ifdef CONFIG_GICV2 137 u32 val, cpu_mask; 138 u32 shift = (irq % 4) * 8; 139 140 if (irq >= PLATFORM_GIC_MAX_IRQ) 141 return -EINVAL; 142 143 /* set enable */ 144 val = gicd_readl(GICD_ISENABLERn + IRQ_REG_X32(irq)); 145 val |= 1 << IRQ_REG_X32_OFFSET(irq); 146 gicd_writel(val, GICD_ISENABLERn + IRQ_REG_X32(irq)); 147 148 /* set target */ 149 cpu_mask = 1 << (read_mpidr() & MPIDR_CPU_MASK); 150 val = gicd_readl(GICD_ITARGETSRn + IRQ_REG_X4(irq)); 151 val &= ~(0xFF << shift); 152 val |= (cpu_mask << shift); 153 gicd_writel(val, GICD_ITARGETSRn + IRQ_REG_X4(irq)); 154 #else 155 u32 val; 156 u64 affinity_val; 157 158 /* set enable */ 159 val = gicd_readl(GICD_ISENABLERn + IRQ_REG_X32(irq)); 160 val |= 1 << IRQ_REG_X32_OFFSET(irq); 161 gicd_writel(val, GICD_ISENABLERn + IRQ_REG_X32(irq)); 162 163 /* set itouter(target) */ 164 affinity_val = gicd_irouter_val_from_mpidr(read_mpidr(), 0); 165 gicd_writeq(affinity_val, GICD_IROUTERn + (irq << 3)); 166 #endif 167 168 return 0; 169 } 170 171 static int gic_irq_disable(int irq) 172 { 173 gicd_writel(1 << IRQ_REG_X32_OFFSET(irq), 174 GICD_ICENABLERn + IRQ_REG_X32(irq)); 175 176 return 0; 177 } 178 179 /* 180 * irq_set_type - set the irq trigger type for an irq 181 * 182 * @irq: irq number 183 * @type: IRQ_TYPE_{LEVEL,EDGE}_* value - see asm/arch/irq.h 184 */ 185 static int gic_irq_set_type(int irq, unsigned int type) 186 { 187 unsigned int int_type; 188 189 switch (type) { 190 case IRQ_TYPE_EDGE_RISING: 191 case IRQ_TYPE_EDGE_FALLING: 192 int_type = 0x1; 193 break; 194 case IRQ_TYPE_LEVEL_HIGH: 195 case IRQ_TYPE_LEVEL_LOW: 196 int_type = 0x0; 197 break; 198 default: 199 return -EINVAL; 200 } 201 202 gic_irq_set_trigger(irq, int_type); 203 204 return 0; 205 } 206 207 static void gic_irq_eoi(int irq) 208 { 209 #ifdef CONFIG_GICV2 210 gicc_writel(irq, GICC_EOIR); 211 #else 212 asm volatile("msr " __stringify(ICC_EOIR1_EL1) ", %0" : : "r" ((u64)irq)); 213 asm volatile("msr " __stringify(ICC_DIR_EL1) ", %0" : : "r" ((u64)irq)); 214 isb(); 215 #endif 216 } 217 218 static int gic_irq_get(void) 219 { 220 #ifdef CONFIG_GICV2 221 return gicc_readl(GICC_IAR) & 0x3fff; /* bit9 - bit0 */ 222 #else 223 u64 irqstat; 224 225 asm volatile("mrs %0, " __stringify(ICC_IAR1_EL1) : "=r" (irqstat)); 226 return (u32)irqstat & 0x3ff; 227 #endif 228 } 229 230 static int gic_irq_suspend(void) 231 { 232 int irq_nr, i, irq; 233 #ifndef CONFIG_GICV2 234 u32 reg; 235 #endif 236 /* irq nr */ 237 irq_nr = ((gicd_readl(GICD_TYPER) & 0x1f) + 1) * 32; 238 if (irq_nr > 1020) 239 irq_nr = 1020; 240 241 /* GICC save */ 242 #ifdef CONFIG_GICV2 243 gicc_save.ctlr = gicc_readl(GICC_CTLR); 244 gicc_save.pmr = gicc_readl(GICC_PMR); 245 #else 246 asm volatile("mrs %0, " __stringify(ICC_CTLR_EL1) : "=r" (reg)); 247 gicc_save.ctlr = reg; 248 asm volatile("mrs %0, " __stringify(ICC_PMR_EL1) : "=r" (reg)); 249 gicc_save.pmr = reg; 250 #endif 251 252 /* GICD save */ 253 gicd_save.ctlr = gicd_readl(GICD_CTLR); 254 255 for (i = 0, irq = 0; irq < irq_nr; irq += 16) 256 gicd_save.icfgr[i++] = 257 gicd_readl(GICD_ICFGR + IRQ_REG_X16(irq)); 258 259 for (i = 0, irq = 0; irq < irq_nr; irq += 4) 260 gicd_save.itargetsr[i++] = 261 gicd_readl(GICD_ITARGETSRn + IRQ_REG_X4(irq)); 262 263 for (i = 0, irq = 0; irq < irq_nr; irq += 4) 264 gicd_save.ipriorityr[i++] = 265 gicd_readl(GICD_IPRIORITYRn + IRQ_REG_X4(irq)); 266 267 for (i = 0, irq = 0; irq < irq_nr; irq += 32) 268 gicd_save.igroupr[i++] = 269 gicd_readl(GICD_IGROUPRn + IRQ_REG_X32(irq)); 270 271 for (i = 0, irq = 0; irq < irq_nr; irq += 32) 272 gicd_save.ispendr[i++] = 273 gicd_readl(GICD_ISPENDRn + IRQ_REG_X32(irq)); 274 275 for (i = 0, irq = 0; irq < irq_nr; irq += 32) 276 gicd_save.isenabler[i++] = 277 gicd_readl(GICD_ISENABLERn + IRQ_REG_X32(irq)); 278 279 dsb(); 280 281 return 0; 282 } 283 284 static int gic_irq_resume(void) 285 { 286 int irq_nr, i, irq; 287 #ifndef CONFIG_GICV2 288 u32 reg; 289 #endif 290 irq_nr = ((gicd_readl(GICD_TYPER) & 0x1f) + 1) * 32; 291 if (irq_nr > 1020) 292 irq_nr = 1020; 293 294 /* Disable ctrl register */ 295 #ifdef CONFIG_GICV2 296 gicc_writel(0, GICC_CTLR); 297 #else 298 reg = 0; 299 asm volatile("msr " __stringify(ICC_CTLR_EL1) ", %0" : : "r" (reg)); 300 #endif 301 gicd_writel(0, GICD_CTLR); 302 dsb(); 303 304 /* Clear all interrupt */ 305 for (i = 0, irq = 0; irq < irq_nr; irq += 32) 306 gicd_writel(0xffffffff, 307 GICD_ICENABLERn + IRQ_REG_X32(irq)); 308 309 for (i = 0, irq = 0; irq < irq_nr; irq += 16) 310 gicd_writel(gicd_save.icfgr[i++], 311 GICD_ICFGR + IRQ_REG_X16(irq)); 312 313 for (i = 0, irq = 0; irq < irq_nr; irq += 4) 314 gicd_writel(gicd_save.itargetsr[i++], 315 GICD_ITARGETSRn + IRQ_REG_X4(irq)); 316 317 for (i = 0, irq = 0; irq < irq_nr; irq += 4) 318 gicd_writel(gicd_save.ipriorityr[i++], 319 GICD_IPRIORITYRn + IRQ_REG_X4(irq)); 320 321 for (i = 0, irq = 0; irq < irq_nr; irq += 32) 322 gicd_writel(gicd_save.igroupr[i++], 323 GICD_IGROUPRn + IRQ_REG_X32(irq)); 324 325 for (i = 0, irq = 0; irq < irq_nr; irq += 32) 326 gicd_writel(gicd_save.isenabler[i++], 327 GICD_ISENABLERn + IRQ_REG_X32(irq)); 328 329 for (i = 0, irq = 0; irq < irq_nr; irq += 32) 330 gicd_writel(gicd_save.ispendr[i++], 331 GICD_ISPENDRn + IRQ_REG_X32(irq)); 332 333 dsb(); 334 #ifdef CONFIG_GICV2 335 gicc_writel(gicc_save.pmr, GICC_PMR); 336 gicc_writel(gicc_save.ctlr, GICC_CTLR); 337 #else 338 reg = gicc_save.pmr; 339 asm volatile("msr " __stringify(ICC_PMR_EL1) ", %0" : : "r" (reg)); 340 reg = gicc_save.ctlr; 341 asm volatile("msr " __stringify(ICC_CTLR_EL1) ", %0" : : "r" (reg)); 342 #endif 343 gicd_writel(gicd_save.ctlr, GICD_CTLR); 344 dsb(); 345 346 #if defined(CONFIG_GICV3) 347 asm volatile("msr " __stringify(ICC_IGRPEN1_EL1) ", %0" : : "r" (1)); 348 dsb(); 349 #endif 350 351 return 0; 352 } 353 354 /**************************************regs save and resume**************************/ 355 static int gic_irq_init(void) 356 { 357 /* GICV3 done in: arch/arm/cpu/armv8/start.S */ 358 #ifdef CONFIG_GICV2 359 u32 val; 360 361 /* 362 * If system boot without Miniloader: 363 * "Maskrom => Trust(optional) => U-Boot" 364 * 365 * IRQ_USB_OTG must be acked by GICC_EIO due to maskrom jumps to the 366 * U-Boot in its USB interrupt. Without this ack, the GICC_IAR always 367 * return a spurious interrupt ID 1023 for USB OTG interrupt. 368 */ 369 #ifdef IRQ_USB_OTG 370 gicc_writel(IRQ_USB_OTG, GICC_EOIR); 371 #endif 372 373 /* disable gicc and gicd */ 374 gicc_writel(0, GICC_CTLR); 375 gicd_writel(0, GICD_CTLR); 376 377 /* disable interrupt */ 378 gicd_writel(0xffffffff, GICD_ICENABLERn + 0); 379 gicd_writel(0xffffffff, GICD_ICENABLERn + 4); 380 gicd_writel(0xffffffff, GICD_ICENABLERn + 8); 381 gicd_writel(0xffffffff, GICD_ICENABLERn + 12); 382 383 val = gicd_readl(GICD_ICFGR + 12); 384 val &= ~(1 << 1); 385 gicd_writel(val, GICD_ICFGR + 12); 386 387 /* set interrupt priority threhold min: 256 */ 388 int_set_prio_filter(0xff); 389 int_enable_secure_signal(); 390 int_enable_nosecure_signal(); 391 int_enable_distributor(); 392 #endif 393 394 return 0; 395 } 396 397 static struct irq_chip gic_irq_chip = { 398 .name = "gic-irq-chip", 399 .irq_init = gic_irq_init, 400 .irq_suspend = gic_irq_suspend, 401 .irq_resume = gic_irq_resume, 402 .irq_get = gic_irq_get, 403 .irq_enable = gic_irq_enable, 404 .irq_disable = gic_irq_disable, 405 .irq_eoi = gic_irq_eoi, 406 .irq_set_type = gic_irq_set_type, 407 }; 408 409 struct irq_chip *arch_gic_get_irqchip(void) 410 { 411 return &gic_irq_chip; 412 } 413