s */ [EV79_CPU] = { 1000000000, 2000000000 }, /* guess */ }; /* Allow for some drift in the crystal. 10MHz is more than enough. */ const unsigned int deviation = 10000000; struct percpu_struct *cpu; unsigned int index; cpu = (struct percpu_struct *)((char*)hwrpb + hwrpb->processor_offset); index = cpu->type & 0xffffffff; /* If index out of bounds, no way to validate. */ if (index >= ARRAY_SIZE(cpu_hz)) return cc; /* If index contains no data, no way to validate. */ if (cpu_hz[index].max == 0) return cc; if (cc < cpu_hz[index].min - deviation || cc > cpu_hz[index].max + deviation) return 0; return cc; } /* * Calibrate CPU clock using legacy 8254 timer/counter. Stolen from * arch/i386/time.c. */ #define CALIBRATE_LATCH 0xffff #define TIMEOUT_COUNT 0x100000 static unsigned long __init calibrate_cc_with_pit(void) { int cc, count = 0; /* Set the Gate high, disable speaker */ outb((inb(0x61) & ~0x02) | 0x01, 0x61); /* * Now let's take care of CTC channel 2 * * Set the Gate high, program CTC channel 2 for mode 0, * (interrupt on terminal count mode), binary count, * load 5 * LATCH count, (LSB and MSB) to begin countdown. */ outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */ outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */ outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */ cc = rpcc(); do { count++; } while ((inb(0x61) & 0x20) == 0 && count < TIMEOUT_COUNT); cc = rpcc() - cc; /* Error: ECTCNEVERSET or ECPUTOOFAST. */ if (count <= 1 || count == TIMEOUT_COUNT) return 0; return ((long)cc * PIT_TICK_RATE) / (CALIBRATE_LATCH + 1); } /* The Linux interpretation of the CMOS clock register contents: When the Update-In-Progress (UIP) flag goes from 1 to 0, the RTC registers show the second which has precisely just started. Let's hope other operating systems interpret the RTC the same way. */ static unsigned long __init rpcc_after_update_in_progress(void) { do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)); do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); return rpcc(); } void __init time_init(void) { unsigned int cc1, cc2; unsigned long cycle_freq, tolerance; long diff; if (alpha_using_qemu) { clocksource_register_hz(&qemu_cs, NSEC_PER_SEC); init_qemu_clockevent(); init_rtc_irq(qemu_timer_interrupt); return; } /* Calibrate CPU clock -- attempt #1. */ if (!est_cycle_freq) est_cycle_freq = validate_cc_value(calibrate_cc_with_pit()); cc1 = rpcc(); /* Calibrate CPU clock -- attempt #2. */ if (!est_cycle_freq) { cc1 = rpcc_after_update_in_progress(); cc2 = rpcc_after_update_in_progress(); est_cycle_freq = validate_cc_value(cc2 - cc1); cc1 = cc2; } cycle_freq = hwrpb->cycle_freq; if (est_cycle_freq) { /* If the given value is within 250 PPM of what we calculated, accept it. Otherwise, use what we found. */ tolerance = cycle_freq / 4000; diff = cycle_freq - est_cycle_freq; if (diff < 0) diff = -diff; if ((unsigned long)diff > tolerance) { cycle_freq = est_cycle_freq; printk("HWRPB cycle frequency bogus. " "Estimated %lu Hz\n", cycle_freq); } else { est_cycle_freq = 0; } } else if (! validate_cc_value (cycle_freq)) { printk("HWRPB cycle frequency bogus, " "and unable to estimate a proper value!\n"); } /* See above for restrictions on using clocksource_rpcc. */ #ifndef CONFIG_ALPHA_WTINT if (hwrpb->nr_processors == 1) clocksource_register_hz(&clocksource_rpcc, cycle_freq); #endif /* Startup the timer source. */ alpha_mv.init_rtc(); init_rtc_clockevent(); } /* Initialize the clock_event_device for secondary cpus. */ #ifdef CONFIG_SMP void __init init_clockevent(void) { if (alpha_using_qemu) init_qemu_clockevent(); else init_rtc_clockevent(); } #endif