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