ixp12x0_clk.c revision 1.16 1 1.16 chs /* $NetBSD: ixp12x0_clk.c,v 1.16 2012/10/27 17:17:39 chs 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.14 martin * 3. All advertising materials mentioning features or use of this software
20 1.14 martin * must display the following acknowledgement:
21 1.14 martin * This product includes software developed by the NetBSD
22 1.14 martin * Foundation, Inc. and its contributors.
23 1.14 martin * 4. Neither the name of The NetBSD Foundation nor the names of its
24 1.14 martin * contributors may be used to endorse or promote products derived
25 1.14 martin * 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.7 igy
40 1.7 igy #include <sys/cdefs.h>
41 1.16 chs __KERNEL_RCSID(0, "$NetBSD: ixp12x0_clk.c,v 1.16 2012/10/27 17:17:39 chs Exp $");
42 1.1 ichiro
43 1.1 ichiro #include <sys/types.h>
44 1.1 ichiro #include <sys/param.h>
45 1.12 joerg #include <sys/atomic.h>
46 1.1 ichiro #include <sys/systm.h>
47 1.1 ichiro #include <sys/kernel.h>
48 1.1 ichiro #include <sys/time.h>
49 1.12 joerg #include <sys/timetc.h>
50 1.1 ichiro #include <sys/device.h>
51 1.1 ichiro
52 1.15 dyoung #include <sys/bus.h>
53 1.1 ichiro #include <machine/intr.h>
54 1.1 ichiro
55 1.1 ichiro #include <arm/cpufunc.h>
56 1.1 ichiro
57 1.1 ichiro #include <arm/ixp12x0/ixpsipvar.h>
58 1.1 ichiro
59 1.1 ichiro #include <arm/ixp12x0/ixp12x0_pcireg.h>
60 1.1 ichiro #include <arm/ixp12x0/ixp12x0_clkreg.h>
61 1.1 ichiro #include <arm/ixp12x0/ixp12x0var.h>
62 1.1 ichiro
63 1.16 chs static int ixpclk_match(device_t, cfdata_t, void *);
64 1.16 chs static void ixpclk_attach(device_t, device_t, void *);
65 1.1 ichiro
66 1.12 joerg static u_int ixpclk_get_timecount(struct timecounter *);
67 1.12 joerg
68 1.1 ichiro int gettick(void);
69 1.1 ichiro void rtcinit(void);
70 1.1 ichiro
71 1.1 ichiro /* callback functions for intr_functions */
72 1.1 ichiro static int ixpclk_intr(void* arg);
73 1.1 ichiro
74 1.1 ichiro struct ixpclk_softc {
75 1.1 ichiro bus_addr_t sc_baseaddr;
76 1.1 ichiro bus_space_tag_t sc_iot;
77 1.1 ichiro bus_space_handle_t sc_ioh;
78 1.6 ichiro bus_space_handle_t sc_pll_ioh;
79 1.1 ichiro
80 1.1 ichiro u_int32_t sc_clock_count;
81 1.1 ichiro u_int32_t sc_count_per_usec;
82 1.1 ichiro u_int32_t sc_coreclock_freq;
83 1.1 ichiro };
84 1.1 ichiro
85 1.1 ichiro #define XTAL_FREQ 3686400 /* 3.6864MHz */
86 1.1 ichiro #define XTAL_FREQ3686400
87 1.1 ichiro #undef XTAL_FREQ3787800
88 1.1 ichiro #undef XTAL_FREQ3579500
89 1.1 ichiro #define MAX_CCF 22
90 1.1 ichiro
91 1.1 ichiro #if defined(XTAL_FREQ3686400)
92 1.1 ichiro static u_int32_t ccf_to_coreclock[MAX_CCF + 1] = {
93 1.1 ichiro 29491000,
94 1.1 ichiro 36865000,
95 1.1 ichiro 44237000,
96 1.1 ichiro 51610000,
97 1.1 ichiro 58982000,
98 1.1 ichiro 66355000,
99 1.1 ichiro 73728000,
100 1.1 ichiro 81101000,
101 1.1 ichiro 88474000,
102 1.1 ichiro 95846000,
103 1.1 ichiro 103219000,
104 1.1 ichiro 110592000,
105 1.1 ichiro 132710000,
106 1.1 ichiro 147456000,
107 1.1 ichiro 154829000,
108 1.1 ichiro 162202000,
109 1.1 ichiro 165890000,
110 1.1 ichiro 176947000,
111 1.1 ichiro 191693000,
112 1.1 ichiro 199066000,
113 1.1 ichiro 206438000,
114 1.1 ichiro 221184000,
115 1.1 ichiro 232243000,
116 1.1 ichiro };
117 1.1 ichiro #elif defined(XTAL_FREQ3787800)
118 1.1 ichiro #elif defined(XTAL_FREQ3579500)
119 1.1 ichiro #else
120 1.1 ichiro #error
121 1.1 ichiro #endif
122 1.1 ichiro
123 1.1 ichiro static struct ixpclk_softc *ixpclk_sc = NULL;
124 1.1 ichiro
125 1.12 joerg static struct timecounter ixpclk_timecounter = {
126 1.12 joerg ixpclk_get_timecount, /* get_timecount */
127 1.12 joerg 0, /* no poll_pps */
128 1.12 joerg 0xffffffff, /* counter_mask */
129 1.12 joerg 0, /* frequency */
130 1.12 joerg "ixpclk", /* name */
131 1.12 joerg 100, /* quality */
132 1.12 joerg NULL, /* prev */
133 1.12 joerg NULL, /* next */
134 1.12 joerg };
135 1.12 joerg
136 1.12 joerg static volatile uint32_t ixpclk_base;
137 1.12 joerg
138 1.1 ichiro #define TIMER_FREQUENCY 3686400 /* 3.6864MHz */
139 1.1 ichiro #define TICKS_PER_MICROSECOND (TIMER_FREQUENCY/1000000)
140 1.1 ichiro
141 1.16 chs CFATTACH_DECL_NEW(ixpclk, sizeof(struct ixpclk_softc),
142 1.5 thorpej ixpclk_match, ixpclk_attach, NULL, NULL);
143 1.1 ichiro
144 1.1 ichiro #define GET_TIMER_VALUE(sc) (bus_space_read_4((sc)->sc_iot, \
145 1.1 ichiro (sc)->sc_ioh, \
146 1.1 ichiro IXPCLK_VALUE) \
147 1.1 ichiro & IXPCL_CTV)
148 1.1 ichiro
149 1.1 ichiro static int
150 1.16 chs ixpclk_match(device_t parent, cfdata_t match, void *aux)
151 1.1 ichiro {
152 1.8 igy
153 1.6 ichiro return 2;
154 1.1 ichiro }
155 1.1 ichiro
156 1.1 ichiro static void
157 1.16 chs ixpclk_attach(device_t parent, device_t self, void *aux)
158 1.1 ichiro {
159 1.8 igy struct ixpclk_softc *sc;
160 1.8 igy struct ixpsip_attach_args *sa;
161 1.6 ichiro u_int32_t ccf;
162 1.12 joerg bool first_run = ixpclk_sc == NULL;
163 1.1 ichiro
164 1.1 ichiro printf("\n");
165 1.1 ichiro
166 1.16 chs sc = device_private(self);
167 1.8 igy sa = aux;
168 1.1 ichiro sc->sc_iot = sa->sa_iot;
169 1.1 ichiro sc->sc_baseaddr = sa->sa_addr;
170 1.1 ichiro
171 1.1 ichiro /* using first timer for system ticks */
172 1.1 ichiro if (ixpclk_sc == NULL)
173 1.1 ichiro ixpclk_sc = sc;
174 1.1 ichiro
175 1.1 ichiro if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 0,
176 1.1 ichiro &sc->sc_ioh))
177 1.16 chs panic("%s: Cannot map registers", device_xname(self));
178 1.6 ichiro if (bus_space_map(sa->sa_iot, sa->sa_addr + IXPCLK_PLL_CFG_OFFSET,
179 1.6 ichiro IXPCLK_PLL_CFG_SIZE, 0, &sc->sc_pll_ioh))
180 1.16 chs panic("%s: Cannot map registers", device_xname(self));
181 1.1 ichiro
182 1.1 ichiro /* disable all channel and clear interrupt status */
183 1.1 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CONTROL,
184 1.1 ichiro IXPCL_DISABLE | IXPCL_PERIODIC | IXPCL_STP_CORE);
185 1.1 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CLEAR, 0);
186 1.6 ichiro
187 1.6 ichiro
188 1.6 ichiro ccf = bus_space_read_4(sc->sc_iot, sc->sc_pll_ioh, 0)
189 1.6 ichiro & IXP12X0_PLL_CFG_CCF;
190 1.6 ichiro sc->sc_coreclock_freq = ccf_to_coreclock[ccf];
191 1.6 ichiro
192 1.6 ichiro sc->sc_clock_count = sc->sc_coreclock_freq / hz;
193 1.6 ichiro sc->sc_count_per_usec = sc->sc_coreclock_freq / 1000000;
194 1.6 ichiro
195 1.6 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CLEAR, IXPT_CLEAR);
196 1.6 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_LOAD,
197 1.6 ichiro sc->sc_clock_count);
198 1.6 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CONTROL,
199 1.6 ichiro IXPCL_ENABLE | IXPCL_PERIODIC | IXPCL_STP_CORE);
200 1.6 ichiro
201 1.12 joerg if (first_run) {
202 1.12 joerg ixpclk_timecounter.tc_frequency = sc->sc_coreclock_freq;
203 1.12 joerg tc_init(&ixpclk_timecounter);
204 1.12 joerg }
205 1.12 joerg
206 1.6 ichiro printf("%s: IXP12x0 Interval Timer (core clock %d.%03dMHz)\n",
207 1.16 chs device_xname(self),
208 1.6 ichiro sc->sc_coreclock_freq / 1000000,
209 1.6 ichiro (sc->sc_coreclock_freq % 1000000) / 1000);
210 1.1 ichiro }
211 1.1 ichiro
212 1.1 ichiro /*
213 1.1 ichiro * ixpclk_intr:
214 1.1 ichiro *
215 1.1 ichiro * Handle the hardclock interrupt.
216 1.1 ichiro */
217 1.1 ichiro static int
218 1.1 ichiro ixpclk_intr(void *arg)
219 1.1 ichiro {
220 1.8 igy
221 1.1 ichiro bus_space_write_4(ixpclk_sc->sc_iot, ixpclk_sc->sc_ioh,
222 1.1 ichiro IXPCLK_CLEAR, 1);
223 1.1 ichiro
224 1.12 joerg atomic_add_32(&ixpclk_base, ixpclk_sc->sc_coreclock_freq);
225 1.12 joerg
226 1.1 ichiro hardclock((struct clockframe*) arg);
227 1.1 ichiro return (1);
228 1.1 ichiro }
229 1.1 ichiro
230 1.1 ichiro /*
231 1.1 ichiro * setstatclockrate:
232 1.1 ichiro *
233 1.1 ichiro * Set the rate of the statistics clock.
234 1.1 ichiro *
235 1.1 ichiro * We assume that hz is either stathz or profhz, and that neither
236 1.1 ichiro * will change after being set by cpu_initclocks(). We could
237 1.1 ichiro * recalculate the intervals here, but that would be a pain.
238 1.1 ichiro */
239 1.1 ichiro void
240 1.9 he setstatclockrate(int newhz)
241 1.1 ichiro {
242 1.8 igy
243 1.1 ichiro /* use hardclock */
244 1.1 ichiro
245 1.1 ichiro /* XXX should I use TIMER2? */
246 1.1 ichiro }
247 1.1 ichiro
248 1.1 ichiro /*
249 1.1 ichiro * cpu_initclocks:
250 1.1 ichiro *
251 1.1 ichiro * Initialize the clock and get them going.
252 1.1 ichiro */
253 1.1 ichiro void
254 1.8 igy cpu_initclocks(void)
255 1.1 ichiro {
256 1.8 igy struct ixpclk_softc* sc;
257 1.1 ichiro
258 1.8 igy sc = ixpclk_sc;
259 1.1 ichiro stathz = profhz = 0;
260 1.1 ichiro
261 1.1 ichiro printf("clock: hz = %d stathz = %d\n", hz, stathz);
262 1.1 ichiro
263 1.6 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CONTROL,
264 1.6 ichiro IXPCL_DISABLE);
265 1.1 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CLEAR, IXPT_CLEAR);
266 1.1 ichiro
267 1.1 ichiro ixp12x0_intr_establish(IXPPCI_INTR_T1, IPL_CLOCK, ixpclk_intr, NULL);
268 1.1 ichiro
269 1.1 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_LOAD,
270 1.1 ichiro sc->sc_clock_count);
271 1.1 ichiro bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CONTROL,
272 1.1 ichiro IXPCL_ENABLE | IXPCL_PERIODIC
273 1.1 ichiro | IXPCL_STP_CORE);
274 1.1 ichiro }
275 1.1 ichiro
276 1.1 ichiro int
277 1.8 igy gettick(void)
278 1.1 ichiro {
279 1.8 igy int counter;
280 1.8 igy u_int savedints;
281 1.8 igy
282 1.1 ichiro savedints = disable_interrupts(I32_bit);
283 1.1 ichiro counter = GET_TIMER_VALUE(ixpclk_sc);
284 1.1 ichiro restore_interrupts(savedints);
285 1.1 ichiro return counter;
286 1.1 ichiro }
287 1.1 ichiro
288 1.12 joerg static u_int
289 1.12 joerg ixpclk_get_timecount(struct timecounter *tc)
290 1.1 ichiro {
291 1.12 joerg u_int savedints, base, counter;
292 1.1 ichiro
293 1.12 joerg savedints = disable_interrupts(I32_bit);
294 1.12 joerg do {
295 1.12 joerg base = ixpclk_base;
296 1.12 joerg counter = GET_TIMER_VALUE(ixpclk_sc);
297 1.12 joerg } while (base != ixpclk_base);
298 1.12 joerg restore_interrupts(savedints);
299 1.1 ichiro
300 1.12 joerg return base - counter;
301 1.1 ichiro }
302 1.1 ichiro
303 1.1 ichiro /*
304 1.1 ichiro * delay:
305 1.1 ichiro *
306 1.1 ichiro * Delay for at least N microseconds.
307 1.1 ichiro */
308 1.1 ichiro void
309 1.6 ichiro delay(unsigned int usecs)
310 1.1 ichiro {
311 1.6 ichiro u_int32_t count;
312 1.9 he u_int32_t ticks;
313 1.6 ichiro u_int32_t otick;
314 1.6 ichiro u_int32_t delta;
315 1.6 ichiro int j;
316 1.8 igy int csec;
317 1.8 igy int usec;
318 1.1 ichiro
319 1.1 ichiro if (ixpclk_sc == NULL) {
320 1.1 ichiro #ifdef DEBUG
321 1.6 ichiro printf("delay: called befor start ixpclk\n");
322 1.1 ichiro #endif
323 1.1 ichiro
324 1.6 ichiro csec = usecs / 10000;
325 1.6 ichiro usec = usecs % 10000;
326 1.6 ichiro
327 1.1 ichiro usecs = (TIMER_FREQUENCY / 100) * csec
328 1.1 ichiro + (TIMER_FREQUENCY / 100) * usec / 10000;
329 1.1 ichiro /* clock isn't initialized yet */
330 1.1 ichiro for(; usecs > 0; usecs--)
331 1.1 ichiro for(j = 100; j > 0; j--)
332 1.1 ichiro ;
333 1.1 ichiro return;
334 1.1 ichiro }
335 1.1 ichiro
336 1.6 ichiro count = ixpclk_sc->sc_count_per_usec * usecs;
337 1.1 ichiro
338 1.1 ichiro otick = gettick();
339 1.1 ichiro
340 1.6 ichiro for (;;) {
341 1.1 ichiro for(j = 100; j > 0; j--)
342 1.1 ichiro ;
343 1.6 ichiro
344 1.9 he ticks = gettick();
345 1.9 he delta = otick < ticks
346 1.9 he ? ixpclk_sc->sc_clock_count + otick - ticks
347 1.9 he : otick - ticks;
348 1.1 ichiro
349 1.6 ichiro if (delta > count)
350 1.1 ichiro break;
351 1.6 ichiro
352 1.6 ichiro count -= delta;
353 1.9 he otick = ticks;
354 1.1 ichiro }
355 1.1 ichiro }
356