2011-01-25 11:20:10 +03:00
/*
* Copyright 2010 PMC - Sierra , Inc , derived from irq_cpu . c
*
* This file define the irq handler for MSP PER subsystem interrupts .
*
2013-01-22 15:59:30 +04:00
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
2011-01-25 11:20:10 +03:00
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*/
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/kernel.h>
# include <linux/spinlock.h>
# include <linux/bitops.h>
# include <asm/mipsregs.h>
# include <msp_cic_int.h>
# include <msp_regs.h>
/*
* Convenience Macro . Should be somewhere generic .
*/
# define get_current_vpe() \
( ( read_c0_tcbind ( ) > > TCBIND_CURVPE_SHIFT ) & TCBIND_CURVPE )
# ifdef CONFIG_SMP
/*
* The PER registers must be protected from concurrent access .
*/
static DEFINE_SPINLOCK ( per_lock ) ;
# endif
/* ensure writes to per are completed */
static inline void per_wmb ( void )
{
const volatile void __iomem * per_mem = PER_INT_MSK_REG ;
volatile u32 dummy_read ;
wmb ( ) ;
dummy_read = __raw_readl ( per_mem ) ;
dummy_read + + ;
}
2011-03-24 00:09:06 +03:00
static inline void unmask_per_irq ( struct irq_data * d )
2011-01-25 11:20:10 +03:00
{
# ifdef CONFIG_SMP
unsigned long flags ;
spin_lock_irqsave ( & per_lock , flags ) ;
2011-03-24 00:09:06 +03:00
* PER_INT_MSK_REG | = ( 1 < < ( d - > irq - MSP_PER_INTBASE ) ) ;
2011-01-25 11:20:10 +03:00
spin_unlock_irqrestore ( & per_lock , flags ) ;
# else
2011-03-24 00:09:06 +03:00
* PER_INT_MSK_REG | = ( 1 < < ( d - > irq - MSP_PER_INTBASE ) ) ;
2011-01-25 11:20:10 +03:00
# endif
per_wmb ( ) ;
}
2011-03-24 00:09:06 +03:00
static inline void mask_per_irq ( struct irq_data * d )
2011-01-25 11:20:10 +03:00
{
# ifdef CONFIG_SMP
unsigned long flags ;
spin_lock_irqsave ( & per_lock , flags ) ;
2011-03-24 00:09:06 +03:00
* PER_INT_MSK_REG & = ~ ( 1 < < ( d - > irq - MSP_PER_INTBASE ) ) ;
2011-01-25 11:20:10 +03:00
spin_unlock_irqrestore ( & per_lock , flags ) ;
# else
2011-03-24 00:09:06 +03:00
* PER_INT_MSK_REG & = ~ ( 1 < < ( d - > irq - MSP_PER_INTBASE ) ) ;
2011-01-25 11:20:10 +03:00
# endif
per_wmb ( ) ;
}
2011-03-24 00:09:06 +03:00
static inline void msp_per_irq_ack ( struct irq_data * d )
2011-01-25 11:20:10 +03:00
{
2011-03-24 00:09:06 +03:00
mask_per_irq ( d ) ;
2011-01-25 11:20:10 +03:00
/*
* In the PER interrupt controller , only bits 11 and 10
* are write - to - clear , ( SPI TX complete , SPI RX complete ) .
* It does nothing for any others .
*/
2011-03-24 00:09:06 +03:00
* PER_INT_STS_REG = ( 1 < < ( d - > irq - MSP_PER_INTBASE ) ) ;
2011-01-25 11:20:10 +03:00
}
# ifdef CONFIG_SMP
2011-03-24 00:09:06 +03:00
static int msp_per_irq_set_affinity ( struct irq_data * d ,
const struct cpumask * affinity , bool force )
2011-01-25 11:20:10 +03:00
{
2011-03-24 00:09:06 +03:00
/* WTF is this doing ????? */
unmask_per_irq ( d ) ;
2011-01-25 11:20:10 +03:00
return 0 ;
}
# endif
static struct irq_chip msp_per_irq_controller = {
. name = " MSP_PER " ,
2011-03-29 10:53:56 +04:00
. irq_enable = unmask_per_irq ,
2011-03-24 00:09:06 +03:00
. irq_disable = mask_per_irq ,
. irq_ack = msp_per_irq_ack ,
2011-01-25 11:20:10 +03:00
# ifdef CONFIG_SMP
2011-03-24 00:09:06 +03:00
. irq_set_affinity = msp_per_irq_set_affinity ,
2011-01-25 11:20:10 +03:00
# endif
} ;
void __init msp_per_irq_init ( void )
{
int i ;
/* Mask/clear interrupts. */
* PER_INT_MSK_REG = 0x00000000 ;
* PER_INT_STS_REG = 0xFFFFFFFF ;
/* initialize all the IRQ descriptors */
for ( i = MSP_PER_INTBASE ; i < MSP_PER_INTBASE + 32 ; i + + ) {
2011-03-24 00:09:06 +03:00
irq_set_chip ( i , & msp_per_irq_controller ) ;
2011-01-25 11:20:10 +03:00
# ifdef CONFIG_MIPS_MT_SMTC
irq_hwmask [ i ] = C_IRQ4 ;
# endif
}
}
void msp_per_irq_dispatch ( void )
{
u32 per_mask = * PER_INT_MSK_REG ;
u32 per_status = * PER_INT_STS_REG ;
u32 pending ;
pending = per_status & per_mask ;
if ( pending ) {
do_IRQ ( ffs ( pending ) + MSP_PER_INTBASE - 1 ) ;
} else {
spurious_interrupt ( ) ;
}
}