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