x86: tsc: Try hardware calibration first
At present if TSC frequency is provided in the device tree, it takes
precedence over hardware calibration result. This swaps the order to
try hardware calibration first and uses device tree as last resort.
This can be helpful when a generic dts (eg: coreboot/efi payload) is
supposed to work on as many hardware as possible, including emulators
like QEMU where TSC hardware calibration sometimes fails.
Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Christian Gmeiner <christian.gmeiner@gmail.com>
diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c
index 747f190..6473de2 100644
--- a/drivers/timer/tsc_timer.c
+++ b/drivers/timer/tsc_timer.c
@@ -341,16 +341,12 @@
return 0;
}
-static void tsc_timer_ensure_setup(void)
+static void tsc_timer_ensure_setup(bool stop)
{
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 (!gd->arch.clock_rate) {
unsigned long fast_calibrate;
@@ -366,7 +362,10 @@
if (fast_calibrate)
goto done;
- panic("TSC frequency is ZERO");
+ if (stop)
+ panic("TSC frequency is ZERO");
+ else
+ return;
done:
gd->arch.clock_rate = fast_calibrate * 1000000;
@@ -377,11 +376,17 @@
{
struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
- if (!uc_priv->clock_rate) {
- tsc_timer_ensure_setup();
- uc_priv->clock_rate = gd->arch.clock_rate;
+ /* 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 {
- gd->arch.tsc_base = rdtsc();
+ uc_priv->clock_rate = gd->arch.clock_rate;
}
return 0;
@@ -394,7 +399,7 @@
* clock rate can only be calibrated via some hardware ways. Specifying
* it in the device tree won't work for the early timer.
*/
- tsc_timer_ensure_setup();
+ tsc_timer_ensure_setup(true);
return gd->arch.clock_rate;
}