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 234 /* irq nr */ 235 irq_nr = ((gicd_readl(GICD_TYPER) & 0x1f) + 1) * 32; 236 if (irq_nr > 1020) 237 irq_nr = 1020; 238 239 /* GICC save */ 240 gicc_save.ctlr = gicc_readl(GICC_CTLR); 241 gicc_save.pmr = gicc_readl(GICC_PMR); 242 243 /* GICD save */ 244 gicd_save.ctlr = gicd_readl(GICD_CTLR); 245 246 for (i = 0, irq = 0; irq < irq_nr; irq += 16) 247 gicd_save.icfgr[i++] = 248 gicd_readl(GICD_ICFGR + IRQ_REG_X16(irq)); 249 250 for (i = 0, irq = 0; irq < irq_nr; irq += 4) 251 gicd_save.itargetsr[i++] = 252 gicd_readl(GICD_ITARGETSRn + IRQ_REG_X4(irq)); 253 254 for (i = 0, irq = 0; irq < irq_nr; irq += 4) 255 gicd_save.ipriorityr[i++] = 256 gicd_readl(GICD_IPRIORITYRn + IRQ_REG_X4(irq)); 257 258 for (i = 0, irq = 0; irq < irq_nr; irq += 32) 259 gicd_save.igroupr[i++] = 260 gicd_readl(GICD_IGROUPRn + IRQ_REG_X32(irq)); 261 262 for (i = 0, irq = 0; irq < irq_nr; irq += 32) 263 gicd_save.ispendr[i++] = 264 gicd_readl(GICD_ISPENDRn + IRQ_REG_X32(irq)); 265 266 for (i = 0, irq = 0; irq < irq_nr; irq += 32) 267 gicd_save.isenabler[i++] = 268 gicd_readl(GICD_ISENABLERn + IRQ_REG_X32(irq)); 269 270 dsb(); 271 272 return 0; 273 } 274 275 static int gic_irq_resume(void) 276 { 277 int irq_nr, i, irq; 278 279 irq_nr = ((gicd_readl(GICD_TYPER) & 0x1f) + 1) * 32; 280 if (irq_nr > 1020) 281 irq_nr = 1020; 282 283 /* Disable ctrl register */ 284 gicc_writel(0, GICC_CTLR); 285 gicd_writel(0, GICD_CTLR); 286 dsb(); 287 288 /* Clear all interrupt */ 289 for (i = 0, irq = 0; irq < irq_nr; irq += 32) 290 gicd_writel(0xffffffff, 291 GICD_ICENABLERn + IRQ_REG_X32(irq)); 292 293 for (i = 0, irq = 0; irq < irq_nr; irq += 16) 294 gicd_writel(gicd_save.icfgr[i++], 295 GICD_ICFGR + IRQ_REG_X16(irq)); 296 297 for (i = 0, irq = 0; irq < irq_nr; irq += 4) 298 gicd_writel(gicd_save.itargetsr[i++], 299 GICD_ITARGETSRn + IRQ_REG_X4(irq)); 300 301 for (i = 0, irq = 0; irq < irq_nr; irq += 4) 302 gicd_writel(gicd_save.ipriorityr[i++], 303 GICD_IPRIORITYRn + IRQ_REG_X4(irq)); 304 305 for (i = 0, irq = 0; irq < irq_nr; irq += 32) 306 gicd_writel(gicd_save.igroupr[i++], 307 GICD_IGROUPRn + IRQ_REG_X32(irq)); 308 309 for (i = 0, irq = 0; irq < irq_nr; irq += 32) 310 gicd_writel(gicd_save.isenabler[i++], 311 GICD_ISENABLERn + IRQ_REG_X32(irq)); 312 313 for (i = 0, irq = 0; irq < irq_nr; irq += 32) 314 gicd_writel(gicd_save.ispendr[i++], 315 GICD_ISPENDRn + IRQ_REG_X32(irq)); 316 317 dsb(); 318 gicc_writel(gicc_save.pmr, GICC_PMR); 319 gicc_writel(gicc_save.ctlr, GICC_CTLR); 320 gicd_writel(gicd_save.ctlr, GICD_CTLR); 321 dsb(); 322 323 #if defined(CONFIG_GICV3) 324 asm volatile("msr " __stringify(ICC_IGRPEN1_EL1) ", %0" : : "r" (1)); 325 dsb(); 326 #endif 327 328 return 0; 329 } 330 331 /**************************************regs save and resume**************************/ 332 static int gic_irq_init(void) 333 { 334 /* GICV3 done in: arch/arm/cpu/armv8/start.S */ 335 #ifdef CONFIG_GICV2 336 u32 val; 337 338 /* 339 * If system boot without Miniloader: 340 * "Maskrom => Trust(optional) => U-Boot" 341 * 342 * IRQ_USB_OTG must be acked by GICC_EIO due to maskrom jumps to the 343 * U-Boot in its USB interrupt. Without this ack, the GICC_IAR always 344 * return a spurious interrupt ID 1023 for USB OTG interrupt. 345 */ 346 #ifdef IRQ_USB_OTG 347 gicc_writel(IRQ_USB_OTG, GICC_EOIR); 348 #endif 349 350 /* disable gicc and gicd */ 351 gicc_writel(0, GICC_CTLR); 352 gicd_writel(0, GICD_CTLR); 353 354 /* disable interrupt */ 355 gicd_writel(0xffffffff, GICD_ICENABLERn + 0); 356 gicd_writel(0xffffffff, GICD_ICENABLERn + 4); 357 gicd_writel(0xffffffff, GICD_ICENABLERn + 8); 358 gicd_writel(0xffffffff, GICD_ICENABLERn + 12); 359 360 val = gicd_readl(GICD_ICFGR + 12); 361 val &= ~(1 << 1); 362 gicd_writel(val, GICD_ICFGR + 12); 363 364 /* set interrupt priority threhold min: 256 */ 365 int_set_prio_filter(0xff); 366 int_enable_secure_signal(); 367 int_enable_nosecure_signal(); 368 int_enable_distributor(); 369 #endif 370 371 return 0; 372 } 373 374 static struct irq_chip gic_irq_chip = { 375 .name = "gic-irq-chip", 376 .irq_init = gic_irq_init, 377 .irq_suspend = gic_irq_suspend, 378 .irq_resume = gic_irq_resume, 379 .irq_get = gic_irq_get, 380 .irq_enable = gic_irq_enable, 381 .irq_disable = gic_irq_disable, 382 .irq_eoi = gic_irq_eoi, 383 .irq_set_type = gic_irq_set_type, 384 }; 385 386 struct irq_chip *arch_gic_get_irqchip(void) 387 { 388 return &gic_irq_chip; 389 } 390