summaryrefslogtreecommitdiffstats
path: root/bsps
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-20 12:08:42 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-20 13:52:19 +0200
commite0dd8a5ad830798bc8082b03b8c42c32fb9660e0 (patch)
treed147bfc4d670fcdfbd2e2d2e75eb209f92e07df1 /bsps
parentbsps: Move startup files to bsps (diff)
downloadrtems-e0dd8a5ad830798bc8082b03b8c42c32fb9660e0.tar.bz2
bsps: Move benchmark timer to bsps
This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'bsps')
-rw-r--r--bsps/arm/csb336/btimer/btimer.c93
-rw-r--r--bsps/arm/csb337/btimer/btimer.c91
-rw-r--r--bsps/arm/edb7312/btimer/btimer.c80
-rw-r--r--bsps/arm/gumstix/btimer/btimer.c75
-rw-r--r--bsps/arm/lpc176x/btimer/btimer.c407
-rw-r--r--bsps/arm/rtl22xx/btimer/btimer.c65
-rw-r--r--bsps/arm/rtl22xx/btimer/lpc_timer.h48
-rw-r--r--bsps/arm/smdk2410/btimer/btimer.c100
-rw-r--r--bsps/epiphany/epiphany_sim/btimer/btimer.c109
-rw-r--r--bsps/i386/pc386/btimer/btimer.c552
-rw-r--r--bsps/i386/pc386/btimer/timerisr.S56
-rw-r--r--bsps/lm32/shared/btimer/btimer.c111
-rw-r--r--bsps/m32c/m32cbsp/btimer/btimer.c69
-rw-r--r--bsps/m68k/av5282/btimer/btimer.c34
-rw-r--r--bsps/m68k/gen68340/btimer/btimer.c256
-rw-r--r--bsps/m68k/gen68360/btimer/btimer.c83
-rw-r--r--bsps/m68k/genmcf548x/btimer/btimer.c83
-rw-r--r--bsps/m68k/mcf52235/btimer/btimer.c39
-rw-r--r--bsps/m68k/mcf5225x/btimer/btimer.c39
-rw-r--r--bsps/m68k/mcf5235/btimer/btimer.c34
-rw-r--r--bsps/m68k/mcf5329/btimer/btimer.c39
-rw-r--r--bsps/m68k/mrm332/btimer/btimer.c60
-rw-r--r--bsps/m68k/mvme147/btimer/btimer.c67
-rw-r--r--bsps/m68k/mvme147/btimer/timerisr.S26
-rw-r--r--bsps/m68k/mvme162/btimer/btimer.c73
-rw-r--r--bsps/m68k/mvme162/btimer/timerisr.S44
-rw-r--r--bsps/m68k/mvme167/btimer/btimer.c139
-rw-r--r--bsps/m68k/mvme167/btimer/timerisr.S50
-rw-r--r--bsps/m68k/uC5282/btimer/btimer.c47
-rw-r--r--bsps/mips/csb350/btimer/btimer.c57
-rw-r--r--bsps/mips/jmr3904/btimer/btimer.c67
-rw-r--r--bsps/nios2/nios2_iss/btimer/btimer.c137
-rw-r--r--bsps/no_cpu/no_bsp/btimer/btimer.c92
-rw-r--r--bsps/no_cpu/no_bsp/btimer/timerisr.c38
-rw-r--r--bsps/or1k/generic_or1k/btimer/btimer.c64
-rw-r--r--bsps/powerpc/qoriq/btimer/btimer.c42
-rw-r--r--bsps/powerpc/tqm8xx/btimer/btimer.c101
-rw-r--r--bsps/riscv/riscv_generic/btimer/btimer.c70
-rw-r--r--bsps/sh/gensh1/btimer/btimer.c195
-rw-r--r--bsps/sh/gensh2/btimer/btimer.c191
-rw-r--r--bsps/sh/gensh4/btimer/btimer.c269
-rw-r--r--bsps/sparc/erc32/btimer/btimer.c81
-rw-r--r--bsps/sparc/leon2/btimer/btimer.c83
-rw-r--r--bsps/sparc/leon3/btimer/btimer.c85
-rw-r--r--bsps/sparc/leon3/btimer/watchdog.c90
-rw-r--r--bsps/sparc/shared/btimer/gptimer.c544
-rw-r--r--bsps/sparc/shared/btimer/tlib.c77
-rw-r--r--bsps/sparc/shared/btimer/tlib_ckinit.c453
48 files changed, 5705 insertions, 0 deletions
diff --git a/bsps/arm/csb336/btimer/btimer.c b/bsps/arm/csb336/btimer/btimer.c
new file mode 100644
index 0000000000..66ff4a0bf4
--- /dev/null
+++ b/bsps/arm/csb336/btimer/btimer.c
@@ -0,0 +1,93 @@
+/**
+ * @file
+ * @brief Cogent CSB336 Timer driver
+ *
+ * This uses timer 2 for timing measurments.
+ */
+
+/*
+ * Copyright (c) 2004 Cogent Computer Systems
+ * Written by Jay Monkman <jtm@lopingdog.com>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <rtems/btimer.h>
+#include <mc9328mxl.h>
+
+uint32_t g_start;
+uint32_t g_freq;
+
+bool benchmark_timer_find_average_overhead;
+
+
+/*
+ * Set up Timer 1
+ */
+void benchmark_timer_initialize( void )
+{
+ MC9328MXL_TMR2_TCTL = (MC9328MXL_TMR_TCTL_CLKSRC_PCLK1 |
+ MC9328MXL_TMR_TCTL_FRR |
+ MC9328MXL_TMR_TCTL_TEN);
+ /* set prescaler to 1 (register value + 1) */ \
+ MC9328MXL_TMR2_TPRER = 0;
+
+ /* get freq of counter in KHz */
+ g_freq = get_perclk1_freq() / 1000;
+
+ g_start = MC9328MXL_TMR2_TCN;
+}
+
+/*
+ * The following controls the behavior of benchmark_timer_read().
+ *
+ * AVG_OVEREHAD is the overhead for starting and stopping the timer. It
+ * is usually deducted from the number returned.
+ *
+ * LEAST_VALID is the lowest number this routine should trust. Numbers
+ * below this are "noise" and zero is returned.
+ */
+
+#define AVG_OVERHEAD 0 /* It typically takes X.X microseconds */
+ /* (Y countdowns) to start/stop the timer. */
+ /* This value is in microseconds. */
+#define LEAST_VALID 1 /* Don't trust a clicks value lower than this */
+
+benchmark_timer_t benchmark_timer_read( void )
+{
+ uint32_t t;
+ unsigned long long total;
+
+ t = MC9328MXL_TMR2_TCN;
+ /*
+ * Total is calculated by taking into account the number of timer overflow
+ * interrupts since the timer was initialized and clicks since the last
+ * interrupts.
+ */
+
+ total = (t - g_start);
+
+ /* convert to nanoseconds */
+ total = (total * 1000)/ g_freq;
+
+ if ( benchmark_timer_find_average_overhead == 1 ) {
+ return (int) total;
+ } else if ( total < LEAST_VALID ) {
+ return 0;
+ }
+ /*
+ * Somehow convert total into microseconds
+ */
+
+ return (total - AVG_OVERHEAD);
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
+
diff --git a/bsps/arm/csb337/btimer/btimer.c b/bsps/arm/csb337/btimer/btimer.c
new file mode 100644
index 0000000000..c65dd8096a
--- /dev/null
+++ b/bsps/arm/csb337/btimer/btimer.c
@@ -0,0 +1,91 @@
+/**
+ * @file
+ * @brief Cogent CSB337 Timer driver
+ *
+ * This uses timer 0 for timing measurments.
+ */
+
+/*
+ * Copyright (c) 2004 by Jay Monkman <jtm@lopingdog.com>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <rtems.h>
+#include <rtems/btimer.h>
+#include <at91rm9200.h>
+#include <at91rm9200_pmc.h>
+
+uint16_t tstart;
+bool benchmark_timer_find_average_overhead;
+uint32_t tick_time;
+/*
+ * Set up TC0 -
+ * timer_clock2 (MCK/8)
+ * capture mode - this shouldn't matter
+ */
+void benchmark_timer_initialize( void )
+{
+ uint32_t tmr_freq;
+
+ /* since we are using timer_clock2, divide mck by 8 */
+ tmr_freq = at91rm9200_get_mck() / 8;
+
+ TC_TC0_REG(TC_CMR) = TC_CMR_TCCLKS(1); /* timer_clock2 */
+ TC_TC0_REG(TC_CCR) = (TC_CCR_CLKEN /* enable the counter */
+ | TC_CCR_SWTRG); /* start it up */
+
+ /* tick time in nanoseconds */
+ tick_time = 1000000000/tmr_freq;
+
+}
+
+/*
+ * The following controls the behavior of benchmark_timer_read().
+ *
+ * AVG_OVEREHAD is the overhead for starting and stopping the timer. It
+ * is usually deducted from the number returned.
+ *
+ * LEAST_VALID is the lowest number this routine should trust. Numbers
+ * below this are "noise" and zero is returned.
+ */
+
+#define AVG_OVERHEAD 0 /* It typically takes X.X microseconds */
+ /* (Y countdowns) to start/stop the timer. */
+ /* This value is in microseconds. */
+#define LEAST_VALID 1 /* Don't trust a clicks value lower than this */
+
+benchmark_timer_t benchmark_timer_read( void )
+{
+ uint16_t t;
+ uint32_t total;
+ t = TC_TC0_REG(TC_CV);
+
+ /*
+ * Total is calculated by taking into account the number of timer overflow
+ * interrupts since the timer was initialized and clicks since the last
+ * interrupts.
+ */
+
+ total = t * tick_time;
+
+ if ( benchmark_timer_find_average_overhead == 1 )
+ return total; /* in nanosecond units */
+ else {
+ if ( total < LEAST_VALID )
+ return 0; /* below timer resolution */
+ /*
+ * Somehow convert total into microseconds
+ */
+ return (total - AVG_OVERHEAD);
+ }
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
+
diff --git a/bsps/arm/edb7312/btimer/btimer.c b/bsps/arm/edb7312/btimer/btimer.c
new file mode 100644
index 0000000000..b795122ff3
--- /dev/null
+++ b/bsps/arm/edb7312/btimer/btimer.c
@@ -0,0 +1,80 @@
+/*
+ * Cirrus EP7312 Timer driver
+ *
+ * Copyright (c) 2002 by Jay Monkman <jtm@smoothsmoothie.com>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ *
+ * Notes:
+ * This file manages the benchmark timer used by the RTEMS Timing Test
+ * Suite. Each measured time period is demarcated by calls to
+ * benchmark_timer_initialize() and benchmark_timer_read(). benchmark_timer_read() usually returns
+ * the number of microseconds since benchmark_timer_initialize() exitted.
+ *
+ * It is important that the timer start/stop overhead be determined
+ * when porting or modifying this code.
+*/
+
+#include <rtems.h>
+#include <bsp.h>
+#include <rtems/btimer.h>
+#include <ep7312.h>
+
+uint16_t tstart;
+bool benchmark_timer_find_average_overhead;
+
+void benchmark_timer_initialize( void )
+{
+ *EP7312_SYSCON1 |= EP7312_SYSCON1_TC2_512KHZ;
+ *EP7312_TC2D = 0xffff;
+}
+
+/*
+ * The following controls the behavior of benchmark_timer_read().
+ *
+ * AVG_OVEREHAD is the overhead for starting and stopping the timer. It
+ * is usually deducted from the number returned.
+ *
+ * LEAST_VALID is the lowest number this routine should trust. Numbers
+ * below this are "noise" and zero is returned.
+ */
+
+#define AVG_OVERHEAD 0 /* It typically takes X.X microseconds */
+ /* (Y countdowns) to start/stop the timer. */
+ /* This value is in microseconds. */
+#define LEAST_VALID 1 /* Don't trust a clicks value lower than this */
+
+benchmark_timer_t benchmark_timer_read( void )
+{
+ uint16_t t;
+ uint32_t total;
+ t = *EP7312_TC2D;
+
+ /*
+ * Total is calculated by taking into account the number of timer overflow
+ * interrupts since the timer was initialized and clicks since the last
+ * interrupts.
+ */
+
+ total = (uint32_t)0x0000ffff - t; /* result is 1/512000 = ~2 uS */
+ total = (total * 1953) / 1000; /* convert to uS */
+ if ( benchmark_timer_find_average_overhead == true )
+ return total; /* in XXX microsecond units */
+ else {
+ if ( total < LEAST_VALID )
+ return 0; /* below timer resolution */
+ /*
+ * Somehow convert total into microseconds
+ */
+ return (total - AVG_OVERHEAD);
+ }
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(
+ bool find_flag
+)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/arm/gumstix/btimer/btimer.c b/bsps/arm/gumstix/btimer/btimer.c
new file mode 100644
index 0000000000..7eb3d5b811
--- /dev/null
+++ b/bsps/arm/gumstix/btimer/btimer.c
@@ -0,0 +1,75 @@
+/**
+ * @file
+ * @brief PXA255 timer
+ */
+
+/*
+ * PXA255 timer by Yang Xi <hiyangxi@gmail.com>
+ * Copyright (c) 2004 by Jay Monkman <jtm@lopingdog.com>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <rtems.h>
+#include <rtems/btimer.h>
+#include <pxa255.h>
+
+uint32_t tstart;
+static uint32_t tick_time;
+bool benchmark_timer_find_average_overhead;
+
+bool benchmark_timer_is_initialized = false;
+
+/*
+ * Use the timer count register to measure.
+ * The frequency of it is 3.4864MHZ
+ * The longest period we are able to capture is 4G/3.4864MHZ
+ */
+void benchmark_timer_initialize(void)
+{
+ tick_time = XSCALE_OS_TIMER_TCR;
+}
+
+/*
+ * The following controls the behavior of Read_timer().
+ *
+ * AVG_OVEREHAD is the overhead for starting and stopping the timer. It
+ * is usually deducted from the number returned.
+ *
+ * LEAST_VALID is the lowest number this routine should trust. Numbers
+ * below this are "noise" and zero is returned.
+ */
+
+#define AVG_OVERHEAD 0 /* It typically takes X.X microseconds */
+ /* (Y countdowns) to start/stop the timer. */
+ /* This value is in microseconds. */
+#define LEAST_VALID 1 /* Don't trust a clicks value lower than this */
+
+benchmark_timer_t benchmark_timer_read(void)
+{
+
+ uint32_t total;
+ total = XSCALE_OS_TIMER_TCR;
+ if(total>=tick_time)
+ total -= tick_time;
+ else
+ total += 0xffffffff - tick_time; /*Round up but not overflow*/
+
+ if ( benchmark_timer_find_average_overhead == true )
+ return total; /*Counter cycles*/
+
+ if ( total < LEAST_VALID )
+ return 0; /* below timer resolution */
+
+ return total;
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(
+ bool find_flag
+)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/arm/lpc176x/btimer/btimer.c b/bsps/arm/lpc176x/btimer/btimer.c
new file mode 100644
index 0000000000..36c720b4fb
--- /dev/null
+++ b/bsps/arm/lpc176x/btimer/btimer.c
@@ -0,0 +1,407 @@
+/**
+ * @file timer.c
+ *
+ * @ingroup lpc176x
+ *
+ * @brief Timer controller for the mbed lpc1768 board.
+ */
+
+/*
+ * Copyright (c) 2014 Taller Technologies.
+ *
+ * @author Boretto Martin (martin.boretto@tallertechnologies.com)
+ * @author Diaz Marcos (marcos.diaz@tallertechnologies.com)
+ * @author Lenarduzzi Federico (federico.lenarduzzi@tallertechnologies.com)
+ * @author Daniel Chicco (daniel.chicco@tallertechnologies.com)
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <stdio.h>
+#include <rtems/status-checks.h>
+#include <bsp.h>
+#include <bsp/irq.h>
+#include <bsp/io.h>
+#include <bsp/timer.h>
+
+/**
+ * @brief Represents all the timers.
+ */
+const lpc176x_timer timers[ LPC176X_TIMER_COUNT ] =
+{
+ {
+ .device = (lpc176x_timer_device *) LPC176X_TMR0_BASE_ADDR,
+ .module = LPC176X_MODULE_TIMER_0,
+ .pinselcap = LPC176X_TIMER0_CAPTURE_PORTS,
+ .pinselemat = LPC176X_TIMER0_EMATCH_PORTS,
+ },
+ {
+ .device = (lpc176x_timer_device *) LPC176X_TMR1_BASE_ADDR,
+ .module = LPC176X_MODULE_TIMER_1,
+ .pinselcap = LPC176X_TIMER1_CAPTURE_PORTS,
+ .pinselemat = LPC176X_TIMER1_EMATCH_PORTS,
+ },
+ {
+ .device = (lpc176x_timer_device *) LPC176X_TMR2_BASE_ADDR,
+ .module = LPC176X_MODULE_TIMER_2,
+ .pinselcap = LPC176X_TIMER2_CAPTURE_PORTS,
+ .pinselemat = LPC176X_TIMER2_EMATCH_PORTS,
+ },
+ {
+ .device = (lpc176x_timer_device *) LPC176X_TMR3_BASE_ADDR,
+ .module = LPC176X_MODULE_TIMER_3,
+ .pinselcap = LPC176X_TIMER3_CAPTURE_PORTS,
+ .pinselemat = LPC176X_TIMER3_EMATCH_PORTS,
+ }
+};
+
+/**
+ * @brief Represents all the functions according to the timers.
+ */
+lpc176x_timer_functions functions_vector[ LPC176X_TIMER_COUNT ] =
+{
+ {
+ .funct_vector = NULL
+ },
+ {
+ .funct_vector = NULL
+ },
+ {
+ .funct_vector = NULL
+ },
+ {
+ .funct_vector = NULL
+ }
+};
+
+/**
+ * @brief Calls the corresponding interrupt function and pass the timer
+ * as parameter.
+ *
+ * @param timer The specific device.
+ * @param interruptnumber Interrupt number.
+ */
+static inline void lpc176x_call_desired_isr(
+ const lpc176x_timer_number number,
+ const lpc176x_isr_function interruptfunction
+)
+{
+ if ( ( *functions_vector[ number ].funct_vector )[ interruptfunction ] !=
+ NULL ) {
+ ( *functions_vector[ number ].funct_vector )[ interruptfunction ]( number );
+ }
+
+ /* else implies that the function vector points NULL. Also,
+ there is nothing to do. */
+}
+
+/**
+ * @brief Gets true if the selected interrupt is pending
+ *
+ * @param number: the number of the timer.
+ * @param interrupt: the interrupt we are checking for.
+ * @return TRUE if the interrupt is pending.
+ */
+static inline bool lpc176x_timer_interrupt_is_pending(
+ const lpc176x_timer_number tnumber,
+ const lpc176x_isr_function function
+)
+{
+ assert( ( tnumber < LPC176X_TIMER_COUNT )
+ && ( function < LPC176X_ISR_FUNCTIONS_COUNT ) );
+
+ return ( timers[ tnumber ].device->IR &
+ LPC176X_TIMER_INTERRUPT_SOURCE_BIT( function ) );
+}
+
+/**
+ * @brief Resets interrupt status for the selected interrupt
+ *
+ * @param tnumber: the number of the timer
+ * @param interrupt: the interrupt we are resetting
+ */
+static inline void lpc176x_timer_reset_interrupt(
+ const lpc176x_timer_number tnumber,
+ const lpc176x_isr_function function
+)
+{
+ assert( ( tnumber < LPC176X_TIMER_COUNT )
+ && ( function < LPC176X_ISR_FUNCTIONS_COUNT ) );
+ timers[ tnumber ].device->IR =
+ LPC176X_TIMER_INTERRUPT_SOURCE_BIT( function );
+}
+
+inline rtems_status_code lpc176x_timer_reset(
+ const lpc176x_timer_number tnumber )
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( tnumber < LPC176X_TIMER_COUNT ) {
+ timers[ tnumber ].device->TCR = LPC176X_TIMER_RESET;
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the timer number is invalid. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+inline rtems_status_code lpc176x_timer_set_mode(
+ const lpc176x_timer_number tnumber,
+ const lpc176x_timer_mode mode
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( tnumber < LPC176X_TIMER_COUNT ) {
+ timers[ tnumber ].device->CTCR = mode;
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the timer number is invalid. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+inline rtems_status_code lpc176x_timer_start(
+ const lpc176x_timer_number tnumber )
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( tnumber < LPC176X_TIMER_COUNT ) {
+ timers[ tnumber ].device->TCR = LPC176X_TIMER_START;
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the timer number is invalid. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+inline rtems_status_code lpc176x_timer_is_started(
+ const lpc176x_timer_number tnumber,
+ bool *is_started
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( tnumber < LPC176X_TIMER_COUNT ) {
+ *is_started = ( timers[ tnumber ].device->TCR & LPC176X_TIMER_START ) ==
+ LPC176X_TIMER_START;
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the timer number is invalid. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+inline rtems_status_code lpc176x_timer_set_resolution(
+ const lpc176x_timer_number tnumber,
+ const lpc176x_microseconds resolution
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( tnumber < LPC176X_TIMER_COUNT ) {
+ timers[ tnumber ].device->PR = ( LPC176X_CCLK /
+ LPC176X_TIMER_PRESCALER_DIVISOR ) *
+ resolution;
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the timer number is invalid. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+rtems_status_code lpc176x_timer_match_config(
+ const lpc176x_timer_number tnumber,
+ const lpc176x_match_port match_port,
+ const lpc176x_match_function function,
+ const uint32_t match_value
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( ( tnumber < LPC176X_TIMER_COUNT )
+ && ( match_port < LPC176X_EMATCH_PORTS_COUNT )
+ && ( function < LPC176X_TIMER_MATCH_FUNCTION_COUNT ) ) {
+ timers[ tnumber ].device->MCR =
+ LPC176X_SET_MCR( timers[ tnumber ].device->MCR,
+ match_port, function );
+ timers[ tnumber ].device->MR[ match_port ] = match_value;
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the timer number, or a match port or a function
+ is invalid. Also, an invalid number is returned. */
+
+ return status_code;
+}
+
+inline rtems_status_code lpc176x_timer_capture_config(
+ const lpc176x_timer_number tnumber,
+ const lpc176x_capture_port capture_port,
+ const lpc176x_capture_function function
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( ( tnumber < LPC176X_TIMER_COUNT )
+ && ( capture_port < LPC176X_CAPTURE_PORTS_COUNT )
+ && ( function < LPC176X_TIMER_CAPTURE_FUNCTION_COUNT ) ) {
+ timers[ tnumber ].device->CCR =
+ LPC176X_SET_CCR( timers[ tnumber ].device->CCR,
+ capture_port, function );
+ lpc176x_pin_select( timers[ tnumber ].pinselcap[ capture_port ],
+ LPC176X_PIN_FUNCTION_11 );
+ }
+
+ /* else implies that the timer number or the capture port is invalid. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+inline rtems_status_code lpc176x_timer_external_match_config(
+ const lpc176x_timer_number number,
+ const lpc176x_match_port match_port,
+ const lpc176x_ext_match_function function
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( ( number < LPC176X_TIMER_COUNT )
+ && ( match_port < LPC176X_EMATCH_PORTS_COUNT ) ) {
+ timers[ number ].device->EMR =
+ LPC176X_SET_EMR( timers[ number ].device->EMR,
+ match_port, function );
+ lpc176x_pin_select( timers[ number ].pinselemat[ match_port ],
+ LPC176X_PIN_FUNCTION_11 );
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the timer number or the match port is invalid. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+inline uint32_t lpc176x_timer_get_capvalue(
+ const lpc176x_timer_number number,
+ const lpc176x_capture_port capture_port
+)
+{
+ assert( ( number < LPC176X_TIMER_COUNT )
+ && ( capture_port < LPC176X_CAPTURE_PORTS_COUNT ) );
+
+ return timers[ number ].device->CR[ capture_port ];
+}
+
+inline uint32_t lpc176x_timer_get_timer_value(
+ const lpc176x_timer_number tnumber )
+{
+ assert( tnumber < LPC176X_TIMER_COUNT );
+
+ return timers[ tnumber ].device->TC;
+}
+
+inline rtems_status_code lpc176x_timer_set_timer_value(
+ const lpc176x_timer_number tnumber,
+ const uint32_t timer_value
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( tnumber < LPC176X_TIMER_COUNT ) {
+ timers[ tnumber ].device->TC = timer_value;
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the timer number is invalid. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+void lpc176x_timer_isr( void *arg )
+{
+ const lpc176x_timer_number tnumber = (lpc176x_timer_number) arg;
+
+ if ( tnumber < LPC176X_TIMER_COUNT ) {
+ lpc176x_isr_function i;
+
+ for ( i = 0; i < LPC176X_ISR_FUNCTIONS_COUNT; ++i ) {
+ if ( lpc176x_timer_interrupt_is_pending( tnumber, i ) ) {
+ lpc176x_call_desired_isr( tnumber, i );
+ lpc176x_timer_reset_interrupt( tnumber, i );
+ }
+
+ /* else implies that the current timer is not pending. Also,
+ there is nothing to do. */
+ }
+ }
+
+ /* else implies that the timer number is not valid. Also,
+ there is nothing to do. */
+}
+
+rtems_status_code lpc176x_timer_init( const lpc176x_timer_number tnumber )
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( tnumber < LPC176X_TIMER_COUNT ) {
+ status_code = lpc176x_module_enable( timers[ tnumber ].module,
+ LPC176X_MODULE_PCLK_DEFAULT );
+ RTEMS_CHECK_SC( status_code, "Enabling the timer module." );
+
+ status_code = lpc176x_timer_reset( tnumber );
+ status_code = lpc176x_timer_set_mode( tnumber,
+ LPC176X_TIMER_MODE_TIMER );
+ status_code = lpc176x_timer_set_resolution( tnumber,
+ LPC176X_TIMER_DEFAULT_RESOLUTION );
+
+ timers[ tnumber ].device->MCR = LPC176X_TIMER_CLEAR_FUNCTION;
+ timers[ tnumber ].device->CCR = LPC176X_TIMER_CLEAR_FUNCTION;
+ timers[ tnumber ].device->EMR = LPC176X_TIMER_CLEAR_FUNCTION;
+ }
+
+ /* else implies that the timer number is not valid. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+rtems_status_code lpc176x_timer_init_with_interrupt(
+ const lpc176x_timer_number tnumber,
+ const lpc176x_isr_funct_vector *const vector
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ char isrname[ LPC176X_ISR_NAME_STRING_SIZE ];
+
+ snprintf( isrname, LPC176X_ISR_NAME_STRING_SIZE, "TimerIsr%d", tnumber );
+
+ if ( tnumber < LPC176X_TIMER_COUNT && vector != NULL ) {
+ functions_vector[ tnumber ].funct_vector = vector;
+
+ status_code = lpc176x_timer_init( tnumber );
+ status_code = rtems_interrupt_handler_install(
+ LPC176X_TIMER_VECTOR_NUMBER( tnumber ),
+ isrname,
+ RTEMS_INTERRUPT_UNIQUE,
+ lpc176x_timer_isr,
+ (void *) tnumber );
+ }
+
+ return status_code;
+} \ No newline at end of file
diff --git a/bsps/arm/rtl22xx/btimer/btimer.c b/bsps/arm/rtl22xx/btimer/btimer.c
new file mode 100644
index 0000000000..ad73aeda3c
--- /dev/null
+++ b/bsps/arm/rtl22xx/btimer/btimer.c
@@ -0,0 +1,65 @@
+/**
+ * @file
+ * @brief RTL22xx board Timer driver
+ *
+ * This uses Timer1 for timing measurments.
+ */
+
+/*
+ * By Ray Xu <rayx.cn@gmail.com>, modify form Mc9328mxl RTEMS DSP
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <rtems.h>
+#include <rtems/btimer.h>
+#include <lpc22xx.h>
+#include "lpc_timer.h"
+
+uint32_t g_start;
+uint32_t g_freq;
+
+bool benchmark_timer_find_average_overhead;
+
+
+/*
+ * Set up Timer 1
+ */
+void benchmark_timer_initialize( void )
+{
+ g_freq = LPC22xx_Fpclk / 1000;
+}
+
+/*
+ * The following controls the behavior of benchmark_timer_read().
+ *
+ * AVG_OVEREHAD is the overhead for starting and stopping the timer. It
+ * is usually deducted from the number returned.
+ *
+ * LEAST_VALID is the lowest number this routine should trust. Numbers
+ * below this are "noise" and zero is returned.
+ */
+
+#define AVG_OVERHEAD 0 /* It typically takes X.X microseconds */
+ /* (Y countdowns) to start/stop the timer. */
+ /* This value is in microseconds. */
+#define LEAST_VALID 1 /* Don't trust a clicks value lower than this */
+
+benchmark_timer_t benchmark_timer_read( void )
+{
+ return (T0TC/(LPC22xx_Fpclk/1000000));
+ /*
+ * Total is calculated by taking into account the number of timer overflow
+ * interrupts since the timer was initialized and clicks since the last
+ * interrupts.
+ */
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
+
diff --git a/bsps/arm/rtl22xx/btimer/lpc_timer.h b/bsps/arm/rtl22xx/btimer/lpc_timer.h
new file mode 100644
index 0000000000..364812ddb8
--- /dev/null
+++ b/bsps/arm/rtl22xx/btimer/lpc_timer.h
@@ -0,0 +1,48 @@
+#ifndef __LPC_TIMER_H
+#define __LPC_TIMER_H
+
+/*************************************************************************
+ *
+ * File name : Timer.h
+ *
+ **************************************************************************/
+
+/* Timer Control register bit descriptions */
+#define TCR_ENABLE_BIT 0
+#define TCR_RESET_BIT 1
+
+// The channel name which is used in matching, in fact they represent
+// corresponding Match Register
+#define CH_MAXNUM 4
+#define CH0 0
+#define CH1 1
+#define CH2 2
+#define CH3 3
+
+// The channel name which is used in capturing, in fact they represent
+// corresponding Capture Register
+#define CPCH_MAXNUM 4
+#define CPCH0 0
+#define CPCH1 1
+#define CPCH2 2
+#define CPCH3 3
+
+//The actions when matching
+#define TimerAction_Interrupt 0x1
+#define TimerAction_ResetTimer 0x2
+#define TimerAction_StopTimer 0x4
+
+//Interrupt source type
+#define TIMERMR0Int 0x01
+#define TIMERMR1Int 0x02
+#define TIMERMR2Int 0x04
+#define TIMERMR3Int 0x08
+#define TIMERCR0Int 0x10
+#define TIMERCR1Int 0x20
+#define TIMERCR2Int 0x40
+#define TIMERCR3Int 0x80
+
+#define TIMERALLInt 0xFF
+
+#endif //__LPC_Timer_H
+
diff --git a/bsps/arm/smdk2410/btimer/btimer.c b/bsps/arm/smdk2410/btimer/btimer.c
new file mode 100644
index 0000000000..2bc599df75
--- /dev/null
+++ b/bsps/arm/smdk2410/btimer/btimer.c
@@ -0,0 +1,100 @@
+/**
+ * @file
+ * @brief S3C2400 Timer driver
+ *
+ * This uses timer 1 for timing measurments.
+ */
+
+/*
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <rtems.h>
+#include <rtems/btimer.h>
+#include <s3c24xx.h>
+
+uint32_t g_start;
+uint32_t g_freq;
+
+bool benchmark_timer_find_average_overhead;
+
+
+/*
+ * Set up Timer 1
+ */
+void benchmark_timer_initialize( void )
+{
+ uint32_t cr;
+
+ /* stop TIMER1*/
+ cr=rTCON & 0xFFFFF0FF;
+ rTCON=(cr | (0x0 << 8));
+
+ /* set MUX for Timer1 to 1/2 */
+ cr=rTCFG1 & 0xFFFFFF0F;
+ rTCFG1=(cr | (0<<4));
+
+ /* input freq=PLCK/2 Mhz*/
+ g_freq = get_PCLK() / 2000;
+ rTCNTB1 = 0xFFFF;
+
+ /* start TIMER1 with manual reload */
+ cr=rTCON & 0xFFFFF0FF;
+ rTCON=(cr | (0x1 << 9));
+ rTCON=(cr | (0x1 << 8));
+
+ g_start = rTCNTO1;
+}
+
+/*
+ * The following controls the behavior of benchmark_timer_read().
+ *
+ * AVG_OVEREHAD is the overhead for starting and stopping the timer. It
+ * is usually deducted from the number returned.
+ *
+ * LEAST_VALID is the lowest number this routine should trust. Numbers
+ * below this are "noise" and zero is returned.
+ */
+
+#define AVG_OVERHEAD 0 /* It typically takes X.X microseconds */
+ /* (Y countdowns) to start/stop the timer. */
+ /* This value is in microseconds. */
+#define LEAST_VALID 1 /* Don't trust a clicks value lower than this */
+
+benchmark_timer_t benchmark_timer_read( void )
+{
+ uint32_t t;
+ unsigned long long total;
+
+ t = rTCNTO1;
+ /*
+ * Total is calculated by taking into account the number of timer overflow
+ * interrupts since the timer was initialized and clicks since the last
+ * interrupts.
+ */
+
+ total = (g_start - t);
+
+ /* convert to microseconds */
+ total = (total*1000) / g_freq;
+
+ if ( benchmark_timer_find_average_overhead == 1 ) {
+ return (int) total;
+ } else if ( total < LEAST_VALID ) {
+ return 0;
+ }
+
+ /*
+ * Somehow convert total into microseconds
+ */
+ return (total - AVG_OVERHEAD);
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
+
diff --git a/bsps/epiphany/epiphany_sim/btimer/btimer.c b/bsps/epiphany/epiphany_sim/btimer/btimer.c
new file mode 100644
index 0000000000..5df9448e01
--- /dev/null
+++ b/bsps/epiphany/epiphany_sim/btimer/btimer.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2015 University of York.
+ * Hesham ALMatary <hmka501@york.ac.uk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <rtems/btimer.h>
+#include <rtems/score/epiphany-utility.h>
+
+extern char bsp_start_vector_table_begin[];
+
+bool benchmark_timer_find_average_overhead;
+
+static void benchmark_timer1_interrupt_handler(void)
+{
+ unsigned int val = 0xFFFFFFFF;
+ unsigned int event_type = 0x1;
+
+ /* Embed assembly code for setting timer1 */
+ __asm__ __volatile__ ("movts ctimer1, %[val] \t \n" :: [val] "r" (val));
+
+ __asm__ __volatile__ ("movfs r16, config; \t \n"
+ "mov r17, %%low(0xfffff0ff);\t \n"
+ "movt r17, %%high(0xffff0ff);\t \n"
+ "lsl r18, %[event_type], 0x8; \t \n"
+ "and r16, r16, r17; \t \n"
+ "orr r16, r16, r18; \t \n"
+ "movts config, r16; \t \n"
+ :: [event_type] "r" (event_type));
+}
+
+/* Start eCore tiemr 1 usef for profiling and timing analysis */
+void benchmark_timer_initialize( void )
+{
+ /* Install interrupt handler for timer 1 */
+
+ proc_ptr *table =
+ (proc_ptr *) bsp_start_vector_table_begin;
+
+ table[TIMER1] = benchmark_timer1_interrupt_handler;
+
+ benchmark_timer1_interrupt_handler();
+}
+
+/*
+ * The following controls the behavior of benchmark_timer_read().
+ *
+ * AVG_OVEREHAD is the overhead for starting and stopping the timer. It
+ * is usually deducted from the number returned.
+ *
+ * LEAST_VALID is the lowest number this routine should trust. Numbers
+ * below this are "noise" and zero is returned.
+ */
+
+#define AVG_OVERHEAD 0 /* It typically takes X.X microseconds */
+ /* (Y countdowns) to start/stop the timer. */
+ /* This value is in microseconds. */
+#define LEAST_VALID 1 /* Don't trust a clicks value lower than this */
+
+benchmark_timer_t benchmark_timer_read( void )
+{
+ uint32_t timer_val = 0;
+ uint32_t total;
+
+ __asm__ __volatile__ ("movfs %[timer_val], ctimer1 \t \n"
+ :[timer_val] "=r" (timer_val):);
+
+ total = (0xFFFFFFFF - timer_val);
+
+ if ( benchmark_timer_find_average_overhead == true )
+ return total;
+ else {
+ if ( total < LEAST_VALID )
+ return 0; /* below timer resolution */
+ /*
+ * Somehow convert total into microseconds
+ */
+ return (total - AVG_OVERHEAD);
+ }
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(
+ bool find_flag
+)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/i386/pc386/btimer/btimer.c b/bsps/i386/pc386/btimer/btimer.c
new file mode 100644
index 0000000000..16d3d66176
--- /dev/null
+++ b/bsps/i386/pc386/btimer/btimer.c
@@ -0,0 +1,552 @@
+/*
+ * This file contains the PC386 timer package.
+ *
+ * Rosimildo daSilva -ConnectTel, Inc - Fixed infinite loop in the Calibration
+ * routine. I've seen this problems with faster machines ( pentiums ). Sometimes
+ * RTEMS just hangs at startup.
+ *
+ * Joel 9 May 2010: This is now seen sometimes on qemu.
+ *
+ * Modifications by:
+ * (C) Copyright 1997 -
+ * NavIST Group - Real-Time Distributed Systems and Industrial Automation
+ * http://pandora.ist.utl.pt
+ * Instituto Superior Tecnico * Lisboa * PORTUGAL
+ *
+ * This file is provided "AS IS" without warranty of any kind, either
+ * expressed or implied.
+ *
+ * Based upon code by
+ * COPYRIGHT (c) 1989-1999.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <stdlib.h>
+#include <bsp.h>
+#include <rtems/btimer.h>
+#include <bsp/irq-generic.h>
+#include <libcpu/cpuModel.h>
+
+/*
+ * Constants
+ */
+#define AVG_OVERHEAD 0 /* 0.1 microseconds to start/stop timer. */
+#define LEAST_VALID 1 /* Don't trust a value lower than this. */
+#define SLOW_DOWN_IO 0x80 /* io which does nothing */
+
+#define TWO_MS (uint32_t)(2000) /* TWO_MS = 2000us (sic!) */
+
+#define MSK_NULL_COUNT 0x40 /* bit counter available for reading */
+
+#define CMD_READ_BACK_STATUS 0xE2 /* command read back status */
+
+RTEMS_INTERRUPT_LOCK_DEFINE( /* visible global variable */ ,
+ rtems_i386_i8254_access_lock, "rtems_i386_i8254_access_lock" );
+
+/*
+ * Global Variables
+ */
+volatile uint32_t Ttimer_val;
+bool benchmark_timer_find_average_overhead = true;
+volatile unsigned int fastLoop1ms, slowLoop1ms;
+
+void (*benchmark_timer_initialize_function)(void) = 0;
+benchmark_timer_t (*benchmark_timer_read_function)(void) = 0;
+void (*Timer_exit_function)(void) = 0;
+
+/* timer (int 08h) Interrupt Service Routine (defined in 'timerisr.s') */
+extern void timerisr(void);
+
+void Timer_exit(void);
+
+/*
+ * Pentium optimized timer handling.
+ */
+
+/*
+ * Timer cleanup routine at RTEMS exit.
+ *
+ * NOTE: This routine is not really necessary, since there will be
+ * a reset at exit.
+ */
+static void tsc_timer_exit(void)
+{
+}
+
+static void tsc_timer_initialize(void)
+{
+ static bool First = true;
+
+ if (First) {
+ First = false;
+
+ atexit(Timer_exit); /* Try not to hose the system at exit. */
+ }
+ Ttimer_val = rdtsc(); /* read starting time */
+}
+
+/*
+ * Read TSC timer value.
+ */
+static uint32_t tsc_read_timer(void)
+{
+ register uint32_t total;
+
+ total = (uint32_t)(rdtsc() - Ttimer_val);
+
+ if (benchmark_timer_find_average_overhead)
+ return total;
+
+ if (total < LEAST_VALID)
+ return 0; /* below timer resolution */
+
+ return (total - AVG_OVERHEAD);
+}
+
+/*
+ * Non-Pentium timer handling.
+ */
+#define US_PER_ISR 250 /* Number of micro-seconds per timer interruption */
+
+/*
+ * Timer cleanup routine at RTEMS exit. NOTE: This routine is
+ * not really necessary, since there will be a reset at exit.
+ */
+static void timerOff(const rtems_raw_irq_connect_data* used)
+{
+ rtems_interrupt_lock_context lock_context;
+ /*
+ * disable interrrupt at i8259 level
+ */
+ bsp_interrupt_vector_disable(used->idtIndex - BSP_IRQ_VECTOR_BASE);
+
+ rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context);
+
+ /* reset timer mode to standard (DOS) value */
+ outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
+ outport_byte(TIMER_CNTR0, 0);
+ outport_byte(TIMER_CNTR0, 0);
+
+ rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
+}
+
+static void timerOn(const rtems_raw_irq_connect_data* used)
+{
+ rtems_interrupt_lock_context lock_context;
+
+ rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context);
+
+ /* load timer for US_PER_ISR microsecond period */
+ outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
+ outport_byte(TIMER_CNTR0, US_TO_TICK(US_PER_ISR) >> 0 & 0xff);
+ outport_byte(TIMER_CNTR0, US_TO_TICK(US_PER_ISR) >> 8 & 0xff);
+
+ rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
+
+ /*
+ * enable interrrupt at i8259 level
+ */
+ bsp_interrupt_vector_enable(used->idtIndex - BSP_IRQ_VECTOR_BASE);
+}
+
+static rtems_raw_irq_connect_data timer_raw_irq_data = {
+ BSP_PERIODIC_TIMER + BSP_IRQ_VECTOR_BASE,
+ timerisr,
+ timerOn,
+ timerOff,
+ NULL
+};
+
+/*
+ * Timer cleanup routine at RTEMS exit.
+ *
+ * NOTE: This routine is not really necessary, since there will be
+ * a reset at exit.
+ */
+static void i386_timer_exit(void)
+{
+ i386_delete_idt_entry (&timer_raw_irq_data);
+}
+
+extern void rtems_irq_prologue_0(void);
+static void i386_timer_initialize(void)
+{
+ static bool First = true;
+
+ if (First) {
+ rtems_raw_irq_connect_data raw_irq_data = {
+ BSP_PERIODIC_TIMER + BSP_IRQ_VECTOR_BASE,
+ rtems_irq_prologue_0,
+ NULL,
+ NULL,
+ NULL
+ };
+
+ First = false;
+ i386_delete_idt_entry (&raw_irq_data);
+
+ atexit(Timer_exit); /* Try not to hose the system at exit. */
+ if (!i386_set_idt_entry (&timer_raw_irq_data)) {
+ printk("raw handler connection failed\n");
+ rtems_fatal_error_occurred(1);
+ }
+ }
+ /* wait for ISR to be called at least once */
+ Ttimer_val = 0;
+ while (Ttimer_val == 0)
+ continue;
+ Ttimer_val = 0;
+}
+
+/*
+ * Read hardware timer value.
+ */
+static uint32_t i386_read_timer(void)
+{
+ register uint32_t total, clicks;
+ register uint8_t lsb, msb;
+ rtems_interrupt_lock_context lock_context;
+
+ rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context);
+ outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_LATCH);
+ inport_byte(TIMER_CNTR0, lsb);
+ inport_byte(TIMER_CNTR0, msb);
+ rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
+
+ clicks = (msb << 8) | lsb;
+ total = (Ttimer_val * US_PER_ISR) + (US_PER_ISR - TICK_TO_US(clicks));
+
+ if (benchmark_timer_find_average_overhead)
+ return total;
+
+ if (total < LEAST_VALID)
+ return 0; /* below timer resolution */
+
+ return (total - AVG_OVERHEAD);
+}
+
+/*
+ * General timer functions using either TSC-based implementation
+ * or interrupt-based implementation
+ */
+
+void benchmark_timer_initialize(void)
+{
+ static bool First = true;
+
+ if (First) {
+ if (x86_has_tsc()) {
+#if defined(DEBUG)
+ printk("TSC: timer initialization\n");
+#endif /* DEBUG */
+ benchmark_timer_initialize_function = &tsc_timer_initialize;
+ benchmark_timer_read_function = &tsc_read_timer;
+ Timer_exit_function = &tsc_timer_exit;
+ } else {
+#if defined(DEBUG)
+ printk("ISR: timer initialization\n");
+#endif /* DEBUG */
+ benchmark_timer_initialize_function = &i386_timer_initialize;
+ benchmark_timer_read_function = &i386_read_timer;
+ Timer_exit_function = &i386_timer_exit;
+ }
+ First = false;
+ }
+ (*benchmark_timer_initialize_function)();
+}
+
+uint32_t benchmark_timer_read(void)
+{
+ return (*benchmark_timer_read_function)();
+}
+
+void Timer_exit(void)
+{
+ if ( Timer_exit_function )
+ return (*Timer_exit_function)();
+}
+
+/*
+ * Set internal benchmark_timer_find_average_overhead flag value.
+ */
+void benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
+
+static unsigned short lastLoadedValue;
+
+/*
+ * Loads timer 0 with value passed as arguemnt.
+ *
+ * Returns: Nothing. Loaded value must be a number of clock bits...
+ */
+static void loadTimerValue( unsigned short loadedValue )
+{
+ rtems_interrupt_lock_context lock_context;
+ rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context);
+ lastLoadedValue = loadedValue;
+ outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_SQWAVE);
+ outport_byte(TIMER_CNTR0, loadedValue & 0xff);
+ outport_byte(TIMER_CNTR0, (loadedValue >> 8) & 0xff);
+ rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
+}
+
+/*
+ * Reads the current value of the timer, and converts the
+ * number of ticks to micro-seconds.
+ *
+ * Returns: number of clock bits elapsed since last load.
+ */
+static unsigned int readTimer0(void)
+{
+ unsigned short lsb, msb;
+ unsigned char status;
+ unsigned int count;
+ rtems_interrupt_lock_context lock_context;
+ rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context);
+
+ outport_byte(
+ TIMER_MODE,
+ (TIMER_RD_BACK | (RB_COUNT_0 & ~(RB_NOT_STATUS | RB_NOT_COUNT)))
+ );
+ inport_byte(TIMER_CNTR0, status);
+ inport_byte(TIMER_CNTR0, lsb);
+ inport_byte(TIMER_CNTR0, msb);
+
+ rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
+
+ count = ( msb << 8 ) | lsb ;
+ if (status & RB_OUTPUT )
+ count += lastLoadedValue;
+
+ return (2*lastLoadedValue - count);
+}
+
+static void Timer0Reset(void)
+{
+ loadTimerValue(0xffff);
+ readTimer0();
+}
+
+static void fastLoop (unsigned int loopCount)
+{
+ unsigned int i;
+ for( i=0; i < loopCount; i++ )outport_byte( SLOW_DOWN_IO, 0 );
+}
+
+static void slowLoop (unsigned int loopCount)
+{
+ unsigned int j;
+ for (j=0; j <100 ; j++) {
+ fastLoop (loopCount);
+ }
+}
+
+/*
+ * #define DEBUG_CALIBRATE
+ */
+void
+Calibrate_loop_1ms(void)
+{
+ unsigned int offset, offsetTmp, emptyCall, emptyCallTmp, res, i, j;
+ unsigned int targetClockBits, currentClockBits;
+ unsigned int slowLoopGranularity, fastLoopGranularity;
+ rtems_interrupt_level level;
+ int retries = 0;
+
+ /*
+ * This code is designed to run before interrupt management
+ * is enabled and running it on multiple CPUs and or after
+ * secondary CPUs are bring up seems really broken.
+ * Disabling of local interrupts is enough.
+ */
+ rtems_interrupt_local_disable(level);
+
+retry:
+ if ( ++retries >= 5 ) {
+ printk( "Calibrate_loop_1ms: too many attempts. giving up!!\n" );
+ while (1);
+ }
+#ifdef DEBUG_CALIBRATE
+ printk("Calibrate_loop_1ms is starting, please wait (but not too long.)\n");
+#endif
+ targetClockBits = US_TO_TICK(1000);
+ /*
+ * Fill up the cache to get a correct offset
+ */
+ Timer0Reset();
+ readTimer0();
+ /*
+ * Compute the minimal offset to apply due to read counter register.
+ */
+ offset = 0xffffffff;
+ for (i=0; i <1000; i++) {
+ Timer0Reset();
+ offsetTmp = readTimer0();
+ offset += offsetTmp;
+ }
+ offset = offset / 1000; /* compute average */
+ /*
+ * calibrate empty call
+ */
+ fastLoop (0);
+ emptyCall = 0;
+ j = 0;
+ for (i=0; i <10; i++) {
+ Timer0Reset();
+ fastLoop (0);
+ res = readTimer0();
+ /* res may be inferior to offset on fast
+ * machine because we took an average for offset
+ */
+ if (res > offset) {
+ ++j;
+ emptyCallTmp = res - offset;
+ emptyCall += emptyCallTmp;
+ }
+ }
+ if (j == 0) emptyCall = 0;
+ else emptyCall = emptyCall / j; /* compute average */
+ /*
+ * calibrate fast loop
+ */
+ Timer0Reset();
+ fastLoop (10000);
+ res = readTimer0() - offset;
+ if (res < emptyCall) {
+ printk(
+ "Problem #1 in offset computation in Calibrate_loop_1ms "
+ " in file libbsp/i386/pc386/timer/timer.c\n"
+ );
+ goto retry;
+ }
+ fastLoopGranularity = (res - emptyCall) / 10000;
+ /*
+ * calibrate slow loop
+ */
+ Timer0Reset();
+ slowLoop(10);
+ res = readTimer0();
+ if (res < offset + emptyCall) {
+ printk(
+ "Problem #2 in offset computation in Calibrate_loop_1ms "
+ " in file libbsp/i386/pc386/timer/timer.c\n"
+ );
+ goto retry;
+ }
+ slowLoopGranularity = (res - offset - emptyCall)/ 10;
+
+ if (slowLoopGranularity == 0) {
+ printk(
+ "Problem #3 in offset computation in Calibrate_loop_1ms "
+ " in file libbsp/i386/pc386/timer/timer.c\n"
+ );
+ goto retry;
+ }
+
+ targetClockBits += offset;
+#ifdef DEBUG_CALIBRATE
+ printk("offset = %u, emptyCall = %u, targetClockBits = %u\n",
+ offset, emptyCall, targetClockBits);
+ printk("slowLoopGranularity = %u fastLoopGranularity = %u\n",
+ slowLoopGranularity, fastLoopGranularity);
+#endif
+ slowLoop1ms = (targetClockBits - emptyCall) / slowLoopGranularity;
+ if (slowLoop1ms != 0) {
+ fastLoop1ms = targetClockBits % slowLoopGranularity;
+ if (fastLoop1ms > emptyCall) fastLoop1ms -= emptyCall;
+ }
+ else
+ fastLoop1ms = targetClockBits - emptyCall / fastLoopGranularity;
+
+ if (slowLoop1ms != 0) {
+ /*
+ * calibrate slow loop
+ */
+
+ while(1)
+ {
+ int previousSign = 0; /* 0 = unset, 1 = incrementing, 2 = decrementing */
+ Timer0Reset();
+ slowLoop(slowLoop1ms);
+ currentClockBits = readTimer0();
+ if (currentClockBits > targetClockBits) {
+ if ((currentClockBits - targetClockBits) < slowLoopGranularity) {
+ /* decrement loop counter anyway to be sure slowLoop(slowLoop1ms) < targetClockBits */
+ --slowLoop1ms;
+ break;
+ }
+ else {
+ --slowLoop1ms;
+ if (slowLoop1ms == 0) break;
+ if (previousSign == 0) previousSign = 2;
+ if (previousSign == 1) break;
+ }
+ }
+ else {
+ if ((targetClockBits - currentClockBits) < slowLoopGranularity) {
+ break;
+ }
+ else {
+ ++slowLoop1ms;
+ if (previousSign == 0) previousSign = 1;
+ if (previousSign == 2) break;
+ }
+ }
+ }
+ }
+ /*
+ * calibrate fast loop
+ */
+
+ if (fastLoopGranularity != 0 ) {
+ while(1) {
+ int previousSign = 0; /* 0 = unset, 1 = incrementing, 2 = decrementing */
+ Timer0Reset();
+ if (slowLoop1ms != 0) slowLoop(slowLoop1ms);
+ fastLoop(fastLoop1ms);
+ currentClockBits = readTimer0();
+ if (currentClockBits > targetClockBits) {
+ if ((currentClockBits - targetClockBits) < fastLoopGranularity)
+ break;
+ else {
+ --fastLoop1ms;
+ if (previousSign == 0) previousSign = 2;
+ if (previousSign == 1) break;
+ }
+ }
+ else {
+ if ((targetClockBits - currentClockBits) < fastLoopGranularity)
+ break;
+ else {
+ ++fastLoop1ms;
+ if (previousSign == 0) previousSign = 1;
+ if (previousSign == 2) break;
+ }
+ }
+ }
+ }
+#ifdef DEBUG_CALIBRATE
+ printk("slowLoop1ms = %u, fastLoop1ms = %u\n", slowLoop1ms, fastLoop1ms);
+#endif
+ rtems_interrupt_local_enable(level);
+
+}
+
+/*
+ * loop which waits at least timeToWait ms
+ */
+void Wait_X_ms( unsigned int timeToWait)
+{
+ unsigned int j;
+
+ for (j=0; j<timeToWait ; j++) {
+ if (slowLoop1ms != 0) slowLoop(slowLoop1ms);
+ fastLoop(fastLoop1ms);
+ }
+}
diff --git a/bsps/i386/pc386/btimer/timerisr.S b/bsps/i386/pc386/btimer/timerisr.S
new file mode 100644
index 0000000000..da2a07845a
--- /dev/null
+++ b/bsps/i386/pc386/btimer/timerisr.S
@@ -0,0 +1,56 @@
+/*-------------------------------------------------------------------------+
+| timerisr.s v1.1 - PC386 BSP - 1997/08/07
++--------------------------------------------------------------------------+
+| This file contains the PC386 timer interrupt handler.
++--------------------------------------------------------------------------+
+| (C) Copyright 1997 -
+| - NavIST Group - Real-Time Distributed Systems and Industrial Automation
+|
+| http://pandora.ist.utl.pt
+|
+| Instituto Superior Tecnico * Lisboa * PORTUGAL
++--------------------------------------------------------------------------+
+| Disclaimer:
+|
+| This file is provided "AS IS" without warranty of any kind, either
+| expressed or implied.
++--------------------------------------------------------------------------+
+| This code is base on:
+| timerisr.s,v 1.5 1995/12/19 20:07:45 joel Exp - go32 BSP
+| With the following copyright notice:
+| **************************************************************************
+| * COPYRIGHT (c) 1989-1999.
+| * On-Line Applications Research Corporation (OAR).
+| *
+| * The license and distribution terms for this file may be
+| * found in the file LICENSE in this distribution or at
+| * http://www.rtems.org/license/LICENSE.
+| **************************************************************************
++--------------------------------------------------------------------------*/
+
+#include <rtems/asm.h>
+
+BEGIN_CODE
+
+ EXTERN(Ttimer_val)
+
+/*-------------------------------------------------------------------------+
+| Function: rtems_isr timerisr(rtems_vector_number);
+| Description: ISR for the timer. The timer is set up to generate an
+| interrupt at maximum intervals.
+| Global Variables: None.
+| Arguments: standard - see RTEMS documentation.
+| Returns: standard return value - see RTEMS documentation.
++--------------------------------------------------------------------------*/
+ PUBLIC(timerisr)
+SYM (timerisr):
+ incl Ttimer_val # another tick
+ pushl eax
+ movb $0x20, al
+ outb al, $0x20 # signal generic End Of Interrupt (EOI) to PIC
+ popl eax
+ iret
+
+END_CODE
+
+END
diff --git a/bsps/lm32/shared/btimer/btimer.c b/bsps/lm32/shared/btimer/btimer.c
new file mode 100644
index 0000000000..e1980a7077
--- /dev/null
+++ b/bsps/lm32/shared/btimer/btimer.c
@@ -0,0 +1,111 @@
+/* timer.c
+ *
+ * This file manages the benchmark timer used by the RTEMS Timing
+ * Test Suite. Each measured time period is demarcated by calls to
+ * benchmark_timer_initialize() and benchmark_timer_read().
+ * benchmark_timer_read() usually returns the number of microseconds
+ * since benchmark_timer_initialize() exitted.
+ *
+ * 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.org/license/LICENSE.
+ *
+ * Jukka Pietarinen <jukka.pietarinen@mrf.fi>, 2008,
+ * Micro-Research Finland Oy
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <rtems/btimer.h>
+#include <rtems/bspIo.h>
+#include "../include/system_conf.h"
+#include "../../shared/clock/clock.h"
+
+static inline int timerread(unsigned int reg)
+{
+#if ON_SIMULATOR && defined(TIMER0_BASE_ADDRESS)
+ return *((int*)(TIMER0_BASE_ADDRESS + reg));
+#elif defined(TIMER1_BASE_ADDRESS)
+ return *((int*)(TIMER1_BASE_ADDRESS + reg));
+#else
+#warning "Benchmarking timer not available!"
+ return 0;
+#endif
+}
+
+static inline void timerwrite(unsigned int reg, int value)
+{
+#if ON_SIMULATOR && defined(TIMER0_BASE_ADDRESS)
+ *((int*)(TIMER0_BASE_ADDRESS + reg)) = value;
+#elif defined(TIMER1_BASE_ADDRESS)
+ *((int*)(TIMER1_BASE_ADDRESS + reg)) = value;
+#endif
+}
+
+bool benchmark_timer_find_average_overhead;
+
+void benchmark_timer_initialize( void )
+{
+ /* Set timer period */
+ timerwrite(LM32_CLOCK_PERIOD, 0xffffffff);
+ /* Stop timer */
+ timerwrite(LM32_CLOCK_CR, LM32_CLOCK_CR_STOP);
+ /* Clear status register */
+ timerwrite(LM32_CLOCK_SR, 0);
+ /* Start timer */
+ timerwrite(LM32_CLOCK_CR, LM32_CLOCK_CR_START);
+}
+
+/*
+ * The following controls the behavior of benchmark_timer_read().
+ *
+ * AVG_OVEREHAD is the overhead for starting and stopping the timer. It
+ * is usually deducted from the number returned.
+ *
+ * LEAST_VALID is the lowest number this routine should trust. Numbers
+ * below this are "noise" and zero is returned.
+ */
+
+#define AVG_OVERHEAD 4 /* It typically takes X.X microseconds */
+ /* (Y countdowns) to start/stop the timer. */
+ /* This value is in microseconds. */
+#define LEAST_VALID 4 /* Don't trust a clicks value lower than this */
+
+benchmark_timer_t benchmark_timer_read( void )
+{
+ uint32_t ticks;
+ uint32_t total;
+ uint32_t status;
+
+ ticks = 0xffffffff - timerread(LM32_CLOCK_SNAPSHOT);
+ status = timerread(LM32_CLOCK_SR);
+ if (status & LM32_CLOCK_SR_TO)
+ printk("Timer overflow!\n");
+
+ total = ticks / (CPU_FREQUENCY / 1000000);
+
+ if ( benchmark_timer_find_average_overhead == true )
+ return total; /* in XXX microsecond units */
+ else
+ {
+ if ( total < LEAST_VALID )
+ return 0; /* below timer resolution */
+ /*
+ * Somehow convert total into microseconds
+ */
+ return (total - AVG_OVERHEAD);
+ }
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(
+ bool find_flag
+)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/m32c/m32cbsp/btimer/btimer.c b/bsps/m32c/m32cbsp/btimer/btimer.c
new file mode 100644
index 0000000000..a27d9ffb1b
--- /dev/null
+++ b/bsps/m32c/m32cbsp/btimer/btimer.c
@@ -0,0 +1,69 @@
+/*
+ * This file implements a stub benchmark timer that is sufficient to
+ * satisfy linking the RTEMS Benchmarks.
+ */
+
+/*
+ * COPYRIGHT (c) 1989-2001.
+ * On-Line Applications Research Corporation (OAR).
+ */
+
+#include <bsp.h>
+#include <rtems/btimer.h>
+
+#include <varvects.h>
+
+bool benchmark_timer_find_average_overhead;
+uint32_t benchmark_timer_overhead = 10;
+
+#define TABSR *((uint8_t *)0x340)
+#define TA0MR *((uint8_t *)0x356)
+#define TA0 *((uint16_t *)0x346)
+#define TA0IC *((uint8_t *)0x6c)
+
+static int benchmark_timer_interrupts;
+
+static void __attribute__((interrupt)) timer_ra_interrupt(void);
+
+#define ivec_timer_a0 12
+
+void __attribute__((interrupt))
+timer_ra_interrupt(void)
+{
+ benchmark_timer_interrupts++;
+ TA0IC = 0x05;
+
+}
+
+void benchmark_timer_initialize(void)
+{
+ benchmark_timer_interrupts = 0;
+ _set_var_vect (timer_ra_interrupt, ivec_timer_a0);
+ TA0MR = 0x00;
+ TA0 = 0xffff;
+ TA0IC = 0x05;
+ TABSR = 0x55;
+}
+
+benchmark_timer_t benchmark_timer_read(void)
+{
+ uint32_t count;
+
+ count = 0xFFFF - TA0;
+ count += benchmark_timer_interrupts * 0xFFFFL;
+
+ if (!benchmark_timer_find_average_overhead) {
+ if ( count > benchmark_timer_overhead )
+ count -= benchmark_timer_overhead;
+ else
+ count = 0;
+ }
+ return count;
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(
+ bool find_flag
+)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/m68k/av5282/btimer/btimer.c b/bsps/m68k/av5282/btimer/btimer.c
new file mode 100644
index 0000000000..8a8323e547
--- /dev/null
+++ b/bsps/m68k/av5282/btimer/btimer.c
@@ -0,0 +1,34 @@
+/*
+ * Timer Init
+ *
+ * Use the last DMA timer (DTIM3) as the diagnostic timer.
+ */
+
+#include <rtems.h>
+#include <rtems/btimer.h>
+#include <bsp.h>
+
+void
+benchmark_timer_initialize(void)
+{
+ int preScaleDivisor = 58;
+ int div = MCF5282_TIMER_DTMR_CLK_DIV1;
+ MCF5282_TIMER3_DTRR = 0x2710;
+ MCF5282_TIMER3_DTMR = 0;
+ MCF5282_TIMER3_DTMR = MCF5282_TIMER_DTMR_PS(preScaleDivisor - 1) | div |
+ MCF5282_TIMER_DTMR_RST;
+}
+
+/*
+ * Return timer value in microsecond units
+ */
+uint32_t
+benchmark_timer_read(void)
+{
+ return MCF5282_TIMER3_DTCN;
+}
+
+void
+benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+}
diff --git a/bsps/m68k/gen68340/btimer/btimer.c b/bsps/m68k/gen68340/btimer/btimer.c
new file mode 100644
index 0000000000..23cddd95b0
--- /dev/null
+++ b/bsps/m68k/gen68340/btimer/btimer.c
@@ -0,0 +1,256 @@
+/*
+ * ATTENTION: As MC68349 has no built-in Timer, the following code doesn't work
+ * in a MC68349. You can't use FIFO full mode for the moment, but
+ * it should be easy to fix this by using an external timer.
+ *
+ * Use TIMER 1 for TIMEOUT when using FIFO FULL mode in UART driver
+ * Use TIMER 2 for timing test suites
+ *
+ * NOTE: It is important that the timer start/stop overhead be
+ * determined when porting or modifying this code.
+ */
+
+/*
+ * Geoffroy Montel
+ * France Telecom - CNET/DSM/TAM/CAT
+ * 4, rue du Clos Courtel
+ * 35512 CESSON-SEVIGNE
+ * FRANCE
+ *
+ * e-mail: g_montel@yahoo.com
+ *
+ * COPYRIGHT (c) 1989-1999.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <rtems/btimer.h>
+#include <m340uart.h>
+#include <m340timer.h>
+#include <m68340.h>
+
+#define TIMER1_VECTOR 122
+#define TIMER1_IRQ_LEVEL 5
+#define TIMER1_INTERRUPT_ARBITRATION 5
+
+#define TIMER2_VECTOR 123
+#define TIMER2_IRQ_LEVEL 4
+#define TIMER2_INTERRUPT_ARBITRATION 4
+
+#define CLOCK_SPEED 25 /* in Mhz */
+
+#define max(a,b) (((a)>(b)) ? (a) : (b))
+
+void (*Restart_Fifo_Full_A_Timer)(void);
+void (*Restart_Check_A_Timer)(void);
+void (*Restart_Fifo_Full_B_Timer)(void);
+void (*Restart_Check_B_Timer)(void);
+
+int preload = 0;
+
+/*
+ * __Restart_Fifo_Full_Timer
+ *
+ * When a character is received, sets the TIMER to raise an interrupt at
+ * TIMEOUT. It's necessary to prevent from not getting n-1 characters
+ * (with n the Uart Fifo size).
+ */
+static void __Restart_Fifo_Full_Timer (void)
+{
+ TSR1 |= m340_TO;
+ TCR1 &= ~m340_CPE;
+ WPREL11 = preload;
+ TCR1 |= m340_CPE;
+}
+
+/*
+ * __Restart_Check_Timer
+ *
+ * When no character has been received recently, check now and then if whether
+ * a there's a character in the FIFO
+ */
+static void __Restart_Check_Timer (void)
+{
+ TSR1 |= m340_TO;
+ TCR1 &= ~m340_CPE;
+ WPREL11 = 0xFFFF;
+ TCR1 |= m340_CPE;
+}
+
+/*
+ * __do_nothing
+ *
+ * We always restart the fifo full timer with a call to Restart_*_Timer
+ * if we do not use FIFO full, Restart_X_Timer are set to do __do_nothing
+ */
+static void __do_nothing (void)
+{
+}
+
+#define Fifo_Full_on_A \
+ (m340_uart_config[UART_CHANNEL_A].rx_mode==UART_FIFO_FULL && \
+ m340_uart_config[UART_CHANNEL_A].enable && \
+ m340_uart_config[UART_CHANNEL_A].mode==UART_INTERRUPTS)
+#define Fifo_Full_on_B \
+ (m340_uart_config[UART_CHANNEL_B].rx_mode==UART_FIFO_FULL && \
+ m340_uart_config[UART_CHANNEL_B].enable && \
+ m340_uart_config[UART_CHANNEL_B].mode==UART_INTERRUPTS)
+
+/*
+ * Fifo_Full_benchmark_timer_initialize
+ *
+ * initialize Timer 1 for FIFO full mode
+ */
+void Fifo_Full_benchmark_timer_initialize (void)
+{
+ float max_baud_rate;
+ int prescaler_output_tap = -1;
+ int nb_of_clock_ticks = 0;
+ rtems_isr_entry old_handler;
+
+ /*
+ * USE TIMER 1 for UART FIFO FULL mode
+ */
+ if ( Fifo_Full_on_A || Fifo_Full_on_B ) {
+ /* Disable the timer */
+ TCR1 &= ~m340_SWR;
+
+ /* Reset the interrupts */
+ TSR1 &= ~(m340_TO | m340_TG | m340_TC);
+
+ /* Init the stop bit for normal operation, ignore FREEZE, user privileges,
+ * set interrupt arbitration.
+ */
+ TMCR1 = TIMER1_INTERRUPT_ARBITRATION;
+
+ /* interrupt priority level and interrupt vector */
+ TIR1 = TIMER1_VECTOR | (TIMER1_IRQ_LEVEL << 8);
+
+ /* compute prescaler */
+ if ( Fifo_Full_on_A && Fifo_Full_on_B) {
+ max_baud_rate = max(
+ m340_uart_config[UART_CHANNEL_A].rx_baudrate,
+ m340_uart_config[UART_CHANNEL_B].rx_baudrate
+ );
+ } else if ( Fifo_Full_on_A ) {
+ max_baud_rate = m340_uart_config[UART_CHANNEL_A].rx_baudrate;
+ } else
+ max_baud_rate = m340_uart_config[UART_CHANNEL_B].rx_baudrate;
+
+ /* find out config */
+ nb_of_clock_ticks = (10/max_baud_rate)*(CLOCK_SPEED*1000000)*1.2;
+ if (nb_of_clock_ticks < 0xFFFF) {
+ preload = nb_of_clock_ticks;
+ prescaler_output_tap = -1;
+ } else if (nb_of_clock_ticks/2 < 0xFFFF) {
+ preload = nb_of_clock_ticks/2;
+ prescaler_output_tap = m340_Divide_by_2;
+ } else if (nb_of_clock_ticks/4 < 0xFFFF) {
+ preload = nb_of_clock_ticks/4;
+ prescaler_output_tap = m340_Divide_by_4;
+ } else if (nb_of_clock_ticks/8 < 0xFFFF) {
+ preload = nb_of_clock_ticks/8;
+ prescaler_output_tap = m340_Divide_by_16;
+ } else if (nb_of_clock_ticks/16 < 0xFFFF) {
+ preload = nb_of_clock_ticks/16;
+ prescaler_output_tap = m340_Divide_by_16;
+ } else if (nb_of_clock_ticks/32 < 0xFFFF) {
+ preload = nb_of_clock_ticks/32;
+ prescaler_output_tap = m340_Divide_by_32;
+ } else if (nb_of_clock_ticks/64 < 0xFFFF) {
+ preload = nb_of_clock_ticks/64;
+ prescaler_output_tap = m340_Divide_by_64;
+ } else if (nb_of_clock_ticks/128 < 0xFFFF) {
+ preload = nb_of_clock_ticks/128;
+ prescaler_output_tap = m340_Divide_by_128;
+ } else if (nb_of_clock_ticks/256 < 0xFFFF) {
+ preload = nb_of_clock_ticks/256;
+ prescaler_output_tap = m340_Divide_by_256;
+ }
+
+ /* Input Capture/Output Compare (ICOC) */
+ TCR1 = m340_SWR | m340_TO_Enabled | m340_ICOC;
+ if (prescaler_output_tap!=-1) TCR1 |= prescaler_output_tap | m340_PSE;
+
+ /* install interrupt vector */
+ rtems_interrupt_catch(InterruptHandler, TIMER1_VECTOR, &old_handler);
+
+ } /* fifo full mode on a uart */
+
+ /* install routines */
+ if ( Fifo_Full_on_A ) {
+ Restart_Check_A_Timer = __Restart_Check_Timer;
+ Restart_Fifo_Full_A_Timer = __Restart_Fifo_Full_Timer;
+ } else {
+ Restart_Check_A_Timer = __do_nothing;
+ Restart_Fifo_Full_A_Timer = __do_nothing;
+ }
+
+ if ( Fifo_Full_on_B ) {
+ Restart_Check_B_Timer = __Restart_Check_Timer;
+ Restart_Fifo_Full_B_Timer = __Restart_Fifo_Full_Timer;
+ } else {
+ Restart_Check_B_Timer = __do_nothing;
+ Restart_Fifo_Full_B_Timer = __do_nothing;
+ }
+
+ /* start checking timer */
+ Restart_Check_A_Timer();
+ Restart_Check_B_Timer();
+}
+
+/*
+ * benchmark_timer_initialize
+ *
+ * init Timer for timing test suites
+ */
+void benchmark_timer_initialize (void)
+{
+ /* Disable the timer */
+ TCR2 &= ~m340_SWR;
+
+ /* Reset the interrupts */
+ TSR2 &= ~(m340_TO | m340_TG | m340_TC);
+
+ /* Init the stop bit for normal operation, ignore FREEZE, user privileges,
+ set interrupt arbitration */
+ TMCR1 = TIMER2_INTERRUPT_ARBITRATION;
+
+ /* interrupt priority level and interrupt vector */
+ TIR1 = TIMER2_VECTOR | (TIMER2_IRQ_LEVEL << 8);
+
+ /* Init the stop bit for normal operation, ignore FREEZE, user privileges,
+ set interrupt arbitration */
+ TMCR2 = TIMER2_INTERRUPT_ARBITRATION;
+
+ /* Preload register 1 */
+ WPREL21 = 0xFFFF;
+
+ /* Input Capture/Output Compare (ICOC) */
+ TCR2 = m340_SWR | m340_ICOC | m340_PSE | m340_Divide_by_16 | m340_CPE;
+}
+
+/*
+ * benchmark_timer_read
+ *
+ * Return timer value in microsecond units
+ */
+uint32_t benchmark_timer_read (void)
+{
+ /* there's CLOCK_SPEED / 16 micro seconds between two timer
+ * register decrements.
+ */
+ return (((0xFFFF - TCNTR2) * CLOCK_SPEED) / 16);
+}
+
+/*
+ * benchmark_timer_disable_subtracting_average_overhead
+ */
+void benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+}
diff --git a/bsps/m68k/gen68360/btimer/btimer.c b/bsps/m68k/gen68360/btimer/btimer.c
new file mode 100644
index 0000000000..40a3e0a4c1
--- /dev/null
+++ b/bsps/m68k/gen68360/btimer/btimer.c
@@ -0,0 +1,83 @@
+/*
+ * Use TIMER 1 and TIMER 2 for Timing Test Suite
+ * The hardware on the MC68360 makes these routines very simple.
+ *
+ * Based on the `gen68302' board support package, and covered by the
+ * original distribution terms.
+ *
+ * W. Eric Norum
+ * Saskatchewan Accelerator Laboratory
+ * University of Saskatchewan
+ * Saskatoon, Saskatchewan, CANADA
+ * eric@skatter.usask.ca
+ */
+
+/*
+ *
+ * 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.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <rtems/btimer.h>
+#include <bsp.h>
+#include <rtems/m68k/m68360.h>
+
+void
+benchmark_timer_initialize (void)
+{
+ /*
+ * Reset timers 1 and 2
+ */
+ m360.tgcr &= ~0x00FF;
+ m360.tcn1 = 0;
+ m360.tcn2 = 0;
+ m360.ter1 = 0xFFFF;
+ m360.ter2 = 0xFFFF;
+
+ /*
+ * Cascade timers 1 and 2
+ */
+ m360.tgcr |= 0x0080;
+
+ /*
+ * Configure timers 1 and 2 to a single 32-bit, 1 MHz timer.
+ * HARDWARE:
+ * Change the `25' to match your processor clock
+ */
+ m360.tmr2 = ((25-1) << 8) | 0x2;
+ m360.tmr1 = 0;
+
+ /*
+ * Start the timers
+ */
+ m360.tgcr |= 0x0011;
+}
+
+/*
+ * Return timer value in microsecond units
+ */
+uint32_t
+benchmark_timer_read (void)
+{
+ unsigned short val;
+
+ val = m360.tcn1;
+ return val;
+}
+
+void
+benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+}
diff --git a/bsps/m68k/genmcf548x/btimer/btimer.c b/bsps/m68k/genmcf548x/btimer/btimer.c
new file mode 100644
index 0000000000..acac6f8f9b
--- /dev/null
+++ b/bsps/m68k/genmcf548x/btimer/btimer.c
@@ -0,0 +1,83 @@
+/*===============================================================*\
+| Project: RTEMS generic mcf548x BSP |
++-----------------------------------------------------------------+
+| File: timer.c |
++-----------------------------------------------------------------+
+| The file contains the diagnostic timer code of generic MCF548x |
+| BSP. |
++-----------------------------------------------------------------+
+| Copyright (c) 2007 |
+| Embedded Brains GmbH |
+| Obere Lagerstr. 30 |
+| D-82178 Puchheim |
+| Germany |
+| rtems@embedded-brains.de |
++-----------------------------------------------------------------+
+| |
+| Parts of the code has been derived from the "dBUG source code" |
+| package Freescale is providing for M548X EVBs. The usage of |
+| the modified or unmodified code and it's integration into the |
+| generic mcf548x BSP has been done according to the Freescale |
+| license terms. |
+| |
+| The Freescale license terms can be reviewed in the file |
+| |
+| Freescale_license.txt |
+| |
++-----------------------------------------------------------------+
+| |
+| The generic mcf548x BSP has been developed on the basic |
+| structures and modules of the av5282 BSP. |
+| |
++-----------------------------------------------------------------+
+| |
+| The license and distribution terms for this file may be |
+| found in the file LICENSE in this distribution or at |
+| |
+| http://www.rtems.org/license/LICENSE. |
+| |
++-----------------------------------------------------------------+
+| |
+| date history ID |
+| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
+| 12.11.07 1.0 ras |
+| |
+\*===============================================================*/
+
+/*
+ * Timer Init
+ *
+ * Use the second slice timer (SLT1) as the diagnostic timer.
+ */
+
+#include <rtems.h>
+#include <rtems/btimer.h>
+#include <bsp.h>
+#include <mcf548x/mcf548x.h>
+
+bool benchmark_timer_find_average_overhead;
+static uint32_t microsecond_timer_value = 0;
+
+void benchmark_timer_initialize(void)
+{
+ MCF548X_SLT_SLTCNT1 = 0xFFFFFFFF;
+ MCF548X_SLT_SCR1 |= (MCF548X_SLT_SCR_TEN | MCF548X_SLT_SCR_RUN);
+}
+
+/*
+ * Return timer value in microsecond units
+ * XLB clock 100 MHz / 1us is equal to 100 counts
+ */
+uint32_t
+benchmark_timer_read(void)
+{
+ microsecond_timer_value = (0xFFFFFFFF - MCF548X_SLT_SCNT1)/100;
+
+ return microsecond_timer_value;
+}
+
+void
+benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/m68k/mcf52235/btimer/btimer.c b/bsps/m68k/mcf52235/btimer/btimer.c
new file mode 100644
index 0000000000..f9122542c2
--- /dev/null
+++ b/bsps/m68k/mcf52235/btimer/btimer.c
@@ -0,0 +1,39 @@
+/*
+ * Timer Init
+ *
+ * Use the last DMA timer (DTIM3) as the diagnostic timer.
+ *
+ * Author: W. Eric Norum <norume@aps.anl.gov>
+ *
+ * COPYRIGHT (c) 2005.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <rtems/btimer.h>
+#include <bsp.h>
+
+void benchmark_timer_initialize(void)
+{
+ uint32_t preScaleDivisor = bsp_get_CPU_clock_speed() / 1000000;
+
+ MCF_DTIM3_DTMR = 0;
+ MCF_DTIM3_DTMR = MCF_DTIM_DTMR_PS(preScaleDivisor - 1) |
+ MCF_DTIM_DTMR_CLK_DIV1 | MCF_DTIM_DTMR_RST;
+}
+
+/*
+ * Return timer value in microsecond units
+ */
+benchmark_timer_t benchmark_timer_read(void)
+{
+ return MCF_DTIM3_DTCN;
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+}
diff --git a/bsps/m68k/mcf5225x/btimer/btimer.c b/bsps/m68k/mcf5225x/btimer/btimer.c
new file mode 100644
index 0000000000..ac0ca6d7d0
--- /dev/null
+++ b/bsps/m68k/mcf5225x/btimer/btimer.c
@@ -0,0 +1,39 @@
+/*
+ * Timer Init
+ *
+ * Use the last DMA timer (DTIM3) as the diagnostic timer.
+ *
+ * Author: W. Eric Norum <norume@aps.anl.gov>
+ *
+ * COPYRIGHT (c) 2005-2010.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <rtems/btimer.h>
+#include <bsp.h>
+
+void benchmark_timer_initialize(void)
+{
+ uint32_t preScaleDivisor = bsp_get_CPU_clock_speed() / 1000000;
+
+ MCF_DTIM3_DTMR = 0;
+ MCF_DTIM3_DTMR = MCF_DTIM_DTMR_PS(preScaleDivisor - 1) |
+ MCF_DTIM_DTMR_CLK_DIV1 | MCF_DTIM_DTMR_RST;
+}
+
+/*
+ * Return timer value in microsecond units
+ */
+benchmark_timer_t benchmark_timer_read(void)
+{
+ return MCF_DTIM3_DTCN;
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+}
diff --git a/bsps/m68k/mcf5235/btimer/btimer.c b/bsps/m68k/mcf5235/btimer/btimer.c
new file mode 100644
index 0000000000..6aae8e99e6
--- /dev/null
+++ b/bsps/m68k/mcf5235/btimer/btimer.c
@@ -0,0 +1,34 @@
+/*
+ * Timer Init
+ *
+ * Use the last DMA timer (DTIM3) as the diagnostic timer.
+ */
+
+#include <rtems.h>
+#include <rtems/btimer.h>
+#include <bsp.h>
+
+void
+benchmark_timer_initialize(void)
+{
+ int preScaleDivisor = 0x4A;
+ int div = MCF5235_TIMER_DTMR_CLK_DIV1;
+ MCF5235_TIMER_DTRR3 = 0x2710;
+ MCF5235_TIMER3_DTMR = 0;
+ MCF5235_TIMER3_DTMR = MCF5235_TIMER_DTMR_PS(preScaleDivisor) | div |
+ MCF5235_TIMER_DTMR_RST;
+}
+
+/*
+ * Return timer value in microsecond units
+ */
+uint32_t
+benchmark_timer_read(void)
+{
+ return MCF5235_TIMER3_DTCN;
+}
+
+void
+benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+}
diff --git a/bsps/m68k/mcf5329/btimer/btimer.c b/bsps/m68k/mcf5329/btimer/btimer.c
new file mode 100644
index 0000000000..0f762c0a6a
--- /dev/null
+++ b/bsps/m68k/mcf5329/btimer/btimer.c
@@ -0,0 +1,39 @@
+/*
+ * Timer Init
+ *
+ * Use the last DMA timer (DTIM3) as the diagnostic timer.
+ *
+ * Author: W. Eric Norum <norume@aps.anl.gov>
+ *
+ * COPYRIGHT (c) 2005.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <rtems/btimer.h>
+#include <bsp.h>
+
+void benchmark_timer_initialize(void)
+{
+ uint32_t preScaleDivisor = bsp_get_BUS_clock_speed() / 1000000;
+
+ MCF_DTIM3_DTMR = 0;
+ MCF_DTIM3_DTMR = MCF_DTIM_DTMR_PS(preScaleDivisor - 1) |
+ MCF_DTIM_DTMR_CLK_DIV1 | MCF_DTIM_DTMR_RST;
+}
+
+/*
+ * Return timer value in microsecond units
+ */
+benchmark_timer_t benchmark_timer_read(void)
+{
+ return MCF_DTIM3_DTCN;
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+}
diff --git a/bsps/m68k/mrm332/btimer/btimer.c b/bsps/m68k/mrm332/btimer/btimer.c
new file mode 100644
index 0000000000..8c14f8fe58
--- /dev/null
+++ b/bsps/m68k/mrm332/btimer/btimer.c
@@ -0,0 +1,60 @@
+/*
+ * COPYRIGHT (c) 1989-1999.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <rtems/btimer.h>
+
+bool benchmark_timer_find_average_overhead;
+
+extern rtems_isr Clock_isr(void);
+
+void benchmark_timer_initialize( void )
+{
+}
+
+/*
+ * The following controls the behavior of benchmark_timer_read().
+ *
+ * FIND_AVG_OVERHEAD * instructs the routine to return the "raw" count.
+ *
+ * AVG_OVEREHAD is the overhead for starting and stopping the timer. It
+ * is usually deducted from the number returned.
+ *
+ * LEAST_VALID is the lowest number this routine should trust. Numbers
+ * below this are "noise" and zero is returned.
+ */
+
+#define AVG_OVERHEAD 0 /* It typically takes X.X microseconds */
+ /* (Y countdowns) to start/stop the timer. */
+ /* This value is in microseconds. */
+#define LEAST_VALID 1 /* Don't trust a clicks value lower than this */
+
+/*
+ * Return timer value in 1/2-microsecond units
+ */
+benchmark_timer_t benchmark_timer_read( void )
+{
+ uint32_t total;
+ total = 0;
+
+ if ( benchmark_timer_find_average_overhead == true )
+ return total; /* in XXX microsecond units */
+
+ if ( total < LEAST_VALID )
+ return 0; /* below timer resolution */
+
+ return (total - AVG_OVERHEAD);
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(
+ bool find_flag
+)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/m68k/mvme147/btimer/btimer.c b/bsps/m68k/mvme147/btimer/btimer.c
new file mode 100644
index 0000000000..9d48fa7075
--- /dev/null
+++ b/bsps/m68k/mvme147/btimer/btimer.c
@@ -0,0 +1,67 @@
+/*
+ * COPYRIGHT (c) 1989-1999.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ *
+ * MVME147 port for TNI - Telecom Bretagne
+ * by Dominique LE CAMPION (Dominique.LECAMPION@enst-bretagne.fr)
+ * May 1996
+ */
+
+#include <rtems/btimer.h>
+#include <bsp.h>
+
+#define TIMER_INT_LEVEL 6
+
+#define COUNTDOWN_VALUE 0
+/* Allows 0.4096 second delay betwin ints */
+/* Each tick is 6.25 us */
+
+int Ttimer_val;
+bool benchmark_timer_find_average_overhead;
+
+rtems_isr timerisr(rtems_vector_number);
+
+void benchmark_timer_initialize(void)
+{
+ (void) set_vector(timerisr, TIMER_1_VECTOR, 0); /* install ISR */
+
+ Ttimer_val = 0; /* clear timer ISR count */
+ pcc->timer1_int_control = 0x00; /* Disable T1 Interr. */
+ pcc->timer1_preload = COUNTDOWN_VALUE;
+ /* write countdown preload value */
+ pcc->timer1_control = 0x00; /* load preload value */
+ pcc->timer1_control = 0x07; /* clear T1 overflow counter, enable counter */
+ pcc->timer1_int_control = TIMER_INT_LEVEL|0x08;
+ /* Enable Timer 1 and set its int. level */
+
+}
+
+#define AVG_OVERHEAD 0 /* No need to start/stop the timer to read
+ its value on the MVME147 PCC: reads are not
+ synchronized whith the counter updates*/
+#define LEAST_VALID 10 /* Don't trust a value lower than this */
+
+benchmark_timer_t benchmark_timer_read(void)
+{
+ uint32_t total;
+ uint16_t counter_value;
+
+ counter_value = pcc->timer1_count; /* read the counter value */
+
+ total = ((Ttimer_val * 0x10000) + counter_value); /* in 6.25 us units */
+ /* DC note : just look at the assembly generated
+ to see gcc's impressive optimization ! */
+ return total;
+
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(
+ bool find_flag
+)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/m68k/mvme147/btimer/timerisr.S b/bsps/m68k/mvme147/btimer/timerisr.S
new file mode 100644
index 0000000000..418cf64108
--- /dev/null
+++ b/bsps/m68k/mvme147/btimer/timerisr.S
@@ -0,0 +1,26 @@
+/* timer_isr()
+ *
+ * This routine provides the ISR for the PCC timer on the MVME147
+ * board. The timer is set up to generate an interrupt at maximum
+ * intervals.
+ *
+ * MVME147 port for TNI - Telecom Bretagne
+ * by Dominique LE CAMPION (Dominique.LECAMPION@enst-bretagne.fr)
+ * May 1996
+ */
+
+#include <rtems/asm.h>
+
+BEGIN_CODE
+
+.set T1_CONTROL_REGISTER, 0xfffe1018 | timer 1 control register
+
+ PUBLIC (timerisr)
+SYM (timerisr):
+ orb #0x80, T1_CONTROL_REGISTER | clear T1 int status bit
+ addql #1, SYM (Ttimer_val) | increment timer value
+end_timerisr:
+ rte
+
+END_CODE
+END
diff --git a/bsps/m68k/mvme162/btimer/btimer.c b/bsps/m68k/mvme162/btimer/btimer.c
new file mode 100644
index 0000000000..c7dce0475d
--- /dev/null
+++ b/bsps/m68k/mvme162/btimer/btimer.c
@@ -0,0 +1,73 @@
+/*
+ * This routine initializes the Tick Timer 1 on the MVME162 board.
+ *
+ * COPYRIGHT (c) 1989-1999.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ *
+ * Modifications of respective RTEMS file: COPYRIGHT (c) 1994.
+ * EISCAT Scientific Association. M.Savitski
+ *
+ * This material is a part of the MVME162 Board Support Package
+ * for the RTEMS executive. Its licensing policies are those of the
+ * RTEMS above.
+ */
+
+#include <rtems.h>
+#include <rtems/btimer.h>
+#include <bsp.h>
+
+/* Periodic tick interval */
+#define TICK_INTERVAL 0x10000U
+#define TIMER_INT_LEVEL 6
+
+uint32_t Ttimer_val;
+bool benchmark_timer_find_average_overhead;
+
+rtems_isr timerisr(rtems_vector_number vector);
+
+void benchmark_timer_initialize(void)
+{
+ (void) set_vector( timerisr, VBR0 * 0x10 + 0x8, 0 );
+
+ Ttimer_val = 0; /* clear timer ISR count */
+ lcsr->vector_base |= MASK_INT; /* unmask VMEchip2 interrupts */
+ lcsr->intr_clear |= 0x01000000; /* clear pending interrupt */
+ lcsr->to_ctl = 0xE7; /* prescaler to 1 MHz (see Appendix A1) */
+ lcsr->timer_cmp_1 = TICK_INTERVAL;
+ lcsr->timer_cnt_1 = 0; /* clear counter */
+ lcsr->board_ctl |= 7; /* increment, reset-on-compare, */
+ /* and clear-overflow-cnt */
+
+ lcsr->intr_level[0] |= TIMER_INT_LEVEL; /* set int level */
+ lcsr->intr_ena |= 0x01000000; /* enable tick timer 1 interrupt */
+}
+
+#define AVG_OVERHEAD 3U /* It typically takes 3.0 microseconds */
+ /* (3 countdowns) to start/stop the timer. */
+#define LEAST_VALID 10U /* Don't trust a value lower than this */
+
+benchmark_timer_t benchmark_timer_read(void)
+{
+ uint32_t total;
+
+ total = (Ttimer_val * TICK_INTERVAL) + lcsr->timer_cnt_1;
+
+ if ( benchmark_timer_find_average_overhead == true )
+ return total; /* in one-half microsecond units */
+
+ if ( total < LEAST_VALID )
+ return 0; /* below timer resolution */
+
+ return (total-AVG_OVERHEAD) >> 1;
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(
+ bool find_flag
+)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/m68k/mvme162/btimer/timerisr.S b/bsps/m68k/mvme162/btimer/timerisr.S
new file mode 100644
index 0000000000..c433d91c59
--- /dev/null
+++ b/bsps/m68k/mvme162/btimer/timerisr.S
@@ -0,0 +1,44 @@
+/* timer_isr()
+ *
+ * This routine provides the ISR for the Z8036 timer on the MVME136
+ * board. The timer is set up to generate an interrupt at maximum
+ * intervals.
+ *
+ * Input parameters: NONE
+ *
+ * Output parameters: NONE
+ *
+ * COPYRIGHT (c) 1989-1999.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ *
+ * Modifications of respective RTEMS file: COPYRIGHT (c) 1994.
+ * EISCAT Scientific Association. M.Savitski
+ *
+ * This material is a part of the MVME162 Board Support Package
+ * for the RTEMS executive. Its licensing policies are those of the
+ * RTEMS above.
+ */
+
+#include <rtems/asm.h>
+
+BEGIN_CODE
+
+.set INTR_CLEAR_REG, 0xfff40074 | interrupt clear register
+.set RELOAD, 0x01000000 | clear tick 1 interrupt
+
+ PUBLIC (Ttimer_val)
+ PUBLIC (timerisr)
+SYM (timerisr):
+ move.l a0, -(a7) | save a0
+ movea.l #INTR_CLEAR_REG, a0 | a0 = addr of cmd status reg
+ ori.l #RELOAD, (a0) | reload countdown
+ addq.l #1, SYM (Ttimer_val) | increment timer value
+ move.l (a7)+, a0 | restore a0
+ rte
+
+END_CODE
+END
diff --git a/bsps/m68k/mvme167/btimer/btimer.c b/bsps/m68k/mvme167/btimer/btimer.c
new file mode 100644
index 0000000000..ed2ce26e51
--- /dev/null
+++ b/bsps/m68k/mvme167/btimer/btimer.c
@@ -0,0 +1,139 @@
+/**
+ * @file
+ *
+ * This file manages the benchmark timer used by the RTEMS Timing Test Suite.
+ * Each measured time period is demarcated by calls to
+ * benchmark_timer_initialize() and benchmark_timer_read().
+ * benchmark_timer_read() usually returns the number of microseconds
+ * since benchmark_timer_initialize() exitted.
+ *
+ * These functions are prototyped in rtems/btimer.h and
+ * must be implemented as part of the BSP.
+ *
+ * This port does not allow the application to select which timer on the
+ * MVME167 to use for the timer, nor does it allow the application to
+ * configure the timer. The timer uses the VMEchip2 Tick Timer #1. This timer
+ * is distinct from the clock, which uses Tick Timer #2 in the VMEchip2.
+ *
+ * All page references are to the MVME166/MVME167/MVME187 Single Board
+ * Computer Programmer's Reference Guide (MVME187PG/D2) with the April 1993
+ * supplements/addenda (MVME187PG/D2A1).
+ */
+
+/*
+ * COPYRIGHT (c) 1989-1999.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ *
+ * Modifications of respective RTEMS file:
+ * Copyright (c) 1998, National Research Council of Canada
+ */
+
+#include <rtems.h>
+#include <rtems/btimer.h>
+#include <bsp.h>
+
+/* Periodic tick interval */
+#define TICK_INTERVAL 10000UL /* T1's countdown constant (10 ms) */
+#define TIMER_INT_LEVEL 6 /* T1's interrupt level */
+#define TIMER_VECTOR (VBR0 * 0x10 + 0x8) /* T1 is vector $X8 (p. 2-71)*/
+
+/* Number of interrupts since timer was re-initialized */
+uint32_t Ttimer_val;
+
+/*
+ * Set to true to return raw value. Normally zero. Depends on being allocated
+ * in the .bss section and on that section being explicitly zeroed at boot
+ * time.
+ */
+bool benchmark_timer_find_average_overhead;
+
+rtems_isr timerisr(rtems_vector_number);
+
+/*
+ * This routine initializes the Tick Timer 1 on the MVME167 board.
+ *
+ * Input parameters: NONE
+ *
+ * Output parameters: NONE
+ *
+ * NOTE: This routine may not work if the optimizer is enabled for some
+ * compilers. The multiple writes may be optimized away.
+ *
+ * It is important that the timer start/stop overhead be
+ * determined when porting or modifying this code.
+ *
+ * THE VMECHIP2 PRESCALER REGISTER IS ASSUMED TO BE SET!
+ * The prescaler is used by all VMEchip2 timers, including the VMEbus grant
+ * timeout counter, the DMAC time off timer, the DMAC timer on timer, and the
+ * VMEbus global timeout timer. The prescaler value is normally set by the
+ * boot ROM to provide a 1 MHz clock to the timers. For a 25 MHz MVME167, the
+ * prescaler value should be 0xE7 (page 2-63).
+ */
+void benchmark_timer_initialize(void)
+{
+ (void) set_vector( timerisr, TIMER_VECTOR, 0 );
+
+ Ttimer_val = 0; /* clear timer ISR count */
+ lcsr->intr_ena &= 0xFEFFFFFF; /* disable tick timer 1 interrupt */
+ lcsr->intr_clear |= 0x01000000; /* clear tick timer 1 interrupt */
+ lcsr->intr_level[0] = /* set int level */
+ (lcsr->intr_level[0] & 0xFFFFFFF0) | TIMER_INT_LEVEL;
+ lcsr->timer_cmp_1 = TICK_INTERVAL; /* period in compare register */
+ lcsr->timer_cnt_1 = 0; /* clear tick timer 1 counter */
+ lcsr->board_ctl |= 7; /* start tick timer 1, reset-on-compare, */
+ /* and clear overflow counter */
+
+ lcsr->intr_ena |= 0x01000000; /* enable tick timer 1 interrupt */
+ lcsr->vector_base |= MASK_INT; /* unmask VMEchip2 interrupts */
+}
+
+#define AVG_OVERHEAD 3UL /* It typically takes 3.0 microseconds */
+ /* (3 countdowns) to start/stop the timer. */
+#define LEAST_VALID 3UL /* Don't trust a value lower than this */
+
+/*
+ * This routine reads the Tick Timer 1 on the MVME167 board.
+ *
+ * Input parameters: NONE
+ *
+ * Output parameters: time in microseconds
+ *
+ * AVG_OVEREHAD is the overhead for starting and stopping the timer. It
+ * is usually deducted from the number returned.
+ *
+ * LEAST_VALID is the lowest number this routine should trust. Numbers
+ * below this are "noise" and zero is returned.
+ */
+benchmark_timer_t benchmark_timer_read(void)
+{
+ uint32_t total;
+
+ total = (Ttimer_val * TICK_INTERVAL) + lcsr->timer_cnt_1;
+
+ if ( benchmark_timer_find_average_overhead )
+ return total; /* in one microsecond units */
+
+ if ( total < LEAST_VALID )
+ return 0; /* below timer resolution */
+
+ return total - AVG_OVERHEAD;
+}
+
+/*
+ * This routine sets the benchmark_timer_find_average_overhead flag in this
+ * module.
+ *
+ * Input parameters: NONE
+ *
+ * Output parameters: time in microseconds
+ */
+void benchmark_timer_disable_subtracting_average_overhead(
+ bool find_flag
+)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/m68k/mvme167/btimer/timerisr.S b/bsps/m68k/mvme167/btimer/timerisr.S
new file mode 100644
index 0000000000..d96f0996a5
--- /dev/null
+++ b/bsps/m68k/mvme167/btimer/timerisr.S
@@ -0,0 +1,50 @@
+/**
+ * @file
+ *
+ * This ISR is used to bump a count of interval "overflow" interrupts which
+ * have occurred since the timer was started. The number of overflows is taken
+ * into account in the benchmark_timer_read() routine.
+ */
+
+/*
+ * COPYRIGHT (c) 1989-2014.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ *
+ * Modifications of respective RTEMS file: COPYRIGHT (c) 1994.
+ * Copyright (c) 1998, National Research Council of Canada
+ */
+
+#include <rtems/asm.h>
+
+BEGIN_CODE
+
+.set INTR_CLEAR_REG, 0xfff40074 | interrupt clear register
+.set T1_CNTRL_REG, 0xfff40060 | tick timer 1 control register
+.set CLEAR_INT, 0x01000000 | clear tick 1 interrupt
+.set CLEAR_OVF, 0x00000004 | clear tick 1 overflow counter
+
+ PUBLIC (Ttimer_val)
+ PUBLIC (timerisr)
+SYM (timerisr):
+ move.l a0, -(a7) | save a0
+ move.l d0, -(a7) | save d0
+ move.w sr, -(a7) | save ccr
+ movea.l #INTR_CLEAR_REG, a0 | a0 = addr of intr clr reg
+ ori.l #CLEAR_INT, (a0) | clear tick timer 1 intr
+ movea.l #T1_CNTRL_REG, a0 | a0 = addr of t1 cntrl reg
+ move.l (a0), d0 | read overflow counter
+ lsr.l #4, d0 | put overflow in low order bits
+ andi.l #0xF, d0 | keep only overflow
+ add.l d0, SYM (Ttimer_val) | increment timer value
+ ori.l #CLEAR_OVF, (a0) | clear overflow counter
+ move.w (a7)+, sr | restore ccr
+ move.l (a7)+, d0 | restore d0
+ move.l (a7)+, a0 | restore a0
+ rte
+
+END_CODE
+END
diff --git a/bsps/m68k/uC5282/btimer/btimer.c b/bsps/m68k/uC5282/btimer/btimer.c
new file mode 100644
index 0000000000..e01b9c8269
--- /dev/null
+++ b/bsps/m68k/uC5282/btimer/btimer.c
@@ -0,0 +1,47 @@
+/*
+ * Timer Init
+ *
+ * Use the last DMA timer (DTIM3) as the diagnostic timer.
+ *
+ * Author: W. Eric Norum <norume@aps.anl.gov>
+ *
+ * COPYRIGHT (c) 2005.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <rtems/btimer.h>
+
+void
+benchmark_timer_initialize(void)
+{
+ int preScaleDivisor = bsp_get_CPU_clock_speed() / 1000000;
+ int div = MCF5282_TIMER_DTMR_CLK_DIV1;
+
+ if (preScaleDivisor > 256) {
+ preScaleDivisor /= 16;
+ div = MCF5282_TIMER_DTMR_CLK_DIV16;
+ }
+ MCF5282_TIMER3_DTMR = 0;
+ MCF5282_TIMER3_DTMR = MCF5282_TIMER_DTMR_PS(preScaleDivisor - 1) | div |
+ MCF5282_TIMER_DTMR_RST;
+}
+
+/*
+ * Return timer value in microsecond units
+ */
+uint32_t
+benchmark_timer_read(void)
+{
+ return MCF5282_TIMER3_DTCN;
+}
+
+void
+benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+}
diff --git a/bsps/mips/csb350/btimer/btimer.c b/bsps/mips/csb350/btimer/btimer.c
new file mode 100644
index 0000000000..30dbfe836b
--- /dev/null
+++ b/bsps/mips/csb350/btimer/btimer.c
@@ -0,0 +1,57 @@
+/*
+ * This file implements a benchmark timer using the count/compare
+ * CP0 registers.
+ *
+ * Copyright (c) 2005 by Cogent Computer Systems
+ * Written by Jay Monkman <jtm@lopingdog.com>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <assert.h>
+
+#include <bsp.h>
+#include <rtems/btimer.h>
+
+bool benchmark_timer_find_average_overhead;
+uint32_t tstart;
+
+void benchmark_timer_initialize(void)
+{
+ __asm__ volatile ("mfc0 %0, $9\n" : "=r" (tstart));
+ /* tick time in picooseconds */
+}
+
+#define AVG_OVERHEAD 0 /* It typically takes N instructions */
+ /* to start/stop the timer. */
+#define LEAST_VALID 1 /* Don't trust a value lower than this */
+ /* tx39 simulator can count instructions. :) */
+
+benchmark_timer_t benchmark_timer_read(void)
+{
+ uint32_t total;
+ uint32_t cnt;
+
+ __asm__ volatile ("mfc0 %0, $9\n" : "=r" (cnt));
+
+ total = cnt - tstart;
+ total = (total * 1000) / 396; /* convert to nanoseconds */
+
+
+ if ( benchmark_timer_find_average_overhead == true )
+ return total; /* in one microsecond units */
+
+ if ( total < LEAST_VALID )
+ return 0; /* below timer resolution */
+
+ return total - AVG_OVERHEAD;
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(
+ bool find_flag
+)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/mips/jmr3904/btimer/btimer.c b/bsps/mips/jmr3904/btimer/btimer.c
new file mode 100644
index 0000000000..ca97cd3a0b
--- /dev/null
+++ b/bsps/mips/jmr3904/btimer/btimer.c
@@ -0,0 +1,67 @@
+/*
+ * This file implements a benchmark timer using a TX39 timer.
+ *
+ * NOTE: On the simulator, the count directly reflects instructions.
+ *
+ * COPYRIGHT (c) 1989-2000.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <assert.h>
+
+#include <bsp.h>
+#include <rtems/btimer.h>
+
+bool benchmark_timer_find_average_overhead;
+
+void benchmark_timer_initialize(void)
+{
+ /*
+ * Programming the compare register as the maximum value should let
+ * it run long enough and accurate enough not to require an interrupt.
+ * but if it ever does generate an interrupt, we will simply fault.
+ *
+ * NOTE: This is similar to the clock driver initialization
+ * with the exception that the divider is disabled and
+ * the compare register is set to the maximum value.
+ */
+
+ TX3904_TIMER_WRITE( TX3904_TIMER1_BASE, TX3904_TIMER_TCR, 0x20 );
+ TX3904_TIMER_WRITE( TX3904_TIMER1_BASE, TX3904_TIMER_CCDR, 0x3 );
+ TX3904_TIMER_WRITE( TX3904_TIMER1_BASE, TX3904_TIMER_TRR, 0x0 );
+ TX3904_TIMER_WRITE( TX3904_TIMER1_BASE, TX3904_TIMER_CPRA, 0xFFFFFFFF );
+ TX3904_TIMER_WRITE( TX3904_TIMER1_BASE, TX3904_TIMER_TISR, 0x00 );
+ TX3904_TIMER_WRITE( TX3904_TIMER1_BASE, TX3904_TIMER_ITMR, 0x0001 );
+ TX3904_TIMER_WRITE( TX3904_TIMER1_BASE, TX3904_TIMER_TCR, 0xe0 );
+}
+
+#define AVG_OVERHEAD 0 /* It typically takes N instructions */
+ /* to start/stop the timer. */
+#define LEAST_VALID 1 /* Don't trust a value lower than this */
+ /* tx39 simulator can count instructions. :) */
+
+benchmark_timer_t benchmark_timer_read(void)
+{
+ uint32_t total;
+
+ total = TX3904_TIMER_READ( TX3904_TIMER1_BASE, TX3904_TIMER_TRR );
+
+ if ( benchmark_timer_find_average_overhead == true )
+ return total; /* in one microsecond units */
+
+ if ( total < LEAST_VALID )
+ return 0; /* below timer resolution */
+
+ return total - AVG_OVERHEAD;
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(
+ bool find_flag
+)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/nios2/nios2_iss/btimer/btimer.c b/bsps/nios2/nios2_iss/btimer/btimer.c
new file mode 100644
index 0000000000..fbb20d892b
--- /dev/null
+++ b/bsps/nios2/nios2_iss/btimer/btimer.c
@@ -0,0 +1,137 @@
+/*
+ * This file manages the benchmark timer used by the RTEMS Timing Test
+ * Suite. Each measured time period is demarcated by calls to
+ * benchmark_timer_initialize() and benchmark_timer_read().
+ * benchmark_timer_read() usually returns the number of microseconds
+ * since benchmark_timer_initialize() exitted.
+ *
+ * NOTE: It is important that the timer start/stop overhead be
+ * determined when porting or modifying this code.
+ */
+
+/*
+ * COPYRIGHT (c) 2005-2006 Kolja Waschk rtemsdev/ixo.de
+ * Derived from no_cpu/no_bsp/timer/timer.c 1.9,
+ * COPYRIGHT (c) 1989-1999.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#define TIMER_WRAPS_AFTER_1MS 0
+
+#include <rtems.h>
+#include <rtems/btimer.h>
+#include <rtems/score/cpu.h>
+#include <bsp.h>
+
+volatile uint32_t Timer_interrupts;
+bool benchmark_timer_find_average_overhead;
+
+#define TIMER_REGS ((altera_avalon_timer_regs*)NIOS2_IO_BASE(TIMER_BASE))
+
+static rtems_isr timerisr(rtems_vector_number vector)
+{
+ TIMER_REGS->status = 0;
+ Timer_interrupts++;
+}
+
+void benchmark_timer_initialize( void )
+{
+ /* Disable timer interrupt, stop timer */
+
+ TIMER_REGS->control = ALTERA_AVALON_TIMER_CONTROL_STOP_MSK;
+
+ set_vector(timerisr, TIMER_VECTOR, 1);
+
+ /* Enable interrupt processing */
+
+ NIOS2_IENABLE(1 << TIMER_VECTOR);
+
+#if TIMER_WRAPS_AFTER_1MS
+ /* Writing to periodl/h resets the counter and eventually
+ stops it. If the timer hasn't been configured with fixed
+ period, set it to 1 ms now */
+
+ TIMER_REGS->period_hi = (TIMER_FREQ/1000)>>16;
+ TIMER_REGS->period_lo = (TIMER_FREQ/1000)&0xFFFF;
+#else
+ /* Writing to periodl/h resets the counter and eventually
+ stops it. Set max period */
+
+ TIMER_REGS->period_hi = 0xFFFF;
+ TIMER_REGS->period_lo = 0xFFFF;
+#endif
+
+ /* For timers that can be stopped, writing to periodl/h
+ also stopped the timer and we have to manually start it. */
+
+ TIMER_REGS->control = ALTERA_AVALON_TIMER_CONTROL_ITO_MSK |
+ ALTERA_AVALON_TIMER_CONTROL_CONT_MSK |
+ ALTERA_AVALON_TIMER_CONTROL_START_MSK;
+
+ /* This is the most safe place for resetting the overflow
+ counter - just _after_ we reset the timer. Depending
+ on the SOPC configuration, the counter may not be
+ stoppable and it doesn't make sense to assume that
+ there is any "safe" period before resetting. */
+
+ Timer_interrupts = 0;
+}
+
+/*
+ * The following controls the behavior of benchmark_timer_read().
+ *
+ * AVG_OVEREHAD is the overhead for starting and stopping the timer. It
+ * is usually deducted from the number returned.
+ *
+ * LEAST_VALID is the lowest number this routine should trust. Numbers
+ * below this are "noise" and zero is returned.
+ */
+
+#define AVG_OVERHEAD 2 /* It typically takes 2 microseconds */
+ /* to start/stop the timer. */
+
+#define LEAST_VALID AVG_OVERHEAD /* Don't trust a value lower than this */
+
+benchmark_timer_t benchmark_timer_read( void )
+{
+ uint32_t timer_wraps;
+ uint32_t timer_snap;
+ uint32_t timer_ticks;
+ uint32_t total;
+
+ /* Hold timer */
+ TIMER_REGS->control = ALTERA_AVALON_TIMER_CONTROL_STOP_MSK;
+
+ /* Write to request snapshot of timer value */
+ TIMER_REGS->snap_lo = 0;
+ /* Get snapshot */
+ timer_snap = ((TIMER_REGS->snap_hi)<<16) | TIMER_REGS->snap_lo;
+ timer_wraps = Timer_interrupts;
+
+ /* Restart timer */
+ TIMER_REGS->control = ALTERA_AVALON_TIMER_CONTROL_START_MSK;
+
+#if TIMER_WRAPS_AFTER_1MS
+ timer_ticks = (TIMER_FREQ / 1000) - 1 - timer_snap;
+ total = timer_wraps * 1000;
+#else
+ timer_ticks = 0xFFFFFFFF - timer_snap;
+ total = timer_wraps * 0x80000000 / (TIMER_FREQ / 2000000L);
+#endif
+ total += timer_ticks / (TIMER_FREQ / 1000000L);
+
+ if(total < LEAST_VALID) return 0;
+
+ if(benchmark_timer_find_average_overhead != TRUE) total-= AVG_OVERHEAD;
+
+ return total;
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/no_cpu/no_bsp/btimer/btimer.c b/bsps/no_cpu/no_bsp/btimer/btimer.c
new file mode 100644
index 0000000000..e9b59dc756
--- /dev/null
+++ b/bsps/no_cpu/no_bsp/btimer/btimer.c
@@ -0,0 +1,92 @@
+/* timer.c
+ *
+ * This file manages the benchmark timer used by the RTEMS Timing Test
+ * Suite. Each measured time period is demarcated by calls to
+ * benchmark_timer_initialize() and benchmark_timer_read(). benchmark_timer_read() usually returns
+ * the number of microseconds since benchmark_timer_initialize() exitted.
+ *
+ * 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.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <rtems/btimer.h>
+#include <bsp.h>
+
+uint32_t Timer_interrupts;
+bool benchmark_timer_find_average_overhead;
+
+void benchmark_timer_initialize( void )
+{
+
+ /*
+ * Timer has never overflowed. This may not be necessary on some
+ * implemenations of timer but ....
+ */
+
+ Timer_interrupts = 0;
+
+ /*
+ * Somehow start the timer
+ */
+}
+
+/*
+ * The following controls the behavior of benchmark_timer_read().
+ *
+ * AVG_OVEREHAD is the overhead for starting and stopping the timer. It
+ * is usually deducted from the number returned.
+ *
+ * LEAST_VALID is the lowest number this routine should trust. Numbers
+ * below this are "noise" and zero is returned.
+ */
+
+#define AVG_OVERHEAD 0 /* It typically takes X.X microseconds */
+ /* (Y countdowns) to start/stop the timer. */
+ /* This value is in microseconds. */
+#define LEAST_VALID 1 /* Don't trust a clicks value lower than this */
+
+benchmark_timer_t benchmark_timer_read( void )
+{
+ uint32_t clicks;
+ uint32_t total;
+
+ /*
+ * Read the timer and see how many clicks it has been since we started.
+ */
+
+ clicks = 0; /* XXX: read some HW here */
+
+ /*
+ * Total is calculated by taking into account the number of timer overflow
+ * interrupts since the timer was initialized and clicks since the last
+ * interrupts.
+ */
+
+ total = clicks * 0;
+
+ if ( benchmark_timer_find_average_overhead == true )
+ return total; /* in XXX microsecond units */
+ else {
+ if ( total < LEAST_VALID )
+ return 0; /* below timer resolution */
+ /*
+ * Somehow convert total into microseconds
+ */
+ return (total - AVG_OVERHEAD);
+ }
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(
+ bool find_flag
+)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/no_cpu/no_bsp/btimer/timerisr.c b/bsps/no_cpu/no_bsp/btimer/timerisr.c
new file mode 100644
index 0000000000..5ca7152a54
--- /dev/null
+++ b/bsps/no_cpu/no_bsp/btimer/timerisr.c
@@ -0,0 +1,38 @@
+/**
+ * @file
+ *
+ * If required this ISR is used to bump a count of interval "overflow"
+ * interrupts which have occurred since the timer was started. The
+ * number of overflows is taken into account in the benchmark_timer_read()
+ * routine if necessary.
+ *
+ * To reduce overhead this is best to be the "rawest" hardware interupt
+ * handler you can write. This should be the only interrupt which can
+ * occur during the measured time period.
+ *
+ * @note This file is USUALLY in assembly and is LEAN AND MEAN.
+ * Any code in this isr is pure overhead which can perturb
+ * the accuracy of the Timing Test Suite.
+ */
+
+/*
+ * COPYRIGHT (c) 1989-1999.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <rtems/btimer.h>
+
+extern uint32_t _Timer_interrupts;
+
+void timerisr( void )
+{
+ /*
+ * _Timer_interrupts += TIMER_BETWEEN_OVERFLOWS (usually in microseconds)
+ * return from interrupt
+ */
+}
diff --git a/bsps/or1k/generic_or1k/btimer/btimer.c b/bsps/or1k/generic_or1k/btimer/btimer.c
new file mode 100644
index 0000000000..872f1af7be
--- /dev/null
+++ b/bsps/or1k/generic_or1k/btimer/btimer.c
@@ -0,0 +1,64 @@
+/**
+ * @file
+ *
+ * @ingroup generic_or1k
+ *
+ * @brief Benchmark timer support.
+ */
+
+/*
+ * Copyright (c) 2014-2015 by Hesham ALMatary
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE
+ */
+
+#include <rtems.h>
+#include <rtems/btimer.h>
+#include <bsp/generic_or1k.h>
+#include <rtems/score/or1k-utility.h>
+
+#define OR1K_NANOSECONDS_PER_CLK_CYCLE 10
+
+static bool benchmark_timer_find_average_overhead = false;
+static uint64_t benchmark_timer_base;
+
+void benchmark_timer_initialize(void)
+{
+ benchmark_timer_base = _OR1K_mfspr(CPU_OR1K_SPR_TTCR);
+}
+
+#define AVG_OVERHEAD 0
+#define LEAST_VALID 1
+
+benchmark_timer_t benchmark_timer_read( void )
+{
+ uint64_t clicks;
+ uint64_t total;
+ uint64_t delta;
+ /*
+ * Read the timer and see how many clicks (clock cycles)
+ * has passed since timer initialization.
+ */
+ clicks = _OR1K_mfspr(CPU_OR1K_SPR_TTCR);
+
+ delta = clicks - benchmark_timer_base;
+
+ /* total in nanoseconds */
+ total = OR1K_NANOSECONDS_PER_CLK_CYCLE * (delta);
+
+ if ( benchmark_timer_find_average_overhead == true )
+ return total; /* in nanoseconds microsecond units */
+ else {
+ if ( total < LEAST_VALID )
+ return 0; /* below timer resolution */
+
+ return (total - AVG_OVERHEAD);
+ }
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/powerpc/qoriq/btimer/btimer.c b/bsps/powerpc/qoriq/btimer/btimer.c
new file mode 100644
index 0000000000..e8927c1194
--- /dev/null
+++ b/bsps/powerpc/qoriq/btimer/btimer.c
@@ -0,0 +1,42 @@
+/**
+ * @file
+ *
+ * @ingroup QorIQ
+ *
+ * @brief QorIQ benchmark timer.
+ */
+
+/*
+ * Copyright (c) 2011 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems/btimer.h>
+
+#include <libcpu/powerpc-utility.h>
+
+static benchmark_timer_t benchmark_timer_base;
+
+void benchmark_timer_initialize(void)
+{
+ benchmark_timer_base = ppc_alternate_time_base();
+}
+
+benchmark_timer_t benchmark_timer_read(void)
+{
+ return ppc_alternate_time_base() - benchmark_timer_base;
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(bool find_average_overhead)
+{
+ /* VOID */
+}
diff --git a/bsps/powerpc/tqm8xx/btimer/btimer.c b/bsps/powerpc/tqm8xx/btimer/btimer.c
new file mode 100644
index 0000000000..06c43c56be
--- /dev/null
+++ b/bsps/powerpc/tqm8xx/btimer/btimer.c
@@ -0,0 +1,101 @@
+/*===============================================================*\
+| Project: RTEMS TQM8xx BSP |
++-----------------------------------------------------------------+
+| This file has been adapted to MPC8xx by |
+| Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> |
+| Copyright (c) 2008 |
+| Embedded Brains GmbH |
+| Obere Lagerstr. 30 |
+| D-82178 Puchheim |
+| Germany |
+| rtems@embedded-brains.de |
+| |
+| See the other copyright notice below for the original parts. |
++-----------------------------------------------------------------+
+| The license and distribution terms for this file may be |
+| found in the file LICENSE in this distribution or at |
+| |
+| http://www.rtems.org/license/LICENSE. |
+| |
++-----------------------------------------------------------------+
+| this file contains the console driver |
+\*===============================================================*/
+/*
+ * benchmark_timer_initialize()
+ *
+ * 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 <Thomas.Doerfler@embedded-brains.de>
+ */
+
+/*
+ *
+ * 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.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <rtems/btimer.h>
+#include <mpc8xx.h>
+
+bool benchmark_timer_find_average_overhead;
+
+void
+benchmark_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
+ */
+benchmark_timer_t benchmark_timer_read(void)
+{
+ uint32_t retval;
+ retval = *(uint32_t*)&m8xx.tcn1;
+ retval = retval * 1000000LL / BSP_bus_frequency;
+ return retval;
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(
+ bool find_flag
+)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/riscv/riscv_generic/btimer/btimer.c b/bsps/riscv/riscv_generic/btimer/btimer.c
new file mode 100644
index 0000000000..4dd3193685
--- /dev/null
+++ b/bsps/riscv/riscv_generic/btimer/btimer.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015 University of York.
+ * Hesham Almatary <hesham@alumni.york.ac.uk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <rtems/btimer.h>
+#include <rtems/score/riscv-utility.h>
+
+extern char bsp_start_vector_table_begin[];
+
+bool benchmark_timer_find_average_overhead;
+
+static void benchmark_timer1_interrupt_handler(void)
+{
+}
+
+/* Start eCore tiemr 1 usef for profiling and timing analysis */
+void benchmark_timer_initialize( void )
+{
+ /* Install interrupt handler for timer 1 */
+}
+
+/*
+ * The following controls the behavior of benchmark_timer_read().
+ *
+ * AVG_OVEREHAD is the overhead for starting and stopping the timer. It
+ * is usually deducted from the number returned.
+ *
+ * LEAST_VALID is the lowest number this routine should trust. Numbers
+ * below this are "noise" and zero is returned.
+ */
+
+#define AVG_OVERHEAD 0 /* It typically takes X.X microseconds */
+/* (Y countdowns) to start/stop the timer. */
+/* This value is in microseconds. */
+#define LEAST_VALID 1 /* Don't trust a clicks value lower than this */
+
+benchmark_timer_t benchmark_timer_read( void )
+{
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(
+ bool find_flag
+)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/sh/gensh1/btimer/btimer.c b/bsps/sh/gensh1/btimer/btimer.c
new file mode 100644
index 0000000000..94a834cb1e
--- /dev/null
+++ b/bsps/sh/gensh1/btimer/btimer.c
@@ -0,0 +1,195 @@
+/**
+ * @file
+ * @brief Timer for the Hitachi SH 703X
+ */
+
+/*
+ * Authors: Ralf Corsepius (corsepiu@faw.uni-ulm.de) and
+ * Bernd Becker (becker@faw.uni-ulm.de)
+ *
+ * COPYRIGHT (c) 1997-1998, FAW Ulm, Germany
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * COPYRIGHT (c) 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.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <rtems/btimer.h>
+
+#include <rtems/score/sh_io.h>
+#include <rtems/score/ispsh7032.h>
+#include <rtems/score/iosh7032.h>
+
+extern uint32_t bsp_clicks_per_second;
+
+#define I_CLK_PHI_1 0
+#define I_CLK_PHI_2 1
+#define I_CLK_PHI_4 2
+#define I_CLK_PHI_8 3
+
+/*
+ * Set I_CLK_PHI to one of the I_CLK_PHI_X values from above to choose
+ * a PHI/X clock rate.
+ */
+
+#define I_CLK_PHI I_CLK_PHI_4
+#define CLOCK_SCALE (1<<I_CLK_PHI)
+
+#define ITU1_STARTMASK 0xfd
+#define ITU1_SYNCMASK 0xfd
+#define ITU1_MODEMASK 0xfd
+#define ITU1_TCRMASK (0x00 | I_CLK_PHI)
+#define ITU1_TIORMASK 0x88
+#define ITU1_STAT_MASK 0xf8
+#define ITU1_TIERMASK 0xfc
+#define IPRC_ITU1_MASK 0xfff0
+
+#ifndef ITU1_PRIO
+#define ITU1_PRIO 15
+#endif
+
+#define ITU1_VECTOR OVI1_ISP_V
+
+extern rtems_isr timerisr(void);
+
+static uint32_t Timer_interrupts;
+
+bool benchmark_timer_find_average_overhead;
+
+static uint32_t Timer_HZ ;
+
+void benchmark_timer_initialize( void )
+{
+ uint8_t temp8;
+ uint16_t temp16;
+ rtems_interrupt_level level;
+ rtems_isr *ignored;
+
+ Timer_HZ = bsp_clicks_per_second / CLOCK_SCALE ;
+
+ /*
+ * Timer has never overflowed. This may not be necessary on some
+ * implemenations of timer but ....
+ */
+
+ Timer_interrupts /* .i */ = 0;
+ rtems_interrupt_disable( level );
+
+ /*
+ * Somehow start the timer
+ */
+ /* stop Timer 1 */
+ temp8 = read8(ITU_TSTR) & ITU1_STARTMASK;
+ write8( temp8, ITU_TSTR );
+
+ /* initialize counter 1 */
+ write16( 0, ITU_TCNT1 );
+
+ /* Timer 1 is independent of other timers */
+ temp8 = read8(ITU_TSNC) & ITU1_SYNCMASK;
+ write8( temp8, ITU_TSNC );
+
+ /* Timer 1, normal mode */
+ temp8 = read8(ITU_TMDR) & ITU1_MODEMASK;
+ write8( temp8, ITU_TMDR );
+
+ /* Use a Phi/X counter */
+ write8( ITU1_TCRMASK, ITU_TCR1 );
+
+ /* gra and grb are not used */
+ write8( ITU1_TIORMASK, ITU_TIOR1 );
+
+ /* reset all status flags */
+ temp8 = read8(ITU_TSR1) & ITU1_STAT_MASK;
+ write8( temp8, ITU_TSR1 );
+
+ /* enable overflow interrupt */
+ write8( ITU1_TIERMASK, ITU_TIER1 );
+
+ /* set interrupt priority */
+ temp16 = read16(INTC_IPRC) & IPRC_ITU1_MASK;
+ temp16 |= ITU1_PRIO;
+ write16( temp16, INTC_IPRC );
+
+ /* initialize ISR */
+ _CPU_ISR_install_raw_handler( ITU1_VECTOR, timerisr, &ignored );
+ rtems_interrupt_enable( level );
+
+ /* start timer 1 */
+ temp8 = read8(ITU_TSTR) | ~ITU1_STARTMASK;
+ write8( temp8, ITU_TSTR );
+}
+
+/*
+ * The following controls the behavior of benchmark_timer_read().
+ *
+ * AVG_OVERHEAD is the overhead for starting and stopping the timer. It
+ * is usually deducted from the number returned.
+ *
+ * LEAST_VALID is the lowest number this routine should trust. Numbers
+ * below this are "noise" and zero is returned.
+ */
+
+#define AVG_OVERHEAD 1 /* It typically takes X.X microseconds */
+ /* (Y countdowns) to start/stop the timer. */
+ /* This value is in microseconds. */
+#define LEAST_VALID 0 /* 20 */ /* Don't trust a clicks value lower than this */
+
+benchmark_timer_t benchmark_timer_read( void )
+{
+ uint32_t cclicks;
+ uint32_t total ;
+ /*
+ * Read the timer and see how many clicks it has been since we started.
+ */
+
+
+ cclicks = read16( ITU_TCNT1 ); /* XXX: read some HW here */
+
+ /*
+ * Total is calculated by taking into account the number of timer overflow
+ * interrupts since the timer was initialized and clicks since the last
+ * interrupts.
+ */
+
+ total = cclicks + Timer_interrupts * 65536;
+
+ if ( benchmark_timer_find_average_overhead )
+ return total / CLOCK_SCALE; /* in XXX microsecond units */
+ else
+ {
+ if ( total < LEAST_VALID )
+ return 0; /* below timer resolution */
+ /*
+ * Somehow convert total into microseconds
+ */
+ return (total / CLOCK_SCALE - AVG_OVERHEAD);
+ }
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
+
+/* Timer 1 is used */
+
+#pragma interrupt
+void timerisr( void )
+{
+ uint8_t temp8;
+
+ /* reset the flags of the status register */
+ temp8 = read8(ITU_TSR1) & ITU1_STAT_MASK;
+ write8( temp8, ITU_TSR1 );
+
+ Timer_interrupts += 1;
+}
diff --git a/bsps/sh/gensh2/btimer/btimer.c b/bsps/sh/gensh2/btimer/btimer.c
new file mode 100644
index 0000000000..152c99b1aa
--- /dev/null
+++ b/bsps/sh/gensh2/btimer/btimer.c
@@ -0,0 +1,191 @@
+/**
+ * @file
+ * @brief Timer for the Hitachi SH 704X
+ */
+
+/*
+ * Authors: Ralf Corsepius (corsepiu@faw.uni-ulm.de) and
+ * Bernd Becker (becker@faw.uni-ulm.de)
+ *
+ * COPYRIGHT (c) 1997-1998, FAW Ulm, Germany
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * COPYRIGHT (c) 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.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <rtems/btimer.h>
+
+#include <rtems/score/sh_io.h>
+#include <rtems/score/iosh7045.h>
+
+extern uint32_t bsp_clicks_per_second;
+
+/*
+ * We use a Phi/4 timer
+ */
+#define SCALE (Timer_MHZ/4)
+
+#define MTU1_STARTMASK 0xfd
+#define MTU1_SYNCMASK 0xfd
+#define MTU1_MODEMASK 0xc0
+#define MTU1_TCRMASK 0x01
+#define MTU1_TIORMASK 0x88
+#define MTU1_STAT_MASK 0xf8
+#define MTU1_TIERMASK 0xfc
+#define IPRC_MTU1_MASK 0xfff0
+
+#ifndef MTU1_PRIO
+#define MTU1_PRIO 15
+#endif
+
+#define MTU1_VECTOR 86
+
+extern rtems_isr timerisr(void);
+
+static uint32_t Timer_interrupts;
+
+bool benchmark_timer_find_average_overhead;
+
+static uint32_t Timer_MHZ ;
+
+void benchmark_timer_initialize( void )
+{
+ uint8_t temp8;
+ uint16_t temp16;
+ rtems_interrupt_level level;
+ rtems_isr *ignored;
+
+ Timer_MHZ = bsp_clicks_per_second / 1000000 ;
+
+ /*
+ * Timer has never overflowed. This may not be necessary on some
+ * implemenations of timer but ....
+ */
+
+ Timer_interrupts /* .i */ = 0;
+ rtems_interrupt_disable( level );
+
+ /*
+ * Somehow start the timer
+ */
+ /* stop Timer 1 */
+ temp8 = read8(MTU_TSTR) & MTU1_STARTMASK;
+ write8( temp8, MTU_TSTR );
+
+ /* initialize counter 1 */
+ write16( 0, MTU_TCNT1);
+
+ /* Timer 1 is independent of other timers */
+ temp8 = read8(MTU_TSYR) & MTU1_SYNCMASK;
+ write8( temp8, MTU_TSYR );
+
+ /* Timer 1, normal mode */
+ temp8 = read8(MTU_TMDR1) & MTU1_MODEMASK;
+ write8( temp8, MTU_TMDR1 );
+
+ /* x0000000
+ * |||||+++--- Internal Clock
+ * |||++------ Count on rising edge
+ * |++-------- disable TCNT clear
+ * +---------- don`t care
+ */
+ write8( MTU1_TCRMASK, MTU_TCR1 );
+
+ /* gra and grb are not used */
+ write8( MTU1_TIORMASK, MTU_TIOR1 );
+
+ /* reset all status flags */
+ temp8 = read8(MTU_TSR1) & MTU1_STAT_MASK;
+ write8( temp8, MTU_TSR1 );
+
+ /* enable overflow interrupt */
+ write8( MTU1_TIERMASK, MTU_TIER1 );
+
+ /* set interrupt priority */
+ temp16 = read16(INTC_IPRC) & IPRC_MTU1_MASK;
+ temp16 |= MTU1_PRIO;
+ write16( temp16, INTC_IPRC);
+
+ /* initialize ISR */
+ _CPU_ISR_install_raw_handler( MTU1_VECTOR, timerisr, &ignored );
+ rtems_interrupt_enable( level );
+
+ /* start timer 1 */
+ temp8 = read8(MTU_TSTR) | ~MTU1_STARTMASK;
+ write8( temp8, MTU_TSTR );
+}
+
+/*
+ * The following controls the behavior of benchmark_timer_read().
+ *
+ * AVG_OVERHEAD is the overhead for starting and stopping the timer. It
+ * is usually deducted from the number returned.
+ *
+ * LEAST_VALID is the lowest number this routine should trust. Numbers
+ * below this are "noise" and zero is returned.
+ */
+
+#define AVG_OVERHEAD 1 /* It typically takes X.X microseconds */
+ /* (Y countdowns) to start/stop the timer. */
+ /* This value is in microseconds. */
+#define LEAST_VALID 0 /* 20 */ /* Don't trust a clicks value lower than this */
+
+benchmark_timer_t benchmark_timer_read( void )
+{
+ uint32_t clicks;
+ uint32_t total ;
+ /*
+ * Read the timer and see how many clicks it has been since we started.
+ */
+
+
+ clicks = read16( MTU_TCNT1 ); /* XXX: read some HW here */
+
+ /*
+ * Total is calculated by taking into account the number of timer overflow
+ * interrupts since the timer was initialized and clicks since the last
+ * interrupts.
+ */
+
+ total = clicks + Timer_interrupts * 65536;
+
+ if ( benchmark_timer_find_average_overhead )
+ return total / SCALE; /* in XXX microsecond units */
+ else
+ {
+ if ( total < LEAST_VALID )
+ return 0; /* below timer resolution */
+ /*
+ * Somehow convert total into microseconds
+ */
+ return (total / SCALE - AVG_OVERHEAD) ;
+ }
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
+
+/* Timer 1 is used */
+
+#pragma interrupt
+void timerisr( void )
+{
+ uint8_t temp8;
+
+ /* reset the flags of the status register */
+ temp8 = read8(MTU_TSR1) & MTU1_STAT_MASK;
+ write8( temp8, MTU_TSR1 );
+
+ Timer_interrupts += 1;
+}
diff --git a/bsps/sh/gensh4/btimer/btimer.c b/bsps/sh/gensh4/btimer/btimer.c
new file mode 100644
index 0000000000..ef462c780c
--- /dev/null
+++ b/bsps/sh/gensh4/btimer/btimer.c
@@ -0,0 +1,269 @@
+/**
+ * @file
+ * @brief Timer driver for the Hitachi SH 7750
+ */
+
+/*
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Victor V. Vengerov <vvv@oktet.ru>
+ *
+ * COPYRIGHT (c) 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.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <rtems/btimer.h>
+
+#include <rtems/score/sh_io.h>
+#include <rtems/score/iosh7750.h>
+
+extern uint32_t bsp_clicks_per_second;
+
+#ifndef TIMER_PRIO
+#define TIMER_PRIO 15
+#endif
+
+/* Timer prescaler division ratio */
+#define TIMER_PRESCALER 4
+#define TCR1_TPSC SH7750_TCR_TPSC_DIV4
+
+#define TIMER_VECTOR SH7750_EVT_TO_NUM(SH7750_EVT_TUNI1)
+
+extern rtems_isr timerisr(void);
+
+static uint32_t Timer_interrupts;
+
+/* Counter should be divided to this value to obtain time in microseconds */
+static uint32_t microseconds_divider;
+
+/* Interrupt period in microseconds */
+static uint32_t microseconds_per_int;
+
+bool benchmark_timer_find_average_overhead;
+
+/* benchmark_timer_initialize --
+ * Initialize Timer 1 to operate as a RTEMS benchmark timer:
+ * - determine timer clock frequency
+ * - install timer interrupt handler
+ * - configure the Timer 1 hardware
+ * - start the timer
+ *
+ * PARAMETERS:
+ * none
+ *
+ * RETURNS:
+ * none
+ */
+void
+benchmark_timer_initialize(void)
+{
+ uint8_t temp8;
+ uint16_t temp16;
+ rtems_interrupt_level level;
+ rtems_isr *ignored;
+ int cpudiv = 1;
+ int tidiv = 1;
+
+ Timer_interrupts = 0;
+ rtems_interrupt_disable(level);
+
+ /* Get CPU frequency divider from clock unit */
+ switch (read16(SH7750_FRQCR) & SH7750_FRQCR_IFC)
+ {
+ case SH7750_FRQCR_IFCDIV1:
+ cpudiv = 1;
+ break;
+
+ case SH7750_FRQCR_IFCDIV2:
+ cpudiv = 2;
+ break;
+
+ case SH7750_FRQCR_IFCDIV3:
+ cpudiv = 3;
+ break;
+
+ case SH7750_FRQCR_IFCDIV4:
+ cpudiv = 4;
+ break;
+
+ case SH7750_FRQCR_IFCDIV6:
+ cpudiv = 6;
+ break;
+
+ case SH7750_FRQCR_IFCDIV8:
+ cpudiv = 8;
+ break;
+
+ default:
+ rtems_fatal_error_occurred( RTEMS_NOT_CONFIGURED);
+ }
+
+ /* Get peripheral module frequency divider from clock unit */
+ switch (read16(SH7750_FRQCR) & SH7750_FRQCR_PFC)
+ {
+ case SH7750_FRQCR_PFCDIV2:
+ tidiv = 2 * TIMER_PRESCALER;
+ break;
+
+ case SH7750_FRQCR_PFCDIV3:
+ tidiv = 3 * TIMER_PRESCALER;
+ break;
+
+ case SH7750_FRQCR_PFCDIV4:
+ tidiv = 4 * TIMER_PRESCALER;
+ break;
+
+ case SH7750_FRQCR_PFCDIV6:
+ tidiv = 6 * TIMER_PRESCALER;
+ break;
+
+ case SH7750_FRQCR_PFCDIV8:
+ tidiv = 8 * TIMER_PRESCALER;
+ break;
+
+ default:
+ rtems_fatal_error_occurred( RTEMS_NOT_CONFIGURED);
+ }
+
+ microseconds_divider = bsp_clicks_per_second * cpudiv / (tidiv * 1000000);
+ microseconds_per_int = 0xFFFFFFFF / microseconds_divider;
+
+ /*
+ * Hardware specific initialization
+ */
+
+ /* Stop the Timer 0 */
+ temp8 = read8(SH7750_TSTR);
+ temp8 &= ~SH7750_TSTR_STR1;
+ write8(temp8, SH7750_TSTR);
+
+ /* Establish interrupt handler */
+ _CPU_ISR_install_raw_handler( TIMER_VECTOR, timerisr, &ignored );
+
+ /* Reset timer constant and counter */
+ write32(0xFFFFFFFF, SH7750_TCOR1);
+ write32(0xFFFFFFFF, SH7750_TCNT1);
+
+ /* Select timer mode */
+ write16(
+ SH7750_TCR_UNIE | /* Enable Underflow Interrupt */
+ SH7750_TCR_CKEG_RAISE | /* Count on rising edge */
+ TCR1_TPSC, /* Timer prescaler ratio */
+ SH7750_TCR1);
+
+ /* Set timer interrupt priority */
+ temp16 = read16(SH7750_IPRA);
+ temp16 = (temp16 & ~SH7750_IPRA_TMU1) | (TIMER_PRIO << SH7750_IPRA_TMU1_S);
+ write16(temp16, SH7750_IPRA);
+
+
+ rtems_interrupt_enable(level);
+
+ /* Start the Timer 1 */
+ temp8 = read8(SH7750_TSTR);
+ temp8 |= SH7750_TSTR_STR1;
+ write8(temp8, SH7750_TSTR);
+
+}
+
+/*
+ * The following controls the behavior of benchmark_timer_read().
+ *
+ * AVG_OVERHEAD is the overhead for starting and stopping the timer. It
+ * is usually deducted from the number returned.
+ *
+ * LEAST_VALID is the lowest number this routine should trust. Numbers
+ * below this are "noise" and zero is returned.
+ */
+
+#define AVG_OVERHEAD 0 /* It typically takes X.X microseconds */
+ /* (Y countdowns) to start/stop the timer. */
+ /* This value is in microseconds. */
+#define LEAST_VALID 0 /* 20 */ /* Don't trust a clicks value lower than this */
+
+/* benchmark_timer_read --
+ * Read timer value in microsecond units since timer start.
+ *
+ * PARAMETERS:
+ * none
+ *
+ * RETURNS:
+ * number of microseconds since timer has been started
+ */
+benchmark_timer_t
+benchmark_timer_read(void)
+{
+ uint32_t clicks;
+ uint32_t ints;
+ uint32_t total;
+ rtems_interrupt_level level;
+ uint32_t tcr;
+
+
+ rtems_interrupt_disable(level);
+
+ clicks = 0xFFFFFFFF - read32(SH7750_TCNT1);
+ tcr = read32(SH7750_TCR1);
+ ints = Timer_interrupts;
+
+ rtems_interrupt_enable(level);
+
+ /* Handle the case when timer overflowed but interrupt was not processed */
+ if ((clicks > 0xFF000000) && ((tcr & SH7750_TCR_UNF) != 0))
+ {
+ ints++;
+ }
+
+ total = microseconds_per_int * ints + (clicks / microseconds_divider);
+
+ if ( benchmark_timer_find_average_overhead )
+ return total; /* in microsecond units */
+ else
+ {
+ if ( total < LEAST_VALID )
+ return 0; /* below timer resolution */
+ /*
+ * Somehow convert total into microseconds
+ */
+ return (total - AVG_OVERHEAD) ;
+ }
+}
+
+/* benchmark_timer_disable_subtracting_average_overhead --
+ * This routine is invoked by the "Check Timer" (tmck) test in the
+ * RTEMS Timing Test Suite. It makes the benchmark_timer_read routine not
+ * subtract the overhead required to initialize and read the benchmark
+ * timer.
+ *
+ * PARAMETERS:
+ * find_flag - boolean flag, true if overhead must not be subtracted.
+ *
+ * RETURNS:
+ * none
+ */
+void
+benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
+
+/* timerisr --
+ * Timer interrupt handler routine. This function invoked on timer
+ * underflow event; once per 2^32 clocks. It should reset the timer
+ * event and increment timer interrupts counter.
+ */
+void
+timerisr(void)
+{
+ uint8_t temp8;
+
+ /* reset the flags of the status register */
+ temp8 = read8(SH7750_TCR1) & ~SH7750_TCR_UNF;
+ write8(temp8, SH7750_TCR1);
+
+ Timer_interrupts += 1;
+}
diff --git a/bsps/sparc/erc32/btimer/btimer.c b/bsps/sparc/erc32/btimer/btimer.c
new file mode 100644
index 0000000000..05728f8acc
--- /dev/null
+++ b/bsps/sparc/erc32/btimer/btimer.c
@@ -0,0 +1,81 @@
+/* timer.c
+ *
+ * This file implements a benchmark timer using the General Purpose Timer on
+ * the MEC.
+ *
+ * COPYRIGHT (c) 1989-1999.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ *
+ * Ported to ERC32 implementation of the SPARC by On-Line Applications
+ * Research Corporation (OAR) under contract to the European Space
+ * Agency (ESA).
+ *
+ * ERC32 modifications of respective RTEMS file: COPYRIGHT (c) 1995.
+ * European Space Agency.
+ */
+
+#include <bsp.h>
+#include <rtems/btimer.h>
+
+bool benchmark_timer_find_average_overhead;
+
+bool benchmark_timer_is_initialized = false;
+
+void benchmark_timer_initialize(void)
+{
+ /*
+ * Timer runs long and accurate enough not to require an interrupt.
+ */
+
+ if ( benchmark_timer_is_initialized == false ) {
+
+ /* approximately 1 us per countdown */
+ ERC32_MEC.General_Purpose_Timer_Scalar = CLOCK_SPEED - 1;
+ ERC32_MEC.General_Purpose_Timer_Counter = 0xffffffff;
+
+ } else {
+ benchmark_timer_is_initialized = true;
+ }
+
+ ERC32_MEC_Set_General_Purpose_Timer_Control(
+ ERC32_MEC_TIMER_COUNTER_ENABLE_COUNTING |
+ ERC32_MEC_TIMER_COUNTER_LOAD_COUNTER
+ );
+
+ ERC32_MEC_Set_General_Purpose_Timer_Control(
+ ERC32_MEC_TIMER_COUNTER_ENABLE_COUNTING
+ );
+
+}
+
+#define AVG_OVERHEAD 12 /* It typically takes 3.0 microseconds */
+ /* to start/stop the timer. */
+#define LEAST_VALID 13 /* Don't trust a value lower than this */
+
+benchmark_timer_t benchmark_timer_read(void)
+{
+ uint32_t total;
+
+ total = ERC32_MEC.General_Purpose_Timer_Counter;
+
+ total = 0xffffffff - total;
+
+ if ( benchmark_timer_find_average_overhead == true )
+ return total; /* in one microsecond units */
+
+ if ( total < LEAST_VALID )
+ return 0; /* below timer resolution */
+
+ return total - AVG_OVERHEAD;
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(
+ bool find_flag
+)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/sparc/leon2/btimer/btimer.c b/bsps/sparc/leon2/btimer/btimer.c
new file mode 100644
index 0000000000..de115c965a
--- /dev/null
+++ b/bsps/sparc/leon2/btimer/btimer.c
@@ -0,0 +1,83 @@
+/**
+ * @file
+ * @ingroup sparc_leon2
+ * @brief Implement a benchmark timer using timer 2
+ */
+
+/* timer.c
+ *
+ * This file implements a benchmark timer using timer 2.
+ *
+ * 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.org/license/LICENSE.
+ *
+ * Ported to LEON implementation of the SPARC by On-Line Applications
+ * Research Corporation (OAR) under contract to the European Space
+ * Agency (ESA).
+ *
+ * LEON modifications of respective RTEMS file: COPYRIGHT (c) 1995.
+ * European Space Agency.
+ */
+
+
+#include <bsp.h>
+#include <rtems/btimer.h>
+
+bool benchmark_timer_find_average_overhead;
+
+bool benchmark_timer_is_initialized = false;
+
+void benchmark_timer_initialize(void)
+{
+ /*
+ * Timer runs long and accurate enough not to require an interrupt.
+ */
+
+ if ( benchmark_timer_is_initialized == false ) {
+
+ /* approximately 1 us per countdown */
+ LEON_REG.Timer_Counter_2 = 0xffffff;
+ LEON_REG.Timer_Reload_2 = 0xffffff;
+
+ } else {
+ benchmark_timer_is_initialized = true;
+ }
+
+ LEON_REG.Timer_Control_2 = (
+ LEON_REG_TIMER_COUNTER_ENABLE_COUNTING |
+ LEON_REG_TIMER_COUNTER_LOAD_COUNTER
+ );
+
+}
+
+#define AVG_OVERHEAD 3 /* It typically takes 3.0 microseconds */
+ /* to start/stop the timer. */
+#define LEAST_VALID 2 /* Don't trust a value lower than this */
+
+benchmark_timer_t benchmark_timer_read(void)
+{
+ uint32_t total;
+
+ total = LEON_REG.Timer_Counter_2;
+
+ total = 0xffffff - total;
+
+ if ( benchmark_timer_find_average_overhead == true )
+ return total; /* in one microsecond units */
+
+ if ( total < LEAST_VALID )
+ return 0; /* below timer resolution */
+
+ return total - AVG_OVERHEAD;
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(
+ bool find_flag
+)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/sparc/leon3/btimer/btimer.c b/bsps/sparc/leon3/btimer/btimer.c
new file mode 100644
index 0000000000..40bdeb87bb
--- /dev/null
+++ b/bsps/sparc/leon3/btimer/btimer.c
@@ -0,0 +1,85 @@
+/* timer.c
+ *
+ * This file implements a benchmark timer using timer 2.
+ *
+ * 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.org/license/LICENSE.
+ *
+ * Ported to LEON implementation of the SPARC by On-Line Applications
+ * Research Corporation (OAR) under contract to the European Space
+ * Agency (ESA).
+ *
+ * LEON modifications of respective RTEMS file: COPYRIGHT (c) 1995.
+ * European Space Agency.
+ */
+
+
+#include <bsp.h>
+#include <rtems/btimer.h>
+
+#if defined(RTEMS_MULTIPROCESSING)
+ #define LEON3_TIMER_INDEX \
+ ((rtems_configuration_get_user_multiprocessing_table()) ? \
+ (rtems_configuration_get_user_multiprocessing_table()->node) - 1 : 1)
+#else
+ #define LEON3_TIMER_INDEX 0
+#endif
+
+bool benchmark_timer_find_average_overhead;
+
+bool benchmark_timer_is_initialized = false;
+
+extern volatile struct gptimer_regs *LEON3_Timer_Regs;
+
+void benchmark_timer_initialize(void)
+{
+ /*
+ * Timer runs long and accurate enough not to require an interrupt.
+ */
+ if (LEON3_Timer_Regs) {
+ if ( benchmark_timer_is_initialized == false ) {
+ /* approximately 1 us per countdown */
+ LEON3_Timer_Regs->timer[LEON3_TIMER_INDEX].reload = 0xffffff;
+ LEON3_Timer_Regs->timer[LEON3_TIMER_INDEX].value = 0xffffff;
+ } else {
+ benchmark_timer_is_initialized = true;
+ }
+ LEON3_Timer_Regs->timer[LEON3_TIMER_INDEX].ctrl =
+ GPTIMER_TIMER_CTRL_EN | GPTIMER_TIMER_CTRL_LD;
+ }
+}
+
+#define AVG_OVERHEAD 3 /* It typically takes 3.0 microseconds */
+ /* to start/stop the timer. */
+#define LEAST_VALID 2 /* Don't trust a value lower than this */
+
+benchmark_timer_t benchmark_timer_read(void)
+{
+ uint32_t total;
+
+ if (LEON3_Timer_Regs) {
+ total = LEON3_Timer_Regs->timer[LEON3_TIMER_INDEX].value;
+
+ total = 0xffffff - total;
+
+ if ( benchmark_timer_find_average_overhead == true )
+ return total; /* in one microsecond units */
+
+ if ( total < LEAST_VALID )
+ return 0; /* below timer resolution */
+
+ return total - AVG_OVERHEAD;
+ }
+ return 0;
+}
+
+void benchmark_timer_disable_subtracting_average_overhead(
+ bool find_flag
+)
+{
+ benchmark_timer_find_average_overhead = find_flag;
+}
diff --git a/bsps/sparc/leon3/btimer/watchdog.c b/bsps/sparc/leon3/btimer/watchdog.c
new file mode 100644
index 0000000000..5ce8e32354
--- /dev/null
+++ b/bsps/sparc/leon3/btimer/watchdog.c
@@ -0,0 +1,90 @@
+/* GPTIMER Watchdog timer routines. On some systems the first GPTIMER
+ * core's last Timer instance underflow signal is connected to system
+ * reset.
+ *
+ * COPYRIGHT (c) 2012.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <bsp/watchdog.h>
+#include <grlib.h>
+
+extern volatile struct gptimer_regs *LEON3_Timer_Regs;
+
+struct gptimer_watchdog_priv {
+ struct gptimer_regs *regs;
+ struct gptimer_timer_regs *timer;
+ int timerno;
+};
+
+struct gptimer_watchdog_priv bsp_watchdogs[1];
+int bsp_watchdog_count = 0;
+
+int bsp_watchdog_init(void)
+{
+ int timercnt;
+
+ if (!LEON3_Timer_Regs)
+ return 0;
+
+ /* Get Watchdogs in system, this is implemented for one GPTIMER core
+ * only.
+ *
+ * First watchdog is a special case, we can get the first timer core by
+ * looking at LEON3_Timer_Regs, the watchdog within a timer core is
+ * always the last timer. Unfortunately we can not know it the watchdog
+ * functionality is available or not, we assume that it is if we
+ * reached this function.
+ */
+ bsp_watchdogs[0].regs = (struct gptimer_regs *)LEON3_Timer_Regs;
+
+ /* Find Timer that has watchdog functionality */
+ timercnt = bsp_watchdogs[0].regs->cfg & 0x7;
+ if (timercnt < 2) /* First timer system clock timer */
+ return 0;
+
+ bsp_watchdogs[0].timerno = timercnt - 1;
+ bsp_watchdogs[0].timer = &bsp_watchdogs[0].regs->timer[bsp_watchdogs[0].timerno];
+
+ bsp_watchdog_count = 1;
+ return bsp_watchdog_count;
+}
+
+void bsp_watchdog_reload(int watchdog, unsigned int reload_value)
+{
+ if (bsp_watchdog_count == 0)
+ bsp_watchdog_init();
+
+ if (bsp_watchdog_count <= watchdog)
+ return;
+
+ /* Kick watchdog, and clear interrupt pending bit */
+ bsp_watchdogs[watchdog].timer->reload = reload_value;
+ bsp_watchdogs[watchdog].timer->ctrl =
+ (GPTIMER_TIMER_CTRL_LD | GPTIMER_TIMER_CTRL_EN) |
+ (bsp_watchdogs[watchdog].timer->ctrl & ~(1<<4));
+}
+
+void bsp_watchdog_stop(int watchdog)
+{
+ if (bsp_watchdog_count == 0)
+ bsp_watchdog_init();
+
+ if (bsp_watchdog_count <= watchdog)
+ return;
+
+ /* Stop watchdog timer */
+ bsp_watchdogs[watchdog].timer->ctrl = 0;
+}
+
+/* Use watchdog timer to reset system */
+void bsp_watchdog_system_reset(void)
+{
+ sparc_disable_interrupts();
+ bsp_watchdog_reload(0, 1);
+}
diff --git a/bsps/sparc/shared/btimer/gptimer.c b/bsps/sparc/shared/btimer/gptimer.c
new file mode 100644
index 0000000000..08e498178e
--- /dev/null
+++ b/bsps/sparc/shared/btimer/gptimer.c
@@ -0,0 +1,544 @@
+/* This file contains the driver for the GRLIB GPTIMER timers port. The driver
+ * is implemented by using the tlib.c simple timer layer and the Driver
+ * Manager.
+ *
+ * The Driver can be configured using driver resources:
+ *
+ * - timerStart Timer Index if first Timer, this parameters is typically used
+ * in AMP systems for resource allocation. The Timers before
+ * timerStart will not be accessed.
+ * - timerCnt Number of timers that the driver will use, this parameters is
+ * typically used in AMP systems for resource allocation between
+ * OS instances.
+ * - prescaler Base prescaler, normally set by bootloader but can be
+ * overridden. The default scaler reload value set by bootloader
+ * is so that Timers operate in 1MHz. Setting the prescaler to a
+ * lower value increase the accuracy of the timers but shortens
+ * the time until underflow happens.
+ * - clockTimer Used to select a particular timer to be the system clock
+ * timer. This is useful when multiple GPTIMERs cores are
+ * available, or in AMP systems. By default the TLIB selects the
+ * first timer registered as system clock timer.
+ *
+ * The BSP define APBUART_INFO_AVAIL in order to add the info routine
+ * used for debugging.
+ *
+ * COPYRIGHT (c) 2010.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <stdlib.h>
+#include <string.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <grlib.h>
+#include <bsp/gptimer.h>
+#include <bsp/tlib.h>
+
+#if defined(LEON3)
+#include <leon.h>
+#endif
+
+#ifdef GPTIMER_INFO_AVAIL
+#include <stdio.h>
+#endif
+
+#ifdef RTEMS_SMP
+#include <rtems/score/processormask.h>
+#include <rtems/score/smpimpl.h>
+#endif
+
+/* GPTIMER Core Configuration Register (READ-ONLY) */
+#define GPTIMER_CFG_TIMERS_BIT 0
+#define GPTIMER_CFG_IRQ_BIT 3
+#define GPTIMER_CFG_SI_BIT 8
+#define GPTIMER_CFG_DF_BIT 9
+
+#define GPTIMER_CFG_TIMERS (0x7<<GPTIMER_CFG_TIMERS_BIT)
+#define GPTIMER_CFG_IRQ (0x1f<<GPTIMER_CFG_IRQ_BIT)
+#define GPTIMER_CFG_SI (1<<GPTIMER_CFG_SI_BIT)
+#define GPTIMER_CFG_DF (1<<GPTIMER_CFG_DF_BIT)
+
+/* GPTIMER Timer Control Register */
+#define GPTIMER_CTRL_EN_BIT 0
+#define GPTIMER_CTRL_RS_BIT 1
+#define GPTIMER_CTRL_LD_BIT 2
+#define GPTIMER_CTRL_IE_BIT 3
+#define GPTIMER_CTRL_IP_BIT 4
+#define GPTIMER_CTRL_CH_BIT 5
+#define GPTIMER_CTRL_DH_BIT 6
+
+#define GPTIMER_CTRL_EN (1<<GPTIMER_CTRL_EN_BIT)
+#define GPTIMER_CTRL_RS (1<<GPTIMER_CTRL_RS_BIT)
+#define GPTIMER_CTRL_LD (1<<GPTIMER_CTRL_LD_BIT)
+#define GPTIMER_CTRL_IE (1<<GPTIMER_CTRL_IE_BIT)
+#define GPTIMER_CTRL_IP (1<<GPTIMER_CTRL_IP_BIT)
+#define GPTIMER_CTRL_CH (1<<GPTIMER_CTRL_CH_BIT)
+#define GPTIMER_CTRL_DH (1<<GPTIMER_CTRL_DH_BIT)
+
+#define DBG(x...)
+
+/* GPTIMER timer private */
+struct gptimer_timer {
+ struct tlib_dev tdev; /* Must be first in struct */
+ struct gptimer_timer_regs *tregs;
+ char index; /* Timer Index in this driver */
+ char tindex; /* Timer Index In Hardware */
+ unsigned char irq_ack_mask;
+};
+
+/* GPTIMER Core private */
+struct gptimer_priv {
+ struct drvmgr_dev *dev;
+ struct gptimer_regs *regs;
+ unsigned int base_clk;
+ unsigned int base_freq;
+ unsigned int widthmask;
+ char separate_interrupt;
+ char isr_installed;
+
+ /* Structure per Timer unit, the core supports up to 8 timers */
+ int timer_cnt;
+ struct gptimer_timer timers[0];
+};
+
+void gptimer_isr(void *data);
+
+#if 0
+void gptimer_tlib_irq_register(struct tlib_drv *tdrv, tlib_isr_t func, void *data)
+{
+ struct gptimer_priv *priv = (struct gptimer_priv *)tdrv;
+
+ if ( SHARED ...)
+
+
+ drvmgr_interrupt_register();
+}
+#endif
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+static struct tlib_drv gptimer_tlib_drv;
+int gptimer_device_init(struct gptimer_priv *priv);
+
+int gptimer_init1(struct drvmgr_dev *dev);
+#ifdef GPTIMER_INFO_AVAIL
+static int gptimer_info(
+ struct drvmgr_dev *dev,
+ void (*print_line)(void *p, char *str),
+ void *p, int, char *argv[]);
+#define GTIMER_INFO_FUNC gptimer_info
+#else
+#define GTIMER_INFO_FUNC NULL
+#endif
+
+struct drvmgr_drv_ops gptimer_ops =
+{
+ .init = {gptimer_init1, NULL, NULL, NULL},
+ .remove = NULL,
+ .info = GTIMER_INFO_FUNC,
+};
+
+struct amba_dev_id gptimer_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_GPTIMER},
+ {VENDOR_GAISLER, GAISLER_GRTIMER},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info gptimer_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GPTIMER_ID,/* Driver ID */
+ "GPTIMER_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &gptimer_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &gptimer_ids[0]
+};
+
+void gptimer_register_drv (void)
+{
+ DBG("Registering GPTIMER driver\n");
+ drvmgr_drv_register(&gptimer_drv_info.general);
+}
+
+int gptimer_init1(struct drvmgr_dev *dev)
+{
+ struct gptimer_priv *priv;
+ struct gptimer_regs *regs;
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ int timer_hw_cnt, timer_cnt, timer_start;
+ int i, size;
+ struct gptimer_timer *timer;
+ union drvmgr_key_value *value;
+ unsigned char irq_ack_mask;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ regs = (struct gptimer_regs *)pnpinfo->apb_slv->start;
+
+ DBG("GPTIMER[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+
+ /* Get number of Timers */
+ timer_hw_cnt = regs->cfg & GPTIMER_CFG_TIMERS;
+
+ /* Let user spelect a range of timers to be used. In AMP systems
+ * it is sometimes neccessary to leave timers for other CPU instances.
+ *
+ * The default operation in AMP is to shared the timers within the
+ * first GPTIMER core as below. This can of course be overrided by
+ * driver resources.
+ */
+ timer_cnt = timer_hw_cnt;
+ timer_start = 0;
+#if defined(RTEMS_MULTIPROCESSING) && defined(LEON3)
+ if ((dev->minor_drv == 0) && drvmgr_on_rootbus(dev)) {
+ timer_cnt = 1;
+ timer_start = LEON3_Cpu_Index;
+ }
+#endif
+ value = drvmgr_dev_key_get(dev, "timerStart", DRVMGR_KT_INT);
+ if ( value) {
+ timer_start = value->i;
+ timer_cnt = timer_hw_cnt - timer_start;
+ }
+ value = drvmgr_dev_key_get(dev, "timerCnt", DRVMGR_KT_INT);
+ if ( value && (value->i < timer_cnt) ) {
+ timer_cnt = value->i;
+ }
+
+ /* Allocate Common Timer Description, size depends on how many timers
+ * are present.
+ */
+ size = sizeof(struct gptimer_priv) +
+ timer_cnt*sizeof(struct gptimer_timer);
+ priv = dev->priv = (struct gptimer_priv *)malloc(size);
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, size);
+ priv->dev = dev;
+ priv->regs = regs;
+
+ /* The Base Frequency of the GPTIMER core is the same as the
+ * frequency of the AMBA bus it is situated on.
+ */
+ drvmgr_freq_get(dev, DEV_APB_SLV, &priv->base_clk);
+
+ /* This core will may provide important Timer functionality
+ * to other drivers and the RTEMS kernel, the Clock driver
+ * may for example use this device. So the Timer driver must be
+ * initialized in the first iiitialization stage.
+ */
+
+ /*** Initialize Hardware ***/
+
+ /* If user request to set prescaler, we will do that. However, note
+ * that doing so for the Root-Bus GPTIMER may affect the RTEMS Clock
+ * so that Clock frequency is wrong.
+ */
+ value = drvmgr_dev_key_get(priv->dev, "prescaler", DRVMGR_KT_INT);
+ if ( value )
+ regs->scaler_reload = value->i;
+
+ /* Get Frequency that the timers are operating in (after prescaler) */
+ priv->base_freq = priv->base_clk / (priv->regs->scaler_reload + 1);
+
+ /* Stop Timer and probe Pending bit. In newer hardware the
+ * timer has pending bit is cleared by writing a one to it,
+ * whereas older versions it is cleared with a zero.
+ */
+ priv->regs->timer[timer_start].ctrl = GPTIMER_CTRL_IP;
+ if ((priv->regs->timer[timer_start].ctrl & GPTIMER_CTRL_IP) != 0)
+ irq_ack_mask = ~GPTIMER_CTRL_IP;
+ else
+ irq_ack_mask = ~0;
+
+ /* Probe timer register width mask */
+ priv->regs->timer[timer_start].value = 0xffffffff;
+ priv->widthmask = priv->regs->timer[timer_start].value;
+
+ priv->timer_cnt = timer_cnt;
+ for (i=0; i<timer_cnt; i++) {
+ timer = &priv->timers[i];
+ timer->index = i;
+ timer->tindex = i + timer_start;
+ timer->tregs = &regs->timer[(int)timer->tindex];
+ timer->tdev.drv = &gptimer_tlib_drv;
+ timer->irq_ack_mask = irq_ack_mask;
+
+ /* Register Timer at Timer Library */
+ tlib_dev_reg(&timer->tdev);
+ }
+
+ /* Check Interrupt support implementation, two cases:
+ * A. All Timers share one IRQ
+ * B. Each Timer have an individual IRQ. The number is:
+ * BASE_IRQ + timer_index
+ */
+ priv->separate_interrupt = (regs->cfg & GPTIMER_CFG_SI) != 0;
+
+ return DRVMGR_OK;
+}
+
+#ifdef GPTIMER_INFO_AVAIL
+static int gptimer_info(
+ struct drvmgr_dev *dev,
+ void (*print_line)(void *p, char *str),
+ void *p, int argc, char *argv[])
+{
+ struct gptimer_priv *priv = dev->priv;
+ struct gptimer_timer *timer;
+ char buf[64];
+ int i;
+
+ if (priv == NULL || argc != 0)
+ return -DRVMGR_EINVAL;
+
+ sprintf(buf, "Timer Count: %d", priv->timer_cnt);
+ print_line(p, buf);
+ sprintf(buf, "REGS: 0x%08x", (unsigned int)priv->regs);
+ print_line(p, buf);
+ sprintf(buf, "BASE SCALER: %d", priv->regs->scaler_reload);
+ print_line(p, buf);
+ sprintf(buf, "BASE FREQ: %dkHz", priv->base_freq / 1000);
+ print_line(p, buf);
+ sprintf(buf, "SeparateIRQ: %s", priv->separate_interrupt ? "YES":"NO");
+ print_line(p, buf);
+
+ for (i=0; i<priv->timer_cnt; i++) {
+ timer = &priv->timers[i];
+ sprintf(buf, " - TIMER HW Index %d -", timer->tindex);
+ print_line(p, buf);
+ sprintf(buf, " TLIB Index: %d", timer->index);
+ print_line(p, buf);
+ sprintf(buf, " RELOAD REG: %d", timer->tregs->reload);
+ print_line(p, buf);
+ sprintf(buf, " CTRL REG: %d", timer->tregs->ctrl);
+ print_line(p, buf);
+ }
+
+ return DRVMGR_OK;
+}
+#endif
+
+static inline struct gptimer_priv *priv_from_timer(struct gptimer_timer *t)
+{
+ return (struct gptimer_priv *)
+ ((unsigned int)t -
+ sizeof(struct gptimer_priv) -
+ t->index * sizeof(struct gptimer_timer));
+}
+
+static int gptimer_tlib_int_pend(struct tlib_dev *hand, int ack)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+ unsigned int ctrl = timer->tregs->ctrl;
+
+ if ((ctrl & (GPTIMER_CTRL_IP | GPTIMER_CTRL_IE)) ==
+ (GPTIMER_CTRL_IP | GPTIMER_CTRL_IE)) {
+ /* clear Pending IRQ ? */
+ if (ack)
+ timer->tregs->ctrl = ctrl & timer->irq_ack_mask;
+ return 1; /* timer generated IRQ */
+ } else
+ return 0; /* was not timer causing IRQ */
+}
+
+void gptimer_isr(void *data)
+{
+ struct gptimer_priv *priv = data;
+ int i;
+
+ /* Check all timers for IRQ */
+ for (i=0;i<priv->timer_cnt; i++) {
+ if (gptimer_tlib_int_pend((void *)&priv->timers[i], 0)) {
+ /* IRQ Was generated by Timer and Pending flag has *not*
+ * yet been cleared, this is to allow ISR to look at
+ * pending bit. Call ISR registered. Clear pending bit.
+ */
+ if (priv->timers[i].tdev.isr_func) {
+ priv->timers[i].tdev.isr_func(
+ priv->timers[i].tdev.isr_data);
+ }
+ gptimer_tlib_int_pend((void *)&priv->timers[i], 1);
+ }
+ }
+}
+
+static void gptimer_tlib_reset(struct tlib_dev *hand)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+
+ timer->tregs->ctrl = (timer->tregs->ctrl & timer->irq_ack_mask) &
+ GPTIMER_CTRL_IP;
+ timer->tregs->reload = 0xffffffff;
+ timer->tregs->ctrl = GPTIMER_CTRL_LD;
+}
+
+static void gptimer_tlib_get_freq(
+ struct tlib_dev *hand,
+ unsigned int *basefreq,
+ unsigned int *tickrate)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+ struct gptimer_priv *priv = priv_from_timer(timer);
+
+ /* Calculate base frequency from Timer Clock and Prescaler */
+ if ( basefreq )
+ *basefreq = priv->base_freq;
+ if ( tickrate )
+ *tickrate = timer->tregs->reload + 1;
+}
+
+static int gptimer_tlib_set_freq(struct tlib_dev *hand, unsigned int tickrate)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+
+ timer->tregs->reload = tickrate - 1;
+
+ /*Check that value was allowed (Timer may not be as wide as expected)*/
+ if ( timer->tregs->reload != (tickrate - 1) )
+ return -1;
+ else
+ return 0;
+}
+
+static void gptimer_tlib_irq_reg(struct tlib_dev *hand, tlib_isr_t func, void *data, int flags)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+ struct gptimer_priv *priv = priv_from_timer(timer);
+
+ if ( priv->separate_interrupt ) {
+ drvmgr_interrupt_register(priv->dev, timer->tindex,
+ "gptimer", func, data);
+ } else {
+ if (priv->isr_installed == 0) {
+ /* Shared IRQ handler */
+ drvmgr_interrupt_register(
+ priv->dev,
+ 0,
+ "gptimer_shared",
+ gptimer_isr,
+ priv);
+ }
+ priv->isr_installed++;
+ }
+
+#if RTEMS_SMP
+ if (flags & TLIB_FLAGS_BROADCAST) {
+ int tindex = 0;
+
+ if (priv->separate_interrupt) {
+ /* Offset interrupt number with HW subtimer index */
+ tindex = timer->tindex;
+ }
+ drvmgr_interrupt_set_affinity(priv->dev, tindex,
+ _SMP_Get_online_processors());
+ }
+#endif
+
+ timer->tregs->ctrl |= GPTIMER_CTRL_IE;
+}
+
+static void gptimer_tlib_irq_unreg(struct tlib_dev *hand, tlib_isr_t func, void *data)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+ struct gptimer_priv *priv = priv_from_timer(timer);
+
+ /* Turn off IRQ at source, unregister IRQ handler */
+ timer->tregs->ctrl &= ~GPTIMER_CTRL_IE;
+
+ if ( priv->separate_interrupt ) {
+ drvmgr_interrupt_unregister(priv->dev, timer->tindex,
+ func, data);
+ } else {
+ timer->tdev.isr_func = NULL;
+ priv->isr_installed--;
+ if (priv->isr_installed == 0) {
+ drvmgr_interrupt_unregister(priv->dev, 0,
+ gptimer_isr, priv);
+ }
+ }
+}
+
+static void gptimer_tlib_start(struct tlib_dev *hand, int once)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+ unsigned int ctrl;
+
+ /* Load the selected frequency before starting Frequency */
+ ctrl = GPTIMER_CTRL_LD | GPTIMER_CTRL_EN;
+ if ( once == 0 )
+ ctrl |= GPTIMER_CTRL_RS; /* Restart Timer */
+ timer->tregs->ctrl = ctrl | (timer->tregs->ctrl & timer->irq_ack_mask &
+ ~GPTIMER_CTRL_RS);
+}
+
+static void gptimer_tlib_stop(struct tlib_dev *hand)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+
+ /* Load the selected Frequency */
+ timer->tregs->ctrl &= ~(GPTIMER_CTRL_EN|GPTIMER_CTRL_IP);
+}
+
+static void gptimer_tlib_restart(struct tlib_dev *hand)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+
+ timer->tregs->ctrl |= GPTIMER_CTRL_LD | GPTIMER_CTRL_EN;
+}
+
+static void gptimer_tlib_get_counter(
+ struct tlib_dev *hand,
+ unsigned int *counter)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+
+ *counter = timer->tregs->value;
+}
+
+static void gptimer_tlib_get_widthmask(
+ struct tlib_dev *hand,
+ unsigned int *widthmask)
+{
+ struct gptimer_timer *timer = (struct gptimer_timer *)hand;
+ struct gptimer_priv *priv = priv_from_timer(timer);
+
+ *widthmask = priv->widthmask;
+}
+
+static struct tlib_drv gptimer_tlib_drv =
+{
+ .reset = gptimer_tlib_reset,
+ .get_freq = gptimer_tlib_get_freq,
+ .set_freq = gptimer_tlib_set_freq,
+ .irq_reg = gptimer_tlib_irq_reg,
+ .irq_unreg = gptimer_tlib_irq_unreg,
+ .start = gptimer_tlib_start,
+ .stop = gptimer_tlib_stop,
+ .restart = gptimer_tlib_restart,
+ .get_counter = gptimer_tlib_get_counter,
+ .custom = NULL,
+ .int_pend = gptimer_tlib_int_pend,
+ .get_widthmask = gptimer_tlib_get_widthmask,
+};
diff --git a/bsps/sparc/shared/btimer/tlib.c b/bsps/sparc/shared/btimer/tlib.c
new file mode 100644
index 0000000000..a0525d072d
--- /dev/null
+++ b/bsps/sparc/shared/btimer/tlib.c
@@ -0,0 +1,77 @@
+/*
+ * Timer Library (TLIB)
+ *
+ * COPYRIGHT (c) 2011.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <bsp/tlib.h>
+
+struct tlib_dev *tlib_dev_head = NULL;
+struct tlib_dev *tlib_dev_tail = NULL;
+static int tlib_dev_cnt = 0;
+
+/* Register Timer device to Timer Library */
+int tlib_dev_reg(struct tlib_dev *newdev)
+{
+ /* Reset device */
+ newdev->status = 0;
+ newdev->isr_func = NULL;
+ newdev->index = tlib_dev_cnt;
+
+ /* Insert last in queue */
+ newdev->next = NULL;
+ if ( tlib_dev_tail == NULL ) {
+ tlib_dev_head = newdev;
+ } else {
+ tlib_dev_tail->next = newdev;
+ }
+ tlib_dev_tail = newdev;
+
+ /* Return Index of Registered Timer */
+ return tlib_dev_cnt++;
+}
+
+void *tlib_open(int timer_no)
+{
+ struct tlib_dev *dev;
+
+ if ( timer_no < 0 )
+ return NULL;
+
+ dev = tlib_dev_head;
+ while ( (timer_no > 0) && dev ) {
+ timer_no--;
+ dev = dev->next;
+ }
+ if ( dev ) {
+ if ( dev->status )
+ return NULL;
+ dev->status = 1;
+ /* Reset Timer to initial state */
+ tlib_reset(dev);
+ }
+ return dev;
+}
+
+void tlib_close(void *hand)
+{
+ struct tlib_dev *dev = hand;
+
+ /* Stop any ongoing timer operation and unregister IRQ if registered */
+ tlib_stop(dev);
+ tlib_irq_unregister(dev);
+
+ /* Mark not open */
+ dev->status = 0;
+}
+
+int tlib_ntimer(void)
+{
+ return tlib_dev_cnt;
+}
diff --git a/bsps/sparc/shared/btimer/tlib_ckinit.c b/bsps/sparc/shared/btimer/tlib_ckinit.c
new file mode 100644
index 0000000000..3f56d725d9
--- /dev/null
+++ b/bsps/sparc/shared/btimer/tlib_ckinit.c
@@ -0,0 +1,453 @@
+/*
+ * Clock Tick Device Driver using Timer Library implemented
+ * by the GRLIB GPTIMER / LEON2 Timer drivers.
+ *
+ * COPYRIGHT (c) 2010 - 2017.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ *
+ */
+
+/*
+ * This is an implementation of the RTEMS "clockdrv_shell" interface for
+ * LEON2/3/4 systems using the Driver Manager. It is clock hardware agnostic
+ * and compatible with SMP and UP. Availability of free running counters is
+ * probed and selected as needed.
+ */
+#include <rtems.h>
+#include <rtems/timecounter.h>
+#include <rtems/clockdrv.h>
+#include <stdlib.h>
+#include <bsp.h>
+#include <bsp/tlib.h>
+
+#ifdef RTEMS_DRVMGR_STARTUP
+
+#if defined(LEON3)
+#include <leon.h>
+#endif
+
+struct ops {
+ /*
+ * Set up the free running counter using the Timecounter or Simple
+ * Timecounter interface.
+ */
+ rtems_device_driver (*initialize_counter)(void);
+
+ /*
+ * Hardware-specific support at tick interrupt which runs early in Clock_isr.
+ * It can for example be used to check if interrupt was actually caused by
+ * the timer hardware. If return value is not RTEMS_SUCCESSFUL then Clock_isr
+ * returns immediately. at_tick can be initialized with NULL.
+ */
+ rtems_device_driver (*at_tick)(void);
+
+ /*
+ * Typically calls rtems_timecounter_tick(). A specialized clock driver may
+ * use for example rtems_timecounter_tick_simple() instead.
+ */
+ void (*timecounter_tick)(void);
+
+ /*
+ * Called when the clock driver exits. It can be used to stop functionality
+ * started by initialize_counter. The tick timer is stopped by default.
+ * shutdown_hardware can be initialized with NULL
+ */
+ void (*shutdown_hardware)(void);
+};
+
+/*
+ * Different implementation depending on available free running counter for the
+ * timecounter.
+ *
+ * NOTE: The clock interface is not compatible with shared interrupts on the
+ * clock (tick) timer in SMP configuration.
+ */
+
+/* "simple timecounter" interface. Only for non-SMP. */
+static const struct ops ops_simple;
+/* Hardware support up-counter using LEON3 %asr23. */
+static const struct ops ops_timetag;
+/* Timestamp counter available in some IRQ(A)MP instantiations. */
+static const struct ops ops_irqamp;
+/* Separate GPTIMER subtimer as timecounter */
+static const struct ops ops_subtimer;
+
+struct clock_priv {
+ const struct ops *ops;
+ /*
+ * Timer number in Timer Library for tick timer used by this interface.
+ * Defaults to the first Timer in the System.
+ */
+ int tlib_tick_index;
+ /* Timer number for timecounter timer if separate GPTIMER subtimer is used */
+ int tlib_counter_index;
+ void *tlib_tick;
+ void *tlib_counter;
+ rtems_timecounter_simple tc_simple;
+ struct timecounter tc;
+};
+static struct clock_priv priv;
+
+/** Common interface **/
+
+/* Set system clock timer instance */
+void Clock_timer_register(int timer_number)
+{
+ priv.tlib_tick_index = timer_number;
+ priv.tlib_counter_index = timer_number + 1;
+}
+
+static rtems_device_driver tlib_clock_find_timer(void)
+{
+ /* Take Timer that should be used as system timer. */
+ priv.tlib_tick = tlib_open(priv.tlib_tick_index);
+ if (priv.tlib_tick == NULL) {
+ /* System Clock Timer not found */
+ return RTEMS_NOT_DEFINED;
+ }
+
+ /* Select which operation set to use */
+#ifndef RTEMS_SMP
+ priv.ops = &ops_simple;
+#else
+ /* When on LEON3 try to use dedicated hardware free running counter. */
+ leon3_up_counter_enable();
+ if (leon3_up_counter_is_available()) {
+ priv.ops = &ops_timetag;
+ return RTEMS_SUCCESSFUL;
+ } else {
+ volatile struct irqmp_timestamp_regs *irqmp_ts;
+
+ irqmp_ts = &LEON3_IrqCtrl_Regs->timestamp[0];
+ if (leon3_irqmp_has_timestamp(irqmp_ts)) {
+ priv.ops = &ops_irqamp;
+ return RTEMS_SUCCESSFUL;
+ }
+ }
+
+ /* Take another subtimer as the final option. */
+ priv.ops = &ops_subtimer;
+#endif
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver tlib_clock_initialize_hardware(void)
+{
+ /* Set tick rate in number of "Base-Frequency ticks" */
+ tlib_set_freq(priv.tlib_tick, rtems_configuration_get_microseconds_per_tick());
+ priv.ops->initialize_counter();
+ tlib_start(priv.tlib_tick, 0);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver tlib_clock_at_tick(void)
+{
+ if (priv.ops->at_tick) {
+ return priv.ops->at_tick();
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static void tlib_clock_timecounter_tick(void)
+{
+ priv.ops->timecounter_tick();
+}
+
+/* Return a value not equal to RTEMS_SUCCESFUL to make Clock_initialize fail. */
+static rtems_device_driver tlib_clock_install_isr(rtems_isr *isr)
+{
+ int flags = 0;
+
+#ifdef RTEMS_SMP
+ /* We shall broadcast the clock interrupt to all processors. */
+ flags = TLIB_FLAGS_BROADCAST;
+#endif
+ tlib_irq_register(priv.tlib_tick, isr, NULL, flags);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static void tlib_clock_shutdown_hardware(void)
+{
+ if (priv.tlib_tick) {
+ tlib_stop(priv.tlib_tick);
+ priv.tlib_tick = NULL;
+ }
+ if (priv.ops->shutdown_hardware) {
+ priv.ops->shutdown_hardware();
+ }
+}
+
+/** Simple counter **/
+static uint32_t simple_tlib_tc_get(rtems_timecounter_simple *tc)
+{
+ unsigned int clicks = 0;
+
+ if (priv.tlib_tick != NULL) {
+ tlib_get_counter(priv.tlib_tick, &clicks);
+ }
+
+ return clicks;
+}
+
+static bool simple_tlib_tc_is_pending(rtems_timecounter_simple *tc)
+{
+ bool pending = false;
+
+ if (priv.tlib_tick != NULL) {
+ pending = tlib_interrupt_pending(priv.tlib_tick, 0) != 0;
+ }
+
+ return pending;
+}
+
+static uint32_t simple_tlib_tc_get_timecount(struct timecounter *tc)
+{
+ return rtems_timecounter_simple_downcounter_get(
+ tc,
+ simple_tlib_tc_get,
+ simple_tlib_tc_is_pending
+ );
+}
+
+static rtems_device_driver simple_initialize_counter(void)
+{
+ uint64_t frequency;
+ unsigned int tick_hz;
+
+ frequency = 1000000;
+ tick_hz = rtems_configuration_get_microseconds_per_tick();
+
+ rtems_timecounter_simple_install(
+ &priv.tc_simple,
+ frequency,
+ tick_hz,
+ simple_tlib_tc_get_timecount
+ );
+
+ return RTEMS_NOT_DEFINED;
+}
+
+static void simple_tlib_tc_at_tick(rtems_timecounter_simple *tc)
+{
+ /* Nothing to do */
+}
+
+/*
+ * Support for shared interrupts. Ack IRQ at source, only handle interrupts
+ * generated from the tick-timer. This is called early in Clock_isr.
+ */
+static rtems_device_driver simple_at_tick(void)
+{
+ if (tlib_interrupt_pending(priv.tlib_tick, 1) == 0) {
+ return RTEMS_NOT_DEFINED;
+ }
+ return RTEMS_SUCCESSFUL;
+}
+
+static void simple_timecounter_tick(void)
+{
+ rtems_timecounter_simple_downcounter_tick(
+ &priv.tc_simple,
+ simple_tlib_tc_get,
+ simple_tlib_tc_at_tick
+ );
+}
+
+static const struct ops ops_simple = {
+ .initialize_counter = simple_initialize_counter,
+ .at_tick = simple_at_tick,
+ .timecounter_tick = simple_timecounter_tick,
+ .shutdown_hardware = NULL,
+};
+
+/** Subtimer as counter **/
+static uint32_t subtimer_get_timecount(struct timecounter *tc)
+{
+ unsigned int counter;
+
+ tlib_get_counter(priv.tlib_counter, &counter);
+
+ return 0xffffffff - counter;
+}
+
+static rtems_device_driver subtimer_initialize_counter(void)
+{
+ unsigned int mask;
+ unsigned int basefreq;
+
+ if (priv.tlib_counter_index == priv.tlib_tick_index) {
+ priv.tlib_counter_index = priv.tlib_tick_index + 1;
+ }
+ /* Take Timer that should be used as timecounter upcounter timer. */
+ priv.tlib_counter = tlib_open(priv.tlib_counter_index);
+ if (priv.tlib_counter == NULL) {
+ /* Timecounter timer not found */
+ return RTEMS_NOT_DEFINED;
+ }
+
+ /* Configure free running counter: GPTIMER */
+ tlib_get_freq(priv.tlib_counter, &basefreq, NULL);
+ tlib_get_widthmask(priv.tlib_counter, &mask);
+
+ priv.tc.tc_get_timecount = subtimer_get_timecount;
+ priv.tc.tc_counter_mask = mask;
+ priv.tc.tc_frequency = basefreq;
+ priv.tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
+ rtems_timecounter_install(&priv.tc);
+ /* Start free running counter */
+ tlib_start(priv.tlib_counter, 0);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static void subtimer_timecounter_tick(void)
+{
+ rtems_timecounter_tick();
+}
+
+static void subtimer_shutdown_hardware(void)
+{
+ if (priv.tlib_counter) {
+ tlib_stop(priv.tlib_counter);
+ priv.tlib_counter = NULL;
+ }
+}
+
+static const struct ops ops_subtimer = {
+ .initialize_counter = subtimer_initialize_counter,
+ .timecounter_tick = subtimer_timecounter_tick,
+ .shutdown_hardware = subtimer_shutdown_hardware,
+};
+
+#if defined(LEON3)
+/** DSU timetag as counter **/
+static uint32_t timetag_get_timecount(struct timecounter *tc)
+{
+ return leon3_up_counter_low();
+}
+
+static rtems_device_driver timetag_initialize_counter(void)
+{
+ /* Configure free running counter: timetag */
+ priv.tc.tc_get_timecount = timetag_get_timecount;
+ priv.tc.tc_counter_mask = 0xffffffff;
+ priv.tc.tc_frequency = leon3_up_counter_frequency();
+ priv.tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
+ rtems_timecounter_install(&priv.tc);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static void timetag_timecounter_tick(void)
+{
+ rtems_timecounter_tick();
+}
+
+static const struct ops ops_timetag = {
+ .initialize_counter = timetag_initialize_counter,
+ .at_tick = NULL,
+ .timecounter_tick = timetag_timecounter_tick,
+ .shutdown_hardware = NULL,
+};
+#endif
+
+#if defined(LEON3)
+/** IRQ(A)MP timestamp as counter **/
+static uint32_t irqamp_get_timecount(struct timecounter *tc)
+{
+ return LEON3_IrqCtrl_Regs->timestamp[0].counter;
+}
+
+static rtems_device_driver irqamp_initialize_counter(void)
+{
+ volatile struct irqmp_timestamp_regs *irqmp_ts;
+ static const uint32_t A_TSISEL_FIELD = 0xf;
+
+ /* Configure free running counter: timetag */
+ priv.tc.tc_get_timecount = irqamp_get_timecount;
+ priv.tc.tc_counter_mask = 0xffffffff;
+ priv.tc.tc_frequency = leon3_up_counter_frequency();
+ priv.tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
+ rtems_timecounter_install(&priv.tc);
+
+ /*
+ * The counter increments whenever a TSISEL field in a Timestamp Control
+ * Register is non-zero.
+ */
+ irqmp_ts = &LEON3_IrqCtrl_Regs->timestamp[0];
+ irqmp_ts->control = A_TSISEL_FIELD;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static void irqamp_timecounter_tick(void)
+{
+ rtems_timecounter_tick();
+}
+
+static const struct ops ops_irqamp = {
+ .initialize_counter = irqamp_initialize_counter,
+ .at_tick = NULL,
+ .timecounter_tick = irqamp_timecounter_tick,
+ .shutdown_hardware = NULL,
+};
+#endif
+
+/** Interface to the Clock Driver Shell (dev/clock/clockimpl.h) **/
+#define Clock_driver_support_find_timer() \
+ do { \
+ rtems_device_driver ret; \
+ ret = tlib_clock_find_timer(); \
+ if (RTEMS_SUCCESSFUL != ret) { \
+ return ret; \
+ } \
+ } while (0)
+
+#define Clock_driver_support_install_isr( isr ) \
+ do { \
+ rtems_device_driver ret; \
+ ret = tlib_clock_install_isr( isr ); \
+ if (RTEMS_SUCCESSFUL != ret) { \
+ return ret; \
+ } \
+ } while (0)
+
+#define Clock_driver_support_set_interrupt_affinity(online_processors) \
+ /* Done by tlib_clock_install_isr() */
+
+#define Clock_driver_support_initialize_hardware() \
+ do { \
+ rtems_device_driver ret; \
+ ret = tlib_clock_initialize_hardware(); \
+ if (RTEMS_SUCCESSFUL != ret) { \
+ return ret; \
+ } \
+ } while (0)
+
+#define Clock_driver_support_shutdown_hardware() \
+ tlib_clock_shutdown_hardware()
+
+#define Clock_driver_timecounter_tick() \
+ tlib_clock_timecounter_tick()
+
+#define Clock_driver_support_at_tick() \
+ do { \
+ rtems_device_driver ret; \
+ ret = tlib_clock_at_tick(); \
+ if (RTEMS_SUCCESSFUL != ret) { \
+ return; \
+ } \
+ } while (0)
+
+#include "../../../shared/dev/clock/clockimpl.h"
+
+#endif /* RTEMS_DRVMGR_STARTUP */
+