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