8354 sync regcomp(3C) with upstream (fix make catalog)
[unleashed/tickless.git] / usr / src / uts / sun4u / io / todm5819p_rmc.c
blob5e92bebd81876b36d6647cf1851706ffcace8ffd
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 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * tod driver module for ALI M5819P part
31 #include <sys/types.h>
32 #include <sys/conf.h>
33 #include <sys/kmem.h>
34 #include <sys/open.h>
35 #include <sys/ddi.h>
36 #include <sys/sunddi.h>
38 #include <sys/todm5819p.h>
39 #include <sys/rmc_comm_dp.h>
40 #include <sys/rmc_comm_drvintf.h>
41 #include <sys/modctl.h>
42 #include <sys/stat.h>
43 #include <sys/clock.h>
44 #include <sys/reboot.h>
45 #include <sys/machsystm.h>
47 static timestruc_t todm5819p_rmc_get(void);
48 static void todm5819p_rmc_set(timestruc_t);
49 static uint_t todm5819p_rmc_set_watchdog_timer(uint_t);
50 static uint_t todm5819p_rmc_clear_watchdog_timer(void);
51 static void todm5819p_rmc_set_power_alarm(timestruc_t);
52 static void todm5819p_rmc_clear_power_alarm(void);
53 static uint64_t todm5819p_rmc_get_cpufrequency(void);
55 extern uint64_t find_cpufrequency(volatile uint8_t *);
58 * External variables
60 extern int watchdog_enable;
61 extern int watchdog_available;
62 extern int boothowto;
65 * Global variables
67 int m5819p_debug_flags;
70 * Module linkage information for the kernel.
72 static struct modlmisc modlmisc = {
73 &mod_miscops, "tod module for ALI M5819P"
76 static struct modlinkage modlinkage = {
77 MODREV_1, (void *)&modlmisc, NULL
80 static todinfo_t rtc_to_tod(struct rtc_t *);
81 static void read_rtc(struct rtc_t *);
82 static void write_rtc_time(struct rtc_t *);
83 static void write_rtc_alarm(struct rtc_t *);
86 int
87 _init(void)
89 if (strcmp(tod_module_name, "todm5819p_rmc") == 0) {
90 M5819P_ADDR_REG = RTC_B;
91 M5819P_DATA_REG = (RTC_DM | RTC_HM);
93 tod_ops.tod_get = todm5819p_rmc_get;
94 tod_ops.tod_set = todm5819p_rmc_set;
96 tod_ops.tod_set_watchdog_timer =
97 todm5819p_rmc_set_watchdog_timer;
98 tod_ops.tod_clear_watchdog_timer =
99 todm5819p_rmc_clear_watchdog_timer;
100 tod_ops.tod_set_power_alarm = todm5819p_rmc_set_power_alarm;
101 tod_ops.tod_clear_power_alarm = todm5819p_rmc_clear_power_alarm;
102 tod_ops.tod_get_cpufrequency = todm5819p_rmc_get_cpufrequency;
103 if (boothowto & RB_DEBUG) {
104 cmn_err(CE_WARN, "todm5819p_rmc: kernel debugger "
105 "detected: hardware watchdog disabled");
109 return (mod_install(&modlinkage));
113 _fini(void)
115 if (strcmp(tod_module_name, "todm5819p_rmc") == 0)
116 return (EBUSY);
118 return (mod_remove(&modlinkage));
122 * The loadable-module _info(9E) entry point
125 _info(struct modinfo *modinfop)
127 return (mod_info(&modlinkage, modinfop));
132 * Read the current time from the clock chip and convert to UNIX form.
133 * Assumes that the year in the clock chip is valid.
134 * Must be called with tod_lock held.
136 static timestruc_t
137 todm5819p_rmc_get(void)
139 int i;
140 int s;
141 timestruc_t ts;
142 struct rtc_t rtc;
144 ASSERT(MUTEX_HELD(&tod_lock));
146 /* set the hw watchdog timer if it's been activated */
147 if (watchdog_activated) {
148 int ret = 0;
149 ret = tod_ops.tod_set_watchdog_timer(0);
151 * The empty set_watchdog routine returns a 0. So if a
152 * coded routine fails we will look for a -1 for a failure.
154 if (ret == -1)
155 cmn_err(CE_WARN, "todm5819p: failed to set hardware "
156 "watchdog timer.");
160 * Read current time from the tod. If the tod isn't accessible, wait and
161 * retry.
162 * Run critical in the time critical section to avoid being interrupted
164 for (i = 0; i < TODM5819_UIP_RETRY_THRESH; i++) {
165 s = ddi_enter_critical();
166 M5819P_ADDR_REG = RTC_A;
167 if (!(M5819P_DATA_REG & RTC_UIP)) {
168 read_rtc(&rtc);
169 ddi_exit_critical(s);
170 break;
172 ddi_exit_critical(s);
173 drv_usecwait(TODM5819_UIP_WAIT_USEC);
175 if (i == TODM5819_UIP_RETRY_THRESH) {
177 * tod is inaccessible: just return current software time
179 tod_status_set(TOD_GET_FAILED);
180 return (hrestime);
183 /* read was successful so ensure failure flag is clear */
184 tod_status_clear(TOD_GET_FAILED);
186 ts.tv_sec = tod_to_utc(rtc_to_tod(&rtc));
187 ts.tv_nsec = 0;
188 return (ts);
191 static todinfo_t
192 rtc_to_tod(struct rtc_t *rtc)
194 todinfo_t tod;
197 * tod_year is base 1900 so this code needs to adjust the true year
198 * retrieved from the rtc's century and year fields.
200 tod.tod_year = rtc->rtc_year + (rtc->rtc_century * 100) - 1900;
201 tod.tod_month = rtc->rtc_mon;
202 tod.tod_day = rtc->rtc_dom;
203 tod.tod_dow = rtc->rtc_dow;
204 tod.tod_hour = rtc->rtc_hrs;
205 tod.tod_min = rtc->rtc_min;
206 tod.tod_sec = rtc->rtc_sec;
208 return (tod);
211 static void
212 read_rtc(struct rtc_t *rtc)
214 M5819P_ADDR_REG = RTC_SEC;
215 rtc->rtc_sec = M5819P_DATA_REG;
216 M5819P_ADDR_REG = RTC_ASEC;
217 rtc->rtc_asec = M5819P_DATA_REG;
218 M5819P_ADDR_REG = RTC_MIN;
219 rtc->rtc_min = M5819P_DATA_REG;
220 M5819P_ADDR_REG = RTC_AMIN;
221 rtc->rtc_amin = M5819P_DATA_REG;
222 M5819P_ADDR_REG = RTC_HRS;
223 rtc->rtc_hrs = M5819P_DATA_REG;
224 M5819P_ADDR_REG = RTC_AHRS;
225 rtc->rtc_ahrs = M5819P_DATA_REG;
226 M5819P_ADDR_REG = RTC_DOW;
227 rtc->rtc_dow = M5819P_DATA_REG;
228 M5819P_ADDR_REG = RTC_DOM;
229 rtc->rtc_dom = M5819P_DATA_REG;
230 M5819P_ADDR_REG = RTC_MON;
231 rtc->rtc_mon = M5819P_DATA_REG;
232 M5819P_ADDR_REG = RTC_YEAR;
233 rtc->rtc_year = M5819P_DATA_REG;
234 M5819P_ADDR_REG = RTC_CENTURY;
235 rtc->rtc_century = M5819P_DATA_REG;
237 /* Read date alarm */
238 M5819P_ADDR_REG = RTC_ADOM_REG;
239 rtc->rtc_adom = (M5819P_DATA_REG) & RTC_ADOM;
243 * Write the specified time into the clock chip.
244 * Must be called with tod_lock held.
246 static void
247 todm5819p_rmc_set(timestruc_t ts)
249 struct rtc_t rtc;
250 todinfo_t tod = utc_to_tod(ts.tv_sec);
251 int year;
252 rmc_comm_msg_t request;
253 dp_set_date_time_t set_time_msg;
255 ASSERT(MUTEX_HELD(&tod_lock));
257 /* tod_year is base 1900 so this code needs to adjust */
258 year = 1900 + tod.tod_year;
259 rtc.rtc_year = year % 100;
260 rtc.rtc_century = year / 100;
261 rtc.rtc_mon = (uint8_t)tod.tod_month;
262 rtc.rtc_dom = (uint8_t)tod.tod_day;
263 rtc.rtc_dow = (uint8_t)tod.tod_dow;
264 rtc.rtc_hrs = (uint8_t)tod.tod_hour;
265 rtc.rtc_min = (uint8_t)tod.tod_min;
266 rtc.rtc_sec = (uint8_t)tod.tod_sec;
268 write_rtc_time(&rtc);
270 set_time_msg.year = year - 1900;
271 set_time_msg.month = tod.tod_month - 1;
272 set_time_msg.day = tod.tod_day;
273 set_time_msg.hour = tod.tod_hour;
274 set_time_msg.minute = tod.tod_min;
275 set_time_msg.second = tod.tod_sec;
277 request.msg_type = DP_SET_DATE_TIME;
278 request.msg_len = sizeof (set_time_msg);
279 request.msg_buf = (caddr_t)&set_time_msg;
281 (void) rmc_comm_request_nowait(&request, 0);
284 void
285 write_rtc_time(struct rtc_t *rtc)
287 uint8_t regb;
288 int i;
291 * Freeze
293 M5819P_ADDR_REG = RTC_B;
294 regb = M5819P_DATA_REG;
295 M5819P_DATA_REG = (regb | RTC_SET);
298 * If an update cycle is in progress wait for the UIP flag to
299 * clear. If we write whilst UIP is still set there is a slight
300 * but real possibility of corrupting the RTC date and time
301 * registers.
303 * The expected wait is one internal cycle of the chip. We could
304 * simply spin but this may hang a CPU if we were to have a broken
305 * RTC chip where UIP is stuck, so we use a retry loop instead.
306 * No critical section is needed here as the UIP flag will not be
307 * re-asserted until we clear RTC_SET.
309 M5819P_ADDR_REG = RTC_A;
310 for (i = 0; i < TODM5819_UIP_RETRY_THRESH; i++) {
311 if (!(M5819P_DATA_REG & RTC_UIP)) {
312 break;
314 drv_usecwait(TODM5819_UIP_WAIT_USEC);
316 if (i < TODM5819_UIP_RETRY_THRESH) {
317 M5819P_ADDR_REG = RTC_SEC;
318 M5819P_DATA_REG = rtc->rtc_sec;
319 M5819P_ADDR_REG = RTC_MIN;
320 M5819P_DATA_REG = rtc->rtc_min;
321 M5819P_ADDR_REG = RTC_HRS;
322 M5819P_DATA_REG = rtc->rtc_hrs;
323 M5819P_ADDR_REG = RTC_DOW;
324 M5819P_DATA_REG = rtc->rtc_dow;
325 M5819P_ADDR_REG = RTC_DOM;
326 M5819P_DATA_REG = rtc->rtc_dom;
327 M5819P_ADDR_REG = RTC_MON;
328 M5819P_DATA_REG = rtc->rtc_mon;
329 M5819P_ADDR_REG = RTC_YEAR;
330 M5819P_DATA_REG = rtc->rtc_year;
331 M5819P_ADDR_REG = RTC_CENTURY;
332 M5819P_DATA_REG = rtc->rtc_century;
333 } else {
334 cmn_err(CE_WARN, "todm5819p_rmc: Could not write the RTC\n");
338 * Unfreeze
340 M5819P_ADDR_REG = RTC_B;
341 M5819P_DATA_REG = regb;
344 void
345 write_rtc_alarm(struct rtc_t *rtc)
347 M5819P_ADDR_REG = RTC_ASEC;
348 M5819P_DATA_REG = rtc->rtc_asec;
349 M5819P_ADDR_REG = RTC_AMIN;
350 M5819P_DATA_REG = rtc->rtc_amin;
351 M5819P_ADDR_REG = RTC_AHRS;
352 M5819P_DATA_REG = rtc->rtc_ahrs;
354 M5819P_ADDR_REG = RTC_ADOM_REG;
355 M5819P_DATA_REG = rtc->rtc_adom;
359 * program the rtc registers for alarm to go off at the specified time
361 static void
362 todm5819p_rmc_set_power_alarm(timestruc_t ts)
364 todinfo_t tod;
365 uint8_t regb;
366 struct rtc_t rtc;
368 ASSERT(MUTEX_HELD(&tod_lock));
369 tod = utc_to_tod(ts.tv_sec);
372 * disable alarms and clear AF flag by reading reg C
374 M5819P_ADDR_REG = RTC_B;
375 regb = M5819P_DATA_REG;
376 M5819P_DATA_REG = regb & ~RTC_AIE;
377 M5819P_ADDR_REG = RTC_C;
378 (void) M5819P_DATA_REG;
380 rtc.rtc_asec = (uint8_t)tod.tod_sec;
381 rtc.rtc_amin = (uint8_t)tod.tod_min;
382 rtc.rtc_ahrs = (uint8_t)tod.tod_hour;
383 rtc.rtc_adom = (uint8_t)tod.tod_day;
386 * Write alarm values and enable alarm
388 write_rtc_alarm(&rtc);
390 M5819P_ADDR_REG = RTC_B;
391 M5819P_DATA_REG = regb | RTC_AIE;
395 * clear alarm interrupt
397 static void
398 todm5819p_rmc_clear_power_alarm(void)
400 uint8_t regb;
402 ASSERT(MUTEX_HELD(&tod_lock));
404 M5819P_ADDR_REG = RTC_B;
405 regb = M5819P_DATA_REG;
406 M5819P_DATA_REG = regb & ~RTC_AIE;
410 * Determine the cpu frequency by watching the TOD chip rollover twice.
411 * Cpu clock rate is determined by computing the ticks added (in tick register)
412 * during one second interval on TOD.
414 uint64_t
415 todm5819p_rmc_get_cpufrequency(void)
417 ASSERT(MUTEX_HELD(&tod_lock));
418 M5819P_ADDR_REG = RTC_SEC;
419 return (find_cpufrequency(v_rtc_data_reg));
422 /*ARGSUSED*/
423 static uint_t
424 todm5819p_rmc_set_watchdog_timer(uint_t timeoutval)
426 ASSERT(MUTEX_HELD(&tod_lock));
427 return (0);
430 static uint_t
431 todm5819p_rmc_clear_watchdog_timer(void)
433 ASSERT(MUTEX_HELD(&tod_lock));
434 return (0);