2009-08-18 13:23:37 +01:00
/*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* Copyright ( C ) 2008 Maxime Bizon < mbizon @ freebox . fr >
* Copyright ( C ) 2008 Nicolas Schichan < nschichan @ freebox . fr >
*/
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/module.h>
2010-10-07 14:08:54 +01:00
# include <linux/irq.h>
2009-08-18 13:23:37 +01:00
# include <asm/irq_cpu.h>
# include <asm/mipsregs.h>
# include <bcm63xx_cpu.h>
# include <bcm63xx_regs.h>
# include <bcm63xx_io.h>
# include <bcm63xx_irq.h>
2011-11-04 19:09:31 +01:00
static void __dispatch_internal ( void ) __maybe_unused ;
2011-11-04 19:09:33 +01:00
static void __dispatch_internal_64 ( void ) __maybe_unused ;
static void __internal_irq_mask_32 ( unsigned int irq ) __maybe_unused ;
static void __internal_irq_mask_64 ( unsigned int irq ) __maybe_unused ;
static void __internal_irq_unmask_32 ( unsigned int irq ) __maybe_unused ;
static void __internal_irq_unmask_64 ( unsigned int irq ) __maybe_unused ;
2011-11-04 19:09:31 +01:00
# ifndef BCMCPU_RUNTIME_DETECT
2013-06-18 16:55:40 +00:00
# ifdef CONFIG_BCM63XX_CPU_3368
# define irq_stat_reg PERF_IRQSTAT_3368_REG
# define irq_mask_reg PERF_IRQMASK_3368_REG
# define irq_bits 32
# define is_ext_irq_cascaded 0
# define ext_irq_start 0
# define ext_irq_end 0
# define ext_irq_count 4
# define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_3368
# define ext_irq_cfg_reg2 0
# endif
2012-07-24 16:33:12 +02:00
# ifdef CONFIG_BCM63XX_CPU_6328
# define irq_stat_reg PERF_IRQSTAT_6328_REG
# define irq_mask_reg PERF_IRQMASK_6328_REG
# define irq_bits 64
# define is_ext_irq_cascaded 1
# define ext_irq_start (BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE)
# define ext_irq_end (BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE)
# define ext_irq_count 4
# define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6328
# define ext_irq_cfg_reg2 0
# endif
2011-11-04 19:09:31 +01:00
# ifdef CONFIG_BCM63XX_CPU_6338
# define irq_stat_reg PERF_IRQSTAT_6338_REG
# define irq_mask_reg PERF_IRQMASK_6338_REG
2011-11-04 19:09:33 +01:00
# define irq_bits 32
2011-11-04 19:09:32 +01:00
# define is_ext_irq_cascaded 0
# define ext_irq_start 0
# define ext_irq_end 0
2011-11-04 19:09:34 +01:00
# define ext_irq_count 4
# define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6338
# define ext_irq_cfg_reg2 0
2011-11-04 19:09:31 +01:00
# endif
# ifdef CONFIG_BCM63XX_CPU_6345
# define irq_stat_reg PERF_IRQSTAT_6345_REG
# define irq_mask_reg PERF_IRQMASK_6345_REG
2011-11-04 19:09:33 +01:00
# define irq_bits 32
2011-11-04 19:09:32 +01:00
# define is_ext_irq_cascaded 0
# define ext_irq_start 0
# define ext_irq_end 0
2012-07-13 07:46:03 +00:00
# define ext_irq_count 4
# define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6345
2011-11-04 19:09:34 +01:00
# define ext_irq_cfg_reg2 0
2011-11-04 19:09:31 +01:00
# endif
# ifdef CONFIG_BCM63XX_CPU_6348
# define irq_stat_reg PERF_IRQSTAT_6348_REG
# define irq_mask_reg PERF_IRQMASK_6348_REG
2011-11-04 19:09:33 +01:00
# define irq_bits 32
2011-11-04 19:09:32 +01:00
# define is_ext_irq_cascaded 0
# define ext_irq_start 0
# define ext_irq_end 0
2011-11-04 19:09:34 +01:00
# define ext_irq_count 4
# define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6348
# define ext_irq_cfg_reg2 0
2011-11-04 19:09:31 +01:00
# endif
# ifdef CONFIG_BCM63XX_CPU_6358
# define irq_stat_reg PERF_IRQSTAT_6358_REG
# define irq_mask_reg PERF_IRQMASK_6358_REG
2011-11-04 19:09:33 +01:00
# define irq_bits 32
2011-11-04 19:09:32 +01:00
# define is_ext_irq_cascaded 1
# define ext_irq_start (BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE)
# define ext_irq_end (BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE)
2011-11-04 19:09:34 +01:00
# define ext_irq_count 4
# define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6358
# define ext_irq_cfg_reg2 0
2011-11-04 19:09:31 +01:00
# endif
2013-03-21 14:03:17 +00:00
# ifdef CONFIG_BCM63XX_CPU_6362
# define irq_stat_reg PERF_IRQSTAT_6362_REG
# define irq_mask_reg PERF_IRQMASK_6362_REG
# define irq_bits 64
# define is_ext_irq_cascaded 1
# define ext_irq_start (BCM_6362_EXT_IRQ0 - IRQ_INTERNAL_BASE)
# define ext_irq_end (BCM_6362_EXT_IRQ3 - IRQ_INTERNAL_BASE)
# define ext_irq_count 4
# define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6362
# define ext_irq_cfg_reg2 0
# endif
2011-11-04 19:09:35 +01:00
# ifdef CONFIG_BCM63XX_CPU_6368
# define irq_stat_reg PERF_IRQSTAT_6368_REG
# define irq_mask_reg PERF_IRQMASK_6368_REG
# define irq_bits 64
# define is_ext_irq_cascaded 1
# define ext_irq_start (BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE)
# define ext_irq_end (BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE)
# define ext_irq_count 6
# define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6368
# define ext_irq_cfg_reg2 PERF_EXTIRQ_CFG_REG2_6368
# endif
2011-11-04 19:09:31 +01:00
2011-11-04 19:09:33 +01:00
# if irq_bits == 32
# define dispatch_internal __dispatch_internal
# define internal_irq_mask __internal_irq_mask_32
# define internal_irq_unmask __internal_irq_unmask_32
# else
# define dispatch_internal __dispatch_internal_64
# define internal_irq_mask __internal_irq_mask_64
# define internal_irq_unmask __internal_irq_unmask_64
# endif
2011-11-04 19:09:31 +01:00
# define irq_stat_addr (bcm63xx_regset_address(RSET_PERF) + irq_stat_reg)
# define irq_mask_addr (bcm63xx_regset_address(RSET_PERF) + irq_mask_reg)
static inline void bcm63xx_init_irq ( void )
{
}
# else /* ! BCMCPU_RUNTIME_DETECT */
static u32 irq_stat_addr , irq_mask_addr ;
static void ( * dispatch_internal ) ( void ) ;
2011-11-04 19:09:32 +01:00
static int is_ext_irq_cascaded ;
2011-11-04 19:09:34 +01:00
static unsigned int ext_irq_count ;
2011-11-04 19:09:32 +01:00
static unsigned int ext_irq_start , ext_irq_end ;
2011-11-04 19:09:34 +01:00
static unsigned int ext_irq_cfg_reg1 , ext_irq_cfg_reg2 ;
2011-11-04 19:09:33 +01:00
static void ( * internal_irq_mask ) ( unsigned int irq ) ;
static void ( * internal_irq_unmask ) ( unsigned int irq ) ;
2011-11-04 19:09:31 +01:00
static void bcm63xx_init_irq ( void )
{
2011-11-04 19:09:33 +01:00
int irq_bits ;
2011-11-04 19:09:31 +01:00
irq_stat_addr = bcm63xx_regset_address ( RSET_PERF ) ;
irq_mask_addr = bcm63xx_regset_address ( RSET_PERF ) ;
switch ( bcm63xx_get_cpu_id ( ) ) {
2013-06-18 16:55:40 +00:00
case BCM3368_CPU_ID :
irq_stat_addr + = PERF_IRQSTAT_3368_REG ;
irq_mask_addr + = PERF_IRQMASK_3368_REG ;
irq_bits = 32 ;
ext_irq_count = 4 ;
ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_3368 ;
break ;
2012-07-24 16:33:12 +02:00
case BCM6328_CPU_ID :
irq_stat_addr + = PERF_IRQSTAT_6328_REG ;
irq_mask_addr + = PERF_IRQMASK_6328_REG ;
irq_bits = 64 ;
ext_irq_count = 4 ;
is_ext_irq_cascaded = 1 ;
ext_irq_start = BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE ;
ext_irq_end = BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE ;
ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6328 ;
break ;
2011-11-04 19:09:31 +01:00
case BCM6338_CPU_ID :
irq_stat_addr + = PERF_IRQSTAT_6338_REG ;
irq_mask_addr + = PERF_IRQMASK_6338_REG ;
2011-11-04 19:09:33 +01:00
irq_bits = 32 ;
2012-07-13 07:46:03 +00:00
ext_irq_count = 4 ;
ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6338 ;
2011-11-04 19:09:31 +01:00
break ;
case BCM6345_CPU_ID :
irq_stat_addr + = PERF_IRQSTAT_6345_REG ;
irq_mask_addr + = PERF_IRQMASK_6345_REG ;
2011-11-04 19:09:33 +01:00
irq_bits = 32 ;
2012-07-13 07:46:03 +00:00
ext_irq_count = 4 ;
ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6345 ;
2011-11-04 19:09:31 +01:00
break ;
case BCM6348_CPU_ID :
irq_stat_addr + = PERF_IRQSTAT_6348_REG ;
irq_mask_addr + = PERF_IRQMASK_6348_REG ;
2011-11-04 19:09:33 +01:00
irq_bits = 32 ;
2011-11-04 19:09:34 +01:00
ext_irq_count = 4 ;
ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6348 ;
2011-11-04 19:09:31 +01:00
break ;
case BCM6358_CPU_ID :
irq_stat_addr + = PERF_IRQSTAT_6358_REG ;
irq_mask_addr + = PERF_IRQMASK_6358_REG ;
2011-11-04 19:09:33 +01:00
irq_bits = 32 ;
2011-11-04 19:09:34 +01:00
ext_irq_count = 4 ;
2011-11-04 19:09:32 +01:00
is_ext_irq_cascaded = 1 ;
ext_irq_start = BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE ;
ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE ;
2011-11-04 19:09:34 +01:00
ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6358 ;
2011-11-04 19:09:31 +01:00
break ;
2013-03-21 14:03:17 +00:00
case BCM6362_CPU_ID :
irq_stat_addr + = PERF_IRQSTAT_6362_REG ;
irq_mask_addr + = PERF_IRQMASK_6362_REG ;
irq_bits = 64 ;
ext_irq_count = 4 ;
is_ext_irq_cascaded = 1 ;
ext_irq_start = BCM_6362_EXT_IRQ0 - IRQ_INTERNAL_BASE ;
ext_irq_end = BCM_6362_EXT_IRQ3 - IRQ_INTERNAL_BASE ;
ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6362 ;
break ;
2011-11-04 19:09:35 +01:00
case BCM6368_CPU_ID :
irq_stat_addr + = PERF_IRQSTAT_6368_REG ;
irq_mask_addr + = PERF_IRQMASK_6368_REG ;
irq_bits = 64 ;
ext_irq_count = 6 ;
is_ext_irq_cascaded = 1 ;
ext_irq_start = BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE ;
ext_irq_end = BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE ;
ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6368 ;
ext_irq_cfg_reg2 = PERF_EXTIRQ_CFG_REG2_6368 ;
break ;
2011-11-04 19:09:31 +01:00
default :
BUG ( ) ;
}
2011-11-04 19:09:33 +01:00
if ( irq_bits = = 32 ) {
dispatch_internal = __dispatch_internal ;
internal_irq_mask = __internal_irq_mask_32 ;
internal_irq_unmask = __internal_irq_unmask_32 ;
} else {
dispatch_internal = __dispatch_internal_64 ;
internal_irq_mask = __internal_irq_mask_64 ;
internal_irq_unmask = __internal_irq_unmask_64 ;
}
2011-11-04 19:09:31 +01:00
}
# endif /* ! BCMCPU_RUNTIME_DETECT */
2011-11-04 19:09:34 +01:00
static inline u32 get_ext_irq_perf_reg ( int irq )
{
if ( irq < 4 )
return ext_irq_cfg_reg1 ;
return ext_irq_cfg_reg2 ;
}
2011-11-04 19:09:31 +01:00
static inline void handle_internal ( int intbit )
{
2011-11-04 19:09:32 +01:00
if ( is_ext_irq_cascaded & &
intbit > = ext_irq_start & & intbit < = ext_irq_end )
do_IRQ ( intbit - ext_irq_start + IRQ_EXTERNAL_BASE ) ;
else
do_IRQ ( intbit + IRQ_INTERNAL_BASE ) ;
2011-11-04 19:09:31 +01:00
}
2009-08-18 13:23:37 +01:00
/*
* dispatch internal devices IRQ ( uart , enet , watchdog , . . . ) . do not
* prioritize any interrupt relatively to another . the static counter
* will resume the loop where it ended the last time we left this
* function .
*/
2011-11-04 19:09:31 +01:00
static void __dispatch_internal ( void )
2009-08-18 13:23:37 +01:00
{
u32 pending ;
static int i ;
2011-11-04 19:09:31 +01:00
pending = bcm_readl ( irq_stat_addr ) & bcm_readl ( irq_mask_addr ) ;
2009-08-18 13:23:37 +01:00
if ( ! pending )
return ;
while ( 1 ) {
int to_call = i ;
i = ( i + 1 ) & 0x1f ;
if ( pending & ( 1 < < to_call ) ) {
2011-11-04 19:09:31 +01:00
handle_internal ( to_call ) ;
2009-08-18 13:23:37 +01:00
break ;
}
}
}
2011-11-04 19:09:33 +01:00
static void __dispatch_internal_64 ( void )
{
u64 pending ;
static int i ;
pending = bcm_readq ( irq_stat_addr ) & bcm_readq ( irq_mask_addr ) ;
if ( ! pending )
return ;
while ( 1 ) {
int to_call = i ;
i = ( i + 1 ) & 0x3f ;
if ( pending & ( 1ull < < to_call ) ) {
handle_internal ( to_call ) ;
break ;
}
}
}
2009-08-18 13:23:37 +01:00
asmlinkage void plat_irq_dispatch ( void )
{
u32 cause ;
do {
cause = read_c0_cause ( ) & read_c0_status ( ) & ST0_IM ;
if ( ! cause )
break ;
if ( cause & CAUSEF_IP7 )
do_IRQ ( 7 ) ;
2013-06-03 14:39:34 +00:00
if ( cause & CAUSEF_IP0 )
do_IRQ ( 0 ) ;
if ( cause & CAUSEF_IP1 )
do_IRQ ( 1 ) ;
2009-08-18 13:23:37 +01:00
if ( cause & CAUSEF_IP2 )
2011-11-04 19:09:31 +01:00
dispatch_internal ( ) ;
2011-11-04 19:09:32 +01:00
if ( ! is_ext_irq_cascaded ) {
if ( cause & CAUSEF_IP3 )
do_IRQ ( IRQ_EXT_0 ) ;
if ( cause & CAUSEF_IP4 )
do_IRQ ( IRQ_EXT_1 ) ;
if ( cause & CAUSEF_IP5 )
do_IRQ ( IRQ_EXT_2 ) ;
if ( cause & CAUSEF_IP6 )
do_IRQ ( IRQ_EXT_3 ) ;
}
2009-08-18 13:23:37 +01:00
} while ( 1 ) ;
}
/*
* internal IRQs operations : only mask / unmask on PERF irq mask
* register .
*/
2011-11-04 19:09:33 +01:00
static void __internal_irq_mask_32 ( unsigned int irq )
2009-08-18 13:23:37 +01:00
{
u32 mask ;
2011-11-04 19:09:31 +01:00
mask = bcm_readl ( irq_mask_addr ) ;
2009-08-18 13:23:37 +01:00
mask & = ~ ( 1 < < irq ) ;
2011-11-04 19:09:31 +01:00
bcm_writel ( mask , irq_mask_addr ) ;
2009-08-18 13:23:37 +01:00
}
2011-11-04 19:09:33 +01:00
static void __internal_irq_mask_64 ( unsigned int irq )
{
u64 mask ;
mask = bcm_readq ( irq_mask_addr ) ;
mask & = ~ ( 1ull < < irq ) ;
bcm_writeq ( mask , irq_mask_addr ) ;
}
static void __internal_irq_unmask_32 ( unsigned int irq )
2009-08-18 13:23:37 +01:00
{
u32 mask ;
2011-11-04 19:09:31 +01:00
mask = bcm_readl ( irq_mask_addr ) ;
2009-08-18 13:23:37 +01:00
mask | = ( 1 < < irq ) ;
2011-11-04 19:09:31 +01:00
bcm_writel ( mask , irq_mask_addr ) ;
2009-08-18 13:23:37 +01:00
}
2011-11-04 19:09:33 +01:00
static void __internal_irq_unmask_64 ( unsigned int irq )
{
u64 mask ;
mask = bcm_readq ( irq_mask_addr ) ;
mask | = ( 1ull < < irq ) ;
bcm_writeq ( mask , irq_mask_addr ) ;
}
2011-11-04 19:09:32 +01:00
static void bcm63xx_internal_irq_mask ( struct irq_data * d )
{
internal_irq_mask ( d - > irq - IRQ_INTERNAL_BASE ) ;
}
static void bcm63xx_internal_irq_unmask ( struct irq_data * d )
{
internal_irq_unmask ( d - > irq - IRQ_INTERNAL_BASE ) ;
}
2009-08-18 13:23:37 +01:00
/*
* external IRQs operations : mask / unmask and clear on PERF external
* irq control register .
*/
2011-03-23 21:08:47 +00:00
static void bcm63xx_external_irq_mask ( struct irq_data * d )
2009-08-18 13:23:37 +01:00
{
2011-11-04 19:09:32 +01:00
unsigned int irq = d - > irq - IRQ_EXTERNAL_BASE ;
2011-11-04 19:09:34 +01:00
u32 reg , regaddr ;
2009-08-18 13:23:37 +01:00
2011-11-04 19:09:34 +01:00
regaddr = get_ext_irq_perf_reg ( irq ) ;
reg = bcm_perf_readl ( regaddr ) ;
if ( BCMCPU_IS_6348 ( ) )
reg & = ~ EXTIRQ_CFG_MASK_6348 ( irq % 4 ) ;
else
reg & = ~ EXTIRQ_CFG_MASK ( irq % 4 ) ;
bcm_perf_writel ( reg , regaddr ) ;
2011-11-04 19:09:32 +01:00
if ( is_ext_irq_cascaded )
internal_irq_mask ( irq + ext_irq_start ) ;
2009-08-18 13:23:37 +01:00
}
2011-03-23 21:08:47 +00:00
static void bcm63xx_external_irq_unmask ( struct irq_data * d )
2009-08-18 13:23:37 +01:00
{
2011-11-04 19:09:32 +01:00
unsigned int irq = d - > irq - IRQ_EXTERNAL_BASE ;
2011-11-04 19:09:34 +01:00
u32 reg , regaddr ;
regaddr = get_ext_irq_perf_reg ( irq ) ;
reg = bcm_perf_readl ( regaddr ) ;
if ( BCMCPU_IS_6348 ( ) )
reg | = EXTIRQ_CFG_MASK_6348 ( irq % 4 ) ;
else
reg | = EXTIRQ_CFG_MASK ( irq % 4 ) ;
bcm_perf_writel ( reg , regaddr ) ;
2009-08-18 13:23:37 +01:00
2011-11-04 19:09:32 +01:00
if ( is_ext_irq_cascaded )
internal_irq_unmask ( irq + ext_irq_start ) ;
2009-08-18 13:23:37 +01:00
}
2011-03-23 21:08:47 +00:00
static void bcm63xx_external_irq_clear ( struct irq_data * d )
2009-08-18 13:23:37 +01:00
{
2011-11-04 19:09:32 +01:00
unsigned int irq = d - > irq - IRQ_EXTERNAL_BASE ;
2011-11-04 19:09:34 +01:00
u32 reg , regaddr ;
regaddr = get_ext_irq_perf_reg ( irq ) ;
reg = bcm_perf_readl ( regaddr ) ;
2009-08-18 13:23:37 +01:00
2011-11-04 19:09:34 +01:00
if ( BCMCPU_IS_6348 ( ) )
reg | = EXTIRQ_CFG_CLEAR_6348 ( irq % 4 ) ;
else
reg | = EXTIRQ_CFG_CLEAR ( irq % 4 ) ;
bcm_perf_writel ( reg , regaddr ) ;
2009-08-18 13:23:37 +01:00
}
2011-03-23 21:08:47 +00:00
static int bcm63xx_external_irq_set_type ( struct irq_data * d ,
2009-08-18 13:23:37 +01:00
unsigned int flow_type )
{
2011-11-04 19:09:32 +01:00
unsigned int irq = d - > irq - IRQ_EXTERNAL_BASE ;
2011-11-04 19:09:34 +01:00
u32 reg , regaddr ;
int levelsense , sense , bothedge ;
2009-08-18 13:23:37 +01:00
flow_type & = IRQ_TYPE_SENSE_MASK ;
if ( flow_type = = IRQ_TYPE_NONE )
flow_type = IRQ_TYPE_LEVEL_LOW ;
2011-11-04 19:09:34 +01:00
levelsense = sense = bothedge = 0 ;
2009-08-18 13:23:37 +01:00
switch ( flow_type ) {
case IRQ_TYPE_EDGE_BOTH :
2011-11-04 19:09:34 +01:00
bothedge = 1 ;
2009-08-18 13:23:37 +01:00
break ;
case IRQ_TYPE_EDGE_RISING :
2011-11-04 19:09:34 +01:00
sense = 1 ;
2009-08-18 13:23:37 +01:00
break ;
case IRQ_TYPE_EDGE_FALLING :
break ;
case IRQ_TYPE_LEVEL_HIGH :
2011-11-04 19:09:34 +01:00
levelsense = 1 ;
sense = 1 ;
2009-08-18 13:23:37 +01:00
break ;
case IRQ_TYPE_LEVEL_LOW :
2011-11-04 19:09:34 +01:00
levelsense = 1 ;
2009-08-18 13:23:37 +01:00
break ;
default :
printk ( KERN_ERR " bogus flow type combination given ! \n " ) ;
return - EINVAL ;
}
2011-11-04 19:09:34 +01:00
regaddr = get_ext_irq_perf_reg ( irq ) ;
reg = bcm_perf_readl ( regaddr ) ;
irq % = 4 ;
2012-07-13 07:46:05 +00:00
switch ( bcm63xx_get_cpu_id ( ) ) {
case BCM6348_CPU_ID :
2011-11-04 19:09:34 +01:00
if ( levelsense )
reg | = EXTIRQ_CFG_LEVELSENSE_6348 ( irq ) ;
else
reg & = ~ EXTIRQ_CFG_LEVELSENSE_6348 ( irq ) ;
if ( sense )
reg | = EXTIRQ_CFG_SENSE_6348 ( irq ) ;
else
reg & = ~ EXTIRQ_CFG_SENSE_6348 ( irq ) ;
if ( bothedge )
reg | = EXTIRQ_CFG_BOTHEDGE_6348 ( irq ) ;
else
reg & = ~ EXTIRQ_CFG_BOTHEDGE_6348 ( irq ) ;
2012-07-13 07:46:05 +00:00
break ;
2011-11-04 19:09:34 +01:00
2013-06-18 16:55:40 +00:00
case BCM3368_CPU_ID :
2012-07-13 07:46:05 +00:00
case BCM6328_CPU_ID :
case BCM6338_CPU_ID :
case BCM6345_CPU_ID :
case BCM6358_CPU_ID :
2013-03-21 14:03:17 +00:00
case BCM6362_CPU_ID :
2012-07-13 07:46:05 +00:00
case BCM6368_CPU_ID :
2011-11-04 19:09:34 +01:00
if ( levelsense )
reg | = EXTIRQ_CFG_LEVELSENSE ( irq ) ;
else
reg & = ~ EXTIRQ_CFG_LEVELSENSE ( irq ) ;
if ( sense )
reg | = EXTIRQ_CFG_SENSE ( irq ) ;
else
reg & = ~ EXTIRQ_CFG_SENSE ( irq ) ;
if ( bothedge )
reg | = EXTIRQ_CFG_BOTHEDGE ( irq ) ;
else
reg & = ~ EXTIRQ_CFG_BOTHEDGE ( irq ) ;
2012-07-13 07:46:05 +00:00
break ;
default :
BUG ( ) ;
2011-11-04 19:09:34 +01:00
}
bcm_perf_writel ( reg , regaddr ) ;
2009-08-18 13:23:37 +01:00
2011-03-23 21:08:47 +00:00
irqd_set_trigger_type ( d , flow_type ) ;
if ( flow_type & ( IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH ) )
__irq_set_handler_locked ( d - > irq , handle_level_irq ) ;
else
__irq_set_handler_locked ( d - > irq , handle_edge_irq ) ;
2009-08-18 13:23:37 +01:00
2011-03-23 21:08:47 +00:00
return IRQ_SET_MASK_OK_NOCOPY ;
2009-08-18 13:23:37 +01:00
}
static struct irq_chip bcm63xx_internal_irq_chip = {
. name = " bcm63xx_ipic " ,
2011-03-23 21:08:47 +00:00
. irq_mask = bcm63xx_internal_irq_mask ,
. irq_unmask = bcm63xx_internal_irq_unmask ,
2009-08-18 13:23:37 +01:00
} ;
static struct irq_chip bcm63xx_external_irq_chip = {
. name = " bcm63xx_epic " ,
2011-03-23 21:08:47 +00:00
. irq_ack = bcm63xx_external_irq_clear ,
2009-08-18 13:23:37 +01:00
2011-03-23 21:08:47 +00:00
. irq_mask = bcm63xx_external_irq_mask ,
. irq_unmask = bcm63xx_external_irq_unmask ,
2009-08-18 13:23:37 +01:00
2011-03-23 21:08:47 +00:00
. irq_set_type = bcm63xx_external_irq_set_type ,
2009-08-18 13:23:37 +01:00
} ;
static struct irqaction cpu_ip2_cascade_action = {
. handler = no_action ,
. name = " cascade_ip2 " ,
2011-07-23 12:41:24 +00:00
. flags = IRQF_NO_THREAD ,
2009-08-18 13:23:37 +01:00
} ;
2011-11-04 19:09:32 +01:00
static struct irqaction cpu_ext_cascade_action = {
. handler = no_action ,
. name = " cascade_extirq " ,
. flags = IRQF_NO_THREAD ,
} ;
2009-08-18 13:23:37 +01:00
void __init arch_init_irq ( void )
{
int i ;
2011-11-04 19:09:31 +01:00
bcm63xx_init_irq ( ) ;
2009-08-18 13:23:37 +01:00
mips_cpu_irq_init ( ) ;
for ( i = IRQ_INTERNAL_BASE ; i < NR_IRQS ; + + i )
2011-03-27 15:19:28 +02:00
irq_set_chip_and_handler ( i , & bcm63xx_internal_irq_chip ,
2009-08-18 13:23:37 +01:00
handle_level_irq ) ;
2011-11-04 19:09:34 +01:00
for ( i = IRQ_EXTERNAL_BASE ; i < IRQ_EXTERNAL_BASE + ext_irq_count ; + + i )
2011-03-27 15:19:28 +02:00
irq_set_chip_and_handler ( i , & bcm63xx_external_irq_chip ,
2009-08-18 13:23:37 +01:00
handle_edge_irq ) ;
2011-11-04 19:09:32 +01:00
if ( ! is_ext_irq_cascaded ) {
2011-11-04 19:09:34 +01:00
for ( i = 3 ; i < 3 + ext_irq_count ; + + i )
2011-11-04 19:09:32 +01:00
setup_irq ( MIPS_CPU_IRQ_BASE + i , & cpu_ext_cascade_action ) ;
}
setup_irq ( MIPS_CPU_IRQ_BASE + 2 , & cpu_ip2_cascade_action ) ;
2009-08-18 13:23:37 +01:00
}