2
0

clock.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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. #include "qemu/osdep.h"
  14. #include "qemu/cutils.h"
  15. #include "qapi/visitor.h"
  16. #include "system/qtest.h"
  17. #include "hw/clock.h"
  18. #include "trace.h"
  19. #define CLOCK_PATH(_clk) (_clk->canonical_path)
  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. Clock *clock_new(Object *parent, const char *name)
  26. {
  27. Object *obj;
  28. Clock *clk;
  29. obj = object_new(TYPE_CLOCK);
  30. object_property_add_child(parent, name, obj);
  31. object_unref(obj);
  32. clk = CLOCK(obj);
  33. clock_setup_canonical_path(clk);
  34. return clk;
  35. }
  36. void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque,
  37. unsigned int events)
  38. {
  39. assert(OBJECT(clk)->parent);
  40. clk->callback = cb;
  41. clk->callback_opaque = opaque;
  42. clk->callback_events = events;
  43. }
  44. bool clock_set(Clock *clk, uint64_t period)
  45. {
  46. if (clk->period == period) {
  47. return false;
  48. }
  49. trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_HZ(clk->period),
  50. CLOCK_PERIOD_TO_HZ(period));
  51. clk->period = period;
  52. return true;
  53. }
  54. static uint64_t clock_get_child_period(Clock *clk)
  55. {
  56. /*
  57. * Return the period to be used for child clocks, which is the parent
  58. * clock period adjusted for multiplier and divider effects.
  59. */
  60. return muldiv64(clk->period, clk->multiplier, clk->divider);
  61. }
  62. static void clock_call_callback(Clock *clk, ClockEvent event)
  63. {
  64. /*
  65. * Call the Clock's callback for this event, if it has one and
  66. * is interested in this event.
  67. */
  68. if (clk->callback && (clk->callback_events & event)) {
  69. clk->callback(clk->callback_opaque, event);
  70. }
  71. }
  72. static void clock_propagate_period(Clock *clk, bool call_callbacks)
  73. {
  74. Clock *child;
  75. uint64_t child_period = clock_get_child_period(clk);
  76. QLIST_FOREACH(child, &clk->children, sibling) {
  77. if (child->period != child_period) {
  78. if (call_callbacks) {
  79. clock_call_callback(child, ClockPreUpdate);
  80. }
  81. child->period = child_period;
  82. trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk),
  83. CLOCK_PERIOD_TO_HZ(child->period),
  84. call_callbacks);
  85. if (call_callbacks) {
  86. clock_call_callback(child, ClockUpdate);
  87. }
  88. clock_propagate_period(child, call_callbacks);
  89. }
  90. }
  91. }
  92. void clock_propagate(Clock *clk)
  93. {
  94. trace_clock_propagate(CLOCK_PATH(clk));
  95. clock_propagate_period(clk, true);
  96. }
  97. void clock_set_source(Clock *clk, Clock *src)
  98. {
  99. /* changing clock source is not supported */
  100. assert(!clk->source);
  101. trace_clock_set_source(CLOCK_PATH(clk), CLOCK_PATH(src));
  102. clk->period = clock_get_child_period(src);
  103. QLIST_INSERT_HEAD(&src->children, clk, sibling);
  104. clk->source = src;
  105. clock_propagate_period(clk, false);
  106. }
  107. static void clock_disconnect(Clock *clk)
  108. {
  109. if (clk->source == NULL) {
  110. return;
  111. }
  112. trace_clock_disconnect(CLOCK_PATH(clk));
  113. clk->source = NULL;
  114. QLIST_REMOVE(clk, sibling);
  115. }
  116. char *clock_display_freq(Clock *clk)
  117. {
  118. return freq_to_str(clock_get_hz(clk));
  119. }
  120. bool clock_set_mul_div(Clock *clk, uint32_t multiplier, uint32_t divider)
  121. {
  122. assert(divider != 0);
  123. if (clk->multiplier == multiplier && clk->divider == divider) {
  124. return false;
  125. }
  126. trace_clock_set_mul_div(CLOCK_PATH(clk), clk->multiplier, multiplier,
  127. clk->divider, divider);
  128. clk->multiplier = multiplier;
  129. clk->divider = divider;
  130. return true;
  131. }
  132. static void clock_period_prop_get(Object *obj, Visitor *v, const char *name,
  133. void *opaque, Error **errp)
  134. {
  135. Clock *clk = CLOCK(obj);
  136. uint64_t period = clock_get(clk);
  137. visit_type_uint64(v, name, &period, errp);
  138. }
  139. static void clock_unparent(Object *obj)
  140. {
  141. /*
  142. * Callback are registered by the parent, which might die anytime after
  143. * it's unparented the children. Avoid having a callback to a deleted
  144. * object in case the clock is still referenced somewhere else (eg: by
  145. * a clock output).
  146. */
  147. clock_set_callback(CLOCK(obj), NULL, NULL, 0);
  148. }
  149. static void clock_initfn(Object *obj)
  150. {
  151. Clock *clk = CLOCK(obj);
  152. clk->multiplier = 1;
  153. clk->divider = 1;
  154. QLIST_INIT(&clk->children);
  155. if (qtest_enabled()) {
  156. object_property_add(obj, "qtest-clock-period", "uint64",
  157. clock_period_prop_get, NULL, NULL, NULL);
  158. }
  159. }
  160. static void clock_finalizefn(Object *obj)
  161. {
  162. Clock *clk = CLOCK(obj);
  163. Clock *child, *next;
  164. /* clear our list of children */
  165. QLIST_FOREACH_SAFE(child, &clk->children, sibling, next) {
  166. clock_disconnect(child);
  167. }
  168. /* remove us from source's children list */
  169. clock_disconnect(clk);
  170. g_free(clk->canonical_path);
  171. }
  172. static void clock_class_init(ObjectClass *klass, void *data)
  173. {
  174. klass->unparent = clock_unparent;
  175. }
  176. static const TypeInfo clock_info = {
  177. .name = TYPE_CLOCK,
  178. .parent = TYPE_OBJECT,
  179. .instance_size = sizeof(Clock),
  180. .instance_init = clock_initfn,
  181. .class_init = clock_class_init,
  182. .instance_finalize = clock_finalizefn,
  183. };
  184. static void clock_register_types(void)
  185. {
  186. type_register_static(&clock_info);
  187. }
  188. type_init(clock_register_types)