xref: /qemu/hw/misc/imx6ul_ccm.c (revision ab9056ff)
1 /*
2  * IMX6UL Clock Control Module
3  *
4  * Copyright (c) 2018 Jean-Christophe Dubois <jcd@tribudubois.net>
5  *
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.
8  *
9  * To get the timer frequencies right, we need to emulate at least part of
10  * the CCM.
11  */
12 
13 #include "qemu/osdep.h"
14 #include "hw/registerfields.h"
15 #include "migration/vmstate.h"
16 #include "hw/misc/imx6ul_ccm.h"
17 #include "qemu/log.h"
18 #include "qemu/module.h"
19 
20 #include "trace.h"
21 
22 static const char *imx6ul_ccm_reg_name(uint32_t reg)
23 {
24     static char unknown[20];
25 
26     switch (reg) {
27     case CCM_CCR:
28         return "CCR";
29     case CCM_CCDR:
30         return "CCDR";
31     case CCM_CSR:
32         return "CSR";
33     case CCM_CCSR:
34         return "CCSR";
35     case CCM_CACRR:
36         return "CACRR";
37     case CCM_CBCDR:
38         return "CBCDR";
39     case CCM_CBCMR:
40         return "CBCMR";
41     case CCM_CSCMR1:
42         return "CSCMR1";
43     case CCM_CSCMR2:
44         return "CSCMR2";
45     case CCM_CSCDR1:
46         return "CSCDR1";
47     case CCM_CS1CDR:
48         return "CS1CDR";
49     case CCM_CS2CDR:
50         return "CS2CDR";
51     case CCM_CDCDR:
52         return "CDCDR";
53     case CCM_CHSCCDR:
54         return "CHSCCDR";
55     case CCM_CSCDR2:
56         return "CSCDR2";
57     case CCM_CSCDR3:
58         return "CSCDR3";
59     case CCM_CDHIPR:
60         return "CDHIPR";
61     case CCM_CTOR:
62         return "CTOR";
63     case CCM_CLPCR:
64         return "CLPCR";
65     case CCM_CISR:
66         return "CISR";
67     case CCM_CIMR:
68         return "CIMR";
69     case CCM_CCOSR:
70         return "CCOSR";
71     case CCM_CGPR:
72         return "CGPR";
73     case CCM_CCGR0:
74         return "CCGR0";
75     case CCM_CCGR1:
76         return "CCGR1";
77     case CCM_CCGR2:
78         return "CCGR2";
79     case CCM_CCGR3:
80         return "CCGR3";
81     case CCM_CCGR4:
82         return "CCGR4";
83     case CCM_CCGR5:
84         return "CCGR5";
85     case CCM_CCGR6:
86         return "CCGR6";
87     case CCM_CMEOR:
88         return "CMEOR";
89     default:
90         sprintf(unknown, "%d ?", reg);
91         return unknown;
92     }
93 }
94 
95 static const char *imx6ul_analog_reg_name(uint32_t reg)
96 {
97     static char unknown[20];
98 
99     switch (reg) {
100     case CCM_ANALOG_PLL_ARM:
101         return "PLL_ARM";
102     case CCM_ANALOG_PLL_ARM_SET:
103         return "PLL_ARM_SET";
104     case CCM_ANALOG_PLL_ARM_CLR:
105         return "PLL_ARM_CLR";
106     case CCM_ANALOG_PLL_ARM_TOG:
107         return "PLL_ARM_TOG";
108     case CCM_ANALOG_PLL_USB1:
109         return "PLL_USB1";
110     case CCM_ANALOG_PLL_USB1_SET:
111         return "PLL_USB1_SET";
112     case CCM_ANALOG_PLL_USB1_CLR:
113         return "PLL_USB1_CLR";
114     case CCM_ANALOG_PLL_USB1_TOG:
115         return "PLL_USB1_TOG";
116     case CCM_ANALOG_PLL_USB2:
117         return "PLL_USB2";
118     case CCM_ANALOG_PLL_USB2_SET:
119         return "PLL_USB2_SET";
120     case CCM_ANALOG_PLL_USB2_CLR:
121         return "PLL_USB2_CLR";
122     case CCM_ANALOG_PLL_USB2_TOG:
123         return "PLL_USB2_TOG";
124     case CCM_ANALOG_PLL_SYS:
125         return "PLL_SYS";
126     case CCM_ANALOG_PLL_SYS_SET:
127         return "PLL_SYS_SET";
128     case CCM_ANALOG_PLL_SYS_CLR:
129         return "PLL_SYS_CLR";
130     case CCM_ANALOG_PLL_SYS_TOG:
131         return "PLL_SYS_TOG";
132     case CCM_ANALOG_PLL_SYS_SS:
133         return "PLL_SYS_SS";
134     case CCM_ANALOG_PLL_SYS_NUM:
135         return "PLL_SYS_NUM";
136     case CCM_ANALOG_PLL_SYS_DENOM:
137         return "PLL_SYS_DENOM";
138     case CCM_ANALOG_PLL_AUDIO:
139         return "PLL_AUDIO";
140     case CCM_ANALOG_PLL_AUDIO_SET:
141         return "PLL_AUDIO_SET";
142     case CCM_ANALOG_PLL_AUDIO_CLR:
143         return "PLL_AUDIO_CLR";
144     case CCM_ANALOG_PLL_AUDIO_TOG:
145         return "PLL_AUDIO_TOG";
146     case CCM_ANALOG_PLL_AUDIO_NUM:
147         return "PLL_AUDIO_NUM";
148     case CCM_ANALOG_PLL_AUDIO_DENOM:
149         return "PLL_AUDIO_DENOM";
150     case CCM_ANALOG_PLL_VIDEO:
151         return "PLL_VIDEO";
152     case CCM_ANALOG_PLL_VIDEO_SET:
153         return "PLL_VIDEO_SET";
154     case CCM_ANALOG_PLL_VIDEO_CLR:
155         return "PLL_VIDEO_CLR";
156     case CCM_ANALOG_PLL_VIDEO_TOG:
157         return "PLL_VIDEO_TOG";
158     case CCM_ANALOG_PLL_VIDEO_NUM:
159         return "PLL_VIDEO_NUM";
160     case CCM_ANALOG_PLL_VIDEO_DENOM:
161         return "PLL_VIDEO_DENOM";
162     case CCM_ANALOG_PLL_ENET:
163         return "PLL_ENET";
164     case CCM_ANALOG_PLL_ENET_SET:
165         return "PLL_ENET_SET";
166     case CCM_ANALOG_PLL_ENET_CLR:
167         return "PLL_ENET_CLR";
168     case CCM_ANALOG_PLL_ENET_TOG:
169         return "PLL_ENET_TOG";
170     case CCM_ANALOG_PFD_480:
171         return "PFD_480";
172     case CCM_ANALOG_PFD_480_SET:
173         return "PFD_480_SET";
174     case CCM_ANALOG_PFD_480_CLR:
175         return "PFD_480_CLR";
176     case CCM_ANALOG_PFD_480_TOG:
177         return "PFD_480_TOG";
178     case CCM_ANALOG_PFD_528:
179         return "PFD_528";
180     case CCM_ANALOG_PFD_528_SET:
181         return "PFD_528_SET";
182     case CCM_ANALOG_PFD_528_CLR:
183         return "PFD_528_CLR";
184     case CCM_ANALOG_PFD_528_TOG:
185         return "PFD_528_TOG";
186     case CCM_ANALOG_MISC0:
187         return "MISC0";
188     case CCM_ANALOG_MISC0_SET:
189         return "MISC0_SET";
190     case CCM_ANALOG_MISC0_CLR:
191         return "MISC0_CLR";
192     case CCM_ANALOG_MISC0_TOG:
193         return "MISC0_TOG";
194     case CCM_ANALOG_MISC2:
195         return "MISC2";
196     case CCM_ANALOG_MISC2_SET:
197         return "MISC2_SET";
198     case CCM_ANALOG_MISC2_CLR:
199         return "MISC2_CLR";
200     case CCM_ANALOG_MISC2_TOG:
201         return "MISC2_TOG";
202     case PMU_REG_1P1:
203         return "PMU_REG_1P1";
204     case PMU_REG_3P0:
205         return "PMU_REG_3P0";
206     case PMU_REG_2P5:
207         return "PMU_REG_2P5";
208     case PMU_REG_CORE:
209         return "PMU_REG_CORE";
210     case PMU_MISC1:
211         return "PMU_MISC1";
212     case PMU_MISC1_SET:
213         return "PMU_MISC1_SET";
214     case PMU_MISC1_CLR:
215         return "PMU_MISC1_CLR";
216     case PMU_MISC1_TOG:
217         return "PMU_MISC1_TOG";
218     case USB_ANALOG_DIGPROG:
219         return "USB_ANALOG_DIGPROG";
220     default:
221         sprintf(unknown, "%d ?", reg);
222         return unknown;
223     }
224 }
225 
226 #define CKIH_FREQ 24000000 /* 24MHz crystal input */
227 
228 static const VMStateDescription vmstate_imx6ul_ccm = {
229     .name = TYPE_IMX6UL_CCM,
230     .version_id = 1,
231     .minimum_version_id = 1,
232     .fields = (VMStateField[]) {
233         VMSTATE_UINT32_ARRAY(ccm, IMX6ULCCMState, CCM_MAX),
234         VMSTATE_UINT32_ARRAY(analog, IMX6ULCCMState, CCM_ANALOG_MAX),
235         VMSTATE_END_OF_LIST()
236     },
237 };
238 
239 static uint64_t imx6ul_analog_get_osc_clk(IMX6ULCCMState *dev)
240 {
241     uint64_t freq = CKIH_FREQ;
242 
243     trace_ccm_freq((uint32_t)freq);
244 
245     return freq;
246 }
247 
248 static uint64_t imx6ul_analog_get_pll2_clk(IMX6ULCCMState *dev)
249 {
250     uint64_t freq = imx6ul_analog_get_osc_clk(dev);
251 
252     if (FIELD_EX32(dev->analog[CCM_ANALOG_PLL_SYS],
253                    ANALOG_PLL_SYS, DIV_SELECT)) {
254         freq *= 22;
255     } else {
256         freq *= 20;
257     }
258 
259     trace_ccm_freq((uint32_t)freq);
260 
261     return freq;
262 }
263 
264 static uint64_t imx6ul_analog_get_pll3_clk(IMX6ULCCMState *dev)
265 {
266     uint64_t freq = imx6ul_analog_get_osc_clk(dev) * 20;
267 
268     trace_ccm_freq((uint32_t)freq);
269 
270     return freq;
271 }
272 
273 static uint64_t imx6ul_analog_get_pll2_pfd0_clk(IMX6ULCCMState *dev)
274 {
275     uint64_t freq = 0;
276 
277     freq = imx6ul_analog_get_pll2_clk(dev) * 18
278            / FIELD_EX32(dev->analog[CCM_ANALOG_PFD_528],
279                         ANALOG_PFD_528, PFD0_FRAC);
280 
281     trace_ccm_freq((uint32_t)freq);
282 
283     return freq;
284 }
285 
286 static uint64_t imx6ul_analog_get_pll2_pfd2_clk(IMX6ULCCMState *dev)
287 {
288     uint64_t freq = 0;
289 
290     freq = imx6ul_analog_get_pll2_clk(dev) * 18
291            / FIELD_EX32(dev->analog[CCM_ANALOG_PFD_528],
292                         ANALOG_PFD_528, PFD2_FRAC);
293 
294     trace_ccm_freq((uint32_t)freq);
295 
296     return freq;
297 }
298 
299 static uint64_t imx6ul_analog_pll2_bypass_clk(IMX6ULCCMState *dev)
300 {
301     uint64_t freq = 0;
302 
303     trace_ccm_freq((uint32_t)freq);
304 
305     return freq;
306 }
307 
308 static uint64_t imx6ul_ccm_get_periph_clk2_sel_clk(IMX6ULCCMState *dev)
309 {
310     uint64_t freq = 0;
311 
312     switch (FIELD_EX32(dev->ccm[CCM_CBCMR], CBCMR, PERIPH_CLK2_SEL)) {
313     case 0:
314         freq = imx6ul_analog_get_pll3_clk(dev);
315         break;
316     case 1:
317         freq = imx6ul_analog_get_osc_clk(dev);
318         break;
319     case 2:
320         freq = imx6ul_analog_pll2_bypass_clk(dev);
321         break;
322     case 3:
323         /* We should never get there as 3 is a reserved value */
324         qemu_log_mask(LOG_GUEST_ERROR,
325                       "[%s]%s: unsupported PERIPH_CLK2_SEL value 3\n",
326                       TYPE_IMX6UL_CCM, __func__);
327         /* freq is set to 0 as we don't know what it should be */
328         break;
329     default:
330         g_assert_not_reached();
331     }
332 
333     trace_ccm_freq((uint32_t)freq);
334 
335     return freq;
336 }
337 
338 static uint64_t imx6ul_ccm_get_periph_clk_sel_clk(IMX6ULCCMState *dev)
339 {
340     uint64_t freq = 0;
341 
342     switch (FIELD_EX32(dev->ccm[CCM_CBCMR], CBCMR, PRE_PERIPH_CLK_SEL)) {
343     case 0:
344         freq = imx6ul_analog_get_pll2_clk(dev);
345         break;
346     case 1:
347         freq = imx6ul_analog_get_pll2_pfd2_clk(dev);
348         break;
349     case 2:
350         freq = imx6ul_analog_get_pll2_pfd0_clk(dev);
351         break;
352     case 3:
353         freq = imx6ul_analog_get_pll2_pfd2_clk(dev) / 2;
354         break;
355     default:
356         g_assert_not_reached();
357     }
358 
359     trace_ccm_freq((uint32_t)freq);
360 
361     return freq;
362 }
363 
364 static uint64_t imx6ul_ccm_get_periph_clk2_clk(IMX6ULCCMState *dev)
365 {
366     uint64_t freq = 0;
367 
368     freq = imx6ul_ccm_get_periph_clk2_sel_clk(dev)
369            / (1 + FIELD_EX32(dev->ccm[CCM_CBCDR], CBCDR, PERIPH_CLK2_PODF));
370 
371     trace_ccm_freq((uint32_t)freq);
372 
373     return freq;
374 }
375 
376 static uint64_t imx6ul_ccm_get_periph_sel_clk(IMX6ULCCMState *dev)
377 {
378     uint64_t freq = 0;
379 
380     switch (FIELD_EX32(dev->ccm[CCM_CBCDR], CBCDR, PERIPH_CLK_SEL)) {
381     case 0:
382         freq = imx6ul_ccm_get_periph_clk_sel_clk(dev);
383         break;
384     case 1:
385         freq = imx6ul_ccm_get_periph_clk2_clk(dev);
386         break;
387     default:
388         g_assert_not_reached();
389     }
390 
391     trace_ccm_freq((uint32_t)freq);
392 
393     return freq;
394 }
395 
396 static uint64_t imx6ul_ccm_get_ahb_clk(IMX6ULCCMState *dev)
397 {
398     uint64_t freq = 0;
399 
400     freq = imx6ul_ccm_get_periph_sel_clk(dev)
401            / (1 + FIELD_EX32(dev->ccm[CCM_CBCDR], CBCDR, AHB_PODF));
402 
403     trace_ccm_freq((uint32_t)freq);
404 
405     return freq;
406 }
407 
408 static uint64_t imx6ul_ccm_get_ipg_clk(IMX6ULCCMState *dev)
409 {
410     uint64_t freq = 0;
411 
412     freq = imx6ul_ccm_get_ahb_clk(dev)
413            / (1 + FIELD_EX32(dev->ccm[CCM_CBCDR], CBCDR, IPG_PODF));
414 
415     trace_ccm_freq((uint32_t)freq);
416 
417     return freq;
418 }
419 
420 static uint64_t imx6ul_ccm_get_per_sel_clk(IMX6ULCCMState *dev)
421 {
422     uint64_t freq = 0;
423 
424     switch (FIELD_EX32(dev->ccm[CCM_CSCMR1], CSCMR1, PERCLK_CLK_SEL)) {
425     case 0:
426         freq = imx6ul_ccm_get_ipg_clk(dev);
427         break;
428     case 1:
429         freq = imx6ul_analog_get_osc_clk(dev);
430         break;
431     default:
432         g_assert_not_reached();
433     }
434 
435     trace_ccm_freq((uint32_t)freq);
436 
437     return freq;
438 }
439 
440 static uint64_t imx6ul_ccm_get_per_clk(IMX6ULCCMState *dev)
441 {
442     uint64_t freq = 0;
443 
444     freq = imx6ul_ccm_get_per_sel_clk(dev)
445            / (1 + FIELD_EX32(dev->ccm[CCM_CSCMR1], CSCMR1, PERCLK_PODF));
446 
447     trace_ccm_freq((uint32_t)freq);
448 
449     return freq;
450 }
451 
452 static uint32_t imx6ul_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
453 {
454     uint32_t freq = 0;
455     IMX6ULCCMState *s = IMX6UL_CCM(dev);
456 
457     switch (clock) {
458     case CLK_NONE:
459         break;
460     case CLK_IPG:
461         freq = imx6ul_ccm_get_ipg_clk(s);
462         break;
463     case CLK_IPG_HIGH:
464         freq = imx6ul_ccm_get_per_clk(s);
465         break;
466     case CLK_32k:
467         freq = CKIL_FREQ;
468         break;
469     case CLK_HIGH:
470         freq = CKIH_FREQ;
471         break;
472     case CLK_HIGH_DIV:
473         freq = CKIH_FREQ / 8;
474         break;
475     default:
476         qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
477                       TYPE_IMX6UL_CCM, __func__, clock);
478         break;
479     }
480 
481     trace_ccm_clock_freq(clock, freq);
482 
483     return freq;
484 }
485 
486 static void imx6ul_ccm_reset(DeviceState *dev)
487 {
488     IMX6ULCCMState *s = IMX6UL_CCM(dev);
489 
490     trace_ccm_entry();
491 
492     s->ccm[CCM_CCR] = 0x0401167F;
493     s->ccm[CCM_CCDR] = 0x00000000;
494     s->ccm[CCM_CSR] = 0x00000010;
495     s->ccm[CCM_CCSR] = 0x00000100;
496     s->ccm[CCM_CACRR] = 0x00000000;
497     s->ccm[CCM_CBCDR] = 0x00018D00;
498     s->ccm[CCM_CBCMR] = 0x24860324;
499     s->ccm[CCM_CSCMR1] = 0x04900080;
500     s->ccm[CCM_CSCMR2] = 0x03192F06;
501     s->ccm[CCM_CSCDR1] = 0x00490B00;
502     s->ccm[CCM_CS1CDR] = 0x0EC102C1;
503     s->ccm[CCM_CS2CDR] = 0x000336C1;
504     s->ccm[CCM_CDCDR] = 0x33F71F92;
505     s->ccm[CCM_CHSCCDR] = 0x000248A4;
506     s->ccm[CCM_CSCDR2] = 0x00029B48;
507     s->ccm[CCM_CSCDR3] = 0x00014841;
508     s->ccm[CCM_CDHIPR] = 0x00000000;
509     s->ccm[CCM_CTOR] = 0x00000000;
510     s->ccm[CCM_CLPCR] = 0x00000079;
511     s->ccm[CCM_CISR] = 0x00000000;
512     s->ccm[CCM_CIMR] = 0xFFFFFFFF;
513     s->ccm[CCM_CCOSR] = 0x000A0001;
514     s->ccm[CCM_CGPR] = 0x0000FE62;
515     s->ccm[CCM_CCGR0] = 0xFFFFFFFF;
516     s->ccm[CCM_CCGR1] = 0xFFFFFFFF;
517     s->ccm[CCM_CCGR2] = 0xFC3FFFFF;
518     s->ccm[CCM_CCGR3] = 0xFFFFFFFF;
519     s->ccm[CCM_CCGR4] = 0xFFFFFFFF;
520     s->ccm[CCM_CCGR5] = 0xFFFFFFFF;
521     s->ccm[CCM_CCGR6] = 0xFFFFFFFF;
522     s->ccm[CCM_CMEOR] = 0xFFFFFFFF;
523 
524     s->analog[CCM_ANALOG_PLL_ARM] = 0x00013063;
525     s->analog[CCM_ANALOG_PLL_USB1] = 0x00012000;
526     s->analog[CCM_ANALOG_PLL_USB2] = 0x00012000;
527     s->analog[CCM_ANALOG_PLL_SYS] = 0x00013001;
528     s->analog[CCM_ANALOG_PLL_SYS_SS] = 0x00000000;
529     s->analog[CCM_ANALOG_PLL_SYS_NUM] = 0x00000000;
530     s->analog[CCM_ANALOG_PLL_SYS_DENOM] = 0x00000012;
531     s->analog[CCM_ANALOG_PLL_AUDIO] = 0x00011006;
532     s->analog[CCM_ANALOG_PLL_AUDIO_NUM] = 0x05F5E100;
533     s->analog[CCM_ANALOG_PLL_AUDIO_DENOM] = 0x2964619C;
534     s->analog[CCM_ANALOG_PLL_VIDEO] = 0x0001100C;
535     s->analog[CCM_ANALOG_PLL_VIDEO_NUM] = 0x05F5E100;
536     s->analog[CCM_ANALOG_PLL_VIDEO_DENOM] = 0x10A24447;
537     s->analog[CCM_ANALOG_PLL_ENET] = 0x00011001;
538     s->analog[CCM_ANALOG_PFD_480] = 0x1311100C;
539     s->analog[CCM_ANALOG_PFD_528] = 0x1018101B;
540 
541     s->analog[PMU_REG_1P1] = 0x00001073;
542     s->analog[PMU_REG_3P0] = 0x00000F74;
543     s->analog[PMU_REG_2P5] = 0x00001073;
544     s->analog[PMU_REG_CORE] = 0x00482012;
545     s->analog[PMU_MISC0] = 0x04000000;
546     s->analog[PMU_MISC1] = 0x00000000;
547     s->analog[PMU_MISC2] = 0x00272727;
548     s->analog[PMU_LOWPWR_CTRL] = 0x00004009;
549 
550     s->analog[USB_ANALOG_USB1_VBUS_DETECT] = 0x01000004;
551     s->analog[USB_ANALOG_USB1_CHRG_DETECT] = 0x00000000;
552     s->analog[USB_ANALOG_USB1_VBUS_DETECT_STAT] = 0x00000000;
553     s->analog[USB_ANALOG_USB1_CHRG_DETECT_STAT] = 0x00000000;
554     s->analog[USB_ANALOG_USB1_MISC] = 0x00000002;
555     s->analog[USB_ANALOG_USB2_VBUS_DETECT] = 0x01000004;
556     s->analog[USB_ANALOG_USB2_CHRG_DETECT] = 0x00000000;
557     s->analog[USB_ANALOG_USB2_MISC] = 0x00000002;
558     s->analog[USB_ANALOG_DIGPROG] = 0x00640000;
559 
560     /* all PLLs need to be locked */
561     s->analog[CCM_ANALOG_PLL_ARM]   |= CCM_ANALOG_PLL_LOCK;
562     s->analog[CCM_ANALOG_PLL_USB1]  |= CCM_ANALOG_PLL_LOCK;
563     s->analog[CCM_ANALOG_PLL_USB2]  |= CCM_ANALOG_PLL_LOCK;
564     s->analog[CCM_ANALOG_PLL_SYS]   |= CCM_ANALOG_PLL_LOCK;
565     s->analog[CCM_ANALOG_PLL_AUDIO] |= CCM_ANALOG_PLL_LOCK;
566     s->analog[CCM_ANALOG_PLL_VIDEO] |= CCM_ANALOG_PLL_LOCK;
567     s->analog[CCM_ANALOG_PLL_ENET]  |= CCM_ANALOG_PLL_LOCK;
568 
569     s->analog[TEMPMON_TEMPSENSE0] = 0x00000001;
570     s->analog[TEMPMON_TEMPSENSE1] = 0x00000001;
571     s->analog[TEMPMON_TEMPSENSE2] = 0x00000000;
572 }
573 
574 static uint64_t imx6ul_ccm_read(void *opaque, hwaddr offset, unsigned size)
575 {
576     uint32_t value = 0;
577     uint32_t index = offset >> 2;
578     IMX6ULCCMState *s = (IMX6ULCCMState *)opaque;
579 
580     assert(index < CCM_MAX);
581 
582     value = s->ccm[index];
583 
584     trace_ccm_read_reg(imx6ul_ccm_reg_name(index), (uint32_t)value);
585 
586     return (uint64_t)value;
587 }
588 
589 static void imx6ul_ccm_write(void *opaque, hwaddr offset, uint64_t value,
590                            unsigned size)
591 {
592     uint32_t index = offset >> 2;
593     IMX6ULCCMState *s = (IMX6ULCCMState *)opaque;
594 
595     assert(index < CCM_MAX);
596 
597     trace_ccm_write_reg(imx6ul_ccm_reg_name(index), (uint32_t)value);
598 
599     /*
600      * We will do a better implementation later. In particular some bits
601      * cannot be written to.
602      */
603     s->ccm[index] = (uint32_t)value;
604 }
605 
606 static uint64_t imx6ul_analog_read(void *opaque, hwaddr offset, unsigned size)
607 {
608     uint32_t value;
609     uint32_t index = offset >> 2;
610     IMX6ULCCMState *s = (IMX6ULCCMState *)opaque;
611 
612     assert(index < CCM_ANALOG_MAX);
613 
614     switch (index) {
615     case CCM_ANALOG_PLL_ARM_SET:
616     case CCM_ANALOG_PLL_USB1_SET:
617     case CCM_ANALOG_PLL_USB2_SET:
618     case CCM_ANALOG_PLL_SYS_SET:
619     case CCM_ANALOG_PLL_AUDIO_SET:
620     case CCM_ANALOG_PLL_VIDEO_SET:
621     case CCM_ANALOG_PLL_ENET_SET:
622     case CCM_ANALOG_PFD_480_SET:
623     case CCM_ANALOG_PFD_528_SET:
624     case CCM_ANALOG_MISC0_SET:
625     case PMU_MISC1_SET:
626     case CCM_ANALOG_MISC2_SET:
627     case USB_ANALOG_USB1_VBUS_DETECT_SET:
628     case USB_ANALOG_USB1_CHRG_DETECT_SET:
629     case USB_ANALOG_USB1_MISC_SET:
630     case USB_ANALOG_USB2_VBUS_DETECT_SET:
631     case USB_ANALOG_USB2_CHRG_DETECT_SET:
632     case USB_ANALOG_USB2_MISC_SET:
633     case TEMPMON_TEMPSENSE0_SET:
634     case TEMPMON_TEMPSENSE1_SET:
635     case TEMPMON_TEMPSENSE2_SET:
636         /*
637          * All REG_NAME_SET register access are in fact targeting
638          * the REG_NAME register.
639          */
640         value = s->analog[index - 1];
641         break;
642     case CCM_ANALOG_PLL_ARM_CLR:
643     case CCM_ANALOG_PLL_USB1_CLR:
644     case CCM_ANALOG_PLL_USB2_CLR:
645     case CCM_ANALOG_PLL_SYS_CLR:
646     case CCM_ANALOG_PLL_AUDIO_CLR:
647     case CCM_ANALOG_PLL_VIDEO_CLR:
648     case CCM_ANALOG_PLL_ENET_CLR:
649     case CCM_ANALOG_PFD_480_CLR:
650     case CCM_ANALOG_PFD_528_CLR:
651     case CCM_ANALOG_MISC0_CLR:
652     case PMU_MISC1_CLR:
653     case CCM_ANALOG_MISC2_CLR:
654     case USB_ANALOG_USB1_VBUS_DETECT_CLR:
655     case USB_ANALOG_USB1_CHRG_DETECT_CLR:
656     case USB_ANALOG_USB1_MISC_CLR:
657     case USB_ANALOG_USB2_VBUS_DETECT_CLR:
658     case USB_ANALOG_USB2_CHRG_DETECT_CLR:
659     case USB_ANALOG_USB2_MISC_CLR:
660     case TEMPMON_TEMPSENSE0_CLR:
661     case TEMPMON_TEMPSENSE1_CLR:
662     case TEMPMON_TEMPSENSE2_CLR:
663         /*
664          * All REG_NAME_CLR register access are in fact targeting
665          * the REG_NAME register.
666          */
667         value = s->analog[index - 2];
668         break;
669     case CCM_ANALOG_PLL_ARM_TOG:
670     case CCM_ANALOG_PLL_USB1_TOG:
671     case CCM_ANALOG_PLL_USB2_TOG:
672     case CCM_ANALOG_PLL_SYS_TOG:
673     case CCM_ANALOG_PLL_AUDIO_TOG:
674     case CCM_ANALOG_PLL_VIDEO_TOG:
675     case CCM_ANALOG_PLL_ENET_TOG:
676     case CCM_ANALOG_PFD_480_TOG:
677     case CCM_ANALOG_PFD_528_TOG:
678     case CCM_ANALOG_MISC0_TOG:
679     case PMU_MISC1_TOG:
680     case CCM_ANALOG_MISC2_TOG:
681     case USB_ANALOG_USB1_VBUS_DETECT_TOG:
682     case USB_ANALOG_USB1_CHRG_DETECT_TOG:
683     case USB_ANALOG_USB1_MISC_TOG:
684     case USB_ANALOG_USB2_VBUS_DETECT_TOG:
685     case USB_ANALOG_USB2_CHRG_DETECT_TOG:
686     case USB_ANALOG_USB2_MISC_TOG:
687     case TEMPMON_TEMPSENSE0_TOG:
688     case TEMPMON_TEMPSENSE1_TOG:
689     case TEMPMON_TEMPSENSE2_TOG:
690         /*
691          * All REG_NAME_TOG register access are in fact targeting
692          * the REG_NAME register.
693          */
694         value = s->analog[index - 3];
695         break;
696     default:
697         value = s->analog[index];
698         break;
699     }
700 
701     trace_ccm_read_reg(imx6ul_analog_reg_name(index), (uint32_t)value);
702 
703     return (uint64_t)value;
704 }
705 
706 static void imx6ul_analog_write(void *opaque, hwaddr offset, uint64_t value,
707                               unsigned size)
708 {
709     uint32_t index = offset >> 2;
710     IMX6ULCCMState *s = (IMX6ULCCMState *)opaque;
711 
712     assert(index < CCM_ANALOG_MAX);
713 
714     trace_ccm_write_reg(imx6ul_analog_reg_name(index), (uint32_t)value);
715 
716     switch (index) {
717     case CCM_ANALOG_PLL_ARM_SET:
718     case CCM_ANALOG_PLL_USB1_SET:
719     case CCM_ANALOG_PLL_USB2_SET:
720     case CCM_ANALOG_PLL_SYS_SET:
721     case CCM_ANALOG_PLL_AUDIO_SET:
722     case CCM_ANALOG_PLL_VIDEO_SET:
723     case CCM_ANALOG_PLL_ENET_SET:
724     case CCM_ANALOG_PFD_480_SET:
725     case CCM_ANALOG_PFD_528_SET:
726     case CCM_ANALOG_MISC0_SET:
727     case PMU_MISC1_SET:
728     case CCM_ANALOG_MISC2_SET:
729     case USB_ANALOG_USB1_VBUS_DETECT_SET:
730     case USB_ANALOG_USB1_CHRG_DETECT_SET:
731     case USB_ANALOG_USB1_MISC_SET:
732     case USB_ANALOG_USB2_VBUS_DETECT_SET:
733     case USB_ANALOG_USB2_CHRG_DETECT_SET:
734     case USB_ANALOG_USB2_MISC_SET:
735         /*
736          * All REG_NAME_SET register access are in fact targeting
737          * the REG_NAME register. So we change the value of the
738          * REG_NAME register, setting bits passed in the value.
739          */
740         s->analog[index - 1] |= value;
741         break;
742     case CCM_ANALOG_PLL_ARM_CLR:
743     case CCM_ANALOG_PLL_USB1_CLR:
744     case CCM_ANALOG_PLL_USB2_CLR:
745     case CCM_ANALOG_PLL_SYS_CLR:
746     case CCM_ANALOG_PLL_AUDIO_CLR:
747     case CCM_ANALOG_PLL_VIDEO_CLR:
748     case CCM_ANALOG_PLL_ENET_CLR:
749     case CCM_ANALOG_PFD_480_CLR:
750     case CCM_ANALOG_PFD_528_CLR:
751     case CCM_ANALOG_MISC0_CLR:
752     case PMU_MISC1_CLR:
753     case CCM_ANALOG_MISC2_CLR:
754     case USB_ANALOG_USB1_VBUS_DETECT_CLR:
755     case USB_ANALOG_USB1_CHRG_DETECT_CLR:
756     case USB_ANALOG_USB1_MISC_CLR:
757     case USB_ANALOG_USB2_VBUS_DETECT_CLR:
758     case USB_ANALOG_USB2_CHRG_DETECT_CLR:
759     case USB_ANALOG_USB2_MISC_CLR:
760         /*
761          * All REG_NAME_CLR register access are in fact targeting
762          * the REG_NAME register. So we change the value of the
763          * REG_NAME register, unsetting bits passed in the value.
764          */
765         s->analog[index - 2] &= ~value;
766         break;
767     case CCM_ANALOG_PLL_ARM_TOG:
768     case CCM_ANALOG_PLL_USB1_TOG:
769     case CCM_ANALOG_PLL_USB2_TOG:
770     case CCM_ANALOG_PLL_SYS_TOG:
771     case CCM_ANALOG_PLL_AUDIO_TOG:
772     case CCM_ANALOG_PLL_VIDEO_TOG:
773     case CCM_ANALOG_PLL_ENET_TOG:
774     case CCM_ANALOG_PFD_480_TOG:
775     case CCM_ANALOG_PFD_528_TOG:
776     case CCM_ANALOG_MISC0_TOG:
777     case PMU_MISC1_TOG:
778     case CCM_ANALOG_MISC2_TOG:
779     case USB_ANALOG_USB1_VBUS_DETECT_TOG:
780     case USB_ANALOG_USB1_CHRG_DETECT_TOG:
781     case USB_ANALOG_USB1_MISC_TOG:
782     case USB_ANALOG_USB2_VBUS_DETECT_TOG:
783     case USB_ANALOG_USB2_CHRG_DETECT_TOG:
784     case USB_ANALOG_USB2_MISC_TOG:
785         /*
786          * All REG_NAME_TOG register access are in fact targeting
787          * the REG_NAME register. So we change the value of the
788          * REG_NAME register, toggling bits passed in the value.
789          */
790         s->analog[index - 3] ^= value;
791         break;
792     default:
793         /*
794          * We will do a better implementation later. In particular some bits
795          * cannot be written to.
796          */
797         s->analog[index] = value;
798         break;
799     }
800 }
801 
802 static const struct MemoryRegionOps imx6ul_ccm_ops = {
803     .read = imx6ul_ccm_read,
804     .write = imx6ul_ccm_write,
805     .endianness = DEVICE_NATIVE_ENDIAN,
806     .valid = {
807         /*
808          * Our device would not work correctly if the guest was doing
809          * unaligned access. This might not be a limitation on the real
810          * device but in practice there is no reason for a guest to access
811          * this device unaligned.
812          */
813         .min_access_size = 4,
814         .max_access_size = 4,
815         .unaligned = false,
816     },
817 };
818 
819 static const struct MemoryRegionOps imx6ul_analog_ops = {
820     .read = imx6ul_analog_read,
821     .write = imx6ul_analog_write,
822     .endianness = DEVICE_NATIVE_ENDIAN,
823     .valid = {
824         /*
825          * Our device would not work correctly if the guest was doing
826          * unaligned access. This might not be a limitation on the real
827          * device but in practice there is no reason for a guest to access
828          * this device unaligned.
829          */
830         .min_access_size = 4,
831         .max_access_size = 4,
832         .unaligned = false,
833     },
834 };
835 
836 static void imx6ul_ccm_init(Object *obj)
837 {
838     DeviceState *dev = DEVICE(obj);
839     SysBusDevice *sd = SYS_BUS_DEVICE(obj);
840     IMX6ULCCMState *s = IMX6UL_CCM(obj);
841 
842     /* initialize a container for the all memory range */
843     memory_region_init(&s->container, OBJECT(dev), TYPE_IMX6UL_CCM, 0x8000);
844 
845     /* We initialize an IO memory region for the CCM part */
846     memory_region_init_io(&s->ioccm, OBJECT(dev), &imx6ul_ccm_ops, s,
847                           TYPE_IMX6UL_CCM ".ccm", CCM_MAX * sizeof(uint32_t));
848 
849     /* Add the CCM as a subregion at offset 0 */
850     memory_region_add_subregion(&s->container, 0, &s->ioccm);
851 
852     /* We initialize an IO memory region for the ANALOG part */
853     memory_region_init_io(&s->ioanalog, OBJECT(dev), &imx6ul_analog_ops, s,
854                           TYPE_IMX6UL_CCM ".analog",
855                           CCM_ANALOG_MAX * sizeof(uint32_t));
856 
857     /* Add the ANALOG as a subregion at offset 0x4000 */
858     memory_region_add_subregion(&s->container, 0x4000, &s->ioanalog);
859 
860     sysbus_init_mmio(sd, &s->container);
861 }
862 
863 static void imx6ul_ccm_class_init(ObjectClass *klass, void *data)
864 {
865     DeviceClass *dc = DEVICE_CLASS(klass);
866     IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
867 
868     dc->reset = imx6ul_ccm_reset;
869     dc->vmsd = &vmstate_imx6ul_ccm;
870     dc->desc = "i.MX6UL Clock Control Module";
871 
872     ccm->get_clock_frequency = imx6ul_ccm_get_clock_frequency;
873 }
874 
875 static const TypeInfo imx6ul_ccm_info = {
876     .name          = TYPE_IMX6UL_CCM,
877     .parent        = TYPE_IMX_CCM,
878     .instance_size = sizeof(IMX6ULCCMState),
879     .instance_init = imx6ul_ccm_init,
880     .class_init    = imx6ul_ccm_class_init,
881 };
882 
883 static void imx6ul_ccm_register_types(void)
884 {
885     type_register_static(&imx6ul_ccm_info);
886 }
887 
888 type_init(imx6ul_ccm_register_types)
889