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 const struct MemoryRegionOps imx7_digprog_ops
= {
135 .read
= imx7_set_clr_tog_read
,
136 .endianness
= DEVICE_NATIVE_ENDIAN
,
138 .min_access_size
= 4,
139 .max_access_size
= 4,
144 static void imx7_ccm_init(Object
*obj
)
146 SysBusDevice
*sd
= SYS_BUS_DEVICE(obj
);
147 IMX7CCMState
*s
= IMX7_CCM(obj
);
149 memory_region_init_io(&s
->iomem
,
151 &imx7_set_clr_tog_ops
,
153 TYPE_IMX7_CCM
".ccm",
156 sysbus_init_mmio(sd
, &s
->iomem
);
159 static void imx7_analog_init(Object
*obj
)
161 SysBusDevice
*sd
= SYS_BUS_DEVICE(obj
);
162 IMX7AnalogState
*s
= IMX7_ANALOG(obj
);
164 memory_region_init(&s
->mmio
.container
, obj
, TYPE_IMX7_ANALOG
,
167 memory_region_init_io(&s
->mmio
.analog
,
169 &imx7_set_clr_tog_ops
,
174 memory_region_add_subregion(&s
->mmio
.container
,
175 0x60, &s
->mmio
.analog
);
177 memory_region_init_io(&s
->mmio
.pmu
,
179 &imx7_set_clr_tog_ops
,
181 TYPE_IMX7_ANALOG
".pmu",
184 memory_region_add_subregion(&s
->mmio
.container
,
185 0x200, &s
->mmio
.pmu
);
187 memory_region_init_io(&s
->mmio
.digprog
,
190 &s
->analog
[ANALOG_DIGPROG
],
191 TYPE_IMX7_ANALOG
".digprog",
194 memory_region_add_subregion_overlap(&s
->mmio
.container
,
195 0x800, &s
->mmio
.digprog
, 10);
198 sysbus_init_mmio(sd
, &s
->mmio
.container
);
201 static const VMStateDescription vmstate_imx7_ccm
= {
202 .name
= TYPE_IMX7_CCM
,
204 .minimum_version_id
= 1,
205 .fields
= (VMStateField
[]) {
206 VMSTATE_UINT32_ARRAY(ccm
, IMX7CCMState
, CCM_MAX
),
207 VMSTATE_END_OF_LIST()
211 static uint32_t imx7_ccm_get_clock_frequency(IMXCCMState
*dev
, IMXClk clock
)
214 * This function is "consumed" by GPT emulation code, however on
215 * i.MX7 each GPT block can have their own clock root. This means
216 * that this functions needs somehow to know requester's identity
217 * and the way to pass it: be it via additional IMXClk constants
218 * or by adding another argument to this method needs to be
221 qemu_log_mask(LOG_GUEST_ERROR
, "[%s]%s: Not implemented\n",
222 TYPE_IMX7_CCM
, __func__
);
226 static void imx7_ccm_class_init(ObjectClass
*klass
, void *data
)
228 DeviceClass
*dc
= DEVICE_CLASS(klass
);
229 IMXCCMClass
*ccm
= IMX_CCM_CLASS(klass
);
231 dc
->reset
= imx7_ccm_reset
;
232 dc
->vmsd
= &vmstate_imx7_ccm
;
233 dc
->desc
= "i.MX7 Clock Control Module";
235 ccm
->get_clock_frequency
= imx7_ccm_get_clock_frequency
;
238 static const TypeInfo imx7_ccm_info
= {
239 .name
= TYPE_IMX7_CCM
,
240 .parent
= TYPE_IMX_CCM
,
241 .instance_size
= sizeof(IMX7CCMState
),
242 .instance_init
= imx7_ccm_init
,
243 .class_init
= imx7_ccm_class_init
,
246 static const VMStateDescription vmstate_imx7_analog
= {
247 .name
= TYPE_IMX7_ANALOG
,
249 .minimum_version_id
= 1,
250 .fields
= (VMStateField
[]) {
251 VMSTATE_UINT32_ARRAY(analog
, IMX7AnalogState
, ANALOG_MAX
),
252 VMSTATE_UINT32_ARRAY(pmu
, IMX7AnalogState
, PMU_MAX
),
253 VMSTATE_END_OF_LIST()
257 static void imx7_analog_class_init(ObjectClass
*klass
, void *data
)
259 DeviceClass
*dc
= DEVICE_CLASS(klass
);
261 dc
->reset
= imx7_analog_reset
;
262 dc
->vmsd
= &vmstate_imx7_analog
;
263 dc
->desc
= "i.MX7 Analog Module";
266 static const TypeInfo imx7_analog_info
= {
267 .name
= TYPE_IMX7_ANALOG
,
268 .parent
= TYPE_SYS_BUS_DEVICE
,
269 .instance_size
= sizeof(IMX7AnalogState
),
270 .instance_init
= imx7_analog_init
,
271 .class_init
= imx7_analog_class_init
,
274 static void imx7_ccm_register_type(void)
276 type_register_static(&imx7_ccm_info
);
277 type_register_static(&imx7_analog_info
);
279 type_init(imx7_ccm_register_type
)