14cba075eSPeter Maydell /* 24cba075eSPeter Maydell * Hardware Clocks 34cba075eSPeter Maydell * 44cba075eSPeter Maydell * Copyright GreenSocs 2016-2020 54cba075eSPeter Maydell * 64cba075eSPeter Maydell * Authors: 74cba075eSPeter Maydell * Frederic Konrad 84cba075eSPeter Maydell * Damien Hedde 94cba075eSPeter Maydell * 104cba075eSPeter Maydell * This work is licensed under the terms of the GNU GPL, version 2 or later. 114cba075eSPeter Maydell * See the COPYING file in the top-level directory. 124cba075eSPeter Maydell */ 134cba075eSPeter Maydell 144cba075eSPeter Maydell #include "qemu/osdep.h" 154cba075eSPeter Maydell #include "hw/clock.h" 164cba075eSPeter Maydell #include "trace.h" 174cba075eSPeter Maydell 184cba075eSPeter Maydell #define CLOCK_PATH(_clk) (_clk->canonical_path) 194cba075eSPeter Maydell 204cba075eSPeter Maydell void clock_setup_canonical_path(Clock *clk) 214cba075eSPeter Maydell { 224cba075eSPeter Maydell g_free(clk->canonical_path); 234cba075eSPeter Maydell clk->canonical_path = object_get_canonical_path(OBJECT(clk)); 244cba075eSPeter Maydell } 254cba075eSPeter Maydell 264cba075eSPeter Maydell void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque) 274cba075eSPeter Maydell { 284cba075eSPeter Maydell clk->callback = cb; 294cba075eSPeter Maydell clk->callback_opaque = opaque; 304cba075eSPeter Maydell } 314cba075eSPeter Maydell 324cba075eSPeter Maydell void clock_clear_callback(Clock *clk) 334cba075eSPeter Maydell { 344cba075eSPeter Maydell clock_set_callback(clk, NULL, NULL); 354cba075eSPeter Maydell } 364cba075eSPeter Maydell 37*15aa2876SPhilippe Mathieu-Daudé bool clock_set(Clock *clk, uint64_t period) 384cba075eSPeter Maydell { 39*15aa2876SPhilippe Mathieu-Daudé if (clk->period == period) { 40*15aa2876SPhilippe Mathieu-Daudé return false; 41*15aa2876SPhilippe Mathieu-Daudé } 424cba075eSPeter Maydell trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_NS(clk->period), 434cba075eSPeter Maydell CLOCK_PERIOD_TO_NS(period)); 444cba075eSPeter Maydell clk->period = period; 45*15aa2876SPhilippe Mathieu-Daudé 46*15aa2876SPhilippe Mathieu-Daudé return true; 474cba075eSPeter Maydell } 484cba075eSPeter Maydell 494cba075eSPeter Maydell static void clock_propagate_period(Clock *clk, bool call_callbacks) 504cba075eSPeter Maydell { 514cba075eSPeter Maydell Clock *child; 524cba075eSPeter Maydell 534cba075eSPeter Maydell QLIST_FOREACH(child, &clk->children, sibling) { 544cba075eSPeter Maydell if (child->period != clk->period) { 554cba075eSPeter Maydell child->period = clk->period; 564cba075eSPeter Maydell trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk), 574cba075eSPeter Maydell CLOCK_PERIOD_TO_NS(clk->period), 584cba075eSPeter Maydell call_callbacks); 594cba075eSPeter Maydell if (call_callbacks && child->callback) { 604cba075eSPeter Maydell child->callback(child->callback_opaque); 614cba075eSPeter Maydell } 624cba075eSPeter Maydell clock_propagate_period(child, call_callbacks); 634cba075eSPeter Maydell } 644cba075eSPeter Maydell } 654cba075eSPeter Maydell } 664cba075eSPeter Maydell 674cba075eSPeter Maydell void clock_propagate(Clock *clk) 684cba075eSPeter Maydell { 694cba075eSPeter Maydell assert(clk->source == NULL); 704cba075eSPeter Maydell trace_clock_propagate(CLOCK_PATH(clk)); 714cba075eSPeter Maydell clock_propagate_period(clk, true); 724cba075eSPeter Maydell } 734cba075eSPeter Maydell 744cba075eSPeter Maydell void clock_set_source(Clock *clk, Clock *src) 754cba075eSPeter Maydell { 764cba075eSPeter Maydell /* changing clock source is not supported */ 774cba075eSPeter Maydell assert(!clk->source); 784cba075eSPeter Maydell 794cba075eSPeter Maydell trace_clock_set_source(CLOCK_PATH(clk), CLOCK_PATH(src)); 804cba075eSPeter Maydell 814cba075eSPeter Maydell clk->period = src->period; 824cba075eSPeter Maydell QLIST_INSERT_HEAD(&src->children, clk, sibling); 834cba075eSPeter Maydell clk->source = src; 844cba075eSPeter Maydell clock_propagate_period(clk, false); 854cba075eSPeter Maydell } 864cba075eSPeter Maydell 874cba075eSPeter Maydell static void clock_disconnect(Clock *clk) 884cba075eSPeter Maydell { 894cba075eSPeter Maydell if (clk->source == NULL) { 904cba075eSPeter Maydell return; 914cba075eSPeter Maydell } 924cba075eSPeter Maydell 934cba075eSPeter Maydell trace_clock_disconnect(CLOCK_PATH(clk)); 944cba075eSPeter Maydell 954cba075eSPeter Maydell clk->source = NULL; 964cba075eSPeter Maydell QLIST_REMOVE(clk, sibling); 974cba075eSPeter Maydell } 984cba075eSPeter Maydell 994cba075eSPeter Maydell static void clock_initfn(Object *obj) 1004cba075eSPeter Maydell { 1014cba075eSPeter Maydell Clock *clk = CLOCK(obj); 1024cba075eSPeter Maydell 1034cba075eSPeter Maydell QLIST_INIT(&clk->children); 1044cba075eSPeter Maydell } 1054cba075eSPeter Maydell 1064cba075eSPeter Maydell static void clock_finalizefn(Object *obj) 1074cba075eSPeter Maydell { 1084cba075eSPeter Maydell Clock *clk = CLOCK(obj); 1094cba075eSPeter Maydell Clock *child, *next; 1104cba075eSPeter Maydell 1114cba075eSPeter Maydell /* clear our list of children */ 1124cba075eSPeter Maydell QLIST_FOREACH_SAFE(child, &clk->children, sibling, next) { 1134cba075eSPeter Maydell clock_disconnect(child); 1144cba075eSPeter Maydell } 1154cba075eSPeter Maydell 1164cba075eSPeter Maydell /* remove us from source's children list */ 1174cba075eSPeter Maydell clock_disconnect(clk); 1184cba075eSPeter Maydell 1194cba075eSPeter Maydell g_free(clk->canonical_path); 1204cba075eSPeter Maydell } 1214cba075eSPeter Maydell 1224cba075eSPeter Maydell static const TypeInfo clock_info = { 1234cba075eSPeter Maydell .name = TYPE_CLOCK, 1244cba075eSPeter Maydell .parent = TYPE_OBJECT, 1254cba075eSPeter Maydell .instance_size = sizeof(Clock), 1264cba075eSPeter Maydell .instance_init = clock_initfn, 1274cba075eSPeter Maydell .instance_finalize = clock_finalizefn, 1284cba075eSPeter Maydell }; 1294cba075eSPeter Maydell 1304cba075eSPeter Maydell static void clock_register_types(void) 1314cba075eSPeter Maydell { 1324cba075eSPeter Maydell type_register_static(&clock_info); 1334cba075eSPeter Maydell } 1344cba075eSPeter Maydell 1354cba075eSPeter Maydell type_init(clock_register_types) 136