clock.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  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 "hw/clock.h"
  16. #include "trace.h"
  17. #define CLOCK_PATH(_clk) (_clk->canonical_path)
  18. void clock_setup_canonical_path(Clock *clk)
  19. {
  20. g_free(clk->canonical_path);
  21. clk->canonical_path = object_get_canonical_path(OBJECT(clk));
  22. }
  23. Clock *clock_new(Object *parent, const char *name)
  24. {
  25. Object *obj;
  26. Clock *clk;
  27. obj = object_new(TYPE_CLOCK);
  28. object_property_add_child(parent, name, obj);
  29. object_unref(obj);
  30. clk = CLOCK(obj);
  31. clock_setup_canonical_path(clk);
  32. return clk;
  33. }
  34. void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque,
  35. unsigned int events)
  36. {
  37. clk->callback = cb;
  38. clk->callback_opaque = opaque;
  39. clk->callback_events = events;
  40. }
  41. void clock_clear_callback(Clock *clk)
  42. {
  43. clock_set_callback(clk, NULL, NULL, 0);
  44. }
  45. bool clock_set(Clock *clk, uint64_t period)
  46. {
  47. if (clk->period == period) {
  48. return false;
  49. }
  50. trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_HZ(clk->period),
  51. CLOCK_PERIOD_TO_HZ(period));
  52. clk->period = period;
  53. return true;
  54. }
  55. static uint64_t clock_get_child_period(Clock *clk)
  56. {
  57. /*
  58. * Return the period to be used for child clocks, which is the parent
  59. * clock period adjusted for multiplier and divider effects.
  60. */
  61. return muldiv64(clk->period, clk->multiplier, clk->divider);
  62. }
  63. static void clock_call_callback(Clock *clk, ClockEvent event)
  64. {
  65. /*
  66. * Call the Clock's callback for this event, if it has one and
  67. * is interested in this event.
  68. */
  69. if (clk->callback && (clk->callback_events & event)) {
  70. clk->callback(clk->callback_opaque, event);
  71. }
  72. }
  73. static void clock_propagate_period(Clock *clk, bool call_callbacks)
  74. {
  75. Clock *child;
  76. uint64_t child_period = clock_get_child_period(clk);
  77. QLIST_FOREACH(child, &clk->children, sibling) {
  78. if (child->period != child_period) {
  79. if (call_callbacks) {
  80. clock_call_callback(child, ClockPreUpdate);
  81. }
  82. child->period = child_period;
  83. trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk),
  84. CLOCK_PERIOD_TO_HZ(child->period),
  85. call_callbacks);
  86. if (call_callbacks) {
  87. clock_call_callback(child, ClockUpdate);
  88. }
  89. clock_propagate_period(child, call_callbacks);
  90. }
  91. }
  92. }
  93. void clock_propagate(Clock *clk)
  94. {
  95. assert(clk->source == NULL);
  96. trace_clock_propagate(CLOCK_PATH(clk));
  97. clock_propagate_period(clk, true);
  98. }
  99. void clock_set_source(Clock *clk, Clock *src)
  100. {
  101. /* changing clock source is not supported */
  102. assert(!clk->source);
  103. trace_clock_set_source(CLOCK_PATH(clk), CLOCK_PATH(src));
  104. clk->period = clock_get_child_period(src);
  105. QLIST_INSERT_HEAD(&src->children, clk, sibling);
  106. clk->source = src;
  107. clock_propagate_period(clk, false);
  108. }
  109. static void clock_disconnect(Clock *clk)
  110. {
  111. if (clk->source == NULL) {
  112. return;
  113. }
  114. trace_clock_disconnect(CLOCK_PATH(clk));
  115. clk->source = NULL;
  116. QLIST_REMOVE(clk, sibling);
  117. }
  118. char *clock_display_freq(Clock *clk)
  119. {
  120. return freq_to_str(clock_get_hz(clk));
  121. }
  122. void clock_set_mul_div(Clock *clk, uint32_t multiplier, uint32_t divider)
  123. {
  124. assert(divider != 0);
  125. trace_clock_set_mul_div(CLOCK_PATH(clk), clk->multiplier, multiplier,
  126. clk->divider, divider);
  127. clk->multiplier = multiplier;
  128. clk->divider = divider;
  129. }
  130. static void clock_initfn(Object *obj)
  131. {
  132. Clock *clk = CLOCK(obj);
  133. clk->multiplier = 1;
  134. clk->divider = 1;
  135. QLIST_INIT(&clk->children);
  136. }
  137. static void clock_finalizefn(Object *obj)
  138. {
  139. Clock *clk = CLOCK(obj);
  140. Clock *child, *next;
  141. /* clear our list of children */
  142. QLIST_FOREACH_SAFE(child, &clk->children, sibling, next) {
  143. clock_disconnect(child);
  144. }
  145. /* remove us from source's children list */
  146. clock_disconnect(clk);
  147. g_free(clk->canonical_path);
  148. }
  149. static const TypeInfo clock_info = {
  150. .name = TYPE_CLOCK,
  151. .parent = TYPE_OBJECT,
  152. .instance_size = sizeof(Clock),
  153. .instance_init = clock_initfn,
  154. .instance_finalize = clock_finalizefn,
  155. };
  156. static void clock_register_types(void)
  157. {
  158. type_register_static(&clock_info);
  159. }
  160. type_init(clock_register_types)