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