[BACK]Return to tod.c CVS log [TXT][DIR] Up to [local] / sys / arch / solbourne / dev

Annotation of sys/arch/solbourne/dev/tod.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: tod.c,v 1.1 2005/04/20 01:00:16 miod Exp $    */
                      2: /*
                      3:  * Copyright (c) 2005, Miodrag Vallat
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  * 1. Redistributions of source code must retain the above copyright
                      9:  *    notice, this list of conditions and the following disclaimer.
                     10:  * 2. Redistributions in binary form must reproduce the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer in the
                     12:  *    documentation and/or other materials provided with the distribution.
                     13:  *
                     14:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     15:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     16:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     17:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     18:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     19:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     20:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     21:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     22:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     23:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     24:  * POSSIBILITY OF SUCH DAMAGE.
                     25:  */
                     26:
                     27: /*
                     28:  * TODclock driver. We only use it to know the current time during boot,
                     29:  * as we do not get interrupts from it.
                     30:  *
                     31:  * The clock in the IDT machines is the Oki MSM62X42BRS.
                     32:  *
                     33:  * A datasheet for this chip is available from:
                     34:  *   http://www.datasheetarchive.com/datasheet/pdf/19/196099.html
                     35:  */
                     36:
                     37: #include <sys/param.h>
                     38: #include <sys/kernel.h>
                     39: #include <sys/device.h>
                     40: #include <sys/systm.h>
                     41:
                     42: #include <machine/autoconf.h>
                     43: #include <machine/cpu.h>
                     44:
                     45: #include <solbourne/dev/todreg.h>
                     46: #include <dev/clock_subr.h>
                     47:
                     48: #include <machine/idt.h>
                     49: #include <machine/kap.h>
                     50:
                     51: int    todmatch(struct device *, void *, void *);
                     52: void   todattach(struct device *, struct device *, void *);
                     53:
                     54: struct cfattach tod_ca = {
                     55:        sizeof(struct device), todmatch, todattach
                     56: };
                     57:
                     58: struct cfdriver tod_cd = {
                     59:        NULL, "tod", DV_DULL
                     60: };
                     61:
                     62: volatile u_char        *tod_regs;
                     63:
                     64: u_char msm_read(u_int);
                     65: void   msm_write(u_int, u_char);
                     66:
                     67: int
                     68: todmatch(parent, vcf, aux)
                     69:        struct device *parent;
                     70:        void *vcf, *aux;
                     71: {
                     72:        struct confargs *ca = aux;
                     73:
                     74:        return (strcmp(tod_cd.cd_name, ca->ca_ra.ra_name) == 0);
                     75: }
                     76:
                     77: void
                     78: todattach(parent, self, aux)
                     79:        struct device *parent, *self;
                     80:        void *aux;
                     81: {
                     82:        printf(": OKI MSM62X42BRS\n");
                     83:
                     84:        /* the register are already mapped 1:1 by pmap_bootstrap() */
                     85:        tod_regs = (volatile u_char *)TODCLOCK_BASE;
                     86: }
                     87:
                     88: /*
                     89:  * Read or write a register of the Oki clock.
                     90:  *
                     91:  * The clock registers are not directly accessible (while control registers
                     92:  * are). We need to freeze them first. To do so, we set the hold bit in
                     93:  * D, and if the busy bit clears, we are free to proceed. If the busy bit
                     94:  * is still set, we need to clear the hold bit and retry.
                     95:  */
                     96: u_char
                     97: msm_read(u_int regno)
                     98: {
                     99:        u_char d, r;
                    100:
                    101:        /* no need to do the hold dance for control registers */
                    102:        if (regno >= MSM_D)
                    103:                return (tod_regs[regno] & 0x0f);
                    104:
                    105:        d = tod_regs[MSM_D] & 0x0f & ~MSM_D_HOLD;
                    106:        for (;;) {
                    107:                tod_regs[MSM_D] = d | MSM_D_HOLD;
                    108:                if (!ISSET(tod_regs[MSM_D], MSM_D_BUSY))
                    109:                        break;
                    110:                tod_regs[MSM_D] = d;
                    111:        }
                    112:
                    113:        r = tod_regs[regno] & 0x0f;
                    114:        tod_regs[MSM_D] = d;
                    115:
                    116:        return (r);
                    117: }
                    118:
                    119: void
                    120: msm_write(u_int regno, u_char value)
                    121: {
                    122:        u_char d;
                    123:
                    124:        /* no need to do the hold dance for control registers */
                    125:        if (regno >= MSM_D) {
                    126:                tod_regs[regno] = value;
                    127:                return;
                    128:        }
                    129:
                    130:        d = tod_regs[MSM_D] & 0x0f & ~MSM_D_HOLD;
                    131:        for (;;) {
                    132:                tod_regs[MSM_D] = d | MSM_D_HOLD;
                    133:                if (!ISSET(tod_regs[MSM_D], MSM_D_BUSY))
                    134:                        break;
                    135:                tod_regs[MSM_D] = d;
                    136:        }
                    137:
                    138:        tod_regs[regno] = value;
                    139:        tod_regs[MSM_D] = d;
                    140: }
                    141:
                    142: void
                    143: inittodr(base)
                    144:        time_t base;
                    145: {
                    146:        struct clock_ymdhms dt;
                    147:
                    148:        dt.dt_sec = msm_read(MSM_SEC_UNITS) + 10 * msm_read(MSM_SEC_TENS);
                    149:        dt.dt_min = msm_read(MSM_MIN_UNITS) + 10 * msm_read(MSM_MIN_TENS);
                    150: #if 0
                    151:        dt.dt_hour = msm_read(MSM_HOUR_UNITS) + 10 * msm_read(MSM_HOUR_TENS);
                    152: #else
                    153:        dt.dt_hour = msm_read(MSM_HOUR_TENS);
                    154:        if (dt.dt_hour & MSM_HOUR_PM)
                    155:                dt.dt_hour = 12 + 10 * (dt.dt_hour & ~MSM_HOUR_TENS);
                    156:        else
                    157:                dt.dt_hour *= 10;
                    158:        dt.dt_hour += msm_read(MSM_HOUR_UNITS);
                    159: #endif
                    160:        dt.dt_day = msm_read(MSM_DAY_UNITS) + 10 * msm_read(MSM_DAY_TENS);
                    161:        dt.dt_mon = msm_read(MSM_MONTH_UNITS) + 10 * msm_read(MSM_MONTH_TENS);
                    162:        dt.dt_year = msm_read(MSM_YEAR_UNITS) + 10 * msm_read(MSM_YEAR_TENS);
                    163:        dt.dt_year += CLOCK_YEAR_BASE;
                    164:        /* dt_wday left uninitialized */
                    165:
                    166:        time.tv_sec = clock_ymdhms_to_secs(&dt);
                    167:
                    168:        if (time.tv_sec == 0) {
                    169:                /*
                    170:                 * Believe the time in the file system for lack of
                    171:                 * anything better, resetting the clock.
                    172:                 */
                    173:                if (base < 35 * SECYR) {/* this port did not exist until 2005 */
                    174:                        /*
                    175:                         * If base is 0, assume filesystem time is just unknown
                    176:                         * in stead of preposterous. Don't bark.
                    177:                         */
                    178:                        if (base != 0)
                    179:                                printf("WARNING: preposterous time in file system\n");
                    180:                        /* not going to use it anyway, if the chip is readable */
                    181:                        time.tv_sec = 35 * SECYR + 90 * SECDAY + SECDAY / 2;
                    182:                } else {
                    183:                        printf("WARNING: bad date in battery clock");
                    184:                        time.tv_sec = base;
                    185:                        resettodr();
                    186:                }
                    187:        } else {
                    188:                int deltat = time.tv_sec - base;
                    189:
                    190:                if (deltat < 0)
                    191:                        deltat = -deltat;
                    192:                if (deltat < 2 * SECDAY)
                    193:                        return;
                    194:
                    195: #ifndef SMALL_KERNEL
                    196:                printf("WARNING: clock %s %d days",
                    197:                    time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
                    198: #endif
                    199:        }
                    200:        printf(" -- CHECK AND RESET THE DATE!\n");
                    201: }
                    202:
                    203: void
                    204: resettodr()
                    205: {
                    206:        struct clock_ymdhms dt;
                    207:
                    208:        if (time.tv_sec == 0 || tod_regs == NULL)
                    209:                return;
                    210:
                    211:        clock_secs_to_ymdhms(time.tv_sec, &dt);
                    212:
                    213:        /*
                    214:         * Since we don't know if the clock is in AM/PM or 24 hour mode,
                    215:         * we need to reset it and force one mode. Being an evil european
                    216:         * person, I'll force 24 hour mode, of course.
                    217:         */
                    218:        msm_write(MSM_F, MSM_F_RESET | MSM_F_24HR);
                    219:        msm_write(MSM_F, MSM_F_STOP);   /* leave reset mode, but stop clock */
                    220:
                    221:        dt.dt_year -= CLOCK_YEAR_BASE;
                    222:        msm_write(MSM_YEAR_TENS, dt.dt_year / 10);
                    223:        msm_write(MSM_YEAR_UNITS, dt.dt_year % 10);
                    224:        msm_write(MSM_MONTH_TENS, dt.dt_mon / 10);
                    225:        msm_write(MSM_MONTH_UNITS, dt.dt_mon % 10);
                    226:        msm_write(MSM_DAY_TENS, dt.dt_day / 10);
                    227:        msm_write(MSM_DAY_UNITS, dt.dt_day % 10);
                    228:        msm_write(MSM_HOUR_TENS, dt.dt_hour / 10);
                    229:        msm_write(MSM_HOUR_UNITS, dt.dt_hour % 10);
                    230:        msm_write(MSM_MIN_TENS, dt.dt_min / 10);
                    231:        msm_write(MSM_MIN_UNITS, dt.dt_min % 10);
                    232:        msm_write(MSM_SEC_TENS, dt.dt_sec / 10);
                    233:        msm_write(MSM_SEC_UNITS, dt.dt_sec % 10);
                    234:
                    235:        msm_write(MSM_F, 0);    /* restart clock */
                    236: }

CVSweb