2 * Device's clock input and output
4 * Copyright GreenSocs 2016-2020
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.
14 #include "qemu/osdep.h"
15 #include "hw/qdev-clock.h"
16 #include "hw/qdev-core.h"
17 #include "qapi/error.h"
20 * qdev_init_clocklist:
21 * Add a new clock in a device
23 static NamedClockList
*qdev_init_clocklist(DeviceState
*dev
, const char *name
,
24 bool output
, Clock
*clk
)
29 * Clock must be added before realize() so that we can compute the
30 * clock's canonical path during device_realize().
32 assert(!dev
->realized
);
35 * The ncl structure is freed by qdev_finalize_clocklist() which will
36 * be called during @dev's device_finalize().
38 ncl
= g_new0(NamedClockList
, 1);
39 ncl
->name
= g_strdup(name
);
41 ncl
->alias
= (clk
!= NULL
);
44 * Trying to create a clock whose name clashes with some other
45 * clock or property is a bug in the caller and we will abort().
48 clk
= CLOCK(object_new(TYPE_CLOCK
));
49 object_property_add_child(OBJECT(dev
), name
, OBJECT(clk
));
52 * Remove object_new()'s initial reference.
53 * Note that for inputs, the reference created by object_new()
54 * will be deleted in qdev_finalize_clocklist().
56 object_unref(OBJECT(clk
));
59 object_property_add_link(OBJECT(dev
), name
,
60 object_get_typename(OBJECT(clk
)),
61 (Object
**) &ncl
->clock
,
62 NULL
, OBJ_PROP_LINK_STRONG
);
67 QLIST_INSERT_HEAD(&dev
->clocks
, ncl
, node
);
71 void qdev_finalize_clocklist(DeviceState
*dev
)
73 /* called by @dev's device_finalize() */
74 NamedClockList
*ncl
, *ncl_next
;
76 QLIST_FOREACH_SAFE(ncl
, &dev
->clocks
, node
, ncl_next
) {
77 QLIST_REMOVE(ncl
, node
);
78 if (!ncl
->output
&& !ncl
->alias
) {
80 * We kept a reference on the input clock to ensure it lives up to
81 * this point so we can safely remove the callback.
82 * It avoids having a callback to a deleted object if ncl->clock
83 * is still referenced somewhere else (eg: by a clock output).
85 clock_clear_callback(ncl
->clock
);
86 object_unref(OBJECT(ncl
->clock
));
93 Clock
*qdev_init_clock_out(DeviceState
*dev
, const char *name
)
99 ncl
= qdev_init_clocklist(dev
, name
, true, NULL
);
104 Clock
*qdev_init_clock_in(DeviceState
*dev
, const char *name
,
105 ClockCallback
*callback
, void *opaque
)
111 ncl
= qdev_init_clocklist(dev
, name
, false, NULL
);
114 clock_set_callback(ncl
->clock
, callback
, opaque
);
119 void qdev_init_clocks(DeviceState
*dev
, const ClockPortInitArray clocks
)
121 const struct ClockPortInitElem
*elem
;
123 for (elem
= &clocks
[0]; elem
->name
!= NULL
; elem
++) {
125 /* offset cannot be inside the DeviceState part */
126 assert(elem
->offset
> sizeof(DeviceState
));
127 clkp
= (Clock
**)(((void *) dev
) + elem
->offset
);
128 if (elem
->is_output
) {
129 *clkp
= qdev_init_clock_out(dev
, elem
->name
);
131 *clkp
= qdev_init_clock_in(dev
, elem
->name
, elem
->callback
, dev
);
136 static NamedClockList
*qdev_get_clocklist(DeviceState
*dev
, const char *name
)
140 QLIST_FOREACH(ncl
, &dev
->clocks
, node
) {
141 if (strcmp(name
, ncl
->name
) == 0) {
149 Clock
*qdev_get_clock_in(DeviceState
*dev
, const char *name
)
155 ncl
= qdev_get_clocklist(dev
, name
);
156 assert(!ncl
->output
);
161 Clock
*qdev_get_clock_out(DeviceState
*dev
, const char *name
)
167 ncl
= qdev_get_clocklist(dev
, name
);
173 Clock
*qdev_alias_clock(DeviceState
*dev
, const char *name
,
174 DeviceState
*alias_dev
, const char *alias_name
)
178 assert(name
&& alias_name
);
180 ncl
= qdev_get_clocklist(dev
, name
);
182 qdev_init_clocklist(alias_dev
, alias_name
, ncl
->output
, ncl
->clock
);