1 /* $NetBSD: rtc.c,v 1.14 2002/02/10 14:15:32 takemura 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 "opt_vr41xx.h" 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 43 #include <machine/sysconf.h> 44 #include <machine/bus.h> 45 46 #include <dev/clock_subr.h> 47 48 #include <hpcmips/vr/vr.h> 49 #include <hpcmips/vr/vrcpudef.h> 50 #include <hpcmips/vr/vripif.h> 51 #include <hpcmips/vr/vripreg.h> 52 #include <hpcmips/vr/rtcreg.h> 53 54 /* 55 * for debugging definitions 56 * VRRTCDEBUG print rtc debugging information 57 * VRRTC_HEARTBEAT print HEARTBEAT (too many print...) 58 */ 59 #ifdef VRRTCDEBUG 60 #ifndef VRRTCDEBUG_CONF 61 #define VRRTCDEBUG_CONF 0 62 #endif 63 int vrrtc_debug = VRRTCDEBUG_CONF; 64 #define DPRINTF(arg) if (vrrtc_debug) printf arg; 65 #define DDUMP_REGS(arg) if (vrrtc_debug) vrrtc_dump_regs(arg); 66 #else /* VRRTCDEBUG */ 67 #define DPRINTF(arg) 68 #define DDUMP_REGS(arg) 69 #endif /* VRRTCDEBUG */ 70 71 struct vrrtc_softc { 72 struct device sc_dev; 73 bus_space_tag_t sc_iot; 74 bus_space_handle_t sc_ioh; 75 void *sc_ih; 76 #ifndef SINGLE_VRIP_BASE 77 int sc_rtcint_reg; 78 int sc_tclk_h_reg, sc_tclk_l_reg; 79 int sc_tclk_cnt_h_reg, sc_tclk_cnt_l_reg; 80 #endif /* SINGLE_VRIP_BASE */ 81 }; 82 83 void clock_init(struct device *); 84 void clock_get(struct device *, time_t, struct clock_ymdhms *); 85 void clock_set(struct device *, struct clock_ymdhms *); 86 87 struct platform_clock vr_clock = { 88 #define CLOCK_RATE 128 89 CLOCK_RATE, clock_init, clock_get, clock_set, 90 }; 91 92 int vrrtc_match(struct device *, struct cfdata *, void *); 93 void vrrtc_attach(struct device *, struct device *, void *); 94 int vrrtc_intr(void*, u_int32_t, u_int32_t); 95 void vrrtc_dump_regs(struct vrrtc_softc *); 96 97 struct cfattach vrrtc_ca = { 98 sizeof(struct vrrtc_softc), vrrtc_match, vrrtc_attach 99 }; 100 101 static __inline__ void vrrtc_write(struct vrrtc_softc *, int, u_int16_t); 102 static __inline__ u_int16_t vrrtc_read(struct vrrtc_softc *, int); 103 void cvt_timehl_ymdhms(u_int32_t, u_int32_t, struct clock_ymdhms *); 104 105 extern int rtc_offset; 106 static int m2d[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 107 108 static __inline__ void 109 vrrtc_write(struct vrrtc_softc *sc, int port, u_int16_t val) 110 { 111 112 bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val); 113 } 114 115 static __inline__ u_int16_t 116 vrrtc_read(struct vrrtc_softc *sc, int port) 117 { 118 119 return (bus_space_read_2(sc->sc_iot, sc->sc_ioh, port)); 120 } 121 122 int 123 vrrtc_match(struct device *parent, struct cfdata *cf, void *aux) 124 { 125 126 return (1); 127 } 128 129 #ifndef SINGLE_VRIP_BASE 130 #define RTCINT_REG_W (sc->sc_rtcint_reg) 131 #define TCLK_H_REG_W (sc->sc_tclk_h_reg) 132 #define TCLK_L_REG_W (sc->sc_tclk_l_reg) 133 #define TCLK_CNT_H_REG_W (sc->sc_tclk_cnt_h_reg) 134 #define TCLK_CNT_L_REG_W (sc->sc_tclk_cnt_l_reg) 135 #endif /* SINGLE_VRIP_BASE */ 136 137 void 138 vrrtc_attach(struct device *parent, struct device *self, void *aux) 139 { 140 struct vrip_attach_args *va = aux; 141 struct vrrtc_softc *sc = (void *)self; 142 143 #ifndef SINGLE_VRIP_BASE 144 if (va->va_addr == VR4102_RTC_ADDR) { 145 sc->sc_rtcint_reg = VR4102_RTCINT_REG_W; 146 sc->sc_tclk_h_reg = VR4102_TCLK_H_REG_W; 147 sc->sc_tclk_l_reg = VR4102_TCLK_L_REG_W; 148 sc->sc_tclk_cnt_h_reg = VR4102_TCLK_CNT_H_REG_W; 149 sc->sc_tclk_cnt_l_reg = VR4102_TCLK_CNT_L_REG_W; 150 } else 151 if (va->va_addr == VR4122_RTC_ADDR) { 152 sc->sc_rtcint_reg = VR4122_RTCINT_REG_W; 153 sc->sc_tclk_h_reg = VR4122_TCLK_H_REG_W; 154 sc->sc_tclk_l_reg = VR4122_TCLK_L_REG_W; 155 sc->sc_tclk_cnt_h_reg = VR4122_TCLK_CNT_H_REG_W; 156 sc->sc_tclk_cnt_l_reg = VR4122_TCLK_CNT_L_REG_W; 157 } else 158 if (va->va_addr == VR4181_RTC_ADDR) { 159 sc->sc_rtcint_reg = VR4181_RTCINT_REG_W; 160 sc->sc_tclk_h_reg = RTC_NO_REG_W; 161 sc->sc_tclk_l_reg = RTC_NO_REG_W; 162 sc->sc_tclk_cnt_h_reg = RTC_NO_REG_W; 163 sc->sc_tclk_cnt_l_reg = RTC_NO_REG_W; 164 } else { 165 panic("%s: unknown base address 0x%lx\n", 166 sc->sc_dev.dv_xname, va->va_addr); 167 } 168 #endif /* SINGLE_VRIP_BASE */ 169 170 sc->sc_iot = va->va_iot; 171 if (bus_space_map(sc->sc_iot, va->va_addr, va->va_size, 172 0 /* no flags */, &sc->sc_ioh)) { 173 printf("vrrtc_attach: can't map i/o space\n"); 174 return; 175 } 176 /* RTC interrupt handler is directly dispatched from CPU intr */ 177 vr_intr_establish(VR_INTR1, vrrtc_intr, sc); 178 /* But need to set level 1 interupt mask register, 179 * so regsiter fake interrurpt handler 180 */ 181 if (!(sc->sc_ih = vrip_intr_establish(va->va_vc, va->va_unit, 0, 182 IPL_CLOCK, 0, 0))) { 183 printf (":can't map interrupt.\n"); 184 return; 185 } 186 /* 187 * Rtc is attached to call this routine 188 * before cpu_initclock() calls clock_init(). 189 * So we must disable all interrupt for now. 190 */ 191 /* 192 * Disable all rtc interrupts 193 */ 194 /* Disable Elapse compare intr */ 195 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECMP_H_REG_W, 0); 196 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECMP_M_REG_W, 0); 197 bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECMP_L_REG_W, 0); 198 /* Disable RTC Long1 intr */ 199 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL1_H_REG_W, 0); 200 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL1_L_REG_W, 0); 201 /* Disable RTC Long2 intr */ 202 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL2_H_REG_W, 0); 203 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL2_L_REG_W, 0); 204 /* Disable RTC TCLK intr */ 205 if (TCLK_H_REG_W != RTC_NO_REG_W) { 206 bus_space_write_2(sc->sc_iot, sc->sc_ioh, TCLK_H_REG_W, 0); 207 bus_space_write_2(sc->sc_iot, sc->sc_ioh, TCLK_L_REG_W, 0); 208 } 209 /* 210 * Clear all rtc intrrupts. 211 */ 212 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCINT_REG_W, RTCINT_ALL); 213 214 platform_clock_attach(sc, &vr_clock); 215 } 216 217 int 218 vrrtc_intr(void *arg, u_int32_t pc, u_int32_t statusReg) 219 { 220 struct vrrtc_softc *sc = arg; 221 struct clockframe cf; 222 223 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCINT_REG_W, RTCINT_ALL); 224 cf.pc = pc; 225 cf.sr = statusReg; 226 hardclock(&cf); 227 intrcnt[HARDCLOCK]++; 228 229 #ifdef VRRTC_HEARTBEAT 230 if ((intrcnt[HARDCLOCK] % (CLOCK_RATE * 5)) == 0) { 231 struct clock_ymdhms dt; 232 clock_get((struct device *)sc, NULL, &dt); 233 printf("%s(%d): rtc_intr: %2d.%2d.%2d %02d:%02d:%02d\n", 234 __FILE__, __LINE__, 235 dt.dt_year, dt.dt_mon, dt.dt_day, 236 dt.dt_hour, dt.dt_min, dt.dt_sec); 237 } 238 #endif 239 return 0; 240 } 241 242 void 243 clock_init(struct device *dev) 244 { 245 struct vrrtc_softc *sc = (struct vrrtc_softc *)dev; 246 247 DDUMP_REGS(sc); 248 /* 249 * Set tick (CLOCK_RATE) 250 */ 251 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL1_H_REG_W, 0); 252 bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL1_L_REG_W, 253 RTCL1_L_HZ/CLOCK_RATE); 254 } 255 256 void 257 clock_get(struct device *dev, time_t base, struct clock_ymdhms *dt) 258 { 259 260 struct vrrtc_softc *sc = (struct vrrtc_softc *)dev; 261 bus_space_tag_t iot = sc->sc_iot; 262 bus_space_handle_t ioh = sc->sc_ioh; 263 u_int32_t timeh; /* elapse time (2*timeh sec) */ 264 u_int32_t timel; /* timel/32768 sec */ 265 266 timeh = bus_space_read_2(iot, ioh, ETIME_H_REG_W); 267 timeh = (timeh << 16) | bus_space_read_2(iot, ioh, ETIME_M_REG_W); 268 timel = bus_space_read_2(iot, ioh, ETIME_L_REG_W); 269 270 DPRINTF(("clock_get: timeh %08x timel %08x\n", timeh, timel)); 271 272 cvt_timehl_ymdhms(timeh, timel, dt); 273 274 DPRINTF(("clock_get: %d/%d/%d/%d/%d/%d\n", dt->dt_year, dt->dt_mon, 275 dt->dt_day, dt->dt_hour, dt->dt_min, dt->dt_sec)); 276 } 277 278 void 279 clock_set(struct device *dev, struct clock_ymdhms *dt) 280 { 281 struct vrrtc_softc *sc = (struct vrrtc_softc *)dev; 282 bus_space_tag_t iot = sc->sc_iot; 283 bus_space_handle_t ioh = sc->sc_ioh; 284 u_int32_t timeh; /* elapse time (2*timeh sec) */ 285 u_int32_t timel; /* timel/32768 sec */ 286 int year, month, sec2; 287 288 timeh = 0; 289 timel = 0; 290 291 DPRINTF(("clock_set: %d/%d/%d/%d/%d/%d\n", dt->dt_year, dt->dt_mon, 292 dt->dt_day, dt->dt_hour, dt->dt_min, dt->dt_sec)); 293 294 dt->dt_year += YBASE; 295 296 DPRINTF(("clock_set: %d/%d/%d/%d/%d/%d\n", dt->dt_year, dt->dt_mon, 297 dt->dt_day, dt->dt_hour, dt->dt_min, dt->dt_sec)); 298 299 year = EPOCHYEAR; 300 sec2 = LEAPYEAR4(year)?SEC2YR+SEC2DAY:SEC2YR; 301 while (year < dt->dt_year) { 302 year++; 303 timeh += sec2; 304 sec2 = LEAPYEAR4(year)?SEC2YR+SEC2DAY:SEC2YR; 305 } 306 month = 1; /* now month is 1..12 */ 307 sec2 = SEC2DAY * m2d[month-1]; 308 while (month < dt->dt_mon) { 309 month++; 310 timeh += sec2; 311 sec2 = SEC2DAY * m2d[month-1]; 312 if (month == 2 && LEAPYEAR4(year)) /* feb. and leapyear */ 313 sec2 += SEC2DAY; 314 } 315 316 timeh += (dt->dt_day - 1)*SEC2DAY; 317 318 timeh += dt->dt_hour*SEC2HOUR; 319 320 timeh += dt->dt_min*SEC2MIN; 321 322 timeh += dt->dt_sec/2; 323 timel += (dt->dt_sec%2)*ETIME_L_HZ; 324 325 timeh += EPOCHOFF; 326 timeh -= (rtc_offset*SEC2MIN); 327 328 #ifdef VRRTCDEBUG 329 cvt_timehl_ymdhms(timeh, timel, NULL); 330 #endif /* RTCDEBUG */ 331 332 bus_space_write_2(iot, ioh, ETIME_H_REG_W, (timeh >> 16) & 0xffff); 333 bus_space_write_2(iot, ioh, ETIME_M_REG_W, timeh & 0xffff); 334 bus_space_write_2(iot, ioh, ETIME_L_REG_W, timel); 335 } 336 337 void 338 cvt_timehl_ymdhms( 339 u_int32_t timeh, /* 2 sec */ 340 u_int32_t timel, /* 1/32768 sec */ 341 struct clock_ymdhms *dt) 342 { 343 u_int32_t year, month, date, hour, min, sec, sec2; 344 345 timeh -= EPOCHOFF; 346 347 timeh += (rtc_offset*SEC2MIN); 348 349 year = EPOCHYEAR; 350 sec2 = LEAPYEAR4(year)?SEC2YR+SEC2DAY:SEC2YR; 351 while (timeh > sec2) { 352 year++; 353 timeh -= sec2; 354 sec2 = LEAPYEAR4(year)?SEC2YR+SEC2DAY:SEC2YR; 355 } 356 357 DPRINTF(("cvt_timehl_ymdhms: timeh %08x year %d yrref %d\n", 358 timeh, year, sec2)); 359 360 month = 0; /* now month is 0..11 */ 361 sec2 = SEC2DAY * m2d[month]; 362 while (timeh > sec2) { 363 timeh -= sec2; 364 month++; 365 sec2 = SEC2DAY * m2d[month]; 366 if (month == 1 && LEAPYEAR4(year)) /* feb. and leapyear */ 367 sec2 += SEC2DAY; 368 } 369 month +=1; /* now month is 1..12 */ 370 371 DPRINTF(("cvt_timehl_ymdhms: timeh %08x month %d mref %d\n", 372 timeh, month, sec2)); 373 374 sec2 = SEC2DAY; 375 date = timeh/sec2+1; /* date is 1..31 */ 376 timeh -= (date-1)*sec2; 377 378 DPRINTF(("cvt_timehl_ymdhms: timeh %08x date %d dref %d\n", 379 timeh, date, sec2)); 380 381 sec2 = SEC2HOUR; 382 hour = timeh/sec2; 383 timeh -= hour*sec2; 384 385 sec2 = SEC2MIN; 386 min = timeh/sec2; 387 timeh -= min*sec2; 388 389 sec = timeh*2 + timel/ETIME_L_HZ; 390 391 DPRINTF(("cvt_timehl_ymdhms: hour %d min %d sec %d\n", hour, min, sec)); 392 393 if (dt) { 394 dt->dt_year = year - YBASE; /* base 1900 */ 395 dt->dt_mon = month; 396 dt->dt_day = date; 397 dt->dt_hour = hour; 398 dt->dt_min = min; 399 dt->dt_sec = sec; 400 } 401 } 402 403 void 404 vrrtc_dump_regs(struct vrrtc_softc *sc) 405 { 406 int timeh; 407 int timel; 408 409 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_H_REG_W); 410 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_M_REG_W); 411 timel = (timel << 16) 412 | bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_L_REG_W); 413 printf("clock_init() Elapse Time %04x%04x\n", timeh, timel); 414 415 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ECMP_H_REG_W); 416 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ECMP_M_REG_W); 417 timel = (timel << 16) 418 | bus_space_read_2(sc->sc_iot, sc->sc_ioh, ECMP_L_REG_W); 419 printf("clock_init() Elapse Compare %04x%04x\n", timeh, timel); 420 421 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_H_REG_W); 422 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_L_REG_W); 423 printf("clock_init() LONG1 %04x%04x\n", timeh, timel); 424 425 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_CNT_H_REG_W); 426 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_CNT_L_REG_W); 427 printf("clock_init() LONG1 CNTL %04x%04x\n", timeh, timel); 428 429 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_H_REG_W); 430 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_L_REG_W); 431 printf("clock_init() LONG2 %04x%04x\n", timeh, timel); 432 433 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_CNT_H_REG_W); 434 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_CNT_L_REG_W); 435 printf("clock_init() LONG2 CNTL %04x%04x\n", timeh, timel); 436 437 if (TCLK_H_REG_W != RTC_NO_REG_W) { 438 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, TCLK_H_REG_W); 439 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, TCLK_L_REG_W); 440 printf("clock_init() TCLK %04x%04x\n", timeh, timel); 441 442 timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, TCLK_CNT_H_REG_W); 443 timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, TCLK_CNT_L_REG_W); 444 printf("clock_init() TCLK CNTL %04x%04x\n", timeh, timel); 445 } 446 } 447