new file mode 100644
@@ -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.
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