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