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/...
>
> Signed-off-by: Steve Chen <[email protected]>
> Signed-off-by: Mark Greer <[email protected]>
> Signed-off-by: Sergei Shtylyov <[email protected]>

Russell,

I'm OK with the basics of this driver, but we've been having some
disagreement about where this driver should live.  It is currently
only used in the TI DaVinci family, so was originally slated for
arch/arm/mach-davinci.  But as Sergei pointed out, this INTC is used
on other non-DaVinci TI parts which do not have mainline support (and
I am not aware of any efforts to push to mainline.)  So, Sergei has
proposed moving to arch/arm/common/

If we really want to be generic, arch/arm/common isn't the right place
since the other TI parts are both ARM and MIPS parts, but I'm not
aware of a good place or any precedents for arch-independent interrupt
controllers.

Therefore, my proposal is to leave it in arch/arm/mach-davinci/ until
there is need to reuse it elsewhere.

Thoughts?

Kevin

> ---
> This controller is also used in TI Puma 5 ARM SoC and TI Titan MIPS SoC (the
> Linux support for which exists out of the mainline trees).
> The patch is against the recent DaVinci tree...
>
> Changes since take 2:
> - fixed the 'mask' variable initializer in the set_type() method;
> - made use of BIT_WORD(), BIT_MASK(), and BITS_TO_LONGS() macros;
> - replaced -1 by -EINVAL in the set_type() method;
> - renamed 2 variables in the set_type() method.
>
>  arch/arm/common/Kconfig                 |    3 
>  arch/arm/common/Makefile                |    1 
>  arch/arm/common/cp_intc.c               |  160 
> ++++++++++++++++++++++++++++++++
>  arch/arm/include/asm/hardware/cp_intc.h |   57 +++++++++++
>  4 files changed, 221 insertions(+)
>
> Index: linux-davinci/arch/arm/common/Kconfig
> ===================================================================
> --- linux-davinci.orig/arch/arm/common/Kconfig
> +++ linux-davinci/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-davinci/arch/arm/common/Makefile
> ===================================================================
> --- linux-davinci.orig/arch/arm/common/Makefile
> +++ linux-davinci/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-davinci/arch/arm/common/cp_intc.c
> ===================================================================
> --- /dev/null
> +++ linux-davinci/arch/arm/common/cp_intc.c
> @@ -0,0 +1,160 @@
> +/*
> + * 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;
> +
> +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            = BIT_WORD(irq);
> +     unsigned mask           = BIT_MASK(irq);
> +     unsigned polarity       = cp_intc_read(CP_INTC_SYS_POLARITY(reg));
> +     unsigned type           = cp_intc_read(CP_INTC_SYS_TYPE(reg));
> +
> +     switch (flow_type) {
> +     case IRQ_TYPE_EDGE_RISING:
> +             polarity |= mask;
> +             type |= mask;
> +             break;
> +     case IRQ_TYPE_EDGE_FALLING:
> +             polarity &= ~mask;
> +             type |= mask;
> +             break;
> +     case IRQ_TYPE_LEVEL_HIGH:
> +             polarity |= mask;
> +             type &= ~mask;
> +             break;
> +     case IRQ_TYPE_LEVEL_LOW:
> +             polarity &= ~mask;
> +             type &= ~mask;
> +             break;
> +     default:
> +             return -EINVAL;
> +     }
> +
> +     cp_intc_write(polarity, CP_INTC_SYS_POLARITY(reg));
> +     cp_intc_write(type, 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        = BITS_TO_LONGS(num_irq);
> +     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-davinci/arch/arm/include/asm/hardware/cp_intc.h
> ===================================================================
> --- /dev/null
> +++ linux-davinci/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