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