2009-08-30 17:15:11 -07:00
/*
* Carsten Langgaard , carstenl @ mips . com
* Copyright ( C ) 2000 , 2001 , 2004 MIPS Technologies , Inc .
* Copyright ( C ) 2001 Ralf Baechle
2013-01-22 12:59:30 +01:00
* Portions copyright ( C ) 2009 Cisco Systems , Inc .
2009-08-30 17:15:11 -07:00
*
* This program is free software ; you can distribute it and / or modify it
* under the terms of the GNU General Public License ( Version 2 ) as
* published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
* for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 59 Temple Place - Suite 330 , Boston MA 02111 - 1307 , USA .
*
* Routines for generic manipulation of the interrupts found on the PowerTV
* platform .
*
* The interrupt controller is located in the South Bridge a PIIX4 device
* with two internal 82 C95 interrupt controllers .
*/
# include <linux/init.h>
# include <linux/irq.h>
# include <linux/sched.h>
# include <linux/interrupt.h>
# include <linux/kernel_stat.h>
# include <linux/kernel.h>
# include <linux/random.h>
# include <asm/irq_cpu.h>
# include <linux/io.h>
# include <asm/irq_regs.h>
2012-03-28 18:30:02 +01:00
# include <asm/setup.h>
2009-08-30 17:15:11 -07:00
# include <asm/mips-boards/generic.h>
# include <asm/mach-powertv/asic_regs.h>
2010-02-27 12:53:34 +01:00
static DEFINE_RAW_SPINLOCK ( asic_irq_lock ) ;
2009-08-30 17:15:11 -07:00
static inline int get_int ( void )
{
unsigned long flags ;
int irq ;
2010-02-27 12:53:34 +01:00
raw_spin_lock_irqsave ( & asic_irq_lock , flags ) ;
2009-08-30 17:15:11 -07:00
irq = ( asic_read ( int_int_scan ) > > 4 ) - 1 ;
if ( irq = = 0 | | irq > = NR_IRQS )
irq = - 1 ;
2010-02-27 12:53:34 +01:00
raw_spin_unlock_irqrestore ( & asic_irq_lock , flags ) ;
2009-08-30 17:15:11 -07:00
return irq ;
}
static void asic_irqdispatch ( void )
{
int irq ;
irq = get_int ( ) ;
if ( irq < 0 )
2013-01-22 12:59:30 +01:00
return ; /* interrupt has already been cleared */
2009-08-30 17:15:11 -07:00
do_IRQ ( irq ) ;
}
static inline int clz ( unsigned long x )
{
__asm__ (
" .set push \n "
" .set mips32 \n "
" clz %0, %1 \n "
" .set pop \n "
: " =r " ( x )
: " r " ( x ) ) ;
return x ;
}
/*
* Version of ffs that only looks at bits 12. .15 .
*/
static inline unsigned int irq_ffs ( unsigned int pending )
{
return fls ( pending ) - 1 + CAUSEB_IP ;
}
/*
* TODO : check how it works under EIC mode .
*/
asmlinkage void plat_irq_dispatch ( void )
{
unsigned int pending = read_c0_cause ( ) & read_c0_status ( ) & ST0_IM ;
int irq ;
irq = irq_ffs ( pending ) ;
if ( irq = = CAUSEF_IP3 )
asic_irqdispatch ( ) ;
else if ( irq > = 0 )
do_IRQ ( irq ) ;
else
spurious_interrupt ( ) ;
}
void __init arch_init_irq ( void )
{
int i ;
asic_irq_init ( ) ;
/*
* Initialize interrupt exception vectors .
*/
if ( cpu_has_veic | | cpu_has_vint ) {
int nvec = cpu_has_veic ? 64 : 8 ;
for ( i = 0 ; i < nvec ; i + + )
set_vi_handler ( i , asic_irqdispatch ) ;
}
}