2 * IMX31 Clock Control Module
4 * Copyright (C) 2012 NICTA
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
9 * To get the timer frequencies right, we need to emulate at least part of
14 #include "hw/sysbus.h"
15 #include "sysemu/sysemu.h"
16 #include "hw/arm/imx.h"
18 #define CKIH_FREQ 26000000 /* 26MHz crystal input */
19 #define CKIL_FREQ 32768 /* nominal 32khz clock */
24 #define DPRINTF(fmt, args...) \
25 do { printf("imx_ccm: " fmt , ##args); } while (0)
27 #define DPRINTF(fmt, args...) do {} while (0)
30 static int imx_ccm_post_load(void *opaque
, int version_id
);
32 #define TYPE_IMX_CCM "imx_ccm"
33 #define IMX_CCM(obj) OBJECT_CHECK(IMXCCMState, (obj), TYPE_IMX_CCM)
35 typedef struct IMXCCMState
{
36 SysBusDevice parent_obj
;
49 /* Frequencies precalculated on register changes */
50 uint32_t pll_refclk_freq
;
51 uint32_t mcu_clk_freq
;
52 uint32_t hsp_clk_freq
;
53 uint32_t ipg_clk_freq
;
56 static const VMStateDescription vmstate_imx_ccm
= {
59 .minimum_version_id
= 1,
60 .fields
= (VMStateField
[]) {
61 VMSTATE_UINT32(ccmr
, IMXCCMState
),
62 VMSTATE_UINT32(pdr0
, IMXCCMState
),
63 VMSTATE_UINT32(pdr1
, IMXCCMState
),
64 VMSTATE_UINT32(mpctl
, IMXCCMState
),
65 VMSTATE_UINT32(spctl
, IMXCCMState
),
66 VMSTATE_UINT32_ARRAY(cgr
, IMXCCMState
, 3),
67 VMSTATE_UINT32(pmcr0
, IMXCCMState
),
68 VMSTATE_UINT32(pmcr1
, IMXCCMState
),
69 VMSTATE_UINT32(pll_refclk_freq
, IMXCCMState
),
72 .post_load
= imx_ccm_post_load
,
76 #define CCMR_FPME (1<<0)
77 #define CCMR_MPE (1<<3)
78 #define CCMR_MDS (1<<7)
79 #define CCMR_FPMF (1<<26)
80 #define CCMR_PRCS (3<<1)
83 #define PDR0_MCU_PODF_SHIFT (0)
84 #define PDR0_MCU_PODF_MASK (0x7)
85 #define PDR0_MAX_PODF_SHIFT (3)
86 #define PDR0_MAX_PODF_MASK (0x7)
87 #define PDR0_IPG_PODF_SHIFT (6)
88 #define PDR0_IPG_PODF_MASK (0x3)
89 #define PDR0_NFC_PODF_SHIFT (8)
90 #define PDR0_NFC_PODF_MASK (0x7)
91 #define PDR0_HSP_PODF_SHIFT (11)
92 #define PDR0_HSP_PODF_MASK (0x7)
93 #define PDR0_PER_PODF_SHIFT (16)
94 #define PDR0_PER_PODF_MASK (0x1f)
95 #define PDR0_CSI_PODF_SHIFT (23)
96 #define PDR0_CSI_PODF_MASK (0x1ff)
98 #define EXTRACT(value, name) (((value) >> PDR0_##name##_PODF_SHIFT) \
99 & PDR0_##name##_PODF_MASK)
100 #define INSERT(value, name) (((value) & PDR0_##name##_PODF_MASK) << \
101 PDR0_##name##_PODF_SHIFT)
102 /* PLL control registers */
103 #define PD(v) (((v) >> 26) & 0xf)
104 #define MFD(v) (((v) >> 16) & 0x3ff)
105 #define MFI(v) (((v) >> 10) & 0xf);
106 #define MFN(v) ((v) & 0x3ff)
108 #define PLL_PD(x) (((x) & 0xf) << 26)
109 #define PLL_MFD(x) (((x) & 0x3ff) << 16)
110 #define PLL_MFI(x) (((x) & 0xf) << 10)
111 #define PLL_MFN(x) (((x) & 0x3ff) << 0)
113 uint32_t imx_clock_frequency(DeviceState
*dev
, IMXClk clock
)
115 IMXCCMState
*s
= IMX_CCM(dev
);
121 return s
->mcu_clk_freq
;
123 return s
->hsp_clk_freq
;
125 return s
->ipg_clk_freq
;
133 * Calculate PLL output frequency
135 static uint32_t calc_pll(uint32_t pllreg
, uint32_t base_freq
)
137 int32_t mfn
= MFN(pllreg
); /* Numerator */
138 uint32_t mfi
= MFI(pllreg
); /* Integer part */
139 uint32_t mfd
= 1 + MFD(pllreg
); /* Denominator */
140 uint32_t pd
= 1 + PD(pllreg
); /* Pre-divider */
145 /* mfn is 10-bit signed twos-complement */
149 return ((2 * (base_freq
>> 10) * (mfi
* mfd
+ mfn
)) /
153 static void update_clocks(IMXCCMState
*s
)
156 * If we ever emulate more clocks, this should switch to a data-driven
160 if ((s
->ccmr
& CCMR_PRCS
) == 2) {
161 s
->pll_refclk_freq
= CKIL_FREQ
* 1024;
163 s
->pll_refclk_freq
= CKIH_FREQ
;
166 /* ipg_clk_arm aka MCU clock */
167 if ((s
->ccmr
& CCMR_MDS
) || !(s
->ccmr
& CCMR_MPE
)) {
168 s
->mcu_clk_freq
= s
->pll_refclk_freq
;
170 s
->mcu_clk_freq
= calc_pll(s
->mpctl
, s
->pll_refclk_freq
);
173 /* High-speed clock */
174 s
->hsp_clk_freq
= s
->mcu_clk_freq
/ (1 + EXTRACT(s
->pdr0
, HSP
));
175 s
->ipg_clk_freq
= s
->hsp_clk_freq
/ (1 + EXTRACT(s
->pdr0
, IPG
));
177 DPRINTF("Clocks: mcu %uMHz, HSP %uMHz, IPG %uHz\n",
178 s
->mcu_clk_freq
/ 1000000,
179 s
->hsp_clk_freq
/ 1000000,
183 static void imx_ccm_reset(DeviceState
*dev
)
185 IMXCCMState
*s
= IMX_CCM(dev
);
187 s
->ccmr
= 0x074b0b7b;
188 s
->pdr0
= 0xff870b48;
189 s
->pdr1
= 0x49fcfe7f;
190 s
->mpctl
= PLL_PD(1) | PLL_MFD(0) | PLL_MFI(6) | PLL_MFN(0);
191 s
->cgr
[0] = s
->cgr
[1] = s
->cgr
[2] = 0xffffffff;
192 s
->spctl
= PLL_PD(1) | PLL_MFD(4) | PLL_MFI(0xc) | PLL_MFN(1);
193 s
->pmcr0
= 0x80209828;
198 static uint64_t imx_ccm_read(void *opaque
, hwaddr offset
,
201 IMXCCMState
*s
= (IMXCCMState
*)opaque
;
203 DPRINTF("read(offset=%x)", offset
>> 2);
204 switch (offset
>> 2) {
206 DPRINTF(" ccmr = 0x%x\n", s
->ccmr
);
209 DPRINTF(" pdr0 = 0x%x\n", s
->pdr0
);
212 DPRINTF(" pdr1 = 0x%x\n", s
->pdr1
);
215 DPRINTF(" mpctl = 0x%x\n", s
->mpctl
);
218 DPRINTF(" spctl = 0x%x\n", s
->spctl
);
221 DPRINTF(" cgr0 = 0x%x\n", s
->cgr
[0]);
224 DPRINTF(" cgr1 = 0x%x\n", s
->cgr
[1]);
227 DPRINTF(" cgr2 = 0x%x\n", s
->cgr
[2]);
232 DPRINTF(" pcmr0 = 0x%x\n", s
->pmcr0
);
235 DPRINTF(" return 0\n");
239 static void imx_ccm_write(void *opaque
, hwaddr offset
,
240 uint64_t value
, unsigned size
)
242 IMXCCMState
*s
= (IMXCCMState
*)opaque
;
244 DPRINTF("write(offset=%x, value = %x)\n",
245 offset
>> 2, (unsigned int)value
);
246 switch (offset
>> 2) {
248 s
->ccmr
= CCMR_FPMF
| (value
& 0x3b6fdfff);
251 s
->pdr0
= value
& 0xff9f3fff;
257 s
->mpctl
= value
& 0xbfff3fff;
260 s
->spctl
= value
& 0xbfff3fff;
278 static const struct MemoryRegionOps imx_ccm_ops
= {
279 .read
= imx_ccm_read
,
280 .write
= imx_ccm_write
,
281 .endianness
= DEVICE_NATIVE_ENDIAN
,
284 static int imx_ccm_init(SysBusDevice
*dev
)
286 IMXCCMState
*s
= IMX_CCM(dev
);
288 memory_region_init_io(&s
->iomem
, OBJECT(dev
), &imx_ccm_ops
, s
,
290 sysbus_init_mmio(dev
, &s
->iomem
);
295 static int imx_ccm_post_load(void *opaque
, int version_id
)
297 IMXCCMState
*s
= (IMXCCMState
*)opaque
;
303 static void imx_ccm_class_init(ObjectClass
*klass
, void *data
)
305 DeviceClass
*dc
= DEVICE_CLASS(klass
);
306 SysBusDeviceClass
*sbc
= SYS_BUS_DEVICE_CLASS(klass
);
308 sbc
->init
= imx_ccm_init
;
309 dc
->reset
= imx_ccm_reset
;
310 dc
->vmsd
= &vmstate_imx_ccm
;
311 dc
->desc
= "i.MX Clock Control Module";
314 static const TypeInfo imx_ccm_info
= {
315 .name
= TYPE_IMX_CCM
,
316 .parent
= TYPE_SYS_BUS_DEVICE
,
317 .instance_size
= sizeof(IMXCCMState
),
318 .class_init
= imx_ccm_class_init
,
321 static void imx_ccm_register_types(void)
323 type_register_static(&imx_ccm_info
);
326 type_init(imx_ccm_register_types
)