2014-06-30 19:01:30 +04:00
/*
* Copyright ( C ) 2002 ARM Limited , All Rights Reserved .
*
* This program is free software ; you can redistribute 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 that 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 , see < http : //www.gnu.org/licenses/>.
*/
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/irq.h>
# include <linux/irqchip/arm-gic.h>
# include "irq-gic-common.h"
2015-09-21 23:58:37 +03:00
void gic_enable_quirks ( u32 iidr , const struct gic_quirk * quirks ,
void * data )
{
for ( ; quirks - > desc ; quirks + + ) {
if ( quirks - > iidr ! = ( quirks - > mask & iidr ) )
continue ;
quirks - > init ( data ) ;
pr_info ( " GIC: enabling workaround for %s \n " , quirks - > desc ) ;
}
}
2015-01-20 19:52:59 +03:00
int gic_configure_irq ( unsigned int irq , unsigned int type ,
2014-06-30 19:01:30 +04:00
void __iomem * base , void ( * sync_access ) ( void ) )
{
u32 confmask = 0x2 < < ( ( irq % 16 ) * 2 ) ;
u32 confoff = ( irq / 16 ) * 4 ;
2015-01-20 19:52:59 +03:00
u32 val , oldval ;
int ret = 0 ;
2014-06-30 19:01:30 +04:00
/*
* Read current configuration register , and insert the config
* for " irq " , depending on " type " .
*/
2015-01-20 19:52:59 +03:00
val = oldval = readl_relaxed ( base + GIC_DIST_CONFIG + confoff ) ;
if ( type & IRQ_TYPE_LEVEL_MASK )
2014-06-30 19:01:30 +04:00
val & = ~ confmask ;
2015-01-20 19:52:59 +03:00
else if ( type & IRQ_TYPE_EDGE_BOTH )
2014-06-30 19:01:30 +04:00
val | = confmask ;
/*
* Write back the new configuration , and possibly re - enable
2015-01-20 19:52:59 +03:00
* the interrupt . If we tried to write a new configuration and failed ,
* return an error .
2014-06-30 19:01:30 +04:00
*/
writel_relaxed ( val , base + GIC_DIST_CONFIG + confoff ) ;
2015-01-20 19:52:59 +03:00
if ( readl_relaxed ( base + GIC_DIST_CONFIG + confoff ) ! = val & & val ! = oldval )
ret = - EINVAL ;
2014-06-30 19:01:30 +04:00
if ( sync_access )
sync_access ( ) ;
2015-01-20 19:52:59 +03:00
return ret ;
2014-06-30 19:01:30 +04:00
}
void __init gic_dist_config ( void __iomem * base , int gic_irqs ,
void ( * sync_access ) ( void ) )
{
unsigned int i ;
/*
* Set all global interrupts to be level triggered , active low .
*/
for ( i = 32 ; i < gic_irqs ; i + = 16 )
2014-07-31 01:56:58 +04:00
writel_relaxed ( GICD_INT_ACTLOW_LVLTRIG ,
base + GIC_DIST_CONFIG + i / 4 ) ;
2014-06-30 19:01:30 +04:00
/*
* Set priority on all global interrupts .
*/
for ( i = 32 ; i < gic_irqs ; i + = 4 )
2014-07-31 01:56:58 +04:00
writel_relaxed ( GICD_INT_DEF_PRI_X4 , base + GIC_DIST_PRI + i ) ;
2014-06-30 19:01:30 +04:00
/*
* Disable all interrupts . Leave the PPI and SGIs alone
* as they are enabled by redistributor registers .
*/
for ( i = 32 ; i < gic_irqs ; i + = 32 )
2014-07-31 01:56:58 +04:00
writel_relaxed ( GICD_INT_EN_CLR_X32 ,
base + GIC_DIST_ENABLE_CLEAR + i / 8 ) ;
2014-06-30 19:01:30 +04:00
if ( sync_access )
sync_access ( ) ;
}
void gic_cpu_config ( void __iomem * base , void ( * sync_access ) ( void ) )
{
int i ;
/*
* Deal with the banked PPI and SGI interrupts - disable all
* PPI interrupts , ensure all SGI interrupts are enabled .
*/
2014-07-31 01:56:58 +04:00
writel_relaxed ( GICD_INT_EN_CLR_PPI , base + GIC_DIST_ENABLE_CLEAR ) ;
writel_relaxed ( GICD_INT_EN_SET_SGI , base + GIC_DIST_ENABLE_SET ) ;
2014-06-30 19:01:30 +04:00
/*
* Set priority on PPI and SGI interrupts
*/
for ( i = 0 ; i < 32 ; i + = 4 )
2014-07-31 01:56:58 +04:00
writel_relaxed ( GICD_INT_DEF_PRI_X4 ,
base + GIC_DIST_PRI + i * 4 / 4 ) ;
2014-06-30 19:01:30 +04:00
if ( sync_access )
sync_access ( ) ;
}