clock.c revision 77957
177957Sbenno/* 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 * 3177957Sbenno * $NetBSD: clock.c,v 1.9 2000/01/19 02:52:19 msaitoh Exp $ */ 3277957Sbenno */ 3377957Sbenno 3477957Sbenno#ifndef lint 3577957Sbennostatic const char rcsid[] = 3677957Sbenno "$FreeBSD: head/sys/powerpc/aim/clock.c 77957 2001-06-10 02:39:37Z benno $"; 3777957Sbenno#endif /* not lint */ 3877957Sbenno 3977957Sbenno#include <sys/param.h> 4077957Sbenno#include <sys/systm.h> 4177957Sbenno#include <sys/bus.h> 4277957Sbenno#include <sys/kernel.h> 4377957Sbenno#include <sys/timetc.h> 4477957Sbenno#include <sys/interrupt.h> 4577957Sbenno 4677957Sbenno#include <vm/vm.h> 4777957Sbenno 4877957Sbenno#include <dev/ofw/openfirm.h> 4977957Sbenno 5077957Sbenno#include <machine/clock.h> 5177957Sbenno#include <machine/cpu.h> 5277957Sbenno 5377957Sbenno#if 0 /* XXX */ 5477957Sbenno#include "adb.h" 5577957Sbenno#else 5677957Sbenno#define NADB 0 5777957Sbenno#endif 5877957Sbenno 5977957Sbenno/* 6077957Sbenno * Initially we assume a processor with a bus frequency of 12.5 MHz. 6177957Sbenno */ 6277957Sbennostatic u_long ns_per_tick = 80; 6377957Sbennostatic long ticks_per_intr; 6477957Sbennostatic volatile u_long lasttb; 6577957Sbenno 6677957Sbenno#define SECDAY 86400 6777957Sbenno#define DIFF19041970 2082844800 6877957Sbenno 6977957Sbenno#if NADB > 0 7077957Sbennoextern int adb_read_date_time __P((int *)); 7177957Sbennoextern int adb_set_date_time __P((int)); 7277957Sbenno#endif 7377957Sbenno 7477957Sbennostatic int clockinitted = 0; 7577957Sbenno 7677957Sbennovoid 7777957Sbennoinittodr(time_t base) 7877957Sbenno{ 7977957Sbenno time_t deltat; 8077957Sbenno u_int rtc_time; 8177957Sbenno struct timespec ts; 8277957Sbenno 8377957Sbenno /* 8477957Sbenno * If we can't read from RTC, use the fs time. 8577957Sbenno */ 8677957Sbenno#if NADB > 0 8777957Sbenno if (adb_read_date_time(&rtc_time) < 0) 8877957Sbenno#endif 8977957Sbenno { 9077957Sbenno ts.tv_sec = base; 9177957Sbenno ts.tv_nsec = 0; 9277957Sbenno tc_setclock(&ts); 9377957Sbenno return; 9477957Sbenno } 9577957Sbenno clockinitted = 1; 9677957Sbenno ts.tv_sec = rtc_time - DIFF19041970; 9777957Sbenno 9877957Sbenno deltat = ts.tv_sec - base; 9977957Sbenno if (deltat < 0) { 10077957Sbenno deltat = -deltat; 10177957Sbenno } 10277957Sbenno if (deltat < 2 * SECDAY) { 10377957Sbenno tc_setclock(&ts); 10477957Sbenno return; 10577957Sbenno } 10677957Sbenno 10777957Sbenno printf("WARNING: clock %s %d days", 10877957Sbenno ts.tv_sec < base ? "lost" : "gained", (int)(deltat / SECDAY)); 10977957Sbenno 11077957Sbenno printf(" -- CHECK AND RESET THE DATE!\n"); 11177957Sbenno} 11277957Sbenno 11377957Sbenno/* 11477957Sbenno * Similar to the above 11577957Sbenno */ 11677957Sbennovoid 11777957Sbennoresettodr() 11877957Sbenno{ 11977957Sbenno#if NADB > 0 12077957Sbenno u_int rtc_time; 12177957Sbenno 12277957Sbenno if (clockinitted) { 12377957Sbenno rtc_time = time.tv_sec + DIFF19041970; 12477957Sbenno adb_set_date_time(rtc_time); 12577957Sbenno } 12677957Sbenno#endif 12777957Sbenno} 12877957Sbenno 12977957Sbennovoid 13077957Sbennodecr_intr(struct clockframe *frame) 13177957Sbenno{ 13277957Sbenno u_long tb; 13377957Sbenno long tick; 13477957Sbenno int nticks; 13577957Sbenno 13677957Sbenno /* 13777957Sbenno * Check whether we are initialized. 13877957Sbenno */ 13977957Sbenno if (!ticks_per_intr) 14077957Sbenno return; 14177957Sbenno 14277957Sbenno /* 14377957Sbenno * Based on the actual time delay since the last decrementer reload, 14477957Sbenno * we arrange for earlier interrupt next time. 14577957Sbenno */ 14677957Sbenno __asm ("mftb %0; mfdec %1" : "=r"(tb), "=r"(tick)); 14777957Sbenno for (nticks = 0; tick < 0; nticks++) 14877957Sbenno tick += ticks_per_intr; 14977957Sbenno __asm __volatile ("mtdec %0" :: "r"(tick)); 15077957Sbenno /* 15177957Sbenno * lasttb is used during microtime. Set it to the virtual 15277957Sbenno * start of this tick interval. 15377957Sbenno */ 15477957Sbenno lasttb = tb + tick - ticks_per_intr; 15577957Sbenno 15677957Sbenno#if 0 /* XXX */ 15777957Sbenno intrcnt[CNT_CLOCK]++; 15877957Sbenno { 15977957Sbenno int pri; 16077957Sbenno int msr; 16177957Sbenno 16277957Sbenno pri = splclock(); 16377957Sbenno if (pri & (1 << SPL_CLOCK)) { 16477957Sbenno tickspending += nticks; 16577957Sbenno } 16677957Sbenno else { 16777957Sbenno nticks += tickspending; 16877957Sbenno tickspending = 0; 16977957Sbenno 17077957Sbenno /* 17177957Sbenno * Reenable interrupts 17277957Sbenno */ 17377957Sbenno __asm __volatile ("mfmsr %0; ori %0, %0, %1; mtmsr %0" 17477957Sbenno : "=r"(msr) : "K"(PSL_EE)); 17577957Sbenno 17677957Sbenno /* 17777957Sbenno * Do standard timer interrupt stuff. 17877957Sbenno * Do softclock stuff only on the last iteration. 17977957Sbenno */ 18077957Sbenno frame->pri = pri | (1 << SIR_CLOCK); 18177957Sbenno while (--nticks > 0) 18277957Sbenno hardclock(frame); 18377957Sbenno frame->pri = pri; 18477957Sbenno hardclock(frame); 18577957Sbenno } 18677957Sbenno splx(pri); 18777957Sbenno } 18877957Sbenno#endif 18977957Sbenno} 19077957Sbenno 19177957Sbennovoid 19277957Sbennocpu_initclocks(void) 19377957Sbenno{ 19477957Sbenno 19577957Sbenno /* Do nothing */ 19677957Sbenno} 19777957Sbenno 19877957Sbennostatic __inline u_quad_t 19977957Sbennomftb(void) 20077957Sbenno{ 20177957Sbenno u_long scratch; 20277957Sbenno u_quad_t tb; 20377957Sbenno 20477957Sbenno __asm ("1: mftbu %0; mftb %0+1; mftbu %1; cmpw 0,%0,%1; bne 1b" 20577957Sbenno : "=r"(tb), "=r"(scratch)); 20677957Sbenno return tb; 20777957Sbenno} 20877957Sbenno 20977957Sbenno/* 21077957Sbenno * Wait for about n microseconds (at least!). 21177957Sbenno */ 21277957Sbennovoid 21377957Sbennodelay(unsigned n) 21477957Sbenno{ 21577957Sbenno u_quad_t tb; 21677957Sbenno u_long tbh, tbl, scratch; 21777957Sbenno 21877957Sbenno tb = mftb(); 21977957Sbenno tb += (n * 1000 + ns_per_tick - 1) / ns_per_tick; 22077957Sbenno tbh = tb >> 32; 22177957Sbenno tbl = tb; 22277957Sbenno __asm ("1: mftbu %0; cmplw %0,%1; blt 1b; bgt 2f;" 22377957Sbenno "mftb %0; cmplw %0,%2; blt 1b; 2:" 22477957Sbenno :: "r"(scratch), "r"(tbh), "r"(tbl)); 22577957Sbenno} 22677957Sbenno 22777957Sbenno/* 22877957Sbenno * Nothing to do. 22977957Sbenno */ 23077957Sbennovoid 23177957Sbennosetstatclockrate(int arg) 23277957Sbenno{ 23377957Sbenno 23477957Sbenno /* Do nothing */ 23577957Sbenno} 236