clock.c revision 108941
1264790Sbapt/* 2264790Sbapt * Copyright (C) 1995, 1996 Wolfgang Solfrank. 3264790Sbapt * Copyright (C) 1995, 1996 TooLs GmbH. 4264790Sbapt * All rights reserved. 5264790Sbapt * 6264790Sbapt * Redistribution and use in source and binary forms, with or without 7264790Sbapt * modification, are permitted provided that the following conditions 8264790Sbapt * are met: 9264790Sbapt * 1. Redistributions of source code must retain the above copyright 10264790Sbapt * notice, this list of conditions and the following disclaimer. 11264790Sbapt * 2. Redistributions in binary form must reproduce the above copyright 12264790Sbapt * notice, this list of conditions and the following disclaimer in the 13264790Sbapt * documentation and/or other materials provided with the distribution. 14264790Sbapt * 3. All advertising materials mentioning features or use of this software 15264790Sbapt * must display the following acknowledgement: 16264790Sbapt * This product includes software developed by TooLs GmbH. 17264790Sbapt * 4. The name of TooLs GmbH may not be used to endorse or promote products 18264790Sbapt * derived from this software without specific prior written permission. 19264790Sbapt * 20264790Sbapt * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 21264790Sbapt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22264790Sbapt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23264790Sbapt * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24264790Sbapt * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25264790Sbapt * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26264790Sbapt * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27264790Sbapt * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28264790Sbapt * 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#ifndef lint 59static const char rcsid[] = 60 "$FreeBSD: head/sys/powerpc/aim/clock.c 108941 2003-01-08 12:17:44Z grehan $"; 61#endif /* not lint */ 62 63#include <sys/param.h> 64#include <sys/systm.h> 65#include <sys/kernel.h> 66#include <sys/sysctl.h> 67#include <sys/bus.h> 68#include <sys/timetc.h> 69#include <sys/interrupt.h> 70 71#include <dev/ofw/openfirm.h> 72 73#include <machine/clock.h> 74#include <machine/cpu.h> 75#include <machine/intr.h> 76 77#if 0 /* XXX */ 78#include "adb.h" 79#else 80#define NADB 0 81#endif 82 83/* 84 * Initially we assume a processor with a bus frequency of 12.5 MHz. 85 */ 86u_int tickspending; 87static u_long ticks_per_sec = 12500000; 88static u_long ns_per_tick = 80; 89static long ticks_per_intr; 90static volatile u_long lasttb; 91 92#define SECDAY 86400 93#define DIFF19041970 2082844800 94 95#if NADB > 0 96extern int adb_read_date_time(int *); 97extern int adb_set_date_time(int); 98#endif 99 100static int clockinitted = 0; 101 102static timecounter_get_t powerpc_get_timecount; 103 104static struct timecounter powerpc_timecounter = { 105 powerpc_get_timecount, /* get_timecount */ 106 0, /* no poll_pps */ 107 ~0u, /* counter_mask */ 108 0, /* frequency */ 109 "powerpc" /* name */ 110}; 111 112void 113inittodr(time_t base) 114{ 115 time_t deltat; 116 u_int rtc_time; 117 struct timespec ts; 118 phandle_t phandle; 119 ihandle_t ihandle; 120 char rtcpath[128]; 121 u_int rtcsecs; 122 123 /* 124 * If we can't read from RTC, use the fs time. 125 */ 126 phandle = OF_finddevice("rtc"); 127 if (phandle != -1) { 128 OF_package_to_path(phandle, rtcpath, sizeof(rtcpath)); 129 ihandle = OF_open(rtcpath); 130 if (ihandle != -1) { 131 if (OF_call_method("read-rtc", ihandle, 132 0, 1, &rtcsecs)) 133 printf("RTC call method error\n"); 134 else { 135 ts.tv_sec = rtcsecs - DIFF19041970; 136 ts.tv_nsec = 0; 137 tc_setclock(&ts); 138 return; 139 } 140 } 141 } 142 143#if NADB > 0 144 if (adb_read_date_time(&rtc_time) < 0) 145#endif 146 { 147 ts.tv_sec = base; 148 ts.tv_nsec = 0; 149 tc_setclock(&ts); 150 return; 151 } 152 clockinitted = 1; 153 ts.tv_sec = rtc_time - DIFF19041970; 154 155 deltat = ts.tv_sec - base; 156 if (deltat < 0) { 157 deltat = -deltat; 158 } 159 if (deltat < 2 * SECDAY) { 160 tc_setclock(&ts); 161 return; 162 } 163 164 printf("WARNING: clock %s %d days", 165 ts.tv_sec < base ? "lost" : "gained", (int)(deltat / SECDAY)); 166 167 printf(" -- CHECK AND RESET THE DATE!\n"); 168} 169 170/* 171 * Similar to the above 172 */ 173void 174resettodr() 175{ 176#if NADB > 0 177 u_int rtc_time; 178 179 if (clockinitted) { 180 rtc_time = time.tv_sec + DIFF19041970; 181 adb_set_date_time(rtc_time); 182 } 183#endif 184} 185 186void 187decr_intr(struct clockframe *frame) 188{ 189 u_long tb; 190 long tick; 191 int nticks; 192 register_t msr; 193 194 /* 195 * Check whether we are initialized. 196 */ 197 if (!ticks_per_intr) 198 return; 199 200 /* 201 * Based on the actual time delay since the last decrementer reload, 202 * we arrange for earlier interrupt next time. 203 */ 204 __asm ("mftb %0; mfdec %1" : "=r"(tb), "=r"(tick)); 205 for (nticks = 0; tick < 0; nticks++) 206 tick += ticks_per_intr; 207 mtdec(tick); 208 /* 209 * lasttb is used during microtime. Set it to the virtual 210 * start of this tick interval. 211 */ 212 lasttb = tb + tick - ticks_per_intr; 213 214 nticks += tickspending; 215 tickspending = 0; 216 217 /* 218 * Reenable interrupts 219 */ 220#if 0 221 msr = mfmsr(); 222 mtmsr(msr | PSL_EE | PSL_RI); 223#endif 224 /* 225 * Do standard timer interrupt stuff. 226 * Do softclock stuff only on the last iteration. 227 */ 228#if 0 229 while (--nticks > 0) { 230 hardclock(frame); 231 } 232#endif 233 hardclock(frame); 234} 235 236void 237cpu_initclocks(void) 238{ 239 int qhandle, phandle; 240 char name[32]; 241 unsigned int msr; 242 243 phandle = 0; 244 245 /* 246 * Get this info during autoconf? XXX 247 */ 248 for (qhandle = OF_peer(0); qhandle; qhandle = phandle) { 249 if (OF_getprop(qhandle, "device_type", name, sizeof name) >= 0 250 && !strcmp(name, "cpu") 251 && OF_getprop(qhandle, "timebase-frequency", 252 &ticks_per_sec, sizeof ticks_per_sec) >= 0) { 253 /* 254 * Should check for correct CPU here? XXX 255 */ 256 msr = mfmsr(); 257 mtmsr(msr & ~(PSL_EE|PSL_RI)); 258 259 powerpc_timecounter.tc_frequency = ticks_per_sec; 260 tc_init(&powerpc_timecounter); 261 262 ns_per_tick = 1000000000 / ticks_per_sec; 263 ticks_per_intr = ticks_per_sec / hz; 264 __asm __volatile ("mftb %0" : "=r"(lasttb)); 265 mtdec(ticks_per_intr); 266 267 mtmsr(msr); 268 269 break; 270 } 271 if ((phandle = OF_child(qhandle))) 272 continue; 273 while (qhandle) { 274 if ((phandle = OF_peer(qhandle))) 275 break; 276 qhandle = OF_parent(qhandle); 277 } 278 } 279 if (!phandle) 280 panic("no cpu node"); 281} 282 283static __inline u_quad_t 284mftb(void) 285{ 286 u_long scratch; 287 u_quad_t tb; 288 289 __asm ("1: mftbu %0; mftb %0+1; mftbu %1; cmpw 0,%0,%1; bne 1b" 290 : "=r"(tb), "=r"(scratch)); 291 return tb; 292} 293 294static unsigned 295powerpc_get_timecount(struct timecounter *tc) 296{ 297 return mftb(); 298} 299 300/* 301 * Wait for about n microseconds (at least!). 302 */ 303void 304delay(int n) 305{ 306 u_quad_t tb; 307 u_long tbh, tbl, scratch; 308 309 tb = mftb(); 310 tb += (n * 1000 + ns_per_tick - 1) / ns_per_tick; 311 tbh = tb >> 32; 312 tbl = tb; 313 __asm ("1: mftbu %0; cmplw %0,%1; blt 1b; bgt 2f;" 314 "mftb %0; cmplw %0,%2; blt 1b; 2:" 315 : "=r"(scratch) : "r"(tbh), "r"(tbl)); 316} 317 318/* 319 * Nothing to do. 320 */ 321void 322setstatclockrate(int arg) 323{ 324 325 /* Do nothing */ 326} 327