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

4.104.114.84.95
Last change on this file since e9ae97fb was e9ae97fb, checked in by Joel Sherrill <joel.sherrill@…>, on 11/09/01 at 00:04:57

2001-11-08 Dennis Ehlin (ECS) <Dennis.Ehlin@…>

This modification is part of the submitted modifications necessary to
support the IBM PPC405 family. This submission was reviewed by
Thomas Doerfler <Thomas.Doerfler@…> who ensured it did
not negatively impact the ppc403 BSPs. The submission and tracking
process was captured as PR50.

  • ppc403/console/console405.c ppc403/tty_drv/.cvsignore, ppc403/tty_drv/Makefile.am, ppc403/tty_drv/tty_drv.c, ppc403/tty_drv/tty_drv.h: New files.
  • Makefile.am, README, configure.ac, old_exception_processing/cpu.c, old_exception_processing/cpu.h, ppc403/Makefile.am, ppc403/clock/clock.c, ppc403/console/Makefile.am, ppc403/console/console.c, ppc403/ictrl/ictrl.c, ppc403/ictrl/ictrl.h, ppc403/timer/timer.c: Modified.
  • Property mode set to 100644
File size: 8.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 *  COPYRIGHT (c) 1989-1999.
29 *  On-Line Applications Research Corporation (OAR).
30 *
31 *  The license and distribution terms for this file may be
32 *  found in the file LICENSE in this distribution or at
33 *  http://www.OARcorp.com/rtems/license.html.
34 *
35 *  Modifications for PPC405GP by Dennis Ehlin
36 *
37 *  $Id$
38 */
39
40#include <rtems.h>
41#include <clockdrv.h>
42#include <rtems/libio.h>
43
44#include <stdlib.h>                     /* for atexit() */
45
46volatile rtems_unsigned32 Clock_driver_ticks;
47static rtems_unsigned32 pit_value, tick_time;
48static rtems_boolean auto_restart;
49
50void Clock_exit( void );
51 
52/*
53 * These are set by clock driver during its init
54 */
55 
56rtems_device_major_number rtems_clock_major = ~0;
57rtems_device_minor_number rtems_clock_minor;
58 
59static inline rtems_unsigned32 get_itimer(void)
60{
61    register rtems_unsigned32 rc;
62
63#ifndef ppc405 /* this is a ppc403 */
64    asm volatile ("mfspr %0, 0x3dd" : "=r" ((rc))); /* TBLO */
65#else /* ppc405 */
66    asm volatile ("mfspr %0, 0x10c" : "=r" ((rc))); /* 405GP TBL */
67#endif /* ppc405 */
68
69    return rc;
70}
71
72/*
73 *  ISR Handler
74 */
75 
76rtems_isr
77Clock_isr(rtems_vector_number vector)
78{
79      rtems_unsigned32 clicks_til_next_interrupt;
80    if (!auto_restart)
81    {
82      rtems_unsigned32 itimer_value;
83      /*
84       * setup for next interrupt; making sure the new value is reasonably
85       * in the future.... in case we lost out on an interrupt somehow
86       */
87 
88      itimer_value = get_itimer();
89      tick_time += pit_value;
90 
91      /*
92       * how far away is next interrupt *really*
93       * It may be a long time; this subtraction works even if
94       * Clock_clicks_interrupt < Clock_clicks_low_order via
95       * the miracle of unsigned math.
96       */
97      clicks_til_next_interrupt = tick_time - itimer_value;
98 
99      /*
100       * If it is too soon then bump it up.
101       * This should only happen if CPU_HPPA_CLICKS_PER_TICK is too small.
102       * But setting it low is useful for debug, so...
103       */
104 
105      if (clicks_til_next_interrupt < 400)
106      {
107        tick_time = itimer_value + 1000;
108        clicks_til_next_interrupt = 1000;
109        /* XXX: count these! this should be rare */
110      }
111 
112      /*
113       * If it is too late, that means we missed the interrupt somehow.
114       * Rather than wait 35-50s for a wrap, we just fudge it here.
115       */
116 
117      if (clicks_til_next_interrupt > pit_value)
118      {
119        tick_time = itimer_value + 1000;
120        clicks_til_next_interrupt = 1000;
121        /* XXX: count these! this should never happen :-) */
122      }
123 
124      asm volatile ("mtspr 0x3db, %0" :: "r"
125                         (clicks_til_next_interrupt)); /* PIT */
126  }
127 
128    asm volatile ( "mtspr 0x3d8, %0" :: "r" (0x08000000)); /* TSR */
129 
130    Clock_driver_ticks++;
131 
132    rtems_clock_tick();
133}
134
135void Install_clock(rtems_isr_entry clock_isr)
136{
137    rtems_isr_entry previous_isr;
138    rtems_unsigned32 iocr;
139    register rtems_unsigned32 tcr;
140#ifdef ppc403
141    rtems_unsigned32 pvr;
142#endif /* ppc403 */
143 
144    Clock_driver_ticks = 0;
145 
146#ifndef ppc405 /* this is a ppc403 */
147    asm volatile ("mfdcr %0, 0xa0" : "=r" (iocr)); /* IOCR */
148    if (rtems_cpu_configuration_get_timer_internal_clock()) {
149        iocr &= ~4; /* timer clocked from system clock */
150    }
151    else {
152        iocr |= 4; /* select external timer clock */
153    }
154    asm volatile ("mtdcr 0xa0, %0" : "=r" (iocr) : "0" (iocr)); /* IOCR */
155 
156    asm volatile ("mfspr %0, 0x11f" : "=r" ((pvr))); /* PVR */
157    if (((pvr & 0xffff0000) >> 16) != 0x0020)
158      return; /* Not a ppc403 */
159 
160    if ((pvr & 0xff00) == 0x0000) /* 403GA */
161#if 0 /* FIXME: in which processor versions will "autoload" work properly? */
162      auto_restart = (pvr & 0x00f0) > 0x0000 ? 1 : 0;
163#else
164    /* no known chip version supports auto restart of timer... */
165    auto_restart = 0;
166#endif
167    else if ((pvr & 0xff00) == 0x0100) /* 403GB */
168      auto_restart = 1;
169 
170#else /* ppc405 */
171    asm volatile ("mfdcr %0, 0x0b2" : "=r" (iocr));  /*405GP CPC0_CR1 */
172    if (rtems_cpu_configuration_get_timer_internal_clock()) {
173        iocr &=~0x800000        ;/* timer clocked from system clock CETE*/
174    }
175    else {
176        iocr |= 0x800000; /* select external timer clock CETE*/
177    }
178    asm volatile ("mtdcr 0x0b2, %0" : "=r" (iocr) : "0" (iocr)); /* 405GP CPC0_CR1 */
179
180     /*
181      * Enable auto restart
182      */
183
184    auto_restart=1;
185
186#endif /* ppc405 */
187    pit_value = rtems_configuration_get_microseconds_per_tick() *
188      rtems_cpu_configuration_get_clicks_per_usec();
189 
190    /*
191     * initialize the interval here
192     * First tick is set to right amount of time in the future
193     * Future ticks will be incremented over last value set
194     * in order to provide consistent clicks in the face of
195     * interrupt overhead
196     */
197
198    rtems_interrupt_catch(clock_isr, PPC_IRQ_PIT, &previous_isr);
199
200     /*
201      * Set PIT value
202      */
203
204    asm volatile ("mtspr 0x3db, %0" : : "r" (pit_value)); /* PIT */
205 
206     /*     
207      * Set timer to autoreload, bit TCR->ARE = 1  0x0400000
208      * Enable PIT interrupt, bit TCR->PIE = 1     0x4000000
209      */
210    tick_time = get_itimer() + pit_value;
211    asm volatile ("mfspr %0, 0x3da" : "=r" ((tcr))); /* TCR */
212    tcr = (tcr & ~0x04400000) | (auto_restart ? 0x04400000 : 0x04000000);
213    asm volatile ("mtspr 0x3da, %0" : "=r" ((tcr)) : "0" ((tcr))); /* TCR */
214
215    atexit(Clock_exit);
216}
217
218void
219ReInstall_clock(rtems_isr_entry new_clock_isr)
220{
221    rtems_isr_entry previous_isr;
222    rtems_unsigned32 isrlevel = 0;
223
224    rtems_interrupt_disable(isrlevel);
225   
226    rtems_interrupt_catch(new_clock_isr, PPC_IRQ_PIT, &previous_isr);
227
228    rtems_interrupt_enable(isrlevel);
229}
230
231
232/*
233 * Called via atexit()
234 * Remove the clock interrupt handler by setting handler to NULL
235 *
236 * This will not work on the 405GP because
237 * when bit's are set in TCR they can only be unset by a reset
238 */
239
240void
241Clock_exit(void)
242{
243    register rtems_unsigned32 tcr;
244 
245    asm volatile ("mfspr %0, 0x3da" : "=r" ((tcr))); /* TCR */
246 
247    tcr &= ~ 0x04400000;
248 
249    asm volatile ("mtspr 0x3da, %0" : "=r" ((tcr)) : "0" ((tcr))); /* TCR */
250 
251    (void) set_vector(0, PPC_IRQ_PIT, 1);
252}
253
254rtems_device_driver Clock_initialize(
255  rtems_device_major_number major,
256  rtems_device_minor_number minor,
257  void *pargp
258)
259{
260  Install_clock( Clock_isr );
261 
262  /*
263   * make major/minor avail to others such as shared memory driver
264   */
265 
266  rtems_clock_major = major;
267  rtems_clock_minor = minor;
268 
269  return RTEMS_SUCCESSFUL;
270}
271 
272rtems_device_driver Clock_control(
273  rtems_device_major_number major,
274  rtems_device_minor_number minor,
275  void *pargp
276)
277{
278    rtems_libio_ioctl_args_t *args = pargp;
279 
280    if (args == 0)
281        goto done;
282 
283    /*
284     * This is hokey, but until we get a defined interface
285     * to do this, it will just be this simple...
286     */
287 
288    if (args->command == rtems_build_name('I', 'S', 'R', ' '))
289    {
290        Clock_isr(PPC_IRQ_PIT);
291    }
292    else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
293    {
294        ReInstall_clock(args->buffer);
295    }
296 
297done:
298    return RTEMS_SUCCESSFUL;
299}
300
Note: See TracBrowser for help on using the repository browser.