]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/arm/sa11x0/sa11x0_ost.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / arm / sa11x0 / sa11x0_ost.c
1 /*      $NetBSD: sa11x0_ost.c,v 1.11 2003/07/15 00:24:51 lukem 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 __FBSDID("$FreeBSD$");
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
46 #include <sys/time.h>
47 #include <sys/bus.h>
48 #include <sys/clock.h>
49 #include <sys/module.h>
50
51 #include <machine/bus.h>
52 #include <sys/rman.h>
53 #include <machine/resource.h>
54 #include <machine/intr.h>
55
56 #include <machine/cpu.h>
57 #include <machine/cpufunc.h>
58 #include <machine/frame.h>
59
60 #include <arm/sa11x0/sa11x0_reg.h> 
61 #include <arm/sa11x0/sa11x0_var.h>
62 #include <arm/sa11x0/sa11x0_ostreg.h>
63
64 static int      saost_probe(device_t);
65 static int      saost_attach(device_t);
66
67 int             gettick(void);
68 static int      clockintr(void *);
69 #if 0
70 static int      statintr(void *);
71 #endif
72 void            rtcinit(void);
73
74 #if 0
75 static struct mtx clock_lock;
76 #endif
77
78 struct saost_softc {
79         device_t                sc_dev;
80         bus_addr_t              sc_baseaddr;
81         bus_space_tag_t         sc_iot;
82         bus_space_handle_t      sc_ioh;
83
84         u_int32_t       sc_clock_count;
85         u_int32_t       sc_statclock_count;
86         u_int32_t       sc_statclock_step;
87 };
88
89 static struct saost_softc *saost_sc = NULL;
90
91 #define TIMER_FREQUENCY         3686400         /* 3.6864MHz */
92 #define TICKS_PER_MICROSECOND   (TIMER_FREQUENCY/1000000)
93
94 #ifndef STATHZ
95 #define STATHZ  64
96 #endif
97
98 static device_method_t saost_methods[] = {
99         DEVMETHOD(device_probe, saost_probe),
100         DEVMETHOD(device_attach, saost_attach),
101         {0, 0},
102 };
103
104 static driver_t saost_driver = {
105         "saost",
106         saost_methods,
107         sizeof(struct saost_softc),
108 };
109 static devclass_t saost_devclass;
110
111 DRIVER_MODULE(saost, saip, saost_driver, saost_devclass, 0, 0);
112 static int
113 saost_probe(device_t dev)
114 {
115
116         return (0);
117 }
118
119 static int
120 saost_attach(device_t dev)
121 {
122         struct saost_softc *sc = device_get_softc(dev);
123         struct sa11x0_softc *sa = device_get_softc(device_get_parent(dev));
124
125         sc->sc_dev = dev;
126         sc->sc_iot = sa->sc_iot;
127         sc->sc_baseaddr = 0x90000000;
128
129         saost_sc = sc;
130
131         if(bus_space_map(sa->sc_iot, sc->sc_baseaddr, 8, 0, 
132                         &sc->sc_ioh))
133                 panic("%s: Cannot map registers", device_get_name(dev));
134
135         /* disable all channel and clear interrupt status */
136         bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_IR, 0);
137         bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_SR, 0xf);
138         return (0);
139
140 }
141
142 static int
143 clockintr(arg)
144         void *arg;
145 {
146         struct trapframe *frame = arg;
147         u_int32_t oscr, nextmatch, oldmatch;
148         int s;
149
150 #if 0
151         mtx_lock_spin(&clock_lock);
152 #endif
153         bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh,
154                         SAOST_SR, 1);
155
156         /* schedule next clock intr */
157         oldmatch = saost_sc->sc_clock_count;
158         nextmatch = oldmatch + TIMER_FREQUENCY / hz;
159
160         oscr = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh,
161                                 SAOST_CR);
162
163         if ((nextmatch > oldmatch &&
164              (oscr > nextmatch || oscr < oldmatch)) ||
165             (nextmatch < oldmatch && oscr > nextmatch && oscr < oldmatch)) {
166                 /*
167                  * we couldn't set the matching register in time.
168                  * just set it to some value so that next interrupt happens.
169                  * XXX is it possible to compansate lost interrupts?
170                  */
171
172                 s = splhigh();
173                 oscr = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh,
174                                         SAOST_CR);
175                 nextmatch = oscr + 10;
176                 splx(s);
177         }
178         saost_sc->sc_clock_count = nextmatch;
179         bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_MR0,
180                           nextmatch);
181         hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
182 #if 0
183         mtx_unlock_spin(&clock_lock);
184 #endif
185         return (FILTER_HANDLED);
186 }
187
188 #if 0
189 static int
190 statintr(arg)
191         void *arg;
192 {
193         struct trapframe *frame = arg;
194         u_int32_t oscr, nextmatch, oldmatch;
195         int s;
196
197         bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh,
198                         SAOST_SR, 2);
199
200         /* schedule next clock intr */
201         oldmatch = saost_sc->sc_statclock_count;
202         nextmatch = oldmatch + saost_sc->sc_statclock_step;
203
204         bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_MR1,
205                           nextmatch);
206         oscr = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh,
207                                 SAOST_CR);
208
209         if ((nextmatch > oldmatch &&
210              (oscr > nextmatch || oscr < oldmatch)) ||
211             (nextmatch < oldmatch && oscr > nextmatch && oscr < oldmatch)) {
212                 /*
213                  * we couldn't set the matching register in time.
214                  * just set it to some value so that next interrupt happens.
215                  * XXX is it possible to compansate lost interrupts?
216                  */
217
218                 s = splhigh();
219                 oscr = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh,
220                                         SAOST_CR);
221                 nextmatch = oscr + 10;
222                 bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh,
223                                   SAOST_MR1, nextmatch);
224                 splx(s);
225         }
226
227         saost_sc->sc_statclock_count = nextmatch;
228         statclock(TRAPF_USERMODE(frame));
229         return (FILTER_HANDLED);
230 }
231 #endif
232
233 #if 0
234 void
235 setstatclockrate(int hz)
236 {
237         u_int32_t count;
238
239         saost_sc->sc_statclock_step = TIMER_FREQUENCY / hz;
240         count = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_CR);
241         count += saost_sc->sc_statclock_step;
242         saost_sc->sc_statclock_count = count;
243         bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh,
244                         SAOST_MR1, count);
245 }
246 #endif
247 void
248 cpu_initclocks()
249 {
250         device_t dev = saost_sc->sc_dev;
251
252         stathz = STATHZ;
253         profhz = stathz;
254 #if 0
255         mtx_init(&clock_lock, "SA1110 Clock locké", NULL, MTX_SPIN);
256 #endif
257         saost_sc->sc_statclock_step = TIMER_FREQUENCY / stathz;
258         struct resource *irq1, *irq2;
259         int rid = 0;
260         void *ih1/*, *ih2 */;
261         
262         printf("clock: hz=%d stathz = %d\n", hz, stathz);
263
264         /* Use the channels 0 and 1 for hardclock and statclock, respectively */
265         saost_sc->sc_clock_count = TIMER_FREQUENCY / hz;
266         saost_sc->sc_statclock_count = TIMER_FREQUENCY / stathz;
267
268         irq1 = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0,
269             ~0, 1, RF_ACTIVE);
270         rid = 1;
271         irq2 = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
272             RF_ACTIVE);
273         bus_setup_intr(dev, irq1, INTR_TYPE_CLK, clockintr, NULL, NULL,
274             &ih1);
275 #if 0
276         bus_setup_intr(dev, irq2, INTR_TYPE_CLK, statintr, NULL, NULL,
277             ,&ih2);
278 #endif
279         bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_SR, 0xf);
280         bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_IR, 3);
281         bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_MR0,
282                           saost_sc->sc_clock_count);
283 #if 0
284         bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_MR1,
285                           0);
286 #endif
287         /* Zero the counter value */
288         bus_space_write_4(saost_sc->sc_iot, saost_sc->sc_ioh, SAOST_CR, 0);
289 }
290
291 int
292 gettick()
293 {
294         int counter;
295         u_int savedints;
296         savedints = disable_interrupts(I32_bit);
297
298         counter = bus_space_read_4(saost_sc->sc_iot, saost_sc->sc_ioh,
299                         SAOST_CR);
300
301         restore_interrupts(savedints);
302         return counter;
303 }
304
305 void
306 DELAY(usecs)
307         int usecs;
308 {
309         u_int32_t tick, otick, delta;
310         int j, csec, usec;
311
312         csec = usecs / 10000;
313         usec = usecs % 10000;
314         
315         usecs = (TIMER_FREQUENCY / 100) * csec
316             + (TIMER_FREQUENCY / 100) * usec / 10000;
317
318         if (! saost_sc) {
319                 /* clock isn't initialized yet */
320                 for(; usecs > 0; usecs--)
321                         for(j = 100; j > 0; j--)
322                                 ;
323                 return;
324         }
325
326 #if 0
327         mtx_lock_spin(&clock_lock);
328 #endif
329         otick = gettick();
330
331         while (1) {
332                 for(j = 100; j > 0; j--)
333                         ;
334                 tick = gettick();
335                 delta = tick - otick;
336                 if (delta > usecs) {
337                         break;
338                 }
339                 usecs -= delta;
340                 otick = tick;
341         }
342 #if 0
343         mtx_unlock_spin(&clock_lock);
344 #endif
345 }
346
347 void
348 cpu_startprofclock(void)
349 {
350         printf("STARTPROFCLOCK\n");
351 }
352
353 void
354 cpu_stopprofclock(void)
355 {
356 }