/* * * avalanche_intdc.c * Description: * interrupt controller file * * GPL LICENSE SUMMARY Copyright(c) 2015-2016 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License 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, write to the Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. The full GNU General Public License is included in this distribution in the file called LICENSE.GPL. Contact Information: Intel Corporation 2200 Mission College Blvd. Santa Clara, CA 97052 */ /****************/ /** Includes **/ /****************/ #include #include #include #include "netip_subsystem_defs.h" #include #include /***************/ /** Defines **/ /***************/ #define INTC_SET_BIT_0 ( 0x00000001 ) #define HOST_ARM_IRQ_NUM ( 1 ) /* ARM nIRQ Number */ #define NUM_SYS_INTS_PER_REG ( 4 ) #define NUM_CHANNELS_PER_REG ( 4 ) #define NUM_CHANNEL_MAP_REGS ( 24 ) #define NUM_HOST_INT_MAP_REGS ( 2 ) /* uncomment to enable debug prints */ //#define INTC_DEBUG #ifdef INTC_DEBUG /* Debug print, also print function name and line number */ # define DPRINTK(fmt, args...) printk("%s(%d): " fmt "\n", __FUNCTION__ , __LINE__, ## args) #else # define DPRINTK(fmt, args...) #endif #ifdef INTC_DEBUG /* Error print, also print function name and line number */ #define EPRINTK(fmt, args...) printk(KERN_ERR "****** %s(%d): " fmt " ******\n", __FUNCTION__ , __LINE__, ## args) #else #define EPRINTK(fmt, args...) printk(KERN_ERR "****** " fmt " ******\n",## args) #endif /***************/ /** Globals **/ /***************/ /* Avalance Intc registers */ struct avalanche_ictrl_regs *avalanche_hw0_icregs; /* NetIp PCI bridge sub devices structure */ extern net_ip_mmios_t net_ip_mmios; /**************************************************************************** * Interrupt Mapping APIs ****************************************************************************/ /***************************************************************************** * Utility Functions ****************************************************************************/ inline unsigned char get_bit_position ( unsigned int irq ) { return((unsigned char)( irq % NUM_INTS_PER_REG )); } inline unsigned char get_reg_index( unsigned int irq ) { return((unsigned char )( irq / NUM_INTS_PER_REG )); } int avalanche_intc_set_interrupt_type( unsigned int irq, unsigned char int_type) { unsigned int int_reg_indx = get_reg_index( irq ); unsigned int irq_bit = get_bit_position( irq ); if (int_type) { avalanche_hw0_icregs->ictypr[int_reg_indx] |= cpu_to_be32((1 << irq_bit)); } else { avalanche_hw0_icregs->ictypr[int_reg_indx] &= ~(cpu_to_be32((1 << irq_bit))); } return(0); } /* low level INTC type get */ int avalanche_intc_get_interrupt_type( unsigned int irq ) { unsigned int int_reg_indx = get_reg_index( irq ); unsigned int irq_bit = get_bit_position( irq ); return(unsigned char)((be32_to_cpu(avalanche_hw0_icregs->ictypr[int_reg_indx]) >> irq_bit)&0x1); } /* low level INTC pol set */ int avalanche_intc_set_interrupt_polarity( unsigned int irq, unsigned char int_polarity) { unsigned int int_reg_indx = get_reg_index( irq ); unsigned int irq_bit = get_bit_position( irq ); if(int_polarity) { avalanche_hw0_icregs->icpolr[int_reg_indx] |= cpu_to_be32((1 << irq_bit)); } else { avalanche_hw0_icregs->icpolr[int_reg_indx] &= ~(cpu_to_be32((1 << irq_bit))); } return(0); } /* low level INTC pol get */ int avalanche_intc_get_interrupt_polarity ( unsigned int irq ) { unsigned int int_reg_indx = get_reg_index( irq ); unsigned int irq_bit = get_bit_position( irq ); return(unsigned char)((be32_to_cpu(avalanche_hw0_icregs->icpolr[int_reg_indx]) >> irq_bit)&0x1); } EXPORT_SYMBOL(avalanche_intc_set_interrupt_type); EXPORT_SYMBOL(avalanche_intc_get_interrupt_type); EXPORT_SYMBOL(avalanche_intc_set_interrupt_polarity); EXPORT_SYMBOL(avalanche_intc_get_interrupt_polarity); /********************************/ /** functions Implementation **/ /********************************/ int avalanche_intc_clear_status( unsigned int irq ) { unsigned char irq_index, irq_bit; irq_index = get_reg_index(irq); irq_bit = get_bit_position(irq); /* Got ARM11 interrupt status regsiter */ /* write 1 to clear status register */ avalanche_hw0_icregs->icestar[irq_index] = cpu_to_be32((1<ichmpr[hst_int_reg_indx] |= (host_irq << ((channel_num % NUM_CHANNELS_PER_REG)* 8 )); return(0); } int avalanche_intc_get_status( unsigned int irq ) { unsigned char irq_index, irq_bit; unsigned int status_reg; DPRINTK("called with irq#=%d\n", irq); irq_index = get_reg_index(irq); irq_bit = get_bit_position(irq); /* ARM11 big endian to CPU native endianness */ /* got ARM11 interrupt status regsiter */ status_reg = be32_to_cpu(avalanche_hw0_icregs->icestar[irq_index]); if ((status_reg & (1<iceisr = cpu_to_be32(irq); } void avalanche_intc_disable_irq( unsigned int irq ) { avalanche_hw0_icregs->ichinteicr = cpu_to_be32(HOST_ARM_IRQ_NUM); avalanche_hw0_icregs->iceicr = cpu_to_be32(irq); avalanche_hw0_icregs->ichinteisr = cpu_to_be32(HOST_ARM_IRQ_NUM); } int avalanche_intc_init(void) { unsigned int cntrl_ver, chnl_num; /* ioremap ATM_INTC IO memory */ /*setting up ATOM_INTC base address */ avalanche_hw0_icregs = (struct avalanche_ictrl_regs *)ioremap( (net_ip_mmios.region1_base + (ATOM_INTC_BASE & 0x0FFFFFFF)), sizeof(struct avalanche_ictrl_regs)); if(!avalanche_hw0_icregs) { EPRINTK(" ATOM_INTC_BASE memory map fail : %x\n",ATOM_INTC_BASE ); return -1; } /* read ATOM_INTC revision register */ /**ARM11 big endian to CPU read register and call the corresponding value */ cntrl_ver = be32_to_cpu(avalanche_hw0_icregs->icrevr); DPRINTK("ATOM_INTC Interrupt controller revision : %x\n", cntrl_ver); /* As VIC is disabled, All the channel will map to to either nFIQ or nIRQ. */ for( chnl_num = 0; chnl_num < (NUM_HOST_INT_MAP_REGS * NUM_CHANNELS_PER_REG); chnl_num++ ) { avalanche_intc_map_channel_to_host_int(chnl_num, HOST_ARM_IRQ_NUM); } /* enable host interrupts 0x3 will enable HOST IRQ */ avalanche_hw0_icregs->ichinter[0] = cpu_to_be32(0x3); /* set global enable */ avalanche_hw0_icregs->icglber = cpu_to_be32(INTC_SET_BIT_0); DPRINTK("avalanche_hw0_icregs->ichinter (host enable register) =%x\n", be32_to_cpu(avalanche_hw0_icregs->ichinter[0])); DPRINTK("avalanche_hw0_icregs->icglber (global enable register) =%x\n", be32_to_cpu(avalanche_hw0_icregs->icglber)); DPRINTK("avalanche_hw0_icregs->ichmpr (channlemap register) =%x\n", be32_to_cpu(avalanche_hw0_icregs->ichmpr[0])); return 0; } void avalanche_intc_cleanup(void) { if(avalanche_hw0_icregs != NULL) { iounmap(avalanche_hw0_icregs); avalanche_hw0_icregs = NULL; } } EXPORT_SYMBOL(avalanche_intc_get_status); EXPORT_SYMBOL(avalanche_intc_clear_status); EXPORT_SYMBOL(avalanche_intc_enable_irq); EXPORT_SYMBOL(avalanche_intc_disable_irq);