OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [lib/] [libcpu/] [powerpc/] [ppc403/] [clock/] [clock.c] - Blame information for rev 173

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 30 unneback
/*  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: clock.c,v 1.2 2001-09-27 12:01:29 chris Exp $
37
 */
38
 
39
#include <rtems.h>
40
#include <clockdrv.h>
41
#include <rtems/libio.h>
42
 
43
#include <stdlib.h>                     /* for atexit() */
44
 
45
volatile rtems_unsigned32 Clock_driver_ticks;
46
static rtems_unsigned32 pit_value, tick_time;
47
static rtems_boolean auto_restart;
48
 
49
void Clock_exit( void );
50
 
51
/*
52
 * These are set by clock driver during its init
53
 */
54
 
55
rtems_device_major_number rtems_clock_major = ~0;
56
rtems_device_minor_number rtems_clock_minor;
57
 
58
static 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
 
71
rtems_isr
72
Clock_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
 
131
void 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
 
194
void
195
ReInstall_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
 
213
void
214
Clock_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
 
227
rtems_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
 
245
rtems_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
 
270
done:
271
    return RTEMS_SUCCESSFUL;
272
}
273
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.