ixp12x0_clk.c revision 1.1 1 1.1 ichiro /* $NetBSD: ixp12x0_clk.c,v 1.1 2002/07/15 16:27:16 ichiro Exp $ */
2 1.1 ichiro
3 1.1 ichiro /*
4 1.1 ichiro * Copyright (c) 1997 Mark Brinicombe.
5 1.1 ichiro * Copyright (c) 1997 Causality Limited.
6 1.1 ichiro * All rights reserved.
7 1.1 ichiro *
8 1.1 ichiro * This code is derived from software contributed to The NetBSD Foundation
9 1.1 ichiro * by IWAMOTO Toshihiro and Ichiro FUKUHARA.
10 1.1 ichiro *
11 1.1 ichiro * Redistribution and use in source and binary forms, with or without
12 1.1 ichiro * modification, are permitted provided that the following conditions
13 1.1 ichiro * are met:
14 1.1 ichiro * 1. Redistributions of source code must retain the above copyright
15 1.1 ichiro * notice, this list of conditions and the following disclaimer.
16 1.1 ichiro * 2. Redistributions in binary form must reproduce the above copyright
17 1.1 ichiro * notice, this list of conditions and the following disclaimer in the
18 1.1 ichiro * documentation and/or other materials provided with the distribution.
19 1.1 ichiro * 3. All advertising materials mentioning features or use of this software
20 1.1 ichiro * must display the following acknowledgement:
21 1.1 ichiro * This product includes software developed by the NetBSD
22 1.1 ichiro * Foundation, Inc. and its contributors.
23 1.1 ichiro * 4. Neither the name of The NetBSD Foundation nor the names of its
24 1.1 ichiro * contributors may be used to endorse or promote products derived
25 1.1 ichiro * from this software without specific prior written permission.
26 1.1 ichiro *
27 1.1 ichiro * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 1.1 ichiro * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 1.1 ichiro * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 1.1 ichiro * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 1.1 ichiro * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 1.1 ichiro * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 1.1 ichiro * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 1.1 ichiro * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 1.1 ichiro * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 1.1 ichiro * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 1.1 ichiro * POSSIBILITY OF SUCH DAMAGE.
38 1.1 ichiro */
39 1.1 ichiro
40 1.1 ichiro #include <sys/types.h>
41 1.1 ichiro #include <sys/param.h>
42 1.1 ichiro #include <sys/systm.h>
43 1.1 ichiro #include <sys/kernel.h>
44 1.1 ichiro #include <sys/time.h>
45 1.1 ichiro #include <sys/device.h>
46 1.1 ichiro
47 1.1 ichiro #include <machine/bus.h>
48 1.1 ichiro #include <machine/intr.h>
49 1.1 ichiro
50 1.1 ichiro #include <arm/cpufunc.h>
51 1.1 ichiro
52 1.1 ichiro #include <evbarm/ixm1200/ixm1200reg.h>
53 1.1 ichiro
54 1.1 ichiro #include <arm/ixp12x0/ixpsipvar.h>
55 1.1 ichiro
56 1.1 ichiro #include <arm/ixp12x0/ixp12x0_pcireg.h>
57 1.1 ichiro #include <arm/ixp12x0/ixp12x0_clkreg.h>
58 1.1 ichiro #include <arm/ixp12x0/ixp12x0var.h>
59 1.1 ichiro
60 1.1 ichiro static int ixpclk_match(struct device *, struct cfdata *, void *);
61 1.1 ichiro static void ixpclk_attach(struct device *, struct device *, void *);
62 1.1 ichiro
63 1.1 ichiro int gettick(void);
64 1.1 ichiro void rtcinit(void);
65 1.1 ichiro
66 1.1 ichiro /* callback functions for intr_functions */
67 1.1 ichiro static int ixpclk_intr(void* arg);
68 1.1 ichiro
69 1.1 ichiro struct ixpclk_softc {
70 1.1 ichiro struct device sc_dev;
71 1.1 ichiro bus_addr_t sc_baseaddr;
72 1.1 ichiro bus_space_tag_t sc_iot;
73 1.1 ichiro bus_space_handle_t sc_ioh;
74 1.1 ichiro
75 1.1 ichiro u_int32_t sc_clock_count;
76 1.1 ichiro u_int32_t sc_count_per_usec;
77 1.1 ichiro u_int32_t sc_coreclock_freq;
78 1.1 ichiro };
79 1.1 ichiro
80 1.1 ichiro #define XTAL_FREQ 3686400 /* 3.6864MHz */
81 1.1 ichiro #define XTAL_FREQ3686400
82 1.1 ichiro #undef XTAL_FREQ3787800
83 1.1 ichiro #undef XTAL_FREQ3579500
84 1.1 ichiro #define MAX_CCF 22
85 1.1 ichiro
86 1.1 ichiro #if defined(XTAL_FREQ3686400)
87 1.1 ichiro static u_int32_t ccf_to_coreclock[MAX_CCF + 1] = {
88 1.1 ichiro 29491000,
89 1.1 ichiro 36865000,
90 1.1 ichiro 44237000,
91 1.1 ichiro 51610000,
92 1.1 ichiro 58982000,
93 1.1 ichiro 66355000,
94 1.1 ichiro 73728000,
95 1.1 ichiro 81101000,
96 1.1 ichiro 88474000,
97 1.1 ichiro 95846000,
98 1.1 ichiro 103219000,
99 1.1 ichiro 110592000,
100 1.1 ichiro 132710000,
101 1.1 ichiro 147456000,
102 1.1 ichiro 154829000,
103 1.1 ichiro 162202000,
104 1.1 ichiro 165890000,
105 1.1 ichiro 176947000,
106 1.1 ichiro 191693000,
107 1.1 ichiro 199066000,
108 1.1 ichiro 206438000,
109 1.1 ichiro 221184000,
110 1.1 ichiro 232243000,
111 1.1 ichiro };
112 1.1 ichiro #elif defined(XTAL_FREQ3787800)
113 1.1 ichiro #elif defined(XTAL_FREQ3579500)
114 1.1 ichiro #else
115 1.1 ichiro #error
116 1.1 ichiro #endif
117 1.1 ichiro
118 1.1 ichiro static struct ixpclk_softc *ixpclk_sc = NULL;
119 1.1 ichiro
120 1.1 ichiro #define TIMER_FREQUENCY 3686400 /* 3.6864MHz */
121 1.1 ichiro #define TICKS_PER_MICROSECOND (TIMER_FREQUENCY/1000000)
122 1.1 ichiro
123 1.1 ichiro struct cfattach ixpclk_ca = {
124 1.1 ichiro sizeof(struct ixpclk_softc), ixpclk_match, ixpclk_attach
125 1.1 ichiro };
126 1.1 ichiro
127 1.1 ichiro #define GET_TIMER_VALUE(sc) (bus_space_read_4((sc)->sc_iot, \
128 1.1 ichiro (sc)->sc_ioh, \
129 1.1 ichiro IXPCLK_VALUE) \
130 1.1 ichiro & IXPCL_CTV)
131 1.1 ichiro
132 1.1 ichiro static int
133 1.1 ichiro ixpclk_match(parent, match, aux)
134 1.1 ichiro struct device *parent;
135 1.1 ichiro struct cfdata *match;
136 1.1 ichiro void *aux;
137 1.1 ichiro {
138 1.1 ichiro return (1);
139 1.1 ichiro }
140 1.1 ichiro
141 1.1 ichiro static void
142 1.1 ichiro ixpclk_attach(parent, self, aux)
143 1.1 ichiro struct device *parent;
144 1.1 ichiro struct device *self;
145 1.1 ichiro void *aux;
146 1.1 ichiro {
147 1.1 ichiro struct ixpclk_softc *sc = (struct ixpclk_softc*) self;
148 1.1 ichiro struct ixpsip_attach_args *sa = aux;
149 1.1 ichiro
150 1.1 ichiro printf("\n");
151 1.1 ichiro
152 1.1 ichiro sc->sc_iot = sa->sa_iot;
153 1.1 ichiro sc->sc_baseaddr = sa->sa_addr;
154 1.1 ichiro
155 1.1 ichiro /* using first timer for system ticks */
156 1.1 ichiro if (ixpclk_sc == NULL)
157 1.1 ichiro ixpclk_sc = sc;
158 1.1 ichiro
159 1.1 ichiro if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 0,
160 1.1 ichiro &sc->sc_ioh))
161 1.1 ichiro panic("%s: Cannot map registers\n", self->dv_xname);
162 1.1 ichiro
163 1.1 ichiro /* disable all channel and clear interrupt status */
164 1.1 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CONTROL,
165 1.1 ichiro IXPCL_DISABLE | IXPCL_PERIODIC | IXPCL_STP_CORE);
166 1.1 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CLEAR, 0);
167 1.1 ichiro printf("%s: IXP12x0 Interval Timer\n", sc->sc_dev.dv_xname);
168 1.1 ichiro }
169 1.1 ichiro
170 1.1 ichiro /*
171 1.1 ichiro * ixpclk_intr:
172 1.1 ichiro *
173 1.1 ichiro * Handle the hardclock interrupt.
174 1.1 ichiro */
175 1.1 ichiro static int
176 1.1 ichiro ixpclk_intr(void *arg)
177 1.1 ichiro
178 1.1 ichiro {
179 1.1 ichiro /* XXX XXX */
180 1.1 ichiro if (!(IXPREG(IXPPCI_IRQ_RAW_STATUS)
181 1.1 ichiro & (1U << (IXPPCI_INTR_T1 - SYS_NIRQ))))
182 1.1 ichiro return (0);
183 1.1 ichiro
184 1.1 ichiro bus_space_write_4(ixpclk_sc->sc_iot, ixpclk_sc->sc_ioh,
185 1.1 ichiro IXPCLK_CLEAR, 1);
186 1.1 ichiro
187 1.1 ichiro hardclock((struct clockframe*) arg);
188 1.1 ichiro return (1);
189 1.1 ichiro }
190 1.1 ichiro
191 1.1 ichiro /*
192 1.1 ichiro * setstatclockrate:
193 1.1 ichiro *
194 1.1 ichiro * Set the rate of the statistics clock.
195 1.1 ichiro *
196 1.1 ichiro * We assume that hz is either stathz or profhz, and that neither
197 1.1 ichiro * will change after being set by cpu_initclocks(). We could
198 1.1 ichiro * recalculate the intervals here, but that would be a pain.
199 1.1 ichiro */
200 1.1 ichiro void
201 1.1 ichiro setstatclockrate(hz)
202 1.1 ichiro int hz;
203 1.1 ichiro {
204 1.1 ichiro /* use hardclock */
205 1.1 ichiro
206 1.1 ichiro /* XXX should I use TIMER2? */
207 1.1 ichiro }
208 1.1 ichiro
209 1.1 ichiro /*
210 1.1 ichiro * cpu_initclocks:
211 1.1 ichiro *
212 1.1 ichiro * Initialize the clock and get them going.
213 1.1 ichiro */
214 1.1 ichiro void
215 1.1 ichiro cpu_initclocks()
216 1.1 ichiro {
217 1.1 ichiro struct ixpclk_softc* sc = ixpclk_sc;
218 1.1 ichiro u_int32_t ccf;
219 1.1 ichiro
220 1.1 ichiro stathz = profhz = 0;
221 1.1 ichiro
222 1.1 ichiro printf("clock: hz = %d stathz = %d\n", hz, stathz);
223 1.1 ichiro
224 1.1 ichiro ccf = IXPREG(IXP12X0_PLL_CFG) & IXP12X0_PLL_CFG_CCF;
225 1.1 ichiro sc->sc_coreclock_freq = ccf_to_coreclock[ccf];
226 1.1 ichiro
227 1.1 ichiro printf("pll_cfg:ccf = %x coreclock frequency = %dHz\n",
228 1.1 ichiro ccf, sc->sc_coreclock_freq);
229 1.1 ichiro
230 1.1 ichiro sc->sc_clock_count = sc->sc_coreclock_freq / hz;
231 1.1 ichiro sc->sc_count_per_usec = sc->sc_coreclock_freq / 10000000;
232 1.1 ichiro
233 1.1 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CLEAR, IXPT_CLEAR);
234 1.1 ichiro
235 1.1 ichiro ixp12x0_intr_establish(IXPPCI_INTR_T1, IPL_CLOCK, ixpclk_intr, NULL);
236 1.1 ichiro
237 1.1 ichiro IXPREG(IXPPCI_IRQ_ENABLE_SET) = (1U << (IXPPCI_INTR_T1 - SYS_NIRQ));
238 1.1 ichiro
239 1.1 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_LOAD,
240 1.1 ichiro sc->sc_clock_count);
241 1.1 ichiro #if 1 /* XXX */
242 1.1 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CONTROL,
243 1.1 ichiro IXPCL_ENABLE | IXPCL_PERIODIC
244 1.1 ichiro | IXPCL_STP_CORE);
245 1.1 ichiro #else
246 1.1 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CONTROL,
247 1.1 ichiro IXPCL_ENABLE | IXPCL_PERIODIC
248 1.1 ichiro | IXPCL_STP_DIV256);
249 1.1 ichiro #endif
250 1.1 ichiro }
251 1.1 ichiro
252 1.1 ichiro int
253 1.1 ichiro gettick()
254 1.1 ichiro {
255 1.1 ichiro int counter;
256 1.1 ichiro u_int savedints;
257 1.1 ichiro savedints = disable_interrupts(I32_bit);
258 1.1 ichiro
259 1.1 ichiro counter = GET_TIMER_VALUE(ixpclk_sc);
260 1.1 ichiro
261 1.1 ichiro restore_interrupts(savedints);
262 1.1 ichiro return counter;
263 1.1 ichiro }
264 1.1 ichiro
265 1.1 ichiro /*
266 1.1 ichiro * microtime:
267 1.1 ichiro *
268 1.1 ichiro * Fill in the specified timeval struct with the current time
269 1.1 ichiro * accurate to the microsecond.
270 1.1 ichiro */
271 1.1 ichiro void
272 1.1 ichiro microtime(tvp)
273 1.1 ichiro register struct timeval *tvp;
274 1.1 ichiro {
275 1.1 ichiro u_int oldirqstate;
276 1.1 ichiro u_int32_t counts;
277 1.1 ichiro static struct timeval lasttv;
278 1.1 ichiro
279 1.1 ichiro if (ixpclk_sc == NULL) {
280 1.1 ichiro #ifdef DEBUG
281 1.1 ichiro printf("microtime: called befor initialize ixpclk\n");
282 1.1 ichiro #endif
283 1.1 ichiro tvp->tv_sec = 0;
284 1.1 ichiro tvp->tv_usec = 0;
285 1.1 ichiro return;
286 1.1 ichiro }
287 1.1 ichiro
288 1.1 ichiro oldirqstate = disable_interrupts(I32_bit);
289 1.1 ichiro
290 1.1 ichiro counts = ixpclk_sc->sc_clock_count - GET_TIMER_VALUE(ixpclk_sc);
291 1.1 ichiro
292 1.1 ichiro #ifdef DEBUG
293 1.1 ichiro printf("microtime: counts = %d\n", counts);
294 1.1 ichiro #endif
295 1.1 ichiro
296 1.1 ichiro /* Fill in the timeval struct. */
297 1.1 ichiro *tvp = time;
298 1.1 ichiro tvp->tv_usec += counts / ixpclk_sc->sc_count_per_usec;
299 1.1 ichiro
300 1.1 ichiro /* Make sure microseconds doesn't overflow. */
301 1.1 ichiro while (tvp->tv_usec >= 1000000) {
302 1.1 ichiro tvp->tv_usec -= 1000000;
303 1.1 ichiro tvp->tv_sec++;
304 1.1 ichiro }
305 1.1 ichiro
306 1.1 ichiro /* Make sure the time has advanced. */
307 1.1 ichiro if (tvp->tv_sec == lasttv.tv_sec &&
308 1.1 ichiro tvp->tv_usec <= lasttv.tv_usec) {
309 1.1 ichiro tvp->tv_usec = lasttv.tv_usec + 1;
310 1.1 ichiro if (tvp->tv_usec >= 1000000) {
311 1.1 ichiro tvp->tv_usec -= 1000000;
312 1.1 ichiro tvp->tv_sec++;
313 1.1 ichiro }
314 1.1 ichiro }
315 1.1 ichiro
316 1.1 ichiro lasttv = *tvp;
317 1.1 ichiro
318 1.1 ichiro restore_interrupts(oldirqstate);
319 1.1 ichiro }
320 1.1 ichiro
321 1.1 ichiro /*
322 1.1 ichiro * delay:
323 1.1 ichiro *
324 1.1 ichiro * Delay for at least N microseconds.
325 1.1 ichiro */
326 1.1 ichiro void
327 1.1 ichiro delay(usecs)
328 1.1 ichiro u_int usecs;
329 1.1 ichiro {
330 1.1 ichiro u_int32_t tick, otick, delta;
331 1.1 ichiro int j, csec, usec;
332 1.1 ichiro
333 1.1 ichiro csec = usecs / 10000;
334 1.1 ichiro usec = usecs % 10000;
335 1.1 ichiro
336 1.1 ichiro if (ixpclk_sc == NULL) {
337 1.1 ichiro static u_int32_t coreclock_freq = 0;
338 1.1 ichiro
339 1.1 ichiro #ifdef DEBUG
340 1.1 ichiro printf("delay: called befor initialize ixpclk\n");
341 1.1 ichiro #endif
342 1.1 ichiro if (coreclock_freq == 0) {
343 1.1 ichiro coreclock_freq
344 1.1 ichiro = ccf_to_coreclock[IXPREG(IXP12X0_PLL_CFG)
345 1.1 ichiro & IXP12X0_PLL_CFG_CCF];
346 1.1 ichiro }
347 1.1 ichiro
348 1.1 ichiro usecs = (TIMER_FREQUENCY / 100) * csec
349 1.1 ichiro + (TIMER_FREQUENCY / 100) * usec / 10000;
350 1.1 ichiro /* clock isn't initialized yet */
351 1.1 ichiro for(; usecs > 0; usecs--)
352 1.1 ichiro for(j = 100; j > 0; j--)
353 1.1 ichiro ;
354 1.1 ichiro return;
355 1.1 ichiro }
356 1.1 ichiro
357 1.1 ichiro usecs = (ixpclk_sc->sc_coreclock_freq / 100) * csec
358 1.1 ichiro + (ixpclk_sc->sc_coreclock_freq / 100) * usec / 10000;
359 1.1 ichiro
360 1.1 ichiro otick = gettick();
361 1.1 ichiro
362 1.1 ichiro while (1) {
363 1.1 ichiro for(j = 100; j > 0; j--)
364 1.1 ichiro ;
365 1.1 ichiro tick = gettick();
366 1.1 ichiro
367 1.1 ichiro delta = otick > tick
368 1.1 ichiro ? otick - tick
369 1.1 ichiro : otick - tick + IXPCL_ITV + 1;
370 1.1 ichiro if (delta > usecs)
371 1.1 ichiro break;
372 1.1 ichiro usecs -= delta;
373 1.1 ichiro otick = tick;
374 1.1 ichiro }
375 1.1 ichiro }
376 1.1 ichiro
377 1.1 ichiro void
378 1.1 ichiro resettodr()
379 1.1 ichiro {
380 1.1 ichiro }
381 1.1 ichiro
382 1.1 ichiro void
383 1.1 ichiro inittodr(base)
384 1.1 ichiro time_t base;
385 1.1 ichiro {
386 1.1 ichiro time.tv_sec = base;
387 1.1 ichiro time.tv_usec = 0;
388 1.1 ichiro }
389