@@ -59,10 +59,11 @@ static inline bool excp_is_internal(int excp)
|| excp == EXCP_SEMIHOST;
}
-/* Scale factor for generic timers, ie number of ns per tick.
- * This gives a 62.5MHz timer.
+/*
+ * Default frequency for the generic timer, in Hz.
+ * This is 62.5MHz, which gives a 16 ns tick period.
*/
-#define GTIMER_SCALE 16
+#define GTIMER_DEFAULT_HZ 62500000
/* Bit definitions for the v7M CONTROL register */
FIELD(V7M_CONTROL, NPRIV, 0, 1)
@@ -1506,9 +1506,12 @@ static void arm_cpu_initfn(Object *obj)
}
}
+/*
+ * 0 means "unset, use the default value". That default might vary depending
+ * on the CPU type, and is set in the realize fn.
+ */
static Property arm_cpu_gt_cntfrq_property =
- DEFINE_PROP_UINT64("cntfrq", ARMCPU, gt_cntfrq_hz,
- NANOSECONDS_PER_SECOND / GTIMER_SCALE);
+ DEFINE_PROP_UINT64("cntfrq", ARMCPU, gt_cntfrq_hz, 0);
static Property arm_cpu_reset_cbar_property =
DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0);
@@ -1954,6 +1957,17 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
return;
}
+ if (!cpu->gt_cntfrq_hz) {
+ /*
+ * 0 means "the board didn't set a value, use the default".
+ * The default value of the generic timer frequency (as seen in
+ * CNTFRQ_EL0) is 62.5MHz, which corresponds to a period of 16ns.
+ * This is what you get (a) for a CONFIG_USER_ONLY CPU (b) if the
+ * board doesn't set it.
+ */
+ cpu->gt_cntfrq_hz = GTIMER_DEFAULT_HZ;
+ }
+
#ifndef CONFIG_USER_ONLY
/* The NVIC and M-profile CPU are two halves of a single piece of
* hardware; trying to use one without the other is a command line
@@ -2002,18 +2016,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
}
{
- uint64_t scale;
-
- if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) {
- if (!cpu->gt_cntfrq_hz) {
- error_setg(errp, "Invalid CNTFRQ: %"PRId64"Hz",
- cpu->gt_cntfrq_hz);
- return;
- }
- scale = gt_cntfrq_period_ns(cpu);
- } else {
- scale = GTIMER_SCALE;
- }
+ uint64_t scale = gt_cntfrq_period_ns(cpu);
cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
arm_gt_ptimer_cb, cpu);
@@ -2474,6 +2474,13 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = {
.resetvalue = 0 },
};
+static void arm_gt_cntfrq_reset(CPUARMState *env, const ARMCPRegInfo *opaque)
+{
+ ARMCPU *cpu = env_archcpu(env);
+
+ cpu->env.cp15.c14_cntfrq = cpu->gt_cntfrq_hz;
+}
+
#ifndef CONFIG_USER_ONLY
static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -3228,13 +3235,6 @@ void arm_gt_hvtimer_cb(void *opaque)
gt_recalc_timer(cpu, GTIMER_HYPVIRT);
}
-static void arm_gt_cntfrq_reset(CPUARMState *env, const ARMCPRegInfo *opaque)
-{
- ARMCPU *cpu = env_archcpu(env);
-
- cpu->env.cp15.c14_cntfrq = cpu->gt_cntfrq_hz;
-}
-
static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
/*
* Note that CNTFRQ is purely reads-as-written for the benefit
@@ -3514,7 +3514,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 0,
.type = ARM_CP_CONST, .access = PL0_R /* no PL1_RW in linux-user */,
.fieldoffset = offsetof(CPUARMState, cp15.c14_cntfrq),
- .resetvalue = NANOSECONDS_PER_SECOND / GTIMER_SCALE,
+ .resetfn = arm_gt_cntfrq_reset,
},
{ .name = "CNTVCT_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 2,