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

Merge branch 'irqchip/stacked-exynos' into irqchip/core

+161 -22
+17
Documentation/devicetree/bindings/arm/samsung/pmu.txt
··· 29 29 - clocks : list of phandles and specifiers to all input clocks listed in 30 30 clock-names property. 31 31 32 + Optional properties: 33 + 34 + Some PMUs are capable of behaving as an interrupt controller (mostly 35 + to wake up a suspended PMU). In which case, they can have the 36 + following properties: 37 + 38 + - interrupt-controller: indicate that said PMU is an interrupt controller 39 + 40 + - #interrupt-cells: must be identical to the that of the parent interrupt 41 + controller. 42 + 43 + - interrupt-parent: a phandle indicating which interrupt controller 44 + this PMU signals interrupts to. 45 + 32 46 Example : 33 47 pmu_system_controller: system-controller@10040000 { 34 48 compatible = "samsung,exynos5250-pmu", "syscon"; 35 49 reg = <0x10040000 0x5000>; 50 + interrupt-controller; 51 + #interrupt-cells = <3>; 52 + interrupt-parent = <&gic>; 36 53 #clock-cells = <1>; 37 54 clock-names = "clkout0", "clkout1", "clkout2", "clkout3", 38 55 "clkout4", "clkout8", "clkout9";
+4
arch/arm/boot/dts/exynos3250.dtsi
··· 130 130 pmu_system_controller: system-controller@10020000 { 131 131 compatible = "samsung,exynos3250-pmu", "syscon"; 132 132 reg = <0x10020000 0x4000>; 133 + interrupt-controller; 134 + #interrupt-cells = <3>; 135 + interrupt-parent = <&gic>; 133 136 }; 134 137 135 138 mipi_phy: video-phy@10020710 { ··· 187 184 compatible = "samsung,exynos3250-rtc"; 188 185 reg = <0x10070000 0x100>; 189 186 interrupts = <0 73 0>, <0 74 0>; 187 + interrupt-parent = <&pmu_system_controller>; 190 188 status = "disabled"; 191 189 }; 192 190
+4
arch/arm/boot/dts/exynos4.dtsi
··· 152 152 pmu_system_controller: system-controller@10020000 { 153 153 compatible = "samsung,exynos4210-pmu", "syscon"; 154 154 reg = <0x10020000 0x4000>; 155 + interrupt-controller; 156 + #interrupt-cells = <3>; 157 + interrupt-parent = <&gic>; 155 158 }; 156 159 157 160 dsi_0: dsi@11C80000 { ··· 267 264 rtc@10070000 { 268 265 compatible = "samsung,s3c6410-rtc"; 269 266 reg = <0x10070000 0x100>; 267 + interrupt-parent = <&pmu_system_controller>; 270 268 interrupts = <0 44 0>, <0 45 0>; 271 269 clocks = <&clock CLK_RTC>; 272 270 clock-names = "rtc";
+4
arch/arm/boot/dts/exynos5250.dtsi
··· 196 196 clock-names = "clkout16"; 197 197 clocks = <&clock CLK_FIN_PLL>; 198 198 #clock-cells = <1>; 199 + interrupt-controller; 200 + #interrupt-cells = <3>; 201 + interrupt-parent = <&gic>; 199 202 }; 200 203 201 204 sysreg_system_controller: syscon@10050000 { ··· 235 232 rtc: rtc@101E0000 { 236 233 clocks = <&clock CLK_RTC>; 237 234 clock-names = "rtc"; 235 + interrupt-parent = <&pmu_system_controller>; 238 236 status = "disabled"; 239 237 }; 240 238
+4
arch/arm/boot/dts/exynos5420.dtsi
··· 327 327 rtc: rtc@101E0000 { 328 328 clocks = <&clock CLK_RTC>; 329 329 clock-names = "rtc"; 330 + interrupt-parent = <&pmu_system_controller>; 330 331 status = "disabled"; 331 332 }; 332 333 ··· 770 769 clock-names = "clkout16"; 771 770 clocks = <&clock CLK_FIN_PLL>; 772 771 #clock-cells = <1>; 772 + interrupt-controller; 773 + #interrupt-cells = <3>; 774 + interrupt-parent = <&gic>; 773 775 }; 774 776 775 777 sysreg_system_controller: syscon@10050000 {
+5 -10
arch/arm/mach-exynos/exynos.c
··· 166 166 exynos_map_io(); 167 167 } 168 168 169 + /* 170 + * Apparently, these SoCs are not able to wake-up from suspend using 171 + * the PMU. Too bad. Should they suddenly become capable of such a 172 + * feat, the matches below should be moved to suspend.c. 173 + */ 169 174 static const struct of_device_id exynos_dt_pmu_match[] = { 170 - { .compatible = "samsung,exynos3250-pmu" }, 171 - { .compatible = "samsung,exynos4210-pmu" }, 172 - { .compatible = "samsung,exynos4212-pmu" }, 173 - { .compatible = "samsung,exynos4412-pmu" }, 174 - { .compatible = "samsung,exynos4415-pmu" }, 175 - { .compatible = "samsung,exynos5250-pmu" }, 176 175 { .compatible = "samsung,exynos5260-pmu" }, 177 176 { .compatible = "samsung,exynos5410-pmu" }, 178 - { .compatible = "samsung,exynos5420-pmu" }, 179 177 { /*sentinel*/ }, 180 178 }; 181 179 ··· 184 186 np = of_find_matching_node(NULL, exynos_dt_pmu_match); 185 187 if (np) 186 188 pmu_base_addr = of_iomap(np, 0); 187 - 188 - if (!pmu_base_addr) 189 - panic("failed to find exynos pmu register\n"); 190 189 } 191 190 192 191 static void __init exynos_init_irq(void)
+123 -12
arch/arm/mach-exynos/suspend.c
··· 18 18 #include <linux/syscore_ops.h> 19 19 #include <linux/cpu_pm.h> 20 20 #include <linux/io.h> 21 - #include <linux/irqchip/arm-gic.h> 21 + #include <linux/irq.h> 22 + #include <linux/irqdomain.h> 23 + #include <linux/of_address.h> 22 24 #include <linux/err.h> 23 25 #include <linux/regulator/machine.h> 24 26 ··· 45 43 #define EXYNOS5420_CPU_STATE 0x28 46 44 47 45 /** 48 - * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping 49 - * @hwirq: Hardware IRQ signal of the GIC 46 + * struct exynos_wkup_irq - PMU IRQ to mask mapping 47 + * @hwirq: Hardware IRQ signal of the PMU 50 48 * @mask: Mask in PMU wake-up mask register 51 49 */ 52 50 struct exynos_wkup_irq { ··· 95 93 }; 96 94 97 95 static const struct exynos_wkup_irq exynos4_wkup_irq[] = { 98 - { 76, BIT(1) }, /* RTC alarm */ 99 - { 77, BIT(2) }, /* RTC tick */ 96 + { 44, BIT(1) }, /* RTC alarm */ 97 + { 45, BIT(2) }, /* RTC tick */ 100 98 { /* sentinel */ }, 101 99 }; 102 100 103 101 static const struct exynos_wkup_irq exynos5250_wkup_irq[] = { 104 - { 75, BIT(1) }, /* RTC alarm */ 105 - { 76, BIT(2) }, /* RTC tick */ 102 + { 43, BIT(1) }, /* RTC alarm */ 103 + { 44, BIT(2) }, /* RTC tick */ 106 104 { /* sentinel */ }, 107 105 }; 108 106 ··· 168 166 169 167 return -ENOENT; 170 168 } 169 + 170 + static struct irq_chip exynos_pmu_chip = { 171 + .name = "PMU", 172 + .irq_eoi = irq_chip_eoi_parent, 173 + .irq_mask = irq_chip_mask_parent, 174 + .irq_unmask = irq_chip_unmask_parent, 175 + .irq_retrigger = irq_chip_retrigger_hierarchy, 176 + .irq_set_wake = exynos_irq_set_wake, 177 + #ifdef CONFIG_SMP 178 + .irq_set_affinity = irq_chip_set_affinity_parent, 179 + #endif 180 + }; 181 + 182 + static int exynos_pmu_domain_xlate(struct irq_domain *domain, 183 + struct device_node *controller, 184 + const u32 *intspec, 185 + unsigned int intsize, 186 + unsigned long *out_hwirq, 187 + unsigned int *out_type) 188 + { 189 + if (domain->of_node != controller) 190 + return -EINVAL; /* Shouldn't happen, really... */ 191 + if (intsize != 3) 192 + return -EINVAL; /* Not GIC compliant */ 193 + if (intspec[0] != 0) 194 + return -EINVAL; /* No PPI should point to this domain */ 195 + 196 + *out_hwirq = intspec[1]; 197 + *out_type = intspec[2]; 198 + return 0; 199 + } 200 + 201 + static int exynos_pmu_domain_alloc(struct irq_domain *domain, 202 + unsigned int virq, 203 + unsigned int nr_irqs, void *data) 204 + { 205 + struct of_phandle_args *args = data; 206 + struct of_phandle_args parent_args; 207 + irq_hw_number_t hwirq; 208 + int i; 209 + 210 + if (args->args_count != 3) 211 + return -EINVAL; /* Not GIC compliant */ 212 + if (args->args[0] != 0) 213 + return -EINVAL; /* No PPI should point to this domain */ 214 + 215 + hwirq = args->args[1]; 216 + 217 + for (i = 0; i < nr_irqs; i++) 218 + irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, 219 + &exynos_pmu_chip, NULL); 220 + 221 + parent_args = *args; 222 + parent_args.np = domain->parent->of_node; 223 + return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_args); 224 + } 225 + 226 + static struct irq_domain_ops exynos_pmu_domain_ops = { 227 + .xlate = exynos_pmu_domain_xlate, 228 + .alloc = exynos_pmu_domain_alloc, 229 + .free = irq_domain_free_irqs_common, 230 + }; 231 + 232 + static int __init exynos_pmu_irq_init(struct device_node *node, 233 + struct device_node *parent) 234 + { 235 + struct irq_domain *parent_domain, *domain; 236 + 237 + if (!parent) { 238 + pr_err("%s: no parent, giving up\n", node->full_name); 239 + return -ENODEV; 240 + } 241 + 242 + parent_domain = irq_find_host(parent); 243 + if (!parent_domain) { 244 + pr_err("%s: unable to obtain parent domain\n", node->full_name); 245 + return -ENXIO; 246 + } 247 + 248 + pmu_base_addr = of_iomap(node, 0); 249 + 250 + if (!pmu_base_addr) { 251 + pr_err("%s: failed to find exynos pmu register\n", 252 + node->full_name); 253 + return -ENOMEM; 254 + } 255 + 256 + domain = irq_domain_add_hierarchy(parent_domain, 0, 0, 257 + node, &exynos_pmu_domain_ops, 258 + NULL); 259 + if (!domain) { 260 + iounmap(pmu_base_addr); 261 + return -ENOMEM; 262 + } 263 + 264 + return 0; 265 + } 266 + 267 + #define EXYNOS_PMU_IRQ(symbol, name) OF_DECLARE_2(irqchip, symbol, name, exynos_pmu_irq_init) 268 + 269 + EXYNOS_PMU_IRQ(exynos3250_pmu_irq, "samsung,exynos3250-pmu"); 270 + EXYNOS_PMU_IRQ(exynos4210_pmu_irq, "samsung,exynos4210-pmu"); 271 + EXYNOS_PMU_IRQ(exynos4212_pmu_irq, "samsung,exynos4212-pmu"); 272 + EXYNOS_PMU_IRQ(exynos4412_pmu_irq, "samsung,exynos4412-pmu"); 273 + EXYNOS_PMU_IRQ(exynos4415_pmu_irq, "samsung,exynos4415-pmu"); 274 + EXYNOS_PMU_IRQ(exynos5250_pmu_irq, "samsung,exynos5250-pmu"); 275 + EXYNOS_PMU_IRQ(exynos5420_pmu_irq, "samsung,exynos5420-pmu"); 171 276 172 277 static int exynos_cpu_do_idle(void) 173 278 { ··· 724 615 void __init exynos_pm_init(void) 725 616 { 726 617 const struct of_device_id *match; 618 + struct device_node *np; 727 619 u32 tmp; 728 620 729 - of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match); 730 - if (!match) { 621 + np = of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match); 622 + if (!np) { 731 623 pr_err("Failed to find PMU node\n"); 732 624 return; 733 625 } 734 - pm_data = (struct exynos_pm_data *) match->data; 735 626 736 - /* Platform-specific GIC callback */ 737 - gic_arch_extn.irq_set_wake = exynos_irq_set_wake; 627 + if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL))) 628 + pr_warn("Outdated DT detected, suspend/resume will NOT work\n"); 629 + 630 + pm_data = (struct exynos_pm_data *) match->data; 738 631 739 632 /* All wakeup disable */ 740 633 tmp = pmu_raw_readl(S5P_WAKEUP_MASK);