xref: /openbmc/qemu/hw/core/clock.c (revision 4cba075e)
1*4cba075eSPeter Maydell /*
2*4cba075eSPeter Maydell  * Hardware Clocks
3*4cba075eSPeter Maydell  *
4*4cba075eSPeter Maydell  * Copyright GreenSocs 2016-2020
5*4cba075eSPeter Maydell  *
6*4cba075eSPeter Maydell  * Authors:
7*4cba075eSPeter Maydell  *  Frederic Konrad
8*4cba075eSPeter Maydell  *  Damien Hedde
9*4cba075eSPeter Maydell  *
10*4cba075eSPeter Maydell  * This work is licensed under the terms of the GNU GPL, version 2 or later.
11*4cba075eSPeter Maydell  * See the COPYING file in the top-level directory.
12*4cba075eSPeter Maydell  */
13*4cba075eSPeter Maydell 
14*4cba075eSPeter Maydell #include "qemu/osdep.h"
15*4cba075eSPeter Maydell #include "hw/clock.h"
16*4cba075eSPeter Maydell #include "trace.h"
17*4cba075eSPeter Maydell 
18*4cba075eSPeter Maydell #define CLOCK_PATH(_clk) (_clk->canonical_path)
19*4cba075eSPeter Maydell 
20*4cba075eSPeter Maydell void clock_setup_canonical_path(Clock *clk)
21*4cba075eSPeter Maydell {
22*4cba075eSPeter Maydell     g_free(clk->canonical_path);
23*4cba075eSPeter Maydell     clk->canonical_path = object_get_canonical_path(OBJECT(clk));
24*4cba075eSPeter Maydell }
25*4cba075eSPeter Maydell 
26*4cba075eSPeter Maydell void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque)
27*4cba075eSPeter Maydell {
28*4cba075eSPeter Maydell     clk->callback = cb;
29*4cba075eSPeter Maydell     clk->callback_opaque = opaque;
30*4cba075eSPeter Maydell }
31*4cba075eSPeter Maydell 
32*4cba075eSPeter Maydell void clock_clear_callback(Clock *clk)
33*4cba075eSPeter Maydell {
34*4cba075eSPeter Maydell     clock_set_callback(clk, NULL, NULL);
35*4cba075eSPeter Maydell }
36*4cba075eSPeter Maydell 
37*4cba075eSPeter Maydell void clock_set(Clock *clk, uint64_t period)
38*4cba075eSPeter Maydell {
39*4cba075eSPeter Maydell     trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_NS(clk->period),
40*4cba075eSPeter Maydell                     CLOCK_PERIOD_TO_NS(period));
41*4cba075eSPeter Maydell     clk->period = period;
42*4cba075eSPeter Maydell }
43*4cba075eSPeter Maydell 
44*4cba075eSPeter Maydell static void clock_propagate_period(Clock *clk, bool call_callbacks)
45*4cba075eSPeter Maydell {
46*4cba075eSPeter Maydell     Clock *child;
47*4cba075eSPeter Maydell 
48*4cba075eSPeter Maydell     QLIST_FOREACH(child, &clk->children, sibling) {
49*4cba075eSPeter Maydell         if (child->period != clk->period) {
50*4cba075eSPeter Maydell             child->period = clk->period;
51*4cba075eSPeter Maydell             trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk),
52*4cba075eSPeter Maydell                                CLOCK_PERIOD_TO_NS(clk->period),
53*4cba075eSPeter Maydell                                call_callbacks);
54*4cba075eSPeter Maydell             if (call_callbacks && child->callback) {
55*4cba075eSPeter Maydell                 child->callback(child->callback_opaque);
56*4cba075eSPeter Maydell             }
57*4cba075eSPeter Maydell             clock_propagate_period(child, call_callbacks);
58*4cba075eSPeter Maydell         }
59*4cba075eSPeter Maydell     }
60*4cba075eSPeter Maydell }
61*4cba075eSPeter Maydell 
62*4cba075eSPeter Maydell void clock_propagate(Clock *clk)
63*4cba075eSPeter Maydell {
64*4cba075eSPeter Maydell     assert(clk->source == NULL);
65*4cba075eSPeter Maydell     trace_clock_propagate(CLOCK_PATH(clk));
66*4cba075eSPeter Maydell     clock_propagate_period(clk, true);
67*4cba075eSPeter Maydell }
68*4cba075eSPeter Maydell 
69*4cba075eSPeter Maydell void clock_set_source(Clock *clk, Clock *src)
70*4cba075eSPeter Maydell {
71*4cba075eSPeter Maydell     /* changing clock source is not supported */
72*4cba075eSPeter Maydell     assert(!clk->source);
73*4cba075eSPeter Maydell 
74*4cba075eSPeter Maydell     trace_clock_set_source(CLOCK_PATH(clk), CLOCK_PATH(src));
75*4cba075eSPeter Maydell 
76*4cba075eSPeter Maydell     clk->period = src->period;
77*4cba075eSPeter Maydell     QLIST_INSERT_HEAD(&src->children, clk, sibling);
78*4cba075eSPeter Maydell     clk->source = src;
79*4cba075eSPeter Maydell     clock_propagate_period(clk, false);
80*4cba075eSPeter Maydell }
81*4cba075eSPeter Maydell 
82*4cba075eSPeter Maydell static void clock_disconnect(Clock *clk)
83*4cba075eSPeter Maydell {
84*4cba075eSPeter Maydell     if (clk->source == NULL) {
85*4cba075eSPeter Maydell         return;
86*4cba075eSPeter Maydell     }
87*4cba075eSPeter Maydell 
88*4cba075eSPeter Maydell     trace_clock_disconnect(CLOCK_PATH(clk));
89*4cba075eSPeter Maydell 
90*4cba075eSPeter Maydell     clk->source = NULL;
91*4cba075eSPeter Maydell     QLIST_REMOVE(clk, sibling);
92*4cba075eSPeter Maydell }
93*4cba075eSPeter Maydell 
94*4cba075eSPeter Maydell static void clock_initfn(Object *obj)
95*4cba075eSPeter Maydell {
96*4cba075eSPeter Maydell     Clock *clk = CLOCK(obj);
97*4cba075eSPeter Maydell 
98*4cba075eSPeter Maydell     QLIST_INIT(&clk->children);
99*4cba075eSPeter Maydell }
100*4cba075eSPeter Maydell 
101*4cba075eSPeter Maydell static void clock_finalizefn(Object *obj)
102*4cba075eSPeter Maydell {
103*4cba075eSPeter Maydell     Clock *clk = CLOCK(obj);
104*4cba075eSPeter Maydell     Clock *child, *next;
105*4cba075eSPeter Maydell 
106*4cba075eSPeter Maydell     /* clear our list of children */
107*4cba075eSPeter Maydell     QLIST_FOREACH_SAFE(child, &clk->children, sibling, next) {
108*4cba075eSPeter Maydell         clock_disconnect(child);
109*4cba075eSPeter Maydell     }
110*4cba075eSPeter Maydell 
111*4cba075eSPeter Maydell     /* remove us from source's children list */
112*4cba075eSPeter Maydell     clock_disconnect(clk);
113*4cba075eSPeter Maydell 
114*4cba075eSPeter Maydell     g_free(clk->canonical_path);
115*4cba075eSPeter Maydell }
116*4cba075eSPeter Maydell 
117*4cba075eSPeter Maydell static const TypeInfo clock_info = {
118*4cba075eSPeter Maydell     .name              = TYPE_CLOCK,
119*4cba075eSPeter Maydell     .parent            = TYPE_OBJECT,
120*4cba075eSPeter Maydell     .instance_size     = sizeof(Clock),
121*4cba075eSPeter Maydell     .instance_init     = clock_initfn,
122*4cba075eSPeter Maydell     .instance_finalize = clock_finalizefn,
123*4cba075eSPeter Maydell };
124*4cba075eSPeter Maydell 
125*4cba075eSPeter Maydell static void clock_register_types(void)
126*4cba075eSPeter Maydell {
127*4cba075eSPeter Maydell     type_register_static(&clock_info);
128*4cba075eSPeter Maydell }
129*4cba075eSPeter Maydell 
130*4cba075eSPeter Maydell type_init(clock_register_types)
131