summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/leon3/clock/ckinit.c
blob: 695e78dfbc2f298d2740592d989110e4a2862878 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
 *  Clock Tick Device Driver
 *
 *  This routine initializes LEON timer 1 which used for the clock tick.
 *
 *  The tick frequency is directly programmed to the configured number of
 *  microseconds per tick.
 *
 *  COPYRIGHT (c) 1989-2006.
 *  On-Line Applications Research Corporation (OAR).
 *
 *  Modified for LEON3 BSP.
 *  COPYRIGHT (c) 2004.
 *  Gaisler Research.
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.com/license/LICENSE.
 */

#include <bsp.h>
#include <bspopts.h>
#include <ambapp.h>

#if SIMSPARC_FAST_IDLE==1
#define CLOCK_DRIVER_USE_FAST_IDLE 1
#endif

/*
 *  The Real Time Clock Counter Timer uses this trap type.
 */

#if defined(RTEMS_MULTIPROCESSING)
  #define LEON3_CLOCK_INDEX \
    (rtems_configuration_get_user_multiprocessing_table() ? LEON3_Cpu_Index : 0)
#else
  #define LEON3_CLOCK_INDEX 0
#endif

volatile struct gptimer_regs *LEON3_Timer_Regs = 0;
static int clkirq;

#define CLOCK_VECTOR LEON_TRAP_TYPE( clkirq )

#define Clock_driver_support_at_tick()

#if defined(RTEMS_MULTIPROCESSING)
  #define Adjust_clkirq_for_node() \
    do { \
      if (rtems_configuration_get_user_multiprocessing_table() != NULL) { \
        clkirq += LEON3_Cpu_Index; \
      } \
    } while(0)
#else
  #define Adjust_clkirq_for_node() do { clkirq += LEON3_CLOCK_INDEX; } while(0)
#endif

#ifndef LEON3_QEMU
#define Clock_driver_support_find_timer() \
  do { \
    struct ambapp_dev *adev; \
    \
    /* Find first LEON3 GP Timer */ \
    adev = (void *)ambapp_for_each(&ambapp_plb, (OPTIONS_ALL|OPTIONS_APB_SLVS),\
              VENDOR_GAISLER, GAISLER_GPTIMER, ambapp_find_by_idx, NULL); \
    if (adev) { \
      /* Found APB GPTIMER Timer */ \
      LEON3_Timer_Regs = (volatile struct gptimer_regs *) \
                         DEV_TO_APB(adev)->start; \
      clkirq = (LEON3_Timer_Regs->cfg & 0xf8) >> 3; \
      \
      Adjust_clkirq_for_node(); \
    } \
  } while (0)
#else /* LEON3_QEMU */
#define Clock_driver_support_find_timer() \
  do { \
    LEON3_Timer_Regs = (volatile struct gptimer_regs *) \
                       0x80000300; \
    clkirq = 6; \
  } while (0)
#endif /* LEON3_QEMU */

#define Clock_driver_support_install_isr( _new, _old ) \
  do { \
    _old = set_vector( _new, CLOCK_VECTOR, 1 ); \
  } while(0)

#ifndef LEON3_QEMU
#define Clock_driver_support_initialize_hardware() \
  do { \
    LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].reload = \
      rtems_configuration_get_microseconds_per_tick() - 1; \
    \
    LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].ctrl = \
      LEON3_GPTIMER_EN | LEON3_GPTIMER_RL | \
        LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN; \
  } while (0)
#else
#define Clock_driver_support_initialize_hardware() \
  do { \
    LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].reload = \
      40 * (rtems_configuration_get_microseconds_per_tick() - 1); \
    \
    LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].ctrl = \
      LEON3_GPTIMER_EN | LEON3_GPTIMER_RL | \
        LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN; \
  } while (0)
#endif

#define Clock_driver_support_shutdown_hardware() \
  do { \
    LEON_Mask_interrupt(LEON_TRAP_TYPE(clkirq)); \
    LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].ctrl = 0; \
  } while (0)

static uint32_t bsp_clock_nanoseconds_since_last_tick(void)
{
  uint32_t clicks;
  uint32_t usecs;

  if ( !LEON3_Timer_Regs )
    return 0;

#ifndef LEON3_QEMU
  clicks = LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].value;
#else
  clicks = LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].value / 40;
#endif

  if ( LEON_Is_interrupt_pending( clkirq ) ) {
    clicks = LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].value;
    usecs = (2*rtems_configuration_get_microseconds_per_tick() - clicks);
  } else {
    usecs = (rtems_configuration_get_microseconds_per_tick() - clicks);
  }
  return usecs * 1000;
}

#define Clock_driver_nanoseconds_since_last_tick \
        bsp_clock_nanoseconds_since_last_tick

#include "../../../shared/clockdrv_shell.h"