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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems/] [c/] [src/] [lib/] [libcpu/] [hppa1.1/] [clock/] [clock.c] - Blame information for rev 208

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 158 chris
/*  Clock
2
 *
3
 *  This routine initializes the interval timer on the
4
 *  PA-RISC CPU.  The tick frequency is specified by the bsp.
5
 *
6
 *  COPYRIGHT (c) 1989-1999.
7
 *  On-Line Applications Research Corporation (OAR).
8
 *
9
 *  The license and distribution terms for this file may be
10
 *  found in the file LICENSE in this distribution or at
11
 *  http://www.OARcorp.com/rtems/license.html.
12
 *
13 208 chris
 *  $Id: clock.c,v 1.2 2001-09-27 12:01:20 chris Exp $
14 158 chris
 */
15
 
16
#include <rtems.h>
17
#include <rtems/libio.h>
18
 
19
/* should get this from bsp.h, but it is not installed yet */
20
rtems_isr_entry set_vector(rtems_isr_entry, rtems_vector_number, int);
21
 
22
#include <stdlib.h>                     /* for atexit() */
23
 
24
typedef unsigned long long hppa_click_count_t;
25
 
26
/*
27
 * These are set by clock driver during its init
28
 */
29
 
30
rtems_device_major_number rtems_clock_major = ~0;
31
rtems_device_minor_number rtems_clock_minor;
32
 
33
/*
34
 * CPU_HPPA_CLICKS_PER_TICK is either a #define or an rtems_unsigned32
35
 *   allocated and set by bsp_start()
36
 */
37
 
38
#ifndef CPU_HPPA_CLICKS_PER_TICK
39
extern rtems_unsigned32 CPU_HPPA_CLICKS_PER_TICK;
40
#endif
41
 
42
volatile rtems_unsigned32 Clock_driver_ticks;
43
rtems_unsigned32 Clock_isrs;              /* ISRs until next tick */
44
 
45
rtems_unsigned32   most_recent_itimer_value;
46
 
47
rtems_unsigned64   Clock_clicks;        /* running total of cycles */
48
 
49
rtems_unsigned32   Clock_clicks_interrupt;
50
 
51
void  Clock_exit(void);
52
 
53
void
54
ReInstall_clock(rtems_isr_entry new_clock_isr)
55
{
56
    rtems_unsigned32 isrlevel = 0;
57
 
58
    rtems_interrupt_disable(isrlevel);
59
    (void) set_vector(
60
      new_clock_isr,
61
      HPPA_INTERRUPT_EXTERNAL_INTERVAL_TIMER,
62
      1
63
    );
64
    rtems_interrupt_enable(isrlevel);
65
}
66
 
67
/*
68
 * read itimer and update Clock_clicks as appropriate
69
 */
70
 
71
rtems_unsigned32
72
Clock_read_itimer()
73
{
74
    rtems_unsigned32 isrlevel;
75
    rtems_unsigned32 itimer_value;
76
    rtems_unsigned32 wrap_count;
77
    rtems_unsigned32 recent_count;
78
 
79
    rtems_interrupt_disable(isrlevel);
80
 
81
    wrap_count = (Clock_clicks & 0xFFFFFFFF00000000ULL) >> 32;
82
    recent_count = (rtems_unsigned32) Clock_clicks;
83
 
84
    itimer_value = get_itimer();
85
 
86
    if (itimer_value < recent_count)
87
        wrap_count++;
88
    Clock_clicks = (((rtems_unsigned64) wrap_count) << 32) + itimer_value;
89
 
90
    rtems_interrupt_enable(isrlevel);
91
 
92
    return itimer_value;
93
}
94
 
95
 
96
void Install_clock(rtems_isr_entry clock_isr)
97
{
98
    Clock_driver_ticks = 0;
99
    Clock_clicks_interrupt = 0;
100
    Clock_clicks = 0;
101
 
102
    Clock_isrs = rtems_configuration_get_milliseconds_per_tick();
103
 
104
    /*
105
     * initialize the interval here
106
     * First tick is set to right amount of time in the future
107
     * Future ticks will be incremented over last value set
108
     * in order to provide consistent clicks in the face of
109
     * interrupt overhead
110
     */
111
 
112
    Clock_clicks_interrupt = Clock_read_itimer() + CPU_HPPA_CLICKS_PER_TICK;
113
    set_itimer((rtems_unsigned32) Clock_clicks_interrupt);
114
 
115
    (void) set_vector(clock_isr, HPPA_INTERRUPT_EXTERNAL_INTERVAL_TIMER, 1);
116
    atexit(Clock_exit);
117
}
118
 
119
rtems_isr
120
Clock_isr(rtems_vector_number vector)
121
{
122
    rtems_unsigned32 clicks_til_next_interrupt;
123
    rtems_unsigned32 itimer_value;
124
 
125
    /*
126
     * setup for next interrupt; making sure the new value is reasonably
127
     * in the future.... in case we lost out on an interrupt somehow
128
     */
129
 
130
    itimer_value = Clock_read_itimer();
131
    Clock_clicks_interrupt += CPU_HPPA_CLICKS_PER_TICK;
132
 
133
    /*
134
     * how far away is next interrupt *really*
135
     * It may be a long time; this subtraction works even if
136
     * Clock_clicks_interrupt < Clock_clicks_low_order via
137
     * the miracle of unsigned math.
138
     */
139
    clicks_til_next_interrupt = Clock_clicks_interrupt - itimer_value;
140
 
141
    /*
142
     * If it is too soon then bump it up.
143
     * This should only happen if CPU_HPPA_CLICKS_PER_TICK is too small.
144
     * But setting it low is useful for debug, so...
145
     */
146
 
147
    if (clicks_til_next_interrupt < 400)
148
    {
149
        Clock_clicks_interrupt = itimer_value + 1000;
150
        /* XXX: count these! this should be rare */
151
    }
152
 
153
    /*
154
     * If it is too late, that means we missed the interrupt somehow.
155
     * Rather than wait 35-50s for a wrap, we just fudge it here.
156
     */
157
 
158
    if (clicks_til_next_interrupt > CPU_HPPA_CLICKS_PER_TICK)
159
    {
160
        Clock_clicks_interrupt = itimer_value + 1000;
161
        /* XXX: count these! this should never happen :-) */
162
    }
163
 
164
    set_itimer((rtems_unsigned32) Clock_clicks_interrupt);
165
 
166
    Clock_driver_ticks++;
167
 
168
    if (Clock_isrs == 1)
169
    {
170
        rtems_clock_tick();
171
        Clock_isrs = rtems_configuration_get_milliseconds_per_tick();
172
        if (Clock_isrs == 0)
173
            Clock_isrs = 1;
174
    }
175
    else
176
        Clock_isrs--;
177
}
178
 
179
/*
180
 * Called via atexit()
181
 * Remove the clock interrupt handler by setting handler to NULL
182
 */
183
 
184
void
185
Clock_exit(void)
186
{
187
  (void) set_vector(0, HPPA_INTERRUPT_EXTERNAL_INTERVAL_TIMER, 1);
188
}
189
 
190
/*
191
 * spin delay for specified number of microseconds
192
 * used by RTEMS delay macro
193
 */
194
 
195
void
196
Clock_delay(rtems_unsigned32 microseconds)
197
{
198
    rtems_unsigned64 future_time;
199
 
200
    (void) Clock_read_itimer();
201
    future_time = Clock_clicks +
202
      ((rtems_unsigned64) microseconds) *
203
        rtems_cpu_configuration_get_itimer_clicks_per_microsecond();
204
 
205
    for (;;)
206
    {
207
        (void) Clock_read_itimer();
208
        if (future_time <= Clock_clicks)
209
            break;
210
    }
211
}
212
 
213
rtems_device_driver Clock_initialize(
214
  rtems_device_major_number major,
215
  rtems_device_minor_number minor,
216
  void *pargp
217
)
218
{
219
    Install_clock(Clock_isr);
220
 
221
    /*
222
     * make major/minor avail to others such as shared memory driver
223
     */
224
    rtems_clock_major = major;
225
    rtems_clock_minor = minor;
226
 
227
    return RTEMS_SUCCESSFUL;
228
}
229
 
230
rtems_device_driver Clock_control(
231
  rtems_device_major_number major,
232
  rtems_device_minor_number minor,
233
  void *pargp
234
)
235
{
236
    rtems_libio_ioctl_args_t *args = pargp;
237
 
238
    if (args == 0)
239
        goto done;
240
 
241
    /*
242
     * This is hokey, but until we get a defined interface
243
     * to do this, it will just be this simple...
244
     */
245
 
246
    if (args->command == rtems_build_name('I', 'S', 'R', ' '))
247
    {
248
        Clock_isr(HPPA_INTERRUPT_EXTERNAL_INTERVAL_TIMER);
249
    }
250
    else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
251
    {
252
        ReInstall_clock(args->buffer);
253
    }
254
 
255
done:
256
    return RTEMS_SUCCESSFUL;
257
}

powered by: WebSVN 2.1.0

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