xref: /illumos-gate/usr/src/uts/sun4u/io/todbq4802.c (revision 71269a2275bf5a143dad6461eee2710a344e7261)
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 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * tod driver module for TI BQ4802 part
30  *
31  * Note: The way to access the bq4802's RTC registers is different than
32  * the previous RTC devices (m5823, m5819p, ds1287, etc) that we used.
33  * The address returns from OBP is mapped directly to the bq4802's RTC
34  * registers. To read/write the data from/to the bq4802 registers, one
35  * just add the register offset to the base address.
36  * To access the previous RTC devices, we write the register index to
37  * the address port (v_rtc_addr_reg) then read/write the data from/to
38  * the data port (v_rtc_data_reg).
39  */
40 
41 #include <sys/types.h>
42 #include <sys/conf.h>
43 #include <sys/kmem.h>
44 #include <sys/open.h>
45 #include <sys/ddi.h>
46 #include <sys/sunddi.h>
47 #include <sys/sysmacros.h>
48 
49 #include <sys/todbq4802.h>
50 #include <sys/modctl.h>
51 #include <sys/stat.h>
52 #include <sys/clock.h>
53 #include <sys/reboot.h>
54 #include <sys/machsystm.h>
55 
56 /*
57  * tod_ops entry routines
58  */
59 static timestruc_t	todbq4802_get(void);
60 static void		todbq4802_set(timestruc_t);
61 static uint_t		todbq4802_set_watchdog_timer(uint_t);
62 static uint_t		todbq4802_clear_watchdog_timer(void);
63 static void		todbq4802_set_power_alarm(timestruc_t);
64 static void		todbq4802_clear_power_alarm(void);
65 static uint64_t		todbq4802_get_cpufrequency(void);
66 
67 extern uint64_t		find_cpufrequency(volatile uint8_t *);
68 
69 /*
70  * External variables
71  */
72 extern int watchdog_enable;
73 extern int watchdog_available;
74 extern int boothowto;
75 
76 /*
77  * Global variables
78  */
79 int bq4802_debug_flags;
80 uint_t bq4802_hrestime_count = 0;
81 uint_t bq4802_uip_count = 0;
82 
83 /*
84  * Module linkage information for the kernel.
85  */
86 static struct modlmisc modlmisc = {
87 	&mod_miscops, "tod module for TI BQ4802"
88 };
89 
90 static struct modlinkage modlinkage = {
91 	MODREV_1, (void *)&modlmisc, NULL
92 };
93 
94 static void read_rtc(struct rtc_t *);
95 static void write_rtc_time(struct rtc_t *);
96 static void write_rtc_alarm(struct rtc_t *);
97 
98 int
99 _init(void)
100 {
101 	if (strcmp(tod_module_name, "todbq4802") == 0) {
102 		if (v_rtc_addr_reg == NULL)
103 			cmn_err(CE_PANIC, "addr not set, cannot read RTC\n");
104 
105 		BQ4802_DATA_REG(RTC_CNTRL) = (RTC_HM | RTC_STOP_N);
106 
107 		/* Clear AF flag by reading reg Flags (D) */
108 		(void) BQ4802_DATA_REG(RTC_FLAGS);
109 
110 		tod_ops.tod_get = todbq4802_get;
111 		tod_ops.tod_set = todbq4802_set;
112 		tod_ops.tod_set_watchdog_timer =
113 		    todbq4802_set_watchdog_timer;
114 		tod_ops.tod_clear_watchdog_timer =
115 		    todbq4802_clear_watchdog_timer;
116 		tod_ops.tod_set_power_alarm = todbq4802_set_power_alarm;
117 		tod_ops.tod_clear_power_alarm = todbq4802_clear_power_alarm;
118 		tod_ops.tod_get_cpufrequency = todbq4802_get_cpufrequency;
119 
120 		/*
121 		 * check if hardware watchdog timer is available and user
122 		 * enabled it.
123 		 */
124 		if (watchdog_enable) {
125 			if (!watchdog_available) {
126 				cmn_err(CE_WARN, "bq4802: Hardware watchdog "
127 				    "unavailable");
128 			} else if (boothowto & RB_DEBUG) {
129 				cmn_err(CE_WARN, "bq4802: Hardware watchdog"
130 				    " disabled [debugger]");
131 			}
132 		}
133 	}
134 
135 	return (mod_install(&modlinkage));
136 }
137 
138 int
139 _fini(void)
140 {
141 	if (strcmp(tod_module_name, "todbq4802") == 0)
142 		return (EBUSY);
143 
144 	return (mod_remove(&modlinkage));
145 }
146 
147 /*
148  * The loadable-module _info(9E) entry point
149  */
150 int
151 _info(struct modinfo *modinfop)
152 {
153 	return (mod_info(&modlinkage, modinfop));
154 }
155 
156 /*
157  * Read the current time from the clock chip and convert to UNIX form.
158  * Assumes that the year in the clock chip is valid.
159  * Must be called with tod_lock held.
160  */
161 static timestruc_t
162 todbq4802_get(void)
163 {
164 	timestruc_t ts;
165 	todinfo_t tod;
166 	struct rtc_t rtc;
167 
168 	ASSERT(MUTEX_HELD(&tod_lock));
169 
170 	read_rtc(&rtc);
171 	DPRINTF("todbq4802_get: century=%d year=%d dom=%d hrs=%d min=%d"
172 	    " sec=%d\n", rtc.rtc_century, rtc.rtc_year, rtc.rtc_dom,
173 	    rtc.rtc_hrs, rtc.rtc_min, rtc.rtc_sec);
174 
175 	/*
176 	 * tod_year is base 1900 so this code needs to adjust the true
177 	 * year retrieved from the rtc's century and year fields.
178 	 */
179 	tod.tod_year	= rtc.rtc_year + (rtc.rtc_century * 100) - 1900;
180 	tod.tod_month	= rtc.rtc_mon;
181 	tod.tod_day	= rtc.rtc_dom;
182 	tod.tod_dow	= rtc.rtc_dow;
183 	tod.tod_hour	= rtc.rtc_hrs;
184 	tod.tod_min	= rtc.rtc_min;
185 	tod.tod_sec	= rtc.rtc_sec;
186 
187 	ts.tv_sec = tod_to_utc(tod);
188 	ts.tv_nsec = 0;
189 	return (ts);
190 }
191 
192 /*
193  * Once every second, the user-accessible clock/calendar
194  * locations are updated simultaneously from the internal
195  * real-time counters. To prevent reading data in transition,
196  * updates to the bq4802 clock registers should be halted.
197  * Updating is halted by setting the Update Transfer Inhibit
198  * (UTI) bit D3 of the control register E. As long as the
199  * UTI bit is 1, updates to user-accessible clock locations are
200  * inhibited. Once the frozen clock information is retrieved by
201  * reading the appropriate clock memory locations, the UTI
202  * bit should be reset to 0 in order to allow updates to occur
203  * from the internal counters. Because the internal counters
204  * are not halted by setting the UTI bit, reading the clock
205  * locations has no effect on clock accuracy. Once the UTI bit
206  * is reset to 0, the internal registers update within one
207  * second the user-accessible registers with the correct time.
208  * A halt command issued during a clock update allows the
209  * update to occur before freezing the data.
210  */
211 static void
212 read_rtc(struct rtc_t *rtc)
213 {
214 	uint8_t	reg_cntrl;
215 
216 	/*
217 	 * Freeze
218 	 */
219 	reg_cntrl = BQ4802_DATA_REG(RTC_CNTRL);
220 	BQ4802_DATA_REG(RTC_CNTRL) = (reg_cntrl | RTC_UTI);
221 
222 	rtc->rtc_sec = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_SEC));
223 	rtc->rtc_asec = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_ASEC));
224 	rtc->rtc_min = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_MIN));
225 	rtc->rtc_amin = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_AMIN));
226 	rtc->rtc_hrs = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_HRS));
227 	rtc->rtc_ahrs = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_AHRS));
228 	rtc->rtc_dom = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_DOM));
229 	rtc->rtc_adom = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_ADOM));
230 	rtc->rtc_dow = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_DOW));
231 	rtc->rtc_mon = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_MON));
232 	rtc->rtc_year = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_YEAR));
233 	rtc->rtc_century = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_CENTURY));
234 
235 	/*
236 	 * Unfreeze
237 	 */
238 	BQ4802_DATA_REG(RTC_CNTRL) = reg_cntrl;
239 }
240 
241 /*
242  * Write the specified time into the clock chip.
243  * Must be called with tod_lock held.
244  */
245 static void
246 todbq4802_set(timestruc_t ts)
247 {
248 	struct rtc_t	rtc;
249 	todinfo_t tod = utc_to_tod(ts.tv_sec);
250 	int year;
251 
252 	ASSERT(MUTEX_HELD(&tod_lock));
253 
254 	/* tod_year is base 1900 so this code needs to adjust */
255 	year = 1900 + tod.tod_year;
256 	rtc.rtc_year	= year % 100;
257 	rtc.rtc_century = year / 100;
258 	rtc.rtc_mon	= (uint8_t)tod.tod_month;
259 	rtc.rtc_dom	= (uint8_t)tod.tod_day;
260 	rtc.rtc_dow	= (uint8_t)tod.tod_dow;
261 	rtc.rtc_hrs	= (uint8_t)tod.tod_hour;
262 	rtc.rtc_min	= (uint8_t)tod.tod_min;
263 	rtc.rtc_sec	= (uint8_t)tod.tod_sec;
264 	DPRINTF("todbq4802_set: year=%d dom=%d hrs=%d min=%d sec=%d\n",
265 	    rtc.rtc_year, rtc.rtc_dom, rtc.rtc_hrs, rtc.rtc_min, rtc.rtc_sec);
266 
267 	write_rtc_time(&rtc);
268 }
269 
270 /*
271  * The UTI bit must be used to set the bq4802 clock.
272  * Once set, the locations can be written with the desired
273  * information in BCD format. Resetting the UTI bit to 0 causes
274  * the written values to be transferred to the internal clock
275  * counters and allows updates to the user-accessible registers
276  * to resume within one second.
277  */
278 void
279 write_rtc_time(struct rtc_t *rtc)
280 {
281 	uint8_t	reg_cntrl;
282 
283 	/*
284 	 * Freeze
285 	 */
286 	reg_cntrl = BQ4802_DATA_REG(RTC_CNTRL);
287 	BQ4802_DATA_REG(RTC_CNTRL) = (reg_cntrl | RTC_UTI);
288 
289 	BQ4802_DATA_REG(RTC_SEC) = BYTE_TO_BCD(rtc->rtc_sec);
290 	BQ4802_DATA_REG(RTC_MIN) = BYTE_TO_BCD(rtc->rtc_min);
291 	BQ4802_DATA_REG(RTC_HRS) = BYTE_TO_BCD(rtc->rtc_hrs);
292 	BQ4802_DATA_REG(RTC_DOM) = BYTE_TO_BCD(rtc->rtc_dom);
293 	BQ4802_DATA_REG(RTC_DOW) = BYTE_TO_BCD(rtc->rtc_dow);
294 	BQ4802_DATA_REG(RTC_MON) = BYTE_TO_BCD(rtc->rtc_mon);
295 	BQ4802_DATA_REG(RTC_YEAR) = BYTE_TO_BCD(rtc->rtc_year);
296 	BQ4802_DATA_REG(RTC_CENTURY) = BYTE_TO_BCD(rtc->rtc_century);
297 
298 	/*
299 	 * Unfreeze
300 	 */
301 	BQ4802_DATA_REG(RTC_CNTRL) = reg_cntrl;
302 }
303 
304 void
305 write_rtc_alarm(struct rtc_t *rtc)
306 {
307 	BQ4802_DATA_REG(RTC_ASEC) = BYTE_TO_BCD(rtc->rtc_asec);
308 	BQ4802_DATA_REG(RTC_AMIN) = BYTE_TO_BCD(rtc->rtc_amin);
309 	BQ4802_DATA_REG(RTC_AHRS) = BYTE_TO_BCD(rtc->rtc_ahrs);
310 	BQ4802_DATA_REG(RTC_ADOM) = BYTE_TO_BCD(rtc->rtc_adom);
311 }
312 
313 /*
314  * program the rtc registers for alarm to go off at the specified time
315  */
316 static void
317 todbq4802_set_power_alarm(timestruc_t ts)
318 {
319 	todinfo_t	tod;
320 	uint8_t		regc;
321 	struct rtc_t	rtc;
322 
323 	ASSERT(MUTEX_HELD(&tod_lock));
324 	tod = utc_to_tod(ts.tv_sec);
325 
326 	/*
327 	 * disable alarms and clear AF flag by reading reg Flags (D)
328 	 */
329 	regc = BQ4802_DATA_REG(RTC_ENABLES);
330 	BQ4802_DATA_REG(RTC_ENABLES) = regc & ~(RTC_AIE | RTC_ABE);
331 	(void) BQ4802_DATA_REG(RTC_FLAGS);
332 
333 	rtc.rtc_asec = (uint8_t)tod.tod_sec;
334 	rtc.rtc_amin = (uint8_t)tod.tod_min;
335 	rtc.rtc_ahrs = (uint8_t)tod.tod_hour;
336 	rtc.rtc_adom = (uint8_t)tod.tod_day;
337 	DPRINTF("todbq4802_set_alarm: dom=%d hrs=%d min=%d sec=%d\n",
338 	    rtc.rtc_adom, rtc.rtc_ahrs, rtc.rtc_amin, rtc.rtc_asec);
339 
340 	/*
341 	 * Write alarm values and enable alarm
342 	 */
343 	write_rtc_alarm(&rtc);
344 
345 	BQ4802_DATA_REG(RTC_ENABLES) = regc | RTC_AIE | RTC_ABE;
346 }
347 
348 /*
349  * clear alarm interrupt
350  */
351 static void
352 todbq4802_clear_power_alarm(void)
353 {
354 	uint8_t regc;
355 
356 	ASSERT(MUTEX_HELD(&tod_lock));
357 
358 	regc = BQ4802_DATA_REG(RTC_ENABLES);
359 	BQ4802_DATA_REG(RTC_ENABLES) = regc & ~(RTC_AIE | RTC_ABE);
360 }
361 
362 /*
363  * Determine the cpu frequency by watching the TOD chip rollover twice.
364  * Cpu clock rate is determined by computing the ticks added (in tick register)
365  * during one second interval on TOD.
366  */
367 uint64_t
368 todbq4802_get_cpufrequency(void)
369 {
370 	ASSERT(MUTEX_HELD(&tod_lock));
371 	return (find_cpufrequency((volatile uint8_t *)v_rtc_addr_reg));
372 }
373 
374 /*ARGSUSED*/
375 static uint_t
376 todbq4802_set_watchdog_timer(uint_t timeoutval)
377 {
378 	ASSERT(MUTEX_HELD(&tod_lock));
379 	return (0);
380 }
381 
382 static uint_t
383 todbq4802_clear_watchdog_timer(void)
384 {
385 	ASSERT(MUTEX_HELD(&tod_lock));
386 	return (0);
387 }
388