source: rtems/c/src/lib/libbsp/m68k/mvme167/clock/ckinit.c @ bdb2899

4.104.114.84.95
Last change on this file since bdb2899 was 08311cc3, checked in by Joel Sherrill <joel.sherrill@…>, on 11/17/99 at 17:51:34

Updated copyright notice.

  • Property mode set to 100644
File size: 8.6 KB
Line 
1/*  ckinit.c
2 *
3 *  Implementation of the Clock_control() and Clock_initialize() functions
4 *  prototyped in rtems/c/src/lib/include/clockdrv.h.
5 *
6 *  This port does not allow the application to select which timer on the
7 *  MVME167 to use for the clock, nor does it allow the application to
8 *  configure the clock. The clock uses the VMEchip2 Tick Timer #2. This
9 *  timer is set up to raise a MC680x0 level-6 interrupt every 1 ms. The
10 *  interrupt vector is 0x69.
11 *
12 *  All page references are to the MVME166/MVME167/MVME187 Single Board
13 *  Computer Programmer's Reference Guide (MVME187PG/D2) with the April
14 *  1993 supplements/addenda (MVME187PG/D2A1).
15 *
16 *  COPYRIGHT (c) 1989-1999.
17 *  On-Line Applications Research Corporation (OAR).
18 *
19 *  The license and distribution terms for this file may be
20 *  found in the file LICENSE in this distribution or at
21 *  http://www.OARcorp.com/rtems/license.html.
22 *
23 *  Modifications of respective RTEMS files:
24 *  Copyright (c) 1998, National Research Council of Canada
25 *
26 *  $Id$
27 */
28 
29#include <stdlib.h>
30#include <bsp.h>
31#include <rtems/libio.h>
32
33#define MS_COUNT          1000              /* T2's countdown constant (1 ms) */
34#define CLOCK_INT_LEVEL   6                 /* T2's interrupt level */
35#define CLOCK_VECTOR (VBR0 * 0x10 + 0x9)    /* T2 is vector $X9 (p. 2-71)*/
36
37/*
38 *  These are declared in rtems/c/src/lib/include/clockdrv.h
39 *  In other BSPs, rtems_clock_major is set to the largest possible value
40 *  (which is almost certainly greater than the number of I/O devices) to
41 *  indicate that this device has not been initialized yet. The actual
42 *  device number is supplied during initialization. We do not do that.
43 *
44 *  Initialized data ends up the the .data section. This causes two problems:
45 *  1) the .data section is no longer ROMable because we need to write into
46 *  it. 2) The initial value is correct only after a download. On subsequent
47 *  program restarts, the value is not re-initialized but left to whatever it
48 *  was when the previous run terminated or aborted. If we depend on some
49 *  global variable value, we must initialize that value explicitly in code
50 *  at boot time.
51 */
52rtems_device_major_number rtems_clock_major;
53rtems_device_minor_number rtems_clock_minor;
54
55/*
56 *  Clock_driver_ticks is a monotonically increasing counter of the number of
57 *  VMEchip2 timer #2 ticks since the driver was initialized.
58 */
59volatile rtems_unsigned32 Clock_driver_ticks;
60
61
62/*
63 *  Clock_isrs is the number of clock ISRs until the next invocation of the
64 *  RTEMS clock tick routine. This clock tick device driver gets an interrupt
65 *  once a millisecond and counts down until the length of time between the
66 *  user configured microseconds per tick has passed. This allows the clock
67 *  device to "tick" faster than the kernel clock. Of course, the kernel clock
68 *  cannot tick faster than the hardware clock. Therefore, the kernel clock
69 *  ticks cannot occur more frequently than every 1 millisecond.
70 */
71rtems_unsigned32 Clock_isrs;
72
73
74/*
75 *  Records the previous clock ISR (should be NULL)
76 */
77rtems_isr_entry  Old_ticker;
78
79
80/*
81 *  Called when the kernel exits.
82 */
83void clock_exit( void );
84
85
86/*
87 *  VMEchip2_T2_isr
88 *
89 *  C ISR Handler. Increment the number of internal ticks. If it is time for a
90 *  kernel clock tick (if Clock_isrs == 1), call rtems_clock_tick() to signal
91 *  the event and reset the Clock_isrs counter; else, just decrement it.
92 *
93 *  Input parameters:
94 *    vector number
95 *
96 *  Output parameters: NONE
97 *
98 *  Return values: NONE
99 */
100rtems_isr VMEchip2_T2_isr(
101  rtems_vector_number vector
102)
103{
104  char overflow;                /* Content of overflow counter */
105  long i;
106  long ct;                      /* Number of T2 ticks per RTEMS ticks */
107 
108  ct = BSP_Configuration.microseconds_per_tick / 1000;
109 
110  /*
111   *  May have missed interrupts, so should look at the overflow counter.
112   */
113  lcsr->intr_clear |= 0x02000000;   /* Clear the interrupt */
114  overflow = (lcsr->board_ctl >> 12) & 0xF;
115  lcsr->board_ctl |= 0x400;         /* Reset overflow counter */
116 
117  /* Attempt to protect against one more period */
118  if ( overflow == 0 )
119    overflow = 16;
120
121  Clock_driver_ticks += overflow;   /* One or more internal ticks */
122
123  if ( Clock_isrs <= overflow ) {
124    /* If its time for kernel clock ticks, signal the events to RTEMS */
125    for( i = overflow - Clock_isrs; i >= 0; i -= ct ) {
126      rtems_clock_tick();
127    }
128    /* Reset the counter */
129    Clock_isrs = (rtems_unsigned32)-i;
130  }
131  else
132    Clock_isrs -= overflow;
133}
134
135
136/*
137 *  VMEchip2_T2_initialize
138 *
139 *  Initialize the VMEchip2 Tick Timer #2.
140 *
141 *  THE VMECHIP2 PRESCALER REGISTER IS ASSUMED TO BE SET!
142 *  The prescaler is used by all VMEchip2 timers, including the VMEbus grant
143 *  timeout counter, the DMAC time off timer, the DMAC timer on timer, and the
144 *  VMEbus global timeout timer. The prescaler value is normally set by the
145 *  boot ROM to provide a 1 MHz clock to the timers. For a 25 MHz MVME167, the
146 *  prescaler value should be 0xE7 (page 2-63).
147 *
148 *  Input parameters: NONE
149 *
150 *  Output paremeters: NONE
151 *
152 *  Return values: NONE
153 */
154void VMEchip2_T2_initialize( void )
155{
156  Clock_driver_ticks = 0;
157  Clock_isrs = BSP_Configuration.microseconds_per_tick / 1000;
158
159  if ( BSP_Configuration.ticks_per_timeslice ) {
160    lcsr->intr_ena &= 0xFDFFFFFF;   /* Disable tick timer 2 interrupt */
161    lcsr->intr_clear = 0x02000000;  /* Clear tick timer 2 interrupt */
162    lcsr->intr_level[0] =           /* Set tick timer 2 interrupt level */
163        (lcsr->intr_level[0] & 0xFFFFFF0F ) | (CLOCK_INT_LEVEL << 4);
164    lcsr->timer_cmp_2 = MS_COUNT;   /* Period in compare register */
165    lcsr->timer_cnt_2 = 0;          /* Clear tick timer 2 counter */
166    Old_ticker =                    /* Install C ISR */
167        (rtems_isr_entry) set_vector( VMEchip2_T2_isr, CLOCK_VECTOR, 1 );
168    lcsr->board_ctl |= 0x700;       /* Start tick timer 2, reset-on-compare, */
169                                    /*  and clear tick timer 2 overflow counter */
170    lcsr->intr_ena |= 0x02000000;   /* Enable tick timer 2 interrupt */
171    lcsr->vector_base |= 0x00800000;/* Unmask VMEchip2 interrupts */
172    atexit( clock_exit );           /* Turn off T2 interrupts when we exit */
173  }
174}
175
176
177/*
178 *  clock_exit
179 *
180 *  This routine stops the VMEchip2 T2 timer, disables its interrupt, and
181 *  re-install the old interrupt vectors.
182 *
183 *  Input parameters:   NONE
184 *
185 *  Output parameters:  NONE
186 *
187 *  Return values:      NONE
188 *
189 */
190void clock_exit( void )
191{
192  if ( BSP_Configuration.ticks_per_timeslice ) {
193    lcsr->board_ctl &= 0xFFFFFEFF;  /* Stop tick timer 2 */
194    lcsr->intr_ena &= 0xFDFFFFFF;   /* Disable tick timer 2 interrupt */
195    lcsr->intr_clear = 0x02000000;  /* Clear tick timer 2 interrupt */
196
197    set_vector( Old_ticker, CLOCK_VECTOR, 1 );
198  }
199}
200
201
202/*
203 *  Clock_initialize()
204 *  prototyped in rtems/c/src/lib/include/clockdrv.h.
205 *
206 *  Input parameters:
207 *     major - console device major number
208 *     minor - console device minor number
209 *             ALWAYS 0 IN VERSION 3.6.0 OF RTEMS!
210 *             Probably provided for symmetry with the other I/O calls.
211 *     arg   - pointer to optional device driver arguments
212 *             ALWAYS NULL IN VERSION 3.6.0 OF RTEMS!
213 *
214 *  Output paremeters: NONE
215 *
216 *  Return values:
217 *     rtems_device_driver status code
218 */
219rtems_device_driver Clock_initialize(
220  rtems_device_major_number major,
221  rtems_device_minor_number minor,
222  void *pargp
223)
224{
225  VMEchip2_T2_initialize();
226 
227  /*
228   *  Make major/minor avail to others such as shared memory driver
229   */
230  rtems_clock_major = major;
231  rtems_clock_minor = minor;
232 
233  return RTEMS_SUCCESSFUL;
234}
235
236
237/*
238 *  Clock_control().
239 *  Prototyped in rtems/c/src/lib/include/clockdrv.h
240 *
241 *  Input parameters:
242 *    major - clock device major number
243 *    minor - clock device minor number
244 *    parg  - pointer to optional device driver arguments
245 *
246 *  Output parameters:  NONE
247 *
248 *  Return values:
249 *    rtems_device_driver status code
250 */
251rtems_device_driver Clock_control(
252  rtems_device_major_number major,
253  rtems_device_minor_number minor,
254  void *pargp)
255{
256    rtems_unsigned32 isrlevel;
257    rtems_libio_ioctl_args_t *args = pargp;
258 
259    if ( args == 0 )
260        goto done;
261 
262    /*
263     * This is hokey, but until we get a defined interface
264     * to do this, it will just be this simple...
265     */
266    if ( args->command == rtems_build_name('I', 'S', 'R', ' ') )
267    {
268      VMEchip2_T2_isr( CLOCK_VECTOR );
269    }
270    else if ( args->command == rtems_build_name('N', 'E', 'W', ' ') )
271    {
272      rtems_interrupt_disable( isrlevel );
273      set_vector( args->buffer, CLOCK_VECTOR, 1 );
274      rtems_interrupt_enable( isrlevel );
275    }
276 
277done:
278    return RTEMS_SUCCESSFUL;
279}
280
Note: See TracBrowser for help on using the repository browser.