source: rtems/c/src/lib/libbsp/powerpc/virtex4/clock/clock.c @ 16f0a50

4.115
Last change on this file since 16f0a50 was 16f0a50, checked in by Joel Sherrill <joel.sherrill@…>, on 05/08/12 at 22:39:26

virtex4 - Eliminate any set_vector() remnants

  • Property mode set to 100644
File size: 6.7 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-2007.
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.rtems.com/license/LICENSE.
34 *
35 *  Modifications for PPC405GP by Dennis Ehlin
36 *
37 *  $Id: clock.c 63 2011-04-26 00:23:51Z claus $
38 */
39
40#include <rtems.h>
41#include <rtems/clockdrv.h>
42#include <rtems/libio.h>
43#include <stdlib.h>                     /* for atexit() */
44#include <rtems/bspIo.h>
45#include <rtems/powerpc/powerpc.h>
46
47/*
48 * check, which exception handling code is present
49 */
50
51#include <bsp.h>
52
53#include <bsp/vectors.h>
54#include <bsp/irq_supp.h>
55
56volatile uint32_t   Clock_driver_ticks;
57static uint32_t   pit_value, tick_time;
58static bool auto_restart;
59
60void Clock_exit( void );
61
62/*
63 * These are set by clock driver during its init
64 */
65
66rtems_device_major_number rtems_clock_major = ~0;
67rtems_device_minor_number rtems_clock_minor;
68
69static inline uint32_t   get_itimer(void)
70{
71    register uint32_t   rc;
72
73    asm volatile ("mfspr %0, 0x10c" : "=r" ((rc))); /* 405GP TBL */
74
75    return rc;
76}
77
78/*
79 *  ISR Handler
80 */
81
82int Clock_isr(BSP_Exception_frame *f, unsigned int vector)
83{
84    uint32_t   clicks_til_next_interrupt;
85#if defined(BSP_PPC403_CLOCK_ISR_IRQ_LEVEL)
86    uint32_t   l_orig = _ISR_Get_level();
87#endif
88    if (!auto_restart)
89    {
90      uint32_t   itimer_value;
91      /*
92       * setup for next interrupt; making sure the new value is reasonably
93       * in the future.... in case we lost out on an interrupt somehow
94       */
95
96      itimer_value = get_itimer();
97      tick_time += pit_value;
98
99      /*
100       * how far away is next interrupt *really*
101       * It may be a long time; this subtraction works even if
102       * Clock_clicks_interrupt < Clock_clicks_low_order via
103       * the miracle of unsigned math.
104       */
105      clicks_til_next_interrupt = tick_time - itimer_value;
106
107      /*
108       * If it is too soon then bump it up.
109       * This should only happen if CPU_HPPA_CLICKS_PER_TICK is too small.
110       * But setting it low is useful for debug, so...
111       */
112
113      if (clicks_til_next_interrupt < 400)
114      {
115        tick_time = itimer_value + 1000;
116        clicks_til_next_interrupt = 1000;
117        /* XXX: count these! this should be rare */
118      }
119
120      /*
121       * If it is too late, that means we missed the interrupt somehow.
122       * Rather than wait 35-50s for a wrap, we just fudge it here.
123       */
124
125      if (clicks_til_next_interrupt > pit_value)
126      {
127        tick_time = itimer_value + 1000;
128        clicks_til_next_interrupt = 1000;
129        /* XXX: count these! this should never happen :-) */
130      }
131
132      asm volatile ("mtspr 0x3db, %0" :: "r"
133                         (clicks_til_next_interrupt)); /* PIT */
134    }
135
136    /* Clear the Programmable Interrupt Status */
137    asm volatile ( "mtspr 0x3d8, %0" :: "r" (0x08000000)); /* TSR */
138
139    Clock_driver_ticks++;
140
141    rtems_clock_tick();
142
143    return 0;
144}
145
146void ClockOff(void)
147{
148    register uint32_t   tcr;
149
150    asm volatile ("mfspr %0, 0x3da" : "=r" ((tcr))); /* TCR */
151
152    tcr &= ~ 0x04400000;
153
154    asm volatile ("mtspr 0x3da, %0" : "=r" ((tcr)) : "0" ((tcr))); /* TCR */
155}
156
157void ClockOn(void)
158{
159    uint32_t   iocr;
160    register uint32_t   tcr;
161
162    Clock_driver_ticks = 0;
163
164    asm volatile ("mfdcr %0, 0x0b2" : "=r" (iocr));  /*405GP CPC0_CR1 */
165    if (bsp_timer_internal_clock) {
166      iocr &=~0x800000;               /* timer clocked from system clock CETE*/
167    }
168    else {
169      iocr |= 0x800000;               /* select external timer clock CETE*/
170    }
171    asm volatile ("mtdcr 0x0b2, %0" : "=r" (iocr) : "0" (iocr)); /* 405GP CPC0_CR1 */
172
173     /*
174      * Enable auto restart
175      */
176
177    auto_restart = true;
178
179    pit_value = rtems_configuration_get_microseconds_per_tick() *
180      bsp_clicks_per_usec;
181
182     /*
183      * Set PIT value
184      */
185
186    asm volatile ("mtspr 0x3db, %0" : : "r" (pit_value)); /* PIT */
187
188     /*
189      * Set timer to autoreload, bit TCR->ARE = 1  0x0400000
190      * Enable PIT interrupt, bit TCR->PIE = 1     0x4000000
191      */
192    tick_time = get_itimer() + pit_value;
193
194    asm volatile ("mfspr %0, 0x3da" : "=r" ((tcr)));               /* TCR */
195    tcr = (tcr & ~0x04400000) | (auto_restart ? 0x04400000 : 0x04000000);
196    asm volatile ("mtspr 0x3da, %0" : "=r" ((tcr)) : "0" ((tcr))); /* TCR */
197}
198
199
200
201void Install_clock(ppc_exc_handler_t clock_isr)
202{
203#ifdef ppc403
204   uint32_t   pvr;
205#endif /* ppc403 */
206
207   Clock_driver_ticks = 0;
208
209   /*
210    * initialize the interval here
211    * First tick is set to right amount of time in the future
212    * Future ticks will be incremented over last value set
213    * in order to provide consistent clicks in the face of
214    * interrupt overhead
215    */
216
217   ppc_exc_set_handler( BSP_PPC403_CLOCK_HOOK_EXCEPTION, clock_isr );
218   ClockOn();
219
220   atexit(Clock_exit);
221}
222
223void
224ReInstall_clock(ppc_exc_handler_t clock_isr)
225{
226  uint32_t   isrlevel = 0;
227
228  rtems_interrupt_disable(isrlevel);
229
230   ppc_exc_set_handler( BSP_PPC403_CLOCK_HOOK_EXCEPTION, clock_isr );
231   ClockOn();
232
233  rtems_interrupt_enable(isrlevel);
234}
235
236
237/*
238 * Called via atexit()
239 * Remove the clock interrupt handler by setting handler to NULL
240 *
241 * This will not work on the 405GP because
242 * when bit's are set in TCR they can only be unset by a reset
243 */
244
245void Clock_exit(void)
246{
247  ClockOff();
248  ppc_exc_set_handler( BSP_PPC403_CLOCK_HOOK_EXCEPTION, 0 );
249}
250
251rtems_device_driver Clock_initialize(
252  rtems_device_major_number major,
253  rtems_device_minor_number minor,
254  void *pargp
255)
256{
257  Install_clock( Clock_isr );
258
259  /*
260   * make major/minor avail to others such as shared memory driver
261   */
262
263  rtems_clock_major = major;
264  rtems_clock_minor = minor;
265
266  return RTEMS_SUCCESSFUL;
267}
Note: See TracBrowser for help on using the repository browser.