xref: /openbmc/qemu/hw/misc/imx25_ccm.c (revision 15eafc2e)
1 /*
2  * IMX25 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/imx25_ccm.h"
15 
16 #ifndef DEBUG_IMX25_CCM
17 #define DEBUG_IMX25_CCM 0
18 #endif
19 
20 #define DPRINTF(fmt, args...) \
21     do { \
22         if (DEBUG_IMX25_CCM) { \
23             fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX25_CCM, \
24                                              __func__, ##args); \
25         } \
26     } while (0)
27 
28 static char const *imx25_ccm_reg_name(uint32_t reg)
29 {
30     static char unknown[20];
31 
32     switch (reg) {
33     case IMX25_CCM_MPCTL_REG:
34         return "mpctl";
35     case IMX25_CCM_UPCTL_REG:
36         return "upctl";
37     case IMX25_CCM_CCTL_REG:
38         return "cctl";
39     case IMX25_CCM_CGCR0_REG:
40         return "cgcr0";
41     case IMX25_CCM_CGCR1_REG:
42         return "cgcr1";
43     case IMX25_CCM_CGCR2_REG:
44         return "cgcr2";
45     case IMX25_CCM_PCDR0_REG:
46         return "pcdr0";
47     case IMX25_CCM_PCDR1_REG:
48         return "pcdr1";
49     case IMX25_CCM_PCDR2_REG:
50         return "pcdr2";
51     case IMX25_CCM_PCDR3_REG:
52         return "pcdr3";
53     case IMX25_CCM_RCSR_REG:
54         return "rcsr";
55     case IMX25_CCM_CRDR_REG:
56         return "crdr";
57     case IMX25_CCM_DCVR0_REG:
58         return "dcvr0";
59     case IMX25_CCM_DCVR1_REG:
60         return "dcvr1";
61     case IMX25_CCM_DCVR2_REG:
62         return "dcvr2";
63     case IMX25_CCM_DCVR3_REG:
64         return "dcvr3";
65     case IMX25_CCM_LTR0_REG:
66         return "ltr0";
67     case IMX25_CCM_LTR1_REG:
68         return "ltr1";
69     case IMX25_CCM_LTR2_REG:
70         return "ltr2";
71     case IMX25_CCM_LTR3_REG:
72         return "ltr3";
73     case IMX25_CCM_LTBR0_REG:
74         return "ltbr0";
75     case IMX25_CCM_LTBR1_REG:
76         return "ltbr1";
77     case IMX25_CCM_PMCR0_REG:
78         return "pmcr0";
79     case IMX25_CCM_PMCR1_REG:
80         return "pmcr1";
81     case IMX25_CCM_PMCR2_REG:
82         return "pmcr2";
83     case IMX25_CCM_MCR_REG:
84         return "mcr";
85     case IMX25_CCM_LPIMR0_REG:
86         return "lpimr0";
87     case IMX25_CCM_LPIMR1_REG:
88         return "lpimr1";
89     default:
90         sprintf(unknown, "[%d ?]", reg);
91         return unknown;
92     }
93 }
94 #define CKIH_FREQ 24000000 /* 24MHz crystal input */
95 
96 static const VMStateDescription vmstate_imx25_ccm = {
97     .name = TYPE_IMX25_CCM,
98     .version_id = 1,
99     .minimum_version_id = 1,
100     .fields = (VMStateField[]) {
101         VMSTATE_UINT32_ARRAY(reg, IMX25CCMState, IMX25_CCM_MAX_REG),
102         VMSTATE_END_OF_LIST()
103     },
104 };
105 
106 static uint32_t imx25_ccm_get_mpll_clk(IMXCCMState *dev)
107 {
108     uint32_t freq;
109     IMX25CCMState *s = IMX25_CCM(dev);
110 
111     if (EXTRACT(s->reg[IMX25_CCM_CCTL_REG], MPLL_BYPASS)) {
112         freq = CKIH_FREQ;
113     } else {
114         freq = imx_ccm_calc_pll(s->reg[IMX25_CCM_MPCTL_REG], CKIH_FREQ);
115     }
116 
117     DPRINTF("freq = %d\n", freq);
118 
119     return freq;
120 }
121 
122 static uint32_t imx25_ccm_get_upll_clk(IMXCCMState *dev)
123 {
124     uint32_t freq = 0;
125     IMX25CCMState *s = IMX25_CCM(dev);
126 
127     if (!EXTRACT(s->reg[IMX25_CCM_CCTL_REG], UPLL_DIS)) {
128         freq = imx_ccm_calc_pll(s->reg[IMX25_CCM_UPCTL_REG], CKIH_FREQ);
129     }
130 
131     DPRINTF("freq = %d\n", freq);
132 
133     return freq;
134 }
135 
136 static uint32_t imx25_ccm_get_mcu_clk(IMXCCMState *dev)
137 {
138     uint32_t freq;
139     IMX25CCMState *s = IMX25_CCM(dev);
140 
141     freq = imx25_ccm_get_mpll_clk(dev);
142 
143     if (EXTRACT(s->reg[IMX25_CCM_CCTL_REG], ARM_SRC)) {
144         freq = (freq * 3 / 4);
145     }
146 
147     freq = freq / (1 + EXTRACT(s->reg[IMX25_CCM_CCTL_REG], ARM_CLK_DIV));
148 
149     DPRINTF("freq = %d\n", freq);
150 
151     return freq;
152 }
153 
154 static uint32_t imx25_ccm_get_ahb_clk(IMXCCMState *dev)
155 {
156     uint32_t freq;
157     IMX25CCMState *s = IMX25_CCM(dev);
158 
159     freq = imx25_ccm_get_mcu_clk(dev)
160            / (1 + EXTRACT(s->reg[IMX25_CCM_CCTL_REG], AHB_CLK_DIV));
161 
162     DPRINTF("freq = %d\n", freq);
163 
164     return freq;
165 }
166 
167 static uint32_t imx25_ccm_get_ipg_clk(IMXCCMState *dev)
168 {
169     uint32_t freq;
170 
171     freq = imx25_ccm_get_ahb_clk(dev) / 2;
172 
173     DPRINTF("freq = %d\n", freq);
174 
175     return freq;
176 }
177 
178 static uint32_t imx25_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
179 {
180     uint32_t freq = 0;
181     DPRINTF("Clock = %d)\n", clock);
182 
183     switch (clock) {
184     case NOCLK:
185         break;
186     case CLK_MPLL:
187         freq = imx25_ccm_get_mpll_clk(dev);
188         break;
189     case CLK_UPLL:
190         freq = imx25_ccm_get_upll_clk(dev);
191         break;
192     case CLK_MCU:
193         freq = imx25_ccm_get_mcu_clk(dev);
194         break;
195     case CLK_AHB:
196         freq = imx25_ccm_get_ahb_clk(dev);
197         break;
198     case CLK_IPG:
199         freq = imx25_ccm_get_ipg_clk(dev);
200         break;
201     case CLK_32k:
202         freq = CKIL_FREQ;
203         break;
204     default:
205         qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
206                       TYPE_IMX25_CCM, __func__, clock);
207         break;
208     }
209 
210     DPRINTF("Clock = %d) = %d\n", clock, freq);
211 
212     return freq;
213 }
214 
215 static void imx25_ccm_reset(DeviceState *dev)
216 {
217     IMX25CCMState *s = IMX25_CCM(dev);
218 
219     DPRINTF("\n");
220 
221     memset(s->reg, 0, IMX25_CCM_MAX_REG * sizeof(uint32_t));
222     s->reg[IMX25_CCM_MPCTL_REG] = 0x800b2c01;
223     s->reg[IMX25_CCM_UPCTL_REG] = 0x84042800;
224     /*
225      * The value below gives:
226      * CPU = 133 MHz, AHB = 66,5 MHz, IPG = 33 MHz.
227      */
228     s->reg[IMX25_CCM_CCTL_REG]  = 0xd0030000;
229     s->reg[IMX25_CCM_CGCR0_REG] = 0x028A0100;
230     s->reg[IMX25_CCM_CGCR1_REG] = 0x04008100;
231     s->reg[IMX25_CCM_CGCR2_REG] = 0x00000438;
232     s->reg[IMX25_CCM_PCDR0_REG] = 0x01010101;
233     s->reg[IMX25_CCM_PCDR1_REG] = 0x01010101;
234     s->reg[IMX25_CCM_PCDR2_REG] = 0x01010101;
235     s->reg[IMX25_CCM_PCDR3_REG] = 0x01010101;
236     s->reg[IMX25_CCM_PMCR0_REG] = 0x00A00000;
237     s->reg[IMX25_CCM_PMCR1_REG] = 0x0000A030;
238     s->reg[IMX25_CCM_PMCR2_REG] = 0x0000A030;
239     s->reg[IMX25_CCM_MCR_REG]   = 0x43000000;
240 
241     /*
242      * default boot will change the reset values to allow:
243      * CPU = 399 MHz, AHB = 133 MHz, IPG = 66,5 MHz.
244      * For some reason, this doesn't work. With the value below, linux
245      * detects a 88 MHz IPG CLK instead of 66,5 MHz.
246     s->reg[IMX25_CCM_CCTL_REG]  = 0x20032000;
247      */
248 }
249 
250 static uint64_t imx25_ccm_read(void *opaque, hwaddr offset, unsigned size)
251 {
252     uint32 value = 0;
253     IMX25CCMState *s = (IMX25CCMState *)opaque;
254 
255     if (offset < 0x70) {
256         value = s->reg[offset >> 2];
257     } else {
258         qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
259                       HWADDR_PRIx "\n", TYPE_IMX25_CCM, __func__, offset);
260     }
261 
262     DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx25_ccm_reg_name(offset >> 2),
263             value);
264 
265     return value;
266 }
267 
268 static void imx25_ccm_write(void *opaque, hwaddr offset, uint64_t value,
269                             unsigned size)
270 {
271     IMX25CCMState *s = (IMX25CCMState *)opaque;
272 
273     DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx25_ccm_reg_name(offset >> 2),
274             (uint32_t)value);
275 
276     if (offset < 0x70) {
277         /*
278          * We will do a better implementation later. In particular some bits
279          * cannot be written to.
280          */
281         s->reg[offset >> 2] = value;
282     } else {
283         qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
284                       HWADDR_PRIx "\n", TYPE_IMX25_CCM, __func__, offset);
285     }
286 }
287 
288 static const struct MemoryRegionOps imx25_ccm_ops = {
289     .read = imx25_ccm_read,
290     .write = imx25_ccm_write,
291     .endianness = DEVICE_NATIVE_ENDIAN,
292     .valid = {
293         /*
294          * Our device would not work correctly if the guest was doing
295          * unaligned access. This might not be a limitation on the real
296          * device but in practice there is no reason for a guest to access
297          * this device unaligned.
298          */
299         .min_access_size = 4,
300         .max_access_size = 4,
301         .unaligned = false,
302     },
303 };
304 
305 static void imx25_ccm_init(Object *obj)
306 {
307     DeviceState *dev = DEVICE(obj);
308     SysBusDevice *sd = SYS_BUS_DEVICE(obj);
309     IMX25CCMState *s = IMX25_CCM(obj);
310 
311     memory_region_init_io(&s->iomem, OBJECT(dev), &imx25_ccm_ops, s,
312                           TYPE_IMX25_CCM, 0x1000);
313     sysbus_init_mmio(sd, &s->iomem);
314 }
315 
316 static void imx25_ccm_class_init(ObjectClass *klass, void *data)
317 {
318     DeviceClass *dc = DEVICE_CLASS(klass);
319     IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
320 
321     dc->reset = imx25_ccm_reset;
322     dc->vmsd = &vmstate_imx25_ccm;
323     dc->desc = "i.MX25 Clock Control Module";
324 
325     ccm->get_clock_frequency = imx25_ccm_get_clock_frequency;
326 }
327 
328 static const TypeInfo imx25_ccm_info = {
329     .name          = TYPE_IMX25_CCM,
330     .parent        = TYPE_IMX_CCM,
331     .instance_size = sizeof(IMX25CCMState),
332     .instance_init = imx25_ccm_init,
333     .class_init    = imx25_ccm_class_init,
334 };
335 
336 static void imx25_ccm_register_types(void)
337 {
338     type_register_static(&imx25_ccm_info);
339 }
340 
341 type_init(imx25_ccm_register_types)
342