1 /* $NetBSD: clock.c,v 1.27 2002/11/08 14:58:25 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include "opt_pclock.h" 40 #include "wdog.h" 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/kernel.h> 45 #include <sys/device.h> 46 47 #include <dev/clock_subr.h> 48 49 #include <sh3/clock.h> 50 #include <sh3/exception.h> 51 #include <sh3/rtcreg.h> 52 #include <sh3/tmureg.h> 53 #include <sh3/wdogvar.h> 54 #include <sh3/wdtreg.h> 55 56 #include <machine/intr.h> 57 58 #ifndef HZ 59 #define HZ 64 60 #endif 61 #define MINYEAR 2002 /* "today" */ 62 #define SH_RTC_CLOCK 16384 /* Hz */ 63 64 /* 65 * NetBSD/sh3 clock module 66 * + default 64Hz 67 * + use TMU channel 0 as clock interrupt source. 68 * + use TMU channel 1 and 2 as emulated software interrupt soruce. 69 * + If RTC module is active, TMU channel 0 input source is RTC output. 70 * (1.6384kHz) 71 */ 72 struct { 73 /* Hard clock */ 74 u_int32_t hz_cnt; /* clock interrupt interval count */ 75 u_int32_t cpucycle_1us; /* calibrated loop variable (1 us) */ 76 u_int32_t tmuclk; /* source clock of TMU0 (Hz) */ 77 78 /* RTC ops holder. default SH RTC module */ 79 struct rtc_ops rtc; 80 int rtc_initialized; 81 82 u_int32_t pclock; /* PCLOCK */ 83 u_int32_t cpuclock; /* CPU clock */ 84 int flags; 85 } sh_clock = { 86 #ifdef PCLOCK 87 .pclock = PCLOCK, 88 #endif 89 .rtc = { 90 /* SH RTC module to default RTC */ 91 .init = sh_rtc_init, 92 .get = sh_rtc_get, 93 .set = sh_rtc_set 94 } 95 }; 96 97 u_int32_t maxwdog; 98 99 /* TMU */ 100 /* interrupt handler is timing critical. prepared for each. */ 101 int sh3_clock_intr(void *); 102 int sh4_clock_intr(void *); 103 104 /* 105 * Estimate CPU and Peripheral clock. 106 */ 107 #define TMU_START(x) \ 108 do { \ 109 _reg_bclr_1(SH_(TSTR), TSTR_STR##x); \ 110 _reg_write_4(SH_(TCNT ## x), 0xffffffff); \ 111 _reg_bset_1(SH_(TSTR), TSTR_STR##x); \ 112 } while (/*CONSTCOND*/0) 113 #define TMU_ELAPSED(x) \ 114 (0xffffffff - _reg_read_4(SH_(TCNT ## x))) 115 void 116 sh_clock_init(int flags, struct rtc_ops *rtc) 117 { 118 u_int32_t s, t0, t1 __attribute__((__unused__)); 119 120 sh_clock.flags = flags; 121 if (rtc != NULL) 122 sh_clock.rtc = *rtc; /* structure copy */ 123 124 /* Initialize TMU */ 125 _reg_write_2(SH_(TCR0), 0); 126 _reg_write_2(SH_(TCR1), 0); 127 _reg_write_2(SH_(TCR2), 0); 128 129 /* Reset RTC alarm and interrupt */ 130 _reg_write_1(SH_(RCR1), 0); 131 132 /* Stop all counter */ 133 _reg_write_1(SH_(TSTR), 0); 134 135 /* 136 * Estimate CPU clock. 137 */ 138 if (sh_clock.flags & SH_CLOCK_NORTC) { 139 /* Set TMU channel 0 source to PCLOCK / 16 */ 140 _reg_write_2(SH_(TCR0), TCR_TPSC_P16); 141 sh_clock.tmuclk = sh_clock.pclock / 16; 142 } else { 143 /* Set TMU channel 0 source to RTC counter clock (16.384kHz) */ 144 _reg_write_2(SH_(TCR0), 145 CPU_IS_SH3 ? SH3_TCR_TPSC_RTC : SH4_TCR_TPSC_RTC); 146 sh_clock.tmuclk = SH_RTC_CLOCK; 147 } 148 149 s = _cpu_exception_suspend(); 150 _cpu_spin(1); /* load function on cache. */ 151 TMU_START(0); 152 _cpu_spin(10000000); 153 t0 = TMU_ELAPSED(0); 154 _cpu_exception_resume(s); 155 156 sh_clock.cpuclock = ((10000000 * 10) / t0) * sh_clock.tmuclk; 157 sh_clock.cpucycle_1us = (sh_clock.tmuclk * 10) / t0; 158 159 if (CPU_IS_SH4) 160 sh_clock.cpuclock >>= 1; /* two-issue */ 161 162 /* 163 * Estimate PCLOCK 164 */ 165 if (sh_clock.pclock == 0) { 166 /* set TMU channel 1 source to PCLOCK / 4 */ 167 _reg_write_2(SH_(TCR1), TCR_TPSC_P4); 168 s = _cpu_exception_suspend(); 169 _cpu_spin(1); /* load function on cache. */ 170 TMU_START(0); 171 TMU_START(1); 172 _cpu_spin(sh_clock.cpucycle_1us * 1000000); /* 1 sec. */ 173 t0 = TMU_ELAPSED(0); 174 t1 = TMU_ELAPSED(1); 175 _cpu_exception_resume(s); 176 177 sh_clock.pclock = ((t1 * 4)/ t0) * SH_RTC_CLOCK; 178 } 179 180 /* Stop all counter */ 181 _reg_write_1(SH_(TSTR), 0); 182 183 #undef TMU_START 184 #undef TMU_ELAPSED 185 } 186 187 int 188 sh_clock_get_cpuclock() 189 { 190 191 return (sh_clock.cpuclock); 192 } 193 194 int 195 sh_clock_get_pclock() 196 { 197 198 return (sh_clock.pclock); 199 } 200 201 void 202 setstatclockrate(int newhz) 203 { 204 /* XXX not yet */ 205 } 206 207 /* 208 * Return the best possible estimate of the time in the timeval to 209 * which tv points. 210 */ 211 void 212 microtime(struct timeval *tv) 213 { 214 static struct timeval lasttime; 215 int s; 216 217 s = splclock(); 218 *tv = time; 219 splx(s); 220 221 tv->tv_usec += ((sh_clock.hz_cnt - _reg_read_4(SH_(TCNT0))) 222 * 1000000) / sh_clock.tmuclk; 223 while (tv->tv_usec >= 1000000) { 224 tv->tv_usec -= 1000000; 225 tv->tv_sec++; 226 } 227 228 if (tv->tv_sec == lasttime.tv_sec && 229 tv->tv_usec <= lasttime.tv_usec && 230 (tv->tv_usec = lasttime.tv_usec + 1) >= 1000000) { 231 tv->tv_usec -= 1000000; 232 tv->tv_sec++; 233 } 234 lasttime = *tv; 235 } 236 237 /* 238 * Wait at least `n' usec. 239 */ 240 void 241 delay(int n) 242 { 243 244 _cpu_spin(sh_clock.cpucycle_1us * n); 245 } 246 247 /* 248 * Start the clock interrupt. 249 */ 250 void 251 cpu_initclocks() 252 { 253 254 if (sh_clock.pclock == 0) 255 panic("No PCLOCK information."); 256 257 /* Set global variables. */ 258 hz = HZ; 259 tick = 1000000 / hz; 260 261 /* 262 * Use TMU channel 0 as hard clock 263 */ 264 _reg_bclr_1(SH_(TSTR), TSTR_STR0); 265 266 if (sh_clock.flags & SH_CLOCK_NORTC) { 267 /* use PCLOCK/16 as TMU0 source */ 268 _reg_write_2(SH_(TCR0), TCR_UNIE | TCR_TPSC_P16); 269 } else { 270 /* use RTC clock as TMU0 source */ 271 _reg_write_2(SH_(TCR0), TCR_UNIE | 272 (CPU_IS_SH3 ? SH3_TCR_TPSC_RTC : SH4_TCR_TPSC_RTC)); 273 } 274 sh_clock.hz_cnt = sh_clock.tmuclk / hz - 1; 275 276 _reg_write_4(SH_(TCOR0), sh_clock.hz_cnt); 277 _reg_write_4(SH_(TCNT0), sh_clock.hz_cnt); 278 279 intc_intr_establish(SH_INTEVT_TMU0_TUNI0, IST_LEVEL, IPL_CLOCK, 280 CPU_IS_SH3 ? sh3_clock_intr : sh4_clock_intr, 0); 281 /* start hardclock */ 282 _reg_bset_1(SH_(TSTR), TSTR_STR0); 283 284 /* 285 * TMU channel 1, 2 are one shot timer. 286 */ 287 _reg_write_2(SH_(TCR1), TCR_UNIE | TCR_TPSC_P4); 288 _reg_write_4(SH_(TCOR1), 0xffffffff); 289 _reg_write_2(SH_(TCR2), TCR_UNIE | TCR_TPSC_P4); 290 _reg_write_4(SH_(TCOR2), 0xffffffff); 291 292 /* Make sure to start RTC */ 293 sh_clock.rtc.init(sh_clock.rtc._cookie); 294 } 295 296 void 297 inittodr(time_t base) 298 { 299 struct clock_ymdhms dt; 300 time_t rtc; 301 int s; 302 303 if (!sh_clock.rtc_initialized) 304 sh_clock.rtc_initialized = 1; 305 306 sh_clock.rtc.get(sh_clock.rtc._cookie, base, &dt); 307 rtc = clock_ymdhms_to_secs(&dt); 308 309 #ifdef DEBUG 310 printf("inittodr: %d/%d/%d/%d/%d/%d(%d)\n", dt.dt_year, 311 dt.dt_mon, dt.dt_day, dt.dt_hour, dt.dt_min, dt.dt_sec, 312 dt.dt_wday); 313 #endif 314 315 if (!(sh_clock.flags & SH_CLOCK_NOINITTODR) && 316 (rtc < base || 317 dt.dt_year < MINYEAR || dt.dt_year > 2037 || 318 dt.dt_mon < 1 || dt.dt_mon > 12 || 319 dt.dt_wday > 6 || 320 dt.dt_day < 1 || dt.dt_day > 31 || 321 dt.dt_hour > 23 || dt.dt_min > 59 || dt.dt_sec > 59)) { 322 /* 323 * Believe the time in the file system for lack of 324 * anything better, resetting the RTC. 325 */ 326 s = splclock(); 327 time.tv_sec = base; 328 time.tv_usec = 0; 329 splx(s); 330 printf("WARNING: preposterous clock chip time\n"); 331 resettodr(); 332 printf(" -- CHECK AND RESET THE DATE!\n"); 333 return; 334 } 335 336 s = splclock(); 337 time.tv_sec = rtc + rtc_offset * 60; 338 time.tv_usec = 0; 339 splx(s); 340 341 return; 342 } 343 344 void 345 resettodr() 346 { 347 struct clock_ymdhms dt; 348 int s; 349 350 if (!sh_clock.rtc_initialized) 351 return; 352 353 s = splclock(); 354 clock_secs_to_ymdhms(time.tv_sec - rtc_offset * 60, &dt); 355 splx(s); 356 357 sh_clock.rtc.set(sh_clock.rtc._cookie, &dt); 358 #ifdef DEBUG 359 printf("%s: %d/%d/%d/%d/%d/%d(%d) rtc_offset %d\n", __FUNCTION__, 360 dt.dt_year, dt.dt_mon, dt.dt_day, dt.dt_hour, dt.dt_min, dt.dt_sec, 361 dt.dt_wday, rtc_offset); 362 #endif 363 } 364 365 #ifdef SH3 366 int 367 sh3_clock_intr(void *arg) /* trap frame */ 368 { 369 #if (NWDOG > 0) 370 u_int32_t i; 371 372 i = (u_int32_t)SHREG_WTCNT_R; 373 if (i > maxwdog) 374 maxwdog = i; 375 wdog_wr_cnt(0); /* reset to zero */ 376 #endif 377 /* clear underflow status */ 378 _reg_bclr_2(SH3_TCR0, TCR_UNF); 379 380 hardclock(arg); 381 382 return (1); 383 } 384 #endif /* SH3 */ 385 #ifdef SH4 386 int 387 sh4_clock_intr(void *arg) /* trap frame */ 388 { 389 #if (NWDOG > 0) 390 u_int32_t i; 391 392 i = (u_int32_t)SHREG_WTCNT_R; 393 if (i > maxwdog) 394 maxwdog = i; 395 wdog_wr_cnt(0); /* reset to zero */ 396 #endif 397 /* clear underflow status */ 398 _reg_bclr_2(SH4_TCR0, TCR_UNF); 399 400 hardclock(arg); 401 402 return (1); 403 } 404 #endif /* SH4 */ 405 406 /* 407 * SH3 RTC module ops. 408 */ 409 410 void 411 sh_rtc_init(void *cookie) 412 { 413 414 /* Make sure to start RTC */ 415 _reg_write_1(SH_(RCR2), SH_RCR2_ENABLE | SH_RCR2_START); 416 } 417 418 void 419 sh_rtc_get(void *cookie, time_t base, struct clock_ymdhms *dt) 420 { 421 int retry = 8; 422 423 /* disable carry interrupt */ 424 _reg_bclr_1(SH_(RCR1), SH_RCR1_CIE); 425 426 do { 427 u_int8_t r = _reg_read_1(SH_(RCR1)); 428 r &= ~SH_RCR1_CF; 429 r |= SH_RCR1_AF; /* don't clear alarm flag */ 430 _reg_write_1(SH_(RCR1), r); 431 432 if (CPU_IS_SH3) 433 dt->dt_year = FROMBCD(_reg_read_1(SH3_RYRCNT)); 434 else 435 dt->dt_year = FROMBCD(_reg_read_2(SH4_RYRCNT) & 0x00ff); 436 437 /* read counter */ 438 #define RTCGET(x, y) dt->dt_ ## x = FROMBCD(_reg_read_1(SH_(R ## y ## CNT))) 439 RTCGET(mon, MON); 440 RTCGET(wday, WK); 441 RTCGET(day, DAY); 442 RTCGET(hour, HR); 443 RTCGET(min, MIN); 444 RTCGET(sec, SEC); 445 #undef RTCGET 446 } while ((_reg_read_1(SH_(RCR1)) & SH_RCR1_CF) && --retry > 0); 447 448 if (retry == 0) { 449 printf("rtc_gettime: couldn't read RTC register.\n"); 450 memset(dt, 0, sizeof(*dt)); 451 return; 452 } 453 454 dt->dt_year = (dt->dt_year % 100) + 1900; 455 if (dt->dt_year < 1970) 456 dt->dt_year += 100; 457 } 458 459 void 460 sh_rtc_set(void *cookie, struct clock_ymdhms *dt) 461 { 462 u_int8_t r; 463 464 /* stop clock */ 465 r = _reg_read_1(SH_(RCR2)); 466 r |= SH_RCR2_RESET; 467 r &= ~SH_RCR2_START; 468 _reg_write_1(SH_(RCR2), r); 469 470 /* set time */ 471 if (CPU_IS_SH3) 472 _reg_write_1(SH3_RYRCNT, TOBCD(dt->dt_year % 100)); 473 else 474 _reg_write_2(SH4_RYRCNT, TOBCD(dt->dt_year % 100)); 475 #define RTCSET(x, y) _reg_write_1(SH_(R ## x ## CNT), TOBCD(dt->dt_ ## y)) 476 RTCSET(MON, mon); 477 RTCSET(WK, wday); 478 RTCSET(DAY, day); 479 RTCSET(HR, hour); 480 RTCSET(MIN, min); 481 RTCSET(SEC, sec); 482 #undef RTCSET 483 /* start clock */ 484 _reg_write_1(SH_(RCR2), r | SH_RCR2_START); 485 } 486 487