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 "qemu/error-report.h"
16 #include "hw/qdev-clock.h"
17 #include "hw/qdev-core.h"
18 #include "qapi/error.h"
21 * qdev_init_clocklist:
22 * Add a new clock in a device
24 static NamedClockList
*qdev_init_clocklist(DeviceState
*dev
, const char *name
,
25 bool output
, Clock
*clk
)
30 * Clock must be added before realize() so that we can compute the
31 * clock's canonical path during device_realize().
33 assert(!dev
->realized
);
36 * The ncl structure is freed by qdev_finalize_clocklist() which will
37 * be called during @dev's device_finalize().
39 ncl
= g_new0(NamedClockList
, 1);
40 ncl
->name
= g_strdup(name
);
42 ncl
->alias
= (clk
!= NULL
);
45 * Trying to create a clock whose name clashes with some other
46 * clock or property is a bug in the caller and we will abort().
49 clk
= CLOCK(object_new(TYPE_CLOCK
));
50 object_property_add_child(OBJECT(dev
), name
, OBJECT(clk
));
53 * Remove object_new()'s initial reference.
54 * Note that for inputs, the reference created by object_new()
55 * will be deleted in qdev_finalize_clocklist().
57 object_unref(OBJECT(clk
));
60 object_property_add_link(OBJECT(dev
), name
,
61 object_get_typename(OBJECT(clk
)),
62 (Object
**) &ncl
->clock
,
63 NULL
, OBJ_PROP_LINK_STRONG
);
68 QLIST_INSERT_HEAD(&dev
->clocks
, ncl
, node
);
72 void qdev_finalize_clocklist(DeviceState
*dev
)
74 /* called by @dev's device_finalize() */
75 NamedClockList
*ncl
, *ncl_next
;
77 QLIST_FOREACH_SAFE(ncl
, &dev
->clocks
, node
, ncl_next
) {
78 QLIST_REMOVE(ncl
, node
);
79 if (!ncl
->output
&& !ncl
->alias
) {
81 * We kept a reference on the input clock to ensure it lives up to
82 * this point so we can safely remove the callback.
83 * It avoids having a callback to a deleted object if ncl->clock
84 * is still referenced somewhere else (eg: by a clock output).
86 clock_clear_callback(ncl
->clock
);
87 object_unref(OBJECT(ncl
->clock
));
94 Clock
*qdev_init_clock_out(DeviceState
*dev
, const char *name
)
100 ncl
= qdev_init_clocklist(dev
, name
, true, NULL
);
105 Clock
*qdev_init_clock_in(DeviceState
*dev
, const char *name
,
106 ClockCallback
*callback
, void *opaque
)
112 ncl
= qdev_init_clocklist(dev
, name
, false, NULL
);
115 clock_set_callback(ncl
->clock
, callback
, opaque
);
120 void qdev_init_clocks(DeviceState
*dev
, const ClockPortInitArray clocks
)
122 const struct ClockPortInitElem
*elem
;
124 for (elem
= &clocks
[0]; elem
->name
!= NULL
; elem
++) {
126 /* offset cannot be inside the DeviceState part */
127 assert(elem
->offset
> sizeof(DeviceState
));
128 clkp
= (Clock
**)(((void *) dev
) + elem
->offset
);
129 if (elem
->is_output
) {
130 *clkp
= qdev_init_clock_out(dev
, elem
->name
);
132 *clkp
= qdev_init_clock_in(dev
, elem
->name
, elem
->callback
, dev
);
137 static NamedClockList
*qdev_get_clocklist(DeviceState
*dev
, const char *name
)
141 QLIST_FOREACH(ncl
, &dev
->clocks
, node
) {
142 if (strcmp(name
, ncl
->name
) == 0) {
150 Clock
*qdev_get_clock_in(DeviceState
*dev
, const char *name
)
156 ncl
= qdev_get_clocklist(dev
, name
);
158 error_report("Can not find clock-in '%s' for device type '%s'",
159 name
, object_get_typename(OBJECT(dev
)));
162 assert(!ncl
->output
);
167 Clock
*qdev_get_clock_out(DeviceState
*dev
, const char *name
)
173 ncl
= qdev_get_clocklist(dev
, name
);
175 error_report("Can not find clock-out '%s' for device type '%s'",
176 name
, object_get_typename(OBJECT(dev
)));
184 Clock
*qdev_alias_clock(DeviceState
*dev
, const char *name
,
185 DeviceState
*alias_dev
, const char *alias_name
)
189 assert(name
&& alias_name
);
191 ncl
= qdev_get_clocklist(dev
, name
);
193 qdev_init_clocklist(alias_dev
, alias_name
, ncl
->output
, ncl
->clock
);
198 void qdev_connect_clock_in(DeviceState
*dev
, const char *name
, Clock
*source
)
200 assert(!dev
->realized
);
201 clock_set_source(qdev_get_clock_in(dev
, name
), source
);