From 09dd82a5974d01525402e32f47d66ff1fe1b6a67 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 13 Mar 2018 16:43:25 +0100 Subject: bsp/ss555: Move libcpu content to bsps This patch is a part of the BSP source reorganization. Update #3285. --- bsps/powerpc/ss555/dev/clock.c | 144 +++++++ bsps/powerpc/ss555/dev/console-generic.c | 317 ++++++++++++++ bsps/powerpc/ss555/dev/timer.c | 104 +++++ bsps/powerpc/ss555/start/irq.c | 463 +++++++++++++++++++++ bsps/powerpc/ss555/start/irq_asm.S | 312 ++++++++++++++ bsps/powerpc/ss555/start/irq_init.c | 165 ++++++++ bsps/powerpc/ss555/start/raw_exception.c | 190 +++++++++ c/src/lib/libbsp/powerpc/ss555/Makefile.am | 14 +- c/src/lib/libbsp/powerpc/ss555/README | 24 ++ c/src/lib/libcpu/powerpc/Makefile.am | 35 -- c/src/lib/libcpu/powerpc/mpc5xx/README | 23 - c/src/lib/libcpu/powerpc/mpc5xx/clock/clock.c | 144 ------- .../mpc5xx/console-generic/console-generic.c | 317 -------------- .../powerpc/mpc5xx/exceptions/raw_exception.c | 190 --------- c/src/lib/libcpu/powerpc/mpc5xx/ictrl/ictrl.c | 68 --- c/src/lib/libcpu/powerpc/mpc5xx/ictrl/ictrl.h | 75 ---- c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.c | 463 --------------------- c/src/lib/libcpu/powerpc/mpc5xx/irq/irq_asm.S | 312 -------------- c/src/lib/libcpu/powerpc/mpc5xx/irq/irq_init.c | 165 -------- c/src/lib/libcpu/powerpc/mpc5xx/timer/timer.c | 104 ----- 20 files changed, 1726 insertions(+), 1903 deletions(-) create mode 100644 bsps/powerpc/ss555/dev/clock.c create mode 100644 bsps/powerpc/ss555/dev/console-generic.c create mode 100644 bsps/powerpc/ss555/dev/timer.c create mode 100644 bsps/powerpc/ss555/start/irq.c create mode 100644 bsps/powerpc/ss555/start/irq_asm.S create mode 100644 bsps/powerpc/ss555/start/irq_init.c create mode 100644 bsps/powerpc/ss555/start/raw_exception.c delete mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/README delete mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/clock/clock.c delete mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/console-generic/console-generic.c delete mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/exceptions/raw_exception.c delete mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/ictrl/ictrl.c delete mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/ictrl/ictrl.h delete mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.c delete mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/irq/irq_asm.S delete mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/irq/irq_init.c delete mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/timer/timer.c diff --git a/bsps/powerpc/ss555/dev/clock.c b/bsps/powerpc/ss555/dev/clock.c new file mode 100644 index 0000000000..9f843cee4f --- /dev/null +++ b/bsps/powerpc/ss555/dev/clock.c @@ -0,0 +1,144 @@ +/* + * This routine initializes the PIT on the MPC5xx. + * The tick frequency is specified by the BSP. + */ + +/* + * MPC5xx port sponsored by Defence Research and Development Canada - Suffield + * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) + * + * Derived from c/src/lib/libcpu/powerpc/mpc8xx/clock/clock.c: + * + * Author: Jay Monkman (jmonkman@frasca.com) + * Copyright (C) 1998 by Frasca International, Inc. + * + * Derived from c/src/lib/libcpu/ppc/ppc403/clock/clock.c: + * + * Author: Andrew Bray + * + * COPYRIGHT (c) 1995 by i-cubed ltd. + * + * 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 i-cubed limited not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * i-cubed limited makes no representations about the suitability + * of this software for any purpose. + * + * Derived from c/src/lib/libcpu/hppa1_1/clock/clock.c: + * + * COPYRIGHT (c) 1989-2007. + * 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 +#include +#include +#include + +#include /* for atexit() */ +#include + +volatile uint32_t Clock_driver_ticks; +extern int BSP_connect_clock_handler(rtems_isr_entry); +extern int BSP_disconnect_clock_handler(void); +extern uint32_t bsp_clicks_per_usec; + +void Clock_exit( void ); + +/* + * ISR Handler + */ +rtems_isr Clock_isr(rtems_vector_number vector) +{ + usiu.piscrk = USIU_UNLOCK_KEY; + usiu.piscr |= USIU_PISCR_PS; /* acknowledge interrupt */ + usiu.piscrk = 0; + + Clock_driver_ticks++; + rtems_clock_tick(); +} + +void clockOn(void* unused) +{ + unsigned desiredLevel; + uint32_t pit_value; + + /* calculate and set modulus */ + pit_value = (rtems_configuration_get_microseconds_per_tick() * + bsp_clicks_per_usec) - 1 ; + + if (pit_value > 0xffff) { /* pit is only 16 bits long */ + rtems_fatal_error_occurred(-1); + } + usiu.sccrk = USIU_UNLOCK_KEY; + usiu.sccr &= ~USIU_SCCR_RTDIV; /* RTC and PIT clock is divided by 4 */ + usiu.sccrk = 0; + + usiu.pitck = USIU_UNLOCK_KEY; + usiu.pitc = pit_value; + usiu.pitck = 0; + + /* set PIT irq level, enable PIT, PIT interrupts */ + /* and clear int. status */ + desiredLevel = CPU_irq_level_from_symbolic_name(CPU_PERIODIC_TIMER); + + usiu.piscrk = USIU_UNLOCK_KEY; + usiu.piscr = USIU_PISCR_PIRQ(desiredLevel) /* set interrupt priority */ + | USIU_PISCR_PS /* acknowledge interrupt */ + | USIU_PISCR_PIE /* enable interrupt */ + | USIU_PISCR_PITF /* freeze during debug */ + | USIU_PISCR_PTE; /* enable timer */ + usiu.piscrk = 0; +} + +void clockOff(void* unused) +{ + /* disable PIT and PIT interrupts */ + usiu.piscrk = USIU_UNLOCK_KEY; + usiu.piscr &= ~(USIU_PISCR_PTE | USIU_PISCR_PIE); + usiu.piscrk = 0; +} + +int clockIsOn(void* unused) +{ + if (usiu.piscr & USIU_PISCR_PIE) + return 1; + return 0; +} + +/* + * Called via atexit() + * Remove the clock interrupt handler by setting handler to NULL + */ +void Clock_exit(void) +{ + (void) BSP_disconnect_clock_handler (); +} + +static void Install_clock(rtems_isr_entry clock_isr) +{ + Clock_driver_ticks = 0; + + BSP_connect_clock_handler (clock_isr); + atexit(Clock_exit); +} + +rtems_device_driver Clock_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *pargp +) +{ + Install_clock( Clock_isr ); + + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/powerpc/ss555/dev/console-generic.c b/bsps/powerpc/ss555/dev/console-generic.c new file mode 100644 index 0000000000..7e1629b714 --- /dev/null +++ b/bsps/powerpc/ss555/dev/console-generic.c @@ -0,0 +1,317 @@ +/* + * General Serial I/O functions. + * + * This file contains the functions for performing serial I/O. The actual + * system calls (console_*) should be in the BSP part of the source tree. + * That way different BSPs can use whichever SCI they wish for /dev/console. + * + * On-chip resources used: + * resource minor note + * SCI1 0 + * SCI2 1 + */ + +/* + * MPC5xx port sponsored by Defence Research and Development Canada - Suffield + * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) + * + * Derived from + * c/src/lib/libcpu/powerpc/mpc8xx/console_generic/console_generic.c: + * Author: Jay Monkman (jmonkman@frasca.com) + * Copyright (C) 1998 by Frasca International, Inc. + * + * Derived from c/src/lib/libbsp/m68k/gen360/console/console.c written by: + * W. Eric Norum + * Saskatchewan Accelerator Laboratory + * University of Saskatchewan + * Saskatoon, Saskatchewan, CANADA + * eric@skatter.usask.ca + * + * COPYRIGHT (c) 1989-1998. + * On-Line Applications Research Corporation (OAR). + * + * Modifications by Darlene Stewart + * and Charles-Antoine Gauthier + * Copyright (c) 1999, National Research Council of Canada + * + * 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 +#include +#include +#include +#include +#include /* for printk */ +#include +#include +#include + + +/* + * SCI port descriptor table. + */ +typedef struct +{ + volatile m5xxSCIRegisters_t *regs; /* hardware registers */ + struct rtems_termios_tty *ttyp; /* termios data for this port */ +} sci_desc; + +static sci_desc sci_descs[] = { + { &imb.qsmcm.sci1, 0 }, /* SCI 1 */ + { &imb.qsmcm.sci2, 0 }, /* SCI 2 */ +}; + +/* + * Number of SCI port initialization calls made so far. Used to avoid + * installing the common interrupt handler more than once. + */ +int init_calls = 0; + +/* + * Default configuration. + */ +static struct termios default_termios = { + 0, /* input mode flags */ + 0, /* output mode flags */ + 0, /* local mode flags */ + 0, /* line discipline */ + { 0 }, /* control characters */ + CS8 | CREAD | CLOCAL | B9600, /* control mode flags */ +}; + + +extern uint32_t bsp_clock_speed; + +/* + * Termios callback functions + */ + +int +m5xx_uart_firstOpen( + int major, + int minor, + void *arg +) +{ + rtems_libio_open_close_args_t *args = arg; + sci_desc* desc = &sci_descs[minor]; + struct rtems_termios_tty *tty = args->iop->data1; + + desc->ttyp = tty; /* connect tty */ + if ( tty->device.outputUsesInterrupts == TERMIOS_IRQ_DRIVEN) + desc->regs->sccr1 |= QSMCM_SCI_RIE; /* enable rx interrupt */ + + return RTEMS_SUCCESSFUL; +} + +int +m5xx_uart_lastClose( + int major, + int minor, + void* arg +) +{ + sci_desc* desc = &sci_descs[minor]; + + desc->regs->sccr1 &= ~(QSMCM_SCI_RIE | QSMCM_SCI_TIE); /* disable all */ + desc->ttyp = NULL; /* disconnect tty */ + + return RTEMS_SUCCESSFUL; +} + +int +m5xx_uart_pollRead( + int minor +) +{ + volatile m5xxSCIRegisters_t *regs = sci_descs[minor].regs; + int c = -1; + + if ( regs ) { + while ( (regs->scsr & QSMCM_SCI_RDRF) == 0 ) + ; + c = regs->scdr; + } + + return c; +} + +ssize_t m5xx_uart_write( + int minor, + const char *buf, + size_t len +) +{ + if (len > 0) { + volatile m5xxSCIRegisters_t *regs = sci_descs[minor].regs; + + regs->scdr = *buf; /* start transmission */ + regs->sccr1 |= QSMCM_SCI_TIE; /* enable interrupt */ + } + + return 0; +} + +ssize_t m5xx_uart_pollWrite( + int minor, + const char *buf, + size_t len +) +{ + volatile m5xxSCIRegisters_t *regs = sci_descs[minor].regs; + size_t retval = len; + + while ( len-- ) { + while ( (regs->scsr & QSMCM_SCI_TDRE) == 0 ) + ; + regs->scdr = *buf++; + } + + return retval; +} + +int +m5xx_uart_setAttributes( + int minor, + const struct termios *t +) +{ + uint16_t sccr0 = sci_descs[minor].regs->sccr0; + uint16_t sccr1 = sci_descs[minor].regs->sccr1; + int baud; + + /* + * Check that port number is valid + */ + if ( (minor < SCI1_MINOR) || (minor > SCI2_MINOR) ) + return RTEMS_INVALID_NUMBER; + + /* Baud rate */ + baud = rtems_termios_baud_to_number( t->c_ospeed ); + if (baud > 0) { + sccr0 &= ~QSMCM_SCI_BAUD(-1); + sccr0 |= QSMCM_SCI_BAUD((bsp_clock_speed + (16 * baud)) / (32 * baud)); + } + + /* Number of data bits -- not available with MPC5xx SCI */ + switch ( t->c_cflag & CSIZE ) { + case CS5: break; + case CS6: break; + case CS7: break; + case CS8: break; + } + + /* Stop bits -- not easily available with MPC5xx SCI */ + if ( t->c_cflag & CSTOPB ) { + /* Two stop bits */ + } else { + /* One stop bit */ + } + + /* Parity */ + if ( t->c_cflag & PARENB ) + sccr1 |= QSMCM_SCI_PE; + else + sccr1 &= ~QSMCM_SCI_PE; + + if ( t->c_cflag & PARODD ) + sccr1 |= QSMCM_SCI_PT; + else + sccr1 &= ~QSMCM_SCI_PT; + + /* Transmitter and receiver enable */ + sccr1 |= QSMCM_SCI_TE; + if ( t->c_cflag & CREAD ) + sccr1 |= QSMCM_SCI_RE; + else + sccr1 &= ~QSMCM_SCI_RE; + + /* Write hardware registers */ + sci_descs[minor].regs->sccr0 = sccr0; + sci_descs[minor].regs->sccr1 = sccr1; + + return RTEMS_SUCCESSFUL; +} + + +/* + * Interrupt handling. + */ +static void +m5xx_sci_interrupt_handler (rtems_irq_hdl_param unused) +{ + int minor; + + for ( minor = 0; minor < NUM_PORTS; minor++ ) { + sci_desc *desc = &sci_descs[minor]; + int sccr1 = desc->regs->sccr1; + int scsr = desc->regs->scsr; + + /* + * Character received? + */ + if ((sccr1 & QSMCM_SCI_RIE) && (scsr & QSMCM_SCI_RDRF)) { + char c = desc->regs->scdr; + rtems_termios_enqueue_raw_characters(desc->ttyp, &c, 1); + } + /* + * Transmitter empty? + */ + if ((sccr1 & QSMCM_SCI_TIE) && (scsr & QSMCM_SCI_TDRE)) { + desc->regs->sccr1 &= ~QSMCM_SCI_TIE; + rtems_termios_dequeue_characters (desc->ttyp, 1); + } + } +} + +static void m5xx_sci_nop(const rtems_irq_connect_data* ptr) +{ +} + +static int m5xx_sci_isOn(const rtems_irq_connect_data* ptr) +{ + return 1; +} + +/* + * Basic initialization. + */ + +void +m5xx_uart_initialize (int minor) +{ + /* + * Check that minor number is valid. + */ + if ( (minor < SCI1_MINOR) || (minor > SCI2_MINOR) ) + return; + + /* + * Configure and enable receiver and transmitter. + */ + m5xx_uart_setAttributes(minor, &default_termios); + + /* + * Connect interrupt if not yet done. + */ + if ( init_calls++ == 0 ) { + rtems_irq_connect_data irq_data; + + irq_data.name = CPU_IRQ_SCI; + irq_data.hdl = m5xx_sci_interrupt_handler; + irq_data.on = m5xx_sci_nop; /* can't enable both channels here */ + irq_data.off = m5xx_sci_nop; /* can't disable both channels here */ + irq_data.isOn = m5xx_sci_isOn; + + if (!CPU_install_rtems_irq_handler (&irq_data)) { + printk("Unable to connect SCI Irq handler\n"); + rtems_fatal_error_occurred(1); + } + + imb.qsmcm.qdsci_il = /* set interrupt level in port */ + QSMCM_ILDSCI(CPU_irq_level_from_symbolic_name(CPU_IRQ_SCI)); + } +} diff --git a/bsps/powerpc/ss555/dev/timer.c b/bsps/powerpc/ss555/dev/timer.c new file mode 100644 index 0000000000..65deae961e --- /dev/null +++ b/bsps/powerpc/ss555/dev/timer.c @@ -0,0 +1,104 @@ +/** + * @file + * @brief Timer Driver for the PowerPC MPC5xx. + * + * This file manages the interval timer on the PowerPC MPC5xx. + * @noe This is not the PIT, but rather the RTEMS interval timer. + * We shall use the bottom 32 bits of the timebase register, + */ + +/* + * MPC5xx port sponsored by Defence Research and Development Canada - Suffield + * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) + * + * Derived from c/src/lib/libcpu/powerpc/mpc8xx/timer/timer.c: + * + * Author: Jay Monkman (jmonkman@frasca.com) + * Copywright (C) 1998 by Frasca International, Inc. + * + * Derived from c/src/lib/libcpu/ppc/ppc403/timer/timer.c: + * + * Author: Andrew Bray + * + * COPYRIGHT (c) 1995 by i-cubed ltd. + * + * 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 i-cubed limited not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * i-cubed limited makes no representations about the suitability + * of this software for any purpose. + * + * Derived from c/src/lib/libcpu/hppa1_1/timer/timer.c: + * + * COPYRIGHT (c) 1989-2007. + * 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 +#include +#include + +static volatile uint32_t Timer_starting; +static bool benchmark_timer_find_average_overhead; + +extern uint32_t bsp_timer_least_valid; +extern uint32_t bsp_timer_average_overhead; + +/* + * This is so small that this code will be reproduced where needed. + */ +static inline uint32_t get_itimer(void) +{ + uint32_t ret; + + __asm__ volatile ("mftb %0" : "=r" ((ret))); /* TBLO */ + + return ret; +} + +void benchmark_timer_initialize(void) +{ + /* set interrupt level and enable timebase. This should never */ + /* generate an interrupt however. */ + usiu.tbscrk = USIU_UNLOCK_KEY; + usiu.tbscr |= USIU_TBSCR_TBIRQ(4) /* interrupt priority level */ + | USIU_TBSCR_TBF /* freeze timebase during debug */ + | USIU_TBSCR_TBE; /* enable timebase */ + usiu.tbscrk = 0; + + Timer_starting = get_itimer(); +} + +benchmark_timer_t benchmark_timer_read(void) +{ + uint32_t clicks; + uint32_t total; + + clicks = get_itimer(); + + total = clicks - Timer_starting; + + if ( benchmark_timer_find_average_overhead == 1 ) + return total; /* in XXX microsecond units */ + + else { + if ( total < bsp_timer_least_valid ) { + return 0; /* below timer resolution */ + } + return (total - bsp_timer_average_overhead); + } +} + +void benchmark_timer_disable_subtracting_average_overhead(bool find_flag) +{ + benchmark_timer_find_average_overhead = find_flag; +} diff --git a/bsps/powerpc/ss555/start/irq.c b/bsps/powerpc/ss555/start/irq.c new file mode 100644 index 0000000000..8bb3cd240e --- /dev/null +++ b/bsps/powerpc/ss555/start/irq.c @@ -0,0 +1,463 @@ +/* + * This file contains the implementation of the function described in irq.h + */ + +/* + * MPC5xx port sponsored by Defence Research and Development Canada - Suffield + * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) + * + * Derived from libbsp/powerpc/mbx8xx/irq/irq.c: + * + * 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 +#include +#include +#include +#include +#include + +/* + * Convert an rtems_irq_number constant to an interrupt level + * suitable for programming into an I/O device's interrupt level field. + */ +int CPU_irq_level_from_symbolic_name(const rtems_irq_number name) +{ + if (CPU_USIU_EXT_IRQ_0 <= name && name <= CPU_USIU_INT_IRQ_7) + return (name - CPU_USIU_EXT_IRQ_0) / 2; + + if (CPU_UIMB_IRQ_8 <= name && name <= CPU_UIMB_IRQ_31) + return 8 + (name - CPU_UIMB_IRQ_8); + + return 31; /* reasonable default */ +} + +/* + * default handler connected on each irq after bsp initialization + */ +static rtems_irq_connect_data default_rtems_entry; + +/* + * location used to store initial tables used for interrupt + * management. + */ +static rtems_irq_global_settings* internal_config; +static rtems_irq_connect_data* rtems_hdl_tbl; + +/* + * Check if symbolic IRQ name is an USIU IRQ + */ +static inline int is_usiu_irq(const rtems_irq_number irqLine) +{ + return (((int) irqLine <= CPU_USIU_IRQ_MAX_OFFSET) && + ((int) irqLine >= CPU_USIU_IRQ_MIN_OFFSET) + ); +} + +/* + * Check if symbolic IRQ name is an UIMB IRQ + */ +static inline int is_uimb_irq(const rtems_irq_number irqLine) +{ + return (((int) irqLine <= CPU_UIMB_IRQ_MAX_OFFSET) && + ((int) irqLine >= CPU_UIMB_IRQ_MIN_OFFSET) + ); +} + +/* + * Check if symbolic IRQ name is a Processor IRQ + */ +static inline int is_proc_irq(const rtems_irq_number irqLine) +{ + return (((int) irqLine <= CPU_PROC_IRQ_MAX_OFFSET) && + ((int) irqLine >= CPU_PROC_IRQ_MIN_OFFSET) + ); +} + + +/* + * Masks used to mask off the interrupts. For exmaple, for ILVL2, the + * mask is used to mask off interrupts ILVL2, IRQ3, ILVL3, ... IRQ7 + * and ILVL7. + * + */ +const static unsigned int USIU_IvectMask[CPU_USIU_IRQ_COUNT] = +{ + 0, /* external IRQ 0 */ + 0xFFFFFFFF << 31, /* internal level 0 */ + 0xFFFFFFFF << 30, /* external IRQ 1 */ + 0xFFFFFFFF << 29, /* internal level 1 */ + 0xFFFFFFFF << 28, /* external IRQ 2 */ + 0xFFFFFFFF << 27, /* internal level 2 */ + 0xFFFFFFFF << 26, /* external IRQ 3 */ + 0xFFFFFFFF << 25, /* internal level 3 */ + 0xFFFFFFFF << 24, /* external IRQ 4 */ + 0xFFFFFFFF << 23, /* internal level 4 */ + 0xFFFFFFFF << 22, /* external IRQ 5 */ + 0xFFFFFFFF << 21, /* internal level 5 */ + 0xFFFFFFFF << 20, /* external IRQ 6 */ + 0xFFFFFFFF << 19, /* internal level 6 */ + 0xFFFFFFFF << 18, /* external IRQ 7 */ + 0xFFFFFFFF << 17 /* internal level 7 */ +}; + + +/* + * ------------------------ 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_USIU_IvectMask_from_prio (void) +{ + /* + * In theory this is feasible. No time to code it yet. See i386/shared/irq.c + * for an example based on 8259 controller mask. The actual masks defined + * correspond to the priorities defined for the USIU in irq_init.c. + */ +} + +/* + * This function check that the value given for the irq line + * is valid. + */ +static int isValidInterrupt(int irq) +{ + if ( (irq < CPU_MIN_OFFSET) || (irq > CPU_MAX_OFFSET) + || (irq == CPU_UIMB_INTERRUPT) ) + return 0; + return 1; +} + +static int CPU_irq_enable_at_uimb(const rtems_irq_number irqLine) +{ + if (!is_uimb_irq(irqLine)) + return 1; + return 0; +} + +static int CPU_irq_disable_at_uimb(const rtems_irq_number irqLine) +{ + if (!is_uimb_irq(irqLine)) + return 1; + return 0; +} + +static int CPU_irq_enable_at_usiu(const rtems_irq_number irqLine) +{ + int usiu_irq_index; + + if (!is_usiu_irq(irqLine)) + return 1; + + usiu_irq_index = ((int) (irqLine) - CPU_USIU_IRQ_MIN_OFFSET); + ppc_cached_irq_mask |= (1 << (31-usiu_irq_index)); + usiu.simask = ppc_cached_irq_mask; + + return 0; +} + +static int CPU_irq_disable_at_usiu(const rtems_irq_number irqLine) +{ + int usiu_irq_index; + + if (!is_usiu_irq(irqLine)) + return 1; + + usiu_irq_index = ((int) (irqLine) - CPU_USIU_IRQ_MIN_OFFSET); + ppc_cached_irq_mask &= ~(1 << (31-usiu_irq_index)); + usiu.simask = ppc_cached_irq_mask; + + return 0; +} + +/* + * --------------- RTEMS Single Irq Handler Mngt Routines ---------------- + */ + +int CPU_install_rtems_irq_handler (const rtems_irq_connect_data* irq) +{ + rtems_interrupt_level level; + + if (!isValidInterrupt(irq->name)) { + return 0; + } + /* + * Check if default handler is actually connected. If not issue an error. + * You must first get the current handler via CPU_get_current_idt_entry + * and then disconnect it using CPU_delete_idt_entry. + * RATIONALE : to always have the same transition by forcing the user + * to get the previous handler before accepting to disconnect. + */ + if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) { + return 0; + } + + rtems_interrupt_disable(level); + + /* + * store the data provided by user + */ + rtems_hdl_tbl[irq->name] = *irq; + + if (is_uimb_irq(irq->name)) { + /* + * Enable interrupt at UIMB level + */ + CPU_irq_enable_at_uimb (irq->name); + } + + if (is_usiu_irq(irq->name)) { + /* + * Enable interrupt at USIU level + */ + CPU_irq_enable_at_usiu (irq->name); + } + + if (is_proc_irq(irq->name)) { + /* + * Should Enable exception at processor level but not needed. Will restore + * EE flags at the end of the routine anyway. + */ + } + /* + * Enable interrupt on device + */ + if (irq->on) + irq->on(irq); + + rtems_interrupt_enable(level); + + return 1; +} + + +int CPU_get_current_rtems_irq_handler (rtems_irq_connect_data* irq) +{ + if (!isValidInterrupt(irq->name)) { + return 0; + } + *irq = rtems_hdl_tbl[irq->name]; + return 1; +} + +int CPU_remove_rtems_irq_handler (const rtems_irq_connect_data* irq) +{ + rtems_interrupt_level level; + + if (!isValidInterrupt(irq->name)) { + return 0; + } + /* + * Check if default handler is actually connected. If not issue an error. + * You must first get the current handler via CPU_get_current_idt_entry + * and then disconnect it using CPU_delete_idt_entry. + * RATIONALE : to always have the same transition by forcing the user + * to get the previous handler before accepting to disconnect. + */ + if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) { + return 0; + } + rtems_interrupt_disable(level); + + /* + * Disable interrupt on device + */ + if (irq->off) + irq->off(irq); + + if (is_uimb_irq(irq->name)) { + /* + * disable interrupt at UIMB level + */ + CPU_irq_disable_at_uimb (irq->name); + } + if (is_usiu_irq(irq->name)) { + /* + * disable interrupt at USIU level + */ + CPU_irq_disable_at_usiu (irq->name); + } + if (is_proc_irq(irq->name)) { + /* + * disable exception at processor level + */ + } + + /* + * restore the default irq value + */ + rtems_hdl_tbl[irq->name] = default_rtems_entry; + + rtems_interrupt_enable(level); + + return 1; +} + +/* + * ---------------- RTEMS Global Irq Handler Mngt Routines ---------------- + */ + +int CPU_rtems_irq_mngt_set (rtems_irq_global_settings* config) +{ + int i; + rtems_interrupt_level level; + + /* + * Store various code accelerators + */ + internal_config = config; + default_rtems_entry = config->defaultEntry; + rtems_hdl_tbl = config->irqHdlTbl; + + rtems_interrupt_disable(level); + + /* + * Start with UIMB IRQ + */ + for (i = CPU_UIMB_IRQ_MIN_OFFSET; i <= CPU_UIMB_IRQ_MAX_OFFSET ; i++) { + if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) { + CPU_irq_enable_at_uimb (i); + if (rtems_hdl_tbl[i].on) + rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); + } + else { + if (rtems_hdl_tbl[i].off) + rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); + CPU_irq_disable_at_uimb (i); + } + } + + /* + * Continue with USIU IRQ + * Set up internal tables used by rtems interrupt prologue + */ + compute_USIU_IvectMask_from_prio (); + + for (i = CPU_USIU_IRQ_MIN_OFFSET; i <= CPU_USIU_IRQ_MAX_OFFSET ; i++) { + if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) { + CPU_irq_enable_at_usiu (i); + if (rtems_hdl_tbl[i].on) + rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); + } + else { + if (rtems_hdl_tbl[i].off) + rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); + CPU_irq_disable_at_usiu (i); + } + } + + /* + * Enable all UIMB interrupt lines, then enable at USIU. + */ + imb.uimb.umcr |= UIMB_UMCR_IRQMUX(3); + CPU_irq_enable_at_usiu (CPU_UIMB_INTERRUPT); + + /* + * finish with Processor exceptions handled like IRQ + */ + for (i = CPU_PROC_IRQ_MIN_OFFSET; i <= CPU_PROC_IRQ_MAX_OFFSET; i++) { + if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) { + if (rtems_hdl_tbl[i].on) + rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); + } + else { + if (rtems_hdl_tbl[i].off) + rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); + } + } + rtems_interrupt_enable(level); + return 1; +} + +int CPU_rtems_irq_mngt_get(rtems_irq_global_settings** config) +{ + *config = internal_config; + return 0; +} + + +/* + * High level IRQ handler called from shared_raw_irq_code_entry + */ +void C_dispatch_irq_handler (MPC5XX_Interrupt_frame *frame, unsigned int excNum) +{ + register unsigned int irq; + register unsigned uimbIntr; /* boolean */ + register unsigned oldMask; /* old siu pic masks */ + register unsigned msr; + register unsigned new_msr; + + /* + * Handle decrementer interrupt + */ + if (excNum == ASM_DEC_VECTOR) { + _CPU_MSR_GET(msr); + new_msr = msr | MSR_EE; + _CPU_MSR_SET(new_msr); + + rtems_hdl_tbl[CPU_DECREMENTER].hdl(rtems_hdl_tbl[CPU_DECREMENTER].handle); + + _CPU_MSR_SET(msr); + return; + } + + /* + * Handle external interrupt generated by USIU on PPC core + */ + while ((ppc_cached_irq_mask & usiu.sipend) != 0) { + irq = (usiu.sivec >> 26); + uimbIntr = (irq == CPU_UIMB_INTERRUPT); + /* + * Disable the interrupt of the same and lower priority. + */ + oldMask = ppc_cached_irq_mask; + ppc_cached_irq_mask = oldMask & USIU_IvectMask[irq]; + usiu.simask = ppc_cached_irq_mask; + /* + * Acknowledge current interrupt. This has no effect on internal level + * interrupts. + */ + usiu.sipend = (1 << (31 - irq)); + + if (uimbIntr) { + /* + * Look at the bits set in the UIMB interrupt-pending register. The + * highest-order set bit indicates the handler we will run. + * + * Unfortunately, we can't easily mask individual UIMB interrupts + * unless they use USIU levels 0 to 6, so we must mask all low-level + * (level > 7) UIMB interrupts while we service any interrupt. + */ + int uipend = imb.uimb.uipend << 8; + + if (uipend == 0) { /* spurious interrupt? use last vector */ + irq = CPU_UIMB_IRQ_MAX_OFFSET; + } + else { + irq = CPU_UIMB_IRQ_MIN_OFFSET; + for ( ; (uipend & 0x8000000) == 0; uipend <<= 1) { + irq++; + } + } + } + _CPU_MSR_GET(msr); + new_msr = msr | MSR_EE; + _CPU_MSR_SET(new_msr); + + rtems_hdl_tbl[irq].hdl(rtems_hdl_tbl[irq].handle); + + _CPU_MSR_SET(msr); + + ppc_cached_irq_mask = oldMask; + usiu.simask = ppc_cached_irq_mask; + } +} diff --git a/bsps/powerpc/ss555/start/irq_asm.S b/bsps/powerpc/ss555/start/irq_asm.S new file mode 100644 index 0000000000..52911c48e3 --- /dev/null +++ b/bsps/powerpc/ss555/start/irq_asm.S @@ -0,0 +1,312 @@ +/* + * irq_asm.S + * + * This file contains the assembly code for the PowerPC + * IRQ veneers for RTEMS. + * + * 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. + * + * + * MPC5xx port sponsored by Defence Research and Development Canada - Suffield + * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) + * + * Derived from libbsp/powerpc/mbx8xx/irq/irq_asm.S: + * + * Modified to support the MCP750. + * Modifications Copyright (C) 1999 Eric Valette. valette@crf.canon.fr + * + * Till Straumann , 2003/7: + * - store isr nesting level in _ISR_Nest_level rather than + * SPRG0 - RTEMS relies on that variable. + */ + +#include +#include +#include +#include +#include + + +#define SYNC \ + sync; \ + isync + +/* + * Common handler for interrupt exceptions. + * + * The function CPU_rtems_irq_mng_init() initializes the decrementer and + * external interrupt entries in the exception handler table with pointers + * to this routine, which saves the remainder of the interrupted code's + * state, then calls C_dispatch_irq_handler(). + * + * On entry, R1 points to a new exception stack frame in which R3, R4, and + * LR have been saved. R4 holds the exception number. + */ + PUBLIC_VAR(C_dispatch_irq_handler) + + PUBLIC_VAR(dispatch_irq_handler) +SYM (dispatch_irq_handler): + /* + * Save SRR0/SRR1 As soon As possible as it is the minimal needed + * to re-enable exception processing. + * + * Note that R2 should never change (it's the EABI pointer to + * .sdata2), but we save it just in case. + */ + stw r0, GPR0_OFFSET(r1) + stw r2, GPR2_OFFSET(r1) + + mfsrr0 r0 + mfsrr1 r3 + + stw r0, SRR0_FRAME_OFFSET(r1) + stw r3, SRR1_FRAME_OFFSET(r1) + + /* + * Enable exception recovery. Also enable FP so that FP context + * can be saved and restored (using FP instructions). + */ + mfmsr r3 + ori r3, r3, MSR_RI | MSR_FP + mtmsr r3 + SYNC + + /* + * Push C scratch registers on the current stack. It may actually be + * the thread stack or the interrupt stack. Anyway we have to make + * it in order to be able to call C/C++ functions. Depending on the + * nesting interrupt level, we will switch to the right stack later. + */ + stw r5, GPR5_OFFSET(r1) + stw r6, GPR6_OFFSET(r1) + stw r7, GPR7_OFFSET(r1) + stw r8, GPR8_OFFSET(r1) + stw r9, GPR9_OFFSET(r1) + stw r10, GPR10_OFFSET(r1) + stw r11, GPR11_OFFSET(r1) + stw r12, GPR12_OFFSET(r1) + stw r13, GPR13_OFFSET(r1) + + mfcr r5 + mfctr r6 + mfxer r7 + + stw r5, EXC_CR_OFFSET(r1) + stw r6, EXC_CTR_OFFSET(r1) + stw r7, EXC_XER_OFFSET(r1) + + /* + * Add some non volatile registers to store information that will be + * used when returning from C handler. + */ + stw r14, GPR14_OFFSET(r1) + stw r15, GPR15_OFFSET(r1) + + /* + * Save current stack pointer location in R14. + */ + addi r14, r1, 0 + + /* + * store part of THREAD_DISPATCH_DISABLE_LEVEL address in R15 + */ + addis r15, 0, THREAD_DISPATCH_DISABLE_LEVEL@ha + + /* + * Retrieve current nesting level from _ISR_Nest_level + */ + lis r7, ISR_NEST_LEVEL@ha + lwz r3, ISR_NEST_LEVEL@l(r7) + + /* + * Check if stack switch is necessary + */ + cmpwi r3, 0 + bne nested + + mfspr r1, SPRG1 /* switch to interrupt stack */ +nested: + + /* + * Start Incrementing nesting level in R3 + */ + addi r3, r3, 1 + + /* + * Start Incrementing THREAD_DISPATCH_DISABLE_LEVEL R4 = THREAD_DISPATCH_DISABLE_LEVEL + */ + lwz r6, THREAD_DISPATCH_DISABLE_LEVEL@l(r15) + + /* store new nesting level in _ISR_Nest_level */ + stw r3, ISR_NEST_LEVEL@l(r7) + + addi r6, r6, 1 + + /* + * store new THREAD_DISPATCH_DISABLE_LEVEL value + */ + stw r6, THREAD_DISPATCH_DISABLE_LEVEL@l(r15) + + /* + * We are now running on the interrupt stack. External and decrementer + * exceptions are still disabled. I see no purpose trying to optimize + * further assembler code. + */ + + /* + * Call C exception handler for decrementer or external interrupt. + * Pass frame along just in case.. + * + * C_dispatch_irq_handler(cpu_interrupt_frame* r3, vector r4) + */ + addi r3, r14, 0x8 + bl C_dispatch_irq_handler + + /* + * start decrementing nesting level. Note : do not test result against 0 + * value as an easy exit condition because if interrupt nesting level > 1 + * then THREAD_DISPATCH_DISABLE_LEVEL > 1 + */ + lis r7, ISR_NEST_LEVEL@ha + lwz r4, ISR_NEST_LEVEL@l(r7) + + /* + * start decrementing THREAD_DISPATCH_DISABLE_LEVEL + */ + lwz r3,THREAD_DISPATCH_DISABLE_LEVEL@l(r15) + + addi r4, r4, -1 /* Continue decrementing nesting level */ + addi r3, r3, -1 /* Continue decrementing THREAD_DISPATCH_DISABLE_LEVEL */ + + stw r4, ISR_NEST_LEVEL@l(r7) /* End decrementing nesting level */ + stw r3,THREAD_DISPATCH_DISABLE_LEVEL@l(r15) /* End decrementing THREAD_DISPATCH_DISABLE_LEVEL */ + + cmpwi r3, 0 + + /* + * switch back to original stack (done here just optimize registers + * contention. Could have been done before...) + */ + addi r1, r14, 0 + bne easy_exit /* if (THREAD_DISPATCH_DISABLE_LEVEL != 0) goto easy_exit */ + + /* + * Here we are running again on the thread system stack. + * We have interrupt nesting level = THREAD_DISPATCH_DISABLE_LEVEL = 0. + * Interrupt are still disabled. Time to check if scheduler request to + * do something with the current thread... + */ + addis r4, 0, DISPATCH_NEEDED@ha + lbz r5, DISPATCH_NEEDED@l(r4) + cmpwi r5, 0 + beq easy_exit + + /* + * going to call _Thread_Dispatch + * Push a complete exception like frame... + */ + stmw r16, GPR16_OFFSET(r1) + addi r3, r1, 0x8 + + /* + * compute SP at exception entry + */ + addi r4, r1, EXCEPTION_FRAME_END + + /* + * store it at the right place + */ + stw r4, GPR1_OFFSET(r1) + + /* + * Call High Level signal handling code + */ + bl _Thread_Dispatch + + /* + * start restoring exception like frame + */ + lwz r31, EXC_CTR_OFFSET(r1) + lwz r30, EXC_XER_OFFSET(r1) + lwz r29, EXC_CR_OFFSET(r1) + lwz r28, EXC_LR_OFFSET(r1) + + mtctr r31 + mtxer r30 + mtcr r29 + mtlr r28 + + lmw r4, GPR4_OFFSET(r1) + lwz r2, GPR2_OFFSET(r1) + lwz r0, GPR0_OFFSET(r1) + + /* + * Make path non recoverable... + */ + mtspr nri, r0 + SYNC + + /* + * Restore rfi related settings + */ + + lwz r3, SRR1_FRAME_OFFSET(r1) + mtsrr1 r3 + lwz r3, SRR0_FRAME_OFFSET(r1) + mtsrr0 r3 + + lwz r3, GPR3_OFFSET(r1) + addi r1,r1, EXCEPTION_FRAME_END + SYNC + rfi + + +easy_exit: + /* + * start restoring interrupt frame + */ + lwz r3, EXC_CTR_OFFSET(r1) + lwz r4, EXC_XER_OFFSET(r1) + lwz r5, EXC_CR_OFFSET(r1) + lwz r6, EXC_LR_OFFSET(r1) + + mtctr r3 + mtxer r4 + mtcr r5 + mtlr r6 + + lwz r15, GPR15_OFFSET(r1) + lwz r14, GPR14_OFFSET(r1) + lwz r13, GPR13_OFFSET(r1) + lwz r12, GPR12_OFFSET(r1) + lwz r11, GPR11_OFFSET(r1) + lwz r10, GPR10_OFFSET(r1) + lwz r9, GPR9_OFFSET(r1) + lwz r8, GPR8_OFFSET(r1) + lwz r7, GPR7_OFFSET(r1) + lwz r6, GPR6_OFFSET(r1) + lwz r5, GPR5_OFFSET(r1) + + /* + * Disable nested exception processing. + */ + mtspr nri, r0 + SYNC + + /* + * Restore rfi related settings + */ + lwz r4, SRR1_FRAME_OFFSET(r1) + lwz r3, SRR0_FRAME_OFFSET(r1) + lwz r2, GPR2_OFFSET(r1) + lwz r0, GPR0_OFFSET(r1) + + mtsrr1 r4 + mtsrr0 r3 + lwz r4, GPR4_OFFSET(r1) + lwz r3, GPR3_OFFSET(r1) + addi r1,r1, EXCEPTION_FRAME_END + SYNC + rfi diff --git a/bsps/powerpc/ss555/start/irq_init.c b/bsps/powerpc/ss555/start/irq_init.c new file mode 100644 index 0000000000..351edb4ffe --- /dev/null +++ b/bsps/powerpc/ss555/start/irq_init.c @@ -0,0 +1,165 @@ +/* + * irq_init.c + * + * This file contains the implementation of rtems initialization + * related to interrupt handling. + */ + +/* + * MPC5xx port sponsored by Defence Research and Development Canada - Suffield + * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) + * + * Derived from libbsp/powerpc/mbx8xx/irq/irq_init.c: + * + * CopyRight (C) 2001 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 +#include +#include +#include +#include + +extern rtems_exception_handler_t dispatch_irq_handler; + +volatile unsigned int ppc_cached_irq_mask; + +/* + * default methods + */ +static void nop_hdl(rtems_irq_hdl_param ignored) +{ +} + +static void nop_irq_enable(const struct __rtems_irq_connect_data__*ignored) +{ +} + +static void nop_raw_enable( + const struct __rtems_raw_except_connect_data__*ignored +) +{ +} + +static int irq_is_connected(const struct __rtems_irq_connect_data__*ignored) +{ + return 0; +} + +static int raw_is_connected(const struct __rtems_raw_except_connect_data__*ignored) +{ + return 0; +} + +static rtems_irq_connect_data rtemsIrq[CPU_IRQ_COUNT]; +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 */ +}; + +static rtems_irq_prio irqPrioTable[CPU_IRQ_COUNT]={ + /* + * actual priorities for interrupt : + * 0 means that only current interrupt is masked + * 255 means all other interrupts are masked + */ + /* + * USIU interrupts. + */ + 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1, 0,0, + /* + * UIMB Interrupts + * + * Note that the first 8 UIMB interrupts overlap the 8 external USIU + * interrupts. + */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* + * Processor exceptions handled as interrupts + */ + 0 +}; + +static void CPU_USIU_irq_init(void) +{ + /* + * In theory we should initialize two registers at least : SIMASK and + * SIEL. SIMASK is reset at 0 value meaning no interrupts. If someone + * find a reasonnable value for SIEL, and the need to change it, please + * feel free to add it here. + */ + ppc_cached_irq_mask = 0; + usiu.simask = ppc_cached_irq_mask; + usiu.sipend = 0xffff0000; + usiu.siel = usiu.siel; +} + +/* + * Initialize UIMB interrupt management + */ +static void CPU_UIMB_irq_init(void) +{ +} + +void CPU_rtems_irq_mng_init(unsigned cpuId) +{ + rtems_raw_except_connect_data vectorDesc; + int i; + + CPU_USIU_irq_init(); + CPU_UIMB_irq_init(); + /* + * Initialize Rtems management interrupt table + */ + /* + * re-init the rtemsIrq table + */ + for (i = 0; i < CPU_IRQ_COUNT; i++) { + rtemsIrq[i] = defaultIrq; + rtemsIrq[i].name = i; + } + /* + * Init initial Interrupt management config + */ + initial_config.irqNb = CPU_IRQ_COUNT; + initial_config.defaultEntry = defaultIrq; + initial_config.irqHdlTbl = rtemsIrq; + initial_config.irqBase = CPU_ASM_IRQ_VECTOR_BASE; + initial_config.irqPrioTbl = irqPrioTable; + + if (!CPU_rtems_irq_mngt_set(&initial_config)) { + /* + * put something here that will show the failure... + */ + rtems_panic("Unable to initialize RTEMS interrupt Management\n"); + } + + /* + * We must connect the raw irq handler for the two + * expected interrupt sources : decrementer and external interrupts. + */ + vectorDesc.exceptIndex = ASM_DEC_VECTOR; + vectorDesc.hdl.vector = ASM_DEC_VECTOR; + vectorDesc.hdl.raw_hdl = dispatch_irq_handler; + vectorDesc.on = nop_raw_enable; + vectorDesc.off = nop_raw_enable; + vectorDesc.isOn = raw_is_connected; + if (!mpc5xx_set_exception (&vectorDesc)) { + rtems_panic("Unable to initialize RTEMS decrementer raw exception\n"); + } + vectorDesc.exceptIndex = ASM_EXT_VECTOR; + vectorDesc.hdl.vector = ASM_EXT_VECTOR; + if (!mpc5xx_set_exception (&vectorDesc)) { + rtems_panic("Unable to initialize RTEMS external raw exception\n"); + } +} diff --git a/bsps/powerpc/ss555/start/raw_exception.c b/bsps/powerpc/ss555/start/raw_exception.c new file mode 100644 index 0000000000..6cb35be650 --- /dev/null +++ b/bsps/powerpc/ss555/start/raw_exception.c @@ -0,0 +1,190 @@ +/* + * raw_exception.c - This file contains implementation of C functions to + * Instantiate mpc5xx primary exception entries. + * More detailled information can be found on the Motorola + * site and more precisely in the following book: + * + * MPC555/MPC556 User's Manual + * Motorola REF : MPC555UM/D Rev. 3, 2000 October 15 + * + * + * MPC5xx port sponsored by Defence Research and Development Canada - Suffield + * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) + * + * Derived from libcpu/powerpc/mpc8xx/exceptions/raw_exception.c: + * + * Copyright (C) 1999 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 +#include +#include +#include +#include /* for printk */ +#include + +static rtems_raw_except_connect_data* raw_except_table; +static rtems_raw_except_connect_data default_raw_except_entry; +static rtems_raw_except_global_settings* local_settings; + +int mpc5xx_vector_is_valid(rtems_vector vector) +{ + switch (current_ppc_cpu) { + case PPC_5XX: + switch(vector) { + case ASM_RESET_VECTOR: + case ASM_MACH_VECTOR: + + case ASM_EXT_VECTOR: + case ASM_ALIGN_VECTOR: + case ASM_PROG_VECTOR: + case ASM_FLOAT_VECTOR: + case ASM_DEC_VECTOR: + + case ASM_SYS_VECTOR: + case ASM_TRACE_VECTOR: + case ASM_FLOATASSIST_VECTOR: + + case ASM_SOFTEMUL_VECTOR: + + case ASM_IPROT_VECTOR: + case ASM_DPROT_VECTOR: + + case ASM_DBREAK_VECTOR: + case ASM_IBREAK_VECTOR: + case ASM_MEBREAK_VECTOR: + case ASM_NMEBREAK_VECTOR: + return 1; + default: + return 0; + } + default: + printk("Please complete libcpu/powerpc/mpc5xx/exceptions/raw_exception.c\n"); + printk("current_ppc_cpu = %x\n", current_ppc_cpu); + return 0; + } +} + +int mpc5xx_set_exception (const rtems_raw_except_connect_data* except) +{ + rtems_interrupt_level level; + + if (!mpc5xx_vector_is_valid(except->exceptIndex)) { + return 0; + } + /* + * Check if default handler is actually connected. If not issue an error. + * You must first get the current handler via mpc5xx_get_current_exception + * and then disconnect it using mpc5xx_delete_exception. + * RATIONALE : to always have the same transition by forcing the user + * to get the previous handler before accepting to disconnect. + */ + if (exception_handler_table[except->exceptIndex] != + default_raw_except_entry.hdl.raw_hdl) { + return 0; + } + + rtems_interrupt_disable(level); + + raw_except_table[except->exceptIndex] = *except; + + exception_handler_table[except->exceptIndex] = except->hdl.raw_hdl; + if (except->on) + except->on(except); + + rtems_interrupt_enable(level); + return 1; +} + +int mpc5xx_get_current_exception (rtems_raw_except_connect_data* except) +{ + if (!mpc5xx_vector_is_valid(except->exceptIndex)){ + return 0; + } + + *except = raw_except_table[except->exceptIndex]; + + return 1; +} + +int mpc5xx_delete_exception (const rtems_raw_except_connect_data* except) +{ + rtems_interrupt_level level; + + if (!mpc5xx_vector_is_valid(except->exceptIndex)){ + return 0; + } + /* + * Check if handler passed is actually connected. If not issue an error. + * You must first get the current handler via mpc5xx_get_current_exception + * and then disconnect it using mpc5xx_delete_exception. + * RATIONALE : to always have the same transition by forcing the user + * to get the previous handler before accepting to disconnect. + */ + if (exception_handler_table[except->exceptIndex] != except->hdl.raw_hdl) { + return 0; + } + + rtems_interrupt_disable(level); + + if (except->off) + except->off(except); + exception_handler_table[except->exceptIndex] = + default_raw_except_entry.hdl.raw_hdl; + + raw_except_table[except->exceptIndex] = default_raw_except_entry; + raw_except_table[except->exceptIndex].exceptIndex = except->exceptIndex; + + rtems_interrupt_enable(level); + + return 1; +} + +/* + * Exception global init. + * + * Install exception handler pointers from the raw exception table into the + * exception handler table. + */ +int mpc5xx_init_exceptions (rtems_raw_except_global_settings* config) +{ + unsigned i; + rtems_interrupt_level level; + + /* + * store various accelerators + */ + raw_except_table = config->rawExceptHdlTbl; + local_settings = config; + default_raw_except_entry = config->defaultRawEntry; + + rtems_interrupt_disable(level); + + for (i = 0; i < NUM_EXCEPTIONS; i++) { + exception_handler_table[i] = raw_except_table[i].hdl.raw_hdl; + + if (raw_except_table[i].hdl.raw_hdl != default_raw_except_entry.hdl.raw_hdl) { + if (raw_except_table[i].on) + raw_except_table[i].on(&raw_except_table[i]); + } + else { + if (raw_except_table[i].off) + raw_except_table[i].off(&raw_except_table[i]); + } + } + rtems_interrupt_enable(level); + + return 1; +} + +int mpc5xx_get_exception_config (rtems_raw_except_global_settings** config) +{ + *config = local_settings; + return 1; +} diff --git a/c/src/lib/libbsp/powerpc/ss555/Makefile.am b/c/src/lib/libbsp/powerpc/ss555/Makefile.am index 6997ece985..0a85ecd539 100644 --- a/c/src/lib/libbsp/powerpc/ss555/Makefile.am +++ b/c/src/lib/libbsp/powerpc/ss555/Makefile.am @@ -37,16 +37,16 @@ libbsp_a_SOURCES += startup/tm27supp.c libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/cache/cache.c libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/exceptions/ppc_exc_print.c +libbsp_a_SOURCES += ../../../../../../bsps/powerpc/ss555/dev/clock.c +libbsp_a_SOURCES += ../../../../../../bsps/powerpc/ss555/dev/console-generic.c +libbsp_a_SOURCES += ../../../../../../bsps/powerpc/ss555/dev/timer.c +libbsp_a_SOURCES += ../../../../../../bsps/powerpc/ss555/start/irq_asm.S +libbsp_a_SOURCES += ../../../../../../bsps/powerpc/ss555/start/irq.c +libbsp_a_SOURCES += ../../../../../../bsps/powerpc/ss555/start/irq_init.c +libbsp_a_SOURCES += ../../../../../../bsps/powerpc/ss555/start/raw_exception.c libbsp_a_SOURCES += ../../../../../../bsps/powerpc/ss555/start/vectors_init.c libbsp_a_SOURCES += ../../../../../../bsps/powerpc/ss555/start/vectors.S -libbsp_a_LIBADD = \ - ../../../libcpu/@RTEMS_CPU@/mpc5xx/clock.rel \ - ../../../libcpu/@RTEMS_CPU@/mpc5xx/console-generic.rel \ - ../../../libcpu/@RTEMS_CPU@/mpc5xx/exceptions.rel \ - ../../../libcpu/@RTEMS_CPU@/mpc5xx/irq.rel \ - ../../../libcpu/@RTEMS_CPU@/mpc5xx/timer.rel - include $(top_srcdir)/../../../../automake/local.am include $(srcdir)/../../../../../../bsps/powerpc/shared/shared.am include $(srcdir)/../../../../../../bsps/powerpc/ss555/headers.am diff --git a/c/src/lib/libbsp/powerpc/ss555/README b/c/src/lib/libbsp/powerpc/ss555/README index d4b020ba19..54d0bfa85a 100644 --- a/c/src/lib/libbsp/powerpc/ss555/README +++ b/c/src/lib/libbsp/powerpc/ss555/README @@ -256,3 +256,27 @@ Sample programs: - The loopback, fileio, unilimited, and pppd tests fail due to memory limitations. - The paranoia program dies on a floating-point assist exception. + +Various non-BSP-dependent support routines. + +timer - Support for the RTEMS timer tick, using the Programmable + Interval Timer (PIT). + +console-generic - Console support via the on-chip dual SCI port in the QSMCM + module. + +exception - Installation and deinstallation of exception handlers, by + manipulation of exception vector table. + +irq - Exception handler for all external and decrementer interrupts. + Generalized interrupt handler which calls specific handlers + via entries in the interrupt connection table. Interrupt + connection table maintenance routines. USIU and UIMB + interrupt masking and level control. + +timer - Support for RTEMS timer tests, using the PowerPC timebase + (TB) registers. + +vectors - Compressed MPC5XX exception vector table, exception handler + prologues, default exception handler. Code to initialize + table with default handlers. diff --git a/c/src/lib/libcpu/powerpc/Makefile.am b/c/src/lib/libcpu/powerpc/Makefile.am index 724dfea710..6d5bc19e5b 100644 --- a/c/src/lib/libcpu/powerpc/Makefile.am +++ b/c/src/lib/libcpu/powerpc/Makefile.am @@ -45,41 +45,6 @@ if ppc405 ## ppc4xx/include endif # ppc405 - -## mpc5xx -EXTRA_DIST += mpc5xx/README -if mpc5xx -# mpc5xx/clock -noinst_PROGRAMS += mpc5xx/clock.rel -mpc5xx_clock_rel_SOURCES = mpc5xx/clock/clock.c -mpc5xx_clock_rel_CPPFLAGS = $(AM_CPPFLAGS) -mpc5xx_clock_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) - -# mpc5xx/console-generic -noinst_PROGRAMS += mpc5xx/console-generic.rel -mpc5xx_console_generic_rel_SOURCES = mpc5xx/console-generic/console-generic.c -mpc5xx_console_generic_rel_CPPFLAGS = $(AM_CPPFLAGS) -mpc5xx_console_generic_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) - -# mpc5xx/exceptions -noinst_PROGRAMS += mpc5xx/exceptions.rel -mpc5xx_exceptions_rel_SOURCES = mpc5xx/exceptions/raw_exception.c -mpc5xx_exceptions_rel_CPPFLAGS = $(AM_CPPFLAGS) -mpc5xx_exceptions_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) - -# mpc5xx/irq -noinst_PROGRAMS += mpc5xx/irq.rel -mpc5xx_irq_rel_SOURCES = mpc5xx/irq/irq.c mpc5xx/irq/irq_init.c mpc5xx/irq/irq_asm.S -mpc5xx_irq_rel_CPPFLAGS = $(AM_CPPFLAGS) -mpc5xx_irq_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) - -# mpc5xx/timer -noinst_PROGRAMS += mpc5xx/timer.rel -mpc5xx_timer_rel_SOURCES = mpc5xx/timer/timer.c -mpc5xx_timer_rel_CPPFLAGS = $(AM_CPPFLAGS) -mpc5xx_timer_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) -endif - if mpc6xx # mpc6xx/mmu diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/README b/c/src/lib/libcpu/powerpc/mpc5xx/README deleted file mode 100644 index 54d6985649..0000000000 --- a/c/src/lib/libcpu/powerpc/mpc5xx/README +++ /dev/null @@ -1,23 +0,0 @@ -Various non-BSP-dependent support routines. - -timer - Support for the RTEMS timer tick, using the Programmable - Interval Timer (PIT). - -console-generic - Console support via the on-chip dual SCI port in the QSMCM - module. - -exception - Installation and deinstallation of exception handlers, by - manipulation of exception vector table. - -irq - Exception handler for all external and decrementer interrupts. - Generalized interrupt handler which calls specific handlers - via entries in the interrupt connection table. Interrupt - connection table maintenance routines. USIU and UIMB - interrupt masking and level control. - -timer - Support for RTEMS timer tests, using the PowerPC timebase - (TB) registers. - -vectors - Compressed MPC5XX exception vector table, exception handler - prologues, default exception handler. Code to initialize - table with default handlers. diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/clock/clock.c b/c/src/lib/libcpu/powerpc/mpc5xx/clock/clock.c deleted file mode 100644 index 9f843cee4f..0000000000 --- a/c/src/lib/libcpu/powerpc/mpc5xx/clock/clock.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * This routine initializes the PIT on the MPC5xx. - * The tick frequency is specified by the BSP. - */ - -/* - * MPC5xx port sponsored by Defence Research and Development Canada - Suffield - * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) - * - * Derived from c/src/lib/libcpu/powerpc/mpc8xx/clock/clock.c: - * - * Author: Jay Monkman (jmonkman@frasca.com) - * Copyright (C) 1998 by Frasca International, Inc. - * - * Derived from c/src/lib/libcpu/ppc/ppc403/clock/clock.c: - * - * Author: Andrew Bray - * - * COPYRIGHT (c) 1995 by i-cubed ltd. - * - * 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 i-cubed limited not be used in - * advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. - * i-cubed limited makes no representations about the suitability - * of this software for any purpose. - * - * Derived from c/src/lib/libcpu/hppa1_1/clock/clock.c: - * - * COPYRIGHT (c) 1989-2007. - * 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 -#include -#include -#include - -#include /* for atexit() */ -#include - -volatile uint32_t Clock_driver_ticks; -extern int BSP_connect_clock_handler(rtems_isr_entry); -extern int BSP_disconnect_clock_handler(void); -extern uint32_t bsp_clicks_per_usec; - -void Clock_exit( void ); - -/* - * ISR Handler - */ -rtems_isr Clock_isr(rtems_vector_number vector) -{ - usiu.piscrk = USIU_UNLOCK_KEY; - usiu.piscr |= USIU_PISCR_PS; /* acknowledge interrupt */ - usiu.piscrk = 0; - - Clock_driver_ticks++; - rtems_clock_tick(); -} - -void clockOn(void* unused) -{ - unsigned desiredLevel; - uint32_t pit_value; - - /* calculate and set modulus */ - pit_value = (rtems_configuration_get_microseconds_per_tick() * - bsp_clicks_per_usec) - 1 ; - - if (pit_value > 0xffff) { /* pit is only 16 bits long */ - rtems_fatal_error_occurred(-1); - } - usiu.sccrk = USIU_UNLOCK_KEY; - usiu.sccr &= ~USIU_SCCR_RTDIV; /* RTC and PIT clock is divided by 4 */ - usiu.sccrk = 0; - - usiu.pitck = USIU_UNLOCK_KEY; - usiu.pitc = pit_value; - usiu.pitck = 0; - - /* set PIT irq level, enable PIT, PIT interrupts */ - /* and clear int. status */ - desiredLevel = CPU_irq_level_from_symbolic_name(CPU_PERIODIC_TIMER); - - usiu.piscrk = USIU_UNLOCK_KEY; - usiu.piscr = USIU_PISCR_PIRQ(desiredLevel) /* set interrupt priority */ - | USIU_PISCR_PS /* acknowledge interrupt */ - | USIU_PISCR_PIE /* enable interrupt */ - | USIU_PISCR_PITF /* freeze during debug */ - | USIU_PISCR_PTE; /* enable timer */ - usiu.piscrk = 0; -} - -void clockOff(void* unused) -{ - /* disable PIT and PIT interrupts */ - usiu.piscrk = USIU_UNLOCK_KEY; - usiu.piscr &= ~(USIU_PISCR_PTE | USIU_PISCR_PIE); - usiu.piscrk = 0; -} - -int clockIsOn(void* unused) -{ - if (usiu.piscr & USIU_PISCR_PIE) - return 1; - return 0; -} - -/* - * Called via atexit() - * Remove the clock interrupt handler by setting handler to NULL - */ -void Clock_exit(void) -{ - (void) BSP_disconnect_clock_handler (); -} - -static void Install_clock(rtems_isr_entry clock_isr) -{ - Clock_driver_ticks = 0; - - BSP_connect_clock_handler (clock_isr); - atexit(Clock_exit); -} - -rtems_device_driver Clock_initialize( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *pargp -) -{ - Install_clock( Clock_isr ); - - return RTEMS_SUCCESSFUL; -} diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/console-generic/console-generic.c b/c/src/lib/libcpu/powerpc/mpc5xx/console-generic/console-generic.c deleted file mode 100644 index 7e1629b714..0000000000 --- a/c/src/lib/libcpu/powerpc/mpc5xx/console-generic/console-generic.c +++ /dev/null @@ -1,317 +0,0 @@ -/* - * General Serial I/O functions. - * - * This file contains the functions for performing serial I/O. The actual - * system calls (console_*) should be in the BSP part of the source tree. - * That way different BSPs can use whichever SCI they wish for /dev/console. - * - * On-chip resources used: - * resource minor note - * SCI1 0 - * SCI2 1 - */ - -/* - * MPC5xx port sponsored by Defence Research and Development Canada - Suffield - * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) - * - * Derived from - * c/src/lib/libcpu/powerpc/mpc8xx/console_generic/console_generic.c: - * Author: Jay Monkman (jmonkman@frasca.com) - * Copyright (C) 1998 by Frasca International, Inc. - * - * Derived from c/src/lib/libbsp/m68k/gen360/console/console.c written by: - * W. Eric Norum - * Saskatchewan Accelerator Laboratory - * University of Saskatchewan - * Saskatoon, Saskatchewan, CANADA - * eric@skatter.usask.ca - * - * COPYRIGHT (c) 1989-1998. - * On-Line Applications Research Corporation (OAR). - * - * Modifications by Darlene Stewart - * and Charles-Antoine Gauthier - * Copyright (c) 1999, National Research Council of Canada - * - * 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 -#include -#include -#include -#include -#include /* for printk */ -#include -#include -#include - - -/* - * SCI port descriptor table. - */ -typedef struct -{ - volatile m5xxSCIRegisters_t *regs; /* hardware registers */ - struct rtems_termios_tty *ttyp; /* termios data for this port */ -} sci_desc; - -static sci_desc sci_descs[] = { - { &imb.qsmcm.sci1, 0 }, /* SCI 1 */ - { &imb.qsmcm.sci2, 0 }, /* SCI 2 */ -}; - -/* - * Number of SCI port initialization calls made so far. Used to avoid - * installing the common interrupt handler more than once. - */ -int init_calls = 0; - -/* - * Default configuration. - */ -static struct termios default_termios = { - 0, /* input mode flags */ - 0, /* output mode flags */ - 0, /* local mode flags */ - 0, /* line discipline */ - { 0 }, /* control characters */ - CS8 | CREAD | CLOCAL | B9600, /* control mode flags */ -}; - - -extern uint32_t bsp_clock_speed; - -/* - * Termios callback functions - */ - -int -m5xx_uart_firstOpen( - int major, - int minor, - void *arg -) -{ - rtems_libio_open_close_args_t *args = arg; - sci_desc* desc = &sci_descs[minor]; - struct rtems_termios_tty *tty = args->iop->data1; - - desc->ttyp = tty; /* connect tty */ - if ( tty->device.outputUsesInterrupts == TERMIOS_IRQ_DRIVEN) - desc->regs->sccr1 |= QSMCM_SCI_RIE; /* enable rx interrupt */ - - return RTEMS_SUCCESSFUL; -} - -int -m5xx_uart_lastClose( - int major, - int minor, - void* arg -) -{ - sci_desc* desc = &sci_descs[minor]; - - desc->regs->sccr1 &= ~(QSMCM_SCI_RIE | QSMCM_SCI_TIE); /* disable all */ - desc->ttyp = NULL; /* disconnect tty */ - - return RTEMS_SUCCESSFUL; -} - -int -m5xx_uart_pollRead( - int minor -) -{ - volatile m5xxSCIRegisters_t *regs = sci_descs[minor].regs; - int c = -1; - - if ( regs ) { - while ( (regs->scsr & QSMCM_SCI_RDRF) == 0 ) - ; - c = regs->scdr; - } - - return c; -} - -ssize_t m5xx_uart_write( - int minor, - const char *buf, - size_t len -) -{ - if (len > 0) { - volatile m5xxSCIRegisters_t *regs = sci_descs[minor].regs; - - regs->scdr = *buf; /* start transmission */ - regs->sccr1 |= QSMCM_SCI_TIE; /* enable interrupt */ - } - - return 0; -} - -ssize_t m5xx_uart_pollWrite( - int minor, - const char *buf, - size_t len -) -{ - volatile m5xxSCIRegisters_t *regs = sci_descs[minor].regs; - size_t retval = len; - - while ( len-- ) { - while ( (regs->scsr & QSMCM_SCI_TDRE) == 0 ) - ; - regs->scdr = *buf++; - } - - return retval; -} - -int -m5xx_uart_setAttributes( - int minor, - const struct termios *t -) -{ - uint16_t sccr0 = sci_descs[minor].regs->sccr0; - uint16_t sccr1 = sci_descs[minor].regs->sccr1; - int baud; - - /* - * Check that port number is valid - */ - if ( (minor < SCI1_MINOR) || (minor > SCI2_MINOR) ) - return RTEMS_INVALID_NUMBER; - - /* Baud rate */ - baud = rtems_termios_baud_to_number( t->c_ospeed ); - if (baud > 0) { - sccr0 &= ~QSMCM_SCI_BAUD(-1); - sccr0 |= QSMCM_SCI_BAUD((bsp_clock_speed + (16 * baud)) / (32 * baud)); - } - - /* Number of data bits -- not available with MPC5xx SCI */ - switch ( t->c_cflag & CSIZE ) { - case CS5: break; - case CS6: break; - case CS7: break; - case CS8: break; - } - - /* Stop bits -- not easily available with MPC5xx SCI */ - if ( t->c_cflag & CSTOPB ) { - /* Two stop bits */ - } else { - /* One stop bit */ - } - - /* Parity */ - if ( t->c_cflag & PARENB ) - sccr1 |= QSMCM_SCI_PE; - else - sccr1 &= ~QSMCM_SCI_PE; - - if ( t->c_cflag & PARODD ) - sccr1 |= QSMCM_SCI_PT; - else - sccr1 &= ~QSMCM_SCI_PT; - - /* Transmitter and receiver enable */ - sccr1 |= QSMCM_SCI_TE; - if ( t->c_cflag & CREAD ) - sccr1 |= QSMCM_SCI_RE; - else - sccr1 &= ~QSMCM_SCI_RE; - - /* Write hardware registers */ - sci_descs[minor].regs->sccr0 = sccr0; - sci_descs[minor].regs->sccr1 = sccr1; - - return RTEMS_SUCCESSFUL; -} - - -/* - * Interrupt handling. - */ -static void -m5xx_sci_interrupt_handler (rtems_irq_hdl_param unused) -{ - int minor; - - for ( minor = 0; minor < NUM_PORTS; minor++ ) { - sci_desc *desc = &sci_descs[minor]; - int sccr1 = desc->regs->sccr1; - int scsr = desc->regs->scsr; - - /* - * Character received? - */ - if ((sccr1 & QSMCM_SCI_RIE) && (scsr & QSMCM_SCI_RDRF)) { - char c = desc->regs->scdr; - rtems_termios_enqueue_raw_characters(desc->ttyp, &c, 1); - } - /* - * Transmitter empty? - */ - if ((sccr1 & QSMCM_SCI_TIE) && (scsr & QSMCM_SCI_TDRE)) { - desc->regs->sccr1 &= ~QSMCM_SCI_TIE; - rtems_termios_dequeue_characters (desc->ttyp, 1); - } - } -} - -static void m5xx_sci_nop(const rtems_irq_connect_data* ptr) -{ -} - -static int m5xx_sci_isOn(const rtems_irq_connect_data* ptr) -{ - return 1; -} - -/* - * Basic initialization. - */ - -void -m5xx_uart_initialize (int minor) -{ - /* - * Check that minor number is valid. - */ - if ( (minor < SCI1_MINOR) || (minor > SCI2_MINOR) ) - return; - - /* - * Configure and enable receiver and transmitter. - */ - m5xx_uart_setAttributes(minor, &default_termios); - - /* - * Connect interrupt if not yet done. - */ - if ( init_calls++ == 0 ) { - rtems_irq_connect_data irq_data; - - irq_data.name = CPU_IRQ_SCI; - irq_data.hdl = m5xx_sci_interrupt_handler; - irq_data.on = m5xx_sci_nop; /* can't enable both channels here */ - irq_data.off = m5xx_sci_nop; /* can't disable both channels here */ - irq_data.isOn = m5xx_sci_isOn; - - if (!CPU_install_rtems_irq_handler (&irq_data)) { - printk("Unable to connect SCI Irq handler\n"); - rtems_fatal_error_occurred(1); - } - - imb.qsmcm.qdsci_il = /* set interrupt level in port */ - QSMCM_ILDSCI(CPU_irq_level_from_symbolic_name(CPU_IRQ_SCI)); - } -} diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/exceptions/raw_exception.c b/c/src/lib/libcpu/powerpc/mpc5xx/exceptions/raw_exception.c deleted file mode 100644 index 6cb35be650..0000000000 --- a/c/src/lib/libcpu/powerpc/mpc5xx/exceptions/raw_exception.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * raw_exception.c - This file contains implementation of C functions to - * Instantiate mpc5xx primary exception entries. - * More detailled information can be found on the Motorola - * site and more precisely in the following book: - * - * MPC555/MPC556 User's Manual - * Motorola REF : MPC555UM/D Rev. 3, 2000 October 15 - * - * - * MPC5xx port sponsored by Defence Research and Development Canada - Suffield - * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) - * - * Derived from libcpu/powerpc/mpc8xx/exceptions/raw_exception.c: - * - * Copyright (C) 1999 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 -#include -#include -#include -#include /* for printk */ -#include - -static rtems_raw_except_connect_data* raw_except_table; -static rtems_raw_except_connect_data default_raw_except_entry; -static rtems_raw_except_global_settings* local_settings; - -int mpc5xx_vector_is_valid(rtems_vector vector) -{ - switch (current_ppc_cpu) { - case PPC_5XX: - switch(vector) { - case ASM_RESET_VECTOR: - case ASM_MACH_VECTOR: - - case ASM_EXT_VECTOR: - case ASM_ALIGN_VECTOR: - case ASM_PROG_VECTOR: - case ASM_FLOAT_VECTOR: - case ASM_DEC_VECTOR: - - case ASM_SYS_VECTOR: - case ASM_TRACE_VECTOR: - case ASM_FLOATASSIST_VECTOR: - - case ASM_SOFTEMUL_VECTOR: - - case ASM_IPROT_VECTOR: - case ASM_DPROT_VECTOR: - - case ASM_DBREAK_VECTOR: - case ASM_IBREAK_VECTOR: - case ASM_MEBREAK_VECTOR: - case ASM_NMEBREAK_VECTOR: - return 1; - default: - return 0; - } - default: - printk("Please complete libcpu/powerpc/mpc5xx/exceptions/raw_exception.c\n"); - printk("current_ppc_cpu = %x\n", current_ppc_cpu); - return 0; - } -} - -int mpc5xx_set_exception (const rtems_raw_except_connect_data* except) -{ - rtems_interrupt_level level; - - if (!mpc5xx_vector_is_valid(except->exceptIndex)) { - return 0; - } - /* - * Check if default handler is actually connected. If not issue an error. - * You must first get the current handler via mpc5xx_get_current_exception - * and then disconnect it using mpc5xx_delete_exception. - * RATIONALE : to always have the same transition by forcing the user - * to get the previous handler before accepting to disconnect. - */ - if (exception_handler_table[except->exceptIndex] != - default_raw_except_entry.hdl.raw_hdl) { - return 0; - } - - rtems_interrupt_disable(level); - - raw_except_table[except->exceptIndex] = *except; - - exception_handler_table[except->exceptIndex] = except->hdl.raw_hdl; - if (except->on) - except->on(except); - - rtems_interrupt_enable(level); - return 1; -} - -int mpc5xx_get_current_exception (rtems_raw_except_connect_data* except) -{ - if (!mpc5xx_vector_is_valid(except->exceptIndex)){ - return 0; - } - - *except = raw_except_table[except->exceptIndex]; - - return 1; -} - -int mpc5xx_delete_exception (const rtems_raw_except_connect_data* except) -{ - rtems_interrupt_level level; - - if (!mpc5xx_vector_is_valid(except->exceptIndex)){ - return 0; - } - /* - * Check if handler passed is actually connected. If not issue an error. - * You must first get the current handler via mpc5xx_get_current_exception - * and then disconnect it using mpc5xx_delete_exception. - * RATIONALE : to always have the same transition by forcing the user - * to get the previous handler before accepting to disconnect. - */ - if (exception_handler_table[except->exceptIndex] != except->hdl.raw_hdl) { - return 0; - } - - rtems_interrupt_disable(level); - - if (except->off) - except->off(except); - exception_handler_table[except->exceptIndex] = - default_raw_except_entry.hdl.raw_hdl; - - raw_except_table[except->exceptIndex] = default_raw_except_entry; - raw_except_table[except->exceptIndex].exceptIndex = except->exceptIndex; - - rtems_interrupt_enable(level); - - return 1; -} - -/* - * Exception global init. - * - * Install exception handler pointers from the raw exception table into the - * exception handler table. - */ -int mpc5xx_init_exceptions (rtems_raw_except_global_settings* config) -{ - unsigned i; - rtems_interrupt_level level; - - /* - * store various accelerators - */ - raw_except_table = config->rawExceptHdlTbl; - local_settings = config; - default_raw_except_entry = config->defaultRawEntry; - - rtems_interrupt_disable(level); - - for (i = 0; i < NUM_EXCEPTIONS; i++) { - exception_handler_table[i] = raw_except_table[i].hdl.raw_hdl; - - if (raw_except_table[i].hdl.raw_hdl != default_raw_except_entry.hdl.raw_hdl) { - if (raw_except_table[i].on) - raw_except_table[i].on(&raw_except_table[i]); - } - else { - if (raw_except_table[i].off) - raw_except_table[i].off(&raw_except_table[i]); - } - } - rtems_interrupt_enable(level); - - return 1; -} - -int mpc5xx_get_exception_config (rtems_raw_except_global_settings** config) -{ - *config = local_settings; - return 1; -} diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/ictrl/ictrl.c b/c/src/lib/libcpu/powerpc/mpc5xx/ictrl/ictrl.c deleted file mode 100644 index 51db6a62c1..0000000000 --- a/c/src/lib/libcpu/powerpc/mpc5xx/ictrl/ictrl.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * mpc505/509 external interrupt controller management. - */ - -#include "ictrl.h" - -#include -#include - -/* - * Internal routines. - */ - -static unsigned long volatile *const IRQAND = - (unsigned long volatile *const)0x8007EFA4; - -static void nullHandler() -{ -} - -/* Interrupt dispatch table. */ -static ExtIsrHandler extIrqHandlers[NUM_IRQS] = -{ - nullHandler, - nullHandler, - nullHandler, - nullHandler, - nullHandler, - nullHandler, - nullHandler -}; - - -/* RTEMS external interrupt handler. Calls installed external interrupt - handlers for every pending external interrupt in turn. */ -static rtems_isr extIsr_( rtems_vector_number i ) -{ -#define BIT_NUMBER(val, bit) \ - __asm__ volatile ( "cntlzw %0, %1; srawi %0, %0, 1": "=r" (bit) : "r" (val) ); - - int bit; - (void)i; - - BIT_NUMBER(*IRQAND & IMASK_ALL, bit); - while ( bit < NUM_IRQS ) { - extIrqHandlers[bit](); - BIT_NUMBER(*IRQAND & IMASK_ALL, bit); - } -} - -/* - * Public routines - */ - -void extIrqSetHandler(ExtInt interrupt,ExtIsrHandler handler) -{ - extIrqHandlers[interrupt] = handler; -} - -void extIsrInit( void ) -{ - int i = 0; - - extIrqDisable(IMASK_ALL); - for( i = 0; i < NUM_IRQS; i++) - extIrqHandlers[i] = nullHandler; - set_vector(extIsr_,PPC_IRQ_EXTERNAL,1); -} diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/ictrl/ictrl.h b/c/src/lib/libcpu/powerpc/mpc5xx/ictrl/ictrl.h deleted file mode 100644 index 303ece825d..0000000000 --- a/c/src/lib/libcpu/powerpc/mpc5xx/ictrl/ictrl.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef _ICTRL_H -#define _ICTRL_H - -/* - * mpc505/509 external interrupt controller management. - * - * FIXME: should be somehow merged into general RTEMS interrupt - * management code. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#define _SIU_IRQENABLE ((unsigned long volatile *const)0x8007EFA8) -#define _SIU_IRQPEND ((unsigned long volatile *const)0x8007EFA0) - -/* Interrupt masks. */ -enum { - IMASK_EXT0 = 0x80000000, - IMASK_EXT1 = 0x20000000, - IMASK_EXT2 = 0x08000000, - IMASK_EXT3 = 0x02000000, - IMASK_EXT4 = 0x00800000, - IMASK_EXT5 = 0x00200000, - IMASK_EXT6 = 0x00080000, - IMASK_ALL = IMASK_EXT0 | IMASK_EXT1 | IMASK_EXT2 | IMASK_EXT3 | - IMASK_EXT4 | IMASK_EXT5 | IMASK_EXT6 -}; - -/* Interrupt numbers. */ -typedef enum { - IRQ_EXT0, - IRQ_EXT1, - IRQ_EXT2, - IRQ_EXT3, - IRQ_EXT4, - IRQ_EXT5, - IRQ_EXT6, - NUM_IRQS -} ExtInt; - -/* Type of external interrupt handlers */ -typedef void (*ExtIsrHandler) (void); - -/* Initialization. Must be called once after RTEMS interrupts sybsystem - is initiailized. 'predriver_hook' is one of such places. */ -extern void extIsrInit( void ); - -/* Set interrupt handler 'handler' for external interrupt number - 'interrupt'. */ -extern void extIrqSetHandler(ExtInt interrupt, ExtIsrHandler handler); - -/* Check is external interrupt 'irq' (IMASK_XXXX) is pended. */ -#define extIrqIsSet(irq) \ - (*_SIU_IRQPEND & (irq)) - -/* Enable external interrupt 'irq' (IMASK_XXXX) processing. */ -#define extIrqEnable(irq) \ - (*_SIU_IRQENABLE |= (irq)) - -/* Disable external interrupt 'irq' (IMASK_XXXX) processing. */ -#define extIrqDisable(irq) \ - (*_SIU_IRQENABLE &= ~(irq)) - -/* Check if external interrupt 'irq' (IMASK_XXXX) processing is - enabled. */ -#define extIrqGetEnable \ - (*_SIU_IRQENABLE) - -#ifdef __cplusplus -} -#endif - -#endif /* _ICTRL_H */ diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.c b/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.c deleted file mode 100644 index 8bb3cd240e..0000000000 --- a/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.c +++ /dev/null @@ -1,463 +0,0 @@ -/* - * This file contains the implementation of the function described in irq.h - */ - -/* - * MPC5xx port sponsored by Defence Research and Development Canada - Suffield - * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) - * - * Derived from libbsp/powerpc/mbx8xx/irq/irq.c: - * - * 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 -#include -#include -#include -#include -#include - -/* - * Convert an rtems_irq_number constant to an interrupt level - * suitable for programming into an I/O device's interrupt level field. - */ -int CPU_irq_level_from_symbolic_name(const rtems_irq_number name) -{ - if (CPU_USIU_EXT_IRQ_0 <= name && name <= CPU_USIU_INT_IRQ_7) - return (name - CPU_USIU_EXT_IRQ_0) / 2; - - if (CPU_UIMB_IRQ_8 <= name && name <= CPU_UIMB_IRQ_31) - return 8 + (name - CPU_UIMB_IRQ_8); - - return 31; /* reasonable default */ -} - -/* - * default handler connected on each irq after bsp initialization - */ -static rtems_irq_connect_data default_rtems_entry; - -/* - * location used to store initial tables used for interrupt - * management. - */ -static rtems_irq_global_settings* internal_config; -static rtems_irq_connect_data* rtems_hdl_tbl; - -/* - * Check if symbolic IRQ name is an USIU IRQ - */ -static inline int is_usiu_irq(const rtems_irq_number irqLine) -{ - return (((int) irqLine <= CPU_USIU_IRQ_MAX_OFFSET) && - ((int) irqLine >= CPU_USIU_IRQ_MIN_OFFSET) - ); -} - -/* - * Check if symbolic IRQ name is an UIMB IRQ - */ -static inline int is_uimb_irq(const rtems_irq_number irqLine) -{ - return (((int) irqLine <= CPU_UIMB_IRQ_MAX_OFFSET) && - ((int) irqLine >= CPU_UIMB_IRQ_MIN_OFFSET) - ); -} - -/* - * Check if symbolic IRQ name is a Processor IRQ - */ -static inline int is_proc_irq(const rtems_irq_number irqLine) -{ - return (((int) irqLine <= CPU_PROC_IRQ_MAX_OFFSET) && - ((int) irqLine >= CPU_PROC_IRQ_MIN_OFFSET) - ); -} - - -/* - * Masks used to mask off the interrupts. For exmaple, for ILVL2, the - * mask is used to mask off interrupts ILVL2, IRQ3, ILVL3, ... IRQ7 - * and ILVL7. - * - */ -const static unsigned int USIU_IvectMask[CPU_USIU_IRQ_COUNT] = -{ - 0, /* external IRQ 0 */ - 0xFFFFFFFF << 31, /* internal level 0 */ - 0xFFFFFFFF << 30, /* external IRQ 1 */ - 0xFFFFFFFF << 29, /* internal level 1 */ - 0xFFFFFFFF << 28, /* external IRQ 2 */ - 0xFFFFFFFF << 27, /* internal level 2 */ - 0xFFFFFFFF << 26, /* external IRQ 3 */ - 0xFFFFFFFF << 25, /* internal level 3 */ - 0xFFFFFFFF << 24, /* external IRQ 4 */ - 0xFFFFFFFF << 23, /* internal level 4 */ - 0xFFFFFFFF << 22, /* external IRQ 5 */ - 0xFFFFFFFF << 21, /* internal level 5 */ - 0xFFFFFFFF << 20, /* external IRQ 6 */ - 0xFFFFFFFF << 19, /* internal level 6 */ - 0xFFFFFFFF << 18, /* external IRQ 7 */ - 0xFFFFFFFF << 17 /* internal level 7 */ -}; - - -/* - * ------------------------ 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_USIU_IvectMask_from_prio (void) -{ - /* - * In theory this is feasible. No time to code it yet. See i386/shared/irq.c - * for an example based on 8259 controller mask. The actual masks defined - * correspond to the priorities defined for the USIU in irq_init.c. - */ -} - -/* - * This function check that the value given for the irq line - * is valid. - */ -static int isValidInterrupt(int irq) -{ - if ( (irq < CPU_MIN_OFFSET) || (irq > CPU_MAX_OFFSET) - || (irq == CPU_UIMB_INTERRUPT) ) - return 0; - return 1; -} - -static int CPU_irq_enable_at_uimb(const rtems_irq_number irqLine) -{ - if (!is_uimb_irq(irqLine)) - return 1; - return 0; -} - -static int CPU_irq_disable_at_uimb(const rtems_irq_number irqLine) -{ - if (!is_uimb_irq(irqLine)) - return 1; - return 0; -} - -static int CPU_irq_enable_at_usiu(const rtems_irq_number irqLine) -{ - int usiu_irq_index; - - if (!is_usiu_irq(irqLine)) - return 1; - - usiu_irq_index = ((int) (irqLine) - CPU_USIU_IRQ_MIN_OFFSET); - ppc_cached_irq_mask |= (1 << (31-usiu_irq_index)); - usiu.simask = ppc_cached_irq_mask; - - return 0; -} - -static int CPU_irq_disable_at_usiu(const rtems_irq_number irqLine) -{ - int usiu_irq_index; - - if (!is_usiu_irq(irqLine)) - return 1; - - usiu_irq_index = ((int) (irqLine) - CPU_USIU_IRQ_MIN_OFFSET); - ppc_cached_irq_mask &= ~(1 << (31-usiu_irq_index)); - usiu.simask = ppc_cached_irq_mask; - - return 0; -} - -/* - * --------------- RTEMS Single Irq Handler Mngt Routines ---------------- - */ - -int CPU_install_rtems_irq_handler (const rtems_irq_connect_data* irq) -{ - rtems_interrupt_level level; - - if (!isValidInterrupt(irq->name)) { - return 0; - } - /* - * Check if default handler is actually connected. If not issue an error. - * You must first get the current handler via CPU_get_current_idt_entry - * and then disconnect it using CPU_delete_idt_entry. - * RATIONALE : to always have the same transition by forcing the user - * to get the previous handler before accepting to disconnect. - */ - if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) { - return 0; - } - - rtems_interrupt_disable(level); - - /* - * store the data provided by user - */ - rtems_hdl_tbl[irq->name] = *irq; - - if (is_uimb_irq(irq->name)) { - /* - * Enable interrupt at UIMB level - */ - CPU_irq_enable_at_uimb (irq->name); - } - - if (is_usiu_irq(irq->name)) { - /* - * Enable interrupt at USIU level - */ - CPU_irq_enable_at_usiu (irq->name); - } - - if (is_proc_irq(irq->name)) { - /* - * Should Enable exception at processor level but not needed. Will restore - * EE flags at the end of the routine anyway. - */ - } - /* - * Enable interrupt on device - */ - if (irq->on) - irq->on(irq); - - rtems_interrupt_enable(level); - - return 1; -} - - -int CPU_get_current_rtems_irq_handler (rtems_irq_connect_data* irq) -{ - if (!isValidInterrupt(irq->name)) { - return 0; - } - *irq = rtems_hdl_tbl[irq->name]; - return 1; -} - -int CPU_remove_rtems_irq_handler (const rtems_irq_connect_data* irq) -{ - rtems_interrupt_level level; - - if (!isValidInterrupt(irq->name)) { - return 0; - } - /* - * Check if default handler is actually connected. If not issue an error. - * You must first get the current handler via CPU_get_current_idt_entry - * and then disconnect it using CPU_delete_idt_entry. - * RATIONALE : to always have the same transition by forcing the user - * to get the previous handler before accepting to disconnect. - */ - if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) { - return 0; - } - rtems_interrupt_disable(level); - - /* - * Disable interrupt on device - */ - if (irq->off) - irq->off(irq); - - if (is_uimb_irq(irq->name)) { - /* - * disable interrupt at UIMB level - */ - CPU_irq_disable_at_uimb (irq->name); - } - if (is_usiu_irq(irq->name)) { - /* - * disable interrupt at USIU level - */ - CPU_irq_disable_at_usiu (irq->name); - } - if (is_proc_irq(irq->name)) { - /* - * disable exception at processor level - */ - } - - /* - * restore the default irq value - */ - rtems_hdl_tbl[irq->name] = default_rtems_entry; - - rtems_interrupt_enable(level); - - return 1; -} - -/* - * ---------------- RTEMS Global Irq Handler Mngt Routines ---------------- - */ - -int CPU_rtems_irq_mngt_set (rtems_irq_global_settings* config) -{ - int i; - rtems_interrupt_level level; - - /* - * Store various code accelerators - */ - internal_config = config; - default_rtems_entry = config->defaultEntry; - rtems_hdl_tbl = config->irqHdlTbl; - - rtems_interrupt_disable(level); - - /* - * Start with UIMB IRQ - */ - for (i = CPU_UIMB_IRQ_MIN_OFFSET; i <= CPU_UIMB_IRQ_MAX_OFFSET ; i++) { - if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) { - CPU_irq_enable_at_uimb (i); - if (rtems_hdl_tbl[i].on) - rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); - } - else { - if (rtems_hdl_tbl[i].off) - rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); - CPU_irq_disable_at_uimb (i); - } - } - - /* - * Continue with USIU IRQ - * Set up internal tables used by rtems interrupt prologue - */ - compute_USIU_IvectMask_from_prio (); - - for (i = CPU_USIU_IRQ_MIN_OFFSET; i <= CPU_USIU_IRQ_MAX_OFFSET ; i++) { - if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) { - CPU_irq_enable_at_usiu (i); - if (rtems_hdl_tbl[i].on) - rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); - } - else { - if (rtems_hdl_tbl[i].off) - rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); - CPU_irq_disable_at_usiu (i); - } - } - - /* - * Enable all UIMB interrupt lines, then enable at USIU. - */ - imb.uimb.umcr |= UIMB_UMCR_IRQMUX(3); - CPU_irq_enable_at_usiu (CPU_UIMB_INTERRUPT); - - /* - * finish with Processor exceptions handled like IRQ - */ - for (i = CPU_PROC_IRQ_MIN_OFFSET; i <= CPU_PROC_IRQ_MAX_OFFSET; i++) { - if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) { - if (rtems_hdl_tbl[i].on) - rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); - } - else { - if (rtems_hdl_tbl[i].off) - rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); - } - } - rtems_interrupt_enable(level); - return 1; -} - -int CPU_rtems_irq_mngt_get(rtems_irq_global_settings** config) -{ - *config = internal_config; - return 0; -} - - -/* - * High level IRQ handler called from shared_raw_irq_code_entry - */ -void C_dispatch_irq_handler (MPC5XX_Interrupt_frame *frame, unsigned int excNum) -{ - register unsigned int irq; - register unsigned uimbIntr; /* boolean */ - register unsigned oldMask; /* old siu pic masks */ - register unsigned msr; - register unsigned new_msr; - - /* - * Handle decrementer interrupt - */ - if (excNum == ASM_DEC_VECTOR) { - _CPU_MSR_GET(msr); - new_msr = msr | MSR_EE; - _CPU_MSR_SET(new_msr); - - rtems_hdl_tbl[CPU_DECREMENTER].hdl(rtems_hdl_tbl[CPU_DECREMENTER].handle); - - _CPU_MSR_SET(msr); - return; - } - - /* - * Handle external interrupt generated by USIU on PPC core - */ - while ((ppc_cached_irq_mask & usiu.sipend) != 0) { - irq = (usiu.sivec >> 26); - uimbIntr = (irq == CPU_UIMB_INTERRUPT); - /* - * Disable the interrupt of the same and lower priority. - */ - oldMask = ppc_cached_irq_mask; - ppc_cached_irq_mask = oldMask & USIU_IvectMask[irq]; - usiu.simask = ppc_cached_irq_mask; - /* - * Acknowledge current interrupt. This has no effect on internal level - * interrupts. - */ - usiu.sipend = (1 << (31 - irq)); - - if (uimbIntr) { - /* - * Look at the bits set in the UIMB interrupt-pending register. The - * highest-order set bit indicates the handler we will run. - * - * Unfortunately, we can't easily mask individual UIMB interrupts - * unless they use USIU levels 0 to 6, so we must mask all low-level - * (level > 7) UIMB interrupts while we service any interrupt. - */ - int uipend = imb.uimb.uipend << 8; - - if (uipend == 0) { /* spurious interrupt? use last vector */ - irq = CPU_UIMB_IRQ_MAX_OFFSET; - } - else { - irq = CPU_UIMB_IRQ_MIN_OFFSET; - for ( ; (uipend & 0x8000000) == 0; uipend <<= 1) { - irq++; - } - } - } - _CPU_MSR_GET(msr); - new_msr = msr | MSR_EE; - _CPU_MSR_SET(new_msr); - - rtems_hdl_tbl[irq].hdl(rtems_hdl_tbl[irq].handle); - - _CPU_MSR_SET(msr); - - ppc_cached_irq_mask = oldMask; - usiu.simask = ppc_cached_irq_mask; - } -} diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq_asm.S b/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq_asm.S deleted file mode 100644 index 52911c48e3..0000000000 --- a/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq_asm.S +++ /dev/null @@ -1,312 +0,0 @@ -/* - * irq_asm.S - * - * This file contains the assembly code for the PowerPC - * IRQ veneers for RTEMS. - * - * 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. - * - * - * MPC5xx port sponsored by Defence Research and Development Canada - Suffield - * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) - * - * Derived from libbsp/powerpc/mbx8xx/irq/irq_asm.S: - * - * Modified to support the MCP750. - * Modifications Copyright (C) 1999 Eric Valette. valette@crf.canon.fr - * - * Till Straumann , 2003/7: - * - store isr nesting level in _ISR_Nest_level rather than - * SPRG0 - RTEMS relies on that variable. - */ - -#include -#include -#include -#include -#include - - -#define SYNC \ - sync; \ - isync - -/* - * Common handler for interrupt exceptions. - * - * The function CPU_rtems_irq_mng_init() initializes the decrementer and - * external interrupt entries in the exception handler table with pointers - * to this routine, which saves the remainder of the interrupted code's - * state, then calls C_dispatch_irq_handler(). - * - * On entry, R1 points to a new exception stack frame in which R3, R4, and - * LR have been saved. R4 holds the exception number. - */ - PUBLIC_VAR(C_dispatch_irq_handler) - - PUBLIC_VAR(dispatch_irq_handler) -SYM (dispatch_irq_handler): - /* - * Save SRR0/SRR1 As soon As possible as it is the minimal needed - * to re-enable exception processing. - * - * Note that R2 should never change (it's the EABI pointer to - * .sdata2), but we save it just in case. - */ - stw r0, GPR0_OFFSET(r1) - stw r2, GPR2_OFFSET(r1) - - mfsrr0 r0 - mfsrr1 r3 - - stw r0, SRR0_FRAME_OFFSET(r1) - stw r3, SRR1_FRAME_OFFSET(r1) - - /* - * Enable exception recovery. Also enable FP so that FP context - * can be saved and restored (using FP instructions). - */ - mfmsr r3 - ori r3, r3, MSR_RI | MSR_FP - mtmsr r3 - SYNC - - /* - * Push C scratch registers on the current stack. It may actually be - * the thread stack or the interrupt stack. Anyway we have to make - * it in order to be able to call C/C++ functions. Depending on the - * nesting interrupt level, we will switch to the right stack later. - */ - stw r5, GPR5_OFFSET(r1) - stw r6, GPR6_OFFSET(r1) - stw r7, GPR7_OFFSET(r1) - stw r8, GPR8_OFFSET(r1) - stw r9, GPR9_OFFSET(r1) - stw r10, GPR10_OFFSET(r1) - stw r11, GPR11_OFFSET(r1) - stw r12, GPR12_OFFSET(r1) - stw r13, GPR13_OFFSET(r1) - - mfcr r5 - mfctr r6 - mfxer r7 - - stw r5, EXC_CR_OFFSET(r1) - stw r6, EXC_CTR_OFFSET(r1) - stw r7, EXC_XER_OFFSET(r1) - - /* - * Add some non volatile registers to store information that will be - * used when returning from C handler. - */ - stw r14, GPR14_OFFSET(r1) - stw r15, GPR15_OFFSET(r1) - - /* - * Save current stack pointer location in R14. - */ - addi r14, r1, 0 - - /* - * store part of THREAD_DISPATCH_DISABLE_LEVEL address in R15 - */ - addis r15, 0, THREAD_DISPATCH_DISABLE_LEVEL@ha - - /* - * Retrieve current nesting level from _ISR_Nest_level - */ - lis r7, ISR_NEST_LEVEL@ha - lwz r3, ISR_NEST_LEVEL@l(r7) - - /* - * Check if stack switch is necessary - */ - cmpwi r3, 0 - bne nested - - mfspr r1, SPRG1 /* switch to interrupt stack */ -nested: - - /* - * Start Incrementing nesting level in R3 - */ - addi r3, r3, 1 - - /* - * Start Incrementing THREAD_DISPATCH_DISABLE_LEVEL R4 = THREAD_DISPATCH_DISABLE_LEVEL - */ - lwz r6, THREAD_DISPATCH_DISABLE_LEVEL@l(r15) - - /* store new nesting level in _ISR_Nest_level */ - stw r3, ISR_NEST_LEVEL@l(r7) - - addi r6, r6, 1 - - /* - * store new THREAD_DISPATCH_DISABLE_LEVEL value - */ - stw r6, THREAD_DISPATCH_DISABLE_LEVEL@l(r15) - - /* - * We are now running on the interrupt stack. External and decrementer - * exceptions are still disabled. I see no purpose trying to optimize - * further assembler code. - */ - - /* - * Call C exception handler for decrementer or external interrupt. - * Pass frame along just in case.. - * - * C_dispatch_irq_handler(cpu_interrupt_frame* r3, vector r4) - */ - addi r3, r14, 0x8 - bl C_dispatch_irq_handler - - /* - * start decrementing nesting level. Note : do not test result against 0 - * value as an easy exit condition because if interrupt nesting level > 1 - * then THREAD_DISPATCH_DISABLE_LEVEL > 1 - */ - lis r7, ISR_NEST_LEVEL@ha - lwz r4, ISR_NEST_LEVEL@l(r7) - - /* - * start decrementing THREAD_DISPATCH_DISABLE_LEVEL - */ - lwz r3,THREAD_DISPATCH_DISABLE_LEVEL@l(r15) - - addi r4, r4, -1 /* Continue decrementing nesting level */ - addi r3, r3, -1 /* Continue decrementing THREAD_DISPATCH_DISABLE_LEVEL */ - - stw r4, ISR_NEST_LEVEL@l(r7) /* End decrementing nesting level */ - stw r3,THREAD_DISPATCH_DISABLE_LEVEL@l(r15) /* End decrementing THREAD_DISPATCH_DISABLE_LEVEL */ - - cmpwi r3, 0 - - /* - * switch back to original stack (done here just optimize registers - * contention. Could have been done before...) - */ - addi r1, r14, 0 - bne easy_exit /* if (THREAD_DISPATCH_DISABLE_LEVEL != 0) goto easy_exit */ - - /* - * Here we are running again on the thread system stack. - * We have interrupt nesting level = THREAD_DISPATCH_DISABLE_LEVEL = 0. - * Interrupt are still disabled. Time to check if scheduler request to - * do something with the current thread... - */ - addis r4, 0, DISPATCH_NEEDED@ha - lbz r5, DISPATCH_NEEDED@l(r4) - cmpwi r5, 0 - beq easy_exit - - /* - * going to call _Thread_Dispatch - * Push a complete exception like frame... - */ - stmw r16, GPR16_OFFSET(r1) - addi r3, r1, 0x8 - - /* - * compute SP at exception entry - */ - addi r4, r1, EXCEPTION_FRAME_END - - /* - * store it at the right place - */ - stw r4, GPR1_OFFSET(r1) - - /* - * Call High Level signal handling code - */ - bl _Thread_Dispatch - - /* - * start restoring exception like frame - */ - lwz r31, EXC_CTR_OFFSET(r1) - lwz r30, EXC_XER_OFFSET(r1) - lwz r29, EXC_CR_OFFSET(r1) - lwz r28, EXC_LR_OFFSET(r1) - - mtctr r31 - mtxer r30 - mtcr r29 - mtlr r28 - - lmw r4, GPR4_OFFSET(r1) - lwz r2, GPR2_OFFSET(r1) - lwz r0, GPR0_OFFSET(r1) - - /* - * Make path non recoverable... - */ - mtspr nri, r0 - SYNC - - /* - * Restore rfi related settings - */ - - lwz r3, SRR1_FRAME_OFFSET(r1) - mtsrr1 r3 - lwz r3, SRR0_FRAME_OFFSET(r1) - mtsrr0 r3 - - lwz r3, GPR3_OFFSET(r1) - addi r1,r1, EXCEPTION_FRAME_END - SYNC - rfi - - -easy_exit: - /* - * start restoring interrupt frame - */ - lwz r3, EXC_CTR_OFFSET(r1) - lwz r4, EXC_XER_OFFSET(r1) - lwz r5, EXC_CR_OFFSET(r1) - lwz r6, EXC_LR_OFFSET(r1) - - mtctr r3 - mtxer r4 - mtcr r5 - mtlr r6 - - lwz r15, GPR15_OFFSET(r1) - lwz r14, GPR14_OFFSET(r1) - lwz r13, GPR13_OFFSET(r1) - lwz r12, GPR12_OFFSET(r1) - lwz r11, GPR11_OFFSET(r1) - lwz r10, GPR10_OFFSET(r1) - lwz r9, GPR9_OFFSET(r1) - lwz r8, GPR8_OFFSET(r1) - lwz r7, GPR7_OFFSET(r1) - lwz r6, GPR6_OFFSET(r1) - lwz r5, GPR5_OFFSET(r1) - - /* - * Disable nested exception processing. - */ - mtspr nri, r0 - SYNC - - /* - * Restore rfi related settings - */ - lwz r4, SRR1_FRAME_OFFSET(r1) - lwz r3, SRR0_FRAME_OFFSET(r1) - lwz r2, GPR2_OFFSET(r1) - lwz r0, GPR0_OFFSET(r1) - - mtsrr1 r4 - mtsrr0 r3 - lwz r4, GPR4_OFFSET(r1) - lwz r3, GPR3_OFFSET(r1) - addi r1,r1, EXCEPTION_FRAME_END - SYNC - rfi diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq_init.c b/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq_init.c deleted file mode 100644 index 351edb4ffe..0000000000 --- a/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq_init.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * irq_init.c - * - * This file contains the implementation of rtems initialization - * related to interrupt handling. - */ - -/* - * MPC5xx port sponsored by Defence Research and Development Canada - Suffield - * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) - * - * Derived from libbsp/powerpc/mbx8xx/irq/irq_init.c: - * - * CopyRight (C) 2001 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 -#include -#include -#include -#include - -extern rtems_exception_handler_t dispatch_irq_handler; - -volatile unsigned int ppc_cached_irq_mask; - -/* - * default methods - */ -static void nop_hdl(rtems_irq_hdl_param ignored) -{ -} - -static void nop_irq_enable(const struct __rtems_irq_connect_data__*ignored) -{ -} - -static void nop_raw_enable( - const struct __rtems_raw_except_connect_data__*ignored -) -{ -} - -static int irq_is_connected(const struct __rtems_irq_connect_data__*ignored) -{ - return 0; -} - -static int raw_is_connected(const struct __rtems_raw_except_connect_data__*ignored) -{ - return 0; -} - -static rtems_irq_connect_data rtemsIrq[CPU_IRQ_COUNT]; -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 */ -}; - -static rtems_irq_prio irqPrioTable[CPU_IRQ_COUNT]={ - /* - * actual priorities for interrupt : - * 0 means that only current interrupt is masked - * 255 means all other interrupts are masked - */ - /* - * USIU interrupts. - */ - 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1, 0,0, - /* - * UIMB Interrupts - * - * Note that the first 8 UIMB interrupts overlap the 8 external USIU - * interrupts. - */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* - * Processor exceptions handled as interrupts - */ - 0 -}; - -static void CPU_USIU_irq_init(void) -{ - /* - * In theory we should initialize two registers at least : SIMASK and - * SIEL. SIMASK is reset at 0 value meaning no interrupts. If someone - * find a reasonnable value for SIEL, and the need to change it, please - * feel free to add it here. - */ - ppc_cached_irq_mask = 0; - usiu.simask = ppc_cached_irq_mask; - usiu.sipend = 0xffff0000; - usiu.siel = usiu.siel; -} - -/* - * Initialize UIMB interrupt management - */ -static void CPU_UIMB_irq_init(void) -{ -} - -void CPU_rtems_irq_mng_init(unsigned cpuId) -{ - rtems_raw_except_connect_data vectorDesc; - int i; - - CPU_USIU_irq_init(); - CPU_UIMB_irq_init(); - /* - * Initialize Rtems management interrupt table - */ - /* - * re-init the rtemsIrq table - */ - for (i = 0; i < CPU_IRQ_COUNT; i++) { - rtemsIrq[i] = defaultIrq; - rtemsIrq[i].name = i; - } - /* - * Init initial Interrupt management config - */ - initial_config.irqNb = CPU_IRQ_COUNT; - initial_config.defaultEntry = defaultIrq; - initial_config.irqHdlTbl = rtemsIrq; - initial_config.irqBase = CPU_ASM_IRQ_VECTOR_BASE; - initial_config.irqPrioTbl = irqPrioTable; - - if (!CPU_rtems_irq_mngt_set(&initial_config)) { - /* - * put something here that will show the failure... - */ - rtems_panic("Unable to initialize RTEMS interrupt Management\n"); - } - - /* - * We must connect the raw irq handler for the two - * expected interrupt sources : decrementer and external interrupts. - */ - vectorDesc.exceptIndex = ASM_DEC_VECTOR; - vectorDesc.hdl.vector = ASM_DEC_VECTOR; - vectorDesc.hdl.raw_hdl = dispatch_irq_handler; - vectorDesc.on = nop_raw_enable; - vectorDesc.off = nop_raw_enable; - vectorDesc.isOn = raw_is_connected; - if (!mpc5xx_set_exception (&vectorDesc)) { - rtems_panic("Unable to initialize RTEMS decrementer raw exception\n"); - } - vectorDesc.exceptIndex = ASM_EXT_VECTOR; - vectorDesc.hdl.vector = ASM_EXT_VECTOR; - if (!mpc5xx_set_exception (&vectorDesc)) { - rtems_panic("Unable to initialize RTEMS external raw exception\n"); - } -} diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/timer/timer.c b/c/src/lib/libcpu/powerpc/mpc5xx/timer/timer.c deleted file mode 100644 index 65deae961e..0000000000 --- a/c/src/lib/libcpu/powerpc/mpc5xx/timer/timer.c +++ /dev/null @@ -1,104 +0,0 @@ -/** - * @file - * @brief Timer Driver for the PowerPC MPC5xx. - * - * This file manages the interval timer on the PowerPC MPC5xx. - * @noe This is not the PIT, but rather the RTEMS interval timer. - * We shall use the bottom 32 bits of the timebase register, - */ - -/* - * MPC5xx port sponsored by Defence Research and Development Canada - Suffield - * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) - * - * Derived from c/src/lib/libcpu/powerpc/mpc8xx/timer/timer.c: - * - * Author: Jay Monkman (jmonkman@frasca.com) - * Copywright (C) 1998 by Frasca International, Inc. - * - * Derived from c/src/lib/libcpu/ppc/ppc403/timer/timer.c: - * - * Author: Andrew Bray - * - * COPYRIGHT (c) 1995 by i-cubed ltd. - * - * 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 i-cubed limited not be used in - * advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. - * i-cubed limited makes no representations about the suitability - * of this software for any purpose. - * - * Derived from c/src/lib/libcpu/hppa1_1/timer/timer.c: - * - * COPYRIGHT (c) 1989-2007. - * 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 -#include -#include - -static volatile uint32_t Timer_starting; -static bool benchmark_timer_find_average_overhead; - -extern uint32_t bsp_timer_least_valid; -extern uint32_t bsp_timer_average_overhead; - -/* - * This is so small that this code will be reproduced where needed. - */ -static inline uint32_t get_itimer(void) -{ - uint32_t ret; - - __asm__ volatile ("mftb %0" : "=r" ((ret))); /* TBLO */ - - return ret; -} - -void benchmark_timer_initialize(void) -{ - /* set interrupt level and enable timebase. This should never */ - /* generate an interrupt however. */ - usiu.tbscrk = USIU_UNLOCK_KEY; - usiu.tbscr |= USIU_TBSCR_TBIRQ(4) /* interrupt priority level */ - | USIU_TBSCR_TBF /* freeze timebase during debug */ - | USIU_TBSCR_TBE; /* enable timebase */ - usiu.tbscrk = 0; - - Timer_starting = get_itimer(); -} - -benchmark_timer_t benchmark_timer_read(void) -{ - uint32_t clicks; - uint32_t total; - - clicks = get_itimer(); - - total = clicks - Timer_starting; - - if ( benchmark_timer_find_average_overhead == 1 ) - return total; /* in XXX microsecond units */ - - else { - if ( total < bsp_timer_least_valid ) { - return 0; /* below timer resolution */ - } - return (total - bsp_timer_average_overhead); - } -} - -void benchmark_timer_disable_subtracting_average_overhead(bool find_flag) -{ - benchmark_timer_find_average_overhead = find_flag; -} -- cgit v1.2.3