^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright 2011-2013 Freescale Semiconductor, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright 2011 Linaro Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/irqchip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/of_irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "hardware.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define GPC_CNTR 0x0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define GPC_IMR1 0x008
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define GPC_PGC_CPU_PDN 0x2a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define GPC_PGC_CPU_PUPSCR 0x2a4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define GPC_PGC_CPU_PDNSCR 0x2a8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define GPC_PGC_SW2ISO_SHIFT 0x8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define GPC_PGC_SW_SHIFT 0x0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define GPC_CNTR_L2_PGE_SHIFT 22
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define IMR_NUM 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define GPC_MAX_IRQS (IMR_NUM * 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static void __iomem *gpc_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static u32 gpc_wake_irqs[IMR_NUM];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static u32 gpc_saved_imrs[IMR_NUM];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) void imx_gpc_set_arm_power_up_timing(u32 sw2iso, u32 sw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) writel_relaxed((sw2iso << GPC_PGC_SW2ISO_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) (sw << GPC_PGC_SW_SHIFT), gpc_base + GPC_PGC_CPU_PUPSCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) void imx_gpc_set_arm_power_down_timing(u32 sw2iso, u32 sw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) writel_relaxed((sw2iso << GPC_PGC_SW2ISO_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) (sw << GPC_PGC_SW_SHIFT), gpc_base + GPC_PGC_CPU_PDNSCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) void imx_gpc_set_arm_power_in_lpm(bool power_off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) writel_relaxed(power_off, gpc_base + GPC_PGC_CPU_PDN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) void imx_gpc_set_l2_mem_power_in_lpm(bool power_off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) val = readl_relaxed(gpc_base + GPC_CNTR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) val &= ~(1 << GPC_CNTR_L2_PGE_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (power_off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) val |= 1 << GPC_CNTR_L2_PGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) writel_relaxed(val, gpc_base + GPC_CNTR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) void imx_gpc_pre_suspend(bool arm_power_off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) /* Tell GPC to power off ARM core when suspend */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) if (arm_power_off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) imx_gpc_set_arm_power_in_lpm(arm_power_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) for (i = 0; i < IMR_NUM; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) gpc_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) writel_relaxed(~gpc_wake_irqs[i], reg_imr1 + i * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) void imx_gpc_post_resume(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) /* Keep ARM core powered on for other low-power modes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) imx_gpc_set_arm_power_in_lpm(false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) for (i = 0; i < IMR_NUM; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) unsigned int idx = d->hwirq / 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) u32 mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) mask = 1 << d->hwirq % 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) gpc_wake_irqs[idx] = on ? gpc_wake_irqs[idx] | mask :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) gpc_wake_irqs[idx] & ~mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * Do *not* call into the parent, as the GIC doesn't have any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * wake-up facility...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) void imx_gpc_mask_all(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) for (i = 0; i < IMR_NUM; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) gpc_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) writel_relaxed(~0, reg_imr1 + i * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) void imx_gpc_restore_all(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) for (i = 0; i < IMR_NUM; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) void imx_gpc_hwirq_unmask(unsigned int hwirq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) void __iomem *reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) reg = gpc_base + GPC_IMR1 + hwirq / 32 * 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) val = readl_relaxed(reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) val &= ~(1 << hwirq % 32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) writel_relaxed(val, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) void imx_gpc_hwirq_mask(unsigned int hwirq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) void __iomem *reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) reg = gpc_base + GPC_IMR1 + hwirq / 32 * 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) val = readl_relaxed(reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) val |= 1 << (hwirq % 32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) writel_relaxed(val, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) static void imx_gpc_irq_unmask(struct irq_data *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) imx_gpc_hwirq_unmask(d->hwirq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) irq_chip_unmask_parent(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) static void imx_gpc_irq_mask(struct irq_data *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) imx_gpc_hwirq_mask(d->hwirq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) irq_chip_mask_parent(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) static struct irq_chip imx_gpc_chip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) .name = "GPC",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) .irq_eoi = irq_chip_eoi_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) .irq_mask = imx_gpc_irq_mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) .irq_unmask = imx_gpc_irq_unmask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) .irq_retrigger = irq_chip_retrigger_hierarchy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) .irq_set_wake = imx_gpc_irq_set_wake,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) .irq_set_type = irq_chip_set_type_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) #ifdef CONFIG_SMP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) .irq_set_affinity = irq_chip_set_affinity_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) static int imx_gpc_domain_translate(struct irq_domain *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) struct irq_fwspec *fwspec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) unsigned long *hwirq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) unsigned int *type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (is_of_node(fwspec->fwnode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (fwspec->param_count != 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) /* No PPI should point to this domain */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) if (fwspec->param[0] != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) *hwirq = fwspec->param[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) *type = fwspec->param[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) static int imx_gpc_domain_alloc(struct irq_domain *domain,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) unsigned int irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) unsigned int nr_irqs, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) struct irq_fwspec *fwspec = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) struct irq_fwspec parent_fwspec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) irq_hw_number_t hwirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) if (fwspec->param_count != 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) return -EINVAL; /* Not GIC compliant */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (fwspec->param[0] != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return -EINVAL; /* No PPI should point to this domain */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) hwirq = fwspec->param[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) if (hwirq >= GPC_MAX_IRQS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return -EINVAL; /* Can't deal with this */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) for (i = 0; i < nr_irqs; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) irq_domain_set_hwirq_and_chip(domain, irq + i, hwirq + i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) &imx_gpc_chip, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) parent_fwspec = *fwspec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) parent_fwspec.fwnode = domain->parent->fwnode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) return irq_domain_alloc_irqs_parent(domain, irq, nr_irqs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) &parent_fwspec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) static const struct irq_domain_ops imx_gpc_domain_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) .translate = imx_gpc_domain_translate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) .alloc = imx_gpc_domain_alloc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) .free = irq_domain_free_irqs_common,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) static int __init imx_gpc_init(struct device_node *node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) struct device_node *parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) struct irq_domain *parent_domain, *domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (!parent) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) pr_err("%pOF: no parent, giving up\n", node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) parent_domain = irq_find_host(parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) if (!parent_domain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) pr_err("%pOF: unable to obtain parent domain\n", node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) gpc_base = of_iomap(node, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) if (WARN_ON(!gpc_base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) domain = irq_domain_add_hierarchy(parent_domain, 0, GPC_MAX_IRQS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) node, &imx_gpc_domain_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) if (!domain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) iounmap(gpc_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) /* Initially mask all interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) for (i = 0; i < IMR_NUM; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) writel_relaxed(~0, gpc_base + GPC_IMR1 + i * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) * Clear the OF_POPULATED flag set in of_irq_init so that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) * later the GPC power domain driver will not be skipped.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) of_node_clear_flag(node, OF_POPULATED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) IRQCHIP_DECLARE(imx_gpc, "fsl,imx6q-gpc", imx_gpc_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) void __init imx_gpc_check_dt(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if (WARN_ON(!np))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) pr_warn("Outdated DT detected, suspend/resume will NOT work\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) /* map GPC, so that at least CPUidle and WARs keep working */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) gpc_base = of_iomap(np, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) }