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