qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Damien Hedde <damien.hedde@greensocs.com>
To: qemu-devel@nongnu.org
Cc: Damien Hedde <damien.hedde@greensocs.com>,
	peter.maydell@linaro.org, berrange@redhat.com,
	ehabkost@redhat.com, alistair@alistair23.me,
	mark.burton@greensocs.com, pbonzini@redhat.com,
	qemu-arm@nongnu.org, marcandre.lureau@redhat.com,
	edgar.iglesias@gmail.com, philmd@redhat.com
Subject: [Qemu-devel] [PATCH v6 6/9] docs/clocks: add device's clock documentation
Date: Wed,  4 Sep 2019 14:55:28 +0200	[thread overview]
Message-ID: <20190904125531.27545-7-damien.hedde@greensocs.com> (raw)
In-Reply-To: <20190904125531.27545-1-damien.hedde@greensocs.com>

Add the documentation about the clock inputs and outputs in devices.

This is based on the original work of Frederic Konrad.

Signed-off-by: Damien Hedde <damien.hedde@greensocs.com>
---
 docs/devel/clock.txt | 246 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 246 insertions(+)
 create mode 100644 docs/devel/clock.txt

diff --git a/docs/devel/clock.txt b/docs/devel/clock.txt
new file mode 100644
index 0000000000..18f79922d0
--- /dev/null
+++ b/docs/devel/clock.txt
@@ -0,0 +1,246 @@
+
+What are clocks
+===============
+
+Clocks are objects representing input and output clocks of objects. They are
+QOM objects developed for the purpose of modeling the distribution of clocks in
+QEMU.
+
+This allows 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 objects are ClockIn for the input and ClockOut for the output. The QOM
+names are respectively CLOCK_IN and CLOCK_OUT.
+
+CLOCK_IN and CLOCK_OUT are typically child of some device and created in a
+similar way as gpios. ClockIn and ClockOut of different devices can be
+connected together. It is possible to create a clock which is not related
+to a device; for example to model a clock source of a machine.
+
+Here is an example of devices with clocks:
+
+                             +-------------------+     +--------------------+
+                             |      Device B     |     |      Device C      |
+  +--------------------+     |           +-----+ |     | +-----+            |
+  |      Device A      |     |           |Clock|>>----->>|Clock|            |
+  |            +-----+ |     | +-----+   |Out 3| |     | |In  5|            |
+  |            |Clock|>>--+-->>|Clock|   +-----+ |     | +-----+            |
+  |            |Out 1| |  |  | |In 2 |   +-----+ |     | +-----+            |
+  |            +-----+ |  |  | +-----+   |Clock|>>----->>|Clock|            |
+  +--------------------+  |  |           |Out 4| |     | |In  6|            |
+                          |  |           +-----+ |     | +-----+            |
+                          |  +-------------------+     +--------------------+
+                          |
+                          |  +--------------------+
+                          |  |      Device D      |
+                          |  | +-----+            |
+                          +-->>|Clock|            |
+                             | |In  7|            |
+                             | +-----+            |
+                             +--------------------+
+
+Clocks are defined in include/hw/clock.h header and device related functions
+are defined in hw/qdev-clock.h header.
+
+The clock state
+===============
+
+The state of a clock is its frequency; it is stored as an integer representing
+it in Hertz. 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.
+
+Only the CLOCK_IN object keeps the value of a clock; this allows a device to
+fetch the current input frequency at any time. When an output is updated, the
+value is immediately propagated to all connected CLOCK_IN.
+
+Adding clocks to a device
+=========================
+
+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 clock.
+Output is more simple, 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 ClockIn/ClockOut 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: 1 input and 1
+output.
+
+/* device structure containing pointer to the clock objects */
+typedef struct MyDeviceState {
+    DeviceState parent_obj;
+    ClockIn *clk_in;
+    ClockOut *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 clk_in
+ *   field of a MyDeviceState structure with callback clk_in_callback.
+ * + a clock output named "clk_out" whose pointer is stored in 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);
+    [...]
+}
+
+Connecting two clocks together
+==============================
+
+Let's say we have 2 devices A and B. A has an output clock named "clk_out" and
+B has an input clock named "clk_in".
+
+The clocks are connected together using the function qdev_connect_clock:
+qdev_connect_clock(B, "clk_in", A, "clk_out", &error_abort);
+The device which has the input must be the first argument.
+
+It is possible to connect several input clocks to the same output. Every
+input callback will be called when the output changes.
+
+It is not possible to disconnect a clock or to change the clock connection
+after it is done.
+
+Unconnected input clocks
+========================
+
+A newly created input clock has a stored frequency value of 0. It means the
+clock will be considered as disabled until one sets a new frequency to the
+output clock it is connected to. If the clock remains unconnected it will
+always keep its initial value of 0.
+If this is not the wanted behaviour, clock_init_frequency should be called
+on the ClockIn object during device instance init.
+For example:
+clk = qdev_init_clock_in(DEVICE(dev), "clk-in", clk_in_callback, dev);
+clock_init_frequency(clk, 100 * 1000 * 1000); // default value is 100Mhz
+
+Using clock input frequency
+===========================
+
+A device can get the current frequency of an input using the
+clock_get_frequency(). It returns the last set frequency (or the init value).
+
+It is also possible to register a callback on input clock frequency changes.
+Here is an example:
+void clock_callback(void *opaque) {
+    MyDeviceState *s = (MyDeviceState *) opaque;
+    /*
+     * opaque may not be the device state pointer, but most probably it is.
+     * (It depends on what is given to the qdev_init_clock_in function)
+     */
+
+    /* do something with the new frequency */
+    fprintf(stdout, "device new frequency is %" PRIu64 "Hz\n",
+                    clock_get_frequency(dev->my_clk_input));
+}
+
+Changing a clock output
+=======================
+
+A device can change its outputs using the clock_set_frequency function. It
+will trigger updates on every connected inputs.
+
+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:
+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:
+clock_set_frequency(dev->clkout, 1000 * 1000 * 1000); /* 1Ghz */
+This operation must be done while holding the qemu io lock.
+
+One can change clocks only when it is allowed to have side effects on other
+objects. In consequence, it is forbidden:
++ during migration,
++ and in the init phase of reset.
+
+Forwarding 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_pass_clock() can be used to achieve this behaviour. Note, that
+it is possible to expose the clock under a different name. This works for both
+inputs or outputs.
+
+For example, if device B is a child of device A, device_a_instance_init may
+do something like this:
+void device_a_instance_init(Object *obj)
+{
+    AState *A = DEVICE_A(obj);
+    BState *B;
+    /* create B object as child of A */
+    [...]
+    /* forward B's clock to A */
+    qdev_pass_clock(A, "b_clk", B, "clk");
+    /*
+     * Now A has a clock "b_clk" which forwards to
+     * the "clk" of its child B.
+     */
+}
+
+This function does not return any clock object. It is not possible to add
+a callback on a forwarded input clock: in the above example, only B can use
+the clock.
+
+Migration
+=========
+
+Only the ClockIn object has a state. ClockOut is not concerned by migration.
+
+In case the frequency of in input clock is needed for a device's migration,
+this state must be migrated. The VMSTATE_CLOCKIN macro defines an entry to
+be added in a vmstate description.
+
+For example, if a device has a clock input and the device state looks like:
+MyDeviceState {
+    DeviceState parent_obj;
+    ClockIn *clk;
+};
+
+Then, to add the clock frequency to the device's migrated state, the vmstate
+description is:
+VMStateDescription my_device_vmstate = {
+    .name = "my_device",
+    .fields = (VMStateField[]) {
+        VMSTATE_CLOCKIN(clk, MyDeviceState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+When adding a input clock support to an existing device, you must care about
+migration compatibility. To this end, you can use the clock_init_frequency in
+a pre_load function to setup a default value in case the source vm does not
+migrate the frequency.
-- 
2.22.0



  parent reply	other threads:[~2019-09-04 13:16 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-09-04 12:55 [Qemu-devel] [PATCH v6 0/9] Clock framework API Damien Hedde
2019-09-04 12:55 ` [Qemu-devel] [PATCH v6 1/9] hw/core/clock: introduce clock objects Damien Hedde
2019-11-25 13:07   ` Philippe Mathieu-Daudé
2019-11-25 13:37   ` Philippe Mathieu-Daudé
2019-12-03 15:14     ` Damien Hedde
2019-12-02 13:42   ` Peter Maydell
2019-12-03 15:28     ` Damien Hedde
2019-09-04 12:55 ` [Qemu-devel] [PATCH v6 2/9] hw/core/clock-vmstate: define a vmstate entry for clock state Damien Hedde
2019-11-25 13:05   ` Philippe Mathieu-Daudé
2019-12-02 13:44   ` Peter Maydell
2019-09-04 12:55 ` [Qemu-devel] [PATCH v6 3/9] qdev: add clock input&output support to devices Damien Hedde
2019-11-25 13:30   ` Philippe Mathieu-Daudé
2019-12-03 15:35     ` Damien Hedde
2019-12-02 14:34   ` Peter Maydell
2019-12-04  9:05     ` Damien Hedde
2019-12-04  9:53       ` Philippe Mathieu-Daudé
2019-12-04 11:58         ` Damien Hedde
2019-09-04 12:55 ` [Qemu-devel] [PATCH v6 4/9] qdev-monitor: print the device's clock with info qtree Damien Hedde
2019-12-02 14:35   ` Peter Maydell
2019-09-04 12:55 ` [Qemu-devel] [PATCH v6 5/9] qdev-clock: introduce an init array to ease the device construction Damien Hedde
2019-12-02 15:13   ` Peter Maydell
2019-12-04 11:04     ` Damien Hedde
2019-09-04 12:55 ` Damien Hedde [this message]
2019-12-02 15:17   ` [PATCH v6 6/9] docs/clocks: add device's clock documentation Peter Maydell
2019-12-04 12:11     ` Damien Hedde
2019-09-04 12:55 ` [Qemu-devel] [PATCH v6 7/9] hw/misc/zynq_slcr: add clock generation for uarts Damien Hedde
2019-12-02 15:20   ` Peter Maydell
2019-12-04 12:51     ` Damien Hedde
2019-09-04 12:55 ` [Qemu-devel] [PATCH v6 8/9] hw/char/cadence_uart: add clock support Damien Hedde
2019-12-02 15:24   ` Peter Maydell
2019-12-04 13:35     ` Damien Hedde
2019-09-04 12:55 ` [Qemu-devel] [PATCH v6 9/9] hw/arm/xilinx_zynq: connect uart clocks to slcr Damien Hedde
2019-12-02 15:34   ` Peter Maydell
2019-12-03 14:59     ` Damien Hedde
2019-12-03 15:29       ` Philippe Mathieu-Daudé
2019-12-02 16:15 ` [PATCH v6 0/9] Clock framework API Peter Maydell
2019-12-04 16:40   ` Damien Hedde
2019-12-04 20:34     ` Philippe Mathieu-Daudé
2019-12-05  9:36       ` Damien Hedde
2019-12-05  9:59         ` Philippe Mathieu-Daudé
2019-12-05 10:21           ` Dr. David Alan Gilbert
2019-12-05 10:44             ` Philippe Mathieu-Daudé
2019-12-05 10:56               ` Dr. David Alan Gilbert
2019-12-05 11:01                 ` Philippe Mathieu-Daudé
2019-12-06 12:46                   ` Cleber Rosa
2019-12-06 13:48                     ` Dr. David Alan Gilbert
  -- strict thread matches above, loose matches on Subject: below --
2019-09-04  9:38 [Qemu-devel] " damien.hedde
2019-09-04  9:38 ` [Qemu-devel] [PATCH v6 6/9] docs/clocks: add device's clock documentation damien.hedde

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190904125531.27545-7-damien.hedde@greensocs.com \
    --to=damien.hedde@greensocs.com \
    --cc=alistair@alistair23.me \
    --cc=berrange@redhat.com \
    --cc=edgar.iglesias@gmail.com \
    --cc=ehabkost@redhat.com \
    --cc=marcandre.lureau@redhat.com \
    --cc=mark.burton@greensocs.com \
    --cc=pbonzini@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=philmd@redhat.com \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).