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 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 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 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 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 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 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 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 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 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