Annotation of sys/arch/arm/s3c2xx0/s3c24x0_clk.c, Revision 1.1.1.1
1.1 nbrk 1: /* $NetBSD: s3c24x0_clk.c,v 1.7 2007/01/06 16:18:18 christos Exp $ */
2:
3: /*
4: * Copyright (c) 2003 Genetec corporation. All rights reserved.
5: * Written by Hiroyuki Bessho for Genetec corporation.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. The name of Genetec corporation may not be used to endorse
16: * or promote products derived from this software without specific prior
17: * written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORP.
23: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29: * POSSIBILITY OF SUCH DAMAGE.
30: */
31:
32: #include <sys/cdefs.h>
33: __KERNEL_RCSID(0, "$NetBSD: s3c24x0_clk.c,v 1.7 2007/01/06 16:18:18 christos Exp $");
34:
35: #include <sys/param.h>
36: #include <sys/systm.h>
37: #include <sys/kernel.h>
38: #include <sys/time.h>
39:
40: #include <machine/bus.h>
41: #include <machine/intr.h>
42: #include <arm/cpufunc.h>
43:
44: #include <arm/s3c2xx0/s3c24x0reg.h>
45: #include <arm/s3c2xx0/s3c24x0var.h>
46:
47:
48: #ifndef STATHZ
49: #define STATHZ 64
50: #endif
51:
52: #define TIMER_FREQUENCY(pclk) ((pclk)/16) /* divider=1/16 */
53:
54: static unsigned int timer4_reload_value;
55: static unsigned int timer4_prescaler;
56: static unsigned int timer4_mseccount;
57:
58: #define usec_to_counter(t) \
59: ((timer4_mseccount*(t))/1000)
60:
61: #define counter_to_usec(c,pclk) \
62: (((c)*timer4_prescaler*1000)/(TIMER_FREQUENCY(pclk)/1000))
63:
64:
65: /*
66: * microtime:
67: *
68: * Fill in the specified timeval struct with the current time
69: * accurate to the microsecond.
70: */
71: void
72: microtime(struct timeval *tvp)
73: {
74: struct s3c24x0_softc *sc = (struct s3c24x0_softc *) s3c2xx0_softc;
75: int save, int_pend0, int_pend1, count, delta;
76: static struct timeval last;
77: int pclk = s3c2xx0_softc->sc_pclk;
78:
79: if( timer4_reload_value == 0 ){
80: /* not initialized yet */
81: tvp->tv_sec = 0;
82: tvp->tv_usec = 0;
83: return;
84: }
85:
86: save = disable_interrupts(I32_bit);
87:
88: again:
89: int_pend0 = S3C24X0_INT_TIMER4 &
90: bus_space_read_4(sc->sc_sx.sc_iot, sc->sc_sx.sc_intctl_ioh,
91: INTCTL_SRCPND);
92: count = bus_space_read_2(sc->sc_sx.sc_iot, sc->sc_timer_ioh,
93: TIMER_TCNTO(4));
94:
95: for (;;){
96:
97: int_pend1 = S3C24X0_INT_TIMER4 &
98: bus_space_read_4(sc->sc_sx.sc_iot, sc->sc_sx.sc_intctl_ioh,
99: INTCTL_SRCPND);
100: if( int_pend0 == int_pend1 )
101: break;
102:
103: /*
104: * Down counter reached to zero while we were reading
105: * timer values. do it again to get consistent values.
106: */
107: int_pend0 = int_pend1;
108: count = bus_space_read_2(sc->sc_sx.sc_iot, sc->sc_timer_ioh,
109: TIMER_TCNTO(4));
110: }
111:
112: if( __predict_false(count > timer4_reload_value) ){
113: /*
114: * Buggy Hardware Warning --- sometimes timer counter
115: * reads bogus value like 0xffff. I guess it happens when
116: * the timer is reloaded.
117: */
118: printf( "Bogus value from timer counter: %d\n", count );
119: goto again;
120: }
121:
122: /* copy system time */
123: *tvp = time;
124:
125: restore_interrupts(save);
126:
127: delta = timer4_reload_value - count;
128:
129: if( int_pend1 ){
130: /*
131: * down counter underflow, but
132: * clock interrupt have not serviced yet
133: */
134: tvp->tv_usec += tick;
135: }
136:
137: tvp->tv_usec += counter_to_usec(delta, pclk);
138:
139: /* Make sure microseconds doesn't overflow. */
140: tvp->tv_sec += tvp->tv_usec / 1000000;
141: tvp->tv_usec = tvp->tv_usec % 1000000;
142:
143: if (last.tv_sec &&
144: (tvp->tv_sec < last.tv_sec ||
145: (tvp->tv_sec == last.tv_sec &&
146: tvp->tv_usec < last.tv_usec) ) ){
147:
148: /* XXX: This happens very often when the kernel runs
149: under Multi-ICE */
150: #if 0
151: printf("time reversal: %ld.%06ld(%d,%d) -> %ld.%06ld(%d,%d)\n",
152: last.tv_sec, last.tv_usec,
153: last_count, last_pend,
154: tvp->tv_sec, tvp->tv_usec,
155: count, int_pend1 );
156: #endif
157:
158: /* make sure the time has advanced. */
159: *tvp = last;
160: tvp->tv_usec++;
161: if( tvp->tv_usec >= 1000000 ){
162: tvp->tv_usec -= 1000000;
163: tvp->tv_sec++;
164: }
165: }
166:
167: last = *tvp;
168:
169: }
170:
171: static inline int
172: read_timer(struct s3c24x0_softc *sc)
173: {
174: int count;
175:
176: do {
177: count = bus_space_read_2(sc->sc_sx.sc_iot, sc->sc_timer_ioh,
178: TIMER_TCNTO(4));
179: } while ( __predict_false(count > timer4_reload_value) );
180:
181: return count;
182: }
183:
184: /*
185: * delay:
186: *
187: * Delay for at least N microseconds.
188: */
189: void
190: delay(u_int n)
191: {
192: struct s3c24x0_softc *sc = (struct s3c24x0_softc *) s3c2xx0_softc;
193: int v0, v1, delta;
194: u_int ucnt;
195:
196: if ( timer4_reload_value == 0 ){
197: /* not initialized yet */
198: while ( n-- > 0 ){
199: int m;
200:
201: for (m=0; m<100; ++m )
202: ;
203: }
204: return;
205: }
206:
207: /* read down counter */
208: v0 = read_timer(sc);
209:
210: ucnt = usec_to_counter(n);
211:
212: while( ucnt > 0 ) {
213: v1 = read_timer(sc);
214: delta = v0 - v1;
215: if ( delta < 0 )
216: delta += timer4_reload_value;
217: #ifdef DEBUG
218: if (delta < 0 || delta > timer4_reload_value)
219: panic("wrong value from timer counter");
220: #endif
221:
222: if((u_int)delta < ucnt){
223: ucnt -= (u_int)delta;
224: v0 = v1;
225: }
226: else {
227: ucnt = 0;
228: }
229: }
230: /*NOTREACHED*/
231: }
232:
233: void
234: setstatclockrate(int newhz)
235: {
236: }
237:
238: #define hardintr (int (*)(void *))hardclock
239: #define statintr (int (*)(void *))statclock
240:
241: void
242: cpu_initclocks(void)
243: {
244: struct s3c24x0_softc *sc = (struct s3c24x0_softc *)s3c2xx0_softc;
245: long tc;
246: int prescaler, h;
247: int pclk = s3c2xx0_softc->sc_pclk;
248: bus_space_tag_t iot = sc->sc_sx.sc_iot;
249: bus_space_handle_t ioh = sc->sc_timer_ioh;
250: uint32_t reg;
251:
252: stathz = STATHZ;
253: profhz = stathz;
254:
255: #define time_constant(hz) (TIMER_FREQUENCY(pclk) /(hz)/ prescaler)
256: #define calc_time_constant(hz) \
257: do { \
258: prescaler = 1; \
259: do { \
260: ++prescaler; \
261: tc = time_constant(hz); \
262: } while( tc > 65536 ); \
263: } while(0)
264:
265:
266: /* Use the channels 4 and 3 for hardclock and statclock, respectively */
267:
268: /* stop all timers */
269: bus_space_write_4(iot, ioh, TIMER_TCON, 0);
270:
271: /* calc suitable prescaler value */
272: h = MIN(hz,stathz);
273: calc_time_constant(h);
274:
275: timer4_prescaler = prescaler;
276: timer4_reload_value = TIMER_FREQUENCY(pclk) / hz / prescaler;
277: timer4_mseccount = TIMER_FREQUENCY(pclk)/timer4_prescaler/1000 ;
278:
279: bus_space_write_4(iot, ioh, TIMER_TCNTB(4),
280: ((prescaler - 1) << 16) | (timer4_reload_value - 1));
281:
282: printf("clock: hz=%d stathz = %d PCLK=%d prescaler=%d tc=%ld\n",
283: hz, stathz, pclk, prescaler, tc);
284:
285: bus_space_write_4(iot, ioh, TIMER_TCNTB(3),
286: ((prescaler - 1) << 16) | (time_constant(stathz) - 1));
287:
288: s3c24x0_intr_establish(S3C24X0_INT_TIMER4, IPL_CLOCK,
289: IST_NONE, hardintr, 0);
290: s3c24x0_intr_establish(S3C24X0_INT_TIMER3, IPL_STATCLOCK,
291: IST_NONE, statintr, 0);
292:
293: /* set prescaler1 */
294: reg = bus_space_read_4(iot, ioh, TIMER_TCFG0);
295: bus_space_write_4(iot, ioh, TIMER_TCFG0,
296: (reg & ~0xff00) | ((prescaler-1) << 8));
297:
298: /* divider 1/16 for ch #3 and #4 */
299: reg = bus_space_read_4(iot, ioh, TIMER_TCFG1);
300: bus_space_write_4(iot, ioh, TIMER_TCFG1,
301: (reg & ~(TCFG1_MUX_MASK(3)|TCFG1_MUX_MASK(4))) |
302: (TCFG1_MUX_DIV16 << TCFG1_MUX_SHIFT(3)) |
303: (TCFG1_MUX_DIV16 << TCFG1_MUX_SHIFT(4)) );
304:
305:
306: /* start timers */
307: reg = bus_space_read_4(iot, ioh, TIMER_TCON);
308: reg &= ~(TCON_MASK(3)|TCON_MASK(4));
309:
310: /* load the time constant */
311: bus_space_write_4(iot, ioh, TIMER_TCON, reg |
312: TCON_MANUALUPDATE(3) | TCON_MANUALUPDATE(4));
313: /* set auto reload and start */
314: bus_space_write_4(iot, ioh, TIMER_TCON, reg |
315: TCON_AUTORELOAD(3) | TCON_START(3) |
316: TCON_AUTORELOAD(4) | TCON_START(4) );
317: }
318:
319:
320: #if 0
321: /* test routine for delay() */
322:
323: void delay_test(void);
324: void
325: delay_test(void)
326: {
327: struct s3c2xx0_softc *sc = s3c2xx0_softc;
328: volatile int *pdatc = (volatile int *)
329: ((char *)bus_space_vaddr(sc->sc_iot, sc->sc_gpio_ioh) + GPIO_PDATC);
330: static const int d[] = {0, 1, 5, 10, 50, 100, 500, 1000, -1};
331: int i;
332: int v = *pdatc & ~0x07;
333:
334: for (;;) {
335: *pdatc = v | 2;
336:
337: for (i=0; d[i] >= 0; ++i) {
338: *pdatc = v | 3;
339: delay(d[i]);
340: *pdatc = v | 2;
341: }
342: *pdatc = v;
343: }
344: }
345: #endif
346:
CVSweb