8354 sync regcomp(3C) with upstream (fix make catalog)
[unleashed/tickless.git] / usr / src / uts / sun4u / io / todmostek.c
blobd9bbca3a9f0c07446b7e3a0b006c71394e8216dd
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * tod driver module for Mostek M48T59 part
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/sysmacros.h>
33 #include <sys/systm.h>
34 #include <sys/errno.h>
35 #include <sys/modctl.h>
36 #include <sys/autoconf.h>
37 #include <sys/debug.h>
38 #include <sys/clock.h>
39 #include <sys/todmostek.h>
40 #include <sys/reboot.h>
41 #include <sys/cmn_err.h>
42 #include <sys/cpuvar.h>
44 static timestruc_t todm_get(void);
45 static void todm_set(timestruc_t);
46 static uint_t todm_set_watchdog_timer(uint_t);
47 static uint_t todm_clear_watchdog_timer(void);
48 static void todm_set_power_alarm(timestruc_t);
49 static void todm_clear_power_alarm(void);
50 static uint64_t todm_get_cpufrequency(void);
52 static uchar_t watchdog_bits = 0;
53 static uint_t watchdog_timeout;
55 extern uint64_t find_cpufrequency(volatile uchar_t *);
58 * Module linkage information for the kernel.
60 static struct modlmisc modlmisc = {
61 &mod_miscops, "tod module for Mostek M48T59"
64 static struct modlinkage modlinkage = {
65 MODREV_1, (void *)&modlmisc, NULL
68 int
69 _init(void)
71 if (strcmp(tod_module_name, "todmostek") == 0) {
72 tod_ops.tod_get = todm_get;
73 tod_ops.tod_set = todm_set;
74 tod_ops.tod_set_watchdog_timer = todm_set_watchdog_timer;
75 tod_ops.tod_clear_watchdog_timer = todm_clear_watchdog_timer;
76 tod_ops.tod_set_power_alarm = todm_set_power_alarm;
77 tod_ops.tod_clear_power_alarm = todm_clear_power_alarm;
78 tod_ops.tod_get_cpufrequency = todm_get_cpufrequency;
81 * check if hardware watchdog timer is available and user
82 * enabled it.
84 if (watchdog_enable) {
85 if (!watchdog_available) {
86 cmn_err(CE_WARN,
87 "Hardware watchdog unavailable");
88 } else if (boothowto & RB_DEBUG) {
89 cmn_err(CE_WARN, "Hardware watchdog disabled"
90 " [debugger]");
95 return (mod_install(&modlinkage));
98 int
99 _fini(void)
101 if (strcmp(tod_module_name, "todmostek") == 0)
102 return (EBUSY);
103 else
104 return (mod_remove(&modlinkage));
108 _info(struct modinfo *modinfop)
110 return (mod_info(&modlinkage, modinfop));
114 * Read the current time from the clock chip and convert to UNIX form.
115 * Assumes that the year in the clock chip is valid.
116 * Must be called with tod_lock held.
118 static timestruc_t
119 todm_get(void)
121 timestruc_t ts;
122 todinfo_t tod;
123 int s;
125 ASSERT(MUTEX_HELD(&tod_lock));
127 s = splhi();
129 CLOCK->clk_ctrl |= CLK_CTRL_READ;
130 tod.tod_year = BCD_TO_BYTE(CLOCK->clk_year) + YRBASE;
131 tod.tod_month = BCD_TO_BYTE(CLOCK->clk_month & 0x1f);
132 tod.tod_day = BCD_TO_BYTE(CLOCK->clk_day & 0x3f);
133 tod.tod_dow = BCD_TO_BYTE(CLOCK->clk_weekday & 0x7);
134 tod.tod_hour = BCD_TO_BYTE(CLOCK->clk_hour & 0x3f);
135 tod.tod_min = BCD_TO_BYTE(CLOCK->clk_min & 0x7f);
136 tod.tod_sec = BCD_TO_BYTE(CLOCK->clk_sec & 0x7f);
137 CLOCK->clk_ctrl &= ~CLK_CTRL_READ;
139 splx(s);
142 * Apparently the m48t59 doesn't quite do what the spec sheet says.
143 * The spec says reading WRD will reset the timer but that doesn't work.
144 * So we need to reload timeout each time we want to reset the timer.
146 CLOCK->clk_watchdog = watchdog_bits;
148 ts.tv_sec = tod_to_utc(tod);
149 ts.tv_nsec = 0;
150 return (ts);
154 * Write the specified time into the clock chip.
155 * Must be called with tod_lock held.
157 /* ARGSUSED */
158 static void
159 todm_set(timestruc_t ts)
161 todinfo_t tod = utc_to_tod(ts.tv_sec);
163 ASSERT(MUTEX_HELD(&tod_lock));
165 CLOCK->clk_ctrl |= CLK_CTRL_WRITE; /* allow writes */
166 CLOCK->clk_year = BYTE_TO_BCD(tod.tod_year - YRBASE);
167 CLOCK->clk_month = BYTE_TO_BCD(tod.tod_month);
168 CLOCK->clk_day = BYTE_TO_BCD(tod.tod_day);
169 CLOCK->clk_weekday = BYTE_TO_BCD(tod.tod_dow);
170 CLOCK->clk_hour = BYTE_TO_BCD(tod.tod_hour);
171 CLOCK->clk_min = BYTE_TO_BCD(tod.tod_min);
172 CLOCK->clk_sec = BYTE_TO_BCD(tod.tod_sec);
173 CLOCK->clk_ctrl &= ~CLK_CTRL_WRITE; /* load values */
178 * Program the watchdog timer shadow register with the specified value.
179 * Setting the timer to zero value means no watchdog timeout.
181 static uint_t
182 todm_set_watchdog_timer(uint_t timeoutval)
184 ASSERT(MUTEX_HELD(&tod_lock));
186 if (watchdog_enable == 0 || watchdog_available == 0 ||
187 (boothowto & RB_DEBUG))
188 return (0);
190 watchdog_timeout = timeoutval;
191 watchdog_bits = CLK_WATCHDOG_BITS(timeoutval);
192 watchdog_activated = 1;
194 return (timeoutval);
198 * Clear the hardware timer register. Also zero out the watchdog timer
199 * shadow register.
201 static uint_t
202 todm_clear_watchdog_timer(void)
204 ASSERT(MUTEX_HELD(&tod_lock));
206 if (watchdog_activated == 0)
207 return (0);
209 CLOCK->clk_watchdog = 0;
211 watchdog_bits = 0;
212 watchdog_activated = 0;
213 return (watchdog_timeout);
217 * program the tod registers for alarm to go off at the specified time
219 static void
220 todm_set_power_alarm(timestruc_t ts)
222 todinfo_t tod;
223 uchar_t c;
225 ASSERT(MUTEX_HELD(&tod_lock));
226 tod = utc_to_tod(ts.tv_sec);
228 c = CLOCK->clk_flags; /* clear alarm intr flag by reading the reg */
229 #ifdef lint
230 CLOCK->clk_flags = c;
231 #endif
232 CLOCK->clk_interrupts &= ~CLK_ALARM_ENABLE; /* disable alarm intr */
234 CLOCK->clk_day &= ~CLK_FREQT; /* keep Freqency Test bit cleared */
236 CLOCK->clk_alm_day = BYTE_TO_BCD(tod.tod_day);
237 CLOCK->clk_alm_hours = BYTE_TO_BCD(tod.tod_hour);
238 CLOCK->clk_alm_mins = BYTE_TO_BCD(tod.tod_min);
239 CLOCK->clk_alm_secs = BYTE_TO_BCD(tod.tod_sec);
241 CLOCK->clk_interrupts |= CLK_ALARM_ENABLE; /* enable alarm intr */
245 * clear alarm interrupt
247 static void
248 todm_clear_power_alarm()
250 uchar_t c;
252 ASSERT(MUTEX_HELD(&tod_lock));
254 c = CLOCK->clk_flags; /* clear alarm intr flag by reading the reg */
256 #ifdef lint
257 CLOCK->clk_flags = c;
258 #endif
260 CLOCK->clk_interrupts &= ~CLK_ALARM_ENABLE; /* disable alarm intr */
264 * Determine the cpu frequency by watching the TOD chip rollover twice.
265 * Cpu clock rate is determined by computing the ticks added (in tick register)
266 * during one second interval on TOD.
268 uint64_t
269 todm_get_cpufrequency(void)
271 ASSERT(MUTEX_HELD(&tod_lock));
273 return (find_cpufrequency(&(TIMECHECK_CLOCK->clk_sec)));