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
);
45 /* Frequencies precalculated on register changes */
46 uint32_t pll_refclk_freq
;
47 uint32_t mcu_clk_freq
;
48 uint32_t hsp_clk_freq
;
49 uint32_t ipg_clk_freq
;
52 static const VMStateDescription vmstate_imx_ccm
= {
55 .minimum_version_id
= 1,
56 .minimum_version_id_old
= 1,
57 .fields
= (VMStateField
[]) {
58 VMSTATE_UINT32(ccmr
, IMXCCMState
),
59 VMSTATE_UINT32(pdr0
, IMXCCMState
),
60 VMSTATE_UINT32(pdr1
, IMXCCMState
),
61 VMSTATE_UINT32(mpctl
, IMXCCMState
),
62 VMSTATE_UINT32(spctl
, IMXCCMState
),
63 VMSTATE_UINT32_ARRAY(cgr
, IMXCCMState
, 3),
64 VMSTATE_UINT32(pmcr0
, IMXCCMState
),
65 VMSTATE_UINT32(pmcr1
, IMXCCMState
),
66 VMSTATE_UINT32(pll_refclk_freq
, IMXCCMState
),
68 .post_load
= imx_ccm_post_load
,
72 #define CCMR_FPME (1<<0)
73 #define CCMR_MPE (1<<3)
74 #define CCMR_MDS (1<<7)
75 #define CCMR_FPMF (1<<26)
76 #define CCMR_PRCS (3<<1)
79 #define PDR0_MCU_PODF_SHIFT (0)
80 #define PDR0_MCU_PODF_MASK (0x7)
81 #define PDR0_MAX_PODF_SHIFT (3)
82 #define PDR0_MAX_PODF_MASK (0x7)
83 #define PDR0_IPG_PODF_SHIFT (6)
84 #define PDR0_IPG_PODF_MASK (0x3)
85 #define PDR0_NFC_PODF_SHIFT (8)
86 #define PDR0_NFC_PODF_MASK (0x7)
87 #define PDR0_HSP_PODF_SHIFT (11)
88 #define PDR0_HSP_PODF_MASK (0x7)
89 #define PDR0_PER_PODF_SHIFT (16)
90 #define PDR0_PER_PODF_MASK (0x1f)
91 #define PDR0_CSI_PODF_SHIFT (23)
92 #define PDR0_CSI_PODF_MASK (0x1ff)
94 #define EXTRACT(value, name) (((value) >> PDR0_##name##_PODF_SHIFT) \
95 & PDR0_##name##_PODF_MASK)
96 #define INSERT(value, name) (((value) & PDR0_##name##_PODF_MASK) << \
97 PDR0_##name##_PODF_SHIFT)
98 /* PLL control registers */
99 #define PD(v) (((v) >> 26) & 0xf)
100 #define MFD(v) (((v) >> 16) & 0x3ff)
101 #define MFI(v) (((v) >> 10) & 0xf);
102 #define MFN(v) ((v) & 0x3ff)
104 #define PLL_PD(x) (((x) & 0xf) << 26)
105 #define PLL_MFD(x) (((x) & 0x3ff) << 16)
106 #define PLL_MFI(x) (((x) & 0xf) << 10)
107 #define PLL_MFN(x) (((x) & 0x3ff) << 0)
109 uint32_t imx_clock_frequency(DeviceState
*dev
, IMXClk clock
)
111 IMXCCMState
*s
= container_of(dev
, IMXCCMState
, busdev
.qdev
);
117 return s
->mcu_clk_freq
;
119 return s
->hsp_clk_freq
;
121 return s
->ipg_clk_freq
;
129 * Calculate PLL output frequency
131 static uint32_t calc_pll(uint32_t pllreg
, uint32_t base_freq
)
133 int32_t mfn
= MFN(pllreg
); /* Numerator */
134 uint32_t mfi
= MFI(pllreg
); /* Integer part */
135 uint32_t mfd
= 1 + MFD(pllreg
); /* Denominator */
136 uint32_t pd
= 1 + PD(pllreg
); /* Pre-divider */
141 /* mfn is 10-bit signed twos-complement */
145 return ((2 * (base_freq
>> 10) * (mfi
* mfd
+ mfn
)) /
149 static void update_clocks(IMXCCMState
*s
)
152 * If we ever emulate more clocks, this should switch to a data-driven
156 if ((s
->ccmr
& CCMR_PRCS
) == 2) {
157 s
->pll_refclk_freq
= CKIL_FREQ
* 1024;
159 s
->pll_refclk_freq
= CKIH_FREQ
;
162 /* ipg_clk_arm aka MCU clock */
163 if ((s
->ccmr
& CCMR_MDS
) || !(s
->ccmr
& CCMR_MPE
)) {
164 s
->mcu_clk_freq
= s
->pll_refclk_freq
;
166 s
->mcu_clk_freq
= calc_pll(s
->mpctl
, s
->pll_refclk_freq
);
169 /* High-speed clock */
170 s
->hsp_clk_freq
= s
->mcu_clk_freq
/ (1 + EXTRACT(s
->pdr0
, HSP
));
171 s
->ipg_clk_freq
= s
->hsp_clk_freq
/ (1 + EXTRACT(s
->pdr0
, IPG
));
173 DPRINTF("Clocks: mcu %uMHz, HSP %uMHz, IPG %uHz\n",
174 s
->mcu_clk_freq
/ 1000000,
175 s
->hsp_clk_freq
/ 1000000,
179 static void imx_ccm_reset(DeviceState
*dev
)
181 IMXCCMState
*s
= container_of(dev
, IMXCCMState
, busdev
.qdev
);
183 s
->ccmr
= 0x074b0b7b;
184 s
->pdr0
= 0xff870b48;
185 s
->pdr1
= 0x49fcfe7f;
186 s
->mpctl
= PLL_PD(1) | PLL_MFD(0) | PLL_MFI(6) | PLL_MFN(0);
187 s
->cgr
[0] = s
->cgr
[1] = s
->cgr
[2] = 0xffffffff;
188 s
->spctl
= PLL_PD(1) | PLL_MFD(4) | PLL_MFI(0xc) | PLL_MFN(1);
189 s
->pmcr0
= 0x80209828;
194 static uint64_t imx_ccm_read(void *opaque
, hwaddr offset
,
197 IMXCCMState
*s
= (IMXCCMState
*)opaque
;
199 DPRINTF("read(offset=%x)", offset
>> 2);
200 switch (offset
>> 2) {
202 DPRINTF(" ccmr = 0x%x\n", s
->ccmr
);
205 DPRINTF(" pdr0 = 0x%x\n", s
->pdr0
);
208 DPRINTF(" pdr1 = 0x%x\n", s
->pdr1
);
211 DPRINTF(" mpctl = 0x%x\n", s
->mpctl
);
214 DPRINTF(" spctl = 0x%x\n", s
->spctl
);
217 DPRINTF(" cgr0 = 0x%x\n", s
->cgr
[0]);
220 DPRINTF(" cgr1 = 0x%x\n", s
->cgr
[1]);
223 DPRINTF(" cgr2 = 0x%x\n", s
->cgr
[2]);
228 DPRINTF(" pcmr0 = 0x%x\n", s
->pmcr0
);
231 DPRINTF(" return 0\n");
235 static void imx_ccm_write(void *opaque
, hwaddr offset
,
236 uint64_t value
, unsigned size
)
238 IMXCCMState
*s
= (IMXCCMState
*)opaque
;
240 DPRINTF("write(offset=%x, value = %x)\n",
241 offset
>> 2, (unsigned int)value
);
242 switch (offset
>> 2) {
244 s
->ccmr
= CCMR_FPMF
| (value
& 0x3b6fdfff);
247 s
->pdr0
= value
& 0xff9f3fff;
253 s
->mpctl
= value
& 0xbfff3fff;
256 s
->spctl
= value
& 0xbfff3fff;
274 static const struct MemoryRegionOps imx_ccm_ops
= {
275 .read
= imx_ccm_read
,
276 .write
= imx_ccm_write
,
277 .endianness
= DEVICE_NATIVE_ENDIAN
,
280 static int imx_ccm_init(SysBusDevice
*dev
)
282 IMXCCMState
*s
= FROM_SYSBUS(typeof(*s
), dev
);
284 memory_region_init_io(&s
->iomem
, OBJECT(dev
), &imx_ccm_ops
, s
,
286 sysbus_init_mmio(dev
, &s
->iomem
);
291 static int imx_ccm_post_load(void *opaque
, int version_id
)
293 IMXCCMState
*s
= (IMXCCMState
*)opaque
;
299 static void imx_ccm_class_init(ObjectClass
*klass
, void *data
)
301 DeviceClass
*dc
= DEVICE_CLASS(klass
);
302 SysBusDeviceClass
*sbc
= SYS_BUS_DEVICE_CLASS(klass
);
304 sbc
->init
= imx_ccm_init
;
305 dc
->reset
= imx_ccm_reset
;
306 dc
->vmsd
= &vmstate_imx_ccm
;
307 dc
->desc
= "i.MX Clock Control Module";
310 static const TypeInfo imx_ccm_info
= {
312 .parent
= TYPE_SYS_BUS_DEVICE
,
313 .instance_size
= sizeof(IMXCCMState
),
314 .class_init
= imx_ccm_class_init
,
317 static void imx_ccm_register_types(void)
319 type_register_static(&imx_ccm_info
);
322 type_init(imx_ccm_register_types
)