2 * Copyright (c) 2018, Impinj, Inc.
4 * i.MX7 CCM, PMU and ANALOG IP blocks emulation code
6 * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
8 * This work is licensed under the terms of the GNU GPL, version 2 or later.
9 * See the COPYING file in the top-level directory.
12 #include "qemu/osdep.h"
14 #include "qemu/module.h"
16 #include "hw/misc/imx7_ccm.h"
17 #include "migration/vmstate.h"
19 static void imx7_analog_reset(DeviceState
*dev
)
21 IMX7AnalogState
*s
= IMX7_ANALOG(dev
);
23 memset(s
->pmu
, 0, sizeof(s
->pmu
));
24 memset(s
->analog
, 0, sizeof(s
->analog
));
26 s
->analog
[ANALOG_PLL_ARM
] = 0x00002042;
27 s
->analog
[ANALOG_PLL_DDR
] = 0x0060302c;
28 s
->analog
[ANALOG_PLL_DDR_SS
] = 0x00000000;
29 s
->analog
[ANALOG_PLL_DDR_NUM
] = 0x06aaac4d;
30 s
->analog
[ANALOG_PLL_DDR_DENOM
] = 0x100003ec;
31 s
->analog
[ANALOG_PLL_480
] = 0x00002000;
32 s
->analog
[ANALOG_PLL_480A
] = 0x52605a56;
33 s
->analog
[ANALOG_PLL_480B
] = 0x52525216;
34 s
->analog
[ANALOG_PLL_ENET
] = 0x00001fc0;
35 s
->analog
[ANALOG_PLL_AUDIO
] = 0x0001301b;
36 s
->analog
[ANALOG_PLL_AUDIO_SS
] = 0x00000000;
37 s
->analog
[ANALOG_PLL_AUDIO_NUM
] = 0x05f5e100;
38 s
->analog
[ANALOG_PLL_AUDIO_DENOM
] = 0x2964619c;
39 s
->analog
[ANALOG_PLL_VIDEO
] = 0x0008201b;
40 s
->analog
[ANALOG_PLL_VIDEO_SS
] = 0x00000000;
41 s
->analog
[ANALOG_PLL_VIDEO_NUM
] = 0x0000f699;
42 s
->analog
[ANALOG_PLL_VIDEO_DENOM
] = 0x000f4240;
43 s
->analog
[ANALOG_PLL_MISC0
] = 0x00000000;
45 /* all PLLs need to be locked */
46 s
->analog
[ANALOG_PLL_ARM
] |= ANALOG_PLL_LOCK
;
47 s
->analog
[ANALOG_PLL_DDR
] |= ANALOG_PLL_LOCK
;
48 s
->analog
[ANALOG_PLL_480
] |= ANALOG_PLL_LOCK
;
49 s
->analog
[ANALOG_PLL_480A
] |= ANALOG_PLL_LOCK
;
50 s
->analog
[ANALOG_PLL_480B
] |= ANALOG_PLL_LOCK
;
51 s
->analog
[ANALOG_PLL_ENET
] |= ANALOG_PLL_LOCK
;
52 s
->analog
[ANALOG_PLL_AUDIO
] |= ANALOG_PLL_LOCK
;
53 s
->analog
[ANALOG_PLL_VIDEO
] |= ANALOG_PLL_LOCK
;
54 s
->analog
[ANALOG_PLL_MISC0
] |= ANALOG_PLL_LOCK
;
57 * Since I couldn't find any info about this in the reference
58 * manual the value of this register is based strictly on matching
59 * what Linux kernel expects it to be.
61 s
->analog
[ANALOG_DIGPROG
] = 0x720000;
63 * Set revision to be 1.0 (Arbitrary choice, no particular
66 s
->analog
[ANALOG_DIGPROG
] |= 0x000010;
69 static void imx7_ccm_reset(DeviceState
*dev
)
71 IMX7CCMState
*s
= IMX7_CCM(dev
);
73 memset(s
->ccm
, 0, sizeof(s
->ccm
));
76 #define CCM_INDEX(offset) (((offset) & ~(hwaddr)0xF) / sizeof(uint32_t))
77 #define CCM_BITOP(offset) ((offset) & (hwaddr)0xF)
80 CCM_BITOP_NONE
= 0x00,
86 static uint64_t imx7_set_clr_tog_read(void *opaque
, hwaddr offset
,
89 const uint32_t *mmio
= opaque
;
91 return mmio
[CCM_INDEX(offset
)];
94 static void imx7_set_clr_tog_write(void *opaque
, hwaddr offset
,
95 uint64_t value
, unsigned size
)
97 const uint8_t bitop
= CCM_BITOP(offset
);
98 const uint32_t index
= CCM_INDEX(offset
);
99 uint32_t *mmio
= opaque
;
106 mmio
[index
] |= value
;
109 mmio
[index
] &= ~value
;
112 mmio
[index
] ^= value
;
117 static const struct MemoryRegionOps imx7_set_clr_tog_ops
= {
118 .read
= imx7_set_clr_tog_read
,
119 .write
= imx7_set_clr_tog_write
,
120 .endianness
= DEVICE_NATIVE_ENDIAN
,
123 * Our device would not work correctly if the guest was doing
124 * unaligned access. This might not be a limitation on the real
125 * device but in practice there is no reason for a guest to access
126 * this device unaligned.
128 .min_access_size
= 4,
129 .max_access_size
= 4,
134 static void imx7_digprog_write(void *opaque
, hwaddr addr
,
135 uint64_t data
, unsigned size
)
137 qemu_log_mask(LOG_GUEST_ERROR
,
138 "Guest write to read-only ANALOG_DIGPROG register\n");
141 static const struct MemoryRegionOps imx7_digprog_ops
= {
142 .read
= imx7_set_clr_tog_read
,
143 .write
= imx7_digprog_write
,
144 .endianness
= DEVICE_NATIVE_ENDIAN
,
146 .min_access_size
= 4,
147 .max_access_size
= 4,
152 static void imx7_ccm_init(Object
*obj
)
154 SysBusDevice
*sd
= SYS_BUS_DEVICE(obj
);
155 IMX7CCMState
*s
= IMX7_CCM(obj
);
157 memory_region_init_io(&s
->iomem
,
159 &imx7_set_clr_tog_ops
,
161 TYPE_IMX7_CCM
".ccm",
164 sysbus_init_mmio(sd
, &s
->iomem
);
167 static void imx7_analog_init(Object
*obj
)
169 SysBusDevice
*sd
= SYS_BUS_DEVICE(obj
);
170 IMX7AnalogState
*s
= IMX7_ANALOG(obj
);
172 memory_region_init(&s
->mmio
.container
, obj
, TYPE_IMX7_ANALOG
,
175 memory_region_init_io(&s
->mmio
.analog
,
177 &imx7_set_clr_tog_ops
,
182 memory_region_add_subregion(&s
->mmio
.container
,
183 0x60, &s
->mmio
.analog
);
185 memory_region_init_io(&s
->mmio
.pmu
,
187 &imx7_set_clr_tog_ops
,
189 TYPE_IMX7_ANALOG
".pmu",
192 memory_region_add_subregion(&s
->mmio
.container
,
193 0x200, &s
->mmio
.pmu
);
195 memory_region_init_io(&s
->mmio
.digprog
,
198 &s
->analog
[ANALOG_DIGPROG
],
199 TYPE_IMX7_ANALOG
".digprog",
202 memory_region_add_subregion_overlap(&s
->mmio
.container
,
203 0x800, &s
->mmio
.digprog
, 10);
206 sysbus_init_mmio(sd
, &s
->mmio
.container
);
209 static const VMStateDescription vmstate_imx7_ccm
= {
210 .name
= TYPE_IMX7_CCM
,
212 .minimum_version_id
= 1,
213 .fields
= (VMStateField
[]) {
214 VMSTATE_UINT32_ARRAY(ccm
, IMX7CCMState
, CCM_MAX
),
215 VMSTATE_END_OF_LIST()
219 static uint32_t imx7_ccm_get_clock_frequency(IMXCCMState
*dev
, IMXClk clock
)
222 * This function is "consumed" by GPT emulation code, however on
223 * i.MX7 each GPT block can have their own clock root. This means
224 * that this functions needs somehow to know requester's identity
225 * and the way to pass it: be it via additional IMXClk constants
226 * or by adding another argument to this method needs to be
229 qemu_log_mask(LOG_GUEST_ERROR
, "[%s]%s: Not implemented\n",
230 TYPE_IMX7_CCM
, __func__
);
234 static void imx7_ccm_class_init(ObjectClass
*klass
, void *data
)
236 DeviceClass
*dc
= DEVICE_CLASS(klass
);
237 IMXCCMClass
*ccm
= IMX_CCM_CLASS(klass
);
239 dc
->reset
= imx7_ccm_reset
;
240 dc
->vmsd
= &vmstate_imx7_ccm
;
241 dc
->desc
= "i.MX7 Clock Control Module";
243 ccm
->get_clock_frequency
= imx7_ccm_get_clock_frequency
;
246 static const TypeInfo imx7_ccm_info
= {
247 .name
= TYPE_IMX7_CCM
,
248 .parent
= TYPE_IMX_CCM
,
249 .instance_size
= sizeof(IMX7CCMState
),
250 .instance_init
= imx7_ccm_init
,
251 .class_init
= imx7_ccm_class_init
,
254 static const VMStateDescription vmstate_imx7_analog
= {
255 .name
= TYPE_IMX7_ANALOG
,
257 .minimum_version_id
= 1,
258 .fields
= (VMStateField
[]) {
259 VMSTATE_UINT32_ARRAY(analog
, IMX7AnalogState
, ANALOG_MAX
),
260 VMSTATE_UINT32_ARRAY(pmu
, IMX7AnalogState
, PMU_MAX
),
261 VMSTATE_END_OF_LIST()
265 static void imx7_analog_class_init(ObjectClass
*klass
, void *data
)
267 DeviceClass
*dc
= DEVICE_CLASS(klass
);
269 dc
->reset
= imx7_analog_reset
;
270 dc
->vmsd
= &vmstate_imx7_analog
;
271 dc
->desc
= "i.MX7 Analog Module";
274 static const TypeInfo imx7_analog_info
= {
275 .name
= TYPE_IMX7_ANALOG
,
276 .parent
= TYPE_SYS_BUS_DEVICE
,
277 .instance_size
= sizeof(IMX7AnalogState
),
278 .instance_init
= imx7_analog_init
,
279 .class_init
= imx7_analog_class_init
,
282 static void imx7_ccm_register_type(void)
284 type_register_static(&imx7_ccm_info
);
285 type_register_static(&imx7_analog_info
);
287 type_init(imx7_ccm_register_type
)