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