Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

irqchip/stm32: Add stm32mp1 support with hierarchy domain

Exti controller has been differently integrated on stm32mp1 SoC.
A parent irq has only one external interrupt. A hierachy domain could
be used. Handlers are call by parent, each parent interrupt could be
masked and unmasked according to the needs.

Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

authored by

Ludovic Barre and committed by
Marc Zyngier
927abfc4 5a2490e0

+325
+3
Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt
··· 5 5 - compatible: Should be: 6 6 "st,stm32-exti" 7 7 "st,stm32h7-exti" 8 + "st,stm32mp1-exti" 8 9 - reg: Specifies base physical address and size of the registers 9 10 - interrupt-controller: Indentifies the node as an interrupt controller 10 11 - #interrupt-cells: Specifies the number of cells to encode an interrupt 11 12 specifier, shall be 2 12 13 - interrupts: interrupts references to primary interrupt controller 14 + (only needed for exti controller with multiple exti under 15 + same parent interrupt: st,stm32-exti and st,stm32h7-exti") 13 16 14 17 Example: 15 18
+322
drivers/irqchip/irq-stm32-exti.c
··· 15 15 #include <linux/of_address.h> 16 16 #include <linux/of_irq.h> 17 17 18 + #include <dt-bindings/interrupt-controller/arm-gic.h> 19 + 18 20 #define IRQS_PER_BANK 32 19 21 20 22 struct stm32_exti_bank { ··· 31 29 32 30 #define UNDEF_REG ~0 33 31 32 + struct stm32_desc_irq { 33 + u32 exti; 34 + u32 irq_parent; 35 + }; 36 + 34 37 struct stm32_exti_drv_data { 35 38 const struct stm32_exti_bank **exti_banks; 39 + const struct stm32_desc_irq *desc_irqs; 36 40 u32 bank_nr; 41 + u32 irq_nr; 37 42 }; 38 43 39 44 struct stm32_exti_chip_data { 40 45 struct stm32_exti_host_data *host_data; 41 46 const struct stm32_exti_bank *reg_bank; 47 + struct raw_spinlock rlock; 48 + u32 wake_active; 49 + u32 mask_cache; 42 50 u32 rtsr_cache; 43 51 u32 ftsr_cache; 44 52 }; ··· 118 106 .exti_banks = stm32h7xx_exti_banks, 119 107 .bank_nr = ARRAY_SIZE(stm32h7xx_exti_banks), 120 108 }; 109 + 110 + static const struct stm32_exti_bank stm32mp1_exti_b1 = { 111 + .imr_ofst = 0x80, 112 + .emr_ofst = 0x84, 113 + .rtsr_ofst = 0x00, 114 + .ftsr_ofst = 0x04, 115 + .swier_ofst = 0x08, 116 + .rpr_ofst = 0x0C, 117 + .fpr_ofst = 0x10, 118 + }; 119 + 120 + static const struct stm32_exti_bank stm32mp1_exti_b2 = { 121 + .imr_ofst = 0x90, 122 + .emr_ofst = 0x94, 123 + .rtsr_ofst = 0x20, 124 + .ftsr_ofst = 0x24, 125 + .swier_ofst = 0x28, 126 + .rpr_ofst = 0x2C, 127 + .fpr_ofst = 0x30, 128 + }; 129 + 130 + static const struct stm32_exti_bank stm32mp1_exti_b3 = { 131 + .imr_ofst = 0xA0, 132 + .emr_ofst = 0xA4, 133 + .rtsr_ofst = 0x40, 134 + .ftsr_ofst = 0x44, 135 + .swier_ofst = 0x48, 136 + .rpr_ofst = 0x4C, 137 + .fpr_ofst = 0x50, 138 + }; 139 + 140 + static const struct stm32_exti_bank *stm32mp1_exti_banks[] = { 141 + &stm32mp1_exti_b1, 142 + &stm32mp1_exti_b2, 143 + &stm32mp1_exti_b3, 144 + }; 145 + 146 + static const struct stm32_desc_irq stm32mp1_desc_irq[] = { 147 + { .exti = 1, .irq_parent = 7 }, 148 + { .exti = 2, .irq_parent = 8 }, 149 + { .exti = 3, .irq_parent = 9 }, 150 + { .exti = 4, .irq_parent = 10 }, 151 + { .exti = 5, .irq_parent = 23 }, 152 + { .exti = 6, .irq_parent = 64 }, 153 + { .exti = 7, .irq_parent = 65 }, 154 + { .exti = 8, .irq_parent = 66 }, 155 + { .exti = 9, .irq_parent = 67 }, 156 + { .exti = 10, .irq_parent = 40 }, 157 + { .exti = 11, .irq_parent = 42 }, 158 + { .exti = 12, .irq_parent = 76 }, 159 + { .exti = 13, .irq_parent = 77 }, 160 + { .exti = 14, .irq_parent = 121 }, 161 + { .exti = 15, .irq_parent = 127 }, 162 + { .exti = 16, .irq_parent = 1 }, 163 + { .exti = 65, .irq_parent = 144 }, 164 + { .exti = 68, .irq_parent = 143 }, 165 + { .exti = 73, .irq_parent = 129 }, 166 + }; 167 + 168 + static const struct stm32_exti_drv_data stm32mp1_drv_data = { 169 + .exti_banks = stm32mp1_exti_banks, 170 + .bank_nr = ARRAY_SIZE(stm32mp1_exti_banks), 171 + .desc_irqs = stm32mp1_desc_irq, 172 + .irq_nr = ARRAY_SIZE(stm32mp1_desc_irq), 173 + }; 174 + 175 + static int stm32_exti_to_irq(const struct stm32_exti_drv_data *drv_data, 176 + irq_hw_number_t hwirq) 177 + { 178 + const struct stm32_desc_irq *desc_irq; 179 + int i; 180 + 181 + if (!drv_data->desc_irqs) 182 + return -EINVAL; 183 + 184 + for (i = 0; i < drv_data->irq_nr; i++) { 185 + desc_irq = &drv_data->desc_irqs[i]; 186 + if (desc_irq->exti == hwirq) 187 + return desc_irq->irq_parent; 188 + } 189 + 190 + return -EINVAL; 191 + } 121 192 122 193 static unsigned long stm32_exti_pending(struct irq_chip_generic *gc) 123 194 { ··· 377 282 378 283 irq_gc_unlock(gc); 379 284 } 285 + 286 + static inline u32 stm32_exti_set_bit(struct irq_data *d, u32 reg) 287 + { 288 + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 289 + void __iomem *base = chip_data->host_data->base; 290 + u32 val; 291 + 292 + val = readl_relaxed(base + reg); 293 + val |= BIT(d->hwirq % IRQS_PER_BANK); 294 + writel_relaxed(val, base + reg); 295 + 296 + return val; 297 + } 298 + 299 + static inline u32 stm32_exti_clr_bit(struct irq_data *d, u32 reg) 300 + { 301 + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 302 + void __iomem *base = chip_data->host_data->base; 303 + u32 val; 304 + 305 + val = readl_relaxed(base + reg); 306 + val &= ~BIT(d->hwirq % IRQS_PER_BANK); 307 + writel_relaxed(val, base + reg); 308 + 309 + return val; 310 + } 311 + 312 + static void stm32_exti_h_eoi(struct irq_data *d) 313 + { 314 + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 315 + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; 316 + 317 + raw_spin_lock(&chip_data->rlock); 318 + 319 + stm32_exti_set_bit(d, stm32_bank->rpr_ofst); 320 + if (stm32_bank->fpr_ofst != UNDEF_REG) 321 + stm32_exti_set_bit(d, stm32_bank->fpr_ofst); 322 + 323 + raw_spin_unlock(&chip_data->rlock); 324 + 325 + if (d->parent_data->chip) 326 + irq_chip_eoi_parent(d); 327 + } 328 + 329 + static void stm32_exti_h_mask(struct irq_data *d) 330 + { 331 + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 332 + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; 333 + 334 + raw_spin_lock(&chip_data->rlock); 335 + chip_data->mask_cache = stm32_exti_clr_bit(d, stm32_bank->imr_ofst); 336 + raw_spin_unlock(&chip_data->rlock); 337 + 338 + if (d->parent_data->chip) 339 + irq_chip_mask_parent(d); 340 + } 341 + 342 + static void stm32_exti_h_unmask(struct irq_data *d) 343 + { 344 + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 345 + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; 346 + 347 + raw_spin_lock(&chip_data->rlock); 348 + chip_data->mask_cache = stm32_exti_set_bit(d, stm32_bank->imr_ofst); 349 + raw_spin_unlock(&chip_data->rlock); 350 + 351 + if (d->parent_data->chip) 352 + irq_chip_unmask_parent(d); 353 + } 354 + 355 + static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type) 356 + { 357 + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 358 + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; 359 + void __iomem *base = chip_data->host_data->base; 360 + u32 rtsr, ftsr; 361 + int err; 362 + 363 + raw_spin_lock(&chip_data->rlock); 364 + rtsr = readl_relaxed(base + stm32_bank->rtsr_ofst); 365 + ftsr = readl_relaxed(base + stm32_bank->ftsr_ofst); 366 + 367 + err = stm32_exti_set_type(d, type, &rtsr, &ftsr); 368 + if (err) { 369 + raw_spin_unlock(&chip_data->rlock); 370 + return err; 371 + } 372 + 373 + writel_relaxed(rtsr, base + stm32_bank->rtsr_ofst); 374 + writel_relaxed(ftsr, base + stm32_bank->ftsr_ofst); 375 + raw_spin_unlock(&chip_data->rlock); 376 + 377 + return 0; 378 + } 379 + 380 + static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on) 381 + { 382 + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 383 + u32 mask = BIT(d->hwirq % IRQS_PER_BANK); 384 + 385 + raw_spin_lock(&chip_data->rlock); 386 + 387 + if (on) 388 + chip_data->wake_active |= mask; 389 + else 390 + chip_data->wake_active &= ~mask; 391 + 392 + raw_spin_unlock(&chip_data->rlock); 393 + 394 + return 0; 395 + } 396 + 397 + static int stm32_exti_h_set_affinity(struct irq_data *d, 398 + const struct cpumask *dest, bool force) 399 + { 400 + if (d->parent_data->chip) 401 + return irq_chip_set_affinity_parent(d, dest, force); 402 + 403 + return -EINVAL; 404 + } 405 + 406 + static struct irq_chip stm32_exti_h_chip = { 407 + .name = "stm32-exti-h", 408 + .irq_eoi = stm32_exti_h_eoi, 409 + .irq_mask = stm32_exti_h_mask, 410 + .irq_unmask = stm32_exti_h_unmask, 411 + .irq_retrigger = irq_chip_retrigger_hierarchy, 412 + .irq_set_type = stm32_exti_h_set_type, 413 + .irq_set_wake = stm32_exti_h_set_wake, 414 + .flags = IRQCHIP_MASK_ON_SUSPEND, 415 + #ifdef CONFIG_SMP 416 + .irq_set_affinity = stm32_exti_h_set_affinity, 417 + #endif 418 + }; 419 + 420 + static int stm32_exti_h_domain_alloc(struct irq_domain *dm, 421 + unsigned int virq, 422 + unsigned int nr_irqs, void *data) 423 + { 424 + struct stm32_exti_host_data *host_data = dm->host_data; 425 + struct stm32_exti_chip_data *chip_data; 426 + struct irq_fwspec *fwspec = data; 427 + struct irq_fwspec p_fwspec; 428 + irq_hw_number_t hwirq; 429 + int p_irq, bank; 430 + 431 + hwirq = fwspec->param[0]; 432 + bank = hwirq / IRQS_PER_BANK; 433 + chip_data = &host_data->chips_data[bank]; 434 + 435 + irq_domain_set_hwirq_and_chip(dm, virq, hwirq, 436 + &stm32_exti_h_chip, chip_data); 437 + 438 + p_irq = stm32_exti_to_irq(host_data->drv_data, hwirq); 439 + if (p_irq >= 0) { 440 + p_fwspec.fwnode = dm->parent->fwnode; 441 + p_fwspec.param_count = 3; 442 + p_fwspec.param[0] = GIC_SPI; 443 + p_fwspec.param[1] = p_irq; 444 + p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH; 445 + 446 + return irq_domain_alloc_irqs_parent(dm, virq, 1, &p_fwspec); 447 + } 448 + 449 + return 0; 450 + } 451 + 380 452 static struct 381 453 stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd, 382 454 struct device_node *node) ··· 584 322 chip_data = &h_data->chips_data[bank_idx]; 585 323 chip_data->host_data = h_data; 586 324 chip_data->reg_bank = stm32_bank; 325 + 326 + raw_spin_lock_init(&chip_data->rlock); 587 327 588 328 /* Determine number of irqs supported */ 589 329 writel_relaxed(~0UL, base + stm32_bank->rtsr_ofst); ··· 685 421 return ret; 686 422 } 687 423 424 + static const struct irq_domain_ops stm32_exti_h_domain_ops = { 425 + .alloc = stm32_exti_h_domain_alloc, 426 + .free = irq_domain_free_irqs_common, 427 + }; 428 + 429 + static int 430 + __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data, 431 + struct device_node *node, 432 + struct device_node *parent) 433 + { 434 + struct irq_domain *parent_domain, *domain; 435 + struct stm32_exti_host_data *host_data; 436 + int ret, i; 437 + 438 + parent_domain = irq_find_host(parent); 439 + if (!parent_domain) { 440 + pr_err("interrupt-parent not found\n"); 441 + return -EINVAL; 442 + } 443 + 444 + host_data = stm32_exti_host_init(drv_data, node); 445 + if (!host_data) { 446 + ret = -ENOMEM; 447 + goto out_free_mem; 448 + } 449 + 450 + for (i = 0; i < drv_data->bank_nr; i++) 451 + stm32_exti_chip_init(host_data, i, node); 452 + 453 + domain = irq_domain_add_hierarchy(parent_domain, 0, 454 + drv_data->bank_nr * IRQS_PER_BANK, 455 + node, &stm32_exti_h_domain_ops, 456 + host_data); 457 + 458 + if (!domain) { 459 + pr_err("%s: Could not register exti domain.\n", node->name); 460 + ret = -ENOMEM; 461 + goto out_unmap; 462 + } 463 + 464 + return 0; 465 + 466 + out_unmap: 467 + iounmap(host_data->base); 468 + out_free_mem: 469 + kfree(host_data->chips_data); 470 + kfree(host_data); 471 + return ret; 472 + } 473 + 688 474 static int __init stm32f4_exti_of_init(struct device_node *np, 689 475 struct device_node *parent) 690 476 { ··· 750 436 } 751 437 752 438 IRQCHIP_DECLARE(stm32h7_exti, "st,stm32h7-exti", stm32h7_exti_of_init); 439 + 440 + static int __init stm32mp1_exti_of_init(struct device_node *np, 441 + struct device_node *parent) 442 + { 443 + return stm32_exti_hierarchy_init(&stm32mp1_drv_data, np, parent); 444 + } 445 + 446 + IRQCHIP_DECLARE(stm32mp1_exti, "st,stm32mp1-exti", stm32mp1_exti_of_init);