1 /* $NetBSD: rtc.c,v 1.3 2000/01/17 04:06:06 sato Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 Shin Takemura. All rights reserved. 5 * Copyright (c) 1999 SATO Kazumi. All rights reserved. 6 * Copyright (c) 1999 PocketBSD Project. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the PocketBSD project 19 * and its contributors. 20 * 4. Neither the name of the project nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/device.h> 41 #include <sys/reboot.h> 42 43 #include <machine/bus.h> 44 #include <machine/clock_machdep.h> 45 #include <machine/cpu.h> 46 47 #include <hpcmips/vr/vr.h> 48 #include <hpcmips/vr/vripvar.h> 49 #include <hpcmips/vr/rtcreg.h> 50 #include <dev/dec/clockvar.h> 51 52 /* 53 * for debugging definitions 54 * RTCDEBUG print rtc debugging infomation 55 * RTC_HEARTBEAT print HEARTBEAT (too many print...) 56 */ 57 58 struct vrrtc_softc { 59 struct device sc_dev; 60 bus_space_tag_t sc_iot; 61 bus_space_handle_t sc_ioh; 62 void *sc_ih; 63 }; 64 65 void clock_init __P((struct device *)); 66 void clock_get __P((struct device *, time_t, struct clocktime *)); 67 void clock_set __P((struct device *, struct clocktime *)); 68 69 static const struct clockfns clockfns = { 70 clock_init, clock_get, clock_set, 71 }; 72 73 int vrrtc_match __P((struct device *, struct cfdata *, void *)); 74 void vrrtc_attach __P((struct device *, struct device *, void *)); 75 int vrrtc_intr __P((void*, u_int32_t, u_int32_t)); 76 77 struct cfattach vrrtc_ca = { 78 sizeof(struct vrrtc_softc), vrrtc_match, vrrtc_attach 79 }; 80 81 void vrrtc_write __P((struct vrrtc_softc *, int, unsigned short)); 82 unsigned short vrrtc_read __P((struct vrrtc_softc *, int)); 83 void cvt_timehl_ct __P((u_long, u_long, struct clocktime *)); 84 85 extern int rtc_offset; 86 87 int 88 vrrtc_match(parent, cf, aux) 89 struct device *parent; 90 struct cfdata *cf; 91 void *aux; 92 { 93 return(1); 94 } 95 96 inline void 97 vrrtc_write(sc, port, val) 98 struct vrrtc_softc *sc; 99 int port; 100 unsigned short val; 101 { 102 bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val); 103 } 104 105 inline unsigned short 106 vrrtc_read(sc, port) 107 struct vrrtc_softc *sc; 108 int port; 109 { 110 return bus_space_read_2(sc->sc_iot, sc->sc_ioh, port); 111 } 112 113 void 114 vrrtc_attach(parent, self, aux) 115 struct device *parent; 116 struct device *self; 117 void *aux; 118 { 119 struct vrip_attach_args *va = aux; 120 struct vrrtc_softc *sc = (void*)self; 121 122 sc->sc_iot = va->va_iot; 123 if (bus_space_map(sc->sc_iot, va->va_addr, va->va_size, 124 0 /* no flags */, &sc->sc_ioh)) { 125 printf("vrrtc_attach: can't map i/o space\n"); 126 return; 127 } 128 /* RTC interrupt handler is directly dispatched from CPU intr */ 129 vr_intr_establish(VR_INTR1, vrrtc_intr, sc); 130 /* But need to set level 1 interupt mask register, 131 * so regsiter fake interrurpt handler 132 */ 133 if (!(sc->sc_ih = vrip_intr_establish(va->va_vc, va->va_intr, 134 IPL_CLOCK, 0, 0))) { 135 printf (":can't map interrupt.\n"); 136 return; 137 } 138 /* 139 * Rtc is attached to call this routine 140 * before cpu_initclock() calls clock_init(). 141 * So we must disable all interrupt for now. 142 */ 143 /* 144 * Disable all rtc interrupts 145 */ 146 /* Disable Elapse compare intr */ 147 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECMP_H_REG_W, 0); 148 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECMP_M_REG_W, 0); 149 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECMP_L_REG_W, 0); 150 /* Disable RTC Long1 intr */ 151 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL1_H_REG_W, 0); 152 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL1_L_REG_W, 0); 153 /* Disable RTC Long2 intr */ 154 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL2_H_REG_W, 0); 155 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL2_L_REG_W, 0); 156 /* Disable RTC TCLK intr */ 157 bus_space_write_2(sc->sc_iot, sc->sc_ioh, TCLK_H_REG_W, 0); 158 bus_space_write_2(sc->sc_iot, sc->sc_ioh, TCLK_L_REG_W, 0); 159 /* 160 * Clear all rtc intrrupts. 161 */ 162 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCINT_REG_W, RTCINT_ALL); 163 164 clockattach(&sc->sc_dev, &clockfns); 165 } 166 167 int 168 vrrtc_intr(arg, pc, statusReg) 169 void *arg; 170 u_int32_t pc; 171 u_int32_t statusReg; 172 { 173 struct vrrtc_softc *sc = arg; 174 struct clockframe cf; 175 176 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCINT_REG_W, RTCINT_ALL); 177 cf.pc = pc; 178 cf.sr = statusReg; 179 hardclock(&cf); 180 intrcnt[HARDCLOCK]++; 181 182 #ifdef RTC_HEARTBEAT 183 if ((intrcnt[HARDCLOCK] % (CLOCK_RATE * 5)) == 0) { 184 struct clocktime ct; 185 clock_get((struct device *)sc, NULL, &ct); 186 printf("%s(%d): rtc_intr: %2d.%2d.%2d %02d:%02d:%02d\n", 187 __FILE__, __LINE__, 188 ct.year, ct.mon, ct.day, 189 ct.hour, ct.min, ct.sec); 190 } 191 #endif 192 return 0; 193 } 194 195 void 196 clock_init(dev) 197 struct device *dev; 198 { 199 struct vrrtc_softc *sc = (struct vrrtc_softc *)dev; 200 #ifdef RTCDEBUG 201 int timeh; 202 int timel; 203 204 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_H_REG_W); 205 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_M_REG_W); 206 timel = (timel << 16) 207 | bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_L_REG_W); 208 printf("clock_init() Elapse Time %04x%04x\n", timeh, timel); 209 210 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ECMP_H_REG_W); 211 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ECMP_M_REG_W); 212 timel = (timel << 16) 213 | bus_space_read_2(sc->sc_iot, sc->sc_ioh, ECMP_L_REG_W); 214 printf("clock_init() Elapse Compare %04x%04x\n", timeh, timel); 215 216 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_H_REG_W); 217 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_L_REG_W); 218 printf("clock_init() LONG1 %04x%04x\n", timeh, timel); 219 220 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_CNT_H_REG_W); 221 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_CNT_L_REG_W); 222 printf("clock_init() LONG1 CNTL %04x%04x\n", timeh, timel); 223 224 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_H_REG_W); 225 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_L_REG_W); 226 printf("clock_init() LONG2 %04x%04x\n", timeh, timel); 227 228 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_CNT_H_REG_W); 229 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_CNT_L_REG_W); 230 printf("clock_init() LONG2 CNTL %04x%04x\n", timeh, timel); 231 232 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, TCLK_H_REG_W); 233 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, TCLK_L_REG_W); 234 printf("clock_init() TCLK %04x%04x\n", timeh, timel); 235 236 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, TCLK_CNT_H_REG_W); 237 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, TCLK_CNT_L_REG_W); 238 printf("clock_init() TCLK CNTL %04x%04x\n", timeh, timel); 239 #endif /* RTCDEBUG */ 240 /* 241 * Set tick (CLOCK_RATE) 242 */ 243 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL1_H_REG_W, 0); 244 bus_space_write_2(sc->sc_iot, sc->sc_ioh, 245 RTCL1_L_REG_W, RTCL1_L_HZ/CLOCK_RATE); 246 } 247 248 static int m2d[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 249 250 void 251 cvt_timehl_ct(timeh, timel, ct) 252 u_long timeh; /* 2 sec */ 253 u_long timel; /* 1/32768 sec */ 254 struct clocktime *ct; 255 { 256 u_long year, month, date, hour, min, sec, sec2; 257 258 timeh -= EPOCHOFF; 259 260 timeh += (rtc_offset*SEC2MIN); 261 262 year = EPOCHYEAR; 263 sec2 = LEAPYEAR4(year)?SEC2YR+SEC2DAY:SEC2YR; 264 while (timeh > sec2) { 265 year++; 266 timeh -= sec2; 267 sec2 = LEAPYEAR4(year)?SEC2YR+SEC2DAY:SEC2YR; 268 } 269 270 #ifdef RTCDEBUG 271 printf("cvt_timehl_ct: timeh %08lx year %ld yrref %ld\n", 272 timeh, year, sec2); 273 #endif /* RTCDEBUG */ 274 275 month = 0; /* now month is 0..11 */ 276 sec2 = SEC2DAY * m2d[month]; 277 while (timeh > sec2) { 278 timeh -= sec2; 279 month++; 280 sec2 = SEC2DAY * m2d[month]; 281 if (month == 1 && LEAPYEAR4(year)) /* feb. and leapyear */ 282 sec2 += SEC2DAY; 283 } 284 month +=1; /* now month is 1..12 */ 285 286 #ifdef RTCDEBUG 287 printf("cvt_timehl_ct: timeh %08lx month %ld mref %ld\n", 288 timeh, month, sec2); 289 #endif /* RTCDEBUG */ 290 291 sec2 = SEC2DAY; 292 date = timeh/sec2+1; /* date is 1..31 */ 293 timeh -= (date-1)*sec2; 294 295 #ifdef RTCDEBUG 296 printf("cvt_timehl_ct: timeh %08lx date %ld dref %ld\n", 297 timeh, date, sec2); 298 #endif /* RTCDEBUG */ 299 300 sec2 = SEC2HOUR; 301 hour = timeh/sec2; 302 timeh -= hour*sec2; 303 304 sec2 = SEC2MIN; 305 min = timeh/sec2; 306 timeh -= min*sec2; 307 308 sec = timeh*2 + timel/ETIME_L_HZ; 309 310 #ifdef RTCDEBUG 311 printf("cvt_timehl_ct: hour %ld min %ld sec %ld\n", hour, min, sec); 312 #endif /* RTCDEBUG */ 313 314 if (ct) { 315 ct->year = year - YBASE; /* base 1900 */ 316 ct->mon = month; 317 ct->day = date; 318 ct->hour = hour; 319 ct->min = min; 320 ct->sec = sec; 321 } 322 } 323 324 void 325 clock_get(dev, base, ct) 326 struct device *dev; 327 time_t base; 328 struct clocktime *ct; 329 { 330 331 struct vrrtc_softc *sc = (struct vrrtc_softc *)dev; 332 u_long timeh; /* elapse time (2*timeh sec) */ 333 u_long timel; /* timel/32768 sec */ 334 335 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_H_REG_W); 336 timeh = (timeh << 16) 337 | bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_M_REG_W); 338 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_L_REG_W); 339 340 #ifdef RTCDEBUG 341 printf("clock_get: timeh %08lx timel %08lx\n", timeh, timel); 342 #endif /* RTCDEBUG */ 343 344 cvt_timehl_ct(timeh, timel, ct); 345 346 #ifdef RTCDEBUG 347 printf("clock_get: %d/%d/%d/%d/%d/%d\n", 348 ct->year, ct->mon, ct->day, ct->hour, ct->min, ct->sec); 349 #endif /* RTCDEBUG */ 350 } 351 352 353 void 354 clock_set(dev, ct) 355 struct device *dev; 356 struct clocktime *ct; 357 { 358 struct vrrtc_softc *sc = (struct vrrtc_softc *)dev; 359 u_long timeh; /* elapse time (2*timeh sec) */ 360 u_long timel; /* timel/32768 sec */ 361 int year, month, sec2; 362 363 timeh = 0; 364 timel = 0; 365 366 #ifdef RTCDEBUG 367 printf("clock_set: %d/%d/%d/%d/%d/%d\n", 368 ct->year, ct->mon, ct->day, ct->hour, ct->min, ct->sec); 369 #endif /* RTCDEBUG */ 370 ct->year += YBASE; 371 #ifdef RTCDEBUG 372 printf("clock_set: %d/%d/%d/%d/%d/%d\n", 373 ct->year, ct->mon, ct->day, ct->hour, ct->min, ct->sec); 374 #endif /* RTCDEBUG */ 375 year = EPOCHYEAR; 376 sec2 = LEAPYEAR4(year)?SEC2YR+SEC2DAY:SEC2YR; 377 while (year < ct->year) { 378 year++; 379 timeh += sec2; 380 sec2 = LEAPYEAR4(year)?SEC2YR+SEC2DAY:SEC2YR; 381 } 382 month = 1; /* now month is 1..12 */ 383 sec2 = SEC2DAY * m2d[month-1]; 384 while (month < ct->mon) { 385 month++; 386 timeh += sec2; 387 sec2 = SEC2DAY * m2d[month-1]; 388 if (month == 2 && LEAPYEAR4(year)) /* feb. and leapyear */ 389 sec2 += SEC2DAY; 390 } 391 392 timeh += (ct->day - 1)*SEC2DAY; 393 394 timeh += ct->hour*SEC2HOUR; 395 396 timeh += ct->min*SEC2MIN; 397 398 timeh += ct->sec/2; 399 timel += (ct->sec%2)*ETIME_L_HZ; 400 401 timeh += EPOCHOFF; 402 timeh -= (rtc_offset*SEC2MIN); 403 404 #ifdef RTCDEBUG 405 cvt_timehl_ct(timeh, timel, NULL); 406 #endif /* RTCDEBUG */ 407 408 bus_space_write_2(sc->sc_iot, sc->sc_ioh, 409 ETIME_H_REG_W, (timeh>>16)&0xffff); 410 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ETIME_M_REG_W, timeh&0xffff); 411 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ETIME_L_REG_W, timel); 412 413 } 414 415