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