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 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 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 52 bool clock_set(Clock *clk, uint64_t period) 53 { 54 if (clk->period == period) { 55 return false; 56 } 57 trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_HZ(clk->period), 58 CLOCK_PERIOD_TO_HZ(period)); 59 clk->period = period; 60 61 return true; 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), 72 CLOCK_PERIOD_TO_HZ(clk->period), 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) 151