blob: 4cc2bbc0ed941abe92e0297fc75ee1a4e5bb2f40 [file] [log] [blame]
Peter Chubbbcc181b2012-07-04 10:43:33 +00001/*
2 * IMX31 Clock Control Module
3 *
4 * Copyright (C) 2012 NICTA
Jean-Christophe Dubois282e74c2015-08-13 11:26:20 +01005 * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
Peter Chubbbcc181b2012-07-04 10:43:33 +00006 *
7 * This work is licensed under the terms of the GNU GPL, version 2 or later.
8 * See the COPYING file in the top-level directory.
9 *
10 * To get the timer frequencies right, we need to emulate at least part of
11 * the CCM.
12 */
13
Jean-Christophe Dubois282e74c2015-08-13 11:26:20 +010014#include "hw/misc/imx_ccm.h"
Peter Chubbbcc181b2012-07-04 10:43:33 +000015
16#define CKIH_FREQ 26000000 /* 26MHz crystal input */
17#define CKIL_FREQ 32768 /* nominal 32khz clock */
18
Jean-Christophe Dubois4a6aa0a2015-10-25 15:16:19 +010019#ifndef DEBUG_IMX_CCM
20#define DEBUG_IMX_CCM 0
Peter Chubbbcc181b2012-07-04 10:43:33 +000021#endif
22
Jean-Christophe Dubois4a6aa0a2015-10-25 15:16:19 +010023#define DPRINTF(fmt, args...) \
24 do { \
25 if (DEBUG_IMX_CCM) { \
26 fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_CCM, \
27 __func__, ##args); \
28 } \
29 } while (0)
30
Peter Chubbbcc181b2012-07-04 10:43:33 +000031static int imx_ccm_post_load(void *opaque, int version_id);
32
Peter Chubbbcc181b2012-07-04 10:43:33 +000033static const VMStateDescription vmstate_imx_ccm = {
Jean-Christophe Duboisc14875b2015-08-13 11:26:20 +010034 .name = TYPE_IMX_CCM,
Peter Chubbbcc181b2012-07-04 10:43:33 +000035 .version_id = 1,
36 .minimum_version_id = 1,
Peter Chubbbcc181b2012-07-04 10:43:33 +000037 .fields = (VMStateField[]) {
38 VMSTATE_UINT32(ccmr, IMXCCMState),
39 VMSTATE_UINT32(pdr0, IMXCCMState),
40 VMSTATE_UINT32(pdr1, IMXCCMState),
41 VMSTATE_UINT32(mpctl, IMXCCMState),
42 VMSTATE_UINT32(spctl, IMXCCMState),
43 VMSTATE_UINT32_ARRAY(cgr, IMXCCMState, 3),
44 VMSTATE_UINT32(pmcr0, IMXCCMState),
45 VMSTATE_UINT32(pmcr1, IMXCCMState),
46 VMSTATE_UINT32(pll_refclk_freq, IMXCCMState),
Peter Maydellef493d52014-07-22 17:10:01 +010047 VMSTATE_END_OF_LIST()
Peter Chubbbcc181b2012-07-04 10:43:33 +000048 },
49 .post_load = imx_ccm_post_load,
50};
51
Peter Chubbbcc181b2012-07-04 10:43:33 +000052uint32_t imx_clock_frequency(DeviceState *dev, IMXClk clock)
53{
Andreas Färberbcb34c72013-07-26 21:50:54 +020054 IMXCCMState *s = IMX_CCM(dev);
Peter Chubbbcc181b2012-07-04 10:43:33 +000055
56 switch (clock) {
57 case NOCLK:
58 return 0;
59 case MCU:
60 return s->mcu_clk_freq;
61 case HSP:
62 return s->hsp_clk_freq;
63 case IPG:
64 return s->ipg_clk_freq;
65 case CLK_32k:
66 return CKIL_FREQ;
67 }
68 return 0;
69}
70
71/*
72 * Calculate PLL output frequency
73 */
74static uint32_t calc_pll(uint32_t pllreg, uint32_t base_freq)
75{
76 int32_t mfn = MFN(pllreg); /* Numerator */
77 uint32_t mfi = MFI(pllreg); /* Integer part */
78 uint32_t mfd = 1 + MFD(pllreg); /* Denominator */
79 uint32_t pd = 1 + PD(pllreg); /* Pre-divider */
80
81 if (mfi < 5) {
82 mfi = 5;
83 }
84 /* mfn is 10-bit signed twos-complement */
85 mfn <<= 32 - 10;
86 mfn >>= 32 - 10;
87
88 return ((2 * (base_freq >> 10) * (mfi * mfd + mfn)) /
89 (mfd * pd)) << 10;
90}
91
92static void update_clocks(IMXCCMState *s)
93{
94 /*
95 * If we ever emulate more clocks, this should switch to a data-driven
96 * approach
97 */
98
Stefan Weilf3c8fac2013-06-09 22:44:22 +020099 if ((s->ccmr & CCMR_PRCS) == 2) {
Peter Chubbbcc181b2012-07-04 10:43:33 +0000100 s->pll_refclk_freq = CKIL_FREQ * 1024;
101 } else {
102 s->pll_refclk_freq = CKIH_FREQ;
103 }
104
105 /* ipg_clk_arm aka MCU clock */
106 if ((s->ccmr & CCMR_MDS) || !(s->ccmr & CCMR_MPE)) {
107 s->mcu_clk_freq = s->pll_refclk_freq;
108 } else {
109 s->mcu_clk_freq = calc_pll(s->mpctl, s->pll_refclk_freq);
110 }
111
112 /* High-speed clock */
113 s->hsp_clk_freq = s->mcu_clk_freq / (1 + EXTRACT(s->pdr0, HSP));
114 s->ipg_clk_freq = s->hsp_clk_freq / (1 + EXTRACT(s->pdr0, IPG));
115
Jean-Christophe Dubois4a6aa0a2015-10-25 15:16:19 +0100116 DPRINTF("mcu %uMHz, HSP %uMHz, IPG %uHz\n",
Peter Chubbbcc181b2012-07-04 10:43:33 +0000117 s->mcu_clk_freq / 1000000,
118 s->hsp_clk_freq / 1000000,
119 s->ipg_clk_freq);
120}
121
122static void imx_ccm_reset(DeviceState *dev)
123{
Andreas Färberbcb34c72013-07-26 21:50:54 +0200124 IMXCCMState *s = IMX_CCM(dev);
Peter Chubbbcc181b2012-07-04 10:43:33 +0000125
126 s->ccmr = 0x074b0b7b;
127 s->pdr0 = 0xff870b48;
128 s->pdr1 = 0x49fcfe7f;
129 s->mpctl = PLL_PD(1) | PLL_MFD(0) | PLL_MFI(6) | PLL_MFN(0);
130 s->cgr[0] = s->cgr[1] = s->cgr[2] = 0xffffffff;
131 s->spctl = PLL_PD(1) | PLL_MFD(4) | PLL_MFI(0xc) | PLL_MFN(1);
132 s->pmcr0 = 0x80209828;
133
134 update_clocks(s);
135}
136
Avi Kivitya8170e52012-10-23 12:30:10 +0200137static uint64_t imx_ccm_read(void *opaque, hwaddr offset,
Peter Chubbbcc181b2012-07-04 10:43:33 +0000138 unsigned size)
139{
140 IMXCCMState *s = (IMXCCMState *)opaque;
141
Jean-Christophe Dubois4a6aa0a2015-10-25 15:16:19 +0100142 DPRINTF("(offset=0x%" HWADDR_PRIx ")\n", offset);
143
Peter Chubbbcc181b2012-07-04 10:43:33 +0000144 switch (offset >> 2) {
145 case 0: /* CCMR */
146 DPRINTF(" ccmr = 0x%x\n", s->ccmr);
147 return s->ccmr;
148 case 1:
149 DPRINTF(" pdr0 = 0x%x\n", s->pdr0);
150 return s->pdr0;
151 case 2:
152 DPRINTF(" pdr1 = 0x%x\n", s->pdr1);
153 return s->pdr1;
154 case 4:
155 DPRINTF(" mpctl = 0x%x\n", s->mpctl);
156 return s->mpctl;
157 case 6:
158 DPRINTF(" spctl = 0x%x\n", s->spctl);
159 return s->spctl;
160 case 8:
161 DPRINTF(" cgr0 = 0x%x\n", s->cgr[0]);
162 return s->cgr[0];
163 case 9:
164 DPRINTF(" cgr1 = 0x%x\n", s->cgr[1]);
165 return s->cgr[1];
166 case 10:
167 DPRINTF(" cgr2 = 0x%x\n", s->cgr[2]);
168 return s->cgr[2];
169 case 18: /* LTR1 */
170 return 0x00004040;
171 case 23:
172 DPRINTF(" pcmr0 = 0x%x\n", s->pmcr0);
173 return s->pmcr0;
Jean-Christophe Dubois4a6aa0a2015-10-25 15:16:19 +0100174 default:
175 qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
176 HWADDR_PRIx "\n", TYPE_IMX_CCM, __func__, offset);
177 return 0;
Peter Chubbbcc181b2012-07-04 10:43:33 +0000178 }
Peter Chubbbcc181b2012-07-04 10:43:33 +0000179}
180
Avi Kivitya8170e52012-10-23 12:30:10 +0200181static void imx_ccm_write(void *opaque, hwaddr offset,
Peter Chubbbcc181b2012-07-04 10:43:33 +0000182 uint64_t value, unsigned size)
183{
184 IMXCCMState *s = (IMXCCMState *)opaque;
185
Jean-Christophe Dubois4a6aa0a2015-10-25 15:16:19 +0100186 DPRINTF("(offset=0x%" HWADDR_PRIx ", value = 0x%x)\n",
187 offset, (unsigned int)value);
188
Peter Chubbbcc181b2012-07-04 10:43:33 +0000189 switch (offset >> 2) {
190 case 0:
191 s->ccmr = CCMR_FPMF | (value & 0x3b6fdfff);
192 break;
193 case 1:
194 s->pdr0 = value & 0xff9f3fff;
195 break;
196 case 2:
197 s->pdr1 = value;
198 break;
199 case 4:
200 s->mpctl = value & 0xbfff3fff;
201 break;
202 case 6:
203 s->spctl = value & 0xbfff3fff;
204 break;
205 case 8:
206 s->cgr[0] = value;
207 return;
208 case 9:
209 s->cgr[1] = value;
210 return;
211 case 10:
212 s->cgr[2] = value;
213 return;
214
215 default:
Jean-Christophe Dubois4a6aa0a2015-10-25 15:16:19 +0100216 qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
217 HWADDR_PRIx "\n", TYPE_IMX_CCM, __func__, offset);
Peter Chubbbcc181b2012-07-04 10:43:33 +0000218 return;
219 }
220 update_clocks(s);
221}
222
223static const struct MemoryRegionOps imx_ccm_ops = {
224 .read = imx_ccm_read,
225 .write = imx_ccm_write,
226 .endianness = DEVICE_NATIVE_ENDIAN,
227};
228
229static int imx_ccm_init(SysBusDevice *dev)
230{
Andreas Färberbcb34c72013-07-26 21:50:54 +0200231 IMXCCMState *s = IMX_CCM(dev);
Peter Chubbbcc181b2012-07-04 10:43:33 +0000232
Paolo Bonzini3c161542013-06-06 21:25:08 -0400233 memory_region_init_io(&s->iomem, OBJECT(dev), &imx_ccm_ops, s,
Jean-Christophe Dubois282e74c2015-08-13 11:26:20 +0100234 TYPE_IMX_CCM, 0x1000);
Peter Chubbbcc181b2012-07-04 10:43:33 +0000235 sysbus_init_mmio(dev, &s->iomem);
236
237 return 0;
238}
239
240static int imx_ccm_post_load(void *opaque, int version_id)
241{
242 IMXCCMState *s = (IMXCCMState *)opaque;
243
244 update_clocks(s);
245 return 0;
246}
247
248static void imx_ccm_class_init(ObjectClass *klass, void *data)
249{
250 DeviceClass *dc = DEVICE_CLASS(klass);
251 SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
252
253 sbc->init = imx_ccm_init;
254 dc->reset = imx_ccm_reset;
255 dc->vmsd = &vmstate_imx_ccm;
256 dc->desc = "i.MX Clock Control Module";
257}
258
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100259static const TypeInfo imx_ccm_info = {
Andreas Färberbcb34c72013-07-26 21:50:54 +0200260 .name = TYPE_IMX_CCM,
Peter Chubbbcc181b2012-07-04 10:43:33 +0000261 .parent = TYPE_SYS_BUS_DEVICE,
262 .instance_size = sizeof(IMXCCMState),
263 .class_init = imx_ccm_class_init,
264};
265
266static void imx_ccm_register_types(void)
267{
268 type_register_static(&imx_ccm_info);
269}
270
271type_init(imx_ccm_register_types)