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
