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