From 8430205c224c1bfcb67156e5b97dd44ecd81fd7d Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Mon, 12 Apr 2004 22:04:28 +0000 Subject: 2004-04-12 David Querbach * README, configure.ac, mpc5xx/Makefile.am, mpc5xx/exceptions/raw_exception.c, mpc5xx/exceptions/raw_exception.h, mpc5xx/timer/timer.c, shared/include/cpuIdent.h: addition of a significant amount of MPC5xx support as part of the addition of the SS555 BSP. * mpc5xx/README, mpc5xx/clock/clock.c, mpc5xx/console-generic/console-generic.c, mpc5xx/include/console.h, mpc5xx/include/mpc5xx.h, mpc5xx/irq/irq.c, mpc5xx/irq/irq.h, mpc5xx/irq/irq_asm.S, mpc5xx/irq/irq_init.c, mpc5xx/vectors/vectors.S, mpc5xx/vectors/vectors.h, mpc5xx/vectors/vectors_init.c: New files. * mpc5xx/exceptions/asm_utils.S: Removed. --- c/src/lib/libcpu/powerpc/mpc5xx/Makefile.am | 112 +++- c/src/lib/libcpu/powerpc/mpc5xx/README | 27 + c/src/lib/libcpu/powerpc/mpc5xx/clock/clock.c | 196 +++++++ .../mpc5xx/console-generic/console-generic.c | 347 ++++++++++++ .../libcpu/powerpc/mpc5xx/exceptions/asm_utils.S | 64 --- .../powerpc/mpc5xx/exceptions/raw_exception.c | 226 ++++---- .../powerpc/mpc5xx/exceptions/raw_exception.h | 102 ++-- c/src/lib/libcpu/powerpc/mpc5xx/include/console.h | 37 ++ c/src/lib/libcpu/powerpc/mpc5xx/include/mpc5xx.h | 621 +++++++++++++++++++++ c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.c | 495 ++++++++++++++++ c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.h | 358 ++++++++++++ c/src/lib/libcpu/powerpc/mpc5xx/irq/irq_asm.S | 325 +++++++++++ c/src/lib/libcpu/powerpc/mpc5xx/irq/irq_init.c | 152 +++++ c/src/lib/libcpu/powerpc/mpc5xx/timer/timer.c | 128 +++-- c/src/lib/libcpu/powerpc/mpc5xx/vectors/vectors.S | 203 +++++++ c/src/lib/libcpu/powerpc/mpc5xx/vectors/vectors.h | 156 ++++++ .../libcpu/powerpc/mpc5xx/vectors/vectors_init.c | 137 +++++ 17 files changed, 3377 insertions(+), 309 deletions(-) create mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/README create mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/clock/clock.c create mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/console-generic/console-generic.c delete mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/exceptions/asm_utils.S create mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/include/console.h create mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/include/mpc5xx.h create mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.c create mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.h create mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/irq/irq_asm.S create mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/irq/irq_init.c create mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/vectors/vectors.S create mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/vectors/vectors.h create mode 100644 c/src/lib/libcpu/powerpc/mpc5xx/vectors/vectors_init.c (limited to 'c/src/lib/libcpu/powerpc/mpc5xx') diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/Makefile.am b/c/src/lib/libcpu/powerpc/mpc5xx/Makefile.am index 582a354de6..2e035eac11 100644 --- a/c/src/lib/libcpu/powerpc/mpc5xx/Makefile.am +++ b/c/src/lib/libcpu/powerpc/mpc5xx/Makefile.am @@ -10,14 +10,49 @@ noinst_DATA = include $(top_srcdir)/../../../automake/compile.am if mpc5xx +include_mpc5xxdir = $(includedir)/mpc5xx include_libcpudir = $(includedir)/libcpu -# exceptions +include_HEADERS = include/mpc5xx.h + +## clock +EXTRA_PROGRAMS += clock.rel +CLEANFILES += clock.rel +clock_rel_SOURCES = clock/clock.c +clock_rel_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAGS_OPTIMIZE_V) +clock_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) + +EXTRA_PROGRAMS += clock_g.rel +CLEANFILES += clock_g.rel +clock_g_rel_SOURCES = $(clock_rel_SOURCES) +clock_g_rel_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAGS_DEBUG_V) +clock_g_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) + +noinst_DATA += clock$(LIB_VARIANT).rel + +## console-generic +include_mpc5xx_HEADERS = include/console.h + +EXTRA_PROGRAMS += console-generic.rel +CLEANFILES += console-generic.rel +console_generic_rel_SOURCES = console-generic/console-generic.c +console_generic_rel_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAGS_OPTIMIZE_V) +console_generic_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) + +EXTRA_PROGRAMS += console-generic_g.rel +CLEANFILES += console-generic_g.rel +console_generic_g_rel_SOURCES = $(console_generic_rel_SOURCES) +console_generic_g_rel_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAGS_DEBUG_V) +console_generic_g_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) + +noinst_DATA += console-generic$(LIB_VARIANT).rel + +## exceptions include_libcpu_HEADERS = exceptions/raw_exception.h EXTRA_PROGRAMS += exceptions.rel CLEANFILES += exceptions.rel -exceptions_rel_SOURCES = exceptions/raw_exception.c exceptions/asm_utils.S +exceptions_rel_SOURCES = exceptions/raw_exception.c exceptions_rel_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAGS_OPTIMIZE_V) exceptions_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) @@ -29,24 +64,24 @@ exceptions_g_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) noinst_DATA += exceptions$(LIB_VARIANT).rel -# ictrl -include_HEADERS = ictrl/ictrl.h +## irq +include_libcpu_HEADERS += irq/irq.h -EXTRA_PROGRAMS += ictrl.rel -CLEANFILES += ictrl.rel -ictrl_rel_SOURCES = ictrl/ictrl.c ictrl/ictrl.h -ictrl_rel_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAGS_OPTIMIZE_V) -ictrl_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) +EXTRA_PROGRAMS += irq.rel +CLEANFILES += irq.rel +irq_rel_SOURCES = irq/irq.c irq/irq_init.c irq/irq_asm.S +irq_rel_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAGS_OPTIMIZE_V) +irq_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) -EXTRA_PROGRAMS += ictrl_g.rel -CLEANFILES += ictrl_g.rel -ictrl_g_rel_SOURCES = $(ictrl_rel_SOURCES) -ictrl_g_rel_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAGS_DEBUG_V) -ictrl_g_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) +EXTRA_PROGRAMS += irq_g.rel +CLEANFILES += irq_g.rel +irq_g_rel_SOURCES = $(irq_rel_SOURCES) +irq_g_rel_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAGS_DEBUG_V) +irq_g_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) -noinst_DATA += ictrl$(LIB_VARIANT).rel +noinst_DATA += irq$(LIB_VARIANT).rel -# timer +## timer EXTRA_PROGRAMS += timer.rel CLEANFILES += timer.rel timer_rel_SOURCES = timer/timer.c @@ -60,8 +95,28 @@ timer_g_rel_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAGS_DEBUG_V) timer_g_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) noinst_DATA += timer$(LIB_VARIANT).rel + +## vectors +include_libcpu_HEADERS += vectors/vectors.h + +EXTRA_PROGRAMS += vectors.rel +CLEANFILES += vectors.rel +vectors_rel_SOURCES = vectors/vectors_init.c vectors/vectors.S +vectors_rel_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAGS_OPTIMIZE_V) +vectors_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) + +EXTRA_PROGRAMS += vectors_g.rel +CLEANFILES += vectors_g.rel +vectors_g_rel_SOURCES = $(vectors_rel_SOURCES) +vectors_g_rel_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAGS_DEBUG_V) +vectors_g_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) + +noinst_DATA += vectors$(LIB_VARIANT).rel endif +## -- +all-local: $(PREINSTALL_FILES) + PREINSTALL_DIRS = PREINSTALL_FILES = @@ -71,21 +126,38 @@ $(PROJECT_INCLUDE)/$(dirstamp): PREINSTALL_DIRS += $(PROJECT_INCLUDE)/$(dirstamp) if mpc5xx +$(PROJECT_INCLUDE)/mpc5xx/$(dirstamp): + @$(mkdir_p) $(PROJECT_INCLUDE)/mpc5xx + @: > $(PROJECT_INCLUDE)/mpc5xx/$(dirstamp) +PREINSTALL_DIRS += $(PROJECT_INCLUDE)/mpc5xx/$(dirstamp) + $(PROJECT_INCLUDE)/libcpu/$(dirstamp): @$(mkdir_p) $(PROJECT_INCLUDE)/libcpu @: > $(PROJECT_INCLUDE)/libcpu/$(dirstamp) PREINSTALL_DIRS += $(PROJECT_INCLUDE)/libcpu/$(dirstamp) +$(PROJECT_INCLUDE)/mpc5xx.h: include/mpc5xx.h $(PROJECT_INCLUDE)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/mpc5xx.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/mpc5xx.h + +$(PROJECT_INCLUDE)/mpc5xx/console.h: include/console.h $(PROJECT_INCLUDE)/mpc5xx/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/mpc5xx/console.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/mpc5xx/console.h + $(PROJECT_INCLUDE)/libcpu/raw_exception.h: exceptions/raw_exception.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/raw_exception.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/raw_exception.h -$(PROJECT_INCLUDE)/ictrl.h: ictrl/ictrl.h $(PROJECT_INCLUDE)/$(dirstamp) - $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/ictrl.h -PREINSTALL_FILES += $(PROJECT_INCLUDE)/ictrl.h +$(PROJECT_INCLUDE)/libcpu/irq.h: irq/irq.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/irq.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/irq.h + +$(PROJECT_INCLUDE)/libcpu/vectors.h: vectors/vectors.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/vectors.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/vectors.h endif CLEANFILES += $(PREINSTALL_FILES) DISTCLEANFILES = $(PREINSTALL_DIRS) -include $(top_srcdir)/../../../../../automake/local.am +include $(top_srcdir)/../../../automake/local.am diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/README b/c/src/lib/libcpu/powerpc/mpc5xx/README new file mode 100644 index 0000000000..47b9a7b9be --- /dev/null +++ b/c/src/lib/libcpu/powerpc/mpc5xx/README @@ -0,0 +1,27 @@ +# +# $Id$ +# + +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 new file mode 100644 index 0000000000..eac471218e --- /dev/null +++ b/c/src/lib/libcpu/powerpc/mpc5xx/clock/clock.c @@ -0,0 +1,196 @@ +/* clock.c + * + * 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-1998. + * 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.com/license/LICENSE. + * + * $Id$ + */ + +#include +#include +#include +#include + +#include /* for atexit() */ +#include + +volatile rtems_unsigned32 Clock_driver_ticks; +extern int BSP_connect_clock_handler(rtems_isr_entry); +extern int BSP_disconnect_clock_handler(); + +void Clock_exit( void ); + +/* + * These are set by clock driver during its init + */ + +rtems_device_major_number rtems_clock_major = ~0; +rtems_device_minor_number rtems_clock_minor; + +/* + * 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; + rtems_unsigned32 pit_value; + + /* calculate and set modulus */ + pit_value = (rtems_configuration_get_microseconds_per_tick() * + rtems_cpu_configuration_get_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 (); +} + +void Install_clock(rtems_isr_entry clock_isr) +{ + Clock_driver_ticks = 0; + + BSP_connect_clock_handler (clock_isr); + atexit(Clock_exit); +} + +void +ReInstall_clock(rtems_isr_entry new_clock_isr) +{ + BSP_connect_clock_handler (new_clock_isr); +} + + +rtems_device_driver Clock_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *pargp +) +{ + Install_clock( Clock_isr ); + + /* + * make major/minor avail to others such as shared memory driver + */ + + rtems_clock_major = major; + rtems_clock_minor = minor; + + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver Clock_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *pargp +) +{ + rtems_libio_ioctl_args_t *args = pargp; + + if (args == 0) + goto done; + + /* + * This is hokey, but until we get a defined interface + * to do this, it will just be this simple... + */ + + if (args->command == rtems_build_name('I', 'S', 'R', ' ')) { + Clock_isr(0); /* vector number ignored */ + } + else if (args->command == rtems_build_name('N', 'E', 'W', ' ')) { + ReInstall_clock(args->buffer); + } + + done: + 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 new file mode 100644 index 0000000000..89282506a7 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/mpc5xx/console-generic/console-generic.c @@ -0,0 +1,347 @@ +/* + * 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.com/license/LICENSE. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include /* for printk */ +#include +#include +#include + + +extern rtems_cpu_table Cpu_table; /* for CPU clock speed */ + +/* + * 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 */ + CS8 | CREAD | CLOCAL | B9600, /* control mode flags */ + 0, /* local mode flags */ + 0, /* line discipline */ + { 0 } /* control characters */ +}; + + +/* + * 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; +} + +int +m5xx_uart_write( + int minor, + const char *buf, + int len +) +{ + volatile m5xxSCIRegisters_t *regs = sci_descs[minor].regs; + + regs->scdr = *buf; /* start transmission */ + regs->sccr1 |= QSMCM_SCI_TIE; /* enable interrupt */ + return 0; +} + +int +m5xx_uart_pollWrite( + int minor, + const char *buf, + int len +) +{ + volatile m5xxSCIRegisters_t *regs = sci_descs[minor].regs; + + while ( len-- ) { + while ( (regs->scsr & QSMCM_SCI_TDRE) == 0 ) + ; + regs->scdr = *buf++; + } + return 0; +} + +void +m5xx_uart_reserve_resources( + rtems_configuration_table *configuration +) +{ + rtems_termios_reserve_resources (configuration, NUM_PORTS); +} + +int +m5xx_uart_setAttributes( + int minor, + const struct termios *t +) +{ + rtems_unsigned16 sccr0 = sci_descs[minor].regs->sccr0; + rtems_unsigned16 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 */ + switch (t->c_cflag & CBAUD) { + default: baud = -1; break; + case B50: baud = 50; break; + case B75: baud = 75; break; + case B110: baud = 110; break; + case B134: baud = 134; break; + case B150: baud = 150; break; + case B200: baud = 200; break; + case B300: baud = 300; break; + case B600: baud = 600; break; + case B1200: baud = 1200; break; + case B1800: baud = 1800; break; + case B2400: baud = 2400; break; + case B4800: baud = 4800; break; + case B9600: baud = 9600; break; + case B19200: baud = 19200; break; + case B38400: baud = 38400; break; + case B57600: baud = 57600; break; + case B115200: baud = 115200; break; + case B230400: baud = 230400; break; + case B460800: baud = 460800; break; + } + if (baud > 0) { + sccr0 &= ~QSMCM_SCI_BAUD(-1); + sccr0 |= + QSMCM_SCI_BAUD((Cpu_table.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 (void) +{ + 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); + } + } +} + +void m5xx_sci_nop(const rtems_irq_connect_data* ptr) +{ +} + +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/asm_utils.S b/c/src/lib/libcpu/powerpc/mpc5xx/exceptions/asm_utils.S deleted file mode 100644 index 36d9748c6b..0000000000 --- a/c/src/lib/libcpu/powerpc/mpc5xx/exceptions/asm_utils.S +++ /dev/null @@ -1,64 +0,0 @@ -/* - * asm_utils.s - * - * asm_utils.S,v 1.2 2002/04/18 20:55:37 joel Exp - * - * Copyright (C) 1999 Eric Valette (valette@crf.canon.fr) - * - * This file contains the low-level support for moving exception - * exception code to appropriate location. - * - * Adapted for MPC5XX Wilfried Busalski (w.busalski@lancier-monitoring.de) - * (C) Lancier Monitoring GmbH - */ - -#include -#include -#include - -//SPR defines -#define SPR_ICCST 560 - - - .globl codemove -codemove: - .type codemove,@function -/* r3 dest, r4 src, r5 length in bytes, r6 cachelinesize */ - cmplw cr1,r3,r4 - addi r0,r5,3 - srwi. r0,r0,2 - beq cr1,4f /* In place copy is not necessary */ - beq 7f /* Protect against 0 count */ - mtctr r0 - bge cr1,2f - - la r8,-4(r4) - la r7,-4(r3) -1: lwzu r0,4(r8) - stwu r0,4(r7) - bdnz 1b - b 4f - -2: slwi r0,r0,2 - add r8,r4,r0 - add r7,r3,r0 -3: lwzu r0,-4(r8) - stwu r0,-4(r7) - bdnz 3b - -/* Now flush the cache: note that we must start from a cache aligned - * address. Otherwise we might miss one cache line. - */ - -4: lis r0, 0x0A00 // Command Unlock All - mtspr SPR_ICCST, r0 // Cache Unlock ALL - - lis r0, 0x0C00 // Command Invalidate All - mtspr SPR_ICCST, r0 // Cache Invalidate ALL - - lis r0, 0x0200 // Command Enable All - mtspr SPR_ICCST, r0 // Cache Enable ALL - -7: sync /* Wait for all icbi to complete on bus */ - isync - blr diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/exceptions/raw_exception.c b/c/src/lib/libcpu/powerpc/mpc5xx/exceptions/raw_exception.c index 649ec0b956..12fff2394e 100644 --- a/c/src/lib/libcpu/powerpc/mpc5xx/exceptions/raw_exception.c +++ b/c/src/lib/libcpu/powerpc/mpc5xx/exceptions/raw_exception.c @@ -1,24 +1,26 @@ /* - * raw_exception.c - This file contains implementation of C function to - * Instanciate 8xx ppc primary exception entries. - * More detailled information can be found on motorola - * site and more precisely in the following book : + * 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: * - * MPC860 - * Risc Microporcessor User's Manual - * Motorola REF : MPC860UM/AD + * 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. * - * Changes for MPC5XX Wilfried Busalski (w.busalski@lancier-monitoring.de) - * Copyright (C) 2003 Lancier Monitoring GmbH - * * The license and distribution terms for this file may be * found in found in the file LICENSE in this distribution or at - * http://www.OARcorp.com/rtems/license.html. + * http://www.rtems.com/license/LICENSE. * - * raw_exception.c,v 1.5 2002/11/04 14:29:02 joel Exp + * $Id$ */ #include @@ -29,88 +31,76 @@ #include /* for printk */ #include -void * codemove(void *, const void *, unsigned int, unsigned long); - 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 mpc565_vector_is_valid(rtems_vector vector) -{ - switch(vector) { - case ASM_RESET_VECTOR: /* fall through */ - case ASM_MACH_VECTOR: - case ASM_PROT_VECTOR: - case ASM_ISI_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_ITLBERROR_VECTOR: - case ASM_DTLBERROR_VECTOR: - - case ASM_DBREAK_VECTOR: - case ASM_IBREAK_VECTOR: - case ASM_PERIFBREAK_VECTOR: - case ASM_DEVPORT_VECTOR: - return 1; - default: return 0; - } -} - int mpc5xx_vector_is_valid(rtems_vector vector) { - switch (current_ppc_cpu) { - case MPC_5XX: - if (!mpc565_vector_is_valid(vector)) { - return 0; - } - break; - default: - printk("Please complete libcpu/powerpc/mpc5xx/exceptions/raw_exception.c\n"); - printk("current_ppc_cpu = %x\n", current_ppc_cpu); - return 0; - } - return 1; + 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) { - unsigned int level; + unsigned int 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 (memcmp(mpc5xx_get_vector_addr(except->exceptIndex), (void*)default_raw_except_entry.hdl.raw_hdl,default_raw_except_entry.hdl.raw_hdl_size)) { - return 0; - } + 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; + } - _CPU_ISR_Disable(level); - - raw_except_table [except->exceptIndex] = *except; - codemove((void*)mpc5xx_get_vector_addr(except->exceptIndex), - except->hdl.raw_hdl, - except->hdl.raw_hdl_size, - PPC_CACHE_ALIGNMENT); - except->on(except); - - _CPU_ISR_Enable(level); - return 1; + _CPU_ISR_Disable(level); + + raw_except_table[except->exceptIndex] = *except; + + exception_handler_table[except->exceptIndex] = except->hdl.raw_hdl; + except->on(except); + + _CPU_ISR_Enable(level); + return 1; } int mpc5xx_get_current_exception (rtems_raw_except_connect_data* except) @@ -119,7 +109,7 @@ int mpc5xx_get_current_exception (rtems_raw_except_connect_data* except) return 0; } - *except = raw_except_table [except->exceptIndex]; + *except = raw_except_table[except->exceptIndex]; return 1; } @@ -138,20 +128,16 @@ int mpc5xx_delete_exception (const rtems_raw_except_connect_data* except) * RATIONALE : to always have the same transition by forcing the user * to get the previous handler before accepting to disconnect. */ - if (memcmp(mpc5xx_get_vector_addr(except->exceptIndex), - (void*)except->hdl.raw_hdl, - except->hdl.raw_hdl_size)) { - return 0; + if (exception_handler_table[except->exceptIndex] != except->hdl.raw_hdl) { + return 0; } + _CPU_ISR_Disable(level); except->off(except); - codemove((void*)mpc5xx_get_vector_addr(except->exceptIndex), - default_raw_except_entry.hdl.raw_hdl, - default_raw_except_entry.hdl.raw_hdl_size, - PPC_CACHE_ALIGNMENT); - - + 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; @@ -162,39 +148,37 @@ int mpc5xx_delete_exception (const rtems_raw_except_connect_data* except) /* * 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; - unsigned int level; - - /* - * store various accelerators - */ - raw_except_table = config->rawExceptHdlTbl; - local_settings = config; - default_raw_except_entry = config->defaultRawEntry; - - _CPU_ISR_Disable(level); - - for (i=0; i <= LAST_VALID_EXC; i++) { - if (!mpc5xx_vector_is_valid(i)){ - continue; - } - codemove((void*)mpc5xx_get_vector_addr(i), - raw_except_table[i].hdl.raw_hdl, - raw_except_table[i].hdl.raw_hdl_size, - PPC_CACHE_ALIGNMENT); - if (raw_except_table[i].hdl.raw_hdl != default_raw_except_entry.hdl.raw_hdl) { - raw_except_table[i].on(&raw_except_table[i]); - } - else { - raw_except_table[i].off(&raw_except_table[i]); - } + unsigned i; + unsigned int level; + + /* + * store various accelerators + */ + raw_except_table = config->rawExceptHdlTbl; + local_settings = config; + default_raw_except_entry = config->defaultRawEntry; + + _CPU_ISR_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) { + raw_except_table[i].on(&raw_except_table[i]); + } + else { + raw_except_table[i].off(&raw_except_table[i]); } - _CPU_ISR_Enable(level); + } + _CPU_ISR_Enable(level); - return 1; + return 1; } int mpc5xx_get_exception_config (rtems_raw_except_global_settings** config) diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/exceptions/raw_exception.h b/c/src/lib/libcpu/powerpc/mpc5xx/exceptions/raw_exception.h index 515a84a201..3b7e6783af 100644 --- a/c/src/lib/libcpu/powerpc/mpc5xx/exceptions/raw_exception.h +++ b/c/src/lib/libcpu/powerpc/mpc5xx/exceptions/raw_exception.h @@ -2,88 +2,62 @@ * raw_execption.h * * This file contains implementation of C function to - * Instanciate 8xx ppc primary exception entries. - * More detailled information can be found on motorola - * site and more precisely in the following book : + * Instantiate mpc5xx primary exception entries. + * More detailled information can be found on the Motorola + * site and more precisely in the following book: * - * MPC860 - * Risc Microporcessor User's Manual - * Motorola REF : MPC860UM/AD 07/98 Rev .1 + * MPC555/MPC556 User's Manual + * Motorola REF : MPC555UM/D Rev. 3, 2000 October 15 * - * Copyright (C) 1999 Eric Valette (valette@crf.canon.fr) - * Canon Centre Recherche France. * - * Changes for MPC5XX Wilfried Busalski (w.busalski@lancier-monitoring.de) - * Copyright (C) 2003 Lancier Monitoring GmbH - + * 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.h: + * + * 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 found in the file LICENSE in this distribution or at - * http://www.OARcorp.com/rtems/license.html. + * http://www.rtems.com/license/LICENSE. * - * raw_exception.h,v 1.1 2001/04/06 15:54:18 joel Exp + * $Id$ */ #ifndef _LIBCPU_MPC5XX_EXCEPTION_RAW_EXCEPTION_H #define _LIBCPU_MPC5XX_EXCEPTION_RAW_EXCEPTION_H +#include + /* - * Exception Vectors as defined in the MCP750 manual + * Exception Vectors as defined in the MPC555 User's Manual */ -#define ASM_RESET_VECTOR 0x01 -#define ASM_MACH_VECTOR 0x02 -#define ASM_PROT_VECTOR 0x03 -#define ASM_ISI_VECTOR 0x04 -#define ASM_EXT_VECTOR 0x05 -#define ASM_ALIGN_VECTOR 0x06 -#define ASM_PROG_VECTOR 0x07 -#define ASM_FLOAT_VECTOR 0x08 -#define ASM_DEC_VECTOR 0x09 - -#define ASM_SYS_VECTOR 0x0C -#define ASM_TRACE_VECTOR 0x0D -#define ASM_FLOATASSIST_VECTOR 0x0E - -#define ASM_SOFTEMUL_VECTOR 0x10 +#define ASM_RESET_VECTOR 0x01 +#define ASM_MACH_VECTOR 0x02 -#define ASM_ITLBERROR_VECTOR 0x13 -#define ASM_DTLBERROR_VECTOR 0x14 +#define ASM_EXT_VECTOR 0x05 +#define ASM_ALIGN_VECTOR 0x06 +#define ASM_PROG_VECTOR 0x07 +#define ASM_FLOAT_VECTOR 0x08 +#define ASM_DEC_VECTOR 0x09 -#define ASM_DBREAK_VECTOR 0x1C -#define ASM_IBREAK_VECTOR 0x1D -#define ASM_PERIFBREAK_VECTOR 0x1E -#define ASM_DEVPORT_VECTOR 0x1F - -#define LAST_VALID_EXC ASM_DEVPORT_VECTOR - -/* - * Vector offsets as defined in the MPC860 manual - */ - -#define ASM_RESET_VECTOR_OFFSET (ASM_RESET_VECTOR << 8) -#define ASM_MACH_VECTOR_OFFSET (ASM_MACH_VECTOR << 8) -#define ASM_PROT_VECTOR_OFFSET (ASM_PROT_VECTOR << 8) -#define ASM_ISI_VECTOR_OFFSET (ASM_ISI_VECTOR << 8) -#define ASM_EXT_VECTOR_OFFSET (ASM_EXT_VECTOR << 8) -#define ASM_ALIGN_VECTOR_OFFSET (ASM_ALIGN_VECTOR << 8) -#define ASM_PROG_VECTOR_OFFSET (ASM_PROG_VECTOR << 8) -#define ASM_FLOAT_VECTOR_OFFSET (ASM_FLOAT_VECTOR << 8) -#define ASM_DEC_VECTOR_OFFSET (ASM_DEC_VECTOR << 8) +#define ASM_SYS_VECTOR 0x0C +#define ASM_TRACE_VECTOR 0x0D +#define ASM_FLOATASSIST_VECTOR 0x0E -#define ASM_SYS_VECTOR_OFFSET (ASM_SYS_VECTOR << 8) -#define ASM_TRACE_VECTOR_OFFSET (ASM_TRACE_VECTOR << 8) -#define ASM_FLOATASSIST_VECTOR_OFFSET (ASM_FLOATASSIST_VECTOR << 8) +#define ASM_SOFTEMUL_VECTOR 0x10 -#define ASM_SOFTEMUL_VECTOR_OFFSET (ASM_SOFTEMUL_VECTOR << 8) +#define ASM_IPROT_VECTOR 0x13 +#define ASM_DPROT_VECTOR 0x14 -#define ASM_ITLBERROR_VECTOR_OFFSET (ASM_ITLBERROR_VECTOR << 8) -#define ASM_DTLBERROR_VECTOR_OFFSET (ASM_DTLBERROR_VECTOR << 8) +#define ASM_DBREAK_VECTOR 0x1C +#define ASM_IBREAK_VECTOR 0x1D +#define ASM_MEBREAK_VECTOR 0x1E +#define ASM_NMEBREAK_VECTOR 0x1F -#define ASM_DBREAK_VECTOR_OFFSET (ASM_DBREAK_VECTOR << 8) -#define ASM_IBREAK_VECTOR_OFFSET (ASM_IBREAK_VECTOR << 8) -#define ASM_PERIFBREAK_VECTOR_OFFSET (ASM_PERIFBREAK_VECTOR << 8) -#define ASM_DEVPORT_VECTOR_OFFSET (ASM_DEVPORT_VECTOR_OFFSET << 8) +#define LAST_VALID_EXC ASM_NMEBREAK_VECTOR #ifndef ASM @@ -93,13 +67,11 @@ typedef unsigned char rtems_vector; struct __rtems_raw_except_connect_data__; -typedef void (*rtems_raw_except_func) (void); typedef unsigned char rtems_raw_except_hdl_size; typedef struct { rtems_vector vector; - rtems_raw_except_func raw_hdl; - rtems_raw_except_hdl_size raw_hdl_size; + rtems_exception_handler_t* raw_hdl; }rtems_raw_except_hdl; typedef void (*rtems_raw_except_enable) (const struct __rtems_raw_except_connect_data__*); @@ -186,5 +158,7 @@ extern int mpc5xx_get_exception_config (rtems_raw_except_global_settings** confi # endif /* ASM */ +#define SIZEOF_ + #endif diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/include/console.h b/c/src/lib/libcpu/powerpc/mpc5xx/include/console.h new file mode 100644 index 0000000000..83dbe8b7f3 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/mpc5xx/include/console.h @@ -0,0 +1,37 @@ +/* + * Console declarations + * + * + * MPC5xx port sponsored by Defence Research and Development Canada - Suffield + * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifndef _M5xx_CONSOLE_H_ +#define _M5xx_CONSOLE_H_ + +#include +#include + +void m5xx_uart_reserve_resources(rtems_configuration_table *configuration); +void m5xx_uart_initialize(int minor); + +/* Termios callbacks */ +int m5xx_uart_firstOpen(int maj, int min, void *arg); +int m5xx_uart_lastClose(int maj, int min, void *arg); +int m5xx_uart_pollRead(int minor); +int m5xx_uart_pollWrite(int minor, const char* buf, int len); +int m5xx_uart_write(int minor, const char *buf, int len); +int m5xx_uart_setAttributes(int, const struct termios* t); + +#define NUM_PORTS 2 /* number of serial ports */ + +#define SCI1_MINOR 0 +#define SCI2_MINOR 1 + +#endif /* _M5xx_CONSOLE_H_ */ diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/include/mpc5xx.h b/c/src/lib/libcpu/powerpc/mpc5xx/include/mpc5xx.h new file mode 100644 index 0000000000..2ec40702ea --- /dev/null +++ b/c/src/lib/libcpu/powerpc/mpc5xx/include/mpc5xx.h @@ -0,0 +1,621 @@ +/* + * mpc5xx.h + * + * MPC5xx Internal I/O Definitions + * + * + * 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/include/mpc8xx.h: + * + * Submitted By: * + * * + * W. Eric Norum * + * Saskatchewan Accelerator Laboratory * + * University of Saskatchewan * + * 107 North Road * + * Saskatoon, Saskatchewan, CANADA * + * S7N 5C6 * + * * + * eric@skatter.usask.ca * + * * + * Modified for use with the MPC860 (original code was for MC68360) * + * by * + * Jay Monkman * + * Frasca International, Inc. * + * 906 E. Airport Rd. * + * Urbana, IL, 61801 * + * * + * jmonkman@frasca.com * + * * + * Modified further for use with the MPC821 by: * + * Andrew Bray * + * * + * With some corrections/additions by: * + * Darlene A. Stewart and * + * Charles-Antoine Gauthier * + * Institute for Information Technology * + * National Research Council of Canada * + * Ottawa, ON K1A 0R6 * + * * + * Darlene.Stewart@iit.nrc.ca * + * charles.gauthier@iit.nrc.ca * + * * + * Corrections/additions: * + * Copyright (c) 1999, National Research Council of Canada * + * + * MPC5xx port sponsored by Defence Research and Development Canada - Suffield + * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifndef _MPC5xx_h +#define _MPC5xx_h + +#include + + +#ifndef ASM + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Macros for accessing Special Purpose Registers (SPRs) + */ + +#define _eieio __asm__ volatile ("eieio\n"::) +#define _sync __asm__ volatile ("sync\n"::) +#define _isync __asm__ volatile ("isync\n"::) + +/* + * Core Registers (SPRs) + */ +#define DER 149 /* Debug Enable Register */ +#define IMMR 638 /* Internal Memory Map Register */ +#define IMMR_FLEN (1<<11) /* Internal flash ROM enabled */ + +/* + * Interrupt Control Registers (SPRs) + */ +#define EIE 80 /* External Interrupt Enable Register */ +#define EID 81 /* External Interrupt Disable Register */ +#define NRI 82 /* Non-Recoverable Interrupt Register */ + +#define ECR 148 /* Exception Cause Register */ + +/* + * Bus Control Registers (SPRs) + */ +#define LCTRL1 156 /* L-Bus Support Control Register 1 */ +#define LCTRL2 157 /* L-Bus Support Control Register 2 */ +#define ICTRL 158 /* I-Bus Support Control Register */ + +/* + * Burst Buffer Control Registers (SPRs) + */ +#define BBCMCR 560 /* Burst Buffer Configuration Register */ +#define BBCMCR_BE (1<<13) /* Burst enable */ +#define BBCMCR_ETRE (1<<12) /* Exception table relocation enable */ + +#define MI_RBA0 784 /* Region 0 Address Register */ +#define MI_RBA1 785 /* Region 1 Address Register */ +#define MI_RBA2 786 /* Region 2 Address Register */ +#define MI_RBA3 787 /* Region 3 Address Register */ + +#define MI_RA0 816 /* Region 0 Attribute Register */ +#define MI_RA1 817 /* Region 1 Attribute Register */ +#define MI_RA2 818 /* Region 2 Attribute Register */ +#define MI_RA3 819 /* Region 3 Attribute Register */ +#define MI_GRA 528 /* Region Global Attribute Register */ +#define MI_RA_PP (3 << 10) /* Protection bits: */ +#define MI_RA_PP_SUPV (1 << 10) /* Supervisor */ +#define MI_RA_PP_USER (2 << 10) /* User */ +#define MI_RA_G (1 << 6) /* Guarded region */ + + +/* + * L-Bus to U-Bus Interface (L2U) Registers (SPRs) + */ +#define L2U_MCR 568 /* L2U Module Configuration Register */ + +#define L2U_RBA0 792 /* L2U Region 0 Address Register */ +#define L2U_RBA1 793 /* L2U Region 1 Address Register */ +#define L2U_RBA2 794 /* L2U Region 2 Address Register */ +#define L2U_RBA3 795 /* L2U Region 3 Address Register */ + +#define L2U_RA0 824 /* L2U Region 0 Attribute Register */ +#define L2U_RA1 825 /* L2U Region 1 Attribute Register */ +#define L2U_RA2 826 /* L2U Region 2 Attribute Register */ +#define L2U_RA3 827 /* L2U Region 3 Attribute Register */ +#define L2U_GRA 536 /* L2U Global Region Attribute Register */ +#define L2U_RA_PP (3 << 10) /* Protection bits: */ +#define L2U_RA_PP_SUPV (1 << 10) /* Supervisor */ +#define L2U_RA_PP_USER (2 << 10) /* User */ +#define L2U_RA_G (1 << 6) /* Guarded region */ + + +/* + ************************************************************************* + * REGISTER SUBBLOCKS * + ************************************************************************* + */ + +/* + ************************************************************************* + * System Protection Control Register (SYPCR) * + ************************************************************************* + */ +#define USIU_SYPCR_SWTC(x) ((x)<<16) /* Software watchdog timer count */ +#define USIU_SYPCR_BMT(x) ((x)<<8) /* Bus monitor timing */ +#define USIU_SYPCR_BME (1<<7) /* Bus monitor enable */ +#define USIU_SYPCR_SWF (1<<3) /* Software watchdog freeze */ +#define USIU_SYPCR_SWE (1<<2) /* Software watchdog enable */ +#define USIU_SYPCR_SWRI (1<<1) /* Watchdog reset/interrupt sel. */ +#define USIU_SYPCR_SWP (1<<0) /* Software watchdog prescale */ + +#define USIU_SYPCR_BMT(x) ((x)<<8) /* Bus monitor timing */ +#define USIU_SYPCR_BME (1<<7) /* Bus monitor enable */ +#define USIU_SYPCR_SWF (1<<3) /* Software watchdog freeze */ +#define USIU_SYPCR_SWE (1<<2) /* Software watchdog enable */ +#define USIU_SYPCR_SWRI (1<<1) /* Watchdog reset/interrupt sel. */ +#define USIU_SYPCR_SWP (1<<0) /* Software watchdog prescale */ + +/* + ************************************************************************* + * Software Service Register (SWSR) * + ************************************************************************* + */ +#define TICKLE_WATCHDOG() \ +do { \ + usiu.swsr = 0x556C; \ + usiu.swsr = 0xAA39; \ +} while (0) \ + +/* + ************************************************************************* + * Memory Control Registers * + ************************************************************************* + */ +#define USIU_MEMC_BR_BA(x) (((rtems_unsigned32)x)&0xffff8000) + /* Base address */ +#define USIU_MEMC_BR_AT(x) ((x)<<12) /* Address type */ +#define USIU_MEMC_BR_PS8 (1<<10) /* 8 bit port */ +#define USIU_MEMC_BR_PS16 (2<<10) /* 16 bit port */ +#define USIU_MEMC_BR_PS32 (0<<10) /* 32 bit port */ +#define USIU_MEMC_BR_WP (1<<8) /* Write protect */ +#define USIU_MEMC_BR_WEBS (1<<5) /* Write enable/byte select */ +#define USIU_MEMC_BR_TBDIP (1<<4) /* Toggle-Burst data in progress*/ +#define USIU_MEMC_BR_LBDIP (1<<3) /* Late-burst data in progress */ +#define USIU_MEMC_BR_SETA (1<<2) /* External transfer acknowledge */ +#define USIU_MEMC_BR_BI (1<<1) /* Burst inhibit */ +#define USIU_MEMC_BR_V (1<<0) /* Base/Option register are valid */ + +#define USIU_MEMC_OR_32K 0xffff8000 /* Address range */ +#define USIU_MEMC_OR_64K 0xffff0000 +#define USIU_MEMC_OR_128K 0xfffe0000 +#define USIU_MEMC_OR_256K 0xfffc0000 +#define USIU_MEMC_OR_512K 0xfff80000 +#define USIU_MEMC_OR_1M 0xfff00000 +#define USIU_MEMC_OR_2M 0xffe00000 +#define USIU_MEMC_OR_4M 0xffc00000 +#define USIU_MEMC_OR_8M 0xff800000 +#define USIU_MEMC_OR_16M 0xff000000 +#define USIU_MEMC_OR_32M 0xfe000000 +#define USIU_MEMC_OR_64M 0xfc000000 +#define USIU_MEMC_OR_128 0xf8000000 +#define USIU_MEMC_OR_256M 0xf0000000 +#define USIU_MEMC_OR_512M 0xe0000000 +#define USIU_MEMC_OR_1G 0xc0000000 +#define USIU_MEMC_OR_2G 0x80000000 +#define USIU_MEMC_OR_4G 0x00000000 +#define USIU_MEMC_OR_ATM(x) ((x)<<12) /* Address type mask */ +#define USIU_MEMC_OR_CSNT (1<<11) /* Chip select is negated early */ +#define USIU_MEMC_OR_ACS_NORM (0<<9) /* *CS asserted with addr lines */ +#define USIU_MEMC_OR_ACS_QRTR (2<<9) /* *CS asserted 1/4 after addr */ +#define USIU_MEMC_OR_ACS_HALF (3<<9) /* *CS asserted 1/2 after addr */ +#define USIU_MEMC_OR_ETHR (1<<8) /* Extended hold time on reads */ +#define USIU_MEMC_OR_SCY(x) ((x)<<4) /* Cycle length in clocks */ +#define USIU_MEMC_OR_BSCY(x) ((x)<<1) /* Burst beat length in clocks */ +#define USIU_MEMC_OR_TRLX (1<<0) /* Relaxed timing in GPCM */ + +/* + ************************************************************************* + * Clocks and Reset Controlmer * + ************************************************************************* + */ + +#define USIU_SCCR_DBCT (1<<31) /* Disable backup clock for timers */ +#define USIU_SCCR_COM(x) ((x)<<29) /* Clock output mode */ +#define USIU_SCCR_RTDIV (1<<24) /* RTC, PIT divide by 256, not 4 */ +#define USIU_PRQEN (1<<21) /* MSR[POW] controls frequency */ +#define USIU_SCCR_EBDF(x) ((x)<<17) /* External bus division factor */ +#define USIU_LME (1<<16) /* Enable limp mode */ +#define USIU_ENGDIV(x) ((x)<<9) /* Set engineering clock divisor */ + +#define USIU_PLPRCR_MF(x) (((x)-1)<<20) /* PLL mult. factor (true) */ +#define USIU_PLPRCR_SPLS (1<<16) /* System PLL locked */ +#define USIU_PLPRCR_TEXPS (1<<14) /* Assert TEXP always */ + +/* + ************************************************************************* + * Programmable Interval Timer * + ************************************************************************* + */ +#define USIU_PISCR_PIRQ(x) (1<<(15-x)) /* PIT interrupt level */ +#define USIU_PISCR_PS (1<<7) /* PIT Interrupt state */ +#define USIU_PISCR_PIE (1<<2) /* PIT interrupt enable */ +#define USIU_PISCR_PITF (1<<1) /* Stop timer when freeze asserted */ +#define USIU_PISCR_PTE (1<<0) /* PIT enable */ + +/* + ************************************************************************* + * Time Base * + ************************************************************************* + */ +#define USIU_TBSCR_TBIRQ(x) (1<<(15-x)) /* TB interrupt level */ +#define USIU_TBSCR_REFA (1<<7) /* TB matches TBREFF0 */ +#define USIU_TBSCR_REFB (1<<6) /* TB matches TBREFF1 */ +#define USIU_TBSCR_REFAE (1<<3) /* Enable ints for REFA */ +#define USIU_TBSCR_REFBE (1<<2) /* Enable ints for REFB */ +#define USIU_TBSCR_TBF (1<<1) /* TB stops on FREEZE */ +#define USIU_TBSCR_TBE (1<<0) /* enable TB and decrementer */ + +/* + ************************************************************************* + * SIU Interrupt Mask * + ************************************************************************* + */ +#define USIU_SIMASK_IRM0 (1<<31) +#define USIU_SIMASK_LVM0 (1<<30) +#define USIU_SIMASK_IRM1 (1<<29) +#define USIU_SIMASK_LVM1 (1<<28) +#define USIU_SIMASK_IRM2 (1<<27) +#define USIU_SIMASK_LVM2 (1<<26) +#define USIU_SIMASK_IRM3 (1<<25) +#define USIU_SIMASK_LVM3 (1<<24) +#define USIU_SIMASK_IRM4 (1<<23) +#define USIU_SIMASK_LVM4 (1<<22) +#define USIU_SIMASK_IRM5 (1<<21) +#define USIU_SIMASK_LVM5 (1<<20) +#define USIU_SIMASK_IRM6 (1<<19) +#define USIU_SIMASK_LVM6 (1<<18) +#define USIU_SIMASK_IRM7 (1<<17) +#define USIU_SIMASK_LVM7 (1<<16) + +/* + ************************************************************************* + * SIU Module Control * + ************************************************************************* + */ +#define USIU_SIUMCR_EARB (1<<31) +#define USIU_SIUMCR_EARP0 (0<<28) +#define USIU_SIUMCR_EARP1 (1<<28) +#define USIU_SIUMCR_EARP2 (2<<28) +#define USIU_SIUMCR_EARP3 (3<<28) +#define USIU_SIUMCR_EARP4 (4<<28) +#define USIU_SIUMCR_EARP5 (5<<28) +#define USIU_SIUMCR_EARP6 (6<<28) +#define USIU_SIUMCR_EARP7 (7<<28) +#define USIU_SIUMCR_DSHW (1<<23) +#define USIU_SIUMCR_DBGC0 (0<<21) +#define USIU_SIUMCR_DBGC1 (1<<21) +#define USIU_SIUMCR_DBGC2 (2<<21) +#define USIU_SIUMCR_DBGC3 (3<<21) +#define USIU_SIUMCR_DBPC (1<<20) +#define USIU_SIUMCR_ATWC (1<<19) +#define USIU_SIUMCR_GPC0 (0<<17) +#define USIU_SIUMCR_GPC1 (1<<17) +#define USIU_SIUMCR_GPC2 (2<<17) +#define USIU_SIUMCR_GPC3 (3<<17) +#define USIU_SIUMCR_DLK (1<<16) +#define USIU_SIUMCR_SC0 (0<<13) +#define USIU_SIUMCR_SC1 (1<<13) +#define USIU_SIUMCR_SC2 (2<<13) +#define USIU_SIUMCR_SC3 (3<<13) +#define USIU_SIUMCR_RCTX (1<<12) +#define USIU_SIUMCR_MLRC0 (0<<10) +#define USIU_SIUMCR_MLRC1 (1<<10) +#define USIU_SIUMCR_MLRC2 (2<<10) +#define USIU_SIUMCR_MLRC3 (3<<10) +#define USIU_SIUMCR_MTSC (1<<7) + +/* + * Value to write to a key register to unlock the corresponding SIU register + */ +#define USIU_UNLOCK_KEY 0x55CCAA33 + +/* + ************************************************************************* + * UIMB Module Control * + ************************************************************************* + */ +#define UIMB_UMCR_STOP (1<<31) +#define UIMB_UMCR_IRQMUX(x) ((x)<<29) +#define UIMB_UMCR_HSPEED (1<<28) + +/* + ************************************************************************* + * QSMCM Serial Communications Interface (SCI) * + ************************************************************************* + */ + + +#define QSMCM_ILDSCI(x) ((x)<<8) /* SCI interrupt level */ + +#define QSMCM_SCI_BAUD(x) ((x)&0x1FFF) /* Baud rate field */ + +#define QSMCM_SCI_LOOPS (1<<14) /* Loopback test mode */ +#define QSMCM_SCI_WOMS (1<<13) /* Wire-or mode select */ +#define QSMCM_SCI_ILT (1<<12) /* Idle-line detect type */ +#define QSMCM_SCI_PT (1<<11) /* Parity type */ +#define QSMCM_SCI_PE (1<<10) /* Parity enable */ +#define QSMCM_SCI_M (1<<9) /* 11-bit mode */ +#define QSMCM_SCI_WAKE (1<<8) /* Wakeup mode */ + +#define QSMCM_SCI_TIE (1<<7) /* Transmitter interrupt enable */ +#define QSMCM_SCI_TCIE (1<<6) /* Transmit complete intr. enable */ +#define QSMCM_SCI_RIE (1<<5) /* Receiver interrupt enable */ +#define QSMCM_SCI_ILIE (1<<4) /* Idle line interrupt enable */ +#define QSMCM_SCI_TE (1<<3) /* Transmitter enable */ +#define QSMCM_SCI_RE (1<<2) /* Receiver enable */ +#define QSMCM_SCI_RWU (1<<1) /* Receiver wake-up enable */ +#define QSMCM_SCI_SBK (1<<0) /* Send break */ + +#define QSMCM_SCI_TDRE (1<<8) /* Transmit data register empty */ +#define QSMCM_SCI_TC (1<<7) /* Transmit complete */ +#define QSMCM_SCI_RDRF (1<<6) /* Receive data register full */ +#define QSMCM_SCI_RAF (1<<5) /* Receiver active flag */ +#define QSMCM_SCI_IDLE (1<<4) /* Idle line detected */ +#define QSMCM_SCI_OR (1<<3) /* Receiver overrun error */ +#define QSMCM_SCI_NF (1<<2) /* Receiver noise error flag */ +#define QSMCM_SCI_FE (1<<1) /* Receiver framing error */ +#define QSMCM_SCI_PF (1<<0) /* Receiver parity error */ + +/* + ************************************************************************* + * Unified System Interface Unit * + ************************************************************************* + */ + +/* + * Memory controller registers + */ +typedef struct m5xxMEMCRegisters_ { + rtems_unsigned32 _br; + rtems_unsigned32 _or; /* Used to be called 'or'; reserved ANSI C++ keyword */ +} m5xxMEMCRegisters_t; + +/* + * USIU itself + */ +typedef struct usiu_ { + /* + * SIU Block + */ + rtems_unsigned32 siumcr; + rtems_unsigned32 sypcr; + rtems_unsigned32 _pad70; + rtems_unsigned16 _pad0; + rtems_unsigned16 swsr; + rtems_unsigned32 sipend; + rtems_unsigned32 simask; + rtems_unsigned32 siel; + rtems_unsigned32 sivec; + rtems_unsigned32 tesr; + rtems_unsigned32 sgpiodt1; + rtems_unsigned32 sgpiodt2; + rtems_unsigned32 sgpiocr; + rtems_unsigned32 emcr; + rtems_unsigned8 _pad71[0x03C-0x034]; + rtems_unsigned32 pdmcr; + rtems_unsigned8 _pad2[0x100-0x40]; + + /* + * MEMC Block + */ + m5xxMEMCRegisters_t memc[4]; + rtems_unsigned8 _pad7[0x140-0x120]; + rtems_unsigned32 dmbr; + rtems_unsigned32 dmor; + rtems_unsigned8 _pad8[0x178-0x148]; + rtems_unsigned16 mstat; + rtems_unsigned8 _pad9[0x200-0x17A]; + + /* + * System integration timers + */ + rtems_unsigned16 tbscr; + rtems_unsigned16 _pad10; + rtems_unsigned32 tbreff0; + rtems_unsigned32 tbreff1; + rtems_unsigned8 _pad11[0x220-0x20c]; + rtems_unsigned16 rtcsc; + rtems_unsigned16 _pad12; + rtems_unsigned32 rtc; + rtems_unsigned32 rtsec; + rtems_unsigned32 rtcal; + rtems_unsigned32 _pad13[4]; + rtems_unsigned16 piscr; + rtems_unsigned16 _pad14; + rtems_unsigned16 pitc; + rtems_unsigned16 _pad_14_1; + rtems_unsigned16 pitr; + rtems_unsigned16 _pad_14_2; + rtems_unsigned8 _pad15[0x280-0x24c]; + + /* + * Clocks and Reset + */ + rtems_unsigned32 sccr; + rtems_unsigned32 plprcr; + rtems_unsigned16 rsr; + rtems_unsigned16 _pad72; + rtems_unsigned16 colir; + rtems_unsigned16 _pad73; + rtems_unsigned16 vsrmcr; + rtems_unsigned8 _pad16[0x300-0x292]; + + /* + * System integration timers keys + */ + rtems_unsigned32 tbscrk; + rtems_unsigned32 tbreff0k; + rtems_unsigned32 tbreff1k; + rtems_unsigned32 tbk; + rtems_unsigned32 _pad17[4]; + rtems_unsigned32 rtcsk; + rtems_unsigned32 rtck; + rtems_unsigned32 rtseck; + rtems_unsigned32 rtcalk; + rtems_unsigned32 _pad18[4]; + rtems_unsigned32 piscrk; + rtems_unsigned32 pitck; + rtems_unsigned8 _pad19[0x380-0x348]; + + /* + * Clocks and Reset Keys + */ + rtems_unsigned32 sccrk; + rtems_unsigned32 plprck; + rtems_unsigned32 rsrk; + rtems_unsigned8 _pad20[0x400-0x38c]; +} usiu_t; + +extern volatile usiu_t usiu; /* defined in linkcmds */ + +/* + ************************************************************************* + * Inter-Module Bus and Devices * + ************************************************************************* + */ + +/* + * Dual-Port TPU RAM (DPTRAM) + */ +typedef struct m5xxDPTRAMRegisters_ { + rtems_unsigned8 pad[0x4000]; /* define later */ +} m5xxDPTRAMRegisters_t; + +/* + * Time Processor Unit (TPU) + */ +typedef struct m5xxTPU3Registers_ { + rtems_unsigned8 pad[0x400]; /* define later */ +} m5xxTPU3Registers_t; + +/* + * Queued A/D Converter (QADC) + */ +typedef struct m5xxQADC64Registers_ { + rtems_unsigned8 pad[0x400]; /* define later */ +} m5xxQADC64Registers_t; + +/* + * Serial Communications Interface (SCI) + */ +typedef struct m5xxSCIRegisters_ { + rtems_unsigned16 sccr0; + rtems_unsigned16 sccr1; + rtems_unsigned16 scsr; + rtems_unsigned16 scdr; +} m5xxSCIRegisters_t; + +/* + * Serial Peripheral Interface (SPI) + */ +typedef struct m5xxSPIRegisters_ { + rtems_unsigned16 spcr0; + rtems_unsigned16 spcr1; + rtems_unsigned16 spcr2; + rtems_unsigned8 spcr3; + rtems_unsigned8 spsr; +} m5xxSPIRegisters_t; + +/* + * Queued Serial Multi-Channel Module (QSMCM) + */ +typedef struct m5xxQSMCMRegisters_ { + rtems_unsigned16 qsmcmmcr; + rtems_unsigned16 qtest; + rtems_unsigned16 qdsci_il; + rtems_unsigned16 qspi_il; + + m5xxSCIRegisters_t sci1; + + rtems_unsigned8 _pad10[0x14-0x10]; + + rtems_unsigned16 portqs; + rtems_unsigned16 pqspar; + m5xxSPIRegisters_t spi; + + m5xxSCIRegisters_t sci2; + + rtems_unsigned16 qsci1cr; + rtems_unsigned16 qsci1sr; + rtems_unsigned16 sctq[0x10]; + rtems_unsigned16 scrq[0x10]; + + rtems_unsigned8 _pad6C[0x140-0x06C]; + + rtems_unsigned16 recram[0x20]; + rtems_unsigned16 tranram[0x20]; + rtems_unsigned16 comdram[0x20]; +} m5xxQSMCMRegisters_t; + +/* + * Modular Input/Output System (MIOS) + */ +typedef struct m5xxMIOS1Registers_ { + rtems_unsigned8 pad[0x1000]; /* define later */ +} m5xxMIOS1Registers_t; + +/* + * Can 2.0B Controller (TouCAN) + */ +typedef struct m5xxTouCANRegisters_ { + rtems_unsigned8 pad[0x400]; /* define later */ +} m5xxTouCANRegisters_t; + +/* + * U-Bus to IMB3 Bus Interface Module (UIMB) + */ +typedef struct m5xxUIMBRegisters_ { + rtems_unsigned32 umcr; + rtems_unsigned32 utstcreg; + rtems_unsigned32 uipend; +} m5xxUIMBRegisters_t; + +/* + * IMB itself + */ +typedef struct imb_ { + m5xxDPTRAMRegisters_t dptram; + m5xxTPU3Registers_t tpu[2]; + m5xxQADC64Registers_t qadc[2]; + m5xxQSMCMRegisters_t qsmcm; + rtems_unsigned8 _pad5200[0x6000-0x5200]; + m5xxMIOS1Registers_t mios; + m5xxTouCANRegisters_t toucan[2]; + rtems_unsigned8 _pad7800[0x7F80-0x7800]; + m5xxUIMBRegisters_t uimb; +} imb_t; + +extern volatile imb_t imb; /* defined in linkcmds */ + + +#ifdef __cplusplus +} +#endif + +#endif /* ASM */ + +#endif /* _MPC5xx_h */ + diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.c b/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.c new file mode 100644 index 0000000000..40bf8341bc --- /dev/null +++ b/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.c @@ -0,0 +1,495 @@ +/* + * irq.c + * + * 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 found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include + +/* + * Convert an rtems_irq_symbolic_name 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_symbolic_name 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_symbolic_name 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_symbolic_name 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_symbolic_name 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 () +{ + /* + * 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; +} + +int CPU_irq_enable_at_uimb(const rtems_irq_symbolic_name irqLine) +{ + if (!is_uimb_irq(irqLine)) + return 1; + return 0; +} + +int CPU_irq_disable_at_uimb(const rtems_irq_symbolic_name irqLine) +{ + if (!is_uimb_irq(irqLine)) + return 1; + return 0; +} + +int CPU_irq_enabled_at_uimb(const rtems_irq_symbolic_name irqLine) +{ + if (!is_uimb_irq(irqLine)) + return 0; + return 1; +} + +int CPU_irq_enable_at_usiu(const rtems_irq_symbolic_name 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; +} + +int CPU_irq_disable_at_usiu(const rtems_irq_symbolic_name 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; +} + +int CPU_irq_enabled_at_usiu(const rtems_irq_symbolic_name irqLine) +{ + int usiu_irq_index; + + if (!is_usiu_irq(irqLine)) + return 0; + + usiu_irq_index = ((int) (irqLine) - CPU_USIU_IRQ_MIN_OFFSET); + return ppc_cached_irq_mask & (1 << (31-usiu_irq_index)); +} + +/* + * --------------- RTEMS Single Irq Handler Mngt Routines ---------------- + */ + +int CPU_install_rtems_irq_handler (const rtems_irq_connect_data* irq) +{ + unsigned int 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; + } + + _CPU_ISR_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 + */ + irq->on(irq); + + _CPU_ISR_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) +{ + unsigned int 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; + } + _CPU_ISR_Disable(level); + + /* + * Disable interrupt on device + */ + 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; + + _CPU_ISR_Enable(level); + + return 1; +} + +/* + * ---------------- RTEMS Global Irq Handler Mngt Routines ---------------- + */ + +int CPU_rtems_irq_mngt_set (rtems_irq_global_settings* config) +{ + int i; + unsigned int level; + + /* + * Store various code accelerators + */ + internal_config = config; + default_rtems_entry = config->defaultEntry; + rtems_hdl_tbl = config->irqHdlTbl; + + _CPU_ISR_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); + rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); + } + else { + 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); + rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); + } + else { + 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) { + rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); + } + else { + rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); + } + } + _CPU_ISR_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 (CPU_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(); + + _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(); + + _CPU_MSR_SET(msr); + + ppc_cached_irq_mask = oldMask; + usiu.simask = ppc_cached_irq_mask; + } +} + +void _ThreadProcessSignalsFromIrq (CPU_Exception_frame* ctx) +{ + /* + * Process pending signals that have not already been + * processed by _Thread_Displatch. This happens quite + * unfrequently : the ISR must have posted an action + * to the current running thread. + */ + if ( _Thread_Do_post_task_switch_extension || + _Thread_Executing->do_post_task_switch_extension ) { + _Thread_Executing->do_post_task_switch_extension = FALSE; + _API_extensions_Run_postswitch(); + } + /* + * I plan to process other thread related events here. + * This will include DEBUG session requested from keyboard... + */ +} diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.h b/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.h new file mode 100644 index 0000000000..dd4f9948e1 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.h @@ -0,0 +1,358 @@ +/* + * irq.h + * + * This include file describe the data structure and the functions implemented + * by rtems to write interrupt handlers. + * + * + * 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.h: + * + * CopyRight (C) 1999 valette@crf.canon.fr + * + * This code is heavilly inspired by the public specification of STREAM V2 + * that can be found at : + * + * by following + * the STREAM API Specification Document link. + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifndef LIBCPU_POWERPC_MBX8XX_IRQ_IRQ_H +#define LIBCPU_POWERPC_MBX8XX_IRQ_IRQ_H + + +#define CPU_ASM_IRQ_VECTOR_BASE 0x0 + +#ifndef ASM + +extern volatile unsigned int ppc_cached_irq_mask; + +/* + * Symblolic IRQ names and related definitions. + */ + +typedef enum { + /* + * Base vector for our USIU IRQ handlers. + */ + CPU_USIU_VECTOR_BASE = CPU_ASM_IRQ_VECTOR_BASE, + /* + * USIU IRQ handler related definitions + */ + CPU_USIU_IRQ_COUNT = 16, /* 16 reserved but in the future... */ + CPU_USIU_IRQ_MIN_OFFSET = 0, + CPU_USIU_IRQ_MAX_OFFSET = CPU_USIU_IRQ_MIN_OFFSET + CPU_USIU_IRQ_COUNT - 1, + /* + * UIMB IRQ handlers related definitions + */ + CPU_UIMB_IRQ_COUNT = 32 - 8, /* first 8 overlap USIU */ + CPU_UIMB_IRQ_MIN_OFFSET = CPU_USIU_IRQ_COUNT + CPU_USIU_VECTOR_BASE, + CPU_UIMB_IRQ_MAX_OFFSET = CPU_UIMB_IRQ_MIN_OFFSET + CPU_UIMB_IRQ_COUNT - 1, + /* + * PowerPc exceptions handled as interrupt where a rtems managed interrupt + * handler might be connected + */ + CPU_PROC_IRQ_COUNT = 1, + CPU_PROC_IRQ_MIN_OFFSET = CPU_UIMB_IRQ_MAX_OFFSET + 1, + CPU_PROC_IRQ_MAX_OFFSET = CPU_PROC_IRQ_MIN_OFFSET + CPU_PROC_IRQ_COUNT - 1, + /* + * Summary + */ + CPU_IRQ_COUNT = CPU_PROC_IRQ_MAX_OFFSET + 1, + CPU_MIN_OFFSET = CPU_USIU_IRQ_MIN_OFFSET, + CPU_MAX_OFFSET = CPU_PROC_IRQ_MAX_OFFSET, + /* + * USIU IRQ symbolic name definitions. + */ + CPU_USIU_EXT_IRQ_0 = CPU_USIU_IRQ_MIN_OFFSET, + CPU_USIU_INT_IRQ_0, + + CPU_USIU_EXT_IRQ_1, + CPU_USIU_INT_IRQ_1, + + CPU_USIU_EXT_IRQ_2, + CPU_USIU_INT_IRQ_2, + + CPU_USIU_EXT_IRQ_3, + CPU_USIU_INT_IRQ_3, + + CPU_USIU_EXT_IRQ_4, + CPU_USIU_INT_IRQ_4, + + CPU_USIU_EXT_IRQ_5, + CPU_USIU_INT_IRQ_5, + + CPU_USIU_EXT_IRQ_6, + CPU_USIU_INT_IRQ_6, + + CPU_USIU_EXT_IRQ_7, + CPU_USIU_INT_IRQ_7, + + /* + * Symbolic names for UISU interrupt sources. + */ + CPU_PERIODIC_TIMER = CPU_USIU_INT_IRQ_6, + CPU_UIMB_INTERRUPT = CPU_USIU_INT_IRQ_7, + + /* + * UIMB IRQ symbolic name definitions. The first 8 sources are aliases to + * the USIU interrupts of the same number, because they are detected in + * the USIU pending register rather than the UIMB pending register. + */ + CPU_UIMB_IRQ_0 = CPU_USIU_INT_IRQ_0, + CPU_UIMB_IRQ_1 = CPU_USIU_INT_IRQ_1, + CPU_UIMB_IRQ_2 = CPU_USIU_INT_IRQ_2, + CPU_UIMB_IRQ_3 = CPU_USIU_INT_IRQ_3, + CPU_UIMB_IRQ_4 = CPU_USIU_INT_IRQ_4, + CPU_UIMB_IRQ_5 = CPU_USIU_INT_IRQ_5, + CPU_UIMB_IRQ_6 = CPU_USIU_INT_IRQ_6, + CPU_UIMB_IRQ_7 = CPU_USIU_INT_IRQ_7, + + CPU_UIMB_IRQ_8 = CPU_UIMB_IRQ_MIN_OFFSET, + CPU_UIMB_IRQ_9, + CPU_UIMB_IRQ_10, + CPU_UIMB_IRQ_11, + CPU_UIMB_IRQ_12, + CPU_UIMB_IRQ_13, + CPU_UIMB_IRQ_14, + CPU_UIMB_IRQ_15, + CPU_UIMB_IRQ_16, + CPU_UIMB_IRQ_17, + CPU_UIMB_IRQ_18, + CPU_UIMB_IRQ_19, + CPU_UIMB_IRQ_20, + CPU_UIMB_IRQ_21, + CPU_UIMB_IRQ_22, + CPU_UIMB_IRQ_23, + CPU_UIMB_IRQ_24, + CPU_UIMB_IRQ_25, + CPU_UIMB_IRQ_26, + CPU_UIMB_IRQ_27, + CPU_UIMB_IRQ_28, + CPU_UIMB_IRQ_29, + CPU_UIMB_IRQ_30, + CPU_UIMB_IRQ_31, + + /* + * Symbolic names for UIMB interrupt sources. + */ + CPU_IRQ_SCI = CPU_UIMB_IRQ_5, + + /* + * Processor exceptions handled as rtems IRQ symbolic name definitions. + */ + CPU_DECREMENTER = CPU_PROC_IRQ_MIN_OFFSET + +}rtems_irq_symbolic_name; + +/* + * Convert an rtems_irq_symbolic_name 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_symbolic_name name); + +/* + * Type definition for RTEMS managed interrupts + */ +typedef unsigned char rtems_irq_prio; +struct __rtems_irq_connect_data__; /* forward declaratiuon */ + +typedef void (*rtems_irq_hdl) (void); +typedef void (*rtems_irq_enable) (const struct __rtems_irq_connect_data__*); +typedef void (*rtems_irq_disable) (const struct __rtems_irq_connect_data__*); +typedef int (*rtems_irq_is_enabled) (const struct __rtems_irq_connect_data__*); + +typedef struct __rtems_irq_connect_data__ { + /* + * IRQ line + */ + rtems_irq_symbolic_name name; + /* + * Handler. See comment on handler properties below in function prototype. + */ + rtems_irq_hdl hdl; + /* + * Function for enabling interrupts at device level (ONLY!). + * The CPU code will automatically enable it at USIU level and UIMB level. + * RATIONALE : anyway such code has to exist in current driver code. + * It is usually called immediately AFTER connecting the interrupt handler. + * RTEMS may well need such a function when restoring normal interrupt + * processing after a debug session. + * + */ + rtems_irq_enable on; + /* + * Function for disabling interrupts at device level (ONLY!). + * The code will disable it at USIU and UIMB level. RATIONALE : anyway + * such code has to exist for clean shutdown. It is usually called + * BEFORE disconnecting the interrupt. RTEMS may well need such + * a function when disabling normal interrupt processing for + * a debug session. May well be a NOP function. + */ + rtems_irq_disable off; + /* + * Function enabling to know what interrupt may currently occur + * if someone manipulates the USIU and UIMB interrupt mask without care... + */ + rtems_irq_is_enabled isOn; +}rtems_irq_connect_data; + +typedef struct { + /* + * size of all the table fields (*Tbl) described below. + */ + unsigned int irqNb; + /* + * Default handler used when disconnecting interrupts. + */ + rtems_irq_connect_data defaultEntry; + /* + * Table containing initials/current value. + */ + rtems_irq_connect_data* irqHdlTbl; + /* + * actual value of CPU_USIU_IRQ_VECTOR_BASE... + */ + rtems_irq_symbolic_name irqBase; + /* + * software priorities associated with interrupts. + * if irqPrio [i] > intrPrio [j] it means that + * interrupt handler hdl connected for interrupt name i + * will not be interrupted by the handler connected for interrupt j + * The interrupt source will be physically masked at USIU and UIMB level. + */ + rtems_irq_prio* irqPrioTbl; +}rtems_irq_global_settings; + + +/*-------------------------------------------------------------------------+ +| Function Prototypes. ++--------------------------------------------------------------------------*/ + +#if 0 +/* + * -------------------- MPC5xx USIU Management Routines ----------------- + */ +/* + * Function to disable a particular irq at USIU level. After calling + * this function, even if the device asserts the interrupt line it will + * not be propagated further to the processor + */ +int CPU_irq_disable_at_usiu (const rtems_irq_symbolic_name irqLine); +/* + * Function to enable a particular irq at USIU level. After calling + * this function, if the device asserts the interrupt line it will + * be propagated further to the processor + */ +int CPU_irq_enable_at_usiu (const rtems_irq_symbolic_name irqLine); +/* + * Function to acknowledge a particular irq at USIU level. After calling + * this function, if a device asserts an enabled interrupt line it will + * be propagated further to the processor. Mainly useful for people + * writing raw handlers as this is automagically done for rtems managed + * handlers. + */ +int CPU_irq_ack_at_siu (const rtems_irq_symbolic_name irqLine); +/* + * function to check if a particular irq is enabled at USIU level. + */ +int CPU_irq_enabled_at_siu (const rtems_irq_symbolic_name irqLine); + +#endif + +/* + * ------------ RTEMS Single Irq Handler Management Routines ---------------- + */ +/* + * Function to connect a particular irq handler. This handler will NOT be + * called directly as the result of the corresponding interrupt. Instead, a + * RTEMS irq prologue will be called that will : + * + * 1) save the C scratch registers, + * 2) switch to a interrupt stack if the interrupt is not nested, + * 4) modify them to disable the current interrupt at USIU level (and + * maybe others depending on software priorities) + * 5) aknowledge the USIU', + * 6) demask the processor, + * 7) call the application handler + * + * As a result the hdl function provided + * + * a) can perfectly be written is C, + * b) may also well directly call the part of the RTEMS API that can be + * used from interrupt level, + * c) It only responsible for handling the jobs that need to be done at + * the device level including (aknowledging/re-enabling the + * interrupt at device, level, getting the data,...) + * + * When returning from the function, the following will be performed by + * the RTEMS irq epilogue : + * + * 1) masks the interrupts again, + * 2) restore the original USIU interrupt masks + * 3) switch back on the orinal stack if needed, + * 4) perform rescheduling when necessary, + * 5) restore the C scratch registers... + * 6) restore initial execution flow + * + */ +int CPU_install_rtems_irq_handler (const rtems_irq_connect_data*); +/* + * Function to connect an RTEMS irq handler for ptr->name. + */ +int CPU_get_current_rtems_irq_handler (rtems_irq_connect_data* ptr); +/* + * Function to get the RTEMS irq handler for ptr->name. + */ +int CPU_remove_rtems_irq_handler (const rtems_irq_connect_data*); +/* + * Function to disconnect the RTEMS irq handler for ptr->name. This + * function checks that the value given is the current one for safety + * reason. The user can use the previous function to get it. + */ + +/* + * ------------ RTEMS Global Irq Handler Management Routines ---------------- + */ +/* + * (Re) Initialize the RTEMS interrupt management. + * + * The result of calling this function will be the same as if each + * individual handler (config->irqHdlTbl[i].hdl) different from + * "config->defaultEntry.hdl" has been individualy connected via + * + * CPU_install_rtems_irq_handler(&config->irqHdlTbl[i]) + * + * and each handler currently equal to config->defaultEntry.hdl + * has been previously disconnected via + * + * CPU_remove_rtems_irq_handler (&config->irqHdlTbl[i]) + * + * This is to say that all information given will be used and not just + * only the space. + * + * CAUTION : the various table address contained in config will be used + * directly by the interrupt mangement code in order to save + * data size so they must stay valid after the call => they should + * not be modified or declared on a stack. + */ + +int CPU_rtems_irq_mngt_set(rtems_irq_global_settings* config); +/* + * (Re) get info on current RTEMS interrupt management. + */ +int CPU_rtems_irq_mngt_get(rtems_irq_global_settings**); + +extern void CPU_rtems_irq_mng_init(unsigned cpuId); + +#endif + +#endif diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq_asm.S b/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq_asm.S new file mode 100644 index 0000000000..2908509bfc --- /dev/null +++ b/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq_asm.S @@ -0,0 +1,325 @@ +/* + * 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 found in the file LICENSE in this distribution or at + * http://www.rtems.com/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. + * + * $Id$ + */ + +#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, _Context_Switch_necessary@ha + lwz r5, _Context_Switch_necessary@l(r4) + cmpwi r5, 0 + bne switch + + addis r6, 0, _ISR_Signals_to_thread_executing@ha + lwz r7, _ISR_Signals_to_thread_executing@l(r6) + cmpwi r7, 0 + li r8, 0 + beq easy_exit + + stw r8, _ISR_Signals_to_thread_executing@l(r6) + + /* + * going to call _ThreadProcessSignalsFromIrq + * 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 _ThreadProcessSignalsFromIrq + + /* + * 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 + + +switch: + bl SYM (_Thread_Dispatch) + +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 new file mode 100644 index 0000000000..bc2a3043f1 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq_init.c @@ -0,0 +1,152 @@ +/* + * 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.com/license/LICENSE. + * + * $Id$ + */ + +#include +#include +#include +#include +#include + + +extern rtems_exception_handler_t dispatch_irq_handler; + +volatile unsigned int ppc_cached_irq_mask; + +/* + * default on/off function + */ +static void nop_func(){} + +/* + * default isOn function + */ +static int not_connected() {return 0;} + +/* + * default possible isOn function + */ +static int connected() {return 1;} + +static rtems_irq_connect_data rtemsIrq[CPU_IRQ_COUNT]; +static rtems_irq_global_settings initial_config; +static rtems_irq_connect_data defaultIrq = { + /* vector, hdl , on , off , isOn */ + 0, nop_func , nop_func , nop_func , not_connected +}; + +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 +}; + +void CPU_USIU_irq_init() +{ + /* + * 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 + */ +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... + */ + BSP_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_func; + vectorDesc.off = nop_func; + vectorDesc.isOn = connected; + if (!mpc5xx_set_exception (&vectorDesc)) { + BSP_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)) { + BSP_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 index 3139e62d6d..5a1ce5e2a6 100644 --- a/c/src/lib/libcpu/powerpc/mpc5xx/timer/timer.c +++ b/c/src/lib/libcpu/powerpc/mpc5xx/timer/timer.c @@ -1,70 +1,118 @@ /* timer.c * - * This file manages the benchmark timer used by the RTEMS Timing Test - * Suite. Each measured time period is demarcated by calls to - * Timer_initialize() and Read_timer(). Read_timer() usually returns - * the number of microseconds since Timer_initialize() exitted. + * This file manages the interval timer on the PowerPC MPC5xx. + * NOTE: This is not the PIT, but rather the RTEMS interval + * timer + * We shall use the bottom 32 bits of the timebase register, * + * The following was in the 403 version of this file. I don't + * know what it means. JTM 5/19/98 * NOTE: It is important that the timer start/stop overhead be * determined when porting or modifying this code. * - * COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994. + * + * 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-1998. * On-Line Applications Research Corporation (OAR). - * All rights assigned to U.S. Government, 1994. * - * This material may be reproduced by or for the U.S. Government pursuant - * to the copyright license under the clause at DFARS 252.227-7013. This - * notice must appear in all copies of this file and its derivatives. + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. * - * timer.c,v 1.2 1995/05/31 16:56:39 joel Exp + * $Id$ */ #include +#include + +static volatile rtems_unsigned32 Timer_starting; +static rtems_boolean Timer_driver_Find_average_overhead; + +/* + * This is so small that this code will be reproduced where needed. + */ +static inline rtems_unsigned32 get_itimer(void) +{ + rtems_unsigned32 ret; -rtems_boolean Timer_driver_Find_average_overhead; + asm volatile ("mftb %0" : "=r" ((ret))); /* TBLO */ -static unsigned int volatile lastInitValue; + return ret; +} -void Timer_initialize( void ) +void Timer_initialize(void) { - asm volatile( " mftb %0": "=r" (lastInitValue) ); + /* 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(); } -/* - * The following controls the behavior of Read_timer(). - * - * AVG_OVEREHAD is the overhead for starting and stopping the timer. It - * is usually deducted from the number returned. - * - * LEAST_VALID is the lowest number this routine should trust. Numbers - * below this are "noise" and zero is returned. - */ +#ifndef rtems_cpu_configuration_get_timer_least_valid +#define rtems_cpu_configuration_get_timer_least_valid() 0 +#endif -#define AVG_OVERHEAD 0 /* It typically takes X.X microseconds */ - /* (Y countdowns) to start/stop the timer. */ - /* This value is in microseconds. */ -#define LEAST_VALID 1 /* Don't trust a clicks value lower than this */ +#ifndef rtems_cpu_configuration_get_timer_average_overhead +#define rtems_cpu_configuration_get_timer_average_overhead() 0 +#endif -int Read_timer( void ) +int Read_timer(void) { - uint32_t value; - asm volatile ( " mftb %0": "=r" (value) ); - return value - lastInitValue; -} + rtems_unsigned32 clicks; + rtems_unsigned32 total; -/* - * Empty function call used in loops to measure basic cost of looping - * in Timing Test Suite. - */ + clicks = get_itimer(); + + total = clicks - Timer_starting; + + if ( Timer_driver_Find_average_overhead == 1 ) + return total; /* in XXX microsecond units */ + + else { + if ( total < rtems_cpu_configuration_get_timer_least_valid() ) { + return 0; /* below timer resolution */ + } + return (total - rtems_cpu_configuration_get_timer_average_overhead()); + } +} -rtems_status_code Empty_function( void ) +rtems_status_code Empty_function(void) { return RTEMS_SUCCESSFUL; } -void Set_find_average_overhead( - rtems_boolean find_flag -) +void Set_find_average_overhead(rtems_boolean find_flag) { Timer_driver_Find_average_overhead = find_flag; } diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/vectors/vectors.S b/c/src/lib/libcpu/powerpc/mpc5xx/vectors/vectors.S new file mode 100644 index 0000000000..125e3f60a4 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/mpc5xx/vectors/vectors.S @@ -0,0 +1,203 @@ +/* + * vectors.S + * + * This file contains the assembly code for the PowerPC exception veneers + * for RTEMS. + * + * + * 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/vectors/vectors.S, + * + * (c) 1999, Eric Valette valette@crf.canon.fr + * + * $Id$ + */ + +#include +#include +#include + +#define SYNC \ + sync; \ + isync + + +/* + * Hardware exception vector table. + * + * The MPC555 can be configured to use a compressed vector table with 8 + * bytes per entry, rather than the usual 0x100 bytes of other PowerPC + * devices. The following macro uses this feature to save the better part + * of 8 kbytes of flash ROM. + * + * Each vector table entry has room for only a simple branch instruction + * which branches to a prologue specific to that exception. This + * exception-specific prologue begins the context save, loads the exception + * number into a register, and jumps to a common exception prologue, below. + */ + + .macro vectors num=0, total=NUM_EXCEPTIONS /* create vector table */ + +/* vector table entry */ + .section .vectors, "ax" + + ba specific_prologue\@ /* run specific prologue */ + .long 0 /* each entry is 8 bytes */ + +/* exception-specific prologue */ + .text + +specific_prologue\@: + stwu r1, -EXCEPTION_FRAME_END(r1) /* open stack frame */ + stw r4, GPR4_OFFSET(r1) /* preserve register */ + li r4, \num /* get exception number */ + b common_prologue /* run common prologue */ + +/* invoke macro recursively to create remainder of table */ + .if \total - (\num + 1) + vectors "(\num + 1)", \total + .endif + + .endm + + +/* invoke macro to create entire vector table */ + vectors + + +/* + * Common exception prologue. + * + * Because the MPC555 vector table is in flash ROM, it's not possible to + * change the exception handlers by overwriting them at run-time, so this + * common exception prologue uses a table of exception handler pointers to + * provide equivalent flexibility. + * + * When the actual exception handler is run, R1 points to the base of a new + * exception stack frame, in which R3, R4 and LR have been saved. R4 holds + * the exception number. + */ + .text + +common_prologue: + stw r3, GPR3_OFFSET(r1) /* preserve registers */ + mflr r3 + stw r3, EXC_LR_OFFSET(r1) + + slwi r3, r4, 2 /* make table offset */ + addis r3, r3, exception_handler_table@ha /* point to entry */ + addi r3, r3, exception_handler_table@l + lwz r3, 0(r3) /* get entry */ + mtlr r3 /* run it */ + blr + + +/* + * Default exception handler. + * + * The function initialize_exceptions() initializes all of the entries in + * the exception handler table with pointers to this routine, which saves + * the remainder of the interrupted code's state, then calls + * C_default_exception_handler() to dump registers. + * + * On entry, R1 points to a new exception stack frame in which R3, R4, and + * LR have been saved. R4 holds the exception number. + */ + .text + +PUBLIC_VAR(default_exception_handler) +SYM (default_exception_handler): + /* + * Save the interrupted code's program counter and MSR. Beyond this + * point, all exceptions are recoverable. Use an RCPU-specific SPR + * to set the RI bit in the MSR to indicate the recoverable state. + */ + mfsrr0 r3 + stw r3, SRR0_FRAME_OFFSET(r1) + mfsrr1 r3 + stw r3, SRR1_FRAME_OFFSET(r1) + + mtspr eid, r3 /* set MSR[RI], clear MSR[EE] */ + SYNC + + /* + * Save the remainder of the general-purpose registers. + * + * Compute the value of R1 at exception entry before storing it in + * the frame. + * + * Note that R2 should never change (it's the EABI pointer to + * .sdata2), but we save it just in case. + * + * Recall that R3 and R4 were saved by the specific- and + * common-exception handlers before entry to this routine. + */ + stw r0, GPR0_OFFSET(r1) + addi r0, r1, EXCEPTION_FRAME_END + stw r0, GPR1_OFFSET(r1) + stw r2, GPR2_OFFSET(r1) + stmw r5, GPR5_OFFSET(r1) /* save R5 to R31 */ + + /* + * Save the remainder of the UISA special-purpose registers. Recall + * that LR was saved before entry. + */ + mfcr r0 + stw r0, EXC_CR_OFFSET(r1) + mfctr r0 + stw r0, EXC_CTR_OFFSET(r1) + mfxer r0 + stw r0, EXC_XER_OFFSET(r1) + + /* + * Call C-language portion of the default exception handler, passing + * in the address of the frame. + * + * To simplify things a bit, we assume that the target routine is + * within +/- 32 Mbyte from here, which is a reasonable assumption + * on the MPC555. + */ + stw r4, EXCEPTION_NUMBER_OFFSET(r1) /* save exception number */ + addi r3, r1, 0x8 /* get frame address */ + bl C_default_exception_handler /* call handler */ + + /* + * Restore UISA special-purpose registers. + */ + lwz r0, EXC_XER_OFFSET(r1) + mtxer r0 + lwz r0, EXC_CTR_OFFSET(r1) + mtctr r0 + lwz r0, EXC_CR_OFFSET(r1) + mtcr r0 + lwz r0, EXC_LR_OFFSET(r1) + mtlr r0 + + /* + * Restore most general-purpose registers. + */ + lmw r2, GPR2_OFFSET(r1) + + /* + * Restore the interrupted code's program counter and MSR, but first + * use an RCPU-specific special-purpose register to clear the RI + * bit, indicating that exceptions are temporarily non-recoverable. + */ + mtspr nri, r0 /* clear MSR[RI] */ + SYNC + + lwz r0, SRR1_FRAME_OFFSET(r1) + mtsrr1 r0 + lwz r0, SRR0_FRAME_OFFSET(r1) + mtsrr0 r0 + + /* + * Restore the final GPR, close the stack frame, and return to the + * interrupted code. + */ + lwz r0, GPR0_OFFSET(r1) + addi r1, r1, EXCEPTION_FRAME_END + SYNC + rfi diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/vectors/vectors.h b/c/src/lib/libcpu/powerpc/mpc5xx/vectors/vectors.h new file mode 100644 index 0000000000..ce1d3fca17 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/mpc5xx/vectors/vectors.h @@ -0,0 +1,156 @@ +/* + * vectors.h Exception frame related contant and API. + * + * This include file describe the data structure and the functions implemented + * by rtems to handle exceptions. + * + * + * 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/vectors/vectors.h: + * + * CopyRight (C) 1999 valette@crf.canon.fr + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ +#ifndef LIBCPU_POWERPC_MBX5XX_VECTORS_H +#define LIBCPU_POWERPC_MBX5XX_VECTORS_H + + +/* + * Size of hardware vector table. + */ +#define NUM_EXCEPTIONS 0x20 + +/* + * The callee (high level exception code written in C) + * will store the Link Registers (return address) at entry r1 + 4 !!!. + * So let room for it!!!. + */ +#define LINK_REGISTER_CALLEE_UPDATE_ROOM 4 +#define SRR0_FRAME_OFFSET 8 +#define SRR1_FRAME_OFFSET 12 +#define EXCEPTION_NUMBER_OFFSET 16 +#define GPR0_OFFSET 20 +#define GPR1_OFFSET 24 +#define GPR2_OFFSET 28 +#define GPR3_OFFSET 32 +#define GPR4_OFFSET 36 +#define GPR5_OFFSET 40 +#define GPR6_OFFSET 44 +#define GPR7_OFFSET 48 +#define GPR8_OFFSET 52 +#define GPR9_OFFSET 56 +#define GPR10_OFFSET 60 +#define GPR11_OFFSET 64 +#define GPR12_OFFSET 68 +#define GPR13_OFFSET 72 +#define GPR14_OFFSET 76 +#define GPR15_OFFSET 80 +#define GPR16_OFFSET 84 +#define GPR17_OFFSET 88 +#define GPR18_OFFSET 92 +#define GPR19_OFFSET 96 +#define GPR20_OFFSET 100 +#define GPR21_OFFSET 104 +#define GPR22_OFFSET 108 +#define GPR23_OFFSET 112 +#define GPR24_OFFSET 116 +#define GPR25_OFFSET 120 +#define GPR26_OFFSET 124 +#define GPR27_OFFSET 128 +#define GPR28_OFFSET 132 +#define GPR29_OFFSET 136 +#define GPR30_OFFSET 140 +#define GPR31_OFFSET 144 +#define EXC_CR_OFFSET 148 +#define EXC_CTR_OFFSET 152 +#define EXC_XER_OFFSET 156 +#define EXC_LR_OFFSET 160 +#define EXC_DAR_OFFSET 164 +/* + * maintain the EABI requested 8 bytes aligment + * As SVR4 ABI requires 16, make it 16 (as some + * exception may need more registers to be processed...) + */ +#define EXCEPTION_FRAME_END 176 + +#ifndef ASM +/* + * default raw exception handlers + */ + +extern void default_exception_vector_code_prolog(); +extern int default_exception_vector_code_prolog_size; +extern void initialize_exceptions(); + +typedef struct { + unsigned EXC_SRR0; + unsigned EXC_SRR1; + unsigned _EXC_number; + unsigned GPR0; + unsigned GPR1; + unsigned GPR2; + unsigned GPR3; + unsigned GPR4; + unsigned GPR5; + unsigned GPR6; + unsigned GPR7; + unsigned GPR8; + unsigned GPR9; + unsigned GPR10; + unsigned GPR11; + unsigned GPR12; + unsigned GPR13; + unsigned GPR14; + unsigned GPR15; + unsigned GPR16; + unsigned GPR17; + unsigned GPR18; + unsigned GPR19; + unsigned GPR20; + unsigned GPR21; + unsigned GPR22; + unsigned GPR23; + unsigned GPR24; + unsigned GPR25; + unsigned GPR26; + unsigned GPR27; + unsigned GPR28; + unsigned GPR29; + unsigned GPR30; + unsigned GPR31; + unsigned EXC_CR; + unsigned EXC_CTR; + unsigned EXC_XER; + unsigned EXC_LR; + unsigned EXC_MSR; + unsigned EXC_DAR; +}CPU_Exception_frame; + + +typedef void rtems_exception_handler_t (CPU_Exception_frame* excPtr); +/*DEBUG typedef rtems_exception_handler_t cpuExcHandlerType; */ + +/* + * Exception handler table. + * + * This table contains pointers to assembly-language exception handlers. + * The common exception prologue in vectors.S looks up an entry in this + * table and jumps to it. No return address is saved, so the handlers in + * this table must return directly to the interrupted code. + * + * On entry to an exception handler, R1 points to a new exception stack + * frame in which R3, R4, and LR have been saved. R4 holds the exception + * number. + */ +extern rtems_exception_handler_t* exception_handler_table[NUM_EXCEPTIONS]; + +#endif /* ASM */ + +#endif /* LIBCPU_POWERPC_MPC5XX_VECTORS_H */ diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/vectors/vectors_init.c b/c/src/lib/libcpu/powerpc/mpc5xx/vectors/vectors_init.c new file mode 100644 index 0000000000..e5314ee50a --- /dev/null +++ b/c/src/lib/libcpu/powerpc/mpc5xx/vectors/vectors_init.c @@ -0,0 +1,137 @@ +/* + * vectors_init.c Exception hanlding initialisation (and generic handler). + * + * This include file describe the data structure and the functions implemented + * by rtems to handle exceptions. + * + * + * 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/vectors/vectors_init.c: + * + * CopyRight (C) 1999 valette@crf.canon.fr + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ +#include +#include +#include + +extern rtems_exception_handler_t default_exception_handler; + +static rtems_raw_except_global_settings exception_config; +static rtems_raw_except_connect_data exception_table[NUM_EXCEPTIONS]; +rtems_exception_handler_t* exception_handler_table[NUM_EXCEPTIONS]; + + +void C_default_exception_handler(CPU_Exception_frame* excPtr) +{ + int recoverable = 0; + + printk("exception handler called for exception %d\n", excPtr->_EXC_number); + printk("\t Next PC or Address of fault = %x\n", excPtr->EXC_SRR0); + printk("\t Saved MSR = %x\n", excPtr->EXC_SRR1); + printk("\t R0 = %x\n", excPtr->GPR0); + printk("\t R1 = %x\n", excPtr->GPR1); + printk("\t R2 = %x\n", excPtr->GPR2); + printk("\t R3 = %x\n", excPtr->GPR3); + printk("\t R4 = %x\n", excPtr->GPR4); + printk("\t R5 = %x\n", excPtr->GPR5); + printk("\t R6 = %x\n", excPtr->GPR6); + printk("\t R7 = %x\n", excPtr->GPR7); + printk("\t R8 = %x\n", excPtr->GPR8); + printk("\t R9 = %x\n", excPtr->GPR9); + printk("\t R10 = %x\n", excPtr->GPR10); + printk("\t R11 = %x\n", excPtr->GPR11); + printk("\t R12 = %x\n", excPtr->GPR12); + printk("\t R13 = %x\n", excPtr->GPR13); + printk("\t R14 = %x\n", excPtr->GPR14); + printk("\t R15 = %x\n", excPtr->GPR15); + printk("\t R16 = %x\n", excPtr->GPR16); + printk("\t R17 = %x\n", excPtr->GPR17); + printk("\t R18 = %x\n", excPtr->GPR18); + printk("\t R19 = %x\n", excPtr->GPR19); + printk("\t R20 = %x\n", excPtr->GPR20); + printk("\t R21 = %x\n", excPtr->GPR21); + printk("\t R22 = %x\n", excPtr->GPR22); + printk("\t R23 = %x\n", excPtr->GPR23); + printk("\t R24 = %x\n", excPtr->GPR24); + printk("\t R25 = %x\n", excPtr->GPR25); + printk("\t R26 = %x\n", excPtr->GPR26); + printk("\t R27 = %x\n", excPtr->GPR27); + printk("\t R28 = %x\n", excPtr->GPR28); + printk("\t R29 = %x\n", excPtr->GPR29); + printk("\t R30 = %x\n", excPtr->GPR30); + printk("\t R31 = %x\n", excPtr->GPR31); + printk("\t CR = %x\n", excPtr->EXC_CR); + printk("\t CTR = %x\n", excPtr->EXC_CTR); + printk("\t XER = %x\n", excPtr->EXC_XER); + printk("\t LR = %x\n", excPtr->EXC_LR); + printk("\t MSR = %x\n", excPtr->EXC_MSR); + if (excPtr->_EXC_number == ASM_DEC_VECTOR) + recoverable = 1; + if (excPtr->_EXC_number == ASM_SYS_VECTOR) +#ifdef TEST_RAW_EXCEPTION_CODE + recoverable = 1; +#else + recoverable = 0; +#endif + if (!recoverable) { + printk("unrecoverable exception!!! Push reset button\n"); + while(1); + } +} + +void nop_except_enable(const rtems_raw_except_connect_data* ptr) +{ +} + +int except_always_enabled(const rtems_raw_except_connect_data* ptr) +{ + return 1; +} + +void initialize_exceptions() +{ + int i; + + /* + * Initialize all entries of the exception table with a description of the + * default exception handler. + */ + exception_config.exceptSize = NUM_EXCEPTIONS; + exception_config.rawExceptHdlTbl = &exception_table[0]; + exception_config.defaultRawEntry.exceptIndex = 0; + exception_config.defaultRawEntry.hdl.vector = 0; + exception_config.defaultRawEntry.hdl.raw_hdl = default_exception_handler; + + for (i = 0; i < exception_config.exceptSize; i++) { + printk("installing exception number %d\n", i); + exception_table[i].exceptIndex = i; + exception_table[i].hdl = exception_config.defaultRawEntry.hdl; + exception_table[i].hdl.vector = i; + exception_table[i].on = nop_except_enable; + exception_table[i].off = nop_except_enable; + exception_table[i].isOn = except_always_enabled; + } + + /* + * Now pass the initialized exception table to the exceptions module which + * will install the handler pointers in the exception handler table. + */ + if (!mpc5xx_init_exceptions(&exception_config)) { + /* + * At this stage we may not call CPU_Panic because it uses exceptions!!! + */ + printk("Exception handling initialization failed\n"); + printk("System locked\n"); while(1); + } + else { + printk("Exception handling initialization done\n"); + } +} -- cgit v1.2.3