1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <linux/bcd.h>
3 #include <linux/delay.h>
4 #include <linux/export.h>
5 #include <linux/mc146818rtc.h>
6 
7 #ifdef CONFIG_ACPI
8 #include <linux/acpi.h>
9 #endif
10 
mc146818_get_time(struct rtc_time * time)11 unsigned int mc146818_get_time(struct rtc_time *time)
12 {
13 	unsigned char ctrl;
14 	unsigned long flags;
15 	unsigned char century = 0;
16 	bool retry;
17 
18 #ifdef CONFIG_MACH_DECSTATION
19 	unsigned int real_year;
20 #endif
21 
22 again:
23 	spin_lock_irqsave(&rtc_lock, flags);
24 	/* Ensure that the RTC is accessible. Bit 6 must be 0! */
25 	if (WARN_ON_ONCE((CMOS_READ(RTC_VALID) & 0x40) != 0)) {
26 		spin_unlock_irqrestore(&rtc_lock, flags);
27 		memset(time, 0xff, sizeof(*time));
28 		return 0;
29 	}
30 
31 	/*
32 	 * Check whether there is an update in progress during which the
33 	 * readout is unspecified. The maximum update time is ~2ms. Poll
34 	 * every msec for completion.
35 	 *
36 	 * Store the second value before checking UIP so a long lasting NMI
37 	 * which happens to hit after the UIP check cannot make an update
38 	 * cycle invisible.
39 	 */
40 	time->tm_sec = CMOS_READ(RTC_SECONDS);
41 
42 	if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
43 		spin_unlock_irqrestore(&rtc_lock, flags);
44 		mdelay(1);
45 		goto again;
46 	}
47 
48 	/* Revalidate the above readout */
49 	if (time->tm_sec != CMOS_READ(RTC_SECONDS)) {
50 		spin_unlock_irqrestore(&rtc_lock, flags);
51 		goto again;
52 	}
53 
54 	/*
55 	 * Only the values that we read from the RTC are set. We leave
56 	 * tm_wday, tm_yday and tm_isdst untouched. Even though the
57 	 * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
58 	 * by the RTC when initially set to a non-zero value.
59 	 */
60 	time->tm_min = CMOS_READ(RTC_MINUTES);
61 	time->tm_hour = CMOS_READ(RTC_HOURS);
62 	time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
63 	time->tm_mon = CMOS_READ(RTC_MONTH);
64 	time->tm_year = CMOS_READ(RTC_YEAR);
65 #ifdef CONFIG_MACH_DECSTATION
66 	real_year = CMOS_READ(RTC_DEC_YEAR);
67 #endif
68 #ifdef CONFIG_ACPI
69 	if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
70 	    acpi_gbl_FADT.century)
71 		century = CMOS_READ(acpi_gbl_FADT.century);
72 #endif
73 	ctrl = CMOS_READ(RTC_CONTROL);
74 	/*
75 	 * Check for the UIP bit again. If it is set now then
76 	 * the above values may contain garbage.
77 	 */
78 	retry = CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP;
79 	/*
80 	 * A NMI might have interrupted the above sequence so check whether
81 	 * the seconds value has changed which indicates that the NMI took
82 	 * longer than the UIP bit was set. Unlikely, but possible and
83 	 * there is also virt...
84 	 */
85 	retry |= time->tm_sec != CMOS_READ(RTC_SECONDS);
86 
87 	spin_unlock_irqrestore(&rtc_lock, flags);
88 
89 	if (retry)
90 		goto again;
91 
92 	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
93 	{
94 		time->tm_sec = bcd2bin(time->tm_sec);
95 		time->tm_min = bcd2bin(time->tm_min);
96 		time->tm_hour = bcd2bin(time->tm_hour);
97 		time->tm_mday = bcd2bin(time->tm_mday);
98 		time->tm_mon = bcd2bin(time->tm_mon);
99 		time->tm_year = bcd2bin(time->tm_year);
100 		century = bcd2bin(century);
101 	}
102 
103 #ifdef CONFIG_MACH_DECSTATION
104 	time->tm_year += real_year - 72;
105 #endif
106 
107 	if (century > 20)
108 		time->tm_year += (century - 19) * 100;
109 
110 	/*
111 	 * Account for differences between how the RTC uses the values
112 	 * and how they are defined in a struct rtc_time;
113 	 */
114 	if (time->tm_year <= 69)
115 		time->tm_year += 100;
116 
117 	time->tm_mon--;
118 
119 	return RTC_24H;
120 }
121 EXPORT_SYMBOL_GPL(mc146818_get_time);
122 
123 /* Set the current date and time in the real time clock. */
mc146818_set_time(struct rtc_time * time)124 int mc146818_set_time(struct rtc_time *time)
125 {
126 	unsigned long flags;
127 	unsigned char mon, day, hrs, min, sec;
128 	unsigned char save_control, save_freq_select;
129 	unsigned int yrs;
130 #ifdef CONFIG_MACH_DECSTATION
131 	unsigned int real_yrs, leap_yr;
132 #endif
133 	unsigned char century = 0;
134 
135 	yrs = time->tm_year;
136 	mon = time->tm_mon + 1;   /* tm_mon starts at zero */
137 	day = time->tm_mday;
138 	hrs = time->tm_hour;
139 	min = time->tm_min;
140 	sec = time->tm_sec;
141 
142 	if (yrs > 255)	/* They are unsigned */
143 		return -EINVAL;
144 
145 #ifdef CONFIG_MACH_DECSTATION
146 	real_yrs = yrs;
147 	leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) ||
148 			!((yrs + 1900) % 400));
149 	yrs = 72;
150 
151 	/*
152 	 * We want to keep the year set to 73 until March
153 	 * for non-leap years, so that Feb, 29th is handled
154 	 * correctly.
155 	 */
156 	if (!leap_yr && mon < 3) {
157 		real_yrs--;
158 		yrs = 73;
159 	}
160 #endif
161 
162 #ifdef CONFIG_ACPI
163 	if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
164 	    acpi_gbl_FADT.century) {
165 		century = (yrs + 1900) / 100;
166 		yrs %= 100;
167 	}
168 #endif
169 
170 	/* These limits and adjustments are independent of
171 	 * whether the chip is in binary mode or not.
172 	 */
173 	if (yrs > 169)
174 		return -EINVAL;
175 
176 	if (yrs >= 100)
177 		yrs -= 100;
178 
179 	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
180 	    || RTC_ALWAYS_BCD) {
181 		sec = bin2bcd(sec);
182 		min = bin2bcd(min);
183 		hrs = bin2bcd(hrs);
184 		day = bin2bcd(day);
185 		mon = bin2bcd(mon);
186 		yrs = bin2bcd(yrs);
187 		century = bin2bcd(century);
188 	}
189 
190 	spin_lock_irqsave(&rtc_lock, flags);
191 	save_control = CMOS_READ(RTC_CONTROL);
192 	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
193 	save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
194 	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
195 
196 #ifdef CONFIG_MACH_DECSTATION
197 	CMOS_WRITE(real_yrs, RTC_DEC_YEAR);
198 #endif
199 	CMOS_WRITE(yrs, RTC_YEAR);
200 	CMOS_WRITE(mon, RTC_MONTH);
201 	CMOS_WRITE(day, RTC_DAY_OF_MONTH);
202 	CMOS_WRITE(hrs, RTC_HOURS);
203 	CMOS_WRITE(min, RTC_MINUTES);
204 	CMOS_WRITE(sec, RTC_SECONDS);
205 #ifdef CONFIG_ACPI
206 	if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
207 	    acpi_gbl_FADT.century)
208 		CMOS_WRITE(century, acpi_gbl_FADT.century);
209 #endif
210 
211 	CMOS_WRITE(save_control, RTC_CONTROL);
212 	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
213 
214 	spin_unlock_irqrestore(&rtc_lock, flags);
215 
216 	return 0;
217 }
218 EXPORT_SYMBOL_GPL(mc146818_set_time);
219