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