aboutsummaryrefslogtreecommitdiff
path: root/hw/core/clock.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2020-04-17 16:54:28 +0100
committerPeter Maydell <peter.maydell@linaro.org>2020-04-30 11:52:28 +0100
commit4cba075efedde66f0a8658001da7fc09a09024e1 (patch)
tree2ab5240b37dbddf56b0ef0aa18308d8b88d941ad /hw/core/clock.c
parent70d7857f935ab3fd6a5c0ff8b7586d0aef20f8b0 (diff)
hw/core/clock: introduce clock object
This object may be used to represent a clock inside a clock tree. A clock may be connected to another clock so that it receives update, through a callback, whenever the source/parent clock is updated. Although only the root clock of a clock tree controls the values (represented as periods) of all clocks in tree, each clock holds a local state containing the current value so that it can be fetched independently. It will allows us to fullfill migration requirements by migrating each clock independently of others. This is based on the original work of Frederic Konrad. Signed-off-by: Damien Hedde <damien.hedde@greensocs.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> Message-id: 20200406135251.157596-2-damien.hedde@greensocs.com [PMM: Use uint64_t rather than unsigned long long in trace events; the dtrace backend can't handle the latter] Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/core/clock.c')
-rw-r--r--hw/core/clock.c130
1 files changed, 130 insertions, 0 deletions
diff --git a/hw/core/clock.c b/hw/core/clock.c
new file mode 100644
index 0000000000..3c0daf7d4c
--- /dev/null
+++ b/hw/core/clock.c
@@ -0,0 +1,130 @@
+/*
+ * Hardware Clocks
+ *
+ * Copyright GreenSocs 2016-2020
+ *
+ * Authors:
+ * Frederic Konrad
+ * Damien Hedde
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/clock.h"
+#include "trace.h"
+
+#define CLOCK_PATH(_clk) (_clk->canonical_path)
+
+void clock_setup_canonical_path(Clock *clk)
+{
+ g_free(clk->canonical_path);
+ clk->canonical_path = object_get_canonical_path(OBJECT(clk));
+}
+
+void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque)
+{
+ clk->callback = cb;
+ clk->callback_opaque = opaque;
+}
+
+void clock_clear_callback(Clock *clk)
+{
+ clock_set_callback(clk, NULL, NULL);
+}
+
+void clock_set(Clock *clk, uint64_t period)
+{
+ trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_NS(clk->period),
+ CLOCK_PERIOD_TO_NS(period));
+ clk->period = period;
+}
+
+static void clock_propagate_period(Clock *clk, bool call_callbacks)
+{
+ Clock *child;
+
+ QLIST_FOREACH(child, &clk->children, sibling) {
+ if (child->period != clk->period) {
+ child->period = clk->period;
+ trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk),
+ CLOCK_PERIOD_TO_NS(clk->period),
+ call_callbacks);
+ if (call_callbacks && child->callback) {
+ child->callback(child->callback_opaque);
+ }
+ clock_propagate_period(child, call_callbacks);
+ }
+ }
+}
+
+void clock_propagate(Clock *clk)
+{
+ assert(clk->source == NULL);
+ trace_clock_propagate(CLOCK_PATH(clk));
+ clock_propagate_period(clk, true);
+}
+
+void clock_set_source(Clock *clk, Clock *src)
+{
+ /* changing clock source is not supported */
+ assert(!clk->source);
+
+ trace_clock_set_source(CLOCK_PATH(clk), CLOCK_PATH(src));
+
+ clk->period = src->period;
+ QLIST_INSERT_HEAD(&src->children, clk, sibling);
+ clk->source = src;
+ clock_propagate_period(clk, false);
+}
+
+static void clock_disconnect(Clock *clk)
+{
+ if (clk->source == NULL) {
+ return;
+ }
+
+ trace_clock_disconnect(CLOCK_PATH(clk));
+
+ clk->source = NULL;
+ QLIST_REMOVE(clk, sibling);
+}
+
+static void clock_initfn(Object *obj)
+{
+ Clock *clk = CLOCK(obj);
+
+ QLIST_INIT(&clk->children);
+}
+
+static void clock_finalizefn(Object *obj)
+{
+ Clock *clk = CLOCK(obj);
+ Clock *child, *next;
+
+ /* clear our list of children */
+ QLIST_FOREACH_SAFE(child, &clk->children, sibling, next) {
+ clock_disconnect(child);
+ }
+
+ /* remove us from source's children list */
+ clock_disconnect(clk);
+
+ g_free(clk->canonical_path);
+}
+
+static const TypeInfo clock_info = {
+ .name = TYPE_CLOCK,
+ .parent = TYPE_OBJECT,
+ .instance_size = sizeof(Clock),
+ .instance_init = clock_initfn,
+ .instance_finalize = clock_finalizefn,
+};
+
+static void clock_register_types(void)
+{
+ type_register_static(&clock_info);
+}
+
+type_init(clock_register_types)