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