All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC PATCH 00/11] Clock framework API.
@ 2016-06-13 16:27 fred.konrad
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 01/11] qemu-clk: introduce qemu-clk qom object fred.konrad
                   ` (11 more replies)
  0 siblings, 12 replies; 38+ messages in thread
From: fred.konrad @ 2016-06-13 16:27 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, edgar.iglesias, alistair.francis, mark.burton,
	fred.konrad

From: KONRAD Frederic <fred.konrad@greensocs.com>

Hi,

This is a first draft of the clock framework API it contains:

  * The first 5 patches which introduce the framework.
  * The 6th patch which introduces a fixed-clock model.
  * The rest which gives an example how to model a PLL from the existing
    zynqmp-crf extracted from the qemu xilinx tree.

No specific behavior is expected yet when the CRF register set is accessed but
the user can see for example the dp_video_ref and vpll_to_lpd rate changing in
the monitor with the "info qtree" command when the vpll_ctrl register is
modified.

bus: main-system-bus
  type System
  dev: xlnx.zynqmp_crf, id ""
    gpio-out "sysbus-irq" 1
    gpio-out "RST_A9" 4
    qemu-clk "dbg_trace" 0.0
    qemu-clk "vpll_to_lpd" 12500000.0
    qemu-clk "dp_stc_ref" 0.0
    qemu-clk "dpll_to_lpd" 12500000.0
    qemu-clk "acpu_clk" 0.0
    qemu-clk "pcie_ref" 0.0
    qemu-clk "topsw_main" 0.0
    qemu-clk "topsw_lsbus" 0.0
    qemu-clk "dp_audio_ref" 0.0
    qemu-clk "sata_ref" 0.0
    qemu-clk "dp_video_ref" 1428571.4
    qemu-clk "vpll_clk" 50000000.0
    qemu-clk "apll_to_lpd" 12500000.0
    qemu-clk "dpll_clk" 50000000.0
    qemu-clk "gpu_ref" 0.0
    qemu-clk "aux_refclk" 0.0
    qemu-clk "video_clk" 27000000.0
    qemu-clk "gdma_ref" 0.0
    qemu-clk "gt_crx_ref_clk" 0.0
    qemu-clk "dbg_fdp" 0.0
    qemu-clk "apll_clk" 50000000.0
    qemu-clk "pss_alt_ref_clk" 0.0
    qemu-clk "ddr" 0.0
    qemu-clk "pss_ref_clk" 50000000.0
    qemu-clk "dpdma_ref" 0.0
    qemu-clk "dbg_tstmp" 0.0
    mmio 00000000fd1a0000/000000000000010c
    
This series is based on the current master
(d6550e9ed2e1a60d889dfb721de00d9a4e3bafbe) with the data-driven register
patch-set from Alistair.

Note that the omap clock infrastructure is really far from what we need so I
think it's worse implement the clock framework and then rework the omaps
platforms to use it.

TODO:
  * reshape the omap clock tree to use this one.

Any comment on that?

Thanks,
Fred

KONRAD Frederic (11):
  qemu-clk: introduce qemu-clk qom object
  qemu-clk: allow to attach a clock to a device
  qemu-clk: allow to bound two clocks together
  qdev-monitor: print the device's clock with info qtree
  docs: add qemu-clock documentation
  introduce fixed-clock
  introduce zynqmp_crf
  zynqmp_crf: fix against AF_EX32 changes
  zynqmp_crf: add the clock mechanism
  zynqmp: add the zynqmp_crf to the platform
  zynqmp: add reference clock

 Makefile.objs                 |   1 +
 docs/clock.txt                | 112 +++++
 hw/arm/xlnx-zynqmp.c          |  49 +++
 hw/misc/Makefile.objs         |   3 +
 hw/misc/fixed-clock.c         |  87 ++++
 hw/misc/xilinx_zynqmp_crf.c   | 972 ++++++++++++++++++++++++++++++++++++++++++
 include/hw/arm/xlnx-zynqmp.h  |   7 +
 include/hw/misc/fixed-clock.h |  30 ++
 include/qemu/qemu-clock.h     | 136 ++++++
 qdev-monitor.c                |   2 +
 qemu-clock.c                  | 153 +++++++
 11 files changed, 1552 insertions(+)
 create mode 100644 docs/clock.txt
 create mode 100644 hw/misc/fixed-clock.c
 create mode 100644 hw/misc/xilinx_zynqmp_crf.c
 create mode 100644 include/hw/misc/fixed-clock.h
 create mode 100644 include/qemu/qemu-clock.h
 create mode 100644 qemu-clock.c

-- 
2.5.5

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [Qemu-devel] [RFC PATCH 01/11] qemu-clk: introduce qemu-clk qom object
  2016-06-13 16:27 [Qemu-devel] [RFC PATCH 00/11] Clock framework API fred.konrad
@ 2016-06-13 16:27 ` fred.konrad
  2016-06-29  0:15   ` Alistair Francis
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 02/11] qemu-clk: allow to attach a clock to a device fred.konrad
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 38+ messages in thread
From: fred.konrad @ 2016-06-13 16:27 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, edgar.iglesias, alistair.francis, mark.burton,
	fred.konrad

From: KONRAD Frederic <fred.konrad@greensocs.com>

This introduces qemu-clk qom object.

Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
---
 Makefile.objs             |  1 +
 include/qemu/qemu-clock.h | 40 ++++++++++++++++++++++++++++++++++++++++
 qemu-clock.c              | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 88 insertions(+)
 create mode 100644 include/qemu/qemu-clock.h
 create mode 100644 qemu-clock.c

diff --git a/Makefile.objs b/Makefile.objs
index 61f4bf4..2284ef5 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -77,6 +77,7 @@ common-obj-y += backends/
 common-obj-$(CONFIG_SECCOMP) += qemu-seccomp.o
 
 common-obj-$(CONFIG_FDT) += device_tree.o
+common-obj-y += qemu-clock.o
 
 ######################################################################
 # qapi
diff --git a/include/qemu/qemu-clock.h b/include/qemu/qemu-clock.h
new file mode 100644
index 0000000..e7acd68
--- /dev/null
+++ b/include/qemu/qemu-clock.h
@@ -0,0 +1,40 @@
+/*
+ * QEMU Clock
+ *
+ *  Copyright (C) 2016 : GreenSocs Ltd
+ *      http://www.greensocs.com/ , email: info@greensocs.com
+ *
+ *  Frederic Konrad <fred.konrad@greensocs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef QEMU_CLOCK_H
+#define QEMU_CLOCK_H
+
+#include "qemu/osdep.h"
+#include "qom/object.h"
+
+#define TYPE_CLOCK "qemu-clk"
+#define QEMU_CLOCK(obj) OBJECT_CHECK(struct qemu_clk, (obj), TYPE_CLOCK)
+
+typedef struct qemu_clk {
+    /*< private >*/
+    Object parent_obj;
+} *qemu_clk;
+
+#endif /* QEMU_CLOCK_H */
+
+
diff --git a/qemu-clock.c b/qemu-clock.c
new file mode 100644
index 0000000..4a47fb4
--- /dev/null
+++ b/qemu-clock.c
@@ -0,0 +1,47 @@
+/*
+ * QEMU Clock
+ *
+ *  Copyright (C) 2016 : GreenSocs Ltd
+ *      http://www.greensocs.com/ , email: info@greensocs.com
+ *
+ *  Frederic Konrad <fred.konrad@greensocs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/qemu-clock.h"
+#include "hw/hw.h"
+
+/* #define DEBUG_QEMU_CLOCK */
+
+#ifdef DEBUG_QEMU_CLOCK
+#define DPRINTF(fmt, ...) \
+do { printf("qemu-clock: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+static const TypeInfo qemu_clk_info = {
+    .name          = TYPE_CLOCK,
+    .parent        = TYPE_OBJECT,
+    .instance_size = sizeof(struct qemu_clk),
+};
+
+static void qemu_clk_register_types(void)
+{
+    type_register_static(&qemu_clk_info);
+}
+
+type_init(qemu_clk_register_types);
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [Qemu-devel] [RFC PATCH 02/11] qemu-clk: allow to attach a clock to a device
  2016-06-13 16:27 [Qemu-devel] [RFC PATCH 00/11] Clock framework API fred.konrad
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 01/11] qemu-clk: introduce qemu-clk qom object fred.konrad
@ 2016-06-13 16:27 ` fred.konrad
  2016-06-29  0:15   ` Alistair Francis
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 03/11] qemu-clk: allow to bound two clocks together fred.konrad
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 38+ messages in thread
From: fred.konrad @ 2016-06-13 16:27 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, edgar.iglesias, alistair.francis, mark.burton,
	fred.konrad

From: KONRAD Frederic <fred.konrad@greensocs.com>

This allows to attach a clock to a DeviceState.
Contrary to gpios, the clock pins are not contained in the DeviceState but
with the child property so they can appears in the qom-tree.

Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
---
 include/qemu/qemu-clock.h | 24 +++++++++++++++++++++++-
 qemu-clock.c              | 22 ++++++++++++++++++++++
 2 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/include/qemu/qemu-clock.h b/include/qemu/qemu-clock.h
index e7acd68..a2ba105 100644
--- a/include/qemu/qemu-clock.h
+++ b/include/qemu/qemu-clock.h
@@ -33,8 +33,30 @@
 typedef struct qemu_clk {
     /*< private >*/
     Object parent_obj;
+    char *name;            /* name of this clock in the device. */
 } *qemu_clk;
 
-#endif /* QEMU_CLOCK_H */
+/**
+ * qemu_clk_attach_to_device:
+ * @d: the device on which the clock need to be attached.
+ * @clk: the clock which need to be attached.
+ * @name: the name of the clock can't be NULL.
+ *
+ * Attach @clk named @name to the device @d.
+ *
+ */
+void qemu_clk_attach_to_device(DeviceState *d, qemu_clk clk,
+                               const char *name);
 
+/**
+ * qemu_clk_get_pin:
+ * @d: the device which contain the clock.
+ * @name: the name of the clock.
+ *
+ * Get the clock named @name located in the device @d, or NULL if not found.
+ *
+ * Returns the clock named @name contained in @d.
+ */
+qemu_clk qemu_clk_get_pin(DeviceState *d, const char *name);
 
+#endif /* QEMU_CLOCK_H */
diff --git a/qemu-clock.c b/qemu-clock.c
index 4a47fb4..81f2852 100644
--- a/qemu-clock.c
+++ b/qemu-clock.c
@@ -23,6 +23,7 @@
 
 #include "qemu/qemu-clock.h"
 #include "hw/hw.h"
+#include "qapi/error.h"
 
 /* #define DEBUG_QEMU_CLOCK */
 
@@ -33,6 +34,27 @@ do { printf("qemu-clock: " fmt , ## __VA_ARGS__); } while (0)
 #define DPRINTF(fmt, ...) do { } while (0)
 #endif
 
+void qemu_clk_attach_to_device(DeviceState *d, qemu_clk clk, const char *name)
+{
+    assert(name);
+    assert(!clk->name);
+    object_property_add_child(OBJECT(d), name, OBJECT(clk), &error_abort);
+    clk->name = g_strdup(name);
+}
+
+qemu_clk qemu_clk_get_pin(DeviceState *d, const char *name)
+{
+    gchar *path = NULL;
+    Object *clk;
+    bool ambiguous;
+
+    path = g_strdup_printf("%s/%s", object_get_canonical_path(OBJECT(d)),
+                           name);
+    clk = object_resolve_path(path, &ambiguous);
+    g_free(path);
+    return QEMU_CLOCK(clk);
+}
+
 static const TypeInfo qemu_clk_info = {
     .name          = TYPE_CLOCK,
     .parent        = TYPE_OBJECT,
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [Qemu-devel] [RFC PATCH 03/11] qemu-clk: allow to bound two clocks together
  2016-06-13 16:27 [Qemu-devel] [RFC PATCH 00/11] Clock framework API fred.konrad
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 01/11] qemu-clk: introduce qemu-clk qom object fred.konrad
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 02/11] qemu-clk: allow to attach a clock to a device fred.konrad
@ 2016-06-13 16:27 ` fred.konrad
  2016-06-29  0:30   ` Alistair Francis
  2016-07-29 13:39   ` Peter Maydell
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 04/11] qdev-monitor: print the device's clock with info qtree fred.konrad
                   ` (8 subsequent siblings)
  11 siblings, 2 replies; 38+ messages in thread
From: fred.konrad @ 2016-06-13 16:27 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, edgar.iglesias, alistair.francis, mark.burton,
	fred.konrad

From: KONRAD Frederic <fred.konrad@greensocs.com>

This introduces the clock binding and the update part.
When the qemu_clk_rate_update(qemu_clk, int) function is called:
  * The clock callback is called on the qemu_clk so it can change the rate.
  * The qemu_clk_rate_update function is called on all the driven clock.

Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
---
 include/qemu/qemu-clock.h | 65 +++++++++++++++++++++++++++++++++++++++++++++++
 qemu-clock.c              | 56 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 121 insertions(+)

diff --git a/include/qemu/qemu-clock.h b/include/qemu/qemu-clock.h
index a2ba105..677de9a 100644
--- a/include/qemu/qemu-clock.h
+++ b/include/qemu/qemu-clock.h
@@ -27,15 +27,29 @@
 #include "qemu/osdep.h"
 #include "qom/object.h"
 
+typedef float (*qemu_clk_on_rate_update_cb)(void *opaque, float rate);
+
 #define TYPE_CLOCK "qemu-clk"
 #define QEMU_CLOCK(obj) OBJECT_CHECK(struct qemu_clk, (obj), TYPE_CLOCK)
 
+typedef struct ClkList ClkList;
+
 typedef struct qemu_clk {
     /*< private >*/
     Object parent_obj;
     char *name;            /* name of this clock in the device. */
+    float in_rate;         /* rate of the clock which drive this pin. */
+    float out_rate;        /* rate of this clock pin. */
+    void *opaque;
+    qemu_clk_on_rate_update_cb cb;
+    QLIST_HEAD(, ClkList) bound;
 } *qemu_clk;
 
+struct ClkList {
+    qemu_clk clk;
+    QLIST_ENTRY(ClkList) node;
+};
+
 /**
  * qemu_clk_attach_to_device:
  * @d: the device on which the clock need to be attached.
@@ -59,4 +73,55 @@ void qemu_clk_attach_to_device(DeviceState *d, qemu_clk clk,
  */
 qemu_clk qemu_clk_get_pin(DeviceState *d, const char *name);
 
+/**
+ * qemu_clk_bound_clock:
+ * @out: the clock output.
+ * @in: the clock input.
+ *
+ * Connect the clock together. This is unidirectionnal so a
+ * qemu_clk_update_rate will go from @out to @in.
+ *
+ */
+void qemu_clk_bound_clock(qemu_clk out, qemu_clk in);
+
+/**
+ * qemu_clk_unbound:
+ * @out: the clock output.
+ * @in: the clock input.
+ *
+ * Disconnect the clock if they were bound together.
+ *
+ */
+void qemu_clk_unbound(qemu_clk out, qemu_clk in);
+
+/**
+ * qemu_clk_update_rate:
+ * @clk: the clock to update.
+ * @rate: the new rate.
+ *
+ * Update the @clk to the new @rate.
+ *
+ */
+void qemu_clk_update_rate(qemu_clk clk, float rate);
+
+/**
+ * qemu_clk_refresh:
+ * @clk: the clock to be refreshed.
+ *
+ * This updates all childs of a clock without changing its own rate.
+ *
+ */
+void qemu_clk_refresh(qemu_clk clk);
+
+/**
+ * qemu_clk_set_callback:
+ * @clk: the clock where to set the callback.
+ * @cb: the callback to associate to the callback.
+ * @opaque: the opaque data passed to the calback.
+ *
+ */
+void qemu_clk_set_callback(qemu_clk clk,
+                           qemu_clk_on_rate_update_cb cb,
+                           void *opaque);
+
 #endif /* QEMU_CLOCK_H */
diff --git a/qemu-clock.c b/qemu-clock.c
index 81f2852..811d6a0 100644
--- a/qemu-clock.c
+++ b/qemu-clock.c
@@ -34,6 +34,62 @@ do { printf("qemu-clock: " fmt , ## __VA_ARGS__); } while (0)
 #define DPRINTF(fmt, ...) do { } while (0)
 #endif
 
+void qemu_clk_refresh(qemu_clk clk)
+{
+    qemu_clk_update_rate(clk, clk->in_rate);
+}
+
+void qemu_clk_update_rate(qemu_clk clk, float rate)
+{
+    ClkList *child;
+
+    clk->in_rate = rate;
+    clk->out_rate = rate;
+
+    if (clk->cb) {
+        clk->out_rate = clk->cb(clk->opaque, rate);
+    }
+
+    DPRINTF("%s output rate updated to %.1f\n",
+            object_get_canonical_path(OBJECT(clk)),
+            clk->out_rate);
+
+    QLIST_FOREACH(child, &clk->bound, node) {
+        qemu_clk_update_rate(child->clk, clk->out_rate);
+    }
+}
+
+void qemu_clk_bound_clock(qemu_clk out, qemu_clk in)
+{
+    ClkList *child;
+
+    child = g_malloc(sizeof(child));
+    assert(child);
+    child->clk = in;
+    QLIST_INSERT_HEAD(&out->bound, child, node);
+    qemu_clk_update_rate(in, out->out_rate);
+}
+
+void qemu_clk_unbound(qemu_clk out, qemu_clk in)
+{
+    ClkList *child, *next;
+
+    QLIST_FOREACH_SAFE(child, &out->bound, node, next) {
+        if (child->clk == in) {
+            QLIST_REMOVE(child, node);
+            g_free(child);
+        }
+    }
+}
+
+void qemu_clk_set_callback(qemu_clk clk,
+                           qemu_clk_on_rate_update_cb cb,
+                           void *opaque)
+{
+    clk->cb = cb;
+    clk->opaque = opaque;
+}
+
 void qemu_clk_attach_to_device(DeviceState *d, qemu_clk clk, const char *name)
 {
     assert(name);
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [Qemu-devel] [RFC PATCH 04/11] qdev-monitor: print the device's clock with info qtree
  2016-06-13 16:27 [Qemu-devel] [RFC PATCH 00/11] Clock framework API fred.konrad
                   ` (2 preceding siblings ...)
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 03/11] qemu-clk: allow to bound two clocks together fred.konrad
@ 2016-06-13 16:27 ` fred.konrad
  2016-06-29  0:33   ` Alistair Francis
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 05/11] docs: add qemu-clock documentation fred.konrad
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 38+ messages in thread
From: fred.konrad @ 2016-06-13 16:27 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, edgar.iglesias, alistair.francis, mark.burton,
	fred.konrad

From: KONRAD Frederic <fred.konrad@greensocs.com>

This prints the clock attached to a DeviceState when using "info qtree" monitor
command.

Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
---
 include/qemu/qemu-clock.h |  9 +++++++++
 qdev-monitor.c            |  2 ++
 qemu-clock.c              | 28 ++++++++++++++++++++++++++++
 3 files changed, 39 insertions(+)

diff --git a/include/qemu/qemu-clock.h b/include/qemu/qemu-clock.h
index 677de9a..265ec65 100644
--- a/include/qemu/qemu-clock.h
+++ b/include/qemu/qemu-clock.h
@@ -124,4 +124,13 @@ void qemu_clk_set_callback(qemu_clk clk,
                            qemu_clk_on_rate_update_cb cb,
                            void *opaque);
 
+/**
+ * qemu_clk_print:
+ * @dev: the device for which the clock need to be printed.
+ *
+ * Print the clock information for a given device.
+ *
+ */
+void qemu_clk_print(Monitor *mon, DeviceState *dev, int indent);
+
 #endif /* QEMU_CLOCK_H */
diff --git a/qdev-monitor.c b/qdev-monitor.c
index e19617f..d6d1aa4 100644
--- a/qdev-monitor.c
+++ b/qdev-monitor.c
@@ -28,6 +28,7 @@
 #include "qemu/config-file.h"
 #include "qemu/error-report.h"
 #include "qemu/help_option.h"
+#include "qemu/qemu-clock.h"
 
 /*
  * Aliases were a bad idea from the start.  Let's keep them
@@ -684,6 +685,7 @@ static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
                         ngl->num_out);
         }
     }
+    qemu_clk_print(mon, dev, indent);
     class = object_get_class(OBJECT(dev));
     do {
         qdev_print_props(mon, dev, DEVICE_CLASS(class)->props, indent);
diff --git a/qemu-clock.c b/qemu-clock.c
index 811d6a0..378a14d 100644
--- a/qemu-clock.c
+++ b/qemu-clock.c
@@ -24,6 +24,7 @@
 #include "qemu/qemu-clock.h"
 #include "hw/hw.h"
 #include "qapi/error.h"
+#include "monitor/monitor.h"
 
 /* #define DEBUG_QEMU_CLOCK */
 
@@ -111,6 +112,33 @@ qemu_clk qemu_clk_get_pin(DeviceState *d, const char *name)
     return QEMU_CLOCK(clk);
 }
 
+struct print_opaque {
+    Monitor *mon;
+    int indent;
+};
+
+static int qemu_clk_print_rec(Object *obj, void *opaque)
+{
+    qemu_clk clk = (qemu_clk)(object_dynamic_cast(obj, TYPE_CLOCK));
+    struct print_opaque *po = opaque;
+
+    if (clk) {
+        monitor_printf(po->mon, "%*s" "qemu-clk \"%s\" %.1f\n", po->indent,
+                       " ", clk->name, clk->out_rate);
+    }
+
+    return 0;
+}
+
+void qemu_clk_print(Monitor *mon, DeviceState *dev, int indent)
+{
+    struct print_opaque po;
+
+    po.indent = indent;
+    po.mon = mon;
+    object_child_foreach(OBJECT(dev), qemu_clk_print_rec, &po);
+}
+
 static const TypeInfo qemu_clk_info = {
     .name          = TYPE_CLOCK,
     .parent        = TYPE_OBJECT,
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [Qemu-devel] [RFC PATCH 05/11] docs: add qemu-clock documentation
  2016-06-13 16:27 [Qemu-devel] [RFC PATCH 00/11] Clock framework API fred.konrad
                   ` (3 preceding siblings ...)
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 04/11] qdev-monitor: print the device's clock with info qtree fred.konrad
@ 2016-06-13 16:27 ` fred.konrad
  2016-06-29  0:38   ` Alistair Francis
  2016-07-29 13:47   ` Peter Maydell
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 06/11] introduce fixed-clock fred.konrad
                   ` (6 subsequent siblings)
  11 siblings, 2 replies; 38+ messages in thread
From: fred.konrad @ 2016-06-13 16:27 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, edgar.iglesias, alistair.francis, mark.burton,
	fred.konrad

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 | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 112 insertions(+)
 create mode 100644 docs/clock.txt

diff --git a/docs/clock.txt b/docs/clock.txt
new file mode 100644
index 0000000..f4ad4c8
--- /dev/null
+++ b/docs/clock.txt
@@ -0,0 +1,112 @@
+
+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.
+
+Bounding 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_bound(clk_a, clk_b) will bound clk_a and clk_b.
+
+Binding two qemu-clk together is a unidirectional link which means that changing
+the rate of clk_a will propagate to clk_b and not the opposite. The bound
+process automatically refresh 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_bound(clk_a, clk_b);
+qemu_clk_bound(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 float (*qemu_clk_rate_change_cb)(void *opaque, float 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:
+float qemu_clk_rate_change_cb(void *opaque, float rate)
+{
+    return 4.0 * 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.
+
+NOTE: It's not recommended that the clock is driven by more than one clock as it
+would mean that we don't know which clock trigger the callback.
+
+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.0
+    qemu-clk "vpll_to_lpd" 625000000.0
+    qemu-clk "dp_stc_ref" 0.0
+    qemu-clk "dpll_to_lpd" 12500000.0
+    qemu-clk "acpu_clk" 0.0
+    qemu-clk "pcie_ref" 0.0
+    qemu-clk "topsw_main" 0.0
+    qemu-clk "topsw_lsbus" 0.0
+    qemu-clk "dp_audio_ref" 0.0
+    qemu-clk "sata_ref" 0.0
+    qemu-clk "dp_video_ref" 71428568.0
+    qemu-clk "vpll_clk" 2500000000.0
+    qemu-clk "apll_to_lpd" 12500000.0
+    qemu-clk "dpll_clk" 50000000.0
+    qemu-clk "gpu_ref" 0.0
+    qemu-clk "aux_refclk" 0.0
+    qemu-clk "video_clk" 27000000.0
+    qemu-clk "gdma_ref" 0.0
+    qemu-clk "gt_crx_ref_clk" 0.0
+    qemu-clk "dbg_fdp" 0.0
+    qemu-clk "apll_clk" 50000000.0
+    qemu-clk "pss_alt_ref_clk" 0.0
+    qemu-clk "ddr" 0.0
+    qemu-clk "pss_ref_clk" 50000000.0
+    qemu-clk "dpdma_ref" 0.0
+    qemu-clk "dbg_tstmp" 0.0
+    mmio 00000000fd1a0000/000000000000010c
+
+This way a DeviceState can have multiple clock input or output.
+
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [Qemu-devel] [RFC PATCH 06/11] introduce fixed-clock
  2016-06-13 16:27 [Qemu-devel] [RFC PATCH 00/11] Clock framework API fred.konrad
                   ` (4 preceding siblings ...)
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 05/11] docs: add qemu-clock documentation fred.konrad
@ 2016-06-13 16:27 ` fred.konrad
  2016-07-01 23:07   ` Alistair Francis
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 07/11] introduce zynqmp_crf fred.konrad
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 38+ messages in thread
From: fred.konrad @ 2016-06-13 16:27 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, edgar.iglesias, alistair.francis, mark.burton,
	fred.konrad

From: KONRAD Frederic <fred.konrad@greensocs.com>

This is a fixed clock device.
It justs behave as an empty device with a parametrable output rate.

Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
---
 hw/misc/Makefile.objs         |  2 +
 hw/misc/fixed-clock.c         | 87 +++++++++++++++++++++++++++++++++++++++++++
 include/hw/misc/fixed-clock.h | 30 +++++++++++++++
 3 files changed, 119 insertions(+)
 create mode 100644 hw/misc/fixed-clock.c
 create mode 100644 include/hw/misc/fixed-clock.h

diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index e504463..e8b8855 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -52,3 +52,5 @@ obj-$(CONFIG_MIPS_ITU) += mips_itu.o
 obj-$(CONFIG_PVPANIC) += pvpanic.o
 obj-$(CONFIG_EDU) += edu.o
 obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
+
+obj-y += fixed-clock.o
diff --git a/hw/misc/fixed-clock.c b/hw/misc/fixed-clock.c
new file mode 100644
index 0000000..c273a91
--- /dev/null
+++ b/hw/misc/fixed-clock.c
@@ -0,0 +1,87 @@
+/*
+ * Fixed clock
+ *
+ *  Copyright (C) 2016 : GreenSocs Ltd
+ *      http://www.greensocs.com/ , email: info@greensocs.com
+ *
+ *  Frederic Konrad   <fred.konrad@greensocs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev.h"
+#include "hw/misc/fixed-clock.h"
+#include "qemu/qemu-clock.h"
+#include "qapi/error.h"
+
+/* #define DEBUG_FIXED_CLOCK */
+
+#ifdef DEBUG_FIXED_CLOCK
+#define DPRINTF(fmt, ...) \
+do { printf("fixed-clock: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+typedef struct {
+    DeviceState parent_obj;
+
+    uint32_t rate;
+    struct qemu_clk out;
+} FixedClock;
+
+static Property fixed_clock_properties[] = {
+    DEFINE_PROP_UINT32("rate", FixedClock, rate, 0),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void fixed_clock_realizefn(DeviceState *d, Error **errp)
+{
+    FixedClock *s = FIXED_CLOCK(d);
+
+    qemu_clk_update_rate(&s->out, s->rate);
+}
+
+static void fixed_clock_instance_init(Object *obj)
+{
+    FixedClock *s = FIXED_CLOCK(obj);
+
+    object_initialize(&s->out, sizeof(s->out), TYPE_CLOCK);
+    qemu_clk_attach_to_device(DEVICE(obj), &s->out, "clk_out");
+}
+
+static void fixed_clock_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = fixed_clock_realizefn;
+    dc->props = fixed_clock_properties;
+}
+
+static const TypeInfo fixed_clock_info = {
+    .name          = TYPE_FIXED_CLOCK,
+    .parent        = TYPE_DEVICE,
+    .instance_size = sizeof(FixedClock),
+    .instance_init = fixed_clock_instance_init,
+    .class_init    = fixed_clock_class_init,
+};
+
+static void fixed_clock_register_types(void)
+{
+    type_register_static(&fixed_clock_info);
+}
+
+type_init(fixed_clock_register_types);
diff --git a/include/hw/misc/fixed-clock.h b/include/hw/misc/fixed-clock.h
new file mode 100644
index 0000000..1376444
--- /dev/null
+++ b/include/hw/misc/fixed-clock.h
@@ -0,0 +1,30 @@
+/*
+ * Fixed clock
+ *
+ *  Copyright (C) 2016 : GreenSocs Ltd
+ *      http://www.greensocs.com/ , email: info@greensocs.com
+ *
+ *  Frederic Konrad   <fred.konrad@greensocs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef FIXED_CLOCK_H
+#define FIXED_CLOCK_H
+
+#define TYPE_FIXED_CLOCK "fixed-clock"
+#define FIXED_CLOCK(obj) OBJECT_CHECK(FixedClock, (obj), TYPE_FIXED_CLOCK)
+
+#endif /* FIXED_CLOCK_H */
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [Qemu-devel] [RFC PATCH 07/11] introduce zynqmp_crf
  2016-06-13 16:27 [Qemu-devel] [RFC PATCH 00/11] Clock framework API fred.konrad
                   ` (5 preceding siblings ...)
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 06/11] introduce fixed-clock fred.konrad
@ 2016-06-13 16:27 ` fred.konrad
  2016-06-29  0:41   ` Alistair Francis
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 08/11] zynqmp_crf: fix against AF_EX32 changes fred.konrad
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 38+ messages in thread
From: fred.konrad @ 2016-06-13 16:27 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, edgar.iglesias, alistair.francis, mark.burton,
	fred.konrad

From: KONRAD Frederic <fred.konrad@greensocs.com>

This introduce Xilinx zynqmp-crf.
It is extracted from the qemu xilinx tree (02d2f0203dd489ed30d9c8d90c14a52c57332b25) and is used as
an example for the clock framework.
---
 hw/misc/Makefile.objs       |   1 +
 hw/misc/xilinx_zynqmp_crf.c | 532 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 533 insertions(+)
 create mode 100644 hw/misc/xilinx_zynqmp_crf.c

diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index e8b8855..c6e3c7f 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -44,6 +44,7 @@ obj-$(CONFIG_SLAVIO) += slavio_misc.o
 obj-$(CONFIG_ZYNQ) += zynq_slcr.o
 obj-$(CONFIG_ZYNQ) += zynq-xadc.o
 obj-$(CONFIG_ZYNQ) += xlnx-zynqmp-iou-slcr.o
+obj-$(CONFIG_ZYNQ) += xilinx_zynqmp_crf.o
 obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o
 obj-$(CONFIG_MIPS_CPS) += mips_cmgcr.o
 obj-$(CONFIG_MIPS_CPS) += mips_cpc.o
diff --git a/hw/misc/xilinx_zynqmp_crf.c b/hw/misc/xilinx_zynqmp_crf.c
new file mode 100644
index 0000000..b1bf2a6
--- /dev/null
+++ b/hw/misc/xilinx_zynqmp_crf.c
@@ -0,0 +1,532 @@
+/*
+ * QEMU model of the CRF_APB APB control registers for clock controller. The
+ * RST_ctrl_fpd will be added to this as well
+ *
+ * Copyright (c) 2014 Xilinx Inc.
+ *
+ * Autogenerated by xregqemu.py 2014-01-22.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "hw/register.h"
+#include "qemu/bitops.h"
+#include "qemu/log.h"
+
+#ifndef XILINX_CRF_APB_ERR_DEBUG
+#define XILINX_CRF_APB_ERR_DEBUG 0
+#endif
+
+#define TYPE_XILINX_CRF_APB "xlnx.zynqmp_crf"
+
+#define XILINX_CRF_APB(obj) \
+     OBJECT_CHECK(CRF_APB, (obj), TYPE_XILINX_CRF_APB)
+
+REG32(ERR_CTRL, 0x0)
+    FIELD(ERR_CTRL, SLVERR_ENABLE, 1, 0)
+REG32(IR_STATUS, 0x4)
+    FIELD(IR_STATUS, ADDR_DECODE_ERR, 1, 0)
+REG32(IR_MASK, 0x8)
+    FIELD(IR_MASK, ADDR_DECODE_ERR, 1, 0)
+REG32(IR_ENABLE, 0xc)
+    FIELD(IR_ENABLE, ADDR_DECODE_ERR, 1, 0)
+REG32(IR_DISABLE, 0x10)
+    FIELD(IR_DISABLE, ADDR_DECODE_ERR, 1, 0)
+REG32(CRF_ECO, 0x18)
+REG32(APLL_CTRL, 0x20)
+    FIELD(APLL_CTRL, POST_SRC, 3, 24)
+    FIELD(APLL_CTRL, PRE_SRC, 3, 20)
+    FIELD(APLL_CTRL, CLKOUTDIV, 1, 17)
+    FIELD(APLL_CTRL, DIV2, 1, 16)
+    FIELD(APLL_CTRL, FBDIV, 7, 8)
+    FIELD(APLL_CTRL, BYPASS, 1, 3)
+    FIELD(APLL_CTRL, RESET, 1, 0)
+REG32(APLL_CFG, 0x24)
+    FIELD(APLL_CFG, LOCK_DLY, 7, 25)
+    FIELD(APLL_CFG, LOCK_CNT, 10, 13)
+    FIELD(APLL_CFG, LFHF, 2, 10)
+    FIELD(APLL_CFG, CP, 4, 5)
+    FIELD(APLL_CFG, RES, 4, 0)
+REG32(APLL_FRAC_CFG, 0x28)
+    FIELD(APLL_FRAC_CFG, ENABLED, 1, 31)
+    FIELD(APLL_FRAC_CFG, SEED, 3, 22)
+    FIELD(APLL_FRAC_CFG, ALGRTHM, 1, 19)
+    FIELD(APLL_FRAC_CFG, ORDER, 1, 18)
+    FIELD(APLL_FRAC_CFG, DATA, 16, 0)
+REG32(DPLL_CTRL, 0x2c)
+    FIELD(DPLL_CTRL, POST_SRC, 3, 24)
+    FIELD(DPLL_CTRL, PRE_SRC, 3, 20)
+    FIELD(DPLL_CTRL, CLKOUTDIV, 1, 17)
+    FIELD(DPLL_CTRL, DIV2, 1, 16)
+    FIELD(DPLL_CTRL, FBDIV, 7, 8)
+    FIELD(DPLL_CTRL, BYPASS, 1, 3)
+    FIELD(DPLL_CTRL, RESET, 1, 0)
+REG32(DPLL_CFG, 0x30)
+    FIELD(DPLL_CFG, LOCK_DLY, 7, 25)
+    FIELD(DPLL_CFG, LOCK_CNT, 10, 13)
+    FIELD(DPLL_CFG, LFHF, 2, 10)
+    FIELD(DPLL_CFG, CP, 4, 5)
+    FIELD(DPLL_CFG, RES, 4, 0)
+REG32(DPLL_FRAC_CFG, 0x34)
+    FIELD(DPLL_FRAC_CFG, ENABLED, 1, 31)
+    FIELD(DPLL_FRAC_CFG, SEED, 3, 22)
+    FIELD(DPLL_FRAC_CFG, ALGRTHM, 1, 19)
+    FIELD(DPLL_FRAC_CFG, ORDER, 1, 18)
+    FIELD(DPLL_FRAC_CFG, DATA, 16, 0)
+REG32(VPLL_CTRL, 0x38)
+    FIELD(VPLL_CTRL, POST_SRC, 3, 24)
+    FIELD(VPLL_CTRL, PRE_SRC, 3, 20)
+    FIELD(VPLL_CTRL, CLKOUTDIV, 1, 17)
+    FIELD(VPLL_CTRL, DIV2, 1, 16)
+    FIELD(VPLL_CTRL, FBDIV, 7, 8)
+    FIELD(VPLL_CTRL, BYPASS, 1, 3)
+    FIELD(VPLL_CTRL, RESET, 1, 0)
+REG32(VPLL_CFG, 0x3c)
+    FIELD(VPLL_CFG, LOCK_DLY, 7, 25)
+    FIELD(VPLL_CFG, LOCK_CNT, 10, 13)
+    FIELD(VPLL_CFG, LFHF, 2, 10)
+    FIELD(VPLL_CFG, CP, 4, 5)
+    FIELD(VPLL_CFG, RES, 4, 0)
+REG32(VPLL_FRAC_CFG, 0x40)
+    FIELD(VPLL_FRAC_CFG, ENABLED, 1, 31)
+    FIELD(VPLL_FRAC_CFG, SEED, 3, 22)
+    FIELD(VPLL_FRAC_CFG, ALGRTHM, 1, 19)
+    FIELD(VPLL_FRAC_CFG, ORDER, 1, 18)
+    FIELD(VPLL_FRAC_CFG, DATA, 16, 0)
+REG32(PLL_STATUS, 0x44)
+    FIELD(PLL_STATUS, VPLL_STABLE, 1, 5)
+    FIELD(PLL_STATUS, DPLL_STABLE, 1, 4)
+    FIELD(PLL_STATUS, APLL_STABLE, 1, 3)
+    FIELD(PLL_STATUS, VPLL_LOCK, 1, 2)
+    FIELD(PLL_STATUS, DPLL_LOCK, 1, 1)
+    FIELD(PLL_STATUS, APLL_LOCK, 1, 0)
+REG32(APLL_TO_LPD_CTRL, 0x48)
+    FIELD(APLL_TO_LPD_CTRL, DIVISOR0, 6, 8)
+REG32(DPLL_TO_LPD_CTRL, 0x4c)
+    FIELD(DPLL_TO_LPD_CTRL, DIVISOR0, 6, 8)
+REG32(VPLL_TO_LPD_CTRL, 0x50)
+    FIELD(VPLL_TO_LPD_CTRL, DIVISOR0, 6, 8)
+REG32(CPU_A9_CTRL, 0x60)
+    FIELD(CPU_A9_CTRL, A9CLKSTOP, 2, 26)
+    FIELD(CPU_A9_CTRL, CLKACT_HALF, 1, 25)
+    FIELD(CPU_A9_CTRL, CLKACT_FULL, 1, 24)
+    FIELD(CPU_A9_CTRL, DIVISOR0, 6, 8)
+    FIELD(CPU_A9_CTRL, SRCSEL, 3, 0)
+REG32(DBG_TRACE_CTRL, 0x64)
+    FIELD(DBG_TRACE_CTRL, CLKACT, 1, 24)
+    FIELD(DBG_TRACE_CTRL, DIVISOR0, 6, 8)
+    FIELD(DBG_TRACE_CTRL, SRCSEL, 3, 0)
+REG32(DBG_FPD_CTRL, 0x68)
+    FIELD(DBG_FPD_CTRL, CLKACT, 1, 24)
+    FIELD(DBG_FPD_CTRL, DIVISOR0, 6, 8)
+    FIELD(DBG_FPD_CTRL, SRCSEL, 3, 0)
+REG32(DP_VIDEO_REF_CTRL, 0x70)
+    FIELD(DP_VIDEO_REF_CTRL, CLKACT, 1, 24)
+    FIELD(DP_VIDEO_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(DP_VIDEO_REF_CTRL, SRCSEL, 3, 0)
+REG32(DP_AUDIO_REF_CTRL, 0x74)
+    FIELD(DP_AUDIO_REF_CTRL, CLKACT, 1, 24)
+    FIELD(DP_AUDIO_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(DP_AUDIO_REF_CTRL, SRCSEL, 3, 0)
+REG32(DP_LINK_REF_CTRL, 0x78)
+    FIELD(DP_LINK_REF_CTRL, CLKACT, 1, 24)
+    FIELD(DP_LINK_REF_CTRL, DIVISOR1, 6, 16)
+    FIELD(DP_LINK_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(DP_LINK_REF_CTRL, SRCSEL, 3, 0)
+REG32(DP_STC_REF_CTRL, 0x7c)
+    FIELD(DP_STC_REF_CTRL, CLKACT, 1, 24)
+    FIELD(DP_STC_REF_CTRL, DIVISOR1, 6, 16)
+    FIELD(DP_STC_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(DP_STC_REF_CTRL, SRCSEL, 3, 0)
+REG32(DDR_CTRL, 0x80)
+    FIELD(DDR_CTRL, CLKACT, 1, 24)
+    FIELD(DDR_CTRL, DIVISOR0, 6, 8)
+    FIELD(DDR_CTRL, SRCSEL, 3, 0)
+REG32(GPU_REF_CTRL, 0x84)
+    FIELD(GPU_REF_CTRL, PP1_CLKACT, 1, 26)
+    FIELD(GPU_REF_CTRL, PP0_CLKACT, 1, 25)
+    FIELD(GPU_REF_CTRL, CLKACT, 1, 24)
+    FIELD(GPU_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(GPU_REF_CTRL, SRCSEL, 3, 0)
+REG32(AFI0_REF_CTRL, 0x88)
+    FIELD(AFI0_REF_CTRL, CLKACT, 1, 24)
+    FIELD(AFI0_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(AFI0_REF_CTRL, SRCSEL, 3, 0)
+REG32(AFI1_REF_CTRL, 0x8c)
+    FIELD(AFI1_REF_CTRL, CLKACT, 1, 24)
+    FIELD(AFI1_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(AFI1_REF_CTRL, SRCSEL, 3, 0)
+REG32(AFI2_REF_CTRL, 0x90)
+    FIELD(AFI2_REF_CTRL, CLKACT, 1, 24)
+    FIELD(AFI2_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(AFI2_REF_CTRL, SRCSEL, 3, 0)
+REG32(AFI3_REF_CTRL, 0x94)
+    FIELD(AFI3_REF_CTRL, CLKACT, 1, 24)
+    FIELD(AFI3_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(AFI3_REF_CTRL, SRCSEL, 3, 0)
+REG32(AFI4_REF_CTRL, 0x98)
+    FIELD(AFI4_REF_CTRL, CLKACT, 1, 24)
+    FIELD(AFI4_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(AFI4_REF_CTRL, SRCSEL, 3, 0)
+REG32(AFI5_REF_CTRL, 0x9c)
+    FIELD(AFI5_REF_CTRL, CLKACT, 1, 24)
+    FIELD(AFI5_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(AFI5_REF_CTRL, SRCSEL, 3, 0)
+REG32(SATA_REF_CTRL, 0xa0)
+    FIELD(SATA_REF_CTRL, CLKACT, 1, 24)
+    FIELD(SATA_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(SATA_REF_CTRL, SRCSEL, 3, 0)
+REG32(PCIE_REF_CTRL, 0xb4)
+    FIELD(PCIE_REF_CTRL, CLKACT, 1, 24)
+    FIELD(PCIE_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(PCIE_REF_CTRL, SRCSEL, 3, 0)
+REG32(GDMA_REF_CTRL, 0xb8)
+    FIELD(GDMA_REF_CTRL, CLKACT, 1, 24)
+    FIELD(GDMA_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(GDMA_REF_CTRL, SRCSEL, 3, 0)
+REG32(DPDMA_REF_CTRL, 0xbc)
+    FIELD(DPDMA_REF_CTRL, CLKACT, 1, 24)
+    FIELD(DPDMA_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(DPDMA_REF_CTRL, SRCSEL, 3, 0)
+REG32(TOPSW_MAIN_CTRL, 0xc0)
+    FIELD(TOPSW_MAIN_CTRL, CLKACT, 1, 24)
+    FIELD(TOPSW_MAIN_CTRL, DIVISOR0, 6, 8)
+    FIELD(TOPSW_MAIN_CTRL, SRCSEL, 3, 0)
+REG32(TOPSW_LSBUS_CTRL, 0xc4)
+    FIELD(TOPSW_LSBUS_CTRL, CLKACT, 1, 24)
+    FIELD(TOPSW_LSBUS_CTRL, DIVISOR0, 6, 8)
+    FIELD(TOPSW_LSBUS_CTRL, SRCSEL, 3, 0)
+REG32(GTGREF0_REF_CTRL, 0xc8)
+    FIELD(GTGREF0_REF_CTRL, CLKACT, 1, 24)
+    FIELD(GTGREF0_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(GTGREF0_REF_CTRL, SRCSEL, 3, 0)
+REG32(GTGREF1_REF_CTRL, 0xcc)
+    FIELD(GTGREF1_REF_CTRL, CLKACT, 1, 24)
+    FIELD(GTGREF1_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(GTGREF1_REF_CTRL, SRCSEL, 3, 0)
+REG32(DFT300_REF_CTRL, 0xd0)
+    FIELD(DFT300_REF_CTRL, CLKACT, 1, 24)
+    FIELD(DFT300_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(DFT300_REF_CTRL, SRCSEL, 3, 0)
+REG32(DFT270_REF_CTRL, 0xd4)
+    FIELD(DFT270_REF_CTRL, CLKACT, 1, 24)
+    FIELD(DFT270_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(DFT270_REF_CTRL, SRCSEL, 3, 0)
+REG32(DFT250_REF_CTRL, 0xd8)
+    FIELD(DFT250_REF_CTRL, CLKACT, 1, 24)
+    FIELD(DFT250_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(DFT250_REF_CTRL, SRCSEL, 3, 0)
+REG32(DFT125_REF_CTRL, 0xdc)
+    FIELD(DFT125_REF_CTRL, CLKACT, 1, 24)
+    FIELD(DFT125_REF_CTRL, DIVISOR0, 6, 8)
+    FIELD(DFT125_REF_CTRL, SRCSEL, 3, 0)
+
+REG32(RST_FPD_TOP, 0x100)
+    FIELD(RST_FPD_TOP, PCIE_BRDG_RESET, 1, 18)
+    FIELD(RST_FPD_TOP, PCIE_CTRL_RESET, 1, 17)
+    FIELD(RST_FPD_TOP, DP_RESET, 1, 16)
+    FIELD(RST_FPD_TOP, AFI_FM5_RESET, 1, 12)
+    FIELD(RST_FPD_TOP, AFI_FM4_RESET, 1, 11)
+    FIELD(RST_FPD_TOP, AFI_FM3_RESET, 1, 10)
+    FIELD(RST_FPD_TOP, AFI_FM2_RESET, 1, 9)
+    FIELD(RST_FPD_TOP, AFI_FM1_RESET, 1, 8)
+    FIELD(RST_FPD_TOP, AFI_FM0_RESET, 1, 7)
+    FIELD(RST_FPD_TOP, GDMA_RESET, 1, 6)
+    FIELD(RST_FPD_TOP, GPU_PP1_RESET, 1, 5)
+    FIELD(RST_FPD_TOP, GPU_PP0_RESET, 1, 4)
+    FIELD(RST_FPD_TOP, GPU_RESET, 1, 3)
+    FIELD(RST_FPD_TOP, GT_RESET, 1, 2)
+    FIELD(RST_FPD_TOP, SATA_RESET, 1, 1)
+REG32(RST_FPD_APU, 0x104)
+    FIELD(RST_FPD_APU, PERI_RESET, 1, 13)
+    FIELD(RST_FPD_APU, SCU_RESET, 1, 12)
+    FIELD(RST_FPD_APU, CPU1_AWDT_RESET, 1, 9)
+    FIELD(RST_FPD_APU, CPU0_AWDT_RESET, 1, 8)
+    FIELD(RST_FPD_APU, CPU1_CP14_RESET, 1, 5)
+    FIELD(RST_FPD_APU, CPU0_CP14_RESET, 1, 4)
+    FIELD(RST_FPD_APU, CPU3_A9_RESET, 1, 3)
+    FIELD(RST_FPD_APU, CPU2_A9_RESET, 1, 2)
+    FIELD(RST_FPD_APU, CPU1_A9_RESET, 1, 1)
+    FIELD(RST_FPD_APU, CPU0_A9_RESET, 1, 0)
+REG32(RST_DDR_SS, 0x108)
+    FIELD(RST_DDR_SS, DDR_RESET, 1, 3)
+    FIELD(RST_DDR_SS, APM_RESET, 1, 2)
+    FIELD(RST_DDR_SS, QOS_RESET, 1, 1)
+    FIELD(RST_DDR_SS, XMPU_RESET, 1, 0)
+
+#define R_MAX (R_RST_DDR_SS + 1)
+
+typedef struct CRF_APB {
+    SysBusDevice parent_obj;
+    MemoryRegion iomem;
+    qemu_irq irq_ir;
+
+    uint32_t regs[R_MAX];
+    RegisterInfo regs_info[R_MAX];
+} CRF_APB;
+
+static const MemoryRegionOps crf_apb_ops = {
+    .read = register_read_memory_le,
+    .write = register_write_memory_le,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void ir_update_irq(CRF_APB *s)
+{
+    bool pending = s->regs[R_IR_STATUS] & ~s->regs[R_IR_MASK];
+    qemu_set_irq(s->irq_ir, pending);
+}
+
+static void ir_status_postw(RegisterInfo *reg, uint64_t val64)
+{
+    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
+    ir_update_irq(s);
+}
+
+static uint64_t ir_enable_prew(RegisterInfo *reg, uint64_t val64)
+{
+    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
+    uint32_t val = val64;
+
+    s->regs[R_IR_MASK] &= ~val;
+    ir_update_irq(s);
+    return 0;
+}
+
+static uint64_t ir_disable_prew(RegisterInfo *reg, uint64_t val64)
+{
+    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
+    uint32_t val = val64;
+
+    s->regs[R_IR_MASK] |= val;
+    ir_update_irq(s);
+    return 0;
+}
+
+static RegisterAccessInfo crf_apb_regs_info[] = {
+    {   .name = "ERR_CTRL",  .decode.addr = A_ERR_CTRL,
+    },{ .name = "IR_STATUS",  .decode.addr = A_IR_STATUS,
+        .w1c = 0x1,
+        .post_write = ir_status_postw,
+    },{ .name = "IR_MASK",  .decode.addr = A_IR_MASK,
+        .reset = 0x1,
+        .ro = 0x1,
+    },{ .name = "IR_ENABLE",  .decode.addr = A_IR_ENABLE,
+        .pre_write = ir_enable_prew,
+    },{ .name = "IR_DISABLE",  .decode.addr = A_IR_DISABLE,
+        .pre_write = ir_disable_prew,
+    },{ .name = "CRF_ECO",  .decode.addr = A_CRF_ECO,
+    },{ .name = "APLL_CTRL",  .decode.addr = A_APLL_CTRL,
+        .reset = 0x2809,
+        .rsvd = 0xf88c80f6L,
+    },{ .name = "APLL_CFG",  .decode.addr = A_APLL_CFG,
+        .rsvd = 0x1801210,
+    },{ .name = "APLL_FRAC_CFG",  .decode.addr = A_APLL_FRAC_CFG,
+        .rsvd = 0x7e330000,
+    },{ .name = "DPLL_CTRL",  .decode.addr = A_DPLL_CTRL,
+        .reset = 0x2809,
+        .rsvd = 0xf88c80f6L,
+    },{ .name = "DPLL_CFG",  .decode.addr = A_DPLL_CFG,
+        .rsvd = 0x1801210,
+    },{ .name = "DPLL_FRAC_CFG",  .decode.addr = A_DPLL_FRAC_CFG,
+        .rsvd = 0x7e330000,
+    },{ .name = "VPLL_CTRL",  .decode.addr = A_VPLL_CTRL,
+        .reset = 0x2809,
+        .rsvd = 0xf88c80f6L,
+    },{ .name = "VPLL_CFG",  .decode.addr = A_VPLL_CFG,
+        .rsvd = 0x1801210,
+    },{ .name = "VPLL_FRAC_CFG",  .decode.addr = A_VPLL_FRAC_CFG,
+        .rsvd = 0x7e330000,
+    },{ .name = "PLL_STATUS",  .decode.addr = A_PLL_STATUS,
+        .reset = 0x3f,
+        .rsvd = 0xc0,
+        .ro = 0x3f,
+    },{ .name = "APLL_TO_LPD_CTRL",  .decode.addr = A_APLL_TO_LPD_CTRL,
+        .reset = 0x400,
+        .rsvd = 0xc0ff,
+    },{ .name = "DPLL_TO_LPD_CTRL",  .decode.addr = A_DPLL_TO_LPD_CTRL,
+        .reset = 0x400,
+        .rsvd = 0xc0ff,
+    },{ .name = "VPLL_TO_LPD_CTRL",  .decode.addr = A_VPLL_TO_LPD_CTRL,
+        .reset = 0x400,
+        .rsvd = 0xc0ff,
+    },{ .name = "CPU_A9_CTRL",  .decode.addr = A_CPU_A9_CTRL,
+        .reset = 0xf000400,
+        .rsvd = 0xf0ffc0f8L,
+    },{ .name = "DBG_TRACE_CTRL",  .decode.addr = A_DBG_TRACE_CTRL,
+        .reset = 0x2500,
+        .rsvd = 0xfeffc0f8L,
+    },{ .name = "DBG_FPD_CTRL",  .decode.addr = A_DBG_FPD_CTRL,
+        .reset = 0x1002500,
+        .rsvd = 0xfeffc0f8L,
+    },{ .name = "DP_VIDEO_REF_CTRL",  .decode.addr = A_DP_VIDEO_REF_CTRL,
+        .reset = 0x1002300,
+        .rsvd = 0xfeffc0f8L,
+    },{ .name = "DP_AUDIO_REF_CTRL",  .decode.addr = A_DP_AUDIO_REF_CTRL,
+        .reset = 0x1002300,
+        .rsvd = 0xfeffc0f8L,
+    },{ .name = "DP_LINK_REF_CTRL",  .decode.addr = A_DP_LINK_REF_CTRL,
+        .reset = 0x1203200,
+        .rsvd = 0xfec0c0f8L,
+    },{ .name = "DP_STC_REF_CTRL",  .decode.addr = A_DP_STC_REF_CTRL,
+        .reset = 0x1203200,
+        .rsvd = 0xfec0c0f8L,
+    },{ .name = "DDR_CTRL",  .decode.addr = A_DDR_CTRL,
+        .reset = 0x1000500,
+        .rsvd = 0xfeffc0f8L,
+    },{ .name = "GPU_REF_CTRL",  .decode.addr = A_GPU_REF_CTRL,
+        .reset = 0x1500,
+        .rsvd = 0xf8ffc0f8L,
+    },{ .name = "AFI0_REF_CTRL",  .decode.addr = A_AFI0_REF_CTRL,
+        .reset = 0x600,
+        .rsvd = 0x7effc0f8,
+    },{ .name = "AFI1_REF_CTRL",  .decode.addr = A_AFI1_REF_CTRL,
+        .reset = 0x600,
+        .rsvd = 0x7effc0f8,
+    },{ .name = "AFI2_REF_CTRL",  .decode.addr = A_AFI2_REF_CTRL,
+        .reset = 0x600,
+        .rsvd = 0x7effc0f8,
+    },{ .name = "AFI3_REF_CTRL",  .decode.addr = A_AFI3_REF_CTRL,
+        .reset = 0x600,
+        .rsvd = 0x7effc0f8,
+    },{ .name = "AFI4_REF_CTRL",  .decode.addr = A_AFI4_REF_CTRL,
+        .reset = 0x600,
+        .rsvd = 0x7effc0f8,
+    },{ .name = "AFI5_REF_CTRL",  .decode.addr = A_AFI5_REF_CTRL,
+        .reset = 0x600,
+        .rsvd = 0x7effc0f8,
+    },{ .name = "SATA_REF_CTRL",  .decode.addr = A_SATA_REF_CTRL,
+        .reset = 0x1001600,
+        .rsvd = 0xfeffc0f8L,
+    },{ .name = "PCIE_REF_CTRL",  .decode.addr = A_PCIE_REF_CTRL,
+        .reset = 0x1500,
+        .rsvd = 0xfeffc0f8L,
+    },{ .name = "GDMA_REF_CTRL",  .decode.addr = A_GDMA_REF_CTRL,
+        .reset = 0x1000500,
+        .rsvd = 0xfeffc0f8L,
+    },{ .name = "DPDMA_REF_CTRL",  .decode.addr = A_DPDMA_REF_CTRL,
+        .reset = 0x1000500,
+        .rsvd = 0xfeffc0f8L,
+    },{ .name = "TOPSW_MAIN_CTRL",  .decode.addr = A_TOPSW_MAIN_CTRL,
+        .reset = 0x1000500,
+        .rsvd = 0xfeffc0f8L,
+    },{ .name = "TOPSW_LSBUS_CTRL",  .decode.addr = A_TOPSW_LSBUS_CTRL,
+        .reset = 0x1000800,
+        .rsvd = 0xfeffc0f8L,
+    },{ .name = "GTGREF0_REF_CTRL",  .decode.addr = A_GTGREF0_REF_CTRL,
+        .reset = 0x800,
+        .rsvd = 0xfeffc0f8L,
+    },{ .name = "GTGREF1_REF_CTRL",  .decode.addr = A_GTGREF1_REF_CTRL,
+        .reset = 0x800,
+        .rsvd = 0xfeffc0f8L,
+    },{ .name = "DFT300_REF_CTRL",  .decode.addr = A_DFT300_REF_CTRL,
+        .reset = 0x800,
+        .rsvd = 0xfeffc0f8L,
+    },{ .name = "DFT270_REF_CTRL",  .decode.addr = A_DFT270_REF_CTRL,
+        .reset = 0x800,
+        .rsvd = 0xfeffc0f8L,
+    },{ .name = "DFT250_REF_CTRL",  .decode.addr = A_DFT250_REF_CTRL,
+        .reset = 0x800,
+        .rsvd = 0xfeffc0f8L,
+    },{ .name = "DFT125_REF_CTRL",  .decode.addr = A_DFT125_REF_CTRL,
+        .reset = 0x800,
+        .rsvd = 0xfeffc0f8L,
+    },{ .name = "RST_FPD_TOP",  .decode.addr = A_RST_FPD_TOP,
+        .reset = 0x71ffe,
+        .rsvd = 0xf8e001,
+    },{ .name = "RST_FPD_APU",  .decode.addr = A_RST_FPD_APU,
+        .reset = 0x334f,
+        .rsvd = 0xffcccc,
+        .gpios = (RegisterGPIOMapping[]) {
+            { .name = "RST_A9", .bit_pos = 0, .num = 4 },
+            {},
+        },
+    },{ .name = "RST_DDR_SS",  .decode.addr = A_RST_DDR_SS,
+        .reset = 0xf,
+        .rsvd = 0xf0,
+    }
+};
+
+static void crf_apb_reset(DeviceState *dev)
+{
+    CRF_APB *s = XILINX_CRF_APB(dev);
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
+        register_reset(&s->regs_info[i]);
+    }
+
+    ir_update_irq(s);
+}
+
+static void crf_apb_init(Object *obj)
+{
+    CRF_APB *s = XILINX_CRF_APB(obj);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+
+    memory_region_init(&s->iomem, obj, TYPE_XILINX_CRF_APB, R_MAX * 4);
+    register_init_block32(DEVICE(obj), crf_apb_regs_info,
+                          ARRAY_SIZE(crf_apb_regs_info),
+                          s->regs_info, s->regs, &s->iomem,
+                          &crf_apb_ops,
+                          XILINX_CRF_APB_ERR_DEBUG,
+                          R_RST_DDR_SS);
+    sysbus_init_mmio(sbd, &s->iomem);
+    sysbus_init_irq(sbd, &s->irq_ir);
+}
+
+static const VMStateDescription vmstate_crf_apb = {
+    .name = TYPE_XILINX_CRF_APB,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, CRF_APB, R_MAX),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static void crf_apb_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = crf_apb_reset;
+    dc->vmsd = &vmstate_crf_apb;
+}
+
+static const TypeInfo crf_apb_info = {
+    .name          = TYPE_XILINX_CRF_APB,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(CRF_APB),
+    .class_init    = crf_apb_class_init,
+    .instance_init = crf_apb_init,
+};
+
+static void crf_apb_register_types(void)
+{
+    type_register_static(&crf_apb_info);
+}
+
+type_init(crf_apb_register_types)
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [Qemu-devel] [RFC PATCH 08/11] zynqmp_crf: fix against AF_EX32 changes
  2016-06-13 16:27 [Qemu-devel] [RFC PATCH 00/11] Clock framework API fred.konrad
                   ` (6 preceding siblings ...)
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 07/11] introduce zynqmp_crf fred.konrad
@ 2016-06-13 16:27 ` fred.konrad
  2016-07-29 13:48   ` Peter Maydell
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 09/11] zynqmp_crf: add the clock mechanism fred.konrad
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 38+ messages in thread
From: fred.konrad @ 2016-06-13 16:27 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, edgar.iglesias, alistair.francis, mark.burton,
	fred.konrad

From: KONRAD Frederic <fred.konrad@greensocs.com>

This seems to be due to a difference between the AF_EX32 define.

Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
---
 hw/misc/xilinx_zynqmp_crf.c | 354 ++++++++++++++++++++++----------------------
 1 file changed, 177 insertions(+), 177 deletions(-)

diff --git a/hw/misc/xilinx_zynqmp_crf.c b/hw/misc/xilinx_zynqmp_crf.c
index b1bf2a6..4c670a0 100644
--- a/hw/misc/xilinx_zynqmp_crf.c
+++ b/hw/misc/xilinx_zynqmp_crf.c
@@ -41,236 +41,236 @@
      OBJECT_CHECK(CRF_APB, (obj), TYPE_XILINX_CRF_APB)
 
 REG32(ERR_CTRL, 0x0)
-    FIELD(ERR_CTRL, SLVERR_ENABLE, 1, 0)
+    FIELD(ERR_CTRL, SLVERR_ENABLE, 0, 1)
 REG32(IR_STATUS, 0x4)
-    FIELD(IR_STATUS, ADDR_DECODE_ERR, 1, 0)
+    FIELD(IR_STATUS, ADDR_DECODE_ERR, 0, 1)
 REG32(IR_MASK, 0x8)
-    FIELD(IR_MASK, ADDR_DECODE_ERR, 1, 0)
+    FIELD(IR_MASK, ADDR_DECODE_ERR, 0, 1)
 REG32(IR_ENABLE, 0xc)
-    FIELD(IR_ENABLE, ADDR_DECODE_ERR, 1, 0)
+    FIELD(IR_ENABLE, ADDR_DECODE_ERR, 0, 1)
 REG32(IR_DISABLE, 0x10)
-    FIELD(IR_DISABLE, ADDR_DECODE_ERR, 1, 0)
+    FIELD(IR_DISABLE, ADDR_DECODE_ERR, 0, 1)
 REG32(CRF_ECO, 0x18)
 REG32(APLL_CTRL, 0x20)
-    FIELD(APLL_CTRL, POST_SRC, 3, 24)
-    FIELD(APLL_CTRL, PRE_SRC, 3, 20)
-    FIELD(APLL_CTRL, CLKOUTDIV, 1, 17)
-    FIELD(APLL_CTRL, DIV2, 1, 16)
-    FIELD(APLL_CTRL, FBDIV, 7, 8)
-    FIELD(APLL_CTRL, BYPASS, 1, 3)
-    FIELD(APLL_CTRL, RESET, 1, 0)
+    FIELD(APLL_CTRL, POST_SRC, 24, 3)
+    FIELD(APLL_CTRL, PRE_SRC, 20, 3)
+    FIELD(APLL_CTRL, CLKOUTDIV, 17, 1)
+    FIELD(APLL_CTRL, DIV2, 16, 1)
+    FIELD(APLL_CTRL, FBDIV, 8, 7)
+    FIELD(APLL_CTRL, BYPASS, 3, 1)
+    FIELD(APLL_CTRL, RESET, 0, 1)
 REG32(APLL_CFG, 0x24)
-    FIELD(APLL_CFG, LOCK_DLY, 7, 25)
-    FIELD(APLL_CFG, LOCK_CNT, 10, 13)
-    FIELD(APLL_CFG, LFHF, 2, 10)
-    FIELD(APLL_CFG, CP, 4, 5)
-    FIELD(APLL_CFG, RES, 4, 0)
+    FIELD(APLL_CFG, LOCK_DLY, 25, 7)
+    FIELD(APLL_CFG, LOCK_CNT, 13, 10)
+    FIELD(APLL_CFG, LFHF, 10, 2)
+    FIELD(APLL_CFG, CP, 5, 4)
+    FIELD(APLL_CFG, RES, 0, 4)
 REG32(APLL_FRAC_CFG, 0x28)
-    FIELD(APLL_FRAC_CFG, ENABLED, 1, 31)
-    FIELD(APLL_FRAC_CFG, SEED, 3, 22)
-    FIELD(APLL_FRAC_CFG, ALGRTHM, 1, 19)
-    FIELD(APLL_FRAC_CFG, ORDER, 1, 18)
-    FIELD(APLL_FRAC_CFG, DATA, 16, 0)
+    FIELD(APLL_FRAC_CFG, ENABLED, 31, 1)
+    FIELD(APLL_FRAC_CFG, SEED, 22, 3)
+    FIELD(APLL_FRAC_CFG, ALGRTHM, 19, 1)
+    FIELD(APLL_FRAC_CFG, ORDER, 18, 1)
+    FIELD(APLL_FRAC_CFG, DATA, 0, 16)
 REG32(DPLL_CTRL, 0x2c)
-    FIELD(DPLL_CTRL, POST_SRC, 3, 24)
-    FIELD(DPLL_CTRL, PRE_SRC, 3, 20)
-    FIELD(DPLL_CTRL, CLKOUTDIV, 1, 17)
-    FIELD(DPLL_CTRL, DIV2, 1, 16)
-    FIELD(DPLL_CTRL, FBDIV, 7, 8)
-    FIELD(DPLL_CTRL, BYPASS, 1, 3)
-    FIELD(DPLL_CTRL, RESET, 1, 0)
+    FIELD(DPLL_CTRL, POST_SRC, 24, 3)
+    FIELD(DPLL_CTRL, PRE_SRC, 20, 3)
+    FIELD(DPLL_CTRL, CLKOUTDIV, 17, 1)
+    FIELD(DPLL_CTRL, DIV2, 16, 1)
+    FIELD(DPLL_CTRL, FBDIV, 8, 7)
+    FIELD(DPLL_CTRL, BYPASS, 3, 1)
+    FIELD(DPLL_CTRL, RESET, 0, 1)
 REG32(DPLL_CFG, 0x30)
-    FIELD(DPLL_CFG, LOCK_DLY, 7, 25)
-    FIELD(DPLL_CFG, LOCK_CNT, 10, 13)
-    FIELD(DPLL_CFG, LFHF, 2, 10)
-    FIELD(DPLL_CFG, CP, 4, 5)
-    FIELD(DPLL_CFG, RES, 4, 0)
+    FIELD(DPLL_CFG, LOCK_DLY, 25, 7)
+    FIELD(DPLL_CFG, LOCK_CNT, 13, 10)
+    FIELD(DPLL_CFG, LFHF, 10, 2)
+    FIELD(DPLL_CFG, CP, 5, 4)
+    FIELD(DPLL_CFG, RES, 0, 4)
 REG32(DPLL_FRAC_CFG, 0x34)
-    FIELD(DPLL_FRAC_CFG, ENABLED, 1, 31)
-    FIELD(DPLL_FRAC_CFG, SEED, 3, 22)
-    FIELD(DPLL_FRAC_CFG, ALGRTHM, 1, 19)
-    FIELD(DPLL_FRAC_CFG, ORDER, 1, 18)
-    FIELD(DPLL_FRAC_CFG, DATA, 16, 0)
+    FIELD(DPLL_FRAC_CFG, ENABLED, 31, 1)
+    FIELD(DPLL_FRAC_CFG, SEED, 22, 3)
+    FIELD(DPLL_FRAC_CFG, ALGRTHM, 19, 1)
+    FIELD(DPLL_FRAC_CFG, ORDER, 18, 1)
+    FIELD(DPLL_FRAC_CFG, DATA, 0, 16)
 REG32(VPLL_CTRL, 0x38)
-    FIELD(VPLL_CTRL, POST_SRC, 3, 24)
-    FIELD(VPLL_CTRL, PRE_SRC, 3, 20)
-    FIELD(VPLL_CTRL, CLKOUTDIV, 1, 17)
-    FIELD(VPLL_CTRL, DIV2, 1, 16)
-    FIELD(VPLL_CTRL, FBDIV, 7, 8)
-    FIELD(VPLL_CTRL, BYPASS, 1, 3)
-    FIELD(VPLL_CTRL, RESET, 1, 0)
+    FIELD(VPLL_CTRL, POST_SRC, 24, 3)
+    FIELD(VPLL_CTRL, PRE_SRC, 20, 3)
+    FIELD(VPLL_CTRL, CLKOUTDIV, 17, 1)
+    FIELD(VPLL_CTRL, DIV2, 16, 1)
+    FIELD(VPLL_CTRL, FBDIV, 8, 7)
+    FIELD(VPLL_CTRL, BYPASS, 3, 1)
+    FIELD(VPLL_CTRL, RESET, 0, 1)
 REG32(VPLL_CFG, 0x3c)
-    FIELD(VPLL_CFG, LOCK_DLY, 7, 25)
-    FIELD(VPLL_CFG, LOCK_CNT, 10, 13)
-    FIELD(VPLL_CFG, LFHF, 2, 10)
-    FIELD(VPLL_CFG, CP, 4, 5)
-    FIELD(VPLL_CFG, RES, 4, 0)
+    FIELD(VPLL_CFG, LOCK_DLY, 25, 7)
+    FIELD(VPLL_CFG, LOCK_CNT, 13, 10)
+    FIELD(VPLL_CFG, LFHF, 10, 2)
+    FIELD(VPLL_CFG, CP, 5, 4)
+    FIELD(VPLL_CFG, RES, 0, 4)
 REG32(VPLL_FRAC_CFG, 0x40)
-    FIELD(VPLL_FRAC_CFG, ENABLED, 1, 31)
-    FIELD(VPLL_FRAC_CFG, SEED, 3, 22)
-    FIELD(VPLL_FRAC_CFG, ALGRTHM, 1, 19)
-    FIELD(VPLL_FRAC_CFG, ORDER, 1, 18)
-    FIELD(VPLL_FRAC_CFG, DATA, 16, 0)
+    FIELD(VPLL_FRAC_CFG, ENABLED, 31, 1)
+    FIELD(VPLL_FRAC_CFG, SEED, 22, 3)
+    FIELD(VPLL_FRAC_CFG, ALGRTHM, 19, 1)
+    FIELD(VPLL_FRAC_CFG, ORDER, 18, 1)
+    FIELD(VPLL_FRAC_CFG, DATA, 0, 16)
 REG32(PLL_STATUS, 0x44)
-    FIELD(PLL_STATUS, VPLL_STABLE, 1, 5)
-    FIELD(PLL_STATUS, DPLL_STABLE, 1, 4)
-    FIELD(PLL_STATUS, APLL_STABLE, 1, 3)
-    FIELD(PLL_STATUS, VPLL_LOCK, 1, 2)
+    FIELD(PLL_STATUS, VPLL_STABLE, 5, 1)
+    FIELD(PLL_STATUS, DPLL_STABLE, 4, 1)
+    FIELD(PLL_STATUS, APLL_STABLE, 3, 1)
+    FIELD(PLL_STATUS, VPLL_LOCK, 2, 1)
     FIELD(PLL_STATUS, DPLL_LOCK, 1, 1)
-    FIELD(PLL_STATUS, APLL_LOCK, 1, 0)
+    FIELD(PLL_STATUS, APLL_LOCK, 0, 1)
 REG32(APLL_TO_LPD_CTRL, 0x48)
-    FIELD(APLL_TO_LPD_CTRL, DIVISOR0, 6, 8)
+    FIELD(APLL_TO_LPD_CTRL, DIVISOR0, 8, 6)
 REG32(DPLL_TO_LPD_CTRL, 0x4c)
-    FIELD(DPLL_TO_LPD_CTRL, DIVISOR0, 6, 8)
+    FIELD(DPLL_TO_LPD_CTRL, DIVISOR0, 8, 6)
 REG32(VPLL_TO_LPD_CTRL, 0x50)
-    FIELD(VPLL_TO_LPD_CTRL, DIVISOR0, 6, 8)
+    FIELD(VPLL_TO_LPD_CTRL, DIVISOR0, 8, 6)
 REG32(CPU_A9_CTRL, 0x60)
-    FIELD(CPU_A9_CTRL, A9CLKSTOP, 2, 26)
-    FIELD(CPU_A9_CTRL, CLKACT_HALF, 1, 25)
-    FIELD(CPU_A9_CTRL, CLKACT_FULL, 1, 24)
-    FIELD(CPU_A9_CTRL, DIVISOR0, 6, 8)
-    FIELD(CPU_A9_CTRL, SRCSEL, 3, 0)
+    FIELD(CPU_A9_CTRL, A9CLKSTOP, 26, 2)
+    FIELD(CPU_A9_CTRL, CLKACT_HALF, 25, 1)
+    FIELD(CPU_A9_CTRL, CLKACT_FULL, 24, 1)
+    FIELD(CPU_A9_CTRL, DIVISOR0, 8, 6)
+    FIELD(CPU_A9_CTRL, SRCSEL, 0, 3)
 REG32(DBG_TRACE_CTRL, 0x64)
-    FIELD(DBG_TRACE_CTRL, CLKACT, 1, 24)
-    FIELD(DBG_TRACE_CTRL, DIVISOR0, 6, 8)
-    FIELD(DBG_TRACE_CTRL, SRCSEL, 3, 0)
+    FIELD(DBG_TRACE_CTRL, CLKACT, 24, 1)
+    FIELD(DBG_TRACE_CTRL, DIVISOR0, 8, 6)
+    FIELD(DBG_TRACE_CTRL, SRCSEL, 0, 3)
 REG32(DBG_FPD_CTRL, 0x68)
-    FIELD(DBG_FPD_CTRL, CLKACT, 1, 24)
-    FIELD(DBG_FPD_CTRL, DIVISOR0, 6, 8)
-    FIELD(DBG_FPD_CTRL, SRCSEL, 3, 0)
+    FIELD(DBG_FPD_CTRL, CLKACT, 24, 1)
+    FIELD(DBG_FPD_CTRL, DIVISOR0, 8, 6)
+    FIELD(DBG_FPD_CTRL, SRCSEL, 0, 3)
 REG32(DP_VIDEO_REF_CTRL, 0x70)
-    FIELD(DP_VIDEO_REF_CTRL, CLKACT, 1, 24)
-    FIELD(DP_VIDEO_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(DP_VIDEO_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(DP_VIDEO_REF_CTRL, CLKACT, 24, 1)
+    FIELD(DP_VIDEO_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(DP_VIDEO_REF_CTRL, SRCSEL, 0, 3)
 REG32(DP_AUDIO_REF_CTRL, 0x74)
-    FIELD(DP_AUDIO_REF_CTRL, CLKACT, 1, 24)
-    FIELD(DP_AUDIO_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(DP_AUDIO_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(DP_AUDIO_REF_CTRL, CLKACT, 24, 1)
+    FIELD(DP_AUDIO_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(DP_AUDIO_REF_CTRL, SRCSEL, 0, 3)
 REG32(DP_LINK_REF_CTRL, 0x78)
-    FIELD(DP_LINK_REF_CTRL, CLKACT, 1, 24)
-    FIELD(DP_LINK_REF_CTRL, DIVISOR1, 6, 16)
-    FIELD(DP_LINK_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(DP_LINK_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(DP_LINK_REF_CTRL, CLKACT, 24, 1)
+    FIELD(DP_LINK_REF_CTRL, DIVISOR1, 16, 6)
+    FIELD(DP_LINK_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(DP_LINK_REF_CTRL, SRCSEL, 0, 3)
 REG32(DP_STC_REF_CTRL, 0x7c)
-    FIELD(DP_STC_REF_CTRL, CLKACT, 1, 24)
-    FIELD(DP_STC_REF_CTRL, DIVISOR1, 6, 16)
-    FIELD(DP_STC_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(DP_STC_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(DP_STC_REF_CTRL, CLKACT, 24, 1)
+    FIELD(DP_STC_REF_CTRL, DIVISOR1, 16, 6)
+    FIELD(DP_STC_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(DP_STC_REF_CTRL, SRCSEL, 0, 3)
 REG32(DDR_CTRL, 0x80)
-    FIELD(DDR_CTRL, CLKACT, 1, 24)
-    FIELD(DDR_CTRL, DIVISOR0, 6, 8)
-    FIELD(DDR_CTRL, SRCSEL, 3, 0)
+    FIELD(DDR_CTRL, CLKACT, 24, 1)
+    FIELD(DDR_CTRL, DIVISOR0, 8, 6)
+    FIELD(DDR_CTRL, SRCSEL, 0, 3)
 REG32(GPU_REF_CTRL, 0x84)
-    FIELD(GPU_REF_CTRL, PP1_CLKACT, 1, 26)
-    FIELD(GPU_REF_CTRL, PP0_CLKACT, 1, 25)
-    FIELD(GPU_REF_CTRL, CLKACT, 1, 24)
-    FIELD(GPU_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(GPU_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(GPU_REF_CTRL, PP1_CLKACT, 26, 1)
+    FIELD(GPU_REF_CTRL, PP0_CLKACT, 25, 1)
+    FIELD(GPU_REF_CTRL, CLKACT, 24, 1)
+    FIELD(GPU_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(GPU_REF_CTRL, SRCSEL, 0, 3)
 REG32(AFI0_REF_CTRL, 0x88)
-    FIELD(AFI0_REF_CTRL, CLKACT, 1, 24)
-    FIELD(AFI0_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(AFI0_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(AFI0_REF_CTRL, CLKACT, 24, 1)
+    FIELD(AFI0_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(AFI0_REF_CTRL, SRCSEL, 0, 3)
 REG32(AFI1_REF_CTRL, 0x8c)
-    FIELD(AFI1_REF_CTRL, CLKACT, 1, 24)
-    FIELD(AFI1_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(AFI1_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(AFI1_REF_CTRL, CLKACT, 24, 1)
+    FIELD(AFI1_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(AFI1_REF_CTRL, SRCSEL, 0, 3)
 REG32(AFI2_REF_CTRL, 0x90)
-    FIELD(AFI2_REF_CTRL, CLKACT, 1, 24)
-    FIELD(AFI2_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(AFI2_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(AFI2_REF_CTRL, CLKACT, 24, 1)
+    FIELD(AFI2_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(AFI2_REF_CTRL, SRCSEL, 0, 3)
 REG32(AFI3_REF_CTRL, 0x94)
-    FIELD(AFI3_REF_CTRL, CLKACT, 1, 24)
-    FIELD(AFI3_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(AFI3_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(AFI3_REF_CTRL, CLKACT, 24, 1)
+    FIELD(AFI3_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(AFI3_REF_CTRL, SRCSEL, 0, 3)
 REG32(AFI4_REF_CTRL, 0x98)
-    FIELD(AFI4_REF_CTRL, CLKACT, 1, 24)
-    FIELD(AFI4_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(AFI4_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(AFI4_REF_CTRL, CLKACT, 24, 1)
+    FIELD(AFI4_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(AFI4_REF_CTRL, SRCSEL, 0, 3)
 REG32(AFI5_REF_CTRL, 0x9c)
-    FIELD(AFI5_REF_CTRL, CLKACT, 1, 24)
-    FIELD(AFI5_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(AFI5_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(AFI5_REF_CTRL, CLKACT, 24, 1)
+    FIELD(AFI5_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(AFI5_REF_CTRL, SRCSEL, 0, 3)
 REG32(SATA_REF_CTRL, 0xa0)
-    FIELD(SATA_REF_CTRL, CLKACT, 1, 24)
-    FIELD(SATA_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(SATA_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(SATA_REF_CTRL, CLKACT, 24, 1)
+    FIELD(SATA_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(SATA_REF_CTRL, SRCSEL, 0, 3)
 REG32(PCIE_REF_CTRL, 0xb4)
-    FIELD(PCIE_REF_CTRL, CLKACT, 1, 24)
-    FIELD(PCIE_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(PCIE_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(PCIE_REF_CTRL, CLKACT, 24, 1)
+    FIELD(PCIE_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(PCIE_REF_CTRL, SRCSEL, 0, 3)
 REG32(GDMA_REF_CTRL, 0xb8)
-    FIELD(GDMA_REF_CTRL, CLKACT, 1, 24)
-    FIELD(GDMA_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(GDMA_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(GDMA_REF_CTRL, CLKACT, 24, 1)
+    FIELD(GDMA_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(GDMA_REF_CTRL, SRCSEL, 0, 3)
 REG32(DPDMA_REF_CTRL, 0xbc)
-    FIELD(DPDMA_REF_CTRL, CLKACT, 1, 24)
-    FIELD(DPDMA_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(DPDMA_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(DPDMA_REF_CTRL, CLKACT, 24, 1)
+    FIELD(DPDMA_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(DPDMA_REF_CTRL, SRCSEL, 0, 3)
 REG32(TOPSW_MAIN_CTRL, 0xc0)
-    FIELD(TOPSW_MAIN_CTRL, CLKACT, 1, 24)
-    FIELD(TOPSW_MAIN_CTRL, DIVISOR0, 6, 8)
-    FIELD(TOPSW_MAIN_CTRL, SRCSEL, 3, 0)
+    FIELD(TOPSW_MAIN_CTRL, CLKACT, 24, 1)
+    FIELD(TOPSW_MAIN_CTRL, DIVISOR0, 8, 6)
+    FIELD(TOPSW_MAIN_CTRL, SRCSEL, 0, 3)
 REG32(TOPSW_LSBUS_CTRL, 0xc4)
-    FIELD(TOPSW_LSBUS_CTRL, CLKACT, 1, 24)
-    FIELD(TOPSW_LSBUS_CTRL, DIVISOR0, 6, 8)
-    FIELD(TOPSW_LSBUS_CTRL, SRCSEL, 3, 0)
+    FIELD(TOPSW_LSBUS_CTRL, CLKACT, 24, 1)
+    FIELD(TOPSW_LSBUS_CTRL, DIVISOR0, 8, 6)
+    FIELD(TOPSW_LSBUS_CTRL, SRCSEL, 0, 3)
 REG32(GTGREF0_REF_CTRL, 0xc8)
-    FIELD(GTGREF0_REF_CTRL, CLKACT, 1, 24)
-    FIELD(GTGREF0_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(GTGREF0_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(GTGREF0_REF_CTRL, CLKACT, 24, 1)
+    FIELD(GTGREF0_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(GTGREF0_REF_CTRL, SRCSEL, 0, 3)
 REG32(GTGREF1_REF_CTRL, 0xcc)
-    FIELD(GTGREF1_REF_CTRL, CLKACT, 1, 24)
-    FIELD(GTGREF1_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(GTGREF1_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(GTGREF1_REF_CTRL, CLKACT, 24, 1)
+    FIELD(GTGREF1_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(GTGREF1_REF_CTRL, SRCSEL, 0, 3)
 REG32(DFT300_REF_CTRL, 0xd0)
-    FIELD(DFT300_REF_CTRL, CLKACT, 1, 24)
-    FIELD(DFT300_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(DFT300_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(DFT300_REF_CTRL, CLKACT, 24, 1)
+    FIELD(DFT300_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(DFT300_REF_CTRL, SRCSEL, 0, 3)
 REG32(DFT270_REF_CTRL, 0xd4)
-    FIELD(DFT270_REF_CTRL, CLKACT, 1, 24)
-    FIELD(DFT270_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(DFT270_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(DFT270_REF_CTRL, CLKACT, 24, 1)
+    FIELD(DFT270_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(DFT270_REF_CTRL, SRCSEL, 0, 3)
 REG32(DFT250_REF_CTRL, 0xd8)
-    FIELD(DFT250_REF_CTRL, CLKACT, 1, 24)
-    FIELD(DFT250_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(DFT250_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(DFT250_REF_CTRL, CLKACT, 24, 1)
+    FIELD(DFT250_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(DFT250_REF_CTRL, SRCSEL, 0, 3)
 REG32(DFT125_REF_CTRL, 0xdc)
-    FIELD(DFT125_REF_CTRL, CLKACT, 1, 24)
-    FIELD(DFT125_REF_CTRL, DIVISOR0, 6, 8)
-    FIELD(DFT125_REF_CTRL, SRCSEL, 3, 0)
+    FIELD(DFT125_REF_CTRL, CLKACT, 24, 1)
+    FIELD(DFT125_REF_CTRL, DIVISOR0, 8, 6)
+    FIELD(DFT125_REF_CTRL, SRCSEL, 0, 3)
 
 REG32(RST_FPD_TOP, 0x100)
-    FIELD(RST_FPD_TOP, PCIE_BRDG_RESET, 1, 18)
-    FIELD(RST_FPD_TOP, PCIE_CTRL_RESET, 1, 17)
-    FIELD(RST_FPD_TOP, DP_RESET, 1, 16)
-    FIELD(RST_FPD_TOP, AFI_FM5_RESET, 1, 12)
-    FIELD(RST_FPD_TOP, AFI_FM4_RESET, 1, 11)
-    FIELD(RST_FPD_TOP, AFI_FM3_RESET, 1, 10)
-    FIELD(RST_FPD_TOP, AFI_FM2_RESET, 1, 9)
-    FIELD(RST_FPD_TOP, AFI_FM1_RESET, 1, 8)
-    FIELD(RST_FPD_TOP, AFI_FM0_RESET, 1, 7)
-    FIELD(RST_FPD_TOP, GDMA_RESET, 1, 6)
-    FIELD(RST_FPD_TOP, GPU_PP1_RESET, 1, 5)
-    FIELD(RST_FPD_TOP, GPU_PP0_RESET, 1, 4)
-    FIELD(RST_FPD_TOP, GPU_RESET, 1, 3)
-    FIELD(RST_FPD_TOP, GT_RESET, 1, 2)
+    FIELD(RST_FPD_TOP, PCIE_BRDG_RESET, 18, 1)
+    FIELD(RST_FPD_TOP, PCIE_CTRL_RESET, 17, 1)
+    FIELD(RST_FPD_TOP, DP_RESET, 16, 1)
+    FIELD(RST_FPD_TOP, AFI_FM5_RESET, 12, 1)
+    FIELD(RST_FPD_TOP, AFI_FM4_RESET, 11, 1)
+    FIELD(RST_FPD_TOP, AFI_FM3_RESET, 10, 1)
+    FIELD(RST_FPD_TOP, AFI_FM2_RESET, 9, 1)
+    FIELD(RST_FPD_TOP, AFI_FM1_RESET, 8, 1)
+    FIELD(RST_FPD_TOP, AFI_FM0_RESET, 7, 1)
+    FIELD(RST_FPD_TOP, GDMA_RESET, 6, 1)
+    FIELD(RST_FPD_TOP, GPU_PP1_RESET, 5, 1)
+    FIELD(RST_FPD_TOP, GPU_PP0_RESET, 4, 1)
+    FIELD(RST_FPD_TOP, GPU_RESET, 3, 1)
+    FIELD(RST_FPD_TOP, GT_RESET, 2, 1)
     FIELD(RST_FPD_TOP, SATA_RESET, 1, 1)
 REG32(RST_FPD_APU, 0x104)
-    FIELD(RST_FPD_APU, PERI_RESET, 1, 13)
-    FIELD(RST_FPD_APU, SCU_RESET, 1, 12)
-    FIELD(RST_FPD_APU, CPU1_AWDT_RESET, 1, 9)
-    FIELD(RST_FPD_APU, CPU0_AWDT_RESET, 1, 8)
-    FIELD(RST_FPD_APU, CPU1_CP14_RESET, 1, 5)
-    FIELD(RST_FPD_APU, CPU0_CP14_RESET, 1, 4)
-    FIELD(RST_FPD_APU, CPU3_A9_RESET, 1, 3)
-    FIELD(RST_FPD_APU, CPU2_A9_RESET, 1, 2)
+    FIELD(RST_FPD_APU, PERI_RESET, 13, 1)
+    FIELD(RST_FPD_APU, SCU_RESET, 12, 1)
+    FIELD(RST_FPD_APU, CPU1_AWDT_RESET, 9, 1)
+    FIELD(RST_FPD_APU, CPU0_AWDT_RESET, 8, 1)
+    FIELD(RST_FPD_APU, CPU1_CP14_RESET, 5, 1)
+    FIELD(RST_FPD_APU, CPU0_CP14_RESET, 4, 1)
+    FIELD(RST_FPD_APU, CPU3_A9_RESET, 3, 1)
+    FIELD(RST_FPD_APU, CPU2_A9_RESET, 2, 1)
     FIELD(RST_FPD_APU, CPU1_A9_RESET, 1, 1)
-    FIELD(RST_FPD_APU, CPU0_A9_RESET, 1, 0)
+    FIELD(RST_FPD_APU, CPU0_A9_RESET, 0, 1)
 REG32(RST_DDR_SS, 0x108)
-    FIELD(RST_DDR_SS, DDR_RESET, 1, 3)
-    FIELD(RST_DDR_SS, APM_RESET, 1, 2)
+    FIELD(RST_DDR_SS, DDR_RESET, 3, 1)
+    FIELD(RST_DDR_SS, APM_RESET, 2, 1)
     FIELD(RST_DDR_SS, QOS_RESET, 1, 1)
-    FIELD(RST_DDR_SS, XMPU_RESET, 1, 0)
+    FIELD(RST_DDR_SS, XMPU_RESET, 0, 1)
 
 #define R_MAX (R_RST_DDR_SS + 1)
 
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [Qemu-devel] [RFC PATCH 09/11] zynqmp_crf: add the clock mechanism
  2016-06-13 16:27 [Qemu-devel] [RFC PATCH 00/11] Clock framework API fred.konrad
                   ` (7 preceding siblings ...)
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 08/11] zynqmp_crf: fix against AF_EX32 changes fred.konrad
@ 2016-06-13 16:27 ` fred.konrad
  2016-07-01 23:23   ` Alistair Francis
  2016-07-29 13:51   ` Peter Maydell
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 10/11] zynqmp: add the zynqmp_crf to the platform fred.konrad
                   ` (2 subsequent siblings)
  11 siblings, 2 replies; 38+ messages in thread
From: fred.konrad @ 2016-06-13 16:27 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, edgar.iglesias, alistair.francis, mark.burton,
	fred.konrad

From: KONRAD Frederic <fred.konrad@greensocs.com>

This adds the pll to the zynqmp_crf and the dp_video clock output.

Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
---
 hw/misc/xilinx_zynqmp_crf.c | 440 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 440 insertions(+)

diff --git a/hw/misc/xilinx_zynqmp_crf.c b/hw/misc/xilinx_zynqmp_crf.c
index 4c670a0..2097534 100644
--- a/hw/misc/xilinx_zynqmp_crf.c
+++ b/hw/misc/xilinx_zynqmp_crf.c
@@ -30,6 +30,7 @@
 #include "hw/register.h"
 #include "qemu/bitops.h"
 #include "qemu/log.h"
+#include "qemu/qemu-clock.h"
 
 #ifndef XILINX_CRF_APB_ERR_DEBUG
 #define XILINX_CRF_APB_ERR_DEBUG 0
@@ -281,6 +282,38 @@ typedef struct CRF_APB {
 
     uint32_t regs[R_MAX];
     RegisterInfo regs_info[R_MAX];
+
+    /* 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;
+
+    /* internal clocks */
+    qemu_clk apll_clk;
+    qemu_clk dpll_clk;
+    qemu_clk vpll_clk;
+
+    /* output clocks */
+    qemu_clk acpu_clk;
+    qemu_clk dbg_trace;
+    qemu_clk dbg_fdp;
+    qemu_clk dp_video_ref;
+    qemu_clk dp_audio_ref;
+    qemu_clk dp_stc_ref;
+    qemu_clk ddr;
+    qemu_clk gpu_ref;
+    qemu_clk sata_ref;
+    qemu_clk pcie_ref;
+    qemu_clk gdma_ref;
+    qemu_clk dpdma_ref;
+    qemu_clk topsw_main;
+    qemu_clk topsw_lsbus;
+    qemu_clk dbg_tstmp;
+    qemu_clk apll_to_lpd;
+    qemu_clk dpll_to_lpd;
+    qemu_clk vpll_to_lpd;
 } CRF_APB;
 
 static const MemoryRegionOps crf_apb_ops = {
@@ -325,6 +358,318 @@ static uint64_t ir_disable_prew(RegisterInfo *reg, uint64_t val64)
     return 0;
 }
 
+enum clk_src {
+    VIDEO_CLK = 4,
+    PSS_ALT_REF_CLK = 5,
+    AUX_REF_CLK = 6,
+    GT_CRX_REF_CLK = 7,
+    PSS_REF_CLK = 0
+};
+
+static void apll_to_lpd_postw(RegisterInfo *reg, uint64_t val64)
+{
+    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
+
+    qemu_clk_refresh(s->apll_to_lpd);
+}
+
+static float apll_to_lpd_update_rate(void *opaque, float input_rate)
+{
+    CRF_APB *s = XILINX_CRF_APB(opaque);
+    uint32_t divisor = AF_EX32(s->regs, APLL_TO_LPD_CTRL, DIVISOR0);
+
+    if (!divisor) {
+        return 0.0f;
+    } else {
+        return input_rate / (float)divisor;
+    }
+}
+
+static void dpll_to_lpd_postw(RegisterInfo *reg, uint64_t val64)
+{
+    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
+
+    qemu_clk_refresh(s->dpll_to_lpd);
+}
+
+static float dpll_to_lpd_update_rate(void *opaque, float input_rate)
+{
+    CRF_APB *s = XILINX_CRF_APB(opaque);
+    uint32_t divisor = AF_EX32(s->regs, DPLL_TO_LPD_CTRL, DIVISOR0);
+
+    if (!divisor) {
+        return 0.0f;
+    } else {
+        return input_rate / (float)divisor;
+    }
+}
+
+static void vpll_to_lpd_postw(RegisterInfo *reg, uint64_t val64)
+{
+    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
+
+    qemu_clk_refresh(s->vpll_to_lpd);
+}
+
+static float vpll_to_lpd_update_rate(void *opaque, float input_rate)
+{
+    CRF_APB *s = XILINX_CRF_APB(opaque);
+    uint32_t divisor = AF_EX32(s->regs, VPLL_TO_LPD_CTRL, DIVISOR0);
+
+    if (!divisor) {
+        return 0.0f;
+    } else {
+        return input_rate / (float)divisor;
+    }
+}
+
+static void apll_ctrl_postw(RegisterInfo *reg, uint64_t val64)
+{
+    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
+    uint32_t source = AF_EX32(s->regs, APLL_CTRL, BYPASS)
+                    ? AF_EX32(s->regs, APLL_CTRL, POST_SRC)
+                    : AF_EX32(s->regs, APLL_CTRL, PRE_SRC);
+
+    /*
+     * We must ensure that only one clock is bound to the apll internal clock.
+     */
+    qemu_clk_unbound(s->pss_ref_clk, s->apll_clk);
+    qemu_clk_unbound(s->video_clk, s->apll_clk);
+    qemu_clk_unbound(s->pss_alt_ref_clk, s->apll_clk);
+    qemu_clk_unbound(s->aux_refclk, s->apll_clk);
+    qemu_clk_unbound(s->gt_crx_ref_clk, s->apll_clk);
+
+    switch (source) {
+    case VIDEO_CLK:
+        qemu_clk_bound_clock(s->video_clk, s->apll_clk);
+        break;
+    case PSS_ALT_REF_CLK:
+        qemu_clk_bound_clock(s->pss_alt_ref_clk, s->apll_clk);
+        break;
+    case AUX_REF_CLK:
+        qemu_clk_bound_clock(s->aux_refclk, s->apll_clk);
+        break;
+    case GT_CRX_REF_CLK:
+        qemu_clk_bound_clock(s->gt_crx_ref_clk, s->apll_clk);
+        break;
+    default:
+        qemu_clk_bound_clock(s->pss_ref_clk, s->apll_clk);
+        break;
+    }
+}
+
+static void dpll_ctrl_postw(RegisterInfo *reg, uint64_t val64)
+{
+    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
+    uint32_t source = AF_EX32(s->regs, DPLL_CTRL, BYPASS)
+                    ? AF_EX32(s->regs, DPLL_CTRL, POST_SRC)
+                    : AF_EX32(s->regs, DPLL_CTRL, PRE_SRC);
+
+    /*
+     * We must ensure that only one clock is bound to the dpll internal clock.
+     */
+    qemu_clk_unbound(s->pss_ref_clk, s->dpll_clk);
+    qemu_clk_unbound(s->video_clk, s->dpll_clk);
+    qemu_clk_unbound(s->pss_alt_ref_clk, s->dpll_clk);
+    qemu_clk_unbound(s->aux_refclk, s->dpll_clk);
+    qemu_clk_unbound(s->gt_crx_ref_clk, s->dpll_clk);
+
+    switch (source) {
+    case VIDEO_CLK:
+        qemu_clk_bound_clock(s->video_clk, s->dpll_clk);
+        break;
+    case PSS_ALT_REF_CLK:
+        qemu_clk_bound_clock(s->pss_alt_ref_clk, s->dpll_clk);
+        break;
+    case AUX_REF_CLK:
+        qemu_clk_bound_clock(s->aux_refclk, s->dpll_clk);
+        break;
+    case GT_CRX_REF_CLK:
+        qemu_clk_bound_clock(s->gt_crx_ref_clk, s->dpll_clk);
+        break;
+    default:
+        qemu_clk_bound_clock(s->pss_ref_clk, s->dpll_clk);
+        break;
+    }
+}
+
+static void vpll_ctrl_postw(RegisterInfo *reg, uint64_t val64)
+{
+    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
+    uint32_t source = AF_EX32(s->regs, VPLL_CTRL, BYPASS)
+                    ? AF_EX32(s->regs, VPLL_CTRL, POST_SRC)
+                    : AF_EX32(s->regs, VPLL_CTRL, PRE_SRC);
+
+    /*
+     * We must ensure that only one clock is bound to the vpll internal clock.
+     */
+    qemu_clk_unbound(s->pss_ref_clk, s->vpll_clk);
+    qemu_clk_unbound(s->video_clk, s->vpll_clk);
+    qemu_clk_unbound(s->pss_alt_ref_clk, s->vpll_clk);
+    qemu_clk_unbound(s->aux_refclk, s->vpll_clk);
+    qemu_clk_unbound(s->gt_crx_ref_clk, s->vpll_clk);
+
+    switch (source) {
+    case VIDEO_CLK:
+        qemu_clk_bound_clock(s->video_clk, s->vpll_clk);
+        break;
+    case PSS_ALT_REF_CLK:
+        qemu_clk_bound_clock(s->pss_alt_ref_clk, s->vpll_clk);
+        break;
+    case AUX_REF_CLK:
+        qemu_clk_bound_clock(s->aux_refclk, s->vpll_clk);
+        break;
+    case GT_CRX_REF_CLK:
+        qemu_clk_bound_clock(s->gt_crx_ref_clk, s->vpll_clk);
+        break;
+    default:
+        qemu_clk_bound_clock(s->pss_ref_clk, s->vpll_clk);
+        break;
+    }
+}
+
+/*
+ * This happen when apll get updated.
+ * As we ensure that only one clk_pin can drive apll we can just do the
+ * computation from input_rate.
+ */
+static float apll_update_rate(void *opaque, float input_rate)
+{
+    CRF_APB *s = XILINX_CRF_APB(opaque);
+    bool bypass = AF_EX32(s->regs, APLL_CTRL, BYPASS);
+    bool reset = AF_EX32(s->regs, APLL_CTRL, RESET);
+    float div2 = AF_EX32(s->regs, APLL_CTRL, DIV2) ? 0.5f : 1.0f;
+    float integer = (float)(AF_EX32(s->regs, APLL_CTRL, FBDIV));
+    float frac = AF_EX32(s->regs, APLL_FRAC_CFG, ENABLED)
+                  ? (float)(AF_EX32(s->regs, APLL_FRAC_CFG, DATA)) / 65536.0f
+                  : 0.0f;
+
+    if (bypass) {
+        return input_rate;
+    } else {
+        if (reset) {
+            /*
+             * This is not supposed to happen user must ensure that BYPASS is
+             * set before the PLL are reset.
+             */
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "APLL is reseted but not bypassed.");
+            return 0.0f;
+        } else {
+            return input_rate * div2 * (integer + frac);
+        }
+    }
+}
+
+/*
+ * This happen when dpll get updated.
+ * As we ensure that only one clk_pin can drive dpll we can just do the
+ * computation from input_rate.
+ */
+static float dpll_update_rate(void *opaque, float input_rate)
+{
+    CRF_APB *s = XILINX_CRF_APB(opaque);
+    bool bypass = AF_EX32(s->regs, DPLL_CTRL, BYPASS);
+    bool reset = AF_EX32(s->regs, DPLL_CTRL, RESET);
+    float div2 = AF_EX32(s->regs, DPLL_CTRL, DIV2) ? 0.5f : 1.0f;
+    float integer = (float)(AF_EX32(s->regs, DPLL_CTRL, FBDIV));
+    float frac = AF_EX32(s->regs, DPLL_FRAC_CFG, ENABLED)
+                  ? (float)(AF_EX32(s->regs, DPLL_FRAC_CFG, DATA)) / 65536.0f
+                  : 0.0f;
+
+    if (bypass) {
+        return input_rate;
+    } else {
+        if (reset) {
+            /*
+             * This is not supposed to happen user must ensure that BYPASS is
+             * set before the PLL are reset.
+             */
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "DPLL is reseted but not bypassed.");
+            return 0.0f;
+        } else {
+            return input_rate * div2 * (integer + frac);
+        }
+    }
+}
+
+/*
+ * This happen when vpll get updated.
+ * As we ensure that only one clk_pin can drive vpll we can just do the
+ * computation from input_rate.
+ */
+static float vpll_update_rate(void *opaque, float input_rate)
+{
+    CRF_APB *s = XILINX_CRF_APB(opaque);
+    bool bypass = AF_EX32(s->regs, VPLL_CTRL, BYPASS);
+    bool reset = AF_EX32(s->regs, VPLL_CTRL, RESET);
+    float div2 = AF_EX32(s->regs, VPLL_CTRL, DIV2) ? 0.5f : 1.0f;
+    float integer = (float)(AF_EX32(s->regs, VPLL_CTRL, FBDIV));
+    float frac = AF_EX32(s->regs, VPLL_FRAC_CFG, ENABLED)
+                  ? (float)(AF_EX32(s->regs, VPLL_FRAC_CFG, DATA)) / 65536.0f
+                  : 0.0f;
+
+    if (bypass) {
+        return input_rate;
+    } else {
+        if (reset) {
+            /*
+             * This is not supposed to happen user must ensure that BYPASS is
+             * set before the PLL are reset.
+             */
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "VPLL is reseted but not bypassed.");
+            return 0.0f;
+        } else {
+            return input_rate * div2 * (integer + frac);
+        }
+    }
+}
+
+/*
+ * FIXME: Only DP video reference clock is modeled here, others are missing.
+ */
+static float dp_video_update_rate(void *opaque, float input_rate)
+{
+    CRF_APB *s = XILINX_CRF_APB(opaque);
+    bool clock_act = AF_EX32(s->regs, DP_VIDEO_REF_CTRL, CLKACT);
+    uint32_t divisor0 = AF_EX32(s->regs, DP_VIDEO_REF_CTRL, DIVISOR0);
+
+    if ((!divisor0) || (!clock_act)) {
+        return 0.0f;
+    } else {
+        return input_rate / (float)(divisor0);
+    }
+}
+
+static void dp_video_ref_ctrl_postw(RegisterInfo *reg, uint64_t val64)
+{
+    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
+    uint32_t source = AF_EX32(s->regs, APLL_CTRL, BYPASS)
+                    ? AF_EX32(s->regs, APLL_CTRL, POST_SRC)
+                    : AF_EX32(s->regs, APLL_CTRL, PRE_SRC);
+
+    /*
+     * We must ensure that only one clock is bound to the dp_video_ref
+     * internal clock, so the callback have always the right rate in it.
+     */
+    qemu_clk_unbound(s->vpll_clk, s->dp_video_ref);
+    qemu_clk_unbound(s->dpll_clk, s->dp_video_ref);
+
+    switch (source) {
+    case 0x00:
+        qemu_clk_bound_clock(s->vpll_clk, s->dp_video_ref);
+        break;
+    case 0x02:
+        qemu_clk_bound_clock(s->dpll_clk, s->dp_video_ref);
+        break;
+    default:
+        abort();
+        break;
+    }
+}
+
 static RegisterAccessInfo crf_apb_regs_info[] = {
     {   .name = "ERR_CTRL",  .decode.addr = A_ERR_CTRL,
     },{ .name = "IR_STATUS",  .decode.addr = A_IR_STATUS,
@@ -341,6 +686,7 @@ static RegisterAccessInfo crf_apb_regs_info[] = {
     },{ .name = "APLL_CTRL",  .decode.addr = A_APLL_CTRL,
         .reset = 0x2809,
         .rsvd = 0xf88c80f6L,
+        .post_write = apll_ctrl_postw,
     },{ .name = "APLL_CFG",  .decode.addr = A_APLL_CFG,
         .rsvd = 0x1801210,
     },{ .name = "APLL_FRAC_CFG",  .decode.addr = A_APLL_FRAC_CFG,
@@ -348,6 +694,7 @@ static RegisterAccessInfo crf_apb_regs_info[] = {
     },{ .name = "DPLL_CTRL",  .decode.addr = A_DPLL_CTRL,
         .reset = 0x2809,
         .rsvd = 0xf88c80f6L,
+        .post_write = dpll_ctrl_postw,
     },{ .name = "DPLL_CFG",  .decode.addr = A_DPLL_CFG,
         .rsvd = 0x1801210,
     },{ .name = "DPLL_FRAC_CFG",  .decode.addr = A_DPLL_FRAC_CFG,
@@ -355,6 +702,7 @@ static RegisterAccessInfo crf_apb_regs_info[] = {
     },{ .name = "VPLL_CTRL",  .decode.addr = A_VPLL_CTRL,
         .reset = 0x2809,
         .rsvd = 0xf88c80f6L,
+        .post_write = vpll_ctrl_postw,
     },{ .name = "VPLL_CFG",  .decode.addr = A_VPLL_CFG,
         .rsvd = 0x1801210,
     },{ .name = "VPLL_FRAC_CFG",  .decode.addr = A_VPLL_FRAC_CFG,
@@ -366,12 +714,15 @@ static RegisterAccessInfo crf_apb_regs_info[] = {
     },{ .name = "APLL_TO_LPD_CTRL",  .decode.addr = A_APLL_TO_LPD_CTRL,
         .reset = 0x400,
         .rsvd = 0xc0ff,
+        .post_write = apll_to_lpd_postw,
     },{ .name = "DPLL_TO_LPD_CTRL",  .decode.addr = A_DPLL_TO_LPD_CTRL,
         .reset = 0x400,
         .rsvd = 0xc0ff,
+        .post_write = dpll_to_lpd_postw,
     },{ .name = "VPLL_TO_LPD_CTRL",  .decode.addr = A_VPLL_TO_LPD_CTRL,
         .reset = 0x400,
         .rsvd = 0xc0ff,
+        .post_write = vpll_to_lpd_postw,
     },{ .name = "CPU_A9_CTRL",  .decode.addr = A_CPU_A9_CTRL,
         .reset = 0xf000400,
         .rsvd = 0xf0ffc0f8L,
@@ -384,6 +735,7 @@ static RegisterAccessInfo crf_apb_regs_info[] = {
     },{ .name = "DP_VIDEO_REF_CTRL",  .decode.addr = A_DP_VIDEO_REF_CTRL,
         .reset = 0x1002300,
         .rsvd = 0xfeffc0f8L,
+        .post_write = dp_video_ref_ctrl_postw,
     },{ .name = "DP_AUDIO_REF_CTRL",  .decode.addr = A_DP_AUDIO_REF_CTRL,
         .reset = 0x1002300,
         .rsvd = 0xfeffc0f8L,
@@ -479,6 +831,25 @@ static void crf_apb_reset(DeviceState *dev)
     }
 
     ir_update_irq(s);
+
+    /*
+     * During reset, the clock selection registers bound the clock like this.
+     */
+    qemu_clk_bound_clock(s->pss_ref_clk, s->apll_clk);
+    qemu_clk_bound_clock(s->pss_ref_clk, s->dpll_clk);
+    qemu_clk_bound_clock(s->pss_ref_clk, s->vpll_clk);
+    qemu_clk_bound_clock(s->vpll_clk, s->dp_video_ref);
+}
+
+static void crf_apb_realize(DeviceState *d, Error **errp)
+{
+    CRF_APB *s = XILINX_CRF_APB(d);
+
+    qemu_clk_bound_clock(s->apll_clk, s->apll_to_lpd);
+    qemu_clk_bound_clock(s->dpll_clk, s->dpll_to_lpd);
+    qemu_clk_bound_clock(s->vpll_clk, s->vpll_to_lpd);
+
+    crf_apb_reset(d);
 }
 
 static void crf_apb_init(Object *obj)
@@ -495,6 +866,74 @@ static void crf_apb_init(Object *obj)
                           R_RST_DDR_SS);
     sysbus_init_mmio(sbd, &s->iomem);
     sysbus_init_irq(sbd, &s->irq_ir);
+
+    /* input clocks */
+    s->pss_ref_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->pss_ref_clk, "pss_ref_clk");
+    s->video_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->video_clk, "video_clk");
+    s->pss_alt_ref_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->pss_alt_ref_clk,
+                              "pss_alt_ref_clk");
+    s->aux_refclk = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->aux_refclk, "aux_refclk");
+    s->gt_crx_ref_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->gt_crx_ref_clk,
+                              "gt_crx_ref_clk");
+
+    /* internal clocks */
+    s->apll_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->apll_clk, "apll_clk");
+    qemu_clk_set_callback(s->apll_clk, apll_update_rate, obj);
+    s->dpll_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->dpll_clk, "dpll_clk");
+    qemu_clk_set_callback(s->dpll_clk, dpll_update_rate, obj);
+    s->vpll_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->vpll_clk, "vpll_clk");
+    qemu_clk_set_callback(s->vpll_clk, vpll_update_rate, obj);
+
+    /* Clock output init */
+    s->acpu_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->acpu_clk, "acpu_clk");
+    s->dbg_trace = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->dbg_trace, "dbg_trace");
+    s->dbg_fdp = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->dbg_fdp, "dbg_fdp");
+    s->dp_video_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->dp_video_ref, "dp_video_ref");
+    qemu_clk_set_callback(s->dp_video_ref, dp_video_update_rate, obj);
+    s->dp_audio_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->dp_audio_ref, "dp_audio_ref");
+    s->dp_stc_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->dp_stc_ref, "dp_stc_ref");
+    s->ddr = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->ddr, "ddr");
+    s->gpu_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->gpu_ref, "gpu_ref");
+    s->sata_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->sata_ref, "sata_ref");
+    s->pcie_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->pcie_ref, "pcie_ref");
+    s->gdma_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->gdma_ref, "gdma_ref");
+    s->dpdma_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->dpdma_ref, "dpdma_ref");
+    s->topsw_main = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->topsw_main, "topsw_main");
+    s->topsw_lsbus = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->topsw_lsbus, "topsw_lsbus");
+    s->dbg_tstmp = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->dbg_tstmp, "dbg_tstmp");
+
+    s->apll_to_lpd = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->apll_to_lpd, "apll_to_lpd");
+    qemu_clk_set_callback(s->apll_to_lpd, apll_to_lpd_update_rate, obj);
+    s->dpll_to_lpd = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->dpll_to_lpd, "dpll_to_lpd");
+    qemu_clk_set_callback(s->dpll_to_lpd, dpll_to_lpd_update_rate, obj);
+    s->vpll_to_lpd = QEMU_CLOCK(object_new(TYPE_CLOCK));
+    qemu_clk_attach_to_device(DEVICE(obj), s->vpll_to_lpd, "vpll_to_lpd");
+    qemu_clk_set_callback(s->vpll_to_lpd, vpll_to_lpd_update_rate, obj);
 }
 
 static const VMStateDescription vmstate_crf_apb = {
@@ -514,6 +953,7 @@ static void crf_apb_class_init(ObjectClass *klass, void *data)
 
     dc->reset = crf_apb_reset;
     dc->vmsd = &vmstate_crf_apb;
+    dc->realize = crf_apb_realize;
 }
 
 static const TypeInfo crf_apb_info = {
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [Qemu-devel] [RFC PATCH 10/11] zynqmp: add the zynqmp_crf to the platform
  2016-06-13 16:27 [Qemu-devel] [RFC PATCH 00/11] Clock framework API fred.konrad
                   ` (8 preceding siblings ...)
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 09/11] zynqmp_crf: add the clock mechanism fred.konrad
@ 2016-06-13 16:27 ` fred.konrad
  2016-07-01 23:11   ` Alistair Francis
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 11/11] zynqmp: add reference clock fred.konrad
  2016-07-29 13:59 ` [Qemu-devel] [RFC PATCH 00/11] Clock framework API Peter Maydell
  11 siblings, 1 reply; 38+ messages in thread
From: fred.konrad @ 2016-06-13 16:27 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, edgar.iglesias, alistair.francis, mark.burton,
	fred.konrad

From: KONRAD Frederic <fred.konrad@greensocs.com>

This adds the zynqmp_crf to the zynqmp platform.

Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
---
 hw/arm/xlnx-zynqmp.c         | 7 +++++++
 include/hw/arm/xlnx-zynqmp.h | 1 +
 2 files changed, 8 insertions(+)

diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index 4d504da..a8b7669 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -135,6 +135,11 @@ static void xlnx_zynqmp_init(Object *obj)
                           TYPE_XILINX_SPIPS);
         qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default());
     }
+
+    s->crf = object_new("xlnx.zynqmp_crf");
+    qdev_set_parent_bus(DEVICE(s->crf), sysbus_get_default());
+    object_property_add_child(obj, "xlnx.zynqmp_crf", OBJECT(s->crf),
+                              &error_abort);
 }
 
 static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
@@ -366,6 +371,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
                                   &error_abort);
 	g_free(bus_name);
     }
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(s->crf), 0, 0xFD1A0000);
 }
 
 static Property xlnx_zynqmp_props[] = {
diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h
index 2332596..78fed6e 100644
--- a/include/hw/arm/xlnx-zynqmp.h
+++ b/include/hw/arm/xlnx-zynqmp.h
@@ -81,6 +81,7 @@ typedef struct XlnxZynqMPState {
     SysbusAHCIState sata;
     SDHCIState sdhci[XLNX_ZYNQMP_NUM_SDHCI];
     XilinxSPIPS spi[XLNX_ZYNQMP_NUM_SPIS];
+    Object *crf;
 
     char *boot_cpu;
     ARMCPU *boot_cpu_ptr;
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [Qemu-devel] [RFC PATCH 11/11] zynqmp: add reference clock
  2016-06-13 16:27 [Qemu-devel] [RFC PATCH 00/11] Clock framework API fred.konrad
                   ` (9 preceding siblings ...)
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 10/11] zynqmp: add the zynqmp_crf to the platform fred.konrad
@ 2016-06-13 16:27 ` fred.konrad
  2016-07-29 13:59 ` [Qemu-devel] [RFC PATCH 00/11] Clock framework API Peter Maydell
  11 siblings, 0 replies; 38+ messages in thread
From: fred.konrad @ 2016-06-13 16:27 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, edgar.iglesias, alistair.francis, mark.burton,
	fred.konrad

From: KONRAD Frederic <fred.konrad@greensocs.com>

This adds some fixed reference clock to the zynqmp platform.
They will feed the zynqmp_crf block.

Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
---
 hw/arm/xlnx-zynqmp.c         | 42 ++++++++++++++++++++++++++++++++++++++++++
 include/hw/arm/xlnx-zynqmp.h |  6 ++++++
 2 files changed, 48 insertions(+)

diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index a8b7669..68f924f 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -22,6 +22,7 @@
 #include "hw/arm/xlnx-zynqmp.h"
 #include "hw/intc/arm_gic_common.h"
 #include "exec/address-spaces.h"
+#include "qemu/qemu-clock.h"
 
 #define GIC_NUM_SPI_INTR 160
 
@@ -140,6 +141,22 @@ static void xlnx_zynqmp_init(Object *obj)
     qdev_set_parent_bus(DEVICE(s->crf), sysbus_get_default());
     object_property_add_child(obj, "xlnx.zynqmp_crf", OBJECT(s->crf),
                               &error_abort);
+
+    s->pss_ref_clk = object_new(TYPE_FIXED_CLOCK);
+    object_property_add_child(obj, "pss_ref_clk", s->pss_ref_clk,
+                              &error_abort);
+    object_property_set_int(s->pss_ref_clk, 50000000, "rate", &error_abort);
+    s->video_clk = object_new(TYPE_FIXED_CLOCK);
+    object_property_add_child(obj, "video_clk", s->video_clk, &error_abort);
+    object_property_set_int(s->video_clk, 27000000, "rate", &error_abort);
+    s->pss_alt_ref_clk = object_new(TYPE_FIXED_CLOCK);
+    object_property_add_child(obj, "pss_alt_ref_clk", s->pss_alt_ref_clk,
+                              &error_abort);
+    s->aux_refclk = object_new(TYPE_FIXED_CLOCK);
+    object_property_add_child(obj, "aux_refclk", s->aux_refclk, &error_abort);
+    s->gt_crx_ref_clk = object_new(TYPE_FIXED_CLOCK);
+    object_property_add_child(obj, "gt_crx_ref_clk", s->gt_crx_ref_clk,
+                              &error_abort);
 }
 
 static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
@@ -373,6 +390,31 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
     }
 
     sysbus_mmio_map(SYS_BUS_DEVICE(s->crf), 0, 0xFD1A0000);
+
+    /* Bound the clock */
+    qemu_clk_bound_clock(qemu_clk_get_pin(DEVICE(s->pss_ref_clk), "clk_out"),
+                         qemu_clk_get_pin(DEVICE(s->crf), "pss_ref_clk"));
+
+    qemu_clk_bound_clock(qemu_clk_get_pin(DEVICE(s->video_clk), "clk_out"),
+                         qemu_clk_get_pin(DEVICE(s->crf), "video_clk"));
+
+    qemu_clk_bound_clock(qemu_clk_get_pin(DEVICE(s->pss_alt_ref_clk),
+                                          "clk_out"),
+                         qemu_clk_get_pin(DEVICE(s->crf), "pss_alt_ref_clk"));
+
+    qemu_clk_bound_clock(qemu_clk_get_pin(DEVICE(s->aux_refclk), "clk_out"),
+                         qemu_clk_get_pin(DEVICE(s->crf), "aux_refclk"));
+
+    qemu_clk_bound_clock(qemu_clk_get_pin(DEVICE(s->gt_crx_ref_clk),
+                                          "clk_out"),
+                         qemu_clk_get_pin(DEVICE(s->crf), "gt_crx_ref_clk"));
+
+    object_property_set_bool(s->crf, true, "realized", &err);
+    object_property_set_bool(s->pss_ref_clk, true, "realized", &err);
+    object_property_set_bool(s->video_clk, true, "realized", &err);
+    object_property_set_bool(s->pss_alt_ref_clk, true, "realized", &err);
+    object_property_set_bool(s->aux_refclk, true, "realized", &err);
+    object_property_set_bool(s->gt_crx_ref_clk, true, "realized", &err);
 }
 
 static Property xlnx_zynqmp_props[] = {
diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h
index 78fed6e..536e4a1 100644
--- a/include/hw/arm/xlnx-zynqmp.h
+++ b/include/hw/arm/xlnx-zynqmp.h
@@ -26,6 +26,7 @@
 #include "hw/ide/ahci.h"
 #include "hw/sd/sdhci.h"
 #include "hw/ssi/xilinx_spips.h"
+#include "hw/misc/fixed-clock.h"
 
 #define TYPE_XLNX_ZYNQMP "xlnx,zynqmp"
 #define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \
@@ -81,6 +82,11 @@ typedef struct XlnxZynqMPState {
     SysbusAHCIState sata;
     SDHCIState sdhci[XLNX_ZYNQMP_NUM_SDHCI];
     XilinxSPIPS spi[XLNX_ZYNQMP_NUM_SPIS];
+    Object *pss_ref_clk;
+    Object *video_clk;
+    Object *pss_alt_ref_clk;
+    Object *aux_refclk;
+    Object *gt_crx_ref_clk;
     Object *crf;
 
     char *boot_cpu;
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 01/11] qemu-clk: introduce qemu-clk qom object
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 01/11] qemu-clk: introduce qemu-clk qom object fred.konrad
@ 2016-06-29  0:15   ` Alistair Francis
  0 siblings, 0 replies; 38+ messages in thread
From: Alistair Francis @ 2016-06-29  0:15 UTC (permalink / raw)
  To: KONRAD Frédéric
  Cc: qemu-devel@nongnu.org Developers, Edgar Iglesias, Peter Maydell,
	Mark Burton, Alistair Francis

On Mon, Jun 13, 2016 at 9:27 AM,  <fred.konrad@greensocs.com> wrote:
> From: KONRAD Frederic <fred.konrad@greensocs.com>
>
> This introduces qemu-clk qom object.
>
> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
> ---
>  Makefile.objs             |  1 +
>  include/qemu/qemu-clock.h | 40 ++++++++++++++++++++++++++++++++++++++++
>  qemu-clock.c              | 47 +++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 88 insertions(+)
>  create mode 100644 include/qemu/qemu-clock.h
>  create mode 100644 qemu-clock.c
>
> diff --git a/Makefile.objs b/Makefile.objs
> index 61f4bf4..2284ef5 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -77,6 +77,7 @@ common-obj-y += backends/
>  common-obj-$(CONFIG_SECCOMP) += qemu-seccomp.o
>
>  common-obj-$(CONFIG_FDT) += device_tree.o
> +common-obj-y += qemu-clock.o
>
>  ######################################################################
>  # qapi
> diff --git a/include/qemu/qemu-clock.h b/include/qemu/qemu-clock.h
> new file mode 100644
> index 0000000..e7acd68
> --- /dev/null
> +++ b/include/qemu/qemu-clock.h
> @@ -0,0 +1,40 @@
> +/*
> + * QEMU Clock
> + *
> + *  Copyright (C) 2016 : GreenSocs Ltd
> + *      http://www.greensocs.com/ , email: info@greensocs.com
> + *
> + *  Frederic Konrad <fred.konrad@greensocs.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#ifndef QEMU_CLOCK_H
> +#define QEMU_CLOCK_H
> +
> +#include "qemu/osdep.h"
> +#include "qom/object.h"
> +
> +#define TYPE_CLOCK "qemu-clk"
> +#define QEMU_CLOCK(obj) OBJECT_CHECK(struct qemu_clk, (obj), TYPE_CLOCK)
> +
> +typedef struct qemu_clk {
> +    /*< private >*/
> +    Object parent_obj;
> +} *qemu_clk;
> +
> +#endif /* QEMU_CLOCK_H */
> +
> +
> diff --git a/qemu-clock.c b/qemu-clock.c
> new file mode 100644
> index 0000000..4a47fb4
> --- /dev/null
> +++ b/qemu-clock.c
> @@ -0,0 +1,47 @@
> +/*
> + * QEMU Clock
> + *
> + *  Copyright (C) 2016 : GreenSocs Ltd
> + *      http://www.greensocs.com/ , email: info@greensocs.com
> + *
> + *  Frederic Konrad <fred.konrad@greensocs.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#include "qemu/qemu-clock.h"
> +#include "hw/hw.h"

I'm pretty sure every file should start with osdep now.

> +
> +/* #define DEBUG_QEMU_CLOCK */

This shouldn't be here.

Thanks,

Alistair

> +
> +#ifdef DEBUG_QEMU_CLOCK
> +#define DPRINTF(fmt, ...) \
> +do { printf("qemu-clock: " fmt , ## __VA_ARGS__); } while (0)
> +#else
> +#define DPRINTF(fmt, ...) do { } while (0)
> +#endif
> +
> +static const TypeInfo qemu_clk_info = {
> +    .name          = TYPE_CLOCK,
> +    .parent        = TYPE_OBJECT,
> +    .instance_size = sizeof(struct qemu_clk),
> +};
> +
> +static void qemu_clk_register_types(void)
> +{
> +    type_register_static(&qemu_clk_info);
> +}
> +
> +type_init(qemu_clk_register_types);
> --
> 2.5.5
>
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 02/11] qemu-clk: allow to attach a clock to a device
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 02/11] qemu-clk: allow to attach a clock to a device fred.konrad
@ 2016-06-29  0:15   ` Alistair Francis
  2016-08-02  7:47     ` KONRAD Frederic
  0 siblings, 1 reply; 38+ messages in thread
From: Alistair Francis @ 2016-06-29  0:15 UTC (permalink / raw)
  To: KONRAD Frédéric
  Cc: qemu-devel@nongnu.org Developers, Edgar Iglesias, Peter Maydell,
	Mark Burton, Alistair Francis

On Mon, Jun 13, 2016 at 9:27 AM,  <fred.konrad@greensocs.com> wrote:
> From: KONRAD Frederic <fred.konrad@greensocs.com>
>
> This allows to attach a clock to a DeviceState.
> Contrary to gpios, the clock pins are not contained in the DeviceState but
> with the child property so they can appears in the qom-tree.
>
> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
> ---
>  include/qemu/qemu-clock.h | 24 +++++++++++++++++++++++-
>  qemu-clock.c              | 22 ++++++++++++++++++++++
>  2 files changed, 45 insertions(+), 1 deletion(-)
>
> diff --git a/include/qemu/qemu-clock.h b/include/qemu/qemu-clock.h
> index e7acd68..a2ba105 100644
> --- a/include/qemu/qemu-clock.h
> +++ b/include/qemu/qemu-clock.h
> @@ -33,8 +33,30 @@
>  typedef struct qemu_clk {
>      /*< private >*/
>      Object parent_obj;
> +    char *name;            /* name of this clock in the device. */
>  } *qemu_clk;
>
> -#endif /* QEMU_CLOCK_H */
> +/**
> + * qemu_clk_attach_to_device:
> + * @d: the device on which the clock need to be attached.
> + * @clk: the clock which need to be attached.
> + * @name: the name of the clock can't be NULL.
> + *
> + * Attach @clk named @name to the device @d.
> + *
> + */
> +void qemu_clk_attach_to_device(DeviceState *d, qemu_clk clk,

dev instead of just d

> +                               const char *name);
>
> +/**
> + * qemu_clk_get_pin:
> + * @d: the device which contain the clock.
> + * @name: the name of the clock.
> + *
> + * Get the clock named @name located in the device @d, or NULL if not found.
> + *
> + * Returns the clock named @name contained in @d.
> + */
> +qemu_clk qemu_clk_get_pin(DeviceState *d, const char *name);
>
> +#endif /* QEMU_CLOCK_H */
> diff --git a/qemu-clock.c b/qemu-clock.c
> index 4a47fb4..81f2852 100644
> --- a/qemu-clock.c
> +++ b/qemu-clock.c
> @@ -23,6 +23,7 @@
>
>  #include "qemu/qemu-clock.h"
>  #include "hw/hw.h"
> +#include "qapi/error.h"
>
>  /* #define DEBUG_QEMU_CLOCK */
>
> @@ -33,6 +34,27 @@ do { printf("qemu-clock: " fmt , ## __VA_ARGS__); } while (0)
>  #define DPRINTF(fmt, ...) do { } while (0)
>  #endif
>
> +void qemu_clk_attach_to_device(DeviceState *d, qemu_clk clk, const char *name)
> +{
> +    assert(name);
> +    assert(!clk->name);
> +    object_property_add_child(OBJECT(d), name, OBJECT(clk), &error_abort);
> +    clk->name = g_strdup(name);
> +}
> +
> +qemu_clk qemu_clk_get_pin(DeviceState *d, const char *name)
> +{
> +    gchar *path = NULL;
> +    Object *clk;
> +    bool ambiguous;
> +
> +    path = g_strdup_printf("%s/%s", object_get_canonical_path(OBJECT(d)),
> +                           name);
> +    clk = object_resolve_path(path, &ambiguous);

Should ambiguous be passed back to the caller?

> +    g_free(path);
> +    return QEMU_CLOCK(clk);

Shouldn't you check to see if you got something valid before casting?

Thanks,

Alistair

> +}
> +
>  static const TypeInfo qemu_clk_info = {
>      .name          = TYPE_CLOCK,
>      .parent        = TYPE_OBJECT,
> --
> 2.5.5
>
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 03/11] qemu-clk: allow to bound two clocks together
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 03/11] qemu-clk: allow to bound two clocks together fred.konrad
@ 2016-06-29  0:30   ` Alistair Francis
  2016-07-29 13:39   ` Peter Maydell
  1 sibling, 0 replies; 38+ messages in thread
From: Alistair Francis @ 2016-06-29  0:30 UTC (permalink / raw)
  To: KONRAD Frédéric
  Cc: qemu-devel@nongnu.org Developers, Edgar Iglesias, Peter Maydell,
	Mark Burton, Alistair Francis

On Mon, Jun 13, 2016 at 9:27 AM,  <fred.konrad@greensocs.com> wrote:
> From: KONRAD Frederic <fred.konrad@greensocs.com>
>
> This introduces the clock binding and the update part.
> When the qemu_clk_rate_update(qemu_clk, int) function is called:
>   * The clock callback is called on the qemu_clk so it can change the rate.
>   * The qemu_clk_rate_update function is called on all the driven clock.
>
> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
> ---
>  include/qemu/qemu-clock.h | 65 +++++++++++++++++++++++++++++++++++++++++++++++
>  qemu-clock.c              | 56 ++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 121 insertions(+)
>
> diff --git a/include/qemu/qemu-clock.h b/include/qemu/qemu-clock.h
> index a2ba105..677de9a 100644
> --- a/include/qemu/qemu-clock.h
> +++ b/include/qemu/qemu-clock.h
> @@ -27,15 +27,29 @@
>  #include "qemu/osdep.h"
>  #include "qom/object.h"
>
> +typedef float (*qemu_clk_on_rate_update_cb)(void *opaque, float rate);
> +
>  #define TYPE_CLOCK "qemu-clk"
>  #define QEMU_CLOCK(obj) OBJECT_CHECK(struct qemu_clk, (obj), TYPE_CLOCK)
>
> +typedef struct ClkList ClkList;
> +
>  typedef struct qemu_clk {
>      /*< private >*/
>      Object parent_obj;
>      char *name;            /* name of this clock in the device. */
> +    float in_rate;         /* rate of the clock which drive this pin. */
> +    float out_rate;        /* rate of this clock pin. */
> +    void *opaque;
> +    qemu_clk_on_rate_update_cb cb;
> +    QLIST_HEAD(, ClkList) bound;
>  } *qemu_clk;
>
> +struct ClkList {
> +    qemu_clk clk;
> +    QLIST_ENTRY(ClkList) node;
> +};
> +
>  /**
>   * qemu_clk_attach_to_device:
>   * @d: the device on which the clock need to be attached.
> @@ -59,4 +73,55 @@ void qemu_clk_attach_to_device(DeviceState *d, qemu_clk clk,
>   */
>  qemu_clk qemu_clk_get_pin(DeviceState *d, const char *name);
>
> +/**
> + * qemu_clk_bound_clock:

Maybe this should be bind and unbind clock instead of bound and unbound.

> + * @out: the clock output.
> + * @in: the clock input.
> + *
> + * Connect the clock together. This is unidirectionnal so a
> + * qemu_clk_update_rate will go from @out to @in.

s/unidirectionnal/unidirectional/g

> + *
> + */
> +void qemu_clk_bound_clock(qemu_clk out, qemu_clk in);
> +
> +/**
> + * qemu_clk_unbound:
> + * @out: the clock output.
> + * @in: the clock input.
> + *
> + * Disconnect the clock if they were bound together.

clocks

> + *
> + */
> +void qemu_clk_unbound(qemu_clk out, qemu_clk in);
> +
> +/**
> + * qemu_clk_update_rate:
> + * @clk: the clock to update.
> + * @rate: the new rate.
> + *
> + * Update the @clk to the new @rate.
> + *
> + */
> +void qemu_clk_update_rate(qemu_clk clk, float rate);
> +
> +/**
> + * qemu_clk_refresh:
> + * @clk: the clock to be refreshed.
> + *
> + * This updates all childs of a clock without changing its own rate.

Can you clarify what this does?

> + *
> + */
> +void qemu_clk_refresh(qemu_clk clk);
> +
> +/**
> + * qemu_clk_set_callback:
> + * @clk: the clock where to set the callback.
> + * @cb: the callback to associate to the callback.
> + * @opaque: the opaque data passed to the calback.
> + *
> + */
> +void qemu_clk_set_callback(qemu_clk clk,
> +                           qemu_clk_on_rate_update_cb cb,
> +                           void *opaque);
> +
>  #endif /* QEMU_CLOCK_H */
> diff --git a/qemu-clock.c b/qemu-clock.c
> index 81f2852..811d6a0 100644
> --- a/qemu-clock.c
> +++ b/qemu-clock.c
> @@ -34,6 +34,62 @@ do { printf("qemu-clock: " fmt , ## __VA_ARGS__); } while (0)
>  #define DPRINTF(fmt, ...) do { } while (0)
>  #endif
>
> +void qemu_clk_refresh(qemu_clk clk)
> +{
> +    qemu_clk_update_rate(clk, clk->in_rate);
> +}
> +
> +void qemu_clk_update_rate(qemu_clk clk, float rate)
> +{
> +    ClkList *child;
> +
> +    clk->in_rate = rate;
> +    clk->out_rate = rate;
> +
> +    if (clk->cb) {
> +        clk->out_rate = clk->cb(clk->opaque, rate);
> +    }
> +
> +    DPRINTF("%s output rate updated to %.1f\n",
> +            object_get_canonical_path(OBJECT(clk)),
> +            clk->out_rate);
> +
> +    QLIST_FOREACH(child, &clk->bound, node) {
> +        qemu_clk_update_rate(child->clk, clk->out_rate);
> +    }
> +}
> +
> +void qemu_clk_bound_clock(qemu_clk out, qemu_clk in)
> +{
> +    ClkList *child;
> +
> +    child = g_malloc(sizeof(child));
> +    assert(child);
> +    child->clk = in;
> +    QLIST_INSERT_HEAD(&out->bound, child, node);
> +    qemu_clk_update_rate(in, out->out_rate);
> +}
> +
> +void qemu_clk_unbound(qemu_clk out, qemu_clk in)
> +{
> +    ClkList *child, *next;
> +
> +    QLIST_FOREACH_SAFE(child, &out->bound, node, next) {
> +        if (child->clk == in) {
> +            QLIST_REMOVE(child, node);
> +            g_free(child);
> +        }
> +    }
> +}
> +
> +void qemu_clk_set_callback(qemu_clk clk,
> +                           qemu_clk_on_rate_update_cb cb,
> +                           void *opaque)
> +{
> +    clk->cb = cb;
> +    clk->opaque = opaque;
> +}
> +
>  void qemu_clk_attach_to_device(DeviceState *d, qemu_clk clk, const char *name)
>  {
>      assert(name);
> --
> 2.5.5
>
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 04/11] qdev-monitor: print the device's clock with info qtree
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 04/11] qdev-monitor: print the device's clock with info qtree fred.konrad
@ 2016-06-29  0:33   ` Alistair Francis
  0 siblings, 0 replies; 38+ messages in thread
From: Alistair Francis @ 2016-06-29  0:33 UTC (permalink / raw)
  To: KONRAD Frédéric
  Cc: qemu-devel@nongnu.org Developers, Edgar Iglesias, Peter Maydell,
	Mark Burton, Alistair Francis

On Mon, Jun 13, 2016 at 9:27 AM,  <fred.konrad@greensocs.com> wrote:
> From: KONRAD Frederic <fred.konrad@greensocs.com>
>
> This prints the clock attached to a DeviceState when using "info qtree" monitor
> command.

Can you include an example of what this will look like?

Thanks,

Alistair

>
> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
> ---
>  include/qemu/qemu-clock.h |  9 +++++++++
>  qdev-monitor.c            |  2 ++
>  qemu-clock.c              | 28 ++++++++++++++++++++++++++++
>  3 files changed, 39 insertions(+)
>
> diff --git a/include/qemu/qemu-clock.h b/include/qemu/qemu-clock.h
> index 677de9a..265ec65 100644
> --- a/include/qemu/qemu-clock.h
> +++ b/include/qemu/qemu-clock.h
> @@ -124,4 +124,13 @@ void qemu_clk_set_callback(qemu_clk clk,
>                             qemu_clk_on_rate_update_cb cb,
>                             void *opaque);
>
> +/**
> + * qemu_clk_print:
> + * @dev: the device for which the clock need to be printed.
> + *
> + * Print the clock information for a given device.
> + *
> + */
> +void qemu_clk_print(Monitor *mon, DeviceState *dev, int indent);
> +
>  #endif /* QEMU_CLOCK_H */
> diff --git a/qdev-monitor.c b/qdev-monitor.c
> index e19617f..d6d1aa4 100644
> --- a/qdev-monitor.c
> +++ b/qdev-monitor.c
> @@ -28,6 +28,7 @@
>  #include "qemu/config-file.h"
>  #include "qemu/error-report.h"
>  #include "qemu/help_option.h"
> +#include "qemu/qemu-clock.h"
>
>  /*
>   * Aliases were a bad idea from the start.  Let's keep them
> @@ -684,6 +685,7 @@ static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
>                          ngl->num_out);
>          }
>      }
> +    qemu_clk_print(mon, dev, indent);
>      class = object_get_class(OBJECT(dev));
>      do {
>          qdev_print_props(mon, dev, DEVICE_CLASS(class)->props, indent);
> diff --git a/qemu-clock.c b/qemu-clock.c
> index 811d6a0..378a14d 100644
> --- a/qemu-clock.c
> +++ b/qemu-clock.c
> @@ -24,6 +24,7 @@
>  #include "qemu/qemu-clock.h"
>  #include "hw/hw.h"
>  #include "qapi/error.h"
> +#include "monitor/monitor.h"
>
>  /* #define DEBUG_QEMU_CLOCK */
>
> @@ -111,6 +112,33 @@ qemu_clk qemu_clk_get_pin(DeviceState *d, const char *name)
>      return QEMU_CLOCK(clk);
>  }
>
> +struct print_opaque {
> +    Monitor *mon;
> +    int indent;
> +};
> +
> +static int qemu_clk_print_rec(Object *obj, void *opaque)
> +{
> +    qemu_clk clk = (qemu_clk)(object_dynamic_cast(obj, TYPE_CLOCK));
> +    struct print_opaque *po = opaque;
> +
> +    if (clk) {
> +        monitor_printf(po->mon, "%*s" "qemu-clk \"%s\" %.1f\n", po->indent,
> +                       " ", clk->name, clk->out_rate);
> +    }
> +
> +    return 0;
> +}
> +
> +void qemu_clk_print(Monitor *mon, DeviceState *dev, int indent)
> +{
> +    struct print_opaque po;
> +
> +    po.indent = indent;
> +    po.mon = mon;
> +    object_child_foreach(OBJECT(dev), qemu_clk_print_rec, &po);
> +}
> +
>  static const TypeInfo qemu_clk_info = {
>      .name          = TYPE_CLOCK,
>      .parent        = TYPE_OBJECT,
> --
> 2.5.5
>
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 05/11] docs: add qemu-clock documentation
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 05/11] docs: add qemu-clock documentation fred.konrad
@ 2016-06-29  0:38   ` Alistair Francis
  2016-08-02  9:29     ` KONRAD Frederic
  2016-07-29 13:47   ` Peter Maydell
  1 sibling, 1 reply; 38+ messages in thread
From: Alistair Francis @ 2016-06-29  0:38 UTC (permalink / raw)
  To: KONRAD Frédéric
  Cc: qemu-devel@nongnu.org Developers, Edgar Iglesias, Peter Maydell,
	Mark Burton, Alistair Francis

On Mon, Jun 13, 2016 at 9:27 AM,  <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 | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 112 insertions(+)
>  create mode 100644 docs/clock.txt
>
> diff --git a/docs/clock.txt b/docs/clock.txt
> new file mode 100644
> index 0000000..f4ad4c8
> --- /dev/null
> +++ b/docs/clock.txt
> @@ -0,0 +1,112 @@
> +
> +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.
> +
> +Bounding 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_bound(clk_a, clk_b) will bound clk_a and clk_b.
> +
> +Binding two qemu-clk together is a unidirectional link which means that changing
> +the rate of clk_a will propagate to clk_b and not the opposite. The bound
> +process automatically refresh 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_bound(clk_a, clk_b);
> +qemu_clk_bound(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 float (*qemu_clk_rate_change_cb)(void *opaque, float 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:
> +float qemu_clk_rate_change_cb(void *opaque, float rate)
> +{
> +    return 4.0 * 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.
> +
> +NOTE: It's not recommended that the clock is driven by more than one clock as it
> +would mean that we don't know which clock trigger the callback.

Would this not be something worth knowing?

Thanks,

Alistair

> +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.0
> +    qemu-clk "vpll_to_lpd" 625000000.0
> +    qemu-clk "dp_stc_ref" 0.0
> +    qemu-clk "dpll_to_lpd" 12500000.0
> +    qemu-clk "acpu_clk" 0.0
> +    qemu-clk "pcie_ref" 0.0
> +    qemu-clk "topsw_main" 0.0
> +    qemu-clk "topsw_lsbus" 0.0
> +    qemu-clk "dp_audio_ref" 0.0
> +    qemu-clk "sata_ref" 0.0
> +    qemu-clk "dp_video_ref" 71428568.0
> +    qemu-clk "vpll_clk" 2500000000.0
> +    qemu-clk "apll_to_lpd" 12500000.0
> +    qemu-clk "dpll_clk" 50000000.0
> +    qemu-clk "gpu_ref" 0.0
> +    qemu-clk "aux_refclk" 0.0
> +    qemu-clk "video_clk" 27000000.0
> +    qemu-clk "gdma_ref" 0.0
> +    qemu-clk "gt_crx_ref_clk" 0.0
> +    qemu-clk "dbg_fdp" 0.0
> +    qemu-clk "apll_clk" 50000000.0
> +    qemu-clk "pss_alt_ref_clk" 0.0
> +    qemu-clk "ddr" 0.0
> +    qemu-clk "pss_ref_clk" 50000000.0
> +    qemu-clk "dpdma_ref" 0.0
> +    qemu-clk "dbg_tstmp" 0.0
> +    mmio 00000000fd1a0000/000000000000010c
> +
> +This way a DeviceState can have multiple clock input or output.
> +
> --
> 2.5.5
>
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 07/11] introduce zynqmp_crf
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 07/11] introduce zynqmp_crf fred.konrad
@ 2016-06-29  0:41   ` Alistair Francis
  0 siblings, 0 replies; 38+ messages in thread
From: Alistair Francis @ 2016-06-29  0:41 UTC (permalink / raw)
  To: KONRAD Frédéric
  Cc: qemu-devel@nongnu.org Developers, Edgar Iglesias, Peter Maydell,
	Mark Burton, Alistair Francis

On Mon, Jun 13, 2016 at 9:27 AM,  <fred.konrad@greensocs.com> wrote:
> From: KONRAD Frederic <fred.konrad@greensocs.com>
>
> This introduce Xilinx zynqmp-crf.
> It is extracted from the qemu xilinx tree (02d2f0203dd489ed30d9c8d90c14a52c57332b25) and is used as
> an example for the clock framework.

Watch out with this one, the newet register API sent to mainline is
differnent to the one we use internally.

This looks like it won't work with the newest version.

I think just leave it as is until the register API is accepted and
then fix it up then.

Thanks,

Alistair

> ---
>  hw/misc/Makefile.objs       |   1 +
>  hw/misc/xilinx_zynqmp_crf.c | 532 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 533 insertions(+)
>  create mode 100644 hw/misc/xilinx_zynqmp_crf.c
>
> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
> index e8b8855..c6e3c7f 100644
> --- a/hw/misc/Makefile.objs
> +++ b/hw/misc/Makefile.objs
> @@ -44,6 +44,7 @@ obj-$(CONFIG_SLAVIO) += slavio_misc.o
>  obj-$(CONFIG_ZYNQ) += zynq_slcr.o
>  obj-$(CONFIG_ZYNQ) += zynq-xadc.o
>  obj-$(CONFIG_ZYNQ) += xlnx-zynqmp-iou-slcr.o
> +obj-$(CONFIG_ZYNQ) += xilinx_zynqmp_crf.o
>  obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o
>  obj-$(CONFIG_MIPS_CPS) += mips_cmgcr.o
>  obj-$(CONFIG_MIPS_CPS) += mips_cpc.o
> diff --git a/hw/misc/xilinx_zynqmp_crf.c b/hw/misc/xilinx_zynqmp_crf.c
> new file mode 100644
> index 0000000..b1bf2a6
> --- /dev/null
> +++ b/hw/misc/xilinx_zynqmp_crf.c
> @@ -0,0 +1,532 @@
> +/*
> + * QEMU model of the CRF_APB APB control registers for clock controller. The
> + * RST_ctrl_fpd will be added to this as well
> + *
> + * Copyright (c) 2014 Xilinx Inc.
> + *
> + * Autogenerated by xregqemu.py 2014-01-22.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/sysbus.h"
> +#include "hw/register.h"
> +#include "qemu/bitops.h"
> +#include "qemu/log.h"
> +
> +#ifndef XILINX_CRF_APB_ERR_DEBUG
> +#define XILINX_CRF_APB_ERR_DEBUG 0
> +#endif
> +
> +#define TYPE_XILINX_CRF_APB "xlnx.zynqmp_crf"
> +
> +#define XILINX_CRF_APB(obj) \
> +     OBJECT_CHECK(CRF_APB, (obj), TYPE_XILINX_CRF_APB)
> +
> +REG32(ERR_CTRL, 0x0)
> +    FIELD(ERR_CTRL, SLVERR_ENABLE, 1, 0)
> +REG32(IR_STATUS, 0x4)
> +    FIELD(IR_STATUS, ADDR_DECODE_ERR, 1, 0)
> +REG32(IR_MASK, 0x8)
> +    FIELD(IR_MASK, ADDR_DECODE_ERR, 1, 0)
> +REG32(IR_ENABLE, 0xc)
> +    FIELD(IR_ENABLE, ADDR_DECODE_ERR, 1, 0)
> +REG32(IR_DISABLE, 0x10)
> +    FIELD(IR_DISABLE, ADDR_DECODE_ERR, 1, 0)
> +REG32(CRF_ECO, 0x18)
> +REG32(APLL_CTRL, 0x20)
> +    FIELD(APLL_CTRL, POST_SRC, 3, 24)
> +    FIELD(APLL_CTRL, PRE_SRC, 3, 20)
> +    FIELD(APLL_CTRL, CLKOUTDIV, 1, 17)
> +    FIELD(APLL_CTRL, DIV2, 1, 16)
> +    FIELD(APLL_CTRL, FBDIV, 7, 8)
> +    FIELD(APLL_CTRL, BYPASS, 1, 3)
> +    FIELD(APLL_CTRL, RESET, 1, 0)
> +REG32(APLL_CFG, 0x24)
> +    FIELD(APLL_CFG, LOCK_DLY, 7, 25)
> +    FIELD(APLL_CFG, LOCK_CNT, 10, 13)
> +    FIELD(APLL_CFG, LFHF, 2, 10)
> +    FIELD(APLL_CFG, CP, 4, 5)
> +    FIELD(APLL_CFG, RES, 4, 0)
> +REG32(APLL_FRAC_CFG, 0x28)
> +    FIELD(APLL_FRAC_CFG, ENABLED, 1, 31)
> +    FIELD(APLL_FRAC_CFG, SEED, 3, 22)
> +    FIELD(APLL_FRAC_CFG, ALGRTHM, 1, 19)
> +    FIELD(APLL_FRAC_CFG, ORDER, 1, 18)
> +    FIELD(APLL_FRAC_CFG, DATA, 16, 0)
> +REG32(DPLL_CTRL, 0x2c)
> +    FIELD(DPLL_CTRL, POST_SRC, 3, 24)
> +    FIELD(DPLL_CTRL, PRE_SRC, 3, 20)
> +    FIELD(DPLL_CTRL, CLKOUTDIV, 1, 17)
> +    FIELD(DPLL_CTRL, DIV2, 1, 16)
> +    FIELD(DPLL_CTRL, FBDIV, 7, 8)
> +    FIELD(DPLL_CTRL, BYPASS, 1, 3)
> +    FIELD(DPLL_CTRL, RESET, 1, 0)
> +REG32(DPLL_CFG, 0x30)
> +    FIELD(DPLL_CFG, LOCK_DLY, 7, 25)
> +    FIELD(DPLL_CFG, LOCK_CNT, 10, 13)
> +    FIELD(DPLL_CFG, LFHF, 2, 10)
> +    FIELD(DPLL_CFG, CP, 4, 5)
> +    FIELD(DPLL_CFG, RES, 4, 0)
> +REG32(DPLL_FRAC_CFG, 0x34)
> +    FIELD(DPLL_FRAC_CFG, ENABLED, 1, 31)
> +    FIELD(DPLL_FRAC_CFG, SEED, 3, 22)
> +    FIELD(DPLL_FRAC_CFG, ALGRTHM, 1, 19)
> +    FIELD(DPLL_FRAC_CFG, ORDER, 1, 18)
> +    FIELD(DPLL_FRAC_CFG, DATA, 16, 0)
> +REG32(VPLL_CTRL, 0x38)
> +    FIELD(VPLL_CTRL, POST_SRC, 3, 24)
> +    FIELD(VPLL_CTRL, PRE_SRC, 3, 20)
> +    FIELD(VPLL_CTRL, CLKOUTDIV, 1, 17)
> +    FIELD(VPLL_CTRL, DIV2, 1, 16)
> +    FIELD(VPLL_CTRL, FBDIV, 7, 8)
> +    FIELD(VPLL_CTRL, BYPASS, 1, 3)
> +    FIELD(VPLL_CTRL, RESET, 1, 0)
> +REG32(VPLL_CFG, 0x3c)
> +    FIELD(VPLL_CFG, LOCK_DLY, 7, 25)
> +    FIELD(VPLL_CFG, LOCK_CNT, 10, 13)
> +    FIELD(VPLL_CFG, LFHF, 2, 10)
> +    FIELD(VPLL_CFG, CP, 4, 5)
> +    FIELD(VPLL_CFG, RES, 4, 0)
> +REG32(VPLL_FRAC_CFG, 0x40)
> +    FIELD(VPLL_FRAC_CFG, ENABLED, 1, 31)
> +    FIELD(VPLL_FRAC_CFG, SEED, 3, 22)
> +    FIELD(VPLL_FRAC_CFG, ALGRTHM, 1, 19)
> +    FIELD(VPLL_FRAC_CFG, ORDER, 1, 18)
> +    FIELD(VPLL_FRAC_CFG, DATA, 16, 0)
> +REG32(PLL_STATUS, 0x44)
> +    FIELD(PLL_STATUS, VPLL_STABLE, 1, 5)
> +    FIELD(PLL_STATUS, DPLL_STABLE, 1, 4)
> +    FIELD(PLL_STATUS, APLL_STABLE, 1, 3)
> +    FIELD(PLL_STATUS, VPLL_LOCK, 1, 2)
> +    FIELD(PLL_STATUS, DPLL_LOCK, 1, 1)
> +    FIELD(PLL_STATUS, APLL_LOCK, 1, 0)
> +REG32(APLL_TO_LPD_CTRL, 0x48)
> +    FIELD(APLL_TO_LPD_CTRL, DIVISOR0, 6, 8)
> +REG32(DPLL_TO_LPD_CTRL, 0x4c)
> +    FIELD(DPLL_TO_LPD_CTRL, DIVISOR0, 6, 8)
> +REG32(VPLL_TO_LPD_CTRL, 0x50)
> +    FIELD(VPLL_TO_LPD_CTRL, DIVISOR0, 6, 8)
> +REG32(CPU_A9_CTRL, 0x60)
> +    FIELD(CPU_A9_CTRL, A9CLKSTOP, 2, 26)
> +    FIELD(CPU_A9_CTRL, CLKACT_HALF, 1, 25)
> +    FIELD(CPU_A9_CTRL, CLKACT_FULL, 1, 24)
> +    FIELD(CPU_A9_CTRL, DIVISOR0, 6, 8)
> +    FIELD(CPU_A9_CTRL, SRCSEL, 3, 0)
> +REG32(DBG_TRACE_CTRL, 0x64)
> +    FIELD(DBG_TRACE_CTRL, CLKACT, 1, 24)
> +    FIELD(DBG_TRACE_CTRL, DIVISOR0, 6, 8)
> +    FIELD(DBG_TRACE_CTRL, SRCSEL, 3, 0)
> +REG32(DBG_FPD_CTRL, 0x68)
> +    FIELD(DBG_FPD_CTRL, CLKACT, 1, 24)
> +    FIELD(DBG_FPD_CTRL, DIVISOR0, 6, 8)
> +    FIELD(DBG_FPD_CTRL, SRCSEL, 3, 0)
> +REG32(DP_VIDEO_REF_CTRL, 0x70)
> +    FIELD(DP_VIDEO_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(DP_VIDEO_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(DP_VIDEO_REF_CTRL, SRCSEL, 3, 0)
> +REG32(DP_AUDIO_REF_CTRL, 0x74)
> +    FIELD(DP_AUDIO_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(DP_AUDIO_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(DP_AUDIO_REF_CTRL, SRCSEL, 3, 0)
> +REG32(DP_LINK_REF_CTRL, 0x78)
> +    FIELD(DP_LINK_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(DP_LINK_REF_CTRL, DIVISOR1, 6, 16)
> +    FIELD(DP_LINK_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(DP_LINK_REF_CTRL, SRCSEL, 3, 0)
> +REG32(DP_STC_REF_CTRL, 0x7c)
> +    FIELD(DP_STC_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(DP_STC_REF_CTRL, DIVISOR1, 6, 16)
> +    FIELD(DP_STC_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(DP_STC_REF_CTRL, SRCSEL, 3, 0)
> +REG32(DDR_CTRL, 0x80)
> +    FIELD(DDR_CTRL, CLKACT, 1, 24)
> +    FIELD(DDR_CTRL, DIVISOR0, 6, 8)
> +    FIELD(DDR_CTRL, SRCSEL, 3, 0)
> +REG32(GPU_REF_CTRL, 0x84)
> +    FIELD(GPU_REF_CTRL, PP1_CLKACT, 1, 26)
> +    FIELD(GPU_REF_CTRL, PP0_CLKACT, 1, 25)
> +    FIELD(GPU_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(GPU_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(GPU_REF_CTRL, SRCSEL, 3, 0)
> +REG32(AFI0_REF_CTRL, 0x88)
> +    FIELD(AFI0_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(AFI0_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(AFI0_REF_CTRL, SRCSEL, 3, 0)
> +REG32(AFI1_REF_CTRL, 0x8c)
> +    FIELD(AFI1_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(AFI1_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(AFI1_REF_CTRL, SRCSEL, 3, 0)
> +REG32(AFI2_REF_CTRL, 0x90)
> +    FIELD(AFI2_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(AFI2_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(AFI2_REF_CTRL, SRCSEL, 3, 0)
> +REG32(AFI3_REF_CTRL, 0x94)
> +    FIELD(AFI3_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(AFI3_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(AFI3_REF_CTRL, SRCSEL, 3, 0)
> +REG32(AFI4_REF_CTRL, 0x98)
> +    FIELD(AFI4_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(AFI4_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(AFI4_REF_CTRL, SRCSEL, 3, 0)
> +REG32(AFI5_REF_CTRL, 0x9c)
> +    FIELD(AFI5_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(AFI5_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(AFI5_REF_CTRL, SRCSEL, 3, 0)
> +REG32(SATA_REF_CTRL, 0xa0)
> +    FIELD(SATA_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(SATA_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(SATA_REF_CTRL, SRCSEL, 3, 0)
> +REG32(PCIE_REF_CTRL, 0xb4)
> +    FIELD(PCIE_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(PCIE_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(PCIE_REF_CTRL, SRCSEL, 3, 0)
> +REG32(GDMA_REF_CTRL, 0xb8)
> +    FIELD(GDMA_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(GDMA_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(GDMA_REF_CTRL, SRCSEL, 3, 0)
> +REG32(DPDMA_REF_CTRL, 0xbc)
> +    FIELD(DPDMA_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(DPDMA_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(DPDMA_REF_CTRL, SRCSEL, 3, 0)
> +REG32(TOPSW_MAIN_CTRL, 0xc0)
> +    FIELD(TOPSW_MAIN_CTRL, CLKACT, 1, 24)
> +    FIELD(TOPSW_MAIN_CTRL, DIVISOR0, 6, 8)
> +    FIELD(TOPSW_MAIN_CTRL, SRCSEL, 3, 0)
> +REG32(TOPSW_LSBUS_CTRL, 0xc4)
> +    FIELD(TOPSW_LSBUS_CTRL, CLKACT, 1, 24)
> +    FIELD(TOPSW_LSBUS_CTRL, DIVISOR0, 6, 8)
> +    FIELD(TOPSW_LSBUS_CTRL, SRCSEL, 3, 0)
> +REG32(GTGREF0_REF_CTRL, 0xc8)
> +    FIELD(GTGREF0_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(GTGREF0_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(GTGREF0_REF_CTRL, SRCSEL, 3, 0)
> +REG32(GTGREF1_REF_CTRL, 0xcc)
> +    FIELD(GTGREF1_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(GTGREF1_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(GTGREF1_REF_CTRL, SRCSEL, 3, 0)
> +REG32(DFT300_REF_CTRL, 0xd0)
> +    FIELD(DFT300_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(DFT300_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(DFT300_REF_CTRL, SRCSEL, 3, 0)
> +REG32(DFT270_REF_CTRL, 0xd4)
> +    FIELD(DFT270_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(DFT270_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(DFT270_REF_CTRL, SRCSEL, 3, 0)
> +REG32(DFT250_REF_CTRL, 0xd8)
> +    FIELD(DFT250_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(DFT250_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(DFT250_REF_CTRL, SRCSEL, 3, 0)
> +REG32(DFT125_REF_CTRL, 0xdc)
> +    FIELD(DFT125_REF_CTRL, CLKACT, 1, 24)
> +    FIELD(DFT125_REF_CTRL, DIVISOR0, 6, 8)
> +    FIELD(DFT125_REF_CTRL, SRCSEL, 3, 0)
> +
> +REG32(RST_FPD_TOP, 0x100)
> +    FIELD(RST_FPD_TOP, PCIE_BRDG_RESET, 1, 18)
> +    FIELD(RST_FPD_TOP, PCIE_CTRL_RESET, 1, 17)
> +    FIELD(RST_FPD_TOP, DP_RESET, 1, 16)
> +    FIELD(RST_FPD_TOP, AFI_FM5_RESET, 1, 12)
> +    FIELD(RST_FPD_TOP, AFI_FM4_RESET, 1, 11)
> +    FIELD(RST_FPD_TOP, AFI_FM3_RESET, 1, 10)
> +    FIELD(RST_FPD_TOP, AFI_FM2_RESET, 1, 9)
> +    FIELD(RST_FPD_TOP, AFI_FM1_RESET, 1, 8)
> +    FIELD(RST_FPD_TOP, AFI_FM0_RESET, 1, 7)
> +    FIELD(RST_FPD_TOP, GDMA_RESET, 1, 6)
> +    FIELD(RST_FPD_TOP, GPU_PP1_RESET, 1, 5)
> +    FIELD(RST_FPD_TOP, GPU_PP0_RESET, 1, 4)
> +    FIELD(RST_FPD_TOP, GPU_RESET, 1, 3)
> +    FIELD(RST_FPD_TOP, GT_RESET, 1, 2)
> +    FIELD(RST_FPD_TOP, SATA_RESET, 1, 1)
> +REG32(RST_FPD_APU, 0x104)
> +    FIELD(RST_FPD_APU, PERI_RESET, 1, 13)
> +    FIELD(RST_FPD_APU, SCU_RESET, 1, 12)
> +    FIELD(RST_FPD_APU, CPU1_AWDT_RESET, 1, 9)
> +    FIELD(RST_FPD_APU, CPU0_AWDT_RESET, 1, 8)
> +    FIELD(RST_FPD_APU, CPU1_CP14_RESET, 1, 5)
> +    FIELD(RST_FPD_APU, CPU0_CP14_RESET, 1, 4)
> +    FIELD(RST_FPD_APU, CPU3_A9_RESET, 1, 3)
> +    FIELD(RST_FPD_APU, CPU2_A9_RESET, 1, 2)
> +    FIELD(RST_FPD_APU, CPU1_A9_RESET, 1, 1)
> +    FIELD(RST_FPD_APU, CPU0_A9_RESET, 1, 0)
> +REG32(RST_DDR_SS, 0x108)
> +    FIELD(RST_DDR_SS, DDR_RESET, 1, 3)
> +    FIELD(RST_DDR_SS, APM_RESET, 1, 2)
> +    FIELD(RST_DDR_SS, QOS_RESET, 1, 1)
> +    FIELD(RST_DDR_SS, XMPU_RESET, 1, 0)
> +
> +#define R_MAX (R_RST_DDR_SS + 1)
> +
> +typedef struct CRF_APB {
> +    SysBusDevice parent_obj;
> +    MemoryRegion iomem;
> +    qemu_irq irq_ir;
> +
> +    uint32_t regs[R_MAX];
> +    RegisterInfo regs_info[R_MAX];
> +} CRF_APB;
> +
> +static const MemoryRegionOps crf_apb_ops = {
> +    .read = register_read_memory_le,
> +    .write = register_write_memory_le,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 4,
> +    },
> +};
> +
> +static void ir_update_irq(CRF_APB *s)
> +{
> +    bool pending = s->regs[R_IR_STATUS] & ~s->regs[R_IR_MASK];
> +    qemu_set_irq(s->irq_ir, pending);
> +}
> +
> +static void ir_status_postw(RegisterInfo *reg, uint64_t val64)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
> +    ir_update_irq(s);
> +}
> +
> +static uint64_t ir_enable_prew(RegisterInfo *reg, uint64_t val64)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
> +    uint32_t val = val64;
> +
> +    s->regs[R_IR_MASK] &= ~val;
> +    ir_update_irq(s);
> +    return 0;
> +}
> +
> +static uint64_t ir_disable_prew(RegisterInfo *reg, uint64_t val64)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
> +    uint32_t val = val64;
> +
> +    s->regs[R_IR_MASK] |= val;
> +    ir_update_irq(s);
> +    return 0;
> +}
> +
> +static RegisterAccessInfo crf_apb_regs_info[] = {
> +    {   .name = "ERR_CTRL",  .decode.addr = A_ERR_CTRL,
> +    },{ .name = "IR_STATUS",  .decode.addr = A_IR_STATUS,
> +        .w1c = 0x1,
> +        .post_write = ir_status_postw,
> +    },{ .name = "IR_MASK",  .decode.addr = A_IR_MASK,
> +        .reset = 0x1,
> +        .ro = 0x1,
> +    },{ .name = "IR_ENABLE",  .decode.addr = A_IR_ENABLE,
> +        .pre_write = ir_enable_prew,
> +    },{ .name = "IR_DISABLE",  .decode.addr = A_IR_DISABLE,
> +        .pre_write = ir_disable_prew,
> +    },{ .name = "CRF_ECO",  .decode.addr = A_CRF_ECO,
> +    },{ .name = "APLL_CTRL",  .decode.addr = A_APLL_CTRL,
> +        .reset = 0x2809,
> +        .rsvd = 0xf88c80f6L,
> +    },{ .name = "APLL_CFG",  .decode.addr = A_APLL_CFG,
> +        .rsvd = 0x1801210,
> +    },{ .name = "APLL_FRAC_CFG",  .decode.addr = A_APLL_FRAC_CFG,
> +        .rsvd = 0x7e330000,
> +    },{ .name = "DPLL_CTRL",  .decode.addr = A_DPLL_CTRL,
> +        .reset = 0x2809,
> +        .rsvd = 0xf88c80f6L,
> +    },{ .name = "DPLL_CFG",  .decode.addr = A_DPLL_CFG,
> +        .rsvd = 0x1801210,
> +    },{ .name = "DPLL_FRAC_CFG",  .decode.addr = A_DPLL_FRAC_CFG,
> +        .rsvd = 0x7e330000,
> +    },{ .name = "VPLL_CTRL",  .decode.addr = A_VPLL_CTRL,
> +        .reset = 0x2809,
> +        .rsvd = 0xf88c80f6L,
> +    },{ .name = "VPLL_CFG",  .decode.addr = A_VPLL_CFG,
> +        .rsvd = 0x1801210,
> +    },{ .name = "VPLL_FRAC_CFG",  .decode.addr = A_VPLL_FRAC_CFG,
> +        .rsvd = 0x7e330000,
> +    },{ .name = "PLL_STATUS",  .decode.addr = A_PLL_STATUS,
> +        .reset = 0x3f,
> +        .rsvd = 0xc0,
> +        .ro = 0x3f,
> +    },{ .name = "APLL_TO_LPD_CTRL",  .decode.addr = A_APLL_TO_LPD_CTRL,
> +        .reset = 0x400,
> +        .rsvd = 0xc0ff,
> +    },{ .name = "DPLL_TO_LPD_CTRL",  .decode.addr = A_DPLL_TO_LPD_CTRL,
> +        .reset = 0x400,
> +        .rsvd = 0xc0ff,
> +    },{ .name = "VPLL_TO_LPD_CTRL",  .decode.addr = A_VPLL_TO_LPD_CTRL,
> +        .reset = 0x400,
> +        .rsvd = 0xc0ff,
> +    },{ .name = "CPU_A9_CTRL",  .decode.addr = A_CPU_A9_CTRL,
> +        .reset = 0xf000400,
> +        .rsvd = 0xf0ffc0f8L,
> +    },{ .name = "DBG_TRACE_CTRL",  .decode.addr = A_DBG_TRACE_CTRL,
> +        .reset = 0x2500,
> +        .rsvd = 0xfeffc0f8L,
> +    },{ .name = "DBG_FPD_CTRL",  .decode.addr = A_DBG_FPD_CTRL,
> +        .reset = 0x1002500,
> +        .rsvd = 0xfeffc0f8L,
> +    },{ .name = "DP_VIDEO_REF_CTRL",  .decode.addr = A_DP_VIDEO_REF_CTRL,
> +        .reset = 0x1002300,
> +        .rsvd = 0xfeffc0f8L,
> +    },{ .name = "DP_AUDIO_REF_CTRL",  .decode.addr = A_DP_AUDIO_REF_CTRL,
> +        .reset = 0x1002300,
> +        .rsvd = 0xfeffc0f8L,
> +    },{ .name = "DP_LINK_REF_CTRL",  .decode.addr = A_DP_LINK_REF_CTRL,
> +        .reset = 0x1203200,
> +        .rsvd = 0xfec0c0f8L,
> +    },{ .name = "DP_STC_REF_CTRL",  .decode.addr = A_DP_STC_REF_CTRL,
> +        .reset = 0x1203200,
> +        .rsvd = 0xfec0c0f8L,
> +    },{ .name = "DDR_CTRL",  .decode.addr = A_DDR_CTRL,
> +        .reset = 0x1000500,
> +        .rsvd = 0xfeffc0f8L,
> +    },{ .name = "GPU_REF_CTRL",  .decode.addr = A_GPU_REF_CTRL,
> +        .reset = 0x1500,
> +        .rsvd = 0xf8ffc0f8L,
> +    },{ .name = "AFI0_REF_CTRL",  .decode.addr = A_AFI0_REF_CTRL,
> +        .reset = 0x600,
> +        .rsvd = 0x7effc0f8,
> +    },{ .name = "AFI1_REF_CTRL",  .decode.addr = A_AFI1_REF_CTRL,
> +        .reset = 0x600,
> +        .rsvd = 0x7effc0f8,
> +    },{ .name = "AFI2_REF_CTRL",  .decode.addr = A_AFI2_REF_CTRL,
> +        .reset = 0x600,
> +        .rsvd = 0x7effc0f8,
> +    },{ .name = "AFI3_REF_CTRL",  .decode.addr = A_AFI3_REF_CTRL,
> +        .reset = 0x600,
> +        .rsvd = 0x7effc0f8,
> +    },{ .name = "AFI4_REF_CTRL",  .decode.addr = A_AFI4_REF_CTRL,
> +        .reset = 0x600,
> +        .rsvd = 0x7effc0f8,
> +    },{ .name = "AFI5_REF_CTRL",  .decode.addr = A_AFI5_REF_CTRL,
> +        .reset = 0x600,
> +        .rsvd = 0x7effc0f8,
> +    },{ .name = "SATA_REF_CTRL",  .decode.addr = A_SATA_REF_CTRL,
> +        .reset = 0x1001600,
> +        .rsvd = 0xfeffc0f8L,
> +    },{ .name = "PCIE_REF_CTRL",  .decode.addr = A_PCIE_REF_CTRL,
> +        .reset = 0x1500,
> +        .rsvd = 0xfeffc0f8L,
> +    },{ .name = "GDMA_REF_CTRL",  .decode.addr = A_GDMA_REF_CTRL,
> +        .reset = 0x1000500,
> +        .rsvd = 0xfeffc0f8L,
> +    },{ .name = "DPDMA_REF_CTRL",  .decode.addr = A_DPDMA_REF_CTRL,
> +        .reset = 0x1000500,
> +        .rsvd = 0xfeffc0f8L,
> +    },{ .name = "TOPSW_MAIN_CTRL",  .decode.addr = A_TOPSW_MAIN_CTRL,
> +        .reset = 0x1000500,
> +        .rsvd = 0xfeffc0f8L,
> +    },{ .name = "TOPSW_LSBUS_CTRL",  .decode.addr = A_TOPSW_LSBUS_CTRL,
> +        .reset = 0x1000800,
> +        .rsvd = 0xfeffc0f8L,
> +    },{ .name = "GTGREF0_REF_CTRL",  .decode.addr = A_GTGREF0_REF_CTRL,
> +        .reset = 0x800,
> +        .rsvd = 0xfeffc0f8L,
> +    },{ .name = "GTGREF1_REF_CTRL",  .decode.addr = A_GTGREF1_REF_CTRL,
> +        .reset = 0x800,
> +        .rsvd = 0xfeffc0f8L,
> +    },{ .name = "DFT300_REF_CTRL",  .decode.addr = A_DFT300_REF_CTRL,
> +        .reset = 0x800,
> +        .rsvd = 0xfeffc0f8L,
> +    },{ .name = "DFT270_REF_CTRL",  .decode.addr = A_DFT270_REF_CTRL,
> +        .reset = 0x800,
> +        .rsvd = 0xfeffc0f8L,
> +    },{ .name = "DFT250_REF_CTRL",  .decode.addr = A_DFT250_REF_CTRL,
> +        .reset = 0x800,
> +        .rsvd = 0xfeffc0f8L,
> +    },{ .name = "DFT125_REF_CTRL",  .decode.addr = A_DFT125_REF_CTRL,
> +        .reset = 0x800,
> +        .rsvd = 0xfeffc0f8L,
> +    },{ .name = "RST_FPD_TOP",  .decode.addr = A_RST_FPD_TOP,
> +        .reset = 0x71ffe,
> +        .rsvd = 0xf8e001,
> +    },{ .name = "RST_FPD_APU",  .decode.addr = A_RST_FPD_APU,
> +        .reset = 0x334f,
> +        .rsvd = 0xffcccc,
> +        .gpios = (RegisterGPIOMapping[]) {
> +            { .name = "RST_A9", .bit_pos = 0, .num = 4 },
> +            {},
> +        },
> +    },{ .name = "RST_DDR_SS",  .decode.addr = A_RST_DDR_SS,
> +        .reset = 0xf,
> +        .rsvd = 0xf0,
> +    }
> +};
> +
> +static void crf_apb_reset(DeviceState *dev)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(dev);
> +    unsigned int i;
> +
> +    for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
> +        register_reset(&s->regs_info[i]);
> +    }
> +
> +    ir_update_irq(s);
> +}
> +
> +static void crf_apb_init(Object *obj)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(obj);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
> +
> +    memory_region_init(&s->iomem, obj, TYPE_XILINX_CRF_APB, R_MAX * 4);
> +    register_init_block32(DEVICE(obj), crf_apb_regs_info,
> +                          ARRAY_SIZE(crf_apb_regs_info),
> +                          s->regs_info, s->regs, &s->iomem,
> +                          &crf_apb_ops,
> +                          XILINX_CRF_APB_ERR_DEBUG,
> +                          R_RST_DDR_SS);
> +    sysbus_init_mmio(sbd, &s->iomem);
> +    sysbus_init_irq(sbd, &s->irq_ir);
> +}
> +
> +static const VMStateDescription vmstate_crf_apb = {
> +    .name = TYPE_XILINX_CRF_APB,
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32_ARRAY(regs, CRF_APB, R_MAX),
> +        VMSTATE_END_OF_LIST(),
> +    }
> +};
> +
> +static void crf_apb_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->reset = crf_apb_reset;
> +    dc->vmsd = &vmstate_crf_apb;
> +}
> +
> +static const TypeInfo crf_apb_info = {
> +    .name          = TYPE_XILINX_CRF_APB,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(CRF_APB),
> +    .class_init    = crf_apb_class_init,
> +    .instance_init = crf_apb_init,
> +};
> +
> +static void crf_apb_register_types(void)
> +{
> +    type_register_static(&crf_apb_info);
> +}
> +
> +type_init(crf_apb_register_types)
> --
> 2.5.5
>
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 06/11] introduce fixed-clock
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 06/11] introduce fixed-clock fred.konrad
@ 2016-07-01 23:07   ` Alistair Francis
  2016-08-02 11:56     ` KONRAD Frederic
  0 siblings, 1 reply; 38+ messages in thread
From: Alistair Francis @ 2016-07-01 23:07 UTC (permalink / raw)
  To: KONRAD Frédéric
  Cc: qemu-devel@nongnu.org Developers, Edgar Iglesias, Peter Maydell,
	Mark Burton, Alistair Francis

On Mon, Jun 13, 2016 at 9:27 AM,  <fred.konrad@greensocs.com> wrote:
> From: KONRAD Frederic <fred.konrad@greensocs.com>
>
> This is a fixed clock device.
> It justs behave as an empty device with a parametrable output rate.
>
> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
> ---
>  hw/misc/Makefile.objs         |  2 +
>  hw/misc/fixed-clock.c         | 87 +++++++++++++++++++++++++++++++++++++++++++
>  include/hw/misc/fixed-clock.h | 30 +++++++++++++++
>  3 files changed, 119 insertions(+)
>  create mode 100644 hw/misc/fixed-clock.c
>  create mode 100644 include/hw/misc/fixed-clock.h
>
> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
> index e504463..e8b8855 100644
> --- a/hw/misc/Makefile.objs
> +++ b/hw/misc/Makefile.objs
> @@ -52,3 +52,5 @@ obj-$(CONFIG_MIPS_ITU) += mips_itu.o
>  obj-$(CONFIG_PVPANIC) += pvpanic.o
>  obj-$(CONFIG_EDU) += edu.o
>  obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
> +
> +obj-y += fixed-clock.o
> diff --git a/hw/misc/fixed-clock.c b/hw/misc/fixed-clock.c
> new file mode 100644
> index 0000000..c273a91
> --- /dev/null
> +++ b/hw/misc/fixed-clock.c
> @@ -0,0 +1,87 @@
> +/*
> + * Fixed clock
> + *
> + *  Copyright (C) 2016 : GreenSocs Ltd
> + *      http://www.greensocs.com/ , email: info@greensocs.com
> + *
> + *  Frederic Konrad   <fred.konrad@greensocs.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/qdev.h"
> +#include "hw/misc/fixed-clock.h"
> +#include "qemu/qemu-clock.h"
> +#include "qapi/error.h"
> +
> +/* #define DEBUG_FIXED_CLOCK */

Don't include this.

> +
> +#ifdef DEBUG_FIXED_CLOCK
> +#define DPRINTF(fmt, ...) \
> +do { printf("fixed-clock: " fmt , ## __VA_ARGS__); } while (0)

It might be better to use __func__ here.

It should also be qemu_log instead of printf().

> +#else
> +#define DPRINTF(fmt, ...) do { } while (0)
> +#endif
> +
> +typedef struct {
> +    DeviceState parent_obj;
> +
> +    uint32_t rate;
> +    struct qemu_clk out;
> +} FixedClock;

Doesn't this need to be in the header file?

> +
> +static Property fixed_clock_properties[] = {
> +    DEFINE_PROP_UINT32("rate", FixedClock, rate, 0),
> +    DEFINE_PROP_END_OF_LIST()
> +};
> +
> +static void fixed_clock_realizefn(DeviceState *d, Error **errp)

dev instead of d

Thanks,

Alistair

> +{
> +    FixedClock *s = FIXED_CLOCK(d);
> +
> +    qemu_clk_update_rate(&s->out, s->rate);
> +}
> +
> +static void fixed_clock_instance_init(Object *obj)
> +{
> +    FixedClock *s = FIXED_CLOCK(obj);
> +
> +    object_initialize(&s->out, sizeof(s->out), TYPE_CLOCK);
> +    qemu_clk_attach_to_device(DEVICE(obj), &s->out, "clk_out");
> +}
> +
> +static void fixed_clock_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->realize = fixed_clock_realizefn;
> +    dc->props = fixed_clock_properties;
> +}
> +
> +static const TypeInfo fixed_clock_info = {
> +    .name          = TYPE_FIXED_CLOCK,
> +    .parent        = TYPE_DEVICE,
> +    .instance_size = sizeof(FixedClock),
> +    .instance_init = fixed_clock_instance_init,
> +    .class_init    = fixed_clock_class_init,
> +};
> +
> +static void fixed_clock_register_types(void)
> +{
> +    type_register_static(&fixed_clock_info);
> +}
> +
> +type_init(fixed_clock_register_types);
> diff --git a/include/hw/misc/fixed-clock.h b/include/hw/misc/fixed-clock.h
> new file mode 100644
> index 0000000..1376444
> --- /dev/null
> +++ b/include/hw/misc/fixed-clock.h
> @@ -0,0 +1,30 @@
> +/*
> + * Fixed clock
> + *
> + *  Copyright (C) 2016 : GreenSocs Ltd
> + *      http://www.greensocs.com/ , email: info@greensocs.com
> + *
> + *  Frederic Konrad   <fred.konrad@greensocs.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#ifndef FIXED_CLOCK_H
> +#define FIXED_CLOCK_H
> +
> +#define TYPE_FIXED_CLOCK "fixed-clock"
> +#define FIXED_CLOCK(obj) OBJECT_CHECK(FixedClock, (obj), TYPE_FIXED_CLOCK)
> +
> +#endif /* FIXED_CLOCK_H */
> --
> 2.5.5
>
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 10/11] zynqmp: add the zynqmp_crf to the platform
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 10/11] zynqmp: add the zynqmp_crf to the platform fred.konrad
@ 2016-07-01 23:11   ` Alistair Francis
  2016-08-02 12:36     ` KONRAD Frederic
  0 siblings, 1 reply; 38+ messages in thread
From: Alistair Francis @ 2016-07-01 23:11 UTC (permalink / raw)
  To: KONRAD Frédéric
  Cc: qemu-devel@nongnu.org Developers, Edgar Iglesias, Peter Maydell,
	Mark Burton, Alistair Francis

On Mon, Jun 13, 2016 at 9:27 AM,  <fred.konrad@greensocs.com> wrote:
> From: KONRAD Frederic <fred.konrad@greensocs.com>
>
> This adds the zynqmp_crf to the zynqmp platform.
>
> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
> ---
>  hw/arm/xlnx-zynqmp.c         | 7 +++++++
>  include/hw/arm/xlnx-zynqmp.h | 1 +
>  2 files changed, 8 insertions(+)
>
> diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
> index 4d504da..a8b7669 100644
> --- a/hw/arm/xlnx-zynqmp.c
> +++ b/hw/arm/xlnx-zynqmp.c
> @@ -135,6 +135,11 @@ static void xlnx_zynqmp_init(Object *obj)
>                            TYPE_XILINX_SPIPS);
>          qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default());
>      }
> +
> +    s->crf = object_new("xlnx.zynqmp_crf");
> +    qdev_set_parent_bus(DEVICE(s->crf), sysbus_get_default());
> +    object_property_add_child(obj, "xlnx.zynqmp_crf", OBJECT(s->crf),
> +                              &error_abort);
>  }
>
>  static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
> @@ -366,6 +371,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
>                                    &error_abort);
>         g_free(bus_name);
>      }
> +
> +    sysbus_mmio_map(SYS_BUS_DEVICE(s->crf), 0, 0xFD1A0000);

Shouldn't this be realised?

Also macro for the address.

>  }
>
>  static Property xlnx_zynqmp_props[] = {
> diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h
> index 2332596..78fed6e 100644
> --- a/include/hw/arm/xlnx-zynqmp.h
> +++ b/include/hw/arm/xlnx-zynqmp.h
> @@ -81,6 +81,7 @@ typedef struct XlnxZynqMPState {
>      SysbusAHCIState sata;
>      SDHCIState sdhci[XLNX_ZYNQMP_NUM_SDHCI];
>      XilinxSPIPS spi[XLNX_ZYNQMP_NUM_SPIS];
> +    Object *crf;

Can we follow the same way as the other devices?

You'll need to split a header file out for the device then.

Thanks,

Alistair

>
>      char *boot_cpu;
>      ARMCPU *boot_cpu_ptr;
> --
> 2.5.5
>
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 09/11] zynqmp_crf: add the clock mechanism
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 09/11] zynqmp_crf: add the clock mechanism fred.konrad
@ 2016-07-01 23:23   ` Alistair Francis
  2016-08-02 12:26     ` KONRAD Frederic
  2016-07-29 13:51   ` Peter Maydell
  1 sibling, 1 reply; 38+ messages in thread
From: Alistair Francis @ 2016-07-01 23:23 UTC (permalink / raw)
  To: KONRAD Frédéric
  Cc: qemu-devel@nongnu.org Developers, Edgar Iglesias, Peter Maydell,
	Mark Burton, Alistair Francis

On Mon, Jun 13, 2016 at 9:27 AM,  <fred.konrad@greensocs.com> wrote:
> From: KONRAD Frederic <fred.konrad@greensocs.com>
>
> This adds the pll to the zynqmp_crf and the dp_video clock output.
>
> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
> ---
>  hw/misc/xilinx_zynqmp_crf.c | 440 ++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 440 insertions(+)
>
> diff --git a/hw/misc/xilinx_zynqmp_crf.c b/hw/misc/xilinx_zynqmp_crf.c
> index 4c670a0..2097534 100644
> --- a/hw/misc/xilinx_zynqmp_crf.c
> +++ b/hw/misc/xilinx_zynqmp_crf.c
> @@ -30,6 +30,7 @@
>  #include "hw/register.h"
>  #include "qemu/bitops.h"
>  #include "qemu/log.h"
> +#include "qemu/qemu-clock.h"
>
>  #ifndef XILINX_CRF_APB_ERR_DEBUG
>  #define XILINX_CRF_APB_ERR_DEBUG 0
> @@ -281,6 +282,38 @@ typedef struct CRF_APB {
>
>      uint32_t regs[R_MAX];
>      RegisterInfo regs_info[R_MAX];
> +
> +    /* 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;
> +
> +    /* internal clocks */
> +    qemu_clk apll_clk;
> +    qemu_clk dpll_clk;
> +    qemu_clk vpll_clk;
> +
> +    /* output clocks */
> +    qemu_clk acpu_clk;
> +    qemu_clk dbg_trace;
> +    qemu_clk dbg_fdp;
> +    qemu_clk dp_video_ref;
> +    qemu_clk dp_audio_ref;
> +    qemu_clk dp_stc_ref;
> +    qemu_clk ddr;
> +    qemu_clk gpu_ref;
> +    qemu_clk sata_ref;
> +    qemu_clk pcie_ref;
> +    qemu_clk gdma_ref;
> +    qemu_clk dpdma_ref;
> +    qemu_clk topsw_main;
> +    qemu_clk topsw_lsbus;
> +    qemu_clk dbg_tstmp;
> +    qemu_clk apll_to_lpd;
> +    qemu_clk dpll_to_lpd;
> +    qemu_clk vpll_to_lpd;
>  } CRF_APB;
>
>  static const MemoryRegionOps crf_apb_ops = {
> @@ -325,6 +358,318 @@ static uint64_t ir_disable_prew(RegisterInfo *reg, uint64_t val64)
>      return 0;
>  }
>
> +enum clk_src {
> +    VIDEO_CLK = 4,
> +    PSS_ALT_REF_CLK = 5,
> +    AUX_REF_CLK = 6,
> +    GT_CRX_REF_CLK = 7,
> +    PSS_REF_CLK = 0
> +};
> +
> +static void apll_to_lpd_postw(RegisterInfo *reg, uint64_t val64)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
> +
> +    qemu_clk_refresh(s->apll_to_lpd);
> +}
> +
> +static float apll_to_lpd_update_rate(void *opaque, float input_rate)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(opaque);
> +    uint32_t divisor = AF_EX32(s->regs, APLL_TO_LPD_CTRL, DIVISOR0);
> +
> +    if (!divisor) {
> +        return 0.0f;
> +    } else {
> +        return input_rate / (float)divisor;
> +    }
> +}
> +
> +static void dpll_to_lpd_postw(RegisterInfo *reg, uint64_t val64)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
> +
> +    qemu_clk_refresh(s->dpll_to_lpd);
> +}
> +
> +static float dpll_to_lpd_update_rate(void *opaque, float input_rate)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(opaque);
> +    uint32_t divisor = AF_EX32(s->regs, DPLL_TO_LPD_CTRL, DIVISOR0);
> +
> +    if (!divisor) {
> +        return 0.0f;
> +    } else {
> +        return input_rate / (float)divisor;
> +    }
> +}
> +
> +static void vpll_to_lpd_postw(RegisterInfo *reg, uint64_t val64)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
> +
> +    qemu_clk_refresh(s->vpll_to_lpd);
> +}
> +
> +static float vpll_to_lpd_update_rate(void *opaque, float input_rate)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(opaque);
> +    uint32_t divisor = AF_EX32(s->regs, VPLL_TO_LPD_CTRL, DIVISOR0);
> +
> +    if (!divisor) {
> +        return 0.0f;
> +    } else {
> +        return input_rate / (float)divisor;
> +    }
> +}
> +
> +static void apll_ctrl_postw(RegisterInfo *reg, uint64_t val64)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
> +    uint32_t source = AF_EX32(s->regs, APLL_CTRL, BYPASS)
> +                    ? AF_EX32(s->regs, APLL_CTRL, POST_SRC)
> +                    : AF_EX32(s->regs, APLL_CTRL, PRE_SRC);
> +
> +    /*
> +     * We must ensure that only one clock is bound to the apll internal clock.
> +     */
> +    qemu_clk_unbound(s->pss_ref_clk, s->apll_clk);
> +    qemu_clk_unbound(s->video_clk, s->apll_clk);
> +    qemu_clk_unbound(s->pss_alt_ref_clk, s->apll_clk);
> +    qemu_clk_unbound(s->aux_refclk, s->apll_clk);
> +    qemu_clk_unbound(s->gt_crx_ref_clk, s->apll_clk);
> +
> +    switch (source) {
> +    case VIDEO_CLK:
> +        qemu_clk_bound_clock(s->video_clk, s->apll_clk);
> +        break;
> +    case PSS_ALT_REF_CLK:
> +        qemu_clk_bound_clock(s->pss_alt_ref_clk, s->apll_clk);
> +        break;
> +    case AUX_REF_CLK:
> +        qemu_clk_bound_clock(s->aux_refclk, s->apll_clk);
> +        break;
> +    case GT_CRX_REF_CLK:
> +        qemu_clk_bound_clock(s->gt_crx_ref_clk, s->apll_clk);
> +        break;
> +    default:
> +        qemu_clk_bound_clock(s->pss_ref_clk, s->apll_clk);
> +        break;
> +    }
> +}
> +
> +static void dpll_ctrl_postw(RegisterInfo *reg, uint64_t val64)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
> +    uint32_t source = AF_EX32(s->regs, DPLL_CTRL, BYPASS)
> +                    ? AF_EX32(s->regs, DPLL_CTRL, POST_SRC)
> +                    : AF_EX32(s->regs, DPLL_CTRL, PRE_SRC);
> +
> +    /*
> +     * We must ensure that only one clock is bound to the dpll internal clock.
> +     */
> +    qemu_clk_unbound(s->pss_ref_clk, s->dpll_clk);
> +    qemu_clk_unbound(s->video_clk, s->dpll_clk);
> +    qemu_clk_unbound(s->pss_alt_ref_clk, s->dpll_clk);
> +    qemu_clk_unbound(s->aux_refclk, s->dpll_clk);
> +    qemu_clk_unbound(s->gt_crx_ref_clk, s->dpll_clk);
> +
> +    switch (source) {
> +    case VIDEO_CLK:
> +        qemu_clk_bound_clock(s->video_clk, s->dpll_clk);
> +        break;
> +    case PSS_ALT_REF_CLK:
> +        qemu_clk_bound_clock(s->pss_alt_ref_clk, s->dpll_clk);
> +        break;
> +    case AUX_REF_CLK:
> +        qemu_clk_bound_clock(s->aux_refclk, s->dpll_clk);
> +        break;
> +    case GT_CRX_REF_CLK:
> +        qemu_clk_bound_clock(s->gt_crx_ref_clk, s->dpll_clk);
> +        break;
> +    default:
> +        qemu_clk_bound_clock(s->pss_ref_clk, s->dpll_clk);
> +        break;
> +    }
> +}
> +
> +static void vpll_ctrl_postw(RegisterInfo *reg, uint64_t val64)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
> +    uint32_t source = AF_EX32(s->regs, VPLL_CTRL, BYPASS)
> +                    ? AF_EX32(s->regs, VPLL_CTRL, POST_SRC)
> +                    : AF_EX32(s->regs, VPLL_CTRL, PRE_SRC);
> +
> +    /*
> +     * We must ensure that only one clock is bound to the vpll internal clock.
> +     */
> +    qemu_clk_unbound(s->pss_ref_clk, s->vpll_clk);
> +    qemu_clk_unbound(s->video_clk, s->vpll_clk);
> +    qemu_clk_unbound(s->pss_alt_ref_clk, s->vpll_clk);
> +    qemu_clk_unbound(s->aux_refclk, s->vpll_clk);
> +    qemu_clk_unbound(s->gt_crx_ref_clk, s->vpll_clk);
> +
> +    switch (source) {
> +    case VIDEO_CLK:
> +        qemu_clk_bound_clock(s->video_clk, s->vpll_clk);
> +        break;
> +    case PSS_ALT_REF_CLK:
> +        qemu_clk_bound_clock(s->pss_alt_ref_clk, s->vpll_clk);
> +        break;
> +    case AUX_REF_CLK:
> +        qemu_clk_bound_clock(s->aux_refclk, s->vpll_clk);
> +        break;
> +    case GT_CRX_REF_CLK:
> +        qemu_clk_bound_clock(s->gt_crx_ref_clk, s->vpll_clk);
> +        break;
> +    default:
> +        qemu_clk_bound_clock(s->pss_ref_clk, s->vpll_clk);
> +        break;
> +    }
> +}

These functions seem very repititive. Can we have one general function
that gets passed the applicable clock into it?

> +
> +/*
> + * This happen when apll get updated.
> + * As we ensure that only one clk_pin can drive apll we can just do the
> + * computation from input_rate.
> + */
> +static float apll_update_rate(void *opaque, float input_rate)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(opaque);
> +    bool bypass = AF_EX32(s->regs, APLL_CTRL, BYPASS);
> +    bool reset = AF_EX32(s->regs, APLL_CTRL, RESET);
> +    float div2 = AF_EX32(s->regs, APLL_CTRL, DIV2) ? 0.5f : 1.0f;
> +    float integer = (float)(AF_EX32(s->regs, APLL_CTRL, FBDIV));
> +    float frac = AF_EX32(s->regs, APLL_FRAC_CFG, ENABLED)
> +                  ? (float)(AF_EX32(s->regs, APLL_FRAC_CFG, DATA)) / 65536.0f
> +                  : 0.0f;
> +
> +    if (bypass) {
> +        return input_rate;
> +    } else {
> +        if (reset) {
> +            /*
> +             * This is not supposed to happen user must ensure that BYPASS is
> +             * set before the PLL are reset.
> +             */
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "APLL is reseted but not bypassed.");
> +            return 0.0f;
> +        } else {
> +            return input_rate * div2 * (integer + frac);
> +        }
> +    }
> +}
> +
> +/*
> + * This happen when dpll get updated.
> + * As we ensure that only one clk_pin can drive dpll we can just do the
> + * computation from input_rate.
> + */
> +static float dpll_update_rate(void *opaque, float input_rate)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(opaque);
> +    bool bypass = AF_EX32(s->regs, DPLL_CTRL, BYPASS);
> +    bool reset = AF_EX32(s->regs, DPLL_CTRL, RESET);
> +    float div2 = AF_EX32(s->regs, DPLL_CTRL, DIV2) ? 0.5f : 1.0f;
> +    float integer = (float)(AF_EX32(s->regs, DPLL_CTRL, FBDIV));
> +    float frac = AF_EX32(s->regs, DPLL_FRAC_CFG, ENABLED)
> +                  ? (float)(AF_EX32(s->regs, DPLL_FRAC_CFG, DATA)) / 65536.0f
> +                  : 0.0f;
> +
> +    if (bypass) {
> +        return input_rate;
> +    } else {
> +        if (reset) {
> +            /*
> +             * This is not supposed to happen user must ensure that BYPASS is
> +             * set before the PLL are reset.
> +             */
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "DPLL is reseted but not bypassed.");
> +            return 0.0f;
> +        } else {
> +            return input_rate * div2 * (integer + frac);
> +        }
> +    }
> +}
> +
> +/*
> + * This happen when vpll get updated.
> + * As we ensure that only one clk_pin can drive vpll we can just do the
> + * computation from input_rate.
> + */
> +static float vpll_update_rate(void *opaque, float input_rate)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(opaque);
> +    bool bypass = AF_EX32(s->regs, VPLL_CTRL, BYPASS);
> +    bool reset = AF_EX32(s->regs, VPLL_CTRL, RESET);
> +    float div2 = AF_EX32(s->regs, VPLL_CTRL, DIV2) ? 0.5f : 1.0f;
> +    float integer = (float)(AF_EX32(s->regs, VPLL_CTRL, FBDIV));
> +    float frac = AF_EX32(s->regs, VPLL_FRAC_CFG, ENABLED)
> +                  ? (float)(AF_EX32(s->regs, VPLL_FRAC_CFG, DATA)) / 65536.0f
> +                  : 0.0f;
> +
> +    if (bypass) {
> +        return input_rate;
> +    } else {
> +        if (reset) {
> +            /*
> +             * This is not supposed to happen user must ensure that BYPASS is
> +             * set before the PLL are reset.
> +             */
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "VPLL is reseted but not bypassed.");
> +            return 0.0f;
> +        } else {
> +            return input_rate * div2 * (integer + frac);
> +        }
> +    }
> +}
> +
> +/*
> + * FIXME: Only DP video reference clock is modeled here, others are missing.
> + */
> +static float dp_video_update_rate(void *opaque, float input_rate)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(opaque);
> +    bool clock_act = AF_EX32(s->regs, DP_VIDEO_REF_CTRL, CLKACT);
> +    uint32_t divisor0 = AF_EX32(s->regs, DP_VIDEO_REF_CTRL, DIVISOR0);
> +
> +    if ((!divisor0) || (!clock_act)) {
> +        return 0.0f;
> +    } else {
> +        return input_rate / (float)(divisor0);
> +    }
> +}
> +
> +static void dp_video_ref_ctrl_postw(RegisterInfo *reg, uint64_t val64)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
> +    uint32_t source = AF_EX32(s->regs, APLL_CTRL, BYPASS)
> +                    ? AF_EX32(s->regs, APLL_CTRL, POST_SRC)
> +                    : AF_EX32(s->regs, APLL_CTRL, PRE_SRC);
> +
> +    /*
> +     * We must ensure that only one clock is bound to the dp_video_ref
> +     * internal clock, so the callback have always the right rate in it.
> +     */
> +    qemu_clk_unbound(s->vpll_clk, s->dp_video_ref);
> +    qemu_clk_unbound(s->dpll_clk, s->dp_video_ref);
> +
> +    switch (source) {
> +    case 0x00:
> +        qemu_clk_bound_clock(s->vpll_clk, s->dp_video_ref);
> +        break;
> +    case 0x02:
> +        qemu_clk_bound_clock(s->dpll_clk, s->dp_video_ref);
> +        break;
> +    default:
> +        abort();
> +        break;
> +    }
> +}

Same comment about a general function here.

> +
>  static RegisterAccessInfo crf_apb_regs_info[] = {
>      {   .name = "ERR_CTRL",  .decode.addr = A_ERR_CTRL,
>      },{ .name = "IR_STATUS",  .decode.addr = A_IR_STATUS,
> @@ -341,6 +686,7 @@ static RegisterAccessInfo crf_apb_regs_info[] = {
>      },{ .name = "APLL_CTRL",  .decode.addr = A_APLL_CTRL,
>          .reset = 0x2809,
>          .rsvd = 0xf88c80f6L,
> +        .post_write = apll_ctrl_postw,
>      },{ .name = "APLL_CFG",  .decode.addr = A_APLL_CFG,
>          .rsvd = 0x1801210,
>      },{ .name = "APLL_FRAC_CFG",  .decode.addr = A_APLL_FRAC_CFG,
> @@ -348,6 +694,7 @@ static RegisterAccessInfo crf_apb_regs_info[] = {
>      },{ .name = "DPLL_CTRL",  .decode.addr = A_DPLL_CTRL,
>          .reset = 0x2809,
>          .rsvd = 0xf88c80f6L,
> +        .post_write = dpll_ctrl_postw,
>      },{ .name = "DPLL_CFG",  .decode.addr = A_DPLL_CFG,
>          .rsvd = 0x1801210,
>      },{ .name = "DPLL_FRAC_CFG",  .decode.addr = A_DPLL_FRAC_CFG,
> @@ -355,6 +702,7 @@ static RegisterAccessInfo crf_apb_regs_info[] = {
>      },{ .name = "VPLL_CTRL",  .decode.addr = A_VPLL_CTRL,
>          .reset = 0x2809,
>          .rsvd = 0xf88c80f6L,
> +        .post_write = vpll_ctrl_postw,
>      },{ .name = "VPLL_CFG",  .decode.addr = A_VPLL_CFG,
>          .rsvd = 0x1801210,
>      },{ .name = "VPLL_FRAC_CFG",  .decode.addr = A_VPLL_FRAC_CFG,
> @@ -366,12 +714,15 @@ static RegisterAccessInfo crf_apb_regs_info[] = {
>      },{ .name = "APLL_TO_LPD_CTRL",  .decode.addr = A_APLL_TO_LPD_CTRL,
>          .reset = 0x400,
>          .rsvd = 0xc0ff,
> +        .post_write = apll_to_lpd_postw,
>      },{ .name = "DPLL_TO_LPD_CTRL",  .decode.addr = A_DPLL_TO_LPD_CTRL,
>          .reset = 0x400,
>          .rsvd = 0xc0ff,
> +        .post_write = dpll_to_lpd_postw,
>      },{ .name = "VPLL_TO_LPD_CTRL",  .decode.addr = A_VPLL_TO_LPD_CTRL,
>          .reset = 0x400,
>          .rsvd = 0xc0ff,
> +        .post_write = vpll_to_lpd_postw,
>      },{ .name = "CPU_A9_CTRL",  .decode.addr = A_CPU_A9_CTRL,
>          .reset = 0xf000400,
>          .rsvd = 0xf0ffc0f8L,
> @@ -384,6 +735,7 @@ static RegisterAccessInfo crf_apb_regs_info[] = {
>      },{ .name = "DP_VIDEO_REF_CTRL",  .decode.addr = A_DP_VIDEO_REF_CTRL,
>          .reset = 0x1002300,
>          .rsvd = 0xfeffc0f8L,
> +        .post_write = dp_video_ref_ctrl_postw,
>      },{ .name = "DP_AUDIO_REF_CTRL",  .decode.addr = A_DP_AUDIO_REF_CTRL,
>          .reset = 0x1002300,
>          .rsvd = 0xfeffc0f8L,
> @@ -479,6 +831,25 @@ static void crf_apb_reset(DeviceState *dev)
>      }
>
>      ir_update_irq(s);
> +
> +    /*
> +     * During reset, the clock selection registers bound the clock like this.
> +     */
> +    qemu_clk_bound_clock(s->pss_ref_clk, s->apll_clk);
> +    qemu_clk_bound_clock(s->pss_ref_clk, s->dpll_clk);
> +    qemu_clk_bound_clock(s->pss_ref_clk, s->vpll_clk);
> +    qemu_clk_bound_clock(s->vpll_clk, s->dp_video_ref);

What if these are already bound?

> +}
> +
> +static void crf_apb_realize(DeviceState *d, Error **errp)
> +{
> +    CRF_APB *s = XILINX_CRF_APB(d);
> +
> +    qemu_clk_bound_clock(s->apll_clk, s->apll_to_lpd);
> +    qemu_clk_bound_clock(s->dpll_clk, s->dpll_to_lpd);
> +    qemu_clk_bound_clock(s->vpll_clk, s->vpll_to_lpd);
> +
> +    crf_apb_reset(d);

Don't call the reset from realise.

>  }
>
>  static void crf_apb_init(Object *obj)
> @@ -495,6 +866,74 @@ static void crf_apb_init(Object *obj)
>                            R_RST_DDR_SS);
>      sysbus_init_mmio(sbd, &s->iomem);
>      sysbus_init_irq(sbd, &s->irq_ir);
> +
> +    /* input clocks */
> +    s->pss_ref_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->pss_ref_clk, "pss_ref_clk");
> +    s->video_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->video_clk, "video_clk");
> +    s->pss_alt_ref_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->pss_alt_ref_clk,
> +                              "pss_alt_ref_clk");
> +    s->aux_refclk = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->aux_refclk, "aux_refclk");
> +    s->gt_crx_ref_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->gt_crx_ref_clk,
> +                              "gt_crx_ref_clk");
> +
> +    /* internal clocks */
> +    s->apll_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->apll_clk, "apll_clk");
> +    qemu_clk_set_callback(s->apll_clk, apll_update_rate, obj);
> +    s->dpll_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->dpll_clk, "dpll_clk");
> +    qemu_clk_set_callback(s->dpll_clk, dpll_update_rate, obj);
> +    s->vpll_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->vpll_clk, "vpll_clk");
> +    qemu_clk_set_callback(s->vpll_clk, vpll_update_rate, obj);
> +
> +    /* Clock output init */
> +    s->acpu_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->acpu_clk, "acpu_clk");
> +    s->dbg_trace = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->dbg_trace, "dbg_trace");
> +    s->dbg_fdp = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->dbg_fdp, "dbg_fdp");
> +    s->dp_video_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->dp_video_ref, "dp_video_ref");
> +    qemu_clk_set_callback(s->dp_video_ref, dp_video_update_rate, obj);
> +    s->dp_audio_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->dp_audio_ref, "dp_audio_ref");
> +    s->dp_stc_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->dp_stc_ref, "dp_stc_ref");
> +    s->ddr = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->ddr, "ddr");
> +    s->gpu_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->gpu_ref, "gpu_ref");
> +    s->sata_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->sata_ref, "sata_ref");
> +    s->pcie_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->pcie_ref, "pcie_ref");
> +    s->gdma_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->gdma_ref, "gdma_ref");
> +    s->dpdma_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->dpdma_ref, "dpdma_ref");
> +    s->topsw_main = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->topsw_main, "topsw_main");
> +    s->topsw_lsbus = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->topsw_lsbus, "topsw_lsbus");
> +    s->dbg_tstmp = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->dbg_tstmp, "dbg_tstmp");
> +
> +    s->apll_to_lpd = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->apll_to_lpd, "apll_to_lpd");
> +    qemu_clk_set_callback(s->apll_to_lpd, apll_to_lpd_update_rate, obj);
> +    s->dpll_to_lpd = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->dpll_to_lpd, "dpll_to_lpd");
> +    qemu_clk_set_callback(s->dpll_to_lpd, dpll_to_lpd_update_rate, obj);
> +    s->vpll_to_lpd = QEMU_CLOCK(object_new(TYPE_CLOCK));
> +    qemu_clk_attach_to_device(DEVICE(obj), s->vpll_to_lpd, "vpll_to_lpd");
> +    qemu_clk_set_callback(s->vpll_to_lpd, vpll_to_lpd_update_rate, obj);

Wow! That is a lot of code

Maybe we would be better off having an array (or three for the
sections) and iterating over those. Between this init code and the
registers in the struct this is getting hard to read/manage.

Thanks,

Alistair

>  }
>
>  static const VMStateDescription vmstate_crf_apb = {
> @@ -514,6 +953,7 @@ static void crf_apb_class_init(ObjectClass *klass, void *data)
>
>      dc->reset = crf_apb_reset;
>      dc->vmsd = &vmstate_crf_apb;
> +    dc->realize = crf_apb_realize;
>  }
>
>  static const TypeInfo crf_apb_info = {
> --
> 2.5.5
>
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 03/11] qemu-clk: allow to bound two clocks together
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 03/11] qemu-clk: allow to bound two clocks together fred.konrad
  2016-06-29  0:30   ` Alistair Francis
@ 2016-07-29 13:39   ` Peter Maydell
  2016-08-02 12:29     ` KONRAD Frederic
  1 sibling, 1 reply; 38+ messages in thread
From: Peter Maydell @ 2016-07-29 13:39 UTC (permalink / raw)
  To: KONRAD Frédéric
  Cc: QEMU Developers, Edgar Iglesias, Alistair Francis, Mark Burton

On 13 June 2016 at 17:27,  <fred.konrad@greensocs.com> wrote:
> From: KONRAD Frederic <fred.konrad@greensocs.com>
>
> This introduces the clock binding and the update part.
> When the qemu_clk_rate_update(qemu_clk, int) function is called:
>   * The clock callback is called on the qemu_clk so it can change the rate.
>   * The qemu_clk_rate_update function is called on all the driven clock.
>
> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
> ---
>  include/qemu/qemu-clock.h | 65 +++++++++++++++++++++++++++++++++++++++++++++++
>  qemu-clock.c              | 56 ++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 121 insertions(+)
>
> diff --git a/include/qemu/qemu-clock.h b/include/qemu/qemu-clock.h
> index a2ba105..677de9a 100644
> --- a/include/qemu/qemu-clock.h
> +++ b/include/qemu/qemu-clock.h
> @@ -27,15 +27,29 @@
>  #include "qemu/osdep.h"
>  #include "qom/object.h"
>
> +typedef float (*qemu_clk_on_rate_update_cb)(void *opaque, float rate);
> +
>  #define TYPE_CLOCK "qemu-clk"
>  #define QEMU_CLOCK(obj) OBJECT_CHECK(struct qemu_clk, (obj), TYPE_CLOCK)
>
> +typedef struct ClkList ClkList;
> +
>  typedef struct qemu_clk {
>      /*< private >*/
>      Object parent_obj;
>      char *name;            /* name of this clock in the device. */
> +    float in_rate;         /* rate of the clock which drive this pin. */
> +    float out_rate;        /* rate of this clock pin. */

I'm rather dubious that we should be using floats here.
Almost nothing in our hardware emulation uses float or double.

> +    void *opaque;
> +    qemu_clk_on_rate_update_cb cb;
> +    QLIST_HEAD(, ClkList) bound;
>  } *qemu_clk;

thanks
-- PMM

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 05/11] docs: add qemu-clock documentation
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 05/11] docs: add qemu-clock documentation fred.konrad
  2016-06-29  0:38   ` Alistair Francis
@ 2016-07-29 13:47   ` Peter Maydell
  1 sibling, 0 replies; 38+ messages in thread
From: Peter Maydell @ 2016-07-29 13:47 UTC (permalink / raw)
  To: KONRAD Frédéric
  Cc: QEMU Developers, Edgar Iglesias, Alistair Francis, Mark Burton

On 13 June 2016 at 17:27,  <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 | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 112 insertions(+)
>  create mode 100644 docs/clock.txt
>
> diff --git a/docs/clock.txt b/docs/clock.txt
> new file mode 100644
> index 0000000..f4ad4c8
> --- /dev/null
> +++ b/docs/clock.txt
> @@ -0,0 +1,112 @@
> +
> +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.

I think this would be a good place to give a brief bullet-point summary
of the operations that can be done on a clock (which then can be
expanded on in sections below).


> +
> +Bounding the clock together to create a tree

"Binding" ?

> +============================================
> +
> +In order to create a clock tree with QEMU_CLOCK two or more clock must be bound
> +together.

Is the simple case of "only one clock, not bound to any other clock,
with a callback" not a valid clock tree ?

> Let's say there are two clocks clk_a and clk_b:
> +Using qemu_clk_bound(clk_a, clk_b) will bound clk_a and clk_b.

"bind" ? (and in the function name)

> +
> +Binding two qemu-clk together is a unidirectional link which means that changing

"creates a unidirectional link" ?

> +the rate of clk_a will propagate to clk_b and not the opposite. The bound
> +process automatically refresh clk_b rate.

"refreshes"

> +
> +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_bound(clk_a, clk_b);
> +qemu_clk_bound(clk_a, clk_c);
> +
> +A clock rate change one clk_a will propagate to clk_b and clk_c.

If you bind clock A to clock B, then is trying to change the rate
of clock B (a) a bug (assert, or fail the call) (b) OK but
ignored (c) OK but the changed rate doesn't get used until/unless
the clocks are unbound ?

Is it possible to bind two clocks together but with a frequency
difference between them (ie to model the common case where there's
some master clock and then a clock divider that creates various
other clocks based on the rate of that master) ?

> +
> +Implementing a callback on a rate change
> +========================================
> +
> +The function prototype is the following:
> +typedef float (*qemu_clk_rate_change_cb)(void *opaque, float 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:
> +float qemu_clk_rate_change_cb(void *opaque, float rate)
> +{
> +    return 4.0 * 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.
> +
> +NOTE: It's not recommended that the clock is driven by more than one clock as it

did you mean "callback" here ?

> +would mean that we don't know which clock trigger the callback.
> +
> +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.0
> +    qemu-clk "vpll_to_lpd" 625000000.0
> +    qemu-clk "dp_stc_ref" 0.0
> +    qemu-clk "dpll_to_lpd" 12500000.0
> +    qemu-clk "acpu_clk" 0.0
> +    qemu-clk "pcie_ref" 0.0
> +    qemu-clk "topsw_main" 0.0
> +    qemu-clk "topsw_lsbus" 0.0
> +    qemu-clk "dp_audio_ref" 0.0
> +    qemu-clk "sata_ref" 0.0
> +    qemu-clk "dp_video_ref" 71428568.0
> +    qemu-clk "vpll_clk" 2500000000.0
> +    qemu-clk "apll_to_lpd" 12500000.0
> +    qemu-clk "dpll_clk" 50000000.0
> +    qemu-clk "gpu_ref" 0.0
> +    qemu-clk "aux_refclk" 0.0
> +    qemu-clk "video_clk" 27000000.0
> +    qemu-clk "gdma_ref" 0.0
> +    qemu-clk "gt_crx_ref_clk" 0.0
> +    qemu-clk "dbg_fdp" 0.0
> +    qemu-clk "apll_clk" 50000000.0
> +    qemu-clk "pss_alt_ref_clk" 0.0
> +    qemu-clk "ddr" 0.0
> +    qemu-clk "pss_ref_clk" 50000000.0
> +    qemu-clk "dpdma_ref" 0.0
> +    qemu-clk "dbg_tstmp" 0.0
> +    mmio 00000000fd1a0000/000000000000010c
> +
> +This way a DeviceState can have multiple clock input or output.
> +
> --
> 2.5.5

thanks
-- PMM

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 08/11] zynqmp_crf: fix against AF_EX32 changes
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 08/11] zynqmp_crf: fix against AF_EX32 changes fred.konrad
@ 2016-07-29 13:48   ` Peter Maydell
  2016-08-02 12:34     ` KONRAD Frederic
  0 siblings, 1 reply; 38+ messages in thread
From: Peter Maydell @ 2016-07-29 13:48 UTC (permalink / raw)
  To: KONRAD Frédéric
  Cc: QEMU Developers, Edgar Iglesias, Alistair Francis, Mark Burton

On 13 June 2016 at 17:27,  <fred.konrad@greensocs.com> wrote:
> From: KONRAD Frederic <fred.konrad@greensocs.com>
>
> This seems to be due to a difference between the AF_EX32 define.
>
> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
> ---
>  hw/misc/xilinx_zynqmp_crf.c | 354 ++++++++++++++++++++++----------------------
>  1 file changed, 177 insertions(+), 177 deletions(-)

This should just be squashed into the previous patch.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 09/11] zynqmp_crf: add the clock mechanism
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 09/11] zynqmp_crf: add the clock mechanism fred.konrad
  2016-07-01 23:23   ` Alistair Francis
@ 2016-07-29 13:51   ` Peter Maydell
  2016-08-03  7:38     ` KONRAD Frederic
  1 sibling, 1 reply; 38+ messages in thread
From: Peter Maydell @ 2016-07-29 13:51 UTC (permalink / raw)
  To: KONRAD Frédéric
  Cc: QEMU Developers, Edgar Iglesias, Alistair Francis, Mark Burton

On 13 June 2016 at 17:27,  <fred.konrad@greensocs.com> wrote:
> From: KONRAD Frederic <fred.konrad@greensocs.com>
>
> This adds the pll to the zynqmp_crf and the dp_video clock output.
>
> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
> ---
>  hw/misc/xilinx_zynqmp_crf.c | 440 ++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 440 insertions(+)
>
> diff --git a/hw/misc/xilinx_zynqmp_crf.c b/hw/misc/xilinx_zynqmp_crf.c
> index 4c670a0..2097534 100644
> --- a/hw/misc/xilinx_zynqmp_crf.c
> +++ b/hw/misc/xilinx_zynqmp_crf.c
> @@ -30,6 +30,7 @@
>  #include "hw/register.h"
>  #include "qemu/bitops.h"
>  #include "qemu/log.h"
> +#include "qemu/qemu-clock.h"
>
>  #ifndef XILINX_CRF_APB_ERR_DEBUG
>  #define XILINX_CRF_APB_ERR_DEBUG 0
> @@ -281,6 +282,38 @@ typedef struct CRF_APB {
>
>      uint32_t regs[R_MAX];
>      RegisterInfo regs_info[R_MAX];
> +
> +    /* 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;
> +
> +    /* internal clocks */
> +    qemu_clk apll_clk;
> +    qemu_clk dpll_clk;
> +    qemu_clk vpll_clk;
> +
> +    /* output clocks */
> +    qemu_clk acpu_clk;
> +    qemu_clk dbg_trace;
> +    qemu_clk dbg_fdp;
> +    qemu_clk dp_video_ref;
> +    qemu_clk dp_audio_ref;
> +    qemu_clk dp_stc_ref;
> +    qemu_clk ddr;
> +    qemu_clk gpu_ref;
> +    qemu_clk sata_ref;
> +    qemu_clk pcie_ref;
> +    qemu_clk gdma_ref;
> +    qemu_clk dpdma_ref;
> +    qemu_clk topsw_main;
> +    qemu_clk topsw_lsbus;
> +    qemu_clk dbg_tstmp;
> +    qemu_clk apll_to_lpd;
> +    qemu_clk dpll_to_lpd;
> +    qemu_clk vpll_to_lpd;
>  } CRF_APB;

This looks a bit weird. Why are the input clocks and the output
clocks the same type? I was expecting that an output clock would
be "owned" by this device (and so a qemu_clk), whereas an input
clock would just be a reference to a clock owned by the device
on the other end of it.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 00/11] Clock framework API.
  2016-06-13 16:27 [Qemu-devel] [RFC PATCH 00/11] Clock framework API fred.konrad
                   ` (10 preceding siblings ...)
  2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 11/11] zynqmp: add reference clock fred.konrad
@ 2016-07-29 13:59 ` Peter Maydell
  2016-08-02  6:28   ` KONRAD Frederic
  11 siblings, 1 reply; 38+ messages in thread
From: Peter Maydell @ 2016-07-29 13:59 UTC (permalink / raw)
  To: KONRAD Frédéric
  Cc: QEMU Developers, Edgar Iglesias, Alistair Francis, Mark Burton

On 13 June 2016 at 17:27,  <fred.konrad@greensocs.com> wrote:
> From: KONRAD Frederic <fred.konrad@greensocs.com>
>
> Hi,
>
> This is a first draft of the clock framework API it contains:
>
>   * The first 5 patches which introduce the framework.
>   * The 6th patch which introduces a fixed-clock model.
>   * The rest which gives an example how to model a PLL from the existing
>     zynqmp-crf extracted from the qemu xilinx tree.
>
> No specific behavior is expected yet when the CRF register set is accessed but
> the user can see for example the dp_video_ref and vpll_to_lpd rate changing in
> the monitor with the "info qtree" command when the vpll_ctrl register is
> modified.

Apologies for the 6-week-late review. I think mostly this is
along the right lines but I've given comments where I have
specific issues.

It might also be useful to sketch out how a simple clock
tree would look in the documentation file.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 00/11] Clock framework API.
  2016-07-29 13:59 ` [Qemu-devel] [RFC PATCH 00/11] Clock framework API Peter Maydell
@ 2016-08-02  6:28   ` KONRAD Frederic
  0 siblings, 0 replies; 38+ messages in thread
From: KONRAD Frederic @ 2016-08-02  6:28 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Edgar Iglesias, Mark Burton, QEMU Developers, Alistair Francis



Le 29/07/2016 à 15:59, Peter Maydell a écrit :
> On 13 June 2016 at 17:27,  <fred.konrad@greensocs.com> wrote:
>> From: KONRAD Frederic <fred.konrad@greensocs.com>
>>
>> Hi,
>>
>> This is a first draft of the clock framework API it contains:
>>
>>    * The first 5 patches which introduce the framework.
>>    * The 6th patch which introduces a fixed-clock model.
>>    * The rest which gives an example how to model a PLL from the existing
>>      zynqmp-crf extracted from the qemu xilinx tree.
>>
>> No specific behavior is expected yet when the CRF register set is accessed but
>> the user can see for example the dp_video_ref and vpll_to_lpd rate changing in
>> the monitor with the "info qtree" command when the vpll_ctrl register is
>> modified.
> Apologies for the 6-week-late review. I think mostly this is
> along the right lines but I've given comments where I have
> specific issues.
>
> It might also be useful to sketch out how a simple clock
> tree would look in the documentation file.

Hi Peter,

Thanks for having looked into this.

Fred

>
> thanks
> -- PMM
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 02/11] qemu-clk: allow to attach a clock to a device
  2016-06-29  0:15   ` Alistair Francis
@ 2016-08-02  7:47     ` KONRAD Frederic
  2016-08-04  0:26       ` Alistair Francis
  0 siblings, 1 reply; 38+ messages in thread
From: KONRAD Frederic @ 2016-08-02  7:47 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-devel@nongnu.org Developers, Edgar Iglesias, Peter Maydell,
	Mark Burton



Le 29/06/2016 à 02:15, Alistair Francis a écrit :
> On Mon, Jun 13, 2016 at 9:27 AM,  <fred.konrad@greensocs.com> wrote:
>> From: KONRAD Frederic <fred.konrad@greensocs.com>
>>
>> This allows to attach a clock to a DeviceState.
>> Contrary to gpios, the clock pins are not contained in the DeviceState but
>> with the child property so they can appears in the qom-tree.
>>
>> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
>> ---
>>   include/qemu/qemu-clock.h | 24 +++++++++++++++++++++++-
>>   qemu-clock.c              | 22 ++++++++++++++++++++++
>>   2 files changed, 45 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/qemu/qemu-clock.h b/include/qemu/qemu-clock.h
>> index e7acd68..a2ba105 100644
>> --- a/include/qemu/qemu-clock.h
>> +++ b/include/qemu/qemu-clock.h
>> @@ -33,8 +33,30 @@
>>   typedef struct qemu_clk {
>>       /*< private >*/
>>       Object parent_obj;
>> +    char *name;            /* name of this clock in the device. */
>>   } *qemu_clk;
>>
>> -#endif /* QEMU_CLOCK_H */
>> +/**
>> + * qemu_clk_attach_to_device:
>> + * @d: the device on which the clock need to be attached.
>> + * @clk: the clock which need to be attached.
>> + * @name: the name of the clock can't be NULL.
>> + *
>> + * Attach @clk named @name to the device @d.
>> + *
>> + */
>> +void qemu_clk_attach_to_device(DeviceState *d, qemu_clk clk,
> dev instead of just d
>
>> +                               const char *name);
>>
>> +/**
>> + * qemu_clk_get_pin:
>> + * @d: the device which contain the clock.
>> + * @name: the name of the clock.
>> + *
>> + * Get the clock named @name located in the device @d, or NULL if not found.
>> + *
>> + * Returns the clock named @name contained in @d.
>> + */
>> +qemu_clk qemu_clk_get_pin(DeviceState *d, const char *name);
>>
>> +#endif /* QEMU_CLOCK_H */
>> diff --git a/qemu-clock.c b/qemu-clock.c
>> index 4a47fb4..81f2852 100644
>> --- a/qemu-clock.c
>> +++ b/qemu-clock.c
>> @@ -23,6 +23,7 @@
>>
>>   #include "qemu/qemu-clock.h"
>>   #include "hw/hw.h"
>> +#include "qapi/error.h"
>>
>>   /* #define DEBUG_QEMU_CLOCK */
>>
>> @@ -33,6 +34,27 @@ do { printf("qemu-clock: " fmt , ## __VA_ARGS__); } while (0)
>>   #define DPRINTF(fmt, ...) do { } while (0)
>>   #endif
>>
>> +void qemu_clk_attach_to_device(DeviceState *d, qemu_clk clk, const char *name)
>> +{
>> +    assert(name);
>> +    assert(!clk->name);
>> +    object_property_add_child(OBJECT(d), name, OBJECT(clk), &error_abort);
>> +    clk->name = g_strdup(name);
>> +}
>> +
>> +qemu_clk qemu_clk_get_pin(DeviceState *d, const char *name)
>> +{
>> +    gchar *path = NULL;
>> +    Object *clk;
>> +    bool ambiguous;
>> +
>> +    path = g_strdup_printf("%s/%s", object_get_canonical_path(OBJECT(d)),
>> +                           name);
>> +    clk = object_resolve_path(path, &ambiguous);
> Should ambiguous be passed back to the caller?

Up to you, I don't see the use case in the machine where we want to get 
the clock?

>
>> +    g_free(path);
>> +    return QEMU_CLOCK(clk);
> Shouldn't you check to see if you got something valid before casting?

Yes true, I was relying on the fact that QEMU_CLOCK is in the end:
object_dynamic_cast_assert(..) which according to the doc:

  * If an invalid object is passed to this function, a run time assert 
will be
  * generated.

but it seems not to be the case in reality if CONFIG_QOM_CAST_DEBUG is 
disabled:

Object *object_dynamic_cast_assert(Object *obj, const char *typename,
                                    const char *file, int line, const 
char *func)
{
     trace_object_dynamic_cast_assert(obj ? obj->class->type->name : 
"(null)",
                                      typename, file, line, func);

#ifdef CONFIG_QOM_CAST_DEBUG
     int i;
     Object *inst;

     for (i = 0; obj && i < OBJECT_CLASS_CAST_CACHE; i++) {
         if (obj->class->object_cast_cache[i] == typename) {
             goto out;
         }
     }

     inst = object_dynamic_cast(obj, typename);

     if (!inst && obj) {
         fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type 
%s\n",
                 file, line, func, obj, typename);
         abort();
     }

     assert(obj == inst);

     if (obj && obj == inst) {
         for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) {
             obj->class->object_cast_cache[i - 1] =
                     obj->class->object_cast_cache[i];
         }
         obj->class->object_cast_cache[i - 1] = typename;
     }

out:
#endif
     return obj;
}

Is that normal?

Thanks,
Fred

>
> Thanks,
>
> Alistair
>
>> +}
>> +
>>   static const TypeInfo qemu_clk_info = {
>>       .name          = TYPE_CLOCK,
>>       .parent        = TYPE_OBJECT,
>> --
>> 2.5.5
>>
>>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 05/11] docs: add qemu-clock documentation
  2016-06-29  0:38   ` Alistair Francis
@ 2016-08-02  9:29     ` KONRAD Frederic
  2016-08-04  0:28       ` Alistair Francis
  0 siblings, 1 reply; 38+ messages in thread
From: KONRAD Frederic @ 2016-08-02  9:29 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-devel@nongnu.org Developers, Edgar Iglesias, Peter Maydell,
	Mark Burton



Le 29/06/2016 à 02:38, Alistair Francis a écrit :
> On Mon, Jun 13, 2016 at 9:27 AM,  <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 | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 112 insertions(+)
>>   create mode 100644 docs/clock.txt
>>
>> diff --git a/docs/clock.txt b/docs/clock.txt
>> new file mode 100644
>> index 0000000..f4ad4c8
>> --- /dev/null
>> +++ b/docs/clock.txt
>> @@ -0,0 +1,112 @@
>> +
>> +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.
>> +
>> +Bounding 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_bound(clk_a, clk_b) will bound clk_a and clk_b.
>> +
>> +Binding two qemu-clk together is a unidirectional link which means that changing
>> +the rate of clk_a will propagate to clk_b and not the opposite. The bound
>> +process automatically refresh 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_bound(clk_a, clk_b);
>> +qemu_clk_bound(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 float (*qemu_clk_rate_change_cb)(void *opaque, float 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:
>> +float qemu_clk_rate_change_cb(void *opaque, float rate)
>> +{
>> +    return 4.0 * 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.
>> +
>> +NOTE: It's not recommended that the clock is driven by more than one clock as it
>> +would mean that we don't know which clock trigger the callback.
> Would this not be something worth knowing?

I think it shouldn't be the case as connecting two inputs on an output 
doesn't mean anything?
Maybe worth adding something to ensure it can't happen and modify 
qemu_clk_bind_clock to automatically unbind the old clock?

Fred
>
> Thanks,
>
> Alistair
>
>> +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.0
>> +    qemu-clk "vpll_to_lpd" 625000000.0
>> +    qemu-clk "dp_stc_ref" 0.0
>> +    qemu-clk "dpll_to_lpd" 12500000.0
>> +    qemu-clk "acpu_clk" 0.0
>> +    qemu-clk "pcie_ref" 0.0
>> +    qemu-clk "topsw_main" 0.0
>> +    qemu-clk "topsw_lsbus" 0.0
>> +    qemu-clk "dp_audio_ref" 0.0
>> +    qemu-clk "sata_ref" 0.0
>> +    qemu-clk "dp_video_ref" 71428568.0
>> +    qemu-clk "vpll_clk" 2500000000.0
>> +    qemu-clk "apll_to_lpd" 12500000.0
>> +    qemu-clk "dpll_clk" 50000000.0
>> +    qemu-clk "gpu_ref" 0.0
>> +    qemu-clk "aux_refclk" 0.0
>> +    qemu-clk "video_clk" 27000000.0
>> +    qemu-clk "gdma_ref" 0.0
>> +    qemu-clk "gt_crx_ref_clk" 0.0
>> +    qemu-clk "dbg_fdp" 0.0
>> +    qemu-clk "apll_clk" 50000000.0
>> +    qemu-clk "pss_alt_ref_clk" 0.0
>> +    qemu-clk "ddr" 0.0
>> +    qemu-clk "pss_ref_clk" 50000000.0
>> +    qemu-clk "dpdma_ref" 0.0
>> +    qemu-clk "dbg_tstmp" 0.0
>> +    mmio 00000000fd1a0000/000000000000010c
>> +
>> +This way a DeviceState can have multiple clock input or output.
>> +
>> --
>> 2.5.5
>>
>>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 06/11] introduce fixed-clock
  2016-07-01 23:07   ` Alistair Francis
@ 2016-08-02 11:56     ` KONRAD Frederic
  2016-08-04  0:29       ` Alistair Francis
  0 siblings, 1 reply; 38+ messages in thread
From: KONRAD Frederic @ 2016-08-02 11:56 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-devel@nongnu.org Developers, Edgar Iglesias, Peter Maydell,
	Mark Burton



Le 02/07/2016 à 01:07, Alistair Francis a écrit :
> On Mon, Jun 13, 2016 at 9:27 AM,  <fred.konrad@greensocs.com> wrote:
>> From: KONRAD Frederic <fred.konrad@greensocs.com>
>>
>> This is a fixed clock device.
>> It justs behave as an empty device with a parametrable output rate.
>>
>> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
>> ---
>>   hw/misc/Makefile.objs         |  2 +
>>   hw/misc/fixed-clock.c         | 87 +++++++++++++++++++++++++++++++++++++++++++
>>   include/hw/misc/fixed-clock.h | 30 +++++++++++++++
>>   3 files changed, 119 insertions(+)
>>   create mode 100644 hw/misc/fixed-clock.c
>>   create mode 100644 include/hw/misc/fixed-clock.h
>>
>> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
>> index e504463..e8b8855 100644
>> --- a/hw/misc/Makefile.objs
>> +++ b/hw/misc/Makefile.objs
>> @@ -52,3 +52,5 @@ obj-$(CONFIG_MIPS_ITU) += mips_itu.o
>>   obj-$(CONFIG_PVPANIC) += pvpanic.o
>>   obj-$(CONFIG_EDU) += edu.o
>>   obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
>> +
>> +obj-y += fixed-clock.o
>> diff --git a/hw/misc/fixed-clock.c b/hw/misc/fixed-clock.c
>> new file mode 100644
>> index 0000000..c273a91
>> --- /dev/null
>> +++ b/hw/misc/fixed-clock.c
>> @@ -0,0 +1,87 @@
>> +/*
>> + * Fixed clock
>> + *
>> + *  Copyright (C) 2016 : GreenSocs Ltd
>> + *      http://www.greensocs.com/ , email: info@greensocs.com
>> + *
>> + *  Frederic Konrad   <fred.konrad@greensocs.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation, either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License along
>> + * with this program; if not, see <http://www.gnu.org/licenses/>.
>> + *
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "hw/qdev.h"
>> +#include "hw/misc/fixed-clock.h"
>> +#include "qemu/qemu-clock.h"
>> +#include "qapi/error.h"
>> +
>> +/* #define DEBUG_FIXED_CLOCK */
> Don't include this.
>
>> +
>> +#ifdef DEBUG_FIXED_CLOCK
>> +#define DPRINTF(fmt, ...) \
>> +do { printf("fixed-clock: " fmt , ## __VA_ARGS__); } while (0)
> It might be better to use __func__ here.
>
> It should also be qemu_log instead of printf().
>
>> +#else
>> +#define DPRINTF(fmt, ...) do { } while (0)
>> +#endif
>> +
>> +typedef struct {
>> +    DeviceState parent_obj;
>> +
>> +    uint32_t rate;
>> +    struct qemu_clk out;
>> +} FixedClock;
> Doesn't this need to be in the header file?

I think it's not necessary as we get the clock through the API?
>
>> +
>> +static Property fixed_clock_properties[] = {
>> +    DEFINE_PROP_UINT32("rate", FixedClock, rate, 0),
>> +    DEFINE_PROP_END_OF_LIST()
>> +};
>> +
>> +static void fixed_clock_realizefn(DeviceState *d, Error **errp)
> dev instead of d
>
> Thanks,
>
> Alistair
>
>> +{
>> +    FixedClock *s = FIXED_CLOCK(d);
>> +
>> +    qemu_clk_update_rate(&s->out, s->rate);
>> +}
>> +
>> +static void fixed_clock_instance_init(Object *obj)
>> +{
>> +    FixedClock *s = FIXED_CLOCK(obj);
>> +
>> +    object_initialize(&s->out, sizeof(s->out), TYPE_CLOCK);
>> +    qemu_clk_attach_to_device(DEVICE(obj), &s->out, "clk_out");
>> +}
>> +
>> +static void fixed_clock_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> +    dc->realize = fixed_clock_realizefn;
>> +    dc->props = fixed_clock_properties;
>> +}
>> +
>> +static const TypeInfo fixed_clock_info = {
>> +    .name          = TYPE_FIXED_CLOCK,
>> +    .parent        = TYPE_DEVICE,
>> +    .instance_size = sizeof(FixedClock),
>> +    .instance_init = fixed_clock_instance_init,
>> +    .class_init    = fixed_clock_class_init,
>> +};
>> +
>> +static void fixed_clock_register_types(void)
>> +{
>> +    type_register_static(&fixed_clock_info);
>> +}
>> +
>> +type_init(fixed_clock_register_types);
>> diff --git a/include/hw/misc/fixed-clock.h b/include/hw/misc/fixed-clock.h
>> new file mode 100644
>> index 0000000..1376444
>> --- /dev/null
>> +++ b/include/hw/misc/fixed-clock.h
>> @@ -0,0 +1,30 @@
>> +/*
>> + * Fixed clock
>> + *
>> + *  Copyright (C) 2016 : GreenSocs Ltd
>> + *      http://www.greensocs.com/ , email: info@greensocs.com
>> + *
>> + *  Frederic Konrad   <fred.konrad@greensocs.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation, either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License along
>> + * with this program; if not, see <http://www.gnu.org/licenses/>.
>> + *
>> + */
>> +
>> +#ifndef FIXED_CLOCK_H
>> +#define FIXED_CLOCK_H
>> +
>> +#define TYPE_FIXED_CLOCK "fixed-clock"
>> +#define FIXED_CLOCK(obj) OBJECT_CHECK(FixedClock, (obj), TYPE_FIXED_CLOCK)
>> +
>> +#endif /* FIXED_CLOCK_H */
>> --
>> 2.5.5
>>
>>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 09/11] zynqmp_crf: add the clock mechanism
  2016-07-01 23:23   ` Alistair Francis
@ 2016-08-02 12:26     ` KONRAD Frederic
  0 siblings, 0 replies; 38+ messages in thread
From: KONRAD Frederic @ 2016-08-02 12:26 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-devel@nongnu.org Developers, Edgar Iglesias, Peter Maydell,
	Mark Burton



Le 02/07/2016 à 01:23, Alistair Francis a écrit :
> On Mon, Jun 13, 2016 at 9:27 AM,  <fred.konrad@greensocs.com> wrote:
>> From: KONRAD Frederic <fred.konrad@greensocs.com>
>>
>> This adds the pll to the zynqmp_crf and the dp_video clock output.
>>
>> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
>> ---
>>   hw/misc/xilinx_zynqmp_crf.c | 440 ++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 440 insertions(+)
>>
>> diff --git a/hw/misc/xilinx_zynqmp_crf.c b/hw/misc/xilinx_zynqmp_crf.c
>> index 4c670a0..2097534 100644
>> --- a/hw/misc/xilinx_zynqmp_crf.c
>> +++ b/hw/misc/xilinx_zynqmp_crf.c
>> @@ -30,6 +30,7 @@
>>   #include "hw/register.h"
>>   #include "qemu/bitops.h"
>>   #include "qemu/log.h"
>> +#include "qemu/qemu-clock.h"
>>
>>   #ifndef XILINX_CRF_APB_ERR_DEBUG
>>   #define XILINX_CRF_APB_ERR_DEBUG 0
>> @@ -281,6 +282,38 @@ typedef struct CRF_APB {
>>
>>       uint32_t regs[R_MAX];
>>       RegisterInfo regs_info[R_MAX];
>> +
>> +    /* 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;
>> +
>> +    /* internal clocks */
>> +    qemu_clk apll_clk;
>> +    qemu_clk dpll_clk;
>> +    qemu_clk vpll_clk;
>> +
>> +    /* output clocks */
>> +    qemu_clk acpu_clk;
>> +    qemu_clk dbg_trace;
>> +    qemu_clk dbg_fdp;
>> +    qemu_clk dp_video_ref;
>> +    qemu_clk dp_audio_ref;
>> +    qemu_clk dp_stc_ref;
>> +    qemu_clk ddr;
>> +    qemu_clk gpu_ref;
>> +    qemu_clk sata_ref;
>> +    qemu_clk pcie_ref;
>> +    qemu_clk gdma_ref;
>> +    qemu_clk dpdma_ref;
>> +    qemu_clk topsw_main;
>> +    qemu_clk topsw_lsbus;
>> +    qemu_clk dbg_tstmp;
>> +    qemu_clk apll_to_lpd;
>> +    qemu_clk dpll_to_lpd;
>> +    qemu_clk vpll_to_lpd;
>>   } CRF_APB;
>>
>>   static const MemoryRegionOps crf_apb_ops = {
>> @@ -325,6 +358,318 @@ static uint64_t ir_disable_prew(RegisterInfo *reg, uint64_t val64)
>>       return 0;
>>   }
>>
>> +enum clk_src {
>> +    VIDEO_CLK = 4,
>> +    PSS_ALT_REF_CLK = 5,
>> +    AUX_REF_CLK = 6,
>> +    GT_CRX_REF_CLK = 7,
>> +    PSS_REF_CLK = 0
>> +};
>> +
>> +static void apll_to_lpd_postw(RegisterInfo *reg, uint64_t val64)
>> +{
>> +    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
>> +
>> +    qemu_clk_refresh(s->apll_to_lpd);
>> +}
>> +
>> +static float apll_to_lpd_update_rate(void *opaque, float input_rate)
>> +{
>> +    CRF_APB *s = XILINX_CRF_APB(opaque);
>> +    uint32_t divisor = AF_EX32(s->regs, APLL_TO_LPD_CTRL, DIVISOR0);
>> +
>> +    if (!divisor) {
>> +        return 0.0f;
>> +    } else {
>> +        return input_rate / (float)divisor;
>> +    }
>> +}
>> +
>> +static void dpll_to_lpd_postw(RegisterInfo *reg, uint64_t val64)
>> +{
>> +    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
>> +
>> +    qemu_clk_refresh(s->dpll_to_lpd);
>> +}
>> +
>> +static float dpll_to_lpd_update_rate(void *opaque, float input_rate)
>> +{
>> +    CRF_APB *s = XILINX_CRF_APB(opaque);
>> +    uint32_t divisor = AF_EX32(s->regs, DPLL_TO_LPD_CTRL, DIVISOR0);
>> +
>> +    if (!divisor) {
>> +        return 0.0f;
>> +    } else {
>> +        return input_rate / (float)divisor;
>> +    }
>> +}
>> +
>> +static void vpll_to_lpd_postw(RegisterInfo *reg, uint64_t val64)
>> +{
>> +    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
>> +
>> +    qemu_clk_refresh(s->vpll_to_lpd);
>> +}
>> +
>> +static float vpll_to_lpd_update_rate(void *opaque, float input_rate)
>> +{
>> +    CRF_APB *s = XILINX_CRF_APB(opaque);
>> +    uint32_t divisor = AF_EX32(s->regs, VPLL_TO_LPD_CTRL, DIVISOR0);
>> +
>> +    if (!divisor) {
>> +        return 0.0f;
>> +    } else {
>> +        return input_rate / (float)divisor;
>> +    }
>> +}
>> +
>> +static void apll_ctrl_postw(RegisterInfo *reg, uint64_t val64)
>> +{
>> +    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
>> +    uint32_t source = AF_EX32(s->regs, APLL_CTRL, BYPASS)
>> +                    ? AF_EX32(s->regs, APLL_CTRL, POST_SRC)
>> +                    : AF_EX32(s->regs, APLL_CTRL, PRE_SRC);
>> +
>> +    /*
>> +     * We must ensure that only one clock is bound to the apll internal clock.
>> +     */
>> +    qemu_clk_unbound(s->pss_ref_clk, s->apll_clk);
>> +    qemu_clk_unbound(s->video_clk, s->apll_clk);
>> +    qemu_clk_unbound(s->pss_alt_ref_clk, s->apll_clk);
>> +    qemu_clk_unbound(s->aux_refclk, s->apll_clk);
>> +    qemu_clk_unbound(s->gt_crx_ref_clk, s->apll_clk);
>> +
>> +    switch (source) {
>> +    case VIDEO_CLK:
>> +        qemu_clk_bound_clock(s->video_clk, s->apll_clk);
>> +        break;
>> +    case PSS_ALT_REF_CLK:
>> +        qemu_clk_bound_clock(s->pss_alt_ref_clk, s->apll_clk);
>> +        break;
>> +    case AUX_REF_CLK:
>> +        qemu_clk_bound_clock(s->aux_refclk, s->apll_clk);
>> +        break;
>> +    case GT_CRX_REF_CLK:
>> +        qemu_clk_bound_clock(s->gt_crx_ref_clk, s->apll_clk);
>> +        break;
>> +    default:
>> +        qemu_clk_bound_clock(s->pss_ref_clk, s->apll_clk);
>> +        break;
>> +    }
>> +}
>> +
>> +static void dpll_ctrl_postw(RegisterInfo *reg, uint64_t val64)
>> +{
>> +    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
>> +    uint32_t source = AF_EX32(s->regs, DPLL_CTRL, BYPASS)
>> +                    ? AF_EX32(s->regs, DPLL_CTRL, POST_SRC)
>> +                    : AF_EX32(s->regs, DPLL_CTRL, PRE_SRC);
>> +
>> +    /*
>> +     * We must ensure that only one clock is bound to the dpll internal clock.
>> +     */
>> +    qemu_clk_unbound(s->pss_ref_clk, s->dpll_clk);
>> +    qemu_clk_unbound(s->video_clk, s->dpll_clk);
>> +    qemu_clk_unbound(s->pss_alt_ref_clk, s->dpll_clk);
>> +    qemu_clk_unbound(s->aux_refclk, s->dpll_clk);
>> +    qemu_clk_unbound(s->gt_crx_ref_clk, s->dpll_clk);
>> +
>> +    switch (source) {
>> +    case VIDEO_CLK:
>> +        qemu_clk_bound_clock(s->video_clk, s->dpll_clk);
>> +        break;
>> +    case PSS_ALT_REF_CLK:
>> +        qemu_clk_bound_clock(s->pss_alt_ref_clk, s->dpll_clk);
>> +        break;
>> +    case AUX_REF_CLK:
>> +        qemu_clk_bound_clock(s->aux_refclk, s->dpll_clk);
>> +        break;
>> +    case GT_CRX_REF_CLK:
>> +        qemu_clk_bound_clock(s->gt_crx_ref_clk, s->dpll_clk);
>> +        break;
>> +    default:
>> +        qemu_clk_bound_clock(s->pss_ref_clk, s->dpll_clk);
>> +        break;
>> +    }
>> +}
>> +
>> +static void vpll_ctrl_postw(RegisterInfo *reg, uint64_t val64)
>> +{
>> +    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
>> +    uint32_t source = AF_EX32(s->regs, VPLL_CTRL, BYPASS)
>> +                    ? AF_EX32(s->regs, VPLL_CTRL, POST_SRC)
>> +                    : AF_EX32(s->regs, VPLL_CTRL, PRE_SRC);
>> +
>> +    /*
>> +     * We must ensure that only one clock is bound to the vpll internal clock.
>> +     */
>> +    qemu_clk_unbound(s->pss_ref_clk, s->vpll_clk);
>> +    qemu_clk_unbound(s->video_clk, s->vpll_clk);
>> +    qemu_clk_unbound(s->pss_alt_ref_clk, s->vpll_clk);
>> +    qemu_clk_unbound(s->aux_refclk, s->vpll_clk);
>> +    qemu_clk_unbound(s->gt_crx_ref_clk, s->vpll_clk);
>> +
>> +    switch (source) {
>> +    case VIDEO_CLK:
>> +        qemu_clk_bound_clock(s->video_clk, s->vpll_clk);
>> +        break;
>> +    case PSS_ALT_REF_CLK:
>> +        qemu_clk_bound_clock(s->pss_alt_ref_clk, s->vpll_clk);
>> +        break;
>> +    case AUX_REF_CLK:
>> +        qemu_clk_bound_clock(s->aux_refclk, s->vpll_clk);
>> +        break;
>> +    case GT_CRX_REF_CLK:
>> +        qemu_clk_bound_clock(s->gt_crx_ref_clk, s->vpll_clk);
>> +        break;
>> +    default:
>> +        qemu_clk_bound_clock(s->pss_ref_clk, s->vpll_clk);
>> +        break;
>> +    }
>> +}
> These functions seem very repititive. Can we have one general function
> that gets passed the applicable clock into it?

Yes I think we can do that.

>
>> +
>> +/*
>> + * This happen when apll get updated.
>> + * As we ensure that only one clk_pin can drive apll we can just do the
>> + * computation from input_rate.
>> + */
>> +static float apll_update_rate(void *opaque, float input_rate)
>> +{
>> +    CRF_APB *s = XILINX_CRF_APB(opaque);
>> +    bool bypass = AF_EX32(s->regs, APLL_CTRL, BYPASS);
>> +    bool reset = AF_EX32(s->regs, APLL_CTRL, RESET);
>> +    float div2 = AF_EX32(s->regs, APLL_CTRL, DIV2) ? 0.5f : 1.0f;
>> +    float integer = (float)(AF_EX32(s->regs, APLL_CTRL, FBDIV));
>> +    float frac = AF_EX32(s->regs, APLL_FRAC_CFG, ENABLED)
>> +                  ? (float)(AF_EX32(s->regs, APLL_FRAC_CFG, DATA)) / 65536.0f
>> +                  : 0.0f;
>> +
>> +    if (bypass) {
>> +        return input_rate;
>> +    } else {
>> +        if (reset) {
>> +            /*
>> +             * This is not supposed to happen user must ensure that BYPASS is
>> +             * set before the PLL are reset.
>> +             */
>> +            qemu_log_mask(LOG_GUEST_ERROR,
>> +                          "APLL is reseted but not bypassed.");
>> +            return 0.0f;
>> +        } else {
>> +            return input_rate * div2 * (integer + frac);
>> +        }
>> +    }
>> +}
>> +
>> +/*
>> + * This happen when dpll get updated.
>> + * As we ensure that only one clk_pin can drive dpll we can just do the
>> + * computation from input_rate.
>> + */
>> +static float dpll_update_rate(void *opaque, float input_rate)
>> +{
>> +    CRF_APB *s = XILINX_CRF_APB(opaque);
>> +    bool bypass = AF_EX32(s->regs, DPLL_CTRL, BYPASS);
>> +    bool reset = AF_EX32(s->regs, DPLL_CTRL, RESET);
>> +    float div2 = AF_EX32(s->regs, DPLL_CTRL, DIV2) ? 0.5f : 1.0f;
>> +    float integer = (float)(AF_EX32(s->regs, DPLL_CTRL, FBDIV));
>> +    float frac = AF_EX32(s->regs, DPLL_FRAC_CFG, ENABLED)
>> +                  ? (float)(AF_EX32(s->regs, DPLL_FRAC_CFG, DATA)) / 65536.0f
>> +                  : 0.0f;
>> +
>> +    if (bypass) {
>> +        return input_rate;
>> +    } else {
>> +        if (reset) {
>> +            /*
>> +             * This is not supposed to happen user must ensure that BYPASS is
>> +             * set before the PLL are reset.
>> +             */
>> +            qemu_log_mask(LOG_GUEST_ERROR,
>> +                          "DPLL is reseted but not bypassed.");
>> +            return 0.0f;
>> +        } else {
>> +            return input_rate * div2 * (integer + frac);
>> +        }
>> +    }
>> +}
>> +
>> +/*
>> + * This happen when vpll get updated.
>> + * As we ensure that only one clk_pin can drive vpll we can just do the
>> + * computation from input_rate.
>> + */
>> +static float vpll_update_rate(void *opaque, float input_rate)
>> +{
>> +    CRF_APB *s = XILINX_CRF_APB(opaque);
>> +    bool bypass = AF_EX32(s->regs, VPLL_CTRL, BYPASS);
>> +    bool reset = AF_EX32(s->regs, VPLL_CTRL, RESET);
>> +    float div2 = AF_EX32(s->regs, VPLL_CTRL, DIV2) ? 0.5f : 1.0f;
>> +    float integer = (float)(AF_EX32(s->regs, VPLL_CTRL, FBDIV));
>> +    float frac = AF_EX32(s->regs, VPLL_FRAC_CFG, ENABLED)
>> +                  ? (float)(AF_EX32(s->regs, VPLL_FRAC_CFG, DATA)) / 65536.0f
>> +                  : 0.0f;
>> +
>> +    if (bypass) {
>> +        return input_rate;
>> +    } else {
>> +        if (reset) {
>> +            /*
>> +             * This is not supposed to happen user must ensure that BYPASS is
>> +             * set before the PLL are reset.
>> +             */
>> +            qemu_log_mask(LOG_GUEST_ERROR,
>> +                          "VPLL is reseted but not bypassed.");
>> +            return 0.0f;
>> +        } else {
>> +            return input_rate * div2 * (integer + frac);
>> +        }
>> +    }
>> +}
>> +
>> +/*
>> + * FIXME: Only DP video reference clock is modeled here, others are missing.
>> + */
>> +static float dp_video_update_rate(void *opaque, float input_rate)
>> +{
>> +    CRF_APB *s = XILINX_CRF_APB(opaque);
>> +    bool clock_act = AF_EX32(s->regs, DP_VIDEO_REF_CTRL, CLKACT);
>> +    uint32_t divisor0 = AF_EX32(s->regs, DP_VIDEO_REF_CTRL, DIVISOR0);
>> +
>> +    if ((!divisor0) || (!clock_act)) {
>> +        return 0.0f;
>> +    } else {
>> +        return input_rate / (float)(divisor0);
>> +    }
>> +}
>> +
>> +static void dp_video_ref_ctrl_postw(RegisterInfo *reg, uint64_t val64)
>> +{
>> +    CRF_APB *s = XILINX_CRF_APB(reg->opaque);
>> +    uint32_t source = AF_EX32(s->regs, APLL_CTRL, BYPASS)
>> +                    ? AF_EX32(s->regs, APLL_CTRL, POST_SRC)
>> +                    : AF_EX32(s->regs, APLL_CTRL, PRE_SRC);
>> +
>> +    /*
>> +     * We must ensure that only one clock is bound to the dp_video_ref
>> +     * internal clock, so the callback have always the right rate in it.
>> +     */
>> +    qemu_clk_unbound(s->vpll_clk, s->dp_video_ref);
>> +    qemu_clk_unbound(s->dpll_clk, s->dp_video_ref);
>> +
>> +    switch (source) {
>> +    case 0x00:
>> +        qemu_clk_bound_clock(s->vpll_clk, s->dp_video_ref);
>> +        break;
>> +    case 0x02:
>> +        qemu_clk_bound_clock(s->dpll_clk, s->dp_video_ref);
>> +        break;
>> +    default:
>> +        abort();
>> +        break;
>> +    }
>> +}
> Same comment about a general function here.
>
>> +
>>   static RegisterAccessInfo crf_apb_regs_info[] = {
>>       {   .name = "ERR_CTRL",  .decode.addr = A_ERR_CTRL,
>>       },{ .name = "IR_STATUS",  .decode.addr = A_IR_STATUS,
>> @@ -341,6 +686,7 @@ static RegisterAccessInfo crf_apb_regs_info[] = {
>>       },{ .name = "APLL_CTRL",  .decode.addr = A_APLL_CTRL,
>>           .reset = 0x2809,
>>           .rsvd = 0xf88c80f6L,
>> +        .post_write = apll_ctrl_postw,
>>       },{ .name = "APLL_CFG",  .decode.addr = A_APLL_CFG,
>>           .rsvd = 0x1801210,
>>       },{ .name = "APLL_FRAC_CFG",  .decode.addr = A_APLL_FRAC_CFG,
>> @@ -348,6 +694,7 @@ static RegisterAccessInfo crf_apb_regs_info[] = {
>>       },{ .name = "DPLL_CTRL",  .decode.addr = A_DPLL_CTRL,
>>           .reset = 0x2809,
>>           .rsvd = 0xf88c80f6L,
>> +        .post_write = dpll_ctrl_postw,
>>       },{ .name = "DPLL_CFG",  .decode.addr = A_DPLL_CFG,
>>           .rsvd = 0x1801210,
>>       },{ .name = "DPLL_FRAC_CFG",  .decode.addr = A_DPLL_FRAC_CFG,
>> @@ -355,6 +702,7 @@ static RegisterAccessInfo crf_apb_regs_info[] = {
>>       },{ .name = "VPLL_CTRL",  .decode.addr = A_VPLL_CTRL,
>>           .reset = 0x2809,
>>           .rsvd = 0xf88c80f6L,
>> +        .post_write = vpll_ctrl_postw,
>>       },{ .name = "VPLL_CFG",  .decode.addr = A_VPLL_CFG,
>>           .rsvd = 0x1801210,
>>       },{ .name = "VPLL_FRAC_CFG",  .decode.addr = A_VPLL_FRAC_CFG,
>> @@ -366,12 +714,15 @@ static RegisterAccessInfo crf_apb_regs_info[] = {
>>       },{ .name = "APLL_TO_LPD_CTRL",  .decode.addr = A_APLL_TO_LPD_CTRL,
>>           .reset = 0x400,
>>           .rsvd = 0xc0ff,
>> +        .post_write = apll_to_lpd_postw,
>>       },{ .name = "DPLL_TO_LPD_CTRL",  .decode.addr = A_DPLL_TO_LPD_CTRL,
>>           .reset = 0x400,
>>           .rsvd = 0xc0ff,
>> +        .post_write = dpll_to_lpd_postw,
>>       },{ .name = "VPLL_TO_LPD_CTRL",  .decode.addr = A_VPLL_TO_LPD_CTRL,
>>           .reset = 0x400,
>>           .rsvd = 0xc0ff,
>> +        .post_write = vpll_to_lpd_postw,
>>       },{ .name = "CPU_A9_CTRL",  .decode.addr = A_CPU_A9_CTRL,
>>           .reset = 0xf000400,
>>           .rsvd = 0xf0ffc0f8L,
>> @@ -384,6 +735,7 @@ static RegisterAccessInfo crf_apb_regs_info[] = {
>>       },{ .name = "DP_VIDEO_REF_CTRL",  .decode.addr = A_DP_VIDEO_REF_CTRL,
>>           .reset = 0x1002300,
>>           .rsvd = 0xfeffc0f8L,
>> +        .post_write = dp_video_ref_ctrl_postw,
>>       },{ .name = "DP_AUDIO_REF_CTRL",  .decode.addr = A_DP_AUDIO_REF_CTRL,
>>           .reset = 0x1002300,
>>           .rsvd = 0xfeffc0f8L,
>> @@ -479,6 +831,25 @@ static void crf_apb_reset(DeviceState *dev)
>>       }
>>
>>       ir_update_irq(s);
>> +
>> +    /*
>> +     * During reset, the clock selection registers bound the clock like this.
>> +     */
>> +    qemu_clk_bound_clock(s->pss_ref_clk, s->apll_clk);
>> +    qemu_clk_bound_clock(s->pss_ref_clk, s->dpll_clk);
>> +    qemu_clk_bound_clock(s->pss_ref_clk, s->vpll_clk);
>> +    qemu_clk_bound_clock(s->vpll_clk, s->dp_video_ref);
> What if these are already bound?

True. I think we better do something like:
when we bind clock we drop the old connection as I said in the previous 
commented patch.

>
>> +}
>> +
>> +static void crf_apb_realize(DeviceState *d, Error **errp)
>> +{
>> +    CRF_APB *s = XILINX_CRF_APB(d);
>> +
>> +    qemu_clk_bound_clock(s->apll_clk, s->apll_to_lpd);
>> +    qemu_clk_bound_clock(s->dpll_clk, s->dpll_to_lpd);
>> +    qemu_clk_bound_clock(s->vpll_clk, s->vpll_to_lpd);
>> +
>> +    crf_apb_reset(d);
> Don't call the reset from realise.
>
>>   }
>>
>>   static void crf_apb_init(Object *obj)
>> @@ -495,6 +866,74 @@ static void crf_apb_init(Object *obj)
>>                             R_RST_DDR_SS);
>>       sysbus_init_mmio(sbd, &s->iomem);
>>       sysbus_init_irq(sbd, &s->irq_ir);
>> +
>> +    /* input clocks */
>> +    s->pss_ref_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->pss_ref_clk, "pss_ref_clk");
>> +    s->video_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->video_clk, "video_clk");
>> +    s->pss_alt_ref_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->pss_alt_ref_clk,
>> +                              "pss_alt_ref_clk");
>> +    s->aux_refclk = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->aux_refclk, "aux_refclk");
>> +    s->gt_crx_ref_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->gt_crx_ref_clk,
>> +                              "gt_crx_ref_clk");
>> +
>> +    /* internal clocks */
>> +    s->apll_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->apll_clk, "apll_clk");
>> +    qemu_clk_set_callback(s->apll_clk, apll_update_rate, obj);
>> +    s->dpll_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->dpll_clk, "dpll_clk");
>> +    qemu_clk_set_callback(s->dpll_clk, dpll_update_rate, obj);
>> +    s->vpll_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->vpll_clk, "vpll_clk");
>> +    qemu_clk_set_callback(s->vpll_clk, vpll_update_rate, obj);
>> +
>> +    /* Clock output init */
>> +    s->acpu_clk = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->acpu_clk, "acpu_clk");
>> +    s->dbg_trace = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->dbg_trace, "dbg_trace");
>> +    s->dbg_fdp = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->dbg_fdp, "dbg_fdp");
>> +    s->dp_video_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->dp_video_ref, "dp_video_ref");
>> +    qemu_clk_set_callback(s->dp_video_ref, dp_video_update_rate, obj);
>> +    s->dp_audio_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->dp_audio_ref, "dp_audio_ref");
>> +    s->dp_stc_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->dp_stc_ref, "dp_stc_ref");
>> +    s->ddr = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->ddr, "ddr");
>> +    s->gpu_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->gpu_ref, "gpu_ref");
>> +    s->sata_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->sata_ref, "sata_ref");
>> +    s->pcie_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->pcie_ref, "pcie_ref");
>> +    s->gdma_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->gdma_ref, "gdma_ref");
>> +    s->dpdma_ref = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->dpdma_ref, "dpdma_ref");
>> +    s->topsw_main = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->topsw_main, "topsw_main");
>> +    s->topsw_lsbus = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->topsw_lsbus, "topsw_lsbus");
>> +    s->dbg_tstmp = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->dbg_tstmp, "dbg_tstmp");
>> +
>> +    s->apll_to_lpd = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->apll_to_lpd, "apll_to_lpd");
>> +    qemu_clk_set_callback(s->apll_to_lpd, apll_to_lpd_update_rate, obj);
>> +    s->dpll_to_lpd = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->dpll_to_lpd, "dpll_to_lpd");
>> +    qemu_clk_set_callback(s->dpll_to_lpd, dpll_to_lpd_update_rate, obj);
>> +    s->vpll_to_lpd = QEMU_CLOCK(object_new(TYPE_CLOCK));
>> +    qemu_clk_attach_to_device(DEVICE(obj), s->vpll_to_lpd, "vpll_to_lpd");
>> +    qemu_clk_set_callback(s->vpll_to_lpd, vpll_to_lpd_update_rate, obj);
> Wow! That is a lot of code
>
> Maybe we would be better off having an array (or three for the
> sections) and iterating over those. Between this init code and the
> registers in the struct this is getting hard to read/manage.

True, there are 26 clocks though :).

We might want an array as you suggested and add it to the framework:
struct clock_list
{
     size_t offset_of_clk;
     qemu_clk_on_rate_update_cb cb;
     const char *name;
}

then walk the array to create the clock.

Does that make sense?

Thanks,
Fred
>
> Thanks,
>
> Alistair
>
>>   }
>>
>>   static const VMStateDescription vmstate_crf_apb = {
>> @@ -514,6 +953,7 @@ static void crf_apb_class_init(ObjectClass *klass, void *data)
>>
>>       dc->reset = crf_apb_reset;
>>       dc->vmsd = &vmstate_crf_apb;
>> +    dc->realize = crf_apb_realize;
>>   }
>>
>>   static const TypeInfo crf_apb_info = {
>> --
>> 2.5.5
>>
>>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 03/11] qemu-clk: allow to bound two clocks together
  2016-07-29 13:39   ` Peter Maydell
@ 2016-08-02 12:29     ` KONRAD Frederic
  0 siblings, 0 replies; 38+ messages in thread
From: KONRAD Frederic @ 2016-08-02 12:29 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Edgar Iglesias, Mark Burton, QEMU Developers, Alistair Francis



Le 29/07/2016 à 15:39, Peter Maydell a écrit :
> On 13 June 2016 at 17:27,  <fred.konrad@greensocs.com> wrote:
>> From: KONRAD Frederic <fred.konrad@greensocs.com>
>>
>> This introduces the clock binding and the update part.
>> When the qemu_clk_rate_update(qemu_clk, int) function is called:
>>    * The clock callback is called on the qemu_clk so it can change the rate.
>>    * The qemu_clk_rate_update function is called on all the driven clock.
>>
>> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
>> ---
>>   include/qemu/qemu-clock.h | 65 +++++++++++++++++++++++++++++++++++++++++++++++
>>   qemu-clock.c              | 56 ++++++++++++++++++++++++++++++++++++++++
>>   2 files changed, 121 insertions(+)
>>
>> diff --git a/include/qemu/qemu-clock.h b/include/qemu/qemu-clock.h
>> index a2ba105..677de9a 100644
>> --- a/include/qemu/qemu-clock.h
>> +++ b/include/qemu/qemu-clock.h
>> @@ -27,15 +27,29 @@
>>   #include "qemu/osdep.h"
>>   #include "qom/object.h"
>>
>> +typedef float (*qemu_clk_on_rate_update_cb)(void *opaque, float rate);
>> +
>>   #define TYPE_CLOCK "qemu-clk"
>>   #define QEMU_CLOCK(obj) OBJECT_CHECK(struct qemu_clk, (obj), TYPE_CLOCK)
>>
>> +typedef struct ClkList ClkList;
>> +
>>   typedef struct qemu_clk {
>>       /*< private >*/
>>       Object parent_obj;
>>       char *name;            /* name of this clock in the device. */
>> +    float in_rate;         /* rate of the clock which drive this pin. */
>> +    float out_rate;        /* rate of this clock pin. */
> I'm rather dubious that we should be using floats here.
> Almost nothing in our hardware emulation uses float or double.

We probably can use uint64_t here?

Thanks,
Fred
>
>> +    void *opaque;
>> +    qemu_clk_on_rate_update_cb cb;
>> +    QLIST_HEAD(, ClkList) bound;
>>   } *qemu_clk;
> thanks
> -- PMM
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 08/11] zynqmp_crf: fix against AF_EX32 changes
  2016-07-29 13:48   ` Peter Maydell
@ 2016-08-02 12:34     ` KONRAD Frederic
  0 siblings, 0 replies; 38+ messages in thread
From: KONRAD Frederic @ 2016-08-02 12:34 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Edgar Iglesias, Mark Burton, QEMU Developers, Alistair Francis


Le 29/07/2016 à 15:48, Peter Maydell a écrit :
> On 13 June 2016 at 17:27,  <fred.konrad@greensocs.com> wrote:
>> From: KONRAD Frederic <fred.konrad@greensocs.com>
>>
>> This seems to be due to a difference between the AF_EX32 define.
>>
>> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
>> ---
>>   hw/misc/xilinx_zynqmp_crf.c | 354 ++++++++++++++++++++++----------------------
>>   1 file changed, 177 insertions(+), 177 deletions(-)
> This should just be squashed into the previous patch.
Yes, my intention was to keep that separate in a first time as I'm not 
sure if this is a bug in the original file.

Thanks,
Fred
> thanks
> -- PMM
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 10/11] zynqmp: add the zynqmp_crf to the platform
  2016-07-01 23:11   ` Alistair Francis
@ 2016-08-02 12:36     ` KONRAD Frederic
  0 siblings, 0 replies; 38+ messages in thread
From: KONRAD Frederic @ 2016-08-02 12:36 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-devel@nongnu.org Developers, Edgar Iglesias, Peter Maydell,
	Mark Burton



Le 02/07/2016 à 01:11, Alistair Francis a écrit :
> On Mon, Jun 13, 2016 at 9:27 AM,  <fred.konrad@greensocs.com> wrote:
>> From: KONRAD Frederic <fred.konrad@greensocs.com>
>>
>> This adds the zynqmp_crf to the zynqmp platform.
>>
>> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
>> ---
>>   hw/arm/xlnx-zynqmp.c         | 7 +++++++
>>   include/hw/arm/xlnx-zynqmp.h | 1 +
>>   2 files changed, 8 insertions(+)
>>
>> diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
>> index 4d504da..a8b7669 100644
>> --- a/hw/arm/xlnx-zynqmp.c
>> +++ b/hw/arm/xlnx-zynqmp.c
>> @@ -135,6 +135,11 @@ static void xlnx_zynqmp_init(Object *obj)
>>                             TYPE_XILINX_SPIPS);
>>           qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default());
>>       }
>> +
>> +    s->crf = object_new("xlnx.zynqmp_crf");
>> +    qdev_set_parent_bus(DEVICE(s->crf), sysbus_get_default());
>> +    object_property_add_child(obj, "xlnx.zynqmp_crf", OBJECT(s->crf),
>> +                              &error_abort);
>>   }
>>
>>   static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
>> @@ -366,6 +371,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
>>                                     &error_abort);
>>          g_free(bus_name);
>>       }
>> +
>> +    sysbus_mmio_map(SYS_BUS_DEVICE(s->crf), 0, 0xFD1A0000);
> Shouldn't this be realised?
>
> Also macro for the address.
>
>>   }
>>
>>   static Property xlnx_zynqmp_props[] = {
>> diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h
>> index 2332596..78fed6e 100644
>> --- a/include/hw/arm/xlnx-zynqmp.h
>> +++ b/include/hw/arm/xlnx-zynqmp.h
>> @@ -81,6 +81,7 @@ typedef struct XlnxZynqMPState {
>>       SysbusAHCIState sata;
>>       SDHCIState sdhci[XLNX_ZYNQMP_NUM_SDHCI];
>>       XilinxSPIPS spi[XLNX_ZYNQMP_NUM_SPIS];
>> +    Object *crf;
> Can we follow the same way as the other devices?
Yes I can do that.

>
> You'll need to split a header file out for the device then.
>
> Thanks,
>
> Alistair
>
>>       char *boot_cpu;
>>       ARMCPU *boot_cpu_ptr;
>> --
>> 2.5.5
>>
>>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 09/11] zynqmp_crf: add the clock mechanism
  2016-07-29 13:51   ` Peter Maydell
@ 2016-08-03  7:38     ` KONRAD Frederic
  0 siblings, 0 replies; 38+ messages in thread
From: KONRAD Frederic @ 2016-08-03  7:38 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Edgar Iglesias, Mark Burton, QEMU Developers, Alistair Francis



Le 29/07/2016 à 15:51, Peter Maydell a écrit :
> On 13 June 2016 at 17:27,  <fred.konrad@greensocs.com> wrote:
>> From: KONRAD Frederic <fred.konrad@greensocs.com>
>>
>> This adds the pll to the zynqmp_crf and the dp_video clock output.
>>
>> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
>> ---
>>  hw/misc/xilinx_zynqmp_crf.c | 440 ++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 440 insertions(+)
>>
>> diff --git a/hw/misc/xilinx_zynqmp_crf.c b/hw/misc/xilinx_zynqmp_crf.c
>> index 4c670a0..2097534 100644
>> --- a/hw/misc/xilinx_zynqmp_crf.c
>> +++ b/hw/misc/xilinx_zynqmp_crf.c
>> @@ -30,6 +30,7 @@
>>  #include "hw/register.h"
>>  #include "qemu/bitops.h"
>>  #include "qemu/log.h"
>> +#include "qemu/qemu-clock.h"
>>
>>  #ifndef XILINX_CRF_APB_ERR_DEBUG
>>  #define XILINX_CRF_APB_ERR_DEBUG 0
>> @@ -281,6 +282,38 @@ typedef struct CRF_APB {
>>
>>      uint32_t regs[R_MAX];
>>      RegisterInfo regs_info[R_MAX];
>> +
>> +    /* 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;
>> +
>> +    /* internal clocks */
>> +    qemu_clk apll_clk;
>> +    qemu_clk dpll_clk;
>> +    qemu_clk vpll_clk;
>> +
>> +    /* output clocks */
>> +    qemu_clk acpu_clk;
>> +    qemu_clk dbg_trace;
>> +    qemu_clk dbg_fdp;
>> +    qemu_clk dp_video_ref;
>> +    qemu_clk dp_audio_ref;
>> +    qemu_clk dp_stc_ref;
>> +    qemu_clk ddr;
>> +    qemu_clk gpu_ref;
>> +    qemu_clk sata_ref;
>> +    qemu_clk pcie_ref;
>> +    qemu_clk gdma_ref;
>> +    qemu_clk dpdma_ref;
>> +    qemu_clk topsw_main;
>> +    qemu_clk topsw_lsbus;
>> +    qemu_clk dbg_tstmp;
>> +    qemu_clk apll_to_lpd;
>> +    qemu_clk dpll_to_lpd;
>> +    qemu_clk vpll_to_lpd;
>>  } CRF_APB;
>
> This looks a bit weird. Why are the input clocks and the output
> clocks the same type? I was expecting that an output clock would
> be "owned" by this device (and so a qemu_clk), whereas an input
> clock would just be a reference to a clock owned by the device
> on the other end of it.
>

Hi Peter,

Yes this is a choice I had to make.
Basically there is nothing different between what we call output and 
input: They both allow to set a callback before the frequency is 
transported to the next clock in the clock tree.
And I use a name to get the clock, eg: for a simple clock divider:

       ----------------
in --o| ClockDivider |o-- out
       ----------------

will be modeled like this in terms of qemu_clock:

     freq_update_cb()
       return rate/4;
           |
           |
          \_/
     ------------                ------------
  --o| qemu_clk |o-- bindings --o| qemu_clk |o--
     |    in    |                |    out   |
     ------------                ------------

Then to bind that to a fixed clock we have in the machine model:
   qemu_clk_bind_clock(
     qemu_clk_get_pin(FixedClock, "out"),
     qemu_clk_get_pin(ClockDivider, "in"));

Thanks,
Fred

> thanks
> -- PMM
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 02/11] qemu-clk: allow to attach a clock to a device
  2016-08-02  7:47     ` KONRAD Frederic
@ 2016-08-04  0:26       ` Alistair Francis
  0 siblings, 0 replies; 38+ messages in thread
From: Alistair Francis @ 2016-08-04  0:26 UTC (permalink / raw)
  To: KONRAD Frederic
  Cc: Alistair Francis, Edgar Iglesias, Peter Maydell, Mark Burton,
	qemu-devel@nongnu.org Developers

On Tue, Aug 2, 2016 at 12:47 AM, KONRAD Frederic
<fred.konrad@greensocs.com> wrote:
>
>
> Le 29/06/2016 à 02:15, Alistair Francis a écrit :
>>
>> On Mon, Jun 13, 2016 at 9:27 AM,  <fred.konrad@greensocs.com> wrote:
>>>
>>> From: KONRAD Frederic <fred.konrad@greensocs.com>
>>>
>>> This allows to attach a clock to a DeviceState.
>>> Contrary to gpios, the clock pins are not contained in the DeviceState
>>> but
>>> with the child property so they can appears in the qom-tree.
>>>
>>> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
>>> ---
>>>   include/qemu/qemu-clock.h | 24 +++++++++++++++++++++++-
>>>   qemu-clock.c              | 22 ++++++++++++++++++++++
>>>   2 files changed, 45 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/include/qemu/qemu-clock.h b/include/qemu/qemu-clock.h
>>> index e7acd68..a2ba105 100644
>>> --- a/include/qemu/qemu-clock.h
>>> +++ b/include/qemu/qemu-clock.h
>>> @@ -33,8 +33,30 @@
>>>   typedef struct qemu_clk {
>>>       /*< private >*/
>>>       Object parent_obj;
>>> +    char *name;            /* name of this clock in the device. */
>>>   } *qemu_clk;
>>>
>>> -#endif /* QEMU_CLOCK_H */
>>> +/**
>>> + * qemu_clk_attach_to_device:
>>> + * @d: the device on which the clock need to be attached.
>>> + * @clk: the clock which need to be attached.
>>> + * @name: the name of the clock can't be NULL.
>>> + *
>>> + * Attach @clk named @name to the device @d.
>>> + *
>>> + */
>>> +void qemu_clk_attach_to_device(DeviceState *d, qemu_clk clk,
>>
>> dev instead of just d
>>
>>> +                               const char *name);
>>>
>>> +/**
>>> + * qemu_clk_get_pin:
>>> + * @d: the device which contain the clock.
>>> + * @name: the name of the clock.
>>> + *
>>> + * Get the clock named @name located in the device @d, or NULL if not
>>> found.
>>> + *
>>> + * Returns the clock named @name contained in @d.
>>> + */
>>> +qemu_clk qemu_clk_get_pin(DeviceState *d, const char *name);
>>>
>>> +#endif /* QEMU_CLOCK_H */
>>> diff --git a/qemu-clock.c b/qemu-clock.c
>>> index 4a47fb4..81f2852 100644
>>> --- a/qemu-clock.c
>>> +++ b/qemu-clock.c
>>> @@ -23,6 +23,7 @@
>>>
>>>   #include "qemu/qemu-clock.h"
>>>   #include "hw/hw.h"
>>> +#include "qapi/error.h"
>>>
>>>   /* #define DEBUG_QEMU_CLOCK */
>>>
>>> @@ -33,6 +34,27 @@ do { printf("qemu-clock: " fmt , ## __VA_ARGS__); }
>>> while (0)
>>>   #define DPRINTF(fmt, ...) do { } while (0)
>>>   #endif
>>>
>>> +void qemu_clk_attach_to_device(DeviceState *d, qemu_clk clk, const char
>>> *name)
>>> +{
>>> +    assert(name);
>>> +    assert(!clk->name);
>>> +    object_property_add_child(OBJECT(d), name, OBJECT(clk),
>>> &error_abort);
>>> +    clk->name = g_strdup(name);
>>> +}
>>> +
>>> +qemu_clk qemu_clk_get_pin(DeviceState *d, const char *name)
>>> +{
>>> +    gchar *path = NULL;
>>> +    Object *clk;
>>> +    bool ambiguous;
>>> +
>>> +    path = g_strdup_printf("%s/%s",
>>> object_get_canonical_path(OBJECT(d)),
>>> +                           name);
>>> +    clk = object_resolve_path(path, &ambiguous);
>>
>> Should ambiguous be passed back to the caller?
>
>
> Up to you, I don't see the use case in the machine where we want to get the
> clock?

Can't you just set it as NULL then.

>
>>
>>> +    g_free(path);
>>> +    return QEMU_CLOCK(clk);
>>
>> Shouldn't you check to see if you got something valid before casting?
>
>
> Yes true, I was relying on the fact that QEMU_CLOCK is in the end:
> object_dynamic_cast_assert(..) which according to the doc:
>
>  * If an invalid object is passed to this function, a run time assert will
> be
>  * generated.
>
> but it seems not to be the case in reality if CONFIG_QOM_CAST_DEBUG is
> disabled:
>
> Object *object_dynamic_cast_assert(Object *obj, const char *typename,
>                                    const char *file, int line, const char
> *func)
> {
>     trace_object_dynamic_cast_assert(obj ? obj->class->type->name :
> "(null)",
>                                      typename, file, line, func);
>
> #ifdef CONFIG_QOM_CAST_DEBUG
>     int i;
>     Object *inst;
>
>     for (i = 0; obj && i < OBJECT_CLASS_CAST_CACHE; i++) {
>         if (obj->class->object_cast_cache[i] == typename) {
>             goto out;
>         }
>     }
>
>     inst = object_dynamic_cast(obj, typename);
>
>     if (!inst && obj) {
>         fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type
> %s\n",
>                 file, line, func, obj, typename);
>         abort();
>     }
>
>     assert(obj == inst);
>
>     if (obj && obj == inst) {
>         for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) {
>             obj->class->object_cast_cache[i - 1] =
>                     obj->class->object_cast_cache[i];
>         }
>         obj->class->object_cast_cache[i - 1] = typename;
>     }
>
> out:
> #endif
>     return obj;
> }
>
> Is that normal?

I'm not sure to be honest. I never expected the cast to do any
checking. Someone else probably knows the history here.

Thanks,

Alistair

>
> Thanks,
> Fred
>
>
>>
>> Thanks,
>>
>> Alistair
>>
>>> +}
>>> +
>>>   static const TypeInfo qemu_clk_info = {
>>>       .name          = TYPE_CLOCK,
>>>       .parent        = TYPE_OBJECT,
>>> --
>>> 2.5.5
>>>
>>>
>
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 05/11] docs: add qemu-clock documentation
  2016-08-02  9:29     ` KONRAD Frederic
@ 2016-08-04  0:28       ` Alistair Francis
  0 siblings, 0 replies; 38+ messages in thread
From: Alistair Francis @ 2016-08-04  0:28 UTC (permalink / raw)
  To: KONRAD Frederic
  Cc: Alistair Francis, Edgar Iglesias, Peter Maydell, Mark Burton,
	qemu-devel@nongnu.org Developers

On Tue, Aug 2, 2016 at 2:29 AM, KONRAD Frederic
<fred.konrad@greensocs.com> wrote:
>
>
> Le 29/06/2016 à 02:38, Alistair Francis a écrit :
>>
>> On Mon, Jun 13, 2016 at 9:27 AM,  <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 | 112
>>> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>   1 file changed, 112 insertions(+)
>>>   create mode 100644 docs/clock.txt
>>>
>>> diff --git a/docs/clock.txt b/docs/clock.txt
>>> new file mode 100644
>>> index 0000000..f4ad4c8
>>> --- /dev/null
>>> +++ b/docs/clock.txt
>>> @@ -0,0 +1,112 @@
>>> +
>>> +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.
>>> +
>>> +Bounding 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_bound(clk_a, clk_b) will bound clk_a and clk_b.
>>> +
>>> +Binding two qemu-clk together is a unidirectional link which means that
>>> changing
>>> +the rate of clk_a will propagate to clk_b and not the opposite. The
>>> bound
>>> +process automatically refresh 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_bound(clk_a, clk_b);
>>> +qemu_clk_bound(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 float (*qemu_clk_rate_change_cb)(void *opaque, float 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:
>>> +float qemu_clk_rate_change_cb(void *opaque, float rate)
>>> +{
>>> +    return 4.0 * 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.
>>> +
>>> +NOTE: It's not recommended that the clock is driven by more than one
>>> clock as it
>>> +would mean that we don't know which clock trigger the callback.
>>
>> Would this not be something worth knowing?
>
>
> I think it shouldn't be the case as connecting two inputs on an output
> doesn't mean anything?

I think I meant worth knowing what you were connected to in general.

> Maybe worth adding something to ensure it can't happen and modify
> qemu_clk_bind_clock to automatically unbind the old clock?

I think that's a good idea.

Thanks,

Alistair

>
> Fred
>
>>
>> Thanks,
>>
>> Alistair
>>
>>> +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.0
>>> +    qemu-clk "vpll_to_lpd" 625000000.0
>>> +    qemu-clk "dp_stc_ref" 0.0
>>> +    qemu-clk "dpll_to_lpd" 12500000.0
>>> +    qemu-clk "acpu_clk" 0.0
>>> +    qemu-clk "pcie_ref" 0.0
>>> +    qemu-clk "topsw_main" 0.0
>>> +    qemu-clk "topsw_lsbus" 0.0
>>> +    qemu-clk "dp_audio_ref" 0.0
>>> +    qemu-clk "sata_ref" 0.0
>>> +    qemu-clk "dp_video_ref" 71428568.0
>>> +    qemu-clk "vpll_clk" 2500000000.0
>>> +    qemu-clk "apll_to_lpd" 12500000.0
>>> +    qemu-clk "dpll_clk" 50000000.0
>>> +    qemu-clk "gpu_ref" 0.0
>>> +    qemu-clk "aux_refclk" 0.0
>>> +    qemu-clk "video_clk" 27000000.0
>>> +    qemu-clk "gdma_ref" 0.0
>>> +    qemu-clk "gt_crx_ref_clk" 0.0
>>> +    qemu-clk "dbg_fdp" 0.0
>>> +    qemu-clk "apll_clk" 50000000.0
>>> +    qemu-clk "pss_alt_ref_clk" 0.0
>>> +    qemu-clk "ddr" 0.0
>>> +    qemu-clk "pss_ref_clk" 50000000.0
>>> +    qemu-clk "dpdma_ref" 0.0
>>> +    qemu-clk "dbg_tstmp" 0.0
>>> +    mmio 00000000fd1a0000/000000000000010c
>>> +
>>> +This way a DeviceState can have multiple clock input or output.
>>> +
>>> --
>>> 2.5.5
>>>
>>>
>
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 06/11] introduce fixed-clock
  2016-08-02 11:56     ` KONRAD Frederic
@ 2016-08-04  0:29       ` Alistair Francis
  0 siblings, 0 replies; 38+ messages in thread
From: Alistair Francis @ 2016-08-04  0:29 UTC (permalink / raw)
  To: KONRAD Frederic
  Cc: Alistair Francis, Edgar Iglesias, Peter Maydell, Mark Burton,
	qemu-devel@nongnu.org Developers

On Tue, Aug 2, 2016 at 4:56 AM, KONRAD Frederic
<fred.konrad@greensocs.com> wrote:
>
>
> Le 02/07/2016 à 01:07, Alistair Francis a écrit :
>>
>> On Mon, Jun 13, 2016 at 9:27 AM,  <fred.konrad@greensocs.com> wrote:
>>>
>>> From: KONRAD Frederic <fred.konrad@greensocs.com>
>>>
>>> This is a fixed clock device.
>>> It justs behave as an empty device with a parametrable output rate.
>>>
>>> Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
>>> ---
>>>   hw/misc/Makefile.objs         |  2 +
>>>   hw/misc/fixed-clock.c         | 87
>>> +++++++++++++++++++++++++++++++++++++++++++
>>>   include/hw/misc/fixed-clock.h | 30 +++++++++++++++
>>>   3 files changed, 119 insertions(+)
>>>   create mode 100644 hw/misc/fixed-clock.c
>>>   create mode 100644 include/hw/misc/fixed-clock.h
>>>
>>> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
>>> index e504463..e8b8855 100644
>>> --- a/hw/misc/Makefile.objs
>>> +++ b/hw/misc/Makefile.objs
>>> @@ -52,3 +52,5 @@ obj-$(CONFIG_MIPS_ITU) += mips_itu.o
>>>   obj-$(CONFIG_PVPANIC) += pvpanic.o
>>>   obj-$(CONFIG_EDU) += edu.o
>>>   obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
>>> +
>>> +obj-y += fixed-clock.o
>>> diff --git a/hw/misc/fixed-clock.c b/hw/misc/fixed-clock.c
>>> new file mode 100644
>>> index 0000000..c273a91
>>> --- /dev/null
>>> +++ b/hw/misc/fixed-clock.c
>>> @@ -0,0 +1,87 @@
>>> +/*
>>> + * Fixed clock
>>> + *
>>> + *  Copyright (C) 2016 : GreenSocs Ltd
>>> + *      http://www.greensocs.com/ , email: info@greensocs.com
>>> + *
>>> + *  Frederic Konrad   <fred.konrad@greensocs.com>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License as published by
>>> + * the Free Software Foundation, either version 2 of the License, or
>>> + * (at your option) any later version.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + * GNU General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU General Public License
>>> along
>>> + * with this program; if not, see <http://www.gnu.org/licenses/>.
>>> + *
>>> + */
>>> +
>>> +#include "qemu/osdep.h"
>>> +#include "hw/qdev.h"
>>> +#include "hw/misc/fixed-clock.h"
>>> +#include "qemu/qemu-clock.h"
>>> +#include "qapi/error.h"
>>> +
>>> +/* #define DEBUG_FIXED_CLOCK */
>>
>> Don't include this.
>>
>>> +
>>> +#ifdef DEBUG_FIXED_CLOCK
>>> +#define DPRINTF(fmt, ...) \
>>> +do { printf("fixed-clock: " fmt , ## __VA_ARGS__); } while (0)
>>
>> It might be better to use __func__ here.
>>
>> It should also be qemu_log instead of printf().
>>
>>> +#else
>>> +#define DPRINTF(fmt, ...) do { } while (0)
>>> +#endif
>>> +
>>> +typedef struct {
>>> +    DeviceState parent_obj;
>>> +
>>> +    uint32_t rate;
>>> +    struct qemu_clk out;
>>> +} FixedClock;
>>
>> Doesn't this need to be in the header file?
>
>
> I think it's not necessary as we get the clock through the API?

True, I always assumed it was general convention, although I noticed
that the qemu_irq infrastructure does it like this. So I don't think
it matters.

Thanks,

Alistair

>
>>
>>> +
>>> +static Property fixed_clock_properties[] = {
>>> +    DEFINE_PROP_UINT32("rate", FixedClock, rate, 0),
>>> +    DEFINE_PROP_END_OF_LIST()
>>> +};
>>> +
>>> +static void fixed_clock_realizefn(DeviceState *d, Error **errp)
>>
>> dev instead of d
>>
>> Thanks,
>>
>> Alistair
>>
>>> +{
>>> +    FixedClock *s = FIXED_CLOCK(d);
>>> +
>>> +    qemu_clk_update_rate(&s->out, s->rate);
>>> +}
>>> +
>>> +static void fixed_clock_instance_init(Object *obj)
>>> +{
>>> +    FixedClock *s = FIXED_CLOCK(obj);
>>> +
>>> +    object_initialize(&s->out, sizeof(s->out), TYPE_CLOCK);
>>> +    qemu_clk_attach_to_device(DEVICE(obj), &s->out, "clk_out");
>>> +}
>>> +
>>> +static void fixed_clock_class_init(ObjectClass *klass, void *data)
>>> +{
>>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>>> +
>>> +    dc->realize = fixed_clock_realizefn;
>>> +    dc->props = fixed_clock_properties;
>>> +}
>>> +
>>> +static const TypeInfo fixed_clock_info = {
>>> +    .name          = TYPE_FIXED_CLOCK,
>>> +    .parent        = TYPE_DEVICE,
>>> +    .instance_size = sizeof(FixedClock),
>>> +    .instance_init = fixed_clock_instance_init,
>>> +    .class_init    = fixed_clock_class_init,
>>> +};
>>> +
>>> +static void fixed_clock_register_types(void)
>>> +{
>>> +    type_register_static(&fixed_clock_info);
>>> +}
>>> +
>>> +type_init(fixed_clock_register_types);
>>> diff --git a/include/hw/misc/fixed-clock.h
>>> b/include/hw/misc/fixed-clock.h
>>> new file mode 100644
>>> index 0000000..1376444
>>> --- /dev/null
>>> +++ b/include/hw/misc/fixed-clock.h
>>> @@ -0,0 +1,30 @@
>>> +/*
>>> + * Fixed clock
>>> + *
>>> + *  Copyright (C) 2016 : GreenSocs Ltd
>>> + *      http://www.greensocs.com/ , email: info@greensocs.com
>>> + *
>>> + *  Frederic Konrad   <fred.konrad@greensocs.com>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License as published by
>>> + * the Free Software Foundation, either version 2 of the License, or
>>> + * (at your option) any later version.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + * GNU General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU General Public License
>>> along
>>> + * with this program; if not, see <http://www.gnu.org/licenses/>.
>>> + *
>>> + */
>>> +
>>> +#ifndef FIXED_CLOCK_H
>>> +#define FIXED_CLOCK_H
>>> +
>>> +#define TYPE_FIXED_CLOCK "fixed-clock"
>>> +#define FIXED_CLOCK(obj) OBJECT_CHECK(FixedClock, (obj),
>>> TYPE_FIXED_CLOCK)
>>> +
>>> +#endif /* FIXED_CLOCK_H */
>>> --
>>> 2.5.5
>>>
>>>
>
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2016-08-04  0:29 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-13 16:27 [Qemu-devel] [RFC PATCH 00/11] Clock framework API fred.konrad
2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 01/11] qemu-clk: introduce qemu-clk qom object fred.konrad
2016-06-29  0:15   ` Alistair Francis
2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 02/11] qemu-clk: allow to attach a clock to a device fred.konrad
2016-06-29  0:15   ` Alistair Francis
2016-08-02  7:47     ` KONRAD Frederic
2016-08-04  0:26       ` Alistair Francis
2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 03/11] qemu-clk: allow to bound two clocks together fred.konrad
2016-06-29  0:30   ` Alistair Francis
2016-07-29 13:39   ` Peter Maydell
2016-08-02 12:29     ` KONRAD Frederic
2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 04/11] qdev-monitor: print the device's clock with info qtree fred.konrad
2016-06-29  0:33   ` Alistair Francis
2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 05/11] docs: add qemu-clock documentation fred.konrad
2016-06-29  0:38   ` Alistair Francis
2016-08-02  9:29     ` KONRAD Frederic
2016-08-04  0:28       ` Alistair Francis
2016-07-29 13:47   ` Peter Maydell
2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 06/11] introduce fixed-clock fred.konrad
2016-07-01 23:07   ` Alistair Francis
2016-08-02 11:56     ` KONRAD Frederic
2016-08-04  0:29       ` Alistair Francis
2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 07/11] introduce zynqmp_crf fred.konrad
2016-06-29  0:41   ` Alistair Francis
2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 08/11] zynqmp_crf: fix against AF_EX32 changes fred.konrad
2016-07-29 13:48   ` Peter Maydell
2016-08-02 12:34     ` KONRAD Frederic
2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 09/11] zynqmp_crf: add the clock mechanism fred.konrad
2016-07-01 23:23   ` Alistair Francis
2016-08-02 12:26     ` KONRAD Frederic
2016-07-29 13:51   ` Peter Maydell
2016-08-03  7:38     ` KONRAD Frederic
2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 10/11] zynqmp: add the zynqmp_crf to the platform fred.konrad
2016-07-01 23:11   ` Alistair Francis
2016-08-02 12:36     ` KONRAD Frederic
2016-06-13 16:27 ` [Qemu-devel] [RFC PATCH 11/11] zynqmp: add reference clock fred.konrad
2016-07-29 13:59 ` [Qemu-devel] [RFC PATCH 00/11] Clock framework API Peter Maydell
2016-08-02  6:28   ` KONRAD Frederic

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.