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