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