Annotation of sys/arch/arm/s3c2xx0/s3c24x0_clk.c, Revision 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