qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/2] i.MX: Add an i.MX25 specific CCM driver
@ 2015-10-27 22:32 Jean-Christophe Dubois
  2015-10-27 22:32 ` [Qemu-devel] [PATCH 1/2] i.MX: rework " Jean-Christophe Dubois
  2015-10-27 22:32 ` [Qemu-devel] [PATCH 2/2] i.MX: Add i.MX25 " Jean-Christophe Dubois
  0 siblings, 2 replies; 3+ messages in thread
From: Jean-Christophe Dubois @ 2015-10-27 22:32 UTC (permalink / raw)
  To: qemu-devel, peter.maydell, crosthwaite.peter; +Cc: Jean-Christophe Dubois

i.MX25 SOC has a different CCM device than i.MX31.

Qemu i.MX25 emulation was built with i.MX31 CCM driver. This allows
Linux to work on top of the i.MX25 emultion but this is not correct.

Furthermore, other SOC we could emulate like i.MX6 have yet a different
implementation of the CCM device.

We then add an i.MX25 specific CCM Device and have the i.MX25 SOC use it.

Jean-Christophe Dubois (2):
  i.MX: rework CCM driver.
  i.MX: Add i.MX25 CCM driver

 hw/arm/fsl-imx25.c          |   6 +-
 hw/arm/fsl-imx31.c          |   6 +-
 hw/misc/Makefile.objs       |   2 +
 hw/misc/imx25_ccm.c         | 224 +++++++++++++++++++++++++++++++++++++++
 hw/misc/imx31_ccm.c         | 240 ++++++++++++++++++++++++++++++++++++++++++
 hw/misc/imx_ccm.c           | 249 +++-----------------------------------------
 hw/timer/imx_epit.c         |   8 +-
 hw/timer/imx_gpt.c          |  12 +--
 include/hw/arm/fsl-imx25.h  |   4 +-
 include/hw/arm/fsl-imx31.h  |   4 +-
 include/hw/misc/imx25_ccm.h |  61 +++++++++++
 include/hw/misc/imx31_ccm.h |  68 ++++++++++++
 include/hw/misc/imx_ccm.h   |  73 +++----------
 include/hw/timer/imx_epit.h |   1 -
 include/hw/timer/imx_gpt.h  |   1 -
 15 files changed, 640 insertions(+), 319 deletions(-)
 create mode 100644 hw/misc/imx25_ccm.c
 create mode 100644 hw/misc/imx31_ccm.c
 create mode 100644 include/hw/misc/imx25_ccm.h
 create mode 100644 include/hw/misc/imx31_ccm.h

-- 
2.5.0

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

* [Qemu-devel] [PATCH 1/2] i.MX: rework CCM driver.
  2015-10-27 22:32 [Qemu-devel] [PATCH 0/2] i.MX: Add an i.MX25 specific CCM driver Jean-Christophe Dubois
@ 2015-10-27 22:32 ` Jean-Christophe Dubois
  2015-10-27 22:32 ` [Qemu-devel] [PATCH 2/2] i.MX: Add i.MX25 " Jean-Christophe Dubois
  1 sibling, 0 replies; 3+ messages in thread
From: Jean-Christophe Dubois @ 2015-10-27 22:32 UTC (permalink / raw)
  To: qemu-devel, peter.maydell, crosthwaite.peter; +Cc: Jean-Christophe Dubois

The CCM driver is in fact specific to the i.MX31. We need to add an i.MX25
CCM driver.

As a first step, we split the CCM driver into 2 parts:
1) A common/utility part that allow to compute an manipulate clock freq for
   any CCM driver
2) The i.MX31 CCM specifc driver.

We also remove EPIT/GPT timer reference to CCM. These objects now use the
utility function we added in 1) instead of direct reference to CCM object.

Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
---
 hw/arm/fsl-imx25.c          |   6 +-
 hw/arm/fsl-imx31.c          |   6 +-
 hw/misc/Makefile.objs       |   1 +
 hw/misc/imx31_ccm.c         | 240 ++++++++++++++++++++++++++++++++++++++++++
 hw/misc/imx_ccm.c           | 249 +++-----------------------------------------
 hw/timer/imx_epit.c         |   8 +-
 hw/timer/imx_gpt.c          |  12 +--
 include/hw/arm/fsl-imx25.h  |   4 +-
 include/hw/arm/fsl-imx31.h  |   4 +-
 include/hw/misc/imx31_ccm.h |  68 ++++++++++++
 include/hw/misc/imx_ccm.h   |  73 +++----------
 include/hw/timer/imx_epit.h |   1 -
 include/hw/timer/imx_gpt.h  |   1 -
 13 files changed, 354 insertions(+), 319 deletions(-)
 create mode 100644 hw/misc/imx31_ccm.c
 create mode 100644 include/hw/misc/imx31_ccm.h

diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c
index e1cadac..620c5c6 100644
--- a/hw/arm/fsl-imx25.c
+++ b/hw/arm/fsl-imx25.c
@@ -38,7 +38,7 @@ static void fsl_imx25_init(Object *obj)
     object_initialize(&s->avic, sizeof(s->avic), TYPE_IMX_AVIC);
     qdev_set_parent_bus(DEVICE(&s->avic), sysbus_get_default());
 
-    object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX_CCM);
+    object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX31_CCM);
     qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default());
 
     for (i = 0; i < FSL_IMX25_NUM_UARTS; i++) {
@@ -150,8 +150,6 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
             { FSL_IMX25_GPT4_ADDR, FSL_IMX25_GPT4_IRQ }
         };
 
-        s->gpt[i].ccm = DEVICE(&s->ccm);
-
         object_property_set_bool(OBJECT(&s->gpt[i]), true, "realized", &err);
         if (err) {
             error_propagate(errp, err);
@@ -173,8 +171,6 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
             { FSL_IMX25_EPIT2_ADDR, FSL_IMX25_EPIT2_IRQ }
         };
 
-        s->epit[i].ccm = DEVICE(&s->ccm);
-
         object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err);
         if (err) {
             error_propagate(errp, err);
diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c
index 53d4473..7ae23d5 100644
--- a/hw/arm/fsl-imx31.c
+++ b/hw/arm/fsl-imx31.c
@@ -35,7 +35,7 @@ static void fsl_imx31_init(Object *obj)
     object_initialize(&s->avic, sizeof(s->avic), TYPE_IMX_AVIC);
     qdev_set_parent_bus(DEVICE(&s->avic), sysbus_get_default());
 
-    object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX_CCM);
+    object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX31_CCM);
     qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default());
 
     for (i = 0; i < FSL_IMX31_NUM_UARTS; i++) {
@@ -128,8 +128,6 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp)
                                             serial_table[i].irq));
     }
 
-    s->gpt.ccm = DEVICE(&s->ccm);
-
     object_property_set_bool(OBJECT(&s->gpt), true, "realized", &err);
     if (err) {
         error_propagate(errp, err);
@@ -150,8 +148,6 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp)
             { FSL_IMX31_EPIT2_ADDR, FSL_IMX31_EPIT2_IRQ },
         };
 
-        s->epit[i].ccm = DEVICE(&s->ccm);
-
         object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err);
         if (err) {
             error_propagate(errp, err);
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 4aa76ff..79b3487 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -26,6 +26,7 @@ obj-$(CONFIG_NSERIES) += cbus.o
 obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o
 obj-$(CONFIG_EXYNOS4) += exynos4210_pmu.o
 obj-$(CONFIG_IMX) += imx_ccm.o
+obj-$(CONFIG_IMX) += imx31_ccm.o
 obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o
 obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o
 obj-$(CONFIG_MAINSTONE) += mst_fpga.o
diff --git a/hw/misc/imx31_ccm.c b/hw/misc/imx31_ccm.c
new file mode 100644
index 0000000..1ef34f4
--- /dev/null
+++ b/hw/misc/imx31_ccm.c
@@ -0,0 +1,240 @@
+/*
+ * IMX31 Clock Control Module
+ *
+ * Copyright (C) 2012 NICTA
+ * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * To get the timer frequencies right, we need to emulate at least part of
+ * the CCM.
+ */
+
+#include "hw/misc/imx31_ccm.h"
+
+#ifndef DEBUG_IMX31_CCM
+#define DEBUG_IMX31_CCM 0
+#endif
+
+#define DPRINTF(fmt, args...) \
+    do { \
+        if (DEBUG_IMX31_CCM) { \
+            fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX31_CCM, \
+                                             __func__, ##args); \
+        } \
+    } while (0)
+
+#define CKIH_FREQ 26000000 /* 26MHz crystal input */
+
+static int imx31_ccm_post_load(void *opaque, int version_id);
+
+static const VMStateDescription vmstate_imx31_ccm = {
+    .name = TYPE_IMX31_CCM,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(ccmr, IMX31CCMState),
+        VMSTATE_UINT32(pdr0, IMX31CCMState),
+        VMSTATE_UINT32(pdr1, IMX31CCMState),
+        VMSTATE_UINT32(mpctl, IMX31CCMState),
+        VMSTATE_UINT32(spctl, IMX31CCMState),
+        VMSTATE_UINT32_ARRAY(cgr, IMX31CCMState, 3),
+        VMSTATE_UINT32(pmcr0, IMX31CCMState),
+        VMSTATE_UINT32(pmcr1, IMX31CCMState),
+        VMSTATE_UINT32(pll_refclk_freq, IMX31CCMState),
+        VMSTATE_END_OF_LIST()
+    },
+    .post_load = imx31_ccm_post_load,
+};
+
+static void update_clocks(IMX31CCMState *s)
+{
+    /*
+     * If we ever emulate more clocks, this should switch to a data-driven
+     * approach
+     */
+
+    if ((s->ccmr & CCMR_PRCS) == 2) {
+        s->pll_refclk_freq = CKIL_FREQ * 1024;
+    } else {
+        s->pll_refclk_freq = CKIH_FREQ;
+    }
+
+    /* ipg_clk_arm aka MCU clock */
+    if ((s->ccmr & CCMR_MDS) || !(s->ccmr & CCMR_MPE)) {
+        imx_ccm_set_clock_frequency(CLK_MPLL, s->pll_refclk_freq);
+    } else {
+        imx_ccm_set_clock_frequency(CLK_MPLL,
+                                    imx_ccm_calc_pll(s->mpctl,
+                                                     s->pll_refclk_freq));
+    }
+
+    /* High-speed clock */
+    imx_ccm_set_clock_frequency(CLK_MCU, imx_ccm_get_clock_frequency(CLK_MPLL)
+                                     / (1 + EXTRACT(s->pdr0, MCU)));
+    imx_ccm_set_clock_frequency(CLK_HSP, imx_ccm_get_clock_frequency(CLK_MPLL)
+                                     / (1 + EXTRACT(s->pdr0, HSP)));
+    imx_ccm_set_clock_frequency(CLK_MAX, imx_ccm_get_clock_frequency(CLK_MPLL)
+                                     / (1 + EXTRACT(s->pdr0, MAX)));
+    imx_ccm_set_clock_frequency(CLK_IPG, imx_ccm_get_clock_frequency(CLK_MAX)
+                                     / (1 + EXTRACT(s->pdr0, IPG)));
+
+    imx_ccm_set_clock_frequency(CLK_32k, CKIL_FREQ);
+
+    DPRINTF("mcu %uMHz, HSP %uMHz, IPG %uHz\n",
+            imx_ccm_get_clock_frequency(CLK_MCU) / 1000000,
+            imx_ccm_get_clock_frequency(CLK_AHB) / 1000000,
+            imx_ccm_get_clock_frequency(CLK_IPG));
+}
+
+static void imx31_ccm_reset(DeviceState *dev)
+{
+    IMX31CCMState *s = IMX31_CCM(dev);
+
+    s->ccmr = 0x074b0b7b;
+    s->pdr0 = 0xff870b48;
+    s->pdr1 = 0x49fcfe7f;
+    s->mpctl = PLL_PD(1) | PLL_MFD(0) | PLL_MFI(6) | PLL_MFN(0);
+    s->cgr[0] = s->cgr[1] = s->cgr[2] = 0xffffffff;
+    s->spctl = PLL_PD(1) | PLL_MFD(4) | PLL_MFI(0xc) | PLL_MFN(1);
+    s->pmcr0 = 0x80209828;
+
+    update_clocks(s);
+}
+
+static uint64_t imx31_ccm_read(void *opaque, hwaddr offset,
+                                unsigned size)
+{
+    IMX31CCMState *s = (IMX31CCMState *)opaque;
+
+    DPRINTF("(offset=0x%" HWADDR_PRIx ")\n", offset);
+
+    switch (offset >> 2) {
+    case 0: /* CCMR */
+        DPRINTF(" ccmr = 0x%x\n", s->ccmr);
+        return s->ccmr;
+    case 1:
+        DPRINTF(" pdr0 = 0x%x\n", s->pdr0);
+        return s->pdr0;
+    case 2:
+        DPRINTF(" pdr1 = 0x%x\n", s->pdr1);
+        return s->pdr1;
+    case 4:
+        DPRINTF(" mpctl = 0x%x\n", s->mpctl);
+        return s->mpctl;
+    case 6:
+        DPRINTF(" spctl = 0x%x\n", s->spctl);
+        return s->spctl;
+    case 8:
+        DPRINTF(" cgr0 = 0x%x\n", s->cgr[0]);
+        return s->cgr[0];
+    case 9:
+        DPRINTF(" cgr1 = 0x%x\n", s->cgr[1]);
+        return s->cgr[1];
+    case 10:
+        DPRINTF(" cgr2 = 0x%x\n", s->cgr[2]);
+        return s->cgr[2];
+    case 18: /* LTR1 */
+        return 0x00004040;
+    case 23:
+        DPRINTF(" pcmr0 = 0x%x\n", s->pmcr0);
+        return s->pmcr0;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
+                      HWADDR_PRIx "\n", TYPE_IMX31_CCM, __func__, offset);
+        return 0;
+    }
+}
+
+static void imx31_ccm_write(void *opaque, hwaddr offset,
+                          uint64_t value, unsigned size)
+{
+    IMX31CCMState *s = (IMX31CCMState *)opaque;
+
+    DPRINTF("(offset=0x%" HWADDR_PRIx ", value = 0x%x)\n",
+            offset, (unsigned int)value);
+
+    switch (offset >> 2) {
+    case 0:
+        s->ccmr = CCMR_FPMF | (value & 0x3b6fdfff);
+        break;
+    case 1:
+        s->pdr0 = value & 0xff9f3fff;
+        break;
+    case 2:
+        s->pdr1 = value;
+        break;
+    case 4:
+        s->mpctl = value & 0xbfff3fff;
+        break;
+    case 6:
+        s->spctl = value & 0xbfff3fff;
+        break;
+    case 8:
+        s->cgr[0] = value;
+        return;
+    case 9:
+        s->cgr[1] = value;
+        return;
+    case 10:
+        s->cgr[2] = value;
+        return;
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
+                      HWADDR_PRIx "\n", TYPE_IMX31_CCM, __func__, offset);
+        return;
+    }
+    update_clocks(s);
+}
+
+static const struct MemoryRegionOps imx31_ccm_ops = {
+    .read = imx31_ccm_read,
+    .write = imx31_ccm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int imx31_ccm_init(SysBusDevice *dev)
+{
+    IMX31CCMState *s = IMX31_CCM(dev);
+
+    memory_region_init_io(&s->iomem, OBJECT(dev), &imx31_ccm_ops, s,
+                          TYPE_IMX31_CCM, 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static int imx31_ccm_post_load(void *opaque, int version_id)
+{
+    IMX31CCMState *s = (IMX31CCMState *)opaque;
+
+    update_clocks(s);
+    return 0;
+}
+
+static void imx31_ccm_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sbc->init = imx31_ccm_init;
+    dc->reset = imx31_ccm_reset;
+    dc->vmsd = &vmstate_imx31_ccm;
+    dc->desc = "i.MX Clock Control Module";
+}
+
+static const TypeInfo imx31_ccm_info = {
+    .name = TYPE_IMX31_CCM,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IMX31CCMState),
+    .class_init = imx31_ccm_class_init,
+};
+
+static void imx31_ccm_register_types(void)
+{
+    type_register_static(&imx31_ccm_info);
+}
+
+type_init(imx31_ccm_register_types)
diff --git a/hw/misc/imx_ccm.c b/hw/misc/imx_ccm.c
index 4cc2bbc..2c776c1 100644
--- a/hw/misc/imx_ccm.c
+++ b/hw/misc/imx_ccm.c
@@ -1,77 +1,37 @@
 /*
- * IMX31 Clock Control Module
+ * IMX common functions for Clock Control Module
  *
  * Copyright (C) 2012 NICTA
  * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
  *
  * This work is licensed under the terms of the GNU GPL, version 2 or later.
  * See the COPYING file in the top-level directory.
- *
- * To get the timer frequencies right, we need to emulate at least part of
- * the CCM.
  */
 
 #include "hw/misc/imx_ccm.h"
 
-#define CKIH_FREQ 26000000 /* 26MHz crystal input */
-#define CKIL_FREQ    32768 /* nominal 32khz clock */
-
-#ifndef DEBUG_IMX_CCM
-#define DEBUG_IMX_CCM 0
-#endif
-
-#define DPRINTF(fmt, args...) \
-    do { \
-        if (DEBUG_IMX_CCM) { \
-            fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_CCM, \
-                                             __func__, ##args); \
-        } \
-    } while (0)
-
-static int imx_ccm_post_load(void *opaque, int version_id);
+static uint32_t imx_ccm_freq_table[CLK_32k+1];
 
-static const VMStateDescription vmstate_imx_ccm = {
-    .name = TYPE_IMX_CCM,
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(ccmr, IMXCCMState),
-        VMSTATE_UINT32(pdr0, IMXCCMState),
-        VMSTATE_UINT32(pdr1, IMXCCMState),
-        VMSTATE_UINT32(mpctl, IMXCCMState),
-        VMSTATE_UINT32(spctl, IMXCCMState),
-        VMSTATE_UINT32_ARRAY(cgr, IMXCCMState, 3),
-        VMSTATE_UINT32(pmcr0, IMXCCMState),
-        VMSTATE_UINT32(pmcr1, IMXCCMState),
-        VMSTATE_UINT32(pll_refclk_freq, IMXCCMState),
-        VMSTATE_END_OF_LIST()
-    },
-    .post_load = imx_ccm_post_load,
-};
-
-uint32_t imx_clock_frequency(DeviceState *dev, IMXClk clock)
+uint32_t imx_ccm_get_clock_frequency(IMXClk clock)
 {
-    IMXCCMState *s = IMX_CCM(dev);
+    if ((clock > NOCLK) && (clock <= CLK_32k)) {
+        return imx_ccm_freq_table[clock];
+    } else {
+        return imx_ccm_freq_table[NOCLK];
+    }
+}
 
-    switch (clock) {
-    case NOCLK:
-        return 0;
-    case MCU:
-        return s->mcu_clk_freq;
-    case HSP:
-        return s->hsp_clk_freq;
-    case IPG:
-        return s->ipg_clk_freq;
-    case CLK_32k:
-        return CKIL_FREQ;
+void imx_ccm_set_clock_frequency(IMXClk clock, uint32_t freq)
+{
+    if ((clock > NOCLK) && (clock <= CLK_32k)) {
+        imx_ccm_freq_table[clock] = freq;
     }
-    return 0;
 }
 
 /*
  * Calculate PLL output frequency
  */
-static uint32_t calc_pll(uint32_t pllreg, uint32_t base_freq)
+uint32_t imx_ccm_calc_pll(uint32_t pllreg, uint32_t base_freq)
 {
     int32_t mfn = MFN(pllreg);  /* Numerator */
     uint32_t mfi = MFI(pllreg); /* Integer part */
@@ -88,184 +48,3 @@ static uint32_t calc_pll(uint32_t pllreg, uint32_t base_freq)
     return ((2 * (base_freq >> 10) * (mfi * mfd + mfn)) /
             (mfd * pd)) << 10;
 }
-
-static void update_clocks(IMXCCMState *s)
-{
-    /*
-     * If we ever emulate more clocks, this should switch to a data-driven
-     * approach
-     */
-
-    if ((s->ccmr & CCMR_PRCS) == 2) {
-        s->pll_refclk_freq = CKIL_FREQ * 1024;
-    } else {
-        s->pll_refclk_freq = CKIH_FREQ;
-    }
-
-    /* ipg_clk_arm aka MCU clock */
-    if ((s->ccmr & CCMR_MDS) || !(s->ccmr & CCMR_MPE)) {
-        s->mcu_clk_freq = s->pll_refclk_freq;
-    } else {
-        s->mcu_clk_freq = calc_pll(s->mpctl, s->pll_refclk_freq);
-    }
-
-    /* High-speed clock */
-    s->hsp_clk_freq = s->mcu_clk_freq / (1 + EXTRACT(s->pdr0, HSP));
-    s->ipg_clk_freq = s->hsp_clk_freq / (1 + EXTRACT(s->pdr0, IPG));
-
-    DPRINTF("mcu %uMHz, HSP %uMHz, IPG %uHz\n",
-            s->mcu_clk_freq / 1000000,
-            s->hsp_clk_freq / 1000000,
-            s->ipg_clk_freq);
-}
-
-static void imx_ccm_reset(DeviceState *dev)
-{
-    IMXCCMState *s = IMX_CCM(dev);
-
-    s->ccmr = 0x074b0b7b;
-    s->pdr0 = 0xff870b48;
-    s->pdr1 = 0x49fcfe7f;
-    s->mpctl = PLL_PD(1) | PLL_MFD(0) | PLL_MFI(6) | PLL_MFN(0);
-    s->cgr[0] = s->cgr[1] = s->cgr[2] = 0xffffffff;
-    s->spctl = PLL_PD(1) | PLL_MFD(4) | PLL_MFI(0xc) | PLL_MFN(1);
-    s->pmcr0 = 0x80209828;
-
-    update_clocks(s);
-}
-
-static uint64_t imx_ccm_read(void *opaque, hwaddr offset,
-                                unsigned size)
-{
-    IMXCCMState *s = (IMXCCMState *)opaque;
-
-    DPRINTF("(offset=0x%" HWADDR_PRIx ")\n", offset);
-
-    switch (offset >> 2) {
-    case 0: /* CCMR */
-        DPRINTF(" ccmr = 0x%x\n", s->ccmr);
-        return s->ccmr;
-    case 1:
-        DPRINTF(" pdr0 = 0x%x\n", s->pdr0);
-        return s->pdr0;
-    case 2:
-        DPRINTF(" pdr1 = 0x%x\n", s->pdr1);
-        return s->pdr1;
-    case 4:
-        DPRINTF(" mpctl = 0x%x\n", s->mpctl);
-        return s->mpctl;
-    case 6:
-        DPRINTF(" spctl = 0x%x\n", s->spctl);
-        return s->spctl;
-    case 8:
-        DPRINTF(" cgr0 = 0x%x\n", s->cgr[0]);
-        return s->cgr[0];
-    case 9:
-        DPRINTF(" cgr1 = 0x%x\n", s->cgr[1]);
-        return s->cgr[1];
-    case 10:
-        DPRINTF(" cgr2 = 0x%x\n", s->cgr[2]);
-        return s->cgr[2];
-    case 18: /* LTR1 */
-        return 0x00004040;
-    case 23:
-        DPRINTF(" pcmr0 = 0x%x\n", s->pmcr0);
-        return s->pmcr0;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
-                      HWADDR_PRIx "\n", TYPE_IMX_CCM, __func__, offset);
-        return 0;
-    }
-}
-
-static void imx_ccm_write(void *opaque, hwaddr offset,
-                          uint64_t value, unsigned size)
-{
-    IMXCCMState *s = (IMXCCMState *)opaque;
-
-    DPRINTF("(offset=0x%" HWADDR_PRIx ", value = 0x%x)\n",
-            offset, (unsigned int)value);
-
-    switch (offset >> 2) {
-    case 0:
-        s->ccmr = CCMR_FPMF | (value & 0x3b6fdfff);
-        break;
-    case 1:
-        s->pdr0 = value & 0xff9f3fff;
-        break;
-    case 2:
-        s->pdr1 = value;
-        break;
-    case 4:
-        s->mpctl = value & 0xbfff3fff;
-        break;
-    case 6:
-        s->spctl = value & 0xbfff3fff;
-        break;
-    case 8:
-        s->cgr[0] = value;
-        return;
-    case 9:
-        s->cgr[1] = value;
-        return;
-    case 10:
-        s->cgr[2] = value;
-        return;
-
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
-                      HWADDR_PRIx "\n", TYPE_IMX_CCM, __func__, offset);
-        return;
-    }
-    update_clocks(s);
-}
-
-static const struct MemoryRegionOps imx_ccm_ops = {
-    .read = imx_ccm_read,
-    .write = imx_ccm_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int imx_ccm_init(SysBusDevice *dev)
-{
-    IMXCCMState *s = IMX_CCM(dev);
-
-    memory_region_init_io(&s->iomem, OBJECT(dev), &imx_ccm_ops, s,
-                          TYPE_IMX_CCM, 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static int imx_ccm_post_load(void *opaque, int version_id)
-{
-    IMXCCMState *s = (IMXCCMState *)opaque;
-
-    update_clocks(s);
-    return 0;
-}
-
-static void imx_ccm_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sbc->init = imx_ccm_init;
-    dc->reset = imx_ccm_reset;
-    dc->vmsd = &vmstate_imx_ccm;
-    dc->desc = "i.MX Clock Control Module";
-}
-
-static const TypeInfo imx_ccm_info = {
-    .name = TYPE_IMX_CCM,
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(IMXCCMState),
-    .class_init = imx_ccm_class_init,
-};
-
-static void imx_ccm_register_types(void)
-{
-    type_register_static(&imx_ccm_info);
-}
-
-type_init(imx_ccm_register_types)
diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c
index 967be4a..90fbb8a 100644
--- a/hw/timer/imx_epit.c
+++ b/hw/timer/imx_epit.c
@@ -51,9 +51,9 @@ static char const *imx_epit_reg_name(uint32_t reg)
  * These are typical.
  */
 static const IMXClk imx_epit_clocks[] =  {
-    0,        /* 00 disabled */
-    IPG,      /* 01 ipg_clk, ~532MHz */
-    IPG,      /* 10 ipg_clk_highfreq */
+    NOCLK,    /* 00 disabled */
+    CLK_IPG,  /* 01 ipg_clk, ~532MHz */
+    CLK_IPG,  /* 10 ipg_clk_highfreq */
     CLK_32k,  /* 11 ipg_clk_32k -- ~32kHz */
 };
 
@@ -78,7 +78,7 @@ static void imx_epit_set_freq(IMXEPITState *s)
     clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, 2);
     prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, 12);
 
-    freq = imx_clock_frequency(s->ccm, imx_epit_clocks[clksrc]) / prescaler;
+    freq = imx_ccm_get_clock_frequency(imx_epit_clocks[clksrc]) / prescaler;
 
     s->freq = freq;
 
diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c
index 7257f42..e1f4f20 100644
--- a/hw/timer/imx_gpt.c
+++ b/hw/timer/imx_gpt.c
@@ -81,19 +81,19 @@ static const VMStateDescription vmstate_imx_timer_gpt = {
 
 static const IMXClk imx_gpt_clocks[] = {
     NOCLK,    /* 000 No clock source */
-    IPG,      /* 001 ipg_clk, 532MHz*/
-    IPG,      /* 010 ipg_clk_highfreq */
+    CLK_IPG,  /* 001 ipg_clk, 532MHz*/
+    CLK_IPG,  /* 010 ipg_clk_highfreq */
     NOCLK,    /* 011 not defined */
     CLK_32k,  /* 100 ipg_clk_32k */
-    NOCLK,    /* 101 not defined */
-    NOCLK,    /* 110 not defined */
-    NOCLK,    /* 111 not defined */
+    CLK_32k,  /* 101 not defined */
+    CLK_32k,  /* 110 not defined */
+    CLK_32k,  /* 111 not defined */
 };
 
 static void imx_gpt_set_freq(IMXGPTState *s)
 {
     uint32_t clksrc = extract32(s->cr, GPT_CR_CLKSRC_SHIFT, 3);
-    uint32_t freq = imx_clock_frequency(s->ccm, imx_gpt_clocks[clksrc])
+    uint32_t freq = imx_ccm_get_clock_frequency(imx_gpt_clocks[clksrc])
                     / (1 + s->pr);
     s->freq = freq;
 
diff --git a/include/hw/arm/fsl-imx25.h b/include/hw/arm/fsl-imx25.h
index 73f50c6..5c62fde 100644
--- a/include/hw/arm/fsl-imx25.h
+++ b/include/hw/arm/fsl-imx25.h
@@ -19,7 +19,7 @@
 
 #include "hw/arm/arm.h"
 #include "hw/intc/imx_avic.h"
-#include "hw/misc/imx_ccm.h"
+#include "hw/misc/imx31_ccm.h"
 #include "hw/char/imx_serial.h"
 #include "hw/timer/imx_gpt.h"
 #include "hw/timer/imx_epit.h"
@@ -44,7 +44,7 @@ typedef struct FslIMX25State {
     /*< public >*/
     ARMCPU         cpu;
     IMXAVICState   avic;
-    IMXCCMState    ccm;
+    IMX31CCMState  ccm;
     IMXSerialState uart[FSL_IMX25_NUM_UARTS];
     IMXGPTState    gpt[FSL_IMX25_NUM_GPTS];
     IMXEPITState   epit[FSL_IMX25_NUM_EPITS];
diff --git a/include/hw/arm/fsl-imx31.h b/include/hw/arm/fsl-imx31.h
index 5e8f795..d408abb 100644
--- a/include/hw/arm/fsl-imx31.h
+++ b/include/hw/arm/fsl-imx31.h
@@ -19,7 +19,7 @@
 
 #include "hw/arm/arm.h"
 #include "hw/intc/imx_avic.h"
-#include "hw/misc/imx_ccm.h"
+#include "hw/misc/imx31_ccm.h"
 #include "hw/char/imx_serial.h"
 #include "hw/timer/imx_gpt.h"
 #include "hw/timer/imx_epit.h"
@@ -42,7 +42,7 @@ typedef struct FslIMX31State {
     /*< public >*/
     ARMCPU         cpu;
     IMXAVICState   avic;
-    IMXCCMState    ccm;
+    IMX31CCMState  ccm;
     IMXSerialState uart[FSL_IMX31_NUM_UARTS];
     IMXGPTState    gpt;
     IMXEPITState   epit[FSL_IMX31_NUM_EPITS];
diff --git a/include/hw/misc/imx31_ccm.h b/include/hw/misc/imx31_ccm.h
new file mode 100644
index 0000000..96b70d8
--- /dev/null
+++ b/include/hw/misc/imx31_ccm.h
@@ -0,0 +1,68 @@
+/*
+ * IMX31 Clock Control Module
+ *
+ * Copyright (C) 2012 NICTA
+ * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef IMX31_CCM_H
+#define IMX31_CCM_H
+
+#include "hw/sysbus.h"
+#include "hw/misc/imx_ccm.h"
+
+/* CCMR */
+#define CCMR_FPME (1<<0)
+#define CCMR_MPE  (1<<3)
+#define CCMR_MDS  (1<<7)
+#define CCMR_FPMF (1<<26)
+#define CCMR_PRCS (3<<1)
+
+/* PDR0 */
+#define PDR0_MCU_PODF_SHIFT (0)
+#define PDR0_MCU_PODF_MASK (0x7)
+#define PDR0_MAX_PODF_SHIFT (3)
+#define PDR0_MAX_PODF_MASK (0x7)
+#define PDR0_IPG_PODF_SHIFT (6)
+#define PDR0_IPG_PODF_MASK (0x3)
+#define PDR0_NFC_PODF_SHIFT (8)
+#define PDR0_NFC_PODF_MASK (0x7)
+#define PDR0_HSP_PODF_SHIFT (11)
+#define PDR0_HSP_PODF_MASK (0x7)
+#define PDR0_PER_PODF_SHIFT (16)
+#define PDR0_PER_PODF_MASK (0x1f)
+#define PDR0_CSI_PODF_SHIFT (23)
+#define PDR0_CSI_PODF_MASK (0x1ff)
+
+#define EXTRACT(value, name) (((value) >> PDR0_##name##_PODF_SHIFT) \
+                              & PDR0_##name##_PODF_MASK)
+#define INSERT(value, name) (((value) & PDR0_##name##_PODF_MASK) << \
+                             PDR0_##name##_PODF_SHIFT)
+
+#define TYPE_IMX31_CCM "imx31.ccm"
+#define IMX31_CCM(obj) OBJECT_CHECK(IMX31CCMState, (obj), TYPE_IMX31_CCM)
+
+typedef struct IMX31CCMState {
+    /* <private> */
+    SysBusDevice parent_obj;
+
+    /* <public> */
+    MemoryRegion iomem;
+
+    uint32_t ccmr;
+    uint32_t pdr0;
+    uint32_t pdr1;
+    uint32_t mpctl;
+    uint32_t spctl;
+    uint32_t cgr[3];
+    uint32_t pmcr0;
+    uint32_t pmcr1;
+
+    /* Frequencies precalculated on register changes */
+    uint32_t pll_refclk_freq;
+} IMX31CCMState;
+
+#endif /* IMX31_CCM_H */
diff --git a/include/hw/misc/imx_ccm.h b/include/hw/misc/imx_ccm.h
index 0f2e469..d25e450 100644
--- a/include/hw/misc/imx_ccm.h
+++ b/include/hw/misc/imx_ccm.h
@@ -1,5 +1,5 @@
 /*
- * IMX31 Clock Control Module
+ * IMX common functions for Clock Control Module
  *
  * Copyright (C) 2012 NICTA
  * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
@@ -13,33 +13,7 @@
 
 #include "hw/sysbus.h"
 
-/* CCMR */
-#define CCMR_FPME (1<<0)
-#define CCMR_MPE  (1<<3)
-#define CCMR_MDS  (1<<7)
-#define CCMR_FPMF (1<<26)
-#define CCMR_PRCS (3<<1)
-
-/* PDR0 */
-#define PDR0_MCU_PODF_SHIFT (0)
-#define PDR0_MCU_PODF_MASK (0x7)
-#define PDR0_MAX_PODF_SHIFT (3)
-#define PDR0_MAX_PODF_MASK (0x7)
-#define PDR0_IPG_PODF_SHIFT (6)
-#define PDR0_IPG_PODF_MASK (0x3)
-#define PDR0_NFC_PODF_SHIFT (8)
-#define PDR0_NFC_PODF_MASK (0x7)
-#define PDR0_HSP_PODF_SHIFT (11)
-#define PDR0_HSP_PODF_MASK (0x7)
-#define PDR0_PER_PODF_SHIFT (16)
-#define PDR0_PER_PODF_MASK (0x1f)
-#define PDR0_CSI_PODF_SHIFT (23)
-#define PDR0_CSI_PODF_MASK (0x1ff)
-
-#define EXTRACT(value, name) (((value) >> PDR0_##name##_PODF_SHIFT) \
-                              & PDR0_##name##_PODF_MASK)
-#define INSERT(value, name) (((value) & PDR0_##name##_PODF_MASK) << \
-                             PDR0_##name##_PODF_SHIFT)
+#define CKIL_FREQ 32768 /* nominal 32khz clock */
 
 /* PLL control registers */
 #define PD(v) (((v) >> 26) & 0xf)
@@ -52,40 +26,23 @@
 #define PLL_MFI(x)              (((x) & 0xf) << 10)
 #define PLL_MFN(x)              (((x) & 0x3ff) << 0)
 
-#define TYPE_IMX_CCM "imx.ccm"
-#define IMX_CCM(obj) OBJECT_CHECK(IMXCCMState, (obj), TYPE_IMX_CCM)
-
-typedef struct IMXCCMState {
-    /* <private> */
-    SysBusDevice parent_obj;
-
-    /* <public> */
-    MemoryRegion iomem;
-
-    uint32_t ccmr;
-    uint32_t pdr0;
-    uint32_t pdr1;
-    uint32_t mpctl;
-    uint32_t spctl;
-    uint32_t cgr[3];
-    uint32_t pmcr0;
-    uint32_t pmcr1;
-
-    /* Frequencies precalculated on register changes */
-    uint32_t pll_refclk_freq;
-    uint32_t mcu_clk_freq;
-    uint32_t hsp_clk_freq;
-    uint32_t ipg_clk_freq;
-} IMXCCMState;
-
 typedef enum  {
     NOCLK,
-    MCU,
-    HSP,
-    IPG,
+    CLK_MPLL,
+    CLK_UPLL,
+    CLK_MCU,
+    CLK_HSP,
+    CLK_MAX,
+    CLK_AHB,
+    CLK_IPG,
+    CLK_PER,
     CLK_32k
 } IMXClk;
 
-uint32_t imx_clock_frequency(DeviceState *s, IMXClk clock);
+uint32_t imx_ccm_calc_pll(uint32_t pllreg, uint32_t base_freq);
+
+uint32_t imx_ccm_get_clock_frequency(IMXClk clock);
+
+void imx_ccm_set_clock_frequency(IMXClk clock, uint32_t freq);
 
 #endif /* IMX_CCM_H */
diff --git a/include/hw/timer/imx_epit.h b/include/hw/timer/imx_epit.h
index c5328ae..d4723ca 100644
--- a/include/hw/timer/imx_epit.h
+++ b/include/hw/timer/imx_epit.h
@@ -64,7 +64,6 @@ typedef struct IMXEPITState{
     ptimer_state *timer_reload;
     ptimer_state *timer_cmp;
     MemoryRegion iomem;
-    DeviceState *ccm;
 
     uint32_t cr;
     uint32_t sr;
diff --git a/include/hw/timer/imx_gpt.h b/include/hw/timer/imx_gpt.h
index 3f02d3b..4cf8c3a 100644
--- a/include/hw/timer/imx_gpt.h
+++ b/include/hw/timer/imx_gpt.h
@@ -83,7 +83,6 @@ typedef struct IMXGPTState{
     /*< public >*/
     ptimer_state *timer;
     MemoryRegion iomem;
-    DeviceState *ccm;
 
     uint32_t cr;
     uint32_t pr;
-- 
2.5.0

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

* [Qemu-devel] [PATCH 2/2] i.MX: Add i.MX25 CCM driver
  2015-10-27 22:32 [Qemu-devel] [PATCH 0/2] i.MX: Add an i.MX25 specific CCM driver Jean-Christophe Dubois
  2015-10-27 22:32 ` [Qemu-devel] [PATCH 1/2] i.MX: rework " Jean-Christophe Dubois
@ 2015-10-27 22:32 ` Jean-Christophe Dubois
  1 sibling, 0 replies; 3+ messages in thread
From: Jean-Christophe Dubois @ 2015-10-27 22:32 UTC (permalink / raw)
  To: qemu-devel, peter.maydell, crosthwaite.peter; +Cc: Jean-Christophe Dubois

The i.MX25 CCM device is different from the i.MX31 one.

So for now the emulation was not correct even if linux was working OK
on top of the i.MX25 emulation.

We add an i.MX25 specific CCM driver and use it in the i.MX25 SOC
emulation.

Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
---
 hw/arm/fsl-imx25.c          |   2 +-
 hw/misc/Makefile.objs       |   1 +
 hw/misc/imx25_ccm.c         | 224 ++++++++++++++++++++++++++++++++++++++++++++
 include/hw/arm/fsl-imx25.h  |   4 +-
 include/hw/misc/imx25_ccm.h |  61 ++++++++++++
 5 files changed, 289 insertions(+), 3 deletions(-)
 create mode 100644 hw/misc/imx25_ccm.c
 create mode 100644 include/hw/misc/imx25_ccm.h

diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c
index 620c5c6..5301c1c 100644
--- a/hw/arm/fsl-imx25.c
+++ b/hw/arm/fsl-imx25.c
@@ -38,7 +38,7 @@ static void fsl_imx25_init(Object *obj)
     object_initialize(&s->avic, sizeof(s->avic), TYPE_IMX_AVIC);
     qdev_set_parent_bus(DEVICE(&s->avic), sysbus_get_default());
 
-    object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX31_CCM);
+    object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX25_CCM);
     qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default());
 
     for (i = 0; i < FSL_IMX25_NUM_UARTS; i++) {
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 79b3487..e8dc22d 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -27,6 +27,7 @@ obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o
 obj-$(CONFIG_EXYNOS4) += exynos4210_pmu.o
 obj-$(CONFIG_IMX) += imx_ccm.o
 obj-$(CONFIG_IMX) += imx31_ccm.o
+obj-$(CONFIG_IMX) += imx25_ccm.o
 obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o
 obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o
 obj-$(CONFIG_MAINSTONE) += mst_fpga.o
diff --git a/hw/misc/imx25_ccm.c b/hw/misc/imx25_ccm.c
new file mode 100644
index 0000000..6cb4c6f
--- /dev/null
+++ b/hw/misc/imx25_ccm.c
@@ -0,0 +1,224 @@
+/*
+ * IMX25 Clock Control Module
+ *
+ * Copyright (C) 2012 NICTA
+ * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * To get the timer frequencies right, we need to emulate at least part of
+ * the CCM.
+ */
+
+#include "hw/misc/imx25_ccm.h"
+
+#define CKIH_FREQ 24000000 /* 24MHz crystal input */
+
+//#define DEBUG_CCM 1
+#ifdef DEBUG_CCM
+#define DPRINTF(fmt, args...) \
+do { printf("%s: " fmt , TYPE_IMX25_CCM, ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+static int imx25_ccm_post_load(void *opaque, int version_id);
+
+static const VMStateDescription vmstate_imx25_ccm = {
+    .name = TYPE_IMX25_CCM,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(mpctl, IMX25CCMState),
+        VMSTATE_UINT32(upctl, IMX25CCMState),
+        VMSTATE_UINT32(cctl, IMX25CCMState),
+        VMSTATE_UINT32_ARRAY(cgcr, IMX25CCMState, 3),
+        VMSTATE_UINT32_ARRAY(pcdr, IMX25CCMState, 4),
+        VMSTATE_UINT32(rcsr, IMX25CCMState),
+        VMSTATE_UINT32(crdr, IMX25CCMState),
+        VMSTATE_UINT32_ARRAY(dcvr, IMX25CCMState, 4),
+        VMSTATE_UINT32_ARRAY(ltr, IMX25CCMState, 4),
+        VMSTATE_UINT32_ARRAY(ltbr, IMX25CCMState, 2),
+        VMSTATE_UINT32_ARRAY(pmcr, IMX25CCMState, 3),
+        VMSTATE_UINT32(mcr, IMX25CCMState),
+        VMSTATE_UINT32_ARRAY(lpimr, IMX25CCMState, 2),
+        VMSTATE_UINT32(pll_refclk_freq, IMX25CCMState),
+        VMSTATE_END_OF_LIST()
+    },
+    .post_load = imx25_ccm_post_load,
+};
+
+static void imx25_ccm_update_clocks(IMX25CCMState *s)
+{
+    DPRINTF("%s()\n", __func__);
+    /*
+     * If we ever emulate more clocks, this should switch to a data-driven
+     * approach
+     */
+
+    /* Our input CLK */
+    s->pll_refclk_freq = CKIH_FREQ;
+
+    /* Set MCU PLL CLK */
+    if (EXTRACT(s->cctl, MPLL_BYPASS)) {
+        imx_ccm_set_clock_frequency(CLK_MPLL, s->pll_refclk_freq);
+    } else {
+        imx_ccm_set_clock_frequency(CLK_MPLL,
+                                    imx_ccm_calc_pll(s->mpctl,
+                                                     s->pll_refclk_freq));
+    }
+
+    /* Set USB PLL CLK */
+    imx_ccm_set_clock_frequency(CLK_UPLL,
+                                imx_ccm_calc_pll(s->upctl,
+                                                 s->pll_refclk_freq));
+
+    /* Set Processor clock */
+    if (EXTRACT(s->cctl, ARM_SRC)) {
+        imx_ccm_set_clock_frequency(CLK_MCU,
+                                    (imx_ccm_get_clock_frequency(CLK_MPLL) * 3
+                                     / 4)
+                                     / (1 + EXTRACT(s->cctl, ARM_CLK_DIV)));
+    } else {
+        imx_ccm_set_clock_frequency(CLK_MCU,
+                                    imx_ccm_get_clock_frequency(CLK_MPLL) /
+                                    (1 + EXTRACT(s->cctl, ARM_CLK_DIV)));
+    }
+
+    /* Set AHB CLK */
+    imx_ccm_set_clock_frequency(CLK_AHB, imx_ccm_get_clock_frequency(CLK_MCU) /
+                                         (1 + EXTRACT(s->cctl, AHB_CLK_DIV)));
+
+    /* Set IPG CLK */
+    imx_ccm_set_clock_frequency(CLK_IPG, imx_ccm_get_clock_frequency(CLK_AHB) /
+                                         2);
+
+    /* Set 32K cristal CLK */
+    imx_ccm_set_clock_frequency(CLK_32k, CKIL_FREQ);
+
+}
+
+static void imx25_ccm_reset(DeviceState *dev)
+{
+    IMX25CCMState *s = IMX25_CCM(dev);
+
+    DPRINTF("%s()\n", __func__);
+
+    s->mpctl = 0x800b2c01;
+    s->upctl = 0x84002800;
+    s->cctl = 0x40030000;
+    s->cgcr[0] = 0x028A0100;
+    s->cgcr[1] = 0x04008100;
+    s->cgcr[2] = 0x00000438;
+    s->pcdr[0] = 0x01010101;
+    s->pcdr[1] = 0x01010101;
+    s->pcdr[2] = 0x01010101;
+    s->pcdr[3] = 0x01010101;
+    s->rcsr = 0;
+    s->crdr = 0;
+    s->dcvr[0] = 0;
+    s->dcvr[1] = 0;
+    s->dcvr[2] = 0;
+    s->dcvr[3] = 0;
+    s->ltr[0] = 0;
+    s->ltr[1] = 0;
+    s->ltr[2] = 0;
+    s->ltr[3] = 0;
+    s->ltbr[0] = 0;
+    s->ltbr[1] = 0;
+    s->pmcr[0] = 0x00A00000;
+    s->pmcr[1] = 0x0000A030;
+    s->pmcr[2] = 0x0000A030;
+    s->mcr = 0x43000000;
+    s->lpimr[0] = 0;
+    s->lpimr[1] = 0;
+
+    /* default ROM Boot will change the reset values */
+    s->cctl |= INSERT(1, ARM_SRC);
+    s->cctl |= INSERT(1, AHB_CLK_DIV);
+
+    imx25_ccm_update_clocks(s);
+}
+
+static uint64_t imx25_ccm_read(void *opaque, hwaddr offset,
+                                unsigned size)
+{
+    IMX25CCMState *s = (IMX25CCMState *)opaque;
+    uint32_t *reg = &s->mpctl;
+
+    DPRINTF("%s(offset=%x)\n", __func__, (int)(offset >> 2));
+
+    if (offset >= 0x70) {
+        return 0;
+    } else {
+        return reg[offset >> 2];
+    }
+}
+
+static void imx25_ccm_write(void *opaque, hwaddr offset,
+                          uint64_t value, unsigned size)
+{
+    IMX25CCMState *s = (IMX25CCMState *)opaque;
+    uint32_t *reg = &s->mpctl;
+
+    DPRINTF("%s(offset=%x, value = %x)\n", __func__,
+            (int)(offset >> 2), (unsigned int)value);
+
+    if (offset < 0x70) {
+        reg[offset >> 2] = value;
+    }
+
+    imx25_ccm_update_clocks(s);
+}
+
+static const struct MemoryRegionOps imx25_ccm_ops = {
+    .read = imx25_ccm_read,
+    .write = imx25_ccm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int imx25_ccm_init(SysBusDevice *dev)
+{
+    IMX25CCMState *s = IMX25_CCM(dev);
+
+    memory_region_init_io(&s->iomem, OBJECT(dev), &imx25_ccm_ops, s,
+                          TYPE_IMX25_CCM, 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static int imx25_ccm_post_load(void *opaque, int version_id)
+{
+    IMX25CCMState *s = (IMX25CCMState *)opaque;
+
+    imx25_ccm_update_clocks(s);
+
+    return 0;
+}
+
+static void imx25_ccm_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sbc->init = imx25_ccm_init;
+    dc->reset = imx25_ccm_reset;
+    dc->vmsd = &vmstate_imx25_ccm;
+    dc->desc = "i.MX Clock Control Module";
+}
+
+static const TypeInfo imx25_ccm_info = {
+    .name = TYPE_IMX25_CCM,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IMX25CCMState),
+    .class_init = imx25_ccm_class_init,
+};
+
+static void imx25_ccm_register_types(void)
+{
+    type_register_static(&imx25_ccm_info);
+}
+
+type_init(imx25_ccm_register_types)
diff --git a/include/hw/arm/fsl-imx25.h b/include/hw/arm/fsl-imx25.h
index 5c62fde..d0e8e9d 100644
--- a/include/hw/arm/fsl-imx25.h
+++ b/include/hw/arm/fsl-imx25.h
@@ -19,7 +19,7 @@
 
 #include "hw/arm/arm.h"
 #include "hw/intc/imx_avic.h"
-#include "hw/misc/imx31_ccm.h"
+#include "hw/misc/imx25_ccm.h"
 #include "hw/char/imx_serial.h"
 #include "hw/timer/imx_gpt.h"
 #include "hw/timer/imx_epit.h"
@@ -44,7 +44,7 @@ typedef struct FslIMX25State {
     /*< public >*/
     ARMCPU         cpu;
     IMXAVICState   avic;
-    IMX31CCMState  ccm;
+    IMX25CCMState  ccm;
     IMXSerialState uart[FSL_IMX25_NUM_UARTS];
     IMXGPTState    gpt[FSL_IMX25_NUM_GPTS];
     IMXEPITState   epit[FSL_IMX25_NUM_EPITS];
diff --git a/include/hw/misc/imx25_ccm.h b/include/hw/misc/imx25_ccm.h
new file mode 100644
index 0000000..20100ca
--- /dev/null
+++ b/include/hw/misc/imx25_ccm.h
@@ -0,0 +1,61 @@
+/*
+ * IMX25 Clock Control Module
+ *
+ * Copyright (C) 2012 NICTA
+ * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef IMX25_CCM_H
+#define IMX25_CCM_H
+
+#include "hw/sysbus.h"
+#include "hw/misc/imx_ccm.h"
+
+/* CCTL */
+#define CCTL_ARM_CLK_DIV_SHIFT (30)
+#define CCTL_ARM_CLK_DIV_MASK  (0x3)
+#define CCTL_AHB_CLK_DIV_SHIFT (28)
+#define CCTL_AHB_CLK_DIV_MASK  (0x3)
+#define CCTL_MPLL_BYPASS_SHIFT (22)
+#define CCTL_MPLL_BYPASS_MASK  (0x1)
+#define CCTL_USB_DIV_SHIFT (16)
+#define CCTL_USB_DIV_MASK  (0x3F)
+#define CCTL_ARM_SRC_SHIFT (13)
+#define CCTL_ARM_SRC_MASK  (0x1)
+
+#define EXTRACT(value, name) (((value) >> CCTL_##name##_SHIFT) \
+                              & CCTL_##name##_MASK)
+#define INSERT(value, name) (((value) & CCTL_##name##_MASK) << \
+                             CCTL_##name##_SHIFT)
+
+#define TYPE_IMX25_CCM "imx25.ccm"
+#define IMX25_CCM(obj) OBJECT_CHECK(IMX25CCMState, (obj), TYPE_IMX25_CCM)
+
+typedef struct IMX25CCMState {
+    /* <private> */
+    SysBusDevice parent_obj;
+
+    /* <public> */
+    MemoryRegion iomem;
+
+    uint32_t mpctl;
+    uint32_t upctl;
+    uint32_t cctl;
+    uint32_t cgcr[3];
+    uint32_t pcdr[4];
+    uint32_t rcsr;
+    uint32_t crdr;
+    uint32_t dcvr[4];
+    uint32_t ltr[4];
+    uint32_t ltbr[2];
+    uint32_t pmcr[3];
+    uint32_t mcr;
+    uint32_t lpimr[2];
+
+    uint32_t pll_refclk_freq;
+} IMX25CCMState;
+
+#endif /* IMX25_CCM_H */
-- 
2.5.0

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

end of thread, other threads:[~2015-10-27 22:32 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-10-27 22:32 [Qemu-devel] [PATCH 0/2] i.MX: Add an i.MX25 specific CCM driver Jean-Christophe Dubois
2015-10-27 22:32 ` [Qemu-devel] [PATCH 1/2] i.MX: rework " Jean-Christophe Dubois
2015-10-27 22:32 ` [Qemu-devel] [PATCH 2/2] i.MX: Add i.MX25 " Jean-Christophe Dubois

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).