summaryrefslogtreecommitdiffstats
path: root/docs/devel/clocks.rst
blob: e5da28e2111c0e3cb1f18452bac4abc1b6a283d2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
Modelling a clock tree in QEMU
==============================

What are clocks?
----------------

Clocks are QOM objects developed for the purpose of modelling the
distribution of clocks in QEMU.

They allow us to model the clock distribution of a platform and detect
configuration errors in the clock tree such as badly configured PLL, clock
source selection or disabled clock.

The object is *Clock* and its QOM name is ``clock`` (in C code, the macro
``TYPE_CLOCK``).

Clocks are typically used with devices where they are used to model inputs
and outputs. They are created in a similar way to GPIOs. Inputs and outputs
of different devices can be connected together.

In these cases a Clock object is a child of a Device object, but this
is not a requirement. Clocks can be independent of devices. For
example it is possible to create a clock outside of any device to
model the main clock source of a machine.

Here is an example of clocks::

    +---------+      +----------------------+   +--------------+
    | Clock 1 |      |       Device B       |   |   Device C   |
    |         |      | +-------+  +-------+ |   | +-------+    |
    |         |>>-+-->>|Clock 2|  |Clock 3|>>--->>|Clock 6|    |
    +---------+   |  | | (in)  |  | (out) | |   | | (in)  |    |
                  |  | +-------+  +-------+ |   | +-------+    |
                  |  |            +-------+ |   +--------------+
                  |  |            |Clock 4|>>
                  |  |            | (out) | |   +--------------+
                  |  |            +-------+ |   |   Device D   |
                  |  |            +-------+ |   | +-------+    |
                  |  |            |Clock 5|>>--->>|Clock 7|    |
                  |  |            | (out) | |   | | (in)  |    |
                  |  |            +-------+ |   | +-------+    |
                  |  +----------------------+   |              |
                  |                             | +-------+    |
                  +----------------------------->>|Clock 8|    |
                                                | | (in)  |    |
                                                | +-------+    |
                                                +--------------+

Clocks are defined in the ``include/hw/clock.h`` header and device
related functions are defined in the ``include/hw/qdev-clock.h``
header.

The clock state
---------------

The state of a clock is its period; it is stored as an integer
representing it in units of 2 :sup:`-32` ns. The special value of 0 is used to
represent the clock being inactive or gated. The clocks do not model
the signal itself (pin toggling) or other properties such as the duty
cycle.

All clocks contain this state: outputs as well as inputs. This allows
the current period of a clock to be fetched at any time. When a clock
is updated, the value is immediately propagated to all connected
clocks in the tree.

To ease interaction with clocks, helpers with a unit suffix are defined for
every clock state setter or getter. The suffixes are:

- ``_ns`` for handling periods in nanoseconds
- ``_hz`` for handling frequencies in hertz

The 0 period value is converted to 0 in hertz and vice versa. 0 always means
that the clock is disabled.

Adding a new clock
------------------

Adding clocks to a device must be done during the init method of the Device
instance.

To add an input clock to a device, the function ``qdev_init_clock_in()``
must be used.  It takes the name, a callback and an opaque parameter
for the callback (this will be explained in a following section).
Output is simpler; only the name is required. Typically::

    qdev_init_clock_in(DEVICE(dev), "clk_in", clk_in_callback, dev);
    qdev_init_clock_out(DEVICE(dev), "clk_out");

Both functions return the created Clock pointer, which should be saved in the
device's state structure for further use.

These objects will be automatically deleted by the QOM reference mechanism.

Note that it is possible to create a static array describing clock inputs and
outputs. The function ``qdev_init_clocks()`` must be called with the array as
parameter to initialize the clocks: it has the same behaviour as calling the
``qdev_init_clock_in/out()`` for each clock in the array. To ease the array
construction, some macros are defined in ``include/hw/qdev-clock.h``.
As an example, the following creates 2 clocks to a device: one input and one
output.

.. code-block:: c

    /* device structure containing pointers to the clock objects */
    typedef struct MyDeviceState {
        DeviceState parent_obj;
        Clock *clk_in;
        Clock *clk_out;
    } MyDeviceState;

    /*
     * callback for the input clock (see "Callback on input clock
     * change" section below for more information).
     */
    static void clk_in_callback(void *opaque);

    /*
     * static array describing clocks:
     * + a clock input named "clk_in", whose pointer is stored in
     *   the clk_in field of a MyDeviceState structure with callback
     *   clk_in_callback.
     * + a clock output named "clk_out" whose pointer is stored in
     *   the clk_out field of a MyDeviceState structure.
     */
    static const ClockPortInitArray mydev_clocks = {
        QDEV_CLOCK_IN(MyDeviceState, clk_in, clk_in_callback),
        QDEV_CLOCK_OUT(MyDeviceState, clk_out),
        QDEV_CLOCK_END
    };

    /* device initialization function */
    static void mydev_init(Object *obj)
    {
        /* cast to MyDeviceState */
        MyDeviceState *mydev = MYDEVICE(obj);
        /* create and fill the pointer fields in the MyDeviceState */
        qdev_init_clocks(mydev, mydev_clocks);
        [...]
    }

An alternative way to create a clock is to simply call
``object_new(TYPE_CLOCK)``. In that case the clock will neither be an
input nor an output of a device. After the whole QOM hierarchy of the
clock has been set ``clock_setup_canonical_path()`` should be called.

At creation, the period of the clock is 0: the clock is disabled. You can
change it using ``clock_set_ns()`` or ``clock_set_hz()``.

Note that if you are creating a clock with a fixed period which will never
change (for example the main clock source of a board), then you'll have
nothing else to do. This value will be propagated to other clocks when
connecting the clocks together and devices will fetch the right value during
the first reset.

Retrieving clocks from a device
-------------------------------

``qdev_get_clock_in()`` and ``dev_get_clock_out()`` are available to
get the clock inputs or outputs of a device. For example:

.. code-block:: c

   Clock *clk = qdev_get_clock_in(DEVICE(mydev), "clk_in");

or:

.. code-block:: c

   Clock *clk = qdev_get_clock_out(DEVICE(mydev), "clk_out");

Connecting two clocks together
------------------------------

To connect two clocks together, use the ``clock_set_source()`` function.
Given two clocks ``clk1``, and ``clk2``, ``clock_set_source(clk2, clk1);``
configures ``clk2`` to follow the ``clk1`` period changes. Every time ``clk1``
is updated, ``clk2`` will be updated too.

When connecting clock between devices, prefer using the
``qdev_connect_clock_in()`` function to set the source of an input
device clock.  For example, to connect the input clock ``clk2`` of
``devB`` to the output clock ``clk1`` of ``devA``, do:

.. code-block:: c

    qdev_connect_clock_in(devB, "clk2", qdev_get_clock_out(devA, "clk1"))

We used ``qdev_get_clock_out()`` above, but any clock can drive an
input clock, even another input clock. The following diagram shows
some examples of connections. Note also that a clock can drive several
other clocks.

::

  +------------+  +--------------------------------------------------+
  |  Device A  |  |                   Device B                       |
  |            |  |               +---------------------+            |
  |            |  |               |       Device C      |            |
  |  +-------+ |  | +-------+     | +-------+ +-------+ |  +-------+ |
  |  |Clock 1|>>-->>|Clock 2|>>+-->>|Clock 3| |Clock 5|>>>>|Clock 6|>>
  |  | (out) | |  | | (in)  |  |  | | (in)  | | (out) | |  | (out) | |
  |  +-------+ |  | +-------+  |  | +-------+ +-------+ |  +-------+ |
  +------------+  |            |  +---------------------+            |
                  |            |                                     |
                  |            |  +--------------+                   |
                  |            |  |   Device D   |                   |
                  |            |  | +-------+    |                   |
                  |            +-->>|Clock 4|    |                   |
                  |               | | (in)  |    |                   |
                  |               | +-------+    |                   |
                  |               +--------------+                   |
                  +--------------------------------------------------+

In the above example, when *Clock 1* is updated by *Device A*, three
clocks get the new clock period value: *Clock 2*, *Clock 3* and *Clock 4*.

It is not possible to disconnect a clock or to change the clock connection
after it is connected.

Unconnected input clocks
------------------------

A newly created input clock is disabled (period of 0). This means the
clock will be considered as disabled until the period is updated. If
the clock remains unconnected it will always keep its initial value
of 0. If this is not the desired behaviour, ``clock_set()``,
``clock_set_ns()`` or ``clock_set_hz()`` should be called on the Clock
object during device instance init. For example:

.. code-block:: c

    clk = qdev_init_clock_in(DEVICE(dev), "clk-in", clk_in_callback,
                             dev);
    /* set initial value to 10ns / 100MHz */
    clock_set_ns(clk, 10);

Fetching clock frequency/period
-------------------------------

To get the current state of a clock, use the functions ``clock_get()``,
``clock_get_ns()`` or ``clock_get_hz()``.

It is also possible to register a callback on clock frequency changes.
Here is an example:

.. code-block:: c

    void clock_callback(void *opaque) {
        MyDeviceState *s = (MyDeviceState *) opaque;
        /*
         * 'opaque' is the argument passed to qdev_init_clock_in();
         * usually this will be the device state pointer.
         */

        /* do something with the new period */
        fprintf(stdout, "device new period is %" PRIu64 "ns\n",
                        clock_get_ns(dev->my_clk_input));
    }

Changing a clock period
-----------------------

A device can change its outputs using the ``clock_update()``,
``clock_update_ns()`` or ``clock_update_hz()`` function. It will trigger
updates on every connected input.

For example, let's say that we have an output clock *clkout* and we
have a pointer to it in the device state because we did the following
in init phase:

.. code-block:: c

   dev->clkout = qdev_init_clock_out(DEVICE(dev), "clkout");

Then at any time (apart from the cases listed below), it is possible to
change the clock value by doing:

.. code-block:: c

   clock_update_hz(dev->clkout, 1000 * 1000 * 1000); /* 1GHz */

Because updating a clock may trigger any side effects through
connected clocks and their callbacks, this operation must be done
while holding the qemu io lock.

For the same reason, one can update clocks only when it is allowed to have
side effects on other objects. In consequence, it is forbidden:

* during migration,
* and in the enter phase of reset.

Note that calling ``clock_update[_ns|_hz]()`` is equivalent to calling
``clock_set[_ns|_hz]()`` (with the same arguments) then
``clock_propagate()`` on the clock. Thus, setting the clock value can
be separated from triggering the side-effects. This is often required
to factorize code to handle reset and migration in devices.

Aliasing clocks
---------------

Sometimes, one needs to forward, or inherit, a clock from another
device.  Typically, when doing device composition, a device might
expose a sub-device's clock without interfering with it.  The function
``qdev_alias_clock()`` can be used to achieve this behaviour. Note
that it is possible to expose the clock under a different name.
``qdev_alias_clock()`` works for both input and output clocks.

For example, if device B is a child of device A,
``device_a_instance_init()`` may do something like this:

.. code-block:: c

    void device_a_instance_init(Object *obj)
    {
        AState *A = DEVICE_A(obj);
        BState *B;
        /* create object B as child of A */
        [...]
        qdev_alias_clock(B, "clk", A, "b_clk");
        /*
         * Now A has a clock "b_clk" which is an alias to
         * the clock "clk" of its child B.
         */
    }

This function does not return any clock object. The new clock has the
same direction (input or output) as the original one. This function
only adds a link to the existing clock. In the above example, object B
remains the only object allowed to use the clock and device A must not
try to change the clock period or set a callback to the clock. This
diagram describes the example with an input clock::

    +--------------------------+
    |        Device A          |
    |         +--------------+ |
    |         |   Device B   | |
    |         | +-------+    | |
    >>"b_clk">>>| "clk" |    | |
    |  (in)   | |  (in) |    | |
    |         | +-------+    | |
    |         +--------------+ |
    +--------------------------+

Migration
---------

Clock state is not migrated automatically. Every device must handle its
clock migration. Alias clocks must not be migrated.

To ensure clock states are restored correctly during migration, there
are two solutions.

Clock states can be migrated by adding an entry into the device
vmstate description. You should use the ``VMSTATE_CLOCK`` macro for this.
This is typically used to migrate an input clock state. For example:

.. code-block:: c

    MyDeviceState {
        DeviceState parent_obj;
        [...] /* some fields */
        Clock *clk;
    };

    VMStateDescription my_device_vmstate = {
        .name = "my_device",
        .fields = (VMStateField[]) {
            [...], /* other migrated fields */
            VMSTATE_CLOCK(clk, MyDeviceState),
            VMSTATE_END_OF_LIST()
        }
    };

The second solution is to restore the clock state using information already
at our disposal. This can be used to restore output clock states using the
device state. The functions ``clock_set[_ns|_hz]()`` can be used during the
``post_load()`` migration callback.

When adding clock support to an existing device, if you care about
migration compatibility you will need to be careful, as simply adding
a ``VMSTATE_CLOCK()`` line will break compatibility. Instead, you can
put the ``VMSTATE_CLOCK()`` line into a vmstate subsection with a
suitable ``needed`` function, and use ``clock_set()`` in a
``pre_load()`` function to set the default value that will be used if
the source virtual machine in the migration does not send the clock
state.

Care should be taken not to use ``clock_update[_ns|_hz]()`` or
``clock_propagate()`` during the whole migration procedure because it
will trigger side effects to other devices in an unknown state.