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
);
65 * Since the link property has the OBJ_PROP_LINK_STRONG flag, the clk
66 * object reference count gets decremented on property deletion.
67 * However object_property_add_link does not increment it since it
68 * doesn't know the linked object. Increment it here to ensure the
69 * aliased clock stays alive during this device life-time.
71 object_ref(OBJECT(clk
));
76 QLIST_INSERT_HEAD(&dev
->clocks
, ncl
, node
);
80 void qdev_finalize_clocklist(DeviceState
*dev
)
82 /* called by @dev's device_finalize() */
83 NamedClockList
*ncl
, *ncl_next
;
85 QLIST_FOREACH_SAFE(ncl
, &dev
->clocks
, node
, ncl_next
) {
86 QLIST_REMOVE(ncl
, node
);
87 if (!ncl
->output
&& !ncl
->alias
) {
89 * We kept a reference on the input clock to ensure it lives up to
90 * this point so we can safely remove the callback.
91 * It avoids having a callback to a deleted object if ncl->clock
92 * is still referenced somewhere else (eg: by a clock output).
94 clock_clear_callback(ncl
->clock
);
95 object_unref(OBJECT(ncl
->clock
));
102 Clock
*qdev_init_clock_out(DeviceState
*dev
, const char *name
)
108 ncl
= qdev_init_clocklist(dev
, name
, true, NULL
);
113 Clock
*qdev_init_clock_in(DeviceState
*dev
, const char *name
,
114 ClockCallback
*callback
, void *opaque
,
121 ncl
= qdev_init_clocklist(dev
, name
, false, NULL
);
124 clock_set_callback(ncl
->clock
, callback
, opaque
, events
);
129 void qdev_init_clocks(DeviceState
*dev
, const ClockPortInitArray clocks
)
131 const struct ClockPortInitElem
*elem
;
133 for (elem
= &clocks
[0]; elem
->name
!= NULL
; elem
++) {
135 /* offset cannot be inside the DeviceState part */
136 assert(elem
->offset
> sizeof(DeviceState
));
137 clkp
= (Clock
**)(((void *) dev
) + elem
->offset
);
138 if (elem
->is_output
) {
139 *clkp
= qdev_init_clock_out(dev
, elem
->name
);
141 *clkp
= qdev_init_clock_in(dev
, elem
->name
, elem
->callback
, dev
,
142 elem
->callback_events
);
147 static NamedClockList
*qdev_get_clocklist(DeviceState
*dev
, const char *name
)
151 QLIST_FOREACH(ncl
, &dev
->clocks
, node
) {
152 if (strcmp(name
, ncl
->name
) == 0) {
160 Clock
*qdev_get_clock_in(DeviceState
*dev
, const char *name
)
166 ncl
= qdev_get_clocklist(dev
, name
);
168 error_report("Can not find clock-in '%s' for device type '%s'",
169 name
, object_get_typename(OBJECT(dev
)));
172 assert(!ncl
->output
);
177 Clock
*qdev_get_clock_out(DeviceState
*dev
, const char *name
)
183 ncl
= qdev_get_clocklist(dev
, name
);
185 error_report("Can not find clock-out '%s' for device type '%s'",
186 name
, object_get_typename(OBJECT(dev
)));
194 Clock
*qdev_alias_clock(DeviceState
*dev
, const char *name
,
195 DeviceState
*alias_dev
, const char *alias_name
)
199 assert(name
&& alias_name
);
201 ncl
= qdev_get_clocklist(dev
, name
);
203 qdev_init_clocklist(alias_dev
, alias_name
, ncl
->output
, ncl
->clock
);
208 void qdev_connect_clock_in(DeviceState
*dev
, const char *name
, Clock
*source
)
210 assert(!dev
->realized
);
211 clock_set_source(qdev_get_clock_in(dev
, name
), source
);