sa11x0_ost.c revision 1.2.6.5 1 1.2.6.5 nathanw /* $NetBSD: sa11x0_ost.c,v 1.2.6.5 2002/10/18 02:35:41 nathanw Exp $ */
2 1.2.6.2 nathanw
3 1.2.6.2 nathanw /*
4 1.2.6.2 nathanw * Copyright (c) 1997 Mark Brinicombe.
5 1.2.6.2 nathanw * Copyright (c) 1997 Causality Limited.
6 1.2.6.2 nathanw * All rights reserved.
7 1.2.6.2 nathanw *
8 1.2.6.2 nathanw * This code is derived from software contributed to The NetBSD Foundation
9 1.2.6.2 nathanw * by IWAMOTO Toshihiro and Ichiro FUKUHARA.
10 1.2.6.2 nathanw *
11 1.2.6.2 nathanw * Redistribution and use in source and binary forms, with or without
12 1.2.6.2 nathanw * modification, are permitted provided that the following conditions
13 1.2.6.2 nathanw * are met:
14 1.2.6.2 nathanw * 1. Redistributions of source code must retain the above copyright
15 1.2.6.2 nathanw * notice, this list of conditions and the following disclaimer.
16 1.2.6.2 nathanw * 2. Redistributions in binary form must reproduce the above copyright
17 1.2.6.2 nathanw * notice, this list of conditions and the following disclaimer in the
18 1.2.6.2 nathanw * documentation and/or other materials provided with the distribution.
19 1.2.6.2 nathanw * 3. All advertising materials mentioning features or use of this software
20 1.2.6.2 nathanw * must display the following acknowledgement:
21 1.2.6.2 nathanw * This product includes software developed by the NetBSD
22 1.2.6.2 nathanw * Foundation, Inc. and its contributors.
23 1.2.6.2 nathanw * 4. Neither the name of The NetBSD Foundation nor the names of its
24 1.2.6.2 nathanw * contributors may be used to endorse or promote products derived
25 1.2.6.2 nathanw * from this software without specific prior written permission.
26 1.2.6.2 nathanw *
27 1.2.6.2 nathanw * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 1.2.6.2 nathanw * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 1.2.6.2 nathanw * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 1.2.6.2 nathanw * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 1.2.6.2 nathanw * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 1.2.6.2 nathanw * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 1.2.6.2 nathanw * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 1.2.6.2 nathanw * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 1.2.6.2 nathanw * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 1.2.6.2 nathanw * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 1.2.6.2 nathanw * POSSIBILITY OF SUCH DAMAGE.
38 1.2.6.2 nathanw */
39 1.2.6.2 nathanw
40 1.2.6.2 nathanw #include <sys/types.h>
41 1.2.6.2 nathanw #include <sys/param.h>
42 1.2.6.2 nathanw #include <sys/systm.h>
43 1.2.6.2 nathanw #include <sys/kernel.h>
44 1.2.6.2 nathanw #include <sys/time.h>
45 1.2.6.2 nathanw #include <sys/device.h>
46 1.2.6.2 nathanw
47 1.2.6.2 nathanw #include <machine/bus.h>
48 1.2.6.2 nathanw #include <machine/intr.h>
49 1.2.6.2 nathanw
50 1.2.6.2 nathanw #include <arm/cpufunc.h>
51 1.2.6.2 nathanw
52 1.2.6.2 nathanw #include <arm/arm32/katelib.h>
53 1.2.6.2 nathanw
54 1.2.6.2 nathanw #include <arm/sa11x0/sa11x0_reg.h>
55 1.2.6.2 nathanw #include <arm/sa11x0/sa11x0_var.h>
56 1.2.6.2 nathanw #include <arm/sa11x0/sa11x0_ostreg.h>
57 1.2.6.2 nathanw
58 1.2.6.2 nathanw static int saost_match(struct device *, struct cfdata *, void *);
59 1.2.6.2 nathanw static void saost_attach(struct device *, struct device *, void *);
60 1.2.6.2 nathanw
61 1.2.6.2 nathanw int gettick(void);
62 1.2.6.2 nathanw static int clockintr(void *);
63 1.2.6.2 nathanw static int statintr(void *);
64 1.2.6.2 nathanw void rtcinit(void);
65 1.2.6.2 nathanw
66 1.2.6.2 nathanw struct saost_softc {
67 1.2.6.2 nathanw struct device sc_dev;
68 1.2.6.2 nathanw bus_addr_t sc_baseaddr;
69 1.2.6.2 nathanw bus_space_tag_t sc_iot;
70 1.2.6.2 nathanw bus_space_handle_t sc_ioh;
71 1.2.6.2 nathanw
72 1.2.6.2 nathanw u_int32_t sc_clock_count;
73 1.2.6.2 nathanw u_int32_t sc_statclock_count;
74 1.2.6.2 nathanw u_int32_t sc_statclock_step;
75 1.2.6.2 nathanw };
76 1.2.6.2 nathanw
77 1.2.6.2 nathanw static struct saost_softc *saost_sc = NULL;
78 1.2.6.2 nathanw
79 1.2.6.2 nathanw #define TIMER_FREQUENCY 3686400 /* 3.6864MHz */
80 1.2.6.2 nathanw #define TICKS_PER_MICROSECOND (TIMER_FREQUENCY/1000000)
81 1.2.6.2 nathanw
82 1.2.6.2 nathanw #ifndef STATHZ
83 1.2.6.2 nathanw #define STATHZ 64
84 1.2.6.2 nathanw #endif
85 1.2.6.2 nathanw
86 1.2.6.5 nathanw CFATTACH_DECL(saost, sizeof(struct saost_softc),
87 1.2.6.5 nathanw saost_match, saost_attach, NULL, NULL);
88 1.2.6.2 nathanw
89 1.2.6.2 nathanw static int
90 1.2.6.2 nathanw saost_match(parent, match, aux)
91 1.2.6.2 nathanw struct device *parent;
92 1.2.6.2 nathanw struct cfdata *match;
93 1.2.6.2 nathanw void *aux;
94 1.2.6.2 nathanw {
95 1.2.6.2 nathanw return (1);
96 1.2.6.2 nathanw }
97 1.2.6.2 nathanw
98 1.2.6.2 nathanw void
99 1.2.6.2 nathanw saost_attach(parent, self, aux)
100 1.2.6.2 nathanw struct device *parent;
101 1.2.6.2 nathanw struct device *self;
102 1.2.6.2 nathanw void *aux;
103 1.2.6.2 nathanw {
104 1.2.6.2 nathanw struct saost_softc *sc = (struct saost_softc*)self;
105 1.2.6.2 nathanw struct sa11x0_attach_args *sa = aux;
106 1.2.6.2 nathanw
107 1.2.6.2 nathanw printf("\n");
108 1.2.6.2 nathanw
109 1.2.6.2 nathanw sc->sc_iot = sa->sa_iot;
110 1.2.6.2 nathanw sc->sc_baseaddr = sa->sa_addr;
111 1.2.6.2 nathanw
112 1.2.6.2 nathanw saost_sc = sc;
113 1.2.6.2 nathanw
114 1.2.6.2 nathanw if(bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 0,
115 1.2.6.2 nathanw &sc->sc_ioh))
116 1.2.6.5 nathanw panic("%s: Cannot map registers", self->dv_xname);
117 1.2.6.2 nathanw
118 1.2.6.2 nathanw /* disable all channel and clear interrupt status */
119 1.2.6.2 nathanw bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_IR, 0);
120 1.2.6.2 nathanw bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_SR, 0xf);
121 1.2.6.2 nathanw
122 1.2.6.2 nathanw printf("%s: SA-11x0 OS Timer\n", sc->sc_dev.dv_xname);
123 1.2.6.2 nathanw }
124 1.2.6.2 nathanw
125 1.2.6.2 nathanw static int
126 1.2.6.2 nathanw clockintr(arg)
127 1.2.6.2 nathanw void *arg;
128 1.2.6.2 nathanw {
129 1.2.6.2 nathanw struct clockframe *frame = arg;
130 1.2.6.2 nathanw u_int32_t oscr, nextmatch, oldmatch;
131 1.2.6.2 nathanw int s;
132 1.2.6.2 nathanw
133 1.2.6.2 nathanw bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh,
134 1.2.6.2 nathanw SAOST_SR, 1);
135 1.2.6.2 nathanw
136 1.2.6.2 nathanw /* schedule next clock intr */
137 1.2.6.2 nathanw oldmatch = saost_sc->sc_clock_count;
138 1.2.6.2 nathanw nextmatch = oldmatch + TIMER_FREQUENCY / hz;
139 1.2.6.2 nathanw
140 1.2.6.2 nathanw bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_MR0,
141 1.2.6.2 nathanw nextmatch);
142 1.2.6.2 nathanw oscr = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh,
143 1.2.6.2 nathanw SAOST_CR);
144 1.2.6.2 nathanw
145 1.2.6.2 nathanw if ((nextmatch > oldmatch &&
146 1.2.6.2 nathanw (oscr > nextmatch || oscr < oldmatch)) ||
147 1.2.6.2 nathanw (nextmatch < oldmatch && oscr > nextmatch && oscr < oldmatch)) {
148 1.2.6.2 nathanw /*
149 1.2.6.2 nathanw * we couldn't set the matching register in time.
150 1.2.6.2 nathanw * just set it to some value so that next interrupt happens.
151 1.2.6.2 nathanw * XXX is it possible to compansate lost interrupts?
152 1.2.6.2 nathanw */
153 1.2.6.2 nathanw
154 1.2.6.2 nathanw s = splhigh();
155 1.2.6.2 nathanw oscr = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh,
156 1.2.6.2 nathanw SAOST_CR);
157 1.2.6.2 nathanw nextmatch = oscr + 10;
158 1.2.6.2 nathanw bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh,
159 1.2.6.2 nathanw SAOST_MR0, nextmatch);
160 1.2.6.2 nathanw splx(s);
161 1.2.6.2 nathanw }
162 1.2.6.2 nathanw
163 1.2.6.2 nathanw saost_sc->sc_clock_count = nextmatch;
164 1.2.6.2 nathanw hardclock(frame);
165 1.2.6.2 nathanw
166 1.2.6.2 nathanw return(1);
167 1.2.6.2 nathanw }
168 1.2.6.2 nathanw
169 1.2.6.2 nathanw static int
170 1.2.6.2 nathanw statintr(arg)
171 1.2.6.2 nathanw void *arg;
172 1.2.6.2 nathanw {
173 1.2.6.2 nathanw struct clockframe *frame = arg;
174 1.2.6.2 nathanw u_int32_t oscr, nextmatch, oldmatch;
175 1.2.6.2 nathanw int s;
176 1.2.6.2 nathanw
177 1.2.6.2 nathanw bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh,
178 1.2.6.2 nathanw SAOST_SR, 2);
179 1.2.6.2 nathanw
180 1.2.6.2 nathanw /* schedule next clock intr */
181 1.2.6.2 nathanw oldmatch = saost_sc->sc_statclock_count;
182 1.2.6.2 nathanw nextmatch = oldmatch + saost_sc->sc_statclock_step;
183 1.2.6.2 nathanw
184 1.2.6.2 nathanw bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_MR1,
185 1.2.6.2 nathanw nextmatch);
186 1.2.6.2 nathanw oscr = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh,
187 1.2.6.2 nathanw SAOST_CR);
188 1.2.6.2 nathanw
189 1.2.6.2 nathanw if ((nextmatch > oldmatch &&
190 1.2.6.2 nathanw (oscr > nextmatch || oscr < oldmatch)) ||
191 1.2.6.2 nathanw (nextmatch < oldmatch && oscr > nextmatch && oscr < oldmatch)) {
192 1.2.6.2 nathanw /*
193 1.2.6.2 nathanw * we couldn't set the matching register in time.
194 1.2.6.2 nathanw * just set it to some value so that next interrupt happens.
195 1.2.6.2 nathanw * XXX is it possible to compansate lost interrupts?
196 1.2.6.2 nathanw */
197 1.2.6.2 nathanw
198 1.2.6.2 nathanw s = splhigh();
199 1.2.6.2 nathanw oscr = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh,
200 1.2.6.2 nathanw SAOST_CR);
201 1.2.6.2 nathanw nextmatch = oscr + 10;
202 1.2.6.2 nathanw bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh,
203 1.2.6.2 nathanw SAOST_MR1, nextmatch);
204 1.2.6.2 nathanw splx(s);
205 1.2.6.2 nathanw }
206 1.2.6.2 nathanw
207 1.2.6.2 nathanw saost_sc->sc_statclock_count = nextmatch;
208 1.2.6.2 nathanw statclock(frame);
209 1.2.6.2 nathanw
210 1.2.6.2 nathanw return(1);
211 1.2.6.2 nathanw }
212 1.2.6.2 nathanw
213 1.2.6.2 nathanw
214 1.2.6.2 nathanw void
215 1.2.6.2 nathanw setstatclockrate(hz)
216 1.2.6.2 nathanw int hz;
217 1.2.6.2 nathanw {
218 1.2.6.2 nathanw u_int32_t count;
219 1.2.6.2 nathanw
220 1.2.6.2 nathanw saost_sc->sc_statclock_step = TIMER_FREQUENCY / hz;
221 1.2.6.2 nathanw count = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_CR);
222 1.2.6.2 nathanw count += saost_sc->sc_statclock_step;
223 1.2.6.2 nathanw saost_sc->sc_statclock_count = count;
224 1.2.6.2 nathanw bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh,
225 1.2.6.2 nathanw SAOST_MR1, count);
226 1.2.6.2 nathanw }
227 1.2.6.2 nathanw
228 1.2.6.2 nathanw void
229 1.2.6.2 nathanw cpu_initclocks()
230 1.2.6.2 nathanw {
231 1.2.6.2 nathanw stathz = STATHZ;
232 1.2.6.2 nathanw profhz = stathz;
233 1.2.6.2 nathanw saost_sc->sc_statclock_step = TIMER_FREQUENCY / stathz;
234 1.2.6.2 nathanw
235 1.2.6.2 nathanw printf("clock: hz=%d stathz = %d\n", hz, stathz);
236 1.2.6.2 nathanw
237 1.2.6.2 nathanw /* Use the channels 0 and 1 for hardclock and statclock, respectively */
238 1.2.6.2 nathanw saost_sc->sc_clock_count = TIMER_FREQUENCY / hz;
239 1.2.6.2 nathanw saost_sc->sc_statclock_count = TIMER_FREQUENCY / stathz;
240 1.2.6.2 nathanw
241 1.2.6.3 nathanw sa11x0_intr_establish(0, 26, 1, IPL_CLOCK, clockintr, 0);
242 1.2.6.3 nathanw sa11x0_intr_establish(0, 27, 1, IPL_CLOCK, statintr, 0);
243 1.2.6.3 nathanw
244 1.2.6.3 nathanw bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_SR, 0xf);
245 1.2.6.2 nathanw bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_IR, 3);
246 1.2.6.2 nathanw bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_MR0,
247 1.2.6.2 nathanw saost_sc->sc_clock_count);
248 1.2.6.2 nathanw bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_MR1,
249 1.2.6.2 nathanw saost_sc->sc_statclock_count);
250 1.2.6.2 nathanw
251 1.2.6.3 nathanw /* Zero the counter value */
252 1.2.6.3 nathanw bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_CR, 0);
253 1.2.6.2 nathanw }
254 1.2.6.2 nathanw
255 1.2.6.2 nathanw int
256 1.2.6.2 nathanw gettick()
257 1.2.6.2 nathanw {
258 1.2.6.2 nathanw int counter;
259 1.2.6.2 nathanw u_int savedints;
260 1.2.6.2 nathanw savedints = disable_interrupts(I32_bit);
261 1.2.6.2 nathanw
262 1.2.6.2 nathanw counter = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh,
263 1.2.6.2 nathanw SAOST_CR);
264 1.2.6.2 nathanw
265 1.2.6.2 nathanw restore_interrupts(savedints);
266 1.2.6.2 nathanw return counter;
267 1.2.6.2 nathanw }
268 1.2.6.2 nathanw
269 1.2.6.2 nathanw void
270 1.2.6.2 nathanw microtime(tvp)
271 1.2.6.2 nathanw register struct timeval *tvp;
272 1.2.6.2 nathanw {
273 1.2.6.3 nathanw int s, tm, deltatm;
274 1.2.6.2 nathanw static struct timeval lasttime;
275 1.2.6.2 nathanw
276 1.2.6.3 nathanw if(saost_sc == NULL) {
277 1.2.6.3 nathanw tvp->tv_sec = 0;
278 1.2.6.3 nathanw tvp->tv_usec = 0;
279 1.2.6.3 nathanw return;
280 1.2.6.3 nathanw }
281 1.2.6.3 nathanw
282 1.2.6.3 nathanw s = splhigh();
283 1.2.6.2 nathanw tm = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh,
284 1.2.6.2 nathanw SAOST_CR);
285 1.2.6.2 nathanw
286 1.2.6.2 nathanw deltatm = saost_sc->sc_clock_count - tm;
287 1.2.6.2 nathanw
288 1.2.6.2 nathanw #ifdef DEBUG
289 1.2.6.2 nathanw printf("deltatm = %d\n",deltatm);
290 1.2.6.2 nathanw #endif
291 1.2.6.2 nathanw
292 1.2.6.2 nathanw *tvp = time;
293 1.2.6.2 nathanw tvp->tv_usec++; /* XXX */
294 1.2.6.2 nathanw while (tvp->tv_usec >= 1000000) {
295 1.2.6.2 nathanw tvp->tv_sec++;
296 1.2.6.2 nathanw tvp->tv_usec -= 1000000;
297 1.2.6.2 nathanw }
298 1.2.6.2 nathanw
299 1.2.6.2 nathanw if (tvp->tv_sec == lasttime.tv_sec &&
300 1.2.6.2 nathanw tvp->tv_usec <= lasttime.tv_usec &&
301 1.2.6.2 nathanw (tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000)
302 1.2.6.2 nathanw {
303 1.2.6.2 nathanw tvp->tv_sec++;
304 1.2.6.2 nathanw tvp->tv_usec -= 1000000;
305 1.2.6.2 nathanw }
306 1.2.6.2 nathanw lasttime = *tvp;
307 1.2.6.2 nathanw splx(s);
308 1.2.6.2 nathanw }
309 1.2.6.2 nathanw
310 1.2.6.2 nathanw void
311 1.2.6.2 nathanw delay(usecs)
312 1.2.6.2 nathanw u_int usecs;
313 1.2.6.2 nathanw {
314 1.2.6.2 nathanw u_int32_t tick, otick, delta;
315 1.2.6.2 nathanw int j, csec, usec;
316 1.2.6.2 nathanw
317 1.2.6.2 nathanw csec = usecs / 10000;
318 1.2.6.2 nathanw usec = usecs % 10000;
319 1.2.6.2 nathanw
320 1.2.6.2 nathanw usecs = (TIMER_FREQUENCY / 100) * csec
321 1.2.6.2 nathanw + (TIMER_FREQUENCY / 100) * usec / 10000;
322 1.2.6.2 nathanw
323 1.2.6.2 nathanw if (! saost_sc) {
324 1.2.6.2 nathanw /* clock isn't initialized yet */
325 1.2.6.2 nathanw for(; usecs > 0; usecs--)
326 1.2.6.2 nathanw for(j = 100; j > 0; j--)
327 1.2.6.2 nathanw ;
328 1.2.6.2 nathanw return;
329 1.2.6.2 nathanw }
330 1.2.6.2 nathanw
331 1.2.6.2 nathanw otick = gettick();
332 1.2.6.2 nathanw
333 1.2.6.2 nathanw while (1) {
334 1.2.6.2 nathanw for(j = 100; j > 0; j--)
335 1.2.6.2 nathanw ;
336 1.2.6.2 nathanw tick = gettick();
337 1.2.6.2 nathanw delta = tick - otick;
338 1.2.6.2 nathanw if (delta > usecs)
339 1.2.6.2 nathanw break;
340 1.2.6.2 nathanw usecs -= delta;
341 1.2.6.2 nathanw otick = tick;
342 1.2.6.2 nathanw }
343 1.2.6.2 nathanw }
344 1.2.6.2 nathanw
345 1.2.6.2 nathanw void
346 1.2.6.2 nathanw resettodr()
347 1.2.6.2 nathanw {
348 1.2.6.2 nathanw }
349 1.2.6.2 nathanw
350 1.2.6.2 nathanw void
351 1.2.6.2 nathanw inittodr(base)
352 1.2.6.2 nathanw time_t base;
353 1.2.6.2 nathanw {
354 1.2.6.2 nathanw time.tv_sec = base;
355 1.2.6.2 nathanw time.tv_usec = 0;
356 1.2.6.2 nathanw }
357