summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libbsp/sparc/shared/timer/tlib_ckinit.c
blob: 2848f4cb3c08d80b507a4e0f960dffa69dd70275 (plain) (tree)
1
2
3
4
5
6
7
8
9








                                                            
                                         


   
                  
                              
                               

                   
                     
 


                                                               

                                                    
                                              




                                                       





















                                                                 
                                 
 
































                                                             




                                                         



                                            

                   


    
  















                                             
                                                                   
                                              




                                                     






                                 
                   
                                                                              
 



         






                                                 
                   








                                                   
                 





























                                                                             





















                                                                   
                     




















                                                                
                                                                       







                                                       

                                                                                


                            
                      




                                                            





                                   












                                                                      











                                                                    
                                     



                                           

      
/*
 *  Clock Tick Device Driver using Timer Library implemented
 *  by the GRLIB GPTIMER / LEON2 Timer drivers.
 *
 *  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 <rtems/timecounter.h>
#include <rtems/score/percpu.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

/* Set the below defines from bsp.h if function needed.
#undef CLOCK_DRIVER_ISRS_PER_TICK
#undef CLOCK_DRIVER_USE_FAST_IDLE
*/

/*
 *  Number of Clock ticks since initialization
 */
volatile uint32_t Clock_driver_ticks;

/*
 *  Timer Number in Timer Library. Defaults to the first Timer in
 *  the System.
 */
int Clock_timer = 0;

/*
 * Timer Handle in Timer Library
 */
void *Clock_handle = NULL;

#ifdef CLOCK_DRIVER_DONT_ASSUME_PRESCALER_1MHZ
unsigned int Clock_basefreq;
#endif

void Clock_exit(void);
void Clock_isr(void *arg_unused);

static rtems_timecounter_simple tlib_tc;

static uint32_t tlib_tc_get(rtems_timecounter_simple *tc)
{
  unsigned int clicks = 0;

  if (Clock_handle != NULL) {
    tlib_get_counter(Clock_handle, &clicks);
  }

  return clicks;
}

static bool tlib_tc_is_pending(rtems_timecounter_simple *tc)
{
  bool pending = false;

  if (Clock_handle != NULL) {
    pending = tlib_interrupt_pending(Clock_handle, 0) != 0;
  }

  return pending;
}

static uint32_t tlib_tc_get_timecount(struct timecounter *tc)
{
  return rtems_timecounter_simple_downcounter_get(
    tc,
    tlib_tc_get,
    tlib_tc_is_pending
  );
}

static void tlib_tc_at_tick(rtems_timecounter_simple *tc)
{
  /* Nothing to do? */
}

static void tlib_tc_tick(void)
{
  rtems_timecounter_simple_downcounter_tick(
    &tlib_tc,
    tlib_tc_get,
    tlib_tc_at_tick
  );
}

/*
 *  Clock_isr
 *
 *  This is the clock tick interrupt handler.
 *
 *  Input parameters:
 *    vector - vector number
 *
 *  Output parameters:  NONE
 *
 *  Return values:      NONE
 *
 */

void Clock_isr(void *arg_unused)
{
  /*
   * 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;

  /*
   *  Accurate count of ISRs
   */

  Clock_driver_ticks += 1;

#ifdef CLOCK_DRIVER_USE_FAST_IDLE
  do {
    tlib_tc_tick();
  } while ( _Thread_Heir == _Thread_Executing && _Thread_Executing->is_idle );

  return;

#else

#ifdef CLOCK_DRIVER_ISRS_PER_TICK
  /*
   *  The driver is multiple ISRs per clock tick.
   */

  if ( !Clock_driver_isrs ) {

    tlib_tc_tick();

    Clock_driver_isrs = CLOCK_DRIVER_ISRS_PER_TICK;
  }
  Clock_driver_isrs--;
#else

  /*
   *  The driver is one ISR per clock tick.
   */
  tlib_tc_tick();
#endif
#endif
}

/*
 *  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
 *
 */

void Clock_exit( 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;
  }
}

/*
 *  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
 */

rtems_device_driver Clock_initialize(
  rtems_device_major_number major,
  rtems_device_minor_number minor,
  void *pargp
)
{
  uint64_t frequency;
  unsigned int tick_hz;

  /*
   *  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;
  }

  /*
   *  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;

    tlib_get_freq(Clock_handle, &Clock_basefreq, NULL);

    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();
#endif

  tlib_set_freq(Clock_handle, tick_hz);

  rtems_timecounter_simple_install(
    &tlib_tc,
    frequency,
    tick_hz,
    tlib_tc_get_timecount
  );

  /*
   *  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);

  /*
   *  Register function called at system shutdown
   */
  atexit( Clock_exit );

  /*
   *  If we are counting ISRs per tick, then initialize the counter.
   */

#ifdef CLOCK_DRIVER_ISRS_PER_TICK
  Clock_driver_isrs = CLOCK_DRIVER_ISRS_PER_TICK;
#endif

  return RTEMS_SUCCESSFUL;
}

/*** Timer Driver Interface ***/

/* Set system clock timer instance */
void Clock_timer_register(int timer_number)
{
  Clock_timer = timer_number;
}

#endif