/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- config_ltimer
- ltimer_irq
- ltimer_beep
- ltimer_gettime
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 }