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