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 377c0f6ba6SLinus Torvalds #include <linux/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> 45a1659d6dSRichard Henderson #include <linux/clockchips.h> 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds #include "proto.h" 481da177e4SLinus Torvalds #include "irq_impl.h" 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds DEFINE_SPINLOCK(rtc_lock); 51cff52dafSAl Viro EXPORT_SYMBOL(rtc_lock); 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds unsigned long est_cycle_freq; 541da177e4SLinus Torvalds 55e360adbeSPeter Zijlstra #ifdef CONFIG_IRQ_WORK 56979f8671SMichael Cree 57e360adbeSPeter Zijlstra DEFINE_PER_CPU(u8, irq_work_pending); 58979f8671SMichael Cree 592999a4b3SChristoph Lameter #define set_irq_work_pending_flag() __this_cpu_write(irq_work_pending, 1) 602999a4b3SChristoph Lameter #define test_irq_work_pending() __this_cpu_read(irq_work_pending) 612999a4b3SChristoph Lameter #define clear_irq_work_pending() __this_cpu_write(irq_work_pending, 0) 62979f8671SMichael Cree 630f933625SPeter Zijlstra void arch_irq_work_raise(void) 64979f8671SMichael Cree { 65e360adbeSPeter Zijlstra set_irq_work_pending_flag(); 66979f8671SMichael Cree } 67979f8671SMichael Cree 68e360adbeSPeter Zijlstra #else /* CONFIG_IRQ_WORK */ 69979f8671SMichael Cree 70e360adbeSPeter Zijlstra #define test_irq_work_pending() 0 71e360adbeSPeter Zijlstra #define clear_irq_work_pending() 72979f8671SMichael Cree 73e360adbeSPeter Zijlstra #endif /* CONFIG_IRQ_WORK */ 74979f8671SMichael Cree 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds static inline __u32 rpcc(void) 771da177e4SLinus Torvalds { 7891531b05SRichard Henderson return __builtin_alpha_rpcc(); 791da177e4SLinus Torvalds } 801da177e4SLinus Torvalds 81a1659d6dSRichard Henderson 82a1659d6dSRichard Henderson 831da177e4SLinus Torvalds /* 84a1659d6dSRichard Henderson * The RTC as a clock_event_device primitive. 851da177e4SLinus Torvalds */ 86a1659d6dSRichard Henderson 87a1659d6dSRichard Henderson static DEFINE_PER_CPU(struct clock_event_device, cpu_ce); 88a1659d6dSRichard Henderson 89a1659d6dSRichard Henderson irqreturn_t 904914d7b4SRichard Henderson rtc_timer_interrupt(int irq, void *dev) 911da177e4SLinus Torvalds { 92a1659d6dSRichard Henderson int cpu = smp_processor_id(); 93a1659d6dSRichard Henderson struct clock_event_device *ce = &per_cpu(cpu_ce, cpu); 941da177e4SLinus Torvalds 95a1659d6dSRichard Henderson /* Don't run the hook for UNUSED or SHUTDOWN. */ 966ec81932SViresh Kumar if (likely(clockevent_state_periodic(ce))) 97a1659d6dSRichard Henderson ce->event_handler(ce); 98aa02cd2dSPeter Zijlstra 99e360adbeSPeter Zijlstra if (test_irq_work_pending()) { 100e360adbeSPeter Zijlstra clear_irq_work_pending(); 101e360adbeSPeter Zijlstra irq_work_run(); 102979f8671SMichael Cree } 103979f8671SMichael Cree 1041da177e4SLinus Torvalds return IRQ_HANDLED; 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds 107a1659d6dSRichard Henderson static int 108a1659d6dSRichard Henderson rtc_ce_set_next_event(unsigned long evt, struct clock_event_device *ce) 109a1659d6dSRichard Henderson { 110a1659d6dSRichard Henderson /* This hook is for oneshot mode, which we don't support. */ 111a1659d6dSRichard Henderson return -EINVAL; 112a1659d6dSRichard Henderson } 113a1659d6dSRichard Henderson 1144914d7b4SRichard Henderson static void __init 1154914d7b4SRichard Henderson init_rtc_clockevent(void) 116a1659d6dSRichard Henderson { 117a1659d6dSRichard Henderson int cpu = smp_processor_id(); 118a1659d6dSRichard Henderson struct clock_event_device *ce = &per_cpu(cpu_ce, cpu); 119a1659d6dSRichard Henderson 120a1659d6dSRichard Henderson *ce = (struct clock_event_device){ 121a1659d6dSRichard Henderson .name = "rtc", 122a1659d6dSRichard Henderson .features = CLOCK_EVT_FEAT_PERIODIC, 123a1659d6dSRichard Henderson .rating = 100, 124a1659d6dSRichard Henderson .cpumask = cpumask_of(cpu), 125a1659d6dSRichard Henderson .set_next_event = rtc_ce_set_next_event, 126a1659d6dSRichard Henderson }; 127a1659d6dSRichard Henderson 128a1659d6dSRichard Henderson clockevents_config_and_register(ce, CONFIG_HZ, 0, 0); 129a1659d6dSRichard Henderson } 130a1659d6dSRichard Henderson 1314914d7b4SRichard Henderson 1324914d7b4SRichard Henderson /* 1334914d7b4SRichard Henderson * The QEMU clock as a clocksource primitive. 1344914d7b4SRichard Henderson */ 1354914d7b4SRichard Henderson 136a5a1d1c2SThomas Gleixner static u64 1374914d7b4SRichard Henderson qemu_cs_read(struct clocksource *cs) 1384914d7b4SRichard Henderson { 1394914d7b4SRichard Henderson return qemu_get_vmtime(); 1404914d7b4SRichard Henderson } 1414914d7b4SRichard Henderson 1424914d7b4SRichard Henderson static struct clocksource qemu_cs = { 1434914d7b4SRichard Henderson .name = "qemu", 1444914d7b4SRichard Henderson .rating = 400, 1454914d7b4SRichard Henderson .read = qemu_cs_read, 1464914d7b4SRichard Henderson .mask = CLOCKSOURCE_MASK(64), 1474914d7b4SRichard Henderson .flags = CLOCK_SOURCE_IS_CONTINUOUS, 1484914d7b4SRichard Henderson .max_idle_ns = LONG_MAX 1494914d7b4SRichard Henderson }; 1504914d7b4SRichard Henderson 1514914d7b4SRichard Henderson 1524914d7b4SRichard Henderson /* 1534914d7b4SRichard Henderson * The QEMU alarm as a clock_event_device primitive. 1544914d7b4SRichard Henderson */ 1554914d7b4SRichard Henderson 1566ec81932SViresh Kumar static int qemu_ce_shutdown(struct clock_event_device *ce) 1574914d7b4SRichard Henderson { 1584914d7b4SRichard Henderson /* The mode member of CE is updated for us in generic code. 1594914d7b4SRichard Henderson Just make sure that the event is disabled. */ 1604914d7b4SRichard Henderson qemu_set_alarm_abs(0); 1616ec81932SViresh Kumar return 0; 1624914d7b4SRichard Henderson } 1634914d7b4SRichard Henderson 1644914d7b4SRichard Henderson static int 1654914d7b4SRichard Henderson qemu_ce_set_next_event(unsigned long evt, struct clock_event_device *ce) 1664914d7b4SRichard Henderson { 1674914d7b4SRichard Henderson qemu_set_alarm_rel(evt); 1684914d7b4SRichard Henderson return 0; 1694914d7b4SRichard Henderson } 1704914d7b4SRichard Henderson 1714914d7b4SRichard Henderson static irqreturn_t 1724914d7b4SRichard Henderson qemu_timer_interrupt(int irq, void *dev) 1734914d7b4SRichard Henderson { 1744914d7b4SRichard Henderson int cpu = smp_processor_id(); 1754914d7b4SRichard Henderson struct clock_event_device *ce = &per_cpu(cpu_ce, cpu); 1764914d7b4SRichard Henderson 1774914d7b4SRichard Henderson ce->event_handler(ce); 1784914d7b4SRichard Henderson return IRQ_HANDLED; 1794914d7b4SRichard Henderson } 1804914d7b4SRichard Henderson 1814914d7b4SRichard Henderson static void __init 1824914d7b4SRichard Henderson init_qemu_clockevent(void) 1834914d7b4SRichard Henderson { 1844914d7b4SRichard Henderson int cpu = smp_processor_id(); 1854914d7b4SRichard Henderson struct clock_event_device *ce = &per_cpu(cpu_ce, cpu); 1864914d7b4SRichard Henderson 1874914d7b4SRichard Henderson *ce = (struct clock_event_device){ 1884914d7b4SRichard Henderson .name = "qemu", 1894914d7b4SRichard Henderson .features = CLOCK_EVT_FEAT_ONESHOT, 1904914d7b4SRichard Henderson .rating = 400, 1914914d7b4SRichard Henderson .cpumask = cpumask_of(cpu), 1926ec81932SViresh Kumar .set_state_shutdown = qemu_ce_shutdown, 1936ec81932SViresh Kumar .set_state_oneshot = qemu_ce_shutdown, 1946ec81932SViresh Kumar .tick_resume = qemu_ce_shutdown, 1954914d7b4SRichard Henderson .set_next_event = qemu_ce_set_next_event, 1964914d7b4SRichard Henderson }; 1974914d7b4SRichard Henderson 1984914d7b4SRichard Henderson clockevents_config_and_register(ce, NSEC_PER_SEC, 1000, LONG_MAX); 1994914d7b4SRichard Henderson } 2004914d7b4SRichard Henderson 2014914d7b4SRichard Henderson 202ebaf4fc1SSam Ravnborg void __init 2031da177e4SLinus Torvalds common_init_rtc(void) 2041da177e4SLinus Torvalds { 205fddd87d6SRichard Henderson unsigned char x, sel = 0; 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds /* Reset periodic interrupt frequency. */ 208fddd87d6SRichard Henderson #if CONFIG_HZ == 1024 || CONFIG_HZ == 1200 2091da177e4SLinus Torvalds x = CMOS_READ(RTC_FREQ_SELECT) & 0x3f; 2101da177e4SLinus Torvalds /* Test includes known working values on various platforms 2111da177e4SLinus Torvalds where 0x26 is wrong; we refuse to change those. */ 2121da177e4SLinus Torvalds if (x != 0x26 && x != 0x25 && x != 0x19 && x != 0x06) { 213fddd87d6SRichard Henderson sel = RTC_REF_CLCK_32KHZ + 6; 214fddd87d6SRichard Henderson } 215fddd87d6SRichard Henderson #elif CONFIG_HZ == 256 || CONFIG_HZ == 128 || CONFIG_HZ == 64 || CONFIG_HZ == 32 216fddd87d6SRichard Henderson sel = RTC_REF_CLCK_32KHZ + __builtin_ffs(32768 / CONFIG_HZ); 217fddd87d6SRichard Henderson #else 218fddd87d6SRichard Henderson # error "Unknown HZ from arch/alpha/Kconfig" 219fddd87d6SRichard Henderson #endif 220fddd87d6SRichard Henderson if (sel) { 221fddd87d6SRichard Henderson printk(KERN_INFO "Setting RTC_FREQ to %d Hz (%x)\n", 222fddd87d6SRichard Henderson CONFIG_HZ, sel); 223fddd87d6SRichard Henderson CMOS_WRITE(sel, RTC_FREQ_SELECT); 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds /* Turn on periodic interrupts. */ 2271da177e4SLinus Torvalds x = CMOS_READ(RTC_CONTROL); 2281da177e4SLinus Torvalds if (!(x & RTC_PIE)) { 2291da177e4SLinus Torvalds printk("Turning on RTC interrupts.\n"); 2301da177e4SLinus Torvalds x |= RTC_PIE; 2311da177e4SLinus Torvalds x &= ~(RTC_AIE | RTC_UIE); 2321da177e4SLinus Torvalds CMOS_WRITE(x, RTC_CONTROL); 2331da177e4SLinus Torvalds } 2341da177e4SLinus Torvalds (void) CMOS_READ(RTC_INTR_FLAGS); 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds outb(0x36, 0x43); /* pit counter 0: system timer */ 2371da177e4SLinus Torvalds outb(0x00, 0x40); 2381da177e4SLinus Torvalds outb(0x00, 0x40); 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds outb(0xb6, 0x43); /* pit counter 2: speaker */ 2411da177e4SLinus Torvalds outb(0x31, 0x42); 2421da177e4SLinus Torvalds outb(0x13, 0x42); 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds init_rtc_irq(); 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds 247db2d3260SRichard Henderson 248db2d3260SRichard Henderson #ifndef CONFIG_ALPHA_WTINT 249db2d3260SRichard Henderson /* 250db2d3260SRichard Henderson * The RPCC as a clocksource primitive. 251db2d3260SRichard Henderson * 252db2d3260SRichard Henderson * While we have free-running timecounters running on all CPUs, and we make 253db2d3260SRichard Henderson * a half-hearted attempt in init_rtc_rpcc_info to sync the timecounter 254db2d3260SRichard Henderson * with the wall clock, that initialization isn't kept up-to-date across 255db2d3260SRichard Henderson * different time counters in SMP mode. Therefore we can only use this 256db2d3260SRichard Henderson * method when there's only one CPU enabled. 257db2d3260SRichard Henderson * 258db2d3260SRichard Henderson * When using the WTINT PALcall, the RPCC may shift to a lower frequency, 259db2d3260SRichard Henderson * or stop altogether, while waiting for the interrupt. Therefore we cannot 260db2d3260SRichard Henderson * use this method when WTINT is in use. 261db2d3260SRichard Henderson */ 262db2d3260SRichard Henderson 263a5a1d1c2SThomas Gleixner static u64 read_rpcc(struct clocksource *cs) 264db2d3260SRichard Henderson { 265db2d3260SRichard Henderson return rpcc(); 266db2d3260SRichard Henderson } 267db2d3260SRichard Henderson 268db2d3260SRichard Henderson static struct clocksource clocksource_rpcc = { 269db2d3260SRichard Henderson .name = "rpcc", 270db2d3260SRichard Henderson .rating = 300, 271db2d3260SRichard Henderson .read = read_rpcc, 272db2d3260SRichard Henderson .mask = CLOCKSOURCE_MASK(32), 273db2d3260SRichard Henderson .flags = CLOCK_SOURCE_IS_CONTINUOUS 274db2d3260SRichard Henderson }; 275db2d3260SRichard Henderson #endif /* ALPHA_WTINT */ 276db2d3260SRichard Henderson 277db2d3260SRichard Henderson 2781da177e4SLinus Torvalds /* Validate a computed cycle counter result against the known bounds for 2791da177e4SLinus Torvalds the given processor core. There's too much brokenness in the way of 2801da177e4SLinus Torvalds timing hardware for any one method to work everywhere. :-( 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds Return 0 if the result cannot be trusted, otherwise return the argument. */ 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds static unsigned long __init 2851da177e4SLinus Torvalds validate_cc_value(unsigned long cc) 2861da177e4SLinus Torvalds { 2871da177e4SLinus Torvalds static struct bounds { 2881da177e4SLinus Torvalds unsigned int min, max; 2891da177e4SLinus Torvalds } cpu_hz[] __initdata = { 2901da177e4SLinus Torvalds [EV3_CPU] = { 50000000, 200000000 }, /* guess */ 2911da177e4SLinus Torvalds [EV4_CPU] = { 100000000, 300000000 }, 2921da177e4SLinus Torvalds [LCA4_CPU] = { 100000000, 300000000 }, /* guess */ 2931da177e4SLinus Torvalds [EV45_CPU] = { 200000000, 300000000 }, 2941da177e4SLinus Torvalds [EV5_CPU] = { 250000000, 433000000 }, 2951da177e4SLinus Torvalds [EV56_CPU] = { 333000000, 667000000 }, 2961da177e4SLinus Torvalds [PCA56_CPU] = { 400000000, 600000000 }, /* guess */ 2971da177e4SLinus Torvalds [PCA57_CPU] = { 500000000, 600000000 }, /* guess */ 2981da177e4SLinus Torvalds [EV6_CPU] = { 466000000, 600000000 }, 2991da177e4SLinus Torvalds [EV67_CPU] = { 600000000, 750000000 }, 3001da177e4SLinus Torvalds [EV68AL_CPU] = { 750000000, 940000000 }, 3011da177e4SLinus Torvalds [EV68CB_CPU] = { 1000000000, 1333333333 }, 3021da177e4SLinus Torvalds /* None of the following are shipping as of 2001-11-01. */ 3031da177e4SLinus Torvalds [EV68CX_CPU] = { 1000000000, 1700000000 }, /* guess */ 3041da177e4SLinus Torvalds [EV69_CPU] = { 1000000000, 1700000000 }, /* guess */ 3051da177e4SLinus Torvalds [EV7_CPU] = { 800000000, 1400000000 }, /* guess */ 3061da177e4SLinus Torvalds [EV79_CPU] = { 1000000000, 2000000000 }, /* guess */ 3071da177e4SLinus Torvalds }; 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds /* Allow for some drift in the crystal. 10MHz is more than enough. */ 3101da177e4SLinus Torvalds const unsigned int deviation = 10000000; 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds struct percpu_struct *cpu; 3131da177e4SLinus Torvalds unsigned int index; 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds cpu = (struct percpu_struct *)((char*)hwrpb + hwrpb->processor_offset); 3161da177e4SLinus Torvalds index = cpu->type & 0xffffffff; 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds /* If index out of bounds, no way to validate. */ 31925c8716cSTobias Klauser if (index >= ARRAY_SIZE(cpu_hz)) 3201da177e4SLinus Torvalds return cc; 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds /* If index contains no data, no way to validate. */ 3231da177e4SLinus Torvalds if (cpu_hz[index].max == 0) 3241da177e4SLinus Torvalds return cc; 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds if (cc < cpu_hz[index].min - deviation 3271da177e4SLinus Torvalds || cc > cpu_hz[index].max + deviation) 3281da177e4SLinus Torvalds return 0; 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds return cc; 3311da177e4SLinus Torvalds } 3321da177e4SLinus Torvalds 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds /* 3351da177e4SLinus Torvalds * Calibrate CPU clock using legacy 8254 timer/counter. Stolen from 3361da177e4SLinus Torvalds * arch/i386/time.c. 3371da177e4SLinus Torvalds */ 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds #define CALIBRATE_LATCH 0xffff 3401da177e4SLinus Torvalds #define TIMEOUT_COUNT 0x100000 3411da177e4SLinus Torvalds 3421da177e4SLinus Torvalds static unsigned long __init 3431da177e4SLinus Torvalds calibrate_cc_with_pit(void) 3441da177e4SLinus Torvalds { 3451da177e4SLinus Torvalds int cc, count = 0; 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds /* Set the Gate high, disable speaker */ 3481da177e4SLinus Torvalds outb((inb(0x61) & ~0x02) | 0x01, 0x61); 3491da177e4SLinus Torvalds 3501da177e4SLinus Torvalds /* 3511da177e4SLinus Torvalds * Now let's take care of CTC channel 2 3521da177e4SLinus Torvalds * 3531da177e4SLinus Torvalds * Set the Gate high, program CTC channel 2 for mode 0, 3541da177e4SLinus Torvalds * (interrupt on terminal count mode), binary count, 3551da177e4SLinus Torvalds * load 5 * LATCH count, (LSB and MSB) to begin countdown. 3561da177e4SLinus Torvalds */ 3571da177e4SLinus Torvalds outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */ 3581da177e4SLinus Torvalds outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */ 3591da177e4SLinus Torvalds outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */ 3601da177e4SLinus Torvalds 3611da177e4SLinus Torvalds cc = rpcc(); 3621da177e4SLinus Torvalds do { 3631da177e4SLinus Torvalds count++; 3641da177e4SLinus Torvalds } while ((inb(0x61) & 0x20) == 0 && count < TIMEOUT_COUNT); 3651da177e4SLinus Torvalds cc = rpcc() - cc; 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds /* Error: ECTCNEVERSET or ECPUTOOFAST. */ 3681da177e4SLinus Torvalds if (count <= 1 || count == TIMEOUT_COUNT) 3691da177e4SLinus Torvalds return 0; 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds return ((long)cc * PIT_TICK_RATE) / (CALIBRATE_LATCH + 1); 3721da177e4SLinus Torvalds } 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds /* The Linux interpretation of the CMOS clock register contents: 3751da177e4SLinus Torvalds When the Update-In-Progress (UIP) flag goes from 1 to 0, the 3761da177e4SLinus Torvalds RTC registers show the second which has precisely just started. 3771da177e4SLinus Torvalds Let's hope other operating systems interpret the RTC the same way. */ 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds static unsigned long __init 3801da177e4SLinus Torvalds rpcc_after_update_in_progress(void) 3811da177e4SLinus Torvalds { 3821da177e4SLinus Torvalds do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)); 3831da177e4SLinus Torvalds do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds return rpcc(); 3861da177e4SLinus Torvalds } 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds void __init 3891da177e4SLinus Torvalds time_init(void) 3901da177e4SLinus Torvalds { 3911e871be1SJohn Stultz unsigned int cc1, cc2; 3921da177e4SLinus Torvalds unsigned long cycle_freq, tolerance; 3931da177e4SLinus Torvalds long diff; 3941da177e4SLinus Torvalds 3954914d7b4SRichard Henderson if (alpha_using_qemu) { 3964914d7b4SRichard Henderson clocksource_register_hz(&qemu_cs, NSEC_PER_SEC); 3974914d7b4SRichard Henderson init_qemu_clockevent(); 3984914d7b4SRichard Henderson 3994914d7b4SRichard Henderson timer_irqaction.handler = qemu_timer_interrupt; 4004914d7b4SRichard Henderson init_rtc_irq(); 4014914d7b4SRichard Henderson return; 4024914d7b4SRichard Henderson } 4034914d7b4SRichard Henderson 4041da177e4SLinus Torvalds /* Calibrate CPU clock -- attempt #1. */ 4051da177e4SLinus Torvalds if (!est_cycle_freq) 4061da177e4SLinus Torvalds est_cycle_freq = validate_cc_value(calibrate_cc_with_pit()); 4071da177e4SLinus Torvalds 4084c2e6f6aSMatt Mackall cc1 = rpcc(); 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds /* Calibrate CPU clock -- attempt #2. */ 4111da177e4SLinus Torvalds if (!est_cycle_freq) { 4124c2e6f6aSMatt Mackall cc1 = rpcc_after_update_in_progress(); 4131da177e4SLinus Torvalds cc2 = rpcc_after_update_in_progress(); 4141da177e4SLinus Torvalds est_cycle_freq = validate_cc_value(cc2 - cc1); 4151da177e4SLinus Torvalds cc1 = cc2; 4161da177e4SLinus Torvalds } 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds cycle_freq = hwrpb->cycle_freq; 4191da177e4SLinus Torvalds if (est_cycle_freq) { 4201da177e4SLinus Torvalds /* If the given value is within 250 PPM of what we calculated, 4211da177e4SLinus Torvalds accept it. Otherwise, use what we found. */ 4221da177e4SLinus Torvalds tolerance = cycle_freq / 4000; 4231da177e4SLinus Torvalds diff = cycle_freq - est_cycle_freq; 4241da177e4SLinus Torvalds if (diff < 0) 4251da177e4SLinus Torvalds diff = -diff; 4261da177e4SLinus Torvalds if ((unsigned long)diff > tolerance) { 4271da177e4SLinus Torvalds cycle_freq = est_cycle_freq; 4281da177e4SLinus Torvalds printk("HWRPB cycle frequency bogus. " 4291da177e4SLinus Torvalds "Estimated %lu Hz\n", cycle_freq); 4301da177e4SLinus Torvalds } else { 4311da177e4SLinus Torvalds est_cycle_freq = 0; 4321da177e4SLinus Torvalds } 4331da177e4SLinus Torvalds } else if (! validate_cc_value (cycle_freq)) { 4341da177e4SLinus Torvalds printk("HWRPB cycle frequency bogus, " 4351da177e4SLinus Torvalds "and unable to estimate a proper value!\n"); 4361da177e4SLinus Torvalds } 4371da177e4SLinus Torvalds 438db2d3260SRichard Henderson /* See above for restrictions on using clocksource_rpcc. */ 439db2d3260SRichard Henderson #ifndef CONFIG_ALPHA_WTINT 440db2d3260SRichard Henderson if (hwrpb->nr_processors == 1) 441db2d3260SRichard Henderson clocksource_register_hz(&clocksource_rpcc, cycle_freq); 442db2d3260SRichard Henderson #endif 443db2d3260SRichard Henderson 4441da177e4SLinus Torvalds /* Startup the timer source. */ 4451da177e4SLinus Torvalds alpha_mv.init_rtc(); 4464914d7b4SRichard Henderson init_rtc_clockevent(); 4471da177e4SLinus Torvalds } 4484914d7b4SRichard Henderson 4494914d7b4SRichard Henderson /* Initialize the clock_event_device for secondary cpus. */ 4504914d7b4SRichard Henderson #ifdef CONFIG_SMP 4514914d7b4SRichard Henderson void __init 4524914d7b4SRichard Henderson init_clockevent(void) 4534914d7b4SRichard Henderson { 4544914d7b4SRichard Henderson if (alpha_using_qemu) 4554914d7b4SRichard Henderson init_qemu_clockevent(); 4564914d7b4SRichard Henderson else 4574914d7b4SRichard Henderson init_rtc_clockevent(); 4584914d7b4SRichard Henderson } 4594914d7b4SRichard Henderson #endif 460