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 2012 Nexenta Systems, Inc. All rights reserved.
23 */
24 /*
25 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
27 */
28
29 /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
30 /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
31 /* All Rights Reserved */
32
33 /* Copyright (c) 1987, 1988 Microsoft Corporation */
34 /* All Rights Reserved */
35
36 #include <sys/param.h>
37 #include <sys/time.h>
38 #include <sys/systm.h>
39
40 #include <sys/cpuvar.h>
41 #include <sys/clock.h>
42 #include <sys/debug.h>
43 #include <sys/rtc.h>
44 #include <sys/archsystm.h>
45 #include <sys/sysmacros.h>
46 #include <sys/lockstat.h>
47 #include <sys/stat.h>
48 #include <sys/sunddi.h>
49
50 #include <sys/acpi/acpi.h>
51 #include <sys/acpica.h>
52
53 static int todpc_rtcget(unsigned char *buf);
54 static void todpc_rtcput(unsigned char *buf);
55
56 #define CLOCK_RES 1000 /* 1 microsec in nanosecs */
57
58 int clock_res = CLOCK_RES;
59
60 /*
61 * The minimum sleep time till an alarm can be fired.
62 * This can be tuned in /etc/system, but if the value is too small,
63 * there is a danger that it will be missed if it takes too long to
64 * get from the set point to sleep. Or that it can fire quickly, and
65 * generate a power spike on the hardware. And small values are
66 * probably only usefull for test setups.
67 */
68 int clock_min_alarm = 4;
313
314 todpc_rtcput((unsigned char *)&rtc);
315 }
316
317 /*
318 * Clear an alarm. This is effectively setting an alarm of 0.
319 */
320 void
321 /*ARGSUSED*/
322 todpc_clralarm(tod_ops_t *top)
323 {
324 mutex_enter(&tod_lock);
325 todpc_setalarm(top, 0);
326 mutex_exit(&tod_lock);
327 }
328
329 /*
330 * Routine to read contents of real time clock to the specified buffer.
331 * Returns ENXIO if clock not valid, or EAGAIN if clock data cannot be read
332 * else 0.
333 * The routine will busy wait for the Update-In-Progress flag to clear.
334 * On completion of the reads the Seconds register is re-read and the
335 * UIP flag is rechecked to confirm that an clock update did not occur
336 * during the accesses. Routine will error exit after 256 attempts.
337 * (See bugid 1158298.)
338 * Routine returns RTC_NREG (which is 15) bytes of data, as given in the
339 * technical reference. This data includes both time and status registers.
340 */
341
342 static int
343 todpc_rtcget(unsigned char *buf)
344 {
345 unsigned char reg;
346 int i;
347 int retries = 256;
348 unsigned char *rawp;
349 unsigned char century = RTC_CENTURY;
350 unsigned char day_alrm;
351 unsigned char mon_alrm;
352
353 ASSERT(MUTEX_HELD(&tod_lock));
354
355 day_alrm = pc_rtc_offset.day_alrm;
356 mon_alrm = pc_rtc_offset.mon_alrm;
357 if (pc_rtc_offset.century != 0) {
358 century = pc_rtc_offset.century;
359 }
360
361 outb(RTC_ADDR, RTC_D); /* check if clock valid */
362 reg = inb(RTC_DATA);
363 if ((reg & RTC_VRT) == 0)
364 return (ENXIO);
365
366 checkuip:
367 if (retries-- < 0)
368 return (EAGAIN);
369 outb(RTC_ADDR, RTC_A); /* check if update in progress */
370 reg = inb(RTC_DATA);
371 if (reg & RTC_UIP) {
372 tenmicrosec();
373 goto checkuip;
374 }
375
376 for (i = 0, rawp = buf; i < RTC_NREG; i++) {
377 outb(RTC_ADDR, i);
378 *rawp++ = inb(RTC_DATA);
379 }
380 outb(RTC_ADDR, century); /* do century */
381 ((struct rtc_t *)buf)->rtc_century = inb(RTC_DATA);
382
383 if (day_alrm > 0) {
384 outb(RTC_ADDR, day_alrm);
385 ((struct rtc_t *)buf)->rtc_adom = inb(RTC_DATA) & 0x3f;
386 }
387 if (mon_alrm > 0) {
|
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 2018 Gary Mills
23 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
24 */
25 /*
26 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
28 */
29
30 /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
31 /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
32 /* All Rights Reserved */
33
34 /* Copyright (c) 1987, 1988 Microsoft Corporation */
35 /* All Rights Reserved */
36
37 #include <sys/param.h>
38 #include <sys/time.h>
39 #include <sys/systm.h>
40
41 #include <sys/cpuvar.h>
42 #include <sys/clock.h>
43 #include <sys/debug.h>
44 #include <sys/rtc.h>
45 #include <sys/archsystm.h>
46 #include <sys/sysmacros.h>
47 #include <sys/lockstat.h>
48 #include <sys/stat.h>
49 #include <sys/sunddi.h>
50 #include <sys/ddi.h>
51
52 #include <sys/acpi/acpi.h>
53 #include <sys/acpica.h>
54
55 static int todpc_rtcget(unsigned char *buf);
56 static void todpc_rtcput(unsigned char *buf);
57
58 #define CLOCK_RES 1000 /* 1 microsec in nanosecs */
59
60 int clock_res = CLOCK_RES;
61
62 /*
63 * The minimum sleep time till an alarm can be fired.
64 * This can be tuned in /etc/system, but if the value is too small,
65 * there is a danger that it will be missed if it takes too long to
66 * get from the set point to sleep. Or that it can fire quickly, and
67 * generate a power spike on the hardware. And small values are
68 * probably only usefull for test setups.
69 */
70 int clock_min_alarm = 4;
315
316 todpc_rtcput((unsigned char *)&rtc);
317 }
318
319 /*
320 * Clear an alarm. This is effectively setting an alarm of 0.
321 */
322 void
323 /*ARGSUSED*/
324 todpc_clralarm(tod_ops_t *top)
325 {
326 mutex_enter(&tod_lock);
327 todpc_setalarm(top, 0);
328 mutex_exit(&tod_lock);
329 }
330
331 /*
332 * Routine to read contents of real time clock to the specified buffer.
333 * Returns ENXIO if clock not valid, or EAGAIN if clock data cannot be read
334 * else 0.
335 * Some RTC hardware is very slow at asserting the validity flag on
336 * startup. The routine will busy wait for the RTC to become valid.
337 * The routine will also busy wait for the Update-In-Progress flag to clear.
338 * On completion of the reads the Seconds register is re-read and the
339 * UIP flag is rechecked to confirm that an clock update did not occur
340 * during the accesses. Routine will error exit after 256 attempts.
341 * (See bugid 1158298.)
342 * Routine returns RTC_NREG (which is 15) bytes of data, as given in the
343 * technical reference. This data includes both time and status registers.
344 */
345
346 static int
347 todpc_rtcget(unsigned char *buf)
348 {
349 unsigned char reg;
350 int i;
351 int uip_try = 256;
352 int vrt_try = 512;
353 unsigned char *rawp;
354 unsigned char century = RTC_CENTURY;
355 unsigned char day_alrm;
356 unsigned char mon_alrm;
357
358 ASSERT(MUTEX_HELD(&tod_lock));
359
360 day_alrm = pc_rtc_offset.day_alrm;
361 mon_alrm = pc_rtc_offset.mon_alrm;
362 if (pc_rtc_offset.century != 0) {
363 century = pc_rtc_offset.century;
364 }
365
366 for (;;) {
367 if (vrt_try-- < 0)
368 return (ENXIO);
369 outb(RTC_ADDR, RTC_D); /* check if clock valid */
370 reg = inb(RTC_DATA);
371 if ((reg & RTC_VRT) != 0)
372 break;
373 drv_usecwait(5000); /* Delay for 5000 us */
374 }
375
376
377 checkuip:
378 if (uip_try-- < 0)
379 return (EAGAIN);
380 outb(RTC_ADDR, RTC_A); /* check if update in progress */
381 reg = inb(RTC_DATA);
382 if (reg & RTC_UIP) {
383 tenmicrosec();
384 goto checkuip;
385 }
386
387 for (i = 0, rawp = buf; i < RTC_NREG; i++) {
388 outb(RTC_ADDR, i);
389 *rawp++ = inb(RTC_DATA);
390 }
391 outb(RTC_ADDR, century); /* do century */
392 ((struct rtc_t *)buf)->rtc_century = inb(RTC_DATA);
393
394 if (day_alrm > 0) {
395 outb(RTC_ADDR, day_alrm);
396 ((struct rtc_t *)buf)->rtc_adom = inb(RTC_DATA) & 0x3f;
397 }
398 if (mon_alrm > 0) {
|