qemu/hw/core/clock.c
<<
>>
Prefs
   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
  20void 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
  26Clock *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
  41void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque)
  42{
  43    clk->callback = cb;
  44    clk->callback_opaque = opaque;
  45}
  46
  47void clock_clear_callback(Clock *clk)
  48{
  49    clock_set_callback(clk, NULL, NULL);
  50}
  51
  52bool 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
  64static 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
  82void 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
  89void 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
 102static 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
 114static void clock_initfn(Object *obj)
 115{
 116    Clock *clk = CLOCK(obj);
 117
 118    QLIST_INIT(&clk->children);
 119}
 120
 121static 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
 137static 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
 145static void clock_register_types(void)
 146{
 147    type_register_static(&clock_info);
 148}
 149
 150type_init(clock_register_types)
 151