diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-23 09:50:39 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-23 15:18:44 +0200 |
commit | 8f8ccee0d9e1c3adfb1de484f26f6d9f6ff08708 (patch) | |
tree | 5dc76f7a4527b0a500fbf5ee91486b2780e47a1a /bsps | |
parent | bsps: Move SPI drivers to bsps (diff) | |
download | rtems-8f8ccee0d9e1c3adfb1de484f26f6d9f6ff08708.tar.bz2 |
bsps: Move interrupt controller support to bsps
This patch is a part of the BSP source reorganization.
Update #3285.
Diffstat (limited to 'bsps')
68 files changed, 13172 insertions, 0 deletions
diff --git a/bsps/arm/beagle/irq/irq.c b/bsps/arm/beagle/irq/irq.c new file mode 100644 index 0000000000..2fa1a5b0f0 --- /dev/null +++ b/bsps/arm/beagle/irq/irq.c @@ -0,0 +1,144 @@ +/** + * @file + * + * @ingroup bsp_interrupt + * @ingroup arm_beagle + * + * @brief Interrupt support. + */ + +/* + * Copyright (c) 2014 Ben Gras <beng@shrike-systems.com>. 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 <bsp.h> +#include <bsp/irq-generic.h> +#include <bsp/linker-symbols.h> +#include <bsp/fatal.h> + +#include <rtems/score/armv4.h> + +#include <libcpu/arm-cp15.h> + +struct omap_intr +{ + uint32_t base; + int size; +}; + +#if IS_DM3730 +static struct omap_intr omap_intr = { + .base = OMAP3_DM37XX_INTR_BASE, + .size = 0x1000, +}; +#endif + +#if IS_AM335X +static struct omap_intr omap_intr = { + .base = OMAP3_AM335X_INTR_BASE, + .size = 0x1000, +}; +#endif + +/* Enables interrupts at the Interrupt Controller side. */ +static inline void omap_irq_ack(void) +{ + mmio_write(omap_intr.base + OMAP3_INTCPS_CONTROL, OMAP3_INTR_NEWIRQAGR); + + /* Flush data cache to make sure all the previous writes are done + before re-enabling interrupts. */ + flush_data_cache(); +} + +void bsp_interrupt_dispatch(void) +{ + const uint32_t reg = mmio_read(omap_intr.base + OMAP3_INTCPS_SIR_IRQ); + + if ((reg & OMAP3_INTR_SPURIOUSIRQ_MASK) != OMAP3_INTR_SPURIOUSIRQ_MASK) { + const rtems_vector_number irq = reg & OMAP3_INTR_ACTIVEIRQ_MASK; + + bsp_interrupt_handler_dispatch(irq); + } else { + /* Ignore spurious interrupts. We'll still ACK it so new interrupts + can be generated. */ + } + + omap_irq_ack(); +} + +/* There are 4 32-bit interrupt mask registers for a total of 128 interrupts. + The IRQ number tells us which register to use. */ +static uint32_t omap_get_mir_reg(rtems_vector_number vector, uint32_t *const mask) +{ + uint32_t mir_reg; + + /* Select which bit to set/clear in the MIR register. */ + *mask = 1ul << (vector % 32u); + + if (vector < 32u) { + mir_reg = OMAP3_INTCPS_MIR0; + } else if (vector < 64u) { + mir_reg = OMAP3_INTCPS_MIR1; + } else if (vector < 96u) { + mir_reg = OMAP3_INTCPS_MIR2; + } else if (vector < 128u) { + mir_reg = OMAP3_INTCPS_MIR3; + } else { + /* Invalid IRQ number. This should never happen. */ + bsp_fatal(0); + } + + return mir_reg; +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + uint32_t mask, cur; + uint32_t mir_reg = omap_get_mir_reg(vector, &mask); + + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + cur = mmio_read(omap_intr.base + mir_reg); + mmio_write(omap_intr.base + mir_reg, cur & ~mask); + flush_data_cache(); +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + uint32_t mask, cur; + uint32_t mir_reg = omap_get_mir_reg(vector, &mask); + + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + cur = mmio_read(omap_intr.base + mir_reg); + mmio_write(omap_intr.base + mir_reg, cur | mask); + flush_data_cache(); +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + int i; + uint32_t intc_ilrx; + + /* AM335X TRM 6.2.1 Initialization Sequence */ + mmio_write(omap_intr.base + OMAP3_INTCPS_SYSCONFIG, OMAP3_SYSCONFIG_AUTOIDLE); + mmio_write(omap_intr.base + OMAP3_INTCPS_IDLE, 0); + /* priority 0 to all IRQs */ + for(intc_ilrx = 0x100; intc_ilrx <= 0x2fc; intc_ilrx += 4) { + mmio_write(omap_intr.base + intc_ilrx, 0); + } + + /* Mask all interrupts */ + for(i = BSP_INTERRUPT_VECTOR_MIN; i <= BSP_INTERRUPT_VECTOR_MAX; i++) + bsp_interrupt_vector_disable(i); + + /* Install generic interrupt handler */ + arm_cp15_set_exception_handler(ARM_EXCEPTION_IRQ, _ARMV4_Exception_interrupt); + arm_cp15_set_vector_base_address(bsp_vector_table_begin); + + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/arm/csb336/irq/irq.c b/bsps/arm/csb336/irq/irq.c new file mode 100644 index 0000000000..e5887b9717 --- /dev/null +++ b/bsps/arm/csb336/irq/irq.c @@ -0,0 +1,51 @@ +/* + * Motorola MC9328MXL Interrupt handler + * + * Copyright (c) 2010 embedded brains GmbH. + * + * Copyright (c) 2004 by Jay Monkman <jtm@lopingdog.com> + * + * 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 <rtems/score/armv4.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> + +#include <mc9328mxl.h> + +void bsp_interrupt_dispatch(void) +{ + + rtems_vector_number vector = MC9328MXL_AITC_NIVECSR >> 16; + + bsp_interrupt_handler_dispatch(vector); +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + if (vector < MC9328MXL_NUM_INTS) + MC9328MXL_AITC_INTENNUM = vector; +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + if (vector < MC9328MXL_NUM_INTS) + MC9328MXL_AITC_INTDISNUM = vector; +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + + _CPU_ISR_install_vector(ARM_EXCEPTION_IRQ, _ARMV4_Exception_interrupt, NULL); + + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/arm/csb337/irq/irq.c b/bsps/arm/csb337/irq/irq.c new file mode 100644 index 0000000000..95e93845b9 --- /dev/null +++ b/bsps/arm/csb337/irq/irq.c @@ -0,0 +1,56 @@ +/* + * Atmel AT91RM9200 Interrupt handler + * + * Copyright (c) 2010 embedded brains GmbH. + * + * Copyright (c) 2004 by Jay Monkman <jtm@lopingdog.com> + * + * 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 <rtems/score/armv4.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> + +#include <at91rm9200.h> + +void bsp_interrupt_dispatch(void) +{ + rtems_vector_number vector = AIC_CTL_REG(AIC_IVR); + + bsp_interrupt_handler_dispatch(vector); + + AIC_CTL_REG(AIC_EOICR) = 0; +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + AIC_CTL_REG(AIC_IECR) = 1 << vector; +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + AIC_CTL_REG(AIC_IDCR) = 1 << vector; +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + unsigned long i = 0; + + for (i = 0; i < 32; ++i) { + AIC_SVR_REG(i<<2) = i; + } + + /* disable all interrupts */ + AIC_CTL_REG(AIC_IDCR) = 0xffffffff; + + _CPU_ISR_install_vector(ARM_EXCEPTION_IRQ, _ARMV4_Exception_interrupt, NULL); + + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/arm/edb7312/irq/bsp_irq_asm.S b/bsps/arm/edb7312/irq/bsp_irq_asm.S new file mode 100644 index 0000000000..c48466967b --- /dev/null +++ b/bsps/arm/edb7312/irq/bsp_irq_asm.S @@ -0,0 +1,323 @@ +/* + * Cirrus EP7312 Intererrupt handler + */ + +/* + * Copyright (c) 2002 by Jay Monkman <jtm@smoothsmoothie.com> + * + * Copyright (c) 2002 by Charlie Steader <charlies@poliac.com> + * + * 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. +*/ + +#define __asm__ +#include <bsp.h> +#include <bsp/irq.h> + + .extern edb7312_interrupt_dispatch + +/* + * Function to obtain, execute an IT handler and acknowledge the IT + */ + + .globl bsp_interrupt_dispatch +bsp_interrupt_dispatch : +/* + * Look at interrupt status register to determine source. + * From source, determine offset into expanded vector table + * and load handler address into r0. + */ + + ldr r1, =0x80000000 /* close to interrupt status/mask registers 1 */ + ldr r2, =0x80001000 /* close to interrupt status/mask registers 2 */ + ldr r3, =0x80002000 /* close to interrupt status/mask registers 3 */ + + stmdb sp!,{r4, r5, r6} + +/* + * INTSR3 + */ +check_dai: + ldr r4, [r3, #0x240] + ldr r5, [r3, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ + tst r6, #0x0001 + beq check_extfiq + mov r0, #BSP_DAIINT + b get_handler + +/* + * INTSR1 + */ +check_extfiq: + ldr r4, [r1, #0x240] + ldr r5, [r1, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ + tst r6, #0x0001 + beq check_bl + mov r0, #BSP_EXTFIQ + b get_handler + +check_bl: +#if 0 +MUST REMEMBER TO UNCOMMENT IF THIS HANDLER MOVES + ldr r4, [r1, #0x240] + ldr r5, [r1, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ +#endif + tst r6, #0x0002 + beq check_we + mov r0, #BSP_BLINT + b get_handler + +check_we: +#if 0 +MUST REMEMBER TO UNCOMMENT IF THIS HANDLER MOVES + ldr r4, [r1, #0x240] + ldr r5, [r1, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ +#endif + tst r6, #0x0004 + beq check_mc + mov r0, #BSP_WEINT + b get_handler + +check_mc: +#if 0 +MUST REMEMBER TO UNCOMMENT IF THIS HANDLER MOVES + ldr r4, [r1, #0x240] + ldr r5, [r1, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ +#endif + tst r6, #0x0008 + beq check_cs + mov r0, #BSP_MCINT + b get_handler + +check_cs: +#if 0 +MUST REMEMBER TO UNCOMMENT IF THIS HANDLER MOVES + ldr r4, [r1, #0x240] + ldr r5, [r1, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ +#endif + tst r6, #0x0010 + beq check_e1 + mov r0, #BSP_CSINT + b get_handler + +check_e1: +#if 0 +MUST REMEMBER TO UNCOMMENT IF THIS HANDLER MOVES + ldr r4, [r1, #0x240] + ldr r5, [r1, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ +#endif + tst r6, #0x0020 + beq check_e2 + mov r0, #BSP_EINT1 + b get_handler + +check_e2: +#if 0 +MUST REMEMBER TO UNCOMMENT IF THIS HANDLER MOVES + ldr r4, [r1, #0x240] + ldr r5, [r1, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ +#endif + tst r6, #0x0040 + beq check_e3 + mov r0, #BSP_EINT2 + b get_handler + +check_e3: +#if 0 +MUST REMEMBER TO UNCOMMENT IF THIS HANDLER MOVES + ldr r4, [r1, #0x240] + ldr r5, [r1, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ +#endif + tst r6, #0x0080 + beq check_tc1 + mov r0, #BSP_EINT3 + b get_handler + +check_tc1: +#if 0 +MUST REMEMBER TO UNCOMMENT IF THIS HANDLER MOVES + ldr r4, [r1, #0x240] + ldr r5, [r1, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ +#endif + tst r6, #0x0100 + beq check_tc2 + mov r0, #BSP_TC1OI + b get_handler + +check_tc2: +#if 0 +MUST REMEMBER TO UNCOMMENT IF THIS HANDLER MOVES + ldr r4, [r1, #0x240] + ldr r5, [r1, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ +#endif + tst r6, #0x0200 + beq check_rtc + mov r0, #BSP_TC2OI + b get_handler + +check_rtc: +#if 0 +MUST REMEMBER TO UNCOMMENT IF THIS HANDLER MOVES + ldr r4, [r1, #0x240] + ldr r5, [r1, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ +#endif + tst r6, #0x0400 + beq check_tick + mov r0, #BSP_RTCMI + b get_handler + +check_tick: +#if 0 +MUST REMEMBER TO UNCOMMENT IF THIS HANDLER MOVES + ldr r4, [r1, #0x240] + ldr r5, [r1, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ +#endif + tst r6, #0x0800 + beq check_utx1 + mov r0, #BSP_TINT + b get_handler + +check_utx1: +#if 0 +MUST REMEMBER TO UNCOMMENT IF THIS HANDLER MOVES + ldr r4, [r1, #0x240] + ldr r5, [r1, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ +#endif + tst r6, #0x1000 + beq check_urx1 + mov r0, #BSP_UTXINT1 + b get_handler + +check_urx1: +#if 0 +MUST REMEMBER TO UNCOMMENT IF THIS HANDLER MOVES + ldr r4, [r1, #0x240] + ldr r5, [r1, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ +#endif + tst r6, #0x2000 + beq check_ums + mov r0, #BSP_URXINT1 + b get_handler + +check_ums: +#if 0 +MUST REMEMBER TO UNCOMMENT IF THIS HANDLER MOVES + ldr r4, [r1, #0x240] + ldr r5, [r1, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ +#endif + tst r6, #0x4000 + beq check_sse + mov r0, #BSP_UMSINT + b get_handler + +check_sse: +#if 0 +MUST REMEMBER TO UNCOMMENT IF THIS HANDLER MOVES + ldr r4, [r1, #0x240] + ldr r5, [r1, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ +#endif + tst r6, #0x8000 + beq check_kbd + mov r0, #BSP_SSEOTI + b get_handler + +/* + * INTSR2 + */ +check_kbd: + ldr r4, [r2, #0x240] + ldr r5, [r2, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ + tst r6, #0x0001 + beq check_ss2rx + mov r0, #BSP_KBDINT + b get_handler + +check_ss2rx: +#if 0 +MUST REMEMBER TO UNCOMMENT IF THIS HANDLER MOVES + ldr r4, [r2, #0x240] + ldr r5, [r2, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ +#endif + tst r6, #0x0002 + beq check_ss2tx + mov r0, #BSP_SS2RX + b get_handler + +check_ss2tx: +#if 0 +MUST REMEMBER TO UNCOMMENT IF THIS HANDLER MOVES + ldr r4, [r2, #0x240] + ldr r5, [r2, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ +#endif + tst r6, #0x0004 + beq check_utx2 + mov r0, #BSP_SS2TX + b get_handler + +check_utx2: +#if 0 +MUST REMEMBER TO UNCOMMENT IF THIS HANDLER MOVES + ldr r4, [r2, #0x240] + ldr r5, [r2, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ +#endif + tst r6, #0x1000 + beq check_urx2 + mov r0, #BSP_UTXINT2 + b get_handler + +check_urx2: +#if 0 +MUST REMEMBER TO UNCOMMENT IF THIS HANDLER MOVES + ldr r4, [r2, #0x240] + ldr r5, [r2, #0x280] + and r6, r4, r5 /* only look at interrupts which are enabled */ +#endif + tst r6, #0x2000 + beq IRQ_NoInterrupt + mov r0, #BSP_URXINT2 + b get_handler + +get_handler: + + ldmia sp!,{r4, r5, r6} + + /* + * re-enable interrupts at processor level as the current + * interrupt source is now masked via VEGA logic + */ +/* + mrs r1, cpsr + and r1, r1, #0xFFFFFF3F + msr cpsr, r1 +*/ + + stmdb sp!,{lr} + bl edb7312_interrupt_dispatch + ldmia sp!,{lr} + +IRQ_NoInterrupt: + /* return to the "main" interrupt handler */ + mov pc, lr diff --git a/bsps/arm/edb7312/irq/irq.c b/bsps/arm/edb7312/irq/irq.c new file mode 100644 index 0000000000..1d9151a1bd --- /dev/null +++ b/bsps/arm/edb7312/irq/irq.c @@ -0,0 +1,180 @@ +/* + * Cirrus EP7312 Intererrupt handler + */ + +/* + * Copyright (c) 2010 embedded brains GmbH. + * + * Copyright (c) 2002 by Jay Monkman <jtm@smoothsmoothie.com> + * + * Copyright (c) 2002 by Charlie Steader <charlies@poliac.com> + * + * 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 <rtems/score/armv4.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> + +#include <ep7312.h> + +void edb7312_interrupt_dispatch(rtems_vector_number vector) +{ + bsp_interrupt_handler_dispatch(vector); +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + if(vector >= BSP_EXTFIQ && vector <= BSP_SSEOTI) + { + /* interrupt managed by INTMR1 and INTSR1 */ + *EP7312_INTMR1 |= (1 << vector); + } + else if(vector >= BSP_KBDINT && vector <= BSP_SS2TX) + { + /* interrupt managed by INTMR2 and INTSR2 */ + *EP7312_INTMR2 |= (1 << (vector - 16)); + } + else if(vector >= BSP_UTXINT2 && vector <= BSP_URXINT2) + { + /* interrupt managed by INTMR2 and INTSR2 */ + *EP7312_INTMR2 |= (1 << (vector - 7)); + } + else if(vector == BSP_DAIINT) + { + /* interrupt managed by INTMR3 and INTSR3 */ + *EP7312_INTMR3 |= (1 << (vector - 21)); + } +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + if(vector >= BSP_EXTFIQ && vector <= BSP_SSEOTI) + { + /* interrupt managed by INTMR1 and INTSR1 */ + *EP7312_INTMR1 &= ~(1 << vector); + } + else if(vector >= BSP_KBDINT && vector <= BSP_SS2TX) + { + /* interrupt managed by INTMR2 and INTSR2 */ + *EP7312_INTMR2 &= ~(1 << (vector - 16)); + } + else if(vector >= BSP_UTXINT2 && vector <= BSP_URXINT2) + { + /* interrupt managed by INTMR2 and INTSR2 */ + *EP7312_INTMR2 &= ~(1 << (vector - 7)); + } + else if(vector == BSP_DAIINT) + { + /* interrupt managed by INTMR3 and INTSR3 */ + *EP7312_INTMR3 &= ~(1 << (vector - 21)); + } +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + uint32_t int_stat = 0; + + /* mask all interrupts */ + *EP7312_INTMR1 = 0x0; + *EP7312_INTMR2 = 0x0; + *EP7312_INTMR3 = 0x0; + + /* clear all pending interrupt status' */ + int_stat = *EP7312_INTSR1; + if(int_stat & EP7312_INTR1_EXTFIQ) + { + } + if(int_stat & EP7312_INTR1_BLINT) + { + *EP7312_BLEOI = 0xFFFFFFFF; + } + if(int_stat & EP7312_INTR1_WEINT) + { + *EP7312_TEOI = 0xFFFFFFFF; + } + if(int_stat & EP7312_INTR1_MCINT) + { + } + if(int_stat & EP7312_INTR1_CSINT) + { + *EP7312_COEOI = 0xFFFFFFFF; + } + if(int_stat & EP7312_INTR1_EINT1) + { + } + if(int_stat & EP7312_INTR1_EINT2) + { + } + if(int_stat & EP7312_INTR1_EINT3) + { + } + if(int_stat & EP7312_INTR1_TC1OI) + { + *EP7312_TC1EOI = 0xFFFFFFFF; + } + if(int_stat & EP7312_INTR1_TC2OI) + { + *EP7312_TC2EOI = 0xFFFFFFFF; + } + if(int_stat & EP7312_INTR1_RTCMI) + { + *EP7312_RTCEOI = 0xFFFFFFFF; + } + if(int_stat & EP7312_INTR1_TINT) + { + *EP7312_TEOI = 0xFFFFFFFF; + } + if(int_stat & EP7312_INTR1_URXINT1) + { + } + if(int_stat & EP7312_INTR1_UTXINT1) + { + } + if(int_stat & EP7312_INTR1_UMSINT) + { + *EP7312_UMSEOI = 0xFFFFFFFF; + } + if(int_stat & EP7312_INTR1_SSEOTI) + { + *EP7312_SYNCIO; + } + int_stat = *EP7312_INTSR1; + + int_stat = *EP7312_INTSR2; + if(int_stat & EP7312_INTR2_KBDINT) + { + *EP7312_KBDEOI = 0xFFFFFFFF; + } + if(int_stat & EP7312_INTR2_SS2RX) + { + } + if(int_stat & EP7312_INTR2_SS2TX) + { + } + if(int_stat & EP7312_INTR2_URXINT2) + { + } + if(int_stat & EP7312_INTR2_UTXINT2) + { + } + int_stat = *EP7312_INTSR2; + + int_stat = *EP7312_INTSR3; + if(int_stat & EP7312_INTR2_DAIINT) + { + } + int_stat = *EP7312_INTSR3; + + _CPU_ISR_install_vector(ARM_EXCEPTION_IRQ, _ARMV4_Exception_interrupt, NULL); + + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/arm/gdbarmsim/irq/irq-dispatch.c b/bsps/arm/gdbarmsim/irq/irq-dispatch.c new file mode 100644 index 0000000000..f045fb8149 --- /dev/null +++ b/bsps/arm/gdbarmsim/irq/irq-dispatch.c @@ -0,0 +1,50 @@ +/** + * @file + * + * @ingroup bsp_interrupt + * + * @brief GDB ARM Simulator interrupt support. + */ + +/* + * Copyright (c) 2008-2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * 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 <rtems/score/armv4.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> + +#ifdef ARM_MULTILIB_ARCH_V4 + +void bsp_interrupt_dispatch(void) +{ + /* Read current vector number */ + /* rtems_vector_number vector = VICVectAddr; */ + rtems_vector_number vector = 0; + + /* Enable interrupts in program status register */ + uint32_t psr = _ARMV4_Status_irq_enable(); + + /* Dispatch interrupt handlers */ + bsp_interrupt_handler_dispatch(vector); + + /* Restore program status register */ + _ARMV4_Status_restore(psr); + + /* Acknowledge interrupt */ + //VICVectAddr = 0; +} + +#endif /* ARM_MULTILIB_ARCH_V4 */ diff --git a/bsps/arm/gdbarmsim/irq/irq.c b/bsps/arm/gdbarmsim/irq/irq.c new file mode 100644 index 0000000000..886f928d2d --- /dev/null +++ b/bsps/arm/gdbarmsim/irq/irq.c @@ -0,0 +1,71 @@ +/** + * @file + * + * @ingroup bsp_interrupt + * + * @brief GDB ARM Simulator interrupt support. + */ + +/* + * Copyright (c) 2008-2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * 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 <rtems/score/armv4.h> +#include <rtems/score/armv7m.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> +#include <bsp/linker-symbols.h> + +/* + * Prototypes + */ +void lpc24xx_irq_set_priority(rtems_vector_number, unsigned); +unsigned lpc24xx_irq_get_priority(rtems_vector_number); + +static inline bool lpc24xx_irq_is_valid(rtems_vector_number vector) +{ + return vector <= BSP_INTERRUPT_VECTOR_MAX; +} + +void lpc24xx_irq_set_priority(rtems_vector_number vector, unsigned priority) +{ +} + +unsigned lpc24xx_irq_get_priority(rtems_vector_number vector) +{ + return 0; /* bogus value to avoid warning */ +} + +#ifdef ARM_MULTILIB_ARCH_V4 + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + /* Install the IRQ exception handler */ + _CPU_ISR_install_vector(ARM_EXCEPTION_IRQ, _ARMV4_Exception_interrupt, NULL); + + return RTEMS_SUCCESSFUL; +} + +#endif /* ARM_MULTILIB_ARCH_V4 */ diff --git a/bsps/arm/gumstix/irq/irq.c b/bsps/arm/gumstix/irq/irq.c new file mode 100644 index 0000000000..425795b165 --- /dev/null +++ b/bsps/arm/gumstix/irq/irq.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2010 embedded brains GmbH. + * + * PXA255 Interrupt handler by Yang Xi <hiyangxi@gmail.com> + * Copyright (c) 2004 by Jay Monkman <jtm@lopingdog.com> + * + * 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 <rtems/score/armv4.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> + +#include <pxa255.h> + +void bsp_interrupt_dispatch(void) +{ + rtems_vector_number vector = 31 - __builtin_clz(XSCALE_INT_ICIP); + + bsp_interrupt_handler_dispatch(vector); +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + XSCALE_INT_ICMR |= 1 << vector; +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + XSCALE_INT_ICMR &= ~(1 << vector); +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + /* disable all interrupts */ + XSCALE_INT_ICMR = 0x0; + + /* Direct the interrupt to IRQ*/ + XSCALE_INT_ICLR = 0x0; + + /* Install the IRQ exception handler */ + _CPU_ISR_install_vector(ARM_EXCEPTION_IRQ, _ARMV4_Exception_interrupt, NULL); + + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/arm/lpc176x/irq/irq.c b/bsps/arm/lpc176x/irq/irq.c new file mode 100644 index 0000000000..e05fd59e6c --- /dev/null +++ b/bsps/arm/lpc176x/irq/irq.c @@ -0,0 +1,75 @@ +/** + * @file + * + * @ingroup bsp_interrupt + * + * @brief LPC176X interrupt support. + */ + +/* + * Copyright (c) 2008-2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * 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 <rtems/score/armv4.h> +#include <rtems/score/armv7m.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> +#include <bsp/lpc176x.h> +#include <bsp/linker-symbols.h> + +/** + * @brief Checks if the current interrupt vector length is valid or not. + * + * @param vector The current interrupt vector length. + * @return TRUE if valid. + * FALSE otherwise. + */ +static inline bool lpc176x_irq_is_valid( const rtems_vector_number vector ) +{ + return vector <= BSP_INTERRUPT_VECTOR_MAX; +} + +void lpc176x_irq_set_priority( + const rtems_vector_number vector, + unsigned priority +) +{ + if ( lpc176x_irq_is_valid( vector ) ) { + if ( priority > LPC176X_IRQ_PRIORITY_VALUE_MAX ) { + priority = LPC176X_IRQ_PRIORITY_VALUE_MAX; + } + + /* else implies that the priority is unlocked. Also, + there is nothing to do. */ + + _ARMV7M_NVIC_Set_priority( (int) vector, (int) ( priority << 3u ) ); + } + + /* else implies that the rtems vector number is invalid. Also, + there is nothing to do. */ +} + +unsigned lpc176x_irq_get_priority( const rtems_vector_number vector ) +{ + unsigned priority; + + if ( lpc176x_irq_is_valid( vector ) ) { + priority = (unsigned) ( _ARMV7M_NVIC_Get_priority( (int) vector ) >> 3u ); + } else { + priority = LPC176X_IRQ_PRIORITY_VALUE_MIN - 1u; + } + + return priority; +} diff --git a/bsps/arm/lpc24xx/irq/irq-dispatch.c b/bsps/arm/lpc24xx/irq/irq-dispatch.c new file mode 100644 index 0000000000..66d05fdf9d --- /dev/null +++ b/bsps/arm/lpc24xx/irq/irq-dispatch.c @@ -0,0 +1,50 @@ +/** + * @file + * + * @ingroup bsp_interrupt + * + * @brief LPC24XX interrupt support. + */ + +/* + * Copyright (c) 2008-2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * 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 <rtems/score/armv4.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> +#include <bsp/lpc24xx.h> + +#ifdef ARM_MULTILIB_ARCH_V4 + +void bsp_interrupt_dispatch(void) +{ + /* Read current vector number */ + rtems_vector_number vector = VICVectAddr; + + /* Enable interrupts in program status register */ + uint32_t psr = _ARMV4_Status_irq_enable(); + + /* Dispatch interrupt handlers */ + bsp_interrupt_handler_dispatch(vector); + + /* Restore program status register */ + _ARMV4_Status_restore(psr); + + /* Acknowledge interrupt */ + VICVectAddr = 0; +} + +#endif /* ARM_MULTILIB_ARCH_V4 */ diff --git a/bsps/arm/lpc24xx/irq/irq.c b/bsps/arm/lpc24xx/irq/irq.c new file mode 100644 index 0000000000..7801c37843 --- /dev/null +++ b/bsps/arm/lpc24xx/irq/irq.c @@ -0,0 +1,120 @@ +/** + * @file + * + * @ingroup bsp_interrupt + * + * @brief LPC24XX interrupt support. + */ + +/* + * Copyright (c) 2008-2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * 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 <rtems/score/armv4.h> +#include <rtems/score/armv7m.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> +#include <bsp/lpc24xx.h> +#include <bsp/linker-symbols.h> + +static inline bool lpc24xx_irq_is_valid(rtems_vector_number vector) +{ + return vector <= BSP_INTERRUPT_VECTOR_MAX; +} + +void lpc24xx_irq_set_priority(rtems_vector_number vector, unsigned priority) +{ + if (lpc24xx_irq_is_valid(vector)) { + if (priority > LPC24XX_IRQ_PRIORITY_VALUE_MAX) { + priority = LPC24XX_IRQ_PRIORITY_VALUE_MAX; + } + + #ifdef ARM_MULTILIB_ARCH_V4 + VICVectPriorityBase [vector] = priority; + #else + _ARMV7M_NVIC_Set_priority((int) vector, (int) (priority << 3)); + #endif + } +} + +unsigned lpc24xx_irq_get_priority(rtems_vector_number vector) +{ + if (lpc24xx_irq_is_valid(vector)) { + #ifdef ARM_MULTILIB_ARCH_V4 + return VICVectPriorityBase [vector]; + #else + return (unsigned) (_ARMV7M_NVIC_Get_priority((int) vector) >> 3); + #endif + } else { + return LPC24XX_IRQ_PRIORITY_VALUE_MIN - 1U; + } +} + +#ifdef ARM_MULTILIB_ARCH_V4 + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + VICIntEnable = 1U << vector; +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + VICIntEnClear = 1U << vector; +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + volatile uint32_t *addr = VICVectAddrBase; + volatile uint32_t *prio = VICVectPriorityBase; + rtems_vector_number i = 0; + + /* Disable all interrupts */ + VICIntEnClear = 0xffffffff; + + /* Clear all software interrupts */ + VICSoftIntClear = 0xffffffff; + + /* Use IRQ category */ + VICIntSelect = 0; + + for (i = BSP_INTERRUPT_VECTOR_MIN; i <= BSP_INTERRUPT_VECTOR_MAX; ++i) { + /* Use the vector address register to store the vector number */ + addr [i] = i; + + /* Give vector lowest priority */ + prio [i] = 15; + } + + /* Reset priority mask register */ + VICSWPrioMask = 0xffff; + + /* Acknowledge interrupts for all priorities */ + for ( + i = LPC24XX_IRQ_PRIORITY_VALUE_MIN; + i <= LPC24XX_IRQ_PRIORITY_VALUE_MAX; + ++i + ) { + VICVectAddr = 0; + } + + /* Install the IRQ exception handler */ + _CPU_ISR_install_vector(ARM_EXCEPTION_IRQ, _ARMV4_Exception_interrupt, NULL); + + return RTEMS_SUCCESSFUL; +} + +#endif /* ARM_MULTILIB_ARCH_V4 */ diff --git a/bsps/arm/lpc32xx/irq/irq.c b/bsps/arm/lpc32xx/irq/irq.c new file mode 100755 index 0000000000..eac320000b --- /dev/null +++ b/bsps/arm/lpc32xx/irq/irq.c @@ -0,0 +1,344 @@ +/** + * @file + * + * @ingroup lpc32xx_interrupt + * + * @brief Interrupt support. + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * 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 <rtems/score/armv4.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> +#include <bsp/lpc32xx.h> +#include <bsp/linker-symbols.h> +#include <bsp/mmu.h> + +/* + * Mask out SIC 1 and 2 IRQ request. There is no need to mask out the FIQ, + * since a pending FIQ would be a fatal error. The default handler will be + * invoked in this case. + */ +#define LPC32XX_MIC_STATUS_MASK (~0x3U) + +typedef union { + struct { + uint32_t mic; + uint32_t sic_1; + uint32_t sic_2; + } field; + uint32_t fields_table [LPC32XX_IRQ_MODULE_COUNT]; +} lpc32xx_irq_fields; + +static uint8_t lpc32xx_irq_priority_table [LPC32XX_IRQ_COUNT]; + +static lpc32xx_irq_fields lpc32xx_irq_priority_masks [LPC32XX_IRQ_PRIORITY_COUNT]; + +static lpc32xx_irq_fields lpc32xx_irq_enable; + +static inline bool lpc32xx_irq_priority_is_valid(unsigned priority) +{ + return priority <= LPC32XX_IRQ_PRIORITY_LOWEST; +} + +#define LPC32XX_IRQ_BIT_OPS_DEFINE \ + unsigned bit = index & 0x1fU; \ + unsigned module = index >> 5 + +#define LPC32XX_IRQ_BIT_OPS_FOR_REG_DEFINE \ + LPC32XX_IRQ_BIT_OPS_DEFINE; \ + unsigned module_offset = module << 14; \ + volatile uint32_t *reg = (volatile uint32_t *) \ + ((volatile char *) &lpc32xx.mic + module_offset + register_offset) + +#define LPC32XX_IRQ_OFFSET_ER 0U +#define LPC32XX_IRQ_OFFSET_RSR 4U +#define LPC32XX_IRQ_OFFSET_SR 8U +#define LPC32XX_IRQ_OFFSET_APR 12U +#define LPC32XX_IRQ_OFFSET_ATR 16U +#define LPC32XX_IRQ_OFFSET_ITR 20U + +static inline bool lpc32xx_irq_is_bit_set_in_register(unsigned index, unsigned register_offset) +{ + LPC32XX_IRQ_BIT_OPS_FOR_REG_DEFINE; + + return *reg & (1U << bit); +} + +static inline void lpc32xx_irq_set_bit_in_register(unsigned index, unsigned register_offset) +{ + LPC32XX_IRQ_BIT_OPS_FOR_REG_DEFINE; + + *reg |= 1U << bit; +} + +static inline void lpc32xx_irq_clear_bit_in_register(unsigned index, unsigned register_offset) +{ + LPC32XX_IRQ_BIT_OPS_FOR_REG_DEFINE; + + *reg &= ~(1U << bit); +} + +static inline void lpc32xx_irq_set_bit_in_field(unsigned index, lpc32xx_irq_fields *fields) +{ + LPC32XX_IRQ_BIT_OPS_DEFINE; + + fields->fields_table [module] |= 1U << bit; +} + +static inline void lpc32xx_irq_clear_bit_in_field(unsigned index, lpc32xx_irq_fields *fields) +{ + LPC32XX_IRQ_BIT_OPS_DEFINE; + + fields->fields_table [module] &= ~(1U << bit); +} + +static inline unsigned lpc32xx_irq_get_index(uint32_t val) +{ + ARM_SWITCH_REGISTERS; + + __asm__ volatile ( + ARM_SWITCH_TO_ARM + "clz %[val], %[val]\n" + "rsb %[val], %[val], #31\n" + ARM_SWITCH_BACK + : [val] "=r" (val) ARM_SWITCH_ADDITIONAL_OUTPUT + : "[val]" (val) + ); + + return val; +} + +void lpc32xx_irq_set_priority(rtems_vector_number vector, unsigned priority) +{ + if (bsp_interrupt_is_valid_vector(vector)) { + rtems_interrupt_level level; + unsigned i = 0; + + if (priority > LPC32XX_IRQ_PRIORITY_LOWEST) { + priority = LPC32XX_IRQ_PRIORITY_LOWEST; + } + + lpc32xx_irq_priority_table [vector] = (uint8_t) priority; + + for (i = LPC32XX_IRQ_PRIORITY_HIGHEST; i <= priority; ++i) { + rtems_interrupt_disable(level); + lpc32xx_irq_clear_bit_in_field(vector, &lpc32xx_irq_priority_masks [i]); + rtems_interrupt_enable(level); + } + + for (i = priority + 1; i <= LPC32XX_IRQ_PRIORITY_LOWEST; ++i) { + rtems_interrupt_disable(level); + lpc32xx_irq_set_bit_in_field(vector, &lpc32xx_irq_priority_masks [i]); + rtems_interrupt_enable(level); + } + } +} + +unsigned lpc32xx_irq_get_priority(rtems_vector_number vector) +{ + if (bsp_interrupt_is_valid_vector(vector)) { + return lpc32xx_irq_priority_table [vector]; + } else { + return LPC32XX_IRQ_PRIORITY_LOWEST; + } +} + +void lpc32xx_irq_set_activation_polarity(rtems_vector_number vector, lpc32xx_irq_activation_polarity activation_polarity) +{ + if (bsp_interrupt_is_valid_vector(vector)) { + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + if (activation_polarity == LPC32XX_IRQ_ACTIVE_HIGH_OR_RISING_EDGE) { + lpc32xx_irq_set_bit_in_register(vector, LPC32XX_IRQ_OFFSET_APR); + } else { + lpc32xx_irq_clear_bit_in_register(vector, LPC32XX_IRQ_OFFSET_APR); + } + rtems_interrupt_enable(level); + } +} + +lpc32xx_irq_activation_polarity lpc32xx_irq_get_activation_polarity(rtems_vector_number vector) +{ + if (bsp_interrupt_is_valid_vector(vector)) { + if (lpc32xx_irq_is_bit_set_in_register(vector, LPC32XX_IRQ_OFFSET_APR)) { + return LPC32XX_IRQ_ACTIVE_HIGH_OR_RISING_EDGE; + } else { + return LPC32XX_IRQ_ACTIVE_LOW_OR_FALLING_EDGE; + } + } else { + return LPC32XX_IRQ_ACTIVE_LOW_OR_FALLING_EDGE; + } +} + +void lpc32xx_irq_set_activation_type(rtems_vector_number vector, lpc32xx_irq_activation_type activation_type) +{ + if (bsp_interrupt_is_valid_vector(vector)) { + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + if (activation_type == LPC32XX_IRQ_EDGE_SENSITIVE) { + lpc32xx_irq_set_bit_in_register(vector, LPC32XX_IRQ_OFFSET_ATR); + } else { + lpc32xx_irq_clear_bit_in_register(vector, LPC32XX_IRQ_OFFSET_ATR); + } + rtems_interrupt_enable(level); + } +} + +lpc32xx_irq_activation_type lpc32xx_irq_get_activation_type(rtems_vector_number vector) +{ + if (bsp_interrupt_is_valid_vector(vector)) { + if (lpc32xx_irq_is_bit_set_in_register(vector, LPC32XX_IRQ_OFFSET_ATR)) { + return LPC32XX_IRQ_EDGE_SENSITIVE; + } else { + return LPC32XX_IRQ_LEVEL_SENSITIVE; + } + } else { + return LPC32XX_IRQ_LEVEL_SENSITIVE; + } +} + +void bsp_interrupt_dispatch(void) +{ + uint32_t status = lpc32xx.mic.sr & LPC32XX_MIC_STATUS_MASK; + uint32_t er_mic = lpc32xx.mic.er; + uint32_t er_sic_1 = lpc32xx.sic_1.er; + uint32_t er_sic_2 = lpc32xx.sic_2.er; + uint32_t psr = 0; + lpc32xx_irq_fields *masks = NULL; + rtems_vector_number vector = 0; + unsigned priority = 0; + + if (status != 0) { + vector = lpc32xx_irq_get_index(status); + } else { + status = lpc32xx.sic_1.sr; + if (status != 0) { + vector = lpc32xx_irq_get_index(status) + LPC32XX_IRQ_MODULE_SIC_1; + } else { + status = lpc32xx.sic_2.sr; + if (status != 0) { + vector = lpc32xx_irq_get_index(status) + LPC32XX_IRQ_MODULE_SIC_2; + } else { + return; + } + } + } + + priority = lpc32xx_irq_priority_table [vector]; + + masks = &lpc32xx_irq_priority_masks [priority]; + + lpc32xx.mic.er = er_mic & masks->field.mic; + lpc32xx.sic_1.er = er_sic_1 & masks->field.sic_1; + lpc32xx.sic_2.er = er_sic_2 & masks->field.sic_2; + + psr = _ARMV4_Status_irq_enable(); + + bsp_interrupt_handler_dispatch(vector); + + _ARMV4_Status_restore(psr); + + lpc32xx.mic.er = er_mic & lpc32xx_irq_enable.field.mic; + lpc32xx.sic_1.er = er_sic_1 & lpc32xx_irq_enable.field.sic_1; + lpc32xx.sic_2.er = er_sic_2 & lpc32xx_irq_enable.field.sic_2; +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + rtems_interrupt_level level; + + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + rtems_interrupt_disable(level); + lpc32xx_irq_set_bit_in_register(vector, LPC32XX_IRQ_OFFSET_ER); + lpc32xx_irq_set_bit_in_field(vector, &lpc32xx_irq_enable); + rtems_interrupt_enable(level); +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + rtems_interrupt_level level; + + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + rtems_interrupt_disable(level); + lpc32xx_irq_clear_bit_in_field(vector, &lpc32xx_irq_enable); + lpc32xx_irq_clear_bit_in_register(vector, LPC32XX_IRQ_OFFSET_ER); + rtems_interrupt_enable(level); +} + +void lpc32xx_set_exception_handler( + Arm_symbolic_exception_name exception, + void (*handler)(void) +) +{ + if ((unsigned) exception < MAX_EXCEPTIONS) { + uint32_t *table = (uint32_t *) bsp_vector_table_begin + MAX_EXCEPTIONS; + + table [exception] = (uint32_t) handler; + + #ifndef LPC32XX_DISABLE_MMU + rtems_cache_flush_multiple_data_lines(table, 64); + rtems_cache_invalidate_multiple_instruction_lines(NULL, 64); + #endif + } +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + size_t i = 0; + + /* Set default priority */ + for (i = 0; i < LPC32XX_IRQ_COUNT; ++i) { + lpc32xx_irq_priority_table [i] = LPC32XX_IRQ_PRIORITY_LOWEST; + } + + /* Enable SIC 1 and 2 at all priorities */ + for (i = 0; i < LPC32XX_IRQ_PRIORITY_COUNT; ++i) { + lpc32xx_irq_priority_masks [i].field.mic = 0xc0000003; + } + + /* Disable all interrupts except SIC 1 and 2 */ + lpc32xx_irq_enable.field.sic_2 = 0x0; + lpc32xx_irq_enable.field.sic_1 = 0x0; + lpc32xx_irq_enable.field.mic = 0xc0000003; + lpc32xx.sic_1.er = 0x0; + lpc32xx.sic_2.er = 0x0; + lpc32xx.mic.er = 0xc0000003; + + /* Set interrupt types to IRQ */ + lpc32xx.mic.itr = 0x0; + lpc32xx.sic_1.itr = 0x0; + lpc32xx.sic_2.itr = 0x0; + + /* Set interrupt activation polarities */ + lpc32xx.mic.apr = 0x3ff0efe0; + lpc32xx.sic_1.apr = 0xfbd27184; + lpc32xx.sic_2.apr = 0x801810c0; + + /* Set interrupt activation types */ + lpc32xx.mic.atr = 0x0; + lpc32xx.sic_1.atr = 0x26000; + lpc32xx.sic_2.atr = 0x0; + + lpc32xx_set_exception_handler(ARM_EXCEPTION_IRQ, _ARMV4_Exception_interrupt); + + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/arm/raspberrypi/irq/irq.c b/bsps/arm/raspberrypi/irq/irq.c new file mode 100644 index 0000000000..5b10385bfe --- /dev/null +++ b/bsps/arm/raspberrypi/irq/irq.c @@ -0,0 +1,168 @@ +/** + * @file irq.c + * + * @ingroup raspberrypi_interrupt + * + * @brief Interrupt support. + */ + +/* + * Copyright (c) 2014 Andre Marques <andre.lousa.marques at gmail.com> + * + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * 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 <rtems/score/armv4.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> +#include <bsp/raspberrypi.h> +#include <bsp/linker-symbols.h> +#include <bsp/mmu.h> +#include <rtems/bspIo.h> +#include <strings.h> + +#ifdef RTEMS_SMP +#include <rtems/score/smp.h> +#include <rtems/score/smpimpl.h> +#endif + +typedef struct { + unsigned long enable_reg_addr; + unsigned long disable_reg_addr; +} bcm2835_irq_ctrl_reg_t; + +static const bcm2835_irq_ctrl_reg_t bcm2835_irq_ctrl_reg_table[] = { + { BCM2835_IRQ_ENABLE1, BCM2835_IRQ_DISABLE1 }, + { BCM2835_IRQ_ENABLE2, BCM2835_IRQ_DISABLE2 }, + { BCM2835_IRQ_ENABLE_BASIC, BCM2835_IRQ_DISABLE_BASIC } +}; + +static inline const bcm2835_irq_ctrl_reg_t * +bsp_vector_to_reg(rtems_vector_number vector) +{ + return bcm2835_irq_ctrl_reg_table + (vector >> 5); +} + +static inline uint32_t +bsp_vector_to_mask(rtems_vector_number vector) +{ + return 1 << (vector & 0x1f); +} + +static const int bcm2835_irq_speedup_table[] = +{ + /* 0 */ BCM2835_IRQ_ID_BASIC_BASE_ID + 0, + /* 1 */ BCM2835_IRQ_ID_BASIC_BASE_ID + 1, + /* 2 */ BCM2835_IRQ_ID_BASIC_BASE_ID + 2, + /* 3 */ BCM2835_IRQ_ID_BASIC_BASE_ID + 3, + /* 4 */ BCM2835_IRQ_ID_BASIC_BASE_ID + 4, + /* 5 */ BCM2835_IRQ_ID_BASIC_BASE_ID + 5, + /* 6 */ BCM2835_IRQ_ID_BASIC_BASE_ID + 6, + /* 7 */ BCM2835_IRQ_ID_BASIC_BASE_ID + 7, + /* 8 */ -1, /* One or more bits set in pending register 1 */ + /* 9 */ -2, /* One or more bits set in pending register 2 */ + /* 10 */ 7, /* GPU IRQ 7 */ + /* 11 */ 9, /* GPU IRQ 9 */ + /* 12 */ 10, /* GPU IRQ 10 */ + /* 13 */ 18, /* GPU IRQ 18 */ + /* 14 */ 19, /* GPU IRQ 19 */ + /* 15 */ 53, /* GPU IRQ 53 */ + /* 16 */ 54, /* GPU IRQ 54 */ + /* 17 */ 55, /* GPU IRQ 55 */ + /* 18 */ 56, /* GPU IRQ 56 */ + /* 19 */ 57, /* GPU IRQ 57 */ + /* 20 */ 62, /* GPU IRQ 62 */ +}; + +/* + * Define which basic peding register (BCM2835_IRQ_BASIC) bits + * should be processed through bcm2835_irq_speedup_table + */ + +#define BCM2835_IRQ_BASIC_SPEEDUP_USED_BITS 0x1ffcff + +/* + * Determine the source of the interrupt and dispatch the correct handler. + */ +void bsp_interrupt_dispatch(void) +{ + unsigned int pend; + unsigned int pend_bit; + + rtems_vector_number vector = 255; + +#ifdef RTEMS_SMP + uint32_t cpu_index_self = _SMP_Get_current_processor(); + uint32_t local_source = BCM2835_REG(BCM2836_IRQ_SOURCE_REG(cpu_index_self)); + + if ( local_source & BCM2836_IRQ_SOURCE_MBOX3 ) { + /* reset mailbox 3 contents to zero */ + BCM2835_REG(BCM2836_MAILBOX_3_READ_CLEAR_BASE + 0x10 * cpu_index_self) = 0xffffffff; + _SMP_Inter_processor_interrupt_handler(); + } + if ( cpu_index_self != 0 ) + return; +#endif /* RTEMS_SMP */ + + pend = BCM2835_REG(BCM2835_IRQ_BASIC); + if ( pend & BCM2835_IRQ_BASIC_SPEEDUP_USED_BITS ) { + pend_bit = ffs(pend) - 1; + vector = bcm2835_irq_speedup_table[pend_bit]; + } else { + pend = BCM2835_REG(BCM2835_IRQ_PENDING1); + if ( pend != 0 ) { + pend_bit = ffs(pend) - 1; + vector = pend_bit; + } else { + pend = BCM2835_REG(BCM2835_IRQ_PENDING2); + if ( pend != 0 ) { + pend_bit = ffs(pend) - 1; + vector = pend_bit + 32; + } + } + } + + if ( vector < 255 ) + { + bsp_interrupt_handler_dispatch(vector); + } +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + BCM2835_REG(bsp_vector_to_reg(vector)->enable_reg_addr) = + bsp_vector_to_mask(vector); +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + BCM2835_REG(bsp_vector_to_reg(vector)->disable_reg_addr) = + bsp_vector_to_mask(vector); +} + +void bsp_interrupt_handler_default(rtems_vector_number vector) +{ + printk("spurious interrupt: %lu\n", vector); +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + BCM2835_REG(BCM2835_IRQ_DISABLE1) = 0xffffffff; + BCM2835_REG(BCM2835_IRQ_DISABLE2) = 0xffffffff; + BCM2835_REG(BCM2835_IRQ_DISABLE_BASIC) = 0xffffffff; + BCM2835_REG(BCM2835_IRQ_FIQ_CTRL) = 0; + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/arm/rtl22xx/irq/irq.c b/bsps/arm/rtl22xx/irq/irq.c new file mode 100644 index 0000000000..83e140bd7b --- /dev/null +++ b/bsps/arm/rtl22xx/irq/irq.c @@ -0,0 +1,70 @@ +/* + * Philps LPC22XX Interrupt handler + * + * Copyright (c) 2010 embedded brains GmbH. + * + * Copyright (c) 2006 by Ray<rayx.cn@gmail.com> to support LPC ARM + * 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 <rtems/score/armv4.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> + +#include <lpc22xx.h> + +void bsp_interrupt_dispatch(void) +{ + rtems_vector_number vector = 31 - __builtin_clz(VICIRQStatus); + + bsp_interrupt_handler_dispatch(vector); + + VICVectAddr = 0; +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + VICIntEnable |= 1 << vector; +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + VICIntEnClr = 1 << vector; +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + volatile uint32_t *ctrl = (volatile uint32_t *) VICVectCntlBase; + size_t i = 0; + + /* Disable all interrupts */ + VICIntEnClr = 0xffffffff; + + /* Use IRQ category */ + VICIntSelect = 0; + + /* Enable access in USER mode */ + VICProtection = 0; + + for (i = 0; i < 16; ++i) { + /* Disable vector mode */ + ctrl [i] = 0; + + /* Acknowledge interrupts for all priorities */ + VICVectAddr = 0; + } + + /* Acknowledge interrupts for all priorities */ + VICVectAddr = 0; + + /* Install the IRQ exception handler */ + _CPU_ISR_install_vector(ARM_EXCEPTION_IRQ, _ARMV4_Exception_interrupt, NULL); + + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/arm/shared/irq/irq-armv7m.c b/bsps/arm/shared/irq/irq-armv7m.c new file mode 100644 index 0000000000..99c0e373bf --- /dev/null +++ b/bsps/arm/shared/irq/irq-armv7m.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2011-2012 Sebastian Huber. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * 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 <string.h> + +#include <rtems/score/armv7m.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> +#include <bsp/linker-symbols.h> +#include <bsp/armv7m-irq.h> + +#ifdef ARM_MULTILIB_ARCH_V7M + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + _ARMV7M_NVIC_Set_enable((int) vector); +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + _ARMV7M_NVIC_Clear_enable((int) vector); +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + int i; + ARMV7M_Exception_handler *vector_table = + (ARMV7M_Exception_handler *) bsp_vector_table_begin; + + if (bsp_vector_table_begin != bsp_start_vector_table_begin) { + memcpy( + vector_table, + bsp_start_vector_table_begin, + (size_t) bsp_vector_table_size + ); + } + + _ARMV7M_SCB->icsr = ARMV7M_SCB_ICSR_PENDSVCLR | ARMV7M_SCB_ICSR_PENDSTCLR; + + for (i = BSP_INTERRUPT_VECTOR_MIN; i <= BSP_INTERRUPT_VECTOR_MAX; ++i) { + vector_table [ARMV7M_VECTOR_IRQ(i)] = _ARMV7M_NVIC_Interrupt_dispatch; + _ARMV7M_NVIC_Clear_enable(i); + _ARMV7M_NVIC_Clear_pending(i); + _ARMV7M_NVIC_Set_priority(i, BSP_ARMV7M_IRQ_PRIORITY_DEFAULT); + } + + _ARMV7M_SCB->vtor = vector_table; + + return RTEMS_SUCCESSFUL; +} + +#endif /* ARM_MULTILIB_ARCH_V7M */ diff --git a/bsps/arm/shared/irq/irq-dispatch-armv7m.c b/bsps/arm/shared/irq/irq-dispatch-armv7m.c new file mode 100644 index 0000000000..c810a9784a --- /dev/null +++ b/bsps/arm/shared/irq/irq-dispatch-armv7m.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011-2012 Sebastian Huber. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * 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 <rtems/score/armv7m.h> + +#include <bsp/irq-generic.h> +#include <bsp/armv7m-irq.h> + +#ifdef ARM_MULTILIB_ARCH_V7M + +void _ARMV7M_NVIC_Interrupt_dispatch(void) +{ + rtems_vector_number vector = + ARMV7M_SCB_ICSR_VECTACTIVE_GET(_ARMV7M_SCB->icsr); + + _ARMV7M_Interrupt_service_enter(); + bsp_interrupt_handler_dispatch(ARMV7M_IRQ_OF_VECTOR(vector)); + _ARMV7M_Interrupt_service_leave(); +} + +#endif /* ARM_MULTILIB_ARCH_V7M */ diff --git a/bsps/arm/shared/irq/irq-gic.c b/bsps/arm/shared/irq/irq-gic.c new file mode 100644 index 0000000000..ea4b6ef06a --- /dev/null +++ b/bsps/arm/shared/irq/irq-gic.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2013 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <info@embedded-brains.de> + * + * 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 <bsp/arm-gic.h> + +#include <rtems/score/armv4.h> + +#include <libcpu/arm-cp15.h> + +#include <bsp/irq.h> +#include <bsp/irq-generic.h> +#include <bsp/start.h> + +#define GIC_CPUIF ((volatile gic_cpuif *) BSP_ARM_GIC_CPUIF_BASE) + +#define PRIORITY_DEFAULT 127 + +void bsp_interrupt_dispatch(void) +{ + volatile gic_cpuif *cpuif = GIC_CPUIF; + uint32_t icciar = cpuif->icciar; + rtems_vector_number vector = GIC_CPUIF_ICCIAR_ACKINTID_GET(icciar); + rtems_vector_number spurious = 1023; + + if (vector != spurious) { + uint32_t psr = _ARMV4_Status_irq_enable(); + + bsp_interrupt_handler_dispatch(vector); + + _ARMV4_Status_restore(psr); + + cpuif->icceoir = icciar; + } +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + volatile gic_dist *dist = ARM_GIC_DIST; + + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + gic_id_enable(dist, vector); +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + volatile gic_dist *dist = ARM_GIC_DIST; + + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + gic_id_disable(dist, vector); +} + +static inline uint32_t get_id_count(volatile gic_dist *dist) +{ + uint32_t id_count = GIC_DIST_ICDICTR_IT_LINES_NUMBER_GET(dist->icdictr); + + id_count = 32 * (id_count + 1); + id_count = id_count <= 1020 ? id_count : 1020; + + return id_count; +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + volatile gic_cpuif *cpuif = GIC_CPUIF; + volatile gic_dist *dist = ARM_GIC_DIST; + uint32_t id_count = get_id_count(dist); + uint32_t id; + + arm_cp15_set_exception_handler( + ARM_EXCEPTION_IRQ, + _ARMV4_Exception_interrupt + ); + + for (id = 0; id < id_count; id += 32) { + dist->icdicer[id / 32] = 0xffffffff; + } + + for (id = 0; id < id_count; ++id) { + gic_id_set_priority(dist, id, PRIORITY_DEFAULT); + } + + for (id = 32; id < id_count; ++id) { + gic_id_set_targets(dist, id, 0x01); + } + + cpuif->iccpmr = GIC_CPUIF_ICCPMR_PRIORITY(0xff); + cpuif->iccbpr = GIC_CPUIF_ICCBPR_BINARY_POINT(0x0); + cpuif->iccicr = GIC_CPUIF_ICCICR_ENABLE; + + dist->icddcr = GIC_DIST_ICDDCR_ENABLE; + + return RTEMS_SUCCESSFUL; +} + +#ifdef RTEMS_SMP +BSP_START_TEXT_SECTION void arm_gic_irq_initialize_secondary_cpu(void) +{ + volatile gic_cpuif *cpuif = GIC_CPUIF; + volatile gic_dist *dist = ARM_GIC_DIST; + + while ((dist->icddcr & GIC_DIST_ICDDCR_ENABLE) == 0) { + /* Wait */ + } + + cpuif->iccpmr = GIC_CPUIF_ICCPMR_PRIORITY(0xff); + cpuif->iccbpr = GIC_CPUIF_ICCBPR_BINARY_POINT(0x0); + cpuif->iccicr = GIC_CPUIF_ICCICR_ENABLE; +} +#endif + +rtems_status_code arm_gic_irq_set_priority( + rtems_vector_number vector, + uint8_t priority +) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + if (bsp_interrupt_is_valid_vector(vector)) { + volatile gic_dist *dist = ARM_GIC_DIST; + + gic_id_set_priority(dist, vector, priority); + } else { + sc = RTEMS_INVALID_ID; + } + + return sc; +} + +rtems_status_code arm_gic_irq_get_priority( + rtems_vector_number vector, + uint8_t *priority +) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + if (bsp_interrupt_is_valid_vector(vector)) { + volatile gic_dist *dist = ARM_GIC_DIST; + + *priority = gic_id_get_priority(dist, vector); + } else { + sc = RTEMS_INVALID_ID; + } + + return sc; +} + +void bsp_interrupt_set_affinity( + rtems_vector_number vector, + const Processor_mask *affinity +) +{ + volatile gic_dist *dist = ARM_GIC_DIST; + uint8_t targets = (uint8_t) _Processor_mask_To_uint32_t(affinity, 0); + + gic_id_set_targets(dist, vector, targets); +} + +void bsp_interrupt_get_affinity( + rtems_vector_number vector, + Processor_mask *affinity +) +{ + volatile gic_dist *dist = ARM_GIC_DIST; + uint8_t targets = gic_id_get_targets(dist, vector); + + _Processor_mask_From_uint32_t(affinity, targets, 0); +} diff --git a/bsps/arm/smdk2410/irq/irq.c b/bsps/arm/smdk2410/irq/irq.c new file mode 100644 index 0000000000..ea8f610353 --- /dev/null +++ b/bsps/arm/smdk2410/irq/irq.c @@ -0,0 +1,45 @@ +/* irq.c + * + * This file contains the implementation of the function described in irq.h + * + * Copyright (c) 2010 embedded brains GmbH. + * + * CopyRight (C) 2000 Canon Research France SA. + * Emmanuel Raguet, mailto:raguet@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.rtems.org/license/LICENSE. + */ + +#include <rtems/score/armv4.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> + +#include <s3c24xx.h> + +void bsp_interrupt_dispatch(void) +{ + rtems_vector_number vector = *((uint32_t *) rINTOFFSET_ADDR); + + bsp_interrupt_handler_dispatch(vector); +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + _CPU_ISR_install_vector(ARM_EXCEPTION_IRQ, _ARMV4_Exception_interrupt, NULL); + + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/arm/tms570/irq/irq.c b/bsps/arm/tms570/irq/irq.c new file mode 100644 index 0000000000..579c11ed2a --- /dev/null +++ b/bsps/arm/tms570/irq/irq.c @@ -0,0 +1,202 @@ +/** + * @file irq.c + * + * @ingroup tms570 + * + * @brief TMS570 interrupt support functions definitions. + */ + +/* + * Copyright (c) 2014 Premysl Houdek <kom541000@gmail.com> + * + * Google Summer of Code 2014 at + * Czech Technical University in Prague + * Zikova 1903/4 + * 166 36 Praha 6 + * Czech Republic + * + * Based on LPC24xx and LPC1768 BSP + * + * 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 <bsp.h> +#include <bsp/irq-generic.h> +#include <bsp/tms570-vim.h> +#include <bsp/irq.h> +#include <rtems/score/armv4.h> + +unsigned int priorityTable[BSP_INTERRUPT_VECTOR_MAX+1]; + +/** + * @brief Set priority of the interrupt vector. + * + * This function is here because of compability. It should set + * priority of the interrupt vector. + * @warning It does not set any priority at HW layer. It is nearly imposible to + * @warning set priority of the interrupt on TMS570 in a nice way. + * @param[in] vector vector of isr + * @param[in] priority new priority assigned to the vector + * @return Void + */ +void tms570_irq_set_priority( + rtems_vector_number vector, + unsigned priority +) +{ + if ( bsp_interrupt_is_valid_vector(vector) ) { + priorityTable[vector] = priority; + } +} + +/** + * @brief Gets priority of the interrupt vector. + * + * This function is here because of compability. It returns priority + * of the isr vector last set by tms570_irq_set_priority function. + * + * @warning It does not return any real priority of the HW layer. + * @param[in] vector vector of isr + * @retval 0 vector is invalid. + * @retval priority priority of the interrupt + */ +unsigned tms570_irq_get_priority( + rtems_vector_number vector +) +{ + if ( bsp_interrupt_is_valid_vector(vector) ) { + return priorityTable[vector]; + } + return 0; +} + +/** + * @brief Interrupt dispatch + * + * Called by OS to determine which interrupt occured. + * Function passes control to interrupt handler. + * + * @return Void + */ +void bsp_interrupt_dispatch(void) +{ + rtems_vector_number vector = TMS570_VIM.IRQINDEX-1; + + bsp_interrupt_handler_dispatch(vector); +} + +/** + * @brief enables interrupt vector in the HW + * + * Enables HW interrupt for specified vector + * + * @param[in] vector vector of the isr which needs to be enabled. + * @retval RTEMS_INVALID_ID vector is invalid. + * @retval RTEMS_SUCCESSFUL interrupt source enabled. + */ +void bsp_interrupt_vector_enable( + rtems_vector_number vector +) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + TMS570_VIM.REQENASET[vector >> 5] = 1 << (vector & 0x1f); +} + +/** + * @brief disables interrupt vector in the HW + * + * Disables HW interrupt for specified vector + * + * @param[in] vector vector of the isr which needs to be disabled. + * @retval RTEMS_INVALID_ID vector is invalid. + * @retval RTEMS_SUCCESSFUL interrupt source disabled. + */ +void bsp_interrupt_vector_disable( + rtems_vector_number vector +) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + TMS570_VIM.REQENACLR[vector >> 5] = 1 << (vector & 0x1f); +} + +/** + * @brief Init function of interrupt module + * + * Resets vectored interrupt interface to default state. + * Disables all interrupts. + * Set all sources as IRQ (not FIR). + * + * @retval RTEMS_SUCCESSFUL All is set + */ +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + void (**vim_vec)(void) = (void (**)(void)) 0xFFF82000; + unsigned int value = 0x00010203; + unsigned int i = 0; + uint32_t sctlr; + + /* Disable interrupts */ + for ( i = 0; i < 3; i++ ) { + TMS570_VIM.REQENACLR[i] = 0xffffffff; + } + /* Map default events on interrupt vectors */ + for ( i = 0; i < 24; i += 1, value += 0x04040404) { + TMS570_VIM.CHANCTRL[i] = value; + } + /* Set all vectors as IRQ (not FIR) */ + TMS570_VIM.FIRQPR[0] = 3; + TMS570_VIM.FIRQPR[1] = 0; + TMS570_VIM.FIRQPR[2] = 0; + + /* + _CPU_ISR_install_vector( + ARM_EXCEPTION_IRQ, + _ARMV4_Exception_interrupt, + NULL + ); + + Call to setup of interrupt entry in CPU level exception vectors table + is not used (necessary/possible) because the table is provided + by c/src/lib/libbsp/arm/shared/start/start.S and POM overlay + solution remaps that to address zero. + */ + + for ( i = 0; i <= 94; ++i ) { + vim_vec[i] = _ARMV4_Exception_interrupt; + } + /* Clear bit VE in SCTLR register to not use VIM IRQ exception bypass*/ + asm volatile ("mrc p15, 0, %0, c1, c0, 0\n": "=r" (sctlr)); + /* + * Disable bypass of CPU level exception table for interrupt entry which + * can be provided by VIM hardware + */ + sctlr &= ~(1 << 24); + #if 0 + /* + * Option to enable exception table bypass for interrupts + * + * Because RTEMS requires all interrupts to be serviced through + * common _ARMV4_Exception_interrupt handler to allow task switching + * on exit from interrupt working correctly, vim_vec cannot point + * directly to individual vector handlers and need to point + * to single entry path. But if TMS570_VIM.IRQINDEX is then used + * to target execution to corresponding service then for some + * peripherals (i.e. EMAC) interrupt is already acknowledged + * by VIM and IRQINDEX is read as zero which leads to spurious + * interrupt and peripheral not serviced/blocked. + * + * To analyze this behavior we used trampolines which setup + * bsp_interrupt_vector_inject and pass execution to + * _ARMV4_Exception_interrupt. It works but is more ugly than + * use of POM remap for these cases where application does not + * start at address 0x00000000. If RTEMS image is placed at + * memory space beginning then no of these constructs is necessary. + */ + sctlr |= 1 << 24; + #endif + asm volatile ("mcr p15, 0, %0, c1, c0, 0\n": : "r" (sctlr)); + + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/epiphany/epiphany_sim/irq/irq.c b/bsps/epiphany/epiphany_sim/irq/irq.c new file mode 100644 index 0000000000..994e25bf0e --- /dev/null +++ b/bsps/epiphany/epiphany_sim/irq/irq.c @@ -0,0 +1,64 @@ +/** + * @file + * + * @ingroup epiphany_interrupt + * + * @brief Interrupt support. + */ + +/* + * Epiphany CPU Dependent Source + * + * Copyright (c) 2015 University of York. + * Hesham ALMatary <hmka501@york.ac.uk> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <bsp/irq.h> +#include <bsp/irq-generic.h> + +#include <rtems/inttypes.h> + +/* Almost all of the jobs that the following functions should + * do are implemented in cpukit + */ + +void bsp_interrupt_handler_default(rtems_vector_number vector) +{ + printk("spurious interrupt: %" PRIdrtems_vector_number "\n", vector); +} + +rtems_status_code bsp_interrupt_facility_initialize() +{ + return 0; +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); +} diff --git a/bsps/i386/shared/irq/elcr.c b/bsps/i386/shared/irq/elcr.c new file mode 100644 index 0000000000..f72e36c33f --- /dev/null +++ b/bsps/i386/shared/irq/elcr.c @@ -0,0 +1,170 @@ +/*- + * Copyright (c) 2004 John Baldwin <jhb@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#ifndef __rtems__ +__FBSDID("$FreeBSD$"); +#endif /* __rtems__ */ + +/* + * The ELCR is a register that controls the trigger mode and polarity of + * EISA and ISA interrupts. In FreeBSD 3.x and 4.x, the ELCR was only + * consulted for determining the appropriate trigger mode of EISA + * interrupts when using an APIC. However, it seems that almost all + * systems that include PCI also include an ELCR that manages the ISA + * IRQs 0 through 15. Thus, we check for the presence of an ELCR on + * every machine by checking to see if the values found at bootup are + * sane. Note that the polarity of ISA and EISA IRQs are linked to the + * trigger mode. All edge triggered IRQs use active-hi polarity, and + * all level triggered interrupts use active-lo polarity. + * + * The format of the ELCR is simple: it is a 16-bit bitmap where bit 0 + * controls IRQ 0, bit 1 controls IRQ 1, etc. If the bit is zero, the + * associated IRQ is edge triggered. If the bit is one, the IRQ is + * level triggered. + */ + +#ifndef __rtems__ +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/systm.h> +#include <machine/intr_machdep.h> +#endif /* __rtems__ */ + +#ifdef __rtems__ +#include <bsp.h> +#include "i386_io.h" +#include <errno.h> +#include "elcr.h" +#endif /* __rtems__ */ + +#define ELCR_PORT 0x4d0 +#define ELCR_MASK(irq) (1 << (irq)) + +static int elcr_status; +#ifdef __rtems__ +static +#endif /* __rtems__ */ +int elcr_found; + +#ifdef __rtems__ +#undef printf +#define printf printk +#define bootverbose 1 +#define KASSERT(...) +#endif /* __rtems__ */ + +/* + * Check to see if we have what looks like a valid ELCR. We do this by + * verifying that IRQs 0, 1, 2, and 13 are all edge triggered. + */ +int +elcr_probe(void) +{ + int i; + + elcr_status = inb(ELCR_PORT) | inb(ELCR_PORT + 1) << 8; + if ((elcr_status & (ELCR_MASK(0) | ELCR_MASK(1) | ELCR_MASK(2) | + ELCR_MASK(8) | ELCR_MASK(13))) != 0) + return (ENXIO); + if (bootverbose) { + printf("ELCR Found. ISA IRQs programmed as:\n"); + for (i = 0; i < 16; i++) + printf(" %2d", i); + printf("\n"); + for (i = 0; i < 16; i++) + if (elcr_status & ELCR_MASK(i)) + printf(" L"); + else + printf(" E"); + printf("\n"); + } +#ifndef __rtems__ + if (resource_disabled("elcr", 0)) + return (ENXIO); +#endif /* __rtems__ */ + elcr_found = 1; + return (0); +} + +/* + * Returns 1 for level trigger, 0 for edge. + */ +enum intr_trigger +elcr_read_trigger(u_int irq) +{ +#ifdef __rtems__ + if (!elcr_found) + return INTR_TRIGGER_EDGE; +#endif /* __rtems__ */ + KASSERT(elcr_found, ("%s: no ELCR was found!", __func__)); + KASSERT(irq <= 15, ("%s: invalid IRQ %u", __func__, irq)); + if (elcr_status & ELCR_MASK(irq)) + return (INTR_TRIGGER_LEVEL); + else + return (INTR_TRIGGER_EDGE); +} + +/* + * Set the trigger mode for a specified IRQ. Mode of 0 means edge triggered, + * and a mode of 1 means level triggered. + */ +void +elcr_write_trigger(u_int irq, enum intr_trigger trigger) +{ + int new_status; + +#ifdef __rtems__ + if (!elcr_found) + return; +#endif /* __rtems__ */ + KASSERT(elcr_found, ("%s: no ELCR was found!", __func__)); + KASSERT(irq <= 15, ("%s: invalid IRQ %u", __func__, irq)); + if (trigger == INTR_TRIGGER_LEVEL) + new_status = elcr_status | ELCR_MASK(irq); + else + new_status = elcr_status & ~ELCR_MASK(irq); + if (new_status == elcr_status) + return; + elcr_status = new_status; + if (irq >= 8) + outb(ELCR_PORT + 1, elcr_status >> 8); + else + outb(ELCR_PORT, elcr_status & 0xff); +} + +void +elcr_resume(void) +{ +#ifdef __rtems__ + if (!elcr_found) + return; +#endif /* __rtems__ */ + + KASSERT(elcr_found, ("%s: no ELCR was found!", __func__)); + outb(ELCR_PORT, elcr_status & 0xff); + outb(ELCR_PORT + 1, elcr_status >> 8); +} diff --git a/bsps/i386/shared/irq/elcr.h b/bsps/i386/shared/irq/elcr.h new file mode 100644 index 0000000000..a006d4f149 --- /dev/null +++ b/bsps/i386/shared/irq/elcr.h @@ -0,0 +1,37 @@ +/* + * Copyright 2016 Chris Johns <chrisj@rtems.org> + * + * Header for the FreeBSD ported elcr.c + */ + +#ifndef _IRQ_ELCR_H_ +#define _IRQ_ELCR_H_ + +#include <sys/cdefs.h> + +enum intr_trigger { + INTR_TRIGGER_EDGE, + INTR_TRIGGER_LEVEL +}; + +/* + * Check to see if we have what looks like a valid ELCR. We do this by + * verifying that IRQs 0, 1, 2, and 13 are all edge triggered. + */ +int elcr_probe(void); + +/* + * Returns 1 for level trigger, 0 for edge. + */ +enum intr_trigger elcr_read_trigger(u_int irq); + +/* + * Set the trigger mode for a specified IRQ. Mode of 0 means edge triggered, + * and a mode of 1 means level triggered. + */ +void elcr_write_trigger(u_int irq, enum intr_trigger trigger); + +void elcr_resume(void); + + +#endif diff --git a/bsps/i386/shared/irq/idt.c b/bsps/i386/shared/irq/idt.c new file mode 100644 index 0000000000..d3adbc4f05 --- /dev/null +++ b/bsps/i386/shared/irq/idt.c @@ -0,0 +1,381 @@ +/* + * cpu.c - This file contains implementation of C function to + * instantiate IDT entries. More detailled information can be found + * on Intel site and more precisely in the following book : + * + * Pentium Processor family + * Developper's Manual + * + * Volume 3 : Architecture and Programming Manual + * + * Copyright (C) 1998 Eric Valette (valette@crf.canon.fr) + * Canon Centre Recherche France. + * + * 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 <rtems/score/cpu.h> +#include <bsp/irq.h> +#include <bsp/tblsizes.h> + +/* + * This locking is not enough if IDT is changed at runtime + * and entry can be changed for vector which is enabled + * at change time. But such use is broken anyway. + * Protect code only against concurrent changes. + * Even that is probably unnecessary if different + * entries are changed concurrently. + */ +RTEMS_INTERRUPT_LOCK_DEFINE( static, rtems_idt_access_lock, "rtems_idt_access_lock" ); + +static rtems_raw_irq_connect_data* raw_irq_table; +static rtems_raw_irq_connect_data default_raw_irq_entry; +static interrupt_gate_descriptor default_idt_entry; +static rtems_raw_irq_global_settings* local_settings; + +void create_interrupt_gate_descriptor (interrupt_gate_descriptor* idtEntry, + rtems_raw_irq_hdl hdl) +{ + idtEntry->low_offsets_bits = (((unsigned) hdl) & 0xffff); + idtEntry->segment_selector = i386_get_cs(); + idtEntry->fixed_value_bits = 0; + idtEntry->gate_type = 0xe; + idtEntry->privilege = 0; + idtEntry->present = 1; + idtEntry->high_offsets_bits = ((((unsigned) hdl) >> 16) & 0xffff); +} + +rtems_raw_irq_hdl get_hdl_from_vector(rtems_vector_offset index) +{ + uint32_t hdl; + interrupt_gate_descriptor* idt_entry_tbl; + unsigned limit; + + i386_get_info_from_IDTR (&idt_entry_tbl, &limit); + + /* Convert limit into number of entries */ + limit = (limit + 1) / sizeof(interrupt_gate_descriptor); + + if(index >= limit) { + return 0; + } + + hdl = (idt_entry_tbl[index].low_offsets_bits | + (idt_entry_tbl[index].high_offsets_bits << 16)); + return (rtems_raw_irq_hdl) hdl; +} + +int i386_set_idt_entry (const rtems_raw_irq_connect_data* irq) +{ + interrupt_gate_descriptor* idt_entry_tbl; + unsigned limit; + rtems_interrupt_lock_context lock_context; + + i386_get_info_from_IDTR (&idt_entry_tbl, &limit); + + /* Convert limit into number of entries */ + limit = (limit + 1) / sizeof(interrupt_gate_descriptor); + + if (irq->idtIndex >= limit) { + return 0; + } + /* + * Check if default handler is actually connected. If not issue an error. + * You must first get the current handler via i386_get_current_idt_entry + * and then disconnect it using i386_delete_idt_entry. + * RATIONALE : to always have the same transition by forcing the user + * to get the previous handler before accepting to disconnect. + */ + if (get_hdl_from_vector(irq->idtIndex) != default_raw_irq_entry.hdl) { + return 0; + } + + rtems_interrupt_lock_acquire(&rtems_idt_access_lock, &lock_context); + + raw_irq_table [irq->idtIndex] = *irq; + create_interrupt_gate_descriptor (&idt_entry_tbl[irq->idtIndex], irq->hdl); + if (irq->on) + irq->on(irq); + + rtems_interrupt_lock_release(&rtems_idt_access_lock, &lock_context); + return 1; +} + +void _CPU_ISR_install_vector (uint32_t vector, + proc_ptr hdl, + proc_ptr * oldHdl) +{ + interrupt_gate_descriptor* idt_entry_tbl; + unsigned limit; + interrupt_gate_descriptor new; + rtems_interrupt_lock_context lock_context; + + i386_get_info_from_IDTR (&idt_entry_tbl, &limit); + + /* Convert limit into number of entries */ + limit = (limit + 1) / sizeof(interrupt_gate_descriptor); + + if (vector >= limit) { + return; + } + rtems_interrupt_lock_acquire(&rtems_idt_access_lock, &lock_context); + * ((unsigned int *) oldHdl) = idt_entry_tbl[vector].low_offsets_bits | + (idt_entry_tbl[vector].high_offsets_bits << 16); + + create_interrupt_gate_descriptor(&new, hdl); + idt_entry_tbl[vector] = new; + + rtems_interrupt_lock_release(&rtems_idt_access_lock, &lock_context); +} + +int i386_get_current_idt_entry (rtems_raw_irq_connect_data* irq) +{ + interrupt_gate_descriptor* idt_entry_tbl; + unsigned limit; + + i386_get_info_from_IDTR (&idt_entry_tbl, &limit); + + /* Convert limit into number of entries */ + limit = (limit + 1) / sizeof(interrupt_gate_descriptor); + + if (irq->idtIndex >= limit) { + return 0; + } + raw_irq_table [irq->idtIndex].hdl = get_hdl_from_vector(irq->idtIndex); + + *irq = raw_irq_table [irq->idtIndex]; + + return 1; +} + +int i386_delete_idt_entry (const rtems_raw_irq_connect_data* irq) +{ + interrupt_gate_descriptor* idt_entry_tbl; + unsigned limit; + rtems_interrupt_lock_context lock_context; + + i386_get_info_from_IDTR (&idt_entry_tbl, &limit); + + /* Convert limit into number of entries */ + limit = (limit + 1) / sizeof(interrupt_gate_descriptor); + + if (irq->idtIndex >= limit) { + return 0; + } + /* + * Check if handler passed is actually connected. If not issue an error. + * You must first get the current handler via i386_get_current_idt_entry + * and then disconnect it using i386_delete_idt_entry. + * RATIONALE : to always have the same transition by forcing the user + * to get the previous handler before accepting to disconnect. + */ + if (get_hdl_from_vector(irq->idtIndex) != irq->hdl){ + return 0; + } + rtems_interrupt_lock_acquire(&rtems_idt_access_lock, &lock_context); + + idt_entry_tbl[irq->idtIndex] = default_idt_entry; + + if (irq->off) + irq->off(irq); + + raw_irq_table[irq->idtIndex] = default_raw_irq_entry; + raw_irq_table[irq->idtIndex].idtIndex = irq->idtIndex; + + rtems_interrupt_lock_release(&rtems_idt_access_lock, &lock_context); + + return 1; +} + +/* + * Caution this function assumes the IDTR has been already set. + */ +int i386_init_idt (rtems_raw_irq_global_settings* config) +{ + unsigned limit; + unsigned i; + rtems_interrupt_lock_context lock_context; + interrupt_gate_descriptor* idt_entry_tbl; + + i386_get_info_from_IDTR (&idt_entry_tbl, &limit); + + /* Convert limit into number of entries */ + limit = (limit + 1) / sizeof(interrupt_gate_descriptor); + + if (config->idtSize != limit) { + return 0; + } + /* + * store various accelarators + */ + raw_irq_table = config->rawIrqHdlTbl; + local_settings = config; + default_raw_irq_entry = config->defaultRawEntry; + + rtems_interrupt_lock_acquire(&rtems_idt_access_lock, &lock_context); + + create_interrupt_gate_descriptor (&default_idt_entry, default_raw_irq_entry.hdl); + + for (i=0; i < limit; i++) { + interrupt_gate_descriptor new; + create_interrupt_gate_descriptor (&new, raw_irq_table[i].hdl); + idt_entry_tbl[i] = new; + if (raw_irq_table[i].hdl != default_raw_irq_entry.hdl) { + raw_irq_table[i].on(&raw_irq_table[i]); + } + else { + raw_irq_table[i].off(&raw_irq_table[i]); + } + } + rtems_interrupt_lock_release(&rtems_idt_access_lock, &lock_context); + + return 1; +} + +int i386_get_idt_config (rtems_raw_irq_global_settings** config) +{ + *config = local_settings; + return 1; +} + +uint32_t i386_raw_gdt_entry (uint16_t segment_selector_index, + segment_descriptors* sd) +{ + uint16_t gdt_limit; + uint16_t tmp_segment = 0; + segment_descriptors* gdt_entry_tbl; + uint8_t present; + + i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit); + + if (segment_selector_index >= (gdt_limit+1)/8) { + /* index to GDT table out of bounds */ + return 0; + } + if (segment_selector_index == 0) { + /* index 0 is not usable */ + return 0; + } + + /* put prepared descriptor into the GDT */ + present = sd->present; + sd->present = 0; + gdt_entry_tbl[segment_selector_index].present = 0; + RTEMS_COMPILER_MEMORY_BARRIER(); + gdt_entry_tbl[segment_selector_index] = *sd; + RTEMS_COMPILER_MEMORY_BARRIER(); + gdt_entry_tbl[segment_selector_index].present = present; + sd->present = present; + /* + * Now, reload all segment registers so that the possible changes takes effect. + */ + __asm__ volatile( "movw %%ds,%0 ; movw %0,%%ds\n\t" + "movw %%es,%0 ; movw %0,%%es\n\t" + "movw %%fs,%0 ; movw %0,%%fs\n\t" + "movw %%gs,%0 ; movw %0,%%gs\n\t" + "movw %%ss,%0 ; movw %0,%%ss" + : "=r" (tmp_segment) + : "0" (tmp_segment) + ); + return 1; +} + +void i386_fill_segment_desc_base(uint32_t base, + segment_descriptors* sd) +{ + sd->base_address_15_0 = base & 0xffff; + sd->base_address_23_16 = (base >> 16) & 0xff; + sd->base_address_31_24 = (base >> 24) & 0xff; +} + +void i386_fill_segment_desc_limit(uint32_t limit, + segment_descriptors* sd) +{ + sd->granularity = 0; + if (limit > 65535) { + sd->granularity = 1; + limit /= 4096; + } + sd->limit_15_0 = limit & 0xffff; + sd->limit_19_16 = (limit >> 16) & 0xf; +} + +/* + * Caution this function assumes the GDTR has been already set. + */ +uint32_t i386_set_gdt_entry (uint16_t segment_selector_index, uint32_t base, + uint32_t limit) +{ + segment_descriptors gdt_entry; + memset(&gdt_entry, 0, sizeof(gdt_entry)); + + i386_fill_segment_desc_limit(limit, &gdt_entry); + i386_fill_segment_desc_base(base, &gdt_entry); + /* + * set up descriptor type (this may well becomes a parameter if needed) + */ + gdt_entry.type = 2; /* Data R/W */ + gdt_entry.descriptor_type = 1; /* Code or Data */ + gdt_entry.privilege = 0; /* ring 0 */ + gdt_entry.present = 1; /* not present */ + + /* + * Now, reload all segment registers so the limit takes effect. + */ + return i386_raw_gdt_entry(segment_selector_index, &gdt_entry); +} + +uint16_t i386_next_empty_gdt_entry () +{ + uint16_t gdt_limit; + segment_descriptors* gdt_entry_tbl; + /* initial amount of filled descriptors */ + static uint16_t segment_selector_index = NUM_SYSTEM_GDT_DESCRIPTORS - 1; + + segment_selector_index += 1; + i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit); + if (segment_selector_index >= (gdt_limit+1)/8) { + return 0; + } + return segment_selector_index; +} + +uint16_t i386_cpy_gdt_entry(uint16_t segment_selector_index, + segment_descriptors* struct_to_fill) +{ + uint16_t gdt_limit; + segment_descriptors* gdt_entry_tbl; + + i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit); + + if (segment_selector_index >= (gdt_limit+1)/8) { + return 0; + } + + *struct_to_fill = gdt_entry_tbl[segment_selector_index]; + return segment_selector_index; +} + +segment_descriptors* i386_get_gdt_entry(uint16_t segment_selector_index) +{ + uint16_t gdt_limit; + segment_descriptors* gdt_entry_tbl; + + i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit); + + if (segment_selector_index >= (gdt_limit+1)/8) { + return 0; + } + return &gdt_entry_tbl[segment_selector_index]; +} + +uint32_t i386_limit_gdt_entry(segment_descriptors* gdt_entry) +{ + uint32_t lim = (gdt_entry->limit_15_0 + (gdt_entry->limit_19_16<<16)); + if (gdt_entry->granularity) { + return lim*4096+4095; + } + return lim; +} diff --git a/bsps/i386/shared/irq/irq.c b/bsps/i386/shared/irq/irq.c new file mode 100644 index 0000000000..ac08f1f7be --- /dev/null +++ b/bsps/i386/shared/irq/irq.c @@ -0,0 +1,405 @@ +/* + * This file contains the implementation of the function described in irq.h + */ + +/* + * Copyright (c) 2009 embedded brains GmbH + * Copyright (C) 1998 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.rtems.org/license/LICENSE. + */ + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> +#include <rtems/score/cpu.h> + +#include <stdlib.h> +#include <stdio.h> +#include <inttypes.h> + + +#include "elcr.h" + +RTEMS_INTERRUPT_LOCK_DEFINE( static, rtems_i8259_access_lock, "rtems_i8259_access_lock" ); + +/* + * 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 teh prioruty table given + * in BSP_rtems_irq_mngt_set(); + * CAUTION : this table is accessed directly by interrupt routine + * prologue. + */ +static rtems_i8259_masks irq_mask_or_tbl[BSP_IRQ_LINES_NUMBER]; + +/* + * Stats of interrupts dispatched. + */ +static uint32_t irq_count[BSP_IRQ_VECTOR_NUMBER] = {0}; +static uint32_t spurious_count; + +/* + * Edge or level trigger interrupts. + */ +static enum intr_trigger irq_trigger[BSP_IRQ_LINES_NUMBER]; + +/*-------------------------------------------------------------------------+ +| Cache for 1st and 2nd PIC IRQ line's mssk (enabled or disabled) register. ++--------------------------------------------------------------------------*/ +/* + * lower byte is interrupt mask on the master PIC. + * while upper bits are interrupt on the slave PIC. + * This cache is initialized in ldseg.s + */ +static rtems_i8259_masks i8259a_imr_cache = 0xFFFB; +static rtems_i8259_masks i8259a_in_progress = 0; + +static inline +void BSP_i8259a_irq_update_master_imr( void ) +{ + rtems_i8259_masks mask = i8259a_in_progress | i8259a_imr_cache; + outport_byte( PIC_MASTER_IMR_IO_PORT, mask & 0xff ); +} + +static inline +void BSP_i8259a_irq_update_slave_imr( void ) +{ + rtems_i8259_masks mask = i8259a_in_progress | i8259a_imr_cache; + outport_byte( PIC_SLAVE_IMR_IO_PORT, ( mask >> 8 ) & 0xff ); +} + +/* + * Print the stats. + */ +uint32_t BSP_irq_count_dump(FILE *f) +{ + uint32_t tot = 0; + int i; + if ( !f ) + f = stdout; + fprintf(f,"SPURIOUS: %9"PRIu32"\n", spurious_count); + for ( i = 0; i < BSP_IRQ_VECTOR_NUMBER; i++ ) { + char type = '-'; + if (i < BSP_IRQ_LINES_NUMBER) + type = irq_trigger[i] == INTR_TRIGGER_EDGE ? 'E' : 'L'; + tot += irq_count[i]; + fprintf(f,"IRQ %2u: %c %9"PRIu32"\n", i, type, irq_count[i]); + } + return tot; +} + +/* + * Is the IRQ valid? + */ +static inline bool BSP_i8259a_irq_valid(const rtems_irq_number irqLine) +{ + return ((int)irqLine >= BSP_IRQ_VECTOR_LOWEST_OFFSET) && + ((int)irqLine <= BSP_IRQ_MAX_ON_i8259A); +} + +/* + * Read the IRR register. The default. + */ +static inline uint8_t BSP_i8259a_irq_int_request_reg(uint32_t ioport) +{ + uint8_t isr; + inport_byte(ioport, isr); + return isr; +} + +/* + * Read the ISR register. Keep the default of the IRR. + */ +static inline uint8_t BSP_i8259a_irq_in_service_reg(uint32_t ioport) +{ + uint8_t isr; + outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR | PIC_OCW3_RIS); + inport_byte(ioport, isr); + outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR); + return isr; +} + +/*-------------------------------------------------------------------------+ +| Function: BSP_irq_disable_at_i8259a +| Description: Mask IRQ line in appropriate PIC chip. +| Global Variables: i8259a_imr_cache, i8259a_in_progress +| Arguments: vector_offset - number of IRQ line to mask. +| Returns: 0 is OK. ++--------------------------------------------------------------------------*/ +static int BSP_irq_disable_at_i8259a(const rtems_irq_number irqLine) +{ + unsigned short mask; + rtems_interrupt_lock_context lock_context; + + rtems_interrupt_lock_acquire(&rtems_i8259_access_lock, &lock_context); + + mask = 1 << irqLine; + i8259a_imr_cache |= mask; + + if (irqLine < 8) + { + BSP_i8259a_irq_update_master_imr(); + } + else + { + BSP_i8259a_irq_update_slave_imr(); + } + + rtems_interrupt_lock_release(&rtems_i8259_access_lock, &lock_context); + + return 0; +} + +/*-------------------------------------------------------------------------+ +| Function: BSP_irq_enable_at_i8259a +| Description: Unmask IRQ line in appropriate PIC chip. +| Global Variables: i8259a_imr_cache, i8259a_in_progress +| Arguments: irqLine - number of IRQ line to mask. +| Returns: Nothing. ++--------------------------------------------------------------------------*/ +static int BSP_irq_enable_at_i8259a(const rtems_irq_number irqLine) +{ + unsigned short mask; + rtems_interrupt_lock_context lock_context; + uint8_t isr; + uint8_t irr; + + rtems_interrupt_lock_acquire(&rtems_i8259_access_lock, &lock_context); + + mask = 1 << irqLine; + i8259a_imr_cache &= ~mask; + + if (irqLine < 8) + { + isr = BSP_i8259a_irq_in_service_reg(PIC_MASTER_COMMAND_IO_PORT); + irr = BSP_i8259a_irq_int_request_reg(PIC_MASTER_COMMAND_IO_PORT); + BSP_i8259a_irq_update_master_imr(); + } + else + { + isr = BSP_i8259a_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT); + irr = BSP_i8259a_irq_int_request_reg(PIC_SLAVE_COMMAND_IO_PORT); + BSP_i8259a_irq_update_slave_imr(); + } + + if (((isr ^ irr) & mask) != 0) + printk("i386: isr=%x irr=%x\n", isr, irr); + + rtems_interrupt_lock_release(&rtems_i8259_access_lock, &lock_context); + + return 0; +} /* mask_irq */ + +/*-------------------------------------------------------------------------+ +| Function: BSP_irq_ack_at_i8259a +| Description: Signal generic End Of Interrupt (EOI) to appropriate PIC. +| Global Variables: None. +| Arguments: irqLine - number of IRQ line to acknowledge. +| Returns: Nothing. ++--------------------------------------------------------------------------*/ +static int BSP_irq_ack_at_i8259a(const rtems_irq_number irqLine) +{ + uint8_t slave_isr = 0; + + if (irqLine >= 8) { + outport_byte(PIC_SLAVE_COMMAND_IO_PORT, PIC_EOI); + slave_isr = BSP_i8259a_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT); + } + + /* + * Only issue the EOI to the master if there are no more interrupts in + * service for the slave. i8259a data sheet page 18, The Special Fully Nested + * Mode, b. + */ + if (slave_isr == 0) + outport_byte(PIC_MASTER_COMMAND_IO_PORT, PIC_EOI); + + return 0; + +} /* ackIRQ */ + +/* + * ------------------------ RTEMS Irq helper functions ---------------- + */ + +static rtems_irq_prio irqPrioTable[BSP_IRQ_LINES_NUMBER]={ + /* + * actual priorities for each interrupt source: + * 0 means that only current interrupt is masked + * 255 means all other interrupts are masked + * The second entry has a priority of 255 because + * it is the slave pic entry and is should always remain + * unmasked. + */ + 0,0, + 255, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static void compute_i8259_masks_from_prio (void) +{ + rtems_interrupt_lock_context lock_context; + unsigned int i; + unsigned int j; + + rtems_interrupt_lock_acquire(&rtems_i8259_access_lock, &lock_context); + + /* + * Always mask at least current interrupt to prevent re-entrance + */ + for (i=0; i < BSP_IRQ_LINES_NUMBER; i++) { + * ((unsigned short*) &irq_mask_or_tbl[i]) = (1 << i); + for (j = 0; j < BSP_IRQ_LINES_NUMBER; j++) { + /* + * Mask interrupts at i8259 level that have a lower priority + */ + if (irqPrioTable [i] > irqPrioTable [j]) { + * ((unsigned short*) &irq_mask_or_tbl[i]) |= (1 << j); + } + } + } + + rtems_interrupt_lock_release(&rtems_i8259_access_lock, &lock_context); +} + +static inline bool bsp_interrupt_vector_is_valid(rtems_vector_number vector) +{ + return BSP_i8259a_irq_valid((const rtems_irq_number) vector); +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + BSP_irq_enable_at_i8259a(vector); +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + BSP_irq_disable_at_i8259a(vector); +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + int i; + + /* + * set up internal tables used by rtems interrupt prologue + */ + compute_i8259_masks_from_prio(); + + /* + * must enable slave pic anyway + */ + BSP_irq_enable_at_i8259a(2); + + /* + * Probe the ELCR. + */ + elcr_probe(); + + for (i = 0; i < BSP_IRQ_LINES_NUMBER; i++) + irq_trigger[i] = elcr_read_trigger(i); + + return RTEMS_SUCCESSFUL; +} + +/* + * Global so the asm handler can call it. + */ +void BSP_dispatch_isr(int vector); + +void BSP_dispatch_isr(int vector) +{ + rtems_interrupt_lock_context lock_context; + rtems_i8259_masks in_progress_save = 0; + + if (vector < BSP_IRQ_VECTOR_NUMBER) { + /* + * Hardware? + */ + if (vector <= BSP_IRQ_MAX_ON_i8259A) { + + rtems_interrupt_lock_acquire_isr(&rtems_i8259_access_lock, &lock_context); + + /* + * See if this is a spurious interrupt. + */ + if ((vector == 7 || vector == 15)) { + /* + * Only check it there no handler for 7 or 15. + */ + if (bsp_interrupt_handler_is_empty(vector)) { + /* + * Read the ISR register to see if IRQ 7/15 is really pending. + */ + uint8_t isr = BSP_i8259a_irq_in_service_reg(PIC_MASTER_COMMAND_IO_PORT); + if ((isr & (1 << 7)) == 0) { + ++spurious_count; + rtems_interrupt_lock_release_isr(&rtems_i8259_access_lock, &lock_context); + return; + } + } + } + + /* + * Save the current cached value for the IMR. It will have the bit for this + * vector clear. + */ + if (vector <= BSP_IRQ_MAX_ON_i8259A) { + in_progress_save = i8259a_in_progress; + i8259a_in_progress |= irq_mask_or_tbl[vector]; + BSP_i8259a_irq_update_master_imr(); + BSP_i8259a_irq_update_slave_imr(); + } + + /* + * Do not use auto-EOI as some slave PIC do not work correctly. + */ + BSP_irq_ack_at_i8259a(vector); + + rtems_interrupt_lock_release_isr(&rtems_i8259_access_lock, &lock_context); + } + + /* + * Count the interrupt. + */ + irq_count[vector]++; + + RTEMS_COMPILER_MEMORY_BARRIER(); + /* + * Allow nesting. + */ + __asm__ __volatile__("sti"); + + bsp_interrupt_handler_dispatch(vector); + + /* + * Disallow nesting. + */ + __asm__ __volatile__("cli"); + + RTEMS_COMPILER_MEMORY_BARRIER(); + + if (vector <= BSP_IRQ_MAX_ON_i8259A) { + + rtems_interrupt_lock_acquire_isr(&rtems_i8259_access_lock, &lock_context); + + /* + * Put the mask back but keep this vector masked if the trigger type is + * level. The driver or a thread level interrupt server needs to enable it + * again. + */ + if (vector <= BSP_IRQ_MAX_ON_i8259A) { + i8259a_in_progress = in_progress_save; + BSP_i8259a_irq_update_master_imr(); + BSP_i8259a_irq_update_slave_imr(); + } + + rtems_interrupt_lock_release_isr(&rtems_i8259_access_lock, &lock_context); + } + } +} diff --git a/bsps/i386/shared/irq/irq_asm.S b/bsps/i386/shared/irq/irq_asm.S new file mode 100644 index 0000000000..181293351e --- /dev/null +++ b/bsps/i386/shared/irq/irq_asm.S @@ -0,0 +1,268 @@ +/* + * This file contains the implementation of the function described in irq.h + */ + +/* + * Copyright (C) 1998 valette@crf.canon.fr + * + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <rtems/asm.h> +#include <rtems/system.h> +#include <bspopts.h> +#include <rtems/score/cpu.h> +#include <rtems/score/percpu.h> + +#include <bsp.h> /* to establish dependency on prototype */ + +#ifndef CPU_STACK_ALIGNMENT +#error "Missing header? CPU_STACK_ALIGNMENT is not defined here" +#endif + +/* Stack frame we use for intermediate storage */ +#define ARG_OFF 0 +#define MSK_OFF 4 /* not used any more */ +#define EBX_OFF 8 /* ebx */ +#define EBP_OFF 12 /* code restoring ebp/esp relies on */ +#define ESP_OFF 16 /* esp being on top of ebp! */ +#ifdef __SSE__ +/* need to be on 16 byte boundary for SSE, add 12 to do that */ +#define FRM_SIZ (20+12+512) +#define SSE_OFF 32 +#else +#define FRM_SIZ 20 +#endif + + BEGIN_CODE + +SYM (_ISR_Handler): + /* + * Before this was point is reached the vectors unique + * entry point did the following: + * + * 1. saved scratch registers registers eax edx ecx" + * 2. put the vector number in ecx. + * + * BEGINNING OF ESTABLISH SEGMENTS + * + * WARNING: If an interrupt can occur when the segments are + * not correct, then this is where we should establish + * the segments. In addition to establishing the + * segments, it may be necessary to establish a stack + * in the current data area on the outermost interrupt. + * + * NOTE: If the previous values of the segment registers are + * pushed, do not forget to adjust SAVED_REGS. + * + * NOTE: Make sure the exit code which restores these + * when this type of code is needed. + */ + + /***** ESTABLISH SEGMENTS CODE GOES HERE ******/ + + /* + * END OF ESTABLISH SEGMENTS + */ + + /* + * Establish an aligned stack frame + * original sp + * saved ebx + * saved ebp + * saved irq mask + * vector arg to BSP_dispatch_isr <- aligned SP + */ + movl esp, eax + subl $FRM_SIZ, esp + andl $ - CPU_STACK_ALIGNMENT, esp + movl ebx, EBX_OFF(esp) + movl eax, ESP_OFF(esp) + movl ebp, EBP_OFF(esp) + + /* + * GCC versions starting with 4.3 no longer place the cld + * instruction before string operations. We need to ensure + * it is set correctly for ISR handlers. + */ + cld + +#ifdef __SSE__ + /* NOTE: SSE only is supported if the BSP enables fxsave/fxrstor + * to save/restore SSE context! This is so far only implemented + * for pc386!. + */ + + /* We save SSE here (on the task stack) because we possibly + * call other C-code (besides the ISR, namely _Thread_Dispatch()) + */ + /* don't wait here; a possible exception condition will eventually be + * detected when the task resumes control and executes a FP instruction + fwait + */ + fxsave SSE_OFF(esp) + fninit /* clean-slate FPU */ + movl $0x1f80, ARG_OFF(esp) /* use ARG_OFF as scratch space */ + ldmxcsr ARG_OFF(esp) /* clean-slate MXCSR */ +#endif + + /* + * Now switch stacks if necessary + */ + +PUBLIC (ISR_STOP) +ISR_STOP: +.check_stack_switch: + movl esp, ebp /* ebp = previous stack pointer */ + +#ifdef RTEMS_SMP + call SYM(_CPU_SMP_Get_current_processor) + sall $PER_CPU_CONTROL_SIZE_LOG2, eax + addl $SYM(_Per_CPU_Information), eax + movl eax, ebx +#else + movl $SYM(_Per_CPU_Information), ebx +#endif + + /* is this the outermost interrupt? */ + cmpl $0, PER_CPU_ISR_NEST_LEVEL(ebx) + jne nested /* No, then continue */ + movl PER_CPU_INTERRUPT_STACK_HIGH(ebx), esp + + /* + * We want to insure that the old stack pointer is in ebp + * By saving it on every interrupt, all we have to do is + * movl ebp->esp near the end of every interrupt. + */ + +nested: + incl PER_CPU_ISR_NEST_LEVEL(ebx) /* one nest level deeper */ + incl PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(ebx) /* disable + multitasking */ + /* + * ECX is preloaded with the vector number; store as arg + * on top of stack. Note that _CPU_Interrupt_stack_high + * was adjusted in _CPU_Interrupt_stack_setup() (score/rtems/cpu.h) + * to make sure there is space. + */ + + movl ecx, ARG_OFF(esp) /* store vector arg in stack */ + call BSP_dispatch_isr + + movl ARG_OFF(esp), ecx /* grab vector arg from stack */ + + /* + * Restore stack. This moves back to the task stack + * when all interrupts are unnested. + */ + movl ebp, esp + + decl PER_CPU_ISR_NEST_LEVEL(ebx) /* one less ISR nest level */ + /* If interrupts are nested, */ + /* then dispatching is disabled */ + + decl PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(ebx) + /* unnest multitasking */ + /* Is dispatch disabled */ + jne .exit /* Yes, then exit */ + + cmpb $0, PER_CPU_DISPATCH_NEEDED(ebx) + /* Is task switch necessary? */ + jne .schedule /* Yes, then call the scheduler */ + jmp .exit /* No, exit */ + +.schedule: + /* + * the scratch registers have already been saved and we are already + * back on the thread system stack. So we can call _Thread_Dispatch + * directly + */ + call _Thread_Dispatch + /* + * fall through exit to restore complete contex (scratch registers + * eip, CS, Flags). + */ +.exit: + +#ifdef __SSE__ + fwait + fxrstor SSE_OFF(esp) +#endif + + /* restore ebx, ebp and original esp */ + addl $EBX_OFF, esp + popl ebx + popl ebp + popl esp + + /* + * BEGINNING OF DE-ESTABLISH SEGMENTS + * + * NOTE: Make sure there is code here if code is added to + * load the segment registers. + * + */ + + /******* DE-ESTABLISH SEGMENTS CODE GOES HERE ********/ + + /* + * END OF DE-ESTABLISH SEGMENTS + */ + popl edx + popl ecx + popl eax + iret + +#define DISTINCT_INTERRUPT_ENTRY(_vector) \ + .p2align 4 ; \ + PUBLIC (rtems_irq_prologue_ ## _vector ) ; \ +SYM (rtems_irq_prologue_ ## _vector ): \ + pushl eax ; \ + pushl ecx ; \ + pushl edx ; \ + movl $ _vector, ecx ; \ + jmp SYM (_ISR_Handler) ; + +DISTINCT_INTERRUPT_ENTRY(0) +DISTINCT_INTERRUPT_ENTRY(1) +DISTINCT_INTERRUPT_ENTRY(2) +DISTINCT_INTERRUPT_ENTRY(3) +DISTINCT_INTERRUPT_ENTRY(4) +DISTINCT_INTERRUPT_ENTRY(5) +DISTINCT_INTERRUPT_ENTRY(6) +DISTINCT_INTERRUPT_ENTRY(7) +DISTINCT_INTERRUPT_ENTRY(8) +DISTINCT_INTERRUPT_ENTRY(9) +DISTINCT_INTERRUPT_ENTRY(10) +DISTINCT_INTERRUPT_ENTRY(11) +DISTINCT_INTERRUPT_ENTRY(12) +DISTINCT_INTERRUPT_ENTRY(13) +DISTINCT_INTERRUPT_ENTRY(14) +DISTINCT_INTERRUPT_ENTRY(15) +DISTINCT_INTERRUPT_ENTRY(16) + + /* + * routine used to initialize the IDT by default + */ + +PUBLIC (default_raw_idt_handler) +PUBLIC (raw_idt_notify) + +SYM (default_raw_idt_handler): + pusha + cld + mov esp, ebp + andl $ - CPU_STACK_ALIGNMENT, esp + call raw_idt_notify + mov ebp, esp + popa + iret + +END_CODE + +END diff --git a/bsps/i386/shared/irq/irq_init.c b/bsps/i386/shared/irq/irq_init.c new file mode 100644 index 0000000000..fdf4801a5a --- /dev/null +++ b/bsps/i386/shared/irq/irq_init.c @@ -0,0 +1,191 @@ +/* irq_init.c + * + * This file contains the implementation of rtems initialization + * related to interrupt handling. + * + * Copyright (c) 2009 embedded brains GmbH + * CopyRight (C) 1998 valette@crf.canon.fr + * + * COPYRIGHT (c) 2011. + * On-Line Applications Research Corporation (OAR). + * + * 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 <rtems/bspIo.h> + +#include <rtems/score/cpu.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> + +/* + * rtems prologue generated in irq_asm.S + */ +extern void rtems_irq_prologue_0(void); +extern void rtems_irq_prologue_1(void); +extern void rtems_irq_prologue_2(void); +extern void rtems_irq_prologue_3(void); +extern void rtems_irq_prologue_4(void); +extern void rtems_irq_prologue_5(void); +extern void rtems_irq_prologue_6(void); +extern void rtems_irq_prologue_7(void); +extern void rtems_irq_prologue_8(void); +extern void rtems_irq_prologue_9(void); +extern void rtems_irq_prologue_10(void); +extern void rtems_irq_prologue_11(void); +extern void rtems_irq_prologue_12(void); +extern void rtems_irq_prologue_13(void); +extern void rtems_irq_prologue_14(void); +extern void rtems_irq_prologue_15(void); +extern void rtems_irq_prologue_16(void); +/* + * default vectors + */ +extern void default_raw_idt_handler(void); + +/* + * default raw on/off function + */ +static void raw_nop_func(const struct __rtems_raw_irq_connect_data__ *unused) +{ +} + +/* + * default raw isOn function + */ +static int raw_not_connected( + const struct __rtems_raw_irq_connect_data__ *unused +) +{ + return 0; +} + +static rtems_raw_irq_connect_data idtHdl[IDT_SIZE]; + +static rtems_raw_irq_hdl rtemsIrq[BSP_IRQ_VECTOR_NUMBER] = { + rtems_irq_prologue_0, + rtems_irq_prologue_1, + rtems_irq_prologue_2, + rtems_irq_prologue_3, + rtems_irq_prologue_4, + rtems_irq_prologue_5, + rtems_irq_prologue_6, + rtems_irq_prologue_7, + rtems_irq_prologue_8, + rtems_irq_prologue_9, + rtems_irq_prologue_10, + rtems_irq_prologue_11, + rtems_irq_prologue_12, + rtems_irq_prologue_13, + rtems_irq_prologue_14, + rtems_irq_prologue_15, + rtems_irq_prologue_16, +}; + +static rtems_raw_irq_connect_data defaultRawIrq = { + 0, /* vectorIdex */ + default_raw_idt_handler, /* hdl */ + raw_nop_func, /* on */ + raw_nop_func, /* off */ + raw_not_connected /* isOn */ +}; + +static interrupt_gate_descriptor idtEntry; + +static rtems_raw_irq_global_settings raw_initial_config; + + +/* + * This method is called from irq_asm.S and cannot be static. + */ +void raw_idt_notify(void) +{ + printk("raw_idt_notify has been called \n"); +} + +void rtems_irq_mngt_init(void) +{ + int i; + interrupt_gate_descriptor* idt_entry_tbl; + unsigned int limit; + rtems_interrupt_level level; + + i386_get_info_from_IDTR(&idt_entry_tbl, &limit); + + /* Convert into number of entries */ + limit = (limit + 1)/sizeof(interrupt_gate_descriptor); + + if(limit != IDT_SIZE) { + printk("IDT table size mismatch !!! System locked\n"); + while(1); + } + + /* + * The interrupt management can be initialized only once + * during system bootup and that should happen on boot + * CPU so there is no need to synchronize with others CPUs. + */ + rtems_interrupt_local_disable(level); + + /* + * Init the complete IDT vector table with defaultRawIrq value + */ + for (i = 0; i < IDT_SIZE ; i++) { + idtHdl[i] = defaultRawIrq; + idtHdl[i].idtIndex = i; + } + + raw_initial_config.idtSize = IDT_SIZE; + raw_initial_config.defaultRawEntry = defaultRawIrq; + raw_initial_config.rawIrqHdlTbl = idtHdl; + + if (!i386_init_idt (&raw_initial_config)) { + /* + * put something here that will show the failure... + */ + printk("Unable to initialize IDT!!! System locked\n"); + while (1); + } + /* + * Patch the entry that will be used by RTEMS for interrupt management + * with RTEMS prologue. + */ + for (i = 0; i < BSP_IRQ_VECTOR_NUMBER; i++) { + create_interrupt_gate_descriptor(&idtEntry, rtemsIrq[i]); + idt_entry_tbl[i + BSP_ASM_IRQ_VECTOR_BASE] = idtEntry; + } + /* + * At this point we have completed the initialization of IDT + * with raw handlers. We must now initialize the higher level + * interrupt management. + */ + + /* + * Init initial Interrupt management config + */ + bsp_interrupt_initialize(); + + /* + * #define DEBUG + */ +#ifdef DEBUG + { + /* + * following adresses should be the same + */ + unsigned tmp; + + printk("idt_entry_tbl = %x Interrupt_descriptor_table addr = %x\n", + idt_entry_tbl, &Interrupt_descriptor_table); + tmp = (unsigned) get_hdl_from_vector (BSP_ASM_IRQ_VECTOR_BASE + BSP_PERIODIC_TIMER); + printk("clock isr address from idt = %x should be %x\n", + tmp, (unsigned) rtems_irq_prologue_0); + } + printk("i8259s_cache = %x\n", * (unsigned short*) &i8259s_cache); + BSP_wait_polled_input(); +#endif +} diff --git a/bsps/lm32/shared/irq/irq.c b/bsps/lm32/shared/irq/irq.c new file mode 100644 index 0000000000..79626ee449 --- /dev/null +++ b/bsps/lm32/shared/irq/irq.c @@ -0,0 +1,30 @@ +/* irq.c + * + * Copyright (c) 2010 Sebastien Bourdeauducq + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <bsp.h> +#include <rtems/score/cpu.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + return RTEMS_SUCCESSFUL; +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + lm32_interrupt_unmask(1 << vector); +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + lm32_interrupt_mask(1 << vector); +} diff --git a/bsps/m68k/genmcf548x/irq/intc-icr-init-values.c b/bsps/m68k/genmcf548x/irq/intc-icr-init-values.c new file mode 100644 index 0000000000..afc58224ea --- /dev/null +++ b/bsps/m68k/genmcf548x/irq/intc-icr-init-values.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2013 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * 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 <bsp.h> +#include <bsp/irq.h> + +#define ICR(lvl, prio) (MCF548X_INTC_ICRn_IL(lvl) | MCF548X_INTC_ICRn_IP(prio)) + +const uint8_t mcf548x_intc_icr_init_values[64] = { + [MCF548X_IRQ_SLT0] = ICR(4, 7), + [MCF548X_IRQ_SLT1] = ICR(4, 6), + [MCF548X_IRQ_PSC0] = ICR(3, 7), + [MCF548X_IRQ_PSC1] = ICR(3, 6), + [MCF548X_IRQ_PSC2] = ICR(3, 5), + [MCF548X_IRQ_PSC3] = ICR(3, 4), + [MCF548X_IRQ_FEC0] = ICR(2, 7), + [MCF548X_IRQ_FEC1] = ICR(2, 6) +}; diff --git a/bsps/m68k/genmcf548x/irq/irq.c b/bsps/m68k/genmcf548x/irq/irq.c new file mode 100644 index 0000000000..f02231b67c --- /dev/null +++ b/bsps/m68k/genmcf548x/irq/irq.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2013 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * 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 <bsp/irq-generic.h> + +#include <mcf548x/mcf548x.h> + +void asm_default_interrupt(void); + +typedef void (*void_func)(void); + +typedef struct { + rtems_interrupt_handler handler; + void *arg; + const char *info; +} interrupt_control; + +static interrupt_control interrupt_controls[BSP_INTERRUPT_VECTOR_MAX + 1]; + +static uint32_t vector_to_reg(rtems_vector_number vector) +{ + return ((vector + 32U) >> 5) & 0x1; +} + +static uint32_t vector_to_bit(rtems_vector_number vector) +{ + return 1U << (vector & 0x1fU); +} + +static volatile uint32_t *vector_to_imr(rtems_vector_number vector) +{ + volatile uint32_t *imr = &MCF548X_INTC_IMRH; + + return &imr[vector_to_reg(vector)]; +} + +static rtems_vector_number exception_vector_to_vector( + rtems_vector_number exception_vector +) +{ + return exception_vector - 64U; +} + +static rtems_vector_number vector_to_exception_vector( + rtems_vector_number vector +) +{ + return vector + 64U; +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + volatile uint32_t *imr = vector_to_imr(vector); + uint32_t bit = vector_to_bit(vector); + rtems_interrupt_level level; + + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + rtems_interrupt_disable(level); + *imr &= ~bit; + rtems_interrupt_enable(level); +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + volatile uint32_t *imr = vector_to_imr(vector); + uint32_t bit = vector_to_bit(vector); + rtems_interrupt_level level; + + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + rtems_interrupt_disable(level); + *imr |= bit; + rtems_interrupt_enable(level); +} + +static void_func get_exception_handler(rtems_vector_number vector) +{ + void **vbr; + void_func *exception_table; + + m68k_get_vbr(vbr); + + exception_table = (void_func *)vbr; + + return exception_table[vector_to_exception_vector(vector)]; +} + +static void set_exception_handler(rtems_vector_number vector, void_func handler) +{ + void **vbr; + void_func *exception_table; + + m68k_get_vbr(vbr); + + exception_table = (void_func *)vbr; + + exception_table[vector_to_exception_vector(vector)] = handler; +} + +static void dispatch_handler(rtems_vector_number exception_vector) +{ + const interrupt_control *ic = + &interrupt_controls[exception_vector_to_vector(exception_vector)]; + + (*ic->handler)(ic->arg); +} + +static uint8_t get_intc_icr(rtems_vector_number vector) +{ + volatile uint8_t *icr = &MCF548X_INTC_ICR0; + + return icr[vector]; +} + +rtems_status_code rtems_interrupt_handler_install( + rtems_vector_number vector, + const char *info, + rtems_option options, + rtems_interrupt_handler handler, + void *arg +) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + if (bsp_interrupt_is_valid_vector(vector)) { + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + + if ( + get_exception_handler(vector) == asm_default_interrupt + && get_intc_icr(vector) != 0 + ) { + interrupt_control *ic = &interrupt_controls[vector]; + + ic->handler = handler; + ic->arg = arg; + ic->info = info; + + _ISR_Vector_table[vector_to_exception_vector(vector)] + = dispatch_handler; + set_exception_handler(vector, _ISR_Handler); + bsp_interrupt_vector_enable(vector); + } else { + sc = RTEMS_RESOURCE_IN_USE; + } + + rtems_interrupt_enable(level); + } else { + sc = RTEMS_INVALID_ID; + } + + return sc; +} + +static bool is_occupied_by_us(rtems_vector_number vector) +{ + return get_exception_handler(vector) == _ISR_Handler + && _ISR_Vector_table[vector_to_exception_vector(vector)] + == dispatch_handler; +} + +rtems_status_code rtems_interrupt_handler_remove( + rtems_vector_number vector, + rtems_interrupt_handler handler, + void *arg +) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + if (bsp_interrupt_is_valid_vector(vector)) { + rtems_interrupt_level level; + interrupt_control *ic = &interrupt_controls[vector]; + + rtems_interrupt_disable(level); + + if ( + is_occupied_by_us(vector) + && ic->handler == handler + && ic->arg == arg + ) { + bsp_interrupt_vector_disable(vector); + set_exception_handler(vector, asm_default_interrupt); + + memset(ic, 0, sizeof(*ic)); + } else { + sc = RTEMS_UNSATISFIED; + } + + rtems_interrupt_enable(level); + } else { + sc = RTEMS_INVALID_ID; + } + + return sc; +} + +rtems_status_code rtems_interrupt_handler_iterate( + rtems_vector_number vector, + rtems_interrupt_per_handler_routine routine, + void *arg +) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + if (bsp_interrupt_is_valid_vector(vector)) { + if (is_occupied_by_us(vector)) { + const interrupt_control *ic = &interrupt_controls[vector]; + + (*routine)(arg, ic->info, RTEMS_INTERRUPT_UNIQUE, ic->handler, ic->arg); + } + } else { + sc = RTEMS_INVALID_ID; + } + + return sc; +} diff --git a/bsps/mips/csb350/irq/vectorisrs.c b/bsps/mips/csb350/irq/vectorisrs.c new file mode 100644 index 0000000000..d8e071281e --- /dev/null +++ b/bsps/mips/csb350/irq/vectorisrs.c @@ -0,0 +1,168 @@ +/** + * @file + * + * Au1x00 Interrupt Vectoring + */ + +/* + * Copyright (c) 2005 by Cogent Computer Systems + * Written by Jay Monkman <jtm@lopingdog.com> + * + * 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 <rtems.h> +#include <stdlib.h> +#include <libcpu/au1x00.h> +#include <libcpu/isr_entries.h> +#include <rtems/irq.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> + +static void call_vectored_isr(CPU_Interrupt_frame *, uint32_t , void *); + +#include <rtems/bspIo.h> /* for printk */ + +void mips_vector_isr_handlers( CPU_Interrupt_frame *frame ) +{ + unsigned int sr; + unsigned int cause; + + mips_get_sr( sr ); + mips_get_cause( cause ); + + cause &= (sr & SR_IMASK); + cause >>= CAUSE_IPSHIFT; + + /* count/compare interrupt */ + if ( cause & 0x80 ) { + unsigned long zero = 0; + /* + * I don't see a good way to disable the compare + * interrupt, so let's just ignore it. + */ + __asm__ volatile ("mtc0 %0, $11\n" :: "r" (zero)); + } + + /* Performance counter */ + if ( cause & 0x40 ) { + bsp_interrupt_handler_dispatch(AU1X00_IRQ_PERF); + } + + /* Interrupt controller 0 */ + if ( cause & 0x0c ) { + call_vectored_isr(frame, cause, (void *)AU1X00_IC0_ADDR); + } + + /* Interrupt controller 1 */ + if ( cause & 0x30 ) { + call_vectored_isr(frame, cause, (void *)AU1X00_IC1_ADDR); + } + + /* SW[0] */ + if ( cause & 0x01 ) + bsp_interrupt_handler_dispatch( AU1X00_IRQ_SW0 ); + + /* SW[1] */ + if ( cause & 0x02 ) + bsp_interrupt_handler_dispatch( AU1X00_IRQ_SW1 ); +} + +void mips_default_isr( int vector ) +{ + unsigned int sr; + unsigned int cause; + + mips_get_sr( sr ); + mips_get_cause( cause ); + + printk( "Unhandled isr exception: vector 0x%02x, cause 0x%08X, sr 0x%08X\n", + vector, cause, sr ); + rtems_fatal_error_occurred(1); +} + +static void call_vectored_isr( + CPU_Interrupt_frame *frame, + uint32_t cause, + void *ctrlr + ) +{ + uint32_t src; + uint32_t mask; + int index; + + /* get mask register */ + mask = AU1X00_IC_MASKRD(ctrlr); + + /* check request 0 */ + src = AU1X00_IC_REQ0INT(ctrlr); + src = src & mask; + index = 0; + while (src) { + /* check LSB */ + if (src & 1) { + /* clear rising/falling edge detects */ + AU1X00_IC_RISINGCLR(ctrlr) = (1 << index); + AU1X00_IC_FALLINGCLR(ctrlr) = (1 << index); + au_sync(); + bsp_interrupt_handler_dispatch(AU1X00_IRQ_IC0_BASE + index); + } + index ++; + + /* shift, and make sure MSB is clear */ + src = (src >> 1) & 0x7fffffff; + } + + /* check request 1 */ + src = AU1X00_IC_REQ1INT(ctrlr); + src = src & mask; + index = 0; + while (src) { + /* check LSB */ + if (src & 1) { + /* clear rising/falling edge detects */ + AU1X00_IC_RISINGCLR(ctrlr) = (1 << index); + AU1X00_IC_FALLINGCLR(ctrlr) = (1 << index); + au_sync(); + bsp_interrupt_handler_dispatch(AU1X00_IRQ_IC0_BASE + index); + } + index ++; + + /* shift, and make sure MSB is clear */ + src = (src >> 1) & 0x7fffffff; + } +} + +/* Generate a software interrupt */ +int assert_sw_irq(uint32_t irqnum) +{ + uint32_t cause; + + if (irqnum <= 1) { + mips_get_cause(cause); + cause = cause | ((irqnum + 1) << CAUSE_IPSHIFT); + mips_set_cause(cause); + + return irqnum; + } else { + return -1; + } +} + +/* Clear a software interrupt */ +int negate_sw_irq(uint32_t irqnum) +{ + uint32_t cause; + + if (irqnum <= 1) { + mips_get_cause(cause); + cause = cause & ~((irqnum + 1) << CAUSE_IPSHIFT); + mips_set_cause(cause); + + return irqnum; + } else { + return -1; + } +} diff --git a/bsps/mips/hurricane/irq/vectorisrs.c b/bsps/mips/hurricane/irq/vectorisrs.c new file mode 100644 index 0000000000..e55566697d --- /dev/null +++ b/bsps/mips/hurricane/irq/vectorisrs.c @@ -0,0 +1,58 @@ +/** + * @file + * + * RM5231 Interrupt Vectoring + */ + +/* + * COPYRIGHT (c) 1989-2012. + * On-Line Applications Research Corporation (OAR). + * + * 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 <rtems.h> +#include <stdlib.h> +#include <libcpu/isr_entries.h> +#include <libcpu/rm5231.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> + +#include <rtems/bspIo.h> /* for printk */ + +void mips_default_isr( int vector ); + +void mips_vector_isr_handlers( CPU_Interrupt_frame *frame ) +{ + unsigned int sr; + unsigned int cause; + unsigned int i; + unsigned int mask; + + mips_get_sr( sr ); + mips_get_cause( cause ); + + cause &= (sr & SR_IMASK); + cause >>= CAUSE_IPSHIFT; + + for ( i=1, mask=0x80 ; i<=8 ; i++, mask >>= 1 ) { + if ( cause & mask ) + bsp_interrupt_handler_dispatch( MIPS_INTERRUPT_BASE + 8 - i ); + } +} + +void mips_default_isr( int vector ) +{ + unsigned int sr; + unsigned int cause; + + mips_get_sr( sr ); + mips_get_cause( cause ); + + printk( "Unhandled isr exception: vector 0x%02x, cause 0x%08X, sr 0x%08X\n", + vector, cause, sr ); + rtems_fatal_error_occurred(1); +} + diff --git a/bsps/mips/jmr3904/irq/vectorisrs.c b/bsps/mips/jmr3904/irq/vectorisrs.c new file mode 100644 index 0000000000..629c4c45f8 --- /dev/null +++ b/bsps/mips/jmr3904/irq/vectorisrs.c @@ -0,0 +1,47 @@ +/** + * @file + * + * TX3904 Interrupt Vectoring + */ + +/* + * COPYRIGHT (c) 1989-2012. + * On-Line Applications Research Corporation (OAR). + * + * 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 <rtems.h> +#include <stdlib.h> +#include <bsp/irq.h> +#include <rtems/bspIo.h> /* for printk */ +#include <bsp/irq-generic.h> +#include <libcpu/isr_entries.h> + +void mips_vector_isr_handlers( CPU_Interrupt_frame *frame ) +{ + unsigned int sr; + unsigned int cause; + + mips_get_sr( sr ); + mips_get_cause( cause ); + + cause &= (sr & SR_IMASK); + cause >>= CAUSE_IPSHIFT; + + if ( cause & 0x80 ) /* IP[5] ==> INT0 */ + bsp_interrupt_handler_dispatch( TX3904_IRQ_INT0 ); + + if ( cause & 0x40 ) { /* (IP[4] == 1) ==> IP[0-3] are valid */ + unsigned int v = (cause >> 2) & 0x0f; + bsp_interrupt_handler_dispatch( MIPS_INTERRUPT_BASE + v ); + } + + if ( cause & 0x02 ) /* SW[0] */ + bsp_interrupt_handler_dispatch( TX3904_IRQ_SOFTWARE_1 ); + + if ( cause & 0x01 ) /* IP[1] */ + bsp_interrupt_handler_dispatch( TX3904_IRQ_SOFTWARE_2 ); +} diff --git a/bsps/mips/malta/irq/interruptmask.c b/bsps/mips/malta/irq/interruptmask.c new file mode 100644 index 0000000000..d639ab17a9 --- /dev/null +++ b/bsps/mips/malta/irq/interruptmask.c @@ -0,0 +1,36 @@ +/** + * @file + * + * This file contains the implementation of the MIPS port + * support routine which provides the BSP specific default + * interrupt mask. + */ + +/* + * COPYRIGHT (c) 1989-2012. + * On-Line Applications Research Corporation (OAR). + * + * 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 <rtems.h> + +/* + * This function returns a mask value which is used to select the bits + * in the processor status register that can be set to enable interrupts. + * The mask value should not include the 2 software interrupt enable bits. + */ + +uint32_t mips_interrupt_mask( void ) +{ + uint32_t interrupt_mask; + + /* + * This has only been tested with qemu for the mips malta and + * may not be correct for the 24k on real hardware. + */ + interrupt_mask = 0x0000ff00; + return(interrupt_mask); +} diff --git a/bsps/mips/malta/irq/vectorisrs.c b/bsps/mips/malta/irq/vectorisrs.c new file mode 100644 index 0000000000..a2b9288646 --- /dev/null +++ b/bsps/mips/malta/irq/vectorisrs.c @@ -0,0 +1,90 @@ +/** + * @file + * + */ + +/* + * COPYRIGHT (c) 1989-2012. + * On-Line Applications Research Corporation (OAR). + * + * 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 <rtems.h> +#include <stdlib.h> +#include <bsp/irq-generic.h> +#include <bsp/pci.h> +#include <bsp/i8259.h> +#include <bsp.h> +#include <libcpu/isr_entries.h> + +void mips_default_isr( int vector ); + +#include <rtems/bspIo.h> /* for printk */ + +void mips_vector_isr_handlers( CPU_Interrupt_frame *frame ) +{ + unsigned int sr; + unsigned int cause; + unsigned int pending; + + mips_get_sr( sr ); + mips_get_cause( cause ); + + pending = (cause & sr & 0xff00) >> CAUSE_IPSHIFT; + + /* SW Bits */ + if ( pending & 0x01) { + printk("Pending IRQ Q 0x%x\n", pending ); + } + + if ( pending & 0x02) { + printk("Pending IRQ Q 0x%x\n", pending ); + } + + /* South Bridge Interrupt */ + if ( pending & 0x04) { + BSP_i8259s_int_process(); + } + + /* South Bridge SMI */ + if (pending & 0x08){ + printk( "Pending IRQ 0x%x\n", pending ); + } + + /* TTY 2 */ + if (pending & 0x10) { + printk( "Pending IRQ 0x%x\n", pending ); + } + /* Core HI */ + if (pending & 0x20) { + printk( "Pending IRQ 0x%x\n", pending ); + } + /* Core LO */ + if (pending & 0x40) { + printk( "Pending IRQ 0x%x\n", pending ); + } + + if ( pending & 0x80 ) { + bsp_interrupt_handler_dispatch( MALTA_INT_TICKER ); + } +} + +void mips_default_isr( int vector ) +{ + unsigned int sr; + unsigned int cause; + + mips_get_sr( sr ); + mips_get_cause( cause ); + + printk( "Unhandled isr exception: vector 0x%02x, cause 0x%08X, sr 0x%08X\n", + vector, cause, sr ); + + while(1); /* Lock it up */ + + rtems_fatal_error_occurred(1); +} + diff --git a/bsps/mips/rbtx4925/irq/vectorisrs.c b/bsps/mips/rbtx4925/irq/vectorisrs.c new file mode 100644 index 0000000000..09020c5020 --- /dev/null +++ b/bsps/mips/rbtx4925/irq/vectorisrs.c @@ -0,0 +1,64 @@ +/** + * @file + * + * TX4925 Interrupt Vectoring + */ + +/* + * COPYRIGHT (c) 1989-2012. + * On-Line Applications Research Corporation (OAR). + * + * 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 <rtems.h> +#include <stdlib.h> +#include <libcpu/isr_entries.h> +#include <libcpu/tx4925.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> +#include <rtems/bspIo.h> /* for printk */ + +void mips_default_isr( int vector ); + +void mips_vector_isr_handlers( CPU_Interrupt_frame *frame ) +{ + unsigned int sr; + unsigned int cause; + unsigned int pending; + + mips_get_sr( sr ); + mips_get_cause( cause ); + + pending = (cause & sr & 0x700) >> CAUSE_IPSHIFT; + + if ( pending & 0x4 ) { /* (IP[2] == 1) ==> IP[3-7] are valid */ + unsigned int v = (cause >> (CAUSE_IPSHIFT + 3)) & 0x1f; + bsp_interrupt_handler_dispatch( MIPS_INTERRUPT_BASE + v ); + } + + if ( pending & 0x01 ) /* IP[0] */ + bsp_interrupt_handler_dispatch( TX4925_IRQ_SOFTWARE_1 ); + + if ( pending & 0x02 ) /* IP[1] */ + bsp_interrupt_handler_dispatch( TX4925_IRQ_SOFTWARE_2 ); +} + +void mips_default_isr( int vector ) +{ + unsigned int sr; + unsigned int cause; + + mips_get_sr( sr ); + mips_get_cause( cause ); + + printk( "Unhandled isr exception: vector 0x%02x, cause 0x%08X, sr 0x%08X\n", + vector, cause, sr ); + + while(1); /* Lock it up */ + + rtems_fatal_error_occurred(1); +} + diff --git a/bsps/mips/rbtx4938/irq/vectorisrs.c b/bsps/mips/rbtx4938/irq/vectorisrs.c new file mode 100644 index 0000000000..d38e4f81c2 --- /dev/null +++ b/bsps/mips/rbtx4938/irq/vectorisrs.c @@ -0,0 +1,64 @@ +/** + * @file + * + * TX4925 Interrupt Vectoring + */ + +/* + * COPYRIGHT (c) 1989-2012. + * On-Line Applications Research Corporation (OAR). + * + * 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 <rtems.h> +#include <stdlib.h> +#include <libcpu/isr_entries.h> +#include <libcpu/tx4938.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> +#include <rtems/bspIo.h> /* for printk */ + +void mips_default_isr( int vector ); + +void mips_vector_isr_handlers( CPU_Interrupt_frame *frame ) +{ + unsigned int sr; + unsigned int cause; + unsigned int pending; + + mips_get_sr( sr ); + mips_get_cause( cause ); + + pending = (cause & sr & 0x700) >> CAUSE_IPSHIFT; + + if ( pending & 0x4 ) { /* (IP[2] == 1) ==> IP[3-7] are valid */ + unsigned int v = (cause >> (CAUSE_IPSHIFT + 3)) & 0x1f; + bsp_interrupt_handler_dispatch( MIPS_INTERRUPT_BASE + v ); + } + + if ( pending & 0x01 ) /* IP[0] */ + bsp_interrupt_handler_dispatch( TX4938_IRQ_SOFTWARE_1 ); + + if ( pending & 0x02 ) /* IP[1] */ + bsp_interrupt_handler_dispatch( TX4938_IRQ_SOFTWARE_2 ); +} + +void mips_default_isr( int vector ) +{ + unsigned int sr; + unsigned int cause; + + mips_get_sr( sr ); + mips_get_cause( cause ); + + printk( "Unhandled isr exception: vector 0x%02x, cause 0x%08X, sr 0x%08X\n", + vector, cause, sr ); + + while(1); /* Lock it up */ + + rtems_fatal_error_occurred(1); +} + diff --git a/bsps/mips/shared/irq/exception.S b/bsps/mips/shared/irq/exception.S new file mode 100644 index 0000000000..e916ae55fe --- /dev/null +++ b/bsps/mips/shared/irq/exception.S @@ -0,0 +1,661 @@ +/* + * This file contains a customized MIPS exception handler. + * It hooks into the exception handler present in the resident + * PMON debug monitor. + */ + +/* + * Author: Bruce Robinson + * + * This code was derived from cpu_asm.S with the following copyright: + * + * COPYRIGHT (c) 1996 by Transition Networks Inc. + * + * To anyone who acknowledges that this file is provided "AS IS" + * without any express or implied warranty: + * permission to use, copy, modify, and distribute this file + * for any purpose is hereby granted without fee, provided that + * the above copyright notice and this notice appears in all + * copies, and that the name of Transition Networks not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * Transition Networks makes no representations about the suitability + * of this software for any purpose. + * + * Derived from c/src/exec/score/cpu/no_cpu/cpu_asm.s: + * + * COPYRIGHT (c) 1989-2010. + * On-Line Applications Research Corporation (OAR). + * + * 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 <bspopts.h> +#include <rtems/asm.h> +#include <rtems/score/percpu.h> +#include <rtems/mips/iregdef.h> +#include <rtems/mips/idtcpu.h> +#if BSP_HAS_USC320 + #include <usc.h> +#endif + +#if __mips == 3 +/* 64 bit register operations */ +#define NOP nop +#define ADD dadd +#define STREG sd +#define LDREG ld +#define ADDU addu +#define ADDIU addiu +#define STREGC1 sdc1 +#define LDREGC1 ldc1 +#define R_SZ 8 +#define F_SZ 8 +#define SZ_INT 8 +#define SZ_INT_POW2 3 + +/* XXX if we don't always want 64 bit register ops, then another ifdef */ + +#elif __mips == 1 +/* 32 bit register operations*/ +#define NOP nop +#define ADD add +#define STREG sw +#define LDREG lw +#define ADDU add +#define ADDIU addi +#define STREGC1 swc1 +#define LDREGC1 lwc1 +#define R_SZ 4 +#define F_SZ 4 +#define SZ_INT 4 +#define SZ_INT_POW2 2 +#else +#error "mips assembly: what size registers do I deal with?" +#endif + + +#define ISR_VEC_SIZE 4 +#define EXCP_STACK_SIZE (NREGS*R_SZ) + +.extern _Thread_Dispatch + +/* void __ISR_Handler() + * + * This routine provides the RTEMS interrupt management. + * + */ + +#if 0 +void _ISR_Handler() +{ + /* + * This discussion ignores a lot of the ugly details in a real + * implementation such as saving enough registers/state to be + * able to do something real. Keep in mind that the goal is + * to invoke a user's ISR handler which is written in C and + * uses a certain set of registers. + * + * Also note that the exact order is to a large extent flexible. + * Hardware will dictate a sequence for a certain subset of + * _ISR_Handler while requirements for setting + */ + + /* + * At entry to "common" _ISR_Handler, the vector number must be + * available. On some CPUs the hardware puts either the vector + * number or the offset into the vector table for this ISR in a + * known place. If the hardware does not give us this information, + * then the assembly portion of RTEMS for this port will contain + * a set of distinct interrupt entry points which somehow place + * the vector number in a known place (which is safe if another + * interrupt nests this one) and branches to _ISR_Handler. + * + */ +#endif +FRAME(bsp_ISR_Handler,sp,0,ra) + .set noreorder + +#if 0 +/* Activate TX49xx PIO19 signal for diagnostics */ + lui k0,0xff1f + ori k0,k0,0xf500 + lw k0,(k0) + lui k1,0x8 + or k1,k1,k0 + lui k0,0xff1f + ori k0,k0,0xf500 + sw k1,(k0) +#endif + mfc0 k0,C0_CAUSE /* Determine if an interrupt generated this exception */ + nop + and k1,k0,CAUSE_EXCMASK + beq k1,zero,_chk_int /* If so, branch to service here */ + nop + la k0,_int_esr_link /* Otherwise, jump to next exception handler in PMON exception chain */ + lw k0,(k0) + lw k0,4(k0) + j k0 + nop +_chk_int: + mfc0 k1,C0_SR + nop + and k0,k1 +#if HAS_RM52xx + and k0,CAUSE_IPMASK +#elif HAS_TX49xx + and k0,(SR_IBIT1 | SR_IBIT2 | SR_IBIT3) +#endif + /* external interrupt not enabled, ignore */ + beq k0,zero,_ISR_Handler_quick_exit + nop + +/* For debugging interrupts, clear EXL to allow breakpoints */ +#if 0 + MFC0 k0, C0_SR +#if __mips == 3 + li k1,SR_EXL /* Clear EXL and Set IE to enable interrupts */ + not k1 + and k0,k1 + li k1,SR_IE +#elif __mips == 1 + li k1,SR_IEC +#endif + or k0, k1 + mtc0 k0, C0_SR + NOP +#endif + + + /* + * save some or all context on stack + * may need to save some special interrupt information for exit + */ + + /* Q: _ISR_Handler, not using IDT/SIM ...save extra regs? */ + + /* wastes a lot of stack space for context?? */ + ADDIU sp,sp,-EXCP_STACK_SIZE + + STREG ra, R_RA*R_SZ(sp) /* store ra on the stack */ + STREG v0, R_V0*R_SZ(sp) + STREG v1, R_V1*R_SZ(sp) + STREG a0, R_A0*R_SZ(sp) + STREG a1, R_A1*R_SZ(sp) + STREG a2, R_A2*R_SZ(sp) + STREG a3, R_A3*R_SZ(sp) + STREG t0, R_T0*R_SZ(sp) + STREG t1, R_T1*R_SZ(sp) + STREG t2, R_T2*R_SZ(sp) + STREG t3, R_T3*R_SZ(sp) + STREG t4, R_T4*R_SZ(sp) + STREG t5, R_T5*R_SZ(sp) + STREG t6, R_T6*R_SZ(sp) + STREG t7, R_T7*R_SZ(sp) + mflo t0 + STREG t8, R_T8*R_SZ(sp) + STREG t0, R_MDLO*R_SZ(sp) + STREG t9, R_T9*R_SZ(sp) + mfhi t0 + STREG gp, R_GP*R_SZ(sp) + STREG t0, R_MDHI*R_SZ(sp) + STREG fp, R_FP*R_SZ(sp) + + .set noat + STREG AT, R_AT*R_SZ(sp) + .set at + + mfc0 t0,C0_SR + dmfc0 t1,C0_EPC + STREG t0,R_SR*R_SZ(sp) + STREG t1,R_EPC*R_SZ(sp) + + /* + * + * #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE ) + * if ( _ISR_Nest_level == 0 ) + * switch to software interrupt stack + * #endif + */ + + /* + * _ISR_Nest_level++; + */ + lw t0,ISR_NEST_LEVEL + NOP + add t0,t0,1 + sw t0,ISR_NEST_LEVEL + /* + * _Thread_Dispatch_disable_level++; + */ + lw t1,THREAD_DISPATCH_DISABLE_LEVEL + NOP + add t1,t1,1 + sw t1,THREAD_DISPATCH_DISABLE_LEVEL + + /* DEBUG - Add the following code to disable interrupts and clear + * EXL in status register, this will allow memory + * exceptions to occur while servicing the current interrupt + */ +#if 0 + /* Disable interrupts from internal interrupt controller */ + li t0,~CAUSE_IP2_MASK + mfc0 t1,C0_SR + nop + and t1,t0 + mtc0 t1,C0_SR + nop + /* Clear EXL in status register to allow memory exceptions to occur */ + li t0,~SR_EXL + mfc0 t1,C0_SR + nop + and t1,t0 + mtc0 t1,C0_SR + nop +#endif + + /* + * Call the CPU model or BSP specific routine to decode the + * interrupt source and actually vector to device ISR handlers. + */ + move a0,sp + jal mips_vector_isr_handlers + NOP + + /* Add the following code to disable interrupts (see DEBUG above) */ +#if 0 + li t0,SR_EXL /* Set EXL to hold off interrupts */ + mfc0 t1,C0_SR + nop + or t1,t0 + mtc0 t1,C0_SR + nop + /* Enable interrupts from internal interrupt controller */ + li t0,CAUSE_IP2_MASK + mfc0 t1,C0_SR + nop + or t1,t0 + mtc0 t1,C0_SR + nop +#endif + +_ISR_Handler_cleanup: + + /* + * --_ISR_Nest_level; + */ + lw t2,ISR_NEST_LEVEL + NOP + add t2,t2,-1 + sw t2,ISR_NEST_LEVEL + /* + * --_Thread_Dispatch_disable_level; + */ + lw t1,THREAD_DISPATCH_DISABLE_LEVEL + NOP + add t1,t1,-1 + sw t1,THREAD_DISPATCH_DISABLE_LEVEL + /* + * if ( _Thread_Dispatch_disable_level || _ISR_Nest_level ) + * goto the label "exit interrupt (simple case)" + */ + or t0,t2,t1 + bne t0,zero,_ISR_Handler_exit + NOP + + + /* + * #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE ) + * restore stack + * #endif + * + * if ( !_Thread_Dispatch_necessary ) + * goto the label "exit interrupt (simple case)" + */ + lb t0,DISPATCH_NEEDED + NOP + or t0,t0,t0 + beq t0,zero,_ISR_Handler_exit + NOP + +/* +** Turn on interrupts before entering Thread_Dispatch which +** will run for a while, thus allowing new interrupts to +** be serviced. Observe the Thread_Dispatch_disable_level interlock +** that prevents recursive entry into Thread_Dispatch. +*/ + + mfc0 t0, C0_SR +#if __mips == 3 + li t1,SR_EXL /* Clear EXL and Set IE to enable interrupts */ + not t1 + and t0,t1 + li t1,SR_IE +#elif __mips == 1 + li t1,SR_IEC +#endif + or t0, t1 + mtc0 t0, C0_SR + NOP + + /* save off our stack frame so the context switcher can get to it */ + la t0,__exceptionStackFrame + STREG sp,(t0) + + jal _Thread_Dispatch + NOP + + /* and make sure its clear in case we didn't dispatch. if we did, its + ** already cleared */ + la t0,__exceptionStackFrame + STREG zero,(t0) + NOP + +/* +** turn interrupts back off while we restore context so +** a badly timed interrupt won't accidentally mess things up +*/ + mfc0 t0, C0_SR +#if __mips == 3 + li t1,SR_IE /* Clear IE first (recommended) */ + not t1 + and t0,t1 + mtc0 t0, C0_SR + li t1,SR_EXL | SR_IE /* Set EXL and IE, this puts status register bits back to interrupted state */ + or t0,t1 +#elif __mips == 1 + /* ints off, current & prev kernel mode on (kernel mode enabled is bit clear..argh!) */ + li t1,SR_IEC | SR_KUP | SR_KUC + not t1 + and t0, t1 +#endif + mtc0 t0, C0_SR + NOP + + /* + * prepare to get out of interrupt + * return from interrupt (maybe to _ISR_Dispatch) + * + * LABEL "exit interrupt (simple case):" + * prepare to get out of interrupt + * return from interrupt + */ + +_ISR_Handler_exit: + +/* restore interrupt context from stack */ + LDREG t8, R_MDLO*R_SZ(sp) + LDREG t0, R_T0*R_SZ(sp) + mtlo t8 + LDREG t8, R_MDHI*R_SZ(sp) + LDREG t1, R_T1*R_SZ(sp) + mthi t8 + LDREG t2, R_T2*R_SZ(sp) + LDREG t3, R_T3*R_SZ(sp) + LDREG t4, R_T4*R_SZ(sp) + LDREG t5, R_T5*R_SZ(sp) + LDREG t6, R_T6*R_SZ(sp) + LDREG t7, R_T7*R_SZ(sp) + LDREG t8, R_T8*R_SZ(sp) + LDREG t9, R_T9*R_SZ(sp) + LDREG gp, R_GP*R_SZ(sp) + LDREG fp, R_FP*R_SZ(sp) + LDREG ra, R_RA*R_SZ(sp) + LDREG a0, R_A0*R_SZ(sp) + LDREG a1, R_A1*R_SZ(sp) + LDREG a2, R_A2*R_SZ(sp) + LDREG a3, R_A3*R_SZ(sp) + LDREG v1, R_V1*R_SZ(sp) + LDREG v0, R_V0*R_SZ(sp) + + LDREG k1, R_EPC*R_SZ(sp) + mtc0 k1,C0_EPC + + .set noat + LDREG AT, R_AT*R_SZ(sp) + .set at + + ADDIU sp,sp,EXCP_STACK_SIZE + +_ISR_Handler_quick_exit: + eret + nop + + +#if BSP_HAS_USC320 + /* Interrupts from USC320 are serviced here */ + .global USC_isr + .extern Clock_isr +USC_isr: + /* check if it's a USC320 heartbeat interrupt */ + la k0,INT_STAT /* read INT_STAT register */ + lw k0,(k0) + nop /* reading from external device */ + sll k0,(31-21) /* test bit 21 (HBI) */ + + bgez k0,USC_isr2 /* branch if not a heartbeat interrupt */ + NOP + + /* clear the heartbeat interrupt */ + la k0,INT_STAT + li t0,HBI_MASK + sw t0,(k0) + /* wait for interrupt to clear */ +USC_isr1: + la k0,INT_STAT /* read INT_STAT register */ + lw k0,(k0) + nop /* reading from external device */ + sll k0,(31-21) /* test bit 21 (HBI) */ + bltz k0,USC_isr1 /* branch if bit set */ + nop + j Clock_isr /* Jump to clock isr */ + nop +USC_isr2: + j ra /* no serviceable interrupt, return without doing anything */ + nop +#endif + +#if 0 + .global int7_isr + .extern Interrupt_7_isr +int7_isr: + /* Verify interrupt is from Timer */ + la k0,IRCS /* read Interrupt Current Status register */ + lw k0,(k0) + nop /* reading from external device */ + li k1,IRCS_CAUSE_MASK + and k0,k0,k1 /* isolate interrupt cause */ + + li k1,INT7INT /* test for interrupt 7 */ + subu k1,k0,k1 + beq k1,zero,int7_isr1 + nop + j ra /* interrupt 7 no longer valid, return without doing anything */ + nop +int7_isr1: + j Interrupt_7_isr /* Jump to Interrupt 7 isr */ + nop +#endif + + .set reorder + +ENDFRAME(bsp_ISR_Handler) + + +FRAME(_BRK_Handler,sp,0,ra) + .set noreorder + +#if BSP_HAS_USC320 + la k0,INT_CFG3 /* Disable heartbeat interrupt in USC320, it interferes with PMON exception handler */ + lw k1,(k0) + li k0,~HBI_MASK + and k1,k1,k0 + la k0,INT_CFG3 + sw k1,(k0) +#endif + + la k0,_brk_esr_link /* Jump to next exception handler in PMON exception chain */ + lw k0,(k0) + lw k0,4(k0) + j k0 + nop + + .set reorder +ENDFRAME(_BRK_Handler) + + +/************************************************************************** +** +** init_exc_vecs() - moves the exception code into the addresses +** reserved for exception vectors +** +** UTLB Miss exception vector at address 0x80000000 +** +** General exception vector at address 0x80000080 +** +** RESET exception vector is at address 0xbfc00000 +** +***************************************************************************/ + +FRAME(init_exc_vecs,sp,0,ra) + .set noreorder + + .extern mon_onintr + +/* Install interrupt handler in PMON exception handling chain */ + + addiu sp,sp,-8 + sw ra,(sp) /* Save ra contents on stack */ + move a0,zero + la a1,_int_esr_link + jal mon_onintr /* Make PMON system call to install interrupt exception handler */ + nop + li a0,9 + la a1,_brk_esr_link + jal mon_onintr /* Make PMON system call to install break exception handler */ + nop + lw ra,(sp) + addiu sp,sp,8 /* Restore ra contents from stack */ + j ra + nop + + .set reorder +ENDFRAME(init_exc_vecs) + + +#if 0 /* Unused code below */ + +/************************************************************* +* enable_int7(ints) +* Enable interrupt 7 +*/ +FRAME(enable_int7,sp,0,ra) + .set noreorder + + la t0,IRDM1 # Set interrupt controller detection mode (bits 2-3 = 0 for int 7 active low) + li t1,0x0 + sw t1,(t0) + + la t0,IRLVL4 # Set interrupt controller level (bit 8-10 = 2 for int 7 at level 2) + li t1,0x200 + sw t1,(t0) + + la t0,IRMSK # Set interrupt controller mask + li t1,0x0 + sw t1,(t0) + + la t0,IRDEN # Enable interrupts from controller + li t1,0x1 + sw t1,(t0) + + j ra + nop + .set reorder +ENDFRAME(enable_int7) + +/************************************************************* +* disable_int7(ints) +* Disable interrupt 7 +*/ +FRAME(disable_int7,sp,0,ra) + .set noreorder + + la t0,IRLVL4 # Set interrupt controller level (bit 8-10 = 0 to diasble int 7) + li t1,0x200 + sw t1,(t0) + + j ra + nop + .set reorder +ENDFRAME(disable_int7) +#endif + +/************************************************************* +* exception: +* Diagnostic code that can be hooked to PMON interrupt handler. +* Generates pulse on PIO22 pin. +* Called from _exception code in PMON (see mips.s of PMON). +* Return address is located in k1. +*/ +FRAME(tx49xxexception,sp,0,ra) + .set noreorder + la k0,k1tmp + sw k1,(k0) + +/* Activate TX49xx PIO22 signal for diagnostics */ + lui k0,0xff1f + ori k0,k0,0xf500 + lw k0,(k0) + lui k1,0x40 + or k1,k1,k0 + lui k0,0xff1f + ori k0,k0,0xf500 + sw k1,(k0) + nop + +/* De-activate TX49xx PIO22 signal for diagnostics */ + lui k0,0xff1f + ori k0,k0,0xf500 + lw k0,(k0) + lui k1,0x40 + not k1 + and k1,k1,k0 + lui k0,0xff1f + ori k0,k0,0xf500 + sw k1,(k0) + nop + + la k0,k1tmp + lw k1,(k0) + j k1 + .set reorder +ENDFRAME(tx49xxexception) + + + + + .data + +k1tmp: .word 0 /* Temporary strage for K1 during interrupt service */ + +/************************************************************* +* +* Exception handler links, used in PMON exception handler chains +*/ + /* Interrupt exception service routine link */ + .global _int_esr_link +_int_esr_link: + .word 0 + .word bsp_ISR_Handler + + /* Break exception service routine link */ + .global _brk_esr_link +_brk_esr_link: + .word 0 + .word _BRK_Handler + + + + diff --git a/bsps/mips/shared/irq/i8259.c b/bsps/mips/shared/irq/i8259.c new file mode 100644 index 0000000000..d92b5400a9 --- /dev/null +++ b/bsps/mips/shared/irq/i8259.c @@ -0,0 +1,332 @@ +/** + * @file + * + * This file was based upon the powerpc and the i386. + */ + +/* + * COPYRIGHT (c) 1989-2012. + * On-Line Applications Research Corporation (OAR). + * + * 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. + */ + +/* + * Copyright (C) 1998, 1999 valette@crf.canon.fr + */ + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/i8259.h> +#include <bsp/pci.h> +#include <bsp/irq-generic.h> +#include <rtems/bspIo.h> + + +#define DEBUG_8259 1 + +#define ValidateIrqLine( _irq ) \ + if ( ((int)_irq < 0) ||((int)_irq > 16)) return 1; + +/*-------------------------------------------------------------------------+ +| Cache for 1st and 2nd PIC IRQ line's status (enabled or disabled) register. ++--------------------------------------------------------------------------*/ +/* + * lower byte is interrupt mask on the master PIC. + * while upper bits are interrupt on the slave PIC. + */ +volatile rtems_i8259_masks i8259s_cache = 0xfffb; + +/*-------------------------------------------------------------------------+ +| Function: BSP_irq_disable_at_i8259s +| Description: Mask IRQ line in appropriate PIC chip. +| Global Variables: i8259s_cache +| Arguments: vector_offset - number of IRQ line to mask. +| Returns: original state or -1 on error. ++--------------------------------------------------------------------------*/ +int BSP_irq_disable_at_i8259s (const rtems_irq_number irqLine) +{ + unsigned short mask; + rtems_interrupt_level level; + int rval; + + ValidateIrqLine(irqLine); + + rtems_interrupt_disable(level); + + /* Recalculate the value */ + mask = 1 << irqLine; + rval = i8259s_cache & mask ? 0 : 1; + i8259s_cache |= mask; + + /* Determine which chip and write the value. */ + if (irqLine < 8) { + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_IMR_IO_PORT, + i8259s_cache & 0xff + ); + } else { + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_SLAVE_IMR_IO_PORT, + ((i8259s_cache & 0xff00) >> 8) + ); + } + + rtems_interrupt_enable(level); + + return rval; +} + +/*-------------------------------------------------------------------------+ +| Function: BSP_irq_enable_at_i8259s +| Description: Unmask IRQ line in appropriate PIC chip. +| Global Variables: i8259s_cache +| Arguments: irqLine - number of IRQ line to mask. +| Returns: Nothing. ++--------------------------------------------------------------------------*/ +int BSP_irq_enable_at_i8259s (const rtems_irq_number irqLine) +{ + unsigned short mask; + rtems_interrupt_level level; + + ValidateIrqLine( irqLine ); + + rtems_interrupt_disable(level); + + /* Calculate the value */ + mask = ~(1 << irqLine); + i8259s_cache &= mask; + + /* Determine which chip and write the value */ + if (irqLine < 8) { + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_IMR_IO_PORT, + i8259s_cache & 0xff + ); + } else { + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_SLAVE_IMR_IO_PORT, + ((i8259s_cache & 0xff00) >> 8) + ); + } + + rtems_interrupt_enable(level); + + return 0; +} /* mask_irq */ + + +int BSP_irq_enabled_at_i8259s(const rtems_irq_number irqLine) +{ + unsigned short mask; + + ValidateIrqLine( irqLine ); + + mask = (1 << irqLine); + + return (~(i8259s_cache & mask)); +} + +/*-------------------------------------------------------------------------+ +| Function: BSP_irq_ack_at_i8259s +| Description: Signal generic End Of Interrupt (EOI) to appropriate PIC. +| Global Variables: None. +| Arguments: irqLine - number of IRQ line to acknowledge. +| Returns: Nothing. ++--------------------------------------------------------------------------*/ +int BSP_irq_ack_at_i8259s (const rtems_irq_number irqLine) +{ + if (irqLine >= 8) { + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_COMMAND_IO_PORT, + SLAVE_PIC_EOSI + ); + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_SLAVE_COMMAND_IO_PORT, + (PIC_EOSI | (irqLine - 8)) + ); + }else { + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_COMMAND_IO_PORT, + (PIC_EOSI | irqLine) + ); + } + + return 0; + +} /* ackIRQ */ + +void BSP_i8259s_init(void) +{ + volatile uint32_t i; + + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_MASTER_IMR_IO_PORT, 0xff ); + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_IMR_IO_PORT, 0xff ); + + + /* + * init master 8259 interrupt controller + */ + + /* Start init sequence */ + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_COMMAND_IO_PORT, + 0x11 + ); + /* Vector base = 0 */ + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_IMR_IO_PORT, + 0x00 + ); + + /* edge tiggered, Cascade (slave) on IRQ2 */ + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_IMR_IO_PORT, + 0x04 + ); + + /* Select 8086 mode */ + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_IMR_IO_PORT, + 0x01 + ); + + /* + * init slave interrupt controller + */ + + /* Start init sequence */ + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_COMMAND_IO_PORT, 0x11); + + /* Vector base = 8 */ + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_IMR_IO_PORT, 0x08); + + /* edge triggered, Cascade (slave) on IRQ2 */ + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_IMR_IO_PORT, 0x02); + + /* Select 8086 mode */ + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_IMR_IO_PORT, 0x01); + + /* Mask all except cascade */ + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_MASTER_IMR_IO_PORT, 0xFB); + + /* Mask all */ + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_IMR_IO_PORT, 0xFF); + + /* + * Enable all interrupts in debug mode. + */ + + if ( DEBUG_8259 ) { + i8259s_cache = 0x0101; + } + + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_IMR_IO_PORT, + i8259s_cache & 0xff + ); + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_SLAVE_IMR_IO_PORT, + ((i8259s_cache & 0xff00) >> 8) + ); + + for (i=0; i<10000; i++); +} + +#define PCI__GEN(bus, off, num) (((off)^((bus) << 7))+((num) << 4)) +#define PCI_INTR_ACK(bus) PCI__GEN(bus, 0x0c34, 0) + +volatile uint8_t master; +volatile uint8_t slave; +volatile uint8_t temp; + +void bsp_show_interrupt_regs(void); +void bsp_show_interrupt_regs() { + unsigned int sr; + unsigned int cause; + unsigned int pending; + + mips_get_sr( sr ); + mips_get_cause( cause ); + pending = (cause & sr & 0xff00) >> CAUSE_IPSHIFT; + + master = simple_in_8(BSP_8259_BASE_ADDRESS, PIC_MASTER_COMMAND_IO_PORT); + slave = simple_in_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_COMMAND_IO_PORT); + + printk("sr: 0x%x cause: 0x%x pending: 0x%x master: 0x%x slave: 0x%x\n", + sr, cause, pending, master, slave + ); +} + +int BSP_i8259s_int_process() +{ + uint8_t irq; + volatile uint32_t temp; + + /* Get the Interrupt */ + irq = simple_in_le32(BSP_PCI_BASE_ADDRESS, PCI_INTR_ACK(0) ); + + /* + * Mask interrupts + * + Mask all except cascade on master + * + Mask all on slave + */ + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_MASTER_IMR_IO_PORT, 0xFB); + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_IMR_IO_PORT, 0xFF); + + /* Call the Handler */ + temp = irq + MALTA_SB_IRQ_0; + bsp_interrupt_handler_dispatch( temp ); + + /* Reset the interrupt on the 8259 either the master or the slave chip */ + if (irq & 8) { + temp = simple_in_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_IMR_IO_PORT); + + /* Mask all */ + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_SLAVE_IMR_IO_PORT, 0xFF); + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_SLAVE_COMMAND_IO_PORT, + (PIC_EOSI + (irq&7)) + ); + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_COMMAND_IO_PORT, + SLAVE_PIC_EOSI + ); + } else { + temp = simple_in_8(BSP_8259_BASE_ADDRESS, PIC_MASTER_IMR_IO_PORT); + /* Mask all except cascade */ + simple_out_8(BSP_8259_BASE_ADDRESS, PIC_MASTER_IMR_IO_PORT, 0xFB); + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_MASTER_COMMAND_IO_PORT, + (PIC_EOSI+irq) + ); + } + + /* Restore the interrupts */ + simple_out_8(BSP_8259_BASE_ADDRESS,PIC_MASTER_IMR_IO_PORT,i8259s_cache&0xff); + simple_out_8( + BSP_8259_BASE_ADDRESS, + PIC_SLAVE_IMR_IO_PORT, + ((i8259s_cache & 0xff00) >> 8) + ); + + return 0; +} diff --git a/bsps/mips/shared/irq/interruptmask.c b/bsps/mips/shared/irq/interruptmask.c new file mode 100644 index 0000000000..c63421e569 --- /dev/null +++ b/bsps/mips/shared/irq/interruptmask.c @@ -0,0 +1,29 @@ +/** + * @file + * + */ + +/* + * COPYRIGHT (c) 1989-2012. + * On-Line Applications Research Corporation (OAR). + * + * 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 <rtems.h> + +/* + * This function returns a mask value which is used to select the bits + * in the processor status register that can be set to enable interrupts. + * The mask value should not include the 2 software interrupt enable bits. + */ + +uint32_t mips_interrupt_mask( void ) +{ + uint32_t interrupt_mask; + + interrupt_mask = 0x0000fc00; + return(interrupt_mask); +} diff --git a/bsps/mips/shared/irq/interruptmask_TX49.c b/bsps/mips/shared/irq/interruptmask_TX49.c new file mode 100644 index 0000000000..5b1daa57c3 --- /dev/null +++ b/bsps/mips/shared/irq/interruptmask_TX49.c @@ -0,0 +1,29 @@ +/** + * @file + * + */ + +/* + * COPYRIGHT (c) 1989-2012. + * On-Line Applications Research Corporation (OAR). + * + * 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 <rtems.h> + +/* + * This function returns a mask value which is used to select the bits + * in the processor status register that can be set to enable interrupts. + * The mask value should not include the 2 software interrupt enable bits. + */ + +uint32_t mips_interrupt_mask( void ) +{ + uint32_t interrupt_mask; + + interrupt_mask = 0x00000400; /* Toshiba TX49 processors have a non-standard interrupt mask */ + return(interrupt_mask); +} diff --git a/bsps/mips/shared/irq/irq.c b/bsps/mips/shared/irq/irq.c new file mode 100644 index 0000000000..1c2d3b8c5b --- /dev/null +++ b/bsps/mips/shared/irq/irq.c @@ -0,0 +1,101 @@ +/** + * @file + * + * @ingroup bsp_interrupt + * + * @brief Interrupt support. + */ + +/* + * Copyright (c) 2005 by Cogent Computer Systems + * Written by Jay Monkman <jtm@lopingdog.com> + * + * COPYRIGHT (c) 1989-2012. + * On-Line Applications Research Corporation (OAR). + * + * 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 <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> +#include <libcpu/isr_entries.h> +#include <rtems/bspIo.h> + +static const char *const cause_strings[32] = { + /* 0 */ "Int", + /* 1 */ "TLB Mods", + /* 2 */ "TLB Load", + /* 3 */ "TLB Store", + /* 4 */ "Address Load", + /* 5 */ "Address Store", + /* 6 */ "Instruction Bus Error", + /* 7 */ "Data Bus Error", + /* 8 */ "Syscall", + /* 9 */ "Breakpoint", + /* 10 */ "Reserved Instruction", + /* 11 */ "Coprocessor Unuseable", + /* 12 */ "Overflow", + /* 13 */ "Trap", + /* 14 */ "Instruction Virtual Coherency Error", + /* 15 */ "FP Exception", + /* 16 */ "Reserved 16", + /* 17 */ "Reserved 17", + /* 18 */ "Reserved 18", + /* 19 */ "Reserved 19", + /* 20 */ "Reserved 20", + /* 21 */ "Reserved 21", + /* 22 */ "Reserved 22", + /* 23 */ "Watch", + /* 24 */ "Reserved 24", + /* 25 */ "Reserved 25", + /* 26 */ "Reserved 26", + /* 27 */ "Reserved 27", + /* 28 */ "Reserved 28", + /* 29 */ "Reserved 29", + /* 30 */ "Reserved 30", + /* 31 */ "Data Virtual Coherency Error" +}; + +static inline bool bsp_irq_is_valid(rtems_vector_number vector) +{ + return vector <= BSP_INTERRUPT_VECTOR_MAX; +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + mips_install_isr_entries(); + return RTEMS_SUCCESSFUL; +} + +void bsp_interrupt_handler_default(rtems_vector_number vector) +{ + uint32_t sr; + uint32_t cause; + + mips_get_sr( sr ); + mips_get_cause( cause ); + + printk( "Unhandled exception %" PRId32 "\n", vector ); + printk( "sr: 0x%08" PRIu32 " cause: 0x%08" PRIu32 " --> %s\n", sr, cause, + cause_strings[(cause >> 2) &0x1f] ); + #if 0 + mips_dump_exception_frame( frame ); + #endif + rtems_fatal_error_occurred(1); +} diff --git a/bsps/mips/shared/irq/vectorexceptions.c b/bsps/mips/shared/irq/vectorexceptions.c new file mode 100644 index 0000000000..cdfd94c136 --- /dev/null +++ b/bsps/mips/shared/irq/vectorexceptions.c @@ -0,0 +1,81 @@ +/** + * @file + * + * Common Code for Vectoring MIPS Exceptions + * + * The actual decoding of the cause register and vector number assignment + * is CPU model specific. + */ + +/* + * COPYRIGHT (c) 1989-2012. + * On-Line Applications Research Corporation (OAR). + * + * 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 <rtems.h> +#include <inttypes.h> +#include <stdlib.h> +#include <string.h> +#include <rtems/mips/iregdef.h> +#include <rtems/mips/idtcpu.h> +#include <rtems/bspIo.h> +#include <bsp/irq-generic.h> + +struct regdef +{ + int offset; + char *name; +}; + +static const struct regdef dumpregs[]= { + { R_RA, "R_RA" }, { R_V0, "R_V0" }, { R_V1, "R_V1" }, + { R_A0, "R_A0" }, { R_A1, "R_A1" }, { R_A2, "R_A2" }, + { R_A3, "R_A3" }, { R_T0, "R_T0" }, { R_T1, "R_T1" }, + { R_T2, "R_T2" }, { R_T3, "R_T3" }, { R_T4, "R_T4" }, + { R_T5, "R_T5" }, { R_T6, "R_T6" }, { R_T7, "R_T7" }, + { R_T8, "R_T8" }, { R_MDLO, "R_MDLO" }, { R_MDHI, "R_MDHI" }, + { R_GP, "R_GP" }, { R_FP, "R_FP" }, { R_AT, "R_AT" }, + { R_EPC,"R_EPC"}, { -1, NULL } +}; + +void _CPU_Exception_frame_print( const CPU_Exception_frame *frame ) +{ + uint32_t *frame_u32; + int i, j; + + frame_u32 = (uint32_t *)frame; + for(i=0; dumpregs[i].offset > -1; i++) + { + printk(" %s", dumpregs[i].name); + for(j=0; j< 7-strlen(dumpregs[i].name); j++) printk(" "); +#if (__mips == 1 ) || (__mips == 32) + printk(" %08" PRIu32 "%c", + frame_u32[dumpregs[i].offset], (i%3) ? '\t' : '\n' ); +#elif __mips == 3 + printk(" %08" PRIu32 "", frame_u32[2 * dumpregs[i].offset + 1] ); + printk("%08" PRIu32 "%c", + frame_u32[2 * dumpregs[i].offset], (i%2) ? '\t' : '\n' ); +#endif + } + printk( "\n" ); +} + +/* + * There are constants defined for these but they should basically + * all be close to the same set. + */ + +void mips_vector_exceptions( CPU_Interrupt_frame *frame ) +{ + uint32_t cause; + uint32_t exc; + + mips_get_cause( cause ); + exc = (cause >> 2) & 0x1f; + + bsp_interrupt_handler_dispatch( exc ); +} diff --git a/bsps/or1k/generic_or1k/irq/irq.c b/bsps/or1k/generic_or1k/irq/irq.c new file mode 100644 index 0000000000..f9a7b6426d --- /dev/null +++ b/bsps/or1k/generic_or1k/irq/irq.c @@ -0,0 +1,43 @@ +/** + * @file + * + * @ingroup or1k_interrupt + * + * @brief Interrupt support. + */ + +/* + * Copyright (c) 2014 Hesham ALMatary + * + * 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 <bsp/irq.h> +#include <bsp/irq-generic.h> +#include <rtems/inttypes.h> + +/* Almost all of the jobs that the following functions should + * do are implemented in cpukit + */ + +void bsp_interrupt_handler_default(rtems_vector_number vector) +{ + printk("spurious interrupt: %" PRIdrtems_vector_number "\n", vector); +} + +rtems_status_code bsp_interrupt_facility_initialize() +{ + return 0; +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); +} diff --git a/bsps/powerpc/beatnik/irq/discovery_pic.c b/bsps/powerpc/beatnik/irq/discovery_pic.c new file mode 100644 index 0000000000..f77125c4a7 --- /dev/null +++ b/bsps/powerpc/beatnik/irq/discovery_pic.c @@ -0,0 +1,993 @@ +/* Interrupt driver + dispatcher for the discovery host controller */ + +/* Author: T. Straumann, 2005-2007 + * + * Acknowledgements: + * Valuable information was obtained from the following drivers + * netbsd: (C) Allegro Networks Inc; Wasabi Systems Inc. + * linux: (C) MontaVista, Software, Inc; Chris Zankel, Mark A. Greer. + * rtems: (C) Brookhaven National Laboratory; K. Feng + * but this implementation is original work by the author. + */ + +/* + * Authorship + * ---------- + * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was + * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The 'beatnik' BSP was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ +#include <rtems.h> +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/gtreg.h> +#include <bsp/gtintrreg.h> +#include <rtems/bspIo.h> +#include <bsp/vectors.h> +#include <libcpu/byteorder.h> +#include <libcpu/spr.h> + +/* dont change the order (main_lo, main_hi, gpp) which + * matches the interrupt numbers! + */ +#define MAIN_LO_IDX 0 +#define MAIN_HI_IDX 1 +#define GPP_IDX 2 +#define NUM_INTR_REGS 3 + + +#define SYNC() __asm__ volatile("sync") + +/* How many times should the ISR dispatcher check for + * pending interrupts until it decides that something's + * fishy (i.e., a user ISR fails to clear the interrupt + * source) + */ +#define MAX_SPIN_LOOPS 100 + +/* If FASTER is defined, a few obscure I/O statements found in the linux + * driver are removed + */ +#define FASTER + +/* Array helper */ +#define NumberOf(arr) (sizeof(arr)/sizeof((arr)[0])) + + +/* MVME6100 specific; re-define watchdog NMI pin to be a normal output + * so we have a way to raise an interrupt in software (GPP[26] is wired to + * GPP[6] on the MVME6100). + */ +#define MVME6100_IRQ_DEBUG 4 + +#define GPP_WIRED_OUT_BIT_6100 26 /* CAVEAT: this is bit 26 on the 6100 */ +#define GPP_WIRED_OUT_BIT_5500 24 /* CAVEAT: this is bit 24 on the 5500 */ +#define GPP_WIRED_IN_BIT 6 + +/* Ored mask of debugging features to enable */ +#define IRQ_DEBUG_BASIC 1 +/* This is _very_ lowlevel */ +#define IRQ_DEBUG_DISPATCHER 2 +/* Record maximal dispatching latency */ +#define IRQ_DEBUG_MAXLAT 8 /* PPC only */ + +#define IRQ_DEBUG (0 /*|(IRQ_DEBUG_BASIC)*/|(MVME6100_IRQ_DEBUG)|(IRQ_DEBUG_MAXLAT)) + +/********** + * Typedefs + **********/ + +/* Set of the three relevant cause registers */ +typedef volatile unsigned IrqMask[NUM_INTR_REGS]; + +#define REGP(x) ((volatile uint32_t *)(x)) + +/* Information we keep about the PIC */ +typedef struct _Mv64x60PicRec { + /* base address as seen from CPU */ + uintptr_t reg_base; + + /* addresses of 'cause' registers */ + volatile uint32_t *causes[NUM_INTR_REGS]; + + /* addresses of 'mask' registers */ + volatile uint32_t *masks[NUM_INTR_REGS]; + + /* masks for all priorities. If an + * interrupt source has priority X, + * its corresponding bit is set + * (enabled) in mcache[i] for all + * i < X and cleared for i >= X + */ + volatile IrqMask mcache[BSP_IRQ_MAX_PRIO+1]; + + /* Priority we're executing at. + * Thread-level is priority 0, + * ISRs range from 1..MAX_PRIO + */ + volatile rtems_irq_prio current_priority; +} Mv64x60PicRec, *Mv64x60Pic; + +/********** + * Globals + **********/ + + +/* Copy of the configuration */ +static rtems_irq_global_settings theConfig; +/* PIC description */ +static Mv64x60PicRec thePic; + +#if (IRQ_DEBUG) & MVME6100_IRQ_DEBUG +static unsigned long gpp_out_bit = 0; +#endif + +#if (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT +unsigned long discovery_pic_max_dispatching_latency = 0; +#ifdef __PPC__ +static inline unsigned long mftb(void) +{ +unsigned long rval; + asm volatile("mftb %0":"=r"(rval)); + return rval; +} +#else +#define mftb() 0 +#endif +#endif + +/********** + * Functions + **********/ + +/* Debugging helper routines */ +static void pregs(volatile uint32_t **p) +{ +int i; + for (i=NUM_INTR_REGS-1; i>=0; i--) { + printk(" 0x%08x", ld_le32(p[i])); + printk( i ? " --":"\n"); + } +} + +static void pmsks(volatile IrqMask p) +{ +int i; + for (i=NUM_INTR_REGS-1; i>=0; i--) { + printk(" 0x%08x", p[i]); + printk( i ? " --":"\n"); + } +} + +static void discovery_dump_picregs(void) +{ + printk(" ..GPP_IRQ. -- ..MAIN_HI. -- ..MAIN_LO.\n"); + printk("Cause:"); pregs(thePic.causes); + printk("Mask: "); pregs(thePic.masks); +} + +/* Small inline helpers */ + +/* return 0 if this PIC is not 'responsible' for a given irq number + * we also 'ignore' the GPP summary bits - these must always remain + * enabled. + */ +static inline int +validIrqNo(rtems_irq_number irq) +{ + return + irq >= BSP_PCI_IRQ_LOWEST_OFFSET + && irq <= BSP_PCI_IRQ_MAX_OFFSET + && ! (IMH_GPP_SUM & (1<<(irq-32))); +} + +/* return 0 if a given priority is outside the valid range */ +static inline int +validPri(rtems_irq_prio pri) +{ + /* silence compiler warning about limited range of type; + * hope it never changes... + */ + return /* pri>=0 && */ pri <=BSP_IRQ_MAX_PRIO; +} + +/* Return position of the most significant bit that is set in 'x' */ +static inline int +__ilog2(unsigned x) +{ + asm volatile("cntlzw %0, %0":"=&r"(x):"0"(x)); + return 31-x; +} + +/* Convert irq number to cause register index + * (array of handles in the PicRec). + * ASSUMES: 'irq' within valid range. + */ +static inline unsigned +irqDiv32(unsigned irq) +{ + return (irq-BSP_PCI_IRQ_LOWEST_OFFSET)>>5; +} + +/* Convert irq number to cause/mask bit number. + * ASSUMES: 'irq' within valid range. + */ + +static inline unsigned +irqMod32(unsigned irq) +{ + return (irq-BSP_PCI_IRQ_LOWEST_OFFSET)&31; +} + +/* NON-ATOMICALLY set/clear bits in a MV64x60 register + * + * register contents at offset 'off' are ANDed with + * complement of the 'clr' mask and ORed with 'set' mask: + * + * *off = (*off & ~clr) | set + * + * ASSUMES: executed from IRQ-disabled section + */ +static inline void +gt_bitmod(unsigned off, unsigned set, unsigned clr) +{ + st_le32(REGP(thePic.reg_base + off), + (ld_le32(REGP(thePic.reg_base+off)) & ~clr) | set); +} + +static inline unsigned +gt_read(unsigned off) +{ + return ld_le32(REGP(thePic.reg_base + off)); +} + +static inline void +gt_write(unsigned off, unsigned val) +{ + st_le32(REGP(thePic.reg_base + off), val); +} + +/* Enable interrupt number 'irq' at the PIC. + * + * Checks for valid arguments but has no way of + * communicating violation; prints to console + * if illegal arguments are given. + * + * This routine may be called from ISR level. + * + * Algorithm: set corresponding bit in masks + * for all priorities lower than the + * target irq's priority and push + * mask for the currently executing + * priority out to the PIC. + */ + +void +BSP_enable_irq_at_pic(rtems_irq_number irq) +{ +unsigned i,j; +unsigned long flags; +volatile uint32_t *p; +uint32_t v,m; + + if ( !validIrqNo(irq) ) { +/* API change - must silently ignore... + printk("BSP_enable_irq_at_pic: Invalid argument (irq #%i)\n",irq); + */ + return; + } + +#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC + printk("IRQ: Enable #%i;",irq); +#endif + + if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) { + /* This is probably a more serious error; don't ignore silently */ + printk("BSP_enable_irq_at_pic: illegal argument\n"); + return; + } + /* compute register pointer and bit mask */ + p = thePic.masks[i]; + m = 1<<irqMod32(irq); + + rtems_interrupt_disable(flags); + { + /* access table from protected section to be thread-safe */ + rtems_irq_prio pri = theConfig.irqPrioTbl[irq]; + for ( j=0; j<pri; j++ ) { + thePic.mcache[j][i] |= m; + } + st_le32(p, (v=thePic.mcache[thePic.current_priority][i])); + /* linux driver reads back GPP mask; maybe it's wise to do the same */ + (void)ld_le32(thePic.masks[GPP_IDX]); + } + SYNC(); + rtems_interrupt_enable(flags); + +#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC + printk(" Mask[%i]: 0x%08x -> 0x%08x\n",i,v,ld_le32(p)); + +#endif +} + +/* Disable interrupt number 'irq' at the PIC. + * + * Checks for valid arguments but has no way of + * communicating violation; prints to console + * if illegal arguments are given. + * + * This routine may be called from ISR level. + * + * Algorithm: clear corresponding bit in masks + * for all priorities and push the + * mask for the currently executing + * priority out to the PIC. + */ + +int +BSP_disable_irq_at_pic(rtems_irq_number irq) +{ +unsigned i,j; +unsigned long flags; +volatile uint32_t *p; +uint32_t v,m; +int rval; + + if ( !validIrqNo(irq) ) { +/* API change - must silently ignore... + printk("BSP_disable_irq_at_pic: Invalid argument (irq #%i)\n",irq); + */ + return -1; + } + +#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC + printk("IRQ: Disable #%i;",irq); +#endif + + if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) { + /* This is probably a more serious error; don't ignore silently */ + printk("BSP_enable_irq_at_pic: illegal argument\n"); + return -1; + } + + /* compute register pointer and bit mask */ + p = thePic.masks[i]; + m = (1<<irqMod32(irq)); + + rtems_interrupt_disable(flags); + { + rval = thePic.mcache[thePic.current_priority][i] & m; + for (j=0; j<=BSP_IRQ_MAX_PRIO; j++) + thePic.mcache[j][i] &= ~m; + st_le32(p, (v=thePic.mcache[thePic.current_priority][i])); + /* linux driver reads back GPP mask; maybe it's wise to do the same */ + (void)ld_le32(thePic.masks[GPP_IDX]); + } + SYNC(); + rtems_interrupt_enable(flags); + +#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC + printk(" Mask[%i]: 0x%08x -> 0x%08x\n",i,v,ld_le32(p)); +#endif + + return rval ? 1 : 0; +} + +int +BSP_irq_is_enabled_at_pic(rtems_irq_number irq) +{ +unsigned i; + if ( !validIrqNo(irq) ) { + printk("BSP_irq_is_enabled_at_pic: Invalid argument (irq #%i)\n",irq); + return -1; + } + + if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) { + printk("BSP_enable_irq_at_pic: illegal argument\n"); + return -1; + } + return ld_le32(thePic.masks[i]) & (1<<irqMod32(irq)) ? 1 : 0; +} + + +/* Change priority of interrupt number 'irq' to 'pri' + * + * RETURNS: 0 on success, nonzero on failure (illegal args) + * + * NOTE: This routine must not be called from ISR level. + * + * Algorithm: Set bit corresponding to 'irq' in the masks for + * all priorities < pri and clear in all masks + * for priorities >=pri + */ +int +BSP_irq_set_priority(rtems_irq_number irq, rtems_irq_prio pri) +{ +unsigned long flags; +volatile uint32_t *p; +uint32_t v,m; +unsigned i,j; + + if ( thePic.current_priority > 0 ) { + printk("BSP_irq_set_priority: must not be called from ISR level\n"); + return -1; + } + + if ( !validPri(pri) ) { + printk("BSP_irq_set_priority: invalid argument (pri #%i)\n",pri); + return -1; + } + + if ( BSP_DECREMENTER != irq ) { + if ( !validIrqNo(irq) ) { + printk("BSP_irq_set_priority: invalid argument (irq #%i)\n",irq); + return -1; + } + + if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) { + printk("BSP_irq_set_priority: illegal argument (irq #%i not PCI?)\n", irq); + return -1; + } + } + +#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC + printk("IRQ: Set Priority #%i -> %i;",irq,pri); +#endif + + if ( BSP_DECREMENTER == irq ) { + theConfig.irqPrioTbl[irq] = pri; + return 0; + } + + /* compute register pointer and bit mask */ + p = thePic.masks[i]; + m = 1<<irqMod32(irq); + + rtems_interrupt_disable(flags); + { + for (j=0; j<=BSP_IRQ_MAX_PRIO; j++) { + if ( j<pri ) + thePic.mcache[j][i] |= m; + else + thePic.mcache[j][i] &= ~m; + } + theConfig.irqPrioTbl[irq] = pri; + st_le32(p, (v=thePic.mcache[thePic.current_priority][i])); + /* linux driver reads back GPP mask; maybe it's wise to do the same */ + (void)ld_le32(thePic.masks[GPP_IDX]); + } + SYNC(); + rtems_interrupt_enable(flags); + +#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC + printk(" Mask[%i]: 0x%08x -> 0x%08x\n",i,v,ld_le32(p)); +#endif + + return 0; +} + +/* Initialize the PIC; routine needed by BSP framework + * + * RETURNS: NONZERO on SUCCESS, 0 on error! + */ +int +BSP_setup_the_pic(rtems_irq_global_settings* config) +{ +int i; + /* + * Store copy of configuration + */ + theConfig = *config; + + /* check config */ + if ( theConfig.irqNb <= BSP_PCI_IRQ_MAX_OFFSET ) { + printk("BSP_setup_the_pic: FATAL ERROR: configured IRQ table too small???\n"); + return 0; + } + + for ( i=0; i<theConfig.irqNb; i++ ) { + if ( !validPri(theConfig.irqPrioTbl[i]) ) { + printk("BSP_setup_the_pic: invalid priority (%i) for irg #%i; setting to 1\n", theConfig.irqPrioTbl[i], i); + theConfig.irqPrioTbl[i]=1; + } + } + + /* TODO: Detect; Switch wired-out bit; */ + thePic.reg_base = BSP_MV64x60_BASE; + + thePic.current_priority = 0; + +#if (IRQ_DEBUG) & MVME6100_IRQ_DEBUG +#endif + + switch ( BSP_getDiscoveryVersion(/* assert */ 1) ) { + case MV_64360: + thePic.causes[MAIN_LO_IDX] = REGP(thePic.reg_base + ICR_360_MIC_LO); + thePic.causes[MAIN_HI_IDX] = REGP(thePic.reg_base + ICR_360_MIC_HI); + thePic.masks[MAIN_LO_IDX] = REGP(thePic.reg_base + ICR_360_C0IM_LO); + thePic.masks[MAIN_HI_IDX] = REGP(thePic.reg_base + ICR_360_C0IM_HI); + break; + + case GT_64260_A: + case GT_64260_B: + thePic.causes[MAIN_LO_IDX] = REGP(thePic.reg_base + ICR_260_MIC_LO); + thePic.causes[MAIN_HI_IDX] = REGP(thePic.reg_base + ICR_260_MIC_HI); + thePic.masks[MAIN_LO_IDX] = REGP(thePic.reg_base + ICR_260_CIM_LO); + thePic.masks[MAIN_HI_IDX] = REGP(thePic.reg_base + ICR_260_CIM_HI); + break; + + default: + rtems_panic("Unable to initialize interrupt controller; unknown chip"); + break; + } + + thePic.causes[GPP_IDX] = REGP(thePic.reg_base + GT_GPP_Interrupt_Cause); + thePic.masks[GPP_IDX] = REGP(thePic.reg_base + GT_GPP_Interrupt_Mask); + + /* Initialize mask cache */ + for ( i=0; i<=BSP_IRQ_MAX_PRIO; i++ ) { + thePic.mcache[i][MAIN_LO_IDX] = 0; + /* Always enable the summary bits. Otherwise, GPP interrupts dont + * make it 'through' to the GPP cause + */ + thePic.mcache[i][MAIN_HI_IDX] = IMH_GPP_SUM; + thePic.mcache[i][GPP_IDX] = 0; + } + + /* mask and clear everything */ + for ( i=0; i<NUM_INTR_REGS; i++ ) { + st_le32(thePic.causes[i], 0); + st_le32(thePic.masks[i], 0); + } + + /* make sure GPP Irqs are level sensitive */ + gt_bitmod( + GT_CommUnitArb_Ctrl, /* reg */ + GT_CommUnitArb_Ctrl_GPP_Ints_Level_Sensitive, /* set */ + 0); /* clr */ + + /* enable summaries */ + st_le32(thePic.masks[MAIN_LO_IDX], thePic.mcache[thePic.current_priority][MAIN_LO_IDX]); + st_le32(thePic.masks[MAIN_HI_IDX], thePic.mcache[thePic.current_priority][MAIN_HI_IDX]); + st_le32(thePic.masks[GPP_IDX ], thePic.mcache[thePic.current_priority][GPP_IDX ]); + + /* believe the interrupts are all level sensitive (which is good); we leave all the + * inputs configured they way the are by MotLoad... + */ + + /* Finally, enable all interrupts for which the configuration table has already + * a handler installed. + */ + for ( i=BSP_PCI_IRQ_LOWEST_OFFSET; i<=BSP_PCI_IRQ_MAX_OFFSET; i++ ) { + if ( theConfig.irqHdlTbl[i].hdl != theConfig.defaultEntry.hdl ) { + BSP_enable_irq_at_pic(i); + } + } + + return 1; +} + +int discovery_pic_max_loops = 0; + + +/* Change the priority level we're executing at and mask all interrupts of + * the same and lower priorities + * + * RETURNS old priority; + */ + +static inline rtems_irq_prio +change_executing_prio_level(rtems_irq_prio pri) +{ +register rtems_irq_prio rval = thePic.current_priority; + thePic.current_priority = pri; + st_le32(thePic.masks[MAIN_LO_IDX], thePic.mcache[pri][MAIN_LO_IDX]); + st_le32(thePic.masks[MAIN_HI_IDX], thePic.mcache[pri][MAIN_HI_IDX]); + st_le32(thePic.masks[GPP_IDX ], thePic.mcache[pri][GPP_IDX ]); + /* this DOES seem to be necessary */ + (void)ld_le32(thePic.masks[GPP_IDX]); + return rval; +} + +/* Scan the three cause register and find the pending interrupt with + * the highest priority. + * + * Two facts make this quite efficient + * a) the PPC has an opcode for finding the number of leading zero-bits + * in a register (__ilog2()). + * b) as we proceed we mask all sources of equal or lower priorites; they won't be + * seen while scanning: + * + * maxpri = 0; + * bits = in_le32(cause); + * while ( bits &= mask[maxpri] ) { + * irq_no = __ilog2(bits); + * maxpri = priority[irq_no]; + * } + * + * a) __ilog() is 1-2 machine instructions + * b) while loop is only executed as many times as interrupts of different + * priorities are pending at the same time (and only if lower-priority + * ones are found first; otherwise, the iteration terminates quicker). + * + * ==> highest priority source is found quickly. It takes at most + * + * BSP_IRQ_MAX_PRIO * ( ~3 reg-only instructions + 2 memory access ) + * + 2 reg-only instructions + 1 I/O + 1 memory access. + * + * + */ + +static unsigned mlc, mhc, gpc; + +static int decrementerPending = 0; +#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER +int decrementerIrqs = 0; +#endif + +static inline unsigned +find_highest_priority_pending_irq(rtems_irq_prio *ppri) +{ +register int rval = -1; +register rtems_irq_prio *pt = theConfig.irqPrioTbl + BSP_PCI_IRQ_LOWEST_OFFSET; +register rtems_irq_prio pmax = *ppri; +register unsigned cse,ocse; + +#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER + discovery_dump_picregs(); +#endif + + if ( decrementerPending ) { +/* Don't flood +#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER + printk("Decrementer IRQ pending\n"); +#endif +*/ + if ( theConfig.irqPrioTbl[BSP_DECREMENTER] > pmax ) { + pmax = theConfig.irqPrioTbl[BSP_DECREMENTER]; + rval = BSP_DECREMENTER; + } + } + + mlc = cse = ld_le32(thePic.causes[MAIN_LO_IDX]); +#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER + printk("MAIN_LO; cse: 0x%08x, msk 0x%08x\n", cse ,thePic.mcache[pmax][MAIN_LO_IDX]); +#endif + while ( cse &= thePic.mcache[pmax][MAIN_LO_IDX] ) { + rval = __ilog2(cse); + pmax = pt[rval]; +#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER + printk("Max pri IRQ now %i\n",rval); +#endif + } + mhc = cse = ocse = ld_le32(thePic.causes[MAIN_HI_IDX]); +#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER + printk("MAIN_HI; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][MAIN_HI_IDX]); +#endif + /* don't look at the GPP summary; only check for 'real' MAIN_HI sources */ + cse &= ~IMH_GPP_SUM; + while ( cse &= thePic.mcache[pmax][MAIN_HI_IDX] ) { + rval = __ilog2(cse) + 32; + pmax = pt[rval]; +#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER + printk("Max pri IRQ now %i\n",rval); +#endif + } + gpc = cse = ld_le32(thePic.causes[GPP_IDX ]); + /* if there were GPP ints, scan the GPP cause now */ + if ( ocse & IMH_GPP_SUM ) { +#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER + printk("GPP; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][GPP_IDX ]); +#endif + cse &= thePic.mcache[pmax][GPP_IDX ]; + ocse = cse; + while ( cse ) { + rval = __ilog2(cse) + 64; + pmax = pt[rval]; + cse &= thePic.mcache[pmax][GPP_IDX ]; +#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER + printk("Max pri IRQ now %i\n",rval); +#endif + } +#ifndef FASTER + /* this doesn't seem to be necessary -- however, the linux people do it... */ + out_le32(thePic.causes[GPP_IDX], ~ocse); +#endif + } +#ifndef FASTER + /* this doesn't seem to be necessary -- however, the linux people do it... */ + (void)in_le32(thePic.causes[GPP_IDX]); +#endif + + *ppri = pmax; + + if ( BSP_DECREMENTER == rval ) { +#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER + decrementerIrqs++; +#endif + decrementerPending = 0; + } + + return rval; +} + +#if 0 /* TODO: should this be cleaned up ? */ +#define _IRQ_DEBUG IRQ_DEBUG_DISPATCHER +static inline unsigned +ffind_highest_priority_pending_irq(rtems_irq_prio *ppri) +{ +register int rval = -1; +register rtems_irq_prio *pt = theConfig.irqPrioTbl + BSP_PCI_IRQ_LOWEST_OFFSET; +register rtems_irq_prio pmax = *ppri; +register unsigned cse,ocse; + +#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER + discovery_dump_picregs(); +#endif + + cse = in_le32(thePic.causes[MAIN_LO_IDX]); +#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER + printk("MAIN_LO; cse: 0x%08x, msk 0x%08x\n", cse ,thePic.mcache[pmax][MAIN_LO_IDX]); +#endif + while ( cse &= thePic.mcache[pmax][MAIN_LO_IDX] ) { + rval = __ilog2(cse); + pmax = pt[rval]; +#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER + printk("Max pri IRQ now %i\n",rval); +#endif + } + cse = ocse = in_le32(thePic.causes[MAIN_HI_IDX]); +#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER + printk("MAIN_HI; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][MAIN_HI_IDX]); +#endif + /* don't look at the GPP summary; only check for 'real' MAIN_HI sources */ + cse &= ~IMH_GPP_SUM; + while ( cse &= thePic.mcache[pmax][MAIN_HI_IDX] ) { + rval = __ilog2(cse) + 32; + pmax = pt[rval]; +#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER + printk("Max pri IRQ now %i\n",rval); +#endif + } + /* if there were GPP ints, scan the GPP cause now */ + if ( ocse & IMH_GPP_SUM ) { + cse = in_le32(thePic.causes[GPP_IDX ]); +#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER + printk("GPP; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][GPP_IDX ]); +#endif + cse &= thePic.mcache[pmax][GPP_IDX ]; + ocse = cse; + while ( cse ) { + rval = __ilog2(cse) + 64; + pmax = pt[rval]; + cse &= thePic.mcache[pmax][GPP_IDX ]; +#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER + printk("Max pri IRQ now %i\n",rval); +#endif + } + /* this doesn't seem to be necessary -- however, the linux people do it... */ + out_le32(thePic.causes[GPP_IDX], ~ocse); + } + /* this doesn't seem to be necessary -- however, the linux people do it... */ + (void)in_le32(thePic.causes[GPP_IDX]); + + *ppri = pmax; + return rval; +} +#endif + + +/* Here's our dispatcher; the BSP framework uses the same one for EE and decrementer + * exceptions... + */ +int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum) +{ +register int irq; +int loop, last_irq; +rtems_irq_prio pri; +#if (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT +unsigned long diff; +#endif + +#if (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT + diff = mftb(); +#endif + + if (excNum == ASM_DEC_VECTOR) { + decrementerPending = 1; + } + + /* Tradeoff: EITHER we loop as long as interrupts are pending + * incurring the overhead of one extra run of the 'find_pending_irq' routine. + * OR we do rely on the handler just being invoked again if multiple + * interrupts are pending. + * + * The first solution gives better worst-case behavior + * the second slightly better average performance. + * --> we go for the first solution. This also enables us to catch + * runaway interrupts, i.e., bad drivers that don't clear interrupts + * at the device. Can be very handy during driver development... + */ + for ( loop=0, last_irq=-1, pri = thePic.current_priority; + (irq=find_highest_priority_pending_irq(&pri)) >=0; + loop++, last_irq = irq ) { + + /* raise priority level and remember current one */ + pri = change_executing_prio_level(pri); + + SYNC(); + +#if (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT + if ( 0 == loop ) { + diff = mftb()-diff; + if ( diff > discovery_pic_max_dispatching_latency ) + discovery_pic_max_dispatching_latency = diff; + } +#endif + +#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER + if ( BSP_DECREMENTER == irq ) { + printk("IRQ: dispatching DECREMENTER\n"); + } else { + int idx = irqDiv32(irq); + printk("IRQ: dispatching #%i; causes[%i]=0x%08x\n", irq, idx, ld_le32(thePic.causes[idx])); + } +#endif + + bsp_irq_dispatch_list( theConfig.irqHdlTbl, irq, theConfig.defaultEntry.hdl ); + + /* restore executing priority level */ + (void)change_executing_prio_level(pri); + + if ( (loop > MAX_SPIN_LOOPS) && (last_irq == irq) ) { + /* try to catch run-away interrupts without disabling a 'legal' one; + * this should never happen with the decrementer (and + * BSP_disable_irq_at_pic(BSP_DECREMENTER) would fail) + */ + printk("Runaway IRQ #%i; disabling\n", irq); + BSP_disable_irq_at_pic(irq); + loop = 0; + } + } + + if (!loop) { + if ( decrementerPending && pri >= theConfig.irqPrioTbl[BSP_DECREMENTER] ) { + /* we cannot mask the decrementer interrupt so it is possible that it + * gets delivered even though it has a lower priority than what we're + * currently executing at. + * In this case, we ignore the zero loop count and return; + * the interrupted instance of C_dispatch_irq_handler() will eventually + * lower the executing priority and catch the 'decrementerPending' flag + * we just set. + */ + } else { + printk("Discovery: Spurious interrupt; causes were gpp: 0x%x, mhc: 0x%x, mlc: 0x%x\n", gpc, mhc, mlc); + printk("Current priority level %i, decrementerPending %i\n", pri, decrementerPending); + { + rtems_irq_prio p=pri; + printk("PIC register dump:\n"); + discovery_dump_picregs(); + printk("Current Priority: %i, found %i\n",pri,find_highest_priority_pending_irq(&p)); + discovery_dump_picregs(); + for (p=0; p<=BSP_IRQ_MAX_PRIO; p++) { + printk("M[%i] :",p);pmsks(thePic.mcache[p]); + } + } + } + } + else if (loop>discovery_pic_max_loops) + discovery_pic_max_loops = loop; + + return 0; +} + + +#if (IRQ_DEBUG) & MVME6100_IRQ_DEBUG +void +discovery_pic_install_debug_irq(void) +{ + switch ( BSP_getBoardType() ) { + case MVME6100: gpp_out_bit = GPP_WIRED_OUT_BIT_6100; break; + case MVME5500: gpp_out_bit = GPP_WIRED_OUT_BIT_5500; break; + default: + gpp_out_bit = 0; break; + break; + } + if ( gpp_out_bit ) { + unsigned mppoff; + switch (gpp_out_bit / 8) { + default: /* silence warning; this is never reached */ + case 0: mppoff = GT_MPP_Control0; break; + case 1: mppoff = GT_MPP_Control1; break; + case 2: mppoff = GT_MPP_Control2; break; + case 3: mppoff = GT_MPP_Control3; break; + } + + /* switch GPP pin allocated to watchdog (value 4) to + * GPP I/O (value 0 ??; have no doc, found out by experimenting) + */ + gt_bitmod(mppoff, 0, (0xf<<(4*(gpp_out_bit % 8)))); + + /* make it an output */ + gt_bitmod(GT_GPP_IO_Control, (1<<gpp_out_bit), 0); + + /* don't invert levels */ + gt_bitmod(GT_GPP_Level_Control, 0, (1<<GPP_WIRED_IN_BIT) | (1<<gpp_out_bit)); + + /* clear output */ + gt_bitmod(GT_GPP_Value, 0, 1<<gpp_out_bit); + + printk("GPP levelctl now 0x%08x\n", gt_read(GT_GPP_Level_Control)); + printk("GPP value now 0x%08x\n", gt_read(GT_GPP_Value)); + printk("MPP ctl 0 now 0x%08x\n", gt_read(GT_MPP_Control0)); + printk("MPP ctl 1 now 0x%08x\n", gt_read(GT_MPP_Control1)); + printk("MPP ctl 2 now 0x%08x\n", gt_read(GT_MPP_Control2)); + printk("MPP ctl 3 now 0x%08x\n", gt_read(GT_MPP_Control3)); + + } +} + +/* Control the state of the external 'wire' that connects the + * GPP_WIRED_OUT --> GPP_WIRED_IN pins + */ +void +discovery_pic_set_debug_irq(int on) +{ +unsigned long flags, clr; + if ( !gpp_out_bit ) { + printk("discovery_pic_set_debug_irq(): unknown wire output\n"); + return; + } + if (on) { + on = 1<<gpp_out_bit; + clr = 0; + } else { + clr = 1<<gpp_out_bit; + on = 0; + } + rtems_interrupt_disable(flags); + gt_bitmod(GT_GPP_Value, on, clr); + rtems_interrupt_enable(flags); +} +#endif + +#if 0 +/* Here's some code for testing */ +#endif diff --git a/bsps/powerpc/beatnik/irq/irq_init.c b/bsps/powerpc/beatnik/irq/irq_init.c new file mode 100644 index 0000000000..2c0554c988 --- /dev/null +++ b/bsps/powerpc/beatnik/irq/irq_init.c @@ -0,0 +1,110 @@ +/* irq_init.c + * + * This file contains the implementation of rtems initialization + * related to interrupt handling. + * + * CopyRight (C) 1999 valette@crf.canon.fr + * + * Enhanced by Jay Kulpinski <jskulpin@eng01.gdds.com> + * to make it valid for MVME2300 Motorola boards. + * + * Modified by T. Straumann for the 'beatnik' BSP. + * + * 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 <rtems.h> +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/vectors.h> +#include <rtems/bspIo.h> + +#if 0 +#include <libcpu/io.h> +#include <libcpu/spr.h> +#include <bsp/pci.h> +#include <bsp/residual.h> +#include <bsp/openpic.h> +#include <bsp/irq.h> +#include <bsp.h> +#include <bsp/motorola.h> +#endif + +/* +#define SHOW_ISA_PCI_BRIDGE_SETTINGS +*/ + +extern unsigned int external_exception_vector_prolog_code_size[]; +extern void external_exception_vector_prolog_code(void); +extern unsigned int decrementer_exception_vector_prolog_code_size[]; +extern void decrementer_exception_vector_prolog_code(void); + +/* + * default handler + */ +static void nop_func(void *arg){} + +static rtems_irq_connect_data rtemsIrq[BSP_IRQ_NUMBER]; +static rtems_irq_global_settings initial_config; +static rtems_irq_prio rtemsPrioTbl[BSP_IRQ_NUMBER]; +static rtems_irq_connect_data defaultIrq = { + name: 0, + hdl: nop_func, + handle: 0, + on: 0, + off: 0, + isOn: 0 +}; + + + /* + * This code assumes the exceptions management setup has already + * been done. We just need to replace the exceptions that will + * be handled like interrupt. On mcp750/mpc750 and many PPC processors + * this means the decrementer exception and the external exception. + */ + +void BSP_rtems_irq_mng_init(unsigned cpuId) +{ +int i; + + /* + * First initialize the Interrupt management hardware + */ + + /* + * Initialize Rtems management interrupt table + */ + + /* + * re-init the rtemsIrq table + */ + for (i = BSP_LOWEST_OFFSET; i <= BSP_MAX_OFFSET; i++) { + rtemsIrq[i] = defaultIrq; + rtemsIrq[i].name = i; + rtemsPrioTbl[i] = BSP_IRQ_DEFAULT_PRIORITY; + } + + /* + * Init initial Interrupt management config + */ + initial_config.irqNb = BSP_IRQ_NUMBER; + initial_config.defaultEntry = defaultIrq; + initial_config.irqHdlTbl = rtemsIrq; + initial_config.irqBase = BSP_LOWEST_OFFSET; + initial_config.irqPrioTbl = rtemsPrioTbl; + + if (!BSP_rtems_irq_mngt_set(&initial_config)) { + /* + * put something here that will show the failure... + */ + rtems_panic("Unable to initialize RTEMS interrupt Management!!! System locked\n"); + } + +#ifdef TRACE_IRQ_INIT + printk("RTEMS IRQ management is now operationnal\n"); +#endif +} + diff --git a/bsps/powerpc/beatnik/irq/irq_test_app.c b/bsps/powerpc/beatnik/irq/irq_test_app.c new file mode 100644 index 0000000000..cb9ff146ad --- /dev/null +++ b/bsps/powerpc/beatnik/irq/irq_test_app.c @@ -0,0 +1,164 @@ +/* Init + * + * This routine is the initialization task for this test program. + * It is called from init_exec and has the responsibility for creating + * and starting the tasks that make up the test. If the time of day + * clock is required for the test, it should also be set to a known + * value by this function. + * + * Input parameters: NONE + * + * Output parameters: NONE + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * 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. + * + * OAR init.c Template modified by T. Straumann who provided + * the implementation of this application. + */ + +#define CONFIGURE_INIT + +#include <rtems.h> + +/* functions */ +rtems_task Init( + rtems_task_argument argument +); + +/* configuration information */ +#include <bsp.h> /* for device driver prototypes */ +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#define CONFIGURE_MAXIMUM_TASKS 1 +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE +#include <confdefs.h> + +#include <stdio.h> +#include <stdlib.h> + +#include <bsp/irq.h> +#include <rtems/bspIo.h> + + +void noop(){} +int connected() {return 1;} + +rtems_irq_connect_data blah = { 0, 0, noop, noop, connected }; +extern void discovery_pic_set_debug_irq(); + +#define WIRE_IRQ (BSP_IRQ_GPP_0 + 6) +#define ABRT_IRQ (BSP_IRQ_GPP_0 + 2) + +static volatile int testno=0; +static volatile int wloops =0; +static volatile int aloops =0; + +void wire_hdl() +{ + if ( 1 == testno ) { + BSP_disable_irq_at_pic(WIRE_IRQ); + } + + if ( 2 == testno || 3 == testno ) { + discovery_pic_set_debug_irq(0); + printk("WIRE -- this message should be printed %s\n", 3==testno ? "FIRST":"SECOND"); + } else { + } + + /* assume the driver checks for less than 1000 loops */ + if ( ++wloops > 1000) { + printk("wire IRQ. FAILURE -- driver couldn't catch runaway ISR. Disabling IRQ source.\n"); + discovery_pic_set_debug_irq(0); + BSP_disable_irq_at_pic(WIRE_IRQ); + } + /* + */ +} + +void abrt_hdl() +{ + aloops++; + if ( 2 == testno || 3 == testno ) { + discovery_pic_set_debug_irq(1); + printk("ABRT -- this message should be printed %s\n", 2==testno ? "FIRST":"SECOND"); + } else + printk("ABRT IRQ\n"); + + if ( 1== testno ) { + BSP_enable_irq_at_pic(WIRE_IRQ); + } + BSP_disable_irq_at_pic(ABRT_IRQ); +} + + +rtems_task Init( + rtems_task_argument ignored +) +{ + blah.name = WIRE_IRQ; + blah.hdl = wire_hdl; + if (!BSP_install_rtems_irq_handler(&blah)) { + fprintf(stderr,"installing handler 1 failed\n"); + } + blah.name = ABRT_IRQ; + blah.hdl = abrt_hdl; + if (!BSP_install_rtems_irq_handler(&blah)) { + fprintf(stderr,"installing handler 2 failed\n"); + } + printf("Hello, testing the ISR dispatcher...\n"); + printf(" 1. Trying to catch runaway interrupt\n"); + printf(" If the system freezes, the test failed!\n"); + fflush(stdout); sleep(1); + aloops = wloops = 0; + discovery_pic_set_debug_irq(1); + printf(" >>> %s\n", wloops<1000 ? "SUCCESS" : "FAILED"); + discovery_pic_set_debug_irq(0); + + testno++; + printf(" 2. Testing enabling / disabling interrupt from ISR\n"); + printf(" Hit the ABORT key for this test\n"); + fflush(stdout); sleep(1); + aloops = wloops = 0; + BSP_disable_irq_at_pic(WIRE_IRQ); + BSP_irq_set_priority(ABRT_IRQ,1); + BSP_enable_irq_at_pic(ABRT_IRQ); + discovery_pic_set_debug_irq(1); + while (!aloops) + ; + discovery_pic_set_debug_irq(0); + sleep(2); + printf(" >>> disabling ABRT IRQ from isr %s\n", 1==aloops ? "SUCCESS":"FAILURE"); + printf(" flashing WIRE IRQ from isr %s\n", 1==wloops ? "SUCCESS":"FAILURE"); + + + testno++; + printf(" 3. Testing interrupt priorities\n"); + BSP_irq_set_priority(ABRT_IRQ,2); + BSP_irq_set_priority(WIRE_IRQ,2); + BSP_enable_irq_at_pic(ABRT_IRQ); + BSP_enable_irq_at_pic(WIRE_IRQ); + printf(" Hit the ABORT key for this test\n"); + fflush(stdout); sleep(1); + aloops = wloops = 0; + while (!aloops) + ; + sleep(2); + testno++; + printf(" Now we are raising the priority of the wire interrupt\n"); + BSP_irq_set_priority(WIRE_IRQ,3); + BSP_enable_irq_at_pic(ABRT_IRQ); + printf(" Hit the ABORT key for this test\n"); + fflush(stdout); sleep(1); + aloops = wloops = 0; + while (!aloops) + ; + + sleep(2); + printf( "That's it; we're done...\n" ); + exit( 0 ); +} diff --git a/bsps/powerpc/gen5200/irq/irq.c b/bsps/powerpc/gen5200/irq/irq.c new file mode 100644 index 0000000000..11d9e3992e --- /dev/null +++ b/bsps/powerpc/gen5200/irq/irq.c @@ -0,0 +1,722 @@ +/*===============================================================*\ +| Project: RTEMS generic MPC5200 BSP | ++-----------------------------------------------------------------+ +| Partially based on the code references which are named below. | +| Adaptions, modifications, enhancements and any recent parts of | +| the code are: | +| Copyright (c) 2005 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | ++-----------------------------------------------------------------+ +| 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. | +| | ++-----------------------------------------------------------------+ +| this file contains the irq controller handler | +\*===============================================================*/ +/***********************************************************************/ +/* */ +/* Module: irq.c */ +/* Date: 07/17/2003 */ +/* Purpose: RTEMS MPC5x00 CPU main interrupt handler & routines */ +/* */ +/*---------------------------------------------------------------------*/ +/* */ +/* Description: This file contains the implementation of the */ +/* functions described in irq.h */ +/* */ +/*---------------------------------------------------------------------*/ +/* */ +/* Code */ +/* References: MPC8260ads main interrupt handler & routines */ +/* Module: irc.c */ +/* Project: RTEMS 4.6.0pre1 / MCF8260ads BSP */ +/* Version 1.2 */ +/* Date: 04/18/2002 */ +/* */ +/* Author(s) / Copyright(s): */ +/* */ +/* Copyright (C) 1998, 1999 valette@crf.canon.fr */ +/* */ +/* Modified for mpc8260 Andy Dachs <a.dachs@sstl.co.uk> */ +/* Surrey Satellite Technology Limited, 2000 */ +/* Nested exception handlers not working yet. */ +/* */ +/* 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. */ +/* */ +/*---------------------------------------------------------------------*/ +/* */ +/* Partially based on the code references which are named above. */ +/* Adaptions, modifications, enhancements and any recent parts of */ +/* the code are under the right of */ +/* */ +/* IPR Engineering, Dachauer Straße 38, D-80335 München */ +/* Copyright(C) 2003 */ +/* */ +/*---------------------------------------------------------------------*/ +/* */ +/* IPR Engineering makes no representation or warranties with */ +/* respect to the performance of this computer program, and */ +/* specifically disclaims any responsibility for any damages, */ +/* special or consequential, connected with the use of this program. */ +/* */ +/*---------------------------------------------------------------------*/ +/* */ +/* Version history: 1.0 */ +/* */ +/***********************************************************************/ + +#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 + */ +void 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); + } +} + +/* + * This function disables a given siu interrupt + */ +void 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); + } +} + +#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(); +} + +rtems_status_code bsp_interrupt_facility_initialize( void) +{ + BSP_SIU_irq_init(); + + /* Install exception handler */ + if (ppc_exc_set_handler( ASM_EXT_VECTOR, C_dispatch_irq_handler)) { + return RTEMS_IO_ERROR; + } + if (ppc_exc_set_handler( ASM_E300_SYSMGMT_VECTOR, C_dispatch_irq_handler)) { + return RTEMS_IO_ERROR; + } + + return RTEMS_SUCCESSFUL; +} + +void bsp_interrupt_handler_default( rtems_vector_number vector) +{ + if (vector != BSP_DECREMENTER) { + printk( "Spurious interrupt: 0x%08" PRIx32 "\n", vector); + } +} diff --git a/bsps/powerpc/gen83xx/irq/irq.c b/bsps/powerpc/gen83xx/irq/irq.c new file mode 100644 index 0000000000..7a8ce3cc0b --- /dev/null +++ b/bsps/powerpc/gen83xx/irq/irq.c @@ -0,0 +1,596 @@ +/*===============================================================*\ +| Project: RTEMS generic MPC83xx BSP | ++-----------------------------------------------------------------+ +| Copyright (c) 2007 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | ++-----------------------------------------------------------------+ +| 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. | +| | ++-----------------------------------------------------------------+ +| this file integrates the IPIC irq controller | +\*===============================================================*/ + +#include <mpc83xx/mpc83xx.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> + +#define MPC83XX_IPIC_VECTOR_NUMBER 92 + +#define MPC83XX_IPIC_IS_VALID_VECTOR( vector) ((vector) >= 0 && (vector) < MPC83XX_IPIC_VECTOR_NUMBER) + +#define MPC83XX_IPIC_INVALID_MASK_POSITION 255 + +typedef struct { + volatile uint32_t *pend_reg; + volatile uint32_t *mask_reg; + const uint32_t bit_num; +} BSP_isrc_rsc_t; + +/* + * data structure to handle all mask registers in the IPIC + * + * Mask positions: + * simsr [0] : 0 .. 31 + * simsr [1] : 32 .. 63 + * semsr : 64 .. 95 + * sermr : 96 .. 127 + */ +typedef struct { + uint32_t simsr_mask [2]; + uint32_t semsr_mask; + uint32_t sermr_mask; +} mpc83xx_ipic_mask_t; + +static const BSP_isrc_rsc_t mpc83xx_ipic_isrc_rsc [MPC83XX_IPIC_VECTOR_NUMBER] = { + /* vector 0 */ + {&mpc83xx.ipic.sersr, &mpc83xx.ipic.sermr, 31}, + {NULL, NULL, 0}, + {NULL, NULL, 0}, + {NULL, NULL, 0}, + {NULL, NULL, 0}, + {NULL, NULL, 0}, + {NULL, NULL, 0}, + {NULL, NULL, 0}, + /* vector 8 */ + {NULL, NULL, 0}, /* reserved vector 8 */ + /* vector 9: UART1 SIxxR_H, Bit 24 */ + {&mpc83xx.ipic.sipnr [0], &mpc83xx.ipic.simsr [0], 24}, + /* vector 10: UART2 SIxxR_H, Bit 25 */ + {&mpc83xx.ipic.sipnr [0], &mpc83xx.ipic.simsr [0], 25}, + /* vector 11: SEC SIxxR_H, Bit 26 */ + {&mpc83xx.ipic.sipnr [0], &mpc83xx.ipic.simsr [0], 26}, + {NULL, NULL, 0}, /* reserved vector 12 */ + {NULL, NULL, 0}, /* reserved vector 13 */ + /* vector 14: I2C1 SIxxR_H, Bit 29 */ + {&mpc83xx.ipic.sipnr [0], &mpc83xx.ipic.simsr [0], 29}, + /* vector 15: I2C2 SIxxR_H, Bit 30 */ + {&mpc83xx.ipic.sipnr [0], &mpc83xx.ipic.simsr [0], 30}, + /* vector 16: SPI SIxxR_H, Bit 31 */ + {&mpc83xx.ipic.sipnr [0], &mpc83xx.ipic.simsr [0], 31}, + /* vector 17: IRQ1 SExxR , Bit 1 */ + {&mpc83xx.ipic.sepnr, &mpc83xx.ipic.semsr, 1}, + /* vector 18: IRQ2 SExxR , Bit 2 */ + {&mpc83xx.ipic.sepnr, &mpc83xx.ipic.semsr, 2}, + /* vector 19: IRQ3 SExxR , Bit 3 */ + {&mpc83xx.ipic.sepnr, &mpc83xx.ipic.semsr, 3}, + /* vector 20: IRQ4 SExxR , Bit 4 */ + {&mpc83xx.ipic.sepnr, &mpc83xx.ipic.semsr, 4}, + /* vector 21: IRQ5 SExxR , Bit 5 */ + {&mpc83xx.ipic.sepnr, &mpc83xx.ipic.semsr, 5}, + /* vector 22: IRQ6 SExxR , Bit 6 */ + {&mpc83xx.ipic.sepnr, &mpc83xx.ipic.semsr, 6}, + /* vector 23: IRQ7 SExxR , Bit 7 */ + {&mpc83xx.ipic.sepnr, &mpc83xx.ipic.semsr, 7}, + {NULL, NULL, 0}, /* reserved vector 24 */ + {NULL, NULL, 0}, /* reserved vector 25 */ + {NULL, NULL, 0}, /* reserved vector 26 */ + {NULL, NULL, 0}, /* reserved vector 27 */ + {NULL, NULL, 0}, /* reserved vector 28 */ + {NULL, NULL, 0}, /* reserved vector 29 */ + {NULL, NULL, 0}, /* reserved vector 30 */ + {NULL, NULL, 0}, /* reserved vector 31 */ + /* vector 32: TSEC1 Tx SIxxR_H , Bit 0 */ + {&mpc83xx.ipic.sipnr [0], &mpc83xx.ipic.simsr [0], 0}, + /* vector 33: TSEC1 Rx SIxxR_H , Bit 1 */ + {&mpc83xx.ipic.sipnr [0], &mpc83xx.ipic.simsr [0], 1}, + /* vector 34: TSEC1 Err SIxxR_H , Bit 2 */ + {&mpc83xx.ipic.sipnr [0], &mpc83xx.ipic.simsr [0], 2}, + /* vector 35: TSEC2 Tx SIxxR_H , Bit 3 */ + {&mpc83xx.ipic.sipnr [0], &mpc83xx.ipic.simsr [0], 3}, + /* vector 36: TSEC2 Rx SIxxR_H , Bit 4 */ + {&mpc83xx.ipic.sipnr [0], &mpc83xx.ipic.simsr [0], 4}, + /* vector 37: TSEC2 Err SIxxR_H , Bit 5 */ + {&mpc83xx.ipic.sipnr [0], &mpc83xx.ipic.simsr [0], 5}, + /* vector 38: USB DR SIxxR_H , Bit 6 */ + {&mpc83xx.ipic.sipnr [0], &mpc83xx.ipic.simsr [0], 6}, + /* vector 39: USB MPH SIxxR_H , Bit 7 */ + {&mpc83xx.ipic.sipnr [0], &mpc83xx.ipic.simsr [0], 7}, + {NULL, NULL, 0}, /* reserved vector 40 */ + {NULL, NULL, 0}, /* reserved vector 41 */ + {NULL, NULL, 0}, /* reserved vector 42 */ + {NULL, NULL, 0}, /* reserved vector 43 */ + {NULL, NULL, 0}, /* reserved vector 44 */ + {NULL, NULL, 0}, /* reserved vector 45 */ + {NULL, NULL, 0}, /* reserved vector 46 */ + {NULL, NULL, 0}, /* reserved vector 47 */ + /* vector 48: IRQ0 SExxR , Bit 0 */ + {&mpc83xx.ipic.sepnr, &mpc83xx.ipic.semsr, 0}, + {NULL, NULL, 0}, /* reserved vector 49 */ + {NULL, NULL, 0}, /* reserved vector 50 */ + {NULL, NULL, 0}, /* reserved vector 51 */ + {NULL, NULL, 0}, /* reserved vector 52 */ + {NULL, NULL, 0}, /* reserved vector 53 */ + {NULL, NULL, 0}, /* reserved vector 54 */ + {NULL, NULL, 0}, /* reserved vector 55 */ + {NULL, NULL, 0}, /* reserved vector 56 */ + {NULL, NULL, 0}, /* reserved vector 57 */ + {NULL, NULL, 0}, /* reserved vector 58 */ + {NULL, NULL, 0}, /* reserved vector 59 */ + {NULL, NULL, 0}, /* reserved vector 60 */ + {NULL, NULL, 0}, /* reserved vector 61 */ + {NULL, NULL, 0}, /* reserved vector 62 */ + {NULL, NULL, 0}, /* reserved vector 63 */ + /* vector 64: RTC SEC SIxxR_L , Bit 0 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 0}, + /* vector 65: PIT SIxxR_L , Bit 1 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 1}, + /* vector 66: PCI1 SIxxR_L , Bit 2 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 2}, + /* vector 67: PCI2 SIxxR_L , Bit 3 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 3}, + /* vector 68: RTC ALR SIxxR_L , Bit 4 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 4}, + /* vector 69: MU SIxxR_L , Bit 5 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 5}, + /* vector 70: SBA SIxxR_L , Bit 6 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 6}, + /* vector 71: DMA SIxxR_L , Bit 7 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 7}, + /* vector 72: GTM4 SIxxR_L , Bit 8 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 8}, + /* vector 73: GTM8 SIxxR_L , Bit 9 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 9}, + /* vector 74: GPIO1 SIxxR_L , Bit 10 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 10}, + /* vector 75: GPIO2 SIxxR_L , Bit 11 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 11}, + /* vector 76: DDR SIxxR_L , Bit 12 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 12}, + /* vector 77: LBC SIxxR_L , Bit 13 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 13}, + /* vector 78: GTM2 SIxxR_L , Bit 14 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 14}, + /* vector 79: GTM6 SIxxR_L , Bit 15 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 15}, + /* vector 80: PMC SIxxR_L , Bit 16 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 16}, + {NULL, NULL, 0}, /* reserved vector 81 */ + {NULL, NULL, 0}, /* reserved vector 82 */ + {NULL, NULL, 0}, /* reserved vector 63 */ + /* vector 84: GTM3 SIxxR_L , Bit 20 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 20}, + /* vector 85: GTM7 SIxxR_L , Bit 21 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 21}, + {NULL, NULL, 0}, /* reserved vector 81 */ + {NULL, NULL, 0}, /* reserved vector 82 */ + {NULL, NULL, 0}, /* reserved vector 63 */ + {NULL, NULL, 0}, /* reserved vector 63 */ + /* vector 90: GTM1 SIxxR_L , Bit 26 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 26}, + /* vector 91: GTM5 SIxxR_L , Bit 27 */ + {&mpc83xx.ipic.sipnr [1], &mpc83xx.ipic.simsr [1], 27} +}; + +static const uint8_t + mpc83xx_ipic_mask_position_table [MPC83XX_IPIC_VECTOR_NUMBER] = { + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + 7, + 6, + 5, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + 2, + 1, + 0, + 94, + 93, + 92, + 91, + 90, + 89, + 88, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + 31, + 30, + 29, + 28, + 27, + 26, + 25, + 24, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + 95, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + 63, + 62, + 61, + 60, + 59, + 58, + 57, + 56, + 55, + 54, + 53, + 52, + 51, + 50, + 49, + 48, + 47, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + 43, + 42, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + MPC83XX_IPIC_INVALID_MASK_POSITION, + 37, + 36 +}; + +/* + * this array will be filled with mask values needed + * to temporarily disable all IRQ soures with lower or same + * priority of the current source (whose vector is the array index) + */ +static mpc83xx_ipic_mask_t mpc83xx_ipic_prio2mask [MPC83XX_IPIC_VECTOR_NUMBER]; + +rtems_status_code mpc83xx_ipic_set_mask( + rtems_vector_number vector, + rtems_vector_number mask_vector, + bool mask +) +{ + uint8_t pos = 0; + mpc83xx_ipic_mask_t *mask_entry; + uint32_t *mask_reg; + rtems_interrupt_level level; + + /* Parameter check */ + if (!MPC83XX_IPIC_IS_VALID_VECTOR( vector) || + !MPC83XX_IPIC_IS_VALID_VECTOR( mask_vector)) { + return RTEMS_INVALID_NUMBER; + } else if (vector == mask_vector) { + return RTEMS_RESOURCE_IN_USE; + } + + /* Position and mask entry */ + pos = mpc83xx_ipic_mask_position_table [mask_vector]; + mask_entry = &mpc83xx_ipic_prio2mask [vector]; + + /* Mask register and position */ + if (pos < 32) { + mask_reg = &mask_entry->simsr_mask [0]; + } else if (pos < 64) { + pos -= 32; + mask_reg = &mask_entry->simsr_mask [1]; + } else if (pos < 96) { + pos -= 64; + mask_reg = &mask_entry->semsr_mask; + } else if (pos < 128) { + pos -= 96; + mask_reg = &mask_entry->sermr_mask; + } else { + return RTEMS_NOT_IMPLEMENTED; + } + + /* Mask or unmask */ + if (mask) { + rtems_interrupt_disable( level); + *mask_reg &= ~(1 << pos); + rtems_interrupt_enable( level); + } else { + rtems_interrupt_disable( level); + *mask_reg |= 1 << pos; + rtems_interrupt_enable( level); + } + + return RTEMS_SUCCESSFUL; +} + +rtems_status_code mpc83xx_ipic_set_highest_priority_interrupt( + rtems_vector_number vector, + int type +) +{ + rtems_interrupt_level level; + uint32_t reg = 0; + + if (!MPC83XX_IPIC_IS_VALID_VECTOR( vector)) { + return RTEMS_INVALID_NUMBER; + } else if (type < 0 || type > MPC83XX_IPIC_INTERRUPT_CRITICAL) { + return RTEMS_INVALID_NUMBER; + } + + rtems_interrupt_disable( level); + reg = mpc83xx.ipic.sicfr; + mpc83xx.ipic.sicfr = (reg & ~0x7f000300) | (vector << 24) | (type << 8); + rtems_interrupt_enable( level); + + return RTEMS_SUCCESSFUL; +} + +/* + * functions to enable/disable a source at the ipic + */ +void bsp_interrupt_vector_enable( rtems_vector_number vector) +{ + rtems_vector_number vecnum = vector - BSP_IPIC_IRQ_LOWEST_OFFSET; + const BSP_isrc_rsc_t *rsc_ptr; + + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + if (MPC83XX_IPIC_IS_VALID_VECTOR( vecnum)) { + rsc_ptr = &mpc83xx_ipic_isrc_rsc [vecnum]; + if (rsc_ptr->mask_reg != NULL) { + uint32_t bit = 1U << (31 - rsc_ptr->bit_num); + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + *(rsc_ptr->mask_reg) |= bit; + rtems_interrupt_enable(level); + } + } +} + +void bsp_interrupt_vector_disable( rtems_vector_number vector) +{ + rtems_vector_number vecnum = vector - BSP_IPIC_IRQ_LOWEST_OFFSET; + const BSP_isrc_rsc_t *rsc_ptr; + + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + if (MPC83XX_IPIC_IS_VALID_VECTOR( vecnum)) { + rsc_ptr = &mpc83xx_ipic_isrc_rsc [vecnum]; + if (rsc_ptr->mask_reg != NULL) { + uint32_t bit = 1U << (31 - rsc_ptr->bit_num); + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + *(rsc_ptr->mask_reg) &= ~bit; + rtems_interrupt_enable(level); + } + } +} + +/* + * IRQ Handler: this is called from the primary exception dispatcher + */ +static int BSP_irq_handle_at_ipic( unsigned excNum) +{ + int32_t vecnum; +#ifdef GEN83XX_ENABLE_INTERRUPT_NESTING + mpc83xx_ipic_mask_t mask_save; + const mpc83xx_ipic_mask_t *mask_ptr; + uint32_t msr = 0; + rtems_interrupt_level level; +#endif + + /* Get vector number */ + switch (excNum) { + case ASM_EXT_VECTOR: + vecnum = MPC83xx_VCR_TO_VEC( mpc83xx.ipic.sivcr); + break; + case ASM_E300_SYSMGMT_VECTOR: + vecnum = MPC83xx_VCR_TO_VEC( mpc83xx.ipic.smvcr); + break; + case ASM_E300_CRIT_VECTOR: + vecnum = MPC83xx_VCR_TO_VEC( mpc83xx.ipic.scvcr); + break; + default: + return 1; + } + + /* + * Check the vector number, mask lower priority interrupts, enable + * exceptions and dispatch the handler. + */ + if (MPC83XX_IPIC_IS_VALID_VECTOR( vecnum)) { +#ifdef GEN83XX_ENABLE_INTERRUPT_NESTING + mask_ptr = &mpc83xx_ipic_prio2mask [vecnum]; + + rtems_interrupt_disable( level); + + /* Save current mask registers */ + mask_save.simsr_mask [0] = mpc83xx.ipic.simsr [0]; + mask_save.simsr_mask [1] = mpc83xx.ipic.simsr [1]; + mask_save.semsr_mask = mpc83xx.ipic.semsr; + mask_save.sermr_mask = mpc83xx.ipic.sermr; + + /* Mask all lower priority interrupts */ + mpc83xx.ipic.simsr [0] &= mask_ptr->simsr_mask [0]; + mpc83xx.ipic.simsr [1] &= mask_ptr->simsr_mask [1]; + mpc83xx.ipic.semsr &= mask_ptr->semsr_mask; + mpc83xx.ipic.sermr &= mask_ptr->sermr_mask; + + rtems_interrupt_enable( level); + + /* Enable all interrupts */ + if (excNum != ASM_E300_CRIT_VECTOR) { + msr = ppc_external_exceptions_enable(); + } +#endif /* GEN83XX_ENABLE_INTERRUPT_NESTING */ + + /* Dispatch interrupt handlers */ + bsp_interrupt_handler_dispatch( vecnum + BSP_IPIC_IRQ_LOWEST_OFFSET); + +#ifdef GEN83XX_ENABLE_INTERRUPT_NESTING + /* Restore machine state */ + if (excNum != ASM_E300_CRIT_VECTOR) { + ppc_external_exceptions_disable( msr); + } + + /* Restore initial masks */ + rtems_interrupt_disable( level); + mpc83xx.ipic.simsr [0] = mask_save.simsr_mask [0]; + mpc83xx.ipic.simsr [1] = mask_save.simsr_mask [1]; + mpc83xx.ipic.semsr = mask_save.semsr_mask; + mpc83xx.ipic.sermr = mask_save.sermr_mask; + rtems_interrupt_enable( level); +#endif /* GEN83XX_ENABLE_INTERRUPT_NESTING */ + } else { + bsp_interrupt_handler_default( vecnum); + } + + return 0; +} + +/* + * Fill the array mpc83xx_ipic_prio2mask to allow masking of lower prio sources + * to implement nested interrupts. + */ +static rtems_status_code mpc83xx_ipic_calc_prio2mask(void) +{ + rtems_status_code rc = RTEMS_SUCCESSFUL; + + /* + * FIXME: fill the array + */ + return rc; +} + +/* + * Activate the interrupt controller + */ +static rtems_status_code mpc83xx_ipic_initialize(void) +{ + /* + * mask off all interrupts + */ + mpc83xx.ipic.simsr [0] = 0; + mpc83xx.ipic.simsr [1] = 0; + mpc83xx.ipic.semsr = 0; + mpc83xx.ipic.sermr = 0; + /* + * set desired configuration as defined in bspopts.h + * normally, the default values should be fine + */ +#if defined( BSP_SICFR_VAL) /* defined in bspopts.h ? */ + mpc83xx.ipic.sicfr = BSP_SICFR_VAL; +#endif + + /* + * set desired priorities as defined in bspopts.h + * normally, the default values should be fine + */ +#if defined( BSP_SIPRR0_VAL) /* defined in bspopts.h ? */ + mpc83xx.ipic.siprr [0] = BSP_SIPRR0_VAL; +#endif + +#if defined( BSP_SIPRR1_VAL) /* defined in bspopts.h ? */ + mpc83xx.ipic.siprr [1] = BSP_SIPRR1_VAL; +#endif + +#if defined( BSP_SIPRR2_VAL) /* defined in bspopts.h ? */ + mpc83xx.ipic.siprr [2] = BSP_SIPRR2_VAL; +#endif + +#if defined( BSP_SIPRR3_VAL) /* defined in bspopts.h ? */ + mpc83xx.ipic.siprr [3] = BSP_SIPRR3_VAL; +#endif + +#if defined( BSP_SMPRR0_VAL) /* defined in bspopts.h ? */ + mpc83xx.ipic.smprr [0] = BSP_SMPRR0_VAL; +#endif + +#if defined( BSP_SMPRR1_VAL) /* defined in bspopts.h ? */ + mpc83xx.ipic.smprr [1] = BSP_SMPRR1_VAL; +#endif + +#if defined( BSP_SECNR_VAL) /* defined in bspopts.h ? */ + mpc83xx.ipic.secnr = BSP_SECNR_VAL; +#endif + + /* + * calculate priority masks + */ + return mpc83xx_ipic_calc_prio2mask(); +} + +static int mpc83xx_exception_handler( + BSP_Exception_frame *frame, + unsigned exception_number +) +{ + return BSP_irq_handle_at_ipic( exception_number); +} + +rtems_status_code bsp_interrupt_facility_initialize() +{ + /* Install exception handler */ + if (ppc_exc_set_handler( ASM_EXT_VECTOR, mpc83xx_exception_handler)) { + return RTEMS_IO_ERROR; + } + if (ppc_exc_set_handler( ASM_E300_SYSMGMT_VECTOR, mpc83xx_exception_handler)) { + return RTEMS_IO_ERROR; + } + if (ppc_exc_set_handler( ASM_E300_CRIT_VECTOR, mpc83xx_exception_handler)) { + return RTEMS_IO_ERROR; + } + + /* Initialize the interrupt controller */ + return mpc83xx_ipic_initialize(); +} diff --git a/bsps/powerpc/haleakala/irq/irq.c b/bsps/powerpc/haleakala/irq/irq.c new file mode 100644 index 0000000000..c9607a032d --- /dev/null +++ b/bsps/powerpc/haleakala/irq/irq.c @@ -0,0 +1,237 @@ +/* + * + * + * 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. + * + * Middleware support for PPC405 by M.Hamel ADInstruments Ltd 2008 + */ + +#include <rtems.h> +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq_supp.h> +#include <bsp/vectors.h> +#include <libcpu/powerpc-utility.h> + + +/* PPC405EX UIC numbers */ +#define UIC_DCR_BASE 0xc0 +#define UIC0_SR (UIC_DCR_BASE+0x0) /* UIC status */ +#define UIC0_SRS (UIC_DCR_BASE+0x1) /* UIC status set */ +#define UIC0_ER (UIC_DCR_BASE+0x2) /* UIC enable */ +#define UIC0_CR (UIC_DCR_BASE+0x3) /* UIC critical */ +#define UIC0_PR (UIC_DCR_BASE+0x4) /* UIC polarity */ +#define UIC0_TR (UIC_DCR_BASE+0x5) /* UIC triggering */ +#define UIC0_MSR (UIC_DCR_BASE+0x6) /* UIC masked status */ +#define UIC0_VR (UIC_DCR_BASE+0x7) /* UIC vector */ +#define UIC0_VCR (UIC_DCR_BASE+0x8) /* UIC vector configuration */ + +#define UIC1_SR (UIC_DCR_BASE+0x10) /* UIC status */ +#define UIC1_SRS (UIC_DCR_BASE+0x11) /* UIC status set */ +#define UIC1_ER (UIC_DCR_BASE+0x12) /* UIC enable */ +#define UIC1_CR (UIC_DCR_BASE+0x13) /* UIC critical */ +#define UIC1_PR (UIC_DCR_BASE+0x14) /* UIC polarity */ +#define UIC1_TR (UIC_DCR_BASE+0x15) /* UIC triggering */ +#define UIC1_MSR (UIC_DCR_BASE+0x16) /* UIC masked status */ +#define UIC1_VR (UIC_DCR_BASE+0x17) /* UIC vector */ +#define UIC1_VCR (UIC_DCR_BASE+0x18) /* UIC vector configuration */ + +#define UIC2_SR (UIC_DCR_BASE+0x20) /* UIC status */ +#define UIC2_SRS (UIC_DCR_BASE+0x21) /* UIC status set */ +#define UIC2_ER (UIC_DCR_BASE+0x22) /* UIC enable */ +#define UIC2_CR (UIC_DCR_BASE+0x23) /* UIC critical */ +#define UIC2_PR (UIC_DCR_BASE+0x24) /* UIC polarity */ +#define UIC2_TR (UIC_DCR_BASE+0x25) /* UIC triggering */ +#define UIC2_MSR (UIC_DCR_BASE+0x26) /* UIC masked status */ +#define UIC2_VR (UIC_DCR_BASE+0x27) /* UIC vector */ +#define UIC2_VCR (UIC_DCR_BASE+0x28) /* UIC vector configuration */ + +enum { kUICWords = 3 }; + +static rtems_irq_connect_data* rtems_hdl_tblP; +static rtems_irq_connect_data dflt_entry; + +static uint32_t gEnabledInts[kUICWords]; /* 1-bits mean enabled */ +static uint32_t gIntInhibited[kUICWords]; /* 1-bits disable, overriding gEnabledInts because the interrupt + is being processed in C_dispatch_irq_handler */ + +static inline int IsUICIRQ(const rtems_irq_number irqLine) +{ + return (((int) irqLine <= BSP_UIC_IRQ_MAX_OFFSET) && + ((int) irqLine >= BSP_UIC_IRQ_LOWEST_OFFSET) + ); +} + +static void WriteIState(void) +/* Write the gEnabledInts state masked by gIntInhibited to the hardware */ +{ + PPC_SET_DEVICE_CONTROL_REGISTER(UIC0_ER, + gEnabledInts[0] & ~gIntInhibited[0]); + PPC_SET_DEVICE_CONTROL_REGISTER(UIC1_ER, + gEnabledInts[1] & ~gIntInhibited[1]); + PPC_SET_DEVICE_CONTROL_REGISTER(UIC2_ER, + gEnabledInts[2] & ~gIntInhibited[2]); +} + +void +BSP_enable_irq_at_pic(const rtems_irq_number irq) +/* Enable an interrupt; this can be called from inside C_dispatch_irq_handler */ +{ + if (IsUICIRQ(irq)) { + /* Set relevant bit in the state, write state to the UIC */ + gEnabledInts[irq>>5] |= (0x80000000 >> (irq & 0x1F)); + WriteIState(); + } +} + +int +BSP_disable_irq_at_pic(const rtems_irq_number irq) +/* Enable an interrupt; this can be called from inside C_dispatch_irq_handler */ +{ + if (IsUICIRQ(irq)) { + uint32_t oldState; + int iword = irq>>5; + uint32_t mask = (0x80000000 >> (irq & 0x1F)); + + oldState = gEnabledInts[iword] & mask; + gEnabledInts[iword] &= ~mask; + WriteIState(); + return oldState ? 1 : 0; + } else + return -1; +} + +int +BSP_setup_the_pic(rtems_irq_global_settings* config) +{ + int i; + + dflt_entry = config->defaultEntry; + rtems_hdl_tblP = config->irqHdlTbl; + for (i=0; i<kUICWords; i++) + gIntInhibited[i] = 0; + + /* disable all interrupts */ + PPC_SET_DEVICE_CONTROL_REGISTER (UIC2_ER, 0x00000000); + /* Set Critical / Non Critical interrupts */ + PPC_SET_DEVICE_CONTROL_REGISTER (UIC2_CR, 0x00000000); + /* Set Interrupt Polarities */ + PPC_SET_DEVICE_CONTROL_REGISTER (UIC2_PR, 0xf7ffffff); + /* Set Interrupt Trigger Levels */ + PPC_SET_DEVICE_CONTROL_REGISTER (UIC2_TR, 0x01e1fff8); + /* Set Vect base=0,INT31 Highest priority */ + PPC_SET_DEVICE_CONTROL_REGISTER (UIC2_VR, 0x00000001); + /* clear all interrupts */ + PPC_SET_DEVICE_CONTROL_REGISTER (UIC2_SR, 0xffffffff); + + /* disable all interrupts */ + PPC_SET_DEVICE_CONTROL_REGISTER (UIC1_ER, 0x00000000); + /* Set Critical / Non Critical interrupts */ + PPC_SET_DEVICE_CONTROL_REGISTER (UIC1_CR, 0x00000000); + /* Set Interrupt Polarities */ + PPC_SET_DEVICE_CONTROL_REGISTER (UIC1_PR, 0xfffac785); + /* Set Interrupt Trigger Levels */ + PPC_SET_DEVICE_CONTROL_REGISTER (UIC1_TR, 0x001d0040); + /* Set Vect base=0,INT31 Highest priority */ + PPC_SET_DEVICE_CONTROL_REGISTER (UIC1_VR, 0x00000001); + /* clear all interrupts */ + PPC_SET_DEVICE_CONTROL_REGISTER (UIC1_SR, 0xffffffff); + + /* Disable all interrupts except cascade UIC0 and UIC1 */ + PPC_SET_DEVICE_CONTROL_REGISTER (UIC0_ER, 0x0000000a); + /* Set Critical / Non Critical interrupts */ + PPC_SET_DEVICE_CONTROL_REGISTER (UIC0_CR, 0x00000000); + /* Set Interrupt Polarities */ + PPC_SET_DEVICE_CONTROL_REGISTER (UIC0_PR, 0xffbfefef); + /* Set Interrupt Trigger Levels */ + PPC_SET_DEVICE_CONTROL_REGISTER (UIC0_TR, 0x00007000); + /* Set Vect base=0,INT31 Highest priority */ + PPC_SET_DEVICE_CONTROL_REGISTER (UIC0_VR, 0x00000001); + /* clear all interrupts */ + PPC_SET_DEVICE_CONTROL_REGISTER (UIC0_SR, 0xffffffff); + + return 1; +} + + +/* + * High level IRQ handler called from shared_raw_irq_code_entry; decode and + * dispatch. Note that this routine needs to be re-entrant + * + * No support for critical interrupts here yet + */ + +int +C_dispatch_irq_handler( BSP_Exception_frame* frame, unsigned int excNum ) +{ + if (excNum == ASM_EXT_VECTOR) { + uint32_t active[kUICWords]; + + /* Fetch the masked flags that tell us what external ints are active. + Likely to be only one, but we need to handle more than one, + OR the flags into gIntInhibited */ + active[0] = PPC_DEVICE_CONTROL_REGISTER(UIC0_MSR); + active[1] = PPC_DEVICE_CONTROL_REGISTER(UIC1_MSR); + active[2] = PPC_DEVICE_CONTROL_REGISTER(UIC2_MSR); + gIntInhibited[0] |= active[0]; + gIntInhibited[1] |= active[1]; + gIntInhibited[2] |= active[2]; + + /* ...and update the hardware so the active interrupts are disabled */ + WriteIState(); + + /* Loop, calling bsp_irq_dispatch_list for each active interrupt */ + while ((active[0] | active[1] | active[2]) != 0) { + uint32_t index = -1; + uint32_t bit, bmask; + + /* Find an active interrupt, searching 0..2, bit 0..bit 31 (IBM order) */ + do { + index++; + asm volatile (" cntlzw %0, %1":"=r" (bit):"r" (active[index])); + } while (bit==32); + + /* Call the matching handler */ + bsp_irq_dispatch_list(rtems_hdl_tblP, (index*32)+bit, dflt_entry.hdl); + + /* Write a 1-bit to the appropriate status register to clear it */ + bmask = 0x80000000 >> bit; + switch (index) { + case 0: + PPC_SET_DEVICE_CONTROL_REGISTER(UIC0_SR, bmask); + break; + case 1: + PPC_SET_DEVICE_CONTROL_REGISTER(UIC1_SR, bmask); + break; + case 2: + PPC_SET_DEVICE_CONTROL_REGISTER(UIC2_SR, bmask); + break; + } + + /* Clear in the active record and gIntInhibited */ + active[index] &= ~bmask; + gIntInhibited[index] &= ~bmask; + }; + + /* Update the hardware again so the interrupts we have handled are unmasked */ + WriteIState(); + return 0; + + } else if (excNum == ASM_DEC_VECTOR) { /* 0x1000 remapped by C_dispatch_dec_handler_bookE */ + bsp_irq_dispatch_list(rtems_hdl_tblP, BSP_PIT, dflt_entry.hdl); + return 0; + + } else if (excNum == ASM_BOOKE_FIT_VECTOR) { /* 0x1010 mapped to 0x13 by ppc_get_vector_addr */ + bsp_irq_dispatch_list(rtems_hdl_tblP, BSP_FIT, dflt_entry.hdl); + return 0; + + } else if (excNum == ASM_BOOKE_WDOG_VECTOR) { /* 0x1020 mapped to 0x14 by ppc_get_vector_addr */ + bsp_irq_dispatch_list(rtems_hdl_tblP, BSP_WDOG, dflt_entry.hdl); + return 0; + + } else + return -1; /* unhandled interrupt, panic time */ +} + diff --git a/bsps/powerpc/haleakala/irq/irq_init.c b/bsps/powerpc/haleakala/irq/irq_init.c new file mode 100644 index 0000000000..d48855a979 --- /dev/null +++ b/bsps/powerpc/haleakala/irq/irq_init.c @@ -0,0 +1,96 @@ +/*===============================================================*\ +| Project: RTEMS Haleakala BSP | +| * by Michael Hamel ADInstruments Ltd 2008 | ++-----------------------------------------------------------------+ +| 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. | +| | ++-----------------------------------------------------------------+ +| this file contains the irq controller handler | +\*===============================================================*/ +#include <libcpu/spr.h> +#include <bsp/irq.h> +#include <bsp.h> +#include <bsp/vectors.h> +#include <rtems/bspIo.h> +#include <rtems/powerpc/powerpc.h> + + +/* + * default on/off function + */ +static void nop_func(void) +{ +} + +/* + * default isOn function + */ +static int not_connected(void) +{ + return 0; +} + +static rtems_irq_connect_data rtemsIrq[BSP_IRQ_NUMBER]; +static rtems_irq_global_settings initial_config; +static rtems_irq_connect_data defaultIrq = { + .name = 0, + .hdl = NULL, + .handle = NULL, + .on = (rtems_irq_enable) nop_func, + .off = (rtems_irq_disable) nop_func, + .isOn = (rtems_irq_is_enabled) not_connected, +#ifdef BSP_SHARED_HANDLER_SUPPORT + .next_handler = NULL +#endif +}; + +static rtems_irq_prio irqPrioTable[BSP_IRQ_NUMBER]={ + /* + * Processor exceptions handled as interrupts + */ + 0 +}; + + /* + * This code assumes the exceptions management setup has already + * been done. We just need to replace the exceptions that will + * be handled like interrupt. On mcp750/mpc750 and many PPC processors + * this means the decrementer exception and the external exception. + */ + +void BSP_rtems_irq_mng_init(unsigned cpuId) +{ + int i; + + /* + * re-init the rtemsIrq table + */ + for (i = 0; i < BSP_IRQ_NUMBER; i++) { + rtemsIrq[i] = defaultIrq; + rtemsIrq[i].name = i; + } + /* + * Init initial Interrupt management config + */ + initial_config.irqNb = BSP_IRQ_NUMBER; + initial_config.defaultEntry = defaultIrq; + initial_config.irqHdlTbl = rtemsIrq; + initial_config.irqBase = BSP_LOWEST_OFFSET; + initial_config.irqPrioTbl = irqPrioTable; + + if (!BSP_rtems_irq_mngt_set(&initial_config)) { + /* + * put something here that will show the failure... + */ + rtems_panic( + "Unable to initialize RTEMS interrupt management!!! System locked\n" + ); + } + + #ifdef TRACE_IRQ_INIT + printk("RTEMS IRQ management is now operational\n"); + #endif +} diff --git a/bsps/powerpc/mpc8260ads/irq/irq.c b/bsps/powerpc/mpc8260ads/irq/irq.c new file mode 100644 index 0000000000..baca1e0e05 --- /dev/null +++ b/bsps/powerpc/mpc8260ads/irq/irq.c @@ -0,0 +1,372 @@ +/* + * + * This file contains the implementation of the function described in irq.h + * + * Copyright (C) 1998, 1999 valette@crf.canon.fr + * + * Modified for mpc8260 Andy Dachs <a.dachs@sstl.co.uk> + * Surrey Satellite Technology Limited, 2000 + * 21/4/2002 Added support for nested interrupts and improved + * masking operations. Now we compute priority mask based + * on table in irq_init.c + * + * 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 <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> +#include <rtems.h> +#include <rtems/bspIo.h> +#include <bsp/vectors.h> +#include <mpc8260.h> + +/* + * Check if symbolic IRQ name is an CPM IRQ + */ +static inline int is_cpm_irq(const rtems_irq_number irqLine) +{ + return (((int) irqLine <= BSP_CPM_IRQ_MAX_OFFSET) & + ((int) irqLine >= BSP_CPM_IRQ_LOWEST_OFFSET) + ); +} + +typedef struct { + uint32_t mask_h; /* mask for sipnr_h and simr_h */ + uint32_t mask_l; /* mask for sipnr_l and simr_l */ + uint32_t priority_h; /* mask this and lower priority ints */ + uint32_t priority_l; +} m82xxIrqMasks_t; + +static unsigned char irqPrioTable[BSP_CPM_IRQ_NUMBER]={ + /* + * actual priorities for interrupt : + */ + /* + * CPM Interrupts + */ + 0, 45, 63, 44, 66, 68, 35, 39, 50, 62, 34, 0, 30, 40, 52, 58, + 2, 3, 0, 5, 15, 16, 17, 18, 49, 51, 0, 0, 0, 0, 0, 0, + 6, 7, 8, 0, 11, 12, 0, 0, 20, 21, 22, 23, 0, 0, 0, 0, + 29, 31, 33, 37, 38, 41, 47, 48, 55, 56, 57, 60, 64, 65, 69, 70, + +}; + +/* + * Mask fields should have a '1' in the bit position for that + * interrupt. + * Priority masks calculated later based on priority table + */ + +static m82xxIrqMasks_t SIU_MaskBit[BSP_CPM_IRQ_NUMBER] = +{ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* err */ + { 0x00000000, 0x00008000, 0x00000000, 0x00000000 }, /* i2c */ + { 0x00000000, 0x00004000, 0x00000000, 0x00000000 }, /* spi */ + { 0x00000000, 0x00002000, 0x00000000, 0x00000000 }, /* rtt */ + { 0x00000000, 0x00001000, 0x00000000, 0x00000000 }, /* smc1 */ + { 0x00000000, 0x00000800, 0x00000000, 0x00000000 }, /* smc2 */ + { 0x00000000, 0x00000400, 0x00000000, 0x00000000 }, /* idma1 */ + { 0x00000000, 0x00000200, 0x00000000, 0x00000000 }, /* idma2 */ + { 0x00000000, 0x00000100, 0x00000000, 0x00000000 }, /* idma3 */ + { 0x00000000, 0x00000080, 0x00000000, 0x00000000 }, /* idma4 */ + { 0x00000000, 0x00000040, 0x00000000, 0x00000000 }, /* sdma */ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */ + { 0x00000000, 0x00000010, 0x00000000, 0x00000000 }, /* tmr1 */ + { 0x00000000, 0x00000008, 0x00000000, 0x00000000 }, /* tmr2 */ + { 0x00000000, 0x00000004, 0x00000000, 0x00000000 }, /* tmr3 */ + { 0x00000000, 0x00000002, 0x00000000, 0x00000000 }, /* tmr4 */ + { 0x00000004, 0x00000000, 0x00000000, 0x00000000 }, /* tmcnt */ + { 0x00000002, 0x00000000, 0x00000000, 0x00000000 }, /* pit */ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */ + { 0x00004000, 0x00000000, 0x00000000, 0x00000000 }, /* irq1 */ + { 0x00002000, 0x00000000, 0x00000000, 0x00000000 }, /* irq2 */ + { 0x00001000, 0x00000000, 0x00000000, 0x00000000 }, /* irq3 */ + { 0x00000800, 0x00000000, 0x00000000, 0x00000000 }, /* irq4 */ + { 0x00000400, 0x00000000, 0x00000000, 0x00000000 }, /* irq5 */ + { 0x00000200, 0x00000000, 0x00000000, 0x00000000 }, /* irq6 */ + { 0x00000100, 0x00000000, 0x00000000, 0x00000000 }, /* irq7 */ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */ + { 0x00000000, 0x80000000, 0x00000000, 0x00000000 }, /* fcc1 */ + { 0x00000000, 0x40000000, 0x00000000, 0x00000000 }, /* fcc2 */ + { 0x00000000, 0x20000000, 0x00000000, 0x00000000 }, /* fcc3 */ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */ + { 0x00000000, 0x08000000, 0x00000000, 0x00000000 }, /* mcc1 */ + { 0x00000000, 0x04000000, 0x00000000, 0x00000000 }, /* mcc2 */ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */ + { 0x00000000, 0x00800000, 0x00000000, 0x00000000 }, /* scc1 */ + { 0x00000000, 0x00400000, 0x00000000, 0x00000000 }, /* scc2 */ + { 0x00000000, 0x00200000, 0x00000000, 0x00000000 }, /* scc3 */ + { 0x00000000, 0x00100000, 0x00000000, 0x00000000 }, /* scc4 */ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */ + { 0x00010000, 0x00000000, 0x00000000, 0x00000000 }, /* pc15 */ + { 0x00020000, 0x00000000, 0x00000000, 0x00000000 }, /* pc14 */ + { 0x00040000, 0x00000000, 0x00000000, 0x00000000 }, /* pc13 */ + { 0x00080000, 0x00000000, 0x00000000, 0x00000000 }, /* pc12 */ + { 0x00100000, 0x00000000, 0x00000000, 0x00000000 }, /* pc11 */ + { 0x00200000, 0x00000000, 0x00000000, 0x00000000 }, /* pc10 */ + { 0x00400000, 0x00000000, 0x00000000, 0x00000000 }, /* pc9 */ + { 0x00800000, 0x00000000, 0x00000000, 0x00000000 }, /* pc8 */ + { 0x01000000, 0x00000000, 0x00000000, 0x00000000 }, /* pc7 */ + { 0x02000000, 0x00000000, 0x00000000, 0x00000000 }, /* pc6 */ + { 0x04000000, 0x00000000, 0x00000000, 0x00000000 }, /* pc5 */ + { 0x08000000, 0x00000000, 0x00000000, 0x00000000 }, /* pc4 */ + { 0x10000000, 0x00000000, 0x00000000, 0x00000000 }, /* pc3 */ + { 0x20000000, 0x00000000, 0x00000000, 0x00000000 }, /* pc2 */ + { 0x40000000, 0x00000000, 0x00000000, 0x00000000 }, /* pc1 */ + { 0x80000000, 0x00000000, 0x00000000, 0x00000000 }, /* pc0 */ + +}; + +/* + * ------------------------ RTEMS Irq helper functions ---------------- + */ + +/* + * Caution : this function assumes the variable "internal_config" + * is already set and that the tables it contains are still valid + * and accessible. + */ +static void compute_SIU_IvectMask_from_prio (void) +{ + /* + * The actual masks defined + * correspond to the priorities defined + * for the SIU in irq_init.c. + */ + + int i,j; + + for( i=0; i<BSP_CPM_IRQ_NUMBER; i++ ) + { + for( j=0;j<BSP_CPM_IRQ_NUMBER; j++ ) + if( irqPrioTable[j] < irqPrioTable[i] ) + { + SIU_MaskBit[i].priority_h |= SIU_MaskBit[j].mask_h; + SIU_MaskBit[i].priority_l |= SIU_MaskBit[j].mask_l; + } + } + +} + + +int BSP_irq_enable_at_cpm(const rtems_irq_number irqLine) +{ + int cpm_irq_index; + + if (!is_cpm_irq(irqLine)) + return 1; + + cpm_irq_index = ((int) (irqLine) - BSP_CPM_IRQ_LOWEST_OFFSET); + + m8260.simr_h |= SIU_MaskBit[cpm_irq_index].mask_h; + m8260.simr_l |= SIU_MaskBit[cpm_irq_index].mask_l; + + return 0; +} + +int BSP_irq_disable_at_cpm(const rtems_irq_number irqLine) +{ + int cpm_irq_index; + + if (!is_cpm_irq(irqLine)) + return 1; + + cpm_irq_index = ((int) (irqLine) - BSP_CPM_IRQ_LOWEST_OFFSET); + + m8260.simr_h &= ~(SIU_MaskBit[cpm_irq_index].mask_h); + m8260.simr_l &= ~(SIU_MaskBit[cpm_irq_index].mask_l); + + return 0; +} + +int BSP_irq_enabled_at_cpm(const rtems_irq_number irqLine) +{ + int cpm_irq_index; + + if (!is_cpm_irq(irqLine)) + return 0; + + cpm_irq_index = ((int) (irqLine) - BSP_CPM_IRQ_LOWEST_OFFSET); + + return ((m8260.simr_h & SIU_MaskBit[cpm_irq_index].mask_h) || + (m8260.simr_l & SIU_MaskBit[cpm_irq_index].mask_l)); +} + +#ifdef DISPATCH_HANDLER_STAT +volatile unsigned int maxLoop = 0; +#endif + +/* + * High level IRQ handler called from shared_raw_irq_code_entry + */ +static int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned excNum) +{ + register unsigned int irq; +#if 0 + register unsigned oldMask; /* old siu pic masks */ +#endif + register unsigned msr; + register unsigned new_msr; + register unsigned old_simr_h; + register unsigned old_simr_l; +#ifdef DISPATCH_HANDLER_STAT + unsigned loopCounter; +#endif + + /* + * Handle decrementer interrupt + */ + if (excNum == ASM_DEC_VECTOR) { + _CPU_MSR_GET(msr); + new_msr = msr | MSR_EE; + _CPU_MSR_SET(new_msr); + + bsp_interrupt_handler_dispatch(BSP_DECREMENTER); + + _CPU_MSR_SET(msr); + + return 0; + } + + /* + * Handle external interrupt generated by SIU on PPC core + */ +#ifdef DISPATCH_HANDLER_STAT + loopCounter = 0; +#endif + + while (1) { + + if( ((m8260.sipnr_h & m8260.simr_h) | (m8260.sipnr_l & m8260.simr_l)) == 0 ) { +#ifdef DISPATCH_HANDLER_STAT + if (loopCounter > maxLoop) maxLoop = loopCounter; +#endif + break; + } + + irq = (m8260.sivec >> 26) + BSP_CPM_IRQ_LOWEST_OFFSET; + + /* Clear mask and pending register */ + if( irq <= BSP_CPM_IRQ_MAX_OFFSET ) { + /* save interrupt masks */ + old_simr_h = m8260.simr_h; + old_simr_l = m8260.simr_l; + + /* mask off current interrupt and lower priority ones */ + m8260.simr_h &= SIU_MaskBit[irq].priority_h; + m8260.simr_l &= SIU_MaskBit[irq].priority_l; + + /* clear pending bit */ + m8260.sipnr_h |= SIU_MaskBit[irq].mask_h; + m8260.sipnr_l |= SIU_MaskBit[irq].mask_l; + + /* + * make sure, that the masking operations in + * ICTL and MSR are executed in order + */ + __asm__ volatile("sync":::"memory"); + + /* re-enable external exceptions */ + _CPU_MSR_GET(msr); + new_msr = msr | MSR_EE; + _CPU_MSR_SET(new_msr); + + /* call handler */ + bsp_interrupt_handler_dispatch(irq); + + /* disable exceptions again */ + _CPU_MSR_SET(msr); + + /* + * make sure, that the masking operations in + * ICTL and MSR are executed in order + */ + __asm__ volatile("sync":::"memory"); + + /* restore interrupt masks */ + m8260.simr_h = old_simr_h; + m8260.simr_l = old_simr_l; + + } +#ifdef DISPATCH_HANDLER_STAT + ++ loopCounter; +#endif + } + return 0; +} + +/* + * Initialize CPM interrupt management + */ +static void +BSP_CPM_irq_init(void) +{ + m8260.simr_l = 0; + m8260.simr_h = 0; + m8260.sipnr_l = 0xffffffff; + m8260.sipnr_h = 0xffffffff; + m8260.sicr = 0; + + /* + * Initialize the interrupt priorities. + */ + m8260.siprr = 0x05309770; /* reset value */ + m8260.scprr_h = 0x05309770; /* reset value */ + m8260.scprr_l = 0x05309770; /* reset value */ + +} + +void bsp_interrupt_vector_enable( rtems_vector_number irqnum) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(irqnum)); + + if (is_cpm_irq(irqnum)) { + /* + * Enable interrupt at PIC level + */ + BSP_irq_enable_at_cpm (irqnum); + } +} + +void bsp_interrupt_vector_disable( rtems_vector_number irqnum) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(irqnum)); + + if (is_cpm_irq(irqnum)) { + /* + * disable interrupt at PIC level + */ + BSP_irq_disable_at_cpm (irqnum); + } +} + +rtems_status_code bsp_interrupt_facility_initialize() +{ + /* Install exception handler */ + if (ppc_exc_set_handler( ASM_EXT_VECTOR, C_dispatch_irq_handler)) { + return RTEMS_IO_ERROR; + } + if (ppc_exc_set_handler( ASM_DEC_VECTOR, C_dispatch_irq_handler)) { + return RTEMS_IO_ERROR; + } + + /* Fill in priority masks */ + compute_SIU_IvectMask_from_prio(); + + /* Initialize the interrupt controller */ + BSP_CPM_irq_init(); + + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/powerpc/mvme3100/irq/irq_init.c b/bsps/powerpc/mvme3100/irq/irq_init.c new file mode 100644 index 0000000000..c40692e688 --- /dev/null +++ b/bsps/powerpc/mvme3100/irq/irq_init.c @@ -0,0 +1,138 @@ +/* irq_init.c + * + * This file contains the implementation of rtems initialization + * related to interrupt handling. + * + * CopyRight (C) 1999 valette@crf.canon.fr + * + * Enhanced by Jay Kulpinski <jskulpin@eng01.gdds.com> + * to make it valid for MVME2300 Motorola boards. + * + * Till Straumann <strauman@slac.stanford.edu>, 12/20/2001: + * Use the new interface to openpic_init + * + * Adapted for the mvme3100 BSP by T. Straumann, 2007. + * + * 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 <libcpu/io.h> +#include <bsp/pci.h> +#include <bsp/openpic.h> +#include <bsp/irq.h> +#include <bsp.h> +#include <bsp/vectors.h> +#include <rtems/bspIo.h> + +static void nop_func(void *unused) +{ + printk("Unhandled IRQ\n"); +} + +static rtems_irq_connect_data rtemsIrq[BSP_IRQ_NUMBER]; +static rtems_irq_global_settings initial_config; +static rtems_irq_connect_data defaultIrq = { + /* vectorIdex, hdl , handle , on , off , isOn */ + 0, nop_func , NULL , 0 , 0 , 0 +}; + +static rtems_irq_prio irqPrioTable[BSP_IRQ_NUMBER]={ + /* + * actual priorities for interrupt : + * 0 means that only current interrupt is masked + * 255 means all other interrupts are masked + */ + /* + * PCI Interrupts + */ + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* for raven prio 0 means unactive... */ + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* for raven prio 0 means unactive... */ + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* for raven prio 0 means unactive... */ + /* + * Processor exceptions handled as interrupts + */ + 0 +}; + + /* + * This code assumes the exceptions management setup has already + * been done. We just need to replace the exceptions that will + * be handled like interrupt. On mcp750/mpc750 and many PPC processors + * this means the decrementer exception and the external exception. + */ +void BSP_rtems_irq_mng_init(unsigned cpuId) +{ + /* We should really have a way to find the number of sources + * the driver will use so that the size of the polarity-array + * matches the driver's idea of it. + */ + unsigned char pol[56]; + int i; + + /* Note: The openpic driver initializes only as many + * 'pic-external' interrupt sources as reported + * by the feature register. + * The 8540's openpic supports 12 core-external + * and 23 core-internal (both of these groups + * are external to the PIC, i.e., 'pic-external') + * interrupts but between the corresponding + * banks of vector/priority registers there is + * a gap leaving space for 4 (unsupported) irqs. + * The driver, not knowing of this gap, would + * initialize the 12 core-external sources + * followed by 4 unsupported sources and 19 + * core-internal sources thus leaving the last + * four core-internal sources uninitialized. + * Luckily, the feature register reports + * too many sources: + * - the 4 IPI plus 4 timer plus 4 messaging + * sources are included with the count + * - there are unused core-internal sources 24..32 + * which are also supported by the pic + * bringing the reported number of sources to + * a count of 56 (12+32+4+4+4) which is enough + * so that all pic-external sources are covered + * and initialized. + * + * NOTE: All core-internal sources are active-high. + * The manual says that setting the polarity + * to 'low/0' will disable the interrupt but + * I found this not to be true: on the device + * I tested the interrupt was asserted hard. + */ + + /* core-external sources on the mvme3100 are active-low, + * core-internal sources are active high. + */ + for (i=0; i<BSP_EXT_IRQ_NUMBER; i++) + pol[i]=0; + for (i=BSP_EXT_IRQ_NUMBER; i< BSP_EXT_IRQ_NUMBER + BSP_CORE_IRQ_NUMBER; i++) + pol[i]=1; + + openpic_init(1, pol, 0, 0, 0, 0); + + /* + * re-init the rtemsIrq table + */ + for (i = 0; i < BSP_IRQ_NUMBER; i++) { + rtemsIrq[i] = defaultIrq; + rtemsIrq[i].name = i; + } + /* + * Init initial Interrupt management config + */ + initial_config.irqNb = BSP_IRQ_NUMBER; + initial_config.defaultEntry = defaultIrq; + initial_config.irqHdlTbl = rtemsIrq; + initial_config.irqBase = BSP_LOWEST_OFFSET; + initial_config.irqPrioTbl = irqPrioTable; + + if (!BSP_rtems_irq_mngt_set(&initial_config)) { + /* + * put something here that will show the failure... + */ + rtems_panic("Unable to initialize RTEMS interrupt Management!!! System locked\n"); + } +} diff --git a/bsps/powerpc/mvme5500/README.irq b/bsps/powerpc/mvme5500/README.irq new file mode 100644 index 0000000000..fb31c4a5c3 --- /dev/null +++ b/bsps/powerpc/mvme5500/README.irq @@ -0,0 +1,20 @@ +README.irq : Shuchen Kate Feng <feng1@bnl.gov>, Sept. 2, 2007 + +As per implementation in shared PPC code, +the BSPirqPrioTable[96] listed in irq_init.c is where the +software developers can change the levels of priority +for all the interrupts based on the need of their +applications. The IRQs can be eanbled dynamically via the +BSP_enable_pic_irq(), or disbaled dynamically via the +BSP_disable_pic_irq(). + + +Support for run-time priority setup could be +added easily, but there is no action taken yet due to concerns +over computer security at VME CPU level. + + +The software developers are forbidden to setup picIsrTable[], +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 pending. diff --git a/bsps/powerpc/mvme5500/irq/BSP_irq.c b/bsps/powerpc/mvme5500/irq/BSP_irq.c new file mode 100644 index 0000000000..eb36cc2a80 --- /dev/null +++ b/bsps/powerpc/mvme5500/irq/BSP_irq.c @@ -0,0 +1,483 @@ +/* + * 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 May 2004, to Till Straumann <strauman@slac.stanford.edu> + * for some inputs. + * + * 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 <inttypes.h> +#include <stdio.h> +#include <rtems/system.h> +#include <bsp.h> +#include <bsp/irq.h> +#include <rtems/score/thread.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 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]; + +/* + * location used to store initial tables used for interrupt + * management.BSP copy of the configuration + */ +static rtems_irq_global_settings BSP_config; +static rtems_irq_connect_data* rtems_hdl_tbl; + +/* + * default handler connected on each irq after bsp initialization + * (locally cached copy) + */ +void (*default_rtems_hdl)(rtems_irq_hdl_param) = (void(*)(rtems_irq_hdl_param)) -1; + + +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 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(void) +{ + 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, 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; + + 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; + + if ( !is_pic_irq(irqNum) ) + return; + + 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((volatile uint32_t *)BSP_irqMask_reg[regNum], BSP_irqMask_cache[regNum]); + while (in_le32((volatile uint32_t *)BSP_irqMask_reg[regNum]) != BSP_irqMask_cache[regNum]); + + rtems_interrupt_enable(level); +} + +int BSP_disable_irq_at_pic(const rtems_irq_number irqNum) +{ + int rval; + unsigned bitNum, regNum; + unsigned int level; + + if ( ! is_pic_irq(irqNum) ) + return -1; + + 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 + + rval = BSP_irqMask_cache[regNum] & (1<<bitNum); + + BSP_irqMask_cache[regNum] &= ~(1 << bitNum); + + out_le32((volatile uint32_t *)BSP_irqMask_reg[regNum], BSP_irqMask_cache[regNum]); + while (in_le32((volatile uint32_t *)BSP_irqMask_reg[regNum]) != BSP_irqMask_cache[regNum]); + + rtems_interrupt_enable(level); + + return rval ? 1 : 0; +} + +/* Use shared/irq : 2008 */ +int BSP_setup_the_pic(rtems_irq_global_settings* config) +{ + int i; + + BSP_config = *config; + default_rtems_hdl = config->defaultEntry.hdl; + rtems_hdl_tbl = config->irqHdlTbl; + + /* 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); + 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. + */ + out_le32((volatile uint32_t *)GT_CommUnitArb_Ctrl, + (in_le32((volatile uint32_t *)GT_CommUnitArb_Ctrl)| (1<<10))); + +#if 0 + printk("BSP_irqMask_reg[0] = 0x%" PRIx32 ", BSP_irqCause_reg[0] 0x%" PRIx32 "\n", + in_le32((volatile uint32_t *)BSP_irqMask_reg[0]), + in_le32((volatile uint32_t *)BSP_irqCause_reg[0])); + printk("BSP_irqMask_reg[1] = 0x%" PRIx32 ", BSP_irqCause_reg[1] 0x%" PRIx32 "\n", + in_le32((volatile uint32_t *)BSP_irqMask_reg[1]), + in_le32((volatile uint32_t *)BSP_irqCause_reg[1])); + printk("BSP_irqMask_reg[2] = 0x%" PRIx32 ", BSP_irqCause_reg[2] 0x%" PRIx32 "\n", + in_le32((volatile uint32_t *)BSP_irqMask_reg[2]), + in_le32((volatile uint32_t *)BSP_irqCause_reg[2])); +#endif + + /* Initialize the interrupt related registers */ + for (i=0; i<3; i++) { + out_le32((volatile uint32_t *)BSP_irqCause_reg[i], 0); + out_le32((volatile uint32_t *)BSP_irqMask_reg[i], 0); + } + in_le32((volatile uint32_t *)BSP_irqMask_reg[2]); + compute_pic_masks_from_prio(); + +#if 0 + printk("BSP_irqMask_reg[0] = 0x%" PRIx32 ", BSP_irqCause_reg[0] 0x%" PRIx32 "\n", + in_le32((volatile uint32_t *)BSP_irqMask_reg[0]), + in_le32((volatile uint32_t *)BSP_irqCause_reg[0])); + printk("BSP_irqMask_reg[1] = 0x%" PRIx32 ", BSP_irqCause_reg[1] 0x%" PRIx32 "\n", + in_le32((volatile uint32_t *)BSP_irqMask_reg[1]), + in_le32((volatile uint32_t *)BSP_irqCause_reg[1])); + printk("BSP_irqMask_reg[2] = 0x%" PRIx32 ", BSP_irqCause_reg[2] 0x%" PRIx32 "\n", + in_le32((volatile uint32_t *)BSP_irqMask_reg[2]), + in_le32((volatile uint32_t *)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 + */ +int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum) +{ + unsigned long irqCause[3]={0, 0,0}; + unsigned oldMask[3]={0,0,0}; + int loop=0, i=0, j; + int irq=0, group=0; + + if (excNum == ASM_DEC_VECTOR) { + bsp_irq_dispatch_list( rtems_hdl_tbl, BSP_DECREMENTER, default_rtems_hdl); + return 0; + } + + for (j=0; j<3; j++ ) oldMask[j] = BSP_irqMask_cache[j]; + for (j=0; j<3; j++) irqCause[j] = in_le32((volatile uint32_t *)BSP_irqCause_reg[j]) & in_le32((volatile uint32_t *)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((volatile uint32_t *)BSP_irqMask_reg[0], BSP_irqMask_cache[0]); + out_le32((volatile uint32_t *)BSP_irqMask_reg[1], BSP_irqMask_cache[1]); + out_le32((volatile uint32_t *)BSP_irqMask_reg[2], BSP_irqMask_cache[2]); + in_le32((volatile uint32_t *)BSP_irqMask_reg[2]); + + bsp_irq_dispatch_list( rtems_hdl_tbl, irq, default_rtems_hdl); + + for (j=0; j<3; j++ ) BSP_irqMask_cache[j] = oldMask[j]; + + out_le32((volatile uint32_t *)BSP_irqMask_reg[0], oldMask[0]); + out_le32((volatile uint32_t *)BSP_irqMask_reg[1], oldMask[1]); + out_le32((volatile uint32_t *)BSP_irqMask_reg[2], oldMask[2]); + in_le32((volatile uint32_t *)BSP_irqMask_reg[2]); + } + } + + return 0; +} + +/* Only print part of the entries for now */ +void BSP_printPicIsrTbl(void) +{ + int i; + + printf("picPrioTable[12]={ {irq# : "); + for (i=0; i<12; i++) + printf("%d,", picPrioTable[i]); + printf("}\n"); + + printf("GPPIrqInTbl: 0x%x :\n", GPPIrqInTbl); +} diff --git a/bsps/powerpc/mvme5500/irq/irq_init.c b/bsps/powerpc/mvme5500/irq/irq_init.c new file mode 100644 index 0000000000..ede4014f22 --- /dev/null +++ b/bsps/powerpc/mvme5500/irq/irq_init.c @@ -0,0 +1,148 @@ +/* irq_init.c + * + * This file contains the implementation of rtems initialization + * related to interrupt handling. + * + * CopyRight (C) 1999 valette@crf.canon.fr + * + * Modified and added support for the MVME5500. + * Copyright 2003, 2004, 2005, Brookhaven National Laboratory and + * Shuchen Kate Feng <feng1@bnl.gov> + * + * 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 <libcpu/io.h> +#include <libcpu/spr.h> +#include <bsp/irq.h> +#include <bsp.h> +#include <bsp/vectors.h> /* ASM_EXT_VECTOR, ASM_DEC_VECTOR ... */ +/*#define TRACE_IRQ_INIT*/ + +/* + * default on/off function + */ +static void nop_func(void){} +/* + * default isOn function + */ +static int not_connected(void) {return 0;} + +static rtems_irq_connect_data rtemsIrq[BSP_IRQ_NUMBER]; +static rtems_irq_global_settings initial_config; + +static rtems_irq_connect_data defaultIrq = { + .name = 0, + .hdl = NULL, + .handle = NULL, + .on = (rtems_irq_enable) nop_func, + .off = (rtems_irq_disable) nop_func, + .isOn = (rtems_irq_is_enabled) not_connected, +#ifdef BSP_SHARED_HANDLER_SUPPORT + .next_handler = NULL +#endif +}; + +rtems_irq_prio BSPirqPrioTable[BSP_PIC_IRQ_NUMBER] = { + /* + * This table is where the developers can change the levels of priority + * based on the need of their applications. + * + * actual priorities for CPU MAIN and GPP interrupts (0-95) + * + * 0 means that only current interrupt is masked (lowest priority) + * 255 is only used by bits 24, 25, 26 and 27 of the CPU high + * interrupt Mask: (e.g. GPP7_0, GPP15_8, GPP23_16, GPP31_24). + * The IRQs of those four bits are always enabled. When it's used, + * the IRQ number is never listed in the dynamic picIsrTable[96]. + * + * The priorities of GPP interrupts were decided by their own + * value set at BSPirqPrioTable. + * + */ + /* CPU Main cause low interrupt */ + /* 0-15 */ + 0, 0, 0, 0, 0, 0, 0, 0, 64/*Timer*/, 0, 0, 0, 0, 0, 0, 0, + /* 16-31 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* CPU Main cause high interrupt */ + /* 32-47 */ + 2/*10/100MHZ*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 48-63 */ + 0, 0, 0, 0, 0, 0, 0, 0, + 255 /*GPP0-7*/, 255/*GPP8-15*/, 255/*GPP16-23*/, 255/*GPP24-31*/, 0, 0, 0, 0, + /* GPP interrupts */ + /* GPP0-7 */ + 1/*serial*/,0, 0, 0, 0, 0, 0, 0, + /* GPP8-15 */ + 47/*PMC1A*/,46/*PMC1B*/,45/*PMC1C*/,44/*PMC1D*/,30/*VME0*/, 29/*VME1*/,3,1, + /* GPP16-23 */ + 37/*PMC2A*/,36/*PMC2B*/,35/*PMC2C*/,34/*PMC2D*/,23/*1GHZ*/, 0,0,0, + /* GPP24-31 */ + 7/*watchdog*/, 0,0,0,0,0,0,0 +}; + +/* + * This code assumes the exceptions management setup has already + * been done. We just need to replace the exceptions that will + * be handled like interrupt. On MPC7455 and many PPC processors + * this means the decrementer exception and the external exception. + */ +void BSP_rtems_irq_mng_init(unsigned cpuId) +{ + int i; + rtems_interrupt_level level; + + /* + * First initialize the Interrupt management hardware + */ +#ifdef TRACE_IRQ_INIT + printk("Initializing the interrupt controller of the GT64260\n"); +#endif + +#ifdef TRACE_IRQ_INIT + printk("Going to re-initialize the rtemsIrq table %d\n",BSP_IRQ_NUMBER); +#endif + /* + * Initialize Rtems management interrupt table + */ + /* + * re-init the rtemsIrq table + */ + for (i = 0; i < BSP_IRQ_NUMBER; i++) { + rtemsIrq[i] = defaultIrq; + rtemsIrq[i].name = i; + } + + /* + * Init initial Interrupt management config + */ + initial_config.irqNb = BSP_IRQ_NUMBER; + initial_config.defaultEntry = defaultIrq; + initial_config.irqHdlTbl = rtemsIrq; + initial_config.irqBase = BSP_LOWEST_OFFSET; + initial_config.irqPrioTbl = BSPirqPrioTable; + +#ifdef TRACE_IRQ_INIT + printk("Going to setup irq mngt configuration\n"); +#endif + + rtems_interrupt_disable(level); + (void) level; /* avoid set but not used warning */ + + if (!BSP_rtems_irq_mngt_set(&initial_config)) { + /* + * put something here that will show the failure... + */ + rtems_panic("Unable to initialize RTEMS interrupt Management!!! System locked\n"); + } +#ifdef TRACE_IRQ_INIT + printk("Done setup irq mngt configuration\n"); +#endif + +#ifdef TRACE_IRQ_INIT + printk("RTEMS IRQ management is now operationnal\n"); +#endif +} diff --git a/bsps/powerpc/psim/irq/irq_init.c b/bsps/powerpc/psim/irq/irq_init.c new file mode 100644 index 0000000000..3d2a82f2c0 --- /dev/null +++ b/bsps/powerpc/psim/irq/irq_init.c @@ -0,0 +1,125 @@ +/* + * This file contains the implementation of rtems initialization + * related to interrupt handling + */ + +/* + * Copyright (C) 1999 valette@crf.canon.fr + * + * Enhanced by Jay Kulpinski <jskulpin@eng01.gdds.com> + * to make it valid for MVME2300 Motorola boards. + * + * 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 <libcpu/io.h> +#include <libcpu/spr.h> +#include <bsp/irq.h> +#include <bsp.h> +#include <psim.h> +#include <bsp/vectors.h> +#include <rtems/bspIo.h> +#include <bsp/openpic.h> +#include <bsp/irq-generic.h> + +static rtems_irq_connect_data rtemsIrq[BSP_IRQ_NUMBER]; +static rtems_irq_global_settings initial_config; +static rtems_irq_connect_data defaultIrq = { + /* vectorIdex, hdl , handle , on , off , isOn */ + 0, NULL, NULL , NULL, NULL, NULL +}; +static rtems_irq_prio irqPrioTable[BSP_IRQ_NUMBER]={ + /* + * Processor exceptions handled as interrupts + */ + 0 +}; + + /* + * This code assumes the exceptions management setup has already + * been done. We just need to replace the exceptions that will + * be handled like interrupt. On mcp750/mpc750 and many PPC processors + * this means the decrementer exception and the external exception. + */ +void BSP_rtems_irq_mng_init(unsigned cpuId) +{ + int i; + + /* + * First initialize the Interrupt management hardware + */ + OpenPIC = (void*)PSIM.OpenPIC; + openpic_init(1,0,0,16,0,0); + + /* + * Initialize Rtems management interrupt table + */ + /* + * re-init the rtemsIrq table + */ + for (i = 0; i < BSP_IRQ_NUMBER; i++) { + rtemsIrq[i] = defaultIrq; + rtemsIrq[i].name = i; + } + /* + * Init initial Interrupt management config + */ + initial_config.irqNb = BSP_IRQ_NUMBER; + initial_config.defaultEntry = defaultIrq; + initial_config.irqHdlTbl = rtemsIrq; + initial_config.irqBase = BSP_LOWEST_OFFSET; + initial_config.irqPrioTbl = irqPrioTable; + + for (i = BSP_PCI_IRQ_LOWEST_OFFSET; i< BSP_PCI_IRQ_NUMBER; i++ ) { + irqPrioTable[i] = 8; + } + + if (!BSP_rtems_irq_mngt_set(&initial_config)) { + /* + * put something here that will show the failure... + */ + rtems_panic( + "Unable to initialize RTEMS interrupt Management!!! System locked\n" + ); + } + + #ifdef TRACE_IRQ_INIT + printk("RTEMS IRQ management is now operationnal\n"); + #endif +} + +static int psim_exception_handler( + BSP_Exception_frame *frame, + unsigned exception_number +) +{ + rtems_panic("Unexpected interrupt occured"); + return 0; +} + +/* + * functions to enable/disable a source at the ipic + */ +void bsp_interrupt_vector_enable( rtems_vector_number irqnum) +{ + /* FIXME: do something */ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(irqnum)); +} + +void bsp_interrupt_vector_disable( rtems_vector_number irqnum) +{ + /* FIXME: do something */ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(irqnum)); +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + /* Install exception handler */ + if (ppc_exc_set_handler( ASM_EXT_VECTOR, psim_exception_handler)) { + return RTEMS_IO_ERROR; + } + + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/powerpc/qemuppc/irq/irq_init.c b/bsps/powerpc/qemuppc/irq/irq_init.c new file mode 100644 index 0000000000..24b15dcd49 --- /dev/null +++ b/bsps/powerpc/qemuppc/irq/irq_init.c @@ -0,0 +1,61 @@ +/*===============================================================*\ +| Project: RTEMS generic MPC83xx BSP | ++-----------------------------------------------------------------+ +| Copyright (c) 2007 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | ++-----------------------------------------------------------------+ +| 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. | +| | ++-----------------------------------------------------------------+ +| this file integrates the IPIC irq controller | +\*===============================================================*/ + +#include <rtems.h> + +#include <libcpu/powerpc-utility.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> +#include <bsp/vectors.h> + +static int qemuppc_exception_handler( + BSP_Exception_frame *frame, + unsigned exception_number +) +{ + rtems_panic("Unexpected interrupt occured"); + return 0; +} + +/* + * functions to enable/disable a source at the ipic + */ +void bsp_interrupt_vector_enable( rtems_vector_number irqnum) +{ + /* FIXME: do something */ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(irqnum)); +} + +void bsp_interrupt_vector_disable( rtems_vector_number irqnum) +{ + /* FIXME: do something */ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(irqnum)); +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + /* Install exception handler */ + if (ppc_exc_set_handler( ASM_EXT_VECTOR, qemuppc_exception_handler)) { + return RTEMS_IO_ERROR; + } + + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/powerpc/qoriq/irq/irq.c b/bsps/powerpc/qoriq/irq/irq.c new file mode 100644 index 0000000000..625b9fce1b --- /dev/null +++ b/bsps/powerpc/qoriq/irq/irq.c @@ -0,0 +1,387 @@ +/** + * @file + * + * @ingroup QorIQ + * + * @brief Interrupt implementation. + */ + +/* + * Copyright (c) 2010, 2017 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * 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 <sys/param.h> + +#include <rtems.h> + +#include <libcpu/powerpc-utility.h> + +#include <asm/epapr_hcalls.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> +#include <bsp/vectors.h> +#include <bsp/utility.h> +#include <bsp/qoriq.h> + +#ifdef RTEMS_SMP +#include <rtems/score/smpimpl.h> +#endif + +RTEMS_INTERRUPT_LOCK_DEFINE(static, lock, "QorIQ IRQ") + +#define SPURIOUS 0xffff + +#ifdef QORIQ_IS_HYPERVISOR_GUEST + +void bsp_interrupt_set_affinity( + rtems_vector_number vector, + const Processor_mask *affinity +) +{ + uint32_t config; + unsigned int priority; + uint32_t destination; + uint32_t new_destination; + rtems_interrupt_lock_context lock_context; + + new_destination = _Processor_mask_Find_last_set(affinity) - 1; + + rtems_interrupt_lock_acquire(&lock, &lock_context); + ev_int_get_config(vector, &config, &priority, &destination); + ev_int_set_config(vector, config, priority, new_destination); + rtems_interrupt_lock_release(&lock, &lock_context); +} + +void bsp_interrupt_get_affinity( + rtems_vector_number vector, + Processor_mask *affinity +) +{ + uint32_t config; + unsigned int priority; + uint32_t destination; + + ev_int_get_config(vector, &config, &priority, &destination); + _Processor_mask_From_uint32_t(affinity, destination, 0); +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + ev_int_set_mask(vector, 0); +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + ev_int_set_mask(vector, 1); +} + +void bsp_interrupt_dispatch(uintptr_t exception_number) +{ + unsigned int vector; + + if (exception_number == 10) { + qoriq_decrementer_dispatch(); + return; + } + +#ifdef RTEMS_SMP + if (exception_number == 36) { + _SMP_Inter_processor_interrupt_handler(); + return; + } +#endif + + /* + * This works only if the "has-external-proxy" property is present in the + * "epapr,hv-pic" device tree node. + */ + vector = PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_EPR); + + if (vector != SPURIOUS) { + uint32_t msr; + + msr = ppc_external_exceptions_enable(); + bsp_interrupt_handler_dispatch(vector); + ppc_external_exceptions_disable(msr); + + ev_int_eoi(vector); + } else { + bsp_interrupt_handler_default(vector); + } +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + unsigned int i; + + for (i = BSP_INTERRUPT_VECTOR_MIN; i <= BSP_INTERRUPT_VECTOR_MAX; ++i) { + uint32_t config; + unsigned int priority; + uint32_t destination; + unsigned int err; + + err = ev_int_get_config(i, &config, &priority, &destination); + if (err != EV_SUCCESS) + continue; + + priority = QORIQ_PIC_PRIORITY_DEFAULT; + + ev_int_set_config(i, config, priority, destination); + } + + return RTEMS_SUCCESSFUL; +} + +#else /* !QORIQ_IS_HYPERVISOR_GUEST */ + +#define VPR_MSK BSP_BBIT32(0) +#define VPR_A BSP_BBIT32(1) +#define VPR_P BSP_BBIT32(8) +#define VPR_S BSP_BBIT32(9) +#define VPR_PRIORITY(val) BSP_BFLD32(val, 12, 15) +#define VPR_PRIORITY_GET(reg) BSP_BFLD32GET(reg, 12, 15) +#define VPR_PRIORITY_SET(reg, val) BSP_BFLD32SET(reg, val, 12, 15) +#define VPR_VECTOR(val) BSP_BFLD32(val, 16, 31) +#define VPR_VECTOR_GET(reg) BSP_BFLD32GET(reg, 16, 31) +#define VPR_VECTOR_SET(reg, val) BSP_BFLD32SET(reg, val, 16, 31) + +#define GCR_RST BSP_BBIT32(0) +#define GCR_M BSP_BBIT32(2) + +#define SRC_CFG_IDX(i) ((i) - QORIQ_IRQ_EXT_BASE) + +static const uint16_t src_cfg_offsets [] = { + [SRC_CFG_IDX(QORIQ_IRQ_EXT_0)] = 0x10000 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_EXT_1)] = 0x10020 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_EXT_2)] = 0x10040 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_EXT_3)] = 0x10060 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_EXT_4)] = 0x10080 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_EXT_5)] = 0x100a0 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_EXT_6)] = 0x100c0 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_EXT_7)] = 0x100e0 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_EXT_8)] = 0x10100 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_EXT_9)] = 0x10120 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_EXT_10)] = 0x10140 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_EXT_11)] = 0x10160 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_IPI_0)] = 0x010a0 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_IPI_1)] = 0x010b0 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_IPI_2)] = 0x010c0 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_IPI_3)] = 0x010d0 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_MI_0)] = 0x11600 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_MI_1)] = 0x11620 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_MI_2)] = 0x11640 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_MI_3)] = 0x11660 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_MI_4)] = 0x11680 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_MI_5)] = 0x116a0 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_MI_6)] = 0x116c0 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_MI_7)] = 0x116e0 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_MSI_0)] = 0x11c00 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_MSI_1)] = 0x11c20 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_MSI_2)] = 0x11c40 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_MSI_3)] = 0x11c60 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_MSI_4)] = 0x11c80 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_MSI_5)] = 0x11ca0 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_MSI_6)] = 0x11cc0 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_MSI_7)] = 0x11ce0 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_GT_A_0)] = 0x01120 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_GT_A_1)] = 0x01160 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_GT_A_2)] = 0x011a0 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_GT_A_3)] = 0x011e0 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_GT_B_0)] = 0x02120 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_GT_B_1)] = 0x02160 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_GT_B_2)] = 0x021a0 >> 4, + [SRC_CFG_IDX(QORIQ_IRQ_GT_B_3)] = 0x021e0 >> 4 +}; + +static volatile qoriq_pic_src_cfg *get_src_cfg(rtems_vector_number vector) +{ + uint32_t n = MIN(RTEMS_ARRAY_SIZE(qoriq.pic.ii_0), QORIQ_IRQ_EXT_BASE); + + if (vector < n) { + return &qoriq.pic.ii_0 [vector]; + } else if (vector < QORIQ_IRQ_EXT_BASE) { + return &qoriq.pic.ii_1 [vector - n]; + } else { + uintptr_t offs = ((uintptr_t) + src_cfg_offsets [vector - QORIQ_IRQ_EXT_BASE]) << 4; + + return (volatile qoriq_pic_src_cfg *) ((uintptr_t) &qoriq.pic + offs); + } +} + +rtems_status_code qoriq_pic_set_priority( + rtems_vector_number vector, + int new_priority, + int *old_priority +) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + uint32_t old_vpr = 0; + + if (bsp_interrupt_is_valid_vector(vector)) { + volatile qoriq_pic_src_cfg *src_cfg = get_src_cfg(vector); + + if (QORIQ_PIC_PRIORITY_IS_VALID(new_priority)) { + rtems_interrupt_lock_context lock_context; + + rtems_interrupt_lock_acquire(&lock, &lock_context); + old_vpr = src_cfg->vpr; + src_cfg->vpr = VPR_PRIORITY_SET(old_vpr, (uint32_t) new_priority); + rtems_interrupt_lock_release(&lock, &lock_context); + } else if (new_priority < 0) { + old_vpr = src_cfg->vpr; + } else { + sc = RTEMS_INVALID_PRIORITY; + } + } else { + sc = RTEMS_INVALID_ID; + } + + if (old_priority != NULL) { + *old_priority = (int) VPR_PRIORITY_GET(old_vpr); + } + + return sc; +} + +void bsp_interrupt_set_affinity( + rtems_vector_number vector, + const Processor_mask *affinity +) +{ + volatile qoriq_pic_src_cfg *src_cfg = get_src_cfg(vector); + + src_cfg->dr = _Processor_mask_To_uint32_t(affinity, 0); +} + +void bsp_interrupt_get_affinity( + rtems_vector_number vector, + Processor_mask *affinity +) +{ + volatile qoriq_pic_src_cfg *src_cfg = get_src_cfg(vector); + + _Processor_mask_From_uint32_t(affinity, src_cfg->dr, 0); +} + +static void pic_vector_enable(rtems_vector_number vector, uint32_t msk) +{ + volatile qoriq_pic_src_cfg *src_cfg = get_src_cfg(vector); + rtems_interrupt_lock_context lock_context; + + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + rtems_interrupt_lock_acquire(&lock, &lock_context); + src_cfg->vpr = (src_cfg->vpr & ~VPR_MSK) | msk; + rtems_interrupt_lock_release(&lock, &lock_context); +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + pic_vector_enable(vector, 0); +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + pic_vector_enable(vector, VPR_MSK); +} + +void bsp_interrupt_dispatch(uintptr_t exception_number) +{ + rtems_vector_number vector = qoriq.pic.iack; + + if (vector != SPURIOUS) { + uint32_t msr = ppc_external_exceptions_enable(); + + bsp_interrupt_handler_dispatch(vector); + + ppc_external_exceptions_disable(msr); + + qoriq.pic.eoi = 0; + qoriq.pic.whoami; + } else { + bsp_interrupt_handler_default(vector); + } +} + +static bool pic_is_ipi(rtems_vector_number vector) +{ + return QORIQ_IRQ_IPI_0 <= vector && vector <= QORIQ_IRQ_IPI_3; +} + +static void pic_reset(void) +{ + qoriq.pic.gcr = GCR_RST; + while ((qoriq.pic.gcr & GCR_RST) != 0) { + /* Wait */ + } +} + +static void pic_global_timer_init(void) +{ + int i = 0; + + qoriq.pic.tcra = 0; + qoriq.pic.tcrb = 0; + + for (i = 0; i < 4; ++i) { + qoriq.pic.gta [0].bcr = GTBCR_CI; + qoriq.pic.gtb [0].bcr = GTBCR_CI; + } +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + rtems_vector_number i = 0; + uint32_t processor_id = ppc_processor_id(); + + if (processor_id == 0) { + /* Core 0 must do the basic initialization */ + + pic_reset(); + + for (i = BSP_INTERRUPT_VECTOR_MIN; i <= BSP_INTERRUPT_VECTOR_MAX; ++i) { + volatile qoriq_pic_src_cfg *src_cfg = get_src_cfg(i); + + src_cfg->vpr = VPR_MSK | VPR_P + | VPR_PRIORITY(QORIQ_PIC_PRIORITY_DEFAULT) | VPR_VECTOR(i); + + if (!pic_is_ipi(i)) { + src_cfg->dr = 0x1; + } + } + + qoriq.pic.mer03 = 0xf; + qoriq.pic.mer47 = 0xf; + qoriq.pic.svr = SPURIOUS; + qoriq.pic.gcr = GCR_M; + + pic_global_timer_init(); + } + + qoriq.pic.ctpr = 0; + + for (i = BSP_INTERRUPT_VECTOR_MIN; i <= BSP_INTERRUPT_VECTOR_MAX; ++i) { + qoriq.pic.iack; + qoriq.pic.eoi = 0; + qoriq.pic.whoami; + } + + return RTEMS_SUCCESSFUL; +} + +#endif /* QORIQ_IS_HYPERVISOR_GUEST */ diff --git a/bsps/powerpc/shared/irq/i8259.c b/bsps/powerpc/shared/irq/i8259.c new file mode 100644 index 0000000000..7363e87ba0 --- /dev/null +++ b/bsps/powerpc/shared/irq/i8259.c @@ -0,0 +1,149 @@ +/* + * This file contains the implementation of the function described in irq.h + * related to Intel 8259 Programmable Interrupt controller. + * + * 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.rtems.org/license/LICENSE. + */ + +#include <bsp.h> +#include <bsp/irq.h> + +/*-------------------------------------------------------------------------+ +| Cache for 1st and 2nd PIC IRQ line's status (enabled or disabled) register. ++--------------------------------------------------------------------------*/ +/* + * lower byte is interrupt mask on the master PIC. + * while upper bits are interrupt on the slave PIC. + */ +volatile rtems_i8259_masks i8259s_cache = 0xfffb; + +/*-------------------------------------------------------------------------+ +| Function: BSP_irq_disable_at_i8259s +| Description: Mask IRQ line in appropriate PIC chip. +| Global Variables: i8259s_cache +| Arguments: vector_offset - number of IRQ line to mask. +| Returns: original state or -1 on error. ++--------------------------------------------------------------------------*/ +int BSP_irq_disable_at_i8259s (const rtems_irq_number irqLine) +{ + unsigned short mask; + rtems_interrupt_level level; + int rval; + + if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) || + ((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET) + ) + return -1; + + rtems_interrupt_disable(level); + + mask = 1 << irqLine; + rval = i8259s_cache & mask ? 0 : 1; + i8259s_cache |= mask; + + if (irqLine < 8) + { + outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff); + } + else + { + outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8)); + } + rtems_interrupt_enable(level); + + return rval; +} + +/*-------------------------------------------------------------------------+ +| Function: BSP_irq_enable_at_i8259s +| Description: Unmask IRQ line in appropriate PIC chip. +| Global Variables: i8259s_cache +| Arguments: irqLine - number of IRQ line to mask. +| Returns: Nothing. ++--------------------------------------------------------------------------*/ +int BSP_irq_enable_at_i8259s (const rtems_irq_number irqLine) +{ + unsigned short mask; + rtems_interrupt_level level; + + if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) || + ((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET ) + ) + return 1; + + rtems_interrupt_disable(level); + + mask = ~(1 << irqLine); + i8259s_cache &= mask; + + if (irqLine < 8) + { + outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff); + } + else + { + outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8)); + } + rtems_interrupt_enable(level); + + return 0; +} /* mask_irq */ + +int BSP_irq_enabled_at_i8259s (const rtems_irq_number irqLine) +{ + unsigned short mask; + + if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) || + ((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET) + ) + return 1; + + mask = (1 << irqLine); + return (~(i8259s_cache & mask)); +} + +/*-------------------------------------------------------------------------+ +| Function: BSP_irq_ack_at_i8259s +| Description: Signal generic End Of Interrupt (EOI) to appropriate PIC. +| Global Variables: None. +| Arguments: irqLine - number of IRQ line to acknowledge. +| Returns: Nothing. ++--------------------------------------------------------------------------*/ +int BSP_irq_ack_at_i8259s (const rtems_irq_number irqLine) +{ + if (irqLine >= 8) { + outport_byte(PIC_MASTER_COMMAND_IO_PORT, SLAVE_PIC_EOSI); + outport_byte(PIC_SLAVE_COMMAND_IO_PORT, (PIC_EOSI | (irqLine - 8))); + } + else { + outport_byte(PIC_MASTER_COMMAND_IO_PORT, (PIC_EOSI | irqLine)); + } + + return 0; + +} /* ackIRQ */ + +void BSP_i8259s_init(void) +{ + /* + * init master 8259 interrupt controller + */ + outport_byte(PIC_MASTER_COMMAND_IO_PORT, 0x11); /* Start init sequence */ + outport_byte(PIC_MASTER_IMR_IO_PORT, 0x00);/* Vector base = 0 */ + outport_byte(PIC_MASTER_IMR_IO_PORT, 0x04);/* edge tiggered, Cascade (slave) on IRQ2 */ + outport_byte(PIC_MASTER_IMR_IO_PORT, 0x01);/* Select 8086 mode */ + outport_byte(PIC_MASTER_IMR_IO_PORT, 0xFB); /* Mask all except cascade */ + /* + * init slave interrupt controller + */ + outport_byte(PIC_SLAVE_COMMAND_IO_PORT, 0x11); /* Start init sequence */ + outport_byte(PIC_SLAVE_IMR_IO_PORT, 0x08);/* Vector base = 8 */ + outport_byte(PIC_SLAVE_IMR_IO_PORT, 0x02);/* edge triggered, Cascade (slave) on IRQ2 */ + outport_byte(PIC_SLAVE_IMR_IO_PORT, 0x01); /* Select 8086 mode */ + outport_byte(PIC_SLAVE_IMR_IO_PORT, 0xFF); /* Mask all */ + +} diff --git a/bsps/powerpc/shared/irq/irq_init.c b/bsps/powerpc/shared/irq/irq_init.c new file mode 100644 index 0000000000..1a44992a5b --- /dev/null +++ b/bsps/powerpc/shared/irq/irq_init.c @@ -0,0 +1,364 @@ +/* irq_init.c + * + * This file contains the implementation of rtems initialization + * related to interrupt handling. + * + * CopyRight (C) 1999 valette@crf.canon.fr + * + * Enhanced by Jay Kulpinski <jskulpin@eng01.gdds.com> + * to make it valid for MVME2300 Motorola boards. + * + * Till Straumann <strauman@slac.stanford.edu>, 12/20/2001: + * Use the new interface to openpic_init + * + * 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 <libcpu/io.h> +#include <libcpu/spr.h> +#include <bsp/pci.h> +#include <bsp/residual.h> +#include <bsp/irq.h> +#if BSP_PCI_IRQ_NUMBER > 0 +#include <bsp/openpic.h> +#endif +#include <bsp/irq_supp.h> +#include <bsp.h> +#include <bsp/motorola.h> +#include <rtems/bspIo.h> + +typedef struct { + unsigned char bus; /* few chance the PCI/ISA bridge is not on first bus but ... */ + unsigned char device; + unsigned char function; +} pci_isa_bridge_device; + +pci_isa_bridge_device* via_82c586 = 0; +#ifndef qemu +static pci_isa_bridge_device bridge; +#endif + +/* + * default methods + */ +static void nop_hdl(rtems_irq_hdl_param ignored) +{ +} + +static void nop_irq_enable(const struct __rtems_irq_connect_data__*ignored) +{ +} + +static int irq_is_connected(const struct __rtems_irq_connect_data__*ignored) +{ + return 0; +} + + +static rtems_irq_connect_data rtemsIrq[BSP_IRQ_NUMBER]; +static rtems_irq_global_settings initial_config; +static rtems_irq_connect_data defaultIrq = { + 0, /* vector */ + nop_hdl, /* hdl */ + NULL, /* handle */ + nop_irq_enable, /* on */ + nop_irq_enable, /* off */ + irq_is_connected /* isOn */ +#ifdef BSP_SHARED_HANDLER_SUPPORT + , NULL /* next_handler */ +#endif +}; +static rtems_irq_prio irqPrioTable[BSP_IRQ_NUMBER]={ + /* + * actual priorities for interrupt : + * 0 means that only current interrupt is masked + * 255 means all other interrupts are masked + */ + /* + * ISA interrupts. + * The second entry has a priority of 255 because + * it is the slave pic entry and should always remain + * unmasked. + */ + 0,0, + 255, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#if BSP_PCI_IRQ_NUMBER > 0 + /* + * PCI Interrupts + */ + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* for raven prio 0 means unactive... */ +#endif + /* + * Processor exceptions handled as interrupts + */ + 0 +}; + +#if BSP_PCI_IRQ_NUMBER > 0 +#if defined(mvme2100) +static unsigned char mvme2100_openpic_initpolarities[16] = { + 0, /* Not used - should be disabled */ + 0, /* DEC21143 Controller */ + 0, /* PMC/PC-MIP Type I Slot 0 */ + 0, /* PC-MIP Type I Slot 1 */ + 0, /* PC-MIP Type II Slot 0 */ + 0, /* PC-MIP Type II Slot 1 */ + 0, /* Not used - should be disabled */ + 0, /* PCI Expansion Interrupt A/Universe II (LINT0) */ + 0, /* PCI Expansion Interrupt B/Universe II (LINT1) */ + 0, /* PCI Expansion Interrupt C/Universe II (LINT2) */ + 0, /* PCI Expansion Interrupt D/Universe II (LINT3) */ + 0, /* Not used - should be disabled */ + 0, /* Not used - should be disabled */ + 1, /* 16550 UART */ + 0, /* Front panel Abort Switch */ + 0, /* RTC IRQ */ +}; + +static unsigned char mvme2100_openpic_initsenses[] = { + 0, /* Not used - should be disabled */ + 1, /* DEC21143 Controller */ + 1, /* PMC/PC-MIP Type I Slot 0 */ + 1, /* PC-MIP Type I Slot 1 */ + 1, /* PC-MIP Type II Slot 0 */ + 1, /* PC-MIP Type II Slot 1 */ + 0, /* Not used - should be disabled */ + 1, /* PCI Expansion Interrupt A/Universe II (LINT0) */ + 1, /* PCI Expansion Interrupt B/Universe II (LINT1) */ + 1, /* PCI Expansion Interrupt C/Universe II (LINT2) */ + 1, /* PCI Expansion Interrupt D/Universe II (LINT3) */ + 0, /* Not used - should be disabled */ + 0, /* Not used - should be disabled */ + 1, /* 16550 UART */ + 0, /* Front panel Abort Switch */ + 1, /* RTC IRQ */ +}; +#else +static unsigned char mcp750_openpic_initpolarities[16] = { + 1, /* 8259 cascade */ + 0, /* all the rest of them */ +}; + +static unsigned char mcp750_openpic_initsenses[] = { + 1, /* MCP750_INT_PCB(8259) */ + 0, /* MCP750_INT_FALCON_ECC_ERR */ + 1, /* MCP750_INT_PCI_ETHERNET */ + 1, /* MCP750_INT_PCI_PMC */ + 1, /* MCP750_INT_PCI_WATCHDOG_TIMER1 */ + 1, /* MCP750_INT_PCI_PRST_SIGNAL */ + 1, /* MCP750_INT_PCI_FALL_SIGNAL */ + 1, /* MCP750_INT_PCI_DEG_SIGNAL */ + 1, /* MCP750_INT_PCI_BUS1_INTA */ + 1, /* MCP750_INT_PCI_BUS1_INTB */ + 1, /* MCP750_INT_PCI_BUS1_INTC */ + 1, /* MCP750_INT_PCI_BUS1_INTD */ + 1, /* MCP750_INT_PCI_BUS2_INTA */ + 1, /* MCP750_INT_PCI_BUS2_INTB */ + 1, /* MCP750_INT_PCI_BUS2_INTC */ + 1, /* MCP750_INT_PCI_BUS2_INTD */ +}; +#endif +#endif + +#if BSP_ISA_IRQ_NUMBER > 0 && !defined(qemu) +void VIA_isa_bridge_interrupts_setup(void) +{ + pci_isa_bridge_device pci_dev; + uint32_t temp; + unsigned char tmp; + unsigned char maxBus; + unsigned found = 0; + + maxBus = pci_bus_count(); + pci_dev.function = 0; /* Assumes the bidge is the first function */ + + for (pci_dev.bus = 0; pci_dev.bus < maxBus; pci_dev.bus++) { +#ifdef SCAN_PCI_PRINT + printk("isa_bridge_interrupts_setup: Scanning bus %d\n", pci_dev.bus); +#endif + for (pci_dev.device = 0; pci_dev.device < PCI_MAX_DEVICES; pci_dev.device++) { +#ifdef SCAN_PCI_PRINT + printk("isa_bridge_interrupts_setup: Scanning device %d\n", pci_dev.device); +#endif + pci_read_config_dword(pci_dev.bus, pci_dev.device, pci_dev.function, + PCI_VENDOR_ID, &temp); +#ifdef SCAN_PCI_PRINT + printk("Vendor/device = %x\n", temp); +#endif + if ((temp == (((unsigned short) PCI_VENDOR_ID_VIA) | (PCI_DEVICE_ID_VIA_82C586_0 << 16))) + ) { + bridge = pci_dev; + via_82c586 = &bridge; +#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS + /* + * Should print : bus = 0, device = 11, function = 0 on a MCP750. + */ + printk("Via PCI/ISA bridge found at bus = %d, device = %d, function = %d\n", + via_82c586->bus, + via_82c586->device, + via_82c586->function); +#endif + found = 1; + goto loop_exit; + + } + } + } +loop_exit: + if (!found) rtems_panic("VIA_82C586 PCI/ISA bridge not found!n"); + + tmp = inb(0x810); + if ( !(tmp & 0x2)) { +#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS + printk("This is a second generation MCP750 board\n"); + printk("We must reprogram the PCI/ISA bridge...\n"); +#endif + pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function, + 0x47, &tmp); +#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS + printk(" PCI ISA bridge control2 = %x\n", (unsigned) tmp); +#endif + /* + * Enable 4D0/4D1 ISA interrupt level/edge config registers + */ + tmp |= 0x20; + pci_write_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function, + 0x47, tmp); + /* + * Now program the ISA interrupt edge/level + */ + tmp = ELCRS_INT9_LVL | ELCRS_INT10_LVL | ELCRS_INT11_LVL; + outb(tmp, ISA8259_S_ELCR); + tmp = ELCRM_INT5_LVL; + outb(tmp, ISA8259_M_ELCR); + /* + * Set the Interrupt inputs to non-inverting level interrupt + */ + pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function, + 0x54, &tmp); +#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS + printk(" PCI ISA bridge PCI/IRQ Edge/Level Select = %x\n", (unsigned) tmp); +#endif + tmp = 0; + pci_write_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function, + 0x54, tmp); + } + else { +#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS + printk("This is a first generation MCP750 board\n"); + printk("We just show the actual value used by PCI/ISA bridge\n"); +#endif + pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function, + 0x47, &tmp); +#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS + printk(" PCI ISA bridge control2 = %x\n", (unsigned) tmp); +#endif + /* + * Show the Interrupt inputs inverting/non-inverting level status + */ + pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function, + 0x54, &tmp); +#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS + printk(" PCI ISA bridge PCI/IRQ Edge/Level Select = %x\n", (unsigned) tmp); +#endif + } +} +#endif + + /* + * This code assumes the exceptions management setup has already + * been done. We just need to replace the exceptions that will + * be handled like interrupt. On mcp750/mpc750 and many PPC processors + * this means the decrementer exception and the external exception. + */ +void BSP_rtems_irq_mng_init(unsigned cpuId) +{ +#if BSP_ISA_IRQ_NUMBER > 0 && !defined(mvme2100) + int known_cpi_isa_bridge = 0; +#endif + int i; + + /* + * First initialize the Interrupt management hardware + */ +#if defined(mvme2100) +#ifdef TRACE_IRQ_INIT + printk("Going to initialize EPIC interrupt controller (openpic compliant)\n"); +#endif + /* EPIC sources don't start at the regular place; define appropriate offset + * prior to initializing the PIC. + */ + openpic_init(1, mvme2100_openpic_initpolarities, mvme2100_openpic_initsenses, 16, 16, BSP_bus_frequency); +#else +#if BSP_PCI_IRQ_NUMBER > 0 +#ifdef TRACE_IRQ_INIT + printk("Going to initialize raven interrupt controller (openpic compliant)\n"); +#endif + openpic_init(1, mcp750_openpic_initpolarities, mcp750_openpic_initsenses, 0, 0, 0); +#ifdef TRACE_IRQ_INIT + printk("Going to initialize the PCI/ISA bridge IRQ related setting (VIA 82C586)\n"); +#endif +#endif + +#if BSP_ISA_IRQ_NUMBER > 0 + if ( currentBoard == MESQUITE ) { +#ifndef qemu + VIA_isa_bridge_interrupts_setup(); +#endif + known_cpi_isa_bridge = 1; + } + if ( currentBoard == MVME_2300 ) { + /* nothing to do for W83C553 bridge */ + known_cpi_isa_bridge = 1; + } + if ( currentBoard == MTX_WO_PP || currentBoard == MTX_W_PP ) { + /* W83C554, don't to anything at the moment. gregm 11/6/2002 */ + known_cpi_isa_bridge = 1; + } + + if (!known_cpi_isa_bridge) { + printk("Please add code for PCI/ISA bridge init to libbsp/powerpc/shared/irq/irq_init.c\n"); + printk("If your card works correctly please add a test and set known_cpi_isa_bridge to true\n"); + printk("currentBoard = %i\n", currentBoard); + } +#ifdef TRACE_IRQ_INIT + printk("Going to initialize the ISA PC legacy IRQ management hardware\n"); +#endif + BSP_i8259s_init(); +#endif + +#endif + + /* + * Initialize RTEMS management interrupt table + */ + /* + * re-init the rtemsIrq table + */ + for (i = 0; i < BSP_IRQ_NUMBER; i++) { + rtemsIrq[i] = defaultIrq; + rtemsIrq[i].name = i; + } + /* + * Init initial Interrupt management config + */ + initial_config.irqNb = BSP_IRQ_NUMBER; + initial_config.defaultEntry = defaultIrq; + initial_config.irqHdlTbl = rtemsIrq; + initial_config.irqBase = BSP_LOWEST_OFFSET; + initial_config.irqPrioTbl = irqPrioTable; + + if (!BSP_rtems_irq_mngt_set(&initial_config)) { + /* + * put something here that will show the failure... + */ + rtems_panic("Unable to initialize RTEMS interrupt Management!!! System locked\n"); + } + +#ifdef TRACE_IRQ_INIT + printk("RTEMS IRQ management is now operational\n"); +#endif +} diff --git a/bsps/powerpc/shared/irq/openpic.c b/bsps/powerpc/shared/irq/openpic.c new file mode 100644 index 0000000000..556014964b --- /dev/null +++ b/bsps/powerpc/shared/irq/openpic.c @@ -0,0 +1,622 @@ +/* + * openpic.c -- OpenPIC Interrupt Handling + * + * Copyright (C) 1997 Geert Uytterhoeven + * + * Modified to compile in RTEMS development environment + * by Eric Valette + * + * Copyright (C) 1999 Eric Valette. 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.rtems.org/license/LICENSE. + */ + +/* + * Note: Interprocessor Interrupt (IPI) and Timer support is incomplete + */ + +#include <rtems.h> +#include <bsp.h> +#include <rtems/bspIo.h> +#include <bsp/openpic.h> +#include <rtems/pci.h> +#include <libcpu/io.h> +#include <libcpu/byteorder.h> +#include <rtems/bspIo.h> +#include <inttypes.h> + +#ifndef NULL +#define NULL 0 +#endif +#define REGISTER_DEBUG +#undef REGISTER_DEBUG + +volatile struct OpenPIC *OpenPIC = NULL; + +static unsigned int NumProcessors; +static unsigned int NumSources; + +static unsigned int openpic_eoi_delay = 0; +static int openpic_src_offst = 0; +#define SOURCE(irq) Source[ (irq) + openpic_src_offst ] + + /* + * Accesses to the current processor's registers + */ + +#define THIS_CPU Processor[cpu] +#define CHECK_THIS_CPU check_arg_cpu(cpu) + + /* + * Sanity checks + */ + +#if 1 +/* This software deliberately uses non-zero values to the method + * __builtin_return_address() and we want to avoid the GCC warning. + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wframe-address" +#define check_arg_ipi(ipi) \ + if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \ + printk("openpic.c:%d: illegal ipi %d\n", __LINE__, ipi); +#define check_arg_timer(timer) \ + if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \ + printk("openpic.c:%d: illegal timer %d\n", __LINE__, timer); +#define check_arg_vec(vec) \ + if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \ + printk("openpic.c:%d: illegal vector %d\n", __LINE__, vec); +#define check_arg_pri(pri) \ + if (pri < 0 || pri >= OPENPIC_NUM_PRI) \ + printk("openpic.c:%d: illegal priority %d\n", __LINE__, pri); +#define check_arg_irq(irq) \ + if (irq < 0 || irq >= NumSources) \ + printk("openpic.c:%d: illegal irq %d from 0x%08" PRIxPTR ",[0x%08" PRIxPTR "],[[0x%08" PRIxPTR "]]\n", \ + __LINE__, irq, (uintptr_t) __builtin_return_address(0), \ + (uintptr_t) __builtin_return_address(1), (uintptr_t) __builtin_return_address(2) \ + ); +#define check_arg_cpu(cpu) \ + if (cpu < 0 || cpu >= NumProcessors) \ + printk("openpic.c:%d: illegal cpu %d\n", __LINE__, cpu); +#else +#define check_arg_ipi(ipi) do {} while (0) +#define check_arg_timer(timer) do {} while (0) +#define check_arg_vec(vec) do {} while (0) +#define check_arg_pri(pri) do {} while (0) +#define check_arg_irq(irq) do {} while (0) +#define check_arg_cpu(cpu) do {} while (0) +#endif + + /* + * I/O functions + */ + +static inline unsigned int openpic_read(volatile unsigned int *addr) +{ + unsigned int val; + +#ifdef BSP_OPEN_PIC_BIG_ENDIAN + val = in_be32((volatile uint32_t *)addr); +#else + val = in_le32((volatile uint32_t *)addr); +#endif +#ifdef REGISTER_DEBUG + printk("openpic_read(0x%08x) = 0x%08x\n", (unsigned int)addr, val); +#endif + return val; +} + +static inline void openpic_write(volatile unsigned int *addr, unsigned int val) +{ +#ifdef REGISTER_DEBUG + printk("openpic_write(0x%08x, 0x%08x)\n", (unsigned int)addr, val); +#endif +#ifdef BSP_OPEN_PIC_BIG_ENDIAN + out_be32((volatile uint32_t *)addr, val); +#else + out_le32((volatile uint32_t *)addr, val); +#endif +} + +static inline unsigned int openpic_readfield(volatile unsigned int *addr, unsigned int mask) +{ + unsigned int val = openpic_read(addr); + return val & mask; +} + +static inline void openpic_writefield(volatile unsigned int *addr, unsigned int mask, + unsigned int field) +{ + unsigned int val = openpic_read(addr); + openpic_write(addr, (val & ~mask) | (field & mask)); +} + +static inline void openpic_clearfield(volatile unsigned int *addr, unsigned int mask) +{ + openpic_writefield(addr, mask, 0); +} + +static inline void openpic_setfield(volatile unsigned int *addr, unsigned int mask) +{ + openpic_writefield(addr, mask, mask); +} + + /* + * Update a Vector/Priority register in a safe manner. The interrupt will + * be disabled. + */ + +static void openpic_safe_writefield(volatile unsigned int *addr, unsigned int mask, + unsigned int field) +{ + openpic_setfield(addr, OPENPIC_MASK); + /* wait until it's not in use */ + while (openpic_read(addr) & OPENPIC_ACTIVITY); + openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK); +} + +/* -------- Global Operations ---------------------------------------------- */ + + /* + * Initialize the OpenPIC + * + * Add some kludge to use the Motorola Raven OpenPIC which does not + * report vendor and device id, and gets the wrong number of interrupts. + * (Motorola did a great job on that one!) + * + * T. Straumann, 12/20/2001: polarities and senses are now passed as + * parameters, eliminated global vars. + * IRQ0 is no longer treated specially. + */ + +void openpic_init(int main_pic, unsigned char *polarities, unsigned char *senses, int num_sources, int source_offset, unsigned long epic_freq) +{ + unsigned int t, i; + unsigned int vendorid, devid, stepping, timerfreq; + const char *version, *vendor, *device; + + if (!OpenPIC) + rtems_panic("No OpenPIC found"); + + t = openpic_read(&OpenPIC->Global.Feature_Reporting0); + switch (t & OPENPIC_FEATURE_VERSION_MASK) { + case 1: + version = "1.0"; + break; + case 2: + version = "1.2"; + break; + default: + version = "?"; + break; + } + NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >> + OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1; + NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >> + OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1; + t = openpic_read(&OpenPIC->Global.Vendor_Identification); + + vendorid = t & OPENPIC_VENDOR_ID_VENDOR_ID_MASK; + devid = (t & OPENPIC_VENDOR_ID_DEVICE_ID_MASK) >> + OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT; + stepping = (t & OPENPIC_VENDOR_ID_STEPPING_MASK) >> + OPENPIC_VENDOR_ID_STEPPING_SHIFT; + + /* Kludge for the Raven */ +/* + pci_read_config_dword(0, 0, 0, 0, &t); +*/ + if (t == PCI_VENDOR_ID_MOTOROLA + (PCI_DEVICE_ID_MOTOROLA_RAVEN<<16)) { + vendor = "Motorola"; + device = "Raven"; + NumSources += 1; + } + else if (t == PCI_VENDOR_ID_MOTOROLA + (PCI_DEVICE_ID_MOTOROLA_HAWK<<16)) { + vendor = "Motorola"; + device = "Hawk"; + NumSources += 1; + } else { + switch (vendorid) { + case OPENPIC_VENDOR_ID_APPLE: + vendor = "Apple"; + break; + default: + vendor = "Unknown"; + break; + } + switch (devid) { + case OPENPIC_DEVICE_ID_APPLE_HYDRA: + device = "Hydra"; + break; + default: + device = "Unknown"; + break; + } + } + printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at 0x%08" PRIuPTR "\n", version, + NumProcessors, NumSources, (uintptr_t) OpenPIC); + + printk("OpenPIC Vendor %d (%s), Device %d (%s), Stepping %d\n", vendorid, + vendor, devid, device, stepping); + + /* Override if they desire */ + if ( num_sources ) { + if ( NumSources != num_sources ) + printk("Overriding NumSources (%i) from configuration with %i\n", + NumSources, num_sources); + NumSources = num_sources; + } + + openpic_src_offst = source_offset; + + timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency); + printk("OpenPIC timer frequency is "); + if (timerfreq) + printk("%d Hz\n", timerfreq); + else + printk("not set\n"); + + if ( main_pic ) + { + /* Initialize timer interrupts */ + for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { + /* Disabled, Priority 0 */ + openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i); + /* No processor */ + openpic_maptimer(i, 0); + } + + /* Initialize IPI interrupts */ + for (i = 0; i < OPENPIC_NUM_IPI; i++) { + /* Disabled, Priority 0 */ + openpic_initipi(i, 0, OPENPIC_VEC_IPI+i); + } + + /* Initialize external interrupts */ + for (i = 0; i < NumSources; i++) { + /* Enabled, Priority 8 */ + openpic_initirq(i, 8, OPENPIC_VEC_SOURCE+i, + polarities ? polarities[i] : 0, + senses ? senses[i] : 1); + /* Processor 0 */ + openpic_mapirq(i, 1<<0); + } + + /* Initialize the spurious interrupt */ + openpic_set_spurious(OPENPIC_VEC_SPURIOUS); +#if 0 + if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT, + "82c59 cascade", NULL)) + printk("Unable to get OpenPIC IRQ 0 for cascade\n"); +#endif + openpic_set_priority(0, 0); + openpic_disable_8259_pass_through(); + } + if ( epic_freq ) { + /* Speed up the serial interface; if it is too slow then we might get spurious + * interrupts: + * After an ISR clears the interrupt condition at the source/device, the wire + * remains asserted during the propagation delay introduced by the serial interface + * (something really stupid). If the ISR returns while the wire is not released + * yet, then a spurious interrupt happens. + * The book says we should be careful if the serial clock is > 33MHz. + * Empirically, it seems that running it at 33MHz is fast enough. Otherwise, + * we should introduce a delay in openpic_eoi(). + * The maximal delay are 16 (serial) clock cycles. If the divisor is 8 + * [power-up default] then the lag is 2us [66MHz SDRAM clock; I assume this + * is equal to the bus frequency]. + * FIXME: This should probably be a EPIC-specific piece in 'openpic.c' + * Unfortunately, there is no easy way of figuring out if the + * device is an EPIC or not. + */ + uint32_t eicr_val, ratio; + /* On the 8240 this is the EICR register */ + eicr_val = in_le32( (volatile uint32_t *)&OpenPIC->Global.Global_Configuration1 ) & ~(7<<28); + if ( (1<<27) & eicr_val ) { + /* serial interface mode enabled */ + + /* round to nearest integer: + * round(Bus_freq/33000000) = floor( 2*(Bus_freq/33e6) + 1 ) / 2 + */ + ratio = epic_freq / 16500000 + 1; + ratio >>= 2; /* EICR value is half actual divisor */ + if ( 0==ratio ) + ratio = 1; + out_le32((volatile uint32_t *)&OpenPIC->Global.Global_Configuration1, eicr_val | ((ratio &7) << 28)); + /* Delay in TB cycles (assuming TB runs at 1/4 of the bus frequency) */ + openpic_set_eoi_delay( 16 * (2*ratio) / 4 ); + } + } +} + + /* + * Reset the OpenPIC + */ + +void openpic_reset(void) +{ + openpic_setfield(&OpenPIC->Global.Global_Configuration0, + OPENPIC_CONFIG_RESET); +} + + /* + * Enable/disable 8259 Pass Through Mode + */ + +void openpic_enable_8259_pass_through(void) +{ + openpic_clearfield(&OpenPIC->Global.Global_Configuration0, + OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE); +} + +void openpic_disable_8259_pass_through(void) +{ + openpic_setfield(&OpenPIC->Global.Global_Configuration0, + OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE); +} + + /* + * Find out the current interrupt + */ + +unsigned int openpic_irq(unsigned int cpu) +{ + unsigned int vec; + + check_arg_cpu(cpu); + vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge, + OPENPIC_VECTOR_MASK); + return vec; +} + + /* + * Signal end of interrupt (EOI) processing + */ + +void openpic_eoi(unsigned int cpu) +{ + check_arg_cpu(cpu); + if ( openpic_eoi_delay ) + rtems_bsp_delay_in_bus_cycles(openpic_eoi_delay); + openpic_write(&OpenPIC->THIS_CPU.EOI, 0); +} + +unsigned openpic_set_eoi_delay(unsigned tb_cycles) +{ +unsigned rval = openpic_eoi_delay; + openpic_eoi_delay = tb_cycles; + return rval; +} + + /* + * Get/set the current task priority + */ + +unsigned int openpic_get_priority(unsigned int cpu) +{ + CHECK_THIS_CPU; + return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority, + OPENPIC_CURRENT_TASK_PRIORITY_MASK); +} + +void openpic_set_priority(unsigned int cpu, unsigned int pri) +{ + CHECK_THIS_CPU; + check_arg_pri(pri); + openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority, + OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri); +} + + /* + * Get/set the spurious vector + */ + +unsigned int openpic_get_spurious(void) +{ + return openpic_readfield(&OpenPIC->Global.Spurious_Vector, + OPENPIC_VECTOR_MASK); +} + +void openpic_set_spurious(unsigned int vec) +{ + check_arg_vec(vec); + openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK, + vec); +} + + /* + * Initialize one or more CPUs + */ + +void openpic_init_processor(unsigned int cpumask) +{ + openpic_write(&OpenPIC->Global.Processor_Initialization, cpumask); +} + +/* -------- Interprocessor Interrupts -------------------------------------- */ + + /* + * Initialize an interprocessor interrupt (and disable it) + * + * ipi: OpenPIC interprocessor interrupt number + * pri: interrupt source priority + * vec: the vector it will produce + */ + +void openpic_initipi(unsigned int ipi, unsigned int pri, unsigned int vec) +{ + check_arg_timer(ipi); + check_arg_pri(pri); + check_arg_vec(vec); + openpic_safe_writefield(&OpenPIC->Global.IPI_Vector_Priority(ipi), + OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK, + (pri << OPENPIC_PRIORITY_SHIFT) | vec); +} + + /* + * Send an IPI to one or more CPUs + */ + +void openpic_cause_IPI(unsigned int cpu, unsigned int ipi, unsigned int cpumask) +{ + CHECK_THIS_CPU; + check_arg_ipi(ipi); + openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), cpumask); +} + +/* -------- Timer Interrupts ----------------------------------------------- */ + + /* + * Initialize a timer interrupt (and disable it) + * + * timer: OpenPIC timer number + * pri: interrupt source priority + * vec: the vector it will produce + */ + +void openpic_inittimer(unsigned int timer, unsigned int pri, unsigned int vec) +{ + check_arg_timer(timer); + check_arg_pri(pri); + check_arg_vec(vec); + openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority, + OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK, + (pri << OPENPIC_PRIORITY_SHIFT) | vec); +} + + /* + * Map a timer interrupt to one or more CPUs + */ + +void openpic_maptimer(unsigned int timer, unsigned int cpumask) +{ + check_arg_timer(timer); + openpic_write(&OpenPIC->Global.Timer[timer].Destination, cpumask); +} + + /* + * Set base count and / or enable / disable interrupt. + */ + + +void openpic_settimer(unsigned int timer, unsigned int base_count, int irq_enable) +{ + check_arg_timer(timer); + if ( base_count ) + openpic_write(&OpenPIC->Global.Timer[timer].Base_Count, base_count); + if ( irq_enable ) + openpic_clearfield(&OpenPIC->Global.Timer[timer].Vector_Priority, OPENPIC_MASK); + else + openpic_setfield(&OpenPIC->Global.Timer[timer].Vector_Priority, OPENPIC_MASK); +} + +unsigned int openpic_gettimer(unsigned int timer) +{ + check_arg_timer(timer); + return (openpic_read(&OpenPIC->Global.Timer[timer].Current_Count) & ~OPENPIC_MASK); +} + +/* -------- Interrupt Sources ---------------------------------------------- */ + + /* + * Enable/disable an interrupt source + */ + +void openpic_enable_irq(unsigned int irq) +{ +unsigned long flags; + check_arg_irq(irq); + rtems_interrupt_disable(flags); + openpic_clearfield(&OpenPIC->SOURCE(irq).Vector_Priority, OPENPIC_MASK); + rtems_interrupt_enable(flags); +} + +int openpic_disable_irq(unsigned int irq) +{ +int rval; +unsigned long flags; + check_arg_irq(irq); + if ( irq < 0 || irq >=NumSources ) + return -1; + rtems_interrupt_disable(flags); + rval = openpic_readfield(&OpenPIC->SOURCE(irq).Vector_Priority, OPENPIC_MASK) ? 0 : 1; + openpic_setfield(&OpenPIC->SOURCE(irq).Vector_Priority, OPENPIC_MASK); + rtems_interrupt_enable(flags); + return rval; +} + + /* + * Initialize an interrupt source (and disable it!) + * + * irq: OpenPIC interrupt number + * pri: interrupt source priority + * vec: the vector it will produce + * pol: polarity (1 for positive, 0 for negative) + * sense: 1 for level, 0 for edge + */ + +void openpic_initirq(unsigned int irq, unsigned int pri, unsigned int vec, int pol, int sense) +{ +#if 0 + printk("openpic_initirq: irq=%d pri=%d vec=%d pol=%d sense=%d\n", + irq, pri, vec, pol, sense); +#endif + + check_arg_irq(irq); + check_arg_pri(pri); + check_arg_vec(vec); + openpic_safe_writefield(&OpenPIC->SOURCE(irq).Vector_Priority, + OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK | + OPENPIC_SENSE_POLARITY | OPENPIC_SENSE_LEVEL, + (pri << OPENPIC_PRIORITY_SHIFT) | vec | + (pol ? OPENPIC_SENSE_POLARITY : 0) | + (sense ? OPENPIC_SENSE_LEVEL : 0)); +} + + /* + * Map an interrupt source to one or more CPUs + */ + +void openpic_mapirq(unsigned int irq, unsigned int cpumask) +{ + check_arg_irq(irq); + openpic_write(&OpenPIC->SOURCE(irq).Destination, cpumask); +} + + /* + * Get the current priority of an external interrupt + */ +unsigned int openpic_get_source_priority(unsigned int irq) +{ + check_arg_irq(irq); + return openpic_readfield(&OpenPIC->SOURCE(irq).Vector_Priority, + OPENPIC_PRIORITY_MASK) >> OPENPIC_PRIORITY_SHIFT; +} + +void openpic_set_source_priority(unsigned int irq, unsigned int pri) +{ +unsigned long flags; + check_arg_irq(irq); + check_arg_pri(pri); + rtems_interrupt_disable(flags); + openpic_writefield( + &OpenPIC->SOURCE(irq).Vector_Priority, + OPENPIC_PRIORITY_MASK, + pri << OPENPIC_PRIORITY_SHIFT); + rtems_interrupt_enable(flags); +} + /* + * Set the sense for an interrupt source (and disable it!) + * + * sense: 1 for level, 0 for edge + */ + +void openpic_set_sense(unsigned int irq, int sense) +{ + check_arg_irq(irq); + openpic_safe_writefield(&OpenPIC->SOURCE(irq).Vector_Priority, + OPENPIC_SENSE_LEVEL, + (sense ? OPENPIC_SENSE_LEVEL : 0)); +} diff --git a/bsps/powerpc/shared/irq/openpic_i8259_irq.c b/bsps/powerpc/shared/irq/openpic_i8259_irq.c new file mode 100644 index 0000000000..4a9c393f7f --- /dev/null +++ b/bsps/powerpc/shared/irq/openpic_i8259_irq.c @@ -0,0 +1,331 @@ +/* + * + * This file contains the i8259/openpic-specific 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.rtems.org/license/LICENSE. + */ + +#include <stdlib.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq_supp.h> +#ifndef BSP_HAS_NO_VME +#include <bsp/VMEConfig.h> +#endif +#if BSP_PCI_IRQ_NUMBER > 0 +#include <bsp/openpic.h> +#endif +#include <libcpu/io.h> +#include <bsp/vectors.h> +#include <stdlib.h> + +#include <rtems/bspIo.h> /* for printk */ + +#ifndef qemu +#define RAVEN_INTR_ACK_REG 0xfeff0030 +#else +#define RAVEN_INTR_ACK_REG 0xbffffff0 +#endif + +#if BSP_ISA_IRQ_NUMBER > 0 +/* + * 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 priority table given + * in BSP_rtems_irq_mngt_set(); + * CAUTION : this table is accessed directly by interrupt routine + * prologue. + */ +rtems_i8259_masks irq_mask_or_tbl[BSP_IRQ_NUMBER]; +#endif + +/* + * default handler connected on each irq after bsp initialization + */ +static rtems_irq_connect_data default_rtems_entry; + +static rtems_irq_connect_data* rtems_hdl_tbl; + +#if BSP_ISA_IRQ_NUMBER > 0 +/* + * Check if IRQ is an ISA IRQ + */ +static inline int is_isa_irq(const rtems_irq_number irqLine) +{ + return (((int) irqLine <= BSP_ISA_IRQ_MAX_OFFSET) && + ((int) irqLine >= BSP_ISA_IRQ_LOWEST_OFFSET) + ); +} +#endif + +#if BSP_PCI_IRQ_NUMBER > 0 +/* + * Check if IRQ is an OPENPIC IRQ + */ +static inline int is_pci_irq(const rtems_irq_number irqLine) +{ + return OpenPIC && (((int) irqLine <= BSP_PCI_IRQ_MAX_OFFSET) && + ((int) irqLine >= BSP_PCI_IRQ_LOWEST_OFFSET) + ); +} +#endif + +/* + * ------------------------ RTEMS Irq helper functions ---------------- + */ + +#if BSP_ISA_IRQ_NUMBER > 0 +/* + * Caution : this function assumes the variable "*config" + * is already set and that the tables it contains are still valid + * and accessible. + */ +static void compute_i8259_masks_from_prio (rtems_irq_global_settings* config) +{ + int i; + int j; + /* + * Always mask at least current interrupt to prevent re-entrance + */ + for (i=BSP_ISA_IRQ_LOWEST_OFFSET; i < BSP_ISA_IRQ_LOWEST_OFFSET + BSP_ISA_IRQ_NUMBER; i++) { + * ((unsigned short*) &irq_mask_or_tbl[i]) = (1 << i); + for (j = BSP_ISA_IRQ_LOWEST_OFFSET; j < BSP_ISA_IRQ_LOWEST_OFFSET + BSP_ISA_IRQ_NUMBER; j++) { + /* + * Mask interrupts at i8259 level that have a lower priority + */ + if (config->irqPrioTbl [i] > config->irqPrioTbl [j]) { + * ((unsigned short*) &irq_mask_or_tbl[i]) |= (1 << j); + } + } + } +} +#endif + +void +BSP_enable_irq_at_pic(const rtems_irq_number name) +{ +#if BSP_ISA_IRQ_NUMBER > 0 + if (is_isa_irq(name)) { + /* + * Enable interrupt at PIC level + */ + BSP_irq_enable_at_i8259s ((int) name - BSP_ISA_IRQ_LOWEST_OFFSET); + } +#endif + +#if BSP_PCI_IRQ_NUMBER > 0 + if (is_pci_irq(name)) { + /* + * Enable interrupt at OPENPIC level + */ + openpic_enable_irq ((int) name - BSP_PCI_IRQ_LOWEST_OFFSET); + } +#endif +} + +int +BSP_disable_irq_at_pic(const rtems_irq_number name) +{ +#if BSP_ISA_IRQ_NUMBER > 0 + if (is_isa_irq(name)) { + /* + * disable interrupt at PIC level + */ + return BSP_irq_disable_at_i8259s ((int) name - BSP_ISA_IRQ_LOWEST_OFFSET); + } +#endif +#if BSP_PCI_IRQ_NUMBER > 0 + if (is_pci_irq(name)) { + /* + * disable interrupt at OPENPIC level + */ + return openpic_disable_irq ((int) name - BSP_PCI_IRQ_LOWEST_OFFSET); + } +#endif + return -1; +} + +/* + * RTEMS Global Interrupt Handler Management Routines + */ +int BSP_setup_the_pic(rtems_irq_global_settings* config) +{ + int i; + /* + * Store various code accelerators + */ + default_rtems_entry = config->defaultEntry; + rtems_hdl_tbl = config->irqHdlTbl; + + /* + * set up internal tables used by rtems interrupt prologue + */ + +#if BSP_ISA_IRQ_NUMBER > 0 + /* + * start with ISA IRQ + */ + compute_i8259_masks_from_prio (config); + + for (i=BSP_ISA_IRQ_LOWEST_OFFSET; i < BSP_ISA_IRQ_LOWEST_OFFSET + BSP_ISA_IRQ_NUMBER; i++) { + if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) { + BSP_irq_enable_at_i8259s (i); + } + else { + BSP_irq_disable_at_i8259s (i); + } + } + + if ( BSP_ISA_IRQ_NUMBER > 0 ) { + /* + * must enable slave pic anyway + */ + BSP_irq_enable_at_i8259s (2); + } +#endif + +#if BSP_PCI_IRQ_NUMBER > 0 + if ( ! OpenPIC ) + return 1; + /* + * continue with PCI IRQ + */ + for (i=BSP_PCI_IRQ_LOWEST_OFFSET; i < BSP_PCI_IRQ_LOWEST_OFFSET + BSP_PCI_IRQ_NUMBER ; i++) { + /* + * Note that openpic_set_priority() sets the TASK priority of the PIC + */ + openpic_set_source_priority(i - BSP_PCI_IRQ_LOWEST_OFFSET, + config->irqPrioTbl[i]); + if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) { + openpic_enable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET); + } + else { + openpic_disable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET); + } + } + +#ifdef BSP_PCI_ISA_BRIDGE_IRQ + /* + * Must enable PCI/ISA bridge IRQ + */ + openpic_enable_irq (BSP_PCI_ISA_BRIDGE_IRQ); +#endif +#endif + + return 1; +} + +int _BSP_vme_bridge_irq = -1; + +unsigned BSP_spuriousIntr = 0; + +/* + * High level IRQ handler called from shared_raw_irq_code_entry + */ +int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum) +{ + register unsigned int irq; +#if BSP_ISA_IRQ_NUMBER > 0 + register unsigned isaIntr; /* boolean */ + register unsigned oldMask = 0; /* old isa pic masks */ + register unsigned newMask; /* new isa pic masks */ +#endif + + if (excNum == ASM_DEC_VECTOR) { + + bsp_irq_dispatch_list(rtems_hdl_tbl, BSP_DECREMENTER, default_rtems_entry.hdl); + + return 0; + + } + +#if BSP_PCI_IRQ_NUMBER > 0 + if ( OpenPIC ) { + irq = openpic_irq(0); + if (irq == OPENPIC_VEC_SPURIOUS) { + ++BSP_spuriousIntr; + return 0; + } + + /* some BSPs might want to use a different numbering... */ + irq = irq - OPENPIC_VEC_SOURCE + BSP_PCI_IRQ_LOWEST_OFFSET; + } else { +#if BSP_ISA_IRQ_NUMBER > 0 +#ifdef BSP_PCI_ISA_BRIDGE_IRQ + irq = BSP_PCI_ISA_BRIDGE_IRQ; +#else +#error "Configuration Error -- BSP with ISA + PCI IRQs MUST define BSP_PCI_ISA_BRIDGE_IRQ" +#endif +#else + rtems_panic("MUST have an OpenPIC if BSP has PCI IRQs but no ISA IRQs"); + /* rtems_panic() never returns but the 'return' statement silences + * a compiler warning about 'irq' possibly being used w/o initialization. + */ + return -1; +#endif + } +#endif + +#if BSP_ISA_IRQ_NUMBER > 0 +#ifdef BSP_PCI_ISA_BRIDGE_IRQ +#if 0 == BSP_PCI_IRQ_NUMBER +#error "Configuration Error -- BSP w/o PCI IRQs MUST NOT define BSP_PCI_ISA_BRIDGE_IRQ" +#endif + isaIntr = (irq == BSP_PCI_ISA_BRIDGE_IRQ); +#else + isaIntr = 1; +#endif + if (isaIntr) { + /* + * Acknowledge and read 8259 vector + */ + irq = (unsigned int) (*(unsigned char *) RAVEN_INTR_ACK_REG); + /* + * store current PIC mask + */ + oldMask = i8259s_cache; + newMask = oldMask | irq_mask_or_tbl [irq]; + i8259s_cache = newMask; + outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff); + outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8)); + BSP_irq_ack_at_i8259s (irq); +#if BSP_PCI_IRQ_NUMBER > 0 + if ( OpenPIC ) + openpic_eoi(0); +#endif + } +#endif + + /* dispatch handlers */ + bsp_irq_dispatch_list(rtems_hdl_tbl, irq, default_rtems_entry.hdl); + +#if BSP_ISA_IRQ_NUMBER > 0 + if (isaIntr) { + i8259s_cache = oldMask; + outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff); + outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8)); + } + else +#endif + { +#if BSP_PCI_IRQ_NUMBER > 0 +#ifdef BSP_PCI_VME_DRIVER_DOES_EOI + /* leave it to the VME bridge driver to do EOI, so + * it can re-enable the openpic while handling + * VME interrupts (-> VME priorities in software) + */ + if (_BSP_vme_bridge_irq != irq && OpenPIC) +#endif + openpic_eoi(0); +#else + do {} while (0); +#endif + } + return 0; +} diff --git a/bsps/powerpc/t32mppc/irq/irq.c b/bsps/powerpc/t32mppc/irq/irq.c new file mode 100644 index 0000000000..5b2c34d2c9 --- /dev/null +++ b/bsps/powerpc/t32mppc/irq/irq.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2012, 2017 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * 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 <bsp.h> +#include <bsp/irq-generic.h> +#include <bsp/vectors.h> + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); +} + +void bsp_interrupt_dispatch(uintptr_t exception_number) +{ + if (exception_number == 10) { + t32mppc_decrementer_dispatch(); + } else { + bsp_interrupt_handler_default(0); + } +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/powerpc/tqm8xx/irq/irq.c b/bsps/powerpc/tqm8xx/irq/irq.c new file mode 100644 index 0000000000..2a94c27d1b --- /dev/null +++ b/bsps/powerpc/tqm8xx/irq/irq.c @@ -0,0 +1,231 @@ +/*===============================================================*\ +| Project: RTEMS TQM8xx BSP | ++-----------------------------------------------------------------+ +| This file has been adapted to MPC8xx by | +| Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> | +| Copyright (c) 2008 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | +| | +| See the other copyright notice below for the original parts. | ++-----------------------------------------------------------------+ +| 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. | +| | ++-----------------------------------------------------------------+ +| this file contains the console driver | +\*===============================================================*/ +/* derived from: generic MPC83xx BSP */ + +#include <rtems.h> +#include <mpc8xx.h> + +#include <libcpu/powerpc-utility.h> +#include <bsp/vectors.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> +/* + * functions to enable/disable a source at the SIU/CPM irq controller + */ + +static rtems_status_code bsp_irq_disable_at_SIU(rtems_vector_number irqnum) +{ + rtems_vector_number vecnum = irqnum - BSP_SIU_IRQ_LOWEST_OFFSET; + m8xx.simask &= ~(1 << (31 - vecnum)); + return RTEMS_SUCCESSFUL; +} + +static rtems_status_code bsp_irq_enable_at_SIU(rtems_vector_number irqnum) +{ + rtems_vector_number vecnum = irqnum - BSP_SIU_IRQ_LOWEST_OFFSET; + m8xx.simask |= (1 << (31 - vecnum)); + return RTEMS_SUCCESSFUL; +} + +static rtems_status_code bsp_irq_disable_at_CPM(rtems_vector_number irqnum) +{ + rtems_vector_number vecnum = irqnum - BSP_CPM_IRQ_LOWEST_OFFSET; + m8xx.cimr &= ~(1 << (vecnum)); + return RTEMS_SUCCESSFUL; +} + +static rtems_status_code bsp_irq_enable_at_CPM(rtems_vector_number irqnum) +{ + rtems_vector_number vecnum = irqnum - BSP_CPM_IRQ_LOWEST_OFFSET; + m8xx.cimr |= (1 << (vecnum)); + return RTEMS_SUCCESSFUL; +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + if (BSP_IS_CPM_IRQ(vector)) { + bsp_irq_enable_at_CPM(vector); + } else if (BSP_IS_SIU_IRQ(vector)) { + bsp_irq_enable_at_SIU(vector); + } +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + if (BSP_IS_CPM_IRQ(vector)) { + bsp_irq_disable_at_CPM(vector); + } else if (BSP_IS_SIU_IRQ(vector)) { + bsp_irq_disable_at_SIU(vector); + } +} + +/* + * IRQ Handler: this is called from the primary exception dispatcher + */ +static int BSP_irq_handle_at_cpm(void) +{ + int32_t cpvecnum; + uint32_t msr; + + /* Get vector number: write IACK=1, then read vectir */ + m8xx.civr = 1; + cpvecnum = (m8xx.civr >> 11) + BSP_CPM_IRQ_LOWEST_OFFSET; + + /* + * Check the vector number, + * enable exceptions and dispatch the handler. + * NOTE: lower-prio interrupts are automatically masked in CPIC + */ + if (BSP_IS_CPM_IRQ(cpvecnum)) { + /* Enable all interrupts */ + msr = ppc_external_exceptions_enable(); + /* Dispatch interrupt handlers */ + bsp_interrupt_handler_dispatch(cpvecnum); + /* Restore machine state */ + ppc_external_exceptions_disable(msr); + } + else { + /* not valid vector */ + bsp_interrupt_handler_default(cpvecnum); + } + /* + * clear "in-service" bit + */ + m8xx.cisr = 1 << (cpvecnum - BSP_CPM_IRQ_LOWEST_OFFSET); + + return 0; +} + +static int BSP_irq_handle_at_siu( unsigned excNum) +{ + int32_t sivecnum; + uint32_t msr; + bool is_cpm_irq; + uint32_t simask_save; + /* + * check, if interrupt is pending + * and repeat as long as valid interrupts are pending + */ + while (0 != (m8xx.simask & m8xx.sipend)) { + /* Get vector number */ + sivecnum = (m8xx.sivec >> 26); + is_cpm_irq = (sivecnum == BSP_CPM_INTERRUPT); + /* + * Check the vector number, mask lower priority interrupts, enable + * exceptions and dispatch the handler. + */ + if (BSP_IS_SIU_IRQ(sivecnum)) { + simask_save = m8xx.simask; + /* + * if this is the CPM interrupt, mask lower prio interrupts at SIU + * else mask lower and same priority interrupts + */ + m8xx.simask &= ~0 << (32 + - sivecnum + - ((is_cpm_irq) ? 1 : 0)); + + if (is_cpm_irq) { + BSP_irq_handle_at_cpm(); + } + else { + /* Enable all interrupts */ + msr = ppc_external_exceptions_enable(); + /* Dispatch interrupt handlers */ + bsp_interrupt_handler_dispatch(sivecnum + BSP_SIU_IRQ_LOWEST_OFFSET); + /* Restore machine state */ + ppc_external_exceptions_disable(msr); + /* + * clear pending bit, if edge triggered interrupt input + */ + m8xx.sipend = 1 << (31 - sivecnum); + } + + + /* Restore initial masks */ + m8xx.simask = simask_save; + } else { + /* not valid vector */ + bsp_interrupt_handler_default(sivecnum); + } + } + return 0; +} + +/* + * Activate the CPIC + */ +static rtems_status_code mpc8xx_cpic_initialize( void) +{ + /* + * mask off all interrupts + */ + m8xx.cimr = 0; + /* + * make sure CPIC request proper level at SIU interrupt controller + */ + m8xx.cicr = (0x00e41f80 | + ((BSP_CPM_INTERRUPT/2) << 13)); + /* + * enable CPIC interrupt in SIU interrupt controller + */ + return bsp_irq_enable_at_SIU(BSP_CPM_INTERRUPT); +} + +/* + * Activate the SIU interrupt controller + */ +static rtems_status_code mpc8xx_siu_int_initialize( void) +{ + /* + * mask off all interrupts + */ + m8xx.simask = 0; + + return RTEMS_SUCCESSFUL; +} + +static int mpc8xx_exception_handler(BSP_Exception_frame *frame, + unsigned exception_number) +{ + return BSP_irq_handle_at_siu(exception_number); +} + +rtems_status_code bsp_interrupt_facility_initialize() +{ + /* Install exception handler */ + if (ppc_exc_set_handler(ASM_EXT_VECTOR, mpc8xx_exception_handler)) { + return RTEMS_IO_ERROR; + } + /* Initialize the SIU interrupt controller */ + if (mpc8xx_siu_int_initialize()) { + return RTEMS_IO_ERROR; + } + /* Initialize the CPIC interrupt controller */ + return mpc8xx_cpic_initialize(); +} diff --git a/bsps/powerpc/virtex/irq/irq_init.c b/bsps/powerpc/virtex/irq/irq_init.c new file mode 100644 index 0000000000..55194cb1e6 --- /dev/null +++ b/bsps/powerpc/virtex/irq/irq_init.c @@ -0,0 +1,167 @@ +/*===============================================================*\ +| Project: RTEMS virtex BSP | ++-----------------------------------------------------------------+ +| Partially based on the code references which are named below. | +| Adaptions, modifications, enhancements and any recent parts of | +| the code are: | +| Copyright (c) 2007 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | ++-----------------------------------------------------------------+ +| 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. | +| | ++-----------------------------------------------------------------+ +| this file contains the irq controller handler | +\*===============================================================*/ + +/* Content moved from opbintctrl.c: + * + * This file contains definitions and declarations for the + * Xilinx Off Processor Bus (OPB) Interrupt Controller + * + * Author: Keith Robertson <kjrobert@alumni.uwaterloo.ca> + * COPYRIGHT (c) 2005 Linn Products Ltd, Scotland. + * + * 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 <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> +#include <bsp/vectors.h> + +#include <libcpu/powerpc-utility.h> + +/* + * Acknowledge a mask of interrupts. + */ +static void set_iar(uint32_t mask) +{ + *((volatile uint32_t *) (OPB_INTC_BASE + OPB_INTC_IAR)) = mask; +} + +/* + * Set IER state. Used to (dis)enable a mask of vectors. + * If you only have to do one, use enable/disable_vector. + */ +static void set_ier(uint32_t mask) +{ + *((volatile uint32_t *) (OPB_INTC_BASE + OPB_INTC_IER)) = mask; +} + +/* + * Retrieve contents of Interrupt Pending Register + */ +static uint32_t get_ipr(void) +{ + uint32_t c = *((volatile uint32_t *) (OPB_INTC_BASE + OPB_INTC_IPR)); + return c; +} + +static void BSP_irq_enable_at_opbintc (rtems_irq_number irqnum) +{ + *((volatile uint32_t *) (OPB_INTC_BASE + OPB_INTC_SIE)) + = 1 << (irqnum - BSP_OPBINTC_IRQ_LOWEST_OFFSET); +} + +static void BSP_irq_disable_at_opbintc (rtems_irq_number irqnum) +{ + *((volatile uint32_t *) (OPB_INTC_BASE + OPB_INTC_CIE)) + = 1 << (irqnum - BSP_OPBINTC_IRQ_LOWEST_OFFSET); +} + +/* + * IRQ Handler: this is called from the primary exception dispatcher + */ +static void BSP_irq_handle_at_opbintc(void) +{ + uint32_t ipr; + + /* Get pending interrupts */ + ipr = get_ipr(); + + if (ipr != 0) { + /* Acknowledge all pending interrupts now and service them afterwards */ + set_iar(ipr); + + do { + /* Get highest priority pending interrupt */ + uint32_t i = 31 - ppc_count_leading_zeros(ipr); + + ipr &= ~(1U << i); + + bsp_interrupt_handler_dispatch(i+BSP_OPBINTC_IRQ_LOWEST_OFFSET); + } while (ipr != 0); + } +} + +/* + * activate the interrupt controller + */ +static void opb_intc_init(void) +{ + uint32_t i, mask = 0; + + /* mask off all interrupts */ + set_ier(0x0); + + for (i = 0; i < OPB_INTC_IRQ_MAX; i++) { + mask |= (1 << i); + } + + /* make sure interupt status register is clear before we enable the interrupt controller */ + *((volatile uint32_t *) (OPB_INTC_BASE + OPB_INTC_ISR)) = 0; + + /* acknowledge all interrupt sources */ + set_iar(mask); + + /* Turn on normal hardware operation of interrupt controller */ + *((volatile uint32_t *) (OPB_INTC_BASE + OPB_INTC_MER)) = + (OPB_INTC_MER_HIE); + + /* Enable master interrupt switch for the interrupt controller */ + *((volatile uint32_t *) (OPB_INTC_BASE + OPB_INTC_MER)) = + (OPB_INTC_MER_HIE | OPB_INTC_MER_ME); +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + if (BSP_IS_OPBINTC_IRQ(vector)) { + BSP_irq_enable_at_opbintc(vector); + } +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + if (BSP_IS_OPBINTC_IRQ(vector)) { + BSP_irq_disable_at_opbintc(vector); + } +} + +static int C_dispatch_irq_handler(BSP_Exception_frame *frame, unsigned int excNum) +{ + BSP_irq_handle_at_opbintc(); + + return 0; +} + +rtems_status_code bsp_interrupt_facility_initialize(void) +{ + opb_intc_init(); + + ppc_exc_set_handler(ASM_EXT_VECTOR, C_dispatch_irq_handler); + + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/powerpc/virtex4/irq/irq_init.c b/bsps/powerpc/virtex4/irq/irq_init.c new file mode 100644 index 0000000000..5feafaf4b6 --- /dev/null +++ b/bsps/powerpc/virtex4/irq/irq_init.c @@ -0,0 +1,326 @@ +/*===============================================================*\ +| Project: RTEMS virtex BSP | ++-----------------------------------------------------------------+ +| Partially based on the code references which are named below. | +| Adaptions, modifications, enhancements and any recent parts of | +| the code are: | +| Copyright (c) 2007 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | ++-----------------------------------------------------------------+ +| 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. | +| | ++-----------------------------------------------------------------+ +| this file contains the irq controller handler | +\*===============================================================*/ +#include <libcpu/spr.h> +#include <bsp/irq.h> +#include <bsp.h> +#include <rtems/bspIo.h> +#include <rtems/powerpc/powerpc.h> +#include <bsp/vectors.h> + +static rtems_irq_connect_data rtemsIrqTbl[BSP_IRQ_NUMBER]; +rtems_irq_connect_data *BSP_rtems_irq_tbl; +rtems_irq_global_settings* BSP_rtems_irq_config; + +/*********************************************************** + * dummy functions for on/off/isOn calls + * these functions just do nothing fulfill the semantic + * requirements to enable/disable a certain interrupt or exception + */ +static void BSP_irq_nop_func(const rtems_irq_connect_data *unused) +{ + /* + * nothing to do + */ +} + +static void BSP_irq_nop_hdl(void *hdl) +{ + /* + * nothing to do + */ +} + +static int BSP_irq_isOn_func(const rtems_irq_connect_data *unused) +{ + /* + * nothing to do + */ + return 0; +} + +/*********************************************************** + * interrupt handler and its enable/disable functions + ***********************************************************/ + +/*********************************************************** + * functions to enable/disable/query external/critical interrupts + */ +void BSP_irqexc_on_fnc(const rtems_irq_connect_data *conn_data) +{ + uint32_t msr_value; + /* + * get current MSR value + */ + _CPU_MSR_GET(msr_value); + + msr_value |= PPC_MSR_EE; + _CPU_MSR_SET(msr_value); +} + +void BSP_irqexc_off_fnc(const rtems_irq_connect_data *unused) +{ + uint32_t msr_value; + /* + * get current MSR value + */ + _CPU_MSR_GET(msr_value); + + msr_value &= ~PPC_MSR_EE; + _CPU_MSR_SET(msr_value); +} + +/*********************************************************** + * High level IRQ handler called from shared_raw_irq_code_entry + */ +static int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum) +{ + /* + * Handle interrupt + */ + switch(excNum) { + case ASM_EXT_VECTOR: + BSP_rtems_irq_tbl[BSP_EXT].hdl(BSP_rtems_irq_tbl[BSP_EXT].handle); + break; + case ASM_BOOKE_DEC_VECTOR: + BSP_rtems_irq_tbl[BSP_PIT].hdl(BSP_rtems_irq_tbl[BSP_PIT].handle); + break; +#if 0 /* Critical interrupts not yet supported */ + case ASM_BOOKE_CRIT_VECTOR: + BSP_rtems_irq_tbl[BSP_CRIT].hdl(BSP_rtems_irq_tbl[BSP_CRIT].handle); + break; +#endif + } + + return 0; +} + +/*********************************************************** + * functions to set/get/remove interrupt handlers + ***********************************************************/ +int BSP_install_rtems_irq_handler (const rtems_irq_connect_data* irq) +{ + rtems_interrupt_level level; + + /* + * check for valid irq name + * if invalid, print error and return 0 + */ + if (!BSP_IS_VALID_IRQ(irq->name)) { + printk("Invalid interrupt vector %d\n",irq->name); + return 0; + } + + /* + * disable interrupts + */ + rtems_interrupt_disable(level); + + /* + * check, that default handler is installed now + */ + if (rtemsIrqTbl[irq->name].hdl != BSP_rtems_irq_config->defaultEntry.hdl) { + rtems_interrupt_enable(level); + printk("IRQ vector %d already connected\n",irq->name); + return 0; + } + + /* + * store new handler data + */ + rtemsIrqTbl[irq->name] = *irq; + + /* + * call "on" function to enable interrupt at device + */ + irq->on(irq); + + /* + * reenable interrupts + */ + rtems_interrupt_enable(level); + + return 1; +} + +int BSP_get_current_rtems_irq_handler (rtems_irq_connect_data* irq) +{ + rtems_interrupt_level level; + + /* + * check for valid IRQ name + */ + if (!BSP_IS_VALID_IRQ(irq->name)) { + return 0; + } + rtems_interrupt_disable(level); + + /* + * return current IRQ entry + */ + *irq = rtemsIrqTbl[irq->name]; + rtems_interrupt_enable(level); + return 1; +} + +int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq) +{ + rtems_interrupt_level level; + + /* + * check for valid IRQ name + */ + if (!BSP_IS_VALID_IRQ(irq->name)) { + return 0; + } + rtems_interrupt_disable(level); + + /* + * check, that specified handler is really connected now + */ + if (rtemsIrqTbl[irq->name].hdl != irq->hdl) { + rtems_interrupt_enable(level); + return 0; + } + + /* + * disable interrupt at source + */ + irq->off(irq); + + /* + * restore default interrupt handler + */ + rtemsIrqTbl[irq->name] = BSP_rtems_irq_config->defaultEntry; + + /* + * reenable interrupts + */ + rtems_interrupt_enable(level); + + return 1; +} + +/*********************************************************** + * functions to set/get the basic interrupt management setup + ***********************************************************/ +/* + * (Re) get info on current RTEMS interrupt management. + */ +int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** ret_ptr) +{ + *ret_ptr = BSP_rtems_irq_config; + return 0; +} + + +/* + * set management stuff + */ +int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config) +{ + int i; + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + + /* + * store given configuration + */ + BSP_rtems_irq_config = config; + BSP_rtems_irq_tbl = BSP_rtems_irq_config->irqHdlTbl; + + /* + * store any irq-like processor exceptions + */ + for (i = BSP_PROCESSOR_IRQ_LOWEST_OFFSET; + i < BSP_PROCESSOR_IRQ_MAX_OFFSET; + i++) { + if (BSP_rtems_irq_tbl[i].hdl != config->defaultEntry.hdl) { + if (BSP_rtems_irq_tbl[i].on != NULL) { + BSP_rtems_irq_tbl[i].on + (&(BSP_rtems_irq_tbl[i])); + } + } + else { + if (BSP_rtems_irq_tbl[i].off != NULL) { + BSP_rtems_irq_tbl[i].off + (&(BSP_rtems_irq_tbl[i])); + } + } + } + rtems_interrupt_enable(level); + return 1; +} + +/* + * dummy for an empty IRQ handler entry + */ +static rtems_irq_connect_data emptyIrq = { + 0, /* IRQ Name */ + BSP_irq_nop_hdl, /* handler function */ + NULL, /* handle passed to handler */ + BSP_irq_nop_func, /* on function */ + BSP_irq_nop_func, /* off function */ + BSP_irq_isOn_func /* isOn function */ +}; + +static rtems_irq_global_settings initialConfig = { + BSP_IRQ_NUMBER, /* IRQ Number */ + { 0, /* IRQ Name */ + BSP_irq_nop_hdl, /* handler function */ + NULL, /* handle passed to handler */ + BSP_irq_nop_func, /* on function */ + BSP_irq_nop_func, /* off function */ + BSP_irq_isOn_func /* isOn function */ + }, /* emptyIrq */ + rtemsIrqTbl, /* irqHdlTbl */ + 0, /* irqBase */ + NULL /* irqPrioTbl */ +}; + +void BSP_rtems_irq_mngt_init(unsigned cpuId) +{ + int i; + + /* + * connect all exception vectors needed + */ + ppc_exc_set_handler(ASM_EXT_VECTOR, C_dispatch_irq_handler); + ppc_exc_set_handler(ASM_BOOKE_DEC_VECTOR, C_dispatch_irq_handler); + + /* + * setup interrupt handlers table + */ + for (i = 0; + i < BSP_IRQ_NUMBER; + i++) { + rtemsIrqTbl[i] = emptyIrq; + rtemsIrqTbl[i].name = i; + } + + /* + * initialize interrupt management + */ + if (!BSP_rtems_irq_mngt_set(&initialConfig)) { + rtems_panic("Unable to initialize RTEMS interrupt Management!!! System locked\n"); + } +} diff --git a/bsps/powerpc/virtex5/irq/irq_init.c b/bsps/powerpc/virtex5/irq/irq_init.c new file mode 100644 index 0000000000..1fea9214aa --- /dev/null +++ b/bsps/powerpc/virtex5/irq/irq_init.c @@ -0,0 +1,343 @@ +/*===============================================================*\ +| Project: RTEMS virtex BSP | ++-----------------------------------------------------------------+ +| Partially based on the code references which are named below. | +| Adaptions, modifications, enhancements and any recent parts of | +| the code are: | +| Copyright (c) 2007 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | ++-----------------------------------------------------------------+ +| 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. | +| | ++-----------------------------------------------------------------+ +| this file contains the irq controller handler | +\*===============================================================*/ +#include <libcpu/spr.h> +#include <bsp/irq.h> +#include <bsp.h> +#include <rtems/bspIo.h> +#include <rtems/powerpc/powerpc.h> +#include <bsp/vectors.h> + +static rtems_irq_connect_data rtemsIrqTbl[BSP_IRQ_NUMBER]; +rtems_irq_connect_data *BSP_rtems_irq_tbl; +rtems_irq_global_settings* BSP_rtems_irq_config; + +/*********************************************************** + * dummy functions for on/off/isOn calls + * these functions just do nothing fulfill the semantic + * requirements to enable/disable a certain interrupt or exception + */ +static void BSP_irq_nop_func(const rtems_irq_connect_data *unused) +{ + /* + * nothing to do + */ +} + +static void BSP_irq_nop_hdl(void *hdl) +{ + /* + * nothing to do + */ +} + +static int BSP_irq_isOn_func(const rtems_irq_connect_data *unused) +{ + /* + * nothing to do + */ + return 0; +} + +/*********************************************************** + * interrupt handler and its enable/disable functions + ***********************************************************/ + +/*********************************************************** + * functions to enable/disable/query external/critical interrupts + */ +void BSP_irqexc_on_fnc(const rtems_irq_connect_data *conn_data) +{ + uint32_t msr_value; + /* + * get current MSR value + */ + _CPU_MSR_GET(msr_value); + + msr_value |= PPC_MSR_EE; + _CPU_MSR_SET(msr_value); +} + +void BSP_irqexc_off_fnc(const rtems_irq_connect_data *unused) +{ + uint32_t msr_value; + /* + * get current MSR value + */ + _CPU_MSR_GET(msr_value); + + msr_value &= ~PPC_MSR_EE; + _CPU_MSR_SET(msr_value); +} + +SPR_RW(BOOKE_TSR) + +static int C_dispatch_dec_handler (BSP_Exception_frame *frame, unsigned int excNum) +{ + /* Acknowledge the interrupt */ + _write_BOOKE_TSR( BOOKE_TSR_DIS ); + + /* Handle the interrupt */ + BSP_rtems_irq_tbl[BSP_DEC].hdl(BSP_rtems_irq_tbl[BSP_DEC].handle); + + return 0; +} + + +/*********************************************************** + * High level IRQ handler called from shared_raw_irq_code_entry + */ +static int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum) +{ + /* + * Handle interrupt + */ + switch(excNum) { + case ASM_EXT_VECTOR: + BSP_rtems_irq_tbl[BSP_EXT].hdl(BSP_rtems_irq_tbl[BSP_EXT].handle); + break; +#if 0 /* Dealt with by C_dispatch_dec_handler(), above */ + case ASM_BOOKE_DEC_VECTOR: + _write_BOOKE_TSR( BOOKE_TSR_DIS ); + BSP_rtems_irq_tbl[BSP_DEC].hdl(BSP_rtems_irq_tbl[BSP_DEC].handle); + break; +#endif +#if 0 /* Critical interrupts not yet supported */ + case ASM_BOOKE_CRIT_VECTOR: + BSP_rtems_irq_tbl[BSP_CRIT].hdl(BSP_rtems_irq_tbl[BSP_CRIT].handle); + break; +#endif + } + + return 0; +} + +/*********************************************************** + * functions to set/get/remove interrupt handlers + ***********************************************************/ +int BSP_install_rtems_irq_handler (const rtems_irq_connect_data* irq) +{ + rtems_interrupt_level level; + + /* + * check for valid irq name + * if invalid, print error and return 0 + */ + if (!BSP_IS_VALID_IRQ(irq->name)) { + printk("Invalid interrupt vector %d\n",irq->name); + return 0; + } + + /* + * disable interrupts + */ + rtems_interrupt_disable(level); + + /* + * check, that default handler is installed now + */ + if (rtemsIrqTbl[irq->name].hdl != BSP_rtems_irq_config->defaultEntry.hdl) { + rtems_interrupt_enable(level); + printk("IRQ vector %d already connected\n",irq->name); + return 0; + } + + /* + * store new handler data + */ + rtemsIrqTbl[irq->name] = *irq; + + /* + * call "on" function to enable interrupt at device + */ + irq->on(irq); + + /* + * reenable interrupts + */ + rtems_interrupt_enable(level); + + return 1; +} + +int BSP_get_current_rtems_irq_handler (rtems_irq_connect_data* irq) +{ + rtems_interrupt_level level; + + /* + * check for valid IRQ name + */ + if (!BSP_IS_VALID_IRQ(irq->name)) { + return 0; + } + rtems_interrupt_disable(level); + + /* + * return current IRQ entry + */ + *irq = rtemsIrqTbl[irq->name]; + rtems_interrupt_enable(level); + return 1; +} + +int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq) +{ + rtems_interrupt_level level; + + /* + * check for valid IRQ name + */ + if (!BSP_IS_VALID_IRQ(irq->name)) { + return 0; + } + rtems_interrupt_disable(level); + + /* + * check, that specified handler is really connected now + */ + if (rtemsIrqTbl[irq->name].hdl != irq->hdl) { + rtems_interrupt_enable(level); + return 0; + } + + /* + * disable interrupt at source + */ + irq->off(irq); + + /* + * restore default interrupt handler + */ + rtemsIrqTbl[irq->name] = BSP_rtems_irq_config->defaultEntry; + + /* + * reenable interrupts + */ + rtems_interrupt_enable(level); + + return 1; +} + +/*********************************************************** + * functions to set/get the basic interrupt management setup + ***********************************************************/ +/* + * (Re) get info on current RTEMS interrupt management. + */ +int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** ret_ptr) +{ + *ret_ptr = BSP_rtems_irq_config; + return 0; +} + + +/* + * set management stuff + */ +int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config) +{ + int i; + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + + /* + * store given configuration + */ + BSP_rtems_irq_config = config; + BSP_rtems_irq_tbl = BSP_rtems_irq_config->irqHdlTbl; + + /* + * store any irq-like processor exceptions + */ + for (i = BSP_PROCESSOR_IRQ_LOWEST_OFFSET; + i < BSP_PROCESSOR_IRQ_MAX_OFFSET; + i++) { + if (BSP_rtems_irq_tbl[i].hdl != config->defaultEntry.hdl) { + if (BSP_rtems_irq_tbl[i].on != NULL) { + BSP_rtems_irq_tbl[i].on + (&(BSP_rtems_irq_tbl[i])); + } + } + else { + if (BSP_rtems_irq_tbl[i].off != NULL) { + BSP_rtems_irq_tbl[i].off + (&(BSP_rtems_irq_tbl[i])); + } + } + } + rtems_interrupt_enable(level); + return 1; +} + +/* + * dummy for an empty IRQ handler entry + */ +static rtems_irq_connect_data emptyIrq = { + 0, /* IRQ Name */ + BSP_irq_nop_hdl, /* handler function */ + NULL, /* handle passed to handler */ + BSP_irq_nop_func, /* on function */ + BSP_irq_nop_func, /* off function */ + BSP_irq_isOn_func /* isOn function */ +}; + +static rtems_irq_global_settings initialConfig = { + BSP_IRQ_NUMBER, /* IRQ number */ + { 0, /* IRQ Name */ + BSP_irq_nop_hdl, /* handler function */ + NULL, /* handle passed to handler */ + BSP_irq_nop_func, /* on function */ + BSP_irq_nop_func, /* off function */ + BSP_irq_isOn_func /* isOn function */ + }, /* emptyIrq */ + rtemsIrqTbl, /* irqHdlTbl */ + 0, /* irqBase */ + NULL /* irqPrioTbl */ +}; + +void BSP_rtems_irq_mngt_init(unsigned cpuId) +{ + int i; + + /* + * connect all exception vectors needed + */ + ppc_exc_set_handler(ASM_EXT_VECTOR, C_dispatch_irq_handler); + ppc_exc_set_handler(ASM_BOOKE_DEC_VECTOR, C_dispatch_dec_handler); + + /* + * setup interrupt handlers table + */ + for (i = 0; + i < BSP_IRQ_NUMBER; + i++) { + rtemsIrqTbl[i] = emptyIrq; + rtemsIrqTbl[i].name = i; + } + + /* + * initialize interrupt management + */ + if (!BSP_rtems_irq_mngt_set(&initialConfig)) { + rtems_panic("Unable to initialize RTEMS interrupt Management!!! System locked\n"); + } +} diff --git a/bsps/riscv/riscv_generic/irq/irq.c b/bsps/riscv/riscv_generic/irq/irq.c new file mode 100644 index 0000000000..8090dcea98 --- /dev/null +++ b/bsps/riscv/riscv_generic/irq/irq.c @@ -0,0 +1,60 @@ +/** + * @file + * + * @ingroup riscv_interrupt + * + * @brief Interrupt support. + */ + +/* + * RISCV CPU Dependent Source + * + * Copyright (c) 2015 University of York. + * Hesham Almatary <hesham@alumni.york.ac.uk> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <bsp/irq.h> +#include <bsp/irq-generic.h> + +/* Almost all of the jobs that the following functions should + * do are implemented in cpukit + */ + +void bsp_interrupt_handler_default(rtems_vector_number vector) +{ + printk("spurious interrupt: %u\n", vector); +} + +rtems_status_code bsp_interrupt_facility_initialize() +{ + return RTEMS_NOT_IMPLEMENTED; +} + +void bsp_interrupt_vector_enable(rtems_vector_number vector) +{ +} + +void bsp_interrupt_vector_disable(rtems_vector_number vector) +{ +} |