Sergei Shtylyov <[email protected]> writes:

> Add support for Texas Instuments Common Platform Interrupt Controller
> (cp_intc).
>
> It's being added as a part of DA830/OMAP-L137 support, however as cp_intc is
> not really specific to this architecture (or even ARM specific), I thought 
> that
> the best place for this code will be in arch/arm/common/...

Are there other known, or upcoming users this block outside the
da830/omap-L1x family parts?  If not, I would lean towards keeping it
in arch/arm/mach-davinci and abstracting it out later if/when
necessary since if it really is generic, and not ARM specific,
arch/arm/common is no less appropriate than arch/arm/mach-davinci.

> Signed-off-by: Steve Chen <[email protected]>
> Signed-off-by: Mark Greer <[email protected]>
> Signed-off-by: Sergei Shtylyov <[email protected]>

Mostly, it looks pretty good.  Some comments below...

> ---
> This patch is against the recent Linus' tree...
>
>  arch/arm/common/Kconfig                 |    3 
>  arch/arm/common/Makefile                |    1 
>  arch/arm/common/cp_intc.c               |  159 
> ++++++++++++++++++++++++++++++++
>  arch/arm/include/asm/hardware/cp_intc.h |   57 +++++++++++
>  4 files changed, 220 insertions(+)
>
> Index: linux-2.6/arch/arm/common/Kconfig
> ===================================================================
> --- linux-2.6.orig/arch/arm/common/Kconfig
> +++ linux-2.6/arch/arm/common/Kconfig
> @@ -34,5 +34,8 @@ config SHARPSL_PM
>  config SHARP_SCOOP
>       bool
>  
> +config TI_CP_INTC
> +     bool
> +
>  config COMMON_CLKDEV
>       bool
> Index: linux-2.6/arch/arm/common/Makefile
> ===================================================================
> --- linux-2.6.orig/arch/arm/common/Makefile
> +++ linux-2.6/arch/arm/common/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_SHARP_LOCOMO)  += locomo.o
>  obj-$(CONFIG_SHARP_PARAM)    += sharpsl_param.o
>  obj-$(CONFIG_SHARPSL_PM)     += sharpsl_pm.o
>  obj-$(CONFIG_SHARP_SCOOP)    += scoop.o
> +obj-$(CONFIG_TI_CP_INTC)     += cp_intc.o
>  obj-$(CONFIG_ARCH_IXP2000)   += uengine.o
>  obj-$(CONFIG_ARCH_IXP23XX)   += uengine.o
>  obj-$(CONFIG_PCI_HOST_ITE8152)  += it8152.o
> Index: linux-2.6/arch/arm/common/cp_intc.c
> ===================================================================
> --- /dev/null
> +++ linux-2.6/arch/arm/common/cp_intc.c
> @@ -0,0 +1,159 @@
> +/*
> + * TI Common Platform Interrupt Controller (cp_intc) driver
> + *
> + * Author: Steve Chen <[email protected]>
> + * Copyright (C) 2008-2009, MontaVista Software, Inc. <[email protected]>
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/sched.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/irq.h>
> +#include <linux/io.h>
> +#include <asm/hardware/cp_intc.h>
> +
> +static void __iomem *cp_intc_base;
> +

Is there only ever going to be a single CP_INTC on any given device?
If not, this approach will fall down.

Instead of this global, maybe adding a struct with the base and
num_irqs that is allocated during cp_intc_init() ?

> +static inline unsigned int cp_intc_read(unsigned offset)
> +{
> +     return __raw_readl(cp_intc_base + offset);
> +}
> +
> +static inline void cp_intc_write(unsigned long value, unsigned offset)
> +{
> +     __raw_writel(value, cp_intc_base + offset);
> +}
> +
> +static void cp_intc_ack_irq(unsigned int irq)
> +{
> +     cp_intc_write(irq, CP_INTC_SYS_STAT_IDX_CLR);
> +}
> +
> +/* Disable interrupt */
> +static void cp_intc_mask_irq(unsigned int irq)
> +{
> +     /* XXX don't know why we need to disable nIRQ here... */
> +     cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_CLR);
> +     cp_intc_write(irq, CP_INTC_SYS_ENABLE_IDX_CLR);
> +     cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET);
> +}
> +
> +/* Enable interrupt */
> +static void cp_intc_unmask_irq(unsigned int irq)
> +{
> +     cp_intc_write(irq, CP_INTC_SYS_ENABLE_IDX_SET);
> +}
> +
> +static int cp_intc_set_irq_type(unsigned int irq, unsigned int flow_type)
> +{
> +     unsigned reg            = irq >> 5;

minor nitpick: for a little more clarity, you can use BIT_WORD() here.

> +     unsigned mask           = irq & 0x1f;

maybe a #define here instead of hard-coded constant.

> +     unsigned pol_mask       = cp_intc_read(CP_INTC_SYS_POLARITY(reg));
> +     unsigned type_mask      = cp_intc_read(CP_INTC_SYS_TYPE(reg));
> +
> +     switch (flow_type) {
> +     case IRQ_TYPE_EDGE_RISING:
> +             pol_mask  |= mask;
> +             type_mask |= mask;
> +             break;
> +     case IRQ_TYPE_EDGE_FALLING:
> +             pol_mask  &= ~mask;
> +             type_mask |= mask;
> +             break;
> +     case IRQ_TYPE_LEVEL_HIGH:
> +             pol_mask  |= mask;
> +             type_mask &= ~mask;
> +             break;
> +     case IRQ_TYPE_LEVEL_LOW:
> +             pol_mask  &= ~mask;
> +             type_mask &= ~mask;
> +             break;
> +     default:
> +             return -1;
> +     }
> +
> +     cp_intc_write(pol_mask,  CP_INTC_SYS_POLARITY(reg));
> +     cp_intc_write(type_mask, CP_INTC_SYS_TYPE(reg));
> +     return 0;
> +}
> +
> +static struct irq_chip cp_intc_irq_chip = {
> +     .name           = "cp_intc",
> +     .ack            = cp_intc_ack_irq,
> +     .mask           = cp_intc_mask_irq,
> +     .unmask         = cp_intc_unmask_irq,
> +     .set_type       = cp_intc_set_irq_type,
> +};
> +
> +void __init cp_intc_init(void __iomem *base, unsigned short num_irq,
> +                      u8 *irq_prio)
> +{
> +     unsigned num_reg        = (num_irq + 0x1f) >> 5;
> +     int i;
> +
> +     cp_intc_base = base;
> +
> +     cp_intc_write(0, CP_INTC_GLOBAL_ENABLE);
> +
> +     /* Disable all host interrupts */
> +     cp_intc_write(0, CP_INTC_HOST_ENABLE(0));
> +
> +     /* Disable system interrupts */
> +     for (i = 0; i < num_reg; i++)
> +             cp_intc_write(~0, CP_INTC_SYS_ENABLE_CLR(i));
> +
> +     /* Set to normal mode, no nesting, no priority hold */
> +     cp_intc_write(0, CP_INTC_CTRL);
> +     cp_intc_write(0, CP_INTC_HOST_CTRL);
> +
> +     /* Clear system interrupt status */
> +     for (i = 0; i < num_reg; i++)
> +             cp_intc_write(~0, CP_INTC_SYS_STAT_CLR(i));
> +
> +     /* Enable nIRQ (what about nFIQ?) */
> +     cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET);
> +
> +     /*
> +      * Priority is determined by host channel: lower channel number has
> +      * higher priority i.e. channel 0 has highest priority and channel 31
> +      * had the lowest priority.
> +      */
> +     num_reg = (num_irq + 3) >> 2; /* 4 channels per register */
> +     if (irq_prio) {
> +             unsigned j, k;
> +             u32 val;
> +
> +             for (k = i = 0; i < num_reg; i++) {
> +                     for (val = j = 0; j < 4; j++, k++) {
> +                             val >>= 8;
> +                             if (k < num_irq)
> +                                     val |= irq_prio[k] << 24;
> +                     }
> +
> +                     cp_intc_write(val, CP_INTC_CHAN_MAP(i));
> +             }
> +     } else {
> +             /*
> +              * Default everything to channel 15 if priority not specified.
> +              * Note that channel 0-1 are mapped to nFIQ and channels 2-31
> +              * are mapped to nIRQ.
> +              */
> +             for (i = 0; i < num_reg; i++)
> +                     cp_intc_write(0x0f0f0f0f, CP_INTC_CHAN_MAP(i));
> +     }
> +
> +     /* Set up genirq dispatching for cp_intc */
> +     for (i = 0; i < num_irq; i++) {
> +             set_irq_chip(i, &cp_intc_irq_chip);
> +             set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
> +             set_irq_handler(i, handle_edge_irq);
> +     }
> +
> +     /* Enable global interrupt */
> +     cp_intc_write(1, CP_INTC_GLOBAL_ENABLE);
> +}
> Index: linux-2.6/arch/arm/include/asm/hardware/cp_intc.h
> ===================================================================
> --- /dev/null
> +++ linux-2.6/arch/arm/include/asm/hardware/cp_intc.h
> @@ -0,0 +1,57 @@
> +/*
> + * TI Common Platform Interrupt Controller (cp_intc) definitions
> + *
> + * Author: Steve Chen <[email protected]>
> + * Copyright (C) 2008-2009, MontaVista Software, Inc. <[email protected]>
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +#ifndef __ASM_HARDWARE_CP_INTC_H
> +#define __ASM_HARDWARE_CP_INTC_H
> +
> +#define CP_INTC_REV                  0x00
> +#define CP_INTC_CTRL                 0x04
> +#define CP_INTC_HOST_CTRL            0x0C
> +#define CP_INTC_GLOBAL_ENABLE                0x10
> +#define CP_INTC_GLOBAL_NESTING_LEVEL 0x1C
> +#define CP_INTC_SYS_STAT_IDX_SET     0x20
> +#define CP_INTC_SYS_STAT_IDX_CLR     0x24
> +#define CP_INTC_SYS_ENABLE_IDX_SET   0x28
> +#define CP_INTC_SYS_ENABLE_IDX_CLR   0x2C
> +#define CP_INTC_GLOBAL_WAKEUP_ENABLE 0x30
> +#define CP_INTC_HOST_ENABLE_IDX_SET  0x34
> +#define CP_INTC_HOST_ENABLE_IDX_CLR  0x38
> +#define CP_INTC_PACING_PRESCALE      0x40
> +#define CP_INTC_VECTOR_BASE          0x50
> +#define CP_INTC_VECTOR_SIZE          0x54
> +#define CP_INTC_VECTOR_NULL          0x58
> +#define CP_INTC_PRIO_IDX             0x80
> +#define CP_INTC_PRIO_VECTOR          0x84
> +#define CP_INTC_SECURE_ENABLE                0x90
> +#define CP_INTC_SECURE_PRIO_IDX      0x94
> +#define CP_INTC_PACING_PARAM(n)      (0x0100 + (n << 4))
> +#define CP_INTC_PACING_DEC(n)                (0x0104 + (n << 4))
> +#define CP_INTC_PACING_MAP(n)                (0x0108 + (n << 4))
> +#define CP_INTC_SYS_RAW_STAT(n)      (0x0200 + (n << 2))
> +#define CP_INTC_SYS_STAT_CLR(n)      (0x0280 + (n << 2))
> +#define CP_INTC_SYS_ENABLE_SET(n)    (0x0300 + (n << 2))
> +#define CP_INTC_SYS_ENABLE_CLR(n)    (0x0380 + (n << 2))
> +#define CP_INTC_CHAN_MAP(n)          (0x0400 + (n << 2))
> +#define CP_INTC_HOST_MAP(n)          (0x0800 + (n << 2))
> +#define CP_INTC_HOST_PRIO_IDX(n)     (0x0900 + (n << 2))
> +#define CP_INTC_SYS_POLARITY(n)      (0x0D00 + (n << 2))
> +#define CP_INTC_SYS_TYPE(n)          (0x0D80 + (n << 2))
> +#define CP_INTC_WAKEUP_ENABLE(n)     (0x0E00 + (n << 2))
> +#define CP_INTC_DEBUG_SELECT(n)      (0x0F00 + (n << 2))
> +#define CP_INTC_SYS_SECURE_ENABLE(n) (0x1000 + (n << 2))
> +#define CP_INTC_HOST_NESTING_LEVEL(n)        (0x1100 + (n << 2))
> +#define CP_INTC_HOST_ENABLE(n)               (0x1500 + (n << 2))
> +#define CP_INTC_HOST_PRIO_VECTOR(n)  (0x1600 + (n << 2))
> +#define CP_INTC_VECTOR_ADDR(n)               (0x2000 + (n << 2))
> +
> +void __init cp_intc_init(void __iomem *base, unsigned short num_irq,
> +                      u8 *irq_prio);
> +
> +#endif       /* __ASM_HARDWARE_CP_INTC_H */

_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to