xref: /netbsd-src/sys/arch/next68k/next68k/rtc.c (revision fcb4a6dc912e93ee3c5f4a1655d502e228b24f5c)
1 /*      $NetBSD: rtc.c,v 1.20 2023/10/19 22:07:13 andvar Exp $        */
2 /*
3  * Copyright (c) 1998 Darrin Jewell
4  * Copyright (c) 1997 Rolf Grossmann
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Rolf Grossmann.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /* These haven't been tested to see how they interact with NeXTstep's
34  * interpretation of the rtc.
35  */
36 
37 /* Now using this in the kernel.  This should be turned into a device
38  * Darrin B Jewell <jewell@mit.edu>  Tue Jan 27 20:59:25 1998
39  */
40 
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: rtc.c,v 1.20 2023/10/19 22:07:13 andvar Exp $");
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>          /* for panic */
46 
47 #include <machine/bus.h>
48 #include <machine/cpu.h>
49 
50 #include <dev/clock_subr.h>
51 
52 #include <next68k/next68k/rtc.h>
53 
54 #include <next68k/dev/clockreg.h>
55 #include <next68k/dev/intiovar.h>
56 
57 /* #define RTC_DEBUG */
58 
59 u_char new_clock;
60 
61 /* will get memory mapped in rtc_init */
62 volatile u_int *scr2 = (u_int *)NEXT_P_SCR2;
63 
64 static int gettime_old(todr_chip_handle_t, struct clock_ymdhms *);
65 static int settime_old(todr_chip_handle_t, struct clock_ymdhms *);
66 static int gettime_new(todr_chip_handle_t, struct timeval *);
67 static int settime_new(todr_chip_handle_t, struct timeval *);
68 
69 /*
70  * NB: This code should probably be converted to a _true_ device, then this
71  * initialization could happen in attach.  The printf could get fixed then,
72  * too.
73  */
74 void
rtc_init(void)75 rtc_init(void)
76 {
77 	static struct todr_chip_handle tch;
78 	uint8_t val;
79 
80 	scr2 = (u_int *)IIOV(NEXT_P_SCR2);
81 	val = rtc_read(RTC_STATUS);
82 	new_clock = (val & RTC_NEW_CLOCK) ? 1 : 0;
83 
84 	printf("Looks like a %s clock chip.\n", new_clock ?
85 	    "MCS1850 (new style)" :
86 	    "MC68HC68T1 (old style)");
87 
88 #ifdef RTC_DEBUG
89 	rtc_print();
90 #endif
91 
92 	if (new_clock) {
93 		tch.todr_gettime = gettime_new;
94 		tch.todr_settime = settime_new;
95 		tch.todr_gettime_ymdhms = NULL;
96 		tch.todr_settime_ymdhms = NULL;
97 	} else {
98 		tch.todr_gettime_ymdhms = gettime_old;
99 		tch.todr_settime_ymdhms = settime_old;
100 		tch.todr_gettime = NULL;
101 		tch.todr_settime = NULL;
102 	}
103 	tch.todr_setwen = NULL;
104 
105 	todr_attach(&tch);
106 }
107 
108 void
rtc_print(void)109 rtc_print(void)
110 {
111 
112 #define RTC_PRINT(x)	printf("\t%16s= 0x%02x\n",#x, rtc_read(x))
113 
114 	if (new_clock) {
115 		RTC_PRINT(RTC_RAM);
116 		RTC_PRINT(RTC_CNTR0);
117 		RTC_PRINT(RTC_CNTR1);
118 		RTC_PRINT(RTC_CNTR2);
119 		RTC_PRINT(RTC_CNTR3);
120 		RTC_PRINT(RTC_ALARM0);
121 		RTC_PRINT(RTC_ALARM1);
122 		RTC_PRINT(RTC_ALARM2);
123 		RTC_PRINT(RTC_ALARM3);
124 		RTC_PRINT(RTC_STATUS);
125 		RTC_PRINT(RTC_CONTROL);
126 	} else {
127 		RTC_PRINT(RTC_RAM);
128 		RTC_PRINT(RTC_SEC);
129 		RTC_PRINT(RTC_MIN);
130 		RTC_PRINT(RTC_HRS);
131 		RTC_PRINT(RTC_DAY);
132 		RTC_PRINT(RTC_DATE);
133 		RTC_PRINT(RTC_MON);
134 		RTC_PRINT(RTC_YR);
135 		RTC_PRINT(RTC_ALARM_SEC);
136 		RTC_PRINT(RTC_ALARM_MIN);
137 		RTC_PRINT(RTC_ALARM_HR);
138 		RTC_PRINT(RTC_STATUS);
139 		RTC_PRINT(RTC_CONTROL);
140 		RTC_PRINT(RTC_INTRCTL);
141 	}
142 }
143 
144 
145 uint8_t
rtc_read(uint8_t reg)146 rtc_read(uint8_t reg)
147 {
148 	int i;
149 	u_int tmp;
150 	uint8_t val;
151 
152 	*scr2 = (*scr2 & ~(SCR2_RTDATA | SCR2_RTCLK)) | SCR2_RTCE;
153 	DELAY(1);
154 
155 	val = reg;
156 	for (i = 0; i < 8; i++) {
157 		tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK);
158 		if ((val & 0x80) != 0)
159 			tmp |= SCR2_RTDATA;
160 
161 		*scr2 = tmp;
162 		DELAY(1);
163 		*scr2 = tmp | SCR2_RTCLK;
164 		DELAY(1);
165 		*scr2 = tmp;
166 		DELAY(1);
167 
168 		val <<= 1;
169 	}
170 
171 	val = 0;			/* should be anyway */
172 	for (i = 0; i < 8; i++) {
173 		val <<= 1;
174 
175 		tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK);
176 
177 		*scr2 = tmp | SCR2_RTCLK;
178 		DELAY(1);
179 		*scr2 = tmp;
180 		DELAY(1);
181 
182 		if ((*scr2 & SCR2_RTDATA) != 0)
183 			val |= 1;
184 	}
185 
186 	*scr2 &= ~(SCR2_RTDATA | SCR2_RTCLK | SCR2_RTCE);
187 	DELAY(1);
188 
189 	return val;
190 }
191 
192 void
rtc_write(uint8_t reg,uint8_t v)193 rtc_write(uint8_t reg, uint8_t v)
194 {
195 	int i;
196 	u_int tmp;
197 	uint8_t val;
198 
199 	*scr2 = (*scr2 & ~(SCR2_RTDATA | SCR2_RTCLK)) | SCR2_RTCE;
200 	DELAY(1);
201 
202 	val = reg | RTC_WRITE;
203 
204 	for (i = 0; i < 8; i++) {
205 		tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK);
206 		if ((val & 0x80) != 0)
207 			tmp |= SCR2_RTDATA;
208 
209 		*scr2 = tmp;
210 		DELAY(1);
211 		*scr2 = tmp | SCR2_RTCLK;
212 		DELAY(1);
213 		*scr2 = tmp;
214 		DELAY(1);
215 
216 		val <<= 1;
217 	}
218 
219 	DELAY(1);
220 
221 	for (i = 0; i < 8; i++) {
222 		tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK);
223 		if ((v & 0x80) != 0)
224 			tmp |= SCR2_RTDATA;
225 
226 		*scr2 = tmp;
227 		DELAY(1);
228 		*scr2 = tmp | SCR2_RTCLK;
229 		DELAY(1);
230 		*scr2 = tmp;
231 		DELAY(1);
232 
233 		v <<= 1;
234 	}
235 
236 	*scr2 &= ~(SCR2_RTDATA | SCR2_RTCLK | SCR2_RTCE);
237 	DELAY(1);
238 }
239 
240 void
poweroff(void)241 poweroff(void)
242 {
243 	int reg, t;
244 
245 	if(new_clock) {
246 		reg = RTC_CNTR3;
247 	} else {
248 		reg = RTC_CNTR0;
249 	}
250 
251 	t = rtc_read(reg);	/* seconds */
252 	/* wait for clock to tick */
253 	while(t == rtc_read(reg))
254 		continue;
255 
256 	DELAY(850000);	/* hardware bug workaround ? */
257 
258 	if (new_clock) {
259 		reg = RTC_CONTROL;
260 	} else {
261 		reg = RTC_INTRCTL;
262 	}
263 
264 	rtc_write(reg, rtc_read(reg)|(RTC_PDOWN));
265 
266 	printf("....................."); /* @@@ work around some sort of bug. */
267 
268 	panic("Failed to poweroff!");
269 }
270 
271 
272 int
gettime_old(todr_chip_handle_t tch,struct clock_ymdhms * dt)273 gettime_old(todr_chip_handle_t tch, struct clock_ymdhms *dt)
274 {
275 	uint8_t h, y;
276 
277 	y = bcdtobin(rtc_read(RTC_YR));
278 	if (y >= 69) {
279 		dt->dt_year = 1900 + y;
280 	} else {
281 		dt->dt_year = 2000 + y;
282 	}
283 
284 	dt->dt_mon  = bcdtobin(rtc_read(RTC_MON)  & 0x1f);
285 	dt->dt_day  = bcdtobin(rtc_read(RTC_DATE) & 0x3f);
286 	dt->dt_wday = bcdtobin(rtc_read(RTC_DAY)  & 0x07);
287 
288 	h = rtc_read(RTC_HRS);
289 	if ((h & 0x80) != 0) {
290 		/* time is am/pm format */
291 		dt->dt_hour = bcdtobin(h & 0x1f);
292 		if ((h & 0x20) != 0) {
293 			/* pm */
294 			if (dt->dt_hour < 12)
295 				dt->dt_hour += 12;
296 		} else {
297 			/* am */
298 			if (dt->dt_hour == 12)
299 				dt->dt_hour = 0;
300 		}
301 #ifdef notdef
302 	} else {
303 		/* time is 24 hour format */
304 		struct clock_ymdhms val;
305 		val.dt_hour = bcdtobin(h & 0x3f);
306 #endif
307 	}
308 
309 	dt->dt_min = bcdtobin(rtc_read(RTC_MIN) & 0x7f);
310 	dt->dt_sec = bcdtobin(rtc_read(RTC_SEC) & 0x7f);
311 
312 	return 0;
313 }
314 
315 int
settime_old(todr_chip_handle_t tcr,struct clock_ymdhms * dt)316 settime_old(todr_chip_handle_t tcr, struct clock_ymdhms *dt)
317 {
318 	uint8_t h;
319 
320 	/* Stop the clock */
321 	rtc_write(RTC_CONTROL, rtc_read(RTC_CONTROL) & ~RTC_START);
322 
323 #ifdef RTC_DEBUG
324 	printf("Regs before:\n");
325 	rtc_print();
326 #endif
327 
328 	rtc_write(RTC_SEC, bintobcd(dt->dt_sec));
329 	rtc_write(RTC_MIN, bintobcd(dt->dt_min));
330 	h = rtc_read(RTC_HRS);
331 	if ((h & 0x80) != 0) {
332 		/* time is am/pm format */
333 		if (dt->dt_hour == 0) {
334 			rtc_write(RTC_HRS, bintobcd(12) | 0x80);
335 		} else if (dt->dt_hour < 12) {
336 			/* am */
337 			rtc_write(RTC_HRS, bintobcd(dt->dt_hour) | 0x80);
338 		} else if (dt->dt_hour == 12) {
339 			rtc_write(RTC_HRS, bintobcd(12) | 0x80 | 0x20);
340 		} else {
341 			/* pm */
342 			rtc_write(RTC_HRS,
343 			    bintobcd(dt->dt_hour - 12) | 0x80 | 0x20);
344 		}
345 	} else {
346 		/* time is 24 hour format */
347 		rtc_write(RTC_HRS, bintobcd(dt->dt_hour));
348 	}
349 	rtc_write(RTC_DAY, bintobcd(dt->dt_wday));
350 	rtc_write(RTC_DATE, bintobcd(dt->dt_day));
351 	rtc_write(RTC_MON, bintobcd(dt->dt_mon));
352 	rtc_write(RTC_YR, bintobcd(dt->dt_year % 100));
353 
354 #ifdef RTC_DEBUG
355 	printf("Regs after:\n");
356 	rtc_print();
357 #endif
358 
359 	/* restart the clock */
360 	rtc_write(RTC_CONTROL, rtc_read(RTC_CONTROL) | RTC_START);
361 	return 0;
362 }
363 
364 int
gettime_new(todr_chip_handle_t tch,struct timeval * tvp)365 gettime_new(todr_chip_handle_t tch, struct timeval *tvp)
366 {
367 	tvp->tv_sec =
368 	    rtc_read(RTC_CNTR0) << 24 |
369 	    rtc_read(RTC_CNTR1) << 16 |
370 	    rtc_read(RTC_CNTR2) <<  8 |
371 	    rtc_read(RTC_CNTR3);
372 	return 0;
373 }
374 
375 int
settime_new(todr_chip_handle_t tch,struct timeval * tvp)376 settime_new(todr_chip_handle_t tch, struct timeval *tvp)
377 {
378 
379 	/* Stop the clock */
380 	rtc_write(RTC_CONTROL, rtc_read(RTC_CONTROL) & ~RTC_START);
381 
382 #ifdef RTC_DEBUG
383 	printf("Setting RTC to 0x%08llx.  Regs before:\n", tvp->tv_sec);
384 	rtc_print();
385 #endif
386 
387 	rtc_write(RTC_CNTR0, (tvp->tv_sec >> 24) & 0xff);
388 	rtc_write(RTC_CNTR1, (tvp->tv_sec >> 16) & 0xff);
389 	rtc_write(RTC_CNTR2, (tvp->tv_sec >>  8) & 0xff);
390 	rtc_write(RTC_CNTR3, (tvp->tv_sec) & 0xff);
391 
392 #ifdef RTC_DEBUG
393 	printf("Regs after:\n");
394 	rtc_print();
395 #endif
396 
397 	/* restart the clock */
398 	rtc_write(RTC_CONTROL, rtc_read(RTC_CONTROL) | RTC_START);
399 
400 	return 0;
401 }
402