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