source: rtems/c/src/lib/libcpu/powerpc/ppc403/clock/clock.c @ 08311cc3

4.104.114.84.95
Last change on this file since 08311cc3 was 08311cc3, checked in by Joel Sherrill <joel.sherrill@…>, on Nov 17, 1999 at 5:51:34 PM

Updated copyright notice.

  • Property mode set to 100644
File size: 7.1 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 
136    Clock_driver_ticks = 0;
137 
138    asm volatile ("mfdcr %0, 0xa0" : "=r" (iocr)); /* IOCR */
139
140    if (rtems_cpu_configuration_get_timer_internal_clock()) {
141        iocr &= ~4; /* timer clocked from system clock */
142    }
143    else {
144        iocr |= 4; /* select external timer clock */
145    }
146
147    asm volatile ("mtdcr 0xa0, %0" : "=r" (iocr) : "0" (iocr)); /* IOCR */
148 
149    asm volatile ("mfspr %0, 0x11f" : "=r" ((pvr))); /* PVR */
150 
151    if (((pvr & 0xffff0000) >> 16) != 0x0020)
152      return; /* Not a ppc403 */
153 
154    if ((pvr & 0xff00) == 0x0000) /* 403GA */
155#if 0 /* FIXME: in which processor versions will "autoload" work properly? */
156      auto_restart = (pvr & 0x00f0) > 0x0000 ? 1 : 0;
157#else
158    /* no known chip version supports auto restart of timer... */
159    auto_restart = 0;
160#endif
161    else if ((pvr & 0xff00) == 0x0100) /* 403GB */
162      auto_restart = 1;
163 
164    pit_value = rtems_configuration_get_microseconds_per_tick() *
165      rtems_cpu_configuration_get_clicks_per_usec();
166 
167    if ( rtems_configuration_get_ticks_per_timeslice() ) {
168      register rtems_unsigned32 tcr;
169
170        /*
171         * initialize the interval here
172         * First tick is set to right amount of time in the future
173         * Future ticks will be incremented over last value set
174         * in order to provide consistent clicks in the face of
175         * interrupt overhead
176         */
177 
178      rtems_interrupt_catch(clock_isr, PPC_IRQ_PIT, &previous_isr);
179 
180      asm volatile ("mtspr 0x3db, %0" : : "r" (pit_value)); /* PIT */
181 
182      asm volatile ("mfspr %0, 0x3da" : "=r" ((tcr))); /* TCR */
183 
184      tcr &= ~ 0x04400000;
185 
186      tcr |= (auto_restart ? 0x04400000 : 0x04000000);
187 
188      tick_time = get_itimer() + pit_value;
189 
190      asm volatile ("mtspr 0x3da, %0" : "=r" ((tcr)) : "0" ((tcr))); /* TCR */
191    }
192    atexit(Clock_exit);
193}
194
195void
196ReInstall_clock(rtems_isr_entry new_clock_isr)
197{
198    rtems_isr_entry previous_isr;
199    rtems_unsigned32 isrlevel = 0;
200
201    rtems_interrupt_disable(isrlevel);
202   
203    rtems_interrupt_catch(new_clock_isr, PPC_IRQ_PIT, &previous_isr);
204
205    rtems_interrupt_enable(isrlevel);
206}
207
208
209/*
210 * Called via atexit()
211 * Remove the clock interrupt handler by setting handler to NULL
212 */
213
214void
215Clock_exit(void)
216{
217    if ( rtems_configuration_get_ticks_per_timeslice() ) {
218      register rtems_unsigned32 tcr;
219 
220      asm volatile ("mfspr %0, 0x3da" : "=r" ((tcr))); /* TCR */
221 
222      tcr &= ~ 0x04400000;
223 
224      asm volatile ("mtspr 0x3da, %0" : "=r" ((tcr)) : "0" ((tcr))); /* TCR */
225 
226      (void) set_vector(0, PPC_IRQ_PIT, 1);
227    }
228
229}
230
231rtems_device_driver Clock_initialize(
232  rtems_device_major_number major,
233  rtems_device_minor_number minor,
234  void *pargp
235)
236{
237  Install_clock( Clock_isr );
238 
239  /*
240   * make major/minor avail to others such as shared memory driver
241   */
242 
243  rtems_clock_major = major;
244  rtems_clock_minor = minor;
245 
246  return RTEMS_SUCCESSFUL;
247}
248 
249rtems_device_driver Clock_control(
250  rtems_device_major_number major,
251  rtems_device_minor_number minor,
252  void *pargp
253)
254{
255    rtems_libio_ioctl_args_t *args = pargp;
256 
257    if (args == 0)
258        goto done;
259 
260    /*
261     * This is hokey, but until we get a defined interface
262     * to do this, it will just be this simple...
263     */
264 
265    if (args->command == rtems_build_name('I', 'S', 'R', ' '))
266    {
267        Clock_isr(PPC_IRQ_PIT);
268    }
269    else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
270    {
271        ReInstall_clock(args->buffer);
272    }
273 
274done:
275    return RTEMS_SUCCESSFUL;
276}
277
Note: See TracBrowser for help on using the repository browser.