From: Tero Kristo <t-kristo@ti.com>
To: "Hilman, Kevin" <khilman@ti.com>
Cc: linux-omap@vger.kernel.org,
Thomas Petazzoni <thomas.petazzoni@free-electrons.com>,
"Mahadeva, Avinash" <avinashhm@ti.com>,
"Cousson, Benoit" <b-cousson@ti.com>
Subject: Re: [PATCHv3 1/6] omap: prcm: switch to a chained IRQ handler mechanism
Date: Thu, 23 Jun 2011 10:24:45 +0300 [thread overview]
Message-ID: <1308813885.5972.9.camel@sokoban> (raw)
In-Reply-To: <87fwn1h18r.fsf@ti.com>
On Thu, 2011-06-23 at 01:53 +0200, Hilman, Kevin wrote:
> 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?
Actually no, I just sent this patch out as is, forgot to update this
comment. I'll update this also as I need to update this patch anyway. :)
>
> > 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.
Ok, easy one to fix.
>
> > ---
> > 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.
I tried this out and yea, you are right. It is not needed anymore. 1st
level chain handler + level_handler for them is enough to handle PRCM
interrupts properly. We still need the actual interrupt to wake up from
WFI.
>
> > + 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.)
I'll take a look at this if it is possible.
>
> > +/*
> > + * 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.
I was actually thinking something like this myself, but stayed with the
original implementation here. I'll change this part.
>
> > + 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.
I'll remove those.
>
> > + * 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.
omap3 specific unmask functions are still needed by the omap_sram_idle
to enable wakeup sources. Or, I could just enable those manually from
the PRCM registers. I'll look up a solution for this.
>
> > +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
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
next prev parent reply other threads:[~2011-06-23 7:24 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
2011-06-23 7:24 ` Tero Kristo [this message]
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=1308813885.5972.9.camel@sokoban \
--to=t-kristo@ti.com \
--cc=avinashhm@ti.com \
--cc=b-cousson@ti.com \
--cc=khilman@ti.com \
--cc=linux-omap@vger.kernel.org \
--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