clock.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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 "hw/clock.h"
  15. #include "trace.h"
  16. #define CLOCK_PATH(_clk) (_clk->canonical_path)
  17. void clock_setup_canonical_path(Clock *clk)
  18. {
  19. g_free(clk->canonical_path);
  20. clk->canonical_path = object_get_canonical_path(OBJECT(clk));
  21. }
  22. void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque)
  23. {
  24. clk->callback = cb;
  25. clk->callback_opaque = opaque;
  26. }
  27. void clock_clear_callback(Clock *clk)
  28. {
  29. clock_set_callback(clk, NULL, NULL);
  30. }
  31. bool clock_set(Clock *clk, uint64_t period)
  32. {
  33. if (clk->period == period) {
  34. return false;
  35. }
  36. trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_NS(clk->period),
  37. CLOCK_PERIOD_TO_NS(period));
  38. clk->period = period;
  39. return true;
  40. }
  41. static void clock_propagate_period(Clock *clk, bool call_callbacks)
  42. {
  43. Clock *child;
  44. QLIST_FOREACH(child, &clk->children, sibling) {
  45. if (child->period != clk->period) {
  46. child->period = clk->period;
  47. trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk),
  48. CLOCK_PERIOD_TO_NS(clk->period),
  49. call_callbacks);
  50. if (call_callbacks && child->callback) {
  51. child->callback(child->callback_opaque);
  52. }
  53. clock_propagate_period(child, call_callbacks);
  54. }
  55. }
  56. }
  57. void clock_propagate(Clock *clk)
  58. {
  59. assert(clk->source == NULL);
  60. trace_clock_propagate(CLOCK_PATH(clk));
  61. clock_propagate_period(clk, true);
  62. }
  63. void clock_set_source(Clock *clk, Clock *src)
  64. {
  65. /* changing clock source is not supported */
  66. assert(!clk->source);
  67. trace_clock_set_source(CLOCK_PATH(clk), CLOCK_PATH(src));
  68. clk->period = src->period;
  69. QLIST_INSERT_HEAD(&src->children, clk, sibling);
  70. clk->source = src;
  71. clock_propagate_period(clk, false);
  72. }
  73. static void clock_disconnect(Clock *clk)
  74. {
  75. if (clk->source == NULL) {
  76. return;
  77. }
  78. trace_clock_disconnect(CLOCK_PATH(clk));
  79. clk->source = NULL;
  80. QLIST_REMOVE(clk, sibling);
  81. }
  82. static void clock_initfn(Object *obj)
  83. {
  84. Clock *clk = CLOCK(obj);
  85. QLIST_INIT(&clk->children);
  86. }
  87. static void clock_finalizefn(Object *obj)
  88. {
  89. Clock *clk = CLOCK(obj);
  90. Clock *child, *next;
  91. /* clear our list of children */
  92. QLIST_FOREACH_SAFE(child, &clk->children, sibling, next) {
  93. clock_disconnect(child);
  94. }
  95. /* remove us from source's children list */
  96. clock_disconnect(clk);
  97. g_free(clk->canonical_path);
  98. }
  99. static const TypeInfo clock_info = {
  100. .name = TYPE_CLOCK,
  101. .parent = TYPE_OBJECT,
  102. .instance_size = sizeof(Clock),
  103. .instance_init = clock_initfn,
  104. .instance_finalize = clock_finalizefn,
  105. };
  106. static void clock_register_types(void)
  107. {
  108. type_register_static(&clock_info);
  109. }
  110. type_init(clock_register_types)