clock.c revision 139825
1139825Simp/*- 277957Sbenno * Copyright (C) 1995, 1996 Wolfgang Solfrank. 377957Sbenno * Copyright (C) 1995, 1996 TooLs GmbH. 477957Sbenno * All rights reserved. 577957Sbenno * 677957Sbenno * Redistribution and use in source and binary forms, with or without 777957Sbenno * modification, are permitted provided that the following conditions 877957Sbenno * are met: 977957Sbenno * 1. Redistributions of source code must retain the above copyright 1077957Sbenno * notice, this list of conditions and the following disclaimer. 1177957Sbenno * 2. Redistributions in binary form must reproduce the above copyright 1277957Sbenno * notice, this list of conditions and the following disclaimer in the 1377957Sbenno * documentation and/or other materials provided with the distribution. 1477957Sbenno * 3. All advertising materials mentioning features or use of this software 1577957Sbenno * must display the following acknowledgement: 1677957Sbenno * This product includes software developed by TooLs GmbH. 1777957Sbenno * 4. The name of TooLs GmbH may not be used to endorse or promote products 1877957Sbenno * derived from this software without specific prior written permission. 1977957Sbenno * 2077957Sbenno * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 2177957Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2277957Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2377957Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2477957Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2577957Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 2677957Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2777957Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2877957Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 2977957Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3077957Sbenno * 3178880Sbenno * $NetBSD: clock.c,v 1.9 2000/01/19 02:52:19 msaitoh Exp $ 3277957Sbenno */ 3378880Sbenno/* 3478880Sbenno * Copyright (C) 2001 Benno Rice. 3578880Sbenno * All rights reserved. 3678880Sbenno * 3778880Sbenno * Redistribution and use in source and binary forms, with or without 3878880Sbenno * modification, are permitted provided that the following conditions 3978880Sbenno * are met: 4078880Sbenno * 1. Redistributions of source code must retain the above copyright 4178880Sbenno * notice, this list of conditions and the following disclaimer. 4278880Sbenno * 2. Redistributions in binary form must reproduce the above copyright 4378880Sbenno * notice, this list of conditions and the following disclaimer in the 4478880Sbenno * documentation and/or other materials provided with the distribution. 4578880Sbenno * 4678880Sbenno * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 4778880Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 4878880Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 4978880Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 5078880Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 5178880Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 5278880Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 5378880Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 5478880Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 5578880Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5678880Sbenno */ 5777957Sbenno 58113038Sobrien#include <sys/cdefs.h> 59113038Sobrien__FBSDID("$FreeBSD: head/sys/powerpc/aim/clock.c 139825 2005-01-07 02:29:27Z imp $"); 6077957Sbenno 6177957Sbenno#include <sys/param.h> 6277957Sbenno#include <sys/systm.h> 6378880Sbenno#include <sys/kernel.h> 6478880Sbenno#include <sys/sysctl.h> 6577957Sbenno#include <sys/bus.h> 6677957Sbenno#include <sys/timetc.h> 6777957Sbenno#include <sys/interrupt.h> 6877957Sbenno 6977957Sbenno#include <dev/ofw/openfirm.h> 7077957Sbenno 7177957Sbenno#include <machine/clock.h> 7277957Sbenno#include <machine/cpu.h> 7378880Sbenno#include <machine/intr.h> 74125691Sgrehan#include <machine/md_var.h> 7577957Sbenno 7677957Sbenno/* 7777957Sbenno * Initially we assume a processor with a bus frequency of 12.5 MHz. 7877957Sbenno */ 7999032Sbennou_int tickspending; 80110388Sbennou_long ns_per_tick = 80; 8199032Sbennostatic u_long ticks_per_sec = 12500000; 8277957Sbennostatic long ticks_per_intr; 8377957Sbennostatic volatile u_long lasttb; 8477957Sbenno 8577957Sbenno#define SECDAY 86400 8677957Sbenno#define DIFF19041970 2082844800 8777957Sbenno 8877957Sbennostatic int clockinitted = 0; 8977957Sbenno 90110380Sbennostatic timecounter_get_t decr_get_timecount; 9178880Sbenno 92110380Sbennostatic struct timecounter decr_timecounter = { 93110380Sbenno decr_get_timecount, /* get_timecount */ 9478880Sbenno 0, /* no poll_pps */ 9578880Sbenno ~0u, /* counter_mask */ 9678880Sbenno 0, /* frequency */ 97110380Sbenno "decrementer" /* name */ 9878880Sbenno}; 9978880Sbenno 10077957Sbennovoid 10177957Sbennoinittodr(time_t base) 10277957Sbenno{ 10377957Sbenno time_t deltat; 10477957Sbenno u_int rtc_time; 10577957Sbenno struct timespec ts; 106108941Sgrehan phandle_t phandle; 107108941Sgrehan ihandle_t ihandle; 108108941Sgrehan char rtcpath[128]; 109108941Sgrehan u_int rtcsecs; 11077957Sbenno 11177957Sbenno /* 11277957Sbenno * If we can't read from RTC, use the fs time. 11377957Sbenno */ 114108941Sgrehan phandle = OF_finddevice("rtc"); 115108941Sgrehan if (phandle != -1) { 116108941Sgrehan OF_package_to_path(phandle, rtcpath, sizeof(rtcpath)); 117108941Sgrehan ihandle = OF_open(rtcpath); 118108941Sgrehan if (ihandle != -1) { 119108941Sgrehan if (OF_call_method("read-rtc", ihandle, 120108941Sgrehan 0, 1, &rtcsecs)) 121108941Sgrehan printf("RTC call method error\n"); 122108941Sgrehan else { 123108941Sgrehan ts.tv_sec = rtcsecs - DIFF19041970; 124108941Sgrehan ts.tv_nsec = 0; 125108941Sgrehan tc_setclock(&ts); 126108941Sgrehan return; 127108941Sgrehan } 128108941Sgrehan } 129108941Sgrehan } 130108941Sgrehan 13177957Sbenno { 13277957Sbenno ts.tv_sec = base; 13377957Sbenno ts.tv_nsec = 0; 13477957Sbenno tc_setclock(&ts); 13577957Sbenno return; 13677957Sbenno } 13777957Sbenno clockinitted = 1; 13877957Sbenno ts.tv_sec = rtc_time - DIFF19041970; 13977957Sbenno 14077957Sbenno deltat = ts.tv_sec - base; 14177957Sbenno if (deltat < 0) { 14277957Sbenno deltat = -deltat; 14377957Sbenno } 14477957Sbenno if (deltat < 2 * SECDAY) { 14577957Sbenno tc_setclock(&ts); 14677957Sbenno return; 14777957Sbenno } 14877957Sbenno 14977957Sbenno printf("WARNING: clock %s %d days", 15077957Sbenno ts.tv_sec < base ? "lost" : "gained", (int)(deltat / SECDAY)); 15177957Sbenno 15277957Sbenno printf(" -- CHECK AND RESET THE DATE!\n"); 15377957Sbenno} 15477957Sbenno 15577957Sbenno/* 15677957Sbenno * Similar to the above 15777957Sbenno */ 15877957Sbennovoid 15977957Sbennoresettodr() 16077957Sbenno{ 16177957Sbenno 16277957Sbenno} 16377957Sbenno 16477957Sbennovoid 16577957Sbennodecr_intr(struct clockframe *frame) 16677957Sbenno{ 16791485Sbenno u_long tb; 16891485Sbenno long tick; 16991485Sbenno int nticks; 17077957Sbenno 17177957Sbenno /* 17277957Sbenno * Check whether we are initialized. 17377957Sbenno */ 17477957Sbenno if (!ticks_per_intr) 17577957Sbenno return; 17677957Sbenno 17777957Sbenno /* 17877957Sbenno * Based on the actual time delay since the last decrementer reload, 17977957Sbenno * we arrange for earlier interrupt next time. 18077957Sbenno */ 18177957Sbenno __asm ("mftb %0; mfdec %1" : "=r"(tb), "=r"(tick)); 18277957Sbenno for (nticks = 0; tick < 0; nticks++) 18377957Sbenno tick += ticks_per_intr; 18495121Sbenno mtdec(tick); 18577957Sbenno /* 18677957Sbenno * lasttb is used during microtime. Set it to the virtual 18777957Sbenno * start of this tick interval. 18877957Sbenno */ 18977957Sbenno lasttb = tb + tick - ticks_per_intr; 19077957Sbenno 19191485Sbenno nticks += tickspending; 19291485Sbenno tickspending = 0; 19377957Sbenno 19491485Sbenno /* 19591485Sbenno * Reenable interrupts 19691485Sbenno */ 19799032Sbenno#if 0 19891485Sbenno msr = mfmsr(); 19991485Sbenno mtmsr(msr | PSL_EE | PSL_RI); 200125691Sgrehan#endif 20191485Sbenno /* 20291485Sbenno * Do standard timer interrupt stuff. 20391485Sbenno * Do softclock stuff only on the last iteration. 20491485Sbenno */ 20599032Sbenno#if 0 20691485Sbenno while (--nticks > 0) { 20778880Sbenno hardclock(frame); 20877957Sbenno } 20999032Sbenno#endif 21091485Sbenno hardclock(frame); 21177957Sbenno} 21277957Sbenno 21377957Sbennovoid 21477957Sbennocpu_initclocks(void) 21577957Sbenno{ 216110380Sbenno 217110380Sbenno return; 218110380Sbenno} 219110380Sbenno 220110380Sbennovoid 221110380Sbennodecr_init(void) 222110380Sbenno{ 22378880Sbenno int qhandle, phandle; 22478880Sbenno char name[32]; 22578880Sbenno unsigned int msr; 226125691Sgrehan 22791485Sbenno phandle = 0; 22891485Sbenno 22978880Sbenno /* 23078880Sbenno * Get this info during autoconf? XXX 23178880Sbenno */ 23278880Sbenno for (qhandle = OF_peer(0); qhandle; qhandle = phandle) { 23378880Sbenno if (OF_getprop(qhandle, "device_type", name, sizeof name) >= 0 23478880Sbenno && !strcmp(name, "cpu") 23578880Sbenno && OF_getprop(qhandle, "timebase-frequency", 23678880Sbenno &ticks_per_sec, sizeof ticks_per_sec) >= 0) { 23778880Sbenno /* 23878880Sbenno * Should check for correct CPU here? XXX 23978880Sbenno */ 24078880Sbenno msr = mfmsr(); 24191485Sbenno mtmsr(msr & ~(PSL_EE|PSL_RI)); 24277957Sbenno 243110380Sbenno decr_timecounter.tc_frequency = ticks_per_sec; 244110380Sbenno tc_init(&decr_timecounter); 24578880Sbenno 24678880Sbenno ns_per_tick = 1000000000 / ticks_per_sec; 24778880Sbenno ticks_per_intr = ticks_per_sec / hz; 24878880Sbenno __asm __volatile ("mftb %0" : "=r"(lasttb)); 24978880Sbenno mtdec(ticks_per_intr); 25078880Sbenno 25178880Sbenno mtmsr(msr); 25278880Sbenno 25378880Sbenno break; 25478880Sbenno } 25578880Sbenno if ((phandle = OF_child(qhandle))) 25678880Sbenno continue; 25778880Sbenno while (qhandle) { 25878880Sbenno if ((phandle = OF_peer(qhandle))) 25978880Sbenno break; 26078880Sbenno qhandle = OF_parent(qhandle); 26178880Sbenno } 26278880Sbenno } 26378880Sbenno if (!phandle) 26478880Sbenno panic("no cpu node"); 26577957Sbenno} 26677957Sbenno 26777957Sbennostatic __inline u_quad_t 26877957Sbennomftb(void) 26977957Sbenno{ 27077957Sbenno u_long scratch; 27177957Sbenno u_quad_t tb; 272125691Sgrehan 27377957Sbenno __asm ("1: mftbu %0; mftb %0+1; mftbu %1; cmpw 0,%0,%1; bne 1b" 27477957Sbenno : "=r"(tb), "=r"(scratch)); 27577957Sbenno return tb; 27677957Sbenno} 27777957Sbenno 27878880Sbennostatic unsigned 279110380Sbennodecr_get_timecount(struct timecounter *tc) 28078880Sbenno{ 28178880Sbenno return mftb(); 28278880Sbenno} 28378880Sbenno 28477957Sbenno/* 28577957Sbenno * Wait for about n microseconds (at least!). 28677957Sbenno */ 28777957Sbennovoid 288120460SgrehanDELAY(int n) 28977957Sbenno{ 290110381Sbenno u_quad_t tb, ttb; 291125691Sgrehan 29277957Sbenno tb = mftb(); 293110381Sbenno ttb = tb + (n * 1000 + ns_per_tick - 1) / ns_per_tick; 294110381Sbenno while (tb < ttb) 295110381Sbenno tb = mftb(); 29677957Sbenno} 29777957Sbenno 29877957Sbenno/* 29977957Sbenno * Nothing to do. 30077957Sbenno */ 30177957Sbennovoid 302110296Sjakecpu_startprofclock(void) 30377957Sbenno{ 30477957Sbenno 30577957Sbenno /* Do nothing */ 30677957Sbenno} 307110296Sjake 308110296Sjakevoid 309110296Sjakecpu_stopprofclock(void) 310110296Sjake{ 311110296Sjake} 312124771Sgrehan 313124771Sgrehan/* 314124771Sgrehan * XXX Needed by syscons 315124771Sgrehan */ 316124771Sgrehanint 317124771Sgrehansysbeep(int pitch, int period) 318124771Sgrehan{ 319124771Sgrehan 320124771Sgrehan return (0); 321124771Sgrehan} 322