Re: [PATCHv3 1/6] omap: prcm: switch to a chained IRQ handler mechanism

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 2011-06-23 at 01:53 +0200, Hilman, Kevin wrote:
> Hi Tero,
> 
> Tero Kristo <t-kristo@xxxxxx> 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@xxxxxx>
> > Cc: Thomas Petazzoni <thomas.petazzoni@xxxxxxxxxxxxxxxxxx>
> > Cc: Avinash.H.M <avinashhm@xxxxxx>
> > Cc: Kevin Hilman <khilman@xxxxxx>
> > Cc: Cousson, Benoit <b-cousson@xxxxxx>
> 
> 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@xxxxxx>
> > + * 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@xxxxxx>
> > + * 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
 

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux