xref: /openbmc/linux/arch/alpha/kernel/time.c (revision db2d3260)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  linux/arch/alpha/kernel/time.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *  Copyright (C) 1991, 1992, 1995, 1999, 2000  Linus Torvalds
51da177e4SLinus Torvalds  *
685d0b3a5SRichard Henderson  * This file contains the clocksource time handling.
71da177e4SLinus Torvalds  * 1997-09-10	Updated NTP code according to technical memorandum Jan '96
81da177e4SLinus Torvalds  *		"A Kernel Model for Precision Timekeeping" by Dave Mills
91da177e4SLinus Torvalds  * 1997-01-09    Adrian Sun
101da177e4SLinus Torvalds  *      use interval timer if CONFIG_RTC=y
111da177e4SLinus Torvalds  * 1997-10-29    John Bowman (bowman@math.ualberta.ca)
121da177e4SLinus Torvalds  *      fixed tick loss calculation in timer_interrupt
131da177e4SLinus Torvalds  *      (round system clock to nearest tick instead of truncating)
141da177e4SLinus Torvalds  *      fixed algorithm in time_init for getting time from CMOS clock
151da177e4SLinus Torvalds  * 1999-04-16	Thorsten Kranzkowski (dl8bcu@gmx.net)
161da177e4SLinus Torvalds  *	fixed algorithm in do_gettimeofday() for calculating the precise time
171da177e4SLinus Torvalds  *	from processor cycle counter (now taking lost_ticks into account)
181da177e4SLinus Torvalds  * 2003-06-03	R. Scott Bailey <scott.bailey@eds.com>
191da177e4SLinus Torvalds  *	Tighten sanity in time_init from 1% (10,000 PPM) to 250 PPM
201da177e4SLinus Torvalds  */
211da177e4SLinus Torvalds #include <linux/errno.h>
221da177e4SLinus Torvalds #include <linux/module.h>
231da177e4SLinus Torvalds #include <linux/sched.h>
241da177e4SLinus Torvalds #include <linux/kernel.h>
251da177e4SLinus Torvalds #include <linux/param.h>
261da177e4SLinus Torvalds #include <linux/string.h>
271da177e4SLinus Torvalds #include <linux/mm.h>
281da177e4SLinus Torvalds #include <linux/delay.h>
291da177e4SLinus Torvalds #include <linux/ioport.h>
301da177e4SLinus Torvalds #include <linux/irq.h>
311da177e4SLinus Torvalds #include <linux/interrupt.h>
321da177e4SLinus Torvalds #include <linux/init.h>
331da177e4SLinus Torvalds #include <linux/bcd.h>
341da177e4SLinus Torvalds #include <linux/profile.h>
35e360adbeSPeter Zijlstra #include <linux/irq_work.h>
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds #include <asm/uaccess.h>
381da177e4SLinus Torvalds #include <asm/io.h>
391da177e4SLinus Torvalds #include <asm/hwrpb.h>
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds #include <linux/mc146818rtc.h>
421da177e4SLinus Torvalds #include <linux/time.h>
431da177e4SLinus Torvalds #include <linux/timex.h>
449ce34c8fSJohn Stultz #include <linux/clocksource.h>
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds #include "proto.h"
471da177e4SLinus Torvalds #include "irq_impl.h"
481da177e4SLinus Torvalds 
491da177e4SLinus Torvalds DEFINE_SPINLOCK(rtc_lock);
50cff52dafSAl Viro EXPORT_SYMBOL(rtc_lock);
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds #define TICK_SIZE (tick_nsec / 1000)
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds /*
551da177e4SLinus Torvalds  * Shift amount by which scaled_ticks_per_cycle is scaled.  Shifting
561da177e4SLinus Torvalds  * by 48 gives us 16 bits for HZ while keeping the accuracy good even
571da177e4SLinus Torvalds  * for large CPU clock rates.
581da177e4SLinus Torvalds  */
591da177e4SLinus Torvalds #define FIX_SHIFT	48
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds /* lump static variables together for more efficient access: */
621da177e4SLinus Torvalds static struct {
631da177e4SLinus Torvalds 	/* cycle counter last time it got invoked */
641da177e4SLinus Torvalds 	__u32 last_time;
651da177e4SLinus Torvalds 	/* ticks/cycle * 2^48 */
661da177e4SLinus Torvalds 	unsigned long scaled_ticks_per_cycle;
671da177e4SLinus Torvalds 	/* partial unused tick */
681da177e4SLinus Torvalds 	unsigned long partial_tick;
691da177e4SLinus Torvalds } state;
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds unsigned long est_cycle_freq;
721da177e4SLinus Torvalds 
73e360adbeSPeter Zijlstra #ifdef CONFIG_IRQ_WORK
74979f8671SMichael Cree 
75e360adbeSPeter Zijlstra DEFINE_PER_CPU(u8, irq_work_pending);
76979f8671SMichael Cree 
77e360adbeSPeter Zijlstra #define set_irq_work_pending_flag()  __get_cpu_var(irq_work_pending) = 1
78e360adbeSPeter Zijlstra #define test_irq_work_pending()      __get_cpu_var(irq_work_pending)
79e360adbeSPeter Zijlstra #define clear_irq_work_pending()     __get_cpu_var(irq_work_pending) = 0
80979f8671SMichael Cree 
810f933625SPeter Zijlstra void arch_irq_work_raise(void)
82979f8671SMichael Cree {
83e360adbeSPeter Zijlstra 	set_irq_work_pending_flag();
84979f8671SMichael Cree }
85979f8671SMichael Cree 
86e360adbeSPeter Zijlstra #else  /* CONFIG_IRQ_WORK */
87979f8671SMichael Cree 
88e360adbeSPeter Zijlstra #define test_irq_work_pending()      0
89e360adbeSPeter Zijlstra #define clear_irq_work_pending()
90979f8671SMichael Cree 
91e360adbeSPeter Zijlstra #endif /* CONFIG_IRQ_WORK */
92979f8671SMichael Cree 
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds static inline __u32 rpcc(void)
951da177e4SLinus Torvalds {
9691531b05SRichard Henderson 	return __builtin_alpha_rpcc();
971da177e4SLinus Torvalds }
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds /*
1001da177e4SLinus Torvalds  * timer_interrupt() needs to keep up the real-time clock,
1011340f3e0STorben Hohn  * as well as call the "xtime_update()" routine every clocktick
1021da177e4SLinus Torvalds  */
1038774cb81SAl Viro irqreturn_t timer_interrupt(int irq, void *dev)
1041da177e4SLinus Torvalds {
1051da177e4SLinus Torvalds 	unsigned long delta;
1061da177e4SLinus Torvalds 	__u32 now;
1071da177e4SLinus Torvalds 	long nticks;
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds #ifndef CONFIG_SMP
1101da177e4SLinus Torvalds 	/* Not SMP, do kernel PC profiling here.  */
1118774cb81SAl Viro 	profile_tick(CPU_PROFILING);
1121da177e4SLinus Torvalds #endif
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds 	/*
1151da177e4SLinus Torvalds 	 * Calculate how many ticks have passed since the last update,
1161da177e4SLinus Torvalds 	 * including any previous partial leftover.  Save any resulting
1171da177e4SLinus Torvalds 	 * fraction for the next pass.
1181da177e4SLinus Torvalds 	 */
1191da177e4SLinus Torvalds 	now = rpcc();
1201da177e4SLinus Torvalds 	delta = now - state.last_time;
1211da177e4SLinus Torvalds 	state.last_time = now;
1221da177e4SLinus Torvalds 	delta = delta * state.scaled_ticks_per_cycle + state.partial_tick;
1231da177e4SLinus Torvalds 	state.partial_tick = delta & ((1UL << FIX_SHIFT) - 1);
1241da177e4SLinus Torvalds 	nticks = delta >> FIX_SHIFT;
1251da177e4SLinus Torvalds 
126aa02cd2dSPeter Zijlstra 	if (nticks)
1271340f3e0STorben Hohn 		xtime_update(nticks);
128aa02cd2dSPeter Zijlstra 
129e360adbeSPeter Zijlstra 	if (test_irq_work_pending()) {
130e360adbeSPeter Zijlstra 		clear_irq_work_pending();
131e360adbeSPeter Zijlstra 		irq_work_run();
132979f8671SMichael Cree 	}
133979f8671SMichael Cree 
134bdc8b891SMichael Cree #ifndef CONFIG_SMP
135bdc8b891SMichael Cree 	while (nticks--)
136bdc8b891SMichael Cree 		update_process_times(user_mode(get_irq_regs()));
137bdc8b891SMichael Cree #endif
138bdc8b891SMichael Cree 
1391da177e4SLinus Torvalds 	return IRQ_HANDLED;
1401da177e4SLinus Torvalds }
1411da177e4SLinus Torvalds 
142ebaf4fc1SSam Ravnborg void __init
1431da177e4SLinus Torvalds common_init_rtc(void)
1441da177e4SLinus Torvalds {
145fddd87d6SRichard Henderson 	unsigned char x, sel = 0;
1461da177e4SLinus Torvalds 
1471da177e4SLinus Torvalds 	/* Reset periodic interrupt frequency.  */
148fddd87d6SRichard Henderson #if CONFIG_HZ == 1024 || CONFIG_HZ == 1200
1491da177e4SLinus Torvalds  	x = CMOS_READ(RTC_FREQ_SELECT) & 0x3f;
1501da177e4SLinus Torvalds 	/* Test includes known working values on various platforms
1511da177e4SLinus Torvalds 	   where 0x26 is wrong; we refuse to change those. */
1521da177e4SLinus Torvalds  	if (x != 0x26 && x != 0x25 && x != 0x19 && x != 0x06) {
153fddd87d6SRichard Henderson 		sel = RTC_REF_CLCK_32KHZ + 6;
154fddd87d6SRichard Henderson 	}
155fddd87d6SRichard Henderson #elif CONFIG_HZ == 256 || CONFIG_HZ == 128 || CONFIG_HZ == 64 || CONFIG_HZ == 32
156fddd87d6SRichard Henderson 	sel = RTC_REF_CLCK_32KHZ + __builtin_ffs(32768 / CONFIG_HZ);
157fddd87d6SRichard Henderson #else
158fddd87d6SRichard Henderson # error "Unknown HZ from arch/alpha/Kconfig"
159fddd87d6SRichard Henderson #endif
160fddd87d6SRichard Henderson 	if (sel) {
161fddd87d6SRichard Henderson 		printk(KERN_INFO "Setting RTC_FREQ to %d Hz (%x)\n",
162fddd87d6SRichard Henderson 		       CONFIG_HZ, sel);
163fddd87d6SRichard Henderson 		CMOS_WRITE(sel, RTC_FREQ_SELECT);
1641da177e4SLinus Torvalds  	}
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds 	/* Turn on periodic interrupts.  */
1671da177e4SLinus Torvalds 	x = CMOS_READ(RTC_CONTROL);
1681da177e4SLinus Torvalds 	if (!(x & RTC_PIE)) {
1691da177e4SLinus Torvalds 		printk("Turning on RTC interrupts.\n");
1701da177e4SLinus Torvalds 		x |= RTC_PIE;
1711da177e4SLinus Torvalds 		x &= ~(RTC_AIE | RTC_UIE);
1721da177e4SLinus Torvalds 		CMOS_WRITE(x, RTC_CONTROL);
1731da177e4SLinus Torvalds 	}
1741da177e4SLinus Torvalds 	(void) CMOS_READ(RTC_INTR_FLAGS);
1751da177e4SLinus Torvalds 
1761da177e4SLinus Torvalds 	outb(0x36, 0x43);	/* pit counter 0: system timer */
1771da177e4SLinus Torvalds 	outb(0x00, 0x40);
1781da177e4SLinus Torvalds 	outb(0x00, 0x40);
1791da177e4SLinus Torvalds 
1801da177e4SLinus Torvalds 	outb(0xb6, 0x43);	/* pit counter 2: speaker */
1811da177e4SLinus Torvalds 	outb(0x31, 0x42);
1821da177e4SLinus Torvalds 	outb(0x13, 0x42);
1831da177e4SLinus Torvalds 
1841da177e4SLinus Torvalds 	init_rtc_irq();
1851da177e4SLinus Torvalds }
1861da177e4SLinus Torvalds 
187db2d3260SRichard Henderson 
188db2d3260SRichard Henderson #ifndef CONFIG_ALPHA_WTINT
189db2d3260SRichard Henderson /*
190db2d3260SRichard Henderson  * The RPCC as a clocksource primitive.
191db2d3260SRichard Henderson  *
192db2d3260SRichard Henderson  * While we have free-running timecounters running on all CPUs, and we make
193db2d3260SRichard Henderson  * a half-hearted attempt in init_rtc_rpcc_info to sync the timecounter
194db2d3260SRichard Henderson  * with the wall clock, that initialization isn't kept up-to-date across
195db2d3260SRichard Henderson  * different time counters in SMP mode.  Therefore we can only use this
196db2d3260SRichard Henderson  * method when there's only one CPU enabled.
197db2d3260SRichard Henderson  *
198db2d3260SRichard Henderson  * When using the WTINT PALcall, the RPCC may shift to a lower frequency,
199db2d3260SRichard Henderson  * or stop altogether, while waiting for the interrupt.  Therefore we cannot
200db2d3260SRichard Henderson  * use this method when WTINT is in use.
201db2d3260SRichard Henderson  */
202db2d3260SRichard Henderson 
203db2d3260SRichard Henderson static cycle_t read_rpcc(struct clocksource *cs)
204db2d3260SRichard Henderson {
205db2d3260SRichard Henderson 	return rpcc();
206db2d3260SRichard Henderson }
207db2d3260SRichard Henderson 
208db2d3260SRichard Henderson static struct clocksource clocksource_rpcc = {
209db2d3260SRichard Henderson 	.name                   = "rpcc",
210db2d3260SRichard Henderson 	.rating                 = 300,
211db2d3260SRichard Henderson 	.read                   = read_rpcc,
212db2d3260SRichard Henderson 	.mask                   = CLOCKSOURCE_MASK(32),
213db2d3260SRichard Henderson 	.flags                  = CLOCK_SOURCE_IS_CONTINUOUS
214db2d3260SRichard Henderson };
215db2d3260SRichard Henderson #endif /* ALPHA_WTINT */
216db2d3260SRichard Henderson 
217db2d3260SRichard Henderson 
2181da177e4SLinus Torvalds /* Validate a computed cycle counter result against the known bounds for
2191da177e4SLinus Torvalds    the given processor core.  There's too much brokenness in the way of
2201da177e4SLinus Torvalds    timing hardware for any one method to work everywhere.  :-(
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds    Return 0 if the result cannot be trusted, otherwise return the argument.  */
2231da177e4SLinus Torvalds 
2241da177e4SLinus Torvalds static unsigned long __init
2251da177e4SLinus Torvalds validate_cc_value(unsigned long cc)
2261da177e4SLinus Torvalds {
2271da177e4SLinus Torvalds 	static struct bounds {
2281da177e4SLinus Torvalds 		unsigned int min, max;
2291da177e4SLinus Torvalds 	} cpu_hz[] __initdata = {
2301da177e4SLinus Torvalds 		[EV3_CPU]    = {   50000000,  200000000 },	/* guess */
2311da177e4SLinus Torvalds 		[EV4_CPU]    = {  100000000,  300000000 },
2321da177e4SLinus Torvalds 		[LCA4_CPU]   = {  100000000,  300000000 },	/* guess */
2331da177e4SLinus Torvalds 		[EV45_CPU]   = {  200000000,  300000000 },
2341da177e4SLinus Torvalds 		[EV5_CPU]    = {  250000000,  433000000 },
2351da177e4SLinus Torvalds 		[EV56_CPU]   = {  333000000,  667000000 },
2361da177e4SLinus Torvalds 		[PCA56_CPU]  = {  400000000,  600000000 },	/* guess */
2371da177e4SLinus Torvalds 		[PCA57_CPU]  = {  500000000,  600000000 },	/* guess */
2381da177e4SLinus Torvalds 		[EV6_CPU]    = {  466000000,  600000000 },
2391da177e4SLinus Torvalds 		[EV67_CPU]   = {  600000000,  750000000 },
2401da177e4SLinus Torvalds 		[EV68AL_CPU] = {  750000000,  940000000 },
2411da177e4SLinus Torvalds 		[EV68CB_CPU] = { 1000000000, 1333333333 },
2421da177e4SLinus Torvalds 		/* None of the following are shipping as of 2001-11-01.  */
2431da177e4SLinus Torvalds 		[EV68CX_CPU] = { 1000000000, 1700000000 },	/* guess */
2441da177e4SLinus Torvalds 		[EV69_CPU]   = { 1000000000, 1700000000 },	/* guess */
2451da177e4SLinus Torvalds 		[EV7_CPU]    = {  800000000, 1400000000 },	/* guess */
2461da177e4SLinus Torvalds 		[EV79_CPU]   = { 1000000000, 2000000000 },	/* guess */
2471da177e4SLinus Torvalds 	};
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds 	/* Allow for some drift in the crystal.  10MHz is more than enough.  */
2501da177e4SLinus Torvalds 	const unsigned int deviation = 10000000;
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds 	struct percpu_struct *cpu;
2531da177e4SLinus Torvalds 	unsigned int index;
2541da177e4SLinus Torvalds 
2551da177e4SLinus Torvalds 	cpu = (struct percpu_struct *)((char*)hwrpb + hwrpb->processor_offset);
2561da177e4SLinus Torvalds 	index = cpu->type & 0xffffffff;
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 	/* If index out of bounds, no way to validate.  */
25925c8716cSTobias Klauser 	if (index >= ARRAY_SIZE(cpu_hz))
2601da177e4SLinus Torvalds 		return cc;
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds 	/* If index contains no data, no way to validate.  */
2631da177e4SLinus Torvalds 	if (cpu_hz[index].max == 0)
2641da177e4SLinus Torvalds 		return cc;
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds 	if (cc < cpu_hz[index].min - deviation
2671da177e4SLinus Torvalds 	    || cc > cpu_hz[index].max + deviation)
2681da177e4SLinus Torvalds 		return 0;
2691da177e4SLinus Torvalds 
2701da177e4SLinus Torvalds 	return cc;
2711da177e4SLinus Torvalds }
2721da177e4SLinus Torvalds 
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds /*
2751da177e4SLinus Torvalds  * Calibrate CPU clock using legacy 8254 timer/counter. Stolen from
2761da177e4SLinus Torvalds  * arch/i386/time.c.
2771da177e4SLinus Torvalds  */
2781da177e4SLinus Torvalds 
2791da177e4SLinus Torvalds #define CALIBRATE_LATCH	0xffff
2801da177e4SLinus Torvalds #define TIMEOUT_COUNT	0x100000
2811da177e4SLinus Torvalds 
2821da177e4SLinus Torvalds static unsigned long __init
2831da177e4SLinus Torvalds calibrate_cc_with_pit(void)
2841da177e4SLinus Torvalds {
2851da177e4SLinus Torvalds 	int cc, count = 0;
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds 	/* Set the Gate high, disable speaker */
2881da177e4SLinus Torvalds 	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds 	/*
2911da177e4SLinus Torvalds 	 * Now let's take care of CTC channel 2
2921da177e4SLinus Torvalds 	 *
2931da177e4SLinus Torvalds 	 * Set the Gate high, program CTC channel 2 for mode 0,
2941da177e4SLinus Torvalds 	 * (interrupt on terminal count mode), binary count,
2951da177e4SLinus Torvalds 	 * load 5 * LATCH count, (LSB and MSB) to begin countdown.
2961da177e4SLinus Torvalds 	 */
2971da177e4SLinus Torvalds 	outb(0xb0, 0x43);		/* binary, mode 0, LSB/MSB, Ch 2 */
2981da177e4SLinus Torvalds 	outb(CALIBRATE_LATCH & 0xff, 0x42);	/* LSB of count */
2991da177e4SLinus Torvalds 	outb(CALIBRATE_LATCH >> 8, 0x42);	/* MSB of count */
3001da177e4SLinus Torvalds 
3011da177e4SLinus Torvalds 	cc = rpcc();
3021da177e4SLinus Torvalds 	do {
3031da177e4SLinus Torvalds 		count++;
3041da177e4SLinus Torvalds 	} while ((inb(0x61) & 0x20) == 0 && count < TIMEOUT_COUNT);
3051da177e4SLinus Torvalds 	cc = rpcc() - cc;
3061da177e4SLinus Torvalds 
3071da177e4SLinus Torvalds 	/* Error: ECTCNEVERSET or ECPUTOOFAST.  */
3081da177e4SLinus Torvalds 	if (count <= 1 || count == TIMEOUT_COUNT)
3091da177e4SLinus Torvalds 		return 0;
3101da177e4SLinus Torvalds 
3111da177e4SLinus Torvalds 	return ((long)cc * PIT_TICK_RATE) / (CALIBRATE_LATCH + 1);
3121da177e4SLinus Torvalds }
3131da177e4SLinus Torvalds 
3141da177e4SLinus Torvalds /* The Linux interpretation of the CMOS clock register contents:
3151da177e4SLinus Torvalds    When the Update-In-Progress (UIP) flag goes from 1 to 0, the
3161da177e4SLinus Torvalds    RTC registers show the second which has precisely just started.
3171da177e4SLinus Torvalds    Let's hope other operating systems interpret the RTC the same way.  */
3181da177e4SLinus Torvalds 
3191da177e4SLinus Torvalds static unsigned long __init
3201da177e4SLinus Torvalds rpcc_after_update_in_progress(void)
3211da177e4SLinus Torvalds {
3221da177e4SLinus Torvalds 	do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
3231da177e4SLinus Torvalds 	do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
3241da177e4SLinus Torvalds 
3251da177e4SLinus Torvalds 	return rpcc();
3261da177e4SLinus Torvalds }
3271da177e4SLinus Torvalds 
3281da177e4SLinus Torvalds void __init
3291da177e4SLinus Torvalds time_init(void)
3301da177e4SLinus Torvalds {
3311e871be1SJohn Stultz 	unsigned int cc1, cc2;
3321da177e4SLinus Torvalds 	unsigned long cycle_freq, tolerance;
3331da177e4SLinus Torvalds 	long diff;
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds 	/* Calibrate CPU clock -- attempt #1.  */
3361da177e4SLinus Torvalds 	if (!est_cycle_freq)
3371da177e4SLinus Torvalds 		est_cycle_freq = validate_cc_value(calibrate_cc_with_pit());
3381da177e4SLinus Torvalds 
3394c2e6f6aSMatt Mackall 	cc1 = rpcc();
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds 	/* Calibrate CPU clock -- attempt #2.  */
3421da177e4SLinus Torvalds 	if (!est_cycle_freq) {
3434c2e6f6aSMatt Mackall 		cc1 = rpcc_after_update_in_progress();
3441da177e4SLinus Torvalds 		cc2 = rpcc_after_update_in_progress();
3451da177e4SLinus Torvalds 		est_cycle_freq = validate_cc_value(cc2 - cc1);
3461da177e4SLinus Torvalds 		cc1 = cc2;
3471da177e4SLinus Torvalds 	}
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds 	cycle_freq = hwrpb->cycle_freq;
3501da177e4SLinus Torvalds 	if (est_cycle_freq) {
3511da177e4SLinus Torvalds 		/* If the given value is within 250 PPM of what we calculated,
3521da177e4SLinus Torvalds 		   accept it.  Otherwise, use what we found.  */
3531da177e4SLinus Torvalds 		tolerance = cycle_freq / 4000;
3541da177e4SLinus Torvalds 		diff = cycle_freq - est_cycle_freq;
3551da177e4SLinus Torvalds 		if (diff < 0)
3561da177e4SLinus Torvalds 			diff = -diff;
3571da177e4SLinus Torvalds 		if ((unsigned long)diff > tolerance) {
3581da177e4SLinus Torvalds 			cycle_freq = est_cycle_freq;
3591da177e4SLinus Torvalds 			printk("HWRPB cycle frequency bogus.  "
3601da177e4SLinus Torvalds 			       "Estimated %lu Hz\n", cycle_freq);
3611da177e4SLinus Torvalds 		} else {
3621da177e4SLinus Torvalds 			est_cycle_freq = 0;
3631da177e4SLinus Torvalds 		}
3641da177e4SLinus Torvalds 	} else if (! validate_cc_value (cycle_freq)) {
3651da177e4SLinus Torvalds 		printk("HWRPB cycle frequency bogus, "
3661da177e4SLinus Torvalds 		       "and unable to estimate a proper value!\n");
3671da177e4SLinus Torvalds 	}
3681da177e4SLinus Torvalds 
369db2d3260SRichard Henderson 	/* See above for restrictions on using clocksource_rpcc.  */
370db2d3260SRichard Henderson #ifndef CONFIG_ALPHA_WTINT
371db2d3260SRichard Henderson 	if (hwrpb->nr_processors == 1)
372db2d3260SRichard Henderson 		clocksource_register_hz(&clocksource_rpcc, cycle_freq);
373db2d3260SRichard Henderson #endif
374db2d3260SRichard Henderson 
3751da177e4SLinus Torvalds 	/* From John Bowman <bowman@math.ualberta.ca>: allow the values
3761da177e4SLinus Torvalds 	   to settle, as the Update-In-Progress bit going low isn't good
3771da177e4SLinus Torvalds 	   enough on some hardware.  2ms is our guess; we haven't found
3781da177e4SLinus Torvalds 	   bogomips yet, but this is close on a 500Mhz box.  */
3791da177e4SLinus Torvalds 	__delay(1000000);
3801da177e4SLinus Torvalds 
3811da177e4SLinus Torvalds 	if (HZ > (1<<16)) {
3821da177e4SLinus Torvalds 		extern void __you_loose (void);
3831da177e4SLinus Torvalds 		__you_loose();
3841da177e4SLinus Torvalds 	}
3851da177e4SLinus Torvalds 
3861da177e4SLinus Torvalds 	state.last_time = cc1;
3871da177e4SLinus Torvalds 	state.scaled_ticks_per_cycle
3881da177e4SLinus Torvalds 		= ((unsigned long) HZ << FIX_SHIFT) / cycle_freq;
3891da177e4SLinus Torvalds 	state.partial_tick = 0L;
3901da177e4SLinus Torvalds 
3911da177e4SLinus Torvalds 	/* Startup the timer source. */
3921da177e4SLinus Torvalds 	alpha_mv.init_rtc();
3931da177e4SLinus Torvalds }
394