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" 15b7cd9c1eSPeter Maydell #include "qemu/cutils.h" 16*9240d65eSInès Varhol #include "qapi/visitor.h" 17*9240d65eSInès Varhol #include "sysemu/qtest.h" 184cba075eSPeter Maydell #include "hw/clock.h" 194cba075eSPeter Maydell #include "trace.h" 204cba075eSPeter Maydell 214cba075eSPeter Maydell #define CLOCK_PATH(_clk) (_clk->canonical_path) 224cba075eSPeter Maydell 234cba075eSPeter Maydell void clock_setup_canonical_path(Clock *clk) 244cba075eSPeter Maydell { 254cba075eSPeter Maydell g_free(clk->canonical_path); 264cba075eSPeter Maydell clk->canonical_path = object_get_canonical_path(OBJECT(clk)); 274cba075eSPeter Maydell } 284cba075eSPeter Maydell 295ebc6648SLuc Michel Clock *clock_new(Object *parent, const char *name) 305ebc6648SLuc Michel { 315ebc6648SLuc Michel Object *obj; 325ebc6648SLuc Michel Clock *clk; 335ebc6648SLuc Michel 345ebc6648SLuc Michel obj = object_new(TYPE_CLOCK); 355ebc6648SLuc Michel object_property_add_child(parent, name, obj); 365ebc6648SLuc Michel object_unref(obj); 375ebc6648SLuc Michel 385ebc6648SLuc Michel clk = CLOCK(obj); 395ebc6648SLuc Michel clock_setup_canonical_path(clk); 405ebc6648SLuc Michel 415ebc6648SLuc Michel return clk; 425ebc6648SLuc Michel } 435ebc6648SLuc Michel 445ee0abedSPeter Maydell void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque, 455ee0abedSPeter Maydell unsigned int events) 464cba075eSPeter Maydell { 474cba075eSPeter Maydell clk->callback = cb; 484cba075eSPeter Maydell clk->callback_opaque = opaque; 495ee0abedSPeter Maydell clk->callback_events = events; 504cba075eSPeter Maydell } 514cba075eSPeter Maydell 524cba075eSPeter Maydell void clock_clear_callback(Clock *clk) 534cba075eSPeter Maydell { 545ee0abedSPeter Maydell clock_set_callback(clk, NULL, NULL, 0); 554cba075eSPeter Maydell } 564cba075eSPeter Maydell 5715aa2876SPhilippe Mathieu-Daudé bool clock_set(Clock *clk, uint64_t period) 584cba075eSPeter Maydell { 5915aa2876SPhilippe Mathieu-Daudé if (clk->period == period) { 6015aa2876SPhilippe Mathieu-Daudé return false; 6115aa2876SPhilippe Mathieu-Daudé } 62a6414d3bSLuc Michel trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_HZ(clk->period), 63a6414d3bSLuc Michel CLOCK_PERIOD_TO_HZ(period)); 644cba075eSPeter Maydell clk->period = period; 6515aa2876SPhilippe Mathieu-Daudé 6615aa2876SPhilippe Mathieu-Daudé return true; 674cba075eSPeter Maydell } 684cba075eSPeter Maydell 6999abcbc7SPeter Maydell static uint64_t clock_get_child_period(Clock *clk) 7099abcbc7SPeter Maydell { 7199abcbc7SPeter Maydell /* 7299abcbc7SPeter Maydell * Return the period to be used for child clocks, which is the parent 737a21bee2SDaniel P. Berrangé * clock period adjusted for multiplier and divider effects. 7499abcbc7SPeter Maydell */ 7599abcbc7SPeter Maydell return muldiv64(clk->period, clk->multiplier, clk->divider); 7699abcbc7SPeter Maydell } 7799abcbc7SPeter Maydell 785ee0abedSPeter Maydell static void clock_call_callback(Clock *clk, ClockEvent event) 795ee0abedSPeter Maydell { 805ee0abedSPeter Maydell /* 815ee0abedSPeter Maydell * Call the Clock's callback for this event, if it has one and 825ee0abedSPeter Maydell * is interested in this event. 835ee0abedSPeter Maydell */ 845ee0abedSPeter Maydell if (clk->callback && (clk->callback_events & event)) { 855ee0abedSPeter Maydell clk->callback(clk->callback_opaque, event); 865ee0abedSPeter Maydell } 875ee0abedSPeter Maydell } 885ee0abedSPeter Maydell 894cba075eSPeter Maydell static void clock_propagate_period(Clock *clk, bool call_callbacks) 904cba075eSPeter Maydell { 914cba075eSPeter Maydell Clock *child; 9299abcbc7SPeter Maydell uint64_t child_period = clock_get_child_period(clk); 934cba075eSPeter Maydell 944cba075eSPeter Maydell QLIST_FOREACH(child, &clk->children, sibling) { 9599abcbc7SPeter Maydell if (child->period != child_period) { 96e4341623SPeter Maydell if (call_callbacks) { 97e4341623SPeter Maydell clock_call_callback(child, ClockPreUpdate); 98e4341623SPeter Maydell } 9999abcbc7SPeter Maydell child->period = child_period; 1004cba075eSPeter Maydell trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk), 10199abcbc7SPeter Maydell CLOCK_PERIOD_TO_HZ(child->period), 1024cba075eSPeter Maydell call_callbacks); 1035ee0abedSPeter Maydell if (call_callbacks) { 1045ee0abedSPeter Maydell clock_call_callback(child, ClockUpdate); 1054cba075eSPeter Maydell } 1064cba075eSPeter Maydell clock_propagate_period(child, call_callbacks); 1074cba075eSPeter Maydell } 1084cba075eSPeter Maydell } 1094cba075eSPeter Maydell } 1104cba075eSPeter Maydell 1114cba075eSPeter Maydell void clock_propagate(Clock *clk) 1124cba075eSPeter Maydell { 1134cba075eSPeter Maydell trace_clock_propagate(CLOCK_PATH(clk)); 1144cba075eSPeter Maydell clock_propagate_period(clk, true); 1154cba075eSPeter Maydell } 1164cba075eSPeter Maydell 1174cba075eSPeter Maydell void clock_set_source(Clock *clk, Clock *src) 1184cba075eSPeter Maydell { 1194cba075eSPeter Maydell /* changing clock source is not supported */ 1204cba075eSPeter Maydell assert(!clk->source); 1214cba075eSPeter Maydell 1224cba075eSPeter Maydell trace_clock_set_source(CLOCK_PATH(clk), CLOCK_PATH(src)); 1234cba075eSPeter Maydell 12499abcbc7SPeter Maydell clk->period = clock_get_child_period(src); 1254cba075eSPeter Maydell QLIST_INSERT_HEAD(&src->children, clk, sibling); 1264cba075eSPeter Maydell clk->source = src; 1274cba075eSPeter Maydell clock_propagate_period(clk, false); 1284cba075eSPeter Maydell } 1294cba075eSPeter Maydell 1304cba075eSPeter Maydell static void clock_disconnect(Clock *clk) 1314cba075eSPeter Maydell { 1324cba075eSPeter Maydell if (clk->source == NULL) { 1334cba075eSPeter Maydell return; 1344cba075eSPeter Maydell } 1354cba075eSPeter Maydell 1364cba075eSPeter Maydell trace_clock_disconnect(CLOCK_PATH(clk)); 1374cba075eSPeter Maydell 1384cba075eSPeter Maydell clk->source = NULL; 1394cba075eSPeter Maydell QLIST_REMOVE(clk, sibling); 1404cba075eSPeter Maydell } 1414cba075eSPeter Maydell 142b7cd9c1eSPeter Maydell char *clock_display_freq(Clock *clk) 143b7cd9c1eSPeter Maydell { 144b7cd9c1eSPeter Maydell return freq_to_str(clock_get_hz(clk)); 145b7cd9c1eSPeter Maydell } 146b7cd9c1eSPeter Maydell 14752405b7fSPhilippe Mathieu-Daudé bool clock_set_mul_div(Clock *clk, uint32_t multiplier, uint32_t divider) 14899abcbc7SPeter Maydell { 14999abcbc7SPeter Maydell assert(divider != 0); 15099abcbc7SPeter Maydell 15152405b7fSPhilippe Mathieu-Daudé if (clk->multiplier == multiplier && clk->divider == divider) { 15252405b7fSPhilippe Mathieu-Daudé return false; 15352405b7fSPhilippe Mathieu-Daudé } 15452405b7fSPhilippe Mathieu-Daudé 15599abcbc7SPeter Maydell trace_clock_set_mul_div(CLOCK_PATH(clk), clk->multiplier, multiplier, 15699abcbc7SPeter Maydell clk->divider, divider); 15799abcbc7SPeter Maydell clk->multiplier = multiplier; 15899abcbc7SPeter Maydell clk->divider = divider; 15952405b7fSPhilippe Mathieu-Daudé 16052405b7fSPhilippe Mathieu-Daudé return true; 16199abcbc7SPeter Maydell } 16299abcbc7SPeter Maydell 163*9240d65eSInès Varhol static void clock_period_prop_get(Object *obj, Visitor *v, const char *name, 164*9240d65eSInès Varhol void *opaque, Error **errp) 165*9240d65eSInès Varhol { 166*9240d65eSInès Varhol Clock *clk = CLOCK(obj); 167*9240d65eSInès Varhol uint64_t period = clock_get(clk); 168*9240d65eSInès Varhol visit_type_uint64(v, name, &period, errp); 169*9240d65eSInès Varhol } 170*9240d65eSInès Varhol 171*9240d65eSInès Varhol 1724cba075eSPeter Maydell static void clock_initfn(Object *obj) 1734cba075eSPeter Maydell { 1744cba075eSPeter Maydell Clock *clk = CLOCK(obj); 1754cba075eSPeter Maydell 17699abcbc7SPeter Maydell clk->multiplier = 1; 17799abcbc7SPeter Maydell clk->divider = 1; 17899abcbc7SPeter Maydell 1794cba075eSPeter Maydell QLIST_INIT(&clk->children); 180*9240d65eSInès Varhol 181*9240d65eSInès Varhol if (qtest_enabled()) { 182*9240d65eSInès Varhol object_property_add(obj, "qtest-clock-period", "uint64", 183*9240d65eSInès Varhol clock_period_prop_get, NULL, NULL, NULL); 184*9240d65eSInès Varhol } 1854cba075eSPeter Maydell } 1864cba075eSPeter Maydell 1874cba075eSPeter Maydell static void clock_finalizefn(Object *obj) 1884cba075eSPeter Maydell { 1894cba075eSPeter Maydell Clock *clk = CLOCK(obj); 1904cba075eSPeter Maydell Clock *child, *next; 1914cba075eSPeter Maydell 1924cba075eSPeter Maydell /* clear our list of children */ 1934cba075eSPeter Maydell QLIST_FOREACH_SAFE(child, &clk->children, sibling, next) { 1944cba075eSPeter Maydell clock_disconnect(child); 1954cba075eSPeter Maydell } 1964cba075eSPeter Maydell 1974cba075eSPeter Maydell /* remove us from source's children list */ 1984cba075eSPeter Maydell clock_disconnect(clk); 1994cba075eSPeter Maydell 2004cba075eSPeter Maydell g_free(clk->canonical_path); 2014cba075eSPeter Maydell } 2024cba075eSPeter Maydell 2034cba075eSPeter Maydell static const TypeInfo clock_info = { 2044cba075eSPeter Maydell .name = TYPE_CLOCK, 2054cba075eSPeter Maydell .parent = TYPE_OBJECT, 2064cba075eSPeter Maydell .instance_size = sizeof(Clock), 2074cba075eSPeter Maydell .instance_init = clock_initfn, 2084cba075eSPeter Maydell .instance_finalize = clock_finalizefn, 2094cba075eSPeter Maydell }; 2104cba075eSPeter Maydell 2114cba075eSPeter Maydell static void clock_register_types(void) 2124cba075eSPeter Maydell { 2134cba075eSPeter Maydell type_register_static(&clock_info); 2144cba075eSPeter Maydell } 2154cba075eSPeter Maydell 2164cba075eSPeter Maydell type_init(clock_register_types) 217