]> Git Repo - qemu.git/blame - hw/misc/imx31_ccm.c
i.MX: Split the CCM class into an abstract base class and a concrete class
[qemu.git] / hw / misc / imx31_ccm.c
CommitLineData
cb54d868
JCD
1/*
2 * IMX31 Clock Control Module
3 *
4 * Copyright (C) 2012 NICTA
5 * Updated by Jean-Christophe Dubois <[email protected]>
6 *
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 i.MX31 CCM.
12 */
13
14#include "hw/misc/imx31_ccm.h"
15
16#define CKIH_FREQ 26000000 /* 26MHz crystal input */
17
18#ifndef DEBUG_IMX31_CCM
19#define DEBUG_IMX31_CCM 0
20#endif
21
22#define DPRINTF(fmt, args...) \
23 do { \
24 if (DEBUG_IMX31_CCM) { \
25 fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX31_CCM, \
26 __func__, ##args); \
27 } \
28 } while (0)
29
30static char const *imx31_ccm_reg_name(uint32_t reg)
31{
32 switch (reg) {
33 case 0:
34 return "CCMR";
35 case 1:
36 return "PDR0";
37 case 2:
38 return "PDR1";
39 case 3:
40 return "RCSR";
41 case 4:
42 return "MPCTL";
43 case 5:
44 return "UPCTL";
45 case 6:
46 return "SPCTL";
47 case 7:
48 return "COSR";
49 case 8:
50 return "CGR0";
51 case 9:
52 return "CGR1";
53 case 10:
54 return "CGR2";
55 case 11:
56 return "WIMR";
57 case 12:
58 return "LDC";
59 case 13:
60 return "DCVR0";
61 case 14:
62 return "DCVR1";
63 case 15:
64 return "DCVR2";
65 case 16:
66 return "DCVR3";
67 case 17:
68 return "LTR0";
69 case 18:
70 return "LTR1";
71 case 19:
72 return "LTR2";
73 case 20:
74 return "LTR3";
75 case 21:
76 return "LTBR0";
77 case 22:
78 return "LTBR1";
79 case 23:
80 return "PMCR0";
81 case 24:
82 return "PMCR1";
83 case 25:
84 return "PDR2";
85 default:
86 return "???";
87 }
88}
89
90static const VMStateDescription vmstate_imx31_ccm = {
91 .name = TYPE_IMX31_CCM,
92 .version_id = 1,
93 .minimum_version_id = 1,
94 .fields = (VMStateField[]) {
95 VMSTATE_UINT32(ccmr, IMX31CCMState),
96 VMSTATE_UINT32(pdr0, IMX31CCMState),
97 VMSTATE_UINT32(pdr1, IMX31CCMState),
98 VMSTATE_UINT32(mpctl, IMX31CCMState),
99 VMSTATE_UINT32(spctl, IMX31CCMState),
100 VMSTATE_UINT32_ARRAY(cgr, IMX31CCMState, 3),
101 VMSTATE_UINT32(pmcr0, IMX31CCMState),
102 VMSTATE_UINT32(pmcr1, IMX31CCMState),
103 VMSTATE_END_OF_LIST()
104 },
105};
106
107static uint32_t imx31_ccm_get_pll_ref_clk(IMXCCMState *dev)
108{
109 uint32_t freq = 0;
110 IMX31CCMState *s = IMX31_CCM(dev);
111
112 if ((s->ccmr & CCMR_PRCS) == 2) {
113 if (s->ccmr & CCMR_FPME) {
114 freq = CKIL_FREQ;
115 if (s->ccmr & CCMR_FPMF) {
116 freq *= 1024;
117 }
118 }
119 } else {
120 freq = CKIH_FREQ;
121 }
122
123 DPRINTF("freq = %d\n", freq);
124
125 return freq;
126}
127
128static uint32_t imx31_ccm_get_mpll_clk(IMXCCMState *dev)
129{
130 uint32_t freq;
131 IMX31CCMState *s = IMX31_CCM(dev);
132
133 freq = imx_ccm_calc_pll(s->mpctl, imx31_ccm_get_pll_ref_clk(dev));
134
135 DPRINTF("freq = %d\n", freq);
136
137 return freq;
138}
139
140static uint32_t imx31_ccm_get_mcu_main_clk(IMXCCMState *dev)
141{
142 uint32_t freq;
143 IMX31CCMState *s = IMX31_CCM(dev);
144
145 if ((s->ccmr & CCMR_MDS) || !(s->ccmr & CCMR_MPE)) {
146 freq = imx31_ccm_get_pll_ref_clk(dev);
147 } else {
148 freq = imx31_ccm_get_mpll_clk(dev);
149 }
150
151 DPRINTF("freq = %d\n", freq);
152
153 return freq;
154}
155
156static uint32_t imx31_ccm_get_mcu_clk(IMXCCMState *dev)
157{
158 uint32_t freq;
159 IMX31CCMState *s = IMX31_CCM(dev);
160
161 freq = imx31_ccm_get_mcu_main_clk(dev) / (1 + EXTRACT(s->pdr0, MCU));
162
163 DPRINTF("freq = %d\n", freq);
164
165 return freq;
166}
167
168static uint32_t imx31_ccm_get_hsp_clk(IMXCCMState *dev)
169{
170 uint32_t freq;
171 IMX31CCMState *s = IMX31_CCM(dev);
172
173 freq = imx31_ccm_get_mcu_main_clk(dev) / (1 + EXTRACT(s->pdr0, HSP));
174
175 DPRINTF("freq = %d\n", freq);
176
177 return freq;
178}
179
180static uint32_t imx31_ccm_get_hclk_clk(IMXCCMState *dev)
181{
182 uint32_t freq;
183 IMX31CCMState *s = IMX31_CCM(dev);
184
185 freq = imx31_ccm_get_mcu_main_clk(dev) / (1 + EXTRACT(s->pdr0, MAX));
186
187 DPRINTF("freq = %d\n", freq);
188
189 return freq;
190}
191
192static uint32_t imx31_ccm_get_ipg_clk(IMXCCMState *dev)
193{
194 uint32_t freq;
195 IMX31CCMState *s = IMX31_CCM(dev);
196
197 freq = imx31_ccm_get_hclk_clk(dev) / (1 + EXTRACT(s->pdr0, IPG));
198
199 DPRINTF("freq = %d\n", freq);
200
201 return freq;
202}
203
204static uint32_t imx31_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
205{
206 uint32_t freq = 0;
207
208 switch (clock) {
209 case NOCLK:
210 break;
211 case CLK_MCU:
212 freq = imx31_ccm_get_mcu_clk(dev);
213 break;
214 case CLK_HSP:
215 freq = imx31_ccm_get_hsp_clk(dev);
216 break;
217 case CLK_IPG:
218 freq = imx31_ccm_get_ipg_clk(dev);
219 break;
220 case CLK_32k:
221 freq = CKIL_FREQ;
222 break;
223 default:
224 qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
225 TYPE_IMX31_CCM, __func__, clock);
226 break;
227 }
228
229 DPRINTF("Clock = %d) = %d\n", clock, freq);
230
231 return freq;
232}
233
234static void imx31_ccm_reset(DeviceState *dev)
235{
236 IMX31CCMState *s = IMX31_CCM(dev);
237
238 DPRINTF("()\n");
239
240 s->ccmr = 0x074b0b7d;
241 s->pdr0 = 0xff870b48;
242 s->pdr1 = 0x49fcfe7f;
243 s->mpctl = 0x04001800;
244 s->cgr[0] = s->cgr[1] = s->cgr[2] = 0xffffffff;
245 s->spctl = 0x04043001;
246 s->pmcr0 = 0x80209828;
247 s->pmcr1 = 0x00aa0000;
248}
249
250static uint64_t imx31_ccm_read(void *opaque, hwaddr offset, unsigned size)
251{
252 uint32 value = 0;
253 IMX31CCMState *s = (IMX31CCMState *)opaque;
254
255 switch (offset >> 2) {
256 case 0: /* CCMR */
257 value = s->ccmr;
258 break;
259 case 1:
260 value = s->pdr0;
261 break;
262 case 2:
263 value = s->pdr1;
264 break;
265 case 4:
266 value = s->mpctl;
267 break;
268 case 6:
269 value = s->spctl;
270 break;
271 case 8:
272 value = s->cgr[0];
273 break;
274 case 9:
275 value = s->cgr[1];
276 break;
277 case 10:
278 value = s->cgr[2];
279 break;
280 case 18: /* LTR1 */
281 value = 0x00004040;
282 break;
283 case 23:
284 value = s->pmcr0;
285 break;
286 default:
287 qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
288 HWADDR_PRIx "\n", TYPE_IMX31_CCM, __func__, offset);
289 break;
290 }
291
292 DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx31_ccm_reg_name(offset >> 2),
293 value);
294
295 return (uint64_t)value;
296}
297
298static void imx31_ccm_write(void *opaque, hwaddr offset, uint64_t value,
299 unsigned size)
300{
301 IMX31CCMState *s = (IMX31CCMState *)opaque;
302
303 DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx31_ccm_reg_name(offset >> 2),
304 (uint32_t)value);
305
306 switch (offset >> 2) {
307 case 0:
308 s->ccmr = CCMR_FPMF | (value & 0x3b6fdfff);
309 break;
310 case 1:
311 s->pdr0 = value & 0xff9f3fff;
312 break;
313 case 2:
314 s->pdr1 = value;
315 break;
316 case 4:
317 s->mpctl = value & 0xbfff3fff;
318 break;
319 case 6:
320 s->spctl = value & 0xbfff3fff;
321 break;
322 case 8:
323 s->cgr[0] = value;
324 break;
325 case 9:
326 s->cgr[1] = value;
327 break;
328 case 10:
329 s->cgr[2] = value;
330 break;
331 default:
332 qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
333 HWADDR_PRIx "\n", TYPE_IMX31_CCM, __func__, offset);
334 break;
335 }
336}
337
338static const struct MemoryRegionOps imx31_ccm_ops = {
339 .read = imx31_ccm_read,
340 .write = imx31_ccm_write,
341 .endianness = DEVICE_NATIVE_ENDIAN,
342 .valid = {
343 /*
344 * Our device would not work correctly if the guest was doing
345 * unaligned access. This might not be a limitation on the real
346 * device but in practice there is no reason for a guest to access
347 * this device unaligned.
348 */
349 .min_access_size = 4,
350 .max_access_size = 4,
351 .unaligned = false,
352 },
353
354};
355
356static void imx31_ccm_init(Object *obj)
357{
358 DeviceState *dev = DEVICE(obj);
359 SysBusDevice *sd = SYS_BUS_DEVICE(obj);
360 IMX31CCMState *s = IMX31_CCM(obj);
361
362 memory_region_init_io(&s->iomem, OBJECT(dev), &imx31_ccm_ops, s,
363 TYPE_IMX31_CCM, 0x1000);
364 sysbus_init_mmio(sd, &s->iomem);
365}
366
367static void imx31_ccm_class_init(ObjectClass *klass, void *data)
368{
369 DeviceClass *dc = DEVICE_CLASS(klass);
370 IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
371
372 dc->reset = imx31_ccm_reset;
373 dc->vmsd = &vmstate_imx31_ccm;
374 dc->desc = "i.MX31 Clock Control Module";
375
376 ccm->get_clock_frequency = imx31_ccm_get_clock_frequency;
377}
378
379static const TypeInfo imx31_ccm_info = {
380 .name = TYPE_IMX31_CCM,
381 .parent = TYPE_IMX_CCM,
382 .instance_size = sizeof(IMX31CCMState),
383 .instance_init = imx31_ccm_init,
384 .class_init = imx31_ccm_class_init,
385};
386
387static void imx31_ccm_register_types(void)
388{
389 type_register_static(&imx31_ccm_info);
390}
391
392type_init(imx31_ccm_register_types)
This page took 0.05876 seconds and 4 git commands to generate.