1 /* 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1992 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department, Ralph Campbell, and Kazumasa Utashiro of 9 * Software Research Associates, Inc. 10 * 11 * %sccs.include.redist.c% 12 * 13 * from: Utah $Hdr: clock.c 1.18 91/01/21$ 14 * 15 * @(#)clock.c 7.6 (Berkeley) 01/21/93 16 */ 17 18 #include <machine/fix_machine_type.h> 19 #include <machine/adrsmap.h> 20 21 #include <sys/param.h> 22 #include <sys/kernel.h> 23 24 #include <news3400/news3400/clockreg.h> 25 26 /* 27 * Machine-dependent clock routines. 28 * 29 * Startrtclock restarts the real-time clock, which provides 30 * hardclock interrupts to kern_clock.c. 31 * 32 * Inittodr initializes the time of day hardware which provides 33 * date functions. Its primary function is to use some file 34 * system information in case the hardare clock lost state. 35 * 36 * Resettodr restores the time of day hardware after a time change. 37 */ 38 39 /* 40 * We assume newhz is either stathz or profhz, and that neither will 41 * change after being set up above. Could recalculate intervals here 42 * but that would be a drag. 43 */ 44 void 45 setstatclockrate(newhz) 46 int newhz; 47 { 48 49 /* KU:XXX do something! */ 50 } 51 52 /* 53 * Set up the real-time and statistics clocks. Leave stathz 0 only if 54 * no alternative timer is available. 55 */ 56 cpu_initclocks() 57 { 58 59 /* 60 * Start the real-time clock. 61 */ 62 *(char *)ITIMER = IOCLOCK / 6144 / 100 - 1; 63 64 /* 65 * Enable the real-time clock. 66 */ 67 *(char *)INTEN0 |= (char)INTEN0_TIMINT; 68 } 69 70 /* 71 * This code is defunct after 2099. 72 * Will Unix still be here then?? 73 */ 74 static short dayyr[12] = { 75 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 76 }; 77 78 #define bcd_to_int(BCD) (i = BCD, (((i) >> 4) & 0xf) * 10 + ((i) & 0xf)) 79 #define int_to_bcd(INT) (i = INT, ((((i) / 10) % 10) << 4) + (i) % 10) 80 81 /* 82 * Initialze the time of day register, based on the time base which is, e.g. 83 * from a filesystem. Base provides the time to within six months, 84 * and the time of year clock (if any) provides the rest. 85 */ 86 inittodr(base) 87 time_t base; 88 { 89 register volatile u_char *rtc_port = (u_char *)RTC_PORT; 90 register volatile u_char *rtc_data = (u_char *)DATA_PORT; 91 register int days, yr; 92 int sec, min, hour, week, day, mon, year; 93 long deltat, badbase = 0; 94 register u_int i; 95 96 if (base < 5*SECYR) { 97 printf("WARNING: preposterous time in file system\n"); 98 /* read the system clock anyway */ 99 base = 6*SECYR + 186*SECDAY + SECDAY/2; 100 badbase = 1; 101 } 102 103 *rtc_port = READ_CLOCK; 104 sec = bcd_to_int(*rtc_data++); 105 min = bcd_to_int(*rtc_data++); 106 hour = bcd_to_int(*rtc_data++); 107 week = bcd_to_int(*rtc_data++); 108 day = bcd_to_int(*rtc_data++); 109 mon = bcd_to_int(*rtc_data++); 110 year = bcd_to_int(*rtc_data++); 111 *rtc_port = 0; 112 113 /* simple sanity checks */ 114 if (year < 70 || mon < 1 || mon > 12 || day < 1 || day > 31 || 115 hour > 23 || min > 59 || sec > 59) { 116 printf("WARNING: preposterous clock chip time\n"); 117 /* 118 * Believe the time in the file system for lack of 119 * anything better, resetting the TODR. 120 */ 121 time.tv_sec = base; 122 if (!badbase) 123 resettodr(); 124 return (0); 125 } 126 days = 0; 127 for (yr = 70; yr < year; yr++) 128 days += LEAPYEAR(yr) ? 366 : 365; 129 days += dayyr[mon - 1] + day - 1; 130 if (LEAPYEAR(yr) && mon > 2) 131 days++; 132 /* now have days since Jan 1, 1970; the rest is easy... */ 133 time.tv_sec = days * SECDAY + hour * 3600 + min * 60 + sec; 134 135 if (!badbase) { 136 /* 137 * See if we gained/lost two or more days; 138 * if so, assume something is amiss. 139 */ 140 deltat = time.tv_sec - base; 141 if (deltat < 0) 142 deltat = -deltat; 143 if (deltat < 2 * SECDAY) 144 return; 145 printf("WARNING: clock %s %d days", 146 time.tv_sec < base ? "lost" : "gained", deltat / SECDAY); 147 } 148 printf(" -- CHECK AND RESET THE DATE!\n"); 149 } 150 151 /* 152 * Reset the TODR based on the time value; used when the TODR 153 * has a preposterous value and also when the time is reset 154 * by the stime system call. Also called when the TODR goes past 155 * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight) 156 * to wrap the TODR around. 157 */ 158 resettodr() 159 { 160 register volatile u_char *rtc_port = (u_char *)RTC_PORT; 161 register volatile u_char *rtc_data = (u_char *)DATA_PORT; 162 int sec, min, hour, week, day, mon, year; 163 register int t, t2, t3; 164 register int i; 165 166 /* compute the year */ 167 t2 = time.tv_sec / SECDAY; 168 t = 69; 169 while (t2 >= 0) { /* whittle off years */ 170 t3 = t2; 171 t++; 172 t2 -= LEAPYEAR(t) ? 366 : 365; 173 } 174 175 year = t; 176 177 /* t3 = month + day; separate */ 178 t = LEAPYEAR(t); 179 for (t2 = 1; t2 < 12; t2++) 180 if (t3 < dayyr[t2] + (t && t2 > 1)) 181 break; 182 183 /* t2 is month */ 184 mon = t2; 185 t3 = t3 - dayyr[t2 - 1] + 1; 186 if (t && t2 > 2) 187 t3--; 188 day = t3; 189 190 week = 0; 191 192 /* the rest is easy */ 193 t = time.tv_sec % SECDAY; 194 hour = t / 3600; 195 t %= 3600; 196 min = t / 60; 197 sec = t % 60; 198 199 *rtc_port = SET_CLOCK; 200 *rtc_data++ = int_to_bcd(sec); 201 *rtc_data++ = int_to_bcd(min); 202 *rtc_data++ = int_to_bcd(hour); 203 *rtc_data++ = int_to_bcd(week); 204 *rtc_data++ = int_to_bcd(day); 205 *rtc_data++ = int_to_bcd(mon); 206 *rtc_data = int_to_bcd(year); 207 *rtc_port = 0; 208 } 209