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"
15 #include "hw/misc/imx7_ccm.h"
17 static void imx7_analog_reset(DeviceState
*dev
)
19 IMX7AnalogState
*s
= IMX7_ANALOG(dev
);
21 memset(s
->pmu
, 0, sizeof(s
->pmu
));
22 memset(s
->analog
, 0, sizeof(s
->analog
));
24 s
->analog
[ANALOG_PLL_ARM
] = 0x00002042;
25 s
->analog
[ANALOG_PLL_DDR
] = 0x0060302c;
26 s
->analog
[ANALOG_PLL_DDR_SS
] = 0x00000000;
27 s
->analog
[ANALOG_PLL_DDR_NUM
] = 0x06aaac4d;
28 s
->analog
[ANALOG_PLL_DDR_DENOM
] = 0x100003ec;
29 s
->analog
[ANALOG_PLL_480
] = 0x00002000;
30 s
->analog
[ANALOG_PLL_480A
] = 0x52605a56;
31 s
->analog
[ANALOG_PLL_480B
] = 0x52525216;
32 s
->analog
[ANALOG_PLL_ENET
] = 0x00001fc0;
33 s
->analog
[ANALOG_PLL_AUDIO
] = 0x0001301b;
34 s
->analog
[ANALOG_PLL_AUDIO_SS
] = 0x00000000;
35 s
->analog
[ANALOG_PLL_AUDIO_NUM
] = 0x05f5e100;
36 s
->analog
[ANALOG_PLL_AUDIO_DENOM
] = 0x2964619c;
37 s
->analog
[ANALOG_PLL_VIDEO
] = 0x0008201b;
38 s
->analog
[ANALOG_PLL_VIDEO_SS
] = 0x00000000;
39 s
->analog
[ANALOG_PLL_VIDEO_NUM
] = 0x0000f699;
40 s
->analog
[ANALOG_PLL_VIDEO_DENOM
] = 0x000f4240;
41 s
->analog
[ANALOG_PLL_MISC0
] = 0x00000000;
43 /* all PLLs need to be locked */
44 s
->analog
[ANALOG_PLL_ARM
] |= ANALOG_PLL_LOCK
;
45 s
->analog
[ANALOG_PLL_DDR
] |= ANALOG_PLL_LOCK
;
46 s
->analog
[ANALOG_PLL_480
] |= ANALOG_PLL_LOCK
;
47 s
->analog
[ANALOG_PLL_480A
] |= ANALOG_PLL_LOCK
;
48 s
->analog
[ANALOG_PLL_480B
] |= ANALOG_PLL_LOCK
;
49 s
->analog
[ANALOG_PLL_ENET
] |= ANALOG_PLL_LOCK
;
50 s
->analog
[ANALOG_PLL_AUDIO
] |= ANALOG_PLL_LOCK
;
51 s
->analog
[ANALOG_PLL_VIDEO
] |= ANALOG_PLL_LOCK
;
52 s
->analog
[ANALOG_PLL_MISC0
] |= ANALOG_PLL_LOCK
;
55 * Since I couldn't find any info about this in the reference
56 * manual the value of this register is based strictly on matching
57 * what Linux kernel expects it to be.
59 s
->analog
[ANALOG_DIGPROG
] = 0x720000;
61 * Set revision to be 1.0 (Arbitrary choice, no particular
64 s
->analog
[ANALOG_DIGPROG
] |= 0x000010;
67 static void imx7_ccm_reset(DeviceState
*dev
)
69 IMX7CCMState
*s
= IMX7_CCM(dev
);
71 memset(s
->ccm
, 0, sizeof(s
->ccm
));
74 #define CCM_INDEX(offset) (((offset) & ~(hwaddr)0xF) / sizeof(uint32_t))
75 #define CCM_BITOP(offset) ((offset) & (hwaddr)0xF)
78 CCM_BITOP_NONE
= 0x00,
84 static uint64_t imx7_set_clr_tog_read(void *opaque
, hwaddr offset
,
87 const uint32_t *mmio
= opaque
;
89 return mmio
[CCM_INDEX(offset
)];
92 static void imx7_set_clr_tog_write(void *opaque
, hwaddr offset
,
93 uint64_t value
, unsigned size
)
95 const uint8_t bitop
= CCM_BITOP(offset
);
96 const uint32_t index
= CCM_INDEX(offset
);
97 uint32_t *mmio
= opaque
;
104 mmio
[index
] |= value
;
107 mmio
[index
] &= ~value
;
110 mmio
[index
] ^= value
;
115 static const struct MemoryRegionOps imx7_set_clr_tog_ops
= {
116 .read
= imx7_set_clr_tog_read
,
117 .write
= imx7_set_clr_tog_write
,
118 .endianness
= DEVICE_NATIVE_ENDIAN
,
121 * Our device would not work correctly if the guest was doing
122 * unaligned access. This might not be a limitation on the real
123 * device but in practice there is no reason for a guest to access
124 * this device unaligned.
126 .min_access_size
= 4,
127 .max_access_size
= 4,
132 static const struct MemoryRegionOps imx7_digprog_ops
= {
133 .read
= imx7_set_clr_tog_read
,
134 .endianness
= DEVICE_NATIVE_ENDIAN
,
136 .min_access_size
= 4,
137 .max_access_size
= 4,
142 static void imx7_ccm_init(Object
*obj
)
144 SysBusDevice
*sd
= SYS_BUS_DEVICE(obj
);
145 IMX7CCMState
*s
= IMX7_CCM(obj
);
147 memory_region_init_io(&s
->iomem
,
149 &imx7_set_clr_tog_ops
,
151 TYPE_IMX7_CCM
".ccm",
154 sysbus_init_mmio(sd
, &s
->iomem
);
157 static void imx7_analog_init(Object
*obj
)
159 SysBusDevice
*sd
= SYS_BUS_DEVICE(obj
);
160 IMX7AnalogState
*s
= IMX7_ANALOG(obj
);
162 memory_region_init(&s
->mmio
.container
, obj
, TYPE_IMX7_ANALOG
,
165 memory_region_init_io(&s
->mmio
.analog
,
167 &imx7_set_clr_tog_ops
,
172 memory_region_add_subregion(&s
->mmio
.container
,
173 0x60, &s
->mmio
.analog
);
175 memory_region_init_io(&s
->mmio
.pmu
,
177 &imx7_set_clr_tog_ops
,
179 TYPE_IMX7_ANALOG
".pmu",
182 memory_region_add_subregion(&s
->mmio
.container
,
183 0x200, &s
->mmio
.pmu
);
185 memory_region_init_io(&s
->mmio
.digprog
,
188 &s
->analog
[ANALOG_DIGPROG
],
189 TYPE_IMX7_ANALOG
".digprog",
192 memory_region_add_subregion_overlap(&s
->mmio
.container
,
193 0x800, &s
->mmio
.digprog
, 10);
196 sysbus_init_mmio(sd
, &s
->mmio
.container
);
199 static const VMStateDescription vmstate_imx7_ccm
= {
200 .name
= TYPE_IMX7_CCM
,
202 .minimum_version_id
= 1,
203 .fields
= (VMStateField
[]) {
204 VMSTATE_UINT32_ARRAY(ccm
, IMX7CCMState
, CCM_MAX
),
205 VMSTATE_END_OF_LIST()
209 static uint32_t imx7_ccm_get_clock_frequency(IMXCCMState
*dev
, IMXClk clock
)
212 * This function is "consumed" by GPT emulation code, however on
213 * i.MX7 each GPT block can have their own clock root. This means
214 * that this functions needs somehow to know requester's identity
215 * and the way to pass it: be it via additional IMXClk constants
216 * or by adding another argument to this method needs to be
219 qemu_log_mask(LOG_GUEST_ERROR
, "[%s]%s: Not implemented\n",
220 TYPE_IMX7_CCM
, __func__
);
224 static void imx7_ccm_class_init(ObjectClass
*klass
, void *data
)
226 DeviceClass
*dc
= DEVICE_CLASS(klass
);
227 IMXCCMClass
*ccm
= IMX_CCM_CLASS(klass
);
229 dc
->reset
= imx7_ccm_reset
;
230 dc
->vmsd
= &vmstate_imx7_ccm
;
231 dc
->desc
= "i.MX7 Clock Control Module";
233 ccm
->get_clock_frequency
= imx7_ccm_get_clock_frequency
;
236 static const TypeInfo imx7_ccm_info
= {
237 .name
= TYPE_IMX7_CCM
,
238 .parent
= TYPE_IMX_CCM
,
239 .instance_size
= sizeof(IMX7CCMState
),
240 .instance_init
= imx7_ccm_init
,
241 .class_init
= imx7_ccm_class_init
,
244 static const VMStateDescription vmstate_imx7_analog
= {
245 .name
= TYPE_IMX7_ANALOG
,
247 .minimum_version_id
= 1,
248 .fields
= (VMStateField
[]) {
249 VMSTATE_UINT32_ARRAY(analog
, IMX7AnalogState
, ANALOG_MAX
),
250 VMSTATE_UINT32_ARRAY(pmu
, IMX7AnalogState
, PMU_MAX
),
251 VMSTATE_END_OF_LIST()
255 static void imx7_analog_class_init(ObjectClass
*klass
, void *data
)
257 DeviceClass
*dc
= DEVICE_CLASS(klass
);
259 dc
->reset
= imx7_analog_reset
;
260 dc
->vmsd
= &vmstate_imx7_analog
;
261 dc
->desc
= "i.MX7 Analog Module";
264 static const TypeInfo imx7_analog_info
= {
265 .name
= TYPE_IMX7_ANALOG
,
266 .parent
= TYPE_SYS_BUS_DEVICE
,
267 .instance_size
= sizeof(IMX7AnalogState
),
268 .instance_init
= imx7_analog_init
,
269 .class_init
= imx7_analog_class_init
,
272 static void imx7_ccm_register_type(void)
274 type_register_static(&imx7_ccm_info
);
275 type_register_static(&imx7_analog_info
);
277 type_init(imx7_ccm_register_type
)