forked from Imagelibrary/rtems
713 lines
20 KiB
C
713 lines
20 KiB
C
/*
|
|
* RTEMS generic MPC5200 BSP
|
|
*
|
|
* This file contains the irq controller handler.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 1998, 1999 valette@crf.canon.fr
|
|
*
|
|
* Copyright (c) 2000 Andy Dachs <a.dachs@sstl.co.uk>
|
|
* Surrey Satellite Technology Limited
|
|
*
|
|
* Copyright (c) 2003 IPR Engineering. All rights reserved.
|
|
*
|
|
* Copyright (c) 2005 embedded brains GmbH. All rights reserved.
|
|
*
|
|
* The license and distribution terms for this file may be
|
|
* found in the file LICENSE in this distribution or at
|
|
* http://www.rtems.org/license/LICENSE.
|
|
*/
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <rtems.h>
|
|
|
|
#include <libcpu/powerpc-utility.h>
|
|
#include <bsp/vectors.h>
|
|
|
|
#include <bsp.h>
|
|
#include <bsp/irq.h>
|
|
#include <bsp/irq-generic.h>
|
|
#include <bsp/mpc5200.h>
|
|
|
|
/*
|
|
* bit in the SIU mask registers (PPC bit numbering) that should
|
|
* be set to enable the relevant interrupt, mask of 32 is for unused entries
|
|
*
|
|
*/
|
|
const static unsigned int SIU_MaskBit [BSP_SIU_IRQ_NUMBER] = {
|
|
0, 1, 2, 3, /* smart_comm, psc1, psc2, psc3 */
|
|
4, 5, 6, 7, /* irda/psc6, eth, usb, ata */
|
|
8, 9, 10, 11, /* pci_ctrl, pci_sc_rx, pci_sc_tx, psc4 */
|
|
12, 13, 14, 15, /* psc5,spi_modf, spi_spif, i2c1 */
|
|
16, 17, 18, 19, /* i2c, can1, can2, ir_rx */
|
|
20, 21, 15, 16, /* ir_rx, xlb_arb, slice_tim2, irq1, */
|
|
17, 18, 19, 20, /* irq2, irq3, lo_int, rtc_pint */
|
|
21, 22, 23, 24, /* rtc_sint, gpio_std, gpio_wkup, tmr0 */
|
|
25, 26, 27, 28, /* tmr1, tmr2, tmr3, tmr4 */
|
|
29, 30, 31, 32, /* tmr5, tmr6, tmr7, res */
|
|
32, 32, 32 /* res, res, res */
|
|
};
|
|
|
|
static unsigned char irqPrioTable [BSP_SIU_IRQ_NUMBER] = {
|
|
/* per. int. priorities (0-7) / 4bit coding / msb is HI/LO selection */
|
|
/* msb = 0 -> non-critical per. int. is routed to main int. (LO_int) */
|
|
/* msb = 1 -> critical per. int. is routed to critical int. (HI_int) */
|
|
0xF, 0, 0, 0, /* smart_comm (do not change!), psc1, psc2, psc3 */
|
|
0, 0, 0, 0, /* irda, eth, usb, ata */
|
|
0, 0, 0, 0, /* pci_ctrl, pci_sc_rx, pci_sc_tx, res */
|
|
0, 0, 0, 0, /* res, spi_modf, spi_spif, i2c1 */
|
|
0, 0, 0, 0, /* i2c, can1, can2, ir_rx */
|
|
0, 0, /* ir_rx, xlb_arb */
|
|
/* main interrupt priorities (0-7) / 4bit coding / msb is INT/SMI selection */
|
|
/* msb = 0 -> main int. is routed to processor INT (low vector base 0x500 ) */
|
|
/* msb = 1 -> main int. is routed to processor SMI (low vector base 0x1400 ) */
|
|
0, 0, /* slice_tim2, irq1 */
|
|
0, 0, 0, 0, /* irq2, irq3, lo_int, rtc_pint */
|
|
0, 0, 0, 0, /* rtc_sint, gpio_std, gpio_wkup, tmr0 */
|
|
0, 0, 0, 0, /* tmr1, tmr2, tmr3, tmr4 */
|
|
0, 0, 0, /* tmr5, tmr6, tmr7 */
|
|
/* critical interrupt priorities (0-3) / 2bit coding / no special purpose of msb */
|
|
0, /* irq0 */
|
|
0, 0, 0 /* slice_tim1, hi_int, ccs_wkup */
|
|
};
|
|
|
|
static uint32_t irqMaskTable [BSP_PER_IRQ_NUMBER + BSP_MAIN_IRQ_NUMBER];
|
|
|
|
/*
|
|
* Check if symbolic IRQ name is a Processor IRQ
|
|
*/
|
|
static inline bool is_processor_irq( rtems_vector_number irqLine)
|
|
{
|
|
|
|
return ((irqLine <= BSP_PROCESSOR_IRQ_MAX_OFFSET)
|
|
&& (irqLine >= BSP_PROCESSOR_IRQ_LOWEST_OFFSET));
|
|
}
|
|
|
|
/*
|
|
* Check for SIU IRQ and return base index
|
|
*/
|
|
static inline bool is_siu_irq( rtems_vector_number irqLine)
|
|
{
|
|
|
|
return ((irqLine <= BSP_SIU_IRQ_MAX_OFFSET)
|
|
&& (irqLine >= BSP_SIU_IRQ_LOWEST_OFFSET));
|
|
}
|
|
|
|
/*
|
|
* Check for SIU IRQ and return base index
|
|
*/
|
|
static inline int get_siu_irq_base_index( rtems_vector_number irqLine)
|
|
{
|
|
if (irqLine <= BSP_PER_IRQ_MAX_OFFSET)
|
|
return BSP_PER_IRQ_LOWEST_OFFSET;
|
|
|
|
if (irqLine <= BSP_MAIN_IRQ_MAX_OFFSET)
|
|
return BSP_MAIN_IRQ_LOWEST_OFFSET;
|
|
|
|
if (irqLine <= BSP_CRIT_IRQ_MAX_OFFSET)
|
|
return BSP_CRIT_IRQ_LOWEST_OFFSET;
|
|
|
|
return -1;
|
|
}
|
|
|
|
static inline void BSP_enable_per_irq_at_siu(
|
|
rtems_vector_number irqLine
|
|
)
|
|
{
|
|
uint8_t lo_hi_ind = 0,
|
|
prio_index_offset;
|
|
uint32_t *reg;
|
|
|
|
/* calculate the index offset of priority value bit field */
|
|
prio_index_offset = (irqLine - BSP_PER_IRQ_LOWEST_OFFSET) % 8;
|
|
|
|
/* set interrupt priorities */
|
|
if (irqPrioTable [irqLine] <= 15) {
|
|
|
|
/* set peripheral int priority */
|
|
reg = (uint32_t *) (&(mpc5200.per_pri_1));
|
|
|
|
/* choose proper register */
|
|
reg += (irqLine >> 3);
|
|
|
|
/* set priority as given in priority table */
|
|
*reg |= (irqPrioTable [irqLine] << (28 - (prio_index_offset << 2)));
|
|
|
|
/* test msb (hash-bit) and set LO_/HI_int indicator */
|
|
if ((lo_hi_ind = (irqPrioTable [irqLine] >> 3))) {
|
|
|
|
/* set critical HI_int priority */
|
|
reg = (uint32_t *) (&(mpc5200.crit_pri_main_mask));
|
|
*reg |= (irqPrioTable [BSP_SIU_IRQ_HI_INT] << 26);
|
|
|
|
/*
|
|
* critical interrupt handling for the 603le core is not
|
|
* yet supported, routing of critical interrupts is forced
|
|
* to core_int (bit 31 / CEb)
|
|
*/
|
|
mpc5200.ext_en_type |= 1;
|
|
|
|
} else {
|
|
if (irqPrioTable [irqLine] <= 15) {
|
|
/* set main LO_int priority */
|
|
reg = (uint32_t *) (&(mpc5200.main_pri_1));
|
|
*reg |= (irqPrioTable [BSP_SIU_IRQ_LO_INT] << 16);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* if LO_int ind., enable (unmask) main interrupt */
|
|
if (!lo_hi_ind) {
|
|
mpc5200.crit_pri_main_mask &=
|
|
~(0x80000000 >> SIU_MaskBit [BSP_SIU_IRQ_LO_INT]);
|
|
}
|
|
|
|
/* enable (unmask) peripheral interrupt */
|
|
mpc5200.per_mask &= ~(0x80000000 >> SIU_MaskBit [irqLine]);
|
|
|
|
/* FIXME: Why? */
|
|
mpc5200.main_pri_1;
|
|
mpc5200.crit_pri_main_mask;
|
|
mpc5200.per_pri_1;
|
|
mpc5200.per_mask;
|
|
}
|
|
|
|
static inline void BSP_enable_main_irq_at_siu(
|
|
rtems_vector_number irqLine
|
|
)
|
|
{
|
|
|
|
uint8_t prio_index_offset;
|
|
uint32_t *reg;
|
|
|
|
/* calculate the index offset of priority value bit field */
|
|
prio_index_offset = (irqLine - BSP_MAIN_IRQ_LOWEST_OFFSET) % 8;
|
|
|
|
/* set main interrupt priority */
|
|
if (irqPrioTable [irqLine] <= 15) {
|
|
|
|
/* set main int priority */
|
|
reg = (uint32_t *) (&(mpc5200.main_pri_1));
|
|
|
|
/* choose proper register */
|
|
reg += (irqLine >> 3);
|
|
|
|
/* set priority as given in priority table */
|
|
*reg |= (irqPrioTable [irqLine] << (28 - (prio_index_offset << 2)));
|
|
|
|
if ((irqLine >= BSP_SIU_IRQ_IRQ1) && (irqLine <= BSP_SIU_IRQ_IRQ3)) {
|
|
/* enable external irq-pin */
|
|
mpc5200.ext_en_type |= (0x80000000 >> (20 + prio_index_offset));
|
|
}
|
|
}
|
|
|
|
/* enable (unmask) main interrupt */
|
|
mpc5200.crit_pri_main_mask &= ~(0x80000000 >> SIU_MaskBit [irqLine]);
|
|
|
|
}
|
|
|
|
static inline void BSP_enable_crit_irq_at_siu(
|
|
rtems_vector_number irqLine
|
|
)
|
|
{
|
|
uint8_t prio_index_offset;
|
|
uint32_t *reg;
|
|
|
|
prio_index_offset = irqLine - BSP_CRIT_IRQ_LOWEST_OFFSET;
|
|
|
|
/*
|
|
* critical interrupt handling for the 603Le core is not
|
|
* yet supported, routing of critical interrupts is forced
|
|
* to core_int (bit 31 / CEb)
|
|
*/
|
|
mpc5200.ext_en_type |= 1;
|
|
|
|
/* set critical interrupt priorities */
|
|
if (irqPrioTable [irqLine] <= 3) {
|
|
|
|
/* choose proper register */
|
|
reg = (uint32_t *) (&(mpc5200.crit_pri_main_mask));
|
|
|
|
/* set priority as given in priority table */
|
|
*reg |= (irqPrioTable [irqLine] << (30 - (prio_index_offset << 1)));
|
|
|
|
/* external irq0-pin */
|
|
if (irqLine == BSP_SIU_IRQ_IRQ1) {
|
|
/* enable external irq-pin */
|
|
mpc5200.ext_en_type |= (0x80000000 >> (20 + prio_index_offset));
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline void BSP_disable_per_irq_at_siu(
|
|
rtems_vector_number irqLine
|
|
)
|
|
{
|
|
uint8_t prio_index_offset;
|
|
uint32_t *reg;
|
|
|
|
/* calculate the index offset of priority value bit field */
|
|
prio_index_offset = (irqLine - BSP_PER_IRQ_LOWEST_OFFSET) % 8;
|
|
|
|
/* disable (mask) peripheral interrupt */
|
|
mpc5200.per_mask |= (0x80000000 >> SIU_MaskBit [irqLine]);
|
|
|
|
/* reset priority to lowest level (reset value) */
|
|
reg = (uint32_t *) (&(mpc5200.per_pri_1));
|
|
reg += (irqLine >> 3);
|
|
*reg &= ~(15 << (28 - (prio_index_offset << 2)));
|
|
}
|
|
|
|
static inline void BSP_disable_main_irq_at_siu(
|
|
rtems_vector_number irqLine
|
|
)
|
|
{
|
|
uint8_t prio_index_offset;
|
|
uint32_t *reg;
|
|
|
|
/* calculate the index offset of priority value bit field */
|
|
prio_index_offset = (irqLine - BSP_MAIN_IRQ_LOWEST_OFFSET) % 8;
|
|
|
|
/* disable (mask) main interrupt */
|
|
mpc5200.crit_pri_main_mask |= (0x80000000 >> SIU_MaskBit [irqLine]);
|
|
|
|
if ((irqLine >= BSP_SIU_IRQ_IRQ1) && (irqLine <= BSP_SIU_IRQ_IRQ3)) {
|
|
/* disable external irq-pin */
|
|
mpc5200.ext_en_type &= ~(0x80000000 >> (20 + prio_index_offset));
|
|
}
|
|
|
|
/* reset priority to lowest level (reset value) */
|
|
reg = (uint32_t *) (&(mpc5200.main_pri_1));
|
|
reg += (irqLine >> 3);
|
|
*reg &= ~(15 << (28 - (prio_index_offset << 2)));
|
|
}
|
|
|
|
static inline void BSP_disable_crit_irq_at_siu( rtems_vector_number
|
|
irqLine)
|
|
{
|
|
uint8_t prio_index_offset;
|
|
uint32_t *reg;
|
|
|
|
prio_index_offset = irqLine - BSP_CRIT_IRQ_LOWEST_OFFSET;
|
|
|
|
/* reset critical int priority to lowest level (reset value) */
|
|
reg = (uint32_t *) (&(mpc5200.crit_pri_main_mask));
|
|
*reg &= ~(3 << (30 - (prio_index_offset << 1)));
|
|
|
|
if (irqLine == BSP_SIU_IRQ_IRQ1) {
|
|
/* disable external irq0-pin */
|
|
mpc5200.ext_en_type &= ~(0x80000000 >> (20 + prio_index_offset));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This function enables a given siu interrupt
|
|
*/
|
|
rtems_status_code bsp_interrupt_get_attributes(
|
|
rtems_vector_number vector,
|
|
rtems_interrupt_attributes *attributes
|
|
)
|
|
{
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
rtems_status_code bsp_interrupt_is_pending(
|
|
rtems_vector_number vector,
|
|
bool *pending
|
|
)
|
|
{
|
|
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
|
|
bsp_interrupt_assert(pending != NULL);
|
|
*pending = false;
|
|
return RTEMS_UNSATISFIED;
|
|
}
|
|
|
|
rtems_status_code bsp_interrupt_raise(rtems_vector_number vector)
|
|
{
|
|
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
|
|
return RTEMS_UNSATISFIED;
|
|
}
|
|
|
|
rtems_status_code bsp_interrupt_clear(rtems_vector_number vector)
|
|
{
|
|
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
|
|
return RTEMS_UNSATISFIED;
|
|
}
|
|
|
|
rtems_status_code bsp_interrupt_vector_is_enabled(
|
|
rtems_vector_number vector,
|
|
bool *enabled
|
|
)
|
|
{
|
|
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
|
|
bsp_interrupt_assert(enabled != NULL);
|
|
*enabled = false;
|
|
return RTEMS_UNSATISFIED;
|
|
}
|
|
|
|
rtems_status_code bsp_interrupt_vector_enable( rtems_vector_number vector)
|
|
{
|
|
int base_index = get_siu_irq_base_index( vector);
|
|
|
|
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
|
|
|
|
if (is_siu_irq( vector)) {
|
|
rtems_interrupt_level level;
|
|
|
|
rtems_interrupt_disable( level);
|
|
|
|
switch (base_index) {
|
|
case BSP_PER_IRQ_LOWEST_OFFSET:
|
|
BSP_enable_per_irq_at_siu( vector);
|
|
break;
|
|
case BSP_MAIN_IRQ_LOWEST_OFFSET:
|
|
BSP_enable_main_irq_at_siu( vector);
|
|
break;
|
|
case BSP_CRIT_IRQ_LOWEST_OFFSET:
|
|
BSP_enable_crit_irq_at_siu( vector);
|
|
break;
|
|
default:
|
|
bsp_interrupt_assert(0);
|
|
break;
|
|
}
|
|
|
|
rtems_interrupt_enable( level);
|
|
}
|
|
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
/*
|
|
* This function disables a given siu interrupt
|
|
*/
|
|
rtems_status_code bsp_interrupt_vector_disable( rtems_vector_number vector)
|
|
{
|
|
int base_index = get_siu_irq_base_index( vector);
|
|
|
|
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
|
|
|
|
if (is_siu_irq( vector)) {
|
|
rtems_interrupt_level level;
|
|
|
|
rtems_interrupt_disable( level);
|
|
|
|
switch (base_index) {
|
|
case BSP_PER_IRQ_LOWEST_OFFSET:
|
|
BSP_disable_per_irq_at_siu( vector);
|
|
break;
|
|
case BSP_MAIN_IRQ_LOWEST_OFFSET:
|
|
BSP_disable_main_irq_at_siu( vector);
|
|
break;
|
|
case BSP_CRIT_IRQ_LOWEST_OFFSET:
|
|
BSP_disable_crit_irq_at_siu( vector);
|
|
break;
|
|
default:
|
|
bsp_interrupt_assert(0);
|
|
break;
|
|
}
|
|
|
|
rtems_interrupt_enable( level);
|
|
}
|
|
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
#if (BENCHMARK_IRQ_PROCESSING == 0)
|
|
void BSP_IRQ_Benchmarking_Reset( void)
|
|
{
|
|
}
|
|
void BSP_IRQ_Benchmarking_Report( void)
|
|
{
|
|
}
|
|
#else
|
|
#include <stdio.h>
|
|
uint64_t BSP_Starting_TBR;
|
|
uint64_t BSP_Total_in_ISR;
|
|
uint32_t BSP_ISR_Count;
|
|
uint32_t BSP_Worst_ISR;
|
|
|
|
#define BSP_COUNTED_IRQ 16
|
|
uint32_t BSP_ISR_Count_Per [BSP_COUNTED_IRQ + 1];
|
|
|
|
void BSP_IRQ_Benchmarking_Reset( void)
|
|
{
|
|
int i;
|
|
|
|
BSP_Starting_TBR = PPC_Get_timebase_register();
|
|
BSP_Total_in_ISR = 0;
|
|
BSP_ISR_Count = 0;
|
|
BSP_Worst_ISR = 0;
|
|
for (i = 0; i < BSP_COUNTED_IRQ; i++)
|
|
BSP_ISR_Count_Per [i] = 0;
|
|
}
|
|
|
|
static const char *u64tostring( char *buffer, uint64_t v)
|
|
{
|
|
sprintf( buffer, "%lld cycles %lld usecs", v, (v / 33));
|
|
return buffer;
|
|
}
|
|
|
|
void BSP_IRQ_Benchmarking_Report( void)
|
|
{
|
|
uint64_t now;
|
|
char buffer [96];
|
|
int i;
|
|
|
|
now = PPC_Get_timebase_register();
|
|
printk( "Started at: %s\n", u64tostring( buffer, BSP_Starting_TBR));
|
|
printk( "Current : %s\n", u64tostring( buffer, now));
|
|
printk( "System up : %s\n", u64tostring( buffer, now - BSP_Starting_TBR));
|
|
printk( "ISRs : %d\n", BSP_ISR_Count);
|
|
printk( "ISRs ran : %s\n", u64tostring( buffer, BSP_Total_in_ISR));
|
|
printk( "Worst ISR : %s\n", u64tostring( buffer, BSP_Worst_ISR));
|
|
for (i = 0; i < BSP_COUNTED_IRQ; i++)
|
|
printk( "IRQ %d: %d\n", i, BSP_ISR_Count_Per [i]);
|
|
printk( "Ticks : %d\n", Clock_driver_ticks);
|
|
}
|
|
#endif
|
|
|
|
static void dispatch(uint32_t irq, uint32_t offset, volatile uint32_t *maskreg)
|
|
{
|
|
#if (ALLOW_IRQ_NESTING == 1)
|
|
uint32_t msr;
|
|
uint32_t mask = *maskreg;
|
|
#endif
|
|
|
|
irq += offset;
|
|
|
|
#if (ALLOW_IRQ_NESTING == 1)
|
|
*maskreg = mask | irqMaskTable [irq];
|
|
/* Make sure that the write operation completed (cache inhibited area) */
|
|
*maskreg;
|
|
msr = ppc_external_exceptions_enable();
|
|
#endif
|
|
|
|
bsp_interrupt_handler_dispatch(irq);
|
|
|
|
#if (ALLOW_IRQ_NESTING == 1)
|
|
ppc_external_exceptions_disable(msr);
|
|
*maskreg = mask;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* High level IRQ handler called from shared_raw_irq_code_entry
|
|
*/
|
|
static int C_dispatch_irq_handler(BSP_Exception_frame *frame, unsigned excNum)
|
|
{
|
|
uint32_t irq;
|
|
uint32_t pmce;
|
|
|
|
#if (BENCHMARK_IRQ_PROCESSING == 1)
|
|
uint64_t start,
|
|
stop,
|
|
thisTime;
|
|
|
|
start = PPC_Get_timebase_register();
|
|
BSP_ISR_Count++;
|
|
if (excNum < BSP_COUNTED_IRQ)
|
|
BSP_ISR_Count_Per [excNum]++;
|
|
else
|
|
printk( "not counting %d\n", excNum);
|
|
#endif
|
|
|
|
/* get the content of main interrupt status register */
|
|
pmce = mpc5200.pmce;
|
|
|
|
/* critical interrupts are routed to the core_int, see premature
|
|
* initialization
|
|
*/
|
|
while ((pmce & (PMCE_CSE_STICKY | PMCE_MSE_STICKY)) != 0) {
|
|
/* first: check for critical interrupt sources (hierarchical order)
|
|
* -> HI_int indicates peripheral sources
|
|
*/
|
|
if ((pmce & PMCE_CSE_STICKY) != 0) {
|
|
/* get source of critical interrupt */
|
|
irq = PMCE_CSE_SOURCE(pmce);
|
|
|
|
switch (irq) {
|
|
/* peripheral HI_int interrupt source detected */
|
|
case 2:
|
|
/* check for valid peripheral interrupt source */
|
|
if ((pmce & PMCE_PSE_STICKY) != 0) {
|
|
/* get source of peripheral interrupt */
|
|
irq = PMCE_PSE_SOURCE(pmce);
|
|
|
|
dispatch(irq, BSP_PER_IRQ_LOWEST_OFFSET, &mpc5200.per_mask);
|
|
} else {
|
|
/* this case may not occur: no valid peripheral
|
|
* interrupt source */
|
|
printk( "No valid peripheral HI_int interrupt source\n");
|
|
}
|
|
break;
|
|
|
|
/* irq0, slice timer 1 or ccs wakeup detected */
|
|
case 0:
|
|
case 1:
|
|
case 3:
|
|
|
|
/* add proper offset for critical interrupts in the siu
|
|
* handler array */
|
|
irq += BSP_CRIT_IRQ_LOWEST_OFFSET;
|
|
|
|
/* Dispatch interrupt handlers */
|
|
bsp_interrupt_handler_dispatch( irq);
|
|
|
|
break;
|
|
|
|
default:
|
|
/* error: unknown interrupt source */
|
|
printk( "Unknown HI_int interrupt source\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* second: check for main interrupt sources (hierarchical order)
|
|
* -> LO_int indicates peripheral sources */
|
|
if ((pmce & PMCE_MSE_STICKY) != 0) {
|
|
/* get source of main interrupt */
|
|
irq = PMCE_MSE_SOURCE(pmce);
|
|
|
|
if (irq == 4) {
|
|
/* peripheral LO_int interrupt source detected */
|
|
/* check for valid peripheral interrupt source */
|
|
if ((pmce & PMCE_PSE_STICKY) != 0) {
|
|
/* get source of peripheral interrupt */
|
|
irq = PMCE_PSE_SOURCE(pmce);
|
|
|
|
dispatch(irq, BSP_PER_IRQ_LOWEST_OFFSET, &mpc5200.per_mask);
|
|
} else {
|
|
/* this case may not occur: no valid peripheral
|
|
* interrupt source */
|
|
printk( "No valid peripheral LO_int interrupt source\n");
|
|
}
|
|
} else if (irq <= 16) {
|
|
/* irq1-3, RTC, GPIO, TMR0-7 detected (attention: slice timer
|
|
* 2 is always routed to SMI) */
|
|
dispatch(irq, BSP_MAIN_IRQ_LOWEST_OFFSET, &mpc5200.crit_pri_main_mask);
|
|
} else {
|
|
/* error: unknown interrupt source */
|
|
printk( "Unknown peripheral LO_int interrupt source\n");
|
|
}
|
|
}
|
|
|
|
/* force re-evaluation of interrupts */
|
|
mpc5200.pmce = PMCE_CSE_STICKY | PMCE_MSE_STICKY | PMCE_PSE_STICKY;
|
|
|
|
/* get the content of main interrupt status register */
|
|
pmce = mpc5200.pmce;
|
|
}
|
|
|
|
#if (BENCHMARK_IRQ_PROCESSING == 1)
|
|
stop = PPC_Get_timebase_register();
|
|
thisTime = stop - start;
|
|
BSP_Total_in_ISR += thisTime;
|
|
if (thisTime > BSP_Worst_ISR)
|
|
BSP_Worst_ISR = thisTime;
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* setup irqMaskTable to support a priorized/nested interrupt environment
|
|
*/
|
|
static void setup_irqMaskTable( void)
|
|
{
|
|
rtems_irq_prio prio = 0;
|
|
uint32_t i = 0,
|
|
j = 0,
|
|
mask = 0;
|
|
|
|
/* set up the priority dependent masks for peripheral interrupts */
|
|
for (i = BSP_PER_IRQ_LOWEST_OFFSET; i <= BSP_PER_IRQ_MAX_OFFSET; i++) {
|
|
prio = irqPrioTable [i];
|
|
mask = 0;
|
|
|
|
for (j = BSP_PER_IRQ_LOWEST_OFFSET; j <= BSP_PER_IRQ_MAX_OFFSET; j++) {
|
|
if (prio > irqPrioTable [j]) {
|
|
mask |= (1 << (31 - j + BSP_PER_IRQ_LOWEST_OFFSET));
|
|
}
|
|
|
|
if ((prio == irqPrioTable [j]) && (j >= i)) {
|
|
mask |= (1 << (31 - j + BSP_PER_IRQ_LOWEST_OFFSET));
|
|
}
|
|
}
|
|
|
|
irqMaskTable [i] = mask;
|
|
}
|
|
|
|
/* set up the priority dependent masks for main interrupts */
|
|
for (i = BSP_MAIN_IRQ_LOWEST_OFFSET; i <= BSP_MAIN_IRQ_MAX_OFFSET; i++) {
|
|
prio = irqPrioTable [i];
|
|
mask = 0;
|
|
|
|
for (j = BSP_MAIN_IRQ_LOWEST_OFFSET; j <= BSP_MAIN_IRQ_MAX_OFFSET; j++) {
|
|
if (prio > irqPrioTable [j]) {
|
|
mask |= (1 << (16 - j + BSP_MAIN_IRQ_LOWEST_OFFSET));
|
|
}
|
|
|
|
if ((prio == irqPrioTable [j]) && (j >= i)) {
|
|
mask |= (1 << (16 - j + BSP_MAIN_IRQ_LOWEST_OFFSET));
|
|
}
|
|
}
|
|
|
|
irqMaskTable [i] = mask;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Initialize MPC5x00 SIU interrupt management
|
|
*/
|
|
static void BSP_SIU_irq_init( void)
|
|
{
|
|
|
|
/* disable all peripheral interrupts */
|
|
mpc5200.per_mask = 0xFFFFFC00;
|
|
|
|
/* peripheral interrupt priorities according to reset value */
|
|
mpc5200.per_pri_1 = 0xF0000000;
|
|
mpc5200.per_pri_2 = 0x00000000;
|
|
mpc5200.per_pri_3 = 0x00000000;
|
|
|
|
/* disable external interrupts IRQ0-4 / critical interrupts are routed to core_int */
|
|
mpc5200.ext_en_type = 0x0F000001;
|
|
|
|
/* disable main interrupts / crit. int. priorities according to reset values */
|
|
mpc5200.crit_pri_main_mask = 0x0001FFFF;
|
|
|
|
/* main priorities according to reset value */
|
|
mpc5200.main_pri_1 = 0;
|
|
mpc5200.main_pri_2 = 0;
|
|
|
|
/* reset all status indicators */
|
|
mpc5200.csa = 0x0001FFFF;
|
|
mpc5200.msa = 0x0001FFFF;
|
|
mpc5200.psa = 0x003FFFFF;
|
|
mpc5200.psa_be = 0x03000000;
|
|
|
|
setup_irqMaskTable();
|
|
}
|
|
|
|
void bsp_interrupt_facility_initialize( void)
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
BSP_SIU_irq_init();
|
|
|
|
/* Install exception handler */
|
|
sc = ppc_exc_set_handler( ASM_EXT_VECTOR, C_dispatch_irq_handler);
|
|
_Assert_Unused_variable_equals( sc, RTEMS_SUCCESSFUL);
|
|
sc = ppc_exc_set_handler( ASM_E300_SYSMGMT_VECTOR, C_dispatch_irq_handler);
|
|
_Assert_Unused_variable_equals( sc, RTEMS_SUCCESSFUL);
|
|
}
|
|
|
|
void bsp_interrupt_handler_default( rtems_vector_number vector)
|
|
{
|
|
if (vector != BSP_DECREMENTER) {
|
|
printk( "Spurious interrupt: 0x%08" PRIx32 "\n", vector);
|
|
}
|
|
}
|