Lines Matching +full:fiq +full:- +full:based

1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Based on irq-lpc32xx:
6 * Copyright 2015-2016 Vladimir Zapolskiy <vz@mleia.com>
7 * Based on irq-bcm2836:
14 * - 896 level-triggered hardware IRQs
15 * - Single mask bit per IRQ
16 * - Per-IRQ affinity setting
17 * - Automatic masking on event delivery (auto-ack)
18 * - Software triggering (ORed with hw line)
19 * - 2 per-CPU IPIs (meant as "self" and "other", but they are
21 * - Automatic prioritization (single event/ack register per CPU, lower IRQs =
23 * - Automatic masking on ack
24 * - Default "this CPU" register view and explicit per-CPU views
32 * - This driver creates two IRQ domains, one for HW IRQs and internal FIQs,
34 * - Since Linux needs more than 2 IPIs, we implement a software IRQ controller
35 * and funnel all IPIs into one per-CPU IPI (the second "self" IPI is unused).
36 * - FIQ hwirq numbers are assigned after true hwirqs, and are per-cpu.
37 * - DT bindings use 3-cell form (like GIC):
38 * - <0 nr flags> - hwirq #nr
39 * - <1 nr flags> - FIQ #nr
40 * - nr=0 Physical HV timer
41 * - nr=1 Virtual HV timer
42 * - nr=2 Physical guest timer
43 * - nr=3 Virtual guest timer
53 #include <linux/irqchip/arm-vgic-info.h>
65 #include <dt-bindings/interrupt-controller/apple-aic.h>
153 * forward-compatible.
163 * IMP-DEF sysregs that control FIQ sources
182 /* Guest timer FIQ enable register */
217 * FIQ hwirq index definitions: FIQ sources use the DT binding defines
277 .compatible = "apple,t8103-aic",
319 return readl_relaxed(ic->base + reg); in aic_ic_read()
324 writel_relaxed(val, ic->base + reg); in aic_ic_write()
336 u32 off = AIC_HWIRQ_DIE(hwirq) * ic->info.die_stride; in aic_irq_mask()
339 aic_ic_write(ic, ic->info.mask_set + off + MASK_REG(irq), MASK_BIT(irq)); in aic_irq_mask()
347 u32 off = AIC_HWIRQ_DIE(hwirq) * ic->info.die_stride; in aic_irq_unmask()
350 aic_ic_write(ic, ic->info.mask_clr + off + MASK_REG(irq), MASK_BIT(irq)); in aic_irq_unmask()
373 event = readl(ic->event + ic->info.event); in aic_handle_irq()
378 generic_handle_domain_irq(aic_irqc->hw_domain, event); in aic_handle_irq()
405 BUG_ON(!ic->info.target_cpu); in aic_irq_set_affinity()
412 aic_ic_write(ic, ic->info.target_cpu + AIC_HWIRQ_IRQ(hwirq) * 4, BIT(cpu)); in aic_irq_set_affinity()
424 return (type == IRQ_TYPE_LEVEL_HIGH || type == IRQ_TYPE_EDGE_RISING) ? 0 : -EINVAL; in aic_irq_set_type()
445 * FIQ irqchip
514 * the FIQ source state without having to peek down into sources... in aic_handle_fiq()
518 * - Fast IPIs (not yet used) in aic_handle_fiq()
519 * - The 4 timers (CNTP, CNTV for each of HV and guest) in aic_handle_fiq()
520 * - Per-core PMCs (not yet supported) in aic_handle_fiq()
521 * - Per-cluster uncore PMCs (not yet supported) in aic_handle_fiq()
523 * Since not dealing with any of these results in a FIQ storm, in aic_handle_fiq()
537 generic_handle_domain_irq(aic_irqc->hw_domain, in aic_handle_fiq()
541 generic_handle_domain_irq(aic_irqc->hw_domain, in aic_handle_fiq()
549 generic_handle_domain_irq(aic_irqc->hw_domain, in aic_handle_fiq()
554 generic_handle_domain_irq(aic_irqc->hw_domain, in aic_handle_fiq()
561 &aic_irqc->fiq_aff[AIC_CPU_PMU_P]->aff)) in aic_handle_fiq()
565 generic_handle_domain_irq(aic_irqc->hw_domain, in aic_handle_fiq()
572 pr_err_ratelimited("Uncore PMC FIQ fired. Masking.\n"); in aic_handle_fiq()
580 return (type == IRQ_TYPE_LEVEL_HIGH) ? 0 : -EINVAL; in aic_fiq_set_type()
584 .name = "AIC-FIQ",
599 struct aic_irq_chip *ic = id->host_data; in aic_irq_domain_map()
603 if (ic->info.version == 2) in aic_irq_domain_map()
607 irq_domain_set_info(id, irq, hw, chip, id->host_data, in aic_irq_domain_map()
611 int fiq = FIELD_GET(AIC_EVENT_NUM, hw); in aic_irq_domain_map() local
613 switch (fiq) { in aic_irq_domain_map()
616 irq_set_percpu_devid_partition(irq, &ic->fiq_aff[fiq]->aff); in aic_irq_domain_map()
623 irq_domain_set_info(id, irq, hw, &fiq_chip, id->host_data, in aic_irq_domain_map()
635 struct aic_irq_chip *ic = id->host_data; in aic_irq_domain_translate()
639 if (fwspec->param_count < 3 || fwspec->param_count > 4 || in aic_irq_domain_translate()
640 !is_of_node(fwspec->fwnode)) in aic_irq_domain_translate()
641 return -EINVAL; in aic_irq_domain_translate()
643 args = &fwspec->param[1]; in aic_irq_domain_translate()
645 if (fwspec->param_count == 4) { in aic_irq_domain_translate()
650 switch (fwspec->param[0]) { in aic_irq_domain_translate()
652 if (die >= ic->nr_die) in aic_irq_domain_translate()
653 return -EINVAL; in aic_irq_domain_translate()
654 if (args[0] >= ic->nr_irq) in aic_irq_domain_translate()
655 return -EINVAL; in aic_irq_domain_translate()
660 return -EINVAL; in aic_irq_domain_translate()
662 return -EINVAL; in aic_irq_domain_translate()
666 * In EL1 the non-redirected registers are the guest's, in aic_irq_domain_translate()
679 return -ENOENT; in aic_irq_domain_translate()
686 return -EINVAL; in aic_irq_domain_translate()
777 * No barriers needed here since this is a self-IPI. in aic_ipi_unmask()
831 .name = "AIC-IPI",
864 * the barrier that is part of the top-level AIC handler's readl()). in aic_handle_ipi()
880 generic_handle_domain_irq(aic_irqc->ipi_domain, i); in aic_handle_ipi()
897 irq_domain_set_info(d, virq + i, i, &ipi_chip, d->host_data, in aic_ipi_alloc()
919 ipi_domain = irq_domain_create_linear(irqc->hw_domain->fwnode, AIC_NR_SWIPI, in aic_init_smp()
922 return -ENODEV; in aic_init_smp()
924 ipi_domain->flags |= IRQ_DOMAIN_FLAG_IPI_SINGLE; in aic_init_smp()
927 base_ipi = __irq_domain_alloc_irqs(ipi_domain, -1, AIC_NR_SWIPI, in aic_init_smp()
932 return -ENODEV; in aic_init_smp()
937 irqc->ipi_domain = ipi_domain; in aic_init_smp()
944 /* Mask all hard-wired per-CPU IRQ/FIQ sources */ in aic_init_cpu()
953 /* EL2-only (VHE mode) IRQ sources */ in aic_init_cpu()
963 /* PMC FIQ */ in aic_init_cpu()
967 /* Uncore PMC FIQ */ in aic_init_cpu()
974 if (aic_irqc->info.version == 1) { in aic_init_cpu()
983 * Always keep IPIs unmasked at the hardware level (except auto-masking in aic_init_cpu()
1011 u32 fiq; in build_fiq_affinity() local
1013 if (of_property_read_u32(aff, "apple,fiq-index", &fiq) || in build_fiq_affinity()
1014 WARN_ON(fiq >= AIC_NR_FIQ) || ic->fiq_aff[fiq]) in build_fiq_affinity()
1021 ic->fiq_aff[fiq] = kzalloc(sizeof(*ic->fiq_aff[fiq]), GFP_KERNEL); in build_fiq_affinity()
1022 if (!ic->fiq_aff[fiq]) in build_fiq_affinity()
1042 cpumask_set_cpu(cpu, &ic->fiq_aff[fiq]->aff); in build_fiq_affinity()
1057 return -EIO; in aic_of_ic_init()
1062 return -ENOMEM; in aic_of_ic_init()
1065 irqc->base = regs; in aic_of_ic_init()
1071 irqc->info = *(struct aic_info *)match->data; in aic_of_ic_init()
1075 switch (irqc->info.version) { in aic_of_ic_init()
1080 irqc->nr_irq = FIELD_GET(AIC_INFO_NR_IRQ, info); in aic_of_ic_init()
1081 irqc->max_irq = AIC_MAX_IRQ; in aic_of_ic_init()
1082 irqc->nr_die = irqc->max_die = 1; in aic_of_ic_init()
1084 off = start_off = irqc->info.target_cpu; in aic_of_ic_init()
1085 off += sizeof(u32) * irqc->max_irq; /* TARGET_CPU */ in aic_of_ic_init()
1087 irqc->event = irqc->base; in aic_of_ic_init()
1097 irqc->nr_irq = FIELD_GET(AIC2_INFO1_NR_IRQ, info1); in aic_of_ic_init()
1098 irqc->max_irq = FIELD_GET(AIC2_INFO3_MAX_IRQ, info3); in aic_of_ic_init()
1099 irqc->nr_die = FIELD_GET(AIC2_INFO1_LAST_DIE, info1) + 1; in aic_of_ic_init()
1100 irqc->max_die = FIELD_GET(AIC2_INFO3_MAX_DIE, info3); in aic_of_ic_init()
1102 off = start_off = irqc->info.irq_cfg; in aic_of_ic_init()
1103 off += sizeof(u32) * irqc->max_irq; /* IRQ_CFG */ in aic_of_ic_init()
1105 irqc->event = of_iomap(node, 1); in aic_of_ic_init()
1106 if (WARN_ON(!irqc->event)) in aic_of_ic_init()
1113 irqc->info.sw_set = off; in aic_of_ic_init()
1114 off += sizeof(u32) * (irqc->max_irq >> 5); /* SW_SET */ in aic_of_ic_init()
1115 irqc->info.sw_clr = off; in aic_of_ic_init()
1116 off += sizeof(u32) * (irqc->max_irq >> 5); /* SW_CLR */ in aic_of_ic_init()
1117 irqc->info.mask_set = off; in aic_of_ic_init()
1118 off += sizeof(u32) * (irqc->max_irq >> 5); /* MASK_SET */ in aic_of_ic_init()
1119 irqc->info.mask_clr = off; in aic_of_ic_init()
1120 off += sizeof(u32) * (irqc->max_irq >> 5); /* MASK_CLR */ in aic_of_ic_init()
1121 off += sizeof(u32) * (irqc->max_irq >> 5); /* HW_STATE */ in aic_of_ic_init()
1123 if (irqc->info.fast_ipi) in aic_of_ic_init()
1128 irqc->info.die_stride = off - start_off; in aic_of_ic_init()
1130 irqc->hw_domain = irq_domain_create_tree(of_node_to_fwnode(node), in aic_of_ic_init()
1132 if (WARN_ON(!irqc->hw_domain)) in aic_of_ic_init()
1135 irq_domain_update_bus_token(irqc->hw_domain, DOMAIN_BUS_WIRED); in aic_of_ic_init()
1153 for (die = 0; die < irqc->nr_die; die++) { in aic_of_ic_init()
1154 for (i = 0; i < BITS_TO_U32(irqc->nr_irq); i++) in aic_of_ic_init()
1155 aic_ic_write(irqc, irqc->info.mask_set + off + i * 4, U32_MAX); in aic_of_ic_init()
1156 for (i = 0; i < BITS_TO_U32(irqc->nr_irq); i++) in aic_of_ic_init()
1157 aic_ic_write(irqc, irqc->info.sw_clr + off + i * 4, U32_MAX); in aic_of_ic_init()
1158 if (irqc->info.target_cpu) in aic_of_ic_init()
1159 for (i = 0; i < irqc->nr_irq; i++) in aic_of_ic_init()
1160 aic_ic_write(irqc, irqc->info.target_cpu + off + i * 4, 1); in aic_of_ic_init()
1161 off += irqc->info.die_stride; in aic_of_ic_init()
1164 if (irqc->info.version == 2) { in aic_of_ic_init()
1178 "irqchip/apple-aic/ipi:starting", in aic_of_ic_init()
1184 irqc->nr_irq, irqc->max_irq, irqc->nr_die, irqc->max_die, AIC_NR_FIQ, AIC_NR_SWIPI); in aic_of_ic_init()
1189 irq_domain_remove(irqc->hw_domain); in aic_of_ic_init()
1191 if (irqc->event && irqc->event != irqc->base) in aic_of_ic_init()
1192 iounmap(irqc->event); in aic_of_ic_init()
1193 iounmap(irqc->base); in aic_of_ic_init()
1195 return -ENODEV; in aic_of_ic_init()