Skip to contentSkip to conversation

Add an i.MX25 specific CCM driver

PATCH Superseded Jean-Christophe Dubois 3 participants 8 messages Oct 28, 2015 – Nov 13, 2015 Arm i.MX and Layerscape

v2 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

v2 cover Add an i.MX25 specific CCM driver

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         | 228 ++++++++++++++++++++++++++++++++++++++++
 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, 644 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
Signature · 1 line
2.5.0
#1 lore raw

PATCH v2 1/2 i.MX: rework CCM driver.

The CCM drive 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.

---

Changes since v1:
* None

 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
hw/arm/fsl-imx25.c +1 -5
index e1cadac..620c5c6 100644
@@ -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);
hw/arm/fsl-imx31.c +1 -5
index 53d4473..7ae23d5 100644
@@ -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);
hw/misc/Makefile.objs +1 -0
index 4aa76ff..79b3487 100644
@@ -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
hw/misc/imx31_ccm.c new file +240 -0

240 lines not on this page · raw message

hw/misc/imx_ccm.c +14 -235

275 lines not on this page · raw message

hw/timer/imx_epit.c +4 -4
index 967be4a..90fbb8a 100644
@@ -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;
 
hw/timer/imx_gpt.c +6 -6
index 7257f42..e1f4f20 100644
@@ -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;
 
include/hw/arm/fsl-imx25.h +2 -2
index 73f50c6..5c62fde 100644
@@ -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];
include/hw/arm/fsl-imx31.h +2 -2
index 5e8f795..d408abb 100644
@@ -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];
include/hw/misc/imx31_ccm.h new file +68 -0

68 lines not on this page · raw message

include/hw/misc/imx_ccm.h +15 -58

93 lines not on this page · raw message

include/hw/timer/imx_epit.h +0 -1
index c5328ae..d4723ca 100644
@@ -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;
include/hw/timer/imx_gpt.h +0 -1
index 3f02d3b..4cf8c3a 100644
@@ -83,7 +83,6 @@ typedef struct IMXGPTState{
     /*< public >*/
     ptimer_state *timer;
     MemoryRegion iomem;
-    DeviceState *ccm;
 
     uint32_t cr;
     uint32_t pr;
Signature · 1 line
2.5.0
#2 lore raw

Re: [Qemu-devel] [PATCH v2 1/2] i.MX: rework CCM driver.

Quoted 14 lines · Jean-Christophe Dubois

The CCM drive 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.

---

Quoted 8 lines

Changes since v1:
* None

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

This is tricky to review as there is a combination of refactoring as well as major code motion. To get a diff on this, I split the patch in two, first with a pure mechanical patch that renames everything "IMX CCM" related to "IMX31 CCM". The diff on that is then easily reviewed if the patch is formatted with rename detection on. To setup rename detection:

git config diff.renames true; git config diff.algorithm patience

With that, the diff on the rest (second patch) is:

$ git diff --stat HEAD..77f8cde33bebe057d668c6e6e2c420ee4e37dbae
 hw/arm/fsl-imx25.c          |  4 ---
 hw/arm/fsl-imx31.c          |  4 ---
 hw/misc/Makefile.objs       |  1 +
 hw/misc/imx31_ccm.c         | 73 +++++++++++++--------------------------------
 hw/misc/imx_ccm.c           | 50 +++++++++++++++++++++++++++++++
 hw/timer/imx_epit.c         | 10 +++----
 hw/timer/imx_gpt.c          | 14 ++++-----
 include/hw/misc/imx31_ccm.h | 25 +---------------
 include/hw/misc/imx_ccm.h   | 48 +++++++++++++++++++++++++++++
 include/hw/timer/imx_epit.h |  1 -
 include/hw/timer/imx_gpt.h  |  1 -
 11 files changed, 133 insertions(+), 98 deletions(-)

I'm reviewing based on what I can see in this new diff. You can get the split version here:

https://github.com/pcrost/qemu/commits/imx-ccm.next

Quoted 46 lines
 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
hw/arm/fsl-imx25.c +12 -3
index e1cadac..620c5c6 100644
@@ -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);
 
+            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;

hw/arm/fsl-imx25.c static void fsl_imx25_realize(DeviceState *dev, Error **errp)

Quoted 10 lines
hw/arm/fsl-imx25.c +10 -0
+    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)

Indentation of continued arg list slightly out. Here and for write.

Quoted 30 lines
hw/arm/fsl-imx25.c +23 -6
+{
+    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]);
 
-#define CKIL_FREQ    32768 /* nominal 32khz clock */
-
-#ifndef DEBUG_IMX_CCM
-#define DEBUG_IMX_CCM 0
-#endif
-

hw/arm/fsl-imx25.c

Quoted 10 lines
hw/arm/fsl-imx25.c +1 -9
-#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];

I don't think this can really be a global variable. The SoC as a non-global object can't assume that it can set this via ccm_set_clock_frequency. I'm guessing the real issue is that when you go implement the CCM25, the peripherals don't know which CCM device to ref. That has a few solutions

1: QOM inheritence. There is an abstract device TYPE_IMX_CCM of which both TYPE_IMX25_CCM and TYPE_IMX31_CCM inherit. The peripherals then ref the abstraction, which provides the functionality.

2: QOM interface. There is an interface for the same, which implements the imx_ccm_get_clock_frequency and set_clock_frequency. TYPE_ARM_LINUX_BOOT_IF or TYPE_STREAM_SLAVE are two examples of devices implementing interfaces.

3: The GPIO approach. You can (hackishly) use the full numeric value of a GPIO (as set by qemu_set_irq) at the sink. This means you could propagate clock frequencies around a system via GPIOs. I have done this a fair bit in out-of-tree work.

A formalisation of number 3 would be ideal. This means existing GPIO support should be either generalised or replicated, or something in-between; create an abstraction for "signal" which then has concretes GPIO and clock. Then we have a qemu_set_clock or a qemu_irq like object.

If you don't want to take that on however (which is reasonable becuase its a big new core feature), solution #1 or #2 would be ok. #2 feels right by gut to me.

Quoted 40 lines
hw/arm/fsl-imx25.c +13 -13
-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),
 
+    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 */
include/hw/misc/imx_ccm.h +1 -1
index 0f2e469..d25e450 100644
@@ -1,5 +1,5 @@
 /*
- * IMX31 Clock Control Module
+ * IMX common functions for Clock Control Module
  *
  * Copyright (C) 2012 NICTA
  * Updated by Jean-Christophe Dubois <[email protected]>

include/hw/misc/imx_ccm.h line 14

Quoted 2 lines
include/hw/misc/imx_ccm.h +0 -0
@@ -13,33 +13,7 @@
 
 #include "hw/sysbus.h"

I think this header can be dropped.

Regards,
Peter

Quoted 7 lines
include/hw/misc/imx_ccm.h +0 -6
-/* 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)
#3 lore raw

PATCH v2 2/2 i.MX: Add i.MX25 CCM driver

In reply to 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.

---

Changes since v1:
* rework loging to match other i.MX drivers

 hw/arm/fsl-imx25.c          |   2 +-
 hw/misc/Makefile.objs       |   1 +
 hw/misc/imx25_ccm.c         | 228 ++++++++++++++++++++++++++++++++++++++++++++
 include/hw/arm/fsl-imx25.h  |   4 +-
 include/hw/misc/imx25_ccm.h |  61 ++++++++++++
 5 files changed, 293 insertions(+), 3 deletions(-)
 create mode 100644 hw/misc/imx25_ccm.c
 create mode 100644 include/hw/misc/imx25_ccm.h
hw/arm/fsl-imx25.c +1 -1
index 620c5c6..5301c1c 100644
@@ -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++) {
hw/misc/Makefile.objs +1 -0
index 79b3487..e8dc22d 100644
@@ -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
hw/misc/imx25_ccm.c new file +228 -0

228 lines not on this page · raw message

include/hw/arm/fsl-imx25.h +2 -2
index 5c62fde..d0e8e9d 100644
@@ -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];
include/hw/misc/imx25_ccm.h new file +61 -0

61 lines not on this page · raw message

Signature · 1 line
2.5.0
#4 lore raw

Re: [Qemu-devel] [PATCH v2 2/2] i.MX: Add i.MX25 CCM driver

Quoted 8 lines · 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.

s/driver/device here and in subject.

Quoted 65 lines

---

Changes since v1:
* rework loging to match other i.MX drivers

 hw/arm/fsl-imx25.c          |   2 +-
 hw/misc/Makefile.objs       |   1 +
 hw/misc/imx25_ccm.c         | 228 ++++++++++++++++++++++++++++++++++++++++++++
 include/hw/arm/fsl-imx25.h  |   4 +-
 include/hw/misc/imx25_ccm.h |  61 ++++++++++++
 5 files changed, 293 insertions(+), 3 deletions(-)
 create mode 100644 hw/misc/imx25_ccm.c
 create mode 100644 include/hw/misc/imx25_ccm.h
hw/arm/fsl-imx25.c +1 -1
index 620c5c6..5301c1c 100644
@@ -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++) {
hw/misc/Makefile.objs +1 -0
index 79b3487..e8dc22d 100644
@@ -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
hw/misc/imx25_ccm.c new file +19 -0
new file mode 100644
index 0000000..e76292d
@@ -0,0 +1,228 @@
+/*
+ * IMX25 Clock Control Module
+ *
+ * Copyright (C) 2012 NICTA
+ * Updated by Jean-Christophe Dubois <[email protected]>
+ *
+ * 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"
+
+#ifndef DEBUG_IMX25_CCM
+#define DEBUG_IMX25_CCM 0
+#endif
+

hw/misc/imx25_ccm.c line 29

Quoted 10 lines
hw/misc/imx25_ccm.c new file +10 -0
+#define DPRINTF(fmt, args...) \
+    do { \
+        if (DEBUG_IMX25_CCM) { \
+            fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX25_CCM, \
+                                             __func__, ##args); \
+        } \
+    } while (0)
+
+#define CKIH_FREQ 24000000 /* 24MHz crystal input */
+

Is the crystal freq really decided by the controller? Should this be on the board level instead? Same applies to prev patch.

hw/misc/imx25_ccm.c line 31

Quoted 2 lines
hw/misc/imx25_ccm.c new file +2 -0
+static int imx25_ccm_post_load(void *opaque, int version_id);
+

Can you just reorder to remove the forward reference?

Quoted 100 lines
hw/misc/imx25_ccm.c new file +100 -0
+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("\n");
+    /*
+     * 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("\n");
+
+    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;

hw/misc/imx25_ccm.c line 141

Quoted 10 lines
hw/misc/imx25_ccm.c new file +10 -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 */

"boot"

hw/misc/imx25_ccm.c line 152

Quoted 11 lines
hw/misc/imx25_ccm.c new file +11 -0
+    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;

I think it is just easier to just make it an array in state, and index into it with macros for the non-array uses. Then you can also memset-0 in reset and just set the non-zeros afterwards.

Quoted 48 lines
hw/misc/imx25_ccm.c new file +48 -0
+
+    DPRINTF("(offset=0x%" HWADDR_PRIx ")\n", offset);
+
+    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("(offset=0x%" HWADDR_PRIx ", value = %x)\n",
+            offset, (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);

hw/misc/imx25_ccm.c line 210

Quoted 10 lines
hw/misc/imx25_ccm.c new file +10 -0
+
+    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;

Sysbus device init is deprecated, use object instance_init and device realize instead. I think this is hangover from the i.MX31 that is unconverted. A possible follow up patch is to do the conversion for 31 based on this change. You have just mr_init_io and sb_init_mmio with constant sizes, so that can be done with just an instance_init I think.

Quoted 69 lines
hw/misc/imx25_ccm.c new file +18 -0
+    dc->reset = imx25_ccm_reset;
+    dc->vmsd = &vmstate_imx25_ccm;
+    dc->desc = "i.MX25 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)
include/hw/arm/fsl-imx25.h +2 -2
index 5c62fde..d0e8e9d 100644
@@ -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];
include/hw/misc/imx25_ccm.h new file +23 -0
new file mode 100644
index 0000000..20100ca
@@ -0,0 +1,61 @@
+/*
+ * IMX25 Clock Control Module
+ *
+ * Copyright (C) 2012 NICTA
+ * Updated by Jean-Christophe Dubois <[email protected]>
+ *
+ * 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)

include/hw/misc/imx25_ccm.h line 33

Quoted 10 lines
include/hw/misc/imx25_ccm.h new file +10 -0
+#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)
+

I have used this approach before, but wanted to make it globally available, this might be relevant:

https://lists.nongnu.org/archive/html/qemu-devel/2015-04/msg03614.html

We could split off just the macros from that patch into a new register.h (basically make that P4 a patch in its own right).

Regards,
Peter

Quoted 31 lines
include/hw/misc/imx25_ccm.h new file +28 -1
+#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

#5 lore raw
In reply to Jean-Christophe Dubois
Quoted 5 lines · 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.

Quoted 8 lines

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

Just to let you know, as this is a new feature and we're in softfreeze I'm not intending to put it in target-arm for 2.5. It is still on my to-review list though (though I'm hoping Peter C will get to it first ;-))

thanks
-- PMM

#6 lore raw
Quoted 11 lines · Peter Maydell
Quoted 10 lines · 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.

Quoted 9 lines
Quoted 3 lines

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

Just to let you know, as this is a new feature and we're in softfreeze I'm not intending to put it in target-arm for 2.5. It is still on my to-review list though (though I'm hoping Peter C will get to it first ;-))

I'm prioritising for-2.5 stuffs for the next few days, there's still one or two more series I need to look at. Probably get to this next week.

Regards,
Peter

Quoted 2 lines

thanks
-- PMM

#7 lore raw
Quoted 20 lines · Peter Crosthwaite
Quoted 11 lines · Peter Maydell
Quoted 10 lines · 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.

Quoted 8 lines
Quoted 3 lines

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

Just to let you know, as this is a new feature and we're in softfreeze I'm not intending to put it in target-arm for 2.5. It is still on my to-review list though (though I'm hoping Peter C will get to it first ;-))

Quoted 6 lines

I'm prioritising for-2.5 stuffs for the next few days, there's still one or two more series I need to look at. Probably get to this next week.

Regards,
Peter

No problem, Whenever you have time.

JC

Quoted 3 lines
Quoted 3 lines

thanks
-- PMM