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