2017-10-25 10:42:51 +03:00
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2005-2017 Andes Technology Corporation
# include <linux/irq.h>
# include <linux/of.h>
# include <linux/of_irq.h>
# include <linux/of_address.h>
2021-10-20 13:36:08 +03:00
# include <linux/hardirq.h>
2017-10-25 10:42:51 +03:00
# include <linux/interrupt.h>
# include <linux/irqdomain.h>
# include <linux/irqchip.h>
# include <nds32_intrinsic.h>
2021-10-20 13:36:08 +03:00
# include <asm/irq_regs.h>
2018-10-24 13:14:32 +03:00
unsigned long wake_mask ;
2017-10-25 10:42:51 +03:00
static void ativic32_ack_irq ( struct irq_data * data )
{
__nds32__mtsr_dsb ( BIT ( data - > hwirq ) , NDS32_SR_INT_PEND2 ) ;
}
static void ativic32_mask_irq ( struct irq_data * data )
{
unsigned long int_mask2 = __nds32__mfsr ( NDS32_SR_INT_MASK2 ) ;
__nds32__mtsr_dsb ( int_mask2 & ( ~ ( BIT ( data - > hwirq ) ) ) , NDS32_SR_INT_MASK2 ) ;
}
static void ativic32_unmask_irq ( struct irq_data * data )
{
unsigned long int_mask2 = __nds32__mfsr ( NDS32_SR_INT_MASK2 ) ;
__nds32__mtsr_dsb ( int_mask2 | ( BIT ( data - > hwirq ) ) , NDS32_SR_INT_MASK2 ) ;
}
2018-10-24 13:14:32 +03:00
static int nointc_set_wake ( struct irq_data * data , unsigned int on )
{
unsigned long int_mask = __nds32__mfsr ( NDS32_SR_INT_MASK ) ;
static unsigned long irq_orig_bit ;
u32 bit = 1 < < data - > hwirq ;
if ( on ) {
if ( int_mask & bit )
__assign_bit ( data - > hwirq , & irq_orig_bit , true ) ;
else
__assign_bit ( data - > hwirq , & irq_orig_bit , false ) ;
__assign_bit ( data - > hwirq , & int_mask , true ) ;
__assign_bit ( data - > hwirq , & wake_mask , true ) ;
} else {
if ( ! ( irq_orig_bit & bit ) )
__assign_bit ( data - > hwirq , & int_mask , false ) ;
__assign_bit ( data - > hwirq , & wake_mask , false ) ;
__assign_bit ( data - > hwirq , & irq_orig_bit , false ) ;
}
__nds32__mtsr_dsb ( int_mask , NDS32_SR_INT_MASK ) ;
return 0 ;
}
2017-10-25 10:42:51 +03:00
static struct irq_chip ativic32_chip = {
. name = " ativic32 " ,
. irq_ack = ativic32_ack_irq ,
. irq_mask = ativic32_mask_irq ,
. irq_unmask = ativic32_unmask_irq ,
2018-10-24 13:14:32 +03:00
. irq_set_wake = nointc_set_wake ,
2017-10-25 10:42:51 +03:00
} ;
static unsigned int __initdata nivic_map [ 6 ] = { 6 , 2 , 10 , 16 , 24 , 32 } ;
static struct irq_domain * root_domain ;
static int ativic32_irq_domain_map ( struct irq_domain * id , unsigned int virq ,
irq_hw_number_t hw )
{
unsigned long int_trigger_type ;
u32 type ;
struct irq_data * irq_data ;
int_trigger_type = __nds32__mfsr ( NDS32_SR_INT_TRIGGER ) ;
irq_data = irq_get_irq_data ( virq ) ;
if ( ! irq_data )
return - EINVAL ;
if ( int_trigger_type & ( BIT ( hw ) ) ) {
irq_set_chip_and_handler ( virq , & ativic32_chip , handle_edge_irq ) ;
type = IRQ_TYPE_EDGE_RISING ;
} else {
irq_set_chip_and_handler ( virq , & ativic32_chip , handle_level_irq ) ;
type = IRQ_TYPE_LEVEL_HIGH ;
}
irqd_set_trigger_type ( irq_data , type ) ;
return 0 ;
}
2020-07-14 20:38:57 +03:00
static const struct irq_domain_ops ativic32_ops = {
2017-10-25 10:42:51 +03:00
. map = ativic32_irq_domain_map ,
. xlate = irq_domain_xlate_onecell
} ;
static irq_hw_number_t get_intr_src ( void )
{
return ( ( __nds32__mfsr ( NDS32_SR_ITYPE ) & ITYPE_mskVECTOR ) > > ITYPE_offVECTOR )
- NDS32_VECTOR_offINTERRUPT ;
}
2021-10-20 13:36:08 +03:00
static void ativic32_handle_irq ( struct pt_regs * regs )
2017-10-25 10:42:51 +03:00
{
irq_hw_number_t hwirq = get_intr_src ( ) ;
2021-10-20 13:36:08 +03:00
generic_handle_domain_irq ( root_domain , hwirq ) ;
}
/*
* TODO : convert nds32 to GENERIC_IRQ_MULTI_HANDLER so that this entry logic
* can live in arch code .
*/
asmlinkage void asm_do_IRQ ( struct pt_regs * regs )
{
struct pt_regs * old_regs ;
irq_enter ( ) ;
old_regs = set_irq_regs ( regs ) ;
ativic32_handle_irq ( regs ) ;
set_irq_regs ( old_regs ) ;
irq_exit ( ) ;
2017-10-25 10:42:51 +03:00
}
int __init ativic32_init_irq ( struct device_node * node , struct device_node * parent )
{
unsigned long int_vec_base , nivic , nr_ints ;
if ( WARN ( parent , " non-root ativic32 are not supported " ) )
return - EINVAL ;
int_vec_base = __nds32__mfsr ( NDS32_SR_IVB ) ;
if ( ( ( int_vec_base & IVB_mskIVIC_VER ) > > IVB_offIVIC_VER ) = = 0 )
panic ( " Unable to use atcivic32 for this cpu. \n " ) ;
nivic = ( int_vec_base & IVB_mskNIVIC ) > > IVB_offNIVIC ;
if ( nivic > = ARRAY_SIZE ( nivic_map ) )
panic ( " The number of input for ativic32 is not supported. \n " ) ;
nr_ints = nivic_map [ nivic ] ;
root_domain = irq_domain_add_linear ( node , nr_ints ,
& ativic32_ops , NULL ) ;
if ( ! root_domain )
panic ( " %s: unable to create IRQ domain \n " , node - > full_name ) ;
return 0 ;
}
IRQCHIP_DECLARE ( ativic32 , " andestech,ativic32 " , ativic32_init_irq ) ;