diff mbox

[V1,06/10] docs: add qemu-clock documentation

Message ID 1475705464-27130-7-git-send-email-fred.konrad@greensocs.com (mailing list archive)
State New, archived
Headers show

Commit Message

KONRAD Frédéric Oct. 5, 2016, 10:11 p.m. UTC
From: KONRAD Frederic <fred.konrad@greensocs.com>

This adds the qemu-clock documentation.

Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
---
 docs/clock.txt | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 109 insertions(+)
 create mode 100644 docs/clock.txt

Comments

Peter Maydell Oct. 17, 2016, 6:31 p.m. UTC | #1
On 5 October 2016 at 23:11,  <fred.konrad@greensocs.com> wrote:
> From: KONRAD Frederic <fred.konrad@greensocs.com>
>
> This adds the qemu-clock documentation.
>
> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
> ---
>  docs/clock.txt | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 109 insertions(+)
>  create mode 100644 docs/clock.txt
>
> diff --git a/docs/clock.txt b/docs/clock.txt
> new file mode 100644
> index 0000000..b25c5ab
> --- /dev/null
> +++ b/docs/clock.txt
> @@ -0,0 +1,109 @@
> +
> +What is a QEMU_CLOCK
> +====================
> +
> +A QEMU_CLOCK is a QOM Object developed for the purpose of modeling a clock tree
> +with QEMU.

This doesn't match the type name you use in the code.

> +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.

So is a QEMU_CLOCK a clock source?
How does this scheme model "I'm a device, and I have a clock
input (ie a clock sink)" ?

> +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.

What's the rate of a clock initially? Do you need to call
qemu_clk_update_rate() during board construction for a
fixed clock (or is it forbidden to call it during board
construction? during device reset?)

Presumably it's a programming error to bind a bunch of clocks
in a loop...

> +
> +Implementing a callback on a rate change
> +========================================
> +
> +The function prototype is the following:
> +typedef uint64_t (*qemu_clk_rate_change_cb)(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, qemu_clk_on_rate_update_cb 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 clock with the
> +    value returned by the callback.
> +
> +NOTE: When no callback is attached, the clock qemu_clk_update_rate(..) is called
> +with the unmodified rate.
> +
> +Attaching a QEMU_CLOCK to a DeviceState
> +=======================================
> +
> +Attaching a qemu-clk to a DeviceState is required to be able to get the clock
> +outside the model through qemu_clk_get_pin(..).
> +
> +It is also required to be able to print the clock and its rate with info qtree.
> +For example:

This seems to be missing a description of how you actually write
a device that has some clocksources.

thanks
-- PMM
KONRAD Frédéric Oct. 18, 2016, 7:03 a.m. UTC | #2
Le 17/10/2016 à 20:31, Peter Maydell a écrit :
> On 5 October 2016 at 23:11,  <fred.konrad@greensocs.com> wrote:
>> From: KONRAD Frederic <fred.konrad@greensocs.com>
>>
>> This adds the qemu-clock documentation.
>>
>> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
>> ---
>>  docs/clock.txt | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 109 insertions(+)
>>  create mode 100644 docs/clock.txt
>>
>> diff --git a/docs/clock.txt b/docs/clock.txt
>> new file mode 100644
>> index 0000000..b25c5ab
>> --- /dev/null
>> +++ b/docs/clock.txt
>> @@ -0,0 +1,109 @@
>> +
>> +What is a QEMU_CLOCK
>> +====================
>> +
>> +A QEMU_CLOCK is a QOM Object developed for the purpose of modeling a clock tree
>> +with QEMU.
>
> This doesn't match the type name you use in the code.
>
>> +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.
>
> So is a QEMU_CLOCK a clock source?
> How does this scheme model "I'm a device, and I have a clock
> input (ie a clock sink)" ?

A qemu-clk is a clock pin. It can be either input or output.

So for a clock source device:

typedef struct {
     DeviceState parent_obj;

     uint32_t rate;
     struct qemu_clk out;
} FixedClock;

out is actually a clock output.

During instance init:

     object_initialize(&s->out, sizeof(s->out), TYPE_CLOCK);
     qemu_clk_attach_to_device(DEVICE(obj), &s->out, "clk_out");

So after that: any device which wants to get the clock pin can do it
like this (fixed is a FixedClock):

     qemu_clk_get_pin(DEVICE(fixed), "clk_out");

Or like this: fixed->out.

For a clock sink device:

typedef struct CRF_APB {
     < ... >
     /* input clocks */
     qemu_clk pss_ref_clk;
     qemu_clk video_clk;
     qemu_clk pss_alt_ref_clk;
     qemu_clk aux_refclk;
     qemu_clk gt_crx_ref_clk;
     < ... >
} CRF_APB;

Those are actually clock input. But this is the same object.

It works the same way for instance init:
     object_initialize(&s->pss_ref_clk,
                       sizeof(s->pss_ref_clk), TYPE_CLOCK);
     qemu_clk_attach_to_device(DEVICE(obj),
                               &s->pss_ref_clk, "pss_ref_clk");

But you might want to register a callback when the rate is updated:
     qemu_clk_set_callback(s->pss_ref_clk, cb, s);

cb will be called when the clock tree is refreshed.
When the callback is called it will take the opaque passed to
qemu_clk_set_callback() and the rate of the previous clock in the chain.
This callback need to return the rate which will be passed to the next
clock in the chain.

So if we connect those two previous models together:

     qemu_clk_bind_clock(qemu_clk_get_pin(DEVICE(s->fixed),
                                          "clk_out"),
                         qemu_clk_get_pin(DEVICE(s->crf),
                                          "pss_ref_clk"));

When the clock source is refreshed for example during realize for
FixedClock:
     qemu_clk_update_rate(&s->out, s->rate);

It will call refresh on all the connected clocks with the rate modified
by it's own callback if there is a callback defined, so here:
     qemu_clk_update_rate(pss_ref_clk, (rate of FixedClock));
As we defined cb as a update_rate callback it will be notified with the
rate of the previous clock.

>
>> +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.
>
> What's the rate of a clock initially? Do you need to call
> qemu_clk_update_rate() during board construction for a
> fixed clock (or is it forbidden to call it during board
> construction? during device reset?)

The rate is initially 0. The clock tree is refreshed from the sources to 
the device. And the fixed-clock model calls qemu_clk_update_rate()
in realize.
>
> Presumably it's a programming error to bind a bunch of clocks
> in a loop...

Yes and connecting a qemu-clock which is actually considered as an
input to an output as well.
>
>> +
>> +Implementing a callback on a rate change
>> +========================================
>> +
>> +The function prototype is the following:
>> +typedef uint64_t (*qemu_clk_rate_change_cb)(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, qemu_clk_on_rate_update_cb 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 clock with the
>> +    value returned by the callback.
>> +
>> +NOTE: When no callback is attached, the clock qemu_clk_update_rate(..) is called
>> +with the unmodified rate.
>> +
>> +Attaching a QEMU_CLOCK to a DeviceState
>> +=======================================
>> +
>> +Attaching a qemu-clk to a DeviceState is required to be able to get the clock
>> +outside the model through qemu_clk_get_pin(..).
>> +
>> +It is also required to be able to print the clock and its rate with info qtree.
>> +For example:
>
> This seems to be missing a description of how you actually write
> a device that has some clocksources.

Yes definitely, I'll add two simple example for that.

Thanks,
Fred

>
> thanks
> -- PMM
>
diff mbox

Patch

diff --git a/docs/clock.txt b/docs/clock.txt
new file mode 100644
index 0000000..b25c5ab
--- /dev/null
+++ b/docs/clock.txt
@@ -0,0 +1,109 @@ 
+
+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 (*qemu_clk_rate_change_cb)(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, qemu_clk_on_rate_update_cb 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 clock with the
+    value returned by the callback.
+
+NOTE: When no callback is attached, the clock qemu_clk_update_rate(..) is called
+with the unmodified rate.
+
+Attaching a QEMU_CLOCK to a DeviceState
+=======================================
+
+Attaching a qemu-clk to a DeviceState is required to be able to get the clock
+outside the model through qemu_clk_get_pin(..).
+
+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.
+