source: rtems/c/src/lib/libcpu/powerpc/ppc403/clock/clock.c @ 0dd1d44

4.104.114.84.95
Last change on this file since 0dd1d44 was 0dd1d44, checked in by Joel Sherrill <joel.sherrill@…>, on Jan 11, 2000 at 5:34:20 PM

Removed old hack of using Configuration Table entry ticks_per_timeslice
being set to 0 to indicate that there should be no Clock Tick. This
was used by the Timing Tests to avoid clock tick overhead perturbing
execution times. Now the Timing Tests simply leave the Clock Tick
Driver out of the Device Driver Table.

  • Property mode set to 100644
File size: 7.0 KB
Line 
1/*  clock.c
2 *
3 *  This routine initializes the interval timer on the
4 *  PowerPC 403 CPU.  The tick frequency is specified by the bsp.
5 *
6 *  Author: Andrew Bray <andy@i-cubed.co.uk>
7 *
8 *  COPYRIGHT (c) 1995 by i-cubed ltd.
9 *
10 *  To anyone who acknowledges that this file is provided "AS IS"
11 *  without any express or implied warranty:
12 *      permission to use, copy, modify, and distribute this file
13 *      for any purpose is hereby granted without fee, provided that
14 *      the above copyright notice and this notice appears in all
15 *      copies, and that the name of i-cubed limited not be used in
16 *      advertising or publicity pertaining to distribution of the
17 *      software without specific, written prior permission.
18 *      i-cubed limited makes no representations about the suitability
19 *      of this software for any purpose.
20 *
21 *  Derived from c/src/lib/libcpu/hppa1.1/clock/clock.c:
22 *
23 *  Modifications for deriving timer clock from cpu system clock by
24 *              Thomas Doerfler <td@imd.m.isar.de>
25 *  for these modifications:
26 *  COPYRIGHT (c) 1997 by IMD, Puchheim, Germany.
27 *
28 *
29 *  COPYRIGHT (c) 1989-1999.
30 *  On-Line Applications Research Corporation (OAR).
31 *
32 *  The license and distribution terms for this file may be
33 *  found in the file LICENSE in this distribution or at
34 *  http://www.OARcorp.com/rtems/license.html.
35 *
36 *  $Id$
37 */
38
39#include <rtems.h>
40#include <clockdrv.h>
41#include <rtems/libio.h>
42
43#include <stdlib.h>                     /* for atexit() */
44
45volatile rtems_unsigned32 Clock_driver_ticks;
46static rtems_unsigned32 pit_value, tick_time;
47static rtems_boolean auto_restart;
48
49void Clock_exit( void );
50 
51/*
52 * These are set by clock driver during its init
53 */
54 
55rtems_device_major_number rtems_clock_major = ~0;
56rtems_device_minor_number rtems_clock_minor;
57 
58static inline rtems_unsigned32 get_itimer(void)
59{
60    register rtems_unsigned32 rc;
61
62    asm volatile ("mfspr %0, 0x3dd" : "=r" ((rc))); /* TBLO */
63
64    return rc;
65}
66
67/*
68 *  ISR Handler
69 */
70 
71rtems_isr
72Clock_isr(rtems_vector_number vector)
73{
74    if (!auto_restart)
75    {
76      rtems_unsigned32 clicks_til_next_interrupt;
77      rtems_unsigned32 itimer_value;
78 
79      /*
80       * setup for next interrupt; making sure the new value is reasonably
81       * in the future.... in case we lost out on an interrupt somehow
82       */
83 
84      itimer_value = get_itimer();
85      tick_time += pit_value;
86 
87      /*
88       * how far away is next interrupt *really*
89       * It may be a long time; this subtraction works even if
90       * Clock_clicks_interrupt < Clock_clicks_low_order via
91       * the miracle of unsigned math.
92       */
93      clicks_til_next_interrupt = tick_time - itimer_value;
94 
95      /*
96       * If it is too soon then bump it up.
97       * This should only happen if CPU_HPPA_CLICKS_PER_TICK is too small.
98       * But setting it low is useful for debug, so...
99       */
100 
101      if (clicks_til_next_interrupt < 400)
102      {
103        tick_time = itimer_value + 1000;
104        clicks_til_next_interrupt = 1000;
105        /* XXX: count these! this should be rare */
106      }
107 
108      /*
109       * If it is too late, that means we missed the interrupt somehow.
110       * Rather than wait 35-50s for a wrap, we just fudge it here.
111       */
112 
113      if (clicks_til_next_interrupt > pit_value)
114      {
115        tick_time = itimer_value + 1000;
116        clicks_til_next_interrupt = 1000;
117        /* XXX: count these! this should never happen :-) */
118      }
119 
120      asm volatile ("mtspr 0x3db, %0" :: "r" 
121                         (clicks_til_next_interrupt)); /* PIT */
122  }
123 
124    asm volatile ( "mtspr 0x3d8, %0" :: "r" (0x08000000)); /* TSR */
125 
126    Clock_driver_ticks++;
127 
128    rtems_clock_tick();
129}
130
131void Install_clock(rtems_isr_entry clock_isr)
132{
133    rtems_isr_entry previous_isr;
134    rtems_unsigned32 pvr, iocr;
135    register rtems_unsigned32 tcr;
136 
137    Clock_driver_ticks = 0;
138 
139    asm volatile ("mfdcr %0, 0xa0" : "=r" (iocr)); /* IOCR */
140
141    if (rtems_cpu_configuration_get_timer_internal_clock()) {
142        iocr &= ~4; /* timer clocked from system clock */
143    }
144    else {
145        iocr |= 4; /* select external timer clock */
146    }
147
148    asm volatile ("mtdcr 0xa0, %0" : "=r" (iocr) : "0" (iocr)); /* IOCR */
149 
150    asm volatile ("mfspr %0, 0x11f" : "=r" ((pvr))); /* PVR */
151 
152    if (((pvr & 0xffff0000) >> 16) != 0x0020)
153      return; /* Not a ppc403 */
154 
155    if ((pvr & 0xff00) == 0x0000) /* 403GA */
156#if 0 /* FIXME: in which processor versions will "autoload" work properly? */
157      auto_restart = (pvr & 0x00f0) > 0x0000 ? 1 : 0;
158#else
159    /* no known chip version supports auto restart of timer... */
160    auto_restart = 0;
161#endif
162    else if ((pvr & 0xff00) == 0x0100) /* 403GB */
163      auto_restart = 1;
164 
165    pit_value = rtems_configuration_get_microseconds_per_tick() *
166      rtems_cpu_configuration_get_clicks_per_usec();
167 
168
169    /*
170     * initialize the interval here
171     * First tick is set to right amount of time in the future
172     * Future ticks will be incremented over last value set
173     * in order to provide consistent clicks in the face of
174     * interrupt overhead
175     */
176
177    rtems_interrupt_catch(clock_isr, PPC_IRQ_PIT, &previous_isr);
178
179    asm volatile ("mtspr 0x3db, %0" : : "r" (pit_value)); /* PIT */
180 
181    asm volatile ("mfspr %0, 0x3da" : "=r" ((tcr))); /* TCR */
182 
183    tcr &= ~ 0x04400000;
184 
185    tcr |= (auto_restart ? 0x04400000 : 0x04000000);
186 
187    tick_time = get_itimer() + pit_value;
188 
189    asm volatile ("mtspr 0x3da, %0" : "=r" ((tcr)) : "0" ((tcr))); /* TCR */
190
191    atexit(Clock_exit);
192}
193
194void
195ReInstall_clock(rtems_isr_entry new_clock_isr)
196{
197    rtems_isr_entry previous_isr;
198    rtems_unsigned32 isrlevel = 0;
199
200    rtems_interrupt_disable(isrlevel);
201   
202    rtems_interrupt_catch(new_clock_isr, PPC_IRQ_PIT, &previous_isr);
203
204    rtems_interrupt_enable(isrlevel);
205}
206
207
208/*
209 * Called via atexit()
210 * Remove the clock interrupt handler by setting handler to NULL
211 */
212
213void
214Clock_exit(void)
215{
216    register rtems_unsigned32 tcr;
217 
218    asm volatile ("mfspr %0, 0x3da" : "=r" ((tcr))); /* TCR */
219 
220    tcr &= ~ 0x04400000;
221 
222    asm volatile ("mtspr 0x3da, %0" : "=r" ((tcr)) : "0" ((tcr))); /* TCR */
223 
224    (void) set_vector(0, PPC_IRQ_PIT, 1);
225}
226
227rtems_device_driver Clock_initialize(
228  rtems_device_major_number major,
229  rtems_device_minor_number minor,
230  void *pargp
231)
232{
233  Install_clock( Clock_isr );
234 
235  /*
236   * make major/minor avail to others such as shared memory driver
237   */
238 
239  rtems_clock_major = major;
240  rtems_clock_minor = minor;
241 
242  return RTEMS_SUCCESSFUL;
243}
244 
245rtems_device_driver Clock_control(
246  rtems_device_major_number major,
247  rtems_device_minor_number minor,
248  void *pargp
249)
250{
251    rtems_libio_ioctl_args_t *args = pargp;
252 
253    if (args == 0)
254        goto done;
255 
256    /*
257     * This is hokey, but until we get a defined interface
258     * to do this, it will just be this simple...
259     */
260 
261    if (args->command == rtems_build_name('I', 'S', 'R', ' '))
262    {
263        Clock_isr(PPC_IRQ_PIT);
264    }
265    else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
266    {
267        ReInstall_clock(args->buffer);
268    }
269 
270done:
271    return RTEMS_SUCCESSFUL;
272}
273
Note: See TracBrowser for help on using the repository browser.