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