From: fred.konrad@greensocs.com
To: qemu-devel@nongnu.org
Cc: peter.maydell@linaro.org, edgar.iglesias@xilinx.com,
alistair.francis@xilinx.com, clg@kaod.org,
mark.burton@greensocs.com, fred.konrad@greensocs.com
Subject: [Qemu-devel] [PATCH v3 06/10] docs: add qemu-clock documentation
Date: Tue, 28 Feb 2017 11:03:01 +0100 [thread overview]
Message-ID: <1488276185-31168-7-git-send-email-fred.konrad@greensocs.com> (raw)
In-Reply-To: <1488276185-31168-1-git-send-email-fred.konrad@greensocs.com>
From: KONRAD Frederic <fred.konrad@greensocs.com>
This adds the qemu-clock documentation.
Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
V1 -> V2:
* Fixed in accordance with the changes in the previous patches.
---
docs/clock.txt | 278 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 278 insertions(+)
create mode 100644 docs/clock.txt
diff --git a/docs/clock.txt b/docs/clock.txt
new file mode 100644
index 0000000..010ae50
--- /dev/null
+++ b/docs/clock.txt
@@ -0,0 +1,278 @@
+
+What is a QEMU_CLOCK
+====================
+
+A QEMU_CLOCK is a QOM Object developed for the purpose of modeling a clock tree
+with QEMU.
+
+It only simulates the clock by keeping a copy of the current frequency and
+doesn't model the signal itself such as pin toggle or duty cycle.
+
+It allows to model the impact of badly configured PLL, clock source selection
+or disabled clock on the models.
+
+Binding the clock together to create a tree
+===========================================
+
+In order to create a clock tree with QEMU_CLOCK two or more clock must be bound
+together. Let's say there are two clocks clk_a and clk_b:
+Using qemu_clk_bind(clk_a, clk_b) will bind clk_a and clk_b.
+
+Binding two qemu-clk together creates a unidirectional link which means that
+changing the rate of clk_a will propagate to clk_b and not the opposite.
+The binding process automatically refreshes clk_b rate.
+
+Clock can be bound and unbound during execution for modeling eg: a clock
+selector.
+
+A clock can drive more than one other clock. eg with this code:
+qemu_clk_bind(clk_a, clk_b);
+qemu_clk_bind(clk_a, clk_c);
+
+A clock rate change one clk_a will propagate to clk_b and clk_c.
+
+Implementing a callback on a rate change
+========================================
+
+The function prototype is the following:
+typedef uint64_t QEMUClkRateUpdateCallback(void *opaque, uint64_t rate);
+
+It's main goal is to modify the rate before it's passed to the next clocks in
+the tree.
+
+eg: for a 4x PLL the function will be:
+uint64_t qemu_clk_rate_change_cb(void *opaque, uint64_t rate)
+{
+ return 4 * rate;
+}
+
+To set the callback for the clock:
+void qemu_clk_set_callback(qemu_clk clk, QEMUClkRateUpdateCallback *cb,
+ void *opaque);
+can be called.
+
+The rate update process
+=======================
+
+The rate update happen in this way:
+When a model wants to update a clock frequency (eg: based on a register change
+or something similar) it will call qemu_clk_update_rate(..) on the clock:
+ * The callback associated to the clock is called with the new rate.
+ * qemu_clk_update_rate(..) is then called on all bound clocks with the value
+ returned by the callback.
+
+NOTE: When no callback is attached, the clock qemu_clk_update_rate(..) is called
+on the next clock in the tree with the rate unmodified.
+
+Adding a QEMU_CLOCK to a DeviceState
+====================================
+
+Adding a qemu-clk to a DeviceState is required to be able to get the clock
+outside the model through qemu_clk_device_get_clock(..).
+
+It is also required to be able to print the clock and its rate with info qtree.
+For example:
+
+ type System
+ dev: xlnx.zynqmp_crf, id ""
+ gpio-out "sysbus-irq" 1
+ gpio-out "RST_A9" 4
+ qemu-clk "dbg_trace" 0
+ qemu-clk "vpll_to_lpd" 625000000
+ qemu-clk "dp_stc_ref" 0
+ qemu-clk "dpll_to_lpd" 12500000
+ qemu-clk "acpu_clk" 0
+ qemu-clk "pcie_ref" 0
+ qemu-clk "topsw_main" 0
+ qemu-clk "topsw_lsbus" 0
+ qemu-clk "dp_audio_ref" 0
+ qemu-clk "sata_ref" 0
+ qemu-clk "dp_video_ref" 71428568
+ qemu-clk "vpll_clk" 2500000000
+ qemu-clk "apll_to_lpd" 12500000
+ qemu-clk "dpll_clk" 50000000
+ qemu-clk "gpu_ref" 0
+ qemu-clk "aux_refclk" 0
+ qemu-clk "video_clk" 27000000
+ qemu-clk "gdma_ref" 0
+ qemu-clk "gt_crx_ref_clk" 0
+ qemu-clk "dbg_fdp" 0
+ qemu-clk "apll_clk" 50000000
+ qemu-clk "pss_alt_ref_clk" 0
+ qemu-clk "ddr" 0
+ qemu-clk "pss_ref_clk" 50000000
+ qemu-clk "dpdma_ref" 0
+ qemu-clk "dbg_tstmp" 0
+ mmio 00000000fd1a0000/000000000000010c
+
+This way a DeviceState can have multiple clock input or output.
+
+Examples
+========
+
+Those are the different way of using the QEMUClock object.
+
+Modelling a fixed clock generator
+=================================
+
+Here is a brief example of a device acting as a clock source:
+
+typedef struct {
+ DeviceState parent_obj;
+
+ uint32_t rate;
+ QEMUClock out;
+} FixedClock;
+
+During the initialization the device must initialize its clock object:
+
+static void fixed_clock_instance_init(Object *obj)
+{
+ FixedClock *s = FIXED_CLOCK(obj);
+
+ object_initialize(&s->out, sizeof(s->out), TYPE_CLOCK);
+ qemu_clk_device_add_clock(DEVICE(obj), &s->out, "clk_out");
+}
+
+As the device acts as a clock source it must refresh the clock tree during the
+realize phase:
+
+static void fixed_clock_realizefn(DeviceState *dev, Error **errp)
+{
+ FixedClock *s = FIXED_CLOCK(dev);
+
+ qemu_clk_update_rate(&s->out, s->rate);
+}
+
+This means that the clock tree must be finished before realize is called on the
+fixed clock.
+
+Modelling a clock user device
+=============================
+
+Here is a brief example of a clock user:
+
+typedef struct {
+ DeviceState parent_obj;
+
+ QEMUClock in;
+} ClockUser;
+
+As before the clock must be initialized through the device initialize function:
+
+static void clock_user_instance_init(Object *obj)
+{
+ ClockUser *s = CLOCK_USER(obj);
+
+ object_initialize(&s->in, sizeof(s->in), TYPE_CLOCK);
+ qemu_clk_device_add_clock(DEVICE(obj), &s->in, "clk_in");
+ /*
+ * Call on_rate_change_cb when something change on clk_in.
+ */
+ qemu_clk_set_callback(s->in, on_rate_change_cb, obj);
+}
+
+The callback is in this case used as a notifier when the clock tree which
+sources the device change:
+
+static uint64_t on_rate_change_cb(void *opaque, uint64_t input_rate)
+{
+ printf("the new rate is %ld\n", input_rate);
+
+ /* The return is ignored if nothing is bound to clk_in. */
+ return input_rate;
+}
+
+Modelling a clock multiplier
+============================
+
+Here is a brief example of a device acting as a clock modifier:
+
+typedef struct {
+ DeviceState parent_obj;
+
+ uint32_t rate;
+ QEMUClock out;
+ QEMUClock in;
+} ClockMultiplier;
+
+As before the clocks must be initialized through the device initialize function
+but they must be bound together so a change on the input will propagate on the
+output:
+
+static void clock_multiplier_instance_init(Object *obj)
+{
+ ClockMultiplier *s = CLOCK_MULTIPLIER(obj);
+
+ object_initialize(&s->out, sizeof(s->out), TYPE_CLOCK);
+ object_initialize(&s->in, sizeof(s->in), TYPE_CLOCK);
+
+ qemu_clk_device_add_clock(DEVICE(obj), &s->in, "clk_in");
+ qemu_clk_device_add_clock(DEVICE(obj), &s->out, "clk_out");
+ /*
+ * Propagate the change from in to out, this can be done dynamically during
+ * the simulation but we need to do the initial binding here to get the
+ * initial refresh happening when the realize function is called on the
+ * fixed clock.
+ */
+ qemu_clk_bind(s->in, s->out);
+ /*
+ * But before propagating the rate modify it with multiplier_cb.
+ */
+ qemu_clk_set_callback(s->out, multiplier_cb, obj);
+}
+
+In this example when clk_in changes it will trigger a change on clk_out and this
+callback can modify the rate of clk_out (the return value of this callback)
+accordingly to clk_in rate (input_rate).
+
+static uint64_t multiplier_cb(void *opaque, uint64_t input_rate)
+{
+ return input_rate * 4;
+}
+
+This device doesn't refresh the clock tree as it will be done by the clock tree
+source.
+
+Modelling a clock selector
+==========================
+
+Here is a brief example of a device acting as a device which alter the clock
+topology such as a clock selector:
+
+typedef struct {
+ DeviceState parent_obj;
+
+ QEMUClock out;
+ QEMUClock in_a;
+ QEMUClock in_b;
+} ClockSelector;
+
+The clocks must be initialized through the device initialize function but they
+must be bound together like they will be when the device is reset so a change on
+the input during the realize of the fixed clock will propagate to the output:
+
+static void clock_selector_instance_init(Object *obj)
+{
+ ClockSelector *s = CLOCK_SELECTOR(obj);
+
+ object_initialize(&s->out, sizeof(s->out), TYPE_CLOCK);
+ object_initialize(&s->in_a, sizeof(s->in_a), TYPE_CLOCK);
+ object_initialize(&s->in_b, sizeof(s->in_b), TYPE_CLOCK);
+
+ qemu_clk_device_add_clock(DEVICE(obj), &s->in_a, "clk_in_a");
+ qemu_clk_device_add_clock(DEVICE(obj), &s->in_b, "clk_in_b");
+ qemu_clk_device_add_clock(DEVICE(obj), &s->out, "clk_out");
+
+ /* Assuming at the reset that the input_a is connected to output. */
+ qemu_clk_bind(s->in_a, s->out);
+}
+
+/* This is called for example by a register change or something like that */
+void update_topology(ClockSelector *s)
+{
+ /* Unbind the old clock */
+ qemu_clk_unbind(s->in_a, s->out);
+ /* Bind the new one, the rate is automatically refreshed. */
+ qemu_clk_bind(s->in_b, s->out);
+}
--
1.8.3.1
next prev parent reply other threads:[~2017-02-28 10:03 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-02-28 10:02 [Qemu-devel] [PATCH v3 00/10] Clock framework API fred.konrad
2017-02-28 10:02 ` [Qemu-devel] [PATCH v3 01/10] qemu-clk: introduce qemu-clk qom object fred.konrad
2017-02-28 10:02 ` [Qemu-devel] [PATCH v3 02/10] qemu-clk: allow to add a clock to a device fred.konrad
2017-02-28 10:02 ` [Qemu-devel] [PATCH v3 03/10] qemu-clk: allow to bind two clocks together fred.konrad
2017-02-28 10:02 ` [Qemu-devel] [PATCH v3 04/10] qemu-clk: introduce an init array to help the device construction fred.konrad
2017-02-28 10:03 ` [Qemu-devel] [PATCH v3 05/10] qdev-monitor: print the device's clock with info qtree fred.konrad
2017-02-28 10:03 ` fred.konrad [this message]
2017-06-15 15:44 ` [Qemu-devel] [PATCH v3 06/10] docs: add qemu-clock documentation Edgar E. Iglesias
2017-02-28 10:03 ` [Qemu-devel] [PATCH v3 07/10] introduce fixed-clock fred.konrad
2017-02-28 10:03 ` [Qemu-devel] [PATCH v3 08/10] introduce zynqmp_crf fred.konrad
2017-02-28 10:03 ` [Qemu-devel] [PATCH v3 09/10] zynqmp: add the zynqmp_crf to the platform fred.konrad
2017-02-28 10:03 ` [Qemu-devel] [PATCH v3 10/10] zynqmp: add reference clock fred.konrad
2017-05-24 7:35 ` [Qemu-devel] [PATCH v3 00/10] Clock framework API KONRAD Frederic
2017-06-06 15:18 ` Peter Maydell
2017-06-08 7:54 ` KONRAD Frederic
2017-06-13 10:33 ` Peter Maydell
2017-06-14 11:54 ` Paolo Bonzini
2017-06-14 13:10 ` KONRAD Frederic
2017-06-15 14:40 ` Peter Maydell
2017-06-15 14:49 ` Paolo Bonzini
2017-06-15 14:57 ` Edgar E. Iglesias
2017-06-15 15:04 ` Peter Maydell
2017-06-15 15:15 ` Edgar E. Iglesias
2017-06-15 15:38 ` KONRAD Frederic
2017-06-23 9:51 ` Peter Maydell
2017-06-23 12:38 ` KONRAD Frederic
2017-06-23 12:47 ` Peter Maydell
2017-06-23 13:07 ` KONRAD Frederic
2017-06-23 13:58 ` Peter Maydell
2017-06-27 7:04 ` KONRAD Frederic
2017-06-27 9:34 ` Peter Maydell
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=1488276185-31168-7-git-send-email-fred.konrad@greensocs.com \
--to=fred.konrad@greensocs.com \
--cc=alistair.francis@xilinx.com \
--cc=clg@kaod.org \
--cc=edgar.iglesias@xilinx.com \
--cc=mark.burton@greensocs.com \
--cc=peter.maydell@linaro.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).