1 /* 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1992 OMRON Corporation. 4 * Copyright (c) 1982, 1990, 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * the Systems Programming Group of the University of Utah Computer 9 * Science Department. 10 * 11 * %sccs.include.redist.c% 12 * 13 * from: Utah $Hdr: clock.c 1.18 91/01/21$ 14 * from: hp300/hp300/clock.c 7.19 (Berkeley) 2/18/93 15 * 16 * @(#)clock.c 8.1 (Berkeley) 06/10/93 17 */ 18 19 #include <sys/param.h> 20 #include <sys/kernel.h> 21 22 #include <machine/cpu.h> 23 #include <luna68k/luna68k/clockreg.h> 24 25 extern int clock_on; 26 27 static int month_days[12] = { 28 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 29 }; 30 struct bbc_tm *gmt_to_bbc(); 31 32 volatile struct bbc *bbc = (struct bbc *)BBC_ADDR; 33 #ifdef LUNA2 34 volatile struct bbc2 *bbc2 = (struct bbc2 *)BBC_ADDR; 35 #endif 36 37 int battery_clock; 38 int battery_chkfg; 39 40 /* 41 * Machine-dependent clock routines. 42 * 43 * Startrtclock just checks battry backuped clock 44 * (when it does not work, starts it). 45 * 46 * Enablertclock sets flag for clock interrupt. 47 * 48 * Inittodr initializes the time of day hardware which provides 49 * date functions. 50 * 51 * Resettodr restores the time of day hardware after a time change. 52 * 53 */ 54 55 /* 56 * Start the real-time clock. 57 */ 58 cpu_initclocks() 59 { 60 static char *rtcstrings = "RTC"; /* For compat */ 61 62 /* set flag for clockintr. */ 63 clock_on = 1; 64 65 #ifdef LUNA2 66 if (machineid == LUNA_II) { 67 /* not yet */ 68 battery_chkfg = 1; 69 battery_clock = 1; 70 return; 71 } 72 #endif 73 74 batterychk(); 75 if (!battery_clock) 76 return; 77 78 if (!strncmp(bbc->nvram.nv_calclock, rtcstrings, sizeof(rtcstrings))) /* Okey */ 79 return; 80 81 printf("Initialize Battery Backup Clock.\n"); 82 bbc->cal_ctl |= BBC_WRT; 83 bbc->cal_sec &= ~BBC_STOP; 84 bbc->cal_hour |= BBC_KICK; 85 bbc->cal_dow &= ~BBC_FRQ; 86 bbc->cal_ctl &= ~BBC_WRT; 87 DELAY(BBC_DELAY); 88 bbc->cal_ctl |= BBC_WRT; 89 bbc->cal_hour &= ~BBC_KICK; 90 bbc->cal_ctl &= ~BBC_WRT; 91 strcpy(bbc->nvram.nv_calclock, rtcstrings); 92 } 93 94 void 95 setstatclockrate(newhz) 96 int newhz; 97 { 98 } 99 100 microtime(tvp) 101 register struct timeval *tvp; 102 { 103 int s = splhigh(); 104 105 *tvp = time; 106 tvp->tv_usec += tick; 107 while (tvp->tv_usec > 1000000) { 108 tvp->tv_sec++; 109 tvp->tv_usec -= 1000000; 110 } 111 splx(s); 112 } 113 114 /* 115 * Initialize the time of day register, based on the time base which is, e.g. 116 * from a filesystem. 117 */ 118 inittodr(base) 119 time_t base; 120 { 121 u_long timbuf = base; /* assume no battery clock exists */ 122 123 /* 124 * bbc_to_gmt converts and stores the gmt in timbuf. 125 * If an error is detected in bbc_to_gmt, or if the filesystem 126 * time is more recent than the gmt time in the clock, 127 * then use the filesystem time and warn the user. 128 */ 129 if (!bbc_to_gmt(&timbuf) || timbuf < base) { 130 printf("WARNING: bad date in battery clock\n"); 131 timbuf = base; 132 } 133 if (base < 5*SECYR) { 134 printf("WARNING: preposterous time in file system"); 135 timbuf = 6*SECYR + 186*SECDAY + SECDAY/2; 136 printf(" -- CHECK AND RESET THE DATE!\n"); 137 } 138 139 /* Battery clock does not store usec's, so forget about it. */ 140 time.tv_sec = timbuf; 141 } 142 143 resettodr() 144 { 145 register int i,s; 146 register struct bbc_tm *tmptr; 147 148 tmptr = gmt_to_bbc(time.tv_sec); 149 150 s = splimp(); 151 152 /* set bb-clock */ 153 #ifdef LUNA2 154 if (machineid == LUNA_II) { 155 bbc2->cal_sec = tmptr->tm_sec; 156 bbc2->cal_min = tmptr->tm_min; 157 bbc2->cal_hour =tmptr->tm_hour; 158 bbc2->cal_day = tmptr->tm_mday; 159 bbc2->cal_mon = tmptr->tm_mon; 160 bbc2->cal_year = tmptr->tm_year; 161 } else 162 #endif 163 { 164 bbc->cal_ctl |= BBC_WRT; 165 bbc->cal_sec = binary_to_bcd(tmptr->tm_sec); 166 bbc->cal_min = binary_to_bcd(tmptr->tm_min); 167 bbc->cal_hour = binary_to_bcd(tmptr->tm_hour); 168 bbc->cal_day = binary_to_bcd(tmptr->tm_mday); 169 bbc->cal_mon = binary_to_bcd(tmptr->tm_mon); 170 bbc->cal_year = binary_to_bcd(tmptr->tm_year); 171 bbc->cal_ctl &= ~BBC_WRT; 172 } 173 174 splx(s); 175 } 176 177 struct bbc_tm * 178 gmt_to_bbc(tim) 179 long tim; 180 { 181 register int i; 182 register long hms, day; 183 static struct bbc_tm rt; 184 185 day = tim / SECDAY; 186 hms = tim % SECDAY; 187 188 /* Hours, minutes, seconds are easy */ 189 rt.tm_hour = hms / 3600; 190 rt.tm_min = (hms % 3600) / 60; 191 rt.tm_sec = (hms % 3600) % 60; 192 193 /* Number of years in days */ 194 for (i = STARTOFTIME - 1900; day >= days_in_year(i); i++) 195 day -= days_in_year(i); 196 rt.tm_year = i; 197 198 /* Number of months in days left */ 199 if (leapyear(rt.tm_year)) 200 days_in_month(FEBRUARY) = 29; 201 for (i = 1; day >= days_in_month(i); i++) 202 day -= days_in_month(i); 203 days_in_month(FEBRUARY) = 28; 204 rt.tm_mon = i; 205 206 /* Days are what is left over (+1) from all that. */ 207 rt.tm_mday = day + 1; 208 209 return(&rt); 210 } 211 212 bbc_to_gmt(timbuf) 213 u_long *timbuf; 214 { 215 register int i,s; 216 register u_long tmp; 217 int year, month, day, hour, min, sec; 218 219 if (!battery_clock) 220 return(0); 221 222 s = splimp(); 223 224 /* read bb-clock */ 225 #ifdef LUNA2 226 if (machineid == LUNA_II) { 227 sec = bbc2->cal_sec; 228 min = bbc2->cal_min; 229 hour = bbc2->cal_hour; 230 day = bbc2->cal_day; 231 month = bbc2->cal_mon; 232 year = bbc2->cal_year + 1900; 233 } else 234 #endif 235 { 236 bbc->cal_ctl |= BBC_RD; 237 sec = bcd_to_binary(bbc->cal_sec); 238 min = bcd_to_binary(bbc->cal_min); 239 hour = bcd_to_binary(bbc->cal_hour); 240 day = bcd_to_binary(bbc->cal_day); 241 month = bcd_to_binary(bbc->cal_mon); 242 year = bcd_to_binary(bbc->cal_year) + 1900; 243 bbc->cal_ctl &= ~BBC_RD; 244 } 245 246 splx(s); 247 248 range_test(hour, 0, 23); 249 range_test(day, 1, 31); 250 range_test(month, 1, 12); 251 #if 1 /* limitted 2000 now ... */ 252 range_test(year, STARTOFTIME, 2000); 253 #else 254 if (year < 1970) { 255 year += 100; 256 } 257 #endif 258 259 tmp = 0; 260 261 for (i = STARTOFTIME; i < year; i++) 262 tmp += days_in_year(i); 263 if (leapyear(year) && month > FEBRUARY) 264 tmp++; 265 266 for (i = 1; i < month; i++) 267 tmp += days_in_month(i); 268 269 tmp += (day - 1); 270 tmp = ((tmp * 24 + hour) * 60 + min) * 60 + sec; 271 272 *timbuf = tmp; 273 return(1); 274 } 275 276 batterychk() 277 { 278 static char btchkdata[] = "chk"; 279 280 #ifdef LUNA2 281 if (machineid == LUNA_II) { 282 /* not yet */ 283 battery_chkfg = 1; 284 battery_clock = 1; 285 return; 286 } 287 #endif 288 /* if already checked, return */ 289 if (battery_chkfg) 290 return; 291 292 battery_chkfg = 1; 293 if (badaddr((caddr_t)bbc, 2)) 294 return; 295 296 strcpy(bbc->nvram.nv_testwrite, btchkdata); 297 if (strncmp(bbc->nvram.nv_testwrite, btchkdata, sizeof(btchkdata))) { 298 printf("WARNING: calendar clock battery down\n"); 299 return; 300 } 301 battery_clock = 1; 302 return; 303 } 304 305 #define LUNA1_HZ 60 306 307 modify_clock_param() 308 { 309 extern int hz, tick, tickadj; 310 311 if (machineid == LUNA_I) { 312 hz = LUNA1_HZ; 313 tick = 1000000 / hz; 314 tickadj = 30000 / (60 * hz); /* can adjust 30ms in 60s */ 315 } 316 } 317