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