[BACK]Return to s3c24x0_clk.c CVS log [TXT][DIR] Up to [local] / sys / arch / arm / s3c2xx0

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