X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Ftimer%2Ftsc_timer.c;h=9296de65432dce7c13d01d8189d284d47b84d682;hb=e8d5291824e27575fe71222f683579325221e0cb;hp=5c4ec0018f6860a622d409a6aefd559e2a9496c2;hpb=4932443d260d23c882e48eefcc66a83dfca7ee5a;p=u-boot diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c index 5c4ec0018f..9296de6543 100644 --- a/drivers/timer/tsc_timer.c +++ b/drivers/timer/tsc_timer.c @@ -11,19 +11,14 @@ #include #include #include +#include #include #include #include #include #include -/* CPU reference clock frequency: in KHz */ -#define FREQ_83 83200 -#define FREQ_100 99840 -#define FREQ_133 133200 -#define FREQ_166 166400 - -#define MAX_NUM_FREQS 8 +#define MAX_NUM_FREQS 9 DECLARE_GLOBAL_DATA_PTR; @@ -45,17 +40,20 @@ struct freq_desc { static struct freq_desc freq_desc_tables[] = { /* PNW */ - { 6, 0x27, 0, { 0, 0, 0, 0, 0, FREQ_100, 0, FREQ_83 } }, + { 6, 0x27, 0, { 0, 0, 0, 0, 0, 99840, 0, 83200, 0 } }, /* CLV+ */ - { 6, 0x35, 0, { 0, FREQ_133, 0, 0, 0, FREQ_100, 0, FREQ_83 } }, - /* TNG */ - { 6, 0x4a, 1, { 0, FREQ_100, FREQ_133, 0, 0, 0, 0, 0 } }, - /* VLV2 */ - { 6, 0x37, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_166, 0, 0, 0, 0 } }, + { 6, 0x35, 0, { 0, 133200, 0, 0, 0, 99840, 0, 83200, 0 } }, + /* TNG - Intel Atom processor Z3400 series */ + { 6, 0x4a, 1, { 0, 100000, 133300, 0, 0, 0, 0, 0, 0 } }, + /* VLV2 - Intel Atom processor E3000, Z3600, Z3700 series */ + { 6, 0x37, 1, { 83300, 100000, 133300, 116700, 80000, 0, 0, 0, 0 } }, + /* ANN - Intel Atom processor Z3500 series */ + { 6, 0x5a, 1, { 83300, 100000, 133300, 100000, 0, 0, 0, 0, 0 } }, + /* AMT - Intel Atom processor X7-Z8000 and X5-Z8000 series */ + { 6, 0x4c, 1, { 83300, 100000, 133300, 116700, + 80000, 93300, 90000, 88900, 87500 } }, /* Ivybridge */ - { 6, 0x3a, 2, { 0, 0, 0, 0, 0, 0, 0, 0 } }, - /* ANN */ - { 6, 0x5a, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_100, 0, 0, 0, 0 } }, + { 6, 0x3a, 2, { 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, }; static int match_cpu(u8 family, u8 model) @@ -76,35 +74,40 @@ static int match_cpu(u8 family, u8 model) (freq_desc_tables[cpu_index].freqs[freq_id]) /* - * Do MSR calibration only for known/supported CPUs. + * TSC on Intel Atom SoCs capable of determining TSC frequency by MSR is + * reliable and the frequency is known (provided by HW). + * + * On these platforms PIT/HPET is generally not available so calibration won't + * work at all and there is no other clocksource to act as a watchdog for the + * TSC, so we have no other choice than to trust it. * - * Returns the calibration value or 0 if MSR calibration failed. + * Returns the TSC frequency in MHz or 0 if HW does not provide it. */ -static unsigned long __maybe_unused try_msr_calibrate_tsc(void) +static unsigned long __maybe_unused cpu_mhz_from_msr(void) { u32 lo, hi, ratio, freq_id, freq; unsigned long res; int cpu_index; + if (gd->arch.x86_vendor != X86_VENDOR_INTEL) + return 0; + cpu_index = match_cpu(gd->arch.x86, gd->arch.x86_model); if (cpu_index < 0) return 0; if (freq_desc_tables[cpu_index].msr_plat) { rdmsr(MSR_PLATFORM_INFO, lo, hi); - ratio = (lo >> 8) & 0x1f; + ratio = (lo >> 8) & 0xff; } else { rdmsr(MSR_IA32_PERF_STATUS, lo, hi); ratio = (hi >> 8) & 0x1f; } debug("Maximum core-clock to bus-clock ratio: 0x%x\n", ratio); - if (!ratio) - goto fail; - if (freq_desc_tables[cpu_index].msr_plat == 2) { /* TODO: Figure out how best to deal with this */ - freq = FREQ_100; + freq = 100000; debug("Using frequency: %u KHz\n", freq); } else { /* Get FSB FREQ ID */ @@ -114,18 +117,12 @@ static unsigned long __maybe_unused try_msr_calibrate_tsc(void) debug("Resolved frequency ID: %u, frequency: %u KHz\n", freq_id, freq); } - if (!freq) - goto fail; /* TSC frequency = maximum resolved freq * maximum resolved bus ratio */ res = freq * ratio / 1000; debug("TSC runs at %lu MHz\n", res); return res; - -fail: - debug("Fast TSC calibration using MSR failed\n"); - return 0; } /* @@ -334,32 +331,52 @@ static int tsc_timer_get_count(struct udevice *dev, u64 *count) return 0; } -static int tsc_timer_probe(struct udevice *dev) +static void tsc_timer_ensure_setup(void) { - struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); - + if (gd->arch.tsc_base) + return; gd->arch.tsc_base = rdtsc(); /* * If there is no clock frequency specified in the device tree, * calibrate it by ourselves. */ - if (!uc_priv->clock_rate) { + if (!gd->arch.clock_rate) { unsigned long fast_calibrate; - fast_calibrate = try_msr_calibrate_tsc(); + fast_calibrate = cpu_mhz_from_msr(); if (!fast_calibrate) { fast_calibrate = quick_pit_calibrate(); if (!fast_calibrate) panic("TSC frequency is ZERO"); } - uc_priv->clock_rate = fast_calibrate * 1000000; + gd->arch.clock_rate = fast_calibrate * 1000000; } +} + +static int tsc_timer_probe(struct udevice *dev) +{ + struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + tsc_timer_ensure_setup(); + uc_priv->clock_rate = gd->arch.clock_rate; return 0; } +unsigned long notrace timer_early_get_rate(void) +{ + tsc_timer_ensure_setup(); + + return gd->arch.clock_rate; +} + +u64 notrace timer_early_get_count(void) +{ + return rdtsc() - gd->arch.tsc_base; +} + static const struct timer_ops tsc_timer_ops = { .get_count = tsc_timer_get_count, };