1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate #include <sys/types.h> 31*0Sstevel@tonic-gate #include <sys/conf.h> 32*0Sstevel@tonic-gate #include <sys/kmem.h> 33*0Sstevel@tonic-gate #include <sys/open.h> 34*0Sstevel@tonic-gate #include <sys/ddi.h> 35*0Sstevel@tonic-gate #include <sys/sunddi.h> 36*0Sstevel@tonic-gate 37*0Sstevel@tonic-gate #include <sys/todm5819.h> 38*0Sstevel@tonic-gate #include <sys/modctl.h> 39*0Sstevel@tonic-gate #include <sys/stat.h> 40*0Sstevel@tonic-gate #include <sys/clock.h> 41*0Sstevel@tonic-gate #include <sys/reboot.h> 42*0Sstevel@tonic-gate #include <sys/machsystm.h> 43*0Sstevel@tonic-gate #include <sys/poll.h> 44*0Sstevel@tonic-gate #include <sys/pbio.h> 45*0Sstevel@tonic-gate #include <sys/lom_priv.h> 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate #define WDOG_ON 1 48*0Sstevel@tonic-gate #define WDOG_OFF 0 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate static timestruc_t todbl_get(void); 51*0Sstevel@tonic-gate static void todbl_set(timestruc_t); 52*0Sstevel@tonic-gate static uint_t todbl_set_watchdog_timer(uint_t); 53*0Sstevel@tonic-gate static uint_t todbl_clear_watchdog_timer(void); 54*0Sstevel@tonic-gate static void todbl_set_power_alarm(timestruc_t); 55*0Sstevel@tonic-gate static void todbl_clear_power_alarm(void); 56*0Sstevel@tonic-gate static uint64_t todbl_get_cpufrequency(void); 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate static todinfo_t rtc_to_tod(struct rtc_t *); 59*0Sstevel@tonic-gate static uint_t read_rtc(struct rtc_t *); 60*0Sstevel@tonic-gate static void write_rtc_time(struct rtc_t *); 61*0Sstevel@tonic-gate static uint_t configure_wdog(uint8_t new_state); 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate extern uint64_t find_cpufrequency(volatile uint8_t *); 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate /* 66*0Sstevel@tonic-gate * External variables 67*0Sstevel@tonic-gate */ 68*0Sstevel@tonic-gate extern int watchdog_enable; 69*0Sstevel@tonic-gate extern int watchdog_available; 70*0Sstevel@tonic-gate extern int watchdog_activated; 71*0Sstevel@tonic-gate extern uint_t watchdog_timeout_seconds; 72*0Sstevel@tonic-gate extern int boothowto; 73*0Sstevel@tonic-gate extern void (*bsc_drv_func_ptr)(struct bscv_idi_info *); 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate /* 76*0Sstevel@tonic-gate * Global variables 77*0Sstevel@tonic-gate */ 78*0Sstevel@tonic-gate int m5819_debug_flags; 79*0Sstevel@tonic-gate uint8_t wdog_reset_on_timeout = 1; 80*0Sstevel@tonic-gate static clock_t last_pat_lbt; 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate static struct modlmisc modlmisc = { 84*0Sstevel@tonic-gate &mod_miscops, "todblade module v%I%", 85*0Sstevel@tonic-gate }; 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 88*0Sstevel@tonic-gate MODREV_1, &modlmisc, NULL 89*0Sstevel@tonic-gate }; 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate int 93*0Sstevel@tonic-gate _init(void) 94*0Sstevel@tonic-gate { 95*0Sstevel@tonic-gate if (strcmp(tod_module_name, "todblade") == 0) { 96*0Sstevel@tonic-gate RTC_PUT8(RTC_B, (RTC_DM | RTC_HM)); 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate tod_ops.tod_get = todbl_get; 99*0Sstevel@tonic-gate tod_ops.tod_set = todbl_set; 100*0Sstevel@tonic-gate tod_ops.tod_set_watchdog_timer = 101*0Sstevel@tonic-gate todbl_set_watchdog_timer; 102*0Sstevel@tonic-gate tod_ops.tod_clear_watchdog_timer = 103*0Sstevel@tonic-gate todbl_clear_watchdog_timer; 104*0Sstevel@tonic-gate tod_ops.tod_set_power_alarm = todbl_set_power_alarm; 105*0Sstevel@tonic-gate tod_ops.tod_clear_power_alarm = todbl_clear_power_alarm; 106*0Sstevel@tonic-gate tod_ops.tod_get_cpufrequency = todbl_get_cpufrequency; 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate if (watchdog_enable && (boothowto & RB_DEBUG)) { 109*0Sstevel@tonic-gate watchdog_available = 0; 110*0Sstevel@tonic-gate cmn_err(CE_WARN, "todblade: kernel debugger " 111*0Sstevel@tonic-gate "detected: hardware watchdog disabled"); 112*0Sstevel@tonic-gate } 113*0Sstevel@tonic-gate } 114*0Sstevel@tonic-gate return (mod_install(&modlinkage)); 115*0Sstevel@tonic-gate } 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate int 118*0Sstevel@tonic-gate _fini(void) 119*0Sstevel@tonic-gate { 120*0Sstevel@tonic-gate if (strcmp(tod_module_name, "todblade") == 0) { 121*0Sstevel@tonic-gate return (EBUSY); 122*0Sstevel@tonic-gate } else { 123*0Sstevel@tonic-gate return (mod_remove(&modlinkage)); 124*0Sstevel@tonic-gate } 125*0Sstevel@tonic-gate } 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate /* 128*0Sstevel@tonic-gate * The loadable-module _info(9E) entry point 129*0Sstevel@tonic-gate */ 130*0Sstevel@tonic-gate int 131*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 132*0Sstevel@tonic-gate { 133*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 134*0Sstevel@tonic-gate } 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate 137*0Sstevel@tonic-gate /* 138*0Sstevel@tonic-gate * Read the current time from the clock chip and convert to UNIX form. 139*0Sstevel@tonic-gate * Assumes that the year in the clock chip is valid. 140*0Sstevel@tonic-gate * Must be called with tod_lock held. 141*0Sstevel@tonic-gate */ 142*0Sstevel@tonic-gate static timestruc_t 143*0Sstevel@tonic-gate todbl_get(void) 144*0Sstevel@tonic-gate { 145*0Sstevel@tonic-gate int i; 146*0Sstevel@tonic-gate timestruc_t ts; 147*0Sstevel@tonic-gate struct rtc_t rtc; 148*0Sstevel@tonic-gate struct bscv_idi_info bscv_info; 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tod_lock)); 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gate /* 153*0Sstevel@tonic-gate * We must check that the value of watchdog enable hasnt changed 154*0Sstevel@tonic-gate * as its a user knob for turning it on and off 155*0Sstevel@tonic-gate */ 156*0Sstevel@tonic-gate if (watchdog_available) { 157*0Sstevel@tonic-gate if (watchdog_activated && !watchdog_enable) { 158*0Sstevel@tonic-gate (void) configure_wdog(WDOG_OFF); 159*0Sstevel@tonic-gate } else if (!watchdog_activated && watchdog_enable) { 160*0Sstevel@tonic-gate (void) configure_wdog(WDOG_ON); 161*0Sstevel@tonic-gate } else if (watchdog_activated && 162*0Sstevel@tonic-gate (ddi_get_lbolt() - last_pat_lbt) >= 163*0Sstevel@tonic-gate SEC_TO_TICK(1)) { 164*0Sstevel@tonic-gate /* 165*0Sstevel@tonic-gate * PAT THE WATCHDOG!! 166*0Sstevel@tonic-gate * We dont want to accelerate the pat frequency 167*0Sstevel@tonic-gate * when userland calls to the TOD_GET_DATE ioctl 168*0Sstevel@tonic-gate * pass through here. 169*0Sstevel@tonic-gate */ 170*0Sstevel@tonic-gate bscv_info.type = BSCV_IDI_WDOG_PAT; 171*0Sstevel@tonic-gate bscv_info.data = NULL; 172*0Sstevel@tonic-gate bscv_info.size = 0; 173*0Sstevel@tonic-gate if (bsc_drv_func_ptr != NULL) { 174*0Sstevel@tonic-gate (*bsc_drv_func_ptr)(&bscv_info); 175*0Sstevel@tonic-gate last_pat_lbt = ddi_get_lbolt(); 176*0Sstevel@tonic-gate } 177*0Sstevel@tonic-gate } 178*0Sstevel@tonic-gate } 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate /* 181*0Sstevel@tonic-gate * Read from the tod, and if it isnt accessible wait 182*0Sstevel@tonic-gate * before retrying. 183*0Sstevel@tonic-gate */ 184*0Sstevel@tonic-gate for (i = 0; i < TODM5819_UIP_RETRY_THRESH; i++) { 185*0Sstevel@tonic-gate if (read_rtc(&rtc)) 186*0Sstevel@tonic-gate break; 187*0Sstevel@tonic-gate drv_usecwait(TODM5819_UIP_WAIT_USEC); 188*0Sstevel@tonic-gate } 189*0Sstevel@tonic-gate if (i == TODM5819_UIP_RETRY_THRESH) { 190*0Sstevel@tonic-gate /* 191*0Sstevel@tonic-gate * We couldnt read from the tod 192*0Sstevel@tonic-gate */ 193*0Sstevel@tonic-gate tod_fault_reset(); 194*0Sstevel@tonic-gate return (hrestime); 195*0Sstevel@tonic-gate } 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate DPRINTF("todbl_get: century=%d year=%d dom=%d hrs=%d\n", 198*0Sstevel@tonic-gate rtc.rtc_century, rtc.rtc_year, rtc.rtc_dom, rtc.rtc_hrs); 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate ts.tv_sec = tod_to_utc(rtc_to_tod(&rtc)); 201*0Sstevel@tonic-gate ts.tv_nsec = 0; 202*0Sstevel@tonic-gate return (ts); 203*0Sstevel@tonic-gate } 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate static todinfo_t 206*0Sstevel@tonic-gate rtc_to_tod(struct rtc_t *rtc) 207*0Sstevel@tonic-gate { 208*0Sstevel@tonic-gate todinfo_t tod; 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate /* 211*0Sstevel@tonic-gate * tod_year is base 1900 so this code needs to adjust the true 212*0Sstevel@tonic-gate * year retrieved from the rtc's century and year fields. 213*0Sstevel@tonic-gate */ 214*0Sstevel@tonic-gate tod.tod_year = rtc->rtc_year + (rtc->rtc_century * 100) - 1900; 215*0Sstevel@tonic-gate tod.tod_month = rtc->rtc_mon; 216*0Sstevel@tonic-gate tod.tod_day = rtc->rtc_dom; 217*0Sstevel@tonic-gate tod.tod_dow = rtc->rtc_dow; 218*0Sstevel@tonic-gate tod.tod_hour = rtc->rtc_hrs; 219*0Sstevel@tonic-gate tod.tod_min = rtc->rtc_min; 220*0Sstevel@tonic-gate tod.tod_sec = rtc->rtc_sec; 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate return (tod); 223*0Sstevel@tonic-gate } 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate static uint_t 227*0Sstevel@tonic-gate read_rtc(struct rtc_t *rtc) 228*0Sstevel@tonic-gate { 229*0Sstevel@tonic-gate int s; 230*0Sstevel@tonic-gate uint_t rtc_readable = 0; 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate s = splhi(); 233*0Sstevel@tonic-gate /* 234*0Sstevel@tonic-gate * If UIP bit is not set we have at least 274us 235*0Sstevel@tonic-gate * to read the values. 236*0Sstevel@tonic-gate */ 237*0Sstevel@tonic-gate if (!(RTC_GET8(RTC_A) & RTC_UIP)) { 238*0Sstevel@tonic-gate rtc_readable = 1; 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate rtc->rtc_sec = RTC_GET8(RTC_SEC); 241*0Sstevel@tonic-gate rtc->rtc_asec = RTC_GET8(RTC_ASEC); 242*0Sstevel@tonic-gate rtc->rtc_min = RTC_GET8(RTC_MIN); 243*0Sstevel@tonic-gate rtc->rtc_amin = RTC_GET8(RTC_AMIN); 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate rtc->rtc_hrs = RTC_GET8(RTC_HRS); 246*0Sstevel@tonic-gate rtc->rtc_ahrs = RTC_GET8(RTC_AHRS); 247*0Sstevel@tonic-gate rtc->rtc_dow = RTC_GET8(RTC_DOW); 248*0Sstevel@tonic-gate rtc->rtc_dom = RTC_GET8(RTC_DOM); 249*0Sstevel@tonic-gate rtc->rtc_adom = RTC_GET8(RTC_D) & 0x3f; 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate rtc->rtc_mon = RTC_GET8(RTC_MON); 252*0Sstevel@tonic-gate rtc->rtc_year = RTC_GET8(RTC_YEAR); 253*0Sstevel@tonic-gate rtc->rtc_century = RTC_GET8(RTC_CENTURY); 254*0Sstevel@tonic-gate rtc->rtc_amon = 0; 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate /* Clear wakeup data */ 257*0Sstevel@tonic-gate rtc->apc_wdwr = 0; 258*0Sstevel@tonic-gate rtc->apc_wdmr = 0; 259*0Sstevel@tonic-gate rtc->apc_wmr = 0; 260*0Sstevel@tonic-gate rtc->apc_wyr = 0; 261*0Sstevel@tonic-gate rtc->apc_wcr = 0; 262*0Sstevel@tonic-gate } 263*0Sstevel@tonic-gate 264*0Sstevel@tonic-gate splx(s); 265*0Sstevel@tonic-gate return (rtc_readable); 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate /* 269*0Sstevel@tonic-gate * Write the specified time into the clock chip. 270*0Sstevel@tonic-gate * Must be called with tod_lock held. 271*0Sstevel@tonic-gate */ 272*0Sstevel@tonic-gate static void 273*0Sstevel@tonic-gate todbl_set(timestruc_t ts) 274*0Sstevel@tonic-gate { 275*0Sstevel@tonic-gate struct rtc_t rtc; 276*0Sstevel@tonic-gate todinfo_t tod = utc_to_tod(ts.tv_sec); 277*0Sstevel@tonic-gate struct bscv_idi_info bscv_info; 278*0Sstevel@tonic-gate int year; 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tod_lock)); 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate /* tod_year is base 1900 so this code needs to adjust */ 283*0Sstevel@tonic-gate year = 1900 + tod.tod_year; 284*0Sstevel@tonic-gate rtc.rtc_year = year % 100; 285*0Sstevel@tonic-gate rtc.rtc_century = year / 100; 286*0Sstevel@tonic-gate rtc.rtc_mon = (uint8_t)tod.tod_month; 287*0Sstevel@tonic-gate rtc.rtc_dom = (uint8_t)tod.tod_day; 288*0Sstevel@tonic-gate rtc.rtc_dow = (uint8_t)tod.tod_dow; 289*0Sstevel@tonic-gate rtc.rtc_hrs = (uint8_t)tod.tod_hour; 290*0Sstevel@tonic-gate rtc.rtc_min = (uint8_t)tod.tod_min; 291*0Sstevel@tonic-gate rtc.rtc_sec = (uint8_t)tod.tod_sec; 292*0Sstevel@tonic-gate DPRINTF("todbl_set: century=%d year=%d dom=%d hrs=%d\n", 293*0Sstevel@tonic-gate rtc.rtc_century, rtc.rtc_year, rtc.rtc_dom, rtc.rtc_hrs); 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate write_rtc_time(&rtc); 296*0Sstevel@tonic-gate 297*0Sstevel@tonic-gate /* 298*0Sstevel@tonic-gate * Because of a generic solaris problem where calls to stime() 299*0Sstevel@tonic-gate * starve calls to tod_get(), we need to check to see when the 300*0Sstevel@tonic-gate * watchdog was last patted and pat it if necessary. 301*0Sstevel@tonic-gate */ 302*0Sstevel@tonic-gate if (watchdog_activated && 303*0Sstevel@tonic-gate (ddi_get_lbolt() - last_pat_lbt) >= SEC_TO_TICK(1)) { 304*0Sstevel@tonic-gate /* 305*0Sstevel@tonic-gate * Pat the watchdog! 306*0Sstevel@tonic-gate */ 307*0Sstevel@tonic-gate bscv_info.type = BSCV_IDI_WDOG_PAT; 308*0Sstevel@tonic-gate bscv_info.data = NULL; 309*0Sstevel@tonic-gate bscv_info.size = 0; 310*0Sstevel@tonic-gate if (bsc_drv_func_ptr != NULL) { 311*0Sstevel@tonic-gate (*bsc_drv_func_ptr)(&bscv_info); 312*0Sstevel@tonic-gate last_pat_lbt = ddi_get_lbolt(); 313*0Sstevel@tonic-gate } 314*0Sstevel@tonic-gate } 315*0Sstevel@tonic-gate } 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate static void 318*0Sstevel@tonic-gate write_rtc_time(struct rtc_t *rtc) 319*0Sstevel@tonic-gate { 320*0Sstevel@tonic-gate uint8_t regb; 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate /* 323*0Sstevel@tonic-gate * Freeze 324*0Sstevel@tonic-gate */ 325*0Sstevel@tonic-gate regb = RTC_GET8(RTC_B); 326*0Sstevel@tonic-gate RTC_PUT8(RTC_B, (regb | RTC_SET)); 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate RTC_PUT8(RTC_SEC, (rtc->rtc_sec)); 329*0Sstevel@tonic-gate RTC_PUT8(RTC_ASEC, (rtc->rtc_asec)); 330*0Sstevel@tonic-gate RTC_PUT8(RTC_MIN, (rtc->rtc_min)); 331*0Sstevel@tonic-gate RTC_PUT8(RTC_AMIN, (rtc->rtc_amin)); 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate RTC_PUT8(RTC_HRS, (rtc->rtc_hrs)); 334*0Sstevel@tonic-gate RTC_PUT8(RTC_AHRS, (rtc->rtc_ahrs)); 335*0Sstevel@tonic-gate RTC_PUT8(RTC_DOW, (rtc->rtc_dow)); 336*0Sstevel@tonic-gate RTC_PUT8(RTC_DOM, (rtc->rtc_dom)); 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate RTC_PUT8(RTC_MON, (rtc->rtc_mon)); 339*0Sstevel@tonic-gate RTC_PUT8(RTC_YEAR, (rtc->rtc_year)); 340*0Sstevel@tonic-gate RTC_PUT8(RTC_CENTURY, (rtc->rtc_century)); 341*0Sstevel@tonic-gate 342*0Sstevel@tonic-gate /* 343*0Sstevel@tonic-gate * Unfreeze 344*0Sstevel@tonic-gate */ 345*0Sstevel@tonic-gate RTC_PUT8(RTC_B, regb); 346*0Sstevel@tonic-gate } 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate /* 351*0Sstevel@tonic-gate * The TOD alarm functionality is not supported on our platform 352*0Sstevel@tonic-gate * as the interrupt is not wired, so do nothing. 353*0Sstevel@tonic-gate */ 354*0Sstevel@tonic-gate /*ARGSUSED*/ 355*0Sstevel@tonic-gate static void 356*0Sstevel@tonic-gate todbl_set_power_alarm(timestruc_t ts) 357*0Sstevel@tonic-gate { 358*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tod_lock)); 359*0Sstevel@tonic-gate } 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate /* 362*0Sstevel@tonic-gate * clear alarm interrupt 363*0Sstevel@tonic-gate */ 364*0Sstevel@tonic-gate static void 365*0Sstevel@tonic-gate todbl_clear_power_alarm(void) 366*0Sstevel@tonic-gate { 367*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tod_lock)); 368*0Sstevel@tonic-gate } 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate /* 371*0Sstevel@tonic-gate * Determine the cpu frequency by watching the TOD chip rollover twice. 372*0Sstevel@tonic-gate * Cpu clock rate is determined by computing the ticks added (in tick register) 373*0Sstevel@tonic-gate * during one second interval on TOD. 374*0Sstevel@tonic-gate */ 375*0Sstevel@tonic-gate uint64_t 376*0Sstevel@tonic-gate todbl_get_cpufrequency(void) 377*0Sstevel@tonic-gate { 378*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tod_lock)); 379*0Sstevel@tonic-gate M5819_ADDR_REG = RTC_SEC; 380*0Sstevel@tonic-gate return (find_cpufrequency(v_rtc_data_reg)); 381*0Sstevel@tonic-gate } 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate static uint_t 385*0Sstevel@tonic-gate todbl_set_watchdog_timer(uint_t timeoutval) 386*0Sstevel@tonic-gate { 387*0Sstevel@tonic-gate /* 388*0Sstevel@tonic-gate * We get started during kernel intilaisation only 389*0Sstevel@tonic-gate * if watchdog_enable is set. 390*0Sstevel@tonic-gate */ 391*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tod_lock)); 392*0Sstevel@tonic-gate 393*0Sstevel@tonic-gate if (watchdog_available && (!watchdog_activated || 394*0Sstevel@tonic-gate (watchdog_activated && (timeoutval != watchdog_timeout_seconds)))) { 395*0Sstevel@tonic-gate watchdog_timeout_seconds = timeoutval; 396*0Sstevel@tonic-gate if (configure_wdog(WDOG_ON)) 397*0Sstevel@tonic-gate return (watchdog_timeout_seconds); 398*0Sstevel@tonic-gate } 399*0Sstevel@tonic-gate return (0); 400*0Sstevel@tonic-gate } 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gate static uint_t 403*0Sstevel@tonic-gate todbl_clear_watchdog_timer(void) 404*0Sstevel@tonic-gate { 405*0Sstevel@tonic-gate /* 406*0Sstevel@tonic-gate * The core kernel will call us here to disable the wdog when: 407*0Sstevel@tonic-gate * 1. we're panicing 408*0Sstevel@tonic-gate * 2. we're entering debug 409*0Sstevel@tonic-gate * 3. we're rebooting 410*0Sstevel@tonic-gate */ 411*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tod_lock)); 412*0Sstevel@tonic-gate 413*0Sstevel@tonic-gate if (watchdog_available && watchdog_activated) { 414*0Sstevel@tonic-gate watchdog_enable = 0; 415*0Sstevel@tonic-gate if (!configure_wdog(WDOG_OFF)) 416*0Sstevel@tonic-gate return (0); 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate return (watchdog_timeout_seconds); 419*0Sstevel@tonic-gate } 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gate static uint_t 422*0Sstevel@tonic-gate configure_wdog(uint8_t new_state) 423*0Sstevel@tonic-gate { 424*0Sstevel@tonic-gate bscv_wdog_t wdog_cmd; 425*0Sstevel@tonic-gate struct bscv_idi_info bscv_info; 426*0Sstevel@tonic-gate 427*0Sstevel@tonic-gate if (new_state == WDOG_ON || new_state == WDOG_OFF) { 428*0Sstevel@tonic-gate 429*0Sstevel@tonic-gate wdog_cmd.enable_wdog = new_state; 430*0Sstevel@tonic-gate wdog_cmd.wdog_timeout_s = watchdog_timeout_seconds; 431*0Sstevel@tonic-gate wdog_cmd.reset_system_on_timeout = wdog_reset_on_timeout; 432*0Sstevel@tonic-gate bscv_info.type = BSCV_IDI_WDOG_CFG; 433*0Sstevel@tonic-gate bscv_info.data = &wdog_cmd; 434*0Sstevel@tonic-gate bscv_info.size = sizeof (wdog_cmd); 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate if (bsc_drv_func_ptr != NULL) { 437*0Sstevel@tonic-gate watchdog_activated = new_state; 438*0Sstevel@tonic-gate (*bsc_drv_func_ptr)(&bscv_info); 439*0Sstevel@tonic-gate return (1); 440*0Sstevel@tonic-gate } 441*0Sstevel@tonic-gate } 442*0Sstevel@tonic-gate return (0); 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gate } 445