xref: /qemu/hw/core/clock.c (revision 15aa2876d9c7181c58305430f726461a2f24cb00)
14cba075eSPeter Maydell /*
24cba075eSPeter Maydell  * Hardware Clocks
34cba075eSPeter Maydell  *
44cba075eSPeter Maydell  * Copyright GreenSocs 2016-2020
54cba075eSPeter Maydell  *
64cba075eSPeter Maydell  * Authors:
74cba075eSPeter Maydell  *  Frederic Konrad
84cba075eSPeter Maydell  *  Damien Hedde
94cba075eSPeter Maydell  *
104cba075eSPeter Maydell  * This work is licensed under the terms of the GNU GPL, version 2 or later.
114cba075eSPeter Maydell  * See the COPYING file in the top-level directory.
124cba075eSPeter Maydell  */
134cba075eSPeter Maydell 
144cba075eSPeter Maydell #include "qemu/osdep.h"
154cba075eSPeter Maydell #include "hw/clock.h"
164cba075eSPeter Maydell #include "trace.h"
174cba075eSPeter Maydell 
184cba075eSPeter Maydell #define CLOCK_PATH(_clk) (_clk->canonical_path)
194cba075eSPeter Maydell 
204cba075eSPeter Maydell void clock_setup_canonical_path(Clock *clk)
214cba075eSPeter Maydell {
224cba075eSPeter Maydell     g_free(clk->canonical_path);
234cba075eSPeter Maydell     clk->canonical_path = object_get_canonical_path(OBJECT(clk));
244cba075eSPeter Maydell }
254cba075eSPeter Maydell 
264cba075eSPeter Maydell void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque)
274cba075eSPeter Maydell {
284cba075eSPeter Maydell     clk->callback = cb;
294cba075eSPeter Maydell     clk->callback_opaque = opaque;
304cba075eSPeter Maydell }
314cba075eSPeter Maydell 
324cba075eSPeter Maydell void clock_clear_callback(Clock *clk)
334cba075eSPeter Maydell {
344cba075eSPeter Maydell     clock_set_callback(clk, NULL, NULL);
354cba075eSPeter Maydell }
364cba075eSPeter Maydell 
37*15aa2876SPhilippe Mathieu-Daudé bool clock_set(Clock *clk, uint64_t period)
384cba075eSPeter Maydell {
39*15aa2876SPhilippe Mathieu-Daudé     if (clk->period == period) {
40*15aa2876SPhilippe Mathieu-Daudé         return false;
41*15aa2876SPhilippe Mathieu-Daudé     }
424cba075eSPeter Maydell     trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_NS(clk->period),
434cba075eSPeter Maydell                     CLOCK_PERIOD_TO_NS(period));
444cba075eSPeter Maydell     clk->period = period;
45*15aa2876SPhilippe Mathieu-Daudé 
46*15aa2876SPhilippe Mathieu-Daudé     return true;
474cba075eSPeter Maydell }
484cba075eSPeter Maydell 
494cba075eSPeter Maydell static void clock_propagate_period(Clock *clk, bool call_callbacks)
504cba075eSPeter Maydell {
514cba075eSPeter Maydell     Clock *child;
524cba075eSPeter Maydell 
534cba075eSPeter Maydell     QLIST_FOREACH(child, &clk->children, sibling) {
544cba075eSPeter Maydell         if (child->period != clk->period) {
554cba075eSPeter Maydell             child->period = clk->period;
564cba075eSPeter Maydell             trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk),
574cba075eSPeter Maydell                                CLOCK_PERIOD_TO_NS(clk->period),
584cba075eSPeter Maydell                                call_callbacks);
594cba075eSPeter Maydell             if (call_callbacks && child->callback) {
604cba075eSPeter Maydell                 child->callback(child->callback_opaque);
614cba075eSPeter Maydell             }
624cba075eSPeter Maydell             clock_propagate_period(child, call_callbacks);
634cba075eSPeter Maydell         }
644cba075eSPeter Maydell     }
654cba075eSPeter Maydell }
664cba075eSPeter Maydell 
674cba075eSPeter Maydell void clock_propagate(Clock *clk)
684cba075eSPeter Maydell {
694cba075eSPeter Maydell     assert(clk->source == NULL);
704cba075eSPeter Maydell     trace_clock_propagate(CLOCK_PATH(clk));
714cba075eSPeter Maydell     clock_propagate_period(clk, true);
724cba075eSPeter Maydell }
734cba075eSPeter Maydell 
744cba075eSPeter Maydell void clock_set_source(Clock *clk, Clock *src)
754cba075eSPeter Maydell {
764cba075eSPeter Maydell     /* changing clock source is not supported */
774cba075eSPeter Maydell     assert(!clk->source);
784cba075eSPeter Maydell 
794cba075eSPeter Maydell     trace_clock_set_source(CLOCK_PATH(clk), CLOCK_PATH(src));
804cba075eSPeter Maydell 
814cba075eSPeter Maydell     clk->period = src->period;
824cba075eSPeter Maydell     QLIST_INSERT_HEAD(&src->children, clk, sibling);
834cba075eSPeter Maydell     clk->source = src;
844cba075eSPeter Maydell     clock_propagate_period(clk, false);
854cba075eSPeter Maydell }
864cba075eSPeter Maydell 
874cba075eSPeter Maydell static void clock_disconnect(Clock *clk)
884cba075eSPeter Maydell {
894cba075eSPeter Maydell     if (clk->source == NULL) {
904cba075eSPeter Maydell         return;
914cba075eSPeter Maydell     }
924cba075eSPeter Maydell 
934cba075eSPeter Maydell     trace_clock_disconnect(CLOCK_PATH(clk));
944cba075eSPeter Maydell 
954cba075eSPeter Maydell     clk->source = NULL;
964cba075eSPeter Maydell     QLIST_REMOVE(clk, sibling);
974cba075eSPeter Maydell }
984cba075eSPeter Maydell 
994cba075eSPeter Maydell static void clock_initfn(Object *obj)
1004cba075eSPeter Maydell {
1014cba075eSPeter Maydell     Clock *clk = CLOCK(obj);
1024cba075eSPeter Maydell 
1034cba075eSPeter Maydell     QLIST_INIT(&clk->children);
1044cba075eSPeter Maydell }
1054cba075eSPeter Maydell 
1064cba075eSPeter Maydell static void clock_finalizefn(Object *obj)
1074cba075eSPeter Maydell {
1084cba075eSPeter Maydell     Clock *clk = CLOCK(obj);
1094cba075eSPeter Maydell     Clock *child, *next;
1104cba075eSPeter Maydell 
1114cba075eSPeter Maydell     /* clear our list of children */
1124cba075eSPeter Maydell     QLIST_FOREACH_SAFE(child, &clk->children, sibling, next) {
1134cba075eSPeter Maydell         clock_disconnect(child);
1144cba075eSPeter Maydell     }
1154cba075eSPeter Maydell 
1164cba075eSPeter Maydell     /* remove us from source's children list */
1174cba075eSPeter Maydell     clock_disconnect(clk);
1184cba075eSPeter Maydell 
1194cba075eSPeter Maydell     g_free(clk->canonical_path);
1204cba075eSPeter Maydell }
1214cba075eSPeter Maydell 
1224cba075eSPeter Maydell static const TypeInfo clock_info = {
1234cba075eSPeter Maydell     .name              = TYPE_CLOCK,
1244cba075eSPeter Maydell     .parent            = TYPE_OBJECT,
1254cba075eSPeter Maydell     .instance_size     = sizeof(Clock),
1264cba075eSPeter Maydell     .instance_init     = clock_initfn,
1274cba075eSPeter Maydell     .instance_finalize = clock_finalizefn,
1284cba075eSPeter Maydell };
1294cba075eSPeter Maydell 
1304cba075eSPeter Maydell static void clock_register_types(void)
1314cba075eSPeter Maydell {
1324cba075eSPeter Maydell     type_register_static(&clock_info);
1334cba075eSPeter Maydell }
1344cba075eSPeter Maydell 
1354cba075eSPeter Maydell type_init(clock_register_types)
136