xref: /illumos-gate/usr/src/uts/sun4u/io/todds1287.c (revision 6f1fa39e3cf1b335f342bbca41590e9d76ab29b7)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 /*
28  *	The "todds1287" module has implementation for both tod
29  *	and power button (pbio) interfaces.  This driver controls
30  *	RTC & APC units of National Semiconductor's 87317 SuperI/O
31  *	chip.  The tod interface accesses the RTC unit and pbio
32  *	interface accesses the APC unit of SuperI/O.  Since both
33  *	units are implemented in the same Logical Device, registers
34  *	for both units are accessible through a common set of index
35  *	address & data registers.  That is why both interfaces are
36  *	implemented in a same driver.
37  *
38  *	The APC unit is used to implement the power button.  When the
39  *	button momentarily is pressed, an interrupt is generated and
40  *	at the same time a Fail-safe timer starts to run.  If the
41  *	timer is not stopped in 21 seconds, the power to system is
42  *	turned off.  So the first task in the interrupt handler is to
43  *	reset the Fail-safe timer.  Note that OBP is not clearing
44  *	the Fail-safe timer due to limitation in handling interrupts,
45  *	so when OBP is running, the power button should be pressed
46  *	and held for 4 seconds for the power to go off, otherwise
47  *	a momentarily press will delay the power-off for 21 seconds.
48  *
49  *	PSARC/1999/393 describes the pbio(7I) interface.
50  */
51 
52 #include <sys/types.h>
53 #include <sys/conf.h>
54 #include <sys/kmem.h>
55 #include <sys/open.h>
56 #include <sys/ddi.h>
57 #include <sys/sunddi.h>
58 
59 #include <sys/todds1287.h>
60 #include <sys/modctl.h>
61 #include <sys/stat.h>
62 #include <sys/clock.h>
63 #include <sys/reboot.h>
64 #include <sys/machsystm.h>
65 #include <sys/poll.h>
66 #include <sys/pbio.h>
67 
68 #define	ABORT_INCREMENT_DELAY	10
69 
70 static timestruc_t todds_get(void);
71 static void todds_set(timestruc_t);
72 static uint_t todds_set_watchdog_timer(uint_t);
73 static uint_t todds_clear_watchdog_timer(void);
74 static void todds_set_power_alarm(timestruc_t);
75 static void todds_clear_power_alarm(void);
76 static uint64_t todds_get_cpufrequency(void);
77 
78 extern uint64_t find_cpufrequency(volatile uint8_t *);
79 
80 /*
81  * External variables
82  */
83 extern int	watchdog_activated;
84 extern uint_t	watchdog_timeout_seconds;
85 extern volatile uint8_t	*v_pmc_addr_reg;
86 
87 /*
88  * Global variables
89  */
90 int ds1287_debug_flags;
91 int ds1287_caddr_warn;
92 
93 /*
94  * cb ops
95  */
96 static int ds1287_open(dev_t *, int, int, cred_t *);
97 static int ds1287_close(dev_t, int, int, cred_t *);
98 static int ds1287_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
99 static int ds1287_chpoll(dev_t, short, int, short *, struct pollhead **);
100 
101 static void read_rtc(struct rtc_t *);
102 static void write_rtc_time(struct rtc_t *);
103 static void write_rtc_alarm(struct rtc_t *);
104 static void select_bank(int bank);
105 static uint_t ds1287_intr(caddr_t);
106 static uint_t ds1287_softintr(caddr_t);
107 static void ds1287_timeout(caddr_t);
108 static uint_t ds1287_issue_shutdown(caddr_t);
109 static void ds1287_log_message(void);
110 
111 static struct cb_ops ds1287_cbops = {
112 	ds1287_open,			/* open */
113 	ds1287_close,			/* close */
114 	nodev,				/* strategy */
115 	nodev,				/* print */
116 	nodev,				/* dump */
117 	nodev,				/* read */
118 	nodev,				/* write */
119 	ds1287_ioctl,			/* ioctl */
120 	nodev,				/* devmap */
121 	nodev,				/* mmap */
122 	nodev,				/* segmap */
123 	ds1287_chpoll,			/* poll */
124 	ddi_prop_op,			/* cb_prop_op */
125 	NULL,				/* streamtab */
126 	D_NEW | D_MP,			/* Driver compatibility flag */
127 	CB_REV,				/* rev */
128 	nodev,				/* int (*cb_aread)() */
129 	nodev				/* int (*cb_awrite)() */
130 };
131 
132 /*
133  * dev ops
134  */
135 static int ds1287_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
136 static int ds1287_attach(dev_info_t *, ddi_attach_cmd_t);
137 static int ds1287_detach(dev_info_t *, ddi_detach_cmd_t);
138 
139 static struct dev_ops ds1287_ops = {
140 	DEVO_REV,			/* devo_rev */
141 	0,				/* refcnt */
142 	ds1287_getinfo,			/* getinfo */
143 	nulldev,			/* identify */
144 	nulldev,			/* probe */
145 	ds1287_attach,			/* attach */
146 	ds1287_detach,			/* detach */
147 	nodev,				/* reset */
148 	&ds1287_cbops,			/* cb_ops */
149 	(struct bus_ops *)NULL,		/* bus_ops */
150 	NULL,				/* power */
151 	ddi_quiesce_not_supported,	/* devo_quiesce */
152 };
153 
154 
155 static void	*ds1287_state;
156 static int	instance = -1;
157 
158 /* Driver Tunables */
159 static int	ds1287_interrupt_priority = 15;
160 static int	ds1287_softint_priority = 2;
161 static hrtime_t power_button_debounce = MSEC2NSEC(10);
162 static hrtime_t power_button_abort_interval = 1.5 * NANOSEC;
163 static int	power_button_abort_presses = 3;
164 static int	power_button_abort_enable = 1;
165 static int	power_button_enable = 1;
166 
167 static int	power_button_pressed = 0;
168 static int	power_button_cancel = 0;
169 static int	power_button_timeouts = 0;
170 static int	timeout_cancel = 0;
171 static int	additional_presses = 0;
172 
173 static ddi_iblock_cookie_t ds1287_lo_iblock;
174 static ddi_iblock_cookie_t ds1287_hi_iblock;
175 static ddi_softintr_t	ds1287_softintr_id;
176 static kmutex_t ds1287_reg_mutex;	/* Protects ds1287 Registers */
177 
178 static struct modldrv modldrv = {
179 	&mod_driverops,		/* Type of module. This one is a driver */
180 	"ds1287 clock driver",	/* Name of the module. */
181 	&ds1287_ops,		/* driver ops */
182 };
183 
184 static struct modlinkage modlinkage = {
185 	MODREV_1, &modldrv, NULL
186 };
187 
188 
189 int
190 _init(void)
191 {
192 	int status;
193 
194 	status = ddi_soft_state_init(&ds1287_state, sizeof (struct ds1287), 0);
195 	if (status != 0) {
196 		return (status);
197 	}
198 
199 	if ((status = mod_install(&modlinkage)) != 0) {
200 		ddi_soft_state_fini(&ds1287_state);
201 		return (status);
202 	}
203 
204 
205 	ds1287_hi_iblock = (ddi_iblock_cookie_t)(uintptr_t)
206 	    ipltospl(ds1287_interrupt_priority);
207 	mutex_init(&ds1287_reg_mutex, NULL, MUTEX_DRIVER, ds1287_hi_iblock);
208 
209 	mutex_enter(&ds1287_reg_mutex);
210 	/* Select Bank 1 */
211 	select_bank(1);
212 	DS1287_ADDR_REG = RTC_B;
213 	DS1287_DATA_REG = (RTC_DM | RTC_HM);
214 	mutex_exit(&ds1287_reg_mutex);
215 
216 	tod_ops.tod_get = todds_get;
217 	tod_ops.tod_set = todds_set;
218 
219 	/*
220 	 * If v_pmc_addr_reg isn't set, it's because it wasn't set in
221 	 * sun4u/os/fillsysinfo.c:have_pmc(). This means the real (pmc)
222 	 * watchdog routines (sun4u/io/pmc.c) will not be used. If the
223 	 * user were to set watchdog_enable in /etc/system, we'll need to
224 	 * use our own NOP routines.
225 	 */
226 	if (v_pmc_addr_reg == NULL) {
227 		tod_ops.tod_set_watchdog_timer = todds_set_watchdog_timer;
228 		tod_ops.tod_clear_watchdog_timer = todds_clear_watchdog_timer;
229 	}
230 	tod_ops.tod_set_power_alarm = todds_set_power_alarm;
231 	tod_ops.tod_clear_power_alarm = todds_clear_power_alarm;
232 	tod_ops.tod_get_cpufrequency = todds_get_cpufrequency;
233 
234 	return (status);
235 }
236 
237 int
238 _fini(void)
239 {
240 	if (strcmp(tod_module_name, "todds1287") == 0)
241 		return (EBUSY);
242 
243 	return (mod_remove(&modlinkage));
244 }
245 
246 /*
247  * The loadable-module _info(9E) entry point
248  */
249 int
250 _info(struct modinfo *modinfop)
251 {
252 	return (mod_info(&modlinkage, modinfop));
253 }
254 
255 /*ARGSUSED*/
256 static int
257 ds1287_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
258     void **result)
259 {
260 	struct ds1287 *softsp;
261 
262 	if (instance == -1)
263 		return (DDI_FAILURE);
264 
265 	switch (infocmd) {
266 	case DDI_INFO_DEVT2DEVINFO:
267 		if ((softsp = ddi_get_soft_state(ds1287_state, instance))
268 		    == NULL)
269 			return (DDI_FAILURE);
270 		*result = (void *)softsp->dip;
271 		return (DDI_SUCCESS);
272 
273 	case DDI_INFO_DEVT2INSTANCE:
274 		*result = (void *)(uintptr_t)instance;
275 		return (DDI_SUCCESS);
276 
277 	default:
278 		return (DDI_FAILURE);
279 	}
280 }
281 
282 static int
283 ds1287_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
284 {
285 	struct ds1287 *softsp;
286 
287 	DPRINTF("ds1287_attach\n");
288 	switch (cmd) {
289 	case DDI_ATTACH:
290 		break;
291 	case DDI_RESUME:
292 		return (DDI_SUCCESS);
293 	default:
294 		return (DDI_FAILURE);
295 	}
296 
297 	if (instance != -1) {
298 		cmn_err(CE_WARN, "ds1287_attach: Another instance is already "
299 		    "attached.");
300 		return (DDI_FAILURE);
301 	}
302 
303 	instance = ddi_get_instance(dip);
304 
305 	if (v_rtc_addr_reg == NULL) {
306 		cmn_err(CE_WARN, "ds1287_attach: v_rtc_addr_reg is NULL");
307 		return (DDI_FAILURE);
308 	}
309 
310 	/*
311 	 * Allocate softc information.
312 	 */
313 	if (ddi_soft_state_zalloc(ds1287_state, instance) != DDI_SUCCESS) {
314 		cmn_err(CE_WARN, "ds1287_attach: Failed to allocate "
315 		    "soft states.");
316 		return (DDI_FAILURE);
317 	}
318 
319 	softsp = ddi_get_soft_state(ds1287_state, instance);
320 	DPRINTF("ds1287_attach: instance=%d softsp=0x%p\n", instance,
321 	    (void *)softsp);
322 
323 	softsp->dip = dip;
324 
325 	if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
326 	    "interrupt-priorities", (caddr_t)&ds1287_interrupt_priority,
327 	    sizeof (int)) != DDI_PROP_SUCCESS) {
328 		cmn_err(CE_WARN, "ds1287_attach: Failed to create \""
329 		    "interrupt-priorities\" property.");
330 		goto error;
331 	}
332 
333 	/* add the softint */
334 	ds1287_lo_iblock = (ddi_iblock_cookie_t)(uintptr_t)
335 	    ipltospl(ds1287_softint_priority);
336 
337 	if (ddi_add_softintr(dip, DDI_SOFTINT_FIXED, &ds1287_softintr_id,
338 	    &ds1287_lo_iblock, NULL, ds1287_softintr, (caddr_t)softsp) !=
339 	    DDI_SUCCESS) {
340 		cmn_err(CE_WARN, "ds1287_attach: Failed to add low interrupt.");
341 		goto error1;
342 	}
343 
344 	/* add the hi interrupt */
345 	if (ddi_add_intr(dip, 0, NULL, (ddi_idevice_cookie_t *)
346 	    &ds1287_hi_iblock, ds1287_intr, NULL) != DDI_SUCCESS) {
347 		cmn_err(CE_WARN, "ds1287_attach: Failed to add high "
348 		    "interrupt.");
349 		goto error2;
350 	}
351 
352 	/*
353 	 * Combination of instance number and clone number 0 is used for
354 	 * creating the minor node.
355 	 */
356 	if (ddi_create_minor_node(dip, "power_button", S_IFCHR,
357 	    (instance << 8) + 0, "ddi_power_button", 0) == DDI_FAILURE) {
358 		cmn_err(CE_WARN, "ds1287_attach: Failed to create minor node");
359 		goto error3;
360 	}
361 
362 	ddi_report_dev(dip);
363 
364 	return (DDI_SUCCESS);
365 
366 error3:
367 	ddi_remove_intr(dip, 0, NULL);
368 error2:
369 	ddi_remove_softintr(ds1287_softintr_id);
370 error1:
371 	(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "interrupt-priorities");
372 error:
373 	ddi_soft_state_free(ds1287_state, instance);
374 	return (DDI_FAILURE);
375 }
376 
377 /*ARGSUSED*/
378 static int
379 ds1287_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
380 {
381 	DPRINTF("ds1287_detach\n");
382 	switch (cmd) {
383 	case DDI_DETACH:
384 		/*
385 		 * Since it needs to always handle the power button, fail
386 		 * to detach.
387 		 */
388 		return (DDI_FAILURE);
389 	case DDI_SUSPEND:
390 		return (DDI_SUCCESS);
391 	default:
392 		return (DDI_FAILURE);
393 	}
394 }
395 
396 /*ARGSUSED1*/
397 static int
398 ds1287_open(dev_t *devp, int flags, int otyp, cred_t *credp)
399 {
400 	struct ds1287 *softsp;
401 	int clone;
402 
403 	if (otyp != OTYP_CHR)
404 		return (EINVAL);
405 
406 	if ((softsp = ddi_get_soft_state(ds1287_state, instance)) ==
407 	    NULL)
408 		return (ENXIO);
409 
410 	mutex_enter(&softsp->ds1287_mutex);
411 	for (clone = 1; clone < DS1287_MAX_CLONE; clone++)
412 		if (!softsp->clones[clone])
413 			break;
414 
415 	if (clone == DS1287_MAX_CLONE) {
416 		cmn_err(CE_WARN, "ds1287_open: No more allocation left "
417 		    "to clone a minor.");
418 		mutex_exit(&softsp->ds1287_mutex);
419 		return (ENXIO);
420 	}
421 
422 	*devp = makedevice(getmajor(*devp), (instance << 8) + clone);
423 	softsp->clones[clone] = 1;
424 	mutex_exit(&softsp->ds1287_mutex);
425 
426 	return (0);
427 }
428 
429 /*ARGSUSED*/
430 static int
431 ds1287_close(dev_t dev, int flags, int otyp, cred_t *credp)
432 {
433 	struct ds1287 *softsp;
434 	int clone;
435 
436 	if (otyp != OTYP_CHR)
437 		return (EINVAL);
438 
439 	if ((softsp = ddi_get_soft_state(ds1287_state, instance)) ==
440 	    NULL)
441 		return (ENXIO);
442 
443 	clone = DS1287_MINOR_TO_CLONE(getminor(dev));
444 	mutex_enter(&softsp->ds1287_mutex);
445 	if (softsp->monitor_on == clone)
446 		softsp->monitor_on = 0;
447 	softsp->clones[clone] = 0;
448 	mutex_exit(&softsp->ds1287_mutex);
449 
450 	return (0);
451 }
452 
453 /*ARGSUSED4*/
454 static int
455 ds1287_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
456     cred_t *credp, int *rvalp)
457 {
458 	struct ds1287 *softsp;
459 	int clone;
460 
461 	if ((softsp = ddi_get_soft_state(ds1287_state, instance)) ==
462 	    NULL)
463 		return (ENXIO);
464 
465 	clone = DS1287_MINOR_TO_CLONE(getminor(dev));
466 	switch (cmd) {
467 	case PB_BEGIN_MONITOR:
468 		DPRINTF("ds1287_ioctl: PB_BEGIN_MONITOR is called.\n");
469 		mutex_enter(&softsp->ds1287_mutex);
470 		if (softsp->monitor_on) {
471 			mutex_exit(&softsp->ds1287_mutex);
472 			return (EBUSY);
473 		}
474 		softsp->monitor_on = clone;
475 		mutex_exit(&softsp->ds1287_mutex);
476 		return (0);
477 
478 	case PB_END_MONITOR:
479 		DPRINTF("ds1287_ioctl: PB_END_MONITOR is called.\n");
480 		mutex_enter(&softsp->ds1287_mutex);
481 
482 		/*
483 		 * If PB_END_MONITOR is called without first
484 		 * calling PB_BEGIN_MONITOR, an error will be
485 		 * returned.
486 		 */
487 		if (!softsp->monitor_on) {
488 			mutex_exit(&softsp->ds1287_mutex);
489 			return (ENXIO);
490 		}
491 
492 		/*
493 		 * This clone is not monitoring the button.
494 		 */
495 		if (softsp->monitor_on != clone) {
496 			mutex_exit(&softsp->ds1287_mutex);
497 			return (EINVAL);
498 		}
499 		softsp->monitor_on = 0;
500 		mutex_exit(&softsp->ds1287_mutex);
501 		return (0);
502 
503 	case PB_GET_EVENTS:
504 		DPRINTF("ds1287_ioctl: PB_GET_EVENTS is called.\n");
505 		mutex_enter(&softsp->ds1287_mutex);
506 		if (ddi_copyout((void *)&softsp->events, (void *)arg,
507 		    sizeof (int), mode) != 0) {
508 			mutex_exit(&softsp->ds1287_mutex);
509 			return (EFAULT);
510 		}
511 
512 		/*
513 		 * This ioctl returned the events detected since last
514 		 * call.  Note that any application can get the events
515 		 * and clear the event register.
516 		 */
517 		softsp->events = 0;
518 		mutex_exit(&softsp->ds1287_mutex);
519 		return (0);
520 
521 	/*
522 	 * This ioctl is used by the test suite.
523 	 */
524 	case PB_CREATE_BUTTON_EVENT:
525 		DPRINTF("ds1287_ioctl: PB_CREATE_BUTTON_EVENT is called.\n");
526 		(void) ds1287_intr(NULL);
527 		return (0);
528 
529 	default:
530 		return (ENOTTY);
531 	}
532 }
533 
534 /*ARGSUSED*/
535 static int
536 ds1287_chpoll(dev_t dev, short events, int anyyet,
537     short *reventsp, struct pollhead **phpp)
538 {
539 	struct ds1287 *softsp;
540 
541 	if ((softsp = ddi_get_soft_state(ds1287_state, instance)) == NULL)
542 		return (ENXIO);
543 
544 	mutex_enter(&softsp->ds1287_mutex);
545 	*reventsp = 0;
546 	if (softsp->events)
547 		*reventsp = POLLRDNORM|POLLIN;
548 	else {
549 		if (!anyyet)
550 			*phpp = &softsp->pollhd;
551 	}
552 	mutex_exit(&softsp->ds1287_mutex);
553 
554 	return (0);
555 }
556 
557 static void
558 ds1287_log_message(void)
559 {
560 	struct ds1287 *softsp;
561 
562 	if ((softsp = ddi_get_soft_state(ds1287_state, instance)) == NULL) {
563 		cmn_err(CE_WARN, "ds1287: Failed to get internal state!");
564 		return;
565 	}
566 
567 	mutex_enter(&softsp->ds1287_mutex);
568 	softsp->shutdown_pending = 0;
569 	cmn_err(CE_WARN, "ds1287: Failed to shut down the system!");
570 	mutex_exit(&softsp->ds1287_mutex);
571 }
572 
573 /*
574  * To facilitate a power button abort, ds1287_intr() now posts
575  * a softint (calling ds1287_softintr()) for all power button presses and
576  * counts the number of button presses. An abort is issued if the desired
577  * number of button presses within the given time interval.
578  *
579  * Two variables are used to synchronize between the high level intr;
580  * the softint handler and timeout handler
581  *
582  * power_button_cancel  - Indicates that an abort happened and the number
583  *                        of outstanding timeouts that have to be cancelled
584  *
585  * power_button_pressed - Indicates the number of button presses outstanding
586  *                        which have not been serviced
587  */
588 /*ARGSUSED*/
589 static uint_t
590 ds1287_intr(caddr_t ignore)
591 {
592 	hrtime_t tstamp;
593 	static hrtime_t o_tstamp = 0;
594 	static hrtime_t power_button_tstamp = 0;
595 	static int power_button_cnt;
596 	uint8_t	apcr1;
597 
598 	/*
599 	 * Stop the Fail-safe timer that starts running
600 	 * after power button is pressed.  If it is not
601 	 * stopped in 21 seconds, system powers off.
602 	 */
603 	mutex_enter(&ds1287_reg_mutex);
604 	select_bank(2);
605 	DS1287_ADDR_REG = APC_APCR1;
606 	apcr1 = DS1287_DATA_REG;
607 	apcr1 |= APC_FSTRC;
608 	DS1287_DATA_REG = apcr1;
609 	select_bank(1);
610 	mutex_exit(&ds1287_reg_mutex);
611 
612 	tstamp = gethrtime();
613 
614 	/* need to deal with power button debounce */
615 	if (o_tstamp && (tstamp - o_tstamp) < power_button_debounce) {
616 		o_tstamp = tstamp;
617 		return (DDI_INTR_CLAIMED);
618 	}
619 	o_tstamp = tstamp;
620 
621 	power_button_cnt++;
622 
623 	mutex_enter(&ds1287_reg_mutex);
624 	power_button_pressed++;
625 	mutex_exit(&ds1287_reg_mutex);
626 
627 	/*
628 	 * If power button abort is enabled and power button was pressed
629 	 * power_button_abort_presses times within power_button_abort_interval
630 	 * then call abort_sequence_enter();
631 	 */
632 	if (power_button_abort_enable) {
633 		if (power_button_abort_presses == 1 ||
634 		    tstamp < (power_button_tstamp +
635 		    power_button_abort_interval)) {
636 			if (power_button_cnt == power_button_abort_presses) {
637 				mutex_enter(&ds1287_reg_mutex);
638 				power_button_cancel += power_button_timeouts;
639 				power_button_pressed = 0;
640 				mutex_exit(&ds1287_reg_mutex);
641 				power_button_cnt = 0;
642 				abort_sequence_enter("Power Button Abort");
643 				return (DDI_INTR_CLAIMED);
644 			}
645 		} else {
646 			power_button_cnt = 1;
647 			power_button_tstamp = tstamp;
648 		}
649 	}
650 
651 	if (!power_button_enable)
652 		return (DDI_INTR_CLAIMED);
653 
654 	/* post softint to issue timeout for power button action */
655 	ddi_trigger_softintr(ds1287_softintr_id);
656 
657 	return (DDI_INTR_CLAIMED);
658 }
659 
660 /*
661  * Handle the softints....
662  *
663  * If only one softint is posted for several button presses, record
664  * the number of additional presses just incase this was actually not quite
665  * an Abort sequence so that we can log this event later.
666  *
667  * Issue a timeout with a duration being a fraction larger than
668  * the specified Abort interval inorder to perform a power down if required.
669  */
670 static uint_t
671 ds1287_softintr(caddr_t arg)
672 {
673 	struct ds1287 *softsp = (struct ds1287 *)arg;
674 
675 	DPRINTF("ds1287_softintr\n");
676 
677 	if (!power_button_abort_enable)
678 		return (ds1287_issue_shutdown(arg));
679 
680 	mutex_enter(&ds1287_reg_mutex);
681 	if (!power_button_pressed) {
682 		mutex_exit(&ds1287_reg_mutex);
683 		return (DDI_INTR_CLAIMED);
684 	}
685 
686 	/*
687 	 * Schedule a timeout to do the necessary
688 	 * work for shutdown, only one timeout for
689 	 * n presses if power button was pressed
690 	 * more than once before softint fired
691 	 */
692 	if (power_button_pressed > 1)
693 		additional_presses += power_button_pressed - 1;
694 
695 	timeout_cancel = 0;
696 	power_button_pressed = 0;
697 	power_button_timeouts++;
698 	mutex_exit(&ds1287_reg_mutex);
699 	(void) timeout((void(*)(void *))ds1287_timeout,
700 	    softsp, NSEC_TO_TICK(power_button_abort_interval) +
701 	    ABORT_INCREMENT_DELAY);
702 
703 	return (DDI_INTR_CLAIMED);
704 }
705 
706 /*
707  * Upon receiving a timeout the following is determined:
708  *
709  * If an  Abort sequence was issued, then we cancel all outstanding timeouts
710  * and additional presses prior to the Abort sequence.
711  *
712  * If we had multiple timeouts issued and the abort sequence was not met,
713  * then we had more than one button press to power down the machine. We
714  * were probably trying to issue an abort. So log a message indicating this
715  * and cancel all outstanding timeouts.
716  *
717  * If we had just one timeout and the abort sequence was not met then
718  * we really did want to power down the machine, so call ds1287_issue_shutdown()
719  * to do the work and schedule a power down
720  */
721 static void
722 ds1287_timeout(caddr_t arg)
723 {
724 	static int first = 0;
725 
726 	DPRINTF("ds1287_timeout\n");
727 
728 	/*
729 	 * Abort was generated cancel all outstanding power
730 	 * button timeouts
731 	 */
732 	mutex_enter(&ds1287_reg_mutex);
733 	if (power_button_cancel) {
734 		power_button_cancel--;
735 		power_button_timeouts--;
736 		if (!first) {
737 			first++;
738 			additional_presses = 0;
739 		}
740 		mutex_exit(&ds1287_reg_mutex);
741 		return;
742 	}
743 	first = 0;
744 
745 	/*
746 	 * We get here if the timeout(s) have fired and they were
747 	 * not issued prior to an abort.
748 	 *
749 	 * If we had more than one press in the interval we were
750 	 * probably trying to issue an abort, but didnt press the
751 	 * required number within the interval. Hence cancel all
752 	 * timeouts and do not continue towards shutdown.
753 	 */
754 	if (!timeout_cancel) {
755 		timeout_cancel = power_button_timeouts +
756 		    additional_presses;
757 
758 		power_button_timeouts--;
759 		if (!power_button_timeouts)
760 			additional_presses = 0;
761 
762 		if (timeout_cancel > 1) {
763 			mutex_exit(&ds1287_reg_mutex);
764 			cmn_err(CE_NOTE, "Power Button pressed "
765 			    "%d times, cancelling all requests",
766 			    timeout_cancel);
767 			return;
768 		}
769 		mutex_exit(&ds1287_reg_mutex);
770 
771 		/* Go and do the work to request shutdown */
772 		(void) ds1287_issue_shutdown(arg);
773 		return;
774 	}
775 
776 	power_button_timeouts--;
777 	if (!power_button_timeouts)
778 		additional_presses = 0;
779 	mutex_exit(&ds1287_reg_mutex);
780 }
781 
782 static uint_t
783 ds1287_issue_shutdown(caddr_t arg)
784 {
785 	struct ds1287 *softsp = (struct ds1287 *)arg;
786 
787 	DPRINTF("ds1287_issue_shutdown\n");
788 
789 	mutex_enter(&softsp->ds1287_mutex);
790 	softsp->events |= PB_BUTTON_PRESS;
791 	if (softsp->monitor_on != 0) {
792 		mutex_exit(&softsp->ds1287_mutex);
793 		pollwakeup(&softsp->pollhd, POLLRDNORM);
794 		pollwakeup(&softsp->pollhd, POLLIN);
795 		return (DDI_INTR_CLAIMED);
796 	}
797 
798 	if (!softsp->shutdown_pending) {
799 		cmn_err(CE_WARN, "Power button is pressed, powering down "
800 		    "the system!");
801 		softsp->shutdown_pending = 1;
802 		do_shutdown();
803 
804 		/*
805 		 * Wait a while for "do_shutdown()" to shut down the system
806 		 * before logging an error message.
807 		 */
808 		(void) timeout((void(*)(void *))ds1287_log_message, NULL,
809 		    100 * hz);
810 	}
811 	mutex_exit(&softsp->ds1287_mutex);
812 
813 	return (DDI_INTR_CLAIMED);
814 }
815 
816 /*
817  * Read the current time from the clock chip and convert to UNIX form.
818  * Assumes that the year in the clock chip is valid.
819  * Must be called with tod_lock held.
820  */
821 static timestruc_t
822 todds_get(void)
823 {
824 	timestruc_t ts;
825 	todinfo_t tod;
826 	struct rtc_t rtc;
827 
828 	ASSERT(MUTEX_HELD(&tod_lock));
829 
830 	read_rtc(&rtc);
831 	DPRINTF("todds_get: century=%d year=%d dom=%d hrs=%d\n",
832 	    rtc.rtc_century, rtc.rtc_year, rtc.rtc_dom, rtc.rtc_hrs);
833 
834 	/*
835 	 * tod_year is base 1900 so this code needs to adjust the true
836 	 * year retrieved from the rtc's century and year fields.
837 	 */
838 	tod.tod_year	= rtc.rtc_year + (rtc.rtc_century * 100) - 1900;
839 	tod.tod_month	= rtc.rtc_mon;
840 	tod.tod_day	= rtc.rtc_dom;
841 	tod.tod_dow	= rtc.rtc_dow;
842 	tod.tod_hour	= rtc.rtc_hrs;
843 	tod.tod_min	= rtc.rtc_min;
844 	tod.tod_sec	= rtc.rtc_sec;
845 
846 	ts.tv_sec = tod_to_utc(tod);
847 	ts.tv_nsec = 0;
848 
849 	/* set the hw watchdog timer if it's been activated */
850 	if (watchdog_activated) {
851 		int ret = 0;
852 		ret = tod_ops.tod_set_watchdog_timer(watchdog_timeout_seconds);
853 		if (ret == 0)
854 			cmn_err(CE_WARN, "ds1287: failed to set hardware "
855 			    "watchdog timer.");
856 	}
857 
858 	return (ts);
859 }
860 
861 void
862 read_rtc(struct rtc_t *rtc)
863 {
864 	uint8_t regb;
865 
866 	/*
867 	 * Some SuperIO tod devices don't seem to properly initialize
868 	 * the CADDR register to place the Century register at bank 1
869 	 * address 0x48.
870 	 */
871 	mutex_enter(&ds1287_reg_mutex);
872 
873 	select_bank(2);
874 	DS1287_ADDR_REG = RTC_CADDR;
875 	regb = DS1287_DATA_REG;
876 	if (regb != 0xc8) {
877 		if (!ds1287_caddr_warn) {
878 			ds1287_caddr_warn = 1;
879 			cmn_err(CE_WARN, "ds1287: century address register "
880 			    "incorrect (exp 0xc8, obs %x)", regb);
881 		}
882 		DS1287_DATA_REG = 0xc8;
883 	}
884 
885 	select_bank(1);
886 	/*
887 	 * Freeze clock update
888 	 */
889 	DS1287_ADDR_REG = RTC_B;
890 	regb = DS1287_DATA_REG;
891 	DS1287_DATA_REG = (regb | RTC_SET);
892 
893 	DS1287_ADDR_REG = RTC_SEC;
894 	rtc->rtc_sec = DS1287_DATA_REG;
895 	DS1287_ADDR_REG = RTC_ASEC;
896 	rtc->rtc_asec = DS1287_DATA_REG;
897 	DS1287_ADDR_REG = RTC_MIN;
898 	rtc->rtc_min = DS1287_DATA_REG;
899 	DS1287_ADDR_REG = RTC_AMIN;
900 	rtc->rtc_amin = DS1287_DATA_REG;
901 	DS1287_ADDR_REG = RTC_HRS;
902 	rtc->rtc_hrs = DS1287_DATA_REG;
903 	DS1287_ADDR_REG = RTC_AHRS;
904 	rtc->rtc_ahrs = DS1287_DATA_REG;
905 	DS1287_ADDR_REG = RTC_DOW;
906 	rtc->rtc_dow = DS1287_DATA_REG;
907 	DS1287_ADDR_REG = RTC_DOM;
908 	rtc->rtc_dom = DS1287_DATA_REG;
909 	DS1287_ADDR_REG = RTC_MON;
910 	rtc->rtc_mon = DS1287_DATA_REG;
911 	DS1287_ADDR_REG = RTC_YEAR;
912 	rtc->rtc_year = DS1287_DATA_REG;
913 	DS1287_ADDR_REG = RTC_CENTURY;
914 	rtc->rtc_century = DS1287_DATA_REG;
915 
916 	/* Read date alarm */
917 	DS1287_ADDR_REG = RTC_ADOM;
918 	rtc->rtc_adom = DS1287_DATA_REG;
919 	DS1287_ADDR_REG = RTC_AMON;
920 	rtc->rtc_amon = DS1287_DATA_REG;
921 
922 	/* Read wakeup data */
923 	select_bank(2);
924 	DS1287_ADDR_REG = APC_WDWR;
925 	rtc->apc_wdwr = DS1287_DATA_REG;
926 	DS1287_ADDR_REG = APC_WDMR;
927 	rtc->apc_wdmr = DS1287_DATA_REG;
928 	DS1287_ADDR_REG = APC_WMR;
929 	rtc->apc_wmr = DS1287_DATA_REG;
930 	DS1287_ADDR_REG = APC_WYR;
931 	rtc->apc_wyr = DS1287_DATA_REG;
932 	DS1287_ADDR_REG = APC_WCR;
933 	rtc->apc_wcr = DS1287_DATA_REG;
934 
935 	/*
936 	 * Unfreeze clock update
937 	 */
938 	DS1287_ADDR_REG = RTC_B;
939 	DS1287_DATA_REG = regb;
940 
941 	mutex_exit(&ds1287_reg_mutex);
942 }
943 
944 /*
945  * Write the specified time into the clock chip.
946  * Must be called with tod_lock held.
947  */
948 static void
949 todds_set(timestruc_t ts)
950 {
951 	struct rtc_t	rtc;
952 	todinfo_t tod = utc_to_tod(ts.tv_sec);
953 	int year;
954 
955 	ASSERT(MUTEX_HELD(&tod_lock));
956 
957 	/* tod_year is base 1900 so this code needs to adjust */
958 	year = 1900 + tod.tod_year;
959 	rtc.rtc_year	= year % 100;
960 	rtc.rtc_century = year / 100;
961 	rtc.rtc_mon	= (uint8_t)tod.tod_month;
962 	rtc.rtc_dom	= (uint8_t)tod.tod_day;
963 	rtc.rtc_dow	= (uint8_t)tod.tod_dow;
964 	rtc.rtc_hrs	= (uint8_t)tod.tod_hour;
965 	rtc.rtc_min	= (uint8_t)tod.tod_min;
966 	rtc.rtc_sec	= (uint8_t)tod.tod_sec;
967 	DPRINTF("todds_set: century=%d year=%d dom=%d hrs=%d\n",
968 	    rtc.rtc_century, rtc.rtc_year, rtc.rtc_dom, rtc.rtc_hrs);
969 
970 	write_rtc_time(&rtc);
971 }
972 
973 void
974 write_rtc_time(struct rtc_t *rtc)
975 {
976 	uint8_t	regb;
977 
978 	/*
979 	 * Some SuperIO tod devices don't seem to properly initialize
980 	 * the CADDR register to place the Century register at bank 1
981 	 * address 0x48.
982 	 */
983 	mutex_enter(&ds1287_reg_mutex);
984 
985 	select_bank(2);
986 	DS1287_ADDR_REG = RTC_CADDR;
987 	regb = DS1287_DATA_REG;
988 	if (regb != 0xc8) {
989 		if (!ds1287_caddr_warn) {
990 			ds1287_caddr_warn = 1;
991 			cmn_err(CE_WARN, "ds1287: century address register "
992 			    "incorrect (exp 0xc8, obs %x)", regb);
993 		}
994 		DS1287_DATA_REG = 0xc8;
995 	}
996 
997 	select_bank(1);
998 
999 	/*
1000 	 * Freeze
1001 	 */
1002 	DS1287_ADDR_REG = RTC_B;
1003 	regb = DS1287_DATA_REG;
1004 
1005 	DS1287_DATA_REG = (regb | RTC_SET);
1006 
1007 	DS1287_ADDR_REG = RTC_SEC;
1008 	DS1287_DATA_REG = rtc->rtc_sec;
1009 	DS1287_ADDR_REG = RTC_MIN;
1010 	DS1287_DATA_REG = rtc->rtc_min;
1011 	DS1287_ADDR_REG = RTC_HRS;
1012 	DS1287_DATA_REG = rtc->rtc_hrs;
1013 	DS1287_ADDR_REG = RTC_DOW;
1014 	DS1287_DATA_REG = rtc->rtc_dow;
1015 	DS1287_ADDR_REG = RTC_DOM;
1016 	DS1287_DATA_REG = rtc->rtc_dom;
1017 	DS1287_ADDR_REG = RTC_MON;
1018 	DS1287_DATA_REG = rtc->rtc_mon;
1019 	DS1287_ADDR_REG = RTC_YEAR;
1020 	DS1287_DATA_REG = rtc->rtc_year;
1021 	DS1287_ADDR_REG = RTC_CENTURY;
1022 	DS1287_DATA_REG = rtc->rtc_century;
1023 
1024 	/*
1025 	 * Unfreeze
1026 	 */
1027 	DS1287_ADDR_REG = RTC_B;
1028 	DS1287_DATA_REG = regb;
1029 
1030 	mutex_exit(&ds1287_reg_mutex);
1031 }
1032 
1033 void
1034 write_rtc_alarm(struct rtc_t *rtc)
1035 {
1036 	mutex_enter(&ds1287_reg_mutex);
1037 
1038 	select_bank(1);
1039 	DS1287_ADDR_REG = RTC_ASEC;
1040 	DS1287_DATA_REG = rtc->rtc_asec;
1041 	DS1287_ADDR_REG = RTC_AMIN;
1042 	DS1287_DATA_REG = rtc->rtc_amin;
1043 	DS1287_ADDR_REG = RTC_AHRS;
1044 	DS1287_DATA_REG = rtc->rtc_ahrs;
1045 	DS1287_ADDR_REG = RTC_ADOM;
1046 	DS1287_DATA_REG = rtc->rtc_adom;
1047 	DS1287_ADDR_REG = RTC_AMON;
1048 	DS1287_DATA_REG = rtc->rtc_amon;
1049 
1050 	select_bank(2);
1051 	DS1287_ADDR_REG = APC_WDWR;
1052 	DS1287_DATA_REG = rtc->apc_wdwr;
1053 	DS1287_ADDR_REG = APC_WDMR;
1054 	DS1287_DATA_REG = rtc->apc_wdmr;
1055 	DS1287_ADDR_REG = APC_WMR;
1056 	DS1287_DATA_REG = rtc->apc_wmr;
1057 	DS1287_ADDR_REG = APC_WYR;
1058 	DS1287_DATA_REG = rtc->apc_wyr;
1059 	DS1287_ADDR_REG = APC_WCR;
1060 	DS1287_DATA_REG = rtc->apc_wcr;
1061 
1062 	mutex_exit(&ds1287_reg_mutex);
1063 }
1064 
1065 /*
1066  * program the rtc registers for alarm to go off at the specified time
1067  */
1068 static void
1069 todds_set_power_alarm(timestruc_t ts)
1070 {
1071 	todinfo_t	tod;
1072 	uint8_t		apcr2;
1073 	struct rtc_t	rtc;
1074 
1075 	ASSERT(MUTEX_HELD(&tod_lock));
1076 	tod = utc_to_tod(ts.tv_sec);
1077 	mutex_enter(&ds1287_reg_mutex);
1078 
1079 	/* Clear Time Match Detect */
1080 	select_bank(2);
1081 	DS1287_ADDR_REG = APC_APSR;
1082 	apcr2 = DS1287_DATA_REG;
1083 
1084 	/* Disable Time Match Enable */
1085 	DS1287_ADDR_REG = APC_APCR2;
1086 	apcr2 = DS1287_DATA_REG;
1087 	DS1287_DATA_REG = (apcr2 & (~APC_TME));
1088 
1089 	mutex_exit(&ds1287_reg_mutex);
1090 
1091 	rtc.rtc_asec = (uint8_t)tod.tod_sec;
1092 	rtc.rtc_amin = (uint8_t)tod.tod_min;
1093 	rtc.rtc_ahrs = (uint8_t)tod.tod_hour;
1094 	rtc.rtc_adom = (uint8_t)tod.tod_day;
1095 	rtc.rtc_amon = (uint8_t)tod.tod_month;
1096 
1097 	rtc.apc_wdwr = (uint8_t)tod.tod_dow;
1098 	rtc.apc_wdmr = (uint8_t)tod.tod_day;
1099 	rtc.apc_wmr = (uint8_t)tod.tod_month;
1100 	rtc.apc_wyr = tod.tod_year % 100;
1101 	rtc.apc_wcr = (tod.tod_year / 100) + 19;
1102 
1103 	write_rtc_alarm(&rtc);
1104 
1105 	mutex_enter(&ds1287_reg_mutex);
1106 	/* Enable Time Match enable */
1107 	select_bank(2);
1108 	DS1287_ADDR_REG = APC_APCR2;
1109 	DS1287_DATA_REG = (apcr2 | APC_TME);
1110 
1111 	mutex_exit(&ds1287_reg_mutex);
1112 }
1113 
1114 /*
1115  * clear alarm interrupt
1116  */
1117 static void
1118 todds_clear_power_alarm(void)
1119 {
1120 	uint8_t	apcr2;
1121 
1122 	ASSERT(MUTEX_HELD(&tod_lock));
1123 
1124 	mutex_enter(&ds1287_reg_mutex);
1125 
1126 	/* Clear Time Match Detect */
1127 	select_bank(2);
1128 	DS1287_ADDR_REG = APC_APSR;
1129 	apcr2 = DS1287_DATA_REG;
1130 
1131 	/* Disable Time Match Enable */
1132 	DS1287_ADDR_REG = APC_APCR2;
1133 	apcr2 = DS1287_DATA_REG;
1134 	DS1287_DATA_REG = (apcr2 & (~APC_TME));
1135 
1136 	mutex_exit(&ds1287_reg_mutex);
1137 }
1138 
1139 /*
1140  * Determine the cpu frequency by watching the TOD chip rollover twice.
1141  * Cpu clock rate is determined by computing the ticks added (in tick register)
1142  * during one second interval on TOD.
1143  */
1144 uint64_t
1145 todds_get_cpufrequency(void)
1146 {
1147 	uint64_t cpu_freq;
1148 
1149 	ASSERT(MUTEX_HELD(&tod_lock));
1150 	mutex_enter(&ds1287_reg_mutex);
1151 
1152 	select_bank(1);
1153 	DS1287_ADDR_REG = RTC_SEC;
1154 	cpu_freq = find_cpufrequency(v_rtc_data_reg);
1155 
1156 	mutex_exit(&ds1287_reg_mutex);
1157 	return (cpu_freq);
1158 }
1159 
1160 static void
1161 select_bank(int bank)
1162 {
1163 	uint8_t	rega;
1164 	int banksel;
1165 
1166 	/* Select Bank 1 */
1167 	DS1287_ADDR_REG = RTC_A;
1168 	rega = DS1287_DATA_REG;
1169 	rega = rega & ~(RTC_DIV0 | RTC_DIV1 | RTC_DIV2);
1170 	switch (bank) {
1171 	case 0:
1172 		banksel = RTC_DIV1;
1173 		break;
1174 	case 1:
1175 		banksel = RTC_DIV0 | RTC_DIV1;
1176 		break;
1177 	case 2:
1178 		banksel = RTC_DIV2;
1179 		break;
1180 	}
1181 	rega |= banksel;
1182 	DS1287_DATA_REG = rega;
1183 }
1184 
1185 /*ARGSUSED*/
1186 static uint_t
1187 todds_set_watchdog_timer(uint_t timeoutval)
1188 {
1189 	ASSERT(MUTEX_HELD(&tod_lock));
1190 	return (0);
1191 }
1192 
1193 static uint_t
1194 todds_clear_watchdog_timer(void)
1195 {
1196 	ASSERT(MUTEX_HELD(&tod_lock));
1197 	return (0);
1198 }
1199