2019-06-03 08:44:50 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2014-06-30 19:01:30 +04:00
/*
* Copyright ( C ) 2002 ARM Limited , All Rights Reserved .
*/
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/irq.h>
# include <linux/irqchip/arm-gic.h>
# include "irq-gic-common.h"
2018-03-28 16:42:00 +03:00
static DEFINE_RAW_SPINLOCK ( irq_controller_lock ) ;
2018-12-10 16:56:31 +03:00
void gic_enable_of_quirks ( const struct device_node * np ,
const struct gic_quirk * quirks , void * data )
{
for ( ; quirks - > desc ; quirks + + ) {
if ( ! of_device_is_compatible ( np , quirks - > compatible ) )
continue ;
if ( quirks - > init ( data ) )
pr_info ( " GIC: enabling workaround for %s \n " ,
quirks - > desc ) ;
}
}
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 + + ) {
2019-07-31 19:28:49 +03:00
if ( quirks - > compatible )
continue ;
2015-09-21 23:58:37 +03:00
if ( quirks - > iidr ! = ( quirks - > mask & iidr ) )
continue ;
2017-10-17 19:55:55 +03:00
if ( quirks - > init ( data ) )
pr_info ( " GIC: enabling workaround for %s \n " ,
quirks - > desc ) ;
2015-09-21 23:58:37 +03:00
}
}
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 ;
2018-03-28 16:42:00 +03:00
unsigned long flags ;
2014-06-30 19:01:30 +04:00
/*
* Read current configuration register , and insert the config
* for " irq " , depending on " type " .
*/
2018-03-28 16:42:00 +03:00
raw_spin_lock_irqsave ( & irq_controller_lock , flags ) ;
2019-07-16 16:35:17 +03:00
val = oldval = readl_relaxed ( base + confoff ) ;
2015-01-20 19:52:59 +03:00
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 ;
2016-05-10 18:14:38 +03:00
/* If the current configuration is the same, then we are done */
2018-03-28 16:42:00 +03:00
if ( val = = oldval ) {
raw_spin_unlock_irqrestore ( & irq_controller_lock , flags ) ;
2016-05-10 18:14:38 +03:00
return 0 ;
2018-03-28 16:42:00 +03:00
}
2016-05-10 18:14:38 +03:00
2014-06-30 19:01:30 +04:00
/*
* Write back the new configuration , and possibly re - enable
2016-05-10 18:14:39 +03:00
* the interrupt . If we fail to write a new configuration for
* an SPI then WARN and return an error . If we fail to write the
* configuration for a PPI this is most likely because the GIC
* does not allow us to set the configuration or we are in a
* non - secure mode , and hence it may not be catastrophic .
2014-06-30 19:01:30 +04:00
*/
2019-07-16 16:35:17 +03:00
writel_relaxed ( val , base + confoff ) ;
if ( readl_relaxed ( base + confoff ) ! = val )
ret = - EINVAL ;
2018-03-28 16:42:00 +03:00
raw_spin_unlock_irqrestore ( & irq_controller_lock , flags ) ;
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
}
2016-06-07 18:12:32 +03:00
void gic_dist_config ( void __iomem * base , int gic_irqs ,
void ( * sync_access ) ( void ) )
2014-06-30 19:01:30 +04:00
{
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
/*
2015-11-16 22:13:26 +03:00
* Deactivate and disable all SPIs . Leave the PPI and SGIs
* alone as they are in the redistributor registers on GICv3 .
2014-06-30 19:01:30 +04:00
*/
2015-11-16 22:13:26 +03:00
for ( i = 32 ; i < gic_irqs ; i + = 32 ) {
2014-07-31 01:56:58 +04:00
writel_relaxed ( GICD_INT_EN_CLR_X32 ,
2015-11-16 22:13:26 +03:00
base + GIC_DIST_ACTIVE_CLEAR + i / 8 ) ;
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 ( ) ;
}
2019-07-18 13:15:14 +03:00
void gic_cpu_config ( void __iomem * base , int nr , void ( * sync_access ) ( void ) )
2014-06-30 19:01:30 +04:00
{
int i ;
/*
* Deal with the banked PPI and SGI interrupts - disable all
2019-07-18 13:15:14 +03:00
* private interrupts . Make sure everything is deactivated .
2014-06-30 19:01:30 +04:00
*/
2019-07-18 13:15:14 +03:00
for ( i = 0 ; i < nr ; i + = 32 ) {
writel_relaxed ( GICD_INT_EN_CLR_X32 ,
base + GIC_DIST_ACTIVE_CLEAR + i / 8 ) ;
writel_relaxed ( GICD_INT_EN_CLR_X32 ,
base + GIC_DIST_ENABLE_CLEAR + i / 8 ) ;
}
2014-06-30 19:01:30 +04:00
/*
* Set priority on PPI and SGI interrupts
*/
2019-07-18 13:15:14 +03:00
for ( i = 0 ; i < nr ; 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 ( ) ;
}