1 /*- 2 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 3 * Copyright (C) 1995, 1996 TooLs GmbH. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by TooLs GmbH. 17 * 4. The name of TooLs GmbH may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 * $NetBSD: clock.c,v 1.9 2000/01/19 02:52:19 msaitoh Exp $ 32 */ 33 /* 34 * Copyright (C) 2001 Benno Rice. 35 * All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 46 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 49 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 52 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 53 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 54 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 55 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 */ 57 58 #include <sys/cdefs.h> 59 __FBSDID("$FreeBSD$"); 60 61 #include <sys/param.h> 62 #include <sys/systm.h> 63 #include <sys/kernel.h> 64 #include <sys/sysctl.h> 65 #include <sys/bus.h> 66 #include <sys/timetc.h> 67 #include <sys/interrupt.h> 68 69 #include <dev/ofw/openfirm.h> 70 71 #include <machine/clock.h> 72 #include <machine/cpu.h> 73 #include <machine/intr.h> 74 #include <machine/md_var.h> 75 76 /* 77 * Initially we assume a processor with a bus frequency of 12.5 MHz. 78 */ 79 u_int tickspending; 80 u_long ns_per_tick = 80; 81 static u_long ticks_per_sec = 12500000; 82 static long ticks_per_intr; 83 static volatile u_long lasttb; 84 85 static int sysctl_machdep_adjkerntz(SYSCTL_HANDLER_ARGS); 86 87 int wall_cmos_clock; /* wall CMOS clock assumed if != 0 */ 88 SYSCTL_INT(_machdep, CPU_WALLCLOCK, wall_cmos_clock, 89 CTLFLAG_RW, &wall_cmos_clock, 0, ""); 90 91 int adjkerntz; /* local offset from GMT in seconds */ 92 SYSCTL_PROC(_machdep, CPU_ADJKERNTZ, adjkerntz, CTLTYPE_INT|CTLFLAG_RW, 93 &adjkerntz, 0, sysctl_machdep_adjkerntz, "I", ""); 94 95 #define SECDAY 86400 96 #define DIFF19041970 2082844800 97 98 static int clockinitted = 0; 99 100 static timecounter_get_t decr_get_timecount; 101 102 static struct timecounter decr_timecounter = { 103 decr_get_timecount, /* get_timecount */ 104 0, /* no poll_pps */ 105 ~0u, /* counter_mask */ 106 0, /* frequency */ 107 "decrementer" /* name */ 108 }; 109 110 static int 111 sysctl_machdep_adjkerntz(SYSCTL_HANDLER_ARGS) 112 { 113 int error; 114 115 error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); 116 if (!error && req->newptr) 117 resettodr(); 118 return (error); 119 } 120 121 void 122 inittodr(time_t base) 123 { 124 time_t deltat; 125 u_int rtc_time; 126 struct timespec ts; 127 phandle_t phandle; 128 ihandle_t ihandle; 129 char rtcpath[128]; 130 u_int rtcsecs; 131 132 /* 133 * If we can't read from RTC, use the fs time. 134 */ 135 phandle = OF_finddevice("rtc"); 136 if (phandle != -1) { 137 OF_package_to_path(phandle, rtcpath, sizeof(rtcpath)); 138 ihandle = OF_open(rtcpath); 139 if (ihandle != -1) { 140 if (OF_call_method("read-rtc", ihandle, 141 0, 1, &rtcsecs)) 142 printf("RTC call method error\n"); 143 else { 144 ts.tv_sec = rtcsecs - DIFF19041970; 145 ts.tv_nsec = 0; 146 tc_setclock(&ts); 147 return; 148 } 149 } 150 } 151 152 { 153 ts.tv_sec = base; 154 ts.tv_nsec = 0; 155 tc_setclock(&ts); 156 return; 157 } 158 clockinitted = 1; 159 ts.tv_sec = rtc_time - DIFF19041970; 160 161 deltat = ts.tv_sec - base; 162 if (deltat < 0) { 163 deltat = -deltat; 164 } 165 if (deltat < 2 * SECDAY) { 166 tc_setclock(&ts); 167 return; 168 } 169 170 printf("WARNING: clock %s %d days", 171 ts.tv_sec < base ? "lost" : "gained", (int)(deltat / SECDAY)); 172 173 printf(" -- CHECK AND RESET THE DATE!\n"); 174 } 175 176 /* 177 * Similar to the above 178 */ 179 void 180 resettodr() 181 { 182 183 } 184 185 void 186 decr_intr(struct trapframe *frame) 187 { 188 u_long tb; 189 long tick; 190 int nticks; 191 192 /* 193 * Check whether we are initialized. 194 */ 195 if (!ticks_per_intr) 196 return; 197 198 /* 199 * Based on the actual time delay since the last decrementer reload, 200 * we arrange for earlier interrupt next time. 201 */ 202 __asm ("mftb %0; mfdec %1" : "=r"(tb), "=r"(tick)); 203 for (nticks = 0; tick < 0; nticks++) 204 tick += ticks_per_intr; 205 mtdec(tick); 206 /* 207 * lasttb is used during microtime. Set it to the virtual 208 * start of this tick interval. 209 */ 210 lasttb = tb + tick - ticks_per_intr; 211 212 nticks += tickspending; 213 tickspending = 0; 214 215 /* 216 * Reenable interrupts 217 */ 218 #if 0 219 msr = mfmsr(); 220 mtmsr(msr | PSL_EE | PSL_RI); 221 #endif 222 /* 223 * Do standard timer interrupt stuff. 224 * Do softclock stuff only on the last iteration. 225 */ 226 #if 0 227 while (--nticks > 0) { 228 hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); 229 } 230 #endif 231 hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); 232 } 233 234 void 235 cpu_initclocks(void) 236 { 237 238 return; 239 } 240 241 void 242 decr_init(void) 243 { 244 int qhandle, phandle; 245 char name[32]; 246 unsigned int msr; 247 248 phandle = 0; 249 250 /* 251 * Get this info during autoconf? XXX 252 */ 253 for (qhandle = OF_peer(0); qhandle; qhandle = phandle) { 254 if (OF_getprop(qhandle, "device_type", name, sizeof name) >= 0 255 && !strcmp(name, "cpu") 256 && OF_getprop(qhandle, "timebase-frequency", 257 &ticks_per_sec, sizeof ticks_per_sec) >= 0) { 258 /* 259 * Should check for correct CPU here? XXX 260 */ 261 msr = mfmsr(); 262 mtmsr(msr & ~(PSL_EE|PSL_RI)); 263 264 decr_timecounter.tc_frequency = ticks_per_sec; 265 tc_init(&decr_timecounter); 266 267 ns_per_tick = 1000000000 / ticks_per_sec; 268 ticks_per_intr = ticks_per_sec / hz; 269 __asm __volatile ("mftb %0" : "=r"(lasttb)); 270 mtdec(ticks_per_intr); 271 272 mtmsr(msr); 273 274 break; 275 } 276 if ((phandle = OF_child(qhandle))) 277 continue; 278 while (qhandle) { 279 if ((phandle = OF_peer(qhandle))) 280 break; 281 qhandle = OF_parent(qhandle); 282 } 283 } 284 if (!phandle) 285 panic("no cpu node"); 286 } 287 288 static __inline u_quad_t 289 mftb(void) 290 { 291 u_long scratch; 292 u_quad_t tb; 293 294 __asm ("1: mftbu %0; mftb %0+1; mftbu %1; cmpw 0,%0,%1; bne 1b" 295 : "=r"(tb), "=r"(scratch)); 296 return tb; 297 } 298 299 static unsigned 300 decr_get_timecount(struct timecounter *tc) 301 { 302 return mftb(); 303 } 304 305 /* 306 * Wait for about n microseconds (at least!). 307 */ 308 void 309 DELAY(int n) 310 { 311 u_quad_t tb, ttb; 312 313 tb = mftb(); 314 ttb = tb + (n * 1000 + ns_per_tick - 1) / ns_per_tick; 315 while (tb < ttb) 316 tb = mftb(); 317 } 318 319 /* 320 * Nothing to do. 321 */ 322 void 323 cpu_startprofclock(void) 324 { 325 326 /* Do nothing */ 327 } 328 329 void 330 cpu_stopprofclock(void) 331 { 332 } 333 334 /* 335 * XXX Needed by syscons 336 */ 337 int 338 sysbeep(int pitch, int period) 339 { 340 341 return (0); 342 } 343