1 /* $NetBSD: sa11x0_ost.c,v 1.27 2009/08/01 10:33:58 kiyohara Exp $ */
4 * Copyright (c) 1997 Mark Brinicombe.
5 * Copyright (c) 1997 Causality Limited.
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
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>
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 *);
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>
85 #define TIMER_FREQUENCY freq
86 #elif defined(CPU_XSCALE_PXA270)
87 #define TIMER_FREQUENCY 3250000 /* PXA270 uses 3.25MHz */
89 #define TIMER_FREQUENCY 3686400 /* 3.6864MHz */
96 CFATTACH_DECL_NEW(saost
, sizeof(struct saost_softc
),
97 saost_match
, saost_attach
, NULL
, NULL
);
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)
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
;
118 sc
->sc_iot
= sa
->sa_iot
;
122 if (bus_space_map(sa
->sa_iot
, sa
->sa_addr
, sa
->sa_size
, 0,
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");
136 struct saost_softc
*sc
= saost_sc
;
137 struct clockframe
*frame
= arg
;
138 uint32_t oscr
, nextmatch
, oldmatch
;
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?
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
);
166 sc
->sc_clock_count
= nextmatch
;
175 struct saost_softc
*sc
= saost_sc
;
176 struct clockframe
*frame
= arg
;
177 uint32_t oscr
, nextmatch
, oldmatch
;
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?
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
);
205 sc
->sc_statclock_count
= nextmatch
;
212 setstatclockrate(int schz
)
214 struct saost_softc
*sc
= saost_sc
;
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
);
227 struct saost_softc
*sc
= saost_sc
;
231 #if defined(CPU_XSCALE_PXA270) && defined(CPU_XSCALE_PXA250)
232 TIMER_FREQUENCY
= (CPU_IS_PXA250
) ? 3686400 : 3250000;
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
,
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);
259 saost_tc_get_timecount(struct timecounter
*tc
)
261 return (u_int
)gettick();
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
,
277 #if defined(CPU_XSCALE_PXA270) && defined(CPU_XSCALE_PXA250)
278 saost_tc
.tc_frequency
= TIMER_FREQUENCY
,
286 struct saost_softc
*sc
= saost_sc
;
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
);
300 uint32_t xtick
, otick
, delta
;
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
) {
312 /* clock isn't initialized yet */
313 for (; usecs
> 0; usecs
--)
314 for (j
= 100; j
> 0; j
--, k
--)
323 delta
= xtick
- otick
;