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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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.
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.
49 * PSARC/1999/393 describes the pbio(7I) interface.
52 #include <sys/types.h>
57 #include <sys/sunddi.h>
59 #include <sys/todds1287.h>
60 #include <sys/modctl.h>
62 #include <sys/clock.h>
63 #include <sys/reboot.h>
64 #include <sys/machsystm.h>
68 #define ABORT_INCREMENT_DELAY 10
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);
78 extern uint64_t find_cpufrequency(volatile uint8_t *);
83 extern int watchdog_activated
;
84 extern uint_t watchdog_timeout_seconds
;
85 extern volatile uint8_t *v_pmc_addr_reg
;
90 int ds1287_debug_flags
;
91 int ds1287_caddr_warn
;
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
**);
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);
111 static struct cb_ops ds1287_cbops
= {
112 ds1287_open
, /* open */
113 ds1287_close
, /* close */
114 nodev
, /* strategy */
119 ds1287_ioctl
, /* ioctl */
123 ds1287_chpoll
, /* poll */
124 ddi_prop_op
, /* cb_prop_op */
125 NULL
, /* streamtab */
126 D_NEW
| D_MP
, /* Driver compatibility flag */
128 nodev
, /* int (*cb_aread)() */
129 nodev
/* int (*cb_awrite)() */
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
);
139 static struct dev_ops ds1287_ops
= {
140 DEVO_REV
, /* devo_rev */
142 ds1287_getinfo
, /* getinfo */
143 nulldev
, /* identify */
145 ds1287_attach
, /* attach */
146 ds1287_detach
, /* detach */
148 &ds1287_cbops
, /* cb_ops */
149 (struct bus_ops
*)NULL
, /* bus_ops */
151 ddi_quiesce_not_supported
, /* devo_quiesce */
155 static void *ds1287_state
;
156 static int instance
= -1;
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;
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;
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 */
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 */
184 static struct modlinkage modlinkage
= {
185 MODREV_1
, &modldrv
, NULL
194 status
= ddi_soft_state_init(&ds1287_state
, sizeof (struct ds1287
), 0);
199 if ((status
= mod_install(&modlinkage
)) != 0) {
200 ddi_soft_state_fini(&ds1287_state
);
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
);
209 mutex_enter(&ds1287_reg_mutex
);
212 DS1287_ADDR_REG
= RTC_B
;
213 DS1287_DATA_REG
= (RTC_DM
| RTC_HM
);
214 mutex_exit(&ds1287_reg_mutex
);
216 tod_ops
.tod_get
= todds_get
;
217 tod_ops
.tod_set
= todds_set
;
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.
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
;
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
;
240 if (strcmp(tod_module_name
, "todds1287") == 0)
243 return (mod_remove(&modlinkage
));
247 * The loadable-module _info(9E) entry point
250 _info(struct modinfo
*modinfop
)
252 return (mod_info(&modlinkage
, modinfop
));
257 ds1287_getinfo(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
,
260 struct ds1287
*softsp
;
263 return (DDI_FAILURE
);
266 case DDI_INFO_DEVT2DEVINFO
:
267 if ((softsp
= ddi_get_soft_state(ds1287_state
, instance
))
269 return (DDI_FAILURE
);
270 *result
= (void *)softsp
->dip
;
271 return (DDI_SUCCESS
);
273 case DDI_INFO_DEVT2INSTANCE
:
274 *result
= (void *)(uintptr_t)instance
;
275 return (DDI_SUCCESS
);
278 return (DDI_FAILURE
);
283 ds1287_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
285 struct ds1287
*softsp
;
287 DPRINTF("ds1287_attach\n");
292 return (DDI_SUCCESS
);
294 return (DDI_FAILURE
);
297 if (instance
!= -1) {
298 cmn_err(CE_WARN
, "ds1287_attach: Another instance is already "
300 return (DDI_FAILURE
);
303 instance
= ddi_get_instance(dip
);
305 if (v_rtc_addr_reg
== NULL
) {
306 cmn_err(CE_WARN
, "ds1287_attach: v_rtc_addr_reg is NULL");
307 return (DDI_FAILURE
);
311 * Allocate softc information.
313 if (ddi_soft_state_zalloc(ds1287_state
, instance
) != DDI_SUCCESS
) {
314 cmn_err(CE_WARN
, "ds1287_attach: Failed to allocate "
316 return (DDI_FAILURE
);
319 softsp
= ddi_get_soft_state(ds1287_state
, instance
);
320 DPRINTF("ds1287_attach: instance=%d softsp=0x%p\n", instance
,
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.");
333 /* add the softint */
334 ds1287_lo_iblock
= (ddi_iblock_cookie_t
)(uintptr_t)
335 ipltospl(ds1287_softint_priority
);
337 if (ddi_add_softintr(dip
, DDI_SOFTINT_FIXED
, &ds1287_softintr_id
,
338 &ds1287_lo_iblock
, NULL
, ds1287_softintr
, (caddr_t
)softsp
) !=
340 cmn_err(CE_WARN
, "ds1287_attach: Failed to add low interrupt.");
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 "
353 * Combination of instance number and clone number 0 is used for
354 * creating the minor node.
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");
364 return (DDI_SUCCESS
);
367 ddi_remove_intr(dip
, 0, NULL
);
369 ddi_remove_softintr(ds1287_softintr_id
);
371 (void) ddi_prop_remove(DDI_DEV_T_NONE
, dip
, "interrupt-priorities");
373 ddi_soft_state_free(ds1287_state
, instance
);
374 return (DDI_FAILURE
);
379 ds1287_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
381 DPRINTF("ds1287_detach\n");
385 * Since it needs to always handle the power button, fail
388 return (DDI_FAILURE
);
390 return (DDI_SUCCESS
);
392 return (DDI_FAILURE
);
398 ds1287_open(dev_t
*devp
, int flags
, int otyp
, cred_t
*credp
)
400 struct ds1287
*softsp
;
403 if (otyp
!= OTYP_CHR
)
406 if ((softsp
= ddi_get_soft_state(ds1287_state
, instance
)) ==
410 mutex_enter(&softsp
->ds1287_mutex
);
411 for (clone
= 1; clone
< DS1287_MAX_CLONE
; clone
++)
412 if (!softsp
->clones
[clone
])
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
);
422 *devp
= makedevice(getmajor(*devp
), (instance
<< 8) + clone
);
423 softsp
->clones
[clone
] = 1;
424 mutex_exit(&softsp
->ds1287_mutex
);
431 ds1287_close(dev_t dev
, int flags
, int otyp
, cred_t
*credp
)
433 struct ds1287
*softsp
;
436 if (otyp
!= OTYP_CHR
)
439 if ((softsp
= ddi_get_soft_state(ds1287_state
, instance
)) ==
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
);
455 ds1287_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
,
456 cred_t
*credp
, int *rvalp
)
458 struct ds1287
*softsp
;
461 if ((softsp
= ddi_get_soft_state(ds1287_state
, instance
)) ==
465 clone
= DS1287_MINOR_TO_CLONE(getminor(dev
));
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
);
474 softsp
->monitor_on
= clone
;
475 mutex_exit(&softsp
->ds1287_mutex
);
479 DPRINTF("ds1287_ioctl: PB_END_MONITOR is called.\n");
480 mutex_enter(&softsp
->ds1287_mutex
);
483 * If PB_END_MONITOR is called without first
484 * calling PB_BEGIN_MONITOR, an error will be
487 if (!softsp
->monitor_on
) {
488 mutex_exit(&softsp
->ds1287_mutex
);
493 * This clone is not monitoring the button.
495 if (softsp
->monitor_on
!= clone
) {
496 mutex_exit(&softsp
->ds1287_mutex
);
499 softsp
->monitor_on
= 0;
500 mutex_exit(&softsp
->ds1287_mutex
);
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
);
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.
518 mutex_exit(&softsp
->ds1287_mutex
);
522 * This ioctl is used by the test suite.
524 case PB_CREATE_BUTTON_EVENT
:
525 DPRINTF("ds1287_ioctl: PB_CREATE_BUTTON_EVENT is called.\n");
526 (void) ds1287_intr(NULL
);
536 ds1287_chpoll(dev_t dev
, short events
, int anyyet
,
537 short *reventsp
, struct pollhead
**phpp
)
539 struct ds1287
*softsp
;
541 if ((softsp
= ddi_get_soft_state(ds1287_state
, instance
)) == NULL
)
544 mutex_enter(&softsp
->ds1287_mutex
);
547 *reventsp
= POLLRDNORM
|POLLIN
;
550 *phpp
= &softsp
->pollhd
;
552 mutex_exit(&softsp
->ds1287_mutex
);
558 ds1287_log_message(void)
560 struct ds1287
*softsp
;
562 if ((softsp
= ddi_get_soft_state(ds1287_state
, instance
)) == NULL
) {
563 cmn_err(CE_WARN
, "ds1287: Failed to get internal state!");
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
);
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.
579 * Two variables are used to synchronize between the high level intr;
580 * the softint handler and timeout handler
582 * power_button_cancel - Indicates that an abort happened and the number
583 * of outstanding timeouts that have to be cancelled
585 * power_button_pressed - Indicates the number of button presses outstanding
586 * which have not been serviced
590 ds1287_intr(caddr_t ignore
)
593 static hrtime_t o_tstamp
= 0;
594 static hrtime_t power_button_tstamp
= 0;
595 static int power_button_cnt
;
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.
603 mutex_enter(&ds1287_reg_mutex
);
605 DS1287_ADDR_REG
= APC_APCR1
;
606 apcr1
= DS1287_DATA_REG
;
608 DS1287_DATA_REG
= apcr1
;
610 mutex_exit(&ds1287_reg_mutex
);
612 tstamp
= gethrtime();
614 /* need to deal with power button debounce */
615 if (o_tstamp
&& (tstamp
- o_tstamp
) < power_button_debounce
) {
617 return (DDI_INTR_CLAIMED
);
623 mutex_enter(&ds1287_reg_mutex
);
624 power_button_pressed
++;
625 mutex_exit(&ds1287_reg_mutex
);
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();
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
);
646 power_button_cnt
= 1;
647 power_button_tstamp
= tstamp
;
651 if (!power_button_enable
)
652 return (DDI_INTR_CLAIMED
);
654 /* post softint to issue timeout for power button action */
655 ddi_trigger_softintr(ds1287_softintr_id
);
657 return (DDI_INTR_CLAIMED
);
661 * Handle the softints....
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.
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.
671 ds1287_softintr(caddr_t arg
)
673 struct ds1287
*softsp
= (struct ds1287
*)arg
;
675 DPRINTF("ds1287_softintr\n");
677 if (!power_button_abort_enable
)
678 return (ds1287_issue_shutdown(arg
));
680 mutex_enter(&ds1287_reg_mutex
);
681 if (!power_button_pressed
) {
682 mutex_exit(&ds1287_reg_mutex
);
683 return (DDI_INTR_CLAIMED
);
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
692 if (power_button_pressed
> 1)
693 additional_presses
+= power_button_pressed
- 1;
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
);
703 return (DDI_INTR_CLAIMED
);
707 * Upon receiving a timeout the following is determined:
709 * If an Abort sequence was issued, then we cancel all outstanding timeouts
710 * and additional presses prior to the Abort sequence.
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.
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
722 ds1287_timeout(caddr_t arg
)
724 static int first
= 0;
726 DPRINTF("ds1287_timeout\n");
729 * Abort was generated cancel all outstanding power
732 mutex_enter(&ds1287_reg_mutex
);
733 if (power_button_cancel
) {
734 power_button_cancel
--;
735 power_button_timeouts
--;
738 additional_presses
= 0;
740 mutex_exit(&ds1287_reg_mutex
);
746 * We get here if the timeout(s) have fired and they were
747 * not issued prior to an abort.
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.
754 if (!timeout_cancel
) {
755 timeout_cancel
= power_button_timeouts
+
758 power_button_timeouts
--;
759 if (!power_button_timeouts
)
760 additional_presses
= 0;
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",
769 mutex_exit(&ds1287_reg_mutex
);
771 /* Go and do the work to request shutdown */
772 (void) ds1287_issue_shutdown(arg
);
776 power_button_timeouts
--;
777 if (!power_button_timeouts
)
778 additional_presses
= 0;
779 mutex_exit(&ds1287_reg_mutex
);
783 ds1287_issue_shutdown(caddr_t arg
)
785 struct ds1287
*softsp
= (struct ds1287
*)arg
;
787 DPRINTF("ds1287_issue_shutdown\n");
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
);
798 if (!softsp
->shutdown_pending
) {
799 cmn_err(CE_WARN
, "Power button is pressed, powering down "
801 softsp
->shutdown_pending
= 1;
805 * Wait a while for "do_shutdown()" to shut down the system
806 * before logging an error message.
808 (void) timeout((void(*)(void *))ds1287_log_message
, NULL
,
811 mutex_exit(&softsp
->ds1287_mutex
);
813 return (DDI_INTR_CLAIMED
);
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.
828 ASSERT(MUTEX_HELD(&tod_lock
));
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
);
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.
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
;
846 ts
.tv_sec
= tod_to_utc(tod
);
849 /* set the hw watchdog timer if it's been activated */
850 if (watchdog_activated
) {
852 ret
= tod_ops
.tod_set_watchdog_timer(watchdog_timeout_seconds
);
854 cmn_err(CE_WARN
, "ds1287: failed to set hardware "
862 read_rtc(struct rtc_t
*rtc
)
867 * Some SuperIO tod devices don't seem to properly initialize
868 * the CADDR register to place the Century register at bank 1
871 mutex_enter(&ds1287_reg_mutex
);
874 DS1287_ADDR_REG
= RTC_CADDR
;
875 regb
= DS1287_DATA_REG
;
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
);
882 DS1287_DATA_REG
= 0xc8;
887 * Freeze clock update
889 DS1287_ADDR_REG
= RTC_B
;
890 regb
= DS1287_DATA_REG
;
891 DS1287_DATA_REG
= (regb
| RTC_SET
);
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
;
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
;
922 /* Read wakeup data */
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
;
936 * Unfreeze clock update
938 DS1287_ADDR_REG
= RTC_B
;
939 DS1287_DATA_REG
= regb
;
941 mutex_exit(&ds1287_reg_mutex
);
945 * Write the specified time into the clock chip.
946 * Must be called with tod_lock held.
949 todds_set(timestruc_t ts
)
952 todinfo_t tod
= utc_to_tod(ts
.tv_sec
);
955 ASSERT(MUTEX_HELD(&tod_lock
));
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
);
970 write_rtc_time(&rtc
);
974 write_rtc_time(struct rtc_t
*rtc
)
979 * Some SuperIO tod devices don't seem to properly initialize
980 * the CADDR register to place the Century register at bank 1
983 mutex_enter(&ds1287_reg_mutex
);
986 DS1287_ADDR_REG
= RTC_CADDR
;
987 regb
= DS1287_DATA_REG
;
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
);
994 DS1287_DATA_REG
= 0xc8;
1002 DS1287_ADDR_REG
= RTC_B
;
1003 regb
= DS1287_DATA_REG
;
1005 DS1287_DATA_REG
= (regb
| RTC_SET
);
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
;
1027 DS1287_ADDR_REG
= RTC_B
;
1028 DS1287_DATA_REG
= regb
;
1030 mutex_exit(&ds1287_reg_mutex
);
1034 write_rtc_alarm(struct rtc_t
*rtc
)
1036 mutex_enter(&ds1287_reg_mutex
);
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
;
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
;
1062 mutex_exit(&ds1287_reg_mutex
);
1066 * program the rtc registers for alarm to go off at the specified time
1069 todds_set_power_alarm(timestruc_t ts
)
1075 ASSERT(MUTEX_HELD(&tod_lock
));
1076 tod
= utc_to_tod(ts
.tv_sec
);
1077 mutex_enter(&ds1287_reg_mutex
);
1079 /* Clear Time Match Detect */
1081 DS1287_ADDR_REG
= APC_APSR
;
1082 apcr2
= DS1287_DATA_REG
;
1084 /* Disable Time Match Enable */
1085 DS1287_ADDR_REG
= APC_APCR2
;
1086 apcr2
= DS1287_DATA_REG
;
1087 DS1287_DATA_REG
= (apcr2
& (~APC_TME
));
1089 mutex_exit(&ds1287_reg_mutex
);
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
;
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;
1103 write_rtc_alarm(&rtc
);
1105 mutex_enter(&ds1287_reg_mutex
);
1106 /* Enable Time Match enable */
1108 DS1287_ADDR_REG
= APC_APCR2
;
1109 DS1287_DATA_REG
= (apcr2
| APC_TME
);
1111 mutex_exit(&ds1287_reg_mutex
);
1115 * clear alarm interrupt
1118 todds_clear_power_alarm(void)
1122 ASSERT(MUTEX_HELD(&tod_lock
));
1124 mutex_enter(&ds1287_reg_mutex
);
1126 /* Clear Time Match Detect */
1128 DS1287_ADDR_REG
= APC_APSR
;
1129 apcr2
= DS1287_DATA_REG
;
1131 /* Disable Time Match Enable */
1132 DS1287_ADDR_REG
= APC_APCR2
;
1133 apcr2
= DS1287_DATA_REG
;
1134 DS1287_DATA_REG
= (apcr2
& (~APC_TME
));
1136 mutex_exit(&ds1287_reg_mutex
);
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.
1145 todds_get_cpufrequency(void)
1149 ASSERT(MUTEX_HELD(&tod_lock
));
1150 mutex_enter(&ds1287_reg_mutex
);
1153 DS1287_ADDR_REG
= RTC_SEC
;
1154 cpu_freq
= find_cpufrequency(v_rtc_data_reg
);
1156 mutex_exit(&ds1287_reg_mutex
);
1161 select_bank(int bank
)
1167 DS1287_ADDR_REG
= RTC_A
;
1168 rega
= DS1287_DATA_REG
;
1169 rega
= rega
& ~(RTC_DIV0
| RTC_DIV1
| RTC_DIV2
);
1175 banksel
= RTC_DIV0
| RTC_DIV1
;
1182 DS1287_DATA_REG
= rega
;
1187 todds_set_watchdog_timer(uint_t timeoutval
)
1189 ASSERT(MUTEX_HELD(&tod_lock
));
1194 todds_clear_watchdog_timer(void)
1196 ASSERT(MUTEX_HELD(&tod_lock
));