todds1287.c revision 7656:2621e50fdf4a
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
70static timestruc_t todds_get(void);
71static void todds_set(timestruc_t);
72static uint_t todds_set_watchdog_timer(uint_t);
73static uint_t todds_clear_watchdog_timer(void);
74static void todds_set_power_alarm(timestruc_t);
75static void todds_clear_power_alarm(void);
76static uint64_t todds_get_cpufrequency(void);
77
78extern uint64_t find_cpufrequency(volatile uint8_t *);
79
80/*
81 * External variables
82 */
83extern int	watchdog_activated;
84extern uint_t	watchdog_timeout_seconds;
85extern volatile uint8_t	*v_pmc_addr_reg;
86
87/*
88 * Global variables
89 */
90int ds1287_debug_flags;
91int ds1287_caddr_warn;
92
93/*
94 * cb ops
95 */
96static int ds1287_open(dev_t *, int, int, cred_t *);
97static int ds1287_close(dev_t, int, int, cred_t *);
98static int ds1287_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
99static int ds1287_chpoll(dev_t, short, int, short *, struct pollhead **);
100
101static void read_rtc(struct rtc_t *);
102static void write_rtc_time(struct rtc_t *);
103static void write_rtc_alarm(struct rtc_t *);
104static void select_bank(int bank);
105static uint_t ds1287_intr(caddr_t);
106static uint_t ds1287_softintr(caddr_t);
107static void ds1287_timeout(caddr_t);
108static uint_t ds1287_issue_shutdown(caddr_t);
109static void ds1287_log_message(void);
110
111static 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 */
135static int ds1287_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
136static int ds1287_attach(dev_info_t *, ddi_attach_cmd_t);
137static int ds1287_detach(dev_info_t *, ddi_detach_cmd_t);
138
139static 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
155static void	*ds1287_state;
156static int	instance = -1;
157
158/* Driver Tunables */
159static int	ds1287_interrupt_priority = 15;
160static int	ds1287_softint_priority = 2;
161static hrtime_t power_button_debounce = NANOSEC/MILLISEC*10;
162static hrtime_t power_button_abort_interval = 1.5 * NANOSEC;
163static int	power_button_abort_presses = 3;
164static int	power_button_abort_enable = 1;
165static int	power_button_enable = 1;
166
167static int	power_button_pressed = 0;
168static int	power_button_cancel = 0;
169static int	power_button_timeouts = 0;
170static int	timeout_cancel = 0;
171static int	additional_presses = 0;
172
173static ddi_iblock_cookie_t ds1287_lo_iblock;
174static ddi_iblock_cookie_t ds1287_hi_iblock;
175static ddi_softintr_t	ds1287_softintr_id;
176static kmutex_t ds1287_reg_mutex;	/* Protects ds1287 Registers */
177
178static 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
184static struct modlinkage modlinkage = {
185	MODREV_1, &modldrv, NULL
186};
187
188
189int
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
237int
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 */
249int
250_info(struct modinfo *modinfop)
251{
252	return (mod_info(&modlinkage, modinfop));
253}
254
255/*ARGSUSED*/
256static int
257ds1287_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
282static int
283ds1287_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", NULL) == 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
366error3:
367	ddi_remove_intr(dip, 0, NULL);
368error2:
369	ddi_remove_softintr(ds1287_softintr_id);
370error1:
371	(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "interrupt-priorities");
372error:
373	ddi_soft_state_free(ds1287_state, instance);
374	return (DDI_FAILURE);
375}
376
377/*ARGSUSED*/
378static int
379ds1287_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*/
397static int
398ds1287_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*/
430static int
431ds1287_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*/
454static int
455ds1287_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*/
535static int
536ds1287_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
557static void
558ds1287_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*/
589static uint_t
590ds1287_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 */
670static uint_t
671ds1287_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 */
721static void
722ds1287_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
782static uint_t
783ds1287_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 */
821static timestruc_t
822todds_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
861void
862read_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 */
948static void
949todds_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
973void
974write_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
1033void
1034write_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 */
1068static void
1069todds_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 */
1117static void
1118todds_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 */
1144uint64_t
1145todds_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
1160static void
1161select_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*/
1186static uint_t
1187todds_set_watchdog_timer(uint_t timeoutval)
1188{
1189	ASSERT(MUTEX_HELD(&tod_lock));
1190	return (0);
1191}
1192
1193static uint_t
1194todds_clear_watchdog_timer(void)
1195{
1196	ASSERT(MUTEX_HELD(&tod_lock));
1197	return (0);
1198}
1199