Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / arm / sa11x0 / sa11x0_ost.c
blob9fc3e17cbee333d674ae128d5235382b1d9e05a7
1 /* $NetBSD: sa11x0_ost.c,v 1.27 2009/08/01 10:33:58 kiyohara Exp $ */
3 /*
4 * Copyright (c) 1997 Mark Brinicombe.
5 * Copyright (c) 1997 Causality Limited.
6 * All rights reserved.
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by IWAMOTO Toshihiro and Ichiro FUKUHARA.
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.
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.
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: sa11x0_ost.c,v 1.27 2009/08/01 10:33:58 kiyohara Exp $");
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>
51 #include <machine/bus.h>
52 #include <machine/intr.h>
54 #include <arm/cpufunc.h>
56 #include <arm/sa11x0/sa11x0_reg.h>
57 #include <arm/sa11x0/sa11x0_var.h>
58 #include <arm/sa11x0/sa11x0_ostreg.h>
60 static int saost_match(device_t, cfdata_t, void *);
61 static void saost_attach(device_t, device_t, void *);
63 static void saost_tc_init(void);
65 static uint32_t gettick(void);
66 static int clockintr(void *);
67 static int statintr(void *);
69 struct saost_softc {
70 device_t sc_dev;
72 bus_space_tag_t sc_iot;
73 bus_space_handle_t sc_ioh;
75 uint32_t sc_clock_count;
76 uint32_t sc_statclock_count;
77 uint32_t sc_statclock_step;
80 static struct saost_softc *saost_sc = NULL;
82 #if defined(CPU_XSCALE_PXA270) && defined(CPU_XSCALE_PXA250)
83 #include <arm/xscale/pxa2x0cpu.h>
84 static uint32_t freq;
85 #define TIMER_FREQUENCY freq
86 #elif defined(CPU_XSCALE_PXA270)
87 #define TIMER_FREQUENCY 3250000 /* PXA270 uses 3.25MHz */
88 #else
89 #define TIMER_FREQUENCY 3686400 /* 3.6864MHz */
90 #endif
92 #ifndef STATHZ
93 #define STATHZ 64
94 #endif
96 CFATTACH_DECL_NEW(saost, sizeof(struct saost_softc),
97 saost_match, saost_attach, NULL, NULL);
99 static int
100 saost_match(device_t parent, cfdata_t match, void *aux)
102 struct sa11x0_attach_args *sa = aux;
104 if (strcmp(sa->sa_name, match->cf_name) != 0)
105 return 0;
106 return 1;
109 static void
110 saost_attach(device_t parent, device_t self, void *aux)
112 struct saost_softc *sc = device_private(self);
113 struct sa11x0_attach_args *sa = aux;
115 aprint_normal("\n");
117 sc->sc_dev = self;
118 sc->sc_iot = sa->sa_iot;
120 saost_sc = sc;
122 if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 0,
123 &sc->sc_ioh))
124 panic("%s: Cannot map registers", device_xname(self));
126 /* disable all channel and clear interrupt status */
127 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_IR, 0);
128 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_SR, 0xf);
130 aprint_normal_dev(self, "SA-11x0 OS Timer\n");
133 static int
134 clockintr(void *arg)
136 struct saost_softc *sc = saost_sc;
137 struct clockframe *frame = arg;
138 uint32_t oscr, nextmatch, oldmatch;
139 int s;
141 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_SR, 1);
143 /* schedule next clock intr */
144 oldmatch = sc->sc_clock_count;
145 nextmatch = oldmatch + TIMER_FREQUENCY / hz;
147 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_MR0, nextmatch);
148 oscr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SAOST_CR);
150 if ((nextmatch > oldmatch &&
151 (oscr > nextmatch || oscr < oldmatch)) ||
152 (nextmatch < oldmatch && oscr > nextmatch && oscr < oldmatch)) {
154 * we couldn't set the matching register in time.
155 * just set it to some value so that next interrupt happens.
156 * XXX is it possible to compensate lost interrupts?
159 s = splhigh();
160 oscr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SAOST_CR);
161 nextmatch = oscr + 10;
162 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_MR0, nextmatch);
163 splx(s);
166 sc->sc_clock_count = nextmatch;
167 hardclock(frame);
169 return 1;
172 static int
173 statintr(void *arg)
175 struct saost_softc *sc = saost_sc;
176 struct clockframe *frame = arg;
177 uint32_t oscr, nextmatch, oldmatch;
178 int s;
180 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_SR, 2);
182 /* schedule next clock intr */
183 oldmatch = sc->sc_statclock_count;
184 nextmatch = oldmatch + sc->sc_statclock_step;
186 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_MR1, nextmatch);
187 oscr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SAOST_CR);
189 if ((nextmatch > oldmatch &&
190 (oscr > nextmatch || oscr < oldmatch)) ||
191 (nextmatch < oldmatch && oscr > nextmatch && oscr < oldmatch)) {
193 * we couldn't set the matching register in time.
194 * just set it to some value so that next interrupt happens.
195 * XXX is it possible to compensate lost interrupts?
198 s = splhigh();
199 oscr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SAOST_CR);
200 nextmatch = oscr + 10;
201 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_MR1, nextmatch);
202 splx(s);
205 sc->sc_statclock_count = nextmatch;
206 statclock(frame);
208 return 1;
211 void
212 setstatclockrate(int schz)
214 struct saost_softc *sc = saost_sc;
215 uint32_t count;
217 sc->sc_statclock_step = TIMER_FREQUENCY / schz;
218 count = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SAOST_CR);
219 count += sc->sc_statclock_step;
220 sc->sc_statclock_count = count;
221 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_MR1, count);
224 void
225 cpu_initclocks(void)
227 struct saost_softc *sc = saost_sc;
229 stathz = STATHZ;
230 profhz = stathz;
231 #if defined(CPU_XSCALE_PXA270) && defined(CPU_XSCALE_PXA250)
232 TIMER_FREQUENCY = (CPU_IS_PXA250) ? 3686400 : 3250000;
233 #endif
234 sc->sc_statclock_step = TIMER_FREQUENCY / stathz;
236 aprint_normal("clock: hz=%d stathz=%d\n", hz, stathz);
238 /* Use the channels 0 and 1 for hardclock and statclock, respectively */
239 sc->sc_clock_count = TIMER_FREQUENCY / hz;
240 sc->sc_statclock_count = TIMER_FREQUENCY / stathz;
242 sa11x0_intr_establish(0, 26, 1, IPL_CLOCK, clockintr, 0);
243 sa11x0_intr_establish(0, 27, 1, IPL_CLOCK, statintr, 0);
245 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_SR, 0xf);
246 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_IR, 3);
247 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_MR0,
248 sc->sc_clock_count);
249 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_MR1,
250 sc->sc_statclock_count);
252 /* Zero the counter value */
253 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_CR, 0);
255 saost_tc_init();
258 static u_int
259 saost_tc_get_timecount(struct timecounter *tc)
261 return (u_int)gettick();
264 static void
265 saost_tc_init(void)
267 static struct timecounter saost_tc = {
268 .tc_get_timecount = saost_tc_get_timecount,
269 .tc_counter_mask = ~0,
270 .tc_name = "saost_count",
271 #if !(defined(CPU_XSCALE_PXA270) && defined(CPU_XSCALE_PXA250))
272 .tc_frequency = TIMER_FREQUENCY,
273 #endif
274 .tc_quality = 100,
277 #if defined(CPU_XSCALE_PXA270) && defined(CPU_XSCALE_PXA250)
278 saost_tc.tc_frequency = TIMER_FREQUENCY,
279 #endif
280 tc_init(&saost_tc);
283 static uint32_t
284 gettick(void)
286 struct saost_softc *sc = saost_sc;
287 uint32_t counter;
288 u_int saved_ints;
290 saved_ints = disable_interrupts(I32_bit);
291 counter = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SAOST_CR);
292 restore_interrupts(saved_ints);
294 return counter;
297 void
298 delay(u_int usecs)
300 uint32_t xtick, otick, delta;
301 int csec, usec;
303 csec = usecs / 10000;
304 usec = usecs % 10000;
306 usecs = (TIMER_FREQUENCY / 100) * csec
307 + (TIMER_FREQUENCY / 100) * usec / 10000;
309 if (saost_sc == NULL) {
310 volatile int k;
311 int j;
312 /* clock isn't initialized yet */
313 for (; usecs > 0; usecs--)
314 for (j = 100; j > 0; j--, k--)
315 continue;
316 return;
319 otick = gettick();
321 while (1) {
322 xtick = gettick();
323 delta = xtick - otick;
324 if (delta > usecs)
325 break;
326 usecs -= delta;
327 otick = xtick;