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