1 /*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * William Jolitz. 7 * 8 * Added stuff to read the cmos clock on startup - Don Ahn 9 * 10 * %sccs.include.386.c% 11 * 12 * @(#)clock.c 5.5 (Berkeley) 05/09/91 13 */ 14 15 /* 16 * Primitive clock interrupt routines. 17 */ 18 #include "param.h" 19 #include "time.h" 20 #include "kernel.h" 21 #include "machine/segments.h" 22 #include "i386/isa/icu.h" 23 #include "i386/isa/isa.h" 24 #include "i386/isa/rtc.h" 25 26 #define DAYST 119 27 #define DAYEN 303 28 29 startrtclock() { 30 int s; 31 32 /* initialize 8253 clock */ 33 outb (IO_TIMER1+3, 0x36); 34 outb (IO_TIMER1, 1193182/hz); 35 outb (IO_TIMER1, (1193182/hz)/256); 36 37 #ifdef notdef 38 /* NMI fail safe 1/4 sec */ 39 /* initialize 8253 clock */ 40 outb(0x461,0); 41 outb (IO_TIMER2+3, 0x30); 42 outb (IO_TIMER2, 298300*40); 43 outb (IO_TIMER2, (298300*40)/256); 44 outb(0x461,4); 45 printf("armed "); 46 #endif 47 48 /* initialize brain-dead battery powered clock */ 49 outb (IO_RTC, RTC_STATUSA); 50 outb (IO_RTC+1, 0x26); 51 outb (IO_RTC, RTC_STATUSB); 52 outb (IO_RTC+1, 2); 53 54 /*outb (IO_RTC, RTC_STATUSD); 55 if((inb(IO_RTC+1) & 0x80) == 0) 56 printf("rtc lost power\n"); 57 outb (IO_RTC, RTC_STATUSD); 58 outb (IO_RTC+1, 0x80);*/ 59 60 outb (IO_RTC, RTC_DIAG); 61 if (s = inb (IO_RTC+1)) 62 printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS); 63 outb (IO_RTC, RTC_DIAG); 64 outb (IO_RTC+1, 0); 65 } 66 67 #ifdef ARGOx 68 reprimefailsafe(){ 69 outb(0x461,0); 70 outb (IO_TIMER2+3, 0x30); 71 outb (IO_TIMER2, 298300*40); 72 outb (IO_TIMER2, (298300*40)/256); 73 outb(0x461,4); 74 } 75 #endif 76 77 /* convert 2 digit BCD number */ 78 bcd(i) 79 int i; 80 { 81 return ((i/16)*10 + (i%16)); 82 } 83 84 /* convert years to seconds (from 1970) */ 85 unsigned long 86 ytos(y) 87 int y; 88 { 89 int i; 90 unsigned long ret; 91 92 ret = 0; y = y - 70; 93 for(i=0;i<y;i++) { 94 if (i % 4) ret += 365*24*60*60; 95 else ret += 366*24*60*60; 96 } 97 return ret; 98 } 99 100 /* convert months to seconds */ 101 unsigned long 102 mtos(m,leap) 103 int m,leap; 104 { 105 int i; 106 unsigned long ret; 107 108 ret = 0; 109 for(i=1;i<m;i++) { 110 switch(i){ 111 case 1: case 3: case 5: case 7: case 8: case 10: case 12: 112 ret += 31*24*60*60; break; 113 case 4: case 6: case 9: case 11: 114 ret += 30*24*60*60; break; 115 case 2: 116 if (leap) ret += 29*24*60*60; 117 else ret += 28*24*60*60; 118 } 119 } 120 return ret; 121 } 122 123 124 /* 125 * Initialize the time of day register, based on the time base which is, e.g. 126 * from a filesystem. 127 */ 128 inittodr(base) 129 time_t base; 130 { 131 unsigned long sec; 132 int leap,day_week,t,yd; 133 int sa,s; 134 135 /* do we have a realtime clock present? (otherwise we loop below) */ 136 sa = rtcin(RTC_STATUSA); 137 if (sa == 0xff || sa == 0) return; 138 139 /* ready for a read? */ 140 while ((sa&RTCSA_TUP) == RTCSA_TUP) 141 sa = rtcin(RTC_STATUSA); 142 143 sec = bcd(rtcin(RTC_YEAR)); 144 leap = !(sec % 4); sec += ytos(sec); /* year */ 145 yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec += yd; /* month */ 146 t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec += t; yd += t; /* date */ 147 day_week = rtcin(RTC_WDAY); /* day */ 148 sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */ 149 sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */ 150 sec += bcd(rtcin(RTC_SEC)); /* seconds */ 151 sec -= 24*60*60; /* XXX why ??? */ 152 153 #ifdef notdef 154 /* XXX off by one? Need to calculate DST on SUNDAY */ 155 /* Perhaps we should have the RTC hold GMT time to save */ 156 /* us the bother of converting. */ 157 yd = yd / 24*60*60; 158 if ((yd >= DAYST) && ( yd <= DAYEN)) { 159 sec -= 60*60; 160 } 161 #endif 162 sec += tz.tz_minuteswest * 60; 163 164 time.tv_sec = sec; 165 } 166 167 #ifdef garbage 168 /* 169 * Initialze the time of day register, based on the time base which is, e.g. 170 * from a filesystem. 171 */ 172 test_inittodr(base) 173 time_t base; 174 { 175 176 outb(IO_RTC,9); /* year */ 177 printf("%d ",bcd(inb(IO_RTC+1))); 178 outb(IO_RTC,8); /* month */ 179 printf("%d ",bcd(inb(IO_RTC+1))); 180 outb(IO_RTC,7); /* day */ 181 printf("%d ",bcd(inb(IO_RTC+1))); 182 outb(IO_RTC,4); /* hour */ 183 printf("%d ",bcd(inb(IO_RTC+1))); 184 outb(IO_RTC,2); /* minutes */ 185 printf("%d ",bcd(inb(IO_RTC+1))); 186 outb(IO_RTC,0); /* seconds */ 187 printf("%d\n",bcd(inb(IO_RTC+1))); 188 189 time.tv_sec = base; 190 } 191 #endif 192 193 #ifdef notdef 194 /* 195 * retreve a value from realtime clock 196 */ 197 u_char rtcin(n) { 198 u_char val; 199 200 /*outb(IO_RTC, RTC_STATUSA); 201 do val = inb(IO_RTC+1) ; while (val&0x80);*/ 202 203 outb(IO_RTC,n); 204 DELAY(100); 205 if (inb(IO_RTC) != n) { 206 outb(IO_RTC,n); 207 DELAY(100); 208 } 209 do val = inb(IO_RTC+1) ; while (val != inb(IO_RTC+1)); 210 return (val); 211 } 212 #endif 213 214 /* 215 * Restart the clock. 216 */ 217 resettodr() 218 { 219 } 220 221 #define V(s) __CONCAT(V, s) 222 extern V(clk)(); 223 enablertclock() { 224 INTREN(IRQ0); 225 setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL); 226 splnone(); 227 } 228