Re: [PATCH v4 14/21] ARM: imx6: convert GPC to stacked domains

2015-01-20 Thread Shawn Guo
On Mon, Jan 19, 2015 at 09:44:08AM +, Marc Zyngier wrote:
 IMX6 has been (ab)using the gic_arch_extn to provide
 wakeup from suspend, and it makes a lot of sense to convert
 this code to use stacked domains instead.
 
 This patch does just this, updating the DT files to actually
 reflect what the HW provides.
 
 BIG FAT WARNING: because the DTs were so far lying by not
 exposing the fact that the GPC block is actually the first
 interrupt controller in the chain, kernels with this patch
 applied wont have any suspend-resume facility when booted
 with old DTs, and old kernels with updated DTs won't even boot.
 
 Tested-by: Stefan Agner ste...@agner.ch
 Acked-by: Stefan Agner ste...@agner.ch
 Signed-off-by: Marc Zyngier marc.zyng...@arm.com

Acked-by: Shawn Guo shawn@linaro.org
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 14/21] ARM: imx6: convert GPC to stacked domains

2015-01-19 Thread Marc Zyngier
IMX6 has been (ab)using the gic_arch_extn to provide
wakeup from suspend, and it makes a lot of sense to convert
this code to use stacked domains instead.

This patch does just this, updating the DT files to actually
reflect what the HW provides.

BIG FAT WARNING: because the DTs were so far lying by not
exposing the fact that the GPC block is actually the first
interrupt controller in the chain, kernels with this patch
applied wont have any suspend-resume facility when booted
with old DTs, and old kernels with updated DTs won't even boot.

Tested-by: Stefan Agner ste...@agner.ch
Acked-by: Stefan Agner ste...@agner.ch
Signed-off-by: Marc Zyngier marc.zyng...@arm.com
---
 arch/arm/boot/dts/imx6qdl.dtsi  |   7 ++-
 arch/arm/boot/dts/imx6sl.dtsi   |   6 +-
 arch/arm/boot/dts/imx6sx.dtsi   |   6 +-
 arch/arm/mach-imx/common.h  |   1 -
 arch/arm/mach-imx/gpc.c | 127 
 arch/arm/mach-imx/mach-imx6q.c  |   1 -
 arch/arm/mach-imx/mach-imx6sl.c |   1 -
 arch/arm/mach-imx/mach-imx6sx.c |   1 -
 8 files changed, 119 insertions(+), 31 deletions(-)

diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 4fc03b7..aff9ded 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -53,6 +53,7 @@
interrupt-controller;
reg = 0x00a01000 0x1000,
  0x00a00100 0x100;
+   interrupt-parent = intc;
};
 
clocks {
@@ -82,7 +83,7 @@
#address-cells = 1;
#size-cells = 1;
compatible = simple-bus;
-   interrupt-parent = intc;
+   interrupt-parent = gpc;
ranges;
 
dma_apbh: dma-apbh@0011 {
@@ -122,6 +123,7 @@
compatible = arm,cortex-a9-twd-timer;
reg = 0x00a00600 0x20;
interrupts = 1 13 0xf01;
+   interrupt-parent = intc;
clocks = clks IMX6QDL_CLK_TWD;
};
 
@@ -694,8 +696,11 @@
gpc: gpc@020dc000 {
compatible = fsl,imx6q-gpc;
reg = 0x020dc000 0x4000;
+   interrupt-controller;
+   #interrupt-cells = 3;
interrupts = 0 89 IRQ_TYPE_LEVEL_HIGH,
 0 90 IRQ_TYPE_LEVEL_HIGH;
+   interrupt-parent = intc;
};
 
gpr: iomuxc-gpr@020e {
diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
index 36ab8e0..0d0962b 100644
--- a/arch/arm/boot/dts/imx6sl.dtsi
+++ b/arch/arm/boot/dts/imx6sl.dtsi
@@ -72,6 +72,7 @@
interrupt-controller;
reg = 0x00a01000 0x1000,
  0x00a00100 0x100;
+   interrupt-parent = intc;
};
 
clocks {
@@ -95,7 +96,7 @@
#address-cells = 1;
#size-cells = 1;
compatible = simple-bus;
-   interrupt-parent = intc;
+   interrupt-parent = gpc;
ranges;
 
ocram: sram@0090 {
@@ -603,7 +604,10 @@
gpc: gpc@020dc000 {
compatible = fsl,imx6sl-gpc, fsl,imx6q-gpc;
reg = 0x020dc000 0x4000;
+   interrupt-controller;
+   #interrupt-cells = 3;
interrupts = 0 89 IRQ_TYPE_LEVEL_HIGH;
+   interrupt-parent = intc;
};
 
gpr: iomuxc-gpr@020e {
diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi
index 7a24fee..dabaf89 100644
--- a/arch/arm/boot/dts/imx6sx.dtsi
+++ b/arch/arm/boot/dts/imx6sx.dtsi
@@ -88,6 +88,7 @@
interrupt-controller;
reg = 0x00a01000 0x1000,
  0x00a00100 0x100;
+   interrupt-parent = intc;
};
 
clocks {
@@ -131,7 +132,7 @@
#address-cells = 1;
#size-cells = 1;
compatible = simple-bus;
-   interrupt-parent = intc;
+   interrupt-parent = gpc;
ranges;
 
pmu {
@@ -700,7 +701,10 @@
gpc: gpc@020dc000 {
compatible = fsl,imx6sx-gpc, fsl,imx6q-gpc;
reg = 0x020dc000 0x4000;
+   interrupt-controller;
+   #interrupt-cells = 3;
interrupts = GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH;
+   interrupt-parent = intc;
};
 
iomuxc: iomuxc@020e {
diff --git 

Re: [PATCH v4 14/21] ARM: imx6: convert GPC to stacked domains

2015-01-19 Thread Lucas Stach
Am Montag, den 19.01.2015, 09:44 + schrieb Marc Zyngier:
 IMX6 has been (ab)using the gic_arch_extn to provide
 wakeup from suspend, and it makes a lot of sense to convert
 this code to use stacked domains instead.
 
 This patch does just this, updating the DT files to actually
 reflect what the HW provides.
 
 BIG FAT WARNING: because the DTs were so far lying by not
 exposing the fact that the GPC block is actually the first
 interrupt controller in the chain, kernels with this patch
 applied wont have any suspend-resume facility when booted
 with old DTs, and old kernels with updated DTs won't even boot.
 
 Tested-by: Stefan Agner ste...@agner.ch
 Acked-by: Stefan Agner ste...@agner.ch
 Signed-off-by: Marc Zyngier marc.zyng...@arm.com
 ---
  arch/arm/boot/dts/imx6qdl.dtsi  |   7 ++-
  arch/arm/boot/dts/imx6sl.dtsi   |   6 +-
  arch/arm/boot/dts/imx6sx.dtsi   |   6 +-
  arch/arm/mach-imx/common.h  |   1 -
  arch/arm/mach-imx/gpc.c | 127 
 
  arch/arm/mach-imx/mach-imx6q.c  |   1 -
  arch/arm/mach-imx/mach-imx6sl.c |   1 -
  arch/arm/mach-imx/mach-imx6sx.c |   1 -
  8 files changed, 119 insertions(+), 31 deletions(-)
 
[...]

 --- a/arch/arm/mach-imx/common.h
 +++ b/arch/arm/mach-imx/common.h
 @@ -102,7 +102,6 @@ static inline void imx_scu_map_io(void) {}
  static inline void imx_smp_prepare(void) {}
  #endif
  void imx_src_init(void);
 -void imx_gpc_init(void);
  void imx_gpc_pre_suspend(bool arm_power_off);
  void imx_gpc_post_resume(void);
  void imx_gpc_mask_all(void);
 diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
 index 5f3602e..838da3c 100644
 --- a/arch/arm/mach-imx/gpc.c
 +++ b/arch/arm/mach-imx/gpc.c
 @@ -22,6 +22,7 @@
  #define GPC_PGC_CPU_PDN  0x2a0
  
  #define IMR_NUM  4
 +#define GPC_MAX_IRQS (IMR_NUM * 32)
  
  static void __iomem *gpc_base;
  static u32 gpc_wake_irqs[IMR_NUM];
 @@ -56,17 +57,17 @@ void imx_gpc_post_resume(void)
  
  static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on)
  {
 - unsigned int idx = d-hwirq / 32 - 1;
 + unsigned int idx = d-hwirq / 32;
   u32 mask;
  
 - /* Sanity check for SPI irq */
 - if (d-hwirq  32)
 - return -EINVAL;
 -
   mask = 1  d-hwirq % 32;
   gpc_wake_irqs[idx] = on ? gpc_wake_irqs[idx] | mask :
 gpc_wake_irqs[idx]  ~mask;
  
 + /*
 +  * Do *not* call into the parent, as the GIC doesn't have any
 +  * wake-up facility...
 +  */
   return 0;
  }
  
 @@ -96,7 +97,7 @@ void imx_gpc_hwirq_unmask(unsigned int hwirq)
   void __iomem *reg;
   u32 val;
  
 - reg = gpc_base + GPC_IMR1 + (hwirq / 32 - 1) * 4;
 + reg = gpc_base + GPC_IMR1 + hwirq / 32 * 4;
   val = readl_relaxed(reg);
   val = ~(1  hwirq % 32);
   writel_relaxed(val, reg);
 @@ -107,7 +108,7 @@ void imx_gpc_hwirq_mask(unsigned int hwirq)
   void __iomem *reg;
   u32 val;
  
 - reg = gpc_base + GPC_IMR1 + (hwirq / 32 - 1) * 4;
 + reg = gpc_base + GPC_IMR1 + hwirq / 32 * 4;
   val = readl_relaxed(reg);
   val |= 1  (hwirq % 32);
   writel_relaxed(val, reg);
 @@ -115,37 +116,115 @@ void imx_gpc_hwirq_mask(unsigned int hwirq)
  
  static void imx_gpc_irq_unmask(struct irq_data *d)
  {
 - /* Sanity check for SPI irq */
 - if (d-hwirq  32)
 - return;
 -
   imx_gpc_hwirq_unmask(d-hwirq);
 + irq_chip_unmask_parent(d);
  }
  
  static void imx_gpc_irq_mask(struct irq_data *d)
  {
 - /* Sanity check for SPI irq */
 - if (d-hwirq  32)
 - return;
 -
   imx_gpc_hwirq_mask(d-hwirq);
 + irq_chip_mask_parent(d);
 +}
 +
 +static struct irq_chip imx_gpc_chip = {
 + .name   = GPC,
 + .irq_eoi= irq_chip_eoi_parent,
 + .irq_mask   = imx_gpc_irq_mask,
 + .irq_unmask = imx_gpc_irq_unmask,
 + .irq_retrigger  = irq_chip_retrigger_hierarchy,
 + .irq_set_wake   = imx_gpc_irq_set_wake,
 +};
 +
 +static int imx_gpc_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 imx_gpc_domain_alloc(struct irq_domain *domain,
 +   unsigned int irq,
 +   unsigned int nr_irqs, void *data)
 +{
 + struct of_phandle_args *args = data;
 + struct 

Re: [PATCH v4 14/21] ARM: imx6: convert GPC to stacked domains

2015-01-19 Thread Marc Zyngier
On 19/01/15 10:47, Lucas Stach wrote:
 Am Montag, den 19.01.2015, 09:44 + schrieb Marc Zyngier:
 IMX6 has been (ab)using the gic_arch_extn to provide
 wakeup from suspend, and it makes a lot of sense to convert
 this code to use stacked domains instead.

 This patch does just this, updating the DT files to actually
 reflect what the HW provides.

 BIG FAT WARNING: because the DTs were so far lying by not
 exposing the fact that the GPC block is actually the first
 interrupt controller in the chain, kernels with this patch
 applied wont have any suspend-resume facility when booted
 with old DTs, and old kernels with updated DTs won't even boot.

 Tested-by: Stefan Agner ste...@agner.ch
 Acked-by: Stefan Agner ste...@agner.ch
 Signed-off-by: Marc Zyngier marc.zyng...@arm.com
 ---
  arch/arm/boot/dts/imx6qdl.dtsi  |   7 ++-
  arch/arm/boot/dts/imx6sl.dtsi   |   6 +-
  arch/arm/boot/dts/imx6sx.dtsi   |   6 +-
  arch/arm/mach-imx/common.h  |   1 -
  arch/arm/mach-imx/gpc.c | 127 
 
  arch/arm/mach-imx/mach-imx6q.c  |   1 -
  arch/arm/mach-imx/mach-imx6sl.c |   1 -
  arch/arm/mach-imx/mach-imx6sx.c |   1 -
  8 files changed, 119 insertions(+), 31 deletions(-)

 [...]
 
 --- a/arch/arm/mach-imx/common.h
 +++ b/arch/arm/mach-imx/common.h
 @@ -102,7 +102,6 @@ static inline void imx_scu_map_io(void) {}
  static inline void imx_smp_prepare(void) {}
  #endif
  void imx_src_init(void);
 -void imx_gpc_init(void);
  void imx_gpc_pre_suspend(bool arm_power_off);
  void imx_gpc_post_resume(void);
  void imx_gpc_mask_all(void);
 diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
 index 5f3602e..838da3c 100644
 --- a/arch/arm/mach-imx/gpc.c
 +++ b/arch/arm/mach-imx/gpc.c
 @@ -22,6 +22,7 @@
  #define GPC_PGC_CPU_PDN 0x2a0
  
  #define IMR_NUM 4
 +#define GPC_MAX_IRQS(IMR_NUM * 32)
  
  static void __iomem *gpc_base;
  static u32 gpc_wake_irqs[IMR_NUM];
 @@ -56,17 +57,17 @@ void imx_gpc_post_resume(void)
  
  static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on)
  {
 -unsigned int idx = d-hwirq / 32 - 1;
 +unsigned int idx = d-hwirq / 32;
  u32 mask;
  
 -/* Sanity check for SPI irq */
 -if (d-hwirq  32)
 -return -EINVAL;
 -
  mask = 1  d-hwirq % 32;
  gpc_wake_irqs[idx] = on ? gpc_wake_irqs[idx] | mask :
gpc_wake_irqs[idx]  ~mask;
  
 +/*
 + * Do *not* call into the parent, as the GIC doesn't have any
 + * wake-up facility...
 + */
  return 0;
  }
  
 @@ -96,7 +97,7 @@ void imx_gpc_hwirq_unmask(unsigned int hwirq)
  void __iomem *reg;
  u32 val;
  
 -reg = gpc_base + GPC_IMR1 + (hwirq / 32 - 1) * 4;
 +reg = gpc_base + GPC_IMR1 + hwirq / 32 * 4;
  val = readl_relaxed(reg);
  val = ~(1  hwirq % 32);
  writel_relaxed(val, reg);
 @@ -107,7 +108,7 @@ void imx_gpc_hwirq_mask(unsigned int hwirq)
  void __iomem *reg;
  u32 val;
  
 -reg = gpc_base + GPC_IMR1 + (hwirq / 32 - 1) * 4;
 +reg = gpc_base + GPC_IMR1 + hwirq / 32 * 4;
  val = readl_relaxed(reg);
  val |= 1  (hwirq % 32);
  writel_relaxed(val, reg);
 @@ -115,37 +116,115 @@ void imx_gpc_hwirq_mask(unsigned int hwirq)
  
  static void imx_gpc_irq_unmask(struct irq_data *d)
  {
 -/* Sanity check for SPI irq */
 -if (d-hwirq  32)
 -return;
 -
  imx_gpc_hwirq_unmask(d-hwirq);
 +irq_chip_unmask_parent(d);
  }
  
  static void imx_gpc_irq_mask(struct irq_data *d)
  {
 -/* Sanity check for SPI irq */
 -if (d-hwirq  32)
 -return;
 -
  imx_gpc_hwirq_mask(d-hwirq);
 +irq_chip_mask_parent(d);
 +}
 +
 +static struct irq_chip imx_gpc_chip = {
 +.name   = GPC,
 +.irq_eoi= irq_chip_eoi_parent,
 +.irq_mask   = imx_gpc_irq_mask,
 +.irq_unmask = imx_gpc_irq_unmask,
 +.irq_retrigger  = irq_chip_retrigger_hierarchy,
 +.irq_set_wake   = imx_gpc_irq_set_wake,
 +};
 +
 +static int imx_gpc_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 imx_gpc_domain_alloc(struct irq_domain *domain,
 +  unsigned int irq,
 +  unsigned int nr_irqs, void *data)
 +{
 +struct of_phandle_args *args = data;
 +struct of_phandle_args parent_args;