1*4cba075eSPeter Maydell /* 2*4cba075eSPeter Maydell * Hardware Clocks 3*4cba075eSPeter Maydell * 4*4cba075eSPeter Maydell * Copyright GreenSocs 2016-2020 5*4cba075eSPeter Maydell * 6*4cba075eSPeter Maydell * Authors: 7*4cba075eSPeter Maydell * Frederic Konrad 8*4cba075eSPeter Maydell * Damien Hedde 9*4cba075eSPeter Maydell * 10*4cba075eSPeter Maydell * This work is licensed under the terms of the GNU GPL, version 2 or later. 11*4cba075eSPeter Maydell * See the COPYING file in the top-level directory. 12*4cba075eSPeter Maydell */ 13*4cba075eSPeter Maydell 14*4cba075eSPeter Maydell #include "qemu/osdep.h" 15*4cba075eSPeter Maydell #include "hw/clock.h" 16*4cba075eSPeter Maydell #include "trace.h" 17*4cba075eSPeter Maydell 18*4cba075eSPeter Maydell #define CLOCK_PATH(_clk) (_clk->canonical_path) 19*4cba075eSPeter Maydell 20*4cba075eSPeter Maydell void clock_setup_canonical_path(Clock *clk) 21*4cba075eSPeter Maydell { 22*4cba075eSPeter Maydell g_free(clk->canonical_path); 23*4cba075eSPeter Maydell clk->canonical_path = object_get_canonical_path(OBJECT(clk)); 24*4cba075eSPeter Maydell } 25*4cba075eSPeter Maydell 26*4cba075eSPeter Maydell void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque) 27*4cba075eSPeter Maydell { 28*4cba075eSPeter Maydell clk->callback = cb; 29*4cba075eSPeter Maydell clk->callback_opaque = opaque; 30*4cba075eSPeter Maydell } 31*4cba075eSPeter Maydell 32*4cba075eSPeter Maydell void clock_clear_callback(Clock *clk) 33*4cba075eSPeter Maydell { 34*4cba075eSPeter Maydell clock_set_callback(clk, NULL, NULL); 35*4cba075eSPeter Maydell } 36*4cba075eSPeter Maydell 37*4cba075eSPeter Maydell void clock_set(Clock *clk, uint64_t period) 38*4cba075eSPeter Maydell { 39*4cba075eSPeter Maydell trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_NS(clk->period), 40*4cba075eSPeter Maydell CLOCK_PERIOD_TO_NS(period)); 41*4cba075eSPeter Maydell clk->period = period; 42*4cba075eSPeter Maydell } 43*4cba075eSPeter Maydell 44*4cba075eSPeter Maydell static void clock_propagate_period(Clock *clk, bool call_callbacks) 45*4cba075eSPeter Maydell { 46*4cba075eSPeter Maydell Clock *child; 47*4cba075eSPeter Maydell 48*4cba075eSPeter Maydell QLIST_FOREACH(child, &clk->children, sibling) { 49*4cba075eSPeter Maydell if (child->period != clk->period) { 50*4cba075eSPeter Maydell child->period = clk->period; 51*4cba075eSPeter Maydell trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk), 52*4cba075eSPeter Maydell CLOCK_PERIOD_TO_NS(clk->period), 53*4cba075eSPeter Maydell call_callbacks); 54*4cba075eSPeter Maydell if (call_callbacks && child->callback) { 55*4cba075eSPeter Maydell child->callback(child->callback_opaque); 56*4cba075eSPeter Maydell } 57*4cba075eSPeter Maydell clock_propagate_period(child, call_callbacks); 58*4cba075eSPeter Maydell } 59*4cba075eSPeter Maydell } 60*4cba075eSPeter Maydell } 61*4cba075eSPeter Maydell 62*4cba075eSPeter Maydell void clock_propagate(Clock *clk) 63*4cba075eSPeter Maydell { 64*4cba075eSPeter Maydell assert(clk->source == NULL); 65*4cba075eSPeter Maydell trace_clock_propagate(CLOCK_PATH(clk)); 66*4cba075eSPeter Maydell clock_propagate_period(clk, true); 67*4cba075eSPeter Maydell } 68*4cba075eSPeter Maydell 69*4cba075eSPeter Maydell void clock_set_source(Clock *clk, Clock *src) 70*4cba075eSPeter Maydell { 71*4cba075eSPeter Maydell /* changing clock source is not supported */ 72*4cba075eSPeter Maydell assert(!clk->source); 73*4cba075eSPeter Maydell 74*4cba075eSPeter Maydell trace_clock_set_source(CLOCK_PATH(clk), CLOCK_PATH(src)); 75*4cba075eSPeter Maydell 76*4cba075eSPeter Maydell clk->period = src->period; 77*4cba075eSPeter Maydell QLIST_INSERT_HEAD(&src->children, clk, sibling); 78*4cba075eSPeter Maydell clk->source = src; 79*4cba075eSPeter Maydell clock_propagate_period(clk, false); 80*4cba075eSPeter Maydell } 81*4cba075eSPeter Maydell 82*4cba075eSPeter Maydell static void clock_disconnect(Clock *clk) 83*4cba075eSPeter Maydell { 84*4cba075eSPeter Maydell if (clk->source == NULL) { 85*4cba075eSPeter Maydell return; 86*4cba075eSPeter Maydell } 87*4cba075eSPeter Maydell 88*4cba075eSPeter Maydell trace_clock_disconnect(CLOCK_PATH(clk)); 89*4cba075eSPeter Maydell 90*4cba075eSPeter Maydell clk->source = NULL; 91*4cba075eSPeter Maydell QLIST_REMOVE(clk, sibling); 92*4cba075eSPeter Maydell } 93*4cba075eSPeter Maydell 94*4cba075eSPeter Maydell static void clock_initfn(Object *obj) 95*4cba075eSPeter Maydell { 96*4cba075eSPeter Maydell Clock *clk = CLOCK(obj); 97*4cba075eSPeter Maydell 98*4cba075eSPeter Maydell QLIST_INIT(&clk->children); 99*4cba075eSPeter Maydell } 100*4cba075eSPeter Maydell 101*4cba075eSPeter Maydell static void clock_finalizefn(Object *obj) 102*4cba075eSPeter Maydell { 103*4cba075eSPeter Maydell Clock *clk = CLOCK(obj); 104*4cba075eSPeter Maydell Clock *child, *next; 105*4cba075eSPeter Maydell 106*4cba075eSPeter Maydell /* clear our list of children */ 107*4cba075eSPeter Maydell QLIST_FOREACH_SAFE(child, &clk->children, sibling, next) { 108*4cba075eSPeter Maydell clock_disconnect(child); 109*4cba075eSPeter Maydell } 110*4cba075eSPeter Maydell 111*4cba075eSPeter Maydell /* remove us from source's children list */ 112*4cba075eSPeter Maydell clock_disconnect(clk); 113*4cba075eSPeter Maydell 114*4cba075eSPeter Maydell g_free(clk->canonical_path); 115*4cba075eSPeter Maydell } 116*4cba075eSPeter Maydell 117*4cba075eSPeter Maydell static const TypeInfo clock_info = { 118*4cba075eSPeter Maydell .name = TYPE_CLOCK, 119*4cba075eSPeter Maydell .parent = TYPE_OBJECT, 120*4cba075eSPeter Maydell .instance_size = sizeof(Clock), 121*4cba075eSPeter Maydell .instance_init = clock_initfn, 122*4cba075eSPeter Maydell .instance_finalize = clock_finalizefn, 123*4cba075eSPeter Maydell }; 124*4cba075eSPeter Maydell 125*4cba075eSPeter Maydell static void clock_register_types(void) 126*4cba075eSPeter Maydell { 127*4cba075eSPeter Maydell type_register_static(&clock_info); 128*4cba075eSPeter Maydell } 129*4cba075eSPeter Maydell 130*4cba075eSPeter Maydell type_init(clock_register_types) 131