X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=drivers%2Ftimer%2Ftsc_timer.c;h=7d19a99622b554c0f59ff026726066f81ca1014c;hb=401d1c4f5d2d29c4bc4beaec95402ca23eb63295;hp=4d1fc9cd13707c8a1caa5d2a3be96d5969c23ce6;hpb=470135be276b2d92c6da464c68839202d4ff0d08;p=platform%2Fkernel%2Fu-boot.git diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c index 4d1fc9c..7d19a99 100644 --- a/drivers/timer/tsc_timer.c +++ b/drivers/timer/tsc_timer.c @@ -1,28 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2012 The Chromium OS Authors. * * TSC calibration codes are adapted from Linux kernel * arch/x86/kernel/tsc_msr.c and arch/x86/kernel/tsc.c - * - * SPDX-License-Identifier: GPL-2.0+ */ #include +#include #include +#include #include +#include #include #include +#include #include #include #include #include #include +#include + +#define MAX_NUM_FREQS 9 -#define MAX_NUM_FREQS 8 +#define INTEL_FAM6_SKYLAKE_MOBILE 0x4E +#define INTEL_FAM6_ATOM_GOLDMONT 0x5C /* Apollo Lake */ +#define INTEL_FAM6_SKYLAKE_DESKTOP 0x5E +#define INTEL_FAM6_ATOM_GOLDMONT_X 0x5F /* Denverton */ +#define INTEL_FAM6_KABYLAKE_MOBILE 0x8E +#define INTEL_FAM6_KABYLAKE_DESKTOP 0x9E DECLARE_GLOBAL_DATA_PTR; /* + * native_calibrate_tsc + * Determine TSC frequency via CPUID, else return 0. + */ +static unsigned long native_calibrate_tsc(void) +{ + struct cpuid_result tsc_info; + unsigned int crystal_freq; + + if (gd->arch.x86_vendor != X86_VENDOR_INTEL) + return 0; + + if (cpuid_eax(0) < 0x15) + return 0; + + tsc_info = cpuid(0x15); + + if (tsc_info.ebx == 0 || tsc_info.eax == 0) + return 0; + + crystal_freq = tsc_info.ecx / 1000; + if (!CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE) && !crystal_freq) { + switch (gd->arch.x86_model) { + case INTEL_FAM6_SKYLAKE_MOBILE: + case INTEL_FAM6_SKYLAKE_DESKTOP: + case INTEL_FAM6_KABYLAKE_MOBILE: + case INTEL_FAM6_KABYLAKE_DESKTOP: + crystal_freq = 24000; /* 24.0 MHz */ + break; + case INTEL_FAM6_ATOM_GOLDMONT_X: + crystal_freq = 25000; /* 25.0 MHz */ + break; + case INTEL_FAM6_ATOM_GOLDMONT: + crystal_freq = 19200; /* 19.2 MHz */ + break; + default: + return 0; + } + } + + return (crystal_freq * tsc_info.ebx / tsc_info.eax) / 1000; +} + +static unsigned long cpu_mhz_from_cpuid(void) +{ + if (gd->arch.x86_vendor != X86_VENDOR_INTEL) + return 0; + + if (cpuid_eax(0) < 0x16) + return 0; + + return cpuid_eax(0x16); +} + +/* * According to Intel 64 and IA-32 System Programming Guide, * if MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be * read in MSR_PLATFORM_ID[12:8], otherwise in MSR_PERF_STAT[44:40]. @@ -40,17 +105,20 @@ struct freq_desc { static struct freq_desc freq_desc_tables[] = { /* PNW */ - { 6, 0x27, 0, { 0, 0, 0, 0, 0, 99840, 0, 83200 } }, + { 6, 0x27, 0, { 0, 0, 0, 0, 0, 99840, 0, 83200, 0 } }, /* CLV+ */ - { 6, 0x35, 0, { 0, 133200, 0, 0, 0, 99840, 0, 83200 } }, + { 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 } }, + { 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 } }, + { 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 } }, + { 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 } }, + { 6, 0x3a, 2, { 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, }; static int match_cpu(u8 family, u8 model) @@ -305,7 +373,7 @@ void __udelay(unsigned long usec) u64 now = get_ticks(); u64 stop; - stop = now + usec * get_tbclk_mhz(); + stop = now + (u64)usec * get_tbclk_mhz(); while ((int64_t)(stop - get_ticks()) > 0) #if defined(CONFIG_QEMU) && defined(CONFIG_SMP) @@ -319,55 +387,108 @@ void __udelay(unsigned long usec) #endif } -static int tsc_timer_get_count(struct udevice *dev, u64 *count) +static u64 tsc_timer_get_count(struct udevice *dev) { u64 now_tick = rdtsc(); - *count = now_tick - gd->arch.tsc_base; + return now_tick - gd->arch.tsc_base; +} - return 0; +static void tsc_timer_ensure_setup(bool early) +{ + if (gd->arch.tsc_inited) + return; + if (IS_ENABLED(CONFIG_X86_TSC_READ_BASE)) + gd->arch.tsc_base = rdtsc(); + + if (!gd->arch.clock_rate) { + unsigned long fast_calibrate; + + fast_calibrate = native_calibrate_tsc(); + if (fast_calibrate) + goto done; + + /* Reduce code size by dropping other methods */ + if (CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE)) + panic("no timer"); + + fast_calibrate = cpu_mhz_from_cpuid(); + if (fast_calibrate) + goto done; + + fast_calibrate = cpu_mhz_from_msr(); + if (fast_calibrate) + goto done; + + fast_calibrate = quick_pit_calibrate(); + if (fast_calibrate) + goto done; + + if (early) + fast_calibrate = CONFIG_X86_TSC_TIMER_EARLY_FREQ; + else + return; + +done: + gd->arch.clock_rate = fast_calibrate * 1000000; + } + gd->arch.tsc_inited = true; } static int tsc_timer_probe(struct udevice *dev) { struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); - gd->arch.tsc_base = rdtsc(); + /* Try hardware calibration first */ + tsc_timer_ensure_setup(false); + if (!gd->arch.clock_rate) { + /* + * Use the clock frequency specified in the + * device tree as last resort + */ + if (!uc_priv->clock_rate) + panic("TSC frequency is ZERO"); + } else { + uc_priv->clock_rate = gd->arch.clock_rate; + } + + return 0; +} +unsigned long notrace timer_early_get_rate(void) +{ /* - * If there is no clock frequency specified in the device tree, - * calibrate it by ourselves. + * When TSC timer is used as the early timer, be warned that the timer + * clock rate can only be calibrated via some hardware ways. Specifying + * it in the device tree won't work for the early timer. */ - if (!uc_priv->clock_rate) { - unsigned long fast_calibrate; + tsc_timer_ensure_setup(true); - fast_calibrate = cpu_mhz_from_msr(); - if (!fast_calibrate) { - fast_calibrate = quick_pit_calibrate(); - if (!fast_calibrate) - panic("TSC frequency is ZERO"); - } + return gd->arch.clock_rate; +} - uc_priv->clock_rate = fast_calibrate * 1000000; - } +u64 notrace timer_early_get_count(void) +{ + tsc_timer_ensure_setup(true); - return 0; + return rdtsc() - gd->arch.tsc_base; } static const struct timer_ops tsc_timer_ops = { .get_count = tsc_timer_get_count, }; +#if !CONFIG_IS_ENABLED(OF_PLATDATA) static const struct udevice_id tsc_timer_ids[] = { { .compatible = "x86,tsc-timer", }, { } }; +#endif -U_BOOT_DRIVER(tsc_timer) = { - .name = "tsc_timer", +U_BOOT_DRIVER(x86_tsc_timer) = { + .name = "x86_tsc_timer", .id = UCLASS_TIMER, - .of_match = tsc_timer_ids, + .of_match = of_match_ptr(tsc_timer_ids), .probe = tsc_timer_probe, .ops = &tsc_timer_ops, - .flags = DM_FLAG_PRE_RELOC, };