Subject: [PATCH v2] ARM: OMAP: Work around hardcoded interrupts

From: [email-masked] (Nishanth Menon)
Date: Mon, 19 Jan 2015 14:14:04 -0600

On 10:21-20150117, Marc Zyngier wrote:
> Commit 9a1091ef0017 (irqchip: gic: Support hierarchy irq domain)
should have been
Commit 9a1091ef0017 ("irqchip: gic: Support hierarchy irq domain")

> changed the GIC driver to use a non-legacy IRQ domain on DT
> platforms. This patch assumes that DT-driven systems are getting
> all of their interrupts from device tree.
> 
> Turns out that OMAP has quite a few hidden gems, and still uses
> hardcoded interrupts despite having fairly complete DTs.
> 
> This patch attempts to work around these by offering a translation
> method that can be called directly from the hwmod code, if present.
> The same hack is sprinkled over PRCM and TWL.
> 
> It isn't pretty, but it seems to do the job without having to add
> more hacks to the interrupt controller code.
> 
> Tested on OMAP4 (Panda-ES) and OMAP5 (UEVM5432).
> 
> Signed-off-by: Marc Zyngier <[email-masked]>

Other than that, This looks good to me.
Acked-by: Nishanth Menon <[email-masked]>

> ---
> From v1:
> - OMAP4 can either get the PRM interrupt from hwmod or from device tree.
>   In the latter case, remove the xlate_irq method.
> 
>  arch/arm/mach-omap2/common.h               |  1 +
>  arch/arm/mach-omap2/omap4-common.c         | 32 ++++++++++++++++++++++++++++++
>  arch/arm/mach-omap2/omap_hwmod.c           | 10 ++++++++--
>  arch/arm/mach-omap2/omap_hwmod.h           |  1 +
>  arch/arm/mach-omap2/omap_hwmod_44xx_data.c |  5 +++++
>  arch/arm/mach-omap2/omap_hwmod_54xx_data.c |  1 +
>  arch/arm/mach-omap2/prcm-common.h          |  1 +
>  arch/arm/mach-omap2/prm44xx.c              |  5 ++++-
>  arch/arm/mach-omap2/prm_common.c           | 14 +++++++++++--
>  arch/arm/mach-omap2/twl-common.c           |  5 ++++-
>  10 files changed, 69 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
> index 377eea8..b664494 100644
> --- a/arch/arm/mach-omap2/common.h
> +++ b/arch/arm/mach-omap2/common.h
> @@ -211,6 +211,7 @@ extern struct device *omap2_get_iva_device(void);
>  extern struct device *omap2_get_l3_device(void);
>  extern struct device *omap4_get_dsp_device(void);
>  
> +unsigned int omap4_xlate_irq(unsigned int hwirq);
>  void omap_gic_of_init(void);
>  
>  #ifdef CONFIG_CACHE_L2X0
> diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
> index b7cb44a..cc30e49 100644
> --- a/arch/arm/mach-omap2/omap4-common.c
> +++ b/arch/arm/mach-omap2/omap4-common.c
> @@ -256,6 +256,38 @@ static int __init omap4_sar_ram_init(void)
>  }
>  omap_early_initcall(omap4_sar_ram_init);
>  
> +static struct of_device_id gic_match[] = {
> +	{ .compatible = "arm,cortex-a9-gic", },
> +	{ .compatible = "arm,cortex-a15-gic", },
> +	{ },
> +};
> +
> +static struct device_node *gic_node;
> +
> +unsigned int omap4_xlate_irq(unsigned int hwirq)
> +{
> +	struct of_phandle_args irq_data;
> +	unsigned int irq;
> +
> +	if (!gic_node)
> +		gic_node = of_find_matching_node(NULL, gic_match);
> +
> +	if (WARN_ON(!gic_node))
> +		return hwirq;
> +
> +	irq_data.np = gic_node;
> +	irq_data.args_count = 3;
> +	irq_data.args[0] = 0;
> +	irq_data.args[1] = hwirq - OMAP44XX_IRQ_GIC_START;
> +	irq_data.args[2] = IRQ_TYPE_LEVEL_HIGH;
> +
> +	irq = irq_create_of_mapping(&irq_data);
> +	if (WARN_ON(!irq))
> +		irq = hwirq;
> +
> +	return irq;
> +}
> +
>  void __init omap_gic_of_init(void)
>  {
>  	struct device_node *np;
> diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
> index cbb908d..9025fff 100644
> --- a/arch/arm/mach-omap2/omap_hwmod.c
> +++ b/arch/arm/mach-omap2/omap_hwmod.c
> @@ -3534,9 +3534,15 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res)
>  
>  	mpu_irqs_cnt = _count_mpu_irqs(oh);
>  	for (i = 0; i < mpu_irqs_cnt; i++) {
> +		unsigned int irq;
> +
> +		if (oh->xlate_irq)
> +			irq = oh->xlate_irq((oh->mpu_irqs + i)->irq);
> +		else
> +			irq = (oh->mpu_irqs + i)->irq;
>  		(res + r)->name = (oh->mpu_irqs + i)->name;
> -		(res + r)->start = (oh->mpu_irqs + i)->irq;
> -		(res + r)->end = (oh->mpu_irqs + i)->irq;
> +		(res + r)->start = irq;
> +		(res + r)->end = irq;
>  		(res + r)->flags = IORESOURCE_IRQ;
>  		r++;
>  	}
> diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h
> index 35ca6ef..5b42faf 100644
> --- a/arch/arm/mach-omap2/omap_hwmod.h
> +++ b/arch/arm/mach-omap2/omap_hwmod.h
> @@ -676,6 +676,7 @@ struct omap_hwmod {
>  	spinlock_t			_lock;
>  	struct list_head		node;
>  	struct omap_hwmod_ocp_if	*_mpu_port;
> +	unsigned int			(*xlate_irq)(unsigned int);
>  	u16				flags;
>  	u8				mpu_rt_idx;
>  	u8				response_lat;
> diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
> index c314b3c..f5e68a7 100644
> --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
> +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
> @@ -479,6 +479,7 @@ static struct omap_hwmod omap44xx_dma_system_hwmod = {
>  	.class		= &omap44xx_dma_hwmod_class,
>  	.clkdm_name	= "l3_dma_clkdm",
>  	.mpu_irqs	= omap44xx_dma_system_irqs,
> +	.xlate_irq	= omap4_xlate_irq,
>  	.main_clk	= "l3_div_ck",
>  	.prcm = {
>  		.omap4 = {
> @@ -640,6 +641,7 @@ static struct omap_hwmod omap44xx_dss_dispc_hwmod = {
>  	.class		= &omap44xx_dispc_hwmod_class,
>  	.clkdm_name	= "l3_dss_clkdm",
>  	.mpu_irqs	= omap44xx_dss_dispc_irqs,
> +	.xlate_irq	= omap4_xlate_irq,
>  	.sdma_reqs	= omap44xx_dss_dispc_sdma_reqs,
>  	.main_clk	= "dss_dss_clk",
>  	.prcm = {
> @@ -693,6 +695,7 @@ static struct omap_hwmod omap44xx_dss_dsi1_hwmod = {
>  	.class		= &omap44xx_dsi_hwmod_class,
>  	.clkdm_name	= "l3_dss_clkdm",
>  	.mpu_irqs	= omap44xx_dss_dsi1_irqs,
> +	.xlate_irq	= omap4_xlate_irq,
>  	.sdma_reqs	= omap44xx_dss_dsi1_sdma_reqs,
>  	.main_clk	= "dss_dss_clk",
>  	.prcm = {
> @@ -726,6 +729,7 @@ static struct omap_hwmod omap44xx_dss_dsi2_hwmod = {
>  	.class		= &omap44xx_dsi_hwmod_class,
>  	.clkdm_name	= "l3_dss_clkdm",
>  	.mpu_irqs	= omap44xx_dss_dsi2_irqs,
> +	.xlate_irq	= omap4_xlate_irq,
>  	.sdma_reqs	= omap44xx_dss_dsi2_sdma_reqs,
>  	.main_clk	= "dss_dss_clk",
>  	.prcm = {
> @@ -784,6 +788,7 @@ static struct omap_hwmod omap44xx_dss_hdmi_hwmod = {
>  	 */
>  	.flags		= HWMOD_SWSUP_SIDLE,
>  	.mpu_irqs	= omap44xx_dss_hdmi_irqs,
> +	.xlate_irq	= omap4_xlate_irq,
>  	.sdma_reqs	= omap44xx_dss_hdmi_sdma_reqs,
>  	.main_clk	= "dss_48mhz_clk",
>  	.prcm = {
> diff --git a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c
> index 3e95230..7c3fac0 100644
> --- a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c
> +++ b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c
> @@ -288,6 +288,7 @@ static struct omap_hwmod omap54xx_dma_system_hwmod = {
>  	.class		= &omap54xx_dma_hwmod_class,
>  	.clkdm_name	= "dma_clkdm",
>  	.mpu_irqs	= omap54xx_dma_system_irqs,
> +	.xlate_irq	= omap4_xlate_irq,
>  	.main_clk	= "l3_iclk_div",
>  	.prcm = {
>  		.omap4 = {
> diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
> index a8e4b58..6163d66 100644
> --- a/arch/arm/mach-omap2/prcm-common.h
> +++ b/arch/arm/mach-omap2/prcm-common.h
> @@ -498,6 +498,7 @@ struct omap_prcm_irq_setup {
>  	u8 nr_irqs;
>  	const struct omap_prcm_irq *irqs;
>  	int irq;
> +	unsigned int (*xlate_irq)(unsigned int);
>  	void (*read_pending_irqs)(unsigned long *events);
>  	void (*ocp_barrier)(void);
>  	void (*save_and_clear_irqen)(u32 *saved_mask);
> diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
> index cc170fb..408c64e 100644
> --- a/arch/arm/mach-omap2/prm44xx.c
> +++ b/arch/arm/mach-omap2/prm44xx.c
> @@ -49,6 +49,7 @@ static struct omap_prcm_irq_setup omap4_prcm_irq_setup = {
>  	.irqs			= omap4_prcm_irqs,
>  	.nr_irqs		= ARRAY_SIZE(omap4_prcm_irqs),
>  	.irq			= 11 + OMAP44XX_IRQ_GIC_START,
> +	.xlate_irq		= omap4_xlate_irq,
>  	.read_pending_irqs	= &omap44xx_prm_read_pending_irqs,
>  	.ocp_barrier		= &omap44xx_prm_ocp_barrier,
>  	.save_and_clear_irqen	= &omap44xx_prm_save_and_clear_irqen,
> @@ -751,8 +752,10 @@ static int omap44xx_prm_late_init(void)
>  		}
>  
>  		/* Once OMAP4 DT is filled as well */
> -		if (irq_num >= 0)
> +		if (irq_num >= 0) {
>  			omap4_prcm_irq_setup.irq = irq_num;
> +			omap4_prcm_irq_setup.xlate_irq = NULL;
> +		}
>  	}
>  
>  	omap44xx_prm_enable_io_wakeup();
> diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
> index 779940c..dea2833 100644
> --- a/arch/arm/mach-omap2/prm_common.c
> +++ b/arch/arm/mach-omap2/prm_common.c
> @@ -187,6 +187,7 @@ int omap_prcm_event_to_irq(const char *name)
>   */
>  void omap_prcm_irq_cleanup(void)
>  {
> +	unsigned int irq;
>  	int i;
>  
>  	if (!prcm_irq_setup) {
> @@ -211,7 +212,11 @@ void omap_prcm_irq_cleanup(void)
>  	kfree(prcm_irq_setup->priority_mask);
>  	prcm_irq_setup->priority_mask = NULL;
>  
> -	irq_set_chained_handler(prcm_irq_setup->irq, NULL);
> +	if (prcm_irq_setup->xlate_irq)
> +		irq = prcm_irq_setup->xlate_irq(prcm_irq_setup->irq);
> +	else
> +		irq = prcm_irq_setup->irq;
> +	irq_set_chained_handler(irq, NULL);
>  
>  	if (prcm_irq_setup->base_irq > 0)
>  		irq_free_descs(prcm_irq_setup->base_irq,
> @@ -259,6 +264,7 @@ int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
>  	int offset, i;
>  	struct irq_chip_generic *gc;
>  	struct irq_chip_type *ct;
> +	unsigned int irq;
>  
>  	if (!irq_setup)
>  		return -EINVAL;
> @@ -298,7 +304,11 @@ int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
>  				1 << (offset & 0x1f);
>  	}
>  
> -	irq_set_chained_handler(irq_setup->irq, omap_prcm_irq_handler);
> +	if (irq_setup->xlate_irq)
> +		irq = irq_setup->xlate_irq(irq_setup->irq);
> +	else
> +		irq = irq_setup->irq;
> +	irq_set_chained_handler(irq, omap_prcm_irq_handler);
>  
>  	irq_setup->base_irq = irq_alloc_descs(-1, 0, irq_setup->nr_regs * 32,
>  		0);
> diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c
> index 4457e73..3031ee1 100644
> --- a/arch/arm/mach-omap2/twl-common.c
> +++ b/arch/arm/mach-omap2/twl-common.c
> @@ -71,9 +71,12 @@ void __init omap4_pmic_init(const char *pmic_type,
>  		    struct i2c_board_info *devices, int nr_devices)
>  {
>  	/* PMIC part*/
> +	unsigned int irq;
> +
>  	omap_mux_init_signal("sys_nirq1", OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE);
>  	omap_mux_init_signal("fref_clk0_out.sys_drm_msecure", OMAP_PIN_OUTPUT);
> -	omap_pmic_init(1, 400, pmic_type, 7 + OMAP44XX_IRQ_GIC_START, pmic_data);
> +	irq = omap4_xlate_irq(7 + OMAP44XX_IRQ_GIC_START);
> +	omap_pmic_init(1, 400, pmic_type, irq, pmic_data);
>  
>  	/* Register additional devices on i2c1 bus if needed */
>  	if (devices)
> -- 
> 2.1.3
> 

-- 
Regards,
Nishanth Menon