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