Commit fb414e90 authored by Jason Cooper's avatar Jason Cooper

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

parents 07c523f1 d4ad0759
...@@ -29,10 +29,27 @@ Properties: ...@@ -29,10 +29,27 @@ Properties:
- clocks : list of phandles and specifiers to all input clocks listed in - clocks : list of phandles and specifiers to all input clocks listed in
clock-names property. clock-names property.
Optional properties:
Some PMUs are capable of behaving as an interrupt controller (mostly
to wake up a suspended PMU). In which case, they can have the
following properties:
- interrupt-controller: indicate that said PMU is an interrupt controller
- #interrupt-cells: must be identical to the that of the parent interrupt
controller.
- interrupt-parent: a phandle indicating which interrupt controller
this PMU signals interrupts to.
Example : Example :
pmu_system_controller: system-controller@10040000 { pmu_system_controller: system-controller@10040000 {
compatible = "samsung,exynos5250-pmu", "syscon"; compatible = "samsung,exynos5250-pmu", "syscon";
reg = <0x10040000 0x5000>; reg = <0x10040000 0x5000>;
interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&gic>;
#clock-cells = <1>; #clock-cells = <1>;
clock-names = "clkout0", "clkout1", "clkout2", "clkout3", clock-names = "clkout0", "clkout1", "clkout2", "clkout3",
"clkout4", "clkout8", "clkout9"; "clkout4", "clkout8", "clkout9";
......
...@@ -130,6 +130,9 @@ sys_reg: syscon@10010000 { ...@@ -130,6 +130,9 @@ sys_reg: syscon@10010000 {
pmu_system_controller: system-controller@10020000 { pmu_system_controller: system-controller@10020000 {
compatible = "samsung,exynos3250-pmu", "syscon"; compatible = "samsung,exynos3250-pmu", "syscon";
reg = <0x10020000 0x4000>; reg = <0x10020000 0x4000>;
interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&gic>;
}; };
mipi_phy: video-phy@10020710 { mipi_phy: video-phy@10020710 {
...@@ -184,6 +187,7 @@ rtc: rtc@10070000 { ...@@ -184,6 +187,7 @@ rtc: rtc@10070000 {
compatible = "samsung,exynos3250-rtc"; compatible = "samsung,exynos3250-rtc";
reg = <0x10070000 0x100>; reg = <0x10070000 0x100>;
interrupts = <0 73 0>, <0 74 0>; interrupts = <0 73 0>, <0 74 0>;
interrupt-parent = <&pmu_system_controller>;
status = "disabled"; status = "disabled";
}; };
......
...@@ -152,6 +152,9 @@ sys_reg: syscon@10010000 { ...@@ -152,6 +152,9 @@ sys_reg: syscon@10010000 {
pmu_system_controller: system-controller@10020000 { pmu_system_controller: system-controller@10020000 {
compatible = "samsung,exynos4210-pmu", "syscon"; compatible = "samsung,exynos4210-pmu", "syscon";
reg = <0x10020000 0x4000>; reg = <0x10020000 0x4000>;
interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&gic>;
}; };
dsi_0: dsi@11C80000 { dsi_0: dsi@11C80000 {
...@@ -264,6 +267,7 @@ watchdog@10060000 { ...@@ -264,6 +267,7 @@ watchdog@10060000 {
rtc@10070000 { rtc@10070000 {
compatible = "samsung,s3c6410-rtc"; compatible = "samsung,s3c6410-rtc";
reg = <0x10070000 0x100>; reg = <0x10070000 0x100>;
interrupt-parent = <&pmu_system_controller>;
interrupts = <0 44 0>, <0 45 0>; interrupts = <0 44 0>, <0 45 0>;
clocks = <&clock CLK_RTC>; clocks = <&clock CLK_RTC>;
clock-names = "rtc"; clock-names = "rtc";
......
...@@ -196,6 +196,9 @@ pmu_system_controller: system-controller@10040000 { ...@@ -196,6 +196,9 @@ pmu_system_controller: system-controller@10040000 {
clock-names = "clkout16"; clock-names = "clkout16";
clocks = <&clock CLK_FIN_PLL>; clocks = <&clock CLK_FIN_PLL>;
#clock-cells = <1>; #clock-cells = <1>;
interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&gic>;
}; };
sysreg_system_controller: syscon@10050000 { sysreg_system_controller: syscon@10050000 {
...@@ -232,6 +235,7 @@ mfc: codec@11000000 { ...@@ -232,6 +235,7 @@ mfc: codec@11000000 {
rtc: rtc@101E0000 { rtc: rtc@101E0000 {
clocks = <&clock CLK_RTC>; clocks = <&clock CLK_RTC>;
clock-names = "rtc"; clock-names = "rtc";
interrupt-parent = <&pmu_system_controller>;
status = "disabled"; status = "disabled";
}; };
......
...@@ -327,6 +327,7 @@ pinctrl_4: pinctrl@03860000 { ...@@ -327,6 +327,7 @@ pinctrl_4: pinctrl@03860000 {
rtc: rtc@101E0000 { rtc: rtc@101E0000 {
clocks = <&clock CLK_RTC>; clocks = <&clock CLK_RTC>;
clock-names = "rtc"; clock-names = "rtc";
interrupt-parent = <&pmu_system_controller>;
status = "disabled"; status = "disabled";
}; };
...@@ -769,6 +770,9 @@ pmu_system_controller: system-controller@10040000 { ...@@ -769,6 +770,9 @@ pmu_system_controller: system-controller@10040000 {
clock-names = "clkout16"; clock-names = "clkout16";
clocks = <&clock CLK_FIN_PLL>; clocks = <&clock CLK_FIN_PLL>;
#clock-cells = <1>; #clock-cells = <1>;
interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&gic>;
}; };
sysreg_system_controller: syscon@10050000 { sysreg_system_controller: syscon@10050000 {
......
...@@ -166,16 +166,14 @@ static void __init exynos_init_io(void) ...@@ -166,16 +166,14 @@ static void __init exynos_init_io(void)
exynos_map_io(); exynos_map_io();
} }
/*
* Apparently, these SoCs are not able to wake-up from suspend using
* the PMU. Too bad. Should they suddenly become capable of such a
* feat, the matches below should be moved to suspend.c.
*/
static const struct of_device_id exynos_dt_pmu_match[] = { static const struct of_device_id exynos_dt_pmu_match[] = {
{ .compatible = "samsung,exynos3250-pmu" },
{ .compatible = "samsung,exynos4210-pmu" },
{ .compatible = "samsung,exynos4212-pmu" },
{ .compatible = "samsung,exynos4412-pmu" },
{ .compatible = "samsung,exynos4415-pmu" },
{ .compatible = "samsung,exynos5250-pmu" },
{ .compatible = "samsung,exynos5260-pmu" }, { .compatible = "samsung,exynos5260-pmu" },
{ .compatible = "samsung,exynos5410-pmu" }, { .compatible = "samsung,exynos5410-pmu" },
{ .compatible = "samsung,exynos5420-pmu" },
{ /*sentinel*/ }, { /*sentinel*/ },
}; };
...@@ -186,9 +184,6 @@ static void exynos_map_pmu(void) ...@@ -186,9 +184,6 @@ static void exynos_map_pmu(void)
np = of_find_matching_node(NULL, exynos_dt_pmu_match); np = of_find_matching_node(NULL, exynos_dt_pmu_match);
if (np) if (np)
pmu_base_addr = of_iomap(np, 0); pmu_base_addr = of_iomap(np, 0);
if (!pmu_base_addr)
panic("failed to find exynos pmu register\n");
} }
static void __init exynos_init_irq(void) static void __init exynos_init_irq(void)
......
...@@ -18,7 +18,9 @@ ...@@ -18,7 +18,9 @@
#include <linux/syscore_ops.h> #include <linux/syscore_ops.h>
#include <linux/cpu_pm.h> #include <linux/cpu_pm.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/irqchip/arm-gic.h> #include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/of_address.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
...@@ -43,8 +45,8 @@ ...@@ -43,8 +45,8 @@
#define EXYNOS5420_CPU_STATE 0x28 #define EXYNOS5420_CPU_STATE 0x28
/** /**
* struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping * struct exynos_wkup_irq - PMU IRQ to mask mapping
* @hwirq: Hardware IRQ signal of the GIC * @hwirq: Hardware IRQ signal of the PMU
* @mask: Mask in PMU wake-up mask register * @mask: Mask in PMU wake-up mask register
*/ */
struct exynos_wkup_irq { struct exynos_wkup_irq {
...@@ -93,14 +95,14 @@ static const struct exynos_wkup_irq exynos3250_wkup_irq[] = { ...@@ -93,14 +95,14 @@ static const struct exynos_wkup_irq exynos3250_wkup_irq[] = {
}; };
static const struct exynos_wkup_irq exynos4_wkup_irq[] = { static const struct exynos_wkup_irq exynos4_wkup_irq[] = {
{ 76, BIT(1) }, /* RTC alarm */ { 44, BIT(1) }, /* RTC alarm */
{ 77, BIT(2) }, /* RTC tick */ { 45, BIT(2) }, /* RTC tick */
{ /* sentinel */ }, { /* sentinel */ },
}; };
static const struct exynos_wkup_irq exynos5250_wkup_irq[] = { static const struct exynos_wkup_irq exynos5250_wkup_irq[] = {
{ 75, BIT(1) }, /* RTC alarm */ { 43, BIT(1) }, /* RTC alarm */
{ 76, BIT(2) }, /* RTC tick */ { 44, BIT(2) }, /* RTC tick */
{ /* sentinel */ }, { /* sentinel */ },
}; };
...@@ -167,6 +169,113 @@ static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) ...@@ -167,6 +169,113 @@ static int exynos_irq_set_wake(struct irq_data *data, unsigned int state)
return -ENOENT; return -ENOENT;
} }
static struct irq_chip exynos_pmu_chip = {
.name = "PMU",
.irq_eoi = irq_chip_eoi_parent,
.irq_mask = irq_chip_mask_parent,
.irq_unmask = irq_chip_unmask_parent,
.irq_retrigger = irq_chip_retrigger_hierarchy,
.irq_set_wake = exynos_irq_set_wake,
#ifdef CONFIG_SMP
.irq_set_affinity = irq_chip_set_affinity_parent,
#endif
};
static int exynos_pmu_domain_xlate(struct irq_domain *domain,
struct device_node *controller,
const u32 *intspec,
unsigned int intsize,
unsigned long *out_hwirq,
unsigned int *out_type)
{
if (domain->of_node != controller)
return -EINVAL; /* Shouldn't happen, really... */
if (intsize != 3)
return -EINVAL; /* Not GIC compliant */
if (intspec[0] != 0)
return -EINVAL; /* No PPI should point to this domain */
*out_hwirq = intspec[1];
*out_type = intspec[2];
return 0;
}
static int exynos_pmu_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs, void *data)
{
struct of_phandle_args *args = data;
struct of_phandle_args parent_args;
irq_hw_number_t hwirq;
int i;
if (args->args_count != 3)
return -EINVAL; /* Not GIC compliant */
if (args->args[0] != 0)
return -EINVAL; /* No PPI should point to this domain */
hwirq = args->args[1];
for (i = 0; i < nr_irqs; i++)
irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
&exynos_pmu_chip, NULL);
parent_args = *args;
parent_args.np = domain->parent->of_node;
return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_args);
}
static struct irq_domain_ops exynos_pmu_domain_ops = {
.xlate = exynos_pmu_domain_xlate,
.alloc = exynos_pmu_domain_alloc,
.free = irq_domain_free_irqs_common,
};
static int __init exynos_pmu_irq_init(struct device_node *node,
struct device_node *parent)
{
struct irq_domain *parent_domain, *domain;
if (!parent) {
pr_err("%s: no parent, giving up\n", node->full_name);
return -ENODEV;
}
parent_domain = irq_find_host(parent);
if (!parent_domain) {
pr_err("%s: unable to obtain parent domain\n", node->full_name);
return -ENXIO;
}
pmu_base_addr = of_iomap(node, 0);
if (!pmu_base_addr) {
pr_err("%s: failed to find exynos pmu register\n",
node->full_name);
return -ENOMEM;
}
domain = irq_domain_add_hierarchy(parent_domain, 0, 0,
node, &exynos_pmu_domain_ops,
NULL);
if (!domain) {
iounmap(pmu_base_addr);
return -ENOMEM;
}
return 0;
}
#define EXYNOS_PMU_IRQ(symbol, name) OF_DECLARE_2(irqchip, symbol, name, exynos_pmu_irq_init)
EXYNOS_PMU_IRQ(exynos3250_pmu_irq, "samsung,exynos3250-pmu");
EXYNOS_PMU_IRQ(exynos4210_pmu_irq, "samsung,exynos4210-pmu");
EXYNOS_PMU_IRQ(exynos4212_pmu_irq, "samsung,exynos4212-pmu");
EXYNOS_PMU_IRQ(exynos4412_pmu_irq, "samsung,exynos4412-pmu");
EXYNOS_PMU_IRQ(exynos4415_pmu_irq, "samsung,exynos4415-pmu");
EXYNOS_PMU_IRQ(exynos5250_pmu_irq, "samsung,exynos5250-pmu");
EXYNOS_PMU_IRQ(exynos5420_pmu_irq, "samsung,exynos5420-pmu");
static int exynos_cpu_do_idle(void) static int exynos_cpu_do_idle(void)
{ {
/* issue the standby signal into the pm unit. */ /* issue the standby signal into the pm unit. */
...@@ -615,17 +724,19 @@ static struct syscore_ops exynos_pm_syscore_ops; ...@@ -615,17 +724,19 @@ static struct syscore_ops exynos_pm_syscore_ops;
void __init exynos_pm_init(void) void __init exynos_pm_init(void)
{ {
const struct of_device_id *match; const struct of_device_id *match;
struct device_node *np;
u32 tmp; u32 tmp;
of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match); np = of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match);
if (!match) { if (!np) {
pr_err("Failed to find PMU node\n"); pr_err("Failed to find PMU node\n");
return; return;
} }
pm_data = (struct exynos_pm_data *) match->data;
/* Platform-specific GIC callback */ if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL)))
gic_arch_extn.irq_set_wake = exynos_irq_set_wake; pr_warn("Outdated DT detected, suspend/resume will NOT work\n");
pm_data = (struct exynos_pm_data *) match->data;
/* All wakeup disable */ /* All wakeup disable */
tmp = pmu_raw_readl(S5P_WAKEUP_MASK); tmp = pmu_raw_readl(S5P_WAKEUP_MASK);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment