clock.c revision 95121
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#ifndef lint 59static const char rcsid[] = 60 "$FreeBSD: head/sys/powerpc/aim/clock.c 95121 2002-04-20 10:06:22Z benno $"; 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 */ 86static u_long ticks_per_sec = 12500000; 87static u_long ns_per_tick = 80; 88static long ticks_per_intr; 89static volatile u_long lasttb; 90 91#define SECDAY 86400 92#define DIFF19041970 2082844800 93 94#if NADB > 0 95extern int adb_read_date_time(int *); 96extern int adb_set_date_time(int); 97#endif 98 99static int clockinitted = 0; 100 101static timecounter_get_t powerpc_get_timecount; 102 103static struct timecounter powerpc_timecounter = { 104 powerpc_get_timecount, /* get_timecount */ 105 0, /* no poll_pps */ 106 ~0u, /* counter_mask */ 107 0, /* frequency */ 108 "powerpc" /* name */ 109}; 110 111SYSCTL_OPAQUE(_debug, OID_AUTO, powerpc_timecounter, CTLFLAG_RD, 112 &powerpc_timecounter, sizeof(powerpc_timecounter), "S,timecounter", ""); 113 114void 115inittodr(time_t base) 116{ 117 time_t deltat; 118 u_int rtc_time; 119 struct timespec ts; 120 121 /* 122 * If we can't read from RTC, use the fs time. 123 */ 124#if NADB > 0 125 if (adb_read_date_time(&rtc_time) < 0) 126#endif 127 { 128 ts.tv_sec = base; 129 ts.tv_nsec = 0; 130 tc_setclock(&ts); 131 return; 132 } 133 clockinitted = 1; 134 ts.tv_sec = rtc_time - DIFF19041970; 135 136 deltat = ts.tv_sec - base; 137 if (deltat < 0) { 138 deltat = -deltat; 139 } 140 if (deltat < 2 * SECDAY) { 141 tc_setclock(&ts); 142 return; 143 } 144 145 printf("WARNING: clock %s %d days", 146 ts.tv_sec < base ? "lost" : "gained", (int)(deltat / SECDAY)); 147 148 printf(" -- CHECK AND RESET THE DATE!\n"); 149} 150 151/* 152 * Similar to the above 153 */ 154void 155resettodr() 156{ 157#if NADB > 0 158 u_int rtc_time; 159 160 if (clockinitted) { 161 rtc_time = time.tv_sec + DIFF19041970; 162 adb_set_date_time(rtc_time); 163 } 164#endif 165} 166 167void 168decr_intr(struct clockframe *frame) 169{ 170 u_long tb; 171 long tick; 172 int nticks; 173 register_t msr; 174 175 /* 176 * Check whether we are initialized. 177 */ 178 if (!ticks_per_intr) 179 return; 180 181 /* 182 * Based on the actual time delay since the last decrementer reload, 183 * we arrange for earlier interrupt next time. 184 */ 185 __asm ("mftb %0; mfdec %1" : "=r"(tb), "=r"(tick)); 186 for (nticks = 0; tick < 0; nticks++) 187 tick += ticks_per_intr; 188 mtdec(tick); 189 /* 190 * lasttb is used during microtime. Set it to the virtual 191 * start of this tick interval. 192 */ 193 lasttb = tb + tick - ticks_per_intr; 194 195 /* 196 * This probably needs some kind of locking. 197 */ 198 199 intrcnt[CNT_CLOCK]++; 200 201 nticks += tickspending; 202 tickspending = 0; 203 204 /* 205 * Reenable interrupts 206 */ 207 msr = mfmsr(); 208 mtmsr(msr | PSL_EE | PSL_RI); 209 210 /* 211 * Do standard timer interrupt stuff. 212 * Do softclock stuff only on the last iteration. 213 */ 214 while (--nticks > 0) { 215 hardclock(frame); 216 } 217 hardclock(frame); 218} 219 220void 221cpu_initclocks(void) 222{ 223 int qhandle, phandle; 224 char name[32]; 225 unsigned int msr; 226 227 phandle = 0; 228 229 /* 230 * Get this info during autoconf? XXX 231 */ 232 for (qhandle = OF_peer(0); qhandle; qhandle = phandle) { 233 if (OF_getprop(qhandle, "device_type", name, sizeof name) >= 0 234 && !strcmp(name, "cpu") 235 && OF_getprop(qhandle, "timebase-frequency", 236 &ticks_per_sec, sizeof ticks_per_sec) >= 0) { 237 /* 238 * Should check for correct CPU here? XXX 239 */ 240 msr = mfmsr(); 241 mtmsr(msr & ~(PSL_EE|PSL_RI)); 242 243 powerpc_timecounter.tc_frequency = ticks_per_sec; 244 tc_init(&powerpc_timecounter); 245 246 ns_per_tick = 1000000000 / ticks_per_sec; 247 ticks_per_intr = ticks_per_sec / hz; 248 __asm __volatile ("mftb %0" : "=r"(lasttb)); 249 mtdec(ticks_per_intr); 250 251 mtmsr(msr); 252 253 break; 254 } 255 if ((phandle = OF_child(qhandle))) 256 continue; 257 while (qhandle) { 258 if ((phandle = OF_peer(qhandle))) 259 break; 260 qhandle = OF_parent(qhandle); 261 } 262 } 263 if (!phandle) 264 panic("no cpu node"); 265} 266 267static __inline u_quad_t 268mftb(void) 269{ 270 u_long scratch; 271 u_quad_t tb; 272 273 __asm ("1: mftbu %0; mftb %0+1; mftbu %1; cmpw 0,%0,%1; bne 1b" 274 : "=r"(tb), "=r"(scratch)); 275 return tb; 276} 277 278static unsigned 279powerpc_get_timecount(struct timecounter *tc) 280{ 281 return mftb(); 282} 283 284/* 285 * Wait for about n microseconds (at least!). 286 */ 287void 288delay(int n) 289{ 290 u_quad_t tb; 291 u_long tbh, tbl, scratch; 292 293 tb = mftb(); 294 tb += (n * 1000 + ns_per_tick - 1) / ns_per_tick; 295 tbh = tb >> 32; 296 tbl = tb; 297 __asm ("1: mftbu %0; cmplw %0,%1; blt 1b; bgt 2f;" 298 "mftb %0; cmplw %0,%2; blt 1b; 2:" 299 : "=r"(scratch) : "r"(tbh), "r"(tbl)); 300} 301 302/* 303 * Nothing to do. 304 */ 305void 306setstatclockrate(int arg) 307{ 308 309 /* Do nothing */ 310} 311