[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v2 1/2] i.MX: rework CCM driver.
From: |
Jean-Christophe Dubois |
Subject: |
[Qemu-devel] [PATCH v2 1/2] i.MX: rework CCM driver. |
Date: |
Thu, 29 Oct 2015 00:02:17 +0100 |
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.
Signed-off-by: Jean-Christophe Dubois <address@hidden>
---
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
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 <address@hidden>
+ *
+ * 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 <address@hidden>
*
* 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 <address@hidden>
+ *
+ * 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 <address@hidden>
@@ -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