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