xref: /qemu/hw/misc/imx6_ccm.c (revision 56a11a9b7580b576a9db930667be07f1dd1564d5)
1a66d815cSJean-Christophe Dubois /*
2a66d815cSJean-Christophe Dubois  * IMX6 Clock Control Module
3a66d815cSJean-Christophe Dubois  *
4a66d815cSJean-Christophe Dubois  * Copyright (c) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
5a66d815cSJean-Christophe Dubois  *
6a66d815cSJean-Christophe Dubois  * This work is licensed under the terms of the GNU GPL, version 2 or later.
7a66d815cSJean-Christophe Dubois  * See the COPYING file in the top-level directory.
8a66d815cSJean-Christophe Dubois  *
9a66d815cSJean-Christophe Dubois  * To get the timer frequencies right, we need to emulate at least part of
10a66d815cSJean-Christophe Dubois  * the CCM.
11a66d815cSJean-Christophe Dubois  */
12a66d815cSJean-Christophe Dubois 
13a66d815cSJean-Christophe Dubois #include "qemu/osdep.h"
14a66d815cSJean-Christophe Dubois #include "hw/misc/imx6_ccm.h"
15d6454270SMarkus Armbruster #include "migration/vmstate.h"
1603dd024fSPaolo Bonzini #include "qemu/log.h"
170b8fa32fSMarkus Armbruster #include "qemu/module.h"
18a66d815cSJean-Christophe Dubois 
19a66d815cSJean-Christophe Dubois #ifndef DEBUG_IMX6_CCM
20a66d815cSJean-Christophe Dubois #define DEBUG_IMX6_CCM 0
21a66d815cSJean-Christophe Dubois #endif
22a66d815cSJean-Christophe Dubois 
23a66d815cSJean-Christophe Dubois #define DPRINTF(fmt, args...) \
24a66d815cSJean-Christophe Dubois     do { \
25a66d815cSJean-Christophe Dubois         if (DEBUG_IMX6_CCM) { \
26a66d815cSJean-Christophe Dubois             fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX6_CCM, \
27a66d815cSJean-Christophe Dubois                                              __func__, ##args); \
28a66d815cSJean-Christophe Dubois         } \
29a66d815cSJean-Christophe Dubois     } while (0)
30a66d815cSJean-Christophe Dubois 
31d675765aSPeter Maydell static const char *imx6_ccm_reg_name(uint32_t reg)
32a66d815cSJean-Christophe Dubois {
33a66d815cSJean-Christophe Dubois     static char unknown[20];
34a66d815cSJean-Christophe Dubois 
35a66d815cSJean-Christophe Dubois     switch (reg) {
36a66d815cSJean-Christophe Dubois     case CCM_CCR:
37a66d815cSJean-Christophe Dubois         return "CCR";
38a66d815cSJean-Christophe Dubois     case CCM_CCDR:
39a66d815cSJean-Christophe Dubois         return "CCDR";
40a66d815cSJean-Christophe Dubois     case CCM_CSR:
41a66d815cSJean-Christophe Dubois         return "CSR";
42a66d815cSJean-Christophe Dubois     case CCM_CCSR:
43a66d815cSJean-Christophe Dubois         return "CCSR";
44a66d815cSJean-Christophe Dubois     case CCM_CACRR:
45a66d815cSJean-Christophe Dubois         return "CACRR";
46a66d815cSJean-Christophe Dubois     case CCM_CBCDR:
47a66d815cSJean-Christophe Dubois         return "CBCDR";
48a66d815cSJean-Christophe Dubois     case CCM_CBCMR:
49a66d815cSJean-Christophe Dubois         return "CBCMR";
50a66d815cSJean-Christophe Dubois     case CCM_CSCMR1:
51a66d815cSJean-Christophe Dubois         return "CSCMR1";
52a66d815cSJean-Christophe Dubois     case CCM_CSCMR2:
53a66d815cSJean-Christophe Dubois         return "CSCMR2";
54a66d815cSJean-Christophe Dubois     case CCM_CSCDR1:
55a66d815cSJean-Christophe Dubois         return "CSCDR1";
56a66d815cSJean-Christophe Dubois     case CCM_CS1CDR:
57a66d815cSJean-Christophe Dubois         return "CS1CDR";
58a66d815cSJean-Christophe Dubois     case CCM_CS2CDR:
59a66d815cSJean-Christophe Dubois         return "CS2CDR";
60a66d815cSJean-Christophe Dubois     case CCM_CDCDR:
61a66d815cSJean-Christophe Dubois         return "CDCDR";
62a66d815cSJean-Christophe Dubois     case CCM_CHSCCDR:
63a66d815cSJean-Christophe Dubois         return "CHSCCDR";
64a66d815cSJean-Christophe Dubois     case CCM_CSCDR2:
65a66d815cSJean-Christophe Dubois         return "CSCDR2";
66a66d815cSJean-Christophe Dubois     case CCM_CSCDR3:
67a66d815cSJean-Christophe Dubois         return "CSCDR3";
68a66d815cSJean-Christophe Dubois     case CCM_CDHIPR:
69a66d815cSJean-Christophe Dubois         return "CDHIPR";
70a66d815cSJean-Christophe Dubois     case CCM_CTOR:
71a66d815cSJean-Christophe Dubois         return "CTOR";
72a66d815cSJean-Christophe Dubois     case CCM_CLPCR:
73a66d815cSJean-Christophe Dubois         return "CLPCR";
74a66d815cSJean-Christophe Dubois     case CCM_CISR:
75a66d815cSJean-Christophe Dubois         return "CISR";
76a66d815cSJean-Christophe Dubois     case CCM_CIMR:
77a66d815cSJean-Christophe Dubois         return "CIMR";
78a66d815cSJean-Christophe Dubois     case CCM_CCOSR:
79a66d815cSJean-Christophe Dubois         return "CCOSR";
80a66d815cSJean-Christophe Dubois     case CCM_CGPR:
81a66d815cSJean-Christophe Dubois         return "CGPR";
82a66d815cSJean-Christophe Dubois     case CCM_CCGR0:
83a66d815cSJean-Christophe Dubois         return "CCGR0";
84a66d815cSJean-Christophe Dubois     case CCM_CCGR1:
85a66d815cSJean-Christophe Dubois         return "CCGR1";
86a66d815cSJean-Christophe Dubois     case CCM_CCGR2:
87a66d815cSJean-Christophe Dubois         return "CCGR2";
88a66d815cSJean-Christophe Dubois     case CCM_CCGR3:
89a66d815cSJean-Christophe Dubois         return "CCGR3";
90a66d815cSJean-Christophe Dubois     case CCM_CCGR4:
91a66d815cSJean-Christophe Dubois         return "CCGR4";
92a66d815cSJean-Christophe Dubois     case CCM_CCGR5:
93a66d815cSJean-Christophe Dubois         return "CCGR5";
94a66d815cSJean-Christophe Dubois     case CCM_CCGR6:
95a66d815cSJean-Christophe Dubois         return "CCGR6";
96a66d815cSJean-Christophe Dubois     case CCM_CMEOR:
97a66d815cSJean-Christophe Dubois         return "CMEOR";
98a66d815cSJean-Christophe Dubois     default:
999197c7bdSAlex Chen         sprintf(unknown, "%u ?", reg);
100a66d815cSJean-Christophe Dubois         return unknown;
101a66d815cSJean-Christophe Dubois     }
102a66d815cSJean-Christophe Dubois }
103a66d815cSJean-Christophe Dubois 
104d675765aSPeter Maydell static const char *imx6_analog_reg_name(uint32_t reg)
105a66d815cSJean-Christophe Dubois {
106a66d815cSJean-Christophe Dubois     static char unknown[20];
107a66d815cSJean-Christophe Dubois 
108a66d815cSJean-Christophe Dubois     switch (reg) {
109a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ARM:
110a66d815cSJean-Christophe Dubois         return "PLL_ARM";
111a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ARM_SET:
112a66d815cSJean-Christophe Dubois         return "PLL_ARM_SET";
113a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ARM_CLR:
114a66d815cSJean-Christophe Dubois         return "PLL_ARM_CLR";
115a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ARM_TOG:
116a66d815cSJean-Christophe Dubois         return "PLL_ARM_TOG";
117a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB1:
118a66d815cSJean-Christophe Dubois         return "PLL_USB1";
119a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB1_SET:
120a66d815cSJean-Christophe Dubois         return "PLL_USB1_SET";
121a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB1_CLR:
122a66d815cSJean-Christophe Dubois         return "PLL_USB1_CLR";
123a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB1_TOG:
124a66d815cSJean-Christophe Dubois         return "PLL_USB1_TOG";
125a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB2:
126a66d815cSJean-Christophe Dubois         return "PLL_USB2";
127a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB2_SET:
128a66d815cSJean-Christophe Dubois         return "PLL_USB2_SET";
129a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB2_CLR:
130a66d815cSJean-Christophe Dubois         return "PLL_USB2_CLR";
131a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB2_TOG:
132a66d815cSJean-Christophe Dubois         return "PLL_USB2_TOG";
133a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_SYS:
134a66d815cSJean-Christophe Dubois         return "PLL_SYS";
135a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_SYS_SET:
136a66d815cSJean-Christophe Dubois         return "PLL_SYS_SET";
137a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_SYS_CLR:
138a66d815cSJean-Christophe Dubois         return "PLL_SYS_CLR";
139a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_SYS_TOG:
140a66d815cSJean-Christophe Dubois         return "PLL_SYS_TOG";
141a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_SYS_SS:
142a66d815cSJean-Christophe Dubois         return "PLL_SYS_SS";
143a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_SYS_NUM:
144a66d815cSJean-Christophe Dubois         return "PLL_SYS_NUM";
145a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_SYS_DENOM:
146a66d815cSJean-Christophe Dubois         return "PLL_SYS_DENOM";
147a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_AUDIO:
148a66d815cSJean-Christophe Dubois         return "PLL_AUDIO";
149a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_AUDIO_SET:
150a66d815cSJean-Christophe Dubois         return "PLL_AUDIO_SET";
151a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_AUDIO_CLR:
152a66d815cSJean-Christophe Dubois         return "PLL_AUDIO_CLR";
153a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_AUDIO_TOG:
154a66d815cSJean-Christophe Dubois         return "PLL_AUDIO_TOG";
155a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_AUDIO_NUM:
156a66d815cSJean-Christophe Dubois         return "PLL_AUDIO_NUM";
157a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_AUDIO_DENOM:
158a66d815cSJean-Christophe Dubois         return "PLL_AUDIO_DENOM";
159a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_VIDEO:
160a66d815cSJean-Christophe Dubois         return "PLL_VIDEO";
161a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_VIDEO_SET:
162a66d815cSJean-Christophe Dubois         return "PLL_VIDEO_SET";
163a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_VIDEO_CLR:
164a66d815cSJean-Christophe Dubois         return "PLL_VIDEO_CLR";
165a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_VIDEO_TOG:
166a66d815cSJean-Christophe Dubois         return "PLL_VIDEO_TOG";
167a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_VIDEO_NUM:
168a66d815cSJean-Christophe Dubois         return "PLL_VIDEO_NUM";
169a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_VIDEO_DENOM:
170a66d815cSJean-Christophe Dubois         return "PLL_VIDEO_DENOM";
171a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_MLB:
172a66d815cSJean-Christophe Dubois         return "PLL_MLB";
173a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_MLB_SET:
174a66d815cSJean-Christophe Dubois         return "PLL_MLB_SET";
175a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_MLB_CLR:
176a66d815cSJean-Christophe Dubois         return "PLL_MLB_CLR";
177a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_MLB_TOG:
178a66d815cSJean-Christophe Dubois         return "PLL_MLB_TOG";
179a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ENET:
180a66d815cSJean-Christophe Dubois         return "PLL_ENET";
181a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ENET_SET:
182a66d815cSJean-Christophe Dubois         return "PLL_ENET_SET";
183a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ENET_CLR:
184a66d815cSJean-Christophe Dubois         return "PLL_ENET_CLR";
185a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ENET_TOG:
186a66d815cSJean-Christophe Dubois         return "PLL_ENET_TOG";
187a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_480:
188a66d815cSJean-Christophe Dubois         return "PFD_480";
189a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_480_SET:
190a66d815cSJean-Christophe Dubois         return "PFD_480_SET";
191a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_480_CLR:
192a66d815cSJean-Christophe Dubois         return "PFD_480_CLR";
193a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_480_TOG:
194a66d815cSJean-Christophe Dubois         return "PFD_480_TOG";
195a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_528:
196a66d815cSJean-Christophe Dubois         return "PFD_528";
197a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_528_SET:
198a66d815cSJean-Christophe Dubois         return "PFD_528_SET";
199a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_528_CLR:
200a66d815cSJean-Christophe Dubois         return "PFD_528_CLR";
201a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_528_TOG:
202a66d815cSJean-Christophe Dubois         return "PFD_528_TOG";
203a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC0:
204a66d815cSJean-Christophe Dubois         return "MISC0";
205a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC0_SET:
206a66d815cSJean-Christophe Dubois         return "MISC0_SET";
207a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC0_CLR:
208a66d815cSJean-Christophe Dubois         return "MISC0_CLR";
209a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC0_TOG:
210a66d815cSJean-Christophe Dubois         return "MISC0_TOG";
211a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC2:
212a66d815cSJean-Christophe Dubois         return "MISC2";
213a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC2_SET:
214a66d815cSJean-Christophe Dubois         return "MISC2_SET";
215a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC2_CLR:
216a66d815cSJean-Christophe Dubois         return "MISC2_CLR";
217a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC2_TOG:
218a66d815cSJean-Christophe Dubois         return "MISC2_TOG";
219a66d815cSJean-Christophe Dubois     case PMU_REG_1P1:
220a66d815cSJean-Christophe Dubois         return "PMU_REG_1P1";
221a66d815cSJean-Christophe Dubois     case PMU_REG_3P0:
222a66d815cSJean-Christophe Dubois         return "PMU_REG_3P0";
223a66d815cSJean-Christophe Dubois     case PMU_REG_2P5:
224a66d815cSJean-Christophe Dubois         return "PMU_REG_2P5";
225a66d815cSJean-Christophe Dubois     case PMU_REG_CORE:
226a66d815cSJean-Christophe Dubois         return "PMU_REG_CORE";
227a66d815cSJean-Christophe Dubois     case PMU_MISC1:
228a66d815cSJean-Christophe Dubois         return "PMU_MISC1";
229a66d815cSJean-Christophe Dubois     case PMU_MISC1_SET:
230a66d815cSJean-Christophe Dubois         return "PMU_MISC1_SET";
231a66d815cSJean-Christophe Dubois     case PMU_MISC1_CLR:
232a66d815cSJean-Christophe Dubois         return "PMU_MISC1_CLR";
233a66d815cSJean-Christophe Dubois     case PMU_MISC1_TOG:
234a66d815cSJean-Christophe Dubois         return "PMU_MISC1_TOG";
235a66d815cSJean-Christophe Dubois     case USB_ANALOG_DIGPROG:
236a66d815cSJean-Christophe Dubois         return "USB_ANALOG_DIGPROG";
237a66d815cSJean-Christophe Dubois     default:
2389197c7bdSAlex Chen         sprintf(unknown, "%u ?", reg);
239a66d815cSJean-Christophe Dubois         return unknown;
240a66d815cSJean-Christophe Dubois     }
241a66d815cSJean-Christophe Dubois }
242a66d815cSJean-Christophe Dubois 
243a66d815cSJean-Christophe Dubois #define CKIH_FREQ 24000000 /* 24MHz crystal input */
244a66d815cSJean-Christophe Dubois 
245a66d815cSJean-Christophe Dubois static const VMStateDescription vmstate_imx6_ccm = {
246a66d815cSJean-Christophe Dubois     .name = TYPE_IMX6_CCM,
247a66d815cSJean-Christophe Dubois     .version_id = 1,
248a66d815cSJean-Christophe Dubois     .minimum_version_id = 1,
249a66d815cSJean-Christophe Dubois     .fields = (VMStateField[]) {
250a66d815cSJean-Christophe Dubois         VMSTATE_UINT32_ARRAY(ccm, IMX6CCMState, CCM_MAX),
251a66d815cSJean-Christophe Dubois         VMSTATE_UINT32_ARRAY(analog, IMX6CCMState, CCM_ANALOG_MAX),
252a66d815cSJean-Christophe Dubois         VMSTATE_END_OF_LIST()
253a66d815cSJean-Christophe Dubois     },
254a66d815cSJean-Christophe Dubois };
255a66d815cSJean-Christophe Dubois 
256a66d815cSJean-Christophe Dubois static uint64_t imx6_analog_get_pll2_clk(IMX6CCMState *dev)
257a66d815cSJean-Christophe Dubois {
258a66d815cSJean-Christophe Dubois     uint64_t freq = 24000000;
259a66d815cSJean-Christophe Dubois 
260a66d815cSJean-Christophe Dubois     if (EXTRACT(dev->analog[CCM_ANALOG_PLL_SYS], DIV_SELECT)) {
261a66d815cSJean-Christophe Dubois         freq *= 22;
262a66d815cSJean-Christophe Dubois     } else {
263a66d815cSJean-Christophe Dubois         freq *= 20;
264a66d815cSJean-Christophe Dubois     }
265a66d815cSJean-Christophe Dubois 
2669197c7bdSAlex Chen     DPRINTF("freq = %u\n", (uint32_t)freq);
267a66d815cSJean-Christophe Dubois 
268a66d815cSJean-Christophe Dubois     return freq;
269a66d815cSJean-Christophe Dubois }
270a66d815cSJean-Christophe Dubois 
271a66d815cSJean-Christophe Dubois static uint64_t imx6_analog_get_pll2_pfd0_clk(IMX6CCMState *dev)
272a66d815cSJean-Christophe Dubois {
273a66d815cSJean-Christophe Dubois     uint64_t freq = 0;
274a66d815cSJean-Christophe Dubois 
275a66d815cSJean-Christophe Dubois     freq = imx6_analog_get_pll2_clk(dev) * 18
276a66d815cSJean-Christophe Dubois            / EXTRACT(dev->analog[CCM_ANALOG_PFD_528], PFD0_FRAC);
277a66d815cSJean-Christophe Dubois 
2789197c7bdSAlex Chen     DPRINTF("freq = %u\n", (uint32_t)freq);
279a66d815cSJean-Christophe Dubois 
280a66d815cSJean-Christophe Dubois     return freq;
281a66d815cSJean-Christophe Dubois }
282a66d815cSJean-Christophe Dubois 
283a66d815cSJean-Christophe Dubois static uint64_t imx6_analog_get_pll2_pfd2_clk(IMX6CCMState *dev)
284a66d815cSJean-Christophe Dubois {
285a66d815cSJean-Christophe Dubois     uint64_t freq = 0;
286a66d815cSJean-Christophe Dubois 
287a66d815cSJean-Christophe Dubois     freq = imx6_analog_get_pll2_clk(dev) * 18
288a66d815cSJean-Christophe Dubois            / EXTRACT(dev->analog[CCM_ANALOG_PFD_528], PFD2_FRAC);
289a66d815cSJean-Christophe Dubois 
2909197c7bdSAlex Chen     DPRINTF("freq = %u\n", (uint32_t)freq);
291a66d815cSJean-Christophe Dubois 
292a66d815cSJean-Christophe Dubois     return freq;
293a66d815cSJean-Christophe Dubois }
294a66d815cSJean-Christophe Dubois 
295a66d815cSJean-Christophe Dubois static uint64_t imx6_analog_get_periph_clk(IMX6CCMState *dev)
296a66d815cSJean-Christophe Dubois {
297a66d815cSJean-Christophe Dubois     uint64_t freq = 0;
298a66d815cSJean-Christophe Dubois 
299a66d815cSJean-Christophe Dubois     switch (EXTRACT(dev->ccm[CCM_CBCMR], PRE_PERIPH_CLK_SEL)) {
300a66d815cSJean-Christophe Dubois     case 0:
301a66d815cSJean-Christophe Dubois         freq = imx6_analog_get_pll2_clk(dev);
302a66d815cSJean-Christophe Dubois         break;
303a66d815cSJean-Christophe Dubois     case 1:
304a66d815cSJean-Christophe Dubois         freq = imx6_analog_get_pll2_pfd2_clk(dev);
305a66d815cSJean-Christophe Dubois         break;
306a66d815cSJean-Christophe Dubois     case 2:
307a66d815cSJean-Christophe Dubois         freq = imx6_analog_get_pll2_pfd0_clk(dev);
308a66d815cSJean-Christophe Dubois         break;
309a66d815cSJean-Christophe Dubois     case 3:
310a66d815cSJean-Christophe Dubois         freq = imx6_analog_get_pll2_pfd2_clk(dev) / 2;
311a66d815cSJean-Christophe Dubois         break;
312a66d815cSJean-Christophe Dubois     default:
313a66d815cSJean-Christophe Dubois         /* We should never get there */
314a66d815cSJean-Christophe Dubois         g_assert_not_reached();
315a66d815cSJean-Christophe Dubois         break;
316a66d815cSJean-Christophe Dubois     }
317a66d815cSJean-Christophe Dubois 
3189197c7bdSAlex Chen     DPRINTF("freq = %u\n", (uint32_t)freq);
319a66d815cSJean-Christophe Dubois 
320a66d815cSJean-Christophe Dubois     return freq;
321a66d815cSJean-Christophe Dubois }
322a66d815cSJean-Christophe Dubois 
323a66d815cSJean-Christophe Dubois static uint64_t imx6_ccm_get_ahb_clk(IMX6CCMState *dev)
324a66d815cSJean-Christophe Dubois {
325a66d815cSJean-Christophe Dubois     uint64_t freq = 0;
326a66d815cSJean-Christophe Dubois 
327a66d815cSJean-Christophe Dubois     freq = imx6_analog_get_periph_clk(dev)
328a66d815cSJean-Christophe Dubois            / (1 + EXTRACT(dev->ccm[CCM_CBCDR], AHB_PODF));
329a66d815cSJean-Christophe Dubois 
3309197c7bdSAlex Chen     DPRINTF("freq = %u\n", (uint32_t)freq);
331a66d815cSJean-Christophe Dubois 
332a66d815cSJean-Christophe Dubois     return freq;
333a66d815cSJean-Christophe Dubois }
334a66d815cSJean-Christophe Dubois 
335a66d815cSJean-Christophe Dubois static uint64_t imx6_ccm_get_ipg_clk(IMX6CCMState *dev)
336a66d815cSJean-Christophe Dubois {
337a66d815cSJean-Christophe Dubois     uint64_t freq = 0;
338a66d815cSJean-Christophe Dubois 
339a66d815cSJean-Christophe Dubois     freq = imx6_ccm_get_ahb_clk(dev)
3403c254ab8SLadi Prosek            / (1 + EXTRACT(dev->ccm[CCM_CBCDR], IPG_PODF));
341a66d815cSJean-Christophe Dubois 
3429197c7bdSAlex Chen     DPRINTF("freq = %u\n", (uint32_t)freq);
343a66d815cSJean-Christophe Dubois 
344a66d815cSJean-Christophe Dubois     return freq;
345a66d815cSJean-Christophe Dubois }
346a66d815cSJean-Christophe Dubois 
347a66d815cSJean-Christophe Dubois static uint64_t imx6_ccm_get_per_clk(IMX6CCMState *dev)
348a66d815cSJean-Christophe Dubois {
349a66d815cSJean-Christophe Dubois     uint64_t freq = 0;
350a66d815cSJean-Christophe Dubois 
351a66d815cSJean-Christophe Dubois     freq = imx6_ccm_get_ipg_clk(dev)
352a66d815cSJean-Christophe Dubois            / (1 + EXTRACT(dev->ccm[CCM_CSCMR1], PERCLK_PODF));
353a66d815cSJean-Christophe Dubois 
3549197c7bdSAlex Chen     DPRINTF("freq = %u\n", (uint32_t)freq);
355a66d815cSJean-Christophe Dubois 
356a66d815cSJean-Christophe Dubois     return freq;
357a66d815cSJean-Christophe Dubois }
358a66d815cSJean-Christophe Dubois 
359a66d815cSJean-Christophe Dubois static uint32_t imx6_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
360a66d815cSJean-Christophe Dubois {
361a66d815cSJean-Christophe Dubois     uint32_t freq = 0;
362a66d815cSJean-Christophe Dubois     IMX6CCMState *s = IMX6_CCM(dev);
363a66d815cSJean-Christophe Dubois 
364a66d815cSJean-Christophe Dubois     switch (clock) {
365a66d815cSJean-Christophe Dubois     case CLK_NONE:
366a66d815cSJean-Christophe Dubois         break;
367a66d815cSJean-Christophe Dubois     case CLK_IPG:
368a66d815cSJean-Christophe Dubois         freq = imx6_ccm_get_ipg_clk(s);
369a66d815cSJean-Christophe Dubois         break;
370a66d815cSJean-Christophe Dubois     case CLK_IPG_HIGH:
371a66d815cSJean-Christophe Dubois         freq = imx6_ccm_get_per_clk(s);
372a66d815cSJean-Christophe Dubois         break;
373a66d815cSJean-Christophe Dubois     case CLK_32k:
374a66d815cSJean-Christophe Dubois         freq = CKIL_FREQ;
375a66d815cSJean-Christophe Dubois         break;
37666542f63SJean-Christophe Dubois     case CLK_HIGH:
37766542f63SJean-Christophe Dubois         freq = 24000000;
37866542f63SJean-Christophe Dubois         break;
37966542f63SJean-Christophe Dubois     case CLK_HIGH_DIV:
38066542f63SJean-Christophe Dubois         freq = 24000000 / 8;
38166542f63SJean-Christophe Dubois         break;
382a66d815cSJean-Christophe Dubois     default:
383a66d815cSJean-Christophe Dubois         qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
384a66d815cSJean-Christophe Dubois                       TYPE_IMX6_CCM, __func__, clock);
385a66d815cSJean-Christophe Dubois         break;
386a66d815cSJean-Christophe Dubois     }
387a66d815cSJean-Christophe Dubois 
3889197c7bdSAlex Chen     DPRINTF("Clock = %d) = %u\n", clock, freq);
389a66d815cSJean-Christophe Dubois 
390a66d815cSJean-Christophe Dubois     return freq;
391a66d815cSJean-Christophe Dubois }
392a66d815cSJean-Christophe Dubois 
393a66d815cSJean-Christophe Dubois static void imx6_ccm_reset(DeviceState *dev)
394a66d815cSJean-Christophe Dubois {
395a66d815cSJean-Christophe Dubois     IMX6CCMState *s = IMX6_CCM(dev);
396a66d815cSJean-Christophe Dubois 
397a66d815cSJean-Christophe Dubois     DPRINTF("\n");
398a66d815cSJean-Christophe Dubois 
399a66d815cSJean-Christophe Dubois     s->ccm[CCM_CCR] = 0x040116FF;
400a66d815cSJean-Christophe Dubois     s->ccm[CCM_CCDR] = 0x00000000;
401a66d815cSJean-Christophe Dubois     s->ccm[CCM_CSR] = 0x00000010;
402a66d815cSJean-Christophe Dubois     s->ccm[CCM_CCSR] = 0x00000100;
403a66d815cSJean-Christophe Dubois     s->ccm[CCM_CACRR] = 0x00000000;
404a66d815cSJean-Christophe Dubois     s->ccm[CCM_CBCDR] = 0x00018D40;
405a66d815cSJean-Christophe Dubois     s->ccm[CCM_CBCMR] = 0x00022324;
406a66d815cSJean-Christophe Dubois     s->ccm[CCM_CSCMR1] = 0x00F00000;
407a66d815cSJean-Christophe Dubois     s->ccm[CCM_CSCMR2] = 0x02B92F06;
408a66d815cSJean-Christophe Dubois     s->ccm[CCM_CSCDR1] = 0x00490B00;
409a66d815cSJean-Christophe Dubois     s->ccm[CCM_CS1CDR] = 0x0EC102C1;
410a66d815cSJean-Christophe Dubois     s->ccm[CCM_CS2CDR] = 0x000736C1;
411a66d815cSJean-Christophe Dubois     s->ccm[CCM_CDCDR] = 0x33F71F92;
412a66d815cSJean-Christophe Dubois     s->ccm[CCM_CHSCCDR] = 0x0002A150;
413a66d815cSJean-Christophe Dubois     s->ccm[CCM_CSCDR2] = 0x0002A150;
414a66d815cSJean-Christophe Dubois     s->ccm[CCM_CSCDR3] = 0x00014841;
415a66d815cSJean-Christophe Dubois     s->ccm[CCM_CDHIPR] = 0x00000000;
416a66d815cSJean-Christophe Dubois     s->ccm[CCM_CTOR] = 0x00000000;
417a66d815cSJean-Christophe Dubois     s->ccm[CCM_CLPCR] = 0x00000079;
418a66d815cSJean-Christophe Dubois     s->ccm[CCM_CISR] = 0x00000000;
419a66d815cSJean-Christophe Dubois     s->ccm[CCM_CIMR] = 0xFFFFFFFF;
420a66d815cSJean-Christophe Dubois     s->ccm[CCM_CCOSR] = 0x000A0001;
421a66d815cSJean-Christophe Dubois     s->ccm[CCM_CGPR] = 0x0000FE62;
422a66d815cSJean-Christophe Dubois     s->ccm[CCM_CCGR0] = 0xFFFFFFFF;
423a66d815cSJean-Christophe Dubois     s->ccm[CCM_CCGR1] = 0xFFFFFFFF;
424a66d815cSJean-Christophe Dubois     s->ccm[CCM_CCGR2] = 0xFC3FFFFF;
425a66d815cSJean-Christophe Dubois     s->ccm[CCM_CCGR3] = 0xFFFFFFFF;
426a66d815cSJean-Christophe Dubois     s->ccm[CCM_CCGR4] = 0xFFFFFFFF;
427a66d815cSJean-Christophe Dubois     s->ccm[CCM_CCGR5] = 0xFFFFFFFF;
428a66d815cSJean-Christophe Dubois     s->ccm[CCM_CCGR6] = 0xFFFFFFFF;
429a66d815cSJean-Christophe Dubois     s->ccm[CCM_CMEOR] = 0xFFFFFFFF;
430a66d815cSJean-Christophe Dubois 
431a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_ARM] = 0x00013042;
432a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_USB1] = 0x00012000;
433a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_USB2] = 0x00012000;
434a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_SYS] = 0x00013001;
435a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_SYS_SS] = 0x00000000;
436a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_SYS_NUM] = 0x00000000;
437a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_SYS_DENOM] = 0x00000012;
438a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_AUDIO] = 0x00011006;
439a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_AUDIO_NUM] = 0x05F5E100;
440a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_AUDIO_DENOM] = 0x2964619C;
441a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_VIDEO] = 0x0001100C;
442a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_VIDEO_NUM] = 0x05F5E100;
443a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_VIDEO_DENOM] = 0x10A24447;
444a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_MLB] = 0x00010000;
445a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_ENET] = 0x00011001;
446a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PFD_480] = 0x1311100C;
447a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PFD_528] = 0x1018101B;
448a66d815cSJean-Christophe Dubois 
449a66d815cSJean-Christophe Dubois     s->analog[PMU_REG_1P1] = 0x00001073;
450a66d815cSJean-Christophe Dubois     s->analog[PMU_REG_3P0] = 0x00000F74;
451a66d815cSJean-Christophe Dubois     s->analog[PMU_REG_2P5] = 0x00005071;
452a66d815cSJean-Christophe Dubois     s->analog[PMU_REG_CORE] = 0x00402010;
453*56a11a9bSBin Meng     s->analog[PMU_MISC0] = 0x04000080;
454a66d815cSJean-Christophe Dubois     s->analog[PMU_MISC1] = 0x00000000;
455a66d815cSJean-Christophe Dubois     s->analog[PMU_MISC2] = 0x00272727;
456a66d815cSJean-Christophe Dubois 
457a66d815cSJean-Christophe Dubois     s->analog[USB_ANALOG_USB1_VBUS_DETECT] = 0x00000004;
458a66d815cSJean-Christophe Dubois     s->analog[USB_ANALOG_USB1_CHRG_DETECT] = 0x00000000;
459a66d815cSJean-Christophe Dubois     s->analog[USB_ANALOG_USB1_VBUS_DETECT_STAT] = 0x00000000;
460a66d815cSJean-Christophe Dubois     s->analog[USB_ANALOG_USB1_CHRG_DETECT_STAT] = 0x00000000;
461a66d815cSJean-Christophe Dubois     s->analog[USB_ANALOG_USB1_MISC] = 0x00000002;
462a66d815cSJean-Christophe Dubois     s->analog[USB_ANALOG_USB2_VBUS_DETECT] = 0x00000004;
463a66d815cSJean-Christophe Dubois     s->analog[USB_ANALOG_USB2_CHRG_DETECT] = 0x00000000;
464a66d815cSJean-Christophe Dubois     s->analog[USB_ANALOG_USB2_MISC] = 0x00000002;
465a66d815cSJean-Christophe Dubois     s->analog[USB_ANALOG_DIGPROG] = 0x00000000;
466a66d815cSJean-Christophe Dubois 
467a66d815cSJean-Christophe Dubois     /* all PLLs need to be locked */
468a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_ARM]   |= CCM_ANALOG_PLL_LOCK;
469a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_USB1]  |= CCM_ANALOG_PLL_LOCK;
470a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_USB2]  |= CCM_ANALOG_PLL_LOCK;
471a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_SYS]   |= CCM_ANALOG_PLL_LOCK;
472a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_AUDIO] |= CCM_ANALOG_PLL_LOCK;
473a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_VIDEO] |= CCM_ANALOG_PLL_LOCK;
474a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_MLB]   |= CCM_ANALOG_PLL_LOCK;
475a66d815cSJean-Christophe Dubois     s->analog[CCM_ANALOG_PLL_ENET]  |= CCM_ANALOG_PLL_LOCK;
476a66d815cSJean-Christophe Dubois }
477a66d815cSJean-Christophe Dubois 
478a66d815cSJean-Christophe Dubois static uint64_t imx6_ccm_read(void *opaque, hwaddr offset, unsigned size)
479a66d815cSJean-Christophe Dubois {
480a66d815cSJean-Christophe Dubois     uint32_t value = 0;
481a66d815cSJean-Christophe Dubois     uint32_t index = offset >> 2;
482a66d815cSJean-Christophe Dubois     IMX6CCMState *s = (IMX6CCMState *)opaque;
483a66d815cSJean-Christophe Dubois 
484a66d815cSJean-Christophe Dubois     value = s->ccm[index];
485a66d815cSJean-Christophe Dubois 
486a66d815cSJean-Christophe Dubois     DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx6_ccm_reg_name(index), value);
487a66d815cSJean-Christophe Dubois 
488a66d815cSJean-Christophe Dubois     return (uint64_t)value;
489a66d815cSJean-Christophe Dubois }
490a66d815cSJean-Christophe Dubois 
491a66d815cSJean-Christophe Dubois static void imx6_ccm_write(void *opaque, hwaddr offset, uint64_t value,
492a66d815cSJean-Christophe Dubois                            unsigned size)
493a66d815cSJean-Christophe Dubois {
494a66d815cSJean-Christophe Dubois     uint32_t index = offset >> 2;
495a66d815cSJean-Christophe Dubois     IMX6CCMState *s = (IMX6CCMState *)opaque;
496a66d815cSJean-Christophe Dubois 
497a66d815cSJean-Christophe Dubois     DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx6_ccm_reg_name(index),
498a66d815cSJean-Christophe Dubois             (uint32_t)value);
499a66d815cSJean-Christophe Dubois 
500a66d815cSJean-Christophe Dubois     /*
501a66d815cSJean-Christophe Dubois      * We will do a better implementation later. In particular some bits
502a66d815cSJean-Christophe Dubois      * cannot be written to.
503a66d815cSJean-Christophe Dubois      */
504a66d815cSJean-Christophe Dubois     s->ccm[index] = (uint32_t)value;
505a66d815cSJean-Christophe Dubois }
506a66d815cSJean-Christophe Dubois 
507a66d815cSJean-Christophe Dubois static uint64_t imx6_analog_read(void *opaque, hwaddr offset, unsigned size)
508a66d815cSJean-Christophe Dubois {
509a66d815cSJean-Christophe Dubois     uint32_t value;
510a66d815cSJean-Christophe Dubois     uint32_t index = offset >> 2;
511a66d815cSJean-Christophe Dubois     IMX6CCMState *s = (IMX6CCMState *)opaque;
512a66d815cSJean-Christophe Dubois 
513a66d815cSJean-Christophe Dubois     switch (index) {
514a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ARM_SET:
515a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB1_SET:
516a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB2_SET:
517a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_SYS_SET:
518a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_AUDIO_SET:
519a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_VIDEO_SET:
520a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_MLB_SET:
521a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ENET_SET:
522a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_480_SET:
523a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_528_SET:
524a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC0_SET:
525a66d815cSJean-Christophe Dubois     case PMU_MISC1_SET:
526a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC2_SET:
527a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB1_VBUS_DETECT_SET:
528a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB1_CHRG_DETECT_SET:
529a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB1_MISC_SET:
530a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB2_VBUS_DETECT_SET:
531a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB2_CHRG_DETECT_SET:
532a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB2_MISC_SET:
533a66d815cSJean-Christophe Dubois         /*
534a66d815cSJean-Christophe Dubois          * All REG_NAME_SET register access are in fact targeting the
535a66d815cSJean-Christophe Dubois          * the REG_NAME register.
536a66d815cSJean-Christophe Dubois          */
537a66d815cSJean-Christophe Dubois         value = s->analog[index - 1];
538a66d815cSJean-Christophe Dubois         break;
539a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ARM_CLR:
540a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB1_CLR:
541a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB2_CLR:
542a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_SYS_CLR:
543a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_AUDIO_CLR:
544a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_VIDEO_CLR:
545a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_MLB_CLR:
546a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ENET_CLR:
547a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_480_CLR:
548a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_528_CLR:
549a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC0_CLR:
550a66d815cSJean-Christophe Dubois     case PMU_MISC1_CLR:
551a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC2_CLR:
552a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB1_VBUS_DETECT_CLR:
553a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB1_CHRG_DETECT_CLR:
554a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB1_MISC_CLR:
555a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB2_VBUS_DETECT_CLR:
556a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB2_CHRG_DETECT_CLR:
557a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB2_MISC_CLR:
558a66d815cSJean-Christophe Dubois         /*
559a66d815cSJean-Christophe Dubois          * All REG_NAME_CLR register access are in fact targeting the
560a66d815cSJean-Christophe Dubois          * the REG_NAME register.
561a66d815cSJean-Christophe Dubois          */
562a66d815cSJean-Christophe Dubois         value = s->analog[index - 2];
563a66d815cSJean-Christophe Dubois         break;
564a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ARM_TOG:
565a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB1_TOG:
566a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB2_TOG:
567a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_SYS_TOG:
568a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_AUDIO_TOG:
569a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_VIDEO_TOG:
570a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_MLB_TOG:
571a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ENET_TOG:
572a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_480_TOG:
573a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_528_TOG:
574a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC0_TOG:
575a66d815cSJean-Christophe Dubois     case PMU_MISC1_TOG:
576a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC2_TOG:
577a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB1_VBUS_DETECT_TOG:
578a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB1_CHRG_DETECT_TOG:
579a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB1_MISC_TOG:
580a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB2_VBUS_DETECT_TOG:
581a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB2_CHRG_DETECT_TOG:
582a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB2_MISC_TOG:
583a66d815cSJean-Christophe Dubois         /*
584a66d815cSJean-Christophe Dubois          * All REG_NAME_TOG register access are in fact targeting the
585a66d815cSJean-Christophe Dubois          * the REG_NAME register.
586a66d815cSJean-Christophe Dubois          */
587a66d815cSJean-Christophe Dubois         value = s->analog[index - 3];
588a66d815cSJean-Christophe Dubois         break;
589a66d815cSJean-Christophe Dubois     default:
590a66d815cSJean-Christophe Dubois         value = s->analog[index];
591a66d815cSJean-Christophe Dubois         break;
592a66d815cSJean-Christophe Dubois     }
593a66d815cSJean-Christophe Dubois 
594a66d815cSJean-Christophe Dubois     DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx6_analog_reg_name(index), value);
595a66d815cSJean-Christophe Dubois 
596a66d815cSJean-Christophe Dubois     return (uint64_t)value;
597a66d815cSJean-Christophe Dubois }
598a66d815cSJean-Christophe Dubois 
599a66d815cSJean-Christophe Dubois static void imx6_analog_write(void *opaque, hwaddr offset, uint64_t value,
600a66d815cSJean-Christophe Dubois                               unsigned size)
601a66d815cSJean-Christophe Dubois {
602a66d815cSJean-Christophe Dubois     uint32_t index = offset >> 2;
603a66d815cSJean-Christophe Dubois     IMX6CCMState *s = (IMX6CCMState *)opaque;
604a66d815cSJean-Christophe Dubois 
605a66d815cSJean-Christophe Dubois     DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx6_analog_reg_name(index),
606a66d815cSJean-Christophe Dubois             (uint32_t)value);
607a66d815cSJean-Christophe Dubois 
608a66d815cSJean-Christophe Dubois     switch (index) {
609a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ARM_SET:
610a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB1_SET:
611a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB2_SET:
612a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_SYS_SET:
613a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_AUDIO_SET:
614a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_VIDEO_SET:
615a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_MLB_SET:
616a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ENET_SET:
617a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_480_SET:
618a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_528_SET:
619a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC0_SET:
620a66d815cSJean-Christophe Dubois     case PMU_MISC1_SET:
621a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC2_SET:
622a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB1_VBUS_DETECT_SET:
623a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB1_CHRG_DETECT_SET:
624a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB1_MISC_SET:
625a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB2_VBUS_DETECT_SET:
626a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB2_CHRG_DETECT_SET:
627a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB2_MISC_SET:
628a66d815cSJean-Christophe Dubois         /*
629a66d815cSJean-Christophe Dubois          * All REG_NAME_SET register access are in fact targeting the
630a66d815cSJean-Christophe Dubois          * the REG_NAME register. So we change the value of the
631a66d815cSJean-Christophe Dubois          * REG_NAME register, setting bits passed in the value.
632a66d815cSJean-Christophe Dubois          */
633a66d815cSJean-Christophe Dubois         s->analog[index - 1] |= value;
634a66d815cSJean-Christophe Dubois         break;
635a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ARM_CLR:
636a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB1_CLR:
637a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB2_CLR:
638a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_SYS_CLR:
639a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_AUDIO_CLR:
640a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_VIDEO_CLR:
641a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_MLB_CLR:
642a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ENET_CLR:
643a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_480_CLR:
644a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_528_CLR:
645a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC0_CLR:
646a66d815cSJean-Christophe Dubois     case PMU_MISC1_CLR:
647a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC2_CLR:
648a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB1_VBUS_DETECT_CLR:
649a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB1_CHRG_DETECT_CLR:
650a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB1_MISC_CLR:
651a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB2_VBUS_DETECT_CLR:
652a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB2_CHRG_DETECT_CLR:
653a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB2_MISC_CLR:
654a66d815cSJean-Christophe Dubois         /*
655a66d815cSJean-Christophe Dubois          * All REG_NAME_CLR register access are in fact targeting the
656a66d815cSJean-Christophe Dubois          * the REG_NAME register. So we change the value of the
657a66d815cSJean-Christophe Dubois          * REG_NAME register, unsetting bits passed in the value.
658a66d815cSJean-Christophe Dubois          */
659a66d815cSJean-Christophe Dubois         s->analog[index - 2] &= ~value;
660a66d815cSJean-Christophe Dubois         break;
661a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ARM_TOG:
662a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB1_TOG:
663a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_USB2_TOG:
664a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_SYS_TOG:
665a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_AUDIO_TOG:
666a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_VIDEO_TOG:
667a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_MLB_TOG:
668a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PLL_ENET_TOG:
669a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_480_TOG:
670a66d815cSJean-Christophe Dubois     case CCM_ANALOG_PFD_528_TOG:
671a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC0_TOG:
672a66d815cSJean-Christophe Dubois     case PMU_MISC1_TOG:
673a66d815cSJean-Christophe Dubois     case CCM_ANALOG_MISC2_TOG:
674a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB1_VBUS_DETECT_TOG:
675a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB1_CHRG_DETECT_TOG:
676a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB1_MISC_TOG:
677a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB2_VBUS_DETECT_TOG:
678a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB2_CHRG_DETECT_TOG:
679a66d815cSJean-Christophe Dubois     case USB_ANALOG_USB2_MISC_TOG:
680a66d815cSJean-Christophe Dubois         /*
681a66d815cSJean-Christophe Dubois          * All REG_NAME_TOG register access are in fact targeting the
682a66d815cSJean-Christophe Dubois          * the REG_NAME register. So we change the value of the
683a66d815cSJean-Christophe Dubois          * REG_NAME register, toggling bits passed in the value.
684a66d815cSJean-Christophe Dubois          */
685a66d815cSJean-Christophe Dubois         s->analog[index - 3] ^= value;
686a66d815cSJean-Christophe Dubois         break;
687a66d815cSJean-Christophe Dubois     default:
688a66d815cSJean-Christophe Dubois         /*
689a66d815cSJean-Christophe Dubois          * We will do a better implementation later. In particular some bits
690a66d815cSJean-Christophe Dubois          * cannot be written to.
691a66d815cSJean-Christophe Dubois          */
692a66d815cSJean-Christophe Dubois         s->analog[index] = value;
693a66d815cSJean-Christophe Dubois         break;
694a66d815cSJean-Christophe Dubois     }
695a66d815cSJean-Christophe Dubois }
696a66d815cSJean-Christophe Dubois 
697a66d815cSJean-Christophe Dubois static const struct MemoryRegionOps imx6_ccm_ops = {
698a66d815cSJean-Christophe Dubois     .read = imx6_ccm_read,
699a66d815cSJean-Christophe Dubois     .write = imx6_ccm_write,
700a66d815cSJean-Christophe Dubois     .endianness = DEVICE_NATIVE_ENDIAN,
701a66d815cSJean-Christophe Dubois     .valid = {
702a66d815cSJean-Christophe Dubois         /*
703a66d815cSJean-Christophe Dubois          * Our device would not work correctly if the guest was doing
704a66d815cSJean-Christophe Dubois          * unaligned access. This might not be a limitation on the real
705a66d815cSJean-Christophe Dubois          * device but in practice there is no reason for a guest to access
706a66d815cSJean-Christophe Dubois          * this device unaligned.
707a66d815cSJean-Christophe Dubois          */
708a66d815cSJean-Christophe Dubois         .min_access_size = 4,
709a66d815cSJean-Christophe Dubois         .max_access_size = 4,
710a66d815cSJean-Christophe Dubois         .unaligned = false,
711a66d815cSJean-Christophe Dubois     },
712a66d815cSJean-Christophe Dubois };
713a66d815cSJean-Christophe Dubois 
714a66d815cSJean-Christophe Dubois static const struct MemoryRegionOps imx6_analog_ops = {
715a66d815cSJean-Christophe Dubois     .read = imx6_analog_read,
716a66d815cSJean-Christophe Dubois     .write = imx6_analog_write,
717a66d815cSJean-Christophe Dubois     .endianness = DEVICE_NATIVE_ENDIAN,
718a66d815cSJean-Christophe Dubois     .valid = {
719a66d815cSJean-Christophe Dubois         /*
720a66d815cSJean-Christophe Dubois          * Our device would not work correctly if the guest was doing
721a66d815cSJean-Christophe Dubois          * unaligned access. This might not be a limitation on the real
722a66d815cSJean-Christophe Dubois          * device but in practice there is no reason for a guest to access
723a66d815cSJean-Christophe Dubois          * this device unaligned.
724a66d815cSJean-Christophe Dubois          */
725a66d815cSJean-Christophe Dubois         .min_access_size = 4,
726a66d815cSJean-Christophe Dubois         .max_access_size = 4,
727a66d815cSJean-Christophe Dubois         .unaligned = false,
728a66d815cSJean-Christophe Dubois     },
729a66d815cSJean-Christophe Dubois };
730a66d815cSJean-Christophe Dubois 
731a66d815cSJean-Christophe Dubois static void imx6_ccm_init(Object *obj)
732a66d815cSJean-Christophe Dubois {
733a66d815cSJean-Christophe Dubois     DeviceState *dev = DEVICE(obj);
734a66d815cSJean-Christophe Dubois     SysBusDevice *sd = SYS_BUS_DEVICE(obj);
735a66d815cSJean-Christophe Dubois     IMX6CCMState *s = IMX6_CCM(obj);
736a66d815cSJean-Christophe Dubois 
737a66d815cSJean-Christophe Dubois     /* initialize a container for the all memory range */
738a66d815cSJean-Christophe Dubois     memory_region_init(&s->container, OBJECT(dev), TYPE_IMX6_CCM, 0x5000);
739a66d815cSJean-Christophe Dubois 
740a66d815cSJean-Christophe Dubois     /* We initialize an IO memory region for the CCM part */
741a66d815cSJean-Christophe Dubois     memory_region_init_io(&s->ioccm, OBJECT(dev), &imx6_ccm_ops, s,
742a66d815cSJean-Christophe Dubois                           TYPE_IMX6_CCM ".ccm", CCM_MAX * sizeof(uint32_t));
743a66d815cSJean-Christophe Dubois 
744a66d815cSJean-Christophe Dubois     /* Add the CCM as a subregion at offset 0 */
745a66d815cSJean-Christophe Dubois     memory_region_add_subregion(&s->container, 0, &s->ioccm);
746a66d815cSJean-Christophe Dubois 
747a66d815cSJean-Christophe Dubois     /* We initialize an IO memory region for the ANALOG part */
748a66d815cSJean-Christophe Dubois     memory_region_init_io(&s->ioanalog, OBJECT(dev), &imx6_analog_ops, s,
749a66d815cSJean-Christophe Dubois                           TYPE_IMX6_CCM ".analog",
750a66d815cSJean-Christophe Dubois                           CCM_ANALOG_MAX * sizeof(uint32_t));
751a66d815cSJean-Christophe Dubois 
752a66d815cSJean-Christophe Dubois     /* Add the ANALOG as a subregion at offset 0x4000 */
753a66d815cSJean-Christophe Dubois     memory_region_add_subregion(&s->container, 0x4000, &s->ioanalog);
754a66d815cSJean-Christophe Dubois 
755a66d815cSJean-Christophe Dubois     sysbus_init_mmio(sd, &s->container);
756a66d815cSJean-Christophe Dubois }
757a66d815cSJean-Christophe Dubois 
758a66d815cSJean-Christophe Dubois static void imx6_ccm_class_init(ObjectClass *klass, void *data)
759a66d815cSJean-Christophe Dubois {
760a66d815cSJean-Christophe Dubois     DeviceClass *dc = DEVICE_CLASS(klass);
761a66d815cSJean-Christophe Dubois     IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
762a66d815cSJean-Christophe Dubois 
763a66d815cSJean-Christophe Dubois     dc->reset = imx6_ccm_reset;
764a66d815cSJean-Christophe Dubois     dc->vmsd = &vmstate_imx6_ccm;
765a66d815cSJean-Christophe Dubois     dc->desc = "i.MX6 Clock Control Module";
766a66d815cSJean-Christophe Dubois 
767a66d815cSJean-Christophe Dubois     ccm->get_clock_frequency = imx6_ccm_get_clock_frequency;
768a66d815cSJean-Christophe Dubois }
769a66d815cSJean-Christophe Dubois 
770a66d815cSJean-Christophe Dubois static const TypeInfo imx6_ccm_info = {
771a66d815cSJean-Christophe Dubois     .name          = TYPE_IMX6_CCM,
772a66d815cSJean-Christophe Dubois     .parent        = TYPE_IMX_CCM,
773a66d815cSJean-Christophe Dubois     .instance_size = sizeof(IMX6CCMState),
774a66d815cSJean-Christophe Dubois     .instance_init = imx6_ccm_init,
775a66d815cSJean-Christophe Dubois     .class_init    = imx6_ccm_class_init,
776a66d815cSJean-Christophe Dubois };
777a66d815cSJean-Christophe Dubois 
778a66d815cSJean-Christophe Dubois static void imx6_ccm_register_types(void)
779a66d815cSJean-Christophe Dubois {
780a66d815cSJean-Christophe Dubois     type_register_static(&imx6_ccm_info);
781a66d815cSJean-Christophe Dubois }
782a66d815cSJean-Christophe Dubois 
783a66d815cSJean-Christophe Dubois type_init(imx6_ccm_register_types)
784