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"
15b7cd9c1eSPeter Maydell #include "qemu/cutils.h"
16*9240d65eSInès Varhol #include "qapi/visitor.h"
17*9240d65eSInès Varhol #include "sysemu/qtest.h"
184cba075eSPeter Maydell #include "hw/clock.h"
194cba075eSPeter Maydell #include "trace.h"
204cba075eSPeter Maydell
214cba075eSPeter Maydell #define CLOCK_PATH(_clk) (_clk->canonical_path)
224cba075eSPeter Maydell
clock_setup_canonical_path(Clock * clk)234cba075eSPeter Maydell void clock_setup_canonical_path(Clock *clk)
244cba075eSPeter Maydell {
254cba075eSPeter Maydell g_free(clk->canonical_path);
264cba075eSPeter Maydell clk->canonical_path = object_get_canonical_path(OBJECT(clk));
274cba075eSPeter Maydell }
284cba075eSPeter Maydell
clock_new(Object * parent,const char * name)295ebc6648SLuc Michel Clock *clock_new(Object *parent, const char *name)
305ebc6648SLuc Michel {
315ebc6648SLuc Michel Object *obj;
325ebc6648SLuc Michel Clock *clk;
335ebc6648SLuc Michel
345ebc6648SLuc Michel obj = object_new(TYPE_CLOCK);
355ebc6648SLuc Michel object_property_add_child(parent, name, obj);
365ebc6648SLuc Michel object_unref(obj);
375ebc6648SLuc Michel
385ebc6648SLuc Michel clk = CLOCK(obj);
395ebc6648SLuc Michel clock_setup_canonical_path(clk);
405ebc6648SLuc Michel
415ebc6648SLuc Michel return clk;
425ebc6648SLuc Michel }
435ebc6648SLuc Michel
clock_set_callback(Clock * clk,ClockCallback * cb,void * opaque,unsigned int events)445ee0abedSPeter Maydell void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque,
455ee0abedSPeter Maydell unsigned int events)
464cba075eSPeter Maydell {
474cba075eSPeter Maydell clk->callback = cb;
484cba075eSPeter Maydell clk->callback_opaque = opaque;
495ee0abedSPeter Maydell clk->callback_events = events;
504cba075eSPeter Maydell }
514cba075eSPeter Maydell
clock_clear_callback(Clock * clk)524cba075eSPeter Maydell void clock_clear_callback(Clock *clk)
534cba075eSPeter Maydell {
545ee0abedSPeter Maydell clock_set_callback(clk, NULL, NULL, 0);
554cba075eSPeter Maydell }
564cba075eSPeter Maydell
clock_set(Clock * clk,uint64_t period)5715aa2876SPhilippe Mathieu-Daudé bool clock_set(Clock *clk, uint64_t period)
584cba075eSPeter Maydell {
5915aa2876SPhilippe Mathieu-Daudé if (clk->period == period) {
6015aa2876SPhilippe Mathieu-Daudé return false;
6115aa2876SPhilippe Mathieu-Daudé }
62a6414d3bSLuc Michel trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_HZ(clk->period),
63a6414d3bSLuc Michel CLOCK_PERIOD_TO_HZ(period));
644cba075eSPeter Maydell clk->period = period;
6515aa2876SPhilippe Mathieu-Daudé
6615aa2876SPhilippe Mathieu-Daudé return true;
674cba075eSPeter Maydell }
684cba075eSPeter Maydell
clock_get_child_period(Clock * clk)6999abcbc7SPeter Maydell static uint64_t clock_get_child_period(Clock *clk)
7099abcbc7SPeter Maydell {
7199abcbc7SPeter Maydell /*
7299abcbc7SPeter Maydell * Return the period to be used for child clocks, which is the parent
737a21bee2SDaniel P. Berrangé * clock period adjusted for multiplier and divider effects.
7499abcbc7SPeter Maydell */
7599abcbc7SPeter Maydell return muldiv64(clk->period, clk->multiplier, clk->divider);
7699abcbc7SPeter Maydell }
7799abcbc7SPeter Maydell
clock_call_callback(Clock * clk,ClockEvent event)785ee0abedSPeter Maydell static void clock_call_callback(Clock *clk, ClockEvent event)
795ee0abedSPeter Maydell {
805ee0abedSPeter Maydell /*
815ee0abedSPeter Maydell * Call the Clock's callback for this event, if it has one and
825ee0abedSPeter Maydell * is interested in this event.
835ee0abedSPeter Maydell */
845ee0abedSPeter Maydell if (clk->callback && (clk->callback_events & event)) {
855ee0abedSPeter Maydell clk->callback(clk->callback_opaque, event);
865ee0abedSPeter Maydell }
875ee0abedSPeter Maydell }
885ee0abedSPeter Maydell
clock_propagate_period(Clock * clk,bool call_callbacks)894cba075eSPeter Maydell static void clock_propagate_period(Clock *clk, bool call_callbacks)
904cba075eSPeter Maydell {
914cba075eSPeter Maydell Clock *child;
9299abcbc7SPeter Maydell uint64_t child_period = clock_get_child_period(clk);
934cba075eSPeter Maydell
944cba075eSPeter Maydell QLIST_FOREACH(child, &clk->children, sibling) {
9599abcbc7SPeter Maydell if (child->period != child_period) {
96e4341623SPeter Maydell if (call_callbacks) {
97e4341623SPeter Maydell clock_call_callback(child, ClockPreUpdate);
98e4341623SPeter Maydell }
9999abcbc7SPeter Maydell child->period = child_period;
1004cba075eSPeter Maydell trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk),
10199abcbc7SPeter Maydell CLOCK_PERIOD_TO_HZ(child->period),
1024cba075eSPeter Maydell call_callbacks);
1035ee0abedSPeter Maydell if (call_callbacks) {
1045ee0abedSPeter Maydell clock_call_callback(child, ClockUpdate);
1054cba075eSPeter Maydell }
1064cba075eSPeter Maydell clock_propagate_period(child, call_callbacks);
1074cba075eSPeter Maydell }
1084cba075eSPeter Maydell }
1094cba075eSPeter Maydell }
1104cba075eSPeter Maydell
clock_propagate(Clock * clk)1114cba075eSPeter Maydell void clock_propagate(Clock *clk)
1124cba075eSPeter Maydell {
1134cba075eSPeter Maydell trace_clock_propagate(CLOCK_PATH(clk));
1144cba075eSPeter Maydell clock_propagate_period(clk, true);
1154cba075eSPeter Maydell }
1164cba075eSPeter Maydell
clock_set_source(Clock * clk,Clock * src)1174cba075eSPeter Maydell void clock_set_source(Clock *clk, Clock *src)
1184cba075eSPeter Maydell {
1194cba075eSPeter Maydell /* changing clock source is not supported */
1204cba075eSPeter Maydell assert(!clk->source);
1214cba075eSPeter Maydell
1224cba075eSPeter Maydell trace_clock_set_source(CLOCK_PATH(clk), CLOCK_PATH(src));
1234cba075eSPeter Maydell
12499abcbc7SPeter Maydell clk->period = clock_get_child_period(src);
1254cba075eSPeter Maydell QLIST_INSERT_HEAD(&src->children, clk, sibling);
1264cba075eSPeter Maydell clk->source = src;
1274cba075eSPeter Maydell clock_propagate_period(clk, false);
1284cba075eSPeter Maydell }
1294cba075eSPeter Maydell
clock_disconnect(Clock * clk)1304cba075eSPeter Maydell static void clock_disconnect(Clock *clk)
1314cba075eSPeter Maydell {
1324cba075eSPeter Maydell if (clk->source == NULL) {
1334cba075eSPeter Maydell return;
1344cba075eSPeter Maydell }
1354cba075eSPeter Maydell
1364cba075eSPeter Maydell trace_clock_disconnect(CLOCK_PATH(clk));
1374cba075eSPeter Maydell
1384cba075eSPeter Maydell clk->source = NULL;
1394cba075eSPeter Maydell QLIST_REMOVE(clk, sibling);
1404cba075eSPeter Maydell }
1414cba075eSPeter Maydell
clock_display_freq(Clock * clk)142b7cd9c1eSPeter Maydell char *clock_display_freq(Clock *clk)
143b7cd9c1eSPeter Maydell {
144b7cd9c1eSPeter Maydell return freq_to_str(clock_get_hz(clk));
145b7cd9c1eSPeter Maydell }
146b7cd9c1eSPeter Maydell
clock_set_mul_div(Clock * clk,uint32_t multiplier,uint32_t divider)14752405b7fSPhilippe Mathieu-Daudé bool clock_set_mul_div(Clock *clk, uint32_t multiplier, uint32_t divider)
14899abcbc7SPeter Maydell {
14999abcbc7SPeter Maydell assert(divider != 0);
15099abcbc7SPeter Maydell
15152405b7fSPhilippe Mathieu-Daudé if (clk->multiplier == multiplier && clk->divider == divider) {
15252405b7fSPhilippe Mathieu-Daudé return false;
15352405b7fSPhilippe Mathieu-Daudé }
15452405b7fSPhilippe Mathieu-Daudé
15599abcbc7SPeter Maydell trace_clock_set_mul_div(CLOCK_PATH(clk), clk->multiplier, multiplier,
15699abcbc7SPeter Maydell clk->divider, divider);
15799abcbc7SPeter Maydell clk->multiplier = multiplier;
15899abcbc7SPeter Maydell clk->divider = divider;
15952405b7fSPhilippe Mathieu-Daudé
16052405b7fSPhilippe Mathieu-Daudé return true;
16199abcbc7SPeter Maydell }
16299abcbc7SPeter Maydell
clock_period_prop_get(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)163*9240d65eSInès Varhol static void clock_period_prop_get(Object *obj, Visitor *v, const char *name,
164*9240d65eSInès Varhol void *opaque, Error **errp)
165*9240d65eSInès Varhol {
166*9240d65eSInès Varhol Clock *clk = CLOCK(obj);
167*9240d65eSInès Varhol uint64_t period = clock_get(clk);
168*9240d65eSInès Varhol visit_type_uint64(v, name, &period, errp);
169*9240d65eSInès Varhol }
170*9240d65eSInès Varhol
171*9240d65eSInès Varhol
clock_initfn(Object * obj)1724cba075eSPeter Maydell static void clock_initfn(Object *obj)
1734cba075eSPeter Maydell {
1744cba075eSPeter Maydell Clock *clk = CLOCK(obj);
1754cba075eSPeter Maydell
17699abcbc7SPeter Maydell clk->multiplier = 1;
17799abcbc7SPeter Maydell clk->divider = 1;
17899abcbc7SPeter Maydell
1794cba075eSPeter Maydell QLIST_INIT(&clk->children);
180*9240d65eSInès Varhol
181*9240d65eSInès Varhol if (qtest_enabled()) {
182*9240d65eSInès Varhol object_property_add(obj, "qtest-clock-period", "uint64",
183*9240d65eSInès Varhol clock_period_prop_get, NULL, NULL, NULL);
184*9240d65eSInès Varhol }
1854cba075eSPeter Maydell }
1864cba075eSPeter Maydell
clock_finalizefn(Object * obj)1874cba075eSPeter Maydell static void clock_finalizefn(Object *obj)
1884cba075eSPeter Maydell {
1894cba075eSPeter Maydell Clock *clk = CLOCK(obj);
1904cba075eSPeter Maydell Clock *child, *next;
1914cba075eSPeter Maydell
1924cba075eSPeter Maydell /* clear our list of children */
1934cba075eSPeter Maydell QLIST_FOREACH_SAFE(child, &clk->children, sibling, next) {
1944cba075eSPeter Maydell clock_disconnect(child);
1954cba075eSPeter Maydell }
1964cba075eSPeter Maydell
1974cba075eSPeter Maydell /* remove us from source's children list */
1984cba075eSPeter Maydell clock_disconnect(clk);
1994cba075eSPeter Maydell
2004cba075eSPeter Maydell g_free(clk->canonical_path);
2014cba075eSPeter Maydell }
2024cba075eSPeter Maydell
2034cba075eSPeter Maydell static const TypeInfo clock_info = {
2044cba075eSPeter Maydell .name = TYPE_CLOCK,
2054cba075eSPeter Maydell .parent = TYPE_OBJECT,
2064cba075eSPeter Maydell .instance_size = sizeof(Clock),
2074cba075eSPeter Maydell .instance_init = clock_initfn,
2084cba075eSPeter Maydell .instance_finalize = clock_finalizefn,
2094cba075eSPeter Maydell };
2104cba075eSPeter Maydell
clock_register_types(void)2114cba075eSPeter Maydell static void clock_register_types(void)
2124cba075eSPeter Maydell {
2134cba075eSPeter Maydell type_register_static(&clock_info);
2144cba075eSPeter Maydell }
2154cba075eSPeter Maydell
2164cba075eSPeter Maydell type_init(clock_register_types)
217