From: Kevin Hilman <khilman@ti.com>
To: Tero Kristo <t-kristo@ti.com>
Cc: linux-omap@vger.kernel.org,
Thomas Petazzoni <thomas.petazzoni@free-electrons.com>,
"Avinash.H.M" <avinashhm@ti.com>,
"Cousson, Benoit" <b-cousson@ti.com>
Subject: Re: [PATCHv3 1/6] omap: prcm: switch to a chained IRQ handler mechanism
Date: Wed, 22 Jun 2011 16:53:24 -0700 [thread overview]
Message-ID: <87fwn1h18r.fsf@ti.com> (raw)
In-Reply-To: <1308760934-9757-2-git-send-email-t-kristo@ti.com> (Tero Kristo's message of "Wed, 22 Jun 2011 19:42:09 +0300")
Hi Tero,
Tero Kristo <t-kristo@ti.com> writes:
> 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.
> arch/arm/mach-omap2/prcm.c implements the chained interrupt mechanism
> itself, with individual PRCM events for OMAP3 and OMAP4 being
> described in arch/arm/mach-omap2/prcm3xxx.c and
> arch/arm/mach-omap2/prcm4xxx.c respectively. At initialization time,
> the set of PRCM events is filtered against the SoC on which we are
> running, keeping only the ones that are actually useful. All the logic
> is written to be generic with regard to OMAP3/OMAP4, even though OMAP3
> has single PRCM event registers and OMAP4 has two PRCM event
> registers.
>
> The wakeup and I/O PRCM events are now handled as two separate
> interrupts, and their handler is registered with IRQF_NO_SUSPEND,
> otherwise the IRQ gets disabled during suspend, which prevents resume.
>
> Patch tested on OMAP4 blaze board, no testing done on OMAP3.
Is this still true?
> Signed-off-by: Tero Kristo <t-kristo@ti.com>
> Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> Cc: Avinash.H.M <avinashhm@ti.com>
> Cc: Kevin Hilman <khilman@ti.com>
> Cc: Cousson, Benoit <b-cousson@ti.com>
Thanks for working on this. So far, I've only had time for a cosmetic
review of this code. I should have some more time later this week for a
more detailed review.
First some general comments:
This series introduces a few section mismatch warnings. Please build
with CONFIG_DEBUG_SECTION_MISMATCH=y for details and fixup.
> ---
> arch/arm/mach-omap2/Makefile | 4 +
> arch/arm/mach-omap2/pm34xx.c | 104 ++++++------------
> arch/arm/mach-omap2/prcm.c | 187 ++++++++++++++++++++++++++++++++
> arch/arm/mach-omap2/prcm3xxx.c | 117 ++++++++++++++++++++
> arch/arm/mach-omap2/prcm4xxx.c | 146 +++++++++++++++++++++++++
> arch/arm/plat-omap/include/plat/irqs.h | 9 ++-
> arch/arm/plat-omap/include/plat/prcm.h | 45 ++++++++
> 7 files changed, 541 insertions(+), 71 deletions(-)
> create mode 100644 arch/arm/mach-omap2/prcm3xxx.c
> create mode 100644 arch/arm/mach-omap2/prcm4xxx.c
>
> diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
> index 5024064..339d2d4 100644
> --- a/arch/arm/mach-omap2/Makefile
> +++ b/arch/arm/mach-omap2/Makefile
> @@ -39,6 +39,10 @@ AFLAGS_sram242x.o :=-Wa,-march=armv6
> AFLAGS_sram243x.o :=-Wa,-march=armv6
> AFLAGS_sram34xx.o :=-Wa,-march=armv7-a
>
> +# PRCM
> +obj-$(CONFIG_ARCH_OMAP3) += prcm3xxx.o
> +obj-$(CONFIG_ARCH_OMAP4) += prcm4xxx.o
> +
> # Pin multiplexing
> obj-$(CONFIG_SOC_OMAP2420) += mux2420.o
> obj-$(CONFIG_SOC_OMAP2430) += mux2430.o
> diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
> index 96a7624..adab4d5 100644
> --- a/arch/arm/mach-omap2/pm34xx.c
> +++ b/arch/arm/mach-omap2/pm34xx.c
> @@ -240,7 +240,7 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs)
> return c;
> }
>
> -static int _prcm_int_handle_wakeup(void)
> +static irqreturn_t _prcm_int_handle_wakeup(int irq, void *unused)
> {
> int c;
>
> @@ -252,64 +252,10 @@ static int _prcm_int_handle_wakeup(void)
> c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
> }
>
> - return c;
> -}
> -
> -/*
> - * PRCM Interrupt Handler
> - *
> - * The PRM_IRQSTATUS_MPU register indicates if there are any pending
> - * interrupts from the PRCM for the MPU. These bits must be cleared in
> - * order to clear the PRCM interrupt. The PRCM interrupt handler is
> - * implemented to simply clear the PRM_IRQSTATUS_MPU in order to clear
> - * the PRCM interrupt. Please note that bit 0 of the PRM_IRQSTATUS_MPU
> - * register indicates that a wake-up event is pending for the MPU and
> - * this bit can only be cleared if the all the wake-up events latched
> - * in the various PM_WKST_x registers have been cleared. The interrupt
> - * handler is implemented using a do-while loop so that if a wake-up
> - * event occurred during the processing of the prcm interrupt handler
> - * (setting a bit in the corresponding PM_WKST_x register and thus
> - * preventing us from clearing bit 0 of the PRM_IRQSTATUS_MPU register)
> - * this would be handled.
> - */
> -static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
> -{
> - u32 irqenable_mpu, irqstatus_mpu;
> - int c = 0;
> -
> - irqenable_mpu = omap2_prm_read_mod_reg(OCP_MOD,
> - OMAP3_PRM_IRQENABLE_MPU_OFFSET);
> - irqstatus_mpu = omap2_prm_read_mod_reg(OCP_MOD,
> - OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
> - irqstatus_mpu &= irqenable_mpu;
> -
> - do {
> - if (irqstatus_mpu & (OMAP3430_WKUP_ST_MASK |
> - OMAP3430_IO_ST_MASK)) {
> - c = _prcm_int_handle_wakeup();
> -
> - /*
> - * Is the MPU PRCM interrupt handler racing with the
> - * IVA2 PRCM interrupt handler ?
> - */
> - WARN(c == 0, "prcm: WARNING: PRCM indicated MPU wakeup "
> - "but no wakeup sources are marked\n");
> - } else {
> - /* XXX we need to expand our PRCM interrupt handler */
> - WARN(1, "prcm: WARNING: PRCM interrupt received, but "
> - "no code to handle it (%08x)\n", irqstatus_mpu);
> - }
> -
> - omap2_prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
> - OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
> -
> - irqstatus_mpu = omap2_prm_read_mod_reg(OCP_MOD,
> - OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
> - irqstatus_mpu &= irqenable_mpu;
> -
> - } while (irqstatus_mpu);
> -
> - return IRQ_HANDLED;
> + if (c)
> + return IRQ_HANDLED;
> + else
> + return IRQ_NONE;
> }
>
> /* Function to restore the table entry that was modified for enabling MMU */
> @@ -880,20 +826,32 @@ static int __init omap3_pm_init(void)
> /* XXX prcm_setup_regs needs to be before enabling hw
> * supervised mode for powerdomains */
> prcm_setup_regs();
> + ret = omap_prcm_irq_init();
> + if (ret) {
> + pr_err("omap_prcm_irq_init() failed with %d\n", ret);
> + goto err_prcm_irq_init;
> + }
> +
> + ret = request_irq(omap_prcm_event_to_irq("wkup"),
> + _prcm_int_handle_wakeup,
> + IRQF_NO_SUSPEND, "prcm_wkup", NULL);
Do you need to register a handler for this if all the handler does is
'return IRQ_HANDLED' ?
Since you're now clearing all the events in every idle path, this
doesn't seem to be necessary.
> + if (ret) {
> + pr_err("request_irq failed to register for PRCM wakeup\n");
> + goto err_prcm_irq_wkup;
> + }
>
> - ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
> - (irq_handler_t)prcm_interrupt_handler,
> - IRQF_DISABLED, "prcm", NULL);
> + ret = request_irq(omap_prcm_event_to_irq("io"),
> + _prcm_int_handle_wakeup,
> + IRQF_NO_SUSPEND, "prcm_io", NULL);
ditto
> if (ret) {
> - printk(KERN_ERR "request_irq failed to register for 0x%x\n",
> - INT_34XX_PRCM_MPU_IRQ);
> - goto err1;
> + pr_err("request_irq failed to register for PRCM io\n");
> + goto err_prcm_irq_io;
> }
>
> ret = pwrdm_for_each(pwrdms_setup, NULL);
> if (ret) {
> printk(KERN_ERR "Failed to setup powerdomains\n");
> - goto err2;
> + goto err_pwrdms_setup;
> }
>
> (void) clkdm_for_each(clkdms_setup, NULL);
> @@ -901,7 +859,7 @@ static int __init omap3_pm_init(void)
> mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
> if (mpu_pwrdm == NULL) {
> printk(KERN_ERR "Failed to get mpu_pwrdm\n");
> - goto err2;
> + goto err_pwrdms_setup;
> }
>
> neon_pwrdm = pwrdm_lookup("neon_pwrdm");
> @@ -950,14 +908,20 @@ static int __init omap3_pm_init(void)
> }
>
> omap3_save_scratchpad_contents();
> -err1:
> +
> return ret;
> -err2:
> - free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
> +
> + err_pwrdms_setup:
> + free_irq(omap_prcm_event_to_irq("io"), NULL);
> list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
> list_del(&pwrst->node);
> kfree(pwrst);
> }
> + err_prcm_irq_io:
> + free_irq(omap_prcm_event_to_irq("wkup"), NULL);
> + err_prcm_irq_wkup:
> + omap_prcm_irq_cleanup();
> + err_prcm_irq_init:
> return ret;
> }
>
> diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c
> index 6be1438..362c59c 100644
> --- a/arch/arm/mach-omap2/prcm.c
> +++ b/arch/arm/mach-omap2/prcm.c
> @@ -23,6 +23,8 @@
> #include <linux/clk.h>
> #include <linux/io.h>
> #include <linux/delay.h>
> +#include <linux/irq.h>
> +#include <linux/slab.h>
>
> #include <mach/system.h>
> #include <plat/common.h>
> @@ -45,6 +47,191 @@ void __iomem *cm2_base;
>
> #define MAX_MODULE_ENABLE_WAIT 100000
>
> +/* Array of valid PRCM events for the current OMAP */
> +static struct omap_prcm_irq *omap_prcm_irqs;
> +
> +/* Number of entries in omap_prcm_irqs */
> +static int omap_prcm_irqs_nr;
> +
> +/* Pointers to either OMAP3 or OMAP4 specific functions */
> +static void (*omap_prcm_mask_event)(unsigned event);
> +static void (*omap_prcm_unmask_event)(unsigned event);
> +static void (*omap_prcm_ack_event)(unsigned event);
> +static void (*omap_prcm_pending_events)(unsigned long *pending);
> +
> +static void prcm_irq_ack(struct irq_data *data)
> +{
> + unsigned int prcm_irq = data->irq - OMAP_PRCM_IRQ_BASE;
> + omap_prcm_ack_event(prcm_irq);
> +}
> +
> +static void prcm_irq_mask(struct irq_data *data)
> +{
> + unsigned int prcm_irq = data->irq - OMAP_PRCM_IRQ_BASE;
> + omap_prcm_mask_event(prcm_irq);
> +}
> +
> +static void prcm_irq_unmask(struct irq_data *data)
> +{
> + unsigned int prcm_irq = data->irq - OMAP_PRCM_IRQ_BASE;
> + omap_prcm_unmask_event(prcm_irq);
> +}
> +
> +static struct irq_chip prcm_irq_chip = {
> + .name = "PRCM",
> + .irq_ack = prcm_irq_ack,
> + .irq_mask = prcm_irq_mask,
> + .irq_unmask = prcm_irq_unmask,
> +};
You can probably use the new generic IRQ chip framework to handle this
(c.f. kernel/irq/generic-chip.c and usage in mach-omap2/irq.c.)
> +/*
> + * PRCM Interrupt Handler
> + *
> + * The PRM_IRQSTATUS_MPU register indicates if there are any pending
> + * interrupts from the PRCM for the MPU. These bits must be cleared in
> + * order to clear the PRCM interrupt. The PRCM interrupt handler is
> + * implemented to simply clear the PRM_IRQSTATUS_MPU in order to clear
> + * the PRCM interrupt. Please note that bit 0 of the PRM_IRQSTATUS_MPU
> + * register indicates that a wake-up event is pending for the MPU and
> + * this bit can only be cleared if the all the wake-up events latched
> + * in the various PM_WKST_x registers have been cleared. The interrupt
> + * handler is implemented using a do-while loop so that if a wake-up
> + * event occurred during the processing of the prcm interrupt handler
> + * (setting a bit in the corresponding PM_WKST_x register and thus
> + * preventing us from clearing bit 0 of the PRM_IRQSTATUS_MPU register)
> + * this would be handled.
> + */
> +static void prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
> +{
> + unsigned long pending[OMAP_PRCM_MAX_NR_PENDING_REG];
> + struct irq_chip *chip = irq_desc_get_chip(desc);
> +
> + /*
> + * Loop until all pending irqs are handled, since
> + * generic_handle_irq(), called by prcm_irq_handle_virtirqs()
> + * can cause new irqs to come
> + */
> + while (1) {
> + unsigned int virtirq;
> +
> + chip->irq_ack(&desc->irq_data);
> +
> + memset(pending, 0, sizeof(pending));
> + omap_prcm_pending_events(pending);
> +
> + /* No bit set, then all IRQs are handled */
> + if (find_first_bit(pending, OMAP_PRCM_NR_IRQS)
> + >= OMAP_PRCM_NR_IRQS) {
> + chip->irq_unmask(&desc->irq_data);
> + break;
> + }
> +
> + /*
> + * Loop on all currently pending irqs so that new irqs
> + * cannot starve previously pending irqs
> + */
> + for_each_set_bit(virtirq, pending, OMAP_PRCM_NR_IRQS)
> + generic_handle_irq(OMAP_PRCM_IRQ_BASE + virtirq);
> +
> + chip->irq_unmask(&desc->irq_data);
> + }
> +}
> +
> +/*
> + * Given a PRCM event name, returns the corresponding IRQ on which the
> + * handler should be registered.
> + */
> +int omap_prcm_event_to_irq(const char *name)
> +{
> + int i;
> +
> + for (i = 0; i < omap_prcm_irqs_nr; i++)
> + if (!strcmp(omap_prcm_irqs[i].name, name))
> + return OMAP_PRCM_IRQ_BASE + omap_prcm_irqs[i].offset;
> +
> + return -ENOENT;
> +}
> +
> +/*
> + * Prepare the array of PRCM events corresponding to the current SoC,
> + * and set-up the chained interrupt handler mechanism.
> + */
> +int omap_prcm_irq_init(void)
> +{
> + int i, j;
> + struct omap_prcm_irq *unfiltered_irqs;
> + unsigned unfiltered_irqs_nr;
> +
> + if (cpu_is_omap34xx() || cpu_is_omap3630()) {
> + unfiltered_irqs = omap_prcm_3xxx_irqs;
> + unfiltered_irqs_nr = omap_prcm_3xxx_irqs_nr;
> + omap_prcm_mask_event = omap3_prcm_mask_event;
> + omap_prcm_unmask_event = omap3_prcm_unmask_event;
> + omap_prcm_ack_event = omap3_prcm_ack_event;
> + omap_prcm_pending_events = omap3_prcm_pending_events;
> + irq_set_chained_handler(INT_34XX_PRCM_MPU_IRQ,
> + prcm_irq_handler);
> + } else if (cpu_is_omap44xx()) {
> + unfiltered_irqs = omap_prcm_4xxx_irqs;
> + unfiltered_irqs_nr = omap_prcm_4xxx_irqs_nr;
> + omap_prcm_mask_event = omap4_prcm_mask_event;
> + omap_prcm_unmask_event = omap4_prcm_unmask_event;
> + omap_prcm_ack_event = omap4_prcm_ack_event;
> + omap_prcm_pending_events = omap4_prcm_pending_events;
> + irq_set_chained_handler(OMAP44XX_IRQ_PRCM, prcm_irq_handler);
> + } else {
> + return -ENODEV;
> + }
Minor nit: rather than use cpu_is_* here, some sort of struct of func
ptrs should be defined that is filled out by the prcm[34]xxx.c code and
registered with the common code.
> + for (i = 0; i < unfiltered_irqs_nr; i++)
> + if (omap_chip_is(unfiltered_irqs[i].omap_chip))
> + omap_prcm_irqs_nr++;
> +
> + omap_prcm_irqs = kmalloc(omap_prcm_irqs_nr *
> + sizeof(struct omap_prcm_irq),
> + GFP_KERNEL);
> + if (!omap_prcm_irqs)
> + return -ENOMEM;
> +
> + for (i = 0, j = 0; i < unfiltered_irqs_nr; i++)
> + if (omap_chip_is(unfiltered_irqs[i].omap_chip)) {
> + memcpy(&omap_prcm_irqs[j], &unfiltered_irqs[i],
> + sizeof(struct omap_prcm_irq));
> + j++;
> + }
> +
> + for (i = OMAP_PRCM_IRQ_BASE; i < OMAP_PRCM_IRQ_END; i++) {
> + irq_set_chip(i, &prcm_irq_chip);
> + irq_set_handler(i, handle_level_irq);
> + set_irq_flags(i, IRQF_VALID);
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * Reverses memory allocated and other setups done by
> + * omap_prcm_irq_init().
> + */
> +void omap_prcm_irq_cleanup(void)
> +{
> + int i;
> +
> + for (i = OMAP_PRCM_IRQ_BASE; i < OMAP_PRCM_IRQ_END; i++) {
> + irq_set_chip(i, NULL);
> + irq_set_handler(i, NULL);
> + set_irq_flags(i, 0);
> + }
> +
> + kfree(omap_prcm_irqs);
> +
> + if (cpu_is_omap34xx() || cpu_is_omap3630()) {
> + irq_set_chained_handler(INT_34XX_PRCM_MPU_IRQ, NULL);
> + } else {
> + irq_set_chained_handler(OMAP44XX_IRQ_PRCM, NULL);
> + }
> +}
> +
> u32 omap_prcm_get_reset_sources(void)
> {
> /* XXX This presumably needs modification for 34XX */
> diff --git a/arch/arm/mach-omap2/prcm3xxx.c b/arch/arm/mach-omap2/prcm3xxx.c
> new file mode 100644
> index 0000000..a57fe69
> --- /dev/null
> +++ b/arch/arm/mach-omap2/prcm3xxx.c
> @@ -0,0 +1,117 @@
> +/*
> + * linux/arch/arm/mach-omap2/prcm3xxx.c
> + *
> + * OMAP 3xxx Power Reset and Clock Management (PRCM) interrupt
> + * definitions
> + *
> + * Written by Thomas Petazzoni <t-petazzoni@ti.com>
> + * Copyright (C) 2010 Texas Instruments, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +
> +#include <plat/prcm.h>
> +
> +#include "prm-regbits-24xx.h"
> +
> +struct omap_prcm_irq __initdata omap_prcm_3xxx_irqs[] = {
> + OMAP_PRCM_IRQ("wkup", 0,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("evgenon", 2,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("evgenoff", 3,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("transition", 4,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("core_dpll_recal", 5,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("periph_dpll_recal", 6,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("mpu_dpll_recal", 7,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("iva2_dpll_recal", 8,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("io", 9,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("vp1_oppchangedone", 10,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("vp1_minvdd", 11,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("vp1_maxvdd", 12,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("vp1_nosmpsack", 13,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("vp1_eqvalue", 14,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("vp1_tranxdone", 15,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("vp2_oppchangedone", 16,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("vp2_minvdd", 17,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("vp2_maxvdd", 18,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("vp2_nosmpsack", 19,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("vp2_eqvalue", 20,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("vp2_tranxdone", 21,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("vc_saerr", 22,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("vc_raerr", 23,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("vc_timeout_err", 24,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("snd_periph_recal", 25,
> + CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("abb_ldo_tranxdone", 26,
> + CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("vc_vp1_ack", 27,
> + CHIP_GE_OMAP3630ES1_1),
> + OMAP_PRCM_IRQ("vc_bypass_ack", 28,
> + CHIP_GE_OMAP3630ES1_1),
> +};
> +
> +unsigned int __initdata
> +omap_prcm_3xxx_irqs_nr = ARRAY_SIZE(omap_prcm_3xxx_irqs);
> +
> +void omap3_prcm_mask_event(unsigned event)
> +{
> + unsigned int bit = BIT(event);
> +
> + omap2_prm_rmw_mod_reg_bits(bit, 0, OCP_MOD,
> + OMAP3_PRM_IRQENABLE_MPU_OFFSET);
> +}
> +
> +void omap3_prcm_unmask_event(unsigned event)
> +{
> + unsigned int bit = BIT(event);
> +
> + omap2_prm_rmw_mod_reg_bits(0, bit, OCP_MOD,
> + OMAP3_PRM_IRQENABLE_MPU_OFFSET);
> +}
> +
> +void omap3_prcm_ack_event(unsigned event)
> +{
> + unsigned int bit = BIT(event);
> +
> + omap2_prm_write_mod_reg(bit, OCP_MOD,
> + OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
> +}
> +
> +void omap3_prcm_pending_events(unsigned long *events)
> +{
> + u32 irqenable_mpu =
> + omap2_prm_read_mod_reg(OCP_MOD,
> + OMAP3_PRM_IRQENABLE_MPU_OFFSET);
> + u32 irqstatus_mpu =
> + omap2_prm_read_mod_reg(OCP_MOD,
> + OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
> + events[0] = irqenable_mpu & irqstatus_mpu;
> +}
> diff --git a/arch/arm/mach-omap2/prcm4xxx.c b/arch/arm/mach-omap2/prcm4xxx.c
> new file mode 100644
> index 0000000..e70f267
> --- /dev/null
> +++ b/arch/arm/mach-omap2/prcm4xxx.c
> @@ -0,0 +1,146 @@
> +/*
> + * linux/arch/arm/mach-omap2/prcm4xxx.c
Minor: filenames are not needed in headers. Files tend to move around
and these comments don't get updated.
> + * OMAP 4xxx Power Reset and Clock Management (PRCM) interrupt
> + * definitions
> + *
> + * Written by Thomas Petazzoni <t-petazzoni@ti.com>
> + * Copyright (C) 2010 Texas Instruments, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +
> +#include <plat/prcm.h>
> +
> +#include "prcm44xx.h"
> +#include "prm44xx.h"
> +
> +struct omap_prcm_irq __initdata omap_prcm_4xxx_irqs[] = {
> + OMAP_PRCM_IRQ("dpll_core_recal", 0,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("dpll_mpu_recal", 1,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("dpll_iva_recal", 2,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("dpll_per_recal", 3,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("dpll_abe_recal", 4,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("dpll_usb_recal", 5,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("dpll_unipro_recal", 7,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("transition", 8,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("io", 9,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vc_saerr", 11,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vc_raerr", 12,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vc_toerr", 13,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vc_bypassack", 14,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_core_oppchangedone", 16,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_core_minvdd", 17,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_core_maxvdd", 18,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_core_nosmpsack", 19,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_core_eqvalue", 20,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_core_tranxdone", 21,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_iva_oppchangedone", 24,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_iva_minvdd", 25,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_iva_maxvdd", 26,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_iva_nosmpsack", 27,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_iva_eqvalue", 28,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_iva_tranxdone", 29,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_iva_vpack", 30,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("abb_iva_done", 31,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_mpu_oppchangedone", 32,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_mpu_minvdd", 33,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_mpu_maxvdd", 34,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_mpu_nosmpsack", 35,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_mpu_eqvalue", 36,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_mpu_tranxdone", 37,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("vp_mpu_vpack", 38,
> + CHIP_IS_OMAP4430),
> + OMAP_PRCM_IRQ("abb_mpu_done", 39,
> + CHIP_IS_OMAP4430),
> +};
> +
> +unsigned int __initdata
> +omap_prcm_4xxx_irqs_nr = ARRAY_SIZE(omap_prcm_4xxx_irqs);
> +
> +void omap4_prcm_mask_event(unsigned event)
> +{
> + unsigned int bit = BIT(event % 32);
> + unsigned int off = (event / 32) * 4;
> +
> + omap4_prm_rmw_inst_reg_bits(bit, 0,
> + OMAP4430_PRM_OCP_SOCKET_INST,
> + OMAP4_PRM_IRQENABLE_MPU_OFFSET + off);
> +}
> +
> +void omap4_prcm_unmask_event(unsigned event)
> +{
> + unsigned int bit = BIT(event % 32);
> + unsigned int off = (event / 32) * 4;
> +
> + omap4_prm_rmw_inst_reg_bits(0, bit,
> + OMAP4430_PRM_OCP_SOCKET_INST,
> + OMAP4_PRM_IRQENABLE_MPU_OFFSET + off);
> +}
> +
> +void omap4_prcm_ack_event(unsigned event)
> +{
> + unsigned int bit = BIT(event % 32);
> + unsigned int off = (event / 32) * 4;
> +
> + omap4_prm_write_inst_reg(bit,
> + OMAP4430_PRM_OCP_SOCKET_INST,
> + OMAP4_PRM_IRQSTATUS_MPU_OFFSET + off);
> +}
> +
> +void omap4_prcm_pending_events(unsigned long *events)
> +{
> + u32 irqenable_mpu, irqstatus_mpu;
> + int i;
> +
> + /* OMAP4 has two enable/status registers for the PRCM */
> + for (i = 0; i < 2; i++) {
> + irqenable_mpu =
> + omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
> + OMAP4_PRM_IRQENABLE_MPU_OFFSET
> + + i * 4);
> + irqstatus_mpu =
> + omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
> + OMAP4_PRM_IRQSTATUS_MPU_OFFSET
> + + i * 4);
> + events[i] = irqenable_mpu & irqstatus_mpu;
> + }
> +}
> diff --git a/arch/arm/plat-omap/include/plat/irqs.h b/arch/arm/plat-omap/include/plat/irqs.h
> index 5a25098..23b9680 100644
> --- a/arch/arm/plat-omap/include/plat/irqs.h
> +++ b/arch/arm/plat-omap/include/plat/irqs.h
> @@ -366,7 +366,14 @@
> #define OMAP_MAX_GPIO_LINES 192
> #define IH_GPIO_BASE (128 + IH2_BASE)
> #define IH_MPUIO_BASE (OMAP_MAX_GPIO_LINES + IH_GPIO_BASE)
> -#define OMAP_IRQ_END (IH_MPUIO_BASE + 16)
> +#define OMAP_MPUIO_IRQ_END (IH_MPUIO_BASE + 16)
> +
> +/* 64 IRQs for the PRCM (32 are needed on OMAP3, 64 on OMAP4) */
> +#define OMAP_PRCM_IRQ_BASE (OMAP_MPUIO_IRQ_END)
> +#define OMAP_PRCM_NR_IRQS 64
> +#define OMAP_PRCM_IRQ_END (OMAP_PRCM_IRQ_BASE + OMAP_PRCM_NR_IRQS)
> +
> +#define OMAP_IRQ_END (OMAP_PRCM_IRQ_END)
>
> /* External FPGA handles interrupts on Innovator boards */
> #define OMAP_FPGA_IRQ_BASE (OMAP_IRQ_END)
> diff --git a/arch/arm/plat-omap/include/plat/prcm.h b/arch/arm/plat-omap/include/plat/prcm.h
> index 267f43b..5785555 100644
> --- a/arch/arm/plat-omap/include/plat/prcm.h
> +++ b/arch/arm/plat-omap/include/plat/prcm.h
> @@ -27,6 +27,51 @@
> #ifndef __ASM_ARM_ARCH_OMAP_PRCM_H
> #define __ASM_ARM_ARCH_OMAP_PRCM_H
>
> +#include <plat/cpu.h>
> +
> +/*
> + * Structure describing the interrupt corresponding to each PRCM event
> + */
> +struct omap_prcm_irq {
> + /* Logical name for the interrupt */
> + const char *name;
> +
> + /*
> + * Corresponding offset in the status/enable register. The
> + * offset can be greater than 32, in which case it spans over
> + * the second status register
> + */
> + unsigned int offset;
> +
> + /* OMAP chip for which this PRCM event exists */
> + const struct omap_chip_id omap_chip;
> +};
> +
> +#define OMAP_PRCM_IRQ(_name, _offset, _chip) \
> + { .name = _name, \
> + .offset = _offset, \
> + .omap_chip = OMAP_CHIP_INIT(_chip) }
> +
> +/* Maximum number of PRCM interrupt status registers */
> +#define OMAP_PRCM_MAX_NR_PENDING_REG 2
> +
> +extern struct omap_prcm_irq omap_prcm_3xxx_irqs[];
> +extern unsigned int omap_prcm_3xxx_irqs_nr;
> +void omap3_prcm_mask_event(unsigned event);
> +void omap3_prcm_unmask_event(unsigned event);
> +void omap3_prcm_ack_event(unsigned event);
> +void omap3_prcm_pending_events(unsigned long *pending);
> +
> +extern struct omap_prcm_irq omap_prcm_4xxx_irqs[];
> +extern unsigned int omap_prcm_4xxx_irqs_nr;
> +void omap4_prcm_mask_event(unsigned event);
> +void omap4_prcm_unmask_event(unsigned event);
> +void omap4_prcm_ack_event(unsigned event);
> +void omap4_prcm_pending_events(unsigned long *pending);
Defining a struct of func ptrs and filling it out in the prcm[34]xxx.c
file would also mean you wouldn't need all the omap3_ and omap4_
functions in the header.
> +int omap_prcm_event_to_irq(const char *name);
> +int omap_prcm_irq_init(void);
> +void omap_prcm_irq_cleanup(void);
> u32 omap_prcm_get_reset_sources(void);
> int omap2_cm_wait_idlest(void __iomem *reg, u32 mask, u8 idlest,
> const char *name);
Kevin
next prev parent reply other threads:[~2011-06-22 23:53 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-06-22 16:42 [PATCHv3 0/6] PRCM chain handler Tero Kristo
2011-06-22 16:42 ` [PATCHv3 1/6] omap: prcm: switch to a chained IRQ handler mechanism Tero Kristo
2011-06-22 23:53 ` Kevin Hilman [this message]
2011-06-23 7:24 ` Tero Kristo
2011-06-23 8:19 ` Tony Lindgren
2011-06-23 9:08 ` Tero Kristo
2011-06-23 9:51 ` Tony Lindgren
2011-06-24 16:00 ` Kevin Hilman
2011-06-24 21:02 ` Kevin Hilman
2011-06-22 16:42 ` [PATCHv3 2/6] PRCM: Add support for PAD wakeup interrupts Tero Kristo
2011-06-23 10:23 ` Govindraj
2011-06-24 21:34 ` Kevin Hilman
2011-06-24 21:21 ` Kevin Hilman
2011-06-22 16:42 ` [PATCHv3 3/6] OMAP: PRCM: Added an api to get id for a PRCM event Tero Kristo
2011-06-24 21:58 ` Kevin Hilman
2011-06-22 16:42 ` [PATCHv3 4/6] OMAP3: PM: Use PRCM chain handler Tero Kristo
2011-06-24 21:57 ` Kevin Hilman
2011-06-22 16:42 ` [PATCHv3 5/6] OMAP3: Serial: Made serial to work properly with " Tero Kristo
2011-06-22 17:09 ` Tero Kristo
2011-06-23 10:30 ` Govindraj
2011-06-23 8:21 ` Tony Lindgren
2011-06-23 9:11 ` Tero Kristo
2011-06-23 10:00 ` Tony Lindgren
2011-06-23 10:35 ` Govindraj
2011-06-23 11:12 ` Tony Lindgren
2011-06-24 15:15 ` Kevin Hilman
2011-06-24 22:00 ` Kevin Hilman
2011-06-22 16:42 ` [PATCHv3 6/6] OMAP3: Serial tty: Added resume_idle calls to critical points Tero Kristo
2011-06-27 15:02 ` [PATCHv3 0/6] PRCM chain handler Tero Kristo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87fwn1h18r.fsf@ti.com \
--to=khilman@ti.com \
--cc=avinashhm@ti.com \
--cc=b-cousson@ti.com \
--cc=linux-omap@vger.kernel.org \
--cc=t-kristo@ti.com \
--cc=thomas.petazzoni@free-electrons.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox