diff options
Diffstat (limited to 'c/src/lib/libbsp/powerpc/mvme5500/irq/BSP_irq.c')
-rw-r--r-- | c/src/lib/libbsp/powerpc/mvme5500/irq/BSP_irq.c | 514 |
1 files changed, 514 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/powerpc/mvme5500/irq/BSP_irq.c b/c/src/lib/libbsp/powerpc/mvme5500/irq/BSP_irq.c new file mode 100644 index 0000000000..00ac8eb952 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mvme5500/irq/BSP_irq.c @@ -0,0 +1,514 @@ +/* BSP_irq.c + * + * This file contains the implementation of the function described in irq.h + * + * Copyright (C) 1998, 1999 valette@crf.canon.fr + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * + * Acknowledgement to Till Straumann <strauman@slac.stanford.edu> + * for some inputs in May 2004. + * + * Copyright 2003, 2004, 2005, 2007 Shuchen Kate Feng <feng1@bnl.gov>, + * NSLS, Brookhaven National Laboratory. All rights reserved. + * + * 1) Used GT_GPP_Value register instead of the GT_GPP_Interrupt_Cause + * register to monitor the cause of the level sensitive interrupts. + * (Copyright : NDA item) + * 2) The implementation of picPrioTable[] is an original work by the + * author to optimize the software IRQ priority scheduling because + * Discovery controller does not provide H/W IRQ priority schedule. + * It ensures the fastest/faster interrupt service to the + * highest/higher priority IRQ, if pendig. + * 3) _CPU_MSR_SET() needs RTEMS_COMPILER_MEMORY_BARRIER() + * + */ + +#include <stdio.h> +#include <rtems/system.h> +#include <bsp.h> +#include <bsp/irq.h> +#include <rtems/score/thread.h> +#include <rtems/score/apiext.h> +#include <libcpu/raw_exception.h> +#include <rtems/rtems/intr.h> +#include <libcpu/io.h> +#include <libcpu/byteorder.h> +#include <bsp/vectors.h> + +#include <rtems/bspIo.h> /* for printk */ +#include "bsp/gtreg.h" + +#define HI_INT_CAUSE 0x40000000 + +#define MAX_IRQ_LOOP 20 + +#define _MSR_GET( _mask) \ + do { \ + RTEMS_COMPILER_MEMORY_BARRIER(); \ + _CPU_MSR_GET( _mask); \ + RTEMS_COMPILER_MEMORY_BARRIER(); \ + } while (0); + +#define _MSR_SET( _mask) \ + do { \ + RTEMS_COMPILER_MEMORY_BARRIER(); \ + _CPU_MSR_SET( _mask); \ + RTEMS_COMPILER_MEMORY_BARRIER(); \ + } while (0); + +/* #define DEBUG_IRQ*/ + +/* + * pointer to the mask representing the additionnal irq vectors + * that must be disabled when a particular entry is activated. + * They will be dynamically computed from the table given + * in BSP_rtems_irq_mngt_set(); + * CAUTION : this table is accessed directly by interrupt routine + * prologue. + */ +static unsigned int BSP_irq_prio_mask_tbl[3][BSP_PIC_IRQ_NUMBER]; + +/* + * default handler connected on each irq after bsp initialization + */ +static rtems_irq_connect_data default_rtems_entry; + +/* + * location used to store initial tables used for interrupt + * management.BSP copy of the configuration + */ +static rtems_irq_global_settings BSP_config; + +static volatile unsigned *BSP_irqMask_reg[3]; +static volatile unsigned *BSP_irqCause_reg[3]; +static volatile unsigned BSP_irqMask_cache[3]={0,0,0}; +static unsigned int BSP_GPP_mask[4]= { 1<<24, 1<<25, 1<<26, 1<<27}; + +static int picPrioTblPtr=0; +static unsigned int GPPIrqInTbl=0; +static unsigned long long MainIrqInTbl=0; + +/* + * The software developers are forbidden to setup picPrioTable[], + * as it is a powerful engine for the BSP to find the pending + * highest priority IRQ at run time. It ensures the fastest/faster + * interrupt service to the highest/higher priority IRQ, if pendig. + * + * The picPrioTable[96] is updated dynamically at run time + * based on the priority levels set at BSPirqPrioTable[96], + * while the BSP_enable_irq_at_pic(), and BSP_disable_irq_at_pic() + * commands are invoked. + * + * The picPrioTable[96] lists the enabled CPU main and GPP external interrupt + * numbers [0 (lowest)- 95 (highest)] starting from the highest priority + * one to the lowest priority one. The highest priority interrupt is + * located at picPrioTable[0], and the lowest priority interrupt is located + * at picPrioTable[picPrioTblPtr-1]. + * + * + */ +#define DynamicIsrTable +#ifdef DynamicIsrTable +/* BitNums for Main Interrupt Lo/High Cause, -1 means invalid bit */ +static unsigned int picPrioTable[BSP_PIC_IRQ_NUMBER]={ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1 }; +#else +static unsigned int picPrioTable[BSP_PIC_IRQ_NUMBER]={ + 80, 84, 76, 77, 32, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1 }; +#endif + +/* + * Check if IRQ is a MAIN CPU internal IRQ or GPP external IRQ + */ +static inline int is_pic_irq(const rtems_irq_number irqLine) +{ + return (((int) irqLine <= BSP_GPP_IRQ_MAX_OFFSET) & + ((int) irqLine >= BSP_MICL_IRQ_LOWEST_OFFSET) + ); +} + +/* + * Check if IRQ is a Porcessor IRQ + */ +static inline int is_processor_irq(const rtems_irq_number irqLine) +{ + return (((int) irqLine <= BSP_PROCESSOR_IRQ_MAX_OFFSET) & + ((int) irqLine >= BSP_PROCESSOR_IRQ_LOWEST_OFFSET) + ); +} + +/* + * ------------------------ RTEMS Irq helper functions ---------------- + */ + +/* + * Caution : this function assumes the variable "BSP_config" + * is already set and that the tables it contains are still valid + * and accessible. + */ +static void compute_pic_masks_from_prio() +{ + int i,j, k, isGppMain; + unsigned long long irq_prio_mask=0; + + /* + * Always mask at least current interrupt to prevent re-entrance + */ + for (i=0; i <BSP_PIC_IRQ_NUMBER; i++) { + switch(i) { + case BSP_MAIN_GPP7_0_IRQ: + case BSP_MAIN_GPP15_8_IRQ: + case BSP_MAIN_GPP23_16_IRQ: + case BSP_MAIN_GPP31_24_IRQ: + for (k=0; k< 3; k++) + BSP_irq_prio_mask_tbl[k][i]=0; + + irq_prio_mask =0; + isGppMain =1; + break; + default : + isGppMain =0; + irq_prio_mask = (unsigned long long) (1LLU << i); + break; + } + if ( isGppMain) continue; + for (j = 0; j <BSP_MAIN_IRQ_NUMBER; j++) { + /* + * Mask interrupts at PIC level that have a lower priority + * or <Till Straumann> a equal priority. + */ + if (BSP_config.irqPrioTbl [i] >= BSP_config.irqPrioTbl [j]) + irq_prio_mask |= (unsigned long long)(1LLU << j); + } + + + BSP_irq_prio_mask_tbl[0][i] = irq_prio_mask & 0xffffffff; + BSP_irq_prio_mask_tbl[1][i] = (irq_prio_mask>>32) & 0xffffffff; +#if 0 + printk("irq_mask_prio_tbl[%d]:0x%8x%8x\n",i,BSP_irq_prio_mask_tbl[1][i], + BSP_irq_prio_mask_tbl[0][i]); +#endif + + BSP_irq_prio_mask_tbl[2][i] = 1<<i; + /* Compute for the GPP priority interrupt mask */ + for (j=BSP_GPP_IRQ_LOWEST_OFFSET; j <BSP_PROCESSOR_IRQ_LOWEST_OFFSET; j++) { + if (BSP_config.irqPrioTbl [i] >= BSP_config.irqPrioTbl [j]) + BSP_irq_prio_mask_tbl[2][i] |= 1 << (j-BSP_GPP_IRQ_LOWEST_OFFSET); + } +#if 0 + printk("GPPirq_mask_prio_tbl[%d]:0x%8x\n",i,BSP_irq_prio_mask_tbl[2][i]); +#endif + } +} + +static void UpdateMainIrqTbl(int irqNum) +{ + int i=0, j, k, shifted=0; + + switch (irqNum) { + case BSP_MAIN_GPP7_0_IRQ: + case BSP_MAIN_GPP15_8_IRQ: + case BSP_MAIN_GPP23_16_IRQ: + case BSP_MAIN_GPP31_24_IRQ: + return; /* Do nothing, let GPP take care of it */ + break; + } +#ifdef SHOW_MORE_INIT_SETTINGS + unsigned long val2, val1; +#endif + + /* If entry not in table*/ + if ( ((irqNum<BSP_GPP_IRQ_LOWEST_OFFSET) && + (!((unsigned long long)(1LLU << irqNum) & MainIrqInTbl))) || + ((irqNum>BSP_MICH_IRQ_MAX_OFFSET) && + (!(( 1 << (irqNum-BSP_GPP_IRQ_LOWEST_OFFSET)) & GPPIrqInTbl)))) + { + while ( picPrioTable[i]!=-1) { + if (BSP_config.irqPrioTbl[irqNum]>BSP_config.irqPrioTbl[picPrioTable[i]]) { + /* all other lower priority entries shifted right */ + for (j=picPrioTblPtr;j>i; j--) { + picPrioTable[j]=picPrioTable[j-1]; + } + picPrioTable[i]=irqNum; + shifted=1; + break; + } + i++; + } + if (!shifted) picPrioTable[picPrioTblPtr] =irqNum; + + if (irqNum >BSP_MICH_IRQ_MAX_OFFSET) + GPPIrqInTbl |= (1<< (irqNum-BSP_GPP_IRQ_LOWEST_OFFSET)); + else + MainIrqInTbl |= (unsigned long long)(1LLU << irqNum); + picPrioTblPtr++; + } +#ifdef SHOW_MORE_INIT_SETTINGS + val2 = (MainIrqInTbl>>32) & 0xffffffff; + val1 = MainIrqInTbl&0xffffffff; + printk("irqNum %d, MainIrqInTbl 0x%x%x\n", irqNum, val2, val1); + BSP_printPicIsrTbl(); +#endif + +} + + +static void CleanMainIrqTbl(int irqNum) +{ + int i, j, k; + + switch (irqNum) { + case BSP_MAIN_GPP7_0_IRQ: + case BSP_MAIN_GPP15_8_IRQ: + case BSP_MAIN_GPP23_16_IRQ: + case BSP_MAIN_GPP31_24_IRQ: + return; /* Do nothing, let GPP take care of it */ + break; + } + if ( ((irqNum<BSP_GPP_IRQ_LOWEST_OFFSET) && + ((unsigned long long)(1LLU << irqNum) & MainIrqInTbl)) || + ((irqNum>BSP_MICH_IRQ_MAX_OFFSET) && + (( 1 << (irqNum-BSP_GPP_IRQ_LOWEST_OFFSET)) & GPPIrqInTbl))) + { /* If entry in table*/ + for (i=0; i<64; i++) { + if (picPrioTable[i]==irqNum) {/*remove it from the entry */ + /* all other lower priority entries shifted left */ + for (j=i;j<picPrioTblPtr; j++) { + picPrioTable[j]=picPrioTable[j+1]; + } + if (irqNum >BSP_MICH_IRQ_MAX_OFFSET) + GPPIrqInTbl &= ~(1<< (irqNum-BSP_GPP_IRQ_LOWEST_OFFSET)); + else + MainIrqInTbl &= ~(1LLU << irqNum); + picPrioTblPtr--; + break; + } + } + } +} + +void BSP_enable_irq_at_pic(const rtems_irq_number irqNum) +{ + unsigned bitNum, regNum; + unsigned int level; + + bitNum = (((unsigned int)irqNum) - BSP_MICL_IRQ_LOWEST_OFFSET)%32; + regNum = (((unsigned int)irqNum) - BSP_MICL_IRQ_LOWEST_OFFSET)>>5; + + rtems_interrupt_disable(level); + +#ifdef DynamicIsrTable + UpdateMainIrqTbl((int) irqNum); +#endif + BSP_irqMask_cache[regNum] |= (1 << bitNum); + + out_le32(BSP_irqMask_reg[regNum], BSP_irqMask_cache[regNum]); + while (in_le32(BSP_irqMask_reg[regNum]) != BSP_irqMask_cache[regNum]); + + memBar(); + rtems_interrupt_enable(level); +} + +void BSP_disable_irq_at_pic(const rtems_irq_number irqNum) +{ + unsigned bitNum, regNum; + unsigned int level; + + bitNum = (((unsigned int)irqNum) - BSP_MICL_IRQ_LOWEST_OFFSET)%32; + regNum = (((unsigned int)irqNum) - BSP_MICL_IRQ_LOWEST_OFFSET)>>5; + + rtems_interrupt_disable(level); + +#ifdef DynamicIsrTable + CleanMainIrqTbl((int) irqNum); +#endif + BSP_irqMask_cache[regNum] &= ~(1 << bitNum); + + out_le32(BSP_irqMask_reg[regNum], BSP_irqMask_cache[regNum]); + while (in_le32(BSP_irqMask_reg[regNum]) != BSP_irqMask_cache[regNum]); + memBar(); + rtems_interrupt_enable(level); +} + +/* Use shared/irq : 2008 */ +int BSP_setup_the_pic(rtems_irq_global_settings* config) +{ + int i; + + BSP_config = *config; + + switch(BSP_getDiscoveryChipVersion()) { + case GT64260B: + case GT64260A: + /* Get ready for discovery BSP */ + BSP_irqMask_reg[0]= (volatile unsigned int *) (GT64x60_REG_BASE + GT64260_CPU_INT_MASK_LO); + BSP_irqMask_reg[1]= (volatile unsigned int *) (GT64x60_REG_BASE + GT64260_CPU_INT_MASK_HI); + BSP_irqCause_reg[0]= (volatile unsigned int *) (GT64x60_REG_BASE + GT64260_MAIN_INT_CAUSE_LO); + BSP_irqCause_reg[1]= (volatile unsigned int *) (GT64x60_REG_BASE + GT64260_MAIN_INT_CAUSE_HI); + break; + default: + printk("Not supported by this BSP yet\n"); + return(0); + break; + } + + BSP_irqMask_reg[2]= (volatile unsigned int *) (GT64x60_REG_BASE + GT_GPP_Interrupt_Mask); + BSP_irqCause_reg[2]= (volatile unsigned int *) (GT64x60_REG_BASE + GT_GPP_Value); + + /* Page 401, Table 598: + * Comm Unit Arbiter Control register : + * bit 10:GPP interrupts as level sensitive(1) or edge sensitive(0). + * MOTload default is set as level sensitive(1). Set it agin to make sure. + */ + outl((inl(GT_CommUnitArb_Ctrl)| (1<<10)), GT_CommUnitArb_Ctrl); + +#if 0 + printk("BSP_irqMask_reg[0] = 0x%x, BSP_irqCause_reg[0] 0x%x\n", + in_le32(BSP_irqMask_reg[0]), + in_le32(BSP_irqCause_reg[0])); + printk("BSP_irqMask_reg[1] = 0x%x, BSP_irqCause_reg[1] 0x%x\n", + in_le32(BSP_irqMask_reg[1]), + in_le32(BSP_irqCause_reg[1])); + printk("BSP_irqMask_reg[2] = 0x%x, BSP_irqCause_reg[2] 0x%x\n", + in_le32(BSP_irqMask_reg[2]), + in_le32(BSP_irqCause_reg[2])); +#endif + + /* Initialize the interrupt related registers */ + for (i=0; i<3; i++) { + out_le32(BSP_irqCause_reg[i], 0); + out_le32(BSP_irqMask_reg[i], 0); + } + in_le32(BSP_irqMask_reg[2]); + compute_pic_masks_from_prio(); + +#if 0 + printk("BSP_irqMask_reg[0] = 0x%x, BSP_irqCause_reg[0] 0x%x\n", + in_le32(BSP_irqMask_reg[0]), + in_le32(BSP_irqCause_reg[0])); + printk("BSP_irqMask_reg[1] = 0x%x, BSP_irqCause_reg[1] 0x%x\n", + in_le32(BSP_irqMask_reg[1]), + in_le32(BSP_irqCause_reg[1])); + printk("BSP_irqMask_reg[2] = 0x%x, BSP_irqCause_reg[2] 0x%x\n", + in_le32(BSP_irqMask_reg[2]), + in_le32(BSP_irqCause_reg[2])); +#endif + + /* + * + */ + for (i=BSP_MICL_IRQ_LOWEST_OFFSET; i < BSP_PROCESSOR_IRQ_LOWEST_OFFSET ; i++) { + if ( BSP_config.irqHdlTbl[i].hdl != BSP_config.defaultEntry.hdl) { + BSP_enable_irq_at_pic(i); + BSP_config.irqHdlTbl[i].on(&BSP_config.irqHdlTbl[i]); + } + else { + BSP_config.irqHdlTbl[i].off(&BSP_config.irqHdlTbl[i]); + BSP_disable_irq_at_pic(i); + } + } + for (i= BSP_MAIN_GPP7_0_IRQ; i < BSP_MAIN_GPP31_24_IRQ; i++) + BSP_enable_irq_at_pic(i); + + return(1); +} + +/* + * High level IRQ handler called from shared_raw_irq_code_entry + */ + +void C_dispatch_irq_handler (CPU_Interrupt_frame *frame, unsigned int excNum) +{ + register unsigned msr, new_msr; + unsigned long irqCause[3]={0, 0,0}; + unsigned oldMask[3]={0,0,0}; + int loop=0, wloop=0, i=0, j; + register irq=0, group=0; + + if (excNum == ASM_DEC_VECTOR) { + _MSR_GET(msr); + new_msr = msr | MSR_EE; + _MSR_SET(new_msr); + + BSP_config.irqHdlTbl[BSP_DECREMENTER].hdl(BSP_config.irqHdlTbl[BSP_DECREMENTER].handle); + _MSR_SET(msr); + return; + + } + + for (j=0; j<3; j++ ) oldMask[j] = BSP_irqMask_cache[j]; + for (j=0; j<3; j++) irqCause[j] = in_le32(BSP_irqCause_reg[j]) & in_le32(BSP_irqMask_reg[j]); + + while (((irq = picPrioTable[i++])!=-1)&& (loop++ < MAX_IRQ_LOOP)) + { + if (irqCause[group= irq/32] & ( 1<<(irq % 32))) { + for (j=0; j<3; j++) + BSP_irqMask_cache[j] &= (~ BSP_irq_prio_mask_tbl[j][irq]); + + out_le32(BSP_irqMask_reg[0], BSP_irqMask_cache[0]); + out_le32(BSP_irqMask_reg[1], BSP_irqMask_cache[1]); + out_le32(BSP_irqMask_reg[2], BSP_irqMask_cache[2]); + in_le32(BSP_irqMask_reg[2]); + + _MSR_GET(msr); + new_msr = msr | MSR_EE; + _MSR_SET(new_msr); + /* handler */ +#ifdef BSP_SHARED_HANDLER_SUPPORT + { + rtems_irq_connect_data* vchain; + for( vchain = &BSP_config.irqHdlTbl[irq]; + (vchain->hdl != BSP_config.defaultEntry.hdl && ((int)vchain != -1) ); + vchain = (rtems_irq_connect_data*)vchain->next_handler ) + { + vchain->hdl(vchain->handle); + } + } +#else + BSP_config.irqHdlTbl[irq].hdl(BSP_config.irqHdlTbl[irq].handle); +#endif + _MSR_SET(msr); + + for (j=0; j<3; j++ ) BSP_irqMask_cache[j] = oldMask[j]; + + out_le32(BSP_irqMask_reg[0], oldMask[0]); + out_le32(BSP_irqMask_reg[1], oldMask[1]); + out_le32(BSP_irqMask_reg[2], oldMask[2]); + in_le32(BSP_irqMask_reg[2]); + } + } +} + +/* Only print part of the entries for now */ +void BSP_printPicIsrTbl() +{ + int i; + + printf("picPrioTable[12]={ irq# :"); + for (i=0; i<12; i++) + printf("%d,", picPrioTable[i]); + printf("}\n"); + + printf("GPPIrqInTbl: 0x%x :\n", GPPIrqInTbl); +} |