summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2021-01-28 11:41:21 +0000
committerPeter Maydell <peter.maydell@linaro.org>2021-01-29 15:54:42 +0000
commitad140dadd591cdfd47959a7b4538e8133053b3c7 (patch)
tree49668bb984275142dfd07f2c9b5112ac6ea0a63f /hw
parentc0f82826a1cc52a2a038b12ccaa1c92bb7e2d4c0 (diff)
ptimer: Add new ptimer_set_period_from_clock() function
The ptimer API currently provides two methods for setting the period: ptimer_set_period(), which takes a period in nanoseconds, and ptimer_set_freq(), which takes a frequency in Hz. Neither of these lines up nicely with the Clock API, because although both the Clock and the ptimer track the frequency using a representation of whole and fractional nanoseconds, conversion via either period-in-ns or frequency-in-Hz will introduce a rounding error. Add a new function ptimer_set_period_from_clock() which takes the Clock object directly to avoid the rounding issues. This includes a facility for the user to specify that there is a frequency divider between the Clock proper and the timer, as some timer devices like the CMSDK APB dualtimer need this. To avoid having to drag in clock.h from ptimer.h we add the Clock type to typedefs.h. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Luc Michel <luc@lmichel.fr> Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Message-id: 20210128114145.20536-2-peter.maydell@linaro.org Message-id: 20210121190622.22000-2-peter.maydell@linaro.org
Diffstat (limited to 'hw')
-rw-r--r--hw/core/ptimer.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c
index 2aa97cb665..6ba19fd965 100644
--- a/hw/core/ptimer.c
+++ b/hw/core/ptimer.c
@@ -15,6 +15,7 @@
#include "sysemu/qtest.h"
#include "block/aio.h"
#include "sysemu/cpus.h"
+#include "hw/clock.h"
#define DELTA_ADJUST 1
#define DELTA_NO_ADJUST -1
@@ -348,6 +349,39 @@ void ptimer_set_period(ptimer_state *s, int64_t period)
}
}
+/* Set counter increment interval from a Clock */
+void ptimer_set_period_from_clock(ptimer_state *s, const Clock *clk,
+ unsigned int divisor)
+{
+ /*
+ * The raw clock period is a 64-bit value in units of 2^-32 ns;
+ * put another way it's a 32.32 fixed-point ns value. Our internal
+ * representation of the period is 64.32 fixed point ns, so
+ * the conversion is simple.
+ */
+ uint64_t raw_period = clock_get(clk);
+ uint64_t period_frac;
+
+ assert(s->in_transaction);
+ s->delta = ptimer_get_count(s);
+ s->period = extract64(raw_period, 32, 32);
+ period_frac = extract64(raw_period, 0, 32);
+ /*
+ * divisor specifies a possible frequency divisor between the
+ * clock and the timer, so it is a multiplier on the period.
+ * We do the multiply after splitting the raw period out into
+ * period and frac to avoid having to do a 32*64->96 multiply.
+ */
+ s->period *= divisor;
+ period_frac *= divisor;
+ s->period += extract64(period_frac, 32, 32);
+ s->period_frac = (uint32_t)period_frac;
+
+ if (s->enabled) {
+ s->need_reload = true;
+ }
+}
+
/* Set counter frequency in Hz. */
void ptimer_set_freq(ptimer_state *s, uint32_t freq)
{