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 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
55static int todpc_rtcget(unsigned char *buf);
56static void todpc_rtcput(unsigned char *buf);
57
58#define	CLOCK_RES	1000		/* 1 microsec in nanosecs */
59
60int 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 */
70int clock_min_alarm = 4;
71
72/*
73 * Machine-dependent clock routines.
74 */
75
76extern long gmt_lag;
77
78struct rtc_offset {
79	int8_t	loaded;
80	uint8_t	day_alrm;
81	uint8_t mon_alrm;
82	uint8_t	century;
83};
84
85static struct rtc_offset pc_rtc_offset = {0, 0, 0, 0};
86
87
88/*
89 * Entry point for ACPI to pass RTC or other clock values that
90 * are useful to TOD.
91 */
92void
93pc_tod_set_rtc_offsets(ACPI_TABLE_FADT *fadt)
94{
95	int		ok = 0;
96
97	/*
98	 * ASSERT is for debugging, but we don't want the machine
99	 * falling over because for some reason we didn't get a valid
100	 * pointer.
101	 */
102	ASSERT(fadt);
103	if (fadt == NULL) {
104		return;
105	}
106
107	if (fadt->DayAlarm) {
108		pc_rtc_offset.day_alrm = fadt->DayAlarm;
109		ok = 1;
110	}
111
112	if (fadt->MonthAlarm) {
113		pc_rtc_offset.mon_alrm = fadt->MonthAlarm;
114		ok = 1;
115	}
116
117	if (fadt->Century) {
118		pc_rtc_offset.century = fadt->Century;
119		ok = 1;
120	}
121
122	pc_rtc_offset.loaded = ok;
123}
124
125
126/*
127 * Write the specified time into the clock chip.
128 * Must be called with tod_lock held.
129 */
130/*ARGSUSED*/
131static void
132todpc_set(tod_ops_t *top, timestruc_t ts)
133{
134	todinfo_t tod = utc_to_tod(ts.tv_sec - ggmtl());
135	struct rtc_t rtc;
136
137	ASSERT(MUTEX_HELD(&tod_lock));
138
139	if (todpc_rtcget((unsigned char *)&rtc))
140		return;
141
142	/*
143	 * rtc bytes are in binary-coded decimal, so we have to convert.
144	 * We assume that we wrap the rtc year back to zero at 2000.
145	 */
146	/* LINTED: YRBASE = 0 for x86 */
147	tod.tod_year -= YRBASE;
148	if (tod.tod_year >= 100) {
149		tod.tod_year -= 100;
150		rtc.rtc_century = BYTE_TO_BCD(20); /* 20xx year */
151	} else
152		rtc.rtc_century = BYTE_TO_BCD(19); /* 19xx year */
153	rtc.rtc_yr	= BYTE_TO_BCD(tod.tod_year);
154	rtc.rtc_mon	= BYTE_TO_BCD(tod.tod_month);
155	rtc.rtc_dom	= BYTE_TO_BCD(tod.tod_day);
156	/* dow < 10, so no conversion */
157	rtc.rtc_dow	= (unsigned char)tod.tod_dow;
158	rtc.rtc_hr	= BYTE_TO_BCD(tod.tod_hour);
159	rtc.rtc_min	= BYTE_TO_BCD(tod.tod_min);
160	rtc.rtc_sec	= BYTE_TO_BCD(tod.tod_sec);
161
162	todpc_rtcput((unsigned char *)&rtc);
163}
164
165/*
166 * Read the current time from the clock chip and convert to UNIX form.
167 * Assumes that the year in the clock chip is valid.
168 * Must be called with tod_lock held.
169 */
170/*ARGSUSED*/
171static timestruc_t
172todpc_get(tod_ops_t *top)
173{
174	timestruc_t ts;
175	todinfo_t tod;
176	struct rtc_t rtc;
177	int compute_century;
178	static int century_warn = 1; /* only warn once, not each time called */
179	static int range_warn = 1;
180
181	ASSERT(MUTEX_HELD(&tod_lock));
182
183	if (todpc_rtcget((unsigned char *)&rtc)) {
184		tod_status_set(TOD_GET_FAILED);
185		return (hrestime);
186	}
187
188	/* assume that we wrap the rtc year back to zero at 2000 */
189	tod.tod_year	= BCD_TO_BYTE(rtc.rtc_yr);
190	if (tod.tod_year < 69) {
191		if (range_warn && tod.tod_year > 38) {
192			cmn_err(CE_WARN, "hardware real-time clock is out "
193			    "of range -- time needs to be reset");
194			range_warn = 0;
195		}
196		tod.tod_year += 100 + YRBASE; /* 20xx year */
197		compute_century = 20;
198	} else {
199		/* LINTED: YRBASE = 0 for x86 */
200		tod.tod_year += YRBASE; /* 19xx year */
201		compute_century = 19;
202	}
203	if (century_warn && BCD_TO_BYTE(rtc.rtc_century) != compute_century) {
204		cmn_err(CE_NOTE,
205		    "The hardware real-time clock appears to have the "
206		    "wrong century: %d.\nSolaris will still operate "
207		    "correctly, but other OS's/firmware agents may "
208		    "not.\nUse date(1) to set the date to the current "
209		    "time to correct the RTC.",
210		    BCD_TO_BYTE(rtc.rtc_century));
211		century_warn = 0;
212	}
213	tod.tod_month	= BCD_TO_BYTE(rtc.rtc_mon);
214	tod.tod_day	= BCD_TO_BYTE(rtc.rtc_dom);
215	tod.tod_dow	= rtc.rtc_dow;	/* dow < 10, so no conversion needed */
216	tod.tod_hour	= BCD_TO_BYTE(rtc.rtc_hr);
217	tod.tod_min	= BCD_TO_BYTE(rtc.rtc_min);
218	tod.tod_sec	= BCD_TO_BYTE(rtc.rtc_sec);
219
220	/* read was successful so ensure failure flag is clear */
221	tod_status_clear(TOD_GET_FAILED);
222
223	ts.tv_sec = tod_to_utc(tod) + ggmtl();
224	ts.tv_nsec = 0;
225
226	return (ts);
227}
228
229#include <sys/promif.h>
230/*
231 * Write the specified wakeup alarm into the clock chip.
232 * Must be called with tod_lock held.
233 */
234void
235/*ARGSUSED*/
236todpc_setalarm(tod_ops_t *top, int nsecs)
237{
238	struct rtc_t rtc;
239	int delta, asec, amin, ahr, adom, amon;
240	int day_alrm = pc_rtc_offset.day_alrm;
241	int mon_alrm = pc_rtc_offset.mon_alrm;
242
243	ASSERT(MUTEX_HELD(&tod_lock));
244
245	/* A delay of zero is not allowed */
246	if (nsecs == 0)
247		return;
248
249	/* Make sure that we delay no less than the minimum time */
250	if (nsecs < clock_min_alarm)
251		nsecs = clock_min_alarm;
252
253	if (todpc_rtcget((unsigned char *)&rtc))
254		return;
255
256	/*
257	 * Compute alarm secs, mins and hrs, and where appropriate, dom
258	 * and mon.  rtc bytes are in binary-coded decimal, so we have
259	 * to convert.
260	 */
261	delta = nsecs + BCD_TO_BYTE(rtc.rtc_sec);
262	asec = delta % 60;
263
264	delta = (delta / 60) + BCD_TO_BYTE(rtc.rtc_min);
265	amin = delta % 60;
266
267	delta = (delta / 60) + BCD_TO_BYTE(rtc.rtc_hr);
268	ahr  = delta % 24;
269
270	if (day_alrm == 0 && delta >= 24) {
271		prom_printf("No day alarm - set to end of today!\n");
272		asec = 59;
273		amin = 59;
274		ahr  = 23;
275	} else {
276		int mon = BCD_TO_BYTE(rtc.rtc_mon);
277		static int dpm[] =
278		    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
279
280		adom = (delta / 24) + BCD_TO_BYTE(rtc.rtc_dom);
281
282		if (mon_alrm == 0) {
283			if (adom > dpm[mon]) {
284				prom_printf("No mon alarm - "
285				    "set to end of current month!\n");
286				asec = 59;
287				amin = 59;
288				ahr  = 23;
289				adom = dpm[mon];
290			}
291		} else {
292			for (amon = mon;
293			    amon <= 12 && adom > dpm[amon]; amon++) {
294				adom -= dpm[amon];
295			}
296			if (amon > 12) {
297				prom_printf("Alarm too far in future - "
298				    "set to end of current year!\n");
299				asec = 59;
300				amin = 59;
301				ahr  = 23;
302				adom = dpm[12];
303				amon = 12;
304			}
305			rtc.rtc_amon = BYTE_TO_BCD(amon);
306		}
307
308		rtc.rtc_adom = BYTE_TO_BCD(adom);
309	}
310
311	rtc.rtc_asec = BYTE_TO_BCD(asec);
312	rtc.rtc_amin = BYTE_TO_BCD(amin);
313	rtc.rtc_ahr  = BYTE_TO_BCD(ahr);
314
315	rtc.rtc_statusb |= RTC_AIE;	/* Enable alarm interrupt */
316
317	todpc_rtcput((unsigned char *)&rtc);
318}
319
320/*
321 * Clear an alarm.  This is effectively setting an alarm of 0.
322 */
323void
324/*ARGSUSED*/
325todpc_clralarm(tod_ops_t *top)
326{
327	mutex_enter(&tod_lock);
328	todpc_setalarm(top, 0);
329	mutex_exit(&tod_lock);
330}
331
332/*
333 * Routine to read contents of real time clock to the specified buffer.
334 * Returns ENXIO if clock not valid, or EAGAIN if clock data cannot be read
335 * else 0.
336 * Some RTC hardware is very slow at asserting the validity flag on
337 * startup.  The routine will busy wait for the RTC to become valid.
338 * The routine will also busy wait for the Update-In-Progress flag to clear.
339 * On completion of the reads the Seconds register is re-read and the
340 * UIP flag is rechecked to confirm that an clock update did not occur
341 * during the accesses.  Routine will error exit after 256 attempts.
342 * (See bugid 1158298.)
343 * Routine returns RTC_NREG (which is 15) bytes of data, as given in the
344 * technical reference.  This data includes both time and status registers.
345 */
346
347static int
348todpc_rtcget(unsigned char *buf)
349{
350	unsigned char	reg;
351	int		i;
352	int		uip_try = 256;
353	int		vrt_try = 512;
354	unsigned char	*rawp;
355	unsigned char	century = RTC_CENTURY;
356	unsigned char	day_alrm;
357	unsigned char	mon_alrm;
358
359	ASSERT(MUTEX_HELD(&tod_lock));
360
361	day_alrm = pc_rtc_offset.day_alrm;
362	mon_alrm = pc_rtc_offset.mon_alrm;
363	if (pc_rtc_offset.century != 0) {
364		century = pc_rtc_offset.century;
365	}
366
367	for (;;) {
368		if (vrt_try-- < 0)
369			return (ENXIO);
370		outb(RTC_ADDR, RTC_D);		/* check if clock valid */
371		reg = inb(RTC_DATA);
372		if ((reg & RTC_VRT) != 0)
373			break;
374		drv_usecwait(5000);		/* Delay for 5000 us */
375	}
376
377
378checkuip:
379	if (uip_try-- < 0)
380		return (EAGAIN);
381	outb(RTC_ADDR, RTC_A);		/* check if update in progress */
382	reg = inb(RTC_DATA);
383	if (reg & RTC_UIP) {
384		tenmicrosec();
385		goto checkuip;
386	}
387
388	for (i = 0, rawp = buf; i < RTC_NREG; i++) {
389		outb(RTC_ADDR, i);
390		*rawp++ = inb(RTC_DATA);
391	}
392	outb(RTC_ADDR, century); /* do century */
393	((struct rtc_t *)buf)->rtc_century = inb(RTC_DATA);
394
395	if (day_alrm > 0) {
396		outb(RTC_ADDR, day_alrm);
397		((struct rtc_t *)buf)->rtc_adom = inb(RTC_DATA) & 0x3f;
398	}
399	if (mon_alrm > 0) {
400		outb(RTC_ADDR, mon_alrm);
401		((struct rtc_t *)buf)->rtc_amon = inb(RTC_DATA);
402	}
403
404	outb(RTC_ADDR, 0);		/* re-read Seconds register */
405	reg = inb(RTC_DATA);
406	if (reg != ((struct rtc_t *)buf)->rtc_sec ||
407	    (((struct rtc_t *)buf)->rtc_statusa & RTC_UIP))
408		/* update occured during reads */
409		goto checkuip;
410
411	return (0);
412}
413
414/*
415 * This routine writes the contents of the given buffer to the real time
416 * clock.  It is given RTC_NREGP bytes of data, which are the 10 bytes used
417 * to write the time and set the alarm.  It should be called with the priority
418 * raised to 5.
419 */
420static void
421todpc_rtcput(unsigned char *buf)
422{
423	unsigned char	reg;
424	int		i;
425	unsigned char	century = RTC_CENTURY;
426	unsigned char	day_alrm = pc_rtc_offset.day_alrm;
427	unsigned char	mon_alrm = pc_rtc_offset.mon_alrm;
428	unsigned char	tmp;
429
430	if (pc_rtc_offset.century != 0) {
431		century = pc_rtc_offset.century;
432	}
433
434	outb(RTC_ADDR, RTC_B);
435	reg = inb(RTC_DATA);
436	outb(RTC_ADDR, RTC_B);
437	outb(RTC_DATA, reg | RTC_SET);	/* allow time set now */
438	for (i = 0; i < RTC_NREGP; i++) { /* set the time */
439		outb(RTC_ADDR, i);
440		outb(RTC_DATA, buf[i]);
441	}
442	outb(RTC_ADDR, century); /* do century */
443	outb(RTC_DATA, ((struct rtc_t *)buf)->rtc_century);
444
445	if (day_alrm > 0) {
446		outb(RTC_ADDR, day_alrm);
447		/* preserve RTC_VRT bit; some virt envs accept writes there */
448		tmp = inb(RTC_DATA) & RTC_VRT;
449		tmp |= ((struct rtc_t *)buf)->rtc_adom & ~RTC_VRT;
450		outb(RTC_DATA, tmp);
451	}
452	if (mon_alrm > 0) {
453		outb(RTC_ADDR, mon_alrm);
454		outb(RTC_DATA, ((struct rtc_t *)buf)->rtc_amon);
455	}
456
457	outb(RTC_ADDR, RTC_B);
458	reg = inb(RTC_DATA);
459	outb(RTC_ADDR, RTC_B);
460	outb(RTC_DATA, reg & ~RTC_SET);	/* allow time update */
461}
462
463static tod_ops_t todpc_ops = {
464	TOD_OPS_VERSION,
465	todpc_get,
466	todpc_set,
467	NULL,
468	NULL,
469	todpc_setalarm,
470	todpc_clralarm,
471	NULL
472};
473
474/*
475 * Initialize for the default TOD ops vector for use on hardware.
476 */
477
478tod_ops_t *tod_ops = &todpc_ops;
479