Home | History | Annotate | Line # | Download | only in next68k
      1 /*      $NetBSD: rtc.c,v 1.21 2025/09/07 04:47:00 thorpej 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 (at) 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.21 2025/09/07 04:47:00 thorpej 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
     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 
    104 	todr_attach(&tch);
    105 }
    106 
    107 void
    108 rtc_print(void)
    109 {
    110 
    111 #define RTC_PRINT(x)	printf("\t%16s= 0x%02x\n",#x, rtc_read(x))
    112 
    113 	if (new_clock) {
    114 		RTC_PRINT(RTC_RAM);
    115 		RTC_PRINT(RTC_CNTR0);
    116 		RTC_PRINT(RTC_CNTR1);
    117 		RTC_PRINT(RTC_CNTR2);
    118 		RTC_PRINT(RTC_CNTR3);
    119 		RTC_PRINT(RTC_ALARM0);
    120 		RTC_PRINT(RTC_ALARM1);
    121 		RTC_PRINT(RTC_ALARM2);
    122 		RTC_PRINT(RTC_ALARM3);
    123 		RTC_PRINT(RTC_STATUS);
    124 		RTC_PRINT(RTC_CONTROL);
    125 	} else {
    126 		RTC_PRINT(RTC_RAM);
    127 		RTC_PRINT(RTC_SEC);
    128 		RTC_PRINT(RTC_MIN);
    129 		RTC_PRINT(RTC_HRS);
    130 		RTC_PRINT(RTC_DAY);
    131 		RTC_PRINT(RTC_DATE);
    132 		RTC_PRINT(RTC_MON);
    133 		RTC_PRINT(RTC_YR);
    134 		RTC_PRINT(RTC_ALARM_SEC);
    135 		RTC_PRINT(RTC_ALARM_MIN);
    136 		RTC_PRINT(RTC_ALARM_HR);
    137 		RTC_PRINT(RTC_STATUS);
    138 		RTC_PRINT(RTC_CONTROL);
    139 		RTC_PRINT(RTC_INTRCTL);
    140 	}
    141 }
    142 
    143 
    144 uint8_t
    145 rtc_read(uint8_t reg)
    146 {
    147 	int i;
    148 	u_int tmp;
    149 	uint8_t val;
    150 
    151 	*scr2 = (*scr2 & ~(SCR2_RTDATA | SCR2_RTCLK)) | SCR2_RTCE;
    152 	DELAY(1);
    153 
    154 	val = reg;
    155 	for (i = 0; i < 8; i++) {
    156 		tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK);
    157 		if ((val & 0x80) != 0)
    158 			tmp |= SCR2_RTDATA;
    159 
    160 		*scr2 = tmp;
    161 		DELAY(1);
    162 		*scr2 = tmp | SCR2_RTCLK;
    163 		DELAY(1);
    164 		*scr2 = tmp;
    165 		DELAY(1);
    166 
    167 		val <<= 1;
    168 	}
    169 
    170 	val = 0;			/* should be anyway */
    171 	for (i = 0; i < 8; i++) {
    172 		val <<= 1;
    173 
    174 		tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK);
    175 
    176 		*scr2 = tmp | SCR2_RTCLK;
    177 		DELAY(1);
    178 		*scr2 = tmp;
    179 		DELAY(1);
    180 
    181 		if ((*scr2 & SCR2_RTDATA) != 0)
    182 			val |= 1;
    183 	}
    184 
    185 	*scr2 &= ~(SCR2_RTDATA | SCR2_RTCLK | SCR2_RTCE);
    186 	DELAY(1);
    187 
    188 	return val;
    189 }
    190 
    191 void
    192 rtc_write(uint8_t reg, uint8_t v)
    193 {
    194 	int i;
    195 	u_int tmp;
    196 	uint8_t val;
    197 
    198 	*scr2 = (*scr2 & ~(SCR2_RTDATA | SCR2_RTCLK)) | SCR2_RTCE;
    199 	DELAY(1);
    200 
    201 	val = reg | RTC_WRITE;
    202 
    203 	for (i = 0; i < 8; i++) {
    204 		tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK);
    205 		if ((val & 0x80) != 0)
    206 			tmp |= SCR2_RTDATA;
    207 
    208 		*scr2 = tmp;
    209 		DELAY(1);
    210 		*scr2 = tmp | SCR2_RTCLK;
    211 		DELAY(1);
    212 		*scr2 = tmp;
    213 		DELAY(1);
    214 
    215 		val <<= 1;
    216 	}
    217 
    218 	DELAY(1);
    219 
    220 	for (i = 0; i < 8; i++) {
    221 		tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK);
    222 		if ((v & 0x80) != 0)
    223 			tmp |= SCR2_RTDATA;
    224 
    225 		*scr2 = tmp;
    226 		DELAY(1);
    227 		*scr2 = tmp | SCR2_RTCLK;
    228 		DELAY(1);
    229 		*scr2 = tmp;
    230 		DELAY(1);
    231 
    232 		v <<= 1;
    233 	}
    234 
    235 	*scr2 &= ~(SCR2_RTDATA | SCR2_RTCLK | SCR2_RTCE);
    236 	DELAY(1);
    237 }
    238 
    239 void
    240 poweroff(void)
    241 {
    242 	int reg, t;
    243 
    244 	if(new_clock) {
    245 		reg = RTC_CNTR3;
    246 	} else {
    247 		reg = RTC_CNTR0;
    248 	}
    249 
    250 	t = rtc_read(reg);	/* seconds */
    251 	/* wait for clock to tick */
    252 	while(t == rtc_read(reg))
    253 		continue;
    254 
    255 	DELAY(850000);	/* hardware bug workaround ? */
    256 
    257 	if (new_clock) {
    258 		reg = RTC_CONTROL;
    259 	} else {
    260 		reg = RTC_INTRCTL;
    261 	}
    262 
    263 	rtc_write(reg, rtc_read(reg)|(RTC_PDOWN));
    264 
    265 	printf("....................."); /* @@@ work around some sort of bug. */
    266 
    267 	panic("Failed to poweroff!");
    268 }
    269 
    270 
    271 int
    272 gettime_old(todr_chip_handle_t tch, struct clock_ymdhms *dt)
    273 {
    274 	uint8_t h, y;
    275 
    276 	y = bcdtobin(rtc_read(RTC_YR));
    277 	if (y >= 69) {
    278 		dt->dt_year = 1900 + y;
    279 	} else {
    280 		dt->dt_year = 2000 + y;
    281 	}
    282 
    283 	dt->dt_mon  = bcdtobin(rtc_read(RTC_MON)  & 0x1f);
    284 	dt->dt_day  = bcdtobin(rtc_read(RTC_DATE) & 0x3f);
    285 	dt->dt_wday = bcdtobin(rtc_read(RTC_DAY)  & 0x07);
    286 
    287 	h = rtc_read(RTC_HRS);
    288 	if ((h & 0x80) != 0) {
    289 		/* time is am/pm format */
    290 		dt->dt_hour = bcdtobin(h & 0x1f);
    291 		if ((h & 0x20) != 0) {
    292 			/* pm */
    293 			if (dt->dt_hour < 12)
    294 				dt->dt_hour += 12;
    295 		} else {
    296 			/* am */
    297 			if (dt->dt_hour == 12)
    298 				dt->dt_hour = 0;
    299 		}
    300 #ifdef notdef
    301 	} else {
    302 		/* time is 24 hour format */
    303 		struct clock_ymdhms val;
    304 		val.dt_hour = bcdtobin(h & 0x3f);
    305 #endif
    306 	}
    307 
    308 	dt->dt_min = bcdtobin(rtc_read(RTC_MIN) & 0x7f);
    309 	dt->dt_sec = bcdtobin(rtc_read(RTC_SEC) & 0x7f);
    310 
    311 	return 0;
    312 }
    313 
    314 int
    315 settime_old(todr_chip_handle_t tcr, struct clock_ymdhms *dt)
    316 {
    317 	uint8_t h;
    318 
    319 	/* Stop the clock */
    320 	rtc_write(RTC_CONTROL, rtc_read(RTC_CONTROL) & ~RTC_START);
    321 
    322 #ifdef RTC_DEBUG
    323 	printf("Regs before:\n");
    324 	rtc_print();
    325 #endif
    326 
    327 	rtc_write(RTC_SEC, bintobcd(dt->dt_sec));
    328 	rtc_write(RTC_MIN, bintobcd(dt->dt_min));
    329 	h = rtc_read(RTC_HRS);
    330 	if ((h & 0x80) != 0) {
    331 		/* time is am/pm format */
    332 		if (dt->dt_hour == 0) {
    333 			rtc_write(RTC_HRS, bintobcd(12) | 0x80);
    334 		} else if (dt->dt_hour < 12) {
    335 			/* am */
    336 			rtc_write(RTC_HRS, bintobcd(dt->dt_hour) | 0x80);
    337 		} else if (dt->dt_hour == 12) {
    338 			rtc_write(RTC_HRS, bintobcd(12) | 0x80 | 0x20);
    339 		} else {
    340 			/* pm */
    341 			rtc_write(RTC_HRS,
    342 			    bintobcd(dt->dt_hour - 12) | 0x80 | 0x20);
    343 		}
    344 	} else {
    345 		/* time is 24 hour format */
    346 		rtc_write(RTC_HRS, bintobcd(dt->dt_hour));
    347 	}
    348 	rtc_write(RTC_DAY, bintobcd(dt->dt_wday));
    349 	rtc_write(RTC_DATE, bintobcd(dt->dt_day));
    350 	rtc_write(RTC_MON, bintobcd(dt->dt_mon));
    351 	rtc_write(RTC_YR, bintobcd(dt->dt_year % 100));
    352 
    353 #ifdef RTC_DEBUG
    354 	printf("Regs after:\n");
    355 	rtc_print();
    356 #endif
    357 
    358 	/* restart the clock */
    359 	rtc_write(RTC_CONTROL, rtc_read(RTC_CONTROL) | RTC_START);
    360 	return 0;
    361 }
    362 
    363 int
    364 gettime_new(todr_chip_handle_t tch, struct timeval *tvp)
    365 {
    366 	tvp->tv_sec =
    367 	    rtc_read(RTC_CNTR0) << 24 |
    368 	    rtc_read(RTC_CNTR1) << 16 |
    369 	    rtc_read(RTC_CNTR2) <<  8 |
    370 	    rtc_read(RTC_CNTR3);
    371 	return 0;
    372 }
    373 
    374 int
    375 settime_new(todr_chip_handle_t tch, struct timeval *tvp)
    376 {
    377 
    378 	/* Stop the clock */
    379 	rtc_write(RTC_CONTROL, rtc_read(RTC_CONTROL) & ~RTC_START);
    380 
    381 #ifdef RTC_DEBUG
    382 	printf("Setting RTC to 0x%08llx.  Regs before:\n", tvp->tv_sec);
    383 	rtc_print();
    384 #endif
    385 
    386 	rtc_write(RTC_CNTR0, (tvp->tv_sec >> 24) & 0xff);
    387 	rtc_write(RTC_CNTR1, (tvp->tv_sec >> 16) & 0xff);
    388 	rtc_write(RTC_CNTR2, (tvp->tv_sec >>  8) & 0xff);
    389 	rtc_write(RTC_CNTR3, (tvp->tv_sec) & 0xff);
    390 
    391 #ifdef RTC_DEBUG
    392 	printf("Regs after:\n");
    393 	rtc_print();
    394 #endif
    395 
    396 	/* restart the clock */
    397 	rtc_write(RTC_CONTROL, rtc_read(RTC_CONTROL) | RTC_START);
    398 
    399 	return 0;
    400 }
    401