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

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