From 63de714ce7c0869715687c728f84efd048cba550 Mon Sep 17 00:00:00 2001 From: Thomas Doerfler Date: Mon, 8 Sep 2008 09:55:39 +0000 Subject: added new BSP for TQM8xx boards --- c/src/lib/libbsp/powerpc/tqm8xx/Makefile.am | 93 ++ c/src/lib/libbsp/powerpc/tqm8xx/README | 141 +++ c/src/lib/libbsp/powerpc/tqm8xx/bsp_specs | 14 + c/src/lib/libbsp/powerpc/tqm8xx/configure.ac | 113 ++ c/src/lib/libbsp/powerpc/tqm8xx/console/console.c | 1112 ++++++++++++++++++++ .../lib/libbsp/powerpc/tqm8xx/include/8xx_immap.h | 477 +++++++++ c/src/lib/libbsp/powerpc/tqm8xx/include/bsp.h | 172 +++ c/src/lib/libbsp/powerpc/tqm8xx/include/coverhd.h | 362 +++++++ .../lib/libbsp/powerpc/tqm8xx/include/irq-config.h | 101 ++ c/src/lib/libbsp/powerpc/tqm8xx/include/irq.h | 154 +++ c/src/lib/libbsp/powerpc/tqm8xx/include/tm27.h | 32 + c/src/lib/libbsp/powerpc/tqm8xx/include/tqm.h | 51 + c/src/lib/libbsp/powerpc/tqm8xx/irq/irq.c | 240 +++++ c/src/lib/libbsp/powerpc/tqm8xx/irq/irq.h | 204 ++++ c/src/lib/libbsp/powerpc/tqm8xx/irq/irq_asm.S | 433 ++++++++ c/src/lib/libbsp/powerpc/tqm8xx/irq/irq_init.c | 185 ++++ .../libbsp/powerpc/tqm8xx/network/network_fec.c | 926 ++++++++++++++++ .../libbsp/powerpc/tqm8xx/network/network_scc.c | 1047 ++++++++++++++++++ c/src/lib/libbsp/powerpc/tqm8xx/preinstall.am | 104 ++ c/src/lib/libbsp/powerpc/tqm8xx/startup/bspstart.c | 234 ++++ c/src/lib/libbsp/powerpc/tqm8xx/startup/cpuinit.c | 134 +++ .../libbsp/powerpc/tqm8xx/startup/linkcmds.base | 316 ++++++ .../libbsp/powerpc/tqm8xx/startup/linkcmds.tqm8xx | 15 + .../lib/libbsp/powerpc/tqm8xx/startup/mmutlbtab.c | 103 ++ c/src/lib/libbsp/powerpc/tqm8xx/startup/start.S | 287 +++++ c/src/lib/libbsp/powerpc/tqm8xx/timer/timer.c | 110 ++ 26 files changed, 7160 insertions(+) create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/Makefile.am create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/README create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/bsp_specs create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/configure.ac create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/console/console.c create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/include/8xx_immap.h create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/include/bsp.h create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/include/coverhd.h create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/include/irq-config.h create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/include/irq.h create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/include/tm27.h create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/include/tqm.h create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/irq/irq.c create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/irq/irq.h create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/irq/irq_asm.S create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/irq/irq_init.c create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/network/network_fec.c create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/network/network_scc.c create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/preinstall.am create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/startup/bspstart.c create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/startup/cpuinit.c create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/startup/linkcmds.base create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/startup/linkcmds.tqm8xx create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/startup/mmutlbtab.c create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/startup/start.S create mode 100644 c/src/lib/libbsp/powerpc/tqm8xx/timer/timer.c (limited to 'c') diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/Makefile.am b/c/src/lib/libbsp/powerpc/tqm8xx/Makefile.am new file mode 100644 index 0000000000..08489adc8d --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/Makefile.am @@ -0,0 +1,93 @@ +## +## $Id$ +## + +ACLOCAL_AMFLAGS = -I ../../../../aclocal + +include $(top_srcdir)/../../../../automake/compile.am +include $(top_srcdir)/../../bsp.am + +dist_project_lib_DATA = bsp_specs + +include_HEADERS = include/bsp.h +include_HEADERS += include/tm27.h + +libcpudir = ../../../libcpu/@RTEMS_CPU@ + +nodist_include_HEADERS = include/bspopts.h +DISTCLEANFILES = include/bspopts.h + +noinst_PROGRAMS = + +include_bspdir = $(includedir)/bsp + +include_HEADERS += include/coverhd.h +include_bsp_HEADERS = include/tqm.h include/8xx_immap.h \ + include/irq.h include/irq-config.h \ + ../../shared/include/irq-generic.h\ + $(libcpudir)/@exceptions@/bspsupport/vectors.h \ + $(libcpudir)/@exceptions@/bspsupport/ppc_exc_bspsupp.h + + +EXTRA_DIST = times-tqm866 + +EXTRA_DIST += startup/start.S +start.$(OBJEXT): startup/start.S + $(CPPASCOMPILE) -o $@ -c $< +project_lib_DATA = start.$(OBJEXT) + +EXTRA_DIST += ../../powerpc/shared/start/rtems_crti.S +rtems_crti.$(OBJEXT): ../../powerpc/shared/start/rtems_crti.S + $(CPPASCOMPILE) -o $@ -c $< +project_lib_DATA += rtems_crti.$(OBJEXT) + +dist_project_lib_DATA += startup/linkcmds.base\ + startup/linkcmds.tqm8xx + +irq_SOURCES = include/irq-config.h \ + irq/irq.c \ + ../../shared/src/irq-generic.c \ + ../../shared/src/irq-legacy.c + +# clock_SOURCES = ../shared/clock/clock.c +p_clock_SOURCES = clock/p_clock.c + +console_SOURCES = console/console.c +timer_SOURCES = timer/timer.c +startup_SOURCES = ../../shared/bspclean.c ../../shared/bsplibc.c \ + ../../shared/bsppost.c ../../shared/bsppredriverhook.c \ + startup/bspstart.c ../../shared/bootcard.c \ + startup/mmutlbtab.c startup/cpuinit.c \ + ../../shared/sbrk.c ../../shared/gnatinstallhandler.c + +if HAS_NETWORKING +network_CPPFLAGS = -D__INSIDE_RTEMS_BSD_TCPIP_STACK__ +noinst_PROGRAMS += network.rel +network_rel_SOURCES = network/network_scc.c network/network_fec.c +network_rel_CPPFLAGS = $(AM_CPPFLAGS) $(network_CPPFLAGS) +network_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) +endif + +noinst_LIBRARIES = libbsp.a +libbsp_a_SOURCES = $(irq_SOURCES) \ + $(startup_SOURCES) $(console_SOURCES) \ + $(p_clock_SOURCES) $(timer_SOURCES) + +libbsp_a_LIBADD = \ + $(libcpudir)/shared/cpuIdent.rel \ + $(libcpudir)/shared/cache.rel \ + $(libcpudir)/@exceptions@/rtems-cpu.rel \ + $(libcpudir)/@exceptions@/raw_exception.rel \ + $(libcpudir)/@exceptions@/exc_bspsupport.rel \ + $(libcpudir)/mpc8xx/console-generic.rel \ + $(libcpudir)/mpc8xx/cpm.rel \ + $(libcpudir)/mpc8xx/clock.rel \ + $(libcpudir)/mpc8xx/mmu.rel \ + $(libcpudir)/mpc8xx/timer.rel + +if HAS_NETWORKING +libbsp_a_LIBADD += network.rel +endif + +include $(srcdir)/preinstall.am +include $(top_srcdir)/../../../../automake/local.am diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/README b/c/src/lib/libbsp/powerpc/tqm8xx/README new file mode 100644 index 0000000000..261932c3c5 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/README @@ -0,0 +1,141 @@ +# +# $Id$ +# + +This is a README file for the tqm8xx BSP + + +Summary +------- + +BSP NAME: tqm8xx +BOARD: various boards based on TQ Components TQM8xx modules +BUS: No backplane. +CPU FAMILY: PowerPC +CPU: PowerPC MPC860 or MPC866 +COPROCESSORS: Built-in Motorola QUICC +MODE: 32 bit mode + +BOOT MONITOR: TQMon + +PERIPHERALS +=========== +TIMERS: PIT / Timebase + RESOLUTION: 1 microsecond / frequency = clock-speed / 16 +SERIAL PORTS: 1-4 SCCs, 1-2 SMC +REAL-TIME CLOCK: +DMA: Each SCC and SMC. +VIDEO: +SCSI: +NETWORKING: Ethernet 10 Mbps on SCC1 and/or + 10/100Mbps on FEC (for MPC866T) + + +DRIVER INFORMATION +================== +CLOCK DRIVER: yes +CONSOLE DRIVER: yes +SHMSUPP: N/A +TIMER DRIVER: yes +NETWORK DRIVER: yes + +NOTES +===== +On-chip resources: + SCC1 network or serial port + SCC2 serial port + SCC3 serial port + SCC4 serial port + SMC1 serial port + SMC2 serial port + CLK1 network + CLK2 network + CLK3 + CLK4 + CLK5 + CLK6 + CLK7 + CLK8 + BRG1 console + BRG2 console + BRG3 console + BRG4 console + RTC + PIT clock + TB + DEC + SWT + UPMA + UPMB + IRQ0 + IRQ1 + IRQ2 + IRQ3 + IRQ4 + IRQ5 + IRQ6 + IRQ7 + IRQ_LVL0 + IRQ_LVL1 + IRQ_LVL2 + IRQ_LVL3 + IRQ_LVL4 + IRQ_LVL5 + IRQ_LVL6 + IRQ_LVL7 + + +Board description +----------------- +Clock rate: 50MHz - 133MHz. +Bus width: 32 bit Flash, 32 bit DRAM +FLASH: 2-8MB +RAM: 32-256MB SDRAM + + +Installation +------------ + + + +Port Description +Console driver +--------------- + +This BSP contains a console driver for polled and interrupt-driven +operation. It supports SCCs and SMCs. +During BSP configuration, various variables can be set to activate a +certain channels and to specify the console channel: + +CONS_SMC1_MODE, CONS_SMC2_MODE, CONS_SCC[1-4]_MODE can be set to +CONS_MODE_UNUSED, CONS_MODE_POLLED or CONS_MODE_IRQ + +The driver always uses termios. + +printk() and debug output +----------------------- + + +Floating-point +-------------- + +The MPC8xx do not have floating-point units. All code should +get compiled with the appropriate -mcpu flag. The nof variants of the gcc +runtime libraries should be used for linking. + + + +Miscellaneous +------------- + +All development was based on the mbx8xx and gen68360 port. + +Test Configuration +------------------ + +Board: pghplus ( +CPU: Motorola MPC866T +Clock Speed: 133MHz +RAM: 64MByte +Cache Configuration: Instruction cache on; data cache on, copyback mode. + diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/bsp_specs b/c/src/lib/libbsp/powerpc/tqm8xx/bsp_specs new file mode 100644 index 0000000000..e5456faee5 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/bsp_specs @@ -0,0 +1,14 @@ +%rename endfile old_endfile +%rename startfile old_startfile +%rename link old_link + +*startfile: +%{!qrtems: %(old_startfile)} %{!nostdlib: %{qrtems: ecrti%O%s rtems_crti%O%s crtbegin.o%s \ +%{!qrtems_debug: start.o%s} \ +%{qrtems_debug: start_g.o%s}}} + +*endfile: +%{!qrtems: %(old_endfile)} %{qrtems: crtend.o%s ecrtn%O%s} + +*link: +%{!qrtems: %(old_link)} %{qrtems: -dc -dp -u __vectors -N -u start -e start} diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/configure.ac b/c/src/lib/libbsp/powerpc/tqm8xx/configure.ac new file mode 100644 index 0000000000..712ba650b6 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/configure.ac @@ -0,0 +1,113 @@ +## Process this file with autoconf to produce a configure script. +## +## $Id$ + +AC_PREREQ(2.60) +AC_INIT([rtems-c-src-lib-libbsp-powerpc-tqm8xx],[_RTEMS_VERSION],[http://www.rtems.org/bugzilla]) +AC_CONFIG_SRCDIR([bsp_specs]) +RTEMS_TOP(../../../../../..) + +RTEMS_CANONICAL_TARGET_CPU +AM_INIT_AUTOMAKE([no-define nostdinc foreign 1.10]) +RTEMS_BSP_CONFIGURE + +RTEMS_PROG_CC_FOR_TARGET([-ansi -fasm]) +RTEMS_CANONICALIZE_TOOLS +RTEMS_PROG_CCAS + +RTEMS_CHECK_NETWORKING +AM_CONDITIONAL(HAS_NETWORKING,test "$HAS_NETWORKING" = "yes") + +RTEMS_BSPOPTS_SET([PPC_USE_DATA_CACHE],[*],[1]) +RTEMS_BSPOPTS_HELP([PPC_USE_DATA_CACHE], +[If defined, then the PowerPC specific code in RTEMS will use + data cache instructions to optimize the context switch code. + This code can conflict with debuggers or emulators.]) + +RTEMS_BSPOPTS_SET([DATA_CACHE_ENABLE],[*],[1]) +RTEMS_BSPOPTS_HELP([DATA_CACHE_ENABLE], +[If defined, the data cache will be enabled after address translation + is turned on.]) + +RTEMS_BSPOPTS_SET([INSTRUCTION_CACHE_ENABLE],[*],[1]) +RTEMS_BSPOPTS_HELP([INSTRUCTION_CACHE_ENABLE], +[If defined, the instruction cache will be enabled after address translation + is turned on.]) + +RTEMS_BSPOPTS_SET([CONSOLE_CHN],[*],[CONS_CHN_SMC1]) +RTEMS_BSPOPTS_HELP([CONSOLE_CHN], +[(BSP--console driver) Must be defined to be one of CONS_CHN_SMC1, + CONS_CHN_SMC2, CONS_CHN_SCC1, CONS_CHN_SCC2, CONS_CHN_SCC3, or CONS_CHN_SCC4. + Determines which device will be registered as /dev/console.]) + +RTEMS_BSPOPTS_SET([PRINTK_CHN],[*],[CONS_CHN_SMC1]) +RTEMS_BSPOPTS_HELP([PRINTK_CHN], +[(BSP--console driver) + Must be defined to be one of CONS_CHN_SMC1, CONS_CHN_SMC2, CONS_CHN_SCC2, + CONS_CHN_SCC3, or CONS_CHN_SCC4. Determines which device is used for output + by printk(). If the port that printk() uses is also used for other + I/O (e.g. if PRINTK_CHN == CONSOLE_CHN), then both ports should + use the same type of I/O, otherwise the drivers will likely conflict with + each other.]) + +RTEMS_BSPOPTS_SET([CONS_SMC1_MODE],[tqm8xx_stk8xx],[CONS_MODE_POLLED]) +RTEMS_BSPOPTS_SET([CONS_SMC1_MODE],[pghplus],[CONS_MODE_POLLED]) +RTEMS_BSPOPTS_SET([CONS_SMC1_MODE],[*],[CONS_MODE_UNUSED]) +RTEMS_BSPOPTS_HELP([CONS_SMC1_MODE], +[(BSP--SMC1 UART IF mode) Must be defined if SMC1 is used as a tty (UART) + channel. Set it to CONS_MODE_POLLED for polled operation, CONS_MODE_IRQ for + interrupt driven (spooled) operation. Set it to CONS_MODE_UNUSED, if not used]) + +RTEMS_BSPOPTS_SET([CONS_SMC2_MODE],[tqm8xx_stk8xx],[CONS_MODE_POLLED]) +RTEMS_BSPOPTS_SET([CONS_SMC2_MODE],[*],[CONS_MODE_UNUSED]) +RTEMS_BSPOPTS_HELP([CONS_SMC2_MODE], +[(BSP--SMC2 UART IF mode) Must be defined if SMC2 is used as a tty (UART) + channel. Set it to CONS_MODE_POLLED for polled operation, CONS_MODE_IRQ for + interrupt driven (spooled) operation. Set it to CONS_MODE_UNUSED, if not used]) + +RTEMS_BSPOPTS_SET([CONS_SCC1_MODE],[*],[CONS_MODE_UNUSED]) +RTEMS_BSPOPTS_HELP([CONS_SCC1_MODE], +[(BSP--SCC1 UART IF mode) Must be defined if SCC1 is used as a tty (UART) + channel. Set it to CONS_MODE_POLLED for polled operation, CONS_MODE_IRQ for + interrupt driven (spooled) operation. Set it to CONS_MODE_UNUSED, if not used]) + +RTEMS_BSPOPTS_SET([CONS_SCC2_MODE],[*],[CONS_MODE_UNUSED]) +RTEMS_BSPOPTS_HELP([CONS_SCC2_MODE], +[(BSP--SCC2 UART IF mode) Must be defined if SCC2 is used as a tty (UART) + channel. Set it to CONS_MODE_POLLED for polled operation, CONS_MODE_IRQ for + interrupt driven (spooled) operation. Set it to CONS_MODE_UNUSED, if not used]) + +RTEMS_BSPOPTS_SET([CONS_SCC3_MODE],[*],[CONS_MODE_UNUSED]) +RTEMS_BSPOPTS_HELP([CONS_SCC3_MODE], +[(BSP--SCC3 UART IF mode) Must be defined if SCC3 is used as a tty (UART) + channel. Set it to CONS_MODE_POLLED for polled operation, CONS_MODE_IRQ for + interrupt driven (spooled) operation. Set it to CONS_MODE_UNUSED, if not used]) + +RTEMS_BSPOPTS_SET([CONS_SCC4_MODE],[*],[CONS_MODE_UNUSED]) +RTEMS_BSPOPTS_HELP([CONS_SCC4_MODE], +[(BSP--SCC4 UART IF mode) Must be defined if SCC4 is used as a tty (UART) + channel. Set it to CONS_MODE_POLLED for polled operation, CONS_MODE_IRQ for + interrupt driven (spooled) operation. Set it to CONS_MODE_UNUSED, if not used]) + +# add selection of primary network interface +RTEMS_BSPOPTS_SET([BSP_USE_NETWORK_FEC],[pghplus],[1]) +RTEMS_BSPOPTS_SET([BSP_USE_NETWORK_FEC],[*],[0]) +RTEMS_BSPOPTS_HELP([BSP_USE_NETWORK_FEC], +[If defined, then the BSP will use the Fast Ethernet Controller + for 10/100MBit networking and used as primary networking interface.]) + +RTEMS_BSPOPTS_SET([BSP_USE_NETWORK_SCC],[pghplus],[0]) +RTEMS_BSPOPTS_SET([BSP_USE_NETWORK_SCC],[*],[1]) +RTEMS_BSPOPTS_HELP([BSP_USE_NETWORK_SCC], +[If defined, then the BSP will use the Serial Communications Controller (SCC1) + for 10MBit networking.]) + + +# Explicitly list a Makefile here +AC_CONFIG_FILES([Makefile]) + +RTEMS_BSP_BOOTCARD_HANDLES_RAM_ALLOCATION + +RTEMS_PPC_EXCEPTIONS + +AC_OUTPUT diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/console/console.c b/c/src/lib/libbsp/powerpc/tqm8xx/console/console.c new file mode 100644 index 0000000000..00e08e79b3 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/console/console.c @@ -0,0 +1,1112 @@ +/*===============================================================*\ +| Project: RTEMS TQM8xx BSP | ++-----------------------------------------------------------------+ +| This file has been adapted to MPC8xx by | +| Thomas Doerfler | +| Copyright (c) 2008 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | +| | +| See the other copyright notice below for the original parts. | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.com/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains the console driver | +\*===============================================================*/ +/* derived from: */ +/* + * SMC1/2 SCC1..4 raw console serial I/O. + * adapted to work with up to 4 SCC and 2 SMC + * + * This driver is an example of `TASK DRIVEN' `POLLING' or `INTERRUPT' I/O. + * + * To run with interrupt-driven I/O, ensure m8xx_smc1_interrupt + * is set before calling the initialization routine. + * + * Author: + * 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). + * Copyright assigned to U.S. Government, 1994. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * + * http://www.OARcorp.com/rtems/license.html. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Declare clock speed -- may be overwritten by downloader or debugger + */ +int m8xx_clock_rate = 0; + +/* + * Interrupt-driven input buffer + */ +#define RXBUFSIZE 256 + +#define M8xx_IVEC_SRC_MASK (0x1f) +#define M8xx_IVEC_SRC_SCC1 (0x1E) +#define M8xx_IVEC_SRC_SCC2 (0x1D) +#define M8xx_IVEC_SRC_SCC3 (0x1C) +#define M8xx_IVEC_SRC_SCC4 (0x1B) +#define M8xx_IVEC_SRC_SMC1 (0x04) +#define M8xx_IVEC_SRC_SMC2 (0x03) + +#define M8xx_IREG_MASK(src) (1UL << src) +#define M8xx_SICR_BRG1 (0) +#define M8xx_SICR_BRG2 (1) +#define M8xx_SICR_BRG3 (2) +#define M8xx_SICR_BRG4 (3) + +#define M8xx_SICR_SCCRX_MSK(scc) (( 7) << (((scc))*8+3)) +#define M8xx_SICR_SCCRX(scc,clk) ((clk) << (((scc))*8+3)) + +#define M8xx_SICR_SCCTX_MSK(scc) (( 7) << (((scc))*8+0)) +#define M8xx_SICR_SCCTX(scc,clk) ((clk) << (((scc))*8+0)) + +#define M8xx_SIMODE_SMCCS(smc,clk) ((clk) << ((smc)*16+12)) +#define M8xx_SIMODE_SMCCS_MSK(smc) M8xx_SIMODE_SMCCS(smc,7) + +#define CONS_CHN_CNT 6 +#define CONS_CHN_SCC1 0 +#define CONS_CHN_SCC2 1 +#define CONS_CHN_SCC3 2 +#define CONS_CHN_SCC4 3 +#define CONS_CHN_SMC1 4 +#define CONS_CHN_SMC2 5 + +/* + * possible identifiers for bspopts.h: CONS_SxCy_MODE + */ +#define CONS_MODE_UNUSED -1 +#define CONS_MODE_POLLED TERMIOS_POLLED +#define CONS_MODE_IRQ TERMIOS_IRQ_DRIVEN + +#define CHN_IS_SCC(chan) ((chan) < CONS_CHN_SMC1) + +#define BRG_CNT 4 + +#define MAX_IDL_DEFAULT 10 +#define DEVICEPREFIX "tty" + +/* + * printk basic support + */ +static void _BSP_null_char( char c ) {return;} +BSP_output_char_function_type BSP_output_char = _BSP_null_char; + +/* + * Interrupt-driven callback + */ +static int m8xx_scc_mode[CONS_CHN_CNT]; +static void *sccttyp[CONS_CHN_CNT]; +typedef struct m8xx_console_chan_desc_s { + bool is_scc; /* true for SCC */ + struct { + volatile m8xxSCCparms_t *sccp; + volatile m8xxSMCparms_t *smcp; + } parms; + struct { + volatile m8xxSCCRegisters_t *sccr; + volatile m8xxSMCRegisters_t *smcr; + } regs; + int ivec_src; + uint32_t ireg_mask; + int cr_chan_code; + int brg_used; +} m8xx_console_chan_desc_t; + +m8xx_console_chan_desc_t m8xx_console_chan_desc[CONS_CHN_CNT] = { + /* SCC1 */ + {TRUE, + {(m8xxSCCparms_t *)&(m8xx.scc1p),NULL}, + {&(m8xx.scc1),NULL}, + M8xx_IVEC_SRC_SCC1, + M8xx_IREG_MASK(M8xx_IVEC_SRC_SCC1), + M8xx_CR_CHAN_SCC1, + -1}, + /* SCC2 */ + {TRUE, + {&(m8xx.scc2p),NULL}, + {&(m8xx.scc2),NULL}, + M8xx_IVEC_SRC_SCC2, + M8xx_IREG_MASK(M8xx_IVEC_SRC_SCC2), + M8xx_CR_CHAN_SCC2, + -1}, + /* SCC3 */ + {TRUE, + {&(m8xx.scc3p),NULL}, + {&(m8xx.scc3),NULL}, + M8xx_IVEC_SRC_SCC3, + M8xx_IREG_MASK(M8xx_IVEC_SRC_SCC3), + M8xx_CR_CHAN_SCC3, + -1}, + /* SCC4 */ + {TRUE, + {&(m8xx.scc4p),NULL}, + {&(m8xx.scc4),NULL}, + M8xx_IVEC_SRC_SCC4, + M8xx_IREG_MASK(M8xx_IVEC_SRC_SCC4), + M8xx_CR_CHAN_SCC4, + -1}, + /* SMC1 */ + {FALSE, + {NULL,&(m8xx.smc1p)}, + {NULL,&(m8xx.smc1)}, + M8xx_IVEC_SRC_SMC1, + M8xx_IREG_MASK(M8xx_IVEC_SRC_SMC1), + M8xx_CR_CHAN_SMC1, + -1}, + /* SMC2 */ + {FALSE, + {NULL,&(m8xx.smc2p)}, + {NULL,&(m8xx.smc2)}, + M8xx_IVEC_SRC_SMC2, + M8xx_IREG_MASK(M8xx_IVEC_SRC_SMC2), + M8xx_CR_CHAN_SMC2, + -1}}; + +#define CHN_PARAM_GET(chan,param) \ + (m8xx_console_chan_desc[chan].is_scc \ + ? m8xx_console_chan_desc[chan].parms.sccp->param \ + : m8xx_console_chan_desc[chan].parms.smcp->param) + +#define CHN_PARAM_SET(chan,param,value) \ + do {if (m8xx_console_chan_desc[chan].is_scc) \ + m8xx_console_chan_desc[chan].parms.sccp->param = value; \ + else \ + m8xx_console_chan_desc[chan].parms.smcp->param = value; \ + } while (0) + +#define CHN_EVENT_GET(chan) \ + (m8xx_console_chan_desc[chan].is_scc \ + ? m8xx_console_chan_desc[chan].regs.sccr->scce \ + : m8xx_console_chan_desc[chan].regs.smcr->smce) + +#define CHN_EVENT_CLR(chan,mask) \ + do { \ + if (m8xx_console_chan_desc[chan].is_scc) \ + m8xx_console_chan_desc[chan].regs.sccr->scce = (mask); \ + else \ + m8xx_console_chan_desc[chan].regs.smcr->smce = (mask); \ + }while (0) + +#define CHN_MASK_GET(chan) \ + (m8xx_console_chan_desc[chan].is_scc \ + ? m8xx_console_chan_desc[chan].regs.sccr->sccm \ + : m8xx_console_chan_desc[chan].regs.smcr->smcm) + +#define CHN_MASK_SET(chan,mask) \ + do { \ + if (m8xx_console_chan_desc[chan].is_scc) \ + m8xx_console_chan_desc[chan].regs.sccr->sccm = (mask); \ + else \ + m8xx_console_chan_desc[chan].regs.smcr->smcm = (mask); \ + }while (0) + + +/* + * I/O buffers and pointers to buffer descriptors + */ +#define SCC_RXBD_CNT 4 +#define SCC_TXBD_CNT 4 +typedef volatile char sccRxBuf_t[SCC_RXBD_CNT][RXBUFSIZE]; +static sccRxBuf_t *rxBuf[CONS_CHN_CNT]; + +static volatile m8xxBufferDescriptor_t *sccFrstRxBd[CONS_CHN_CNT]; +static volatile m8xxBufferDescriptor_t *sccCurrRxBd[CONS_CHN_CNT]; +static volatile m8xxBufferDescriptor_t *sccFrstTxBd[CONS_CHN_CNT]; +static volatile m8xxBufferDescriptor_t *sccPrepTxBd[CONS_CHN_CNT]; +static volatile m8xxBufferDescriptor_t *sccDequTxBd[CONS_CHN_CNT]; + +/* + * Compute baud-rate-generator configuration register value + */ +static uint32_t +sccBRGval (int baud) +{ + int divisor; + int div16 = 0; + + divisor = ((m8xx_clock_rate / 16) + (baud / 2)) / baud; + if (divisor > 4096) { + div16 = 1; + divisor = (divisor + 8) / 16; + } + return M8xx_BRG_EN | M8xx_BRG_EXTC_BRGCLK | ((divisor - 1) << 1) | div16; +} + +typedef struct { + uint32_t reg_content; + int link_cnt; +}brg_state_t; +brg_state_t scc_brg_state[BRG_CNT]; + +/* + * initialize brg_state + */ +static void sccBRGinit(void) +{ + int brg_idx; + + for (brg_idx = 0;brg_idx < BRG_CNT;brg_idx++) { + scc_brg_state[brg_idx].reg_content = 0; + scc_brg_state[brg_idx].link_cnt = 0; + } +#ifndef MDE360 + /* + * on ZEM40, init CLK4/5 inputs + */ + m8xx.papar |= ((1 << 11) | (1 << 12)); + m8xx.padir &= ~((1 << 11) | (1 << 12)); +#endif +} + +/* + * input clock frq for CPM clock inputs + */ +static uint32_t clkin_frq[2][4] = { +#ifdef MDE360 + {0,0,0,0}, + {0,0,0,0} +#else + {0,0,0,1843000}, + {1843000,0,0,0} +#endif +}; + +/* + * allocate, set and connect baud rate generators + * FIXME: or clock input + * FIXME: set pin to be clock input + */ + +static int sccBRGalloc(int chan,int baud) +{ + rtems_interrupt_level level; + m8xx_console_chan_desc_t *chan_desc = &(m8xx_console_chan_desc[chan]); + uint32_t reg_val; + int old_brg; + int new_brg = -1; + int brg_idx; +#if 0 /* we do not support external clocked console */ + int clk_group; + int clk_sel; +#endif + + old_brg = chan_desc->brg_used; + /* compute brg register contents needed */ + reg_val = sccBRGval(baud); + +#if 0 /* we do not support external clocked console */ + /* search for clock input with this frq */ + clk_group = ((chan == CONS_CHN_SCC3) || + (chan == CONS_CHN_SCC4) || + (chan == CONS_CHN_SMC2)) ? 1 : 0; + + for (clk_sel = 0, new_brg = -1; + (clk_sel < 4) && (new_brg < 0); + clk_sel++) { + if (baud == (clkin_frq[clk_group][clk_sel] / 16)) { + new_brg = clk_sel + 4; + } + } +#endif + + rtems_interrupt_disable(level); + + if (new_brg < 0) { + /* search for brg with this settings */ + for (brg_idx = 0; + (new_brg < 0) && (brg_idx < BRG_CNT); + brg_idx++) { + if (scc_brg_state[brg_idx].reg_content == reg_val) { + new_brg = brg_idx; + } + } + /* + * if not found: check, whether brg currently in use + * is linked only from our channel + */ + if ((new_brg < 0) && + (old_brg >= 0) && + (scc_brg_state[old_brg].link_cnt == 1)) { + new_brg = old_brg; + } + /* if not found: search for unused brg, set it */ + for (brg_idx = 0; + (new_brg < 0) && (brg_idx < BRG_CNT); + brg_idx++) { + if (scc_brg_state[brg_idx].link_cnt == 0) { + new_brg = brg_idx; + } + } + } + + /* decrease old link count */ + if ((old_brg >= 0) && + (old_brg < 4)) { + scc_brg_state[old_brg].link_cnt--; + } + /* increase new brg link count, set brg */ + if ((new_brg >= 0) && + (new_brg < 4)) { + scc_brg_state[new_brg].link_cnt++; + scc_brg_state[new_brg].reg_content = reg_val; + (&m8xx.brgc1)[new_brg] = reg_val; + } + rtems_interrupt_enable(level); + + /* connect to scc/smc */ + if (new_brg >= 0) { + m8xx_console_chan_desc[chan].brg_used = new_brg; + /* + * Put SCC in NMSI mode, connect SCC to BRG or CLKx + */ + if (m8xx_console_chan_desc[chan].is_scc) { + m8xx.sicr = ((m8xx.sicr & ~(M8xx_SICR_SCCRX_MSK(chan) | + M8xx_SICR_SCCTX_MSK(chan))) | + M8xx_SICR_SCCRX(chan,new_brg)| + M8xx_SICR_SCCTX(chan,new_brg)); + } + else { + /* connect SMC to BRGx or CLKx... */ + m8xx.simode = ((m8xx.simode & ~(M8xx_SIMODE_SMCCS_MSK(chan - CONS_CHN_SMC1)))| + M8xx_SIMODE_SMCCS(chan - CONS_CHN_SMC1,new_brg)); + } + } + return (new_brg < 0); +} + + +/* + * Hardware-dependent portion of tcsetattr(). + */ +static int +sccSetAttributes (int minor, const struct termios *t) +{ + int baud; + + 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; + } + return sccBRGalloc(minor,baud); + return 0; +} + +/* + * Interrupt handler + */ +static rtems_isr +sccInterruptHandler (rtems_vector_number v) +{ + int chan = 0; + /* + * calculate channel from vector + */ + switch(v & M8xx_IVEC_SRC_MASK) { + case M8xx_IVEC_SRC_SCC1: + chan = CONS_CHN_SCC1; + break; + case M8xx_IVEC_SRC_SCC2: + chan = CONS_CHN_SCC2; + break; + case M8xx_IVEC_SRC_SCC3: + chan = CONS_CHN_SCC3; + break; + case M8xx_IVEC_SRC_SCC4: + chan = CONS_CHN_SCC4; + break; + case M8xx_IVEC_SRC_SMC1: + chan = CONS_CHN_SMC1; + break; + case M8xx_IVEC_SRC_SMC2: + chan = CONS_CHN_SMC2; + break; + } + + /* + * Buffer received? + */ + if (CHN_EVENT_GET(chan) & 0x1) { + /* + * clear SCC event flag + */ + CHN_EVENT_CLR(chan,0x01); + /* + * process event + */ + while ((sccCurrRxBd[chan]->status & M8xx_BD_EMPTY) == 0) { + if (sccttyp[chan] != NULL) { + rtems_cache_invalidate_multiple_data_lines((void *)sccCurrRxBd[chan]->buffer, + sccCurrRxBd[chan]->length); + rtems_termios_enqueue_raw_characters (sccttyp[chan], + (char *)sccCurrRxBd[chan]->buffer, + sccCurrRxBd[chan]->length); + } + /* + * clear status + */ + sccCurrRxBd[chan]->status = + (sccCurrRxBd[chan]->status + & (M8xx_BD_WRAP | M8xx_BD_INTERRUPT)) + | M8xx_BD_EMPTY; + /* + * advance to next BD + */ + if ((sccCurrRxBd[chan]->status & M8xx_BD_WRAP) != 0) { + sccCurrRxBd[chan] = sccFrstRxBd[chan]; + } + else { + sccCurrRxBd[chan]++; + } + } + } + /* + * Buffer transmitted? + */ + if (CHN_EVENT_GET(chan) & 0x2) { + /* + * then clear interrupt event bit + */ + CHN_EVENT_CLR(chan,0x2); + /* + * and signal successful transmit to termios + */ + /* + * FIXME: multiple dequeue calls for multiple buffers + */ + while((sccDequTxBd[chan] != sccPrepTxBd[chan]) && + ((sccDequTxBd[chan]->status & M8xx_BD_READY) == 0)) { + if (sccttyp[chan] != NULL) { + rtems_termios_dequeue_characters (sccttyp[chan], + sccDequTxBd[chan]->length); + } + /* + * advance to next BD + */ + if ((sccDequTxBd[chan]->status & M8xx_BD_WRAP) != 0) { + sccDequTxBd[chan] = sccFrstTxBd[chan]; + } + else { + sccDequTxBd[chan]++; + } + } + } + + m8xx.cisr = m8xx_console_chan_desc[chan].ireg_mask;/* Clear interrupt-in-service bit */ +} + +static void +sccInitialize (int chan) +{ + int i; + /* + * allocate buffers + * FIXME: use a cache-line size boundary alloc here + */ + rxBuf[chan] = malloc(sizeof(*rxBuf[chan]) + 2*PPC_CACHE_ALIGNMENT); + if (rxBuf[chan] == NULL) { + BSP_panic("Cannot allocate console rx buffer\n"); + } + else { + /* + * round up rxBuf[chan] to start at a cache line size + */ + rxBuf[chan] = (sccRxBuf_t *) + (((uint32_t)rxBuf[chan]) + + (PPC_CACHE_ALIGNMENT + - ((uint32_t)rxBuf[chan]) % PPC_CACHE_ALIGNMENT)); + } + /* + * Allocate buffer descriptors + */ + sccCurrRxBd[chan] = + sccFrstRxBd[chan] = m8xx_bd_allocate(SCC_RXBD_CNT); + sccPrepTxBd[chan] = + sccDequTxBd[chan] = + sccFrstTxBd[chan] = m8xx_bd_allocate(SCC_TXBD_CNT); + switch(chan) { + case CONS_CHN_SCC1: + /* + * Configure port A pins to enable TXD1 and RXD1 pins + * FIXME: add setup for modem control lines.... + */ + m8xx.papar |= 0x03; + m8xx.padir &= ~0x03; + + /* + * Configure port C pins to enable RTS1 pins (static active low) + */ + m8xx.pcpar &= ~0x01; + m8xx.pcso &= ~0x01; + m8xx.pcdir |= 0x01; + m8xx.pcdat &= ~0x01; + break; + case CONS_CHN_SCC2: + /* + * Configure port A pins to enable TXD2 and RXD2 pins + * FIXME: add setup for modem control lines.... + */ + m8xx.papar |= 0x0C; + m8xx.padir &= ~0x0C; + + /* + * Configure port C pins to enable RTS2 pins (static active low) + */ + m8xx.pcpar &= ~0x02; + m8xx.pcso &= ~0x02; + m8xx.pcdir |= 0x02; + m8xx.pcdat &= ~0x02; + break; + case CONS_CHN_SCC3: + /* + * Configure port A pins to enable TXD3 and RXD3 pins + * FIXME: add setup for modem control lines.... + */ + m8xx.papar |= 0x30; + m8xx.padir &= ~0x30; + + /* + * Configure port C pins to enable RTS3 (static active low) + */ + m8xx.pcpar &= ~0x04; + m8xx.pcso &= ~0x04; + m8xx.pcdir |= 0x04; + m8xx.pcdat &= ~0x04; + break; + case CONS_CHN_SCC4: + /* + * Configure port A pins to enable TXD4 and RXD4 pins + * FIXME: add setup for modem control lines.... + */ + m8xx.papar |= 0xC0; + m8xx.padir &= ~0xC0; + + /* + * Configure port C pins to enable RTS4 pins (static active low) + */ + m8xx.pcpar &= ~0x08; + m8xx.pcso &= ~0x08; + m8xx.pcdir |= 0x08; + m8xx.pcdat &= ~0x08; + break; + case CONS_CHN_SMC1: + /* + * Configure port B pins to enable SMTXD1 and SMRXD1 pins + */ + m8xx.pbpar |= 0xC0; + m8xx.pbdir &= ~0xC0; + break; + case CONS_CHN_SMC2: + /* + * Configure port B pins to enable SMTXD2 and SMRXD2 pins + */ + m8xx.pbpar |= 0xC00; + m8xx.pbdir &= ~0xC00; + break; + } + /* + * allocate and connect BRG + */ + sccBRGalloc(chan,9600); + + + /* + * Set up SCCx parameter RAM common to all protocols + */ + CHN_PARAM_SET(chan,rbase,(char *)sccFrstRxBd[chan] - (char *)&m8xx); + CHN_PARAM_SET(chan,tbase,(char *)sccFrstTxBd[chan] - (char *)&m8xx); + CHN_PARAM_SET(chan,rfcr ,M8xx_RFCR_MOT | M8xx_RFCR_DMA_SPACE(0)); + CHN_PARAM_SET(chan,tfcr ,M8xx_TFCR_MOT | M8xx_TFCR_DMA_SPACE(0)); + if (m8xx_scc_mode[chan] != TERMIOS_POLLED) + CHN_PARAM_SET(chan,mrblr,RXBUFSIZE); + else + CHN_PARAM_SET(chan,mrblr,1); + + /* + * Set up SCCx parameter RAM UART-specific parameters + */ + CHN_PARAM_SET(chan,un.uart.max_idl ,MAX_IDL_DEFAULT); + CHN_PARAM_SET(chan,un.uart.brkln ,0); + CHN_PARAM_SET(chan,un.uart.brkec ,0); + CHN_PARAM_SET(chan,un.uart.brkcr ,0); + if (m8xx_console_chan_desc[chan].is_scc) { + m8xx_console_chan_desc[chan].parms.sccp->un.uart.character[0]=0x8000; /* no char filter */ + m8xx_console_chan_desc[chan].parms.sccp->un.uart.rccm=0x80FF; /* control character mask */ + } + + /* + * Set up the Receive Buffer Descriptors + */ + for (i = 0;i < SCC_RXBD_CNT;i++) { + sccFrstRxBd[chan][i].status = M8xx_BD_EMPTY | M8xx_BD_INTERRUPT; + if (i == SCC_RXBD_CNT-1) { + sccFrstRxBd[chan][i].status |= M8xx_BD_WRAP; + } + sccFrstRxBd[chan][i].length = 0; + sccFrstRxBd[chan][i].buffer = rxBuf[chan][i]; + } + /* + * Setup the Transmit Buffer Descriptor + */ + for (i = 0;i < SCC_TXBD_CNT;i++) { + sccFrstTxBd[chan][i].status = M8xx_BD_INTERRUPT; + if (i == SCC_TXBD_CNT-1) { + sccFrstTxBd[chan][i].status |= M8xx_BD_WRAP; + } + sccFrstTxBd[chan][i].length = 0; + sccFrstTxBd[chan][i].buffer = NULL; + } + + /* + * Set up SCC general and protocol-specific mode registers + */ + CHN_EVENT_CLR(chan,~0); /* Clear any pending events */ + CHN_MASK_SET(chan,0); /* Mask all interrupt/event sources */ + + if (m8xx_console_chan_desc[chan].is_scc) { + m8xx_console_chan_desc[chan].regs.sccr->psmr = 0xb000; /* 8N1, CTS flow control */ + m8xx_console_chan_desc[chan].regs.sccr->gsmr_h = 0x00000000; + m8xx_console_chan_desc[chan].regs.sccr->gsmr_l = 0x00028004; /* UART mode */ + } + else { + m8xx_console_chan_desc[chan].regs.smcr->smcmr = 0x4820; + } + /* + * Send "Init parameters" command + */ + m8xx_cp_execute_cmd(M8xx_CR_OP_INIT_RX_TX + | m8xx_console_chan_desc[chan].cr_chan_code); + + /* + * Enable receiver and transmitter + */ + if (m8xx_console_chan_desc[chan].is_scc) { + m8xx_console_chan_desc[chan].regs.sccr->gsmr_l |= 0x00000030; + } + else { + m8xx_console_chan_desc[chan].regs.smcr->smcmr |= 0x0003; + } + + if (m8xx_scc_mode[chan] != TERMIOS_POLLED) { + rtems_isr_entry old_handler; + rtems_status_code sc; + + sc = rtems_interrupt_catch (sccInterruptHandler, + m8xx_console_chan_desc[chan].ivec_src + | (m8xx.cicr & 0xE0), + &old_handler); + CHN_MASK_SET(chan,3); /* Enable TX and RX interrupts */ + m8xx.cimr |= m8xx_console_chan_desc[chan].ireg_mask; /* Enable interrupts */ + } +} + +/* + * polled scc read function + */ +static int +sccPollRead (int minor) +{ + unsigned char c; + int chan = minor; + + if ((sccCurrRxBd[chan]->status & M8xx_BD_EMPTY) != 0) { + return -1; + } + rtems_cache_invalidate_multiple_data_lines((void *)sccCurrRxBd[chan]->buffer, + sccCurrRxBd[chan]->length); + c = *((char *)sccCurrRxBd[chan]->buffer); + /* + * clear status + */ + sccCurrRxBd[chan]->status = + (sccCurrRxBd[chan]->status + & (M8xx_BD_WRAP | M8xx_BD_INTERRUPT)) + | M8xx_BD_EMPTY; + /* + * advance to next BD + */ + if ((sccCurrRxBd[chan]->status & M8xx_BD_WRAP) != 0) { + sccCurrRxBd[chan] = sccFrstRxBd[chan]; + } + else { + sccCurrRxBd[chan]++; + } + return c; +} + + +/* + * Device-dependent write routine + * Interrupt-driven devices: + * Begin transmission of as many characters as possible (minimum is 1). + * Polling devices: + * Transmit all characters. + */ +static int +sccInterruptWrite (int minor, const char *buf, int len) +{ + int chan = minor; + + if ((sccPrepTxBd[chan]->status & M8xx_BD_READY) == 0) { + sccPrepTxBd[chan]->buffer = (char *)buf; + sccPrepTxBd[chan]->length = len; + rtems_cache_flush_multiple_data_lines((const void *)buf,len); + /* + * clear status, set ready bit + */ + sccPrepTxBd[chan]->status = + (sccPrepTxBd[chan]->status + & M8xx_BD_WRAP) + | M8xx_BD_READY | M8xx_BD_INTERRUPT; + if ((sccPrepTxBd[chan]->status & M8xx_BD_WRAP) != 0) { + sccPrepTxBd[chan] = sccFrstTxBd[chan]; + } + else { + sccPrepTxBd[chan]++; + } + } + return 0; +} + +static int +sccPollWrite (int minor, const char *buf, int len) +{ + int chan = minor; + int bd_used; + + while (len--) { + static char txBuf[CONS_CHN_CNT][SCC_TXBD_CNT]; + while (sccPrepTxBd[chan]->status & M8xx_BD_READY) + continue; + bd_used = sccPrepTxBd[chan]-sccFrstTxBd[chan]; + txBuf[chan][bd_used] = *buf++; + rtems_cache_flush_multiple_data_lines((const void *)&txBuf[chan][bd_used], + sizeof(txBuf[chan][bd_used])); + sccPrepTxBd[chan]->buffer = &(txBuf[chan][bd_used]); + sccPrepTxBd[chan]->length = 1; + sccPrepTxBd[chan]->status = + (sccPrepTxBd[chan]->status + & M8xx_BD_WRAP) + | M8xx_BD_READY; + if ((sccPrepTxBd[chan]->status & M8xx_BD_WRAP) != 0) { + sccPrepTxBd[chan] = sccFrstTxBd[chan]; + } + else { + sccPrepTxBd[chan]++; + } + } + return 0; +} + +/* +*************** +* BOILERPLATE * +*************** +*/ + +struct { + rtems_device_minor_number minor; + int driver_mode; +} channel_list[] = { + {CONS_CHN_SMC1,CONS_SMC1_MODE}, + {CONS_CHN_SMC2,CONS_SMC2_MODE}, + {CONS_CHN_SCC1,CONS_SCC1_MODE}, + {CONS_CHN_SCC2,CONS_SCC2_MODE}, + {CONS_CHN_SCC3,CONS_SCC3_MODE}, + {CONS_CHN_SCC4,CONS_SCC4_MODE} +}; + + +/* + * Initialize and register the device + */ +rtems_device_driver console_initialize(rtems_device_major_number major, + rtems_device_minor_number minor,/* ignored */ + void *arg + ) +{ + rtems_status_code status = RTEMS_SUCCESSFUL; + int chan,entry,ttynum; + char tty_name[] = "/dev/tty00"; + + /* + * init base clock for BRGs + * (if not already set by debugger etc) + */ + if (m8xx_clock_rate == 0) { + m8xx_clock_rate = BSP_bus_frequency; + } + /* + * Set up TERMIOS + */ + rtems_termios_initialize (); + /* + * init BRG allocataion + */ + sccBRGinit(); + ttynum = 0; + for (entry = 0; + (entry < sizeof(channel_list)/sizeof(channel_list[0])) + && (status == RTEMS_SUCCESSFUL); + entry++) { + if (channel_list[entry].driver_mode != CONS_MODE_UNUSED) { + /* + * Do device-specific initialization + */ + chan = channel_list[entry].minor; + m8xx_scc_mode[chan] = channel_list[entry].driver_mode; + sccInitialize (chan); + + /* + * build device name + */ + tty_name[sizeof(tty_name)-2] = '0'+ttynum; + ttynum++; + /* + * Register the device + */ + status = rtems_io_register_name (tty_name, + major, + channel_list[entry].minor); + if (status != RTEMS_SUCCESSFUL) { + rtems_fatal_error_occurred (status); + } + } + } + /* + * register /dev/console + */ + status = rtems_io_register_name ("/dev/console", + major, + CONSOLE_CHN); + if (status != RTEMS_SUCCESSFUL) { + rtems_fatal_error_occurred (status); + } + /* + * FIXME: enable printk support + */ + return RTEMS_SUCCESSFUL; +} + +/* + * Open the device + */ +rtems_device_driver console_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg + ) +{ + rtems_status_code status; + int chan = minor; + rtems_libio_open_close_args_t *args = (rtems_libio_open_close_args_t *)arg; + static const rtems_termios_callbacks interruptCallbacks = { + NULL, /* firstOpen */ + NULL, /* lastClose */ + NULL, /* pollRead */ + sccInterruptWrite, /* write */ + sccSetAttributes, /* setAttributes */ + NULL, /* stopRemoteTx */ + NULL, /* startRemoteTx */ + TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */ + }; + static const rtems_termios_callbacks pollCallbacks = { + NULL, /* firstOpen */ + NULL, /* lastClose */ + sccPollRead, /* pollRead */ + sccPollWrite, /* write */ + sccSetAttributes, /* setAttributes */ + NULL, /* stopRemoteTx */ + NULL, /* startRemoteTx */ + 0 /* outputUsesInterrupts */ + }; + + if (m8xx_scc_mode[chan] == TERMIOS_IRQ_DRIVEN) { + status = rtems_termios_open (major, minor, arg, &interruptCallbacks); + sccttyp[chan] = args->iop->data1; + } + else { + status = rtems_termios_open (major, minor, arg, &pollCallbacks); + sccttyp[chan] = args->iop->data1; + } + return status; +} + +/* + * Close the device + */ +rtems_device_driver console_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg + ) +{ + rtems_status_code rc; + + rc = rtems_termios_close (arg); + sccttyp[minor] = NULL; + + return rc; + +} + +/* + * Read from the device + */ +rtems_device_driver console_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg + ) +{ + return rtems_termios_read (arg); +} + +/* + * Write to the device + */ +rtems_device_driver console_write( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg + ) +{ + return rtems_termios_write (arg); +} + +#if 0 +static int scc_io_set_trm_char(rtems_device_minor_number minor, + rtems_libio_ioctl_args_t *ioa) +{ + rtems_status_code rc = RTEMS_SUCCESSFUL; + con360_io_trm_char_t *trm_char_info = ioa->buffer; + + printf("ioctl called: maxidl=%d\n",trm_char_info->max_idl); + printf("ioctl called: char_cnt=%d\n",trm_char_info->char_cnt); + /* + * check, that parameter is non-NULL + */ + if ((rc == RTEMS_SUCCESSFUL) && + (trm_char_info == NULL)) { + rc = RTEMS_INVALID_ADDRESS; + } + /* + * transfer max_idl + */ + if (rc == RTEMS_SUCCESSFUL) { + if (trm_char_info->max_idl >= 0x10000) { + printf("ioctl called: invalid number for maxidl\n"); + rc = RTEMS_INVALID_NUMBER; + } + else if (trm_char_info->max_idl > 0) { + CHN_PARAM_SET(minor,un.uart.max_idl ,trm_char_info->max_idl); + } + else if (trm_char_info->max_idl == 0) { + CHN_PARAM_SET(minor,un.uart.max_idl ,MAX_IDL_DEFAULT); + } + } + /* + * transfer characters + */ + if (rc == RTEMS_SUCCESSFUL) { + if (trm_char_info->char_cnt > CON8XX_TRM_CHAR_CNT) { + printf("ioctl called: invalid number for char_cnt\n"); + rc = RTEMS_TOO_MANY; + } + else if (trm_char_info->char_cnt >= 0) { + /* + * check, whether device is a SCC + */ + if ((rc == RTEMS_SUCCESSFUL) && + !m8xx_console_chan_desc[minor].is_scc) { + printf("ioctl called: not an scc:%d\n",minor); + rc = RTEMS_UNSATISFIED; + } + else { + int idx = 0; + for(idx = 0;idx < trm_char_info->char_cnt;idx++) { + m8xx_console_chan_desc[minor].parms.sccp->un.uart.character[idx] = + trm_char_info->character[idx] & 0x00ff; + } + if (trm_char_info->char_cnt < CON8XX_TRM_CHAR_CNT) { + m8xx_console_chan_desc[minor].parms.sccp + ->un.uart.character[trm_char_info->char_cnt] = 0x8000; + } + } + } + } + + printf("ioctl called: return code: %d\n",rc); + return rc; +} +#endif + +/* + * Handle ioctl request. + */ +rtems_device_driver console_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg + ) +{ + rtems_libio_ioctl_args_t *ioa=arg; + + switch (ioa->command) { +#if 0 + case CON8XX_IO_SET_TRM_CHAR: + return scc_io_set_trm_char(minor, ioa); +#endif + default: + return rtems_termios_ioctl (arg); + break; + } +} + diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/include/8xx_immap.h b/c/src/lib/libbsp/powerpc/tqm8xx/include/8xx_immap.h new file mode 100644 index 0000000000..de4be69690 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/include/8xx_immap.h @@ -0,0 +1,477 @@ +/*===============================================================*\ +| Project: RTEMS BSP support for TQ modules | ++-----------------------------------------------------------------+ +| Partially based on the code references which are named below. | +| Adaptions, modifications, enhancements and any recent parts of | +| the code are: | +| Copyright (c) 2007 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.com/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains definitions to interact with TQC's | +| processor modules | +\*===============================================================*/ +/* derived from mbx8xx BSP */ +/* + * MPC8xx Internal Memory Map + * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) + * + * The I/O on the MPC860 is comprised of blocks of special registers + * and the dual port ram for the Communication Processor Module. + * Within this space are functional units such as the SIU, memory + * controller, system timers, and other control functions. It is + * a combination that I found difficult to separate into logical + * functional files.....but anyone else is welcome to try. -- Dan + */ +#ifndef __IMMAP_8XX__ +#define __IMMAP_8XX__ + +/* System configuration registers. +*/ +typedef struct sys_conf { + unsigned int sc_siumcr; + unsigned int sc_sypcr; + unsigned int sc_swt; + char res1[2]; + unsigned short sc_swsr; + unsigned int sc_sipend; + unsigned int sc_simask; + unsigned int sc_siel; + unsigned int sc_sivec; + unsigned int sc_tesr; + char res2[0xc]; + unsigned int sc_sdcr; + char res3[0x4c]; +} sysconf8xx_t; + +/* PCMCIA configuration registers. +*/ +typedef struct pcmcia_conf { + unsigned int pcmc_pbr0; + unsigned int pcmc_por0; + unsigned int pcmc_pbr1; + unsigned int pcmc_por1; + unsigned int pcmc_pbr2; + unsigned int pcmc_por2; + unsigned int pcmc_pbr3; + unsigned int pcmc_por3; + unsigned int pcmc_pbr4; + unsigned int pcmc_por4; + unsigned int pcmc_pbr5; + unsigned int pcmc_por5; + unsigned int pcmc_pbr6; + unsigned int pcmc_por6; + unsigned int pcmc_pbr7; + unsigned int pcmc_por7; + char res1[0x20]; + unsigned int pcmc_pgcra; + unsigned int pcmc_pgcrb; + unsigned int pcmc_pscr; + char res2[4]; + unsigned int pcmc_pipr; + char res3[4]; + unsigned int pcmc_per; + char res4[4]; +} pcmconf8xx_t; + +/* Memory controller registers. +*/ +typedef struct mem_ctlr { + unsigned int memc_br0; + unsigned int memc_or0; + unsigned int memc_br1; + unsigned int memc_or1; + unsigned int memc_br2; + unsigned int memc_or2; + unsigned int memc_br3; + unsigned int memc_or3; + unsigned int memc_br4; + unsigned int memc_or4; + unsigned int memc_br5; + unsigned int memc_or5; + unsigned int memc_br6; + unsigned int memc_or6; + unsigned int memc_br7; + unsigned int memc_or7; + char res1[0x24]; + unsigned int memc_mar; + unsigned int memc_mcr; + char res2[4]; + unsigned int memc_mamr; + unsigned int memc_mbmr; + unsigned short memc_mstat; + unsigned short memc_mptpr; + unsigned int memc_mdr; + char res3[0x80]; +} memctl8xx_t; + +/* System Integration Timers. +*/ +typedef struct sys_int_timers { + unsigned short sit_tbscr; + unsigned int sit_tbreff0; + unsigned int sit_tbreff1; + char res1[0x14]; + unsigned short sit_rtcsc; + unsigned int sit_rtc; + unsigned int sit_rtsec; + unsigned int sit_rtcal; + char res2[0x10]; + unsigned short sit_piscr; + char res3[2]; + unsigned int sit_pitc; + unsigned int sit_pitr; + char res4[0x34]; +} sit8xx_t; + +#define TBSCR_TBIRQ_MASK ((unsigned short)0xff00) +#define TBSCR_REFA ((unsigned short)0x0080) +#define TBSCR_REFB ((unsigned short)0x0040) +#define TBSCR_REFAE ((unsigned short)0x0008) +#define TBSCR_REFBE ((unsigned short)0x0004) +#define TBSCR_TBF ((unsigned short)0x0002) +#define TBSCR_TBE ((unsigned short)0x0001) + +#define RTCSC_RTCIRQ_MASK ((unsigned short)0xff00) +#define RTCSC_SEC ((unsigned short)0x0080) +#define RTCSC_ALR ((unsigned short)0x0040) +#define RTCSC_38K ((unsigned short)0x0010) +#define RTCSC_SIE ((unsigned short)0x0008) +#define RTCSC_ALE ((unsigned short)0x0004) +#define RTCSC_RTF ((unsigned short)0x0002) +#define RTCSC_RTE ((unsigned short)0x0001) + +#define PISCR_PIRQ_MASK ((unsigned short)0xff00) +#define PISCR_PS ((unsigned short)0x0080) +#define PISCR_PIE ((unsigned short)0x0004) +#define PISCR_PTF ((unsigned short)0x0002) +#define PISCR_PTE ((unsigned short)0x0001) + +/* Clocks and Reset. +*/ +typedef struct clk_and_reset { + unsigned int car_sccr; + unsigned int car_plprcr; + unsigned int car_rsr; + char res[0x74]; /* Reserved area */ +} car8xx_t; + +/* System Integration Timers keys. +*/ +typedef struct sitk { + unsigned int sitk_tbscrk; + unsigned int sitk_tbreff0k; + unsigned int sitk_tbreff1k; + unsigned int sitk_tbk; + char res1[0x10]; + unsigned int sitk_rtcsck; + unsigned int sitk_rtck; + unsigned int sitk_rtseck; + unsigned int sitk_rtcalk; + char res2[0x10]; + unsigned int sitk_piscrk; + unsigned int sitk_pitck; + char res3[0x38]; +} sitk8xx_t; + +/* Clocks and reset keys. +*/ +typedef struct cark { + unsigned int cark_sccrk; + unsigned int cark_plprcrk; + unsigned int cark_rsrk; + char res[0x474]; +} cark8xx_t; + +/* The key to unlock registers maintained by keep-alive power. +*/ +#define KAPWR_KEY ((unsigned int)0x55ccaa33) + +/* LCD interface. MPC821 Only. +*/ +typedef struct lcd { + unsigned short lcd_lcolr[16]; + char res[0x20]; + unsigned int lcd_lccr; + unsigned int lcd_lchcr; + unsigned int lcd_lcvcr; + char res2[4]; + unsigned int lcd_lcfaa; + unsigned int lcd_lcfba; + char lcd_lcsr; + char res3[0x7]; +} lcd8xx_t; + +/* I2C +*/ +typedef struct i2c { + unsigned char i2c_i2mod; + char res1[3]; + unsigned char i2c_i2add; + char res2[3]; + unsigned char i2c_i2brg; + char res3[3]; + unsigned char i2c_i2com; + char res4[3]; + unsigned char i2c_i2cer; + char res5[3]; + unsigned char i2c_i2cmr; + char res6[0x8b]; +} i2c8xx_t; + +/* DMA control/status registers. +*/ +typedef struct sdma_csr { + char res1[4]; + unsigned int sdma_sdar; + unsigned char sdma_sdsr; + char res3[3]; + unsigned char sdma_sdmr; + char res4[3]; + unsigned char sdma_idsr1; + char res5[3]; + unsigned char sdma_idmr1; + char res6[3]; + unsigned char sdma_idsr2; + char res7[3]; + unsigned char sdma_idmr2; + char res8[0x13]; +} sdma8xx_t; + +/* Communication Processor Module Interrupt Controller. +*/ +typedef struct cpm_ic { + unsigned short cpic_civr; + char res[0xe]; + unsigned int cpic_cicr; + unsigned int cpic_cipr; + unsigned int cpic_cimr; + unsigned int cpic_cisr; +} cpic8xx_t; + +/* Input/Output Port control/status registers. +*/ +typedef struct io_port { + unsigned short iop_padir; + unsigned short iop_papar; + unsigned short iop_paodr; + unsigned short iop_padat; + char res1[8]; + unsigned short iop_pcdir; + unsigned short iop_pcpar; + unsigned short iop_pcso; + unsigned short iop_pcdat; + unsigned short iop_pcint; + char res2[6]; + unsigned short iop_pddir; + unsigned short iop_pdpar; + char res3[2]; + unsigned short iop_pddat; + char res4[8]; +} iop8xx_t; + +/* Communication Processor Module Timers +*/ +typedef struct cpm_timers { + unsigned short cpmt_tgcr; + char res1[0xe]; + unsigned short cpmt_tmr1; + unsigned short cpmt_tmr2; + unsigned short cpmt_trr1; + unsigned short cpmt_trr2; + unsigned short cpmt_tcr1; + unsigned short cpmt_tcr2; + unsigned short cpmt_tcn1; + unsigned short cpmt_tcn2; + unsigned short cpmt_tmr3; + unsigned short cpmt_tmr4; + unsigned short cpmt_trr3; + unsigned short cpmt_trr4; + unsigned short cpmt_tcr3; + unsigned short cpmt_tcr4; + unsigned short cpmt_tcn3; + unsigned short cpmt_tcn4; + unsigned short cpmt_ter1; + unsigned short cpmt_ter2; + unsigned short cpmt_ter3; + unsigned short cpmt_ter4; + char res2[8]; +} cpmtimer8xx_t; + +/* Finally, the Communication Processor stuff..... +*/ +typedef struct scc { /* Serial communication channels */ + unsigned int scc_gsmrl; + unsigned int scc_gsmrh; + unsigned short scc_pmsr; + char res1[2]; + unsigned short scc_todr; + unsigned short scc_dsr; + unsigned short scc_scce; + char res2[2]; + unsigned short scc_sccm; + char res3; + unsigned char scc_sccs; + char res4[8]; +} scc_t; + +typedef struct smc { /* Serial management channels */ + char res1[2]; + unsigned short smc_smcmr; + char res2[2]; + unsigned char smc_smce; + char res3[3]; + unsigned char smc_smcm; + char res4[5]; +} smc_t; + +/* MPC860T Fast Ethernet Controller. It isn't part of the CPM, but + * it fits within the address space. + */ +typedef struct fec { + unsigned int fec_addr_low; /* LS 32 bits of station address */ + unsigned short fec_addr_high; /* MS 16 bits of address */ + unsigned short res1; + unsigned int fec_hash_table_high; + unsigned int fec_hash_table_low; + unsigned int fec_r_des_start; + unsigned int fec_x_des_start; + unsigned int fec_r_buff_size; + unsigned int res2[9]; + unsigned int fec_ecntrl; + unsigned int fec_ievent; + unsigned int fec_imask; + unsigned int fec_ivec; + unsigned int fec_r_des_active; + unsigned int fec_x_des_active; + unsigned int res3[10]; + unsigned int fec_mii_data; + unsigned int fec_mii_speed; + unsigned int res4[17]; + unsigned int fec_r_bound; + unsigned int fec_r_fstart; + unsigned int res5[6]; + unsigned int fec_x_fstart; + unsigned int res6[17]; + unsigned int fec_fun_code; + unsigned int res7[3]; + unsigned int fec_r_cntrl; + unsigned int fec_r_hash; + unsigned int res8[14]; + unsigned int fec_x_cntrl; + unsigned int res9[0x1e]; +} fec_t; + +typedef struct comm_proc { + /* General control and status registers. + */ + unsigned short cp_cpcr; + char res1[2]; + unsigned short cp_rccr; + char res2[6]; + unsigned short cp_cpmcr1; + unsigned short cp_cpmcr2; + unsigned short cp_cpmcr3; + unsigned short cp_cpmcr4; + char res3[2]; + unsigned short cp_rter; + char res4[2]; + unsigned short cp_rtmr; + char res5[0x14]; + + /* Baud rate generators. + */ + unsigned int cp_brgc1; + unsigned int cp_brgc2; + unsigned int cp_brgc3; + unsigned int cp_brgc4; + + /* Serial Communication Channels. + */ + scc_t cp_scc[4]; + + /* Serial Management Channels. + */ + smc_t cp_smc[2]; + + /* Serial Peripheral Interface. + */ + unsigned short cp_spmode; + char res6[4]; + unsigned char cp_spie; + char res7[3]; + unsigned char cp_spim; + char res8[2]; + unsigned char cp_spcom; + char res9[2]; + + /* Parallel Interface Port. + */ + char res10[2]; + unsigned short cp_pipc; + char res11[2]; + unsigned short cp_ptpr; + unsigned int cp_pbdir; + unsigned int cp_pbpar; + char res12[2]; + unsigned short cp_pbodr; + unsigned int cp_pbdat; + char res13[0x18]; + + /* Serial Interface and Time Slot Assignment. + */ + unsigned int cp_simode; + unsigned char cp_sigmr; + char res14; + unsigned char cp_sistr; + unsigned char cp_sicmr; + char res15[4]; + unsigned int cp_sicr; + unsigned int cp_sirp; + char res16[0x10c]; + unsigned char cp_siram[0x200]; + + /* The fast ethernet controller is not really part of the CPM, + * but it resides in the address space. + */ + fec_t cp_fec; + char res18[0x1000]; + + /* Dual Ported RAM follows. + * There are many different formats for this memory area + * depending upon the devices used and options chosen. + */ + unsigned char cp_dpmem[0x1000]; /* BD / Data / ucode */ + unsigned char res19[0xc00]; + unsigned char cp_dparam[0x400]; /* Parameter RAM */ +} cpm8xx_t; + +/* Internal memory map. +*/ +typedef struct immap { + sysconf8xx_t im_siu_conf; /* SIU Configuration */ + pcmconf8xx_t im_pcmcia; /* PCMCIA Configuration */ + memctl8xx_t im_memctl; /* Memory Controller */ + sit8xx_t im_sit; /* System integration timers */ + car8xx_t im_clkrst; /* Clocks and reset */ + sitk8xx_t im_sitk; /* Sys int timer keys */ + cark8xx_t im_clkrstk; /* Clocks and reset keys */ + lcd8xx_t im_lcd; /* LCD (821 only) */ + i2c8xx_t im_i2c; /* I2C control/status */ + sdma8xx_t im_sdma; /* SDMA control/status */ + cpic8xx_t im_cpic; /* CPM Interrupt Controller */ + iop8xx_t im_ioport; /* IO Port control/status */ + cpmtimer8xx_t im_cpmtimer; /* CPM timers */ + cpm8xx_t im_cpm; /* Communication processor */ +} immap_t; + +#endif /* __IMMAP_8XX__ */ diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/include/bsp.h b/c/src/lib/libbsp/powerpc/tqm8xx/include/bsp.h new file mode 100644 index 0000000000..115ed6392c --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/include/bsp.h @@ -0,0 +1,172 @@ +/*===============================================================*\ +| Project: RTEMS TQM8xx BSP | ++-----------------------------------------------------------------+ +| This file has been adapted to MPC8xx by | +| Thomas Doerfler | +| Copyright (c) 2008 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | +| | +| See the other copyright notice below for the original parts. | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.com/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains the console driver | +\*===============================================================*/ +/* derived from MBX8xx BSP: */ +/* bsp.h + * + * This include file contains all board IO definitions. + * + * This file includes definitions for the MBX860 and MBX821. + * + * 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$ + */ + +#ifndef _BSP_H +#define _BSP_H + +/* + * indicate, that BSP is booted via TQMMon + */ +#define BSP_HAS_TQMMON + +LINKER_SYMBOL(TopRamReserved); + +LINKER_SYMBOL( bsp_ram_start); +LINKER_SYMBOL( bsp_ram_end); +LINKER_SYMBOL( bsp_ram_size); + +LINKER_SYMBOL( bsp_rom_start); +LINKER_SYMBOL( bsp_rom_end); +LINKER_SYMBOL( bsp_rom_size); + +LINKER_SYMBOL( bsp_section_text_start); +LINKER_SYMBOL( bsp_section_text_end); +LINKER_SYMBOL( bsp_section_text_size); + +LINKER_SYMBOL( bsp_section_data_start); +LINKER_SYMBOL( bsp_section_data_end); +LINKER_SYMBOL( bsp_section_data_size); + +LINKER_SYMBOL( bsp_section_bss_start); +LINKER_SYMBOL( bsp_section_bss_end); +LINKER_SYMBOL( bsp_section_bss_size); + +LINKER_SYMBOL( bsp_interrupt_stack_start); +LINKER_SYMBOL( bsp_interrupt_stack_end); +LINKER_SYMBOL( bsp_interrupt_stack_size); + +LINKER_SYMBOL( bsp_work_area_start); + +#ifndef ASM +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Network driver configuration + */ +struct rtems_bsdnet_ifconfig; + +#if BSP_USE_NETWORK_FEC +extern int rtems_fec_enet_driver_attach (struct rtems_bsdnet_ifconfig *config, + int attaching); +#define RTEMS_BSP_FEC_NETWORK_DRIVER_NAME "fec1" +#define RTEMS_BSP_FEC_NETWORK_DRIVER_ATTACH rtems_fec_enet_driver_attach +#endif + +#if BSP_USE_NETWORK_SCC +extern int rtems_scc_enet_driver_attach (struct rtems_bsdnet_ifconfig *config, + int attaching); +#define RTEMS_BSP_SCC_NETWORK_DRIVER_NAME "scc1" +#define RTEMS_BSP_SCC_NETWORK_DRIVER_ATTACH rtems_scc_enet_driver_attach +#endif + +#if BSP_USE_NETWORK_FEC +#define RTEMS_BSP_NETWORK_DRIVER_NAME RTEMS_BSP_FEC_NETWORK_DRIVER_NAME +#define RTEMS_BSP_NETWORK_DRIVER_ATTACH RTEMS_BSP_FEC_NETWORK_DRIVER_ATTACH +#elif BSP_USE_NETWORK_SCC +#define RTEMS_BSP_NETWORK_DRIVER_NAME RTEMS_BSP_SCC_NETWORK_DRIVER_NAME +#define RTEMS_BSP_NETWORK_DRIVER_ATTACH RTEMS_BSP_SCC_NETWORK_DRIVER_ATTACH +#endif +/* + * We need to decide how much memory will be non-cacheable. This + * will mainly be memory that will be used in DMA (network and serial + * buffers). + */ +#define NOCACHE_MEM_SIZE 512*1024 + +/* miscellaneous stuff assumed to exist */ + +/* + * Device Driver Table Entries + */ + +/* + * NOTE: Use the standard Console driver entry + */ + +/* + * NOTE: Use the standard Clock driver entry + */ + +/* + * indicate, that BSP has IDE driver + */ +#undef RTEMS_BSP_HAS_IDE_DRIVER + +/* + * How many libio files we want + */ + +#define BSP_LIBIO_MAX_FDS 20 + +/* + * our bus frequency + */ +extern unsigned int BSP_bus_frequency; + +/* functions */ + +void bsp_cleanup( void ); + +rtems_isr_entry set_vector( /* returns old vector */ + rtems_isr_entry handler, /* isr routine */ + rtems_vector_number vector, /* vector number */ + int type /* RTEMS or RAW intr */ +); + + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/include/coverhd.h b/c/src/lib/libbsp/powerpc/tqm8xx/include/coverhd.h new file mode 100644 index 0000000000..543accb2e5 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/include/coverhd.h @@ -0,0 +1,362 @@ +/* coverhd.h + * + * This include file has defines to represent the overhead associated + * with calling a particular directive from C. These are used in the + * Timing Test Suite to ignore the overhead required to pass arguments + * to directives. On some CPUs and/or target boards, this overhead + * is significant and makes it difficult to distinguish internal + * RTEMS execution time from that used to call the directive. + * This file should be updated after running the C overhead timing + * test. Once this update has been performed, the RTEMS Time Test + * Suite should be rebuilt to account for these overhead times in the + * timing results. + * + * NOTE: If these are all zero, then the times reported include + * all calling overhead including passing of arguments. + * + * 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$ + */ + +#ifndef __COVERHD_h +#define __COVERHD_h + +#ifdef __cplusplus +extern "C" { +#endif + +#if ( defined(mbx821_001) || defined(mbx821_001b) || defined(mbx860_001b) ) +#if defined( INSTRUCTION_CACHE_ENABLE ) +/* + * 50 MHz processor, cache enabled. + */ +#define CALLING_OVERHEAD_INITIALIZE_EXECUTIVE 0 +#define CALLING_OVERHEAD_SHUTDOWN_EXECUTIVE 0 +#define CALLING_OVERHEAD_TASK_CREATE 1 +#define CALLING_OVERHEAD_TASK_IDENT 0 +#define CALLING_OVERHEAD_TASK_START 0 +#define CALLING_OVERHEAD_TASK_RESTART 0 +#define CALLING_OVERHEAD_TASK_DELETE 0 +#define CALLING_OVERHEAD_TASK_SUSPEND 0 +#define CALLING_OVERHEAD_TASK_RESUME 0 +#define CALLING_OVERHEAD_TASK_SET_PRIORITY 0 +#define CALLING_OVERHEAD_TASK_MODE 0 +#define CALLING_OVERHEAD_TASK_GET_NOTE 0 +#define CALLING_OVERHEAD_TASK_SET_NOTE 0 +#define CALLING_OVERHEAD_TASK_WAKE_WHEN 1 +#define CALLING_OVERHEAD_TASK_WAKE_AFTER 0 +#define CALLING_OVERHEAD_INTERRUPT_CATCH 0 +#define CALLING_OVERHEAD_CLOCK_GET 1 +#define CALLING_OVERHEAD_CLOCK_SET 1 +#define CALLING_OVERHEAD_CLOCK_TICK 0 + +#define CALLING_OVERHEAD_TIMER_CREATE 0 +#define CALLING_OVERHEAD_TIMER_IDENT 0 +#define CALLING_OVERHEAD_TIMER_DELETE 0 +#define CALLING_OVERHEAD_TIMER_FIRE_AFTER 0 +#define CALLING_OVERHEAD_TIMER_FIRE_WHEN 1 +#define CALLING_OVERHEAD_TIMER_RESET 0 +#define CALLING_OVERHEAD_TIMER_CANCEL 0 +#define CALLING_OVERHEAD_SEMAPHORE_CREATE 0 +#define CALLING_OVERHEAD_SEMAPHORE_IDENT 0 +#define CALLING_OVERHEAD_SEMAPHORE_DELETE 0 +#define CALLING_OVERHEAD_SEMAPHORE_OBTAIN 0 +#define CALLING_OVERHEAD_SEMAPHORE_RELEASE 0 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_CREATE 0 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_IDENT 0 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_DELETE 0 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_SEND 0 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_URGENT 0 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_BROADCAST 0 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_RECEIVE 0 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_FLUSH 0 + +#define CALLING_OVERHEAD_EVENT_SEND 0 +#define CALLING_OVERHEAD_EVENT_RECEIVE 0 +#define CALLING_OVERHEAD_SIGNAL_CATCH 0 +#define CALLING_OVERHEAD_SIGNAL_SEND 0 +#define CALLING_OVERHEAD_PARTITION_CREATE 1 +#define CALLING_OVERHEAD_PARTITION_IDENT 0 +#define CALLING_OVERHEAD_PARTITION_DELETE 0 +#define CALLING_OVERHEAD_PARTITION_GET_BUFFER 0 +#define CALLING_OVERHEAD_PARTITION_RETURN_BUFFER 0 +#define CALLING_OVERHEAD_REGION_CREATE 1 +#define CALLING_OVERHEAD_REGION_IDENT 0 +#define CALLING_OVERHEAD_REGION_DELETE 0 +#define CALLING_OVERHEAD_REGION_GET_SEGMENT 0 +#define CALLING_OVERHEAD_REGION_RETURN_SEGMENT 0 +#define CALLING_OVERHEAD_PORT_CREATE 0 +#define CALLING_OVERHEAD_PORT_IDENT 0 +#define CALLING_OVERHEAD_PORT_DELETE 0 +#define CALLING_OVERHEAD_PORT_EXTERNAL_TO_INTERNAL 0 +#define CALLING_OVERHEAD_PORT_INTERNAL_TO_EXTERNAL 0 + +#define CALLING_OVERHEAD_IO_INITIALIZE 0 +#define CALLING_OVERHEAD_IO_OPEN 0 +#define CALLING_OVERHEAD_IO_CLOSE 0 +#define CALLING_OVERHEAD_IO_READ 0 +#define CALLING_OVERHEAD_IO_WRITE 0 +#define CALLING_OVERHEAD_IO_CONTROL 0 +#define CALLING_OVERHEAD_FATAL_ERROR_OCCURRED 0 +#define CALLING_OVERHEAD_RATE_MONOTONIC_CREATE 0 +#define CALLING_OVERHEAD_RATE_MONOTONIC_IDENT 0 +#define CALLING_OVERHEAD_RATE_MONOTONIC_DELETE 0 +#define CALLING_OVERHEAD_RATE_MONOTONIC_CANCEL 0 +#define CALLING_OVERHEAD_RATE_MONOTONIC_PERIOD 0 +#define CALLING_OVERHEAD_MULTIPROCESSING_ANNOUNCE 0 + +#else +/* + * 50 MHz processor, cache disabled. + */ +#define CALLING_OVERHEAD_INITIALIZE_EXECUTIVE 4 +#define CALLING_OVERHEAD_SHUTDOWN_EXECUTIVE 4 +#define CALLING_OVERHEAD_TASK_CREATE 7 +#define CALLING_OVERHEAD_TASK_IDENT 6 +#define CALLING_OVERHEAD_TASK_START 5 +#define CALLING_OVERHEAD_TASK_RESTART 5 +#define CALLING_OVERHEAD_TASK_DELETE 4 +#define CALLING_OVERHEAD_TASK_SUSPEND 4 +#define CALLING_OVERHEAD_TASK_RESUME 4 +#define CALLING_OVERHEAD_TASK_SET_PRIORITY 5 +#define CALLING_OVERHEAD_TASK_MODE 5 +#define CALLING_OVERHEAD_TASK_GET_NOTE 5 +#define CALLING_OVERHEAD_TASK_SET_NOTE 5 +#define CALLING_OVERHEAD_TASK_WAKE_WHEN 19 +#define CALLING_OVERHEAD_TASK_WAKE_AFTER 4 +#define CALLING_OVERHEAD_INTERRUPT_CATCH 5 +#define CALLING_OVERHEAD_CLOCK_GET 20 +#define CALLING_OVERHEAD_CLOCK_SET 19 +#define CALLING_OVERHEAD_CLOCK_TICK 3 + +#define CALLING_OVERHEAD_TIMER_CREATE 5 +#define CALLING_OVERHEAD_TIMER_IDENT 4 +#define CALLING_OVERHEAD_TIMER_DELETE 5 +#define CALLING_OVERHEAD_TIMER_FIRE_AFTER 6 +#define CALLING_OVERHEAD_TIMER_FIRE_WHEN 21 +#define CALLING_OVERHEAD_TIMER_RESET 4 +#define CALLING_OVERHEAD_TIMER_CANCEL 4 +#define CALLING_OVERHEAD_SEMAPHORE_CREATE 6 +#define CALLING_OVERHEAD_SEMAPHORE_IDENT 4 +#define CALLING_OVERHEAD_SEMAPHORE_DELETE 6 +#define CALLING_OVERHEAD_SEMAPHORE_OBTAIN 5 +#define CALLING_OVERHEAD_SEMAPHORE_RELEASE 4 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_CREATE 6 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_IDENT 6 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_DELETE 4 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_SEND 5 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_URGENT 5 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_BROADCAST 5 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_RECEIVE 6 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_FLUSH 5 + +#define CALLING_OVERHEAD_EVENT_SEND 5 +#define CALLING_OVERHEAD_EVENT_RECEIVE 5 +#define CALLING_OVERHEAD_SIGNAL_CATCH 4 +#define CALLING_OVERHEAD_SIGNAL_SEND 5 +#define CALLING_OVERHEAD_PARTITION_CREATE 7 +#define CALLING_OVERHEAD_PARTITION_IDENT 6 +#define CALLING_OVERHEAD_PARTITION_DELETE 4 +#define CALLING_OVERHEAD_PARTITION_GET_BUFFER 5 +#define CALLING_OVERHEAD_PARTITION_RETURN_BUFFER 5 +#define CALLING_OVERHEAD_REGION_CREATE 7 +#define CALLING_OVERHEAD_REGION_IDENT 5 +#define CALLING_OVERHEAD_REGION_DELETE 4 +#define CALLING_OVERHEAD_REGION_GET_SEGMENT 6 +#define CALLING_OVERHEAD_REGION_RETURN_SEGMENT 5 +#define CALLING_OVERHEAD_PORT_CREATE 6 +#define CALLING_OVERHEAD_PORT_IDENT 5 +#define CALLING_OVERHEAD_PORT_DELETE 4 +#define CALLING_OVERHEAD_PORT_EXTERNAL_TO_INTERNAL 6 +#define CALLING_OVERHEAD_PORT_INTERNAL_TO_EXTERNAL 6 + +#define CALLING_OVERHEAD_IO_INITIALIZE 6 +#define CALLING_OVERHEAD_IO_OPEN 6 +#define CALLING_OVERHEAD_IO_CLOSE 6 +#define CALLING_OVERHEAD_IO_READ 6 +#define CALLING_OVERHEAD_IO_WRITE 6 +#define CALLING_OVERHEAD_IO_CONTROL 6 +#define CALLING_OVERHEAD_FATAL_ERROR_OCCURRED 4 +#define CALLING_OVERHEAD_RATE_MONOTONIC_CREATE 5 +#define CALLING_OVERHEAD_RATE_MONOTONIC_IDENT 5 +#define CALLING_OVERHEAD_RATE_MONOTONIC_DELETE 4 +#define CALLING_OVERHEAD_RATE_MONOTONIC_CANCEL 4 +#define CALLING_OVERHEAD_RATE_MONOTONIC_PERIOD 5 +#define CALLING_OVERHEAD_MULTIPROCESSING_ANNOUNCE 3 + +#endif /* defined( INSTRUCTION_CACHE_ENABLE ) */ + +#else +#if defined( INSTRUCTION_CACHE_ENABLE ) +/* + * 40 MHz processor, cache enabled. + */ +#define CALLING_OVERHEAD_INITIALIZE_EXECUTIVE 0 +#define CALLING_OVERHEAD_SHUTDOWN_EXECUTIVE 1 +#define CALLING_OVERHEAD_TASK_CREATE 1 +#define CALLING_OVERHEAD_TASK_IDENT 0 +#define CALLING_OVERHEAD_TASK_START 0 +#define CALLING_OVERHEAD_TASK_RESTART 0 +#define CALLING_OVERHEAD_TASK_DELETE 0 +#define CALLING_OVERHEAD_TASK_SUSPEND 0 +#define CALLING_OVERHEAD_TASK_RESUME 0 +#define CALLING_OVERHEAD_TASK_SET_PRIORITY 0 +#define CALLING_OVERHEAD_TASK_MODE 0 +#define CALLING_OVERHEAD_TASK_GET_NOTE 0 +#define CALLING_OVERHEAD_TASK_SET_NOTE 0 +#define CALLING_OVERHEAD_TASK_WAKE_WHEN 1 +#define CALLING_OVERHEAD_TASK_WAKE_AFTER 0 +#define CALLING_OVERHEAD_INTERRUPT_CATCH 0 +#define CALLING_OVERHEAD_CLOCK_GET 1 +#define CALLING_OVERHEAD_CLOCK_SET 1 +#define CALLING_OVERHEAD_CLOCK_TICK 0 + +#define CALLING_OVERHEAD_TIMER_CREATE 0 +#define CALLING_OVERHEAD_TIMER_IDENT 0 +#define CALLING_OVERHEAD_TIMER_DELETE 0 +#define CALLING_OVERHEAD_TIMER_FIRE_AFTER 0 +#define CALLING_OVERHEAD_TIMER_FIRE_WHEN 1 +#define CALLING_OVERHEAD_TIMER_RESET 0 +#define CALLING_OVERHEAD_TIMER_CANCEL 0 +#define CALLING_OVERHEAD_SEMAPHORE_CREATE 0 +#define CALLING_OVERHEAD_SEMAPHORE_IDENT 0 +#define CALLING_OVERHEAD_SEMAPHORE_DELETE 0 +#define CALLING_OVERHEAD_SEMAPHORE_OBTAIN 0 +#define CALLING_OVERHEAD_SEMAPHORE_RELEASE 0 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_CREATE 0 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_IDENT 0 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_DELETE 0 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_SEND 0 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_URGENT 0 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_BROADCAST 0 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_RECEIVE 0 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_FLUSH 0 + +#define CALLING_OVERHEAD_EVENT_SEND 0 +#define CALLING_OVERHEAD_EVENT_RECEIVE 0 +#define CALLING_OVERHEAD_SIGNAL_CATCH 0 +#define CALLING_OVERHEAD_SIGNAL_SEND 0 +#define CALLING_OVERHEAD_PARTITION_CREATE 1 +#define CALLING_OVERHEAD_PARTITION_IDENT 0 +#define CALLING_OVERHEAD_PARTITION_DELETE 0 +#define CALLING_OVERHEAD_PARTITION_GET_BUFFER 0 +#define CALLING_OVERHEAD_PARTITION_RETURN_BUFFER 0 +#define CALLING_OVERHEAD_REGION_CREATE 1 +#define CALLING_OVERHEAD_REGION_IDENT 0 +#define CALLING_OVERHEAD_REGION_DELETE 0 +#define CALLING_OVERHEAD_REGION_GET_SEGMENT 0 +#define CALLING_OVERHEAD_REGION_RETURN_SEGMENT 0 +#define CALLING_OVERHEAD_PORT_CREATE 2 +#define CALLING_OVERHEAD_PORT_IDENT 0 +#define CALLING_OVERHEAD_PORT_DELETE 0 +#define CALLING_OVERHEAD_PORT_EXTERNAL_TO_INTERNAL 0 +#define CALLING_OVERHEAD_PORT_INTERNAL_TO_EXTERNAL 0 + +#define CALLING_OVERHEAD_IO_INITIALIZE 0 +#define CALLING_OVERHEAD_IO_OPEN 0 +#define CALLING_OVERHEAD_IO_CLOSE 0 +#define CALLING_OVERHEAD_IO_READ 0 +#define CALLING_OVERHEAD_IO_WRITE 0 +#define CALLING_OVERHEAD_IO_CONTROL 0 +#define CALLING_OVERHEAD_FATAL_ERROR_OCCURRED 0 +#define CALLING_OVERHEAD_RATE_MONOTONIC_CREATE 0 +#define CALLING_OVERHEAD_RATE_MONOTONIC_IDENT 0 +#define CALLING_OVERHEAD_RATE_MONOTONIC_DELETE 0 +#define CALLING_OVERHEAD_RATE_MONOTONIC_CANCEL 0 +#define CALLING_OVERHEAD_RATE_MONOTONIC_PERIOD 0 +#define CALLING_OVERHEAD_MULTIPROCESSING_ANNOUNCE 0 + +#else +/* + * 40 MHz processor, cache disabled. + */ +#define CALLING_OVERHEAD_INITIALIZE_EXECUTIVE 4 +#define CALLING_OVERHEAD_SHUTDOWN_EXECUTIVE 3 +#define CALLING_OVERHEAD_TASK_CREATE 6 +#define CALLING_OVERHEAD_TASK_IDENT 5 +#define CALLING_OVERHEAD_TASK_START 5 +#define CALLING_OVERHEAD_TASK_RESTART 4 +#define CALLING_OVERHEAD_TASK_DELETE 4 +#define CALLING_OVERHEAD_TASK_SUSPEND 4 +#define CALLING_OVERHEAD_TASK_RESUME 4 +#define CALLING_OVERHEAD_TASK_SET_PRIORITY 5 +#define CALLING_OVERHEAD_TASK_MODE 4 +#define CALLING_OVERHEAD_TASK_GET_NOTE 5 +#define CALLING_OVERHEAD_TASK_SET_NOTE 5 +#define CALLING_OVERHEAD_TASK_WAKE_WHEN 17 +#define CALLING_OVERHEAD_TASK_WAKE_AFTER 3 +#define CALLING_OVERHEAD_INTERRUPT_CATCH 5 +#define CALLING_OVERHEAD_CLOCK_GET 17 +#define CALLING_OVERHEAD_CLOCK_SET 17 +#define CALLING_OVERHEAD_CLOCK_TICK 3 + +#define CALLING_OVERHEAD_TIMER_CREATE 4 +#define CALLING_OVERHEAD_TIMER_IDENT 4 +#define CALLING_OVERHEAD_TIMER_DELETE 5 +#define CALLING_OVERHEAD_TIMER_FIRE_AFTER 5 +#define CALLING_OVERHEAD_TIMER_FIRE_WHEN 19 +#define CALLING_OVERHEAD_TIMER_RESET 4 +#define CALLING_OVERHEAD_TIMER_CANCEL 4 +#define CALLING_OVERHEAD_SEMAPHORE_CREATE 6 +#define CALLING_OVERHEAD_SEMAPHORE_IDENT 4 +#define CALLING_OVERHEAD_SEMAPHORE_DELETE 5 +#define CALLING_OVERHEAD_SEMAPHORE_OBTAIN 5 +#define CALLING_OVERHEAD_SEMAPHORE_RELEASE 4 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_CREATE 5 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_IDENT 5 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_DELETE 4 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_SEND 4 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_URGENT 4 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_BROADCAST 5 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_RECEIVE 5 +#define CALLING_OVERHEAD_MESSAGE_QUEUE_FLUSH 4 + +#define CALLING_OVERHEAD_EVENT_SEND 5 +#define CALLING_OVERHEAD_EVENT_RECEIVE 5 +#define CALLING_OVERHEAD_SIGNAL_CATCH 4 +#define CALLING_OVERHEAD_SIGNAL_SEND 4 +#define CALLING_OVERHEAD_PARTITION_CREATE 6 +#define CALLING_OVERHEAD_PARTITION_IDENT 5 +#define CALLING_OVERHEAD_PARTITION_DELETE 4 +#define CALLING_OVERHEAD_PARTITION_GET_BUFFER 5 +#define CALLING_OVERHEAD_PARTITION_RETURN_BUFFER 5 +#define CALLING_OVERHEAD_REGION_CREATE 6 +#define CALLING_OVERHEAD_REGION_IDENT 5 +#define CALLING_OVERHEAD_REGION_DELETE 4 +#define CALLING_OVERHEAD_REGION_GET_SEGMENT 6 +#define CALLING_OVERHEAD_REGION_RETURN_SEGMENT 5 +#define CALLING_OVERHEAD_PORT_CREATE 6 +#define CALLING_OVERHEAD_PORT_IDENT 5 +#define CALLING_OVERHEAD_PORT_DELETE 4 +#define CALLING_OVERHEAD_PORT_EXTERNAL_TO_INTERNAL 5 +#define CALLING_OVERHEAD_PORT_INTERNAL_TO_EXTERNAL 5 + +#define CALLING_OVERHEAD_IO_INITIALIZE 5 +#define CALLING_OVERHEAD_IO_OPEN 5 +#define CALLING_OVERHEAD_IO_CLOSE 5 +#define CALLING_OVERHEAD_IO_READ 5 +#define CALLING_OVERHEAD_IO_WRITE 5 +#define CALLING_OVERHEAD_IO_CONTROL 5 +#define CALLING_OVERHEAD_FATAL_ERROR_OCCURRED 3 +#define CALLING_OVERHEAD_RATE_MONOTONIC_CREATE 4 +#define CALLING_OVERHEAD_RATE_MONOTONIC_IDENT 5 +#define CALLING_OVERHEAD_RATE_MONOTONIC_DELETE 4 +#define CALLING_OVERHEAD_RATE_MONOTONIC_CANCEL 4 +#define CALLING_OVERHEAD_RATE_MONOTONIC_PERIOD 4 +#define CALLING_OVERHEAD_MULTIPROCESSING_ANNOUNCE 3 + +#endif /* defined( INSTRUCTION_CACHE_ENABLE ) */ + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/include/irq-config.h b/c/src/lib/libbsp/powerpc/tqm8xx/include/irq-config.h new file mode 100644 index 0000000000..cdfdfa9dc0 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/include/irq-config.h @@ -0,0 +1,101 @@ +/*===============================================================*\ +| Project: RTEMS TQM8xx BSP | ++-----------------------------------------------------------------+ +| This file has been adapted to MPC8xx by | +| Thomas Doerfler | +| Copyright (c) 2008 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | +| | +| See the other copyright notice below for the original parts. | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.com/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains the console driver | +\*===============================================================*/ +/* derived from: generic MPC83xx BSP */ +/** + * @file + * + * @ingroup bsp_interrupt + * + * @brief BSP interrupt support configuration. + */ + +/* + * Copyright (c) 2008 + * Embedded Brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * rtems@embedded-brains.de + * + * The license and distribution terms for this file may be found in the file + * LICENSE in this distribution or at http://www.rtems.com/license/LICENSE. + */ + +#ifndef LIBBSP_POWERPC_TQM8XX_IRQ_CONFIG_H +#define LIBBSP_POWERPC_TQM8XX_IRQ_CONFIG_H + +#include + +#include + +/** + * @addtogroup bsp_interrupt + * + * @{ + */ + +/** + * @brief Minimum vector number. + */ +#define BSP_INTERRUPT_VECTOR_MIN BSP_LOWEST_OFFSET + +/** + * @brief Maximum vector number. + */ +#define BSP_INTERRUPT_VECTOR_MAX BSP_MAX_OFFSET + +/** + * @brief Enables the index table. + * + * If you enable the index table, you have to define a size for the handler + * table (@ref BSP_INTERRUPT_HANDLER_TABLE_SIZE) and must provide an integer + * type capable to index the complete handler table (@ref + * bsp_interrupt_handler_index_type). + */ +#undef BSP_INTERRUPT_USE_INDEX_TABLE + +/** + * @brief Disables usage of the heap. + * + * If you define this, you have to define @ref BSP_INTERRUPT_USE_INDEX_TABLE as + * well. + */ +#undef BSP_INTERRUPT_NO_HEAP_USAGE + +#ifdef BSP_INTERRUPT_USE_INDEX_TABLE + +/** + * @brief Size of the handler table. + */ +#define BSP_INTERRUPT_HANDLER_TABLE_SIZE 63 + +/** + * @brief Integer type capable to index the complete handler table. + */ +typedef uint8_t bsp_interrupt_handler_index_type; + +#endif /* BSP_INTERRUPT_USE_INDEX_TABLE */ + +/** @} */ + +#endif /* LIBBSP_POWERPC_TQM8XX_IRQ_CONFIG_H */ diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/include/irq.h b/c/src/lib/libbsp/powerpc/tqm8xx/include/irq.h new file mode 100644 index 0000000000..2ada75bd43 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/include/irq.h @@ -0,0 +1,154 @@ +/*===============================================================*\ +| Project: RTEMS TQM8xx BSP | ++-----------------------------------------------------------------+ +| This file has been adapted to MPC8xx by | +| Thomas Doerfler | +| Copyright (c) 2008 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | +| | +| See the other copyright notice below for the original parts. | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.com/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains the console driver | +\*===============================================================*/ +/* derived from: generic MPC83xx BSP */ +#ifndef TQM8xx_IRQ_IRQ_H +#define TQM8xx_IRQ_IRQ_H + +#include + +#include +#include +#include + +/* + * the following definitions specify the indices used + * to interface the interrupt handler API + */ + +/* + * Peripheral IRQ handlers related definitions + */ +#define BSP_SIU_PER_IRQ_NUMBER 16 +#define BSP_SIU_IRQ_LOWEST_OFFSET 0 +#define BSP_SIU_IRQ_MAX_OFFSET (BSP_SIU_IRQ_LOWEST_OFFSET\ + +BSP_SIU_PER_IRQ_NUMBER-1) + +#define BSP_IS_SIU_IRQ(irqnum) \ + (((irqnum) >= BSP_SIU_IRQ_LOWEST_OFFSET) && \ + ((irqnum) <= BSP_SIU_IRQ_MAX_OFFSET)) + +#define BSP_CPM_PER_IRQ_NUMBER 32 +#define BSP_CPM_IRQ_LOWEST_OFFSET (BSP_SIU_IRQ_MAX_OFFSET+1) +#define BSP_CPM_IRQ_MAX_OFFSET (BSP_CPM_IRQ_LOWEST_OFFSET\ + +BSP_CPM_PER_IRQ_NUMBER-1) + +#define BSP_IS_CPM_IRQ(irqnum) \ + (((irqnum) >= BSP_CPM_IRQ_LOWEST_OFFSET) && \ + ((irqnum) <= BSP_CPM_IRQ_MAX_OFFSET)) +/* + * Processor IRQ handlers related definitions + */ +#define BSP_PROCESSOR_IRQ_NUMBER 1 +#define BSP_PROCESSOR_IRQ_LOWEST_OFFSET (BSP_CPM_IRQ_MAX_OFFSET+1) +#define BSP_PROCESSOR_IRQ_MAX_OFFSET (BSP_PROCESSOR_IRQ_LOWEST_OFFSET\ + +BSP_PROCESSOR_IRQ_NUMBER-1) + +#define BSP_IS_PROCESSOR_IRQ(irqnum) \ + (((irqnum) >= BSP_PROCESSOR_IRQ_LOWEST_OFFSET) && \ + ((irqnum) <= BSP_PROCESSOR_IRQ_MAX_OFFSET)) +/* + * Summary + */ +#define BSP_IRQ_NUMBER (BSP_PROCESSOR_IRQ_MAX_OFFSET+1) +#define BSP_LOWEST_OFFSET BSP_SIU_IRQ_LOWEST_OFFSET +#define BSP_MAX_OFFSET BSP_PROCESSOR_IRQ_MAX_OFFSET + +#define BSP_IS_VALID_IRQ(irqnum) \ + (BSP_IS_PROCESSOR_IRQ(irqnum) \ + || BSP_IS_SIU_IRQ(irqnum) \ + || BSP_IS_CPM_IRQ(irqnum)) + +#ifndef ASM +#ifdef __cplusplus +extern "C" { +#endif + +/* + * index table for the module specific handlers, a few entries are only placeholders + */ + typedef enum { + BSP_SIU_EXT_IRQ_0 = BSP_SIU_IRQ_LOWEST_OFFSET + 0, + BSP_SIU_INT_IRQ_0 = BSP_SIU_IRQ_LOWEST_OFFSET + 1, + BSP_SIU_EXT_IRQ_1 = BSP_SIU_IRQ_LOWEST_OFFSET + 2, + BSP_SIU_INT_IRQ_1 = BSP_SIU_IRQ_LOWEST_OFFSET + 3, + BSP_SIU_EXT_IRQ_2 = BSP_SIU_IRQ_LOWEST_OFFSET + 4, + BSP_SIU_INT_IRQ_2 = BSP_SIU_IRQ_LOWEST_OFFSET + 5, + BSP_SIU_EXT_IRQ_3 = BSP_SIU_IRQ_LOWEST_OFFSET + 6, + BSP_SIU_INT_IRQ_3 = BSP_SIU_IRQ_LOWEST_OFFSET + 7, + BSP_SIU_EXT_IRQ_4 = BSP_SIU_IRQ_LOWEST_OFFSET + 8, + BSP_SIU_INT_IRQ_4 = BSP_SIU_IRQ_LOWEST_OFFSET + 9, + BSP_SIU_EXT_IRQ_5 = BSP_SIU_IRQ_LOWEST_OFFSET + 10, + BSP_SIU_INT_IRQ_5 = BSP_SIU_IRQ_LOWEST_OFFSET + 11, + BSP_SIU_EXT_IRQ_6 = BSP_SIU_IRQ_LOWEST_OFFSET + 12, + BSP_SIU_INT_IRQ_6 = BSP_SIU_IRQ_LOWEST_OFFSET + 13, + BSP_SIU_EXT_IRQ_7 = BSP_SIU_IRQ_LOWEST_OFFSET + 14, + BSP_SIU_INT_IRQ_7 = BSP_SIU_IRQ_LOWEST_OFFSET + 15, + BSP_SIU_IRQ_LAST = BSP_SIU_IRQ_MAX_OFFSET, + /* + * Some CPM IRQ symbolic name definition + */ + BSP_CPM_IRQ_ERROR = (BSP_CPM_IRQ_LOWEST_OFFSET), + BSP_CPM_IRQ_PARALLEL_IO_PC4 = (BSP_CPM_IRQ_LOWEST_OFFSET + 1), + BSP_CPM_IRQ_PARALLEL_IO_PC5 = (BSP_CPM_IRQ_LOWEST_OFFSET + 2), + BSP_CPM_IRQ_SMC2_OR_PIP = (BSP_CPM_IRQ_LOWEST_OFFSET + 3), + BSP_CPM_IRQ_SMC1 = (BSP_CPM_IRQ_LOWEST_OFFSET + 4), + BSP_CPM_IRQ_SPI = (BSP_CPM_IRQ_LOWEST_OFFSET + 5), + BSP_CPM_IRQ_PARALLEL_IO_PC6 = (BSP_CPM_IRQ_LOWEST_OFFSET + 6), + BSP_CPM_IRQ_TIMER_4 = (BSP_CPM_IRQ_LOWEST_OFFSET + 7), + BSP_CPM_IRQ_PARALLEL_IO_PC7 = (BSP_CPM_IRQ_LOWEST_OFFSET + 9), + BSP_CPM_IRQ_PARALLEL_IO_PC8 = (BSP_CPM_IRQ_LOWEST_OFFSET + 10), + BSP_CPM_IRQ_PARALLEL_IO_PC9 = (BSP_CPM_IRQ_LOWEST_OFFSET + 11), + BSP_CPM_IRQ_TIMER_3 = (BSP_CPM_IRQ_LOWEST_OFFSET + 12), + BSP_CPM_IRQ_PARALLEL_IO_PC10= (BSP_CPM_IRQ_LOWEST_OFFSET + 14), + BSP_CPM_IRQ_PARALLEL_IO_PC11= (BSP_CPM_IRQ_LOWEST_OFFSET + 15), + BSP_CPM_I2C = (BSP_CPM_IRQ_LOWEST_OFFSET + 16), + BSP_CPM_RISC_TIMER_TABLE = (BSP_CPM_IRQ_LOWEST_OFFSET + 17), + BSP_CPM_IRQ_TIMER_2 = (BSP_CPM_IRQ_LOWEST_OFFSET + 18), + BSP_CPM_IDMA2 = (BSP_CPM_IRQ_LOWEST_OFFSET + 20), + BSP_CPM_IDMA1 = (BSP_CPM_IRQ_LOWEST_OFFSET + 21), + BSP_CPM_SDMA_CHANNEL_BUS_ERR= (BSP_CPM_IRQ_LOWEST_OFFSET + 22), + BSP_CPM_IRQ_PARALLEL_IO_PC12= (BSP_CPM_IRQ_LOWEST_OFFSET + 23), + BSP_CPM_IRQ_PARALLEL_IO_PC13= (BSP_CPM_IRQ_LOWEST_OFFSET + 24), + BSP_CPM_IRQ_TIMER_1 = (BSP_CPM_IRQ_LOWEST_OFFSET + 25), + BSP_CPM_IRQ_PARALLEL_IO_PC14= (BSP_CPM_IRQ_LOWEST_OFFSET + 26), + BSP_CPM_IRQ_SCC4 = (BSP_CPM_IRQ_LOWEST_OFFSET + 27), + BSP_CPM_IRQ_SCC3 = (BSP_CPM_IRQ_LOWEST_OFFSET + 28), + BSP_CPM_IRQ_SCC2 = (BSP_CPM_IRQ_LOWEST_OFFSET + 29), + BSP_CPM_IRQ_SCC1 = (BSP_CPM_IRQ_LOWEST_OFFSET + 30), + BSP_CPM_IRQ_PARALLEL_IO_PC15= (BSP_CPM_IRQ_LOWEST_OFFSET + 31), + BSP_CPM_IRQ_LAST = BSP_CPM_IRQ_MAX_OFFSET, + } rtems_irq_symbolic_name; + + /* + * Symbolic name for CPM interrupt on SIU Internal level 2 + */ +#define BSP_CPM_INTERRUPT BSP_SIU_INT_IRQ_2 +#define BSP_PERIODIC_TIMER BSP_SIU_INT_IRQ_6 +#define BSP_FAST_ETHERNET_CTRL BSP_SIU_INT_IRQ_3 + +#ifdef __cplusplus +} +#endif +#endif /* ASM */ + +#endif /* TQM8XX_IRQ_IRQ_H */ diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/include/tm27.h b/c/src/lib/libbsp/powerpc/tqm8xx/include/tm27.h new file mode 100644 index 0000000000..ee820ef1ff --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/include/tm27.h @@ -0,0 +1,32 @@ +/* + * tm27.h + * + * 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$ + */ + +#ifndef _RTEMS_TMTEST27 +#error "This is an RTEMS internal file you must not include directly." +#endif + +#ifndef __tm27_h +#define __tm27_h + +/* + * Stuff for Time Test 27 + */ + +#define MUST_WAIT_FOR_INTERRUPT 0 + +#define Install_tm27_vector( handler ) /* set_vector( (handler), 0, 1 ) */ + +#define Cause_tm27_intr() /* empty */ + +#define Clear_tm27_intr() /* empty */ + +#define Lower_tm27_intr() /* empty */ + +#endif diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/include/tqm.h b/c/src/lib/libbsp/powerpc/tqm8xx/include/tqm.h new file mode 100644 index 0000000000..31500e25f2 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/include/tqm.h @@ -0,0 +1,51 @@ +/*===============================================================*\ +| Project: RTEMS BSP support for TQ modules | ++-----------------------------------------------------------------+ +| Partially based on the code references which are named below. | +| Adaptions, modifications, enhancements and any recent parts of | +| the code are: | +| Copyright (c) 2007 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.com/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains definitions to interact with TQC's | +| processor modules | +\*===============================================================*/ + +#ifndef __TQM_H__ +#define __TQM_H__ +#include + +typedef struct { + uint32_t sdram_size; /* existing SDRAM size */ + uint32_t flash_base; /* start address flash */ + uint32_t flash_size; /* existing Flash size */ + uint32_t flash_offset; + uint32_t sram_base; /* start address sram */ + uint32_t sram_size; /* existing sram size */ + uint32_t immr_base; /* start address internal memory map */ + uint32_t reboot; /* reboot flag */ + uint8_t ip_addr[4]; /* IP address */ + uint8_t eth_addr[6]; /* ethernet (MAC) address */ + uint8_t gap_42[2]; /* gap for alignment */ + void (*put_char)(int c); /* function to output characters */ +} tqm_bd_info_t; + +#define TQM_BD_INFO_ADDR 0x3400 +#define TQM_BD_INFO (*(tqm_bd_info_t *)TQM_BD_INFO_ADDR) + +#define TQM_CONF_INFO_BLOCK_ADDR 0x4001fe00 + +#define IMAP_ADDR ((unsigned int)0xfa200000) +#define IMAP_SIZE ((unsigned int)(64 * 1024)) + +#endif /* __TQM_H__ */ diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/irq/irq.c b/c/src/lib/libbsp/powerpc/tqm8xx/irq/irq.c new file mode 100644 index 0000000000..4dac7fb38b --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/irq/irq.c @@ -0,0 +1,240 @@ +/*===============================================================*\ +| Project: RTEMS TQM8xx BSP | ++-----------------------------------------------------------------+ +| This file has been adapted to MPC8xx by | +| Thomas Doerfler | +| Copyright (c) 2008 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | +| | +| See the other copyright notice below for the original parts. | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.com/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains the console driver | +\*===============================================================*/ +/* derived from: generic MPC83xx BSP */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +/* + * functions to enable/disable a source at the SIU/CPM irq controller + */ + +rtems_status_code bsp_irq_disable_at_SIU(rtems_vector_number irqnum) +{ + rtems_vector_number vecnum = irqnum - BSP_SIU_IRQ_LOWEST_OFFSET; + m8xx.simask &= ~(1 << (31 - vecnum)); + return RTEMS_SUCCESSFUL; +} + +rtems_status_code bsp_irq_enable_at_SIU(rtems_vector_number irqnum) +{ + rtems_vector_number vecnum = irqnum - BSP_SIU_IRQ_LOWEST_OFFSET; + m8xx.simask |= (1 << (31 - vecnum)); + return RTEMS_SUCCESSFUL; +} + +rtems_status_code bsp_irq_disable_at_CPM(rtems_vector_number irqnum) +{ + rtems_vector_number vecnum = irqnum - BSP_CPM_IRQ_LOWEST_OFFSET; + m8xx.cimr &= ~(1 << (31 - vecnum)); + return RTEMS_SUCCESSFUL; +} + +rtems_status_code bsp_irq_enable_at_CPM(rtems_vector_number irqnum) +{ + rtems_vector_number vecnum = irqnum - BSP_CPM_IRQ_LOWEST_OFFSET; + m8xx.cimr |= (1 << (31 - vecnum)); + return RTEMS_SUCCESSFUL; +} + +rtems_status_code bsp_interrupt_vector_enable( rtems_vector_number irqnum) +{ + if (BSP_IS_CPM_IRQ(irqnum)) { + bsp_irq_enable_at_CPM(irqnum); + return RTEMS_SUCCESSFUL; + } + else if (BSP_IS_SIU_IRQ(irqnum)) { + bsp_irq_enable_at_SIU(irqnum); + return RTEMS_SUCCESSFUL; + } + return RTEMS_INVALID_ID; +} + +rtems_status_code bsp_interrupt_vector_disable( rtems_vector_number irqnum) +{ + if (BSP_IS_CPM_IRQ(irqnum)) { + bsp_irq_disable_at_CPM(irqnum); + return RTEMS_SUCCESSFUL; + } + else if (BSP_IS_SIU_IRQ(irqnum)) { + bsp_irq_disable_at_SIU(irqnum); + return RTEMS_SUCCESSFUL; + } + return RTEMS_INVALID_ID; +} + +/* + * IRQ Handler: this is called from the primary exception dispatcher + */ +static int BSP_irq_handle_at_cpm(void) +{ + int32_t cpvecnum; + uint32_t msr; + rtems_interrupt_level level; + + /* Get vector number: write IACK=1, then read vectir */ + m8xx.civr = 1; + cpvecnum = (m8xx.civr >> 11) + BSP_CPM_IRQ_LOWEST_OFFSET; + + /* + * Check the vector number, mask lower priority interrupts, enable + * exceptions and dispatch the handler. + */ + if (BSP_IS_CPM_IRQ(cpvecnum)) { + /* Enable all interrupts */ + msr = ppc_external_exceptions_enable(); + /* Dispatch interrupt handlers */ + bsp_interrupt_handler_dispatch(cpvecnum); + /* Restore machine state */ + ppc_external_exceptions_disable(msr); + /* + * clear "in-service" bit + */ + m8xx.cisr = 1 << (cpvecnum - BSP_CPM_IRQ_LOWEST_OFFSET); + } + else { + /* not valid vector */ + bsp_interrupt_handler_default(cpvecnum); + } + return 0; +} + +static int BSP_irq_handle_at_siu( unsigned excNum) +{ + int32_t sivecnum; + uint32_t msr; + rtems_interrupt_level level; + bool is_cpm_irq; + uint32_t simask_save; + /* + * check, if interrupt is pending + * and repeat as long as valid interrupts are pending + */ + while (0 != (m8xx.simask & m8xx.sipend)) { + /* Get vector number */ + sivecnum = (m8xx.sivec >> 26); + is_cpm_irq = (sivecnum == BSP_CPM_INTERRUPT); + /* + * Check the vector number, mask lower priority interrupts, enable + * exceptions and dispatch the handler. + */ + if (BSP_IS_SIU_IRQ(sivecnum)) { + simask_save = m8xx.simask; + /* + * if this is the CPM interrupt, mask lower prio interrupts at SIU + * else mask lower and same priority interrupts + */ + m8xx.simask &= ~0 << (32 + - sivecnum + - ((is_cpm_irq) ? 1 : 0)); + + if (is_cpm_irq) { + BSP_irq_handle_at_cpm(); + } + else { + /* Enable all interrupts */ + msr = ppc_external_exceptions_enable(); + /* Dispatch interrupt handlers */ + bsp_interrupt_handler_dispatch(sivecnum + BSP_SIU_IRQ_LOWEST_OFFSET); + /* Restore machine state */ + ppc_external_exceptions_disable(msr); + /* + * clear pending bit, if edge triggered interrupt input + */ + m8xx.sipend = 1 << (31 - sivecnum); + } + + + /* Restore initial masks */ + m8xx.simask = simask_save; + } else { + /* not valid vector */ + bsp_interrupt_handler_default(sivecnum); + } + } + return 0; +} + +/* + * Activate the CPIC + */ +rtems_status_code mpc8xx_cpic_initialize( void) +{ + /* + * mask off all interrupts + */ + m8xx.cimr = 0; + /* + * make sure CPIC request proper level at SIU interrupt controller + */ + m8xx.cicr = (0x00e41f00 | + ((BSP_CPM_INTERRUPT/2) << 13)); + + return RTEMS_SUCCESSFUL; +} + +/* + * Activate the SIU interrupt controller + */ +rtems_status_code mpc8xx_siu_int_initialize( void) +{ + /* + * mask off all interrupts + */ + m8xx.simask = 0; + + return RTEMS_SUCCESSFUL; +} + +int mpc8xx_exception_handler(BSP_Exception_frame *frame, + unsigned exception_number) +{ + return BSP_irq_handle_at_siu(exception_number); +} + +rtems_status_code bsp_interrupt_facility_initialize() +{ + /* Install exception handler */ + if (ppc_exc_set_handler(ASM_EXT_VECTOR, mpc8xx_exception_handler)) { + return RTEMS_IO_ERROR; + } + /* Initialize the SIU interrupt controller */ + if (mpc8xx_siu_int_initialize()) { + return RTEMS_IO_ERROR; + } + /* Initialize the CPIC interrupt controller */ + return mpc8xx_cpic_initialize(); +} + +void bsp_interrupt_handler_default( rtems_vector_number vector) +{ + printk( "Spurious interrupt: 0x%08x\n", vector); +} diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/irq/irq.h b/c/src/lib/libbsp/powerpc/tqm8xx/irq/irq.h new file mode 100644 index 0000000000..f590317c63 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/irq/irq.h @@ -0,0 +1,204 @@ +/*===============================================================*\ +| Project: RTEMS TQM8xx BSP | ++-----------------------------------------------------------------+ +| This file has been adapted to MPC8xx by | +| Thomas Doerfler | +| Copyright (c) 2008 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | +| | +| See the other copyright notice below for the original parts. | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.com/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains the console driver | +\*===============================================================*/ +/* derived from: generic MPC83xx BSP */ +/* irq.h + * + * This include file describe the data structure and the functions implemented + * by rtems to write interrupt handlers. + * + * 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 LIBBSP_POWERPC_TQM8XX_IRQ_IRQ_H +#define LIBBSP_POWERPC_TQM8XX_IRQ_IRQ_H + +#include + +#ifndef ASM + +#ifdef __cplusplus +extern "C" { +#endif + +extern volatile unsigned int ppc_cached_irq_mask; + +/* + * Symblolic IRQ names and related definitions. + */ + + /* + * SIU IRQ handler related definitions + */ +#define BSP_SIU_IRQ_NUMBER 16 /* 16 reserved but in the future... */ +#define BSP_SIU_IRQ_LOWEST_OFFSET 0 +#define BSP_SIU_IRQ_MAX_OFFSET (BSP_SIU_IRQ_LOWEST_OFFSET + BSP_SIU_IRQ_NUMBER - 1) + /* + * CPM IRQ handlers related definitions + * CAUTION : BSP_CPM_IRQ_LOWEST_OFFSET should be equal to OPENPIC_VEC_SOURCE + */ +#define BSP_CPM_IRQ_NUMBER 32 +#define BSP_CPM_IRQ_LOWEST_OFFSET (BSP_SIU_IRQ_NUMBER + BSP_SIU_IRQ_LOWEST_OFFSET) +#define BSP_CPM_IRQ_MAX_OFFSET (BSP_CPM_IRQ_LOWEST_OFFSET + BSP_CPM_IRQ_NUMBER - 1) + /* + * PowerPc exceptions handled as interrupt where a rtems managed interrupt + * handler might be connected + */ +#define BSP_PROCESSOR_IRQ_NUMBER 1 +#define BSP_PROCESSOR_IRQ_LOWEST_OFFSET (BSP_CPM_IRQ_MAX_OFFSET + 1) +#define BSP_PROCESSOR_IRQ_MAX_OFFSET (BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER - 1) + /* + * Summary + */ +#define BSP_IRQ_NUMBER (BSP_PROCESSOR_IRQ_MAX_OFFSET + 1) +#define BSP_LOWEST_OFFSET (BSP_SIU_IRQ_LOWEST_OFFSET) +#define BSP_MAX_OFFSET (BSP_PROCESSOR_IRQ_MAX_OFFSET) + /* + * Some SIU IRQ symbolic name definition. Please note that + * INT IRQ are defined but a single one will be used to + * redirect all CPM interrupt. + */ +#define BSP_SIU_EXT_IRQ_0 0 +#define BSP_SIU_INT_IRQ_0 1 + +#define BSP_SIU_EXT_IRQ_1 2 +#define BSP_SIU_INT_IRQ_1 3 + +#define BSP_SIU_EXT_IRQ_2 4 +#define BSP_SIU_INT_IRQ_2 5 + +#define BSP_SIU_EXT_IRQ_3 6 +#define BSP_SIU_INT_IRQ_3 7 + +#define BSP_SIU_EXT_IRQ_4 8 +#define BSP_SIU_INT_IRQ_4 9 + +#define BSP_SIU_EXT_IRQ_5 10 +#define BSP_SIU_INT_IRQ_5 11 + +#define BSP_SIU_EXT_IRQ_6 12 +#define BSP_SIU_INT_IRQ_6 13 + +#define BSP_SIU_EXT_IRQ_7 14 +#define BSP_SIU_INT_IRQ_7 15 + /* + * Symbolic name for CPM interrupt on SIU Internal level 2 + */ +#define BSP_CPM_INTERRUPT BSP_SIU_INT_IRQ_2 +#define BSP_PERIODIC_TIMER BSP_SIU_INT_IRQ_6 +#define BSP_FAST_ETHERNET_CTRL BSP_SIU_INT_IRQ_3 + /* + * Some CPM IRQ symbolic name definition + */ +#define BSP_CPM_IRQ_ERROR BSP_CPM_IRQ_LOWEST_OFFSET +#define BSP_CPM_IRQ_PARALLEL_IO_PC4 (BSP_CPM_IRQ_LOWEST_OFFSET + 1) +#define BSP_CPM_IRQ_PARALLEL_IO_PC5 (BSP_CPM_IRQ_LOWEST_OFFSET + 2) +#define BSP_CPM_IRQ_SMC2_OR_PIP (BSP_CPM_IRQ_LOWEST_OFFSET + 3) +#define BSP_CPM_IRQ_SMC1 (BSP_CPM_IRQ_LOWEST_OFFSET + 4) +#define BSP_CPM_IRQ_SPI (BSP_CPM_IRQ_LOWEST_OFFSET + 5) +#define BSP_CPM_IRQ_PARALLEL_IO_PC6 (BSP_CPM_IRQ_LOWEST_OFFSET + 6) +#define BSP_CPM_IRQ_TIMER_4 (BSP_CPM_IRQ_LOWEST_OFFSET + 7) + +#define BSP_CPM_IRQ_PARALLEL_IO_PC7 (BSP_CPM_IRQ_LOWEST_OFFSET + 9) +#define BSP_CPM_IRQ_PARALLEL_IO_PC8 (BSP_CPM_IRQ_LOWEST_OFFSET + 10) +#define BSP_CPM_IRQ_PARALLEL_IO_PC9 (BSP_CPM_IRQ_LOWEST_OFFSET + 11) +#define BSP_CPM_IRQ_TIMER_3 (BSP_CPM_IRQ_LOWEST_OFFSET + 12) + +#define BSP_CPM_IRQ_PARALLEL_IO_PC10 (BSP_CPM_IRQ_LOWEST_OFFSET + 14) +#define BSP_CPM_IRQ_PARALLEL_IO_PC11 (BSP_CPM_IRQ_LOWEST_OFFSET + 15) +#define BSP_CPM_I2C (BSP_CPM_IRQ_LOWEST_OFFSET + 16) +#define BSP_CPM_RISC_TIMER_TABLE (BSP_CPM_IRQ_LOWEST_OFFSET + 17) +#define BSP_CPM_IRQ_TIMER_2 (BSP_CPM_IRQ_LOWEST_OFFSET + 18) + +#define BSP_CPM_IDMA2 (BSP_CPM_IRQ_LOWEST_OFFSET + 20) +#define BSP_CPM_IDMA1 (BSP_CPM_IRQ_LOWEST_OFFSET + 21) +#define BSP_CPM_SDMA_CHANNEL_BUS_ERR (BSP_CPM_IRQ_LOWEST_OFFSET + 22) +#define BSP_CPM_IRQ_PARALLEL_IO_PC12 (BSP_CPM_IRQ_LOWEST_OFFSET + 23) +#define BSP_CPM_IRQ_PARALLEL_IO_PC13 (BSP_CPM_IRQ_LOWEST_OFFSET + 24) +#define BSP_CPM_IRQ_TIMER_1 (BSP_CPM_IRQ_LOWEST_OFFSET + 25) +#define BSP_CPM_IRQ_PARALLEL_IO_PC14 (BSP_CPM_IRQ_LOWEST_OFFSET + 26) +#define BSP_CPM_IRQ_SCC4 (BSP_CPM_IRQ_LOWEST_OFFSET + 27) +#define BSP_CPM_IRQ_SCC3 (BSP_CPM_IRQ_LOWEST_OFFSET + 28) +#define BSP_CPM_IRQ_SCC2 (BSP_CPM_IRQ_LOWEST_OFFSET + 29) +#define BSP_CPM_IRQ_SCC1 (BSP_CPM_IRQ_LOWEST_OFFSET + 30) +#define BSP_CPM_IRQ_PARALLEL_IO_PC15 (BSP_CPM_IRQ_LOWEST_OFFSET + 31) + /* + * Some Processor exception handled as rtems IRQ symbolic name definition + */ +#define BSP_DECREMENTER BSP_PROCESSOR_IRQ_LOWEST_OFFSET + + +#define CPM_INTERRUPT + +/*-------------------------------------------------------------------------+ +| Function Prototypes. ++--------------------------------------------------------------------------*/ +/* + * ------------------------ PPC SIU Mngt Routines ------- + */ + +/* + * function to disable a particular irq at 8259 level. After calling + * this function, even if the device asserts the interrupt line it will + * not be propagated further to the processor + */ +int BSP_irq_disable_at_siu (const rtems_irq_number irqLine); +/* + * function to enable a particular irq at 8259 level. After calling + * this function, if the device asserts the interrupt line it will + * be propagated further to the processor + */ +int BSP_irq_enable_at_siu (const rtems_irq_number irqLine); +/* + * function to acknoledge a particular irq at 8259 level. After calling + * this function, if a device asserts an enabled interrupt line it will + * be propagated further to the processor. Mainly usefull for people + * writting raw handlers as this is automagically done for rtems managed + * handlers. + */ +int BSP_irq_ack_at_siu (const rtems_irq_number irqLine); +/* + * function to check if a particular irq is enabled at 8259 level. After calling + */ +int BSP_irq_enabled_at_siu (const rtems_irq_number irqLine); + +extern void BSP_rtems_irq_mng_init(unsigned cpuId); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/irq/irq_asm.S b/c/src/lib/libbsp/powerpc/tqm8xx/irq/irq_asm.S new file mode 100644 index 0000000000..1a67196b0a --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/irq/irq_asm.S @@ -0,0 +1,433 @@ +/*===============================================================*\ +| Project: RTEMS TQM8xx BSP | ++-----------------------------------------------------------------+ +| This file has been adapted to MPC8xx by | +| Thomas Doerfler | +| Copyright (c) 2008 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | +| | +| See the other copyright notice below for the original parts. | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.com/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains the console driver | +\*===============================================================*/ +/* derived from: generic MPC83xx BSP */ +/* + * 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. + * + * 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. + * Till Straumann , 2005/4: + * - DONT enable FP across user ISR since fpregs are never saved!! + * + * $Id$ + */ + +#include +#include +#include +#include + +#define SYNC \ + sync; \ + isync + + .text + .p2align 5 + + PUBLIC_VAR(decrementer_exception_vector_prolog_code) + +SYM (decrementer_exception_vector_prolog_code): + /* + * let room for exception frame + */ + stwu r1, - (EXCEPTION_FRAME_END)(r1) + stw r4, GPR4_OFFSET(r1) +#ifdef THIS_CODE_LINKED_USING_FLASH_ADDR_RANGE + /* + * save link register + */ + mflr r4 + stw r4, EXC_LR_OFFSET(r1) + /* + * make link register contain shared_raw_irq_code_entry + * address + */ + lis r4,shared_raw_irq_code_entry@h + ori r4,r4,shared_raw_irq_code_entry@l + mtlr r4 + + li r4, ASM_DEC_VECTOR + blr +#else + li r4, ASM_DEC_VECTOR + ba shared_raw_irq_code_entry +#endif + + PUBLIC_VAR (decrementer_exception_vector_prolog_code_size) + + decrementer_exception_vector_prolog_code_size = . - decrementer_exception_vector_prolog_code + + PUBLIC_VAR(external_exception_vector_prolog_code) + +SYM (external_exception_vector_prolog_code): + /* + * let room for exception frame + */ + stwu r1, - (EXCEPTION_FRAME_END)(r1) + stw r4, GPR4_OFFSET(r1) +#ifdef THIS_CODE_LINKED_USING_FLASH_ADDR_RANGE + /* + * save link register + */ + mflr r4 + stw r4, EXC_LR_OFFSET(r1) + /* + * make link register contain shared_raw_irq_code_entry + * address + */ + lis r4,shared_raw_irq_code_entry@h + ori r4,r4,shared_raw_irq_code_entry@l + mtlr r4 + + li r4, ASM_EXT_VECTOR + blr +#else + li r4, ASM_EXT_VECTOR + ba shared_raw_irq_code_entry +#endif + + PUBLIC_VAR (external_exception_vector_prolog_code_size) + + external_exception_vector_prolog_code_size = . - external_exception_vector_prolog_code + + PUBLIC_VAR(shared_raw_irq_code_entry) + PUBLIC_VAR(C_dispatch_irq_handler) + + .p2align 5 +SYM (shared_raw_irq_code_entry): + /* + * Entry conditions : + * Registers already saved : R1, R4 + * R1 : points to a location with enough room for the + * interrupt frame + * R4 : vector number + */ + /* + * Save SRR0/SRR1 As soon As possible as it is the minimal needed + * to reenable exception processing + */ + stw r0, GPR0_OFFSET(r1) + stw r2, GPR2_OFFSET(r1) + stw r3, GPR3_OFFSET(r1) + + mfsrr0 r0 + mfsrr1 r2 + mfmsr r3 + + stw r0, SRR0_FRAME_OFFSET(r1) + stw r2, SRR1_FRAME_OFFSET(r1) + /* + * Enable data and instruction address translation, exception recovery + * + * also, on CPUs with FP, enable FP so that FP context can be + * saved and restored (using FP instructions) + */ + ori r3, r3, MSR_RI | MSR_IR | MSR_DR + 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 +#ifndef THIS_CODE_LINKED_USING_FLASH_ADDR_RANGE + mflr r8 +#endif + + stw r5, EXC_CR_OFFSET(r1) + stw r6, EXC_CTR_OFFSET(r1) + stw r7, EXC_XER_OFFSET(r1) +#ifndef THIS_CODE_LINKED_USING_FLASH_ADDR_RANGE + stw r8, EXC_LR_OFFSET(r1) +#endif + + /* + * 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 +#if BROKEN_ISR_NEST_LEVEL + /* + * Get current nesting level in R2 + */ + mfspr r2, SPRG0 +#else + /* + * Retrieve current nesting level from _ISR_Nest_level + */ + lis r7, _ISR_Nest_level@ha + lwz r2, _ISR_Nest_level@l(r7) +#endif + /* + * Check if stack switch is necessary + */ + cmpwi r2,0 + bne nested + mfspr r1, SPRG1 + +nested: + /* + * Start Incrementing nesting level in R2 + */ + addi r2,r2,1 + /* + * Start Incrementing _Thread_Dispatch_disable_level R4 = _Thread_Dispatch_disable_level + */ + lwz r6,_Thread_Dispatch_disable_level@l(r15) +#if BROKEN_ISR_NEST_LEVEL + /* + * Store new nesting level in SPRG0 + */ + mtspr SPRG0, r2 +#else + /* store new nesting level in _ISR_Nest_level */ + stw r2, _ISR_Nest_level@l(r7) +#endif + + addi r6, r6, 1 + mfmsr r5 + /* + * 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 Interrupt frame is passed just + * in case... + */ + addi r3, r14, 0x8 + bl C_dispatch_irq_handler /* C_dispatch_irq_handler(cpu_interrupt_frame* r3, vector r4) */ + /* + * 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 + */ +#if BROKEN_ISR_NEST_LEVEL + mfspr r2, SPRG0 +#else + lis r7, _ISR_Nest_level@ha + lwz r2, _ISR_Nest_level@l(r7) +#endif + /* + * start decrementing _Thread_Dispatch_disable_level + */ + lwz r3,_Thread_Dispatch_disable_level@l(r15) + addi r2, r2, -1 /* Continue decrementing nesting level */ + addi r3, r3, -1 /* Continue decrementing _Thread_Dispatch_disable_level */ +#if BROKEN_ISR_NEST_LEVEL + mtspr SPRG0, r2 /* End decrementing nesting level */ +#else + stw r2, _ISR_Nest_level@l(r7) /* End decrementing nesting level */ +#endif + 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 r2, r1, EXCEPTION_FRAME_END + /* + * store it at the right place + */ + stw r2, 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) + + /* + * Disable data and instruction translation. Make path non recoverable... + */ + mfmsr r3 + xori r3, r3, MSR_RI | MSR_IR | MSR_DR + mtmsr r3 + 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: +#if ( PPC_HAS_FPU != 0 ) +#if ! defined( CPU_USE_DEFERRED_FP_SWITCH ) +#error missing include file??? +#endif + mfmsr r4 +#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE ) + /* if the executing thread has FP enabled propagate + * this now so _Thread_Dispatch can save/restore the FPREGS + * NOTE: it is *crucial* to disable the FPU across the + * user ISR [independent of using the 'deferred' + * strategy or not]. We don't save FP regs across + * the user ISR and hence we prefer an exception to + * be raised rather than experiencing corruption. + */ + lwz r3, SRR1_FRAME_OFFSET(r1) + rlwimi r4, r3, 0, 18, 18 /* MSR_FP */ +#else + ori r4, r4, MSR_FP +#endif + mtmsr r4 +#endif + 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, data and instruction + * translation. + */ + mfmsr r3 + xori r3, r3, MSR_RI | MSR_IR | MSR_DR + mtmsr r3 + SYNC + /* + * Restore rfi related settings + */ + + lwz r4, SRR1_FRAME_OFFSET(r1) + lwz r2, SRR0_FRAME_OFFSET(r1) + lwz r3, GPR3_OFFSET(r1) + lwz r0, GPR0_OFFSET(r1) + + mtsrr1 r4 + mtsrr0 r2 + lwz r4, GPR4_OFFSET(r1) + lwz r2, GPR2_OFFSET(r1) + addi r1,r1, EXCEPTION_FRAME_END + SYNC + rfi diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/irq/irq_init.c b/c/src/lib/libbsp/powerpc/tqm8xx/irq/irq_init.c new file mode 100644 index 0000000000..6ed06ccfeb --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/irq/irq_init.c @@ -0,0 +1,185 @@ +/*===============================================================*\ +| Project: RTEMS TQM8xx BSP | ++-----------------------------------------------------------------+ +| This file has been adapted to MPC8xx by | +| Thomas Doerfler | +| Copyright (c) 2008 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | +| | +| See the other copyright notice below for the original parts. | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.com/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains the console driver | +\*===============================================================*/ +/* derived from: generic MPC83xx BSP */ +/* irq_init.c + * + * This file contains the implementation of rtems initialization + * related to interrupt handling. + * + * 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 unsigned int external_exception_vector_prolog_code_size; +extern void external_exception_vector_prolog_code(); +extern unsigned int decrementer_exception_vector_prolog_code_size; +extern void decrementer_exception_vector_prolog_code(); + +volatile unsigned int ppc_cached_irq_mask; + +/* + * default on/off function + */ +static void nop_func1(void *unused){} +static void nop_func2(){} + +/* + * default isOn function + */ +static int not_connected() {return 0;} +/* + * default possible isOn function + */ +static int connected() {return 1;} + +static rtems_irq_connect_data rtemsIrq[BSP_IRQ_NUMBER]; +static rtems_irq_global_settings initial_config; +static rtems_irq_connect_data defaultIrq = { + /* vectorIdex, hdl , handle , on , off , isOn */ + 0, nop_func1 , 0 , nop_func2 , nop_func2 , not_connected +}; +static rtems_irq_prio irqPrioTable[BSP_IRQ_NUMBER]={ + /* + * actual rpiorities for interrupt : + * 0 means that only current interrupt is masked + * 255 means all other interrupts are masked + */ + /* + * SIU interrupts. + */ + 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1, 0,0, + /* + * CPM Interrupts + */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + /* + * Processor exceptions handled as interrupts + */ + 0 +}; + +void BSP_SIU_irq_init() +{ + /* + * In theory we should initialize two registers at least : + * SIMASK, SIEL. SIMASK is reset at 0 value meaning no interrupt. But + * we should take care that a monitor may have restoreed to another value. + * If someone find a reasonnable value for SIEL, AND THE NEED TO CHANGE IT + * please feel free to add it here. + */ + ((volatile immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = 0; + ((volatile immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 0xffff0000; + ppc_cached_irq_mask = 0; + ((volatile immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel = ((volatile immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel; +} + +/* + * Initialize CPM interrupt management + */ +void +BSP_CPM_irq_init(void) +{ + /* + * Initialize the CPM interrupt controller. + */ + ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr = +#ifdef mpc860 + (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) | +#else + (CICR_SCB_SCC2 | CICR_SCA_SCC1) | +#endif + ((BSP_CPM_INTERRUPT/2) << 13) | CICR_HP_MASK; + ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr = 0; + + ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr |= CICR_IEN; +} + +void BSP_rtems_irq_mng_init(unsigned cpuId) +{ + rtems_raw_except_connect_data vectorDesc; + int i; + + BSP_SIU_irq_init(); + BSP_CPM_irq_init(); + /* + * Initialize Rtems management interrupt table + */ + /* + * re-init the rtemsIrq table + */ + for (i = 0; i < BSP_IRQ_NUMBER; i++) { + rtemsIrq[i] = defaultIrq; + rtemsIrq[i].name = i; + } + /* + * Init initial Interrupt management config + */ + initial_config.irqNb = BSP_IRQ_NUMBER; + initial_config.defaultEntry = defaultIrq; + initial_config.irqHdlTbl = rtemsIrq; + initial_config.irqBase = BSP_LOWEST_OFFSET; + initial_config.irqPrioTbl = irqPrioTable; + + if (!BSP_rtems_irq_mngt_set(&initial_config)) { + /* + * put something here that will show the failure... + */ + BSP_panic("Unable to initialize RTEMS interrupt Management!!! System locked\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 = decrementer_exception_vector_prolog_code; + vectorDesc.hdl.raw_hdl_size = (unsigned) &decrementer_exception_vector_prolog_code_size; + vectorDesc.on = nop_func2; + vectorDesc.off = nop_func2; + vectorDesc.isOn = connected; + if (!ppc_set_exception (&vectorDesc)) { + BSP_panic("Unable to initialize RTEMS decrementer raw exception\n"); + } + vectorDesc.exceptIndex = ASM_EXT_VECTOR; + vectorDesc.hdl.vector = ASM_EXT_VECTOR; + vectorDesc.hdl.raw_hdl = external_exception_vector_prolog_code; + vectorDesc.hdl.raw_hdl_size = (unsigned) &external_exception_vector_prolog_code_size; + if (!ppc_set_exception (&vectorDesc)) { + BSP_panic("Unable to initialize RTEMS external raw exception\n"); + } +#ifdef TRACE_IRQ_INIT + printk("RTEMS IRQ management is now operationnal\n"); +#endif +} diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/network/network_fec.c b/c/src/lib/libbsp/powerpc/tqm8xx/network/network_fec.c new file mode 100644 index 0000000000..fd2346ed24 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/network/network_fec.c @@ -0,0 +1,926 @@ +/*===============================================================*\ +| Project: RTEMS TQM8xx BSP | ++-----------------------------------------------------------------+ +| This file has been adapted to MPC8xx by | +| Thomas Doerfler | +| Copyright (c) 2008 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | +| | +| See the other copyright notice below for the original parts. | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.com/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains the console driver | +\*===============================================================*/ +/* derived from: */ +/* + * RTEMS/TCPIP driver for MPC8xx Ethernet + * + * split into separate driver files for SCC and FEC by + * Thomas Doerfler + * + * Modified for MPC860 by Jay Monkman (jmonkman@frasca.com) + * + * This supports Ethernet on either SCC1 or the FEC of the MPC860T. + * Right now, we only do 10 Mbps, even with the FEC. The function + * rtems_enet_driver_attach determines which one to use. Currently, + * only one may be used at a time. + * + * Based on the MC68360 network driver by + * W. Eric Norum + * Saskatchewan Accelerator Laboratory + * University of Saskatchewan + * Saskatoon, Saskatchewan, CANADA + * eric@skatter.usask.ca + * + * This supports ethernet on SCC1. Right now, we only do 10 Mbps. + * + * Modifications by Darlene Stewart + * and Charles-Antoine Gauthier + * Copyright (c) 1999, National Research Council of Canada + * + * $Id$ + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include + +/* + * Number of interfaces supported by this driver + */ +#define NIFACES 1 + +/* + * Default number of buffer descriptors set aside for this driver. + * The number of transmit buffer descriptors has to be quite large + * since a single frame often uses four or more buffer descriptors. + */ +#define RX_BUF_COUNT 32 +#define TX_BUF_COUNT 8 +#define TX_BD_PER_BUF 4 + +#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255") + +/* + * RTEMS event used by interrupt handler to signal daemons. + * This must *not* be the same event used by the TCP/IP task synchronization. + */ +#define INTERRUPT_EVENT RTEMS_EVENT_1 + +/* + * RTEMS event used to start transmit daemon. + * This must not be the same as INTERRUPT_EVENT. + */ +#define START_TRANSMIT_EVENT RTEMS_EVENT_2 + +/* + * Receive buffer size -- Allow for a full ethernet packet plus CRC (1518). + * Round off to nearest multiple of RBUF_ALIGN. + */ +#define MAX_MTU_SIZE 1518 +#define RBUF_ALIGN 4 +#define RBUF_SIZE ((MAX_MTU_SIZE + RBUF_ALIGN) & ~RBUF_ALIGN) + +#if (MCLBYTES < RBUF_SIZE) +# error "Driver must have MCLBYTES > RBUF_SIZE" +#endif + +/* + * Per-device data + */ +struct m8xx_fec_enet_struct { + struct arpcom arpcom; + struct mbuf **rxMbuf; + struct mbuf **txMbuf; + int acceptBroadcast; + int rxBdCount; + int txBdCount; + int txBdHead; + int txBdTail; + int txBdActiveCount; + m8xxBufferDescriptor_t *rxBdBase; + m8xxBufferDescriptor_t *txBdBase; + rtems_id rxDaemonTid; + rtems_id txDaemonTid; + + /* + * Statistics + */ + unsigned long rxInterrupts; + unsigned long rxNotFirst; + unsigned long rxNotLast; + unsigned long rxGiant; + unsigned long rxNonOctet; + unsigned long rxRunt; + unsigned long rxBadCRC; + unsigned long rxOverrun; + unsigned long rxCollision; + + unsigned long txInterrupts; + unsigned long txDeferred; + unsigned long txHeartbeat; + unsigned long txLateCollision; + unsigned long txRetryLimit; + unsigned long txUnderrun; + unsigned long txLostCarrier; + unsigned long txRawWait; +}; +static struct m8xx_fec_enet_struct enet_driver[NIFACES]; + +/* + * FEC interrupt handler + */ +static void m8xx_fec_interrupt_handler () +{ + /* + * Frame received? + */ + if (m8xx.fec.ievent & M8xx_FEC_IEVENT_RFINT) { + m8xx.fec.ievent = M8xx_FEC_IEVENT_RFINT; + enet_driver[0].rxInterrupts++; + rtems_event_send (enet_driver[0].rxDaemonTid, INTERRUPT_EVENT); + } + + /* + * Buffer transmitted or transmitter error? + */ + if (m8xx.fec.ievent & M8xx_FEC_IEVENT_TFINT) { + m8xx.fec.ievent = M8xx_FEC_IEVENT_TFINT; + enet_driver[0].txInterrupts++; + rtems_event_send (enet_driver[0].txDaemonTid, INTERRUPT_EVENT); + } +} + +/* + * Please organize FEC controller code better by moving code from + * m860_fec_initialize_hardware to m8xx_fec_ethernet_on + */ +static void m8xx_fec_ethernet_on(){}; +static void m8xx_fec_ethernet_off(){}; +static int m8xx_fec_ethernet_isOn (const rtems_irq_connect_data* ptr) +{ + return BSP_irq_enabled_at_siu (ptr->name); +} + +static rtems_irq_connect_data ethernetFECIrqData = { + BSP_FAST_ETHERNET_CTRL, + (rtems_irq_hdl) m8xx_fec_interrupt_handler, + (rtems_irq_enable) m8xx_fec_ethernet_on, + (rtems_irq_disable) m8xx_fec_ethernet_off, + (rtems_irq_is_enabled)m8xx_fec_ethernet_isOn +}; + +static void +m8xx_fec_initialize_hardware (struct m8xx_fec_enet_struct *sc) +{ + int i; + unsigned char *hwaddr; + + /* + * Issue reset to FEC + */ + m8xx.fec.ecntrl=0x1; + + /* + * Put ethernet transciever in reset + */ + m8xx.pgcra |= 0x80; + + /* + * Configure I/O ports + */ + m8xx.pdpar = 0x1fff; + m8xx.pddir = 0x1c58; + + /* + * Take ethernet transciever out of reset + */ + m8xx.pgcra &= ~0x80; + + /* + * Set SIU interrupt level to LVL2 + * + */ + m8xx.fec.ivec = ((((unsigned) BSP_FAST_ETHERNET_CTRL)/2) << 29); + + /* + * Set the TX and RX fifo sizes. For now, we'll split it evenly + */ + /* If you uncomment these, the FEC will not work right. + m8xx.fec.r_fstart = ((m8xx.fec.r_bound & 0x3ff) >> 2) & 0x3ff; + m8xx.fec.x_fstart = 0; + */ + + /* + * Set our physical address + */ + hwaddr = sc->arpcom.ac_enaddr; + + m8xx.fec.addr_low = (hwaddr[0] << 24) | (hwaddr[1] << 16) | + (hwaddr[2] << 8) | (hwaddr[3] << 0); + m8xx.fec.addr_high = (hwaddr[4] << 24) | (hwaddr[5] << 16); + + /* + * Clear the hash table + */ + m8xx.fec.hash_table_high = 0; + m8xx.fec.hash_table_low = 0; + + /* + * Set up receive buffer size + */ + m8xx.fec.r_buf_size = 0x5f0; /* set to 1520 */ + + /* + * Allocate mbuf pointers + */ + sc->rxMbuf = malloc (sc->rxBdCount * sizeof *sc->rxMbuf, + M_MBUF, M_NOWAIT); + sc->txMbuf = malloc (sc->txBdCount * sizeof *sc->txMbuf, + M_MBUF, M_NOWAIT); + if (!sc->rxMbuf || !sc->txMbuf) + rtems_panic ("No memory for mbuf pointers"); + + /* + * Set receiver and transmitter buffer descriptor bases + */ + sc->rxBdBase = m8xx_bd_allocate(sc->rxBdCount); + sc->txBdBase = m8xx_bd_allocate(sc->txBdCount); + m8xx.fec.r_des_start = (int)sc->rxBdBase; + m8xx.fec.x_des_start = (int)sc->txBdBase; + + /* + * Set up Receive Control Register: + * Not promiscuous mode + * MII mode + * Half duplex + * No loopback + */ + m8xx.fec.r_cntrl = 0x00000006; + + /* + * Set up Transmit Control Register: + * Half duplex + * No heartbeat + */ + m8xx.fec.x_cntrl = 0x00000000; + + /* + * Set up DMA function code: + * Big-endian + * DMA functino code = 0 + */ + m8xx.fec.fun_code = 0x78000000; + + /* + * Initialize SDMA configuration register + * SDMA ignores FRZ + * FEC not aggressive + * FEC arbitration ID = 0 => U-bus arbitration = 6 + * RISC arbitration ID = 1 => U-bus arbitration = 5 + */ + m8xx.sdcr = 1; + + /* + * Set MII speed to 2.5 MHz for 25 Mhz system clock + */ + m8xx.fec.mii_speed = 0x0a; + m8xx.fec.mii_data = 0x58021000; + + /* + * Set up receive buffer descriptors + */ + for (i = 0 ; i < sc->rxBdCount ; i++) + (sc->rxBdBase + i)->status = 0; + + /* + * Set up transmit buffer descriptors + */ + for (i = 0 ; i < sc->txBdCount ; i++) { + (sc->txBdBase + i)->status = 0; + sc->txMbuf[i] = NULL; + } + sc->txBdHead = sc->txBdTail = 0; + sc->txBdActiveCount = 0; + + /* + * Mask all FEC interrupts and clear events + */ + m8xx.fec.imask = M8xx_FEC_IEVENT_TFINT | + M8xx_FEC_IEVENT_RFINT; + m8xx.fec.ievent = ~0; + + /* + * Set up interrupts + */ + if (!BSP_install_rtems_irq_handler (ðernetFECIrqData)) + rtems_panic ("Can't attach M860 FEC interrupt handler\n"); + +} +static void fec_rxDaemon (void *arg) +{ + struct m8xx_fec_enet_struct *sc = (struct m8xx_fec_enet_struct *)arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct mbuf *m; + uint16_t status; + m8xxBufferDescriptor_t *rxBd; + int rxBdIndex; + + /* + * Allocate space for incoming packets and start reception + */ + for (rxBdIndex = 0 ; ;) { + rxBd = sc->rxBdBase + rxBdIndex; + MGETHDR (m, M_WAIT, MT_DATA); + MCLGET (m, M_WAIT); + m->m_pkthdr.rcvif = ifp; + sc->rxMbuf[rxBdIndex] = m; + rxBd->buffer = mtod (m, void *); + rxBd->status = M8xx_BD_EMPTY; + m8xx.fec.r_des_active = 0x1000000; + if (++rxBdIndex == sc->rxBdCount) { + rxBd->status |= M8xx_BD_WRAP; + break; + } + } + + /* + * Input packet handling loop + */ + rxBdIndex = 0; + for (;;) { + rxBd = sc->rxBdBase + rxBdIndex; + + /* + * Wait for packet if there's not one ready + */ + if ((status = rxBd->status) & M8xx_BD_EMPTY) { + /* + * Clear old events + */ + m8xx.fec.ievent = M8xx_FEC_IEVENT_RFINT; + + /* + * Wait for packet + * Note that the buffer descriptor is checked + * *before* the event wait -- this catches the + * possibility that a packet arrived between the + * `if' above, and the clearing of the event register. + */ + while ((status = rxBd->status) & M8xx_BD_EMPTY) { + rtems_event_set events; + + /* + * Unmask RXF (Full frame received) event + */ + m8xx.fec.ievent |= M8xx_FEC_IEVENT_RFINT; + + rtems_bsdnet_event_receive (INTERRUPT_EVENT, + RTEMS_WAIT|RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events); + } + } + + /* + * Check that packet is valid + */ + if (status & M8xx_BD_LAST) { + /* + * Pass the packet up the chain. + * FIXME: Packet filtering hook could be done here. + */ + struct ether_header *eh; + + /* + * Invalidate the buffer for this descriptor + */ + rtems_cache_invalidate_multiple_data_lines((const void *)rxBd->buffer, rxBd->length); + + m = sc->rxMbuf[rxBdIndex]; + m->m_len = m->m_pkthdr.len = rxBd->length - + sizeof(uint32_t) - + sizeof(struct ether_header); + eh = mtod (m, struct ether_header *); + m->m_data += sizeof(struct ether_header); + ether_input (ifp, eh, m); + + /* + * Allocate a new mbuf + */ + MGETHDR (m, M_WAIT, MT_DATA); + MCLGET (m, M_WAIT); + m->m_pkthdr.rcvif = ifp; + sc->rxMbuf[rxBdIndex] = m; + rxBd->buffer = mtod (m, void *); + } + else { + /* + * Something went wrong with the reception + */ + if (!(status & M8xx_BD_LAST)) + sc->rxNotLast++; + if (status & M8xx_BD_LONG) + sc->rxGiant++; + if (status & M8xx_BD_NONALIGNED) + sc->rxNonOctet++; + if (status & M8xx_BD_SHORT) + sc->rxRunt++; + if (status & M8xx_BD_CRC_ERROR) + sc->rxBadCRC++; + if (status & M8xx_BD_OVERRUN) + sc->rxOverrun++; + if (status & M8xx_BD_COLLISION) + sc->rxCollision++; + } + /* + * Reenable the buffer descriptor + */ + rxBd->status = (status & M8xx_BD_WRAP) | + M8xx_BD_EMPTY; + m8xx.fec.r_des_active = 0x1000000; + /* + * Move to next buffer descriptor + */ + if (++rxBdIndex == sc->rxBdCount) + rxBdIndex = 0; + } +} + +/* + * Soak up buffer descriptors that have been sent. + * Note that a buffer descriptor can't be retired as soon as it becomes + * ready. The MPC860 manual (MPC860UM/AD 07/98 Rev.1) and the MPC821 + * manual state that, "If an Ethernet frame is made up of multiple + * buffers, the user should not reuse the first buffer descriptor until + * the last buffer descriptor of the frame has had its ready bit cleared + * by the CPM". + */ +static void +m8xx_fec_Enet_retire_tx_bd (struct m8xx_fec_enet_struct *sc) +{ + uint16_t status; + int i; + int nRetired; + struct mbuf *m, *n; + + i = sc->txBdTail; + nRetired = 0; + while ((sc->txBdActiveCount != 0) + && (((status = (sc->txBdBase + i)->status) & M8xx_BD_READY) == 0)) { + /* + * See if anything went wrong + */ + if (status & (M8xx_BD_DEFER | + M8xx_BD_HEARTBEAT | + M8xx_BD_LATE_COLLISION | + M8xx_BD_RETRY_LIMIT | + M8xx_BD_UNDERRUN | + M8xx_BD_CARRIER_LOST)) { + /* + * Check for errors which stop the transmitter. + */ + if (status & (M8xx_BD_LATE_COLLISION | + M8xx_BD_RETRY_LIMIT | + M8xx_BD_UNDERRUN)) { + if (status & M8xx_BD_LATE_COLLISION) + enet_driver[0].txLateCollision++; + if (status & M8xx_BD_RETRY_LIMIT) + enet_driver[0].txRetryLimit++; + if (status & M8xx_BD_UNDERRUN) + enet_driver[0].txUnderrun++; + + /* + * Restart the transmitter + */ + /* FIXME: this should get executed only if using the SCC */ + m8xx_cp_execute_cmd (M8xx_CR_OP_RESTART_TX | M8xx_CR_CHAN_SCC1); + } + if (status & M8xx_BD_DEFER) + enet_driver[0].txDeferred++; + if (status & M8xx_BD_HEARTBEAT) + enet_driver[0].txHeartbeat++; + if (status & M8xx_BD_CARRIER_LOST) + enet_driver[0].txLostCarrier++; + } + nRetired++; + if (status & M8xx_BD_LAST) { + /* + * A full frame has been transmitted. + * Free all the associated buffer descriptors. + */ + sc->txBdActiveCount -= nRetired; + while (nRetired) { + nRetired--; + m = sc->txMbuf[sc->txBdTail]; + MFREE (m, n); + if (++sc->txBdTail == sc->txBdCount) + sc->txBdTail = 0; + } + } + if (++i == sc->txBdCount) + i = 0; + } +} + +static void fec_sendpacket (struct ifnet *ifp, struct mbuf *m) +{ + struct m8xx_fec_enet_struct *sc = ifp->if_softc; + volatile m8xxBufferDescriptor_t *firstTxBd, *txBd; + /* struct mbuf *l = NULL; */ + uint16_t status; + int nAdded; + + /* + * Free up buffer descriptors + */ + m8xx_fec_Enet_retire_tx_bd (sc); + + /* + * Set up the transmit buffer descriptors. + * No need to pad out short packets since the + * hardware takes care of that automatically. + * No need to copy the packet to a contiguous buffer + * since the hardware is capable of scatter/gather DMA. + */ + nAdded = 0; + txBd = firstTxBd = sc->txBdBase + sc->txBdHead; + for (;;) { + /* + * Wait for buffer descriptor to become available. + */ + if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) { + /* + * Clear old events + */ + m8xx.fec.ievent = M8xx_FEC_IEVENT_TFINT; + + /* + * Wait for buffer descriptor to become available. + * Note that the buffer descriptors are checked + * *before* * entering the wait loop -- this catches + * the possibility that a buffer descriptor became + * available between the `if' above, and the clearing + * of the event register. + * This is to catch the case where the transmitter + * stops in the middle of a frame -- and only the + * last buffer descriptor in a frame can generate + * an interrupt. + */ + m8xx_fec_Enet_retire_tx_bd (sc); + while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) { + rtems_event_set events; + + /* + * Unmask TXB (buffer transmitted) and + * TXE (transmitter error) events. + */ + m8xx.fec.ievent |= M8xx_FEC_IEVENT_TFINT; + rtems_bsdnet_event_receive (INTERRUPT_EVENT, + RTEMS_WAIT|RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events); + m8xx_fec_Enet_retire_tx_bd (sc); + } + } + + /* + * Don't set the READY flag till the + * whole packet has been readied. + */ + status = nAdded ? M8xx_BD_READY : 0; + + /* + * FIXME: Why not deal with empty mbufs at at higher level? + * The IP fragmentation routine in ip_output + * can produce packet fragments with zero length. + * I think that ip_output should be changed to get + * rid of these zero-length mbufs, but for now, + * I'll deal with them here. + */ + if (m->m_len) { + /* + * Fill in the buffer descriptor + */ + txBd->buffer = mtod (m, void *); + txBd->length = m->m_len; + + /* + * Flush the buffer for this descriptor + */ + rtems_cache_flush_multiple_data_lines(txBd->buffer, txBd->length); + + sc->txMbuf[sc->txBdHead] = m; + nAdded++; + if (++sc->txBdHead == sc->txBdCount) { + status |= M8xx_BD_WRAP; + sc->txBdHead = 0; + } + /* l = m;*/ + m = m->m_next; + } + else { + /* + * Just toss empty mbufs + */ + struct mbuf *n; + MFREE (m, n); + m = n; + /* + if (l != NULL) + l->m_next = m; + */ + } + + /* + * Set the transmit buffer status. + * Break out of the loop if this mbuf is the last in the frame. + */ + if (m == NULL) { + if (nAdded) { + status |= M8xx_BD_LAST | M8xx_BD_TX_CRC; + txBd->status = status; + firstTxBd->status |= M8xx_BD_READY; + m8xx.fec.x_des_active = 0x1000000; + sc->txBdActiveCount += nAdded; + } + break; + } + txBd->status = status; + txBd = sc->txBdBase + sc->txBdHead; + } +} +void fec_txDaemon (void *arg) +{ + struct m8xx_fec_enet_struct *sc = (struct m8xx_fec_enet_struct *)arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct mbuf *m; + rtems_event_set events; + + for (;;) { + /* + * Wait for packet + */ + rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events); + + /* + * Send packets till queue is empty + */ + for (;;) { + /* + * Get the next mbuf chain to transmit. + */ + IF_DEQUEUE(&ifp->if_snd, m); + if (!m) + break; + fec_sendpacket (ifp, m); + } + ifp->if_flags &= ~IFF_OACTIVE; + } +} +static void fec_init (void *arg) +{ + struct m8xx_fec_enet_struct *sc = arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + + if (sc->txDaemonTid == 0) { + + /* + * Set up SCC hardware + */ + m8xx_fec_initialize_hardware (sc); + + /* + * Start driver tasks + */ + sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, fec_txDaemon, sc); + sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, fec_rxDaemon, sc); + + } + + /* + * Set flags appropriately + */ + if (ifp->if_flags & IFF_PROMISC) + m8xx.fec.r_cntrl |= 0x8; + else + m8xx.fec.r_cntrl &= ~0x8; + + /* + * Tell the world that we're running. + */ + ifp->if_flags |= IFF_RUNNING; + + /* + * Enable receiver and transmitter + */ + m8xx.fec.ecntrl = 0x2; +} + +/* + * Send packet (caller provides header). + */ +static void +m8xx_fec_enet_start (struct ifnet *ifp) +{ + struct m8xx_fec_enet_struct *sc = ifp->if_softc; + + rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); + ifp->if_flags |= IFF_OACTIVE; +} + +static void fec_stop (struct m8xx_fec_enet_struct *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + + ifp->if_flags &= ~IFF_RUNNING; + + /* + * Shut down receiver and transmitter + */ + m8xx.fec.ecntrl = 0x0; +} + +/* + * Show interface statistics + */ +static void fec_enet_stats (struct m8xx_fec_enet_struct *sc) +{ + printf (" Rx Interrupts:%-8lu", sc->rxInterrupts); + printf (" Not First:%-8lu", sc->rxNotFirst); + printf (" Not Last:%-8lu\n", sc->rxNotLast); + printf (" Giant:%-8lu", sc->rxGiant); + printf (" Runt:%-8lu", sc->rxRunt); + printf (" Non-octet:%-8lu\n", sc->rxNonOctet); + printf (" Bad CRC:%-8lu", sc->rxBadCRC); + printf (" Overrun:%-8lu", sc->rxOverrun); + printf (" Collision:%-8lu\n", sc->rxCollision); + printf (" Discarded:%-8lu\n", (unsigned long)m8xx.scc1p.un.ethernet.disfc); + + printf (" Tx Interrupts:%-8lu", sc->txInterrupts); + printf (" Deferred:%-8lu", sc->txDeferred); + printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat); + printf (" No Carrier:%-8lu", sc->txLostCarrier); + printf ("Retransmit Limit:%-8lu", sc->txRetryLimit); + printf (" Late Collision:%-8lu\n", sc->txLateCollision); + printf (" Underrun:%-8lu", sc->txUnderrun); + printf (" Raw output wait:%-8lu\n", sc->txRawWait); +} + +static int fec_ioctl (struct ifnet *ifp, int command, caddr_t data) +{ + struct m8xx_fec_enet_struct *sc = ifp->if_softc; + int error = 0; + + switch (command) { + case SIOCGIFADDR: + case SIOCSIFADDR: + ether_ioctl (ifp, command, data); + break; + + case SIOCSIFFLAGS: + switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { + case IFF_RUNNING: + fec_stop (sc); + break; + + case IFF_UP: + fec_init (sc); + break; + + case IFF_UP | IFF_RUNNING: + fec_stop (sc); + fec_init (sc); + break; + + default: + break; + } + break; + + case SIO_RTEMS_SHOW_STATS: + fec_enet_stats (sc); + break; + + /* + * FIXME: All sorts of multicast commands need to be added here! + */ + default: + error = EINVAL; + break; + } + return error; +} +int rtems_fec_driver_attach (struct rtems_bsdnet_ifconfig *config) +{ + struct m8xx_fec_enet_struct *sc; + struct ifnet *ifp; + int mtu; + int unitNumber; + char *unitName; + static const uint8_t maczero[] ={0,0,0,0,0,0}; + + /* + * Parse driver name + */ + if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0) + return 0; + + /* + * Is driver free? + */ + if ((unitNumber <= 0) || (unitNumber > NIFACES)) { + printf ("Bad SCC unit number.\n"); + return 0; + } + sc = &enet_driver[unitNumber - 1]; + ifp = &sc->arpcom.ac_if; + if (ifp->if_softc != NULL) { + printf ("Driver already in use.\n"); + return 0; + } + + /* + * Process options + */ + if (config->hardware_address) { + memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN); + } +#ifdef BSP_HAS_TQMMON + else if(0 != memcmp(maczero,TQM_BD_INFO.eth_addr,ETHER_ADDR_LEN)) { + memcpy (sc->arpcom.ac_enaddr, TQM_BD_INFO.eth_addr, ETHER_ADDR_LEN); + } +#endif + else { + /* FIXME to read the enaddr from NVRAM */ + } + if (config->mtu) + mtu = config->mtu; + else + mtu = ETHERMTU; + if (config->rbuf_count) + sc->rxBdCount = config->rbuf_count; + else + sc->rxBdCount = RX_BUF_COUNT; + if (config->xbuf_count) + sc->txBdCount = config->xbuf_count; + else + sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF; + sc->acceptBroadcast = !config->ignore_broadcast; + + /* + * Set up network interface values + */ + ifp->if_softc = sc; + ifp->if_unit = unitNumber; + ifp->if_name = unitName; + ifp->if_mtu = mtu; + ifp->if_init = fec_init; + ifp->if_ioctl = fec_ioctl; + ifp->if_start = m8xx_fec_enet_start; + ifp->if_output = ether_output; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; + if (ifp->if_snd.ifq_maxlen == 0) + ifp->if_snd.ifq_maxlen = ifqmaxlen; + + /* + * Attach the interface + */ + if_attach (ifp); + ether_ifattach (ifp); + return 1; +}; + +int rtems_fec_enet_driver_attach(struct rtems_bsdnet_ifconfig *config, + int attaching) +{ + return rtems_fec_driver_attach(config); +} diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/network/network_scc.c b/c/src/lib/libbsp/powerpc/tqm8xx/network/network_scc.c new file mode 100644 index 0000000000..317ef27a6f --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/network/network_scc.c @@ -0,0 +1,1047 @@ +/*===============================================================*\ +| Project: RTEMS TQM8xx BSP | ++-----------------------------------------------------------------+ +| This file has been adapted to MPC8xx by | +| Thomas Doerfler | +| Copyright (c) 2008 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | +| | +| See the other copyright notice below for the original parts. | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.com/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains the console driver | +\*===============================================================*/ +/* derived from: */ +/* + * RTEMS/TCPIP driver for MPC8xx SCC1 Ethernet + * + * Modified for MPC860 by Jay Monkman (jmonkman@frasca.com) + * + * This supports Ethernet on either SCC1 or the FEC of the MPC860T. + * Right now, we only do 10 Mbps, even with the FEC. The function + * rtems_enet_driver_attach determines which one to use. Currently, + * only one may be used at a time. + * + * Based on the MC68360 network driver by + * W. Eric Norum + * Saskatchewan Accelerator Laboratory + * University of Saskatchewan + * Saskatoon, Saskatchewan, CANADA + * eric@skatter.usask.ca + * + * This supports ethernet on SCC1. Right now, we only do 10 Mbps. + * + * Modifications by Darlene Stewart + * and Charles-Antoine Gauthier + * Copyright (c) 1999, National Research Council of Canada + * + * $Id$ + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include + +/* + * Number of interfaces supported by this driver + */ +#define NIFACES 1 + +/* + * Default number of buffer descriptors set aside for this driver. + * The number of transmit buffer descriptors has to be quite large + * since a single frame often uses four or more buffer descriptors. + */ +#define RX_BUF_COUNT 32 +#define TX_BUF_COUNT 8 +#define TX_BD_PER_BUF 4 + +#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255") + +/* + * RTEMS event used by interrupt handler to signal daemons. + * This must *not* be the same event used by the TCP/IP task synchronization. + */ +#define INTERRUPT_EVENT RTEMS_EVENT_1 + +/* + * RTEMS event used to start transmit daemon. + * This must not be the same as INTERRUPT_EVENT. + */ +#define START_TRANSMIT_EVENT RTEMS_EVENT_2 + +/* + * Receive buffer size -- Allow for a full ethernet packet plus CRC (1518). + * Round off to nearest multiple of RBUF_ALIGN. + */ +#define MAX_MTU_SIZE 1518 +#define RBUF_ALIGN 4 +#define RBUF_SIZE ((MAX_MTU_SIZE + RBUF_ALIGN) & ~RBUF_ALIGN) + +#if (MCLBYTES < RBUF_SIZE) +# error "Driver must have MCLBYTES > RBUF_SIZE" +#endif + +/* + * Per-device data + */ +struct m8xx_enet_struct { + struct arpcom arpcom; + struct mbuf **rxMbuf; + struct mbuf **txMbuf; + int acceptBroadcast; + int rxBdCount; + int txBdCount; + int txBdHead; + int txBdTail; + int txBdActiveCount; + m8xxBufferDescriptor_t *rxBdBase; + m8xxBufferDescriptor_t *txBdBase; + rtems_id rxDaemonTid; + rtems_id txDaemonTid; + + /* + * Statistics + */ + unsigned long rxInterrupts; + unsigned long rxNotFirst; + unsigned long rxNotLast; + unsigned long rxGiant; + unsigned long rxNonOctet; + unsigned long rxRunt; + unsigned long rxBadCRC; + unsigned long rxOverrun; + unsigned long rxCollision; + + unsigned long txInterrupts; + unsigned long txDeferred; + unsigned long txHeartbeat; + unsigned long txLateCollision; + unsigned long txRetryLimit; + unsigned long txUnderrun; + unsigned long txLostCarrier; + unsigned long txRawWait; +}; +static struct m8xx_enet_struct enet_driver[NIFACES]; + +static void m8xx_scc1_ethernet_on(const rtems_irq_connect_data* ptr) +{ +} + +static void m8xx_scc1_ethernet_off(const rtems_irq_connect_data* ptr) +{ + /* + * Please put relevant code there + */ +} + +static void m8xx_scc1_ethernet_isOn(const rtems_irq_connect_data* ptr) +{ + int BSP_irq_enabled_at_cpm(const rtems_irq_number ); + BSP_irq_enabled_at_cpm (ptr->name); +} + +/* + * SCC1 interrupt handler + */ +static void m8xx_scc1_interrupt_handler (void *unused) +{ + /* Frame received? */ + if ((m8xx.scc1.sccm & 0x8) && (m8xx.scc1.scce & 0x8)) { + m8xx.scc1.scce = 0x8; /* Clear receive frame int */ + m8xx.scc1.sccm &= ~0x8; /* Disable receive frame ints */ + enet_driver[0].rxInterrupts++; /* Rx int has occurred */ + rtems_event_send (enet_driver[0].rxDaemonTid, INTERRUPT_EVENT); + } + + /* Buffer transmitted or transmitter error? */ + if ((m8xx.scc1.sccm & 0x12) && (m8xx.scc1.scce & 0x12)) { + m8xx.scc1.scce = 0x12; /* Clear Tx int */ + m8xx.scc1.sccm &= ~0x12; /* Disable Tx ints */ + enet_driver[0].txInterrupts++; /* Tx int has occurred */ + rtems_event_send (enet_driver[0].txDaemonTid, INTERRUPT_EVENT); + } +} + + +static rtems_irq_connect_data ethernetSCC1IrqData = { + BSP_CPM_IRQ_SCC1, + (rtems_irq_hdl) m8xx_scc1_interrupt_handler, + 0, + (rtems_irq_enable) m8xx_scc1_ethernet_on, + (rtems_irq_disable) m8xx_scc1_ethernet_off, + (rtems_irq_is_enabled)m8xx_scc1_ethernet_isOn +}; + +/* + * Initialize the ethernet hardware + */ +static void +m8xx_enet_initialize (struct m8xx_enet_struct *sc) +{ + int i; + unsigned char *hwaddr; + + /* + * Configure port A + * PA15 is enet RxD. Set PAPAR(15) to 1, PADIR(15) to 0. + * PA14 is enet TxD. Set PAPAR(14) to 1, PADIR(14) to 0, PAODR(14) to 0. + * PA7 is input CLK1. Set PAPAR(7) to 1, PADIR(7) to 0. + * PA6 is input CLK2. Set PAPAR(6) to 1, PADIR(6) to 0. + */ + m8xx.papar |= 0x303; + m8xx.padir &= ~0x303; + m8xx.paodr &= ~0x2; + + /* + * Configure port C + * PC11 is CTS1*. Set PCPAR(11) to 0, PCDIR(11) to 0, and PCSO(11) to 1. + * PC10 is CD1*. Set PCPAR(10) to 0, PCDIR(10) to 0, and PCSO(10) to 1. + */ + m8xx.pcpar &= ~0x30; + m8xx.pcdir &= ~0x30; + m8xx.pcso |= 0x30; + + /* + * Connect CLK1 and CLK2 to SCC1 in the SICR. + * CLK1 is TxClk, CLK2 is RxClk. No grant mechanism, SCC1 is directly + * connected to the NMSI pins. + * R1CS = 0b101 (CLK2) + * T1CS = 0b100 (CLK1) + */ + m8xx.sicr |= 0x2C; + + /* + * Initialize SDMA configuration register + */ + m8xx.sdcr = 1; + + /* + * Allocate mbuf pointers + */ + sc->rxMbuf = malloc (sc->rxBdCount * sizeof *sc->rxMbuf, + M_MBUF, M_NOWAIT); + sc->txMbuf = malloc (sc->txBdCount * sizeof *sc->txMbuf, + M_MBUF, M_NOWAIT); + if (!sc->rxMbuf || !sc->txMbuf) + rtems_panic ("No memory for mbuf pointers"); + + /* + * Set receiver and transmitter buffer descriptor bases + */ + sc->rxBdBase = m8xx_bd_allocate(sc->rxBdCount); + sc->txBdBase = m8xx_bd_allocate(sc->txBdCount); + m8xx.scc1p.rbase = (char *)sc->rxBdBase - (char *)&m8xx; + m8xx.scc1p.tbase = (char *)sc->txBdBase - (char *)&m8xx; + + /* + * Send "Init parameters" command + */ + m8xx_cp_execute_cmd (M8xx_CR_OP_INIT_RX_TX | M8xx_CR_CHAN_SCC1); + + /* + * Set receive and transmit function codes + */ + m8xx.scc1p.rfcr = M8xx_RFCR_MOT | M8xx_RFCR_DMA_SPACE(0); + m8xx.scc1p.tfcr = M8xx_TFCR_MOT | M8xx_TFCR_DMA_SPACE(0); + + /* + * Set maximum receive buffer length + */ + m8xx.scc1p.mrblr = RBUF_SIZE; + + /* + * Set CRC parameters + */ + m8xx.scc1p.un.ethernet.c_pres = 0xFFFFFFFF; + m8xx.scc1p.un.ethernet.c_mask = 0xDEBB20E3; + + /* + * Clear diagnostic counters + */ + m8xx.scc1p.un.ethernet.crcec = 0; + m8xx.scc1p.un.ethernet.alec = 0; + m8xx.scc1p.un.ethernet.disfc = 0; + + /* + * Set pad value + */ + m8xx.scc1p.un.ethernet.pads = 0x8888; + + /* + * Set retry limit + */ + m8xx.scc1p.un.ethernet.ret_lim = 15; + + /* + * Set maximum and minimum frame length + */ + m8xx.scc1p.un.ethernet.mflr = 1518; + m8xx.scc1p.un.ethernet.minflr = 64; + m8xx.scc1p.un.ethernet.maxd1 = MAX_MTU_SIZE; + m8xx.scc1p.un.ethernet.maxd2 = MAX_MTU_SIZE; + + /* + * Clear group address hash table + */ + m8xx.scc1p.un.ethernet.gaddr1 = 0; + m8xx.scc1p.un.ethernet.gaddr2 = 0; + m8xx.scc1p.un.ethernet.gaddr3 = 0; + m8xx.scc1p.un.ethernet.gaddr4 = 0; + + /* + * Set our physical address + */ + hwaddr = sc->arpcom.ac_enaddr; + + m8xx.scc1p.un.ethernet.paddr_h = (hwaddr[5] << 8) | hwaddr[4]; + m8xx.scc1p.un.ethernet.paddr_m = (hwaddr[3] << 8) | hwaddr[2]; + m8xx.scc1p.un.ethernet.paddr_l = (hwaddr[1] << 8) | hwaddr[0]; + + /* + * Aggressive retry + */ + m8xx.scc1p.un.ethernet.p_per = 0; + + /* + * Clear individual address hash table + */ + m8xx.scc1p.un.ethernet.iaddr1 = 0; + m8xx.scc1p.un.ethernet.iaddr2 = 0; + m8xx.scc1p.un.ethernet.iaddr3 = 0; + m8xx.scc1p.un.ethernet.iaddr4 = 0; + + /* + * Clear temp address + */ + m8xx.scc1p.un.ethernet.taddr_l = 0; + m8xx.scc1p.un.ethernet.taddr_m = 0; + m8xx.scc1p.un.ethernet.taddr_h = 0; + + /* + * Set up receive buffer descriptors + */ + for (i = 0 ; i < sc->rxBdCount ; i++) { + (sc->rxBdBase + i)->status = 0; + } + + /* + * Set up transmit buffer descriptors + */ + for (i = 0 ; i < sc->txBdCount ; i++) { + (sc->txBdBase + i)->status = 0; + sc->txMbuf[i] = NULL; + } + sc->txBdHead = sc->txBdTail = 0; + sc->txBdActiveCount = 0; + + /* + * Clear any outstanding events + */ + m8xx.scc1.scce = 0xFFFF; + + /* + * Set up interrupts + */ + if (!BSP_install_rtems_irq_handler (ðernetSCC1IrqData)) { + rtems_panic ("Can't attach M8xx SCC1 interrupt handler\n"); + } + m8xx.scc1.sccm = 0; /* No interrupts unmasked till necessary */ + + /* + * Set up General SCC Mode Register + * Ethernet configuration + */ + m8xx.scc1.gsmr_h = 0x0; + m8xx.scc1.gsmr_l = 0x1088000c; + + /* + * Set up data synchronization register + * Ethernet synchronization pattern + */ + m8xx.scc1.dsr = 0xd555; + + /* + * Set up protocol-specific mode register + * No Heartbeat check + * No force collision + * Discard short frames + * Individual address mode + * Ethernet CRC + * Not promisuous + * Ignore/accept broadcast packets as specified + * Normal backoff timer + * No loopback + * No input sample at end of frame + * 64-byte limit for late collision + * Wait 22 bits before looking for start of frame delimiter + * Disable full-duplex operation + */ + m8xx.scc1.psmr = 0x080A | (sc->acceptBroadcast ? 0 : 0x100); + + /* + * Enable the TENA (RTS1*) pin + */ + m8xx.pcpar |= 0x1; + m8xx.pcdir &= ~0x1; + + /* + * Enable receiver and transmitter + */ + m8xx.scc1.gsmr_l = 0x1088003c; +} + + +/* + * Soak up buffer descriptors that have been sent. + * Note that a buffer descriptor can't be retired as soon as it becomes + * ready. The MPC860 manual (MPC860UM/AD 07/98 Rev.1) and the MPC821 + * manual state that, "If an Ethernet frame is made up of multiple + * buffers, the user should not reuse the first buffer descriptor until + * the last buffer descriptor of the frame has had its ready bit cleared + * by the CPM". + */ +static void +m8xx_Enet_retire_tx_bd (struct m8xx_enet_struct *sc) +{ + uint16_t status; + int i; + int nRetired; + struct mbuf *m, *n; + + i = sc->txBdTail; + nRetired = 0; + while ((sc->txBdActiveCount != 0) + && (((status = (sc->txBdBase + i)->status) & M8xx_BD_READY) == 0)) { + /* + * See if anything went wrong + */ + if (status & (M8xx_BD_DEFER | + M8xx_BD_HEARTBEAT | + M8xx_BD_LATE_COLLISION | + M8xx_BD_RETRY_LIMIT | + M8xx_BD_UNDERRUN | + M8xx_BD_CARRIER_LOST)) { + /* + * Check for errors which stop the transmitter. + */ + if (status & (M8xx_BD_LATE_COLLISION | + M8xx_BD_RETRY_LIMIT | + M8xx_BD_UNDERRUN)) { + if (status & M8xx_BD_LATE_COLLISION) + enet_driver[0].txLateCollision++; + if (status & M8xx_BD_RETRY_LIMIT) + enet_driver[0].txRetryLimit++; + if (status & M8xx_BD_UNDERRUN) + enet_driver[0].txUnderrun++; + + /* + * Restart the transmitter + */ + m8xx_cp_execute_cmd (M8xx_CR_OP_RESTART_TX | M8xx_CR_CHAN_SCC1); + } + if (status & M8xx_BD_DEFER) + enet_driver[0].txDeferred++; + if (status & M8xx_BD_HEARTBEAT) + enet_driver[0].txHeartbeat++; + if (status & M8xx_BD_CARRIER_LOST) + enet_driver[0].txLostCarrier++; + } + nRetired++; + if (status & M8xx_BD_LAST) { + /* + * A full frame has been transmitted. + * Free all the associated buffer descriptors. + */ + sc->txBdActiveCount -= nRetired; + while (nRetired) { + nRetired--; + m = sc->txMbuf[sc->txBdTail]; + MFREE (m, n); + if (++sc->txBdTail == sc->txBdCount) + sc->txBdTail = 0; + } + } + if (++i == sc->txBdCount) + i = 0; + } +} + +/* + * reader task + */ +static void +scc_rxDaemon (void *arg) +{ + struct m8xx_enet_struct *sc = (struct m8xx_enet_struct *)arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct mbuf *m; + uint16_t status; + m8xxBufferDescriptor_t *rxBd; + int rxBdIndex; + + /* + * Allocate space for incoming packets and start reception + */ + for (rxBdIndex = 0 ; ;) { + rxBd = sc->rxBdBase + rxBdIndex; + MGETHDR (m, M_WAIT, MT_DATA); + MCLGET (m, M_WAIT); + m->m_pkthdr.rcvif = ifp; + sc->rxMbuf[rxBdIndex] = m; + rxBd->buffer = mtod (m, void *); + rxBd->status = M8xx_BD_EMPTY | M8xx_BD_INTERRUPT; + if (++rxBdIndex == sc->rxBdCount) { + rxBd->status |= M8xx_BD_WRAP; + break; + } + } + + /* + * Input packet handling loop + */ + rxBdIndex = 0; + for (;;) { + rxBd = sc->rxBdBase + rxBdIndex; + + /* + * Wait for packet if there's not one ready + */ + if ((status = rxBd->status) & M8xx_BD_EMPTY) { + /* + * Clear old events + */ + m8xx.scc1.scce = 0x8; + + /* + * Wait for packet + * Note that the buffer descriptor is checked + * *before* the event wait -- this catches the + * possibility that a packet arrived between the + * `if' above, and the clearing of the event register. + */ + while ((status = rxBd->status) & M8xx_BD_EMPTY) { + rtems_event_set events; + + /* + * Unmask RXF (Full frame received) event + */ + m8xx.scc1.sccm |= 0x8; + + rtems_bsdnet_event_receive (INTERRUPT_EVENT, + RTEMS_WAIT|RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events); + } + } + + /* + * Check that packet is valid + */ + if ((status & (M8xx_BD_LAST | + M8xx_BD_FIRST_IN_FRAME | + M8xx_BD_LONG | + M8xx_BD_NONALIGNED | + M8xx_BD_SHORT | + M8xx_BD_CRC_ERROR | + M8xx_BD_OVERRUN | + M8xx_BD_COLLISION)) == + (M8xx_BD_LAST | + M8xx_BD_FIRST_IN_FRAME)) { + /* + * Pass the packet up the chain. + * FIXME: Packet filtering hook could be done here. + */ + struct ether_header *eh; + + /* + * Invalidate the buffer for this descriptor + */ + rtems_cache_invalidate_multiple_data_lines((const void *)rxBd->buffer, rxBd->length); + + m = sc->rxMbuf[rxBdIndex]; + m->m_len = m->m_pkthdr.len = rxBd->length - + sizeof(uint32_t) - + sizeof(struct ether_header); + eh = mtod (m, struct ether_header *); + m->m_data += sizeof(struct ether_header); + ether_input (ifp, eh, m); + + /* + * Allocate a new mbuf + */ + MGETHDR (m, M_WAIT, MT_DATA); + MCLGET (m, M_WAIT); + m->m_pkthdr.rcvif = ifp; + sc->rxMbuf[rxBdIndex] = m; + rxBd->buffer = mtod (m, void *); + } + else { + /* + * Something went wrong with the reception + */ + if (!(status & M8xx_BD_LAST)) + sc->rxNotLast++; + if (!(status & M8xx_BD_FIRST_IN_FRAME)) + sc->rxNotFirst++; + if (status & M8xx_BD_LONG) + sc->rxGiant++; + if (status & M8xx_BD_NONALIGNED) + sc->rxNonOctet++; + if (status & M8xx_BD_SHORT) + sc->rxRunt++; + if (status & M8xx_BD_CRC_ERROR) + sc->rxBadCRC++; + if (status & M8xx_BD_OVERRUN) + sc->rxOverrun++; + if (status & M8xx_BD_COLLISION) + sc->rxCollision++; + } + + /* + * Reenable the buffer descriptor + */ + rxBd->status = (status & (M8xx_BD_WRAP | M8xx_BD_INTERRUPT)) | + M8xx_BD_EMPTY; + + /* + * Move to next buffer descriptor + */ + if (++rxBdIndex == sc->rxBdCount) + rxBdIndex = 0; + } +} + + +static void +scc_sendpacket (struct ifnet *ifp, struct mbuf *m) +{ + struct m8xx_enet_struct *sc = ifp->if_softc; + volatile m8xxBufferDescriptor_t *firstTxBd, *txBd; + struct mbuf *l = NULL; + uint16_t status; + int nAdded; + + /* + * Free up buffer descriptors + */ + m8xx_Enet_retire_tx_bd (sc); + + /* + * Set up the transmit buffer descriptors. + * No need to pad out short packets since the + * hardware takes care of that automatically. + * No need to copy the packet to a contiguous buffer + * since the hardware is capable of scatter/gather DMA. + */ + nAdded = 0; + txBd = firstTxBd = sc->txBdBase + sc->txBdHead; + for (;;) { + /* + * Wait for buffer descriptor to become available. + */ + if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) { + /* + * Clear old events + */ + m8xx.scc1.scce = 0x12; + + /* + * Wait for buffer descriptor to become available. + * Note that the buffer descriptors are checked + * *before* * entering the wait loop -- this catches + * the possibility that a buffer descriptor became + * available between the `if' above, and the clearing + * of the event register. + * This is to catch the case where the transmitter + * stops in the middle of a frame -- and only the + * last buffer descriptor in a frame can generate + * an interrupt. + */ + m8xx_Enet_retire_tx_bd (sc); + while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) { + rtems_event_set events; + + /* + * Unmask TXB (buffer transmitted) and + * TXE (transmitter error) events. + */ + m8xx.scc1.sccm |= 0x12; + rtems_bsdnet_event_receive (INTERRUPT_EVENT, + RTEMS_WAIT|RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events); + m8xx_Enet_retire_tx_bd (sc); + } + } + + /* + * Don't set the READY flag till the + * whole packet has been readied. + */ + status = nAdded ? M8xx_BD_READY : 0; + + /* + * FIXME: Why not deal with empty mbufs at at higher level? + * The IP fragmentation routine in ip_output + * can produce packet fragments with zero length. + * I think that ip_output should be changed to get + * rid of these zero-length mbufs, but for now, + * I'll deal with them here. + */ + if (m->m_len) { + /* + * Fill in the buffer descriptor + */ + txBd->buffer = mtod (m, void *); + txBd->length = m->m_len; + + /* + * Flush the buffer for this descriptor + */ + rtems_cache_flush_multiple_data_lines((const void *)txBd->buffer, txBd->length); + + sc->txMbuf[sc->txBdHead] = m; + nAdded++; + if (++sc->txBdHead == sc->txBdCount) { + status |= M8xx_BD_WRAP; + sc->txBdHead = 0; + } + l = m; + m = m->m_next; + } + else { + /* + * Just toss empty mbufs + */ + struct mbuf *n; + MFREE (m, n); + m = n; + if (l != NULL) + l->m_next = m; + } + + /* + * Set the transmit buffer status. + * Break out of the loop if this mbuf is the last in the frame. + */ + if (m == NULL) { + if (nAdded) { + status |= M8xx_BD_PAD | M8xx_BD_LAST | M8xx_BD_TX_CRC | M8xx_BD_INTERRUPT; + txBd->status = status; + firstTxBd->status |= M8xx_BD_READY; + sc->txBdActiveCount += nAdded; + } + break; + } + txBd->status = status; + txBd = sc->txBdBase + sc->txBdHead; + } +} + + +/* + * Driver transmit daemon + */ +void +scc_txDaemon (void *arg) +{ + struct m8xx_enet_struct *sc = (struct m8xx_enet_struct *)arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct mbuf *m; + rtems_event_set events; + + for (;;) { + /* + * Wait for packet + */ + rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events); + + /* + * Send packets till queue is empty + */ + for (;;) { + /* + * Get the next mbuf chain to transmit. + */ + IF_DEQUEUE(&ifp->if_snd, m); + if (!m) + break; + scc_sendpacket (ifp, m); + } + ifp->if_flags &= ~IFF_OACTIVE; + } +} + + +/* + * Send packet (caller provides header). + */ +static void +m8xx_enet_start (struct ifnet *ifp) +{ + struct m8xx_enet_struct *sc = ifp->if_softc; + + rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); + ifp->if_flags |= IFF_OACTIVE; +} + +/* + * Initialize and start the device + */ +static void +scc_init (void *arg) +{ + struct m8xx_enet_struct *sc = arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + + if (sc->txDaemonTid == 0) { + + /* + * Set up SCC hardware + */ + m8xx_enet_initialize (sc); + + /* + * Start driver tasks + */ + sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, scc_txDaemon, sc); + sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, scc_rxDaemon, sc); + + } + + /* + * Set flags appropriately + */ + if (ifp->if_flags & IFF_PROMISC) + m8xx.scc1.psmr |= 0x200; + else + m8xx.scc1.psmr &= ~0x200; + + /* + * Tell the world that we're running. + */ + ifp->if_flags |= IFF_RUNNING; + + /* + * Enable receiver and transmitter + */ + m8xx.scc1.gsmr_l |= 0x30; +} + + +/* + * Stop the device + */ +static void +scc_stop (struct m8xx_enet_struct *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + + ifp->if_flags &= ~IFF_RUNNING; + + /* + * Shut down receiver and transmitter + */ + m8xx.scc1.gsmr_l &= ~0x30; +} + + +/* + * Show interface statistics + */ +static void +enet_stats (struct m8xx_enet_struct *sc) +{ + printf (" Rx Interrupts:%-8lu", sc->rxInterrupts); + printf (" Not First:%-8lu", sc->rxNotFirst); + printf (" Not Last:%-8lu\n", sc->rxNotLast); + printf (" Giant:%-8lu", sc->rxGiant); + printf (" Runt:%-8lu", sc->rxRunt); + printf (" Non-octet:%-8lu\n", sc->rxNonOctet); + printf (" Bad CRC:%-8lu", sc->rxBadCRC); + printf (" Overrun:%-8lu", sc->rxOverrun); + printf (" Collision:%-8lu\n", sc->rxCollision); + printf (" Discarded:%-8lu\n", (unsigned long)m8xx.scc1p.un.ethernet.disfc); + + printf (" Tx Interrupts:%-8lu", sc->txInterrupts); + printf (" Deferred:%-8lu", sc->txDeferred); + printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat); + printf (" No Carrier:%-8lu", sc->txLostCarrier); + printf ("Retransmit Limit:%-8lu", sc->txRetryLimit); + printf (" Late Collision:%-8lu\n", sc->txLateCollision); + printf (" Underrun:%-8lu", sc->txUnderrun); + printf (" Raw output wait:%-8lu\n", sc->txRawWait); +} + +/* + * Driver ioctl handler + */ +static int +scc_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data) +{ + struct m8xx_enet_struct *sc = ifp->if_softc; + int error = 0; + + switch (command) { + case SIOCGIFADDR: + case SIOCSIFADDR: + ether_ioctl (ifp, command, data); + break; + + case SIOCSIFFLAGS: + switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { + case IFF_RUNNING: + scc_stop (sc); + break; + + case IFF_UP: + scc_init (sc); + break; + + case IFF_UP | IFF_RUNNING: + scc_stop (sc); + scc_init (sc); + break; + + default: + break; + } + break; + + case SIO_RTEMS_SHOW_STATS: + enet_stats (sc); + break; + + /* + * FIXME: All sorts of multicast commands need to be added here! + */ + default: + error = EINVAL; + break; + } + return error; +} + + +/* + * Attach an SCC driver to the system + */ +int +rtems_scc1_driver_attach (struct rtems_bsdnet_ifconfig *config) +{ + struct m8xx_enet_struct *sc; + struct ifnet *ifp; + int mtu; + int unitNumber; + char *unitName; + static const uint8_t maczero[] ={0,0,0,0,0,0}; + /* + * Parse driver name + */ + if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0) + return 0; + + /* + * Is driver free? + */ + if ((unitNumber <= 0) || (unitNumber > NIFACES)) { + printf ("Bad SCC unit number.\n"); + return 0; + } + sc = &enet_driver[unitNumber - 1]; + ifp = &sc->arpcom.ac_if; + if (ifp->if_softc != NULL) { + printf ("Driver already in use.\n"); + return 0; + } + + /* + * Process options + */ + + /* + * MAC address: try to fetch it from config, else from TQMMon, else panic + */ + if (config->hardware_address) { + memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN); + } +#ifdef BSP_HAS_TQMMON + else if(0 != memcmp(maczero,TQM_BD_INFO.eth_addr,ETHER_ADDR_LEN)) { + memcpy (sc->arpcom.ac_enaddr, TQM_BD_INFO.eth_addr, ETHER_ADDR_LEN); + } +#endif + else { + /* There is no ethernet address provided, so it could be read + * from the Ethernet protocol block of SCC1 in DPRAM. + */ + rtems_panic("No Ethernet address specified!\n"); + } + + if (config->mtu) + mtu = config->mtu; + else + mtu = ETHERMTU; + if (config->rbuf_count) + sc->rxBdCount = config->rbuf_count; + else + sc->rxBdCount = RX_BUF_COUNT; + if (config->xbuf_count) + sc->txBdCount = config->xbuf_count; + else + sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF; + sc->acceptBroadcast = !config->ignore_broadcast; + + /* + * Set up network interface values + */ + ifp->if_softc = sc; + ifp->if_unit = unitNumber; + ifp->if_name = unitName; + ifp->if_mtu = mtu; + ifp->if_init = scc_init; + ifp->if_ioctl = scc_ioctl; + ifp->if_start = m8xx_enet_start; + ifp->if_output = ether_output; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; + if (ifp->if_snd.ifq_maxlen == 0) + ifp->if_snd.ifq_maxlen = ifqmaxlen; + + /* + * Attach the interface + */ + if_attach (ifp); + ether_ifattach (ifp); + return 1; +}; + +int +rtems_scc_enet_driver_attach(struct rtems_bsdnet_ifconfig *config, int attaching) +{ + return rtems_scc1_driver_attach(config); +} diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/preinstall.am b/c/src/lib/libbsp/powerpc/tqm8xx/preinstall.am new file mode 100644 index 0000000000..123726ebb4 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/preinstall.am @@ -0,0 +1,104 @@ +## Automatically generated by ampolish3 - Do not edit + +if AMPOLISH3 +$(srcdir)/preinstall.am: Makefile.am + $(AMPOLISH3) $(srcdir)/Makefile.am > $(srcdir)/preinstall.am +endif + +PREINSTALL_DIRS = +DISTCLEANFILES += $(PREINSTALL_DIRS) + +all-local: $(TMPINSTALL_FILES) + +TMPINSTALL_FILES = +CLEANFILES = $(TMPINSTALL_FILES) + +all-am: $(PREINSTALL_FILES) + +PREINSTALL_FILES = +CLEANFILES += $(PREINSTALL_FILES) + +$(PROJECT_LIB)/$(dirstamp): + @$(MKDIR_P) $(PROJECT_LIB) + @: > $(PROJECT_LIB)/$(dirstamp) +PREINSTALL_DIRS += $(PROJECT_LIB)/$(dirstamp) + +$(PROJECT_INCLUDE)/$(dirstamp): + @$(MKDIR_P) $(PROJECT_INCLUDE) + @: > $(PROJECT_INCLUDE)/$(dirstamp) +PREINSTALL_DIRS += $(PROJECT_INCLUDE)/$(dirstamp) + +$(PROJECT_LIB)/bsp_specs: bsp_specs $(PROJECT_LIB)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_LIB)/bsp_specs +PREINSTALL_FILES += $(PROJECT_LIB)/bsp_specs + +$(PROJECT_INCLUDE)/bsp.h: include/bsp.h $(PROJECT_INCLUDE)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp.h + +$(PROJECT_INCLUDE)/tm27.h: include/tm27.h $(PROJECT_INCLUDE)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/tm27.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/tm27.h + +../../../libcpu/@RTEMS_CPU@/$(dirstamp): + @$(MKDIR_P) ../../../libcpu/@RTEMS_CPU@ + @: > ../../../libcpu/@RTEMS_CPU@/$(dirstamp) +PREINSTALL_DIRS += ../../../libcpu/@RTEMS_CPU@/$(dirstamp) + +$(PROJECT_INCLUDE)/bspopts.h: include/bspopts.h $(PROJECT_INCLUDE)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bspopts.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bspopts.h + +$(PROJECT_INCLUDE)/bsp/$(dirstamp): + @$(MKDIR_P) $(PROJECT_INCLUDE)/bsp + @: > $(PROJECT_INCLUDE)/bsp/$(dirstamp) +PREINSTALL_DIRS += $(PROJECT_INCLUDE)/bsp/$(dirstamp) + +$(PROJECT_INCLUDE)/coverhd.h: include/coverhd.h $(PROJECT_INCLUDE)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/coverhd.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/coverhd.h + +$(PROJECT_INCLUDE)/bsp/tqm.h: include/tqm.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/tqm.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/tqm.h + +$(PROJECT_INCLUDE)/bsp/8xx_immap.h: include/8xx_immap.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/8xx_immap.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/8xx_immap.h + +$(PROJECT_INCLUDE)/bsp/irq.h: include/irq.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq.h + +$(PROJECT_INCLUDE)/bsp/irq-config.h: include/irq-config.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-config.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-config.h + +$(PROJECT_INCLUDE)/bsp/irq-generic.h: ../../shared/include/irq-generic.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-generic.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-generic.h + +$(PROJECT_INCLUDE)/bsp/vectors.h: $(libcpudir)/@exceptions@/bspsupport/vectors.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/vectors.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/vectors.h + +$(PROJECT_INCLUDE)/bsp/ppc_exc_bspsupp.h: $(libcpudir)/@exceptions@/bspsupport/ppc_exc_bspsupp.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/ppc_exc_bspsupp.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/ppc_exc_bspsupp.h + +$(PROJECT_LIB)/start.$(OBJEXT): start.$(OBJEXT) $(PROJECT_LIB)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_LIB)/start.$(OBJEXT) +TMPINSTALL_FILES += $(PROJECT_LIB)/start.$(OBJEXT) + +$(PROJECT_LIB)/rtems_crti.$(OBJEXT): rtems_crti.$(OBJEXT) $(PROJECT_LIB)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_LIB)/rtems_crti.$(OBJEXT) +TMPINSTALL_FILES += $(PROJECT_LIB)/rtems_crti.$(OBJEXT) + +$(PROJECT_LIB)/linkcmds.base: startup/linkcmds.base $(PROJECT_LIB)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_LIB)/linkcmds.base +PREINSTALL_FILES += $(PROJECT_LIB)/linkcmds.base + +$(PROJECT_LIB)/linkcmds.tqm8xx: startup/linkcmds.tqm8xx $(PROJECT_LIB)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_LIB)/linkcmds.tqm8xx +PREINSTALL_FILES += $(PROJECT_LIB)/linkcmds.tqm8xx + diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/startup/bspstart.c b/c/src/lib/libbsp/powerpc/tqm8xx/startup/bspstart.c new file mode 100644 index 0000000000..2b4b38fe87 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/startup/bspstart.c @@ -0,0 +1,234 @@ +/** + * @file + * + * @ingroup tqm8xx + * + * @brief Source for BSP startup code. + */ + +/* + * Copyright (c) 2008 + * Embedded Brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * rtems@embedded-brains.de + * + * The license and distribution terms for this file may be found in the file + * LICENSE in this distribution or at http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#include + +#include +#include +#include + +#include + +#include +#include +/* #include + #include */ + +#ifdef BSP_HAS_TQMMON +/* + * FIXME: TQ Monitor structure + */ +#endif /* BSP_HAS_TQMMON */ + +/* Configuration parameters for console driver, ... */ +unsigned int BSP_bus_frequency; + +/* Configuration parameters for clock driver, ... */ +uint32_t bsp_clicks_per_usec; /* for PIT driver: OSCCLK */ +uint32_t bsp_clock_speed ; /* needed for PIT driver */ + +/* + * Use the shared implementations of the following routines. + * Look in rtems/c/src/lib/libbsp/shared/bsplibc.c. + */ +extern void cpu_init( void); + +void BSP_panic( char *s) +{ + rtems_interrupt_level level; + + rtems_interrupt_disable( level); + + printk( "%s PANIC %s\n", _RTEMS_version, s); + + while (1) { + /* Do nothing */ + } +} + +void _BSP_Fatal_error( unsigned n) +{ + rtems_interrupt_level level; + + rtems_interrupt_disable( level); + + printk( "%s PANIC ERROR %u\n", _RTEMS_version, n); + + while (1) { + /* Do nothing */ + } +} + +void bsp_pretasking_hook( void) +{ + /* Do noting */ +} + +const char *bsp_tqm_get_cib_string( const char *cib_id) +{ + char srch_pattern[10] = ""; + char *fnd_str; + /* + * create search pattern + */ + strcat(srch_pattern,"-"); + strncat(srch_pattern, + cib_id, + sizeof(srch_pattern)-1-strlen(srch_pattern)); + strncat(srch_pattern, + " ", + sizeof(srch_pattern)-1-strlen(srch_pattern)); + /* + * search for pattern in info block (CIB) + */ + fnd_str = strstr(TQM_CONF_INFO_BLOCK_ADDR,srch_pattern); + + if (fnd_str == NULL) { + return NULL; + } + else { + /* + * found? then advance behind search pattern + */ + return fnd_str + strlen(srch_pattern); + } +} + +rtems_status_code bsp_tqm_get_cib_uint32( const char *cib_id, + uint32_t *result) +{ + const char *item_ptr; + const char *end_ptr; + item_ptr = bsp_tqm_get_cib_string(cib_id); + if (item_ptr == NULL) { + return RTEMS_INVALID_ID; + } + /* + * convert string to uint32 + */ + *result = strtoul(item_ptr,&end_ptr,10); + return RTEMS_SUCCESSFUL; +} + +void bsp_get_work_area( void **work_area_start, size_t *work_area_size, void **heap_start, size_t *heap_size) +{ + char *ram_end = (char *) (TQM_BD_INFO.sdram_size - (uint32_t)TopRamReserved); + + *work_area_start = bsp_work_area_start; + *work_area_size = ram_end - bsp_work_area_start; + *heap_start = BSP_BOOTCARD_HEAP_USES_WORK_AREA; + *heap_size = BSP_BOOTCARD_HEAP_SIZE_DEFAULT; +} + +void bsp_start( void) +{ + ppc_cpu_id_t myCpu; + ppc_cpu_revision_t myCpuRevision; + + uint32_t interrupt_stack_start = (uint32_t) bsp_interrupt_stack_start; + uint32_t interrupt_stack_size = (uint32_t) bsp_interrupt_stack_size; + + /* + * Get CPU identification dynamically. Note that the get_ppc_cpu_type() function + * store the result in global variables so that it can be used latter... + */ + myCpu = get_ppc_cpu_type(); + myCpuRevision = get_ppc_cpu_revision(); + + /* Basic CPU initialization */ + cpu_init(); + + /* + * Enable instruction and data caches. Do not force writethrough mode. + */ + +#if INSTRUCTION_CACHE_ENABLE + rtems_cache_enable_instruction(); +#endif + +#if DATA_CACHE_ENABLE + rtems_cache_enable_data(); +#endif + + /* + * This is evaluated during runtime, so it should be ok to set it + * before we initialize the drivers. + */ + + /* Initialize some device driver parameters */ + /* + * get the (internal) bus frequency + * NOTE: the external bus may be clocked at a lower speed + * but this does not concern the internal units like PIT, + * DEC, baudrate generator etc) + */ + if (RTEMS_SUCCESSFUL != + bsp_tqm_get_cib_uint32("cu", + &BSP_bus_frequency)) { + BSP_panic("Cannot determine BUS frequency\n"); + } + + bsp_clicks_per_usec = 0; /* force to zero to control + * PIT clock driver from EXTCLK + */ + bsp_clock_speed = BSP_bus_frequency; + + /* Initialize exception handler */ + ppc_exc_initialize(PPC_INTERRUPT_DISABLE_MASK_DEFAULT, + interrupt_stack_start, + interrupt_stack_size + ); + + /* Initalize interrupt support */ + if (bsp_interrupt_initialize() != RTEMS_SUCCESSFUL) { + BSP_panic("Cannot intitialize interrupt support\n"); + } + +#ifdef SHOW_MORE_INIT_SETTINGS + printk("Exit from bspstart\n"); +#endif +} + +/** + * @brief Idle thread body. + * + * Replaces the one in c/src/exec/score/src/threadidlebody.c + * The MSR[POW] bit is set to put the CPU into the low power mode + * defined in HID0. HID0 is set during starup in start.S. + */ +Thread _Thread_Idle_body( uint32_t ignored) +{ + + while (1) { + asm volatile ( + "mfmsr 3;" + "oris 3, 3, 4;" + "sync;" + "mtmsr 3;" + "isync;" + "ori 3, 3, 0;" + "ori 3, 3, 0" + ); + } + + return NULL; +} diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/startup/cpuinit.c b/c/src/lib/libbsp/powerpc/tqm8xx/startup/cpuinit.c new file mode 100644 index 0000000000..e99e9d9a6a --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/startup/cpuinit.c @@ -0,0 +1,134 @@ +/* + * cpuinit.c + * + * TQM8xx initialization routines. + * derived from MBX8xx BSP + * adapted to TQM8xx by Thomas Doerfler + * + * 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. + */ + +#include +#include + + +/* + * Initialize TQM8xx + */ +void _InitTQM8xx (void) +{ + register uint32_t r1; + + /* + * Initialize the Instruction Support Control Register (ICTRL) to a + * an appropriate value for normal operation. A different value, + * such as 0x0, may be more appropriate for debugging. + */ + r1 = 0x00000007; + _mtspr( M8xx_ICTRL, r1 ); + + /* + * Disable and invalidate the instruction and data caches. + */ + r1 = M8xx_CACHE_CMD_DISABLE; + _mtspr( M8xx_IC_CST, r1 ); + _isync; + r1 = M8xx_CACHE_CMD_UNLOCKALL; + _mtspr( M8xx_IC_CST, r1 ); + _isync; + r1 = M8xx_CACHE_CMD_INVALIDATE; /* invalidate all */ + _mtspr( M8xx_IC_CST, r1 ); + _isync; + + r1 = M8xx_CACHE_CMD_DISABLE; + _mtspr( M8xx_DC_CST, r1 ); + _isync; + r1 = M8xx_CACHE_CMD_UNLOCKALL; + _mtspr( M8xx_DC_CST, r1 ); + _isync; + r1 = M8xx_CACHE_CMD_INVALIDATE; /* invalidate all */ + _mtspr( M8xx_DC_CST, r1 ); + _isync; + + /* + * Initialize the SIU Module Configuration Register (SIUMCR) + * m8xx.siumcr = 0x00602900, the default value. + */ + m8xx.siumcr = M8xx_SIUMCR_EARP0 | M8xx_SIUMCR_DBGC3 | M8xx_SIUMCR_DBPC0 | + M8xx_SIUMCR_DPC | M8xx_SIUMCR_MLRC2 | M8xx_SIUMCR_SEME; + + /* + * Initialize the System Protection Control Register (SYPCR). + * The SYPCR can only be written once after Reset. + * - Enable bus monitor + * - Disable software watchdog timer + * m8xx.sypcr = 0xFFFFFF88, the default MBX and firmware value. + */ + m8xx.sypcr = M8xx_SYPCR_SWTC(0xFFFF) | M8xx_SYPCR_BMT(0xFF) | + M8xx_SYPCR_BME | M8xx_SYPCR_SWF; + + /* Initialize the SIU Interrupt Edge Level Mask Register (SIEL) */ + m8xx.siel = 0xAAAA0000; /* Default MBX and firmware value. */ + + /* Initialize the Transfer Error Status Register (TESR) */ + m8xx.tesr = 0xFFFFFFFF; /* Default firmware value. */ + + /* Initialize the SDMA Configuration Register (SDCR) */ + m8xx.sdcr = 0x00000001; /* Default firmware value. */ + + /* + * Initialize the Timebase Status and Control Register (TBSCR) + * m8xx.tbscr = 0x00C3, default MBX and firmware value. + */ + m8xx.tbscrk = M8xx_UNLOCK_KEY; /* unlock TBSCR */ + m8xx.tbscr = M8xx_TBSCR_REFA | M8xx_TBSCR_REFB | + M8xx_TBSCR_TBF | M8xx_TBSCR_TBE; + + /* Initialize the Real-Time Clock Status and Control Register (RTCSC) */ + m8xx.rtcsk = M8xx_UNLOCK_KEY; /* unlock RTCSC */ + m8xx.rtcsc = 0x00C3; /* Default MBX and firmware value. */ + + /* Unlock other Real-Time Clock registers */ + m8xx.rtck = M8xx_UNLOCK_KEY; /* unlock RTC */ + m8xx.rtseck = M8xx_UNLOCK_KEY; /* unlock RTSEC */ + m8xx.rtcalk = M8xx_UNLOCK_KEY; /* unlock RTCAL */ + + /* Initialize the Periodic Interrupt Status and Control Register (PISCR) */ + m8xx.piscrk = M8xx_UNLOCK_KEY; /* unlock PISCR */ + m8xx.piscr = 0x0083; /* Default MBX and firmware value. */ + + /* Initialize the System Clock and Reset Control Register (SCCR) + * Set the clock sources and division factors: + * Timebase Source is GCLK2 / 16 + */ + m8xx.sccrk = M8xx_UNLOCK_KEY; /* unlock SCCR */ + m8xx.sccr |= 0x02000000; + + /* Unlock the timebase and decrementer registers. */ + m8xx.tbk = M8xx_UNLOCK_KEY; + /* + * Initialize decrementer register to a large value to + * guarantee that a decrementer interrupt will not be + * generated before the kernel is fully initialized. + */ + r1 = 0x7FFFFFFF; + _mtspr( M8xx_DEC, r1 ); + + /* Initialize the timebase register (TB is 64 bits) */ + r1 = 0x00000000; + _mtspr( M8xx_TBU_WR, r1 ); + _mtspr( M8xx_TBL_WR, r1 ); +} +/* + * further initialization (called from bsp_start) + */ +void cpu_init(void) +{ + /* + * none up to now + */ +} diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/startup/linkcmds.base b/c/src/lib/libbsp/powerpc/tqm8xx/startup/linkcmds.base new file mode 100644 index 0000000000..c4a0eec115 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/startup/linkcmds.base @@ -0,0 +1,316 @@ +/** + * @file + * + * Derived from internal linker script of GNU ld (GNU Binutils) 2.18 for elf32ppc emulation. + */ + +OUTPUT_FORMAT ("elf32-powerpc", "elf32-powerpc", "elf32-powerpc") +OUTPUT_ARCH (powerpc) +ENTRY (start) + +bsp_ram_start = ORIGIN (RAM); +bsp_ram_end = ORIGIN (RAM) + LENGTH (RAM); +bsp_ram_size = LENGTH (RAM); + +bsp_rom_start = ORIGIN (ROM); +bsp_rom_end = ORIGIN (ROM) + LENGTH (ROM); +bsp_rom_size = LENGTH (ROM); + +bsp_section_align = 32; + +SECTIONS { + + dpram : + { + m8xx = .; + _m8xx = .; + /* . += (16 * 1024); this makes the mbx loader crash */ + } >immr + + /* + * BSP: Exception vectors + */ + .vectors 0x100 : { + *(.vectors) + } > RAM + + /* + * BSP: The initial stack will live in this area - between the vectors + * and the text section. + */ + + .text 0x10000 : { + /* + * BSP: Start of text section + */ + bsp_section_text_start = .; + + /* + * BSP: System startup entry + */ + KEEP (*(.entry)) + + /* + * BSP: Moved into .text from .init + */ + KEEP (*(.init)) + + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glink) + + /* + * BSP: Special FreeBSD sysctl sections + */ + . = ALIGN (16); + __start_set_sysctl_set = .; + *(set_sysctl_*); + __stop_set_sysctl_set = ABSOLUTE(.); + *(set_domain_*); + *(set_pseudo_*); + + /* + * BSP: Moved into .text from .* + */ + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.rodata1) + *(.interp) + *(.note.gnu.build-id) + *(.hash) + *(.gnu.hash) + *(.dynsym) + *(.dynstr) + *(.gnu.version) + *(.gnu.version_d) + *(.gnu.version_r) + *(.eh_frame_hdr) + + /* + * BSP: Magic PPC stuff + */ + *(.PPC.*) + + /* + * BSP: Required by cpukit/score/src/threadhandler.c + */ + PROVIDE (_fini = .); + + /* + * BSP: Moved into .text from .fini + */ + KEEP (*(.fini)) + + . = ALIGN (bsp_section_align); + + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + } > RAM + + .sdata2 : { + PROVIDE (_SDA2_BASE_ = 32768); + + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + + . = ALIGN (bsp_section_align); + } > RAM + + .sbss2 : { + *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) + + . = ALIGN (bsp_section_align); + + /* + * BSP: End and size of text section + */ + bsp_section_text_end = .; + bsp_section_text_size = bsp_section_text_end - bsp_section_text_start; + } > RAM + + .data : { + /* + * BSP: Start of data section + */ + bsp_section_data_start = .; + + /* + * BSP: Moved into .data from .ctors + */ + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + + /* + * BSP: Moved into .data from .dtors + */ + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + + /* + * BSP: Moved into .data from .* + */ + *(.tdata .tdata.* .gnu.linkonce.td.*) + *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) + *(.data1) + KEEP (*(.eh_frame)) + *(.gcc_except_table .gcc_except_table.*) + KEEP (*(.jcr)) + *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) + *(.fixup) + *(.got1) + *(.got2) + *(.dynamic) + *(.got) + *(.plt) + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + + . = ALIGN (bsp_section_align); + } > RAM + + .sdata : { + PROVIDE (_SDA_BASE_ = 32768); + *(.sdata .sdata.* .gnu.linkonce.s.*) + + . = ALIGN (bsp_section_align); + + _edata = .; + PROVIDE (edata = .); + + /* + * BSP: End and size of data section + */ + bsp_section_data_end = .; + bsp_section_data_size = bsp_section_data_end - bsp_section_data_start; + } > RAM + + .sbss : { + /* + * BSP: Start of bss section + */ + bsp_section_bss_start = .; + + __bss_start = .; + + PROVIDE (__sbss_start = .); PROVIDE (___sbss_start = .); + *(.scommon) + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + PROVIDE (__sbss_end = .); PROVIDE (___sbss_end = .); + + . = ALIGN (bsp_section_align); + } > RAM + + .bss : { + *(COMMON) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + + . = ALIGN (bsp_section_align); + + __end = .; + _end = .; + PROVIDE (end = .); + + /* + * BSP: End and size of bss section + */ + bsp_section_bss_end = .; + bsp_section_bss_size = bsp_section_bss_end - bsp_section_bss_start; + } > RAM + + /* + * BSP: Interrupt stack + */ + bsp_interrupt_stack_start = .; + bsp_interrupt_stack_end = bsp_interrupt_stack_start + 32k; + bsp_interrupt_stack_size = bsp_interrupt_stack_end - bsp_interrupt_stack_start; + . = bsp_interrupt_stack_end; + + /* + * BSP: Work area start + */ + bsp_work_area_start = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + + /DISCARD/ : { + *(.note.GNU-stack) *(.gnu_debuglink) + } + + /* + * BSP: Catch all unknown sections + */ + .nirvana : { + *(*) + } > NIRVANA +} diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/startup/linkcmds.tqm8xx b/c/src/lib/libbsp/powerpc/tqm8xx/startup/linkcmds.tqm8xx new file mode 100644 index 0000000000..69b9c32799 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/startup/linkcmds.tqm8xx @@ -0,0 +1,15 @@ +/** + * @file + * + * TQM8xx + */ + +TopRamReserved = DEFINED(TopRamReserved) ? TopRamReserved : 0; +MEMORY { + RAM : ORIGIN = 0x0, LENGTH = 128M + immr : org = 0xfa200000, l = 16K + ROM : ORIGIN = 0x40000000, LENGTH = 8M + NIRVANA : ORIGIN = 0x0, LENGTH = 0 +} + +INCLUDE linkcmds.base diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/startup/mmutlbtab.c b/c/src/lib/libbsp/powerpc/tqm8xx/startup/mmutlbtab.c new file mode 100644 index 0000000000..6dc3aea712 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/startup/mmutlbtab.c @@ -0,0 +1,103 @@ +/*===============================================================*\ +| Project: RTEMS TQM8xx BSP | ++-----------------------------------------------------------------+ +| This file has been adapted to MPC8xx by | +| Thomas Doerfler | +| Copyright (c) 2008 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | +| | +| See the other copyright notice below for the original parts. | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.com/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains the console driver | +\*===============================================================*/ +/* derived from: */ +/* + * mmutlbtab.c + * + * 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. + */ + +#include +#include +/* + * This MMU_TLB_table is used to statically initialize the Table Lookaside + * Buffers in the MMU of the TQM8xx board. + * + * We initialize the entries in both the instruction and data TLBs + * with the same values - a few bits relevant to the data TLB are unused + * in the instruction TLB. + * + * An Effective Page Number (EPN), Tablewalk Control Register (TWC) and + * Real Page Number (RPN) value are supplied in the table for each TLB entry. + * + * The instruction and data TLBs each can hold 32 entries, so _TLB_Table must + * not have more than 32 lines in it! + * + * We set up the virtual memory map so that virtual address of a + * location is equal to its real address. + */ +MMU_TLB_table_t MMU_TLB_table[] = { + /* + * DRAM: Start address 0x00000000, 128M, + * ASID=0x0, APG=0x0, not guarded memory, copyback data cache policy, + * R/W,X for all, no ASID comparison, not cache-inhibited. + * EPN TWC RPN + */ + { 0x00000200, 0x0D, 0x000009FD }, /* DRAM - PS=8M */ + { 0x00800200, 0x0D, 0x008009FD }, /* DRAM - PS=8M */ + { 0x01000200, 0x0D, 0x010009FD }, /* DRAM - PS=8M */ + { 0x01800200, 0x0D, 0x018009FD }, /* DRAM - PS=8M */ + { 0x02000200, 0x0D, 0x020009FD }, /* DRAM - PS=8M */ + { 0x02800200, 0x0D, 0x028009FD }, /* DRAM - PS=8M */ + { 0x03000200, 0x0D, 0x030009FD }, /* DRAM - PS=8M */ + { 0x03800200, 0x0D, 0x038009FD }, /* DRAM - PS=8M */ + { 0x04000200, 0x0D, 0x040009FD }, /* DRAM - PS=8M */ + { 0x04800200, 0x0D, 0x048009FD }, /* DRAM - PS=8M */ + { 0x05000200, 0x0D, 0x050009FD }, /* DRAM - PS=8M */ + { 0x05800200, 0x0D, 0x058009FD }, /* DRAM - PS=8M */ + { 0x06000200, 0x0D, 0x060009FD }, /* DRAM - PS=8M */ + { 0x06800200, 0x0D, 0x068009FD }, /* DRAM - PS=8M */ + { 0x07000200, 0x0D, 0x070009FD }, /* DRAM - PS=8M */ + { 0x07800200, 0x0D, 0x078009FD }, /* DRAM - PS=8M */ + /* + * + * (IMMR-SPRs) Dual Port RAM: Start address 0xFA200000, 16K, + * ASID=0x0, APG=0x0, guarded memory, write-through data cache policy, + * R/W,X for all, no ASID comparison, cache-inhibited. + * + * Note: We use the value in MBXA/PG2, which is also the value that + * EPPC-Bug programmed into our boards. The alternative is the value + * in MBXA/PG1: 0xFFA00000. This value might well depend on the revision + * of the firmware. + * EPN TWC RPN + */ + { 0xFA200200, 0x13, 0xFA2009FF }, /* IMMR - PS=16K */ + /* + * + * Flash: Start address 0x40000000, 8M, + * ASID=0x0, APG=0x0, not guarded memory, + * R/O,X for all, no ASID comparison, not cache-inhibited. + * EPN TWC RPN + */ + { 0x40000200, 0x0D, 0x40000CFD } /* Flash - PS=8M */ +}; + +/* + * MMU_N_TLB_Table_Entries is defined here because the size of the + * MMU_TLB_table is only known in this file. + */ +int MMU_N_TLB_Table_Entries = ( sizeof(MMU_TLB_table) / sizeof(MMU_TLB_table[0]) ); diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/startup/start.S b/c/src/lib/libbsp/powerpc/tqm8xx/startup/start.S new file mode 100644 index 0000000000..42bbdb07d2 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/startup/start.S @@ -0,0 +1,287 @@ +/*===============================================================*\ +| Project: RTEMS generic TQM8xx BSP | ++-----------------------------------------------------------------+ +| Copyright (c) 2008 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.com/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains the startup assembly code | +| it is based on the gen83xx BSP | +\*===============================================================*/ +/* $Id$ */ + +#include +#include +#include +#include + +.extern boot_card + +.section ".entry" +PUBLIC_VAR (start) +start: + + /* + * basic CPU setup: + * init MSR + */ + mfmsr r30 + SETBITS r30, r29, MSR_ME|MSR_RI + CLRBITS r30, r29, MSR_IP|MSR_EE + mtmsr r30 /* Set RI/ME, Clr EE in MSR */ + /* + * init IMMR + */ + LA r30,m8xx + mtspr immr,r30 + /* + * determine current execution address offset + */ + bl start_1 +start_1: + mflr r20 + LA r30,start_1 + sub. r20,r20,r30 + /* + * execution address offset == 0? + * then do not relocate code and data + */ + beq start_code_in_ram + /* + * ROM or relocatable startup: copy startup code to SDRAM + */ + /* get start address of text section in RAM */ + LA r29, bsp_section_text_start + /* get start address of text section in ROM (add reloc offset) */ + add r30, r20, r29 + /* get size of startup code */ + LA r28, end_reloc_startup + LA r31, bsp_section_text_start + sub 28,r28,r31 + /* copy startup code from ROM to RAM location */ + bl copy_image + + /* + * jump to code copy in SDRAM + */ + /* get compile time address of label */ + LA r29, copy_rest_of_text + mtlr r29 + blr /* now further execution RAM */ +copy_rest_of_text: + /* + * ROM or relocatable startup: copy rest of code to SDRAM + */ + /* get start address of rest of code in RAM */ + LA r29, end_reloc_startup + /* get start address of text section in ROM (add reloc offset) */ + add r30, r20, r29 + /* get size of rest of code */ + LA r28, bsp_section_text_start + LA r31, bsp_section_text_size + add r28,r28,r31 + sub r28,r28,r29 + bl copy_image /* copy text section from ROM to RAM location */ + + /* + * ROM or relocatable startup: copy data to SDRAM + */ + /* get start address of data section in RAM */ + LA r29, bsp_section_data_start + /* get start address of data section in ROM (add reloc offset) */ + add r30, r20, r29 + /* get size of RAM image */ + LA r28, bsp_section_data_size + /* copy initialized data section from ROM to RAM location */ + bl copy_image + +start_code_in_ram: + + /* + * ROM/RAM startup: clear bss in SDRAM + */ + LA r3, bsp_section_bss_start /* get start address of bss section */ + LWI r4, bsp_section_bss_size /* get size of bss section */ + bl mpc8xx_zero_4 /* Clear the bss section */ + /* + * call boot_card + */ + + /* Set stack pointer (common for RAM/ROM startup) */ + LA r1, bsp_section_text_start + addi r1, r1, -0x10 /* Set up stack pointer = beginning of text section - 0x10 */ + + /* Create NULL */ + li r0, 0 + + /* Return address */ + stw r0, 4(r1) + + /* Back chain */ + stw r0, 0(r1) + + /* Read-only small data */ + LA r2, _SDA2_BASE_ + + /* Read-write small data */ + LA r13, _SDA_BASE_ + + /* + * init some CPU stuff + */ + bl SYM (_InitTQM8xx) + +/* clear arguments and do further init. in C (common for RAM/ROM startup) */ + + /* Clear argc, argv and envp */ + xor r3, r3, r3 + xor r4, r4, r4 + xor r5, r5, r5 + + bl SYM (boot_card) /* Call the first C routine */ + +twiddle: + /* We don't expect to return from boot_card but if we do */ + /* wait here for watchdog to kick us into hard reset */ + b twiddle + +copy_with_watchdog: + addi r5,r5,16 + rlwinm. r5,r5,28,4,31 + mtctr r5 + +copy_loop: + lwz r6,0(r3) + lwz r7,4(r3) + lwz r8,8(r3) + lwz r9,12(r3) + stw r6,0(r4) + stw r7,4(r4) + stw r8,8(r4) + stw r9,12(r4) + addi r3,r3,16 + addi r4,r4,16 + sth r28,14(r30) + sth r29,14(r30) + bdnz+ copy_loop + blr + +copy_image: + /* + * watchdog: + * r26 = immr + * r25 = watchdog magic 1 + * r24 = watchdog magic 2 + */ + mfimmr r26 + rlwinm. r26,r26,0,0,15 + li r25,0x556c + li r24,0xffffaa39 + + mr r27, r28 /* determine number of 4word chunks */ + srwi r28, r28, 4 + mtctr r28 + + slwi r28, r28, 4 + sub r27, r27, r28 /* determine residual bytes */ +copy_image_4word: + lwz r20, 0(r30) /* fetch data */ + lwz r21, 4(r30) + lwz r22, 8(r30) + lwz r23,12(r30) + stw r20, 0(r29) /* store data */ + stw r21, 4(r29) + stw r22, 8(r29) + stw r23,12(r29) + + addi r30, r30, 0x10 /* increment source pointer */ + addi r29, r29, 0x10 /* increment destination pointer */ + /* + * trigger watchdog + */ + sth r25,14(r26) + sth r24,14(r26) + + bdnz copy_image_4word /* decrement ctr and branch if not 0 */ + + cmpwi r27, 0x00 /* copy image finished ? */ + beq copy_image_end; + mtctr r27 /* reload counter for residual bytes */ +copy_image_byte: + lswi r28, r30, 0x01 + + stswi r28, r29, 0x01 /* do byte copy ROM -> RAM */ + + + addi r30, r30, 0x01 /* increment source pointer */ + addi r29, r29, 0x01 /* increment destination pointer */ + + bdnz copy_image_byte /* decrement ctr and branch if not 0 */ + +copy_image_end: + blr + + +/** + * @fn int mpc8xx_zero_4( void *dest, size_t n) + * + * @brief Zero all @a n bytes starting at @a dest with 4 byte writes. + * + * The address @a dest has to be aligned on 4 byte boundaries. The size @a n + * must be evenly divisible by 4. + */ +GLOBAL_FUNCTION mpc8xx_zero_4 + /* Create zero */ + xor r0, r0, r0 + + /* Set offset */ + xor r5, r5, r5 + + /* Loop counter for the first bytes up to 16 bytes */ + rlwinm. r9, r4, 30, 30, 31 + beq mpc8xx_zero_4_more + mtctr r9 + +mpc8xx_zero_4_head: + + stwx r0, r3, r5 + addi r5, r5, 4 + bdnz mpc8xx_zero_4_head + +mpc8xx_zero_4_more: + + /* More than 16 bytes? */ + srwi. r9, r4, 4 + beqlr + mtctr r9 + + /* Set offsets */ + addi r6, r5, 4 + addi r7, r5, 8 + addi r8, r5, 12 + +mpc8xx_zero_4_tail: + + stwx r0, r3, r5 + addi r5, r5, 16 + stwx r0, r3, r6 + addi r6, r6, 16 + stwx r0, r3, r7 + addi r7, r7, 16 + stwx r0, r3, r8 + addi r8, r8, 16 + bdnz mpc8xx_zero_4_tail + + /* Return */ + blr + +end_reloc_startup: diff --git a/c/src/lib/libbsp/powerpc/tqm8xx/timer/timer.c b/c/src/lib/libbsp/powerpc/tqm8xx/timer/timer.c new file mode 100644 index 0000000000..1df80461d1 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/tqm8xx/timer/timer.c @@ -0,0 +1,110 @@ +/*===============================================================*\ +| Project: RTEMS TQM8xx BSP | ++-----------------------------------------------------------------+ +| This file has been adapted to MPC8xx by | +| Thomas Doerfler | +| Copyright (c) 2008 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | +| | +| See the other copyright notice below for the original parts. | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.com/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains the console driver | +\*===============================================================*/ +/* + * Timer_init() + * + * Use TIMER 1 and TIMER 2 for Timing Test Suite + * + * this is derived from "timer.c" available in the m68k/gen68360 BSP + * adapted by Thomas Doerfler + * + * $Id$ + */ + +/* + * + * Input parameters: NONE + * + * Output parameters: NONE + * + * NOTE: It is important that the timer start/stop overhead be + * determined when porting or modifying this code. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#include +#include +#include + +void +Timer_initialize (void) +{ + /* + * Reset timers 1 and 2 + */ + m8xx.tgcr &= ~0x00FF; + m8xx.tcn1 = 0; + m8xx.tcn2 = 0; + m8xx.ter1 = 0xFFFF; + m8xx.ter2 = 0xFFFF; + + /* + * Cascade timers 1 and 2 + */ + m8xx.tgcr |= M8xx_TGCR_CAS2; + + /* + * Configure timers 1 and 2 to a single 32-bit, BUS_clock timer. + */ + m8xx.tmr2 = (0 << 8) | 0x2; + m8xx.tmr1 = 0; + + /* + * Start the timers + */ + m8xx.tgcr |= 0x0011; +} + +/* + * Return timer value in microsecond units + */ +int +Read_timer (void) +{ + extern unsigned int BSP_bus_frequency; + int retval; + retval = *(uint32_t*)&m8xx.tcn1; + retval = retval * 1000000LL / BSP_bus_frequency; + return retval; +} + +/* + * Empty function call used in loops to measure basic cost of looping + * in Timing Test Suite. + */ +rtems_status_code +Empty_function (void) +{ + return RTEMS_SUCCESSFUL; +} + +void +Set_find_average_overhead(bool find_flag) +{ +} -- cgit v1.2.3