2009-04-30 10:22:24 +04:00
/*
2009-05-19 08:38:08 +04:00
* intc . c - - support for the old ColdFire interrupt controller
2009-04-30 10:22:24 +04: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 08:08:47 +04:00
/*
2009-05-22 07:33:35 +04: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 08:08:47 +04:00
*/
# define EIRQ1 25
# define EIRQ7 31
2009-05-19 08:38:08 +04: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
2011-03-31 05:57:33 +04:00
* sized IMR register . Provide some size independent methods to access the
2009-05-19 08:38:08 +04:00
* IMR register .
*/
# ifdef MCFSIM_IMR_IS_16BITS
void mcf_setimr ( int index )
{
2009-05-22 07:33:35 +04:00
u16 imr ;
2012-07-15 15:42:47 +04:00
imr = __raw_readw ( MCFSIM_IMR ) ;
__raw_writew ( imr | ( 0x1 < < index ) , MCFSIM_IMR ) ;
2009-05-19 08:38:08 +04:00
}
void mcf_clrimr ( int index )
{
2009-05-22 07:33:35 +04:00
u16 imr ;
2012-07-15 15:42:47 +04:00
imr = __raw_readw ( MCFSIM_IMR ) ;
__raw_writew ( imr & ~ ( 0x1 < < index ) , MCFSIM_IMR ) ;
2009-05-19 08:38:08 +04:00
}
void mcf_maskimr ( unsigned int mask )
{
u16 imr ;
2012-07-15 15:42:47 +04:00
imr = __raw_readw ( MCFSIM_IMR ) ;
2009-05-19 08:38:08 +04:00
imr | = mask ;
2012-07-15 15:42:47 +04:00
__raw_writew ( imr , MCFSIM_IMR ) ;
2009-05-19 08:38:08 +04:00
}
# else
void mcf_setimr ( int index )
{
2009-05-22 07:33:35 +04:00
u32 imr ;
2012-07-15 15:42:47 +04:00
imr = __raw_readl ( MCFSIM_IMR ) ;
__raw_writel ( imr | ( 0x1 < < index ) , MCFSIM_IMR ) ;
2009-05-19 08:38:08 +04:00
}
void mcf_clrimr ( int index )
{
2009-05-22 07:33:35 +04:00
u32 imr ;
2012-07-15 15:42:47 +04:00
imr = __raw_readl ( MCFSIM_IMR ) ;
__raw_writel ( imr & ~ ( 0x1 < < index ) , MCFSIM_IMR ) ;
2009-05-19 08:38:08 +04:00
}
void mcf_maskimr ( unsigned int mask )
{
u32 imr ;
2012-07-15 15:42:47 +04:00
imr = __raw_readl ( MCFSIM_IMR ) ;
2009-05-19 08:38:08 +04:00
imr | = mask ;
2012-07-15 15:42:47 +04:00
__raw_writel ( imr , MCFSIM_IMR ) ;
2009-05-19 08:38:08 +04:00
}
# endif
2009-05-19 08:08:47 +04: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 07:33:35 +04:00
# ifdef MCFSIM_AVR
2009-05-19 08:08:47 +04:00
if ( ( irq > = EIRQ1 ) & & ( irq < = EIRQ7 ) ) {
u8 avec ;
2012-07-15 15:42:47 +04:00
avec = __raw_readb ( MCFSIM_AVR ) ;
2009-05-19 08:08:47 +04:00
avec | = ( 0x1 < < ( irq - EIRQ1 + 1 ) ) ;
2012-07-15 15:42:47 +04:00
__raw_writeb ( avec , MCFSIM_AVR ) ;
2009-05-19 08:08:47 +04:00
}
2009-05-22 07:33:35 +04:00
# endif
2009-05-19 08:08:47 +04:00
}
2011-02-07 02:39:14 +03:00
static void intc_irq_mask ( struct irq_data * d )
2009-04-30 10:22:24 +04:00
{
2011-02-07 02:39:14 +03:00
if ( mcf_irq2imr [ d - > irq ] )
mcf_setimr ( mcf_irq2imr [ d - > irq ] ) ;
2009-04-30 10:22:24 +04:00
}
2011-02-07 02:39:14 +03:00
static void intc_irq_unmask ( struct irq_data * d )
2009-04-30 10:22:24 +04:00
{
2011-02-07 02:39:14 +03:00
if ( mcf_irq2imr [ d - > irq ] )
mcf_clrimr ( mcf_irq2imr [ d - > irq ] ) ;
2009-04-30 10:22:24 +04:00
}
2011-02-07 02:39:14 +03:00
static int intc_irq_set_type ( struct irq_data * d , unsigned int type )
2009-04-30 10:22:24 +04:00
{
return 0 ;
}
static struct irq_chip intc_irq_chip = {
. name = " CF-INTC " ,
2011-02-07 02:39:14 +03:00
. irq_mask = intc_irq_mask ,
. irq_unmask = intc_irq_unmask ,
. irq_set_type = intc_irq_set_type ,
2009-04-30 10:22:24 +04:00
} ;
void __init init_IRQ ( void )
{
int irq ;
2009-05-19 08:38:08 +04:00
mcf_maskimr ( 0xffffffff ) ;
2009-04-30 10:22:24 +04:00
for ( irq = 0 ; ( irq < NR_IRQS ) ; irq + + ) {
2011-03-28 15:31:17 +04:00
irq_set_chip ( irq , & intc_irq_chip ) ;
irq_set_irq_type ( irq , IRQ_TYPE_LEVEL_HIGH ) ;
irq_set_handler ( irq , handle_level_irq ) ;
2009-04-30 10:22:24 +04:00
}
}