1 /* 2 * (C) Copyright 2019 Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <dm.h> 9 #include <fdtdec.h> 10 #include <malloc.h> 11 #include <asm/io.h> 12 #include <asm/u-boot-arm.h> 13 #include <irq-generic.h> 14 #include "irq-internal.h" 15 16 DECLARE_GLOBAL_DATA_PTR; 17 18 static LIST_HEAD(virq_desc_head); 19 static u32 virq_id = PLATFORM_MAX_IRQ; 20 21 static u32 virq_id_alloc(void) 22 { 23 return ++virq_id; 24 } 25 26 struct virq_data { 27 int irq; 28 u32 flag; 29 u32 count; 30 31 void *data; 32 interrupt_handler_t *handle_irq; 33 }; 34 35 /* The structure to maintail the irqchip and child virqs */ 36 struct virq_desc { 37 struct virq_chip *chip; /* irq chip */ 38 struct virq_data *virqs; /* child irq data list */ 39 struct udevice *parent; /* parent device */ 40 int pirq; /* parent irq */ 41 int irq_base; /* child irq base */ 42 int irq_end; /* child irq end */ 43 uint reg_stride; 44 uint unalign_reg_idx; 45 uint unalign_reg_stride; 46 uint *status_buf; 47 48 struct list_head node; 49 }; 50 51 static struct virq_desc *find_virq_desc(int irq) 52 { 53 struct virq_desc *desc; 54 struct list_head *node; 55 56 list_for_each(node, &virq_desc_head) { 57 desc = list_entry(node, struct virq_desc, node); 58 if (irq >= desc->irq_base && irq <= desc->irq_end) 59 return desc; 60 } 61 62 return NULL; 63 } 64 65 static struct virq_desc *find_virq_desc_by_pirq(int parent_irq) 66 { 67 struct virq_desc *desc; 68 struct list_head *node; 69 70 list_for_each(node, &virq_desc_head) { 71 desc = list_entry(node, struct virq_desc, node); 72 if (parent_irq == desc->pirq) 73 return desc; 74 } 75 76 return NULL; 77 } 78 79 int virq_to_irq(struct virq_chip *chip, int virq) 80 { 81 struct virq_desc *desc; 82 struct list_head *node; 83 int irq; 84 85 if (!chip) 86 return -EINVAL; 87 88 list_for_each(node, &virq_desc_head) { 89 desc = list_entry(node, struct virq_desc, node); 90 if (desc->chip == chip) { 91 irq = desc->irq_base + virq; 92 if (irq >= desc->irq_base && irq <= desc->irq_end) 93 return irq; 94 } 95 } 96 97 return -ENONET; 98 } 99 100 int bad_virq(int irq) 101 { 102 return !find_virq_desc(irq); 103 } 104 105 void virqs_show(int pirq) 106 { 107 struct virq_data *vdata; 108 struct virq_desc *desc; 109 struct udevice *dev; 110 int num; 111 int i; 112 113 desc = find_virq_desc_by_pirq(pirq); 114 if (!desc) 115 return; 116 117 vdata = desc->virqs; 118 num = desc->irq_end - desc->irq_base; 119 120 for (i = 0; i < num; i++) { 121 if (!vdata[i].handle_irq) 122 continue; 123 124 dev = (struct udevice *)vdata[i].data; 125 printf(" %3d %d 0x%08lx %-12s |-- %-12s %d\n", 126 vdata[i].irq, 127 vdata[i].flag & IRQ_FLG_ENABLE ? 1 : 0, 128 (ulong)vdata[i].handle_irq, dev->driver->name, dev->name, 129 vdata[i].count); 130 } 131 } 132 133 int virq_install_handler(int irq, interrupt_handler_t *handler, void *data) 134 { 135 struct virq_desc *desc; 136 int virq; 137 138 if (!handler) 139 return -EINVAL; 140 141 desc = find_virq_desc(irq); 142 if (!desc) 143 return -ENOENT; 144 145 virq = irq - desc->irq_base; 146 if (desc->virqs[virq].handle_irq) 147 return -EBUSY; 148 149 desc->virqs[virq].handle_irq = handler; 150 desc->virqs[virq].data = data; 151 152 return 0; 153 } 154 155 void virq_free_handler(int irq) 156 { 157 struct virq_desc *desc; 158 int virq; 159 160 desc = find_virq_desc(irq); 161 if (!desc) 162 return; 163 164 virq = irq - desc->irq_base; 165 desc->virqs[virq].handle_irq = NULL; 166 desc->virqs[virq].data = NULL; 167 } 168 169 static uint reg_base_get(struct virq_desc *desc, uint reg_base, int idx) 170 { 171 int reg_addr; 172 173 if (idx <= desc->unalign_reg_idx) { 174 reg_addr = reg_base + (idx * desc->unalign_reg_stride); 175 } else { 176 reg_addr = reg_base + 177 (desc->unalign_reg_idx * desc->unalign_reg_stride); 178 reg_addr += (idx - desc->unalign_reg_idx) * desc->reg_stride; 179 } 180 181 return reg_addr; 182 } 183 184 void virq_chip_generic_handler(int pirq, void *pdata) 185 { 186 struct virq_chip *chip; 187 struct virq_desc *desc; 188 struct virq_data *vdata; 189 struct udevice *parent; 190 uint status_reg; 191 void *data; 192 int irq; 193 int ret; 194 int i; 195 196 desc = find_virq_desc_by_pirq(pirq); 197 if (!desc) 198 return; 199 200 chip = desc->chip; 201 vdata = desc->virqs; 202 parent = (struct udevice *)pdata; 203 204 if (!chip || !vdata || !parent) 205 return; 206 207 /* Read all status register */ 208 for (i = 0; i < chip->num_regs; i++) { 209 status_reg = reg_base_get(desc, chip->status_base, i); 210 desc->status_buf[i] = chip->i2c_read(parent, status_reg); 211 if (desc->status_buf[i] < 0) { 212 printf("%s: Read status register 0x%x failed, ret=%d\n", 213 __func__, status_reg, desc->status_buf[i]); 214 } 215 } 216 217 /* Handle all virq handler */ 218 for (i = 0; i < chip->num_irqs; i++) { 219 if (desc->status_buf[chip->irqs[i].reg_offset] & 220 chip->irqs[i].mask) { 221 irq = vdata[i].irq; 222 data = vdata[i].data; 223 224 if (vdata[i].handle_irq) { 225 vdata[i].count++; 226 vdata[i].handle_irq(irq, data); 227 } 228 } 229 } 230 231 /* Clear all status register */ 232 for (i = 0; i < chip->num_regs; i++) { 233 status_reg = reg_base_get(desc, chip->status_base, i); 234 ret = chip->i2c_write(parent, status_reg, ~0U); 235 if (ret) 236 printf("%s: Clear status register 0x%x failed, ret=%d\n", 237 __func__, status_reg, ret); 238 } 239 } 240 241 int virq_add_chip(struct udevice *dev, struct virq_chip *chip, 242 int irq, int enable) 243 { 244 struct virq_data *vdata; 245 struct virq_desc *desc; 246 uint *status_buf; 247 uint mask_reg; 248 int ret; 249 int i; 250 251 if (irq < 0) 252 return -EINVAL; 253 254 desc = (struct virq_desc *)malloc(sizeof(*desc)); 255 if (!desc) 256 return -ENOMEM; 257 258 vdata = (struct virq_data *)calloc(sizeof(*vdata), chip->num_irqs); 259 if (!vdata) { 260 ret = -ENOMEM; 261 goto free1; 262 } 263 264 status_buf = (uint *)calloc(sizeof(*status_buf), chip->num_irqs); 265 if (!status_buf) { 266 ret = -ENOMEM; 267 goto free2; 268 } 269 270 for (i = 0; i < chip->num_irqs; i++) 271 vdata[i].irq = virq_id_alloc(); 272 273 desc->parent = dev; 274 desc->pirq = irq; 275 desc->chip = chip; 276 desc->virqs = vdata; 277 desc->irq_base = vdata[0].irq; 278 desc->irq_end = vdata[chip->num_irqs - 1].irq; 279 desc->status_buf = status_buf; 280 desc->reg_stride = chip->irq_reg_stride ? : 1; 281 desc->unalign_reg_stride = chip->irq_unalign_reg_stride ? : 1; 282 desc->unalign_reg_idx = chip->irq_unalign_reg_stride ? 283 chip->irq_unalign_reg_idx : 0; 284 list_add_tail(&desc->node, &virq_desc_head); 285 286 /* Mask all register */ 287 for (i = 0; i < chip->num_regs; i++) { 288 mask_reg = reg_base_get(desc, chip->mask_base, i); 289 ret = chip->i2c_write(dev, mask_reg, ~0U); 290 if (ret) 291 printf("%s: Set mask register 0x%x failed, ret=%d\n", 292 __func__, mask_reg, ret); 293 } 294 295 /* Add parent irq into interrupt framework with generic virq handler */ 296 irq_install_handler(irq, virq_chip_generic_handler, dev); 297 298 return enable ? irq_handler_enable(irq) : irq_handler_disable(irq); 299 300 free1: 301 free(desc); 302 free2: 303 free(status_buf); 304 305 return ret; 306 } 307 308 static int virq_init(void) 309 { 310 INIT_LIST_HEAD(&virq_desc_head); 311 return 0; 312 } 313 314 static int __virq_enable(int irq, int enable) 315 { 316 struct virq_chip *chip; 317 struct virq_desc *desc; 318 uint mask_reg, mask_val; 319 uint reg_val; 320 int virq; 321 int ret; 322 323 desc = find_virq_desc(irq); 324 if (!desc) { 325 printf("%s: %s Invalid irq %d\n", 326 __func__, enable ? "Enable" : "Disable", irq); 327 return -ENOENT; 328 } 329 330 chip = desc->chip; 331 if (!chip) 332 return -ENOENT; 333 334 virq = irq - desc->irq_base; 335 mask_val = chip->irqs[virq].mask; 336 mask_reg = reg_base_get(desc, chip->mask_base, 337 chip->irqs[virq].reg_offset); 338 reg_val = chip->i2c_read(desc->parent, mask_reg); 339 if (enable) 340 reg_val &= ~mask_val; 341 else 342 reg_val |= mask_val; 343 344 ret = chip->i2c_write(desc->parent, mask_reg, reg_val); 345 if (ret) { 346 printf("%s: Clear status register 0x%x failed, ret=%d\n", 347 __func__, mask_reg, ret); 348 return ret; 349 } 350 351 if (enable) 352 desc->virqs[virq].flag |= IRQ_FLG_ENABLE; 353 else 354 desc->virqs[virq].flag &= ~IRQ_FLG_ENABLE; 355 356 return 0; 357 } 358 359 static int virq_enable(int irq) 360 { 361 if (bad_virq(irq)) 362 return -EINVAL; 363 364 return __virq_enable(irq, 1); 365 } 366 367 static int virq_disable(int irq) 368 { 369 if (bad_virq(irq)) 370 return -EINVAL; 371 372 return __virq_enable(irq, 0); 373 } 374 375 struct irq_chip virq_generic_chip = { 376 .name = "virq-irq-chip", 377 .irq_init = virq_init, 378 .irq_enable = virq_enable, 379 .irq_disable = virq_disable, 380 }; 381 382 struct irq_chip *arch_virq_get_irqchip(void) 383 { 384 return &virq_generic_chip; 385 } 386