2009-04-30 16:22:24 +10:00
/*
2009-05-19 14:38:08 +10:00
* intc . c - - support for the old ColdFire interrupt controller
2009-04-30 16:22:24 +10:00
*
* ( C ) Copyright 2009 , Greg Ungerer < gerg @ snapgear . com >
*
* 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 .
*/
# include <linux/types.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/interrupt.h>
# include <linux/irq.h>
# include <linux/io.h>
# include <asm/traps.h>
# include <asm/coldfire.h>
# include <asm/mcfsim.h>
2009-05-19 14:08:47 +10:00
/*
2009-05-22 13:33:35 +10:00
* The mapping of irq number to a mask register bit is not one - to - one .
* The irq numbers are either based on " level " of interrupt or fixed
* for an autovector - able interrupt . So we keep a local data structure
* that maps from irq to mask register . Not all interrupts will have
* an IMR bit .
*/
unsigned char mcf_irq2imr [ NR_IRQS ] ;
/*
* Define the miniumun and maximum external interrupt numbers .
* This is also used as the " level " interrupt numbers .
2009-05-19 14:08:47 +10:00
*/
# define EIRQ1 25
# define EIRQ7 31
2009-05-19 14:38:08 +10:00
/*
* In the early version 2 core ColdFire parts the IMR register was 16 bits
* in size . Version 3 ( and later version 2 ) core parts have a 32 bit
* sized IMR register . Provide some size independant methods to access the
* IMR register .
*/
# ifdef MCFSIM_IMR_IS_16BITS
void mcf_setimr ( int index )
{
2009-05-22 13:33:35 +10:00
u16 imr ;
imr = __raw_readw ( MCF_MBAR + MCFSIM_IMR ) ;
2009-05-19 14:38:08 +10:00
__raw_writew ( imr | ( 0x1 < < index ) , MCF_MBAR + MCFSIM_IMR ) ;
}
void mcf_clrimr ( int index )
{
2009-05-22 13:33:35 +10:00
u16 imr ;
imr = __raw_readw ( MCF_MBAR + MCFSIM_IMR ) ;
2009-05-19 14:38:08 +10:00
__raw_writew ( imr & ~ ( 0x1 < < index ) , MCF_MBAR + MCFSIM_IMR ) ;
}
void mcf_maskimr ( unsigned int mask )
{
u16 imr ;
2009-05-22 13:33:35 +10:00
imr = __raw_readw ( MCF_MBAR + MCFSIM_IMR ) ;
2009-05-19 14:38:08 +10:00
imr | = mask ;
__raw_writew ( imr , MCF_MBAR + MCFSIM_IMR ) ;
}
# else
void mcf_setimr ( int index )
{
2009-05-22 13:33:35 +10:00
u32 imr ;
imr = __raw_readl ( MCF_MBAR + MCFSIM_IMR ) ;
2009-05-19 14:38:08 +10:00
__raw_writel ( imr | ( 0x1 < < index ) , MCF_MBAR + MCFSIM_IMR ) ;
}
void mcf_clrimr ( int index )
{
2009-05-22 13:33:35 +10:00
u32 imr ;
imr = __raw_readl ( MCF_MBAR + MCFSIM_IMR ) ;
2009-05-19 14:38:08 +10:00
__raw_writel ( imr & ~ ( 0x1 < < index ) , MCF_MBAR + MCFSIM_IMR ) ;
}
void mcf_maskimr ( unsigned int mask )
{
u32 imr ;
2009-05-22 13:33:35 +10:00
imr = __raw_readl ( MCF_MBAR + MCFSIM_IMR ) ;
2009-05-19 14:38:08 +10:00
imr | = mask ;
__raw_writel ( imr , MCF_MBAR + MCFSIM_IMR ) ;
}
# endif
2009-05-19 14:08:47 +10:00
/*
* Interrupts can be " vectored " on the ColdFire cores that support this old
* interrupt controller . That is , the device raising the interrupt can also
* supply the vector number to interrupt through . The AVR register of the
* interrupt controller enables or disables this for each external interrupt ,
* so provide generic support for this . Setting this up is out - of - band for
* the interrupt system API ' s , and needs to be done by the driver that
* supports this device . Very few devices actually use this .
*/
void mcf_autovector ( int irq )
{
2009-05-22 13:33:35 +10:00
# ifdef MCFSIM_AVR
2009-05-19 14:08:47 +10:00
if ( ( irq > = EIRQ1 ) & & ( irq < = EIRQ7 ) ) {
u8 avec ;
avec = __raw_readb ( MCF_MBAR + MCFSIM_AVR ) ;
avec | = ( 0x1 < < ( irq - EIRQ1 + 1 ) ) ;
__raw_writeb ( avec , MCF_MBAR + MCFSIM_AVR ) ;
}
2009-05-22 13:33:35 +10:00
# endif
2009-05-19 14:08:47 +10:00
}
2009-04-30 16:22:24 +10:00
static void intc_irq_mask ( unsigned int irq )
{
2009-05-22 13:33:35 +10:00
if ( mcf_irq2imr [ irq ] )
mcf_setimr ( mcf_irq2imr [ irq ] ) ;
2009-04-30 16:22:24 +10:00
}
static void intc_irq_unmask ( unsigned int irq )
{
2009-05-22 13:33:35 +10:00
if ( mcf_irq2imr [ irq ] )
mcf_clrimr ( mcf_irq2imr [ irq ] ) ;
2009-04-30 16:22:24 +10:00
}
static int intc_irq_set_type ( unsigned int irq , unsigned int type )
{
return 0 ;
}
static struct irq_chip intc_irq_chip = {
. name = " CF-INTC " ,
. mask = intc_irq_mask ,
. unmask = intc_irq_unmask ,
. set_type = intc_irq_set_type ,
} ;
void __init init_IRQ ( void )
{
int irq ;
init_vectors ( ) ;
2009-05-19 14:38:08 +10:00
mcf_maskimr ( 0xffffffff ) ;
2009-04-30 16:22:24 +10:00
for ( irq = 0 ; ( irq < NR_IRQS ) ; irq + + ) {
2010-09-09 17:12:53 +10:00
set_irq_chip ( irq , & intc_irq_chip ) ;
set_irq_type ( irq , IRQ_TYPE_LEVEL_HIGH ) ;
set_irq_handler ( irq , handle_level_irq ) ;
2009-04-30 16:22:24 +10:00
}
}