xref: /openbmc/qemu/hw/core/clock.c (revision 845dd038)
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"
164cba075eSPeter Maydell #include "hw/clock.h"
174cba075eSPeter Maydell #include "trace.h"
184cba075eSPeter Maydell 
194cba075eSPeter Maydell #define CLOCK_PATH(_clk) (_clk->canonical_path)
204cba075eSPeter Maydell 
clock_setup_canonical_path(Clock * clk)214cba075eSPeter Maydell void clock_setup_canonical_path(Clock *clk)
224cba075eSPeter Maydell {
234cba075eSPeter Maydell     g_free(clk->canonical_path);
244cba075eSPeter Maydell     clk->canonical_path = object_get_canonical_path(OBJECT(clk));
254cba075eSPeter Maydell }
264cba075eSPeter Maydell 
clock_new(Object * parent,const char * name)275ebc6648SLuc Michel Clock *clock_new(Object *parent, const char *name)
285ebc6648SLuc Michel {
295ebc6648SLuc Michel     Object *obj;
305ebc6648SLuc Michel     Clock *clk;
315ebc6648SLuc Michel 
325ebc6648SLuc Michel     obj = object_new(TYPE_CLOCK);
335ebc6648SLuc Michel     object_property_add_child(parent, name, obj);
345ebc6648SLuc Michel     object_unref(obj);
355ebc6648SLuc Michel 
365ebc6648SLuc Michel     clk = CLOCK(obj);
375ebc6648SLuc Michel     clock_setup_canonical_path(clk);
385ebc6648SLuc Michel 
395ebc6648SLuc Michel     return clk;
405ebc6648SLuc Michel }
415ebc6648SLuc Michel 
clock_set_callback(Clock * clk,ClockCallback * cb,void * opaque,unsigned int events)425ee0abedSPeter Maydell void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque,
435ee0abedSPeter Maydell                         unsigned int events)
444cba075eSPeter Maydell {
454cba075eSPeter Maydell     clk->callback = cb;
464cba075eSPeter Maydell     clk->callback_opaque = opaque;
475ee0abedSPeter Maydell     clk->callback_events = events;
484cba075eSPeter Maydell }
494cba075eSPeter Maydell 
clock_clear_callback(Clock * clk)504cba075eSPeter Maydell void clock_clear_callback(Clock *clk)
514cba075eSPeter Maydell {
525ee0abedSPeter Maydell     clock_set_callback(clk, NULL, NULL, 0);
534cba075eSPeter Maydell }
544cba075eSPeter Maydell 
clock_set(Clock * clk,uint64_t period)5515aa2876SPhilippe Mathieu-Daudé bool clock_set(Clock *clk, uint64_t period)
564cba075eSPeter Maydell {
5715aa2876SPhilippe Mathieu-Daudé     if (clk->period == period) {
5815aa2876SPhilippe Mathieu-Daudé         return false;
5915aa2876SPhilippe Mathieu-Daudé     }
60a6414d3bSLuc Michel     trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_HZ(clk->period),
61a6414d3bSLuc Michel                     CLOCK_PERIOD_TO_HZ(period));
624cba075eSPeter Maydell     clk->period = period;
6315aa2876SPhilippe Mathieu-Daudé 
6415aa2876SPhilippe Mathieu-Daudé     return true;
654cba075eSPeter Maydell }
664cba075eSPeter Maydell 
clock_get_child_period(Clock * clk)6799abcbc7SPeter Maydell static uint64_t clock_get_child_period(Clock *clk)
6899abcbc7SPeter Maydell {
6999abcbc7SPeter Maydell     /*
7099abcbc7SPeter Maydell      * Return the period to be used for child clocks, which is the parent
717a21bee2SDaniel P. Berrangé      * clock period adjusted for multiplier and divider effects.
7299abcbc7SPeter Maydell      */
7399abcbc7SPeter Maydell     return muldiv64(clk->period, clk->multiplier, clk->divider);
7499abcbc7SPeter Maydell }
7599abcbc7SPeter Maydell 
clock_call_callback(Clock * clk,ClockEvent event)765ee0abedSPeter Maydell static void clock_call_callback(Clock *clk, ClockEvent event)
775ee0abedSPeter Maydell {
785ee0abedSPeter Maydell     /*
795ee0abedSPeter Maydell      * Call the Clock's callback for this event, if it has one and
805ee0abedSPeter Maydell      * is interested in this event.
815ee0abedSPeter Maydell      */
825ee0abedSPeter Maydell     if (clk->callback && (clk->callback_events & event)) {
835ee0abedSPeter Maydell         clk->callback(clk->callback_opaque, event);
845ee0abedSPeter Maydell     }
855ee0abedSPeter Maydell }
865ee0abedSPeter Maydell 
clock_propagate_period(Clock * clk,bool call_callbacks)874cba075eSPeter Maydell static void clock_propagate_period(Clock *clk, bool call_callbacks)
884cba075eSPeter Maydell {
894cba075eSPeter Maydell     Clock *child;
9099abcbc7SPeter Maydell     uint64_t child_period = clock_get_child_period(clk);
914cba075eSPeter Maydell 
924cba075eSPeter Maydell     QLIST_FOREACH(child, &clk->children, sibling) {
9399abcbc7SPeter Maydell         if (child->period != child_period) {
94e4341623SPeter Maydell             if (call_callbacks) {
95e4341623SPeter Maydell                 clock_call_callback(child, ClockPreUpdate);
96e4341623SPeter Maydell             }
9799abcbc7SPeter Maydell             child->period = child_period;
984cba075eSPeter Maydell             trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk),
9999abcbc7SPeter Maydell                                CLOCK_PERIOD_TO_HZ(child->period),
1004cba075eSPeter Maydell                                call_callbacks);
1015ee0abedSPeter Maydell             if (call_callbacks) {
1025ee0abedSPeter Maydell                 clock_call_callback(child, ClockUpdate);
1034cba075eSPeter Maydell             }
1044cba075eSPeter Maydell             clock_propagate_period(child, call_callbacks);
1054cba075eSPeter Maydell         }
1064cba075eSPeter Maydell     }
1074cba075eSPeter Maydell }
1084cba075eSPeter Maydell 
clock_propagate(Clock * clk)1094cba075eSPeter Maydell void clock_propagate(Clock *clk)
1104cba075eSPeter Maydell {
1114cba075eSPeter Maydell     trace_clock_propagate(CLOCK_PATH(clk));
1124cba075eSPeter Maydell     clock_propagate_period(clk, true);
1134cba075eSPeter Maydell }
1144cba075eSPeter Maydell 
clock_set_source(Clock * clk,Clock * src)1154cba075eSPeter Maydell void clock_set_source(Clock *clk, Clock *src)
1164cba075eSPeter Maydell {
1174cba075eSPeter Maydell     /* changing clock source is not supported */
1184cba075eSPeter Maydell     assert(!clk->source);
1194cba075eSPeter Maydell 
1204cba075eSPeter Maydell     trace_clock_set_source(CLOCK_PATH(clk), CLOCK_PATH(src));
1214cba075eSPeter Maydell 
12299abcbc7SPeter Maydell     clk->period = clock_get_child_period(src);
1234cba075eSPeter Maydell     QLIST_INSERT_HEAD(&src->children, clk, sibling);
1244cba075eSPeter Maydell     clk->source = src;
1254cba075eSPeter Maydell     clock_propagate_period(clk, false);
1264cba075eSPeter Maydell }
1274cba075eSPeter Maydell 
clock_disconnect(Clock * clk)1284cba075eSPeter Maydell static void clock_disconnect(Clock *clk)
1294cba075eSPeter Maydell {
1304cba075eSPeter Maydell     if (clk->source == NULL) {
1314cba075eSPeter Maydell         return;
1324cba075eSPeter Maydell     }
1334cba075eSPeter Maydell 
1344cba075eSPeter Maydell     trace_clock_disconnect(CLOCK_PATH(clk));
1354cba075eSPeter Maydell 
1364cba075eSPeter Maydell     clk->source = NULL;
1374cba075eSPeter Maydell     QLIST_REMOVE(clk, sibling);
1384cba075eSPeter Maydell }
1394cba075eSPeter Maydell 
clock_display_freq(Clock * clk)140b7cd9c1eSPeter Maydell char *clock_display_freq(Clock *clk)
141b7cd9c1eSPeter Maydell {
142b7cd9c1eSPeter Maydell     return freq_to_str(clock_get_hz(clk));
143b7cd9c1eSPeter Maydell }
144b7cd9c1eSPeter Maydell 
clock_set_mul_div(Clock * clk,uint32_t multiplier,uint32_t divider)145*52405b7fSPhilippe Mathieu-Daudé bool clock_set_mul_div(Clock *clk, uint32_t multiplier, uint32_t divider)
14699abcbc7SPeter Maydell {
14799abcbc7SPeter Maydell     assert(divider != 0);
14899abcbc7SPeter Maydell 
149*52405b7fSPhilippe Mathieu-Daudé     if (clk->multiplier == multiplier && clk->divider == divider) {
150*52405b7fSPhilippe Mathieu-Daudé         return false;
151*52405b7fSPhilippe Mathieu-Daudé     }
152*52405b7fSPhilippe Mathieu-Daudé 
15399abcbc7SPeter Maydell     trace_clock_set_mul_div(CLOCK_PATH(clk), clk->multiplier, multiplier,
15499abcbc7SPeter Maydell                             clk->divider, divider);
15599abcbc7SPeter Maydell     clk->multiplier = multiplier;
15699abcbc7SPeter Maydell     clk->divider = divider;
157*52405b7fSPhilippe Mathieu-Daudé 
158*52405b7fSPhilippe Mathieu-Daudé     return true;
15999abcbc7SPeter Maydell }
16099abcbc7SPeter Maydell 
clock_initfn(Object * obj)1614cba075eSPeter Maydell static void clock_initfn(Object *obj)
1624cba075eSPeter Maydell {
1634cba075eSPeter Maydell     Clock *clk = CLOCK(obj);
1644cba075eSPeter Maydell 
16599abcbc7SPeter Maydell     clk->multiplier = 1;
16699abcbc7SPeter Maydell     clk->divider = 1;
16799abcbc7SPeter Maydell 
1684cba075eSPeter Maydell     QLIST_INIT(&clk->children);
1694cba075eSPeter Maydell }
1704cba075eSPeter Maydell 
clock_finalizefn(Object * obj)1714cba075eSPeter Maydell static void clock_finalizefn(Object *obj)
1724cba075eSPeter Maydell {
1734cba075eSPeter Maydell     Clock *clk = CLOCK(obj);
1744cba075eSPeter Maydell     Clock *child, *next;
1754cba075eSPeter Maydell 
1764cba075eSPeter Maydell     /* clear our list of children */
1774cba075eSPeter Maydell     QLIST_FOREACH_SAFE(child, &clk->children, sibling, next) {
1784cba075eSPeter Maydell         clock_disconnect(child);
1794cba075eSPeter Maydell     }
1804cba075eSPeter Maydell 
1814cba075eSPeter Maydell     /* remove us from source's children list */
1824cba075eSPeter Maydell     clock_disconnect(clk);
1834cba075eSPeter Maydell 
1844cba075eSPeter Maydell     g_free(clk->canonical_path);
1854cba075eSPeter Maydell }
1864cba075eSPeter Maydell 
1874cba075eSPeter Maydell static const TypeInfo clock_info = {
1884cba075eSPeter Maydell     .name              = TYPE_CLOCK,
1894cba075eSPeter Maydell     .parent            = TYPE_OBJECT,
1904cba075eSPeter Maydell     .instance_size     = sizeof(Clock),
1914cba075eSPeter Maydell     .instance_init     = clock_initfn,
1924cba075eSPeter Maydell     .instance_finalize = clock_finalizefn,
1934cba075eSPeter Maydell };
1944cba075eSPeter Maydell 
clock_register_types(void)1954cba075eSPeter Maydell static void clock_register_types(void)
1964cba075eSPeter Maydell {
1974cba075eSPeter Maydell     type_register_static(&clock_info);
1984cba075eSPeter Maydell }
1994cba075eSPeter Maydell 
2004cba075eSPeter Maydell type_init(clock_register_types)
201