From 0a84a91c37ada296ffe7147e73af99b5654628ec Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Fri, 16 Dec 2011 14:36:58 -0700 Subject: ARM: OMAP: PRCM: add support for chain interrupt handler Introduce a chained interrupt handler mechanism for the PRCM interrupt, so that individual PRCM event can cleanly be handled by handlers in separate drivers. We do this by introducing PRCM event names, which are then matched to the particular PRCM interrupt bit depending on the specific OMAP SoC being used. PRCM interrupts have two priority levels, high or normal. High priority is needed for IO event handling, so that we can be sure that IO events are processed before other events. This reduces latency for IO event customers and also prevents incorrect ack sequence on OMAP3. Signed-off-by: Tero Kristo Cc: Paul Walmsley Cc: Kevin Hilman Cc: Avinash.H.M Cc: Benoit Cousson Cc: Tony Lindgren Cc: Govindraj.R Tested-by: Kevin Hilman Reviewed-by: Kevin Hilman [paul@pwsan.com: drop some dead code; use SoC-specific pending IRQ detection; move code to prm_common.c; add lots of documentation; remove saved_mask; add OCP barrier on ISR exit; improved error handling; split out per-SoC initialization to a separate patch] Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/prcm-common.h | 63 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-omap2/prcm-common.h') diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h index 0363dcb0ef9..76db3795e68 100644 --- a/arch/arm/mach-omap2/prcm-common.h +++ b/arch/arm/mach-omap2/prcm-common.h @@ -4,7 +4,7 @@ /* * OMAP2/3 PRCM base and module definitions * - * Copyright (C) 2007-2009 Texas Instruments, Inc. + * Copyright (C) 2007-2009, 2011 Texas Instruments, Inc. * Copyright (C) 2007-2009 Nokia Corporation * * Written by Paul Walmsley @@ -408,6 +408,67 @@ extern void __iomem *prm_base; extern void __iomem *cm_base; extern void __iomem *cm2_base; + +/** + * struct omap_prcm_irq - describes a PRCM interrupt bit + * @name: a short name describing the interrupt type, e.g. "wkup" or "io" + * @offset: the bit shift of the interrupt inside the IRQ{ENABLE,STATUS} regs + * @priority: should this interrupt be handled before @priority=false IRQs? + * + * Describes interrupt bits inside the PRM_IRQ{ENABLE,STATUS}_MPU* registers. + * On systems with multiple PRM MPU IRQ registers, the bitfields read from + * the registers are concatenated, so @offset could be > 31 on these systems - + * see omap_prm_irq_handler() for more details. I/O ring interrupts should + * have @priority set to true. + */ +struct omap_prcm_irq { + const char *name; + unsigned int offset; + bool priority; +}; + +/** + * struct omap_prcm_irq_setup - PRCM interrupt controller details + * @ack: PRM register offset for the first PRM_IRQSTATUS_MPU register + * @mask: PRM register offset for the first PRM_IRQENABLE_MPU register + * @nr_regs: number of PRM_IRQ{STATUS,ENABLE}_MPU* registers + * @nr_irqs: number of entries in the @irqs array + * @irqs: ptr to an array of PRCM interrupt bits (see @nr_irqs) + * @irq: MPU IRQ asserted when a PRCM interrupt arrives + * @read_pending_irqs: fn ptr to determine if any PRCM IRQs are pending + * @ocp_barrier: fn ptr to force buffered PRM writes to complete + * @priority_mask: 1 bit per IRQ, set to 1 if omap_prcm_irq.priority = true + * @base_irq: base dynamic IRQ number, returned from irq_alloc_descs() in init + * + * @priority_mask and @base_irq are populated dynamically during + * omap_prcm_register_chain_handler() - these fields are not to be + * specified in static initializers. + */ +struct omap_prcm_irq_setup { + u16 ack; + u16 mask; + u8 nr_regs; + u8 nr_irqs; + const struct omap_prcm_irq *irqs; + int irq; + void (*read_pending_irqs)(unsigned long *events); + void (*ocp_barrier)(void); + u32 *priority_mask; + int base_irq; +}; + +/* OMAP_PRCM_IRQ: convenience macro for creating struct omap_prcm_irq records */ +#define OMAP_PRCM_IRQ(_name, _offset, _priority) { \ + .name = _name, \ + .offset = _offset, \ + .priority = _priority \ + } + +extern void omap_prcm_irq_cleanup(void); +extern int omap_prcm_register_chain_handler( + struct omap_prcm_irq_setup *irq_setup); +extern int omap_prcm_event_to_irq(const char *event); + # endif #endif -- cgit v1.2.3 From 91285b6fa296657d92dc2225100fb94aee869bf2 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Fri, 16 Dec 2011 14:36:58 -0700 Subject: ARM: OMAP: PRCM: add suspend prepare / finish support PRCM chain handler needs to disable forwarding of interrupts during suspend, because runtime PM is disabled and most of the drivers are potentially not able to handle interrupts coming at this time. This patch masks all the PRCM interrupt events if a PRCM interrupt occurs during suspend, but does not ack them. Once suspend finish is called, all the masked events will be re-enabled, which causes immediate PRCM interrupt and handles the postponed event. The suspend prepare and complete callbacks will be called from pm34xx.c / pm44xx.c files in the following patches. The functions defined in this patch should eventually be moved to suspend->prepare and suspend->finish driver hooks, once the PRCM chain handler will be made as its own driver. Signed-off-by: Tero Kristo Cc: Kevin Hilman Cc: Paul Walmsley Tested-by: Kevin Hilman Reviewed-by: Kevin Hilman [paul@pwsan.com: add kerneldoc, add omap_prcm_irq_setup.saved_mask, add fn ptrs for save_and_clear_irqen() and restore_irqen()] Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/prcm-common.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'arch/arm/mach-omap2/prcm-common.h') diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h index 76db3795e68..0f69d8fc562 100644 --- a/arch/arm/mach-omap2/prcm-common.h +++ b/arch/arm/mach-omap2/prcm-common.h @@ -437,11 +437,16 @@ struct omap_prcm_irq { * @irq: MPU IRQ asserted when a PRCM interrupt arrives * @read_pending_irqs: fn ptr to determine if any PRCM IRQs are pending * @ocp_barrier: fn ptr to force buffered PRM writes to complete + * @save_and_clear_irqen: fn ptr to save and clear IRQENABLE regs + * @restore_irqen: fn ptr to save and clear IRQENABLE regs + * @saved_mask: IRQENABLE regs are saved here during suspend * @priority_mask: 1 bit per IRQ, set to 1 if omap_prcm_irq.priority = true * @base_irq: base dynamic IRQ number, returned from irq_alloc_descs() in init + * @suspended: set to true after Linux suspend code has called our ->prepare() + * @suspend_save_flag: set to true after IRQ masks have been saved and disabled * - * @priority_mask and @base_irq are populated dynamically during - * omap_prcm_register_chain_handler() - these fields are not to be + * @saved_mask, @priority_mask, @base_irq, @suspended, and + * @suspend_save_flag are populated dynamically, and are not to be * specified in static initializers. */ struct omap_prcm_irq_setup { @@ -453,8 +458,13 @@ struct omap_prcm_irq_setup { int irq; void (*read_pending_irqs)(unsigned long *events); void (*ocp_barrier)(void); + void (*save_and_clear_irqen)(u32 *saved_mask); + void (*restore_irqen)(u32 *saved_mask); + u32 *saved_mask; u32 *priority_mask; int base_irq; + bool suspended; + bool suspend_save_flag; }; /* OMAP_PRCM_IRQ: convenience macro for creating struct omap_prcm_irq records */ @@ -468,6 +478,8 @@ extern void omap_prcm_irq_cleanup(void); extern int omap_prcm_register_chain_handler( struct omap_prcm_irq_setup *irq_setup); extern int omap_prcm_event_to_irq(const char *event); +extern void omap_prcm_irq_prepare(void); +extern void omap_prcm_irq_complete(void); # endif -- cgit v1.2.3