[PATCH 05/30] leon, clock: new driver manager clock driver

Daniel Hellstrom daniel at gaisler.com
Thu Apr 13 19:31:14 UTC 2017


From: Martin Aberg <maberg at gaisler.com>

- Compatible with SMP
- Selects timecounter depending on features available
- Fixes problem with time going to fast on SMP

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.

GR740:
 RTEMS TESTSUITE FAILURE SUMMARY

 Result Test ExecRes ConsoleRes ExitCode1 ExitCode2
 FAIL: ./fstests/imfs_fsscandir01 OK FAIL 5 0
 FAIL: ./fstests/jffs2_fsscandir01 OK FAIL 5 0
 FAIL: ./fstests/mdosfs_fsscandir01 OK FAIL 5 0
 FAIL: ./fstests/mimfs_fsscandir01 OK FAIL 5 0
 FAIL: ./fstests/mrfs_fsscandir01 OK FAIL 5 0
 FAIL: ./psxtests/psxshm01 FAIL FAIL N/A N/A
 FAIL: ./psxtests/psxshm02 FAIL FAIL N/A N/A
 FAIL: ./sptests/spinternalerror01 OK N/A -559038737 1611526157
 FAIL: ./sptests/sptimecounter01 OK N/A 5 0

 SUMMARY
  Tests failing:    9
  Tests successful: 578

---
GR712RC:
 RTEMS TESTSUITE FAILURE SUMMARY

 Result Test ExecRes ConsoleRes ExitCode1 ExitCode2
 FAIL: ./smptests/smpipi01 FAIL FAIL N/A N/A
 FAIL: ./smptests/smpthreadlife01 FAIL FAIL N/A N/A
 FAIL: ./fstests/imfs_fsscandir01 OK FAIL 5 0
 FAIL: ./fstests/jffs2_fsscandir01 OK FAIL 5 0
 FAIL: ./fstests/mdosfs_fsscandir01 OK FAIL 5 0
 FAIL: ./fstests/mimfs_fsscandir01 OK FAIL 5 0
 FAIL: ./fstests/mrfs_fsscandir01 OK FAIL 5 0
 FAIL: ./psxtests/psxshm01 FAIL FAIL N/A N/A
 FAIL: ./psxtests/psxshm02 FAIL FAIL N/A N/A
 FAIL: ./sptests/spinternalerror01 OK N/A -559038737 1611526157
 FAIL: ./sptests/sptimecounter01 OK N/A 5 0

 SUMMARY
  Tests failing:    11
  Tests successful: 576
---
 c/src/lib/libbsp/sparc/shared/include/tlib.h      |  10 +-
 c/src/lib/libbsp/sparc/shared/timer/gptimer.c     |  14 +-
 c/src/lib/libbsp/sparc/shared/timer/tlib_ckinit.c | 543 ++++++++++++++--------
 3 files changed, 373 insertions(+), 194 deletions(-)

diff --git a/c/src/lib/libbsp/sparc/shared/include/tlib.h b/c/src/lib/libbsp/sparc/shared/include/tlib.h
index 5e49dd4..debb8c8 100644
--- a/c/src/lib/libbsp/sparc/shared/include/tlib.h
+++ b/c/src/lib/libbsp/sparc/shared/include/tlib.h
@@ -27,6 +27,10 @@ struct tlib_dev;
 
 typedef void (*tlib_isr_t)(void *data);
 
+enum {
+	TLIB_FLAGS_BROADCAST = 0x01
+};
+
 struct tlib_drv {
 	/*** Functions ***/
 	void	(*reset)(struct tlib_dev *hand);
@@ -35,7 +39,7 @@ struct tlib_drv {
 		unsigned int *basefreq,
 		unsigned int *tickrate);
 	int	(*set_freq)(struct tlib_dev *hand, unsigned int tickrate);
-	void	(*irq_reg)(struct tlib_dev *hand, tlib_isr_t func, void *data);
+	void	(*irq_reg)(struct tlib_dev *hand, tlib_isr_t func, void *data, int flags);
 	void	(*irq_unreg)(struct tlib_dev *hand, tlib_isr_t func,void *data);
 	void	(*start)(struct tlib_dev *hand, int once);
 	void	(*stop)(struct tlib_dev *hand);
@@ -122,7 +126,7 @@ static inline void tlib_irq_unregister(void *hand)
 }
 
 /* Register ISR at Timer ISR */
-static inline void tlib_irq_register(void *hand, tlib_isr_t func, void *data)
+static inline void tlib_irq_register(void *hand, tlib_isr_t func, void *data, int flags)
 {
 	struct tlib_dev *dev = hand;
 
@@ -130,7 +134,7 @@ static inline void tlib_irq_register(void *hand, tlib_isr_t func, void *data)
 	tlib_irq_unregister(hand);
 	dev->isr_func = func;
 	dev->isr_data = data;
-	dev->drv->irq_reg(dev, func, data);
+	dev->drv->irq_reg(dev, func, data, flags);
 }
 
 /* Start Timer, ISRs will be generated if enabled.
diff --git a/c/src/lib/libbsp/sparc/shared/timer/gptimer.c b/c/src/lib/libbsp/sparc/shared/timer/gptimer.c
index f47952f..e701211 100644
--- a/c/src/lib/libbsp/sparc/shared/timer/gptimer.c
+++ b/c/src/lib/libbsp/sparc/shared/timer/gptimer.c
@@ -48,6 +48,11 @@
 #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
@@ -416,7 +421,7 @@ static int gptimer_tlib_set_freq(struct tlib_dev *hand, unsigned int tickrate)
 		return 0;
 }
 
-static void gptimer_tlib_irq_reg(struct tlib_dev *hand, tlib_isr_t func, void *data)
+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);
@@ -437,6 +442,13 @@ static void gptimer_tlib_irq_reg(struct tlib_dev *hand, tlib_isr_t func, void *d
 		priv->isr_installed++;
 	}
 
+#if RTEMS_SMP
+	if (flags & TLIB_FLAGS_BROADCAST) {
+		drvmgr_interrupt_set_affinity(priv->dev, timer->tindex,
+					      _SMP_Online_processors);
+	}
+#endif
+
 	timer->tregs->ctrl |= GPTIMER_CTRL_IE;
 }
 
diff --git a/c/src/lib/libbsp/sparc/shared/timer/tlib_ckinit.c b/c/src/lib/libbsp/sparc/shared/timer/tlib_ckinit.c
index 2848f4c..7880e86 100644
--- a/c/src/lib/libbsp/sparc/shared/timer/tlib_ckinit.c
+++ b/c/src/lib/libbsp/sparc/shared/timer/tlib_ckinit.c
@@ -2,7 +2,7 @@
  *  Clock Tick Device Driver using Timer Library implemented
  *  by the GRLIB GPTIMER / LEON2 Timer drivers.
  *
- *  COPYRIGHT (c) 2010.
+ *  COPYRIGHT (c) 2010 - 2017.
  *  Cobham Gaisler AB.
  *
  *  The license and distribution terms for this file may be
@@ -11,280 +11,443 @@
  *
  */
 
+/*
+ * 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/score/percpu.h>
+#include <rtems/clockdrv.h>
 #include <stdlib.h>
 #include <bsp.h>
 #include <bsp/tlib.h>
 
 #ifdef RTEMS_DRVMGR_STARTUP
 
-/* Undefine this to save space in standard LEON configurations,
- * it will assume that Prescaler is running at 1MHz.
- */
-#undef CLOCK_DRIVER_DONT_ASSUME_PRESCALER_1MHZ
+#if defined(LEON3)
+#include <leon.h>
+#endif
 
-/* Set the below defines from bsp.h if function needed.
-#undef CLOCK_DRIVER_ISRS_PER_TICK
-#undef CLOCK_DRIVER_USE_FAST_IDLE
-*/
+struct ops {
+  /*
+   * Set up the free running counter using the Timecounter or Simple
+   * Timecounter interface.
+   */
+  rtems_device_driver (*initialize_counter)(void);
 
-/*
- *  Number of Clock ticks since initialization
- */
-volatile uint32_t Clock_driver_ticks;
+  /*
+   * 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);
 
-/*
- *  Timer Number in Timer Library. Defaults to the first Timer in
- *  the System.
- */
-int Clock_timer = 0;
+  /*
+   * 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);
+};
 
 /*
- * Timer Handle in Timer Library
+ * 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.
  */
-void *Clock_handle = NULL;
 
-#ifdef CLOCK_DRIVER_DONT_ASSUME_PRESCALER_1MHZ
-unsigned int Clock_basefreq;
+/* "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);
 
-void Clock_exit(void);
-void Clock_isr(void *arg_unused);
+  return RTEMS_SUCCESSFUL;
+}
 
-static rtems_timecounter_simple tlib_tc;
+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();
+  }
+}
 
-static uint32_t tlib_tc_get(rtems_timecounter_simple *tc)
+/** Simple counter **/
+static uint32_t simple_tlib_tc_get(rtems_timecounter_simple *tc)
 {
   unsigned int clicks = 0;
 
-  if (Clock_handle != NULL) {
-    tlib_get_counter(Clock_handle, &clicks);
+  if (priv.tlib_tick != NULL) {
+    tlib_get_counter(priv.tlib_tick, &clicks);
   }
 
   return clicks;
 }
 
-static bool tlib_tc_is_pending(rtems_timecounter_simple *tc)
+static bool simple_tlib_tc_is_pending(rtems_timecounter_simple *tc)
 {
   bool pending = false;
 
-  if (Clock_handle != NULL) {
-    pending = tlib_interrupt_pending(Clock_handle, 0) != 0;
+  if (priv.tlib_tick != NULL) {
+    pending = tlib_interrupt_pending(priv.tlib_tick, 0) != 0;
   }
 
   return pending;
 }
 
-static uint32_t tlib_tc_get_timecount(struct timecounter *tc)
+static uint32_t simple_tlib_tc_get_timecount(struct timecounter *tc)
 {
   return rtems_timecounter_simple_downcounter_get(
     tc,
-    tlib_tc_get,
-    tlib_tc_is_pending
+    simple_tlib_tc_get,
+    simple_tlib_tc_is_pending
   );
 }
 
-static void tlib_tc_at_tick(rtems_timecounter_simple *tc)
+static rtems_device_driver simple_initialize_counter(void)
 {
-  /* Nothing to do? */
+  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 tlib_tc_tick(void)
+static void simple_tlib_tc_at_tick(rtems_timecounter_simple *tc)
 {
-  rtems_timecounter_simple_downcounter_tick(
-    &tlib_tc,
-    tlib_tc_get,
-    tlib_tc_at_tick
-  );
+  /* Nothing to do */
 }
 
 /*
- *  Clock_isr
- *
- *  This is the clock tick interrupt handler.
- *
- *  Input parameters:
- *    vector - vector number
- *
- *  Output parameters:  NONE
- *
- *  Return values:      NONE
- *
+ * Support for shared interrupts. Ack IRQ at source, only handle interrupts
+ * generated from the tick-timer. This is called early in Clock_isr.
  */
-
-void Clock_isr(void *arg_unused)
+static rtems_device_driver simple_at_tick(void)
 {
-  /*
-   * Support for shared interrupts. Ack IRQ at source, only handle 
-   * interrupts generated from the tick-timer.
-   */
-  if ( tlib_interrupt_pending(Clock_handle, 1) == 0 )
-    return;
+  if (tlib_interrupt_pending(priv.tlib_tick, 1) == 0) {
+    return RTEMS_NOT_DEFINED;
+  }
+  return RTEMS_SUCCESSFUL;
+}
 
-  /*
-   *  Accurate count of ISRs
-   */
+static void simple_timecounter_tick(void)
+{
+  rtems_timecounter_simple_downcounter_tick(
+    &priv.tc_simple,
+    simple_tlib_tc_get,
+    simple_tlib_tc_at_tick
+  );
+}
 
-  Clock_driver_ticks += 1;
+static const struct ops ops_simple = {
+  .initialize_counter = simple_initialize_counter,
+  .at_tick            = simple_at_tick,
+  .timecounter_tick   = simple_timecounter_tick,
+  .shutdown_hardware  = NULL,
+};
 
-#ifdef CLOCK_DRIVER_USE_FAST_IDLE
-  do {
-    tlib_tc_tick();
-  } while ( _Thread_Heir == _Thread_Executing && _Thread_Executing->is_idle );
+/** Subtimer as counter **/
+static uint32_t subtimer_get_timecount(struct timecounter *tc)
+{
+  unsigned int counter;
 
-  return;
+  tlib_get_counter(priv.tlib_counter, &counter);
 
-#else
+  return 0xffffffff - counter;
+}
 
-#ifdef CLOCK_DRIVER_ISRS_PER_TICK
-  /*
-   *  The driver is multiple ISRs per clock tick.
-   */
+static rtems_device_driver subtimer_initialize_counter(void)
+{
+  unsigned int mask;
+  unsigned int basefreq;
 
-  if ( !Clock_driver_isrs ) {
+  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;
+  }
 
-    tlib_tc_tick();
+  /* Configure free running counter: GPTIMER */
+  tlib_get_freq(priv.tlib_counter, &basefreq, NULL);
+  tlib_get_widthmask(priv.tlib_counter, &mask);
 
-    Clock_driver_isrs = CLOCK_DRIVER_ISRS_PER_TICK;
-  }
-  Clock_driver_isrs--;
-#else
+  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);
 
-  /*
-   *  The driver is one ISR per clock tick.
-   */
-  tlib_tc_tick();
-#endif
-#endif
+  return RTEMS_SUCCESSFUL;
 }
 
-/*
- *  Clock_exit
- *
- *  This routine allows the clock driver to exit by masking the interrupt and
- *  disabling the clock's counter.
- *
- *  Input parameters:   NONE
- *
- *  Output parameters:  NONE
- *
- *  Return values:      NONE
- *
- */
+static void subtimer_timecounter_tick(void)
+{
+  rtems_timecounter_tick();
+}
 
-void Clock_exit( void )
+static void subtimer_shutdown_hardware(void)
 {
-  /* Stop all activity of the Timer, no more ISRs.
-   * We could be using tlib_close(), however tlib_stop() is quicker
-   * and independent of IRQ unregister code.
-   */
-  if ( Clock_handle ) {
-    tlib_stop(Clock_handle);
-    Clock_handle = NULL;
+  if (priv.tlib_counter) {
+    tlib_stop(priv.tlib_counter);
+    priv.tlib_counter = NULL;
   }
 }
 
-/*
- *  Clock_initialize
- *
- *  This routine initializes the clock driver and starts the Clock.
- *
- *  Input parameters:
- *    major - clock device major number
- *    minor - clock device minor number
- *    parg  - pointer to optional device driver arguments
- *
- *  Output parameters:  NONE
- *
- *  Return values:
- *    rtems_device_driver status code
- */
+static const struct ops ops_subtimer = {
+  .initialize_counter = subtimer_initialize_counter,
+  .timecounter_tick   = subtimer_timecounter_tick,
+  .shutdown_hardware  = subtimer_shutdown_hardware,
+};
 
-rtems_device_driver Clock_initialize(
-  rtems_device_major_number major,
-  rtems_device_minor_number minor,
-  void *pargp
-)
+#if defined(LEON3)
+/** DSU timetag as counter **/
+static uint32_t timetag_get_timecount(struct timecounter *tc)
 {
-  uint64_t frequency;
-  unsigned int tick_hz;
+  return leon3_up_counter_low();
+}
 
-  /*
-   *  Take Timer that should be used as system timer.
-   *
-   */
-  Clock_handle = tlib_open(Clock_timer);
-  if ( Clock_handle == NULL ) {
-    /* System Clock Timer not found */
-    return RTEMS_NOT_DEFINED;
-  }
+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);
 
-  /*
-   *  Install Clock ISR before starting timer
-   */
-  tlib_irq_register(Clock_handle, Clock_isr, NULL);
-
-  /* Set Timer Frequency to tick at Configured value. The Timer
-   * Frequency is set in multiples of the timer base frequency.
-   *
-   * In standard LEON3 designs the base frequency is is 1MHz, to
-   * save instructions undefine CLOCK_DRIVER_DONT_ASSUME_PRESCALER_1MHZ
-   * to avoid 64-bit calculation.
-   */
-#ifdef CLOCK_DRIVER_DONT_ASSUME_PRESCALER_1MHZ
-  {
-    uint64_t tmp;
+  return RTEMS_SUCCESSFUL;
+}
 
-    tlib_get_freq(Clock_handle, &Clock_basefreq, NULL);
+static void timetag_timecounter_tick(void)
+{
+  rtems_timecounter_tick();
+}
 
-    frequency = Clock_basefreq
-    tmp = frequency * (uint64_t)rtems_configuration_get_microseconds_per_tick();
-    tick_hz = tmp / 1000000;
-  }
-#else
-  frequency = 1000000;
-  tick_hz = rtems_configuration_get_microseconds_per_tick();
+static const struct ops ops_timetag = {
+  .initialize_counter = timetag_initialize_counter,
+  .at_tick            = NULL,
+  .timecounter_tick   = timetag_timecounter_tick,
+  .shutdown_hardware  = NULL,
+};
 #endif
 
-  tlib_set_freq(Clock_handle, tick_hz);
-
-  rtems_timecounter_simple_install(
-    &tlib_tc,
-    frequency,
-    tick_hz,
-    tlib_tc_get_timecount
-  );
+#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;
+}
 
-  /*
-   *  IRQ and Frequency is setup, now we start the Timer. IRQ is still
-   *  disabled globally during startup, so IRQ will hold for a while.
-   */
-  tlib_start(Clock_handle, 0);
+static rtems_device_driver irqamp_initialize_counter(void)
+{
+  volatile struct irqmp_timestamp_regs *irqmp_ts;
+  static const uint32_t A_TSISEL_FIELD = 0xf;
 
-  /*
-   *  Register function called at system shutdown
-   */
-  atexit( Clock_exit );
+  /* 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);
 
   /*
-   *  If we are counting ISRs per tick, then initialize the counter.
+   * The counter increments whenever a TSISEL field in a Timestamp Control
+   * Register is non-zero.
    */
-
-#ifdef CLOCK_DRIVER_ISRS_PER_TICK
-  Clock_driver_isrs = CLOCK_DRIVER_ISRS_PER_TICK;
-#endif
+  irqmp_ts = &LEON3_IrqCtrl_Regs->timestamp[0];
+  irqmp_ts->control = A_TSISEL_FIELD;
 
   return RTEMS_SUCCESSFUL;
 }
 
-/*** Timer Driver Interface ***/
-
-/* Set system clock timer instance */
-void Clock_timer_register(int timer_number)
+static void irqamp_timecounter_tick(void)
 {
-  Clock_timer = timer_number;
+  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 (clockdrv_shell.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, old ) \
+  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/clockdrv_shell.h"
+
+#endif /* RTEMS_DRVMGR_STARTUP */
+
-- 
2.7.4



More information about the devel mailing list