Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
script3r
GitHub Repository: script3r/os161
Path: blob/master/kern/dev/lamebus/ltimer.c
2093 views
1
/*
2
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
3
* The President and Fellows of Harvard College.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
* 3. Neither the name of the University nor the names of its contributors
14
* may be used to endorse or promote products derived from this software
15
* without specific prior written permission.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*/
29
30
/*
31
* Driver for LAMEbus clock/timer card
32
*/
33
#include <types.h>
34
#include <lib.h>
35
#include <spl.h>
36
#include <clock.h>
37
#include <platform/bus.h>
38
#include <lamebus/ltimer.h>
39
#include "autoconf.h"
40
41
/* Registers (offsets within slot) */
42
#define LT_REG_SEC 0 /* time of day: seconds */
43
#define LT_REG_NSEC 4 /* time of day: nanoseconds */
44
#define LT_REG_ROE 8 /* Restart On countdown-timer Expiry flag */
45
#define LT_REG_IRQ 12 /* Interrupt status register */
46
#define LT_REG_COUNT 16 /* Time for countdown timer (usec) */
47
#define LT_REG_SPKR 20 /* Beep control */
48
49
/* Granularity of countdown timer (usec) */
50
#define LT_GRANULARITY 1000000
51
52
static bool havetimerclock;
53
54
/*
55
* Setup routine called by autoconf stuff when an ltimer is found.
56
*/
57
int
58
config_ltimer(struct ltimer_softc *lt, int ltimerno)
59
{
60
/*
61
* Running on System/161 2.x, we always use the processor
62
* on-chip timer for hardclock and we don't need ltimer as
63
* hardclock.
64
*
65
* Ideally there should be code here that will use an ltimer
66
* for hardclock if nothing else is available; e.g. if we
67
* wanted to make OS/161 2.x run on System/161 1.x. However,
68
* that requires a good bit more infrastructure for handling
69
* timers than we have and it doesn't seem worthwhile.
70
*
71
* It would also require some hacking, because all CPUs need
72
* to receive timer interrupts. (Exercise: how would you make
73
* sure all CPUs receive exactly one timer interrupt? Remember
74
* that LAMEbus uses level-triggered interrupts, so the
75
* hardware interrupt line will cause repeated interrupts if
76
* it's not reset on the device; but if it's reset on the
77
* device before all CPUs manage to see it, those CPUs won't
78
* be interrupted at all.)
79
*
80
* Note that the beep and rtclock devices *do* attach to
81
* ltimer.
82
*/
83
(void)ltimerno;
84
lt->lt_hardclock = 0;
85
86
/*
87
* We do, however, use ltimer for the timer clock, since the
88
* on-chip timer can't do that.
89
*/
90
if (!havetimerclock) {
91
havetimerclock = true;
92
lt->lt_timerclock = 1;
93
94
/* Wire it to go off once every second. */
95
bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_ROE, 1);
96
bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_COUNT,
97
LT_GRANULARITY);
98
}
99
100
return 0;
101
}
102
103
/*
104
* Interrupt handler.
105
*/
106
void
107
ltimer_irq(void *vlt)
108
{
109
struct ltimer_softc *lt = vlt;
110
uint32_t val;
111
112
val = bus_read_register(lt->lt_bus, lt->lt_buspos, LT_REG_IRQ);
113
if (val) {
114
/*
115
* Only call hardclock if we're responsible for hardclock.
116
* (Any additional timer devices are unused.)
117
*/
118
if (lt->lt_hardclock) {
119
hardclock();
120
}
121
/*
122
* Likewise for timerclock.
123
*/
124
if (lt->lt_timerclock) {
125
timerclock();
126
}
127
}
128
}
129
130
/*
131
* The timer device will beep if you write to the beep register. It
132
* doesn't matter what value you write. This function is called if
133
* the beep device is attached to this timer.
134
*/
135
void
136
ltimer_beep(void *vlt)
137
{
138
struct ltimer_softc *lt = vlt;
139
140
bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_SPKR, 440);
141
}
142
143
/*
144
* The timer device also has a realtime clock on it.
145
* This function gets called if the rtclock device is attached
146
* to this timer.
147
*/
148
void
149
ltimer_gettime(void *vlt, time_t *secs, uint32_t *nsecs)
150
{
151
struct ltimer_softc *lt = vlt;
152
uint32_t secs1, secs2;
153
int spl;
154
155
/*
156
* Read the seconds twice, on either side of the nanoseconds.
157
* If nsecs is small, use the *later* value of seconds, in case
158
* the nanoseconds turned over between the time we got the earlier
159
* value and the time we got nsecs.
160
*
161
* Note that the clock in the ltimer device is accurate down
162
* to a single processor cycle, so this might actually matter
163
* now and then.
164
*
165
* Do it with interrupts off on the current processor to avoid
166
* getting garbage if we get an interrupt among the register
167
* reads.
168
*/
169
170
spl = splhigh();
171
172
secs1 = bus_read_register(lt->lt_bus, lt->lt_buspos,
173
LT_REG_SEC);
174
*nsecs = bus_read_register(lt->lt_bus, lt->lt_buspos,
175
LT_REG_NSEC);
176
secs2 = bus_read_register(lt->lt_bus, lt->lt_buspos,
177
LT_REG_SEC);
178
179
splx(spl);
180
181
if (*nsecs < 5000000) {
182
*secs = secs2;
183
}
184
else {
185
*secs = secs1;
186
}
187
}
188
189