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"
18 static void imx7_analog_reset(DeviceState
*dev
)
20 IMX7AnalogState
*s
= IMX7_ANALOG(dev
);
22 memset(s
->pmu
, 0, sizeof(s
->pmu
));
23 memset(s
->analog
, 0, sizeof(s
->analog
));
25 s
->analog
[ANALOG_PLL_ARM
] = 0x00002042;
26 s
->analog
[ANALOG_PLL_DDR
] = 0x0060302c;
27 s
->analog
[ANALOG_PLL_DDR_SS
] = 0x00000000;
28 s
->analog
[ANALOG_PLL_DDR_NUM
] = 0x06aaac4d;
29 s
->analog
[ANALOG_PLL_DDR_DENOM
] = 0x100003ec;
30 s
->analog
[ANALOG_PLL_480
] = 0x00002000;
31 s
->analog
[ANALOG_PLL_480A
] = 0x52605a56;
32 s
->analog
[ANALOG_PLL_480B
] = 0x52525216;
33 s
->analog
[ANALOG_PLL_ENET
] = 0x00001fc0;
34 s
->analog
[ANALOG_PLL_AUDIO
] = 0x0001301b;
35 s
->analog
[ANALOG_PLL_AUDIO_SS
] = 0x00000000;
36 s
->analog
[ANALOG_PLL_AUDIO_NUM
] = 0x05f5e100;
37 s
->analog
[ANALOG_PLL_AUDIO_DENOM
] = 0x2964619c;
38 s
->analog
[ANALOG_PLL_VIDEO
] = 0x0008201b;
39 s
->analog
[ANALOG_PLL_VIDEO_SS
] = 0x00000000;
40 s
->analog
[ANALOG_PLL_VIDEO_NUM
] = 0x0000f699;
41 s
->analog
[ANALOG_PLL_VIDEO_DENOM
] = 0x000f4240;
42 s
->analog
[ANALOG_PLL_MISC0
] = 0x00000000;
44 /* all PLLs need to be locked */
45 s
->analog
[ANALOG_PLL_ARM
] |= ANALOG_PLL_LOCK
;
46 s
->analog
[ANALOG_PLL_DDR
] |= ANALOG_PLL_LOCK
;
47 s
->analog
[ANALOG_PLL_480
] |= ANALOG_PLL_LOCK
;
48 s
->analog
[ANALOG_PLL_480A
] |= ANALOG_PLL_LOCK
;
49 s
->analog
[ANALOG_PLL_480B
] |= ANALOG_PLL_LOCK
;
50 s
->analog
[ANALOG_PLL_ENET
] |= ANALOG_PLL_LOCK
;
51 s
->analog
[ANALOG_PLL_AUDIO
] |= ANALOG_PLL_LOCK
;
52 s
->analog
[ANALOG_PLL_VIDEO
] |= ANALOG_PLL_LOCK
;
53 s
->analog
[ANALOG_PLL_MISC0
] |= ANALOG_PLL_LOCK
;
56 * Since I couldn't find any info about this in the reference
57 * manual the value of this register is based strictly on matching
58 * what Linux kernel expects it to be.
60 s
->analog
[ANALOG_DIGPROG
] = 0x720000;
62 * Set revision to be 1.0 (Arbitrary choice, no particular
65 s
->analog
[ANALOG_DIGPROG
] |= 0x000010;
68 static void imx7_ccm_reset(DeviceState
*dev
)
70 IMX7CCMState
*s
= IMX7_CCM(dev
);
72 memset(s
->ccm
, 0, sizeof(s
->ccm
));
75 #define CCM_INDEX(offset) (((offset) & ~(hwaddr)0xF) / sizeof(uint32_t))
76 #define CCM_BITOP(offset) ((offset) & (hwaddr)0xF)
79 CCM_BITOP_NONE
= 0x00,
85 static uint64_t imx7_set_clr_tog_read(void *opaque
, hwaddr offset
,
88 const uint32_t *mmio
= opaque
;
90 return mmio
[CCM_INDEX(offset
)];
93 static void imx7_set_clr_tog_write(void *opaque
, hwaddr offset
,
94 uint64_t value
, unsigned size
)
96 const uint8_t bitop
= CCM_BITOP(offset
);
97 const uint32_t index
= CCM_INDEX(offset
);
98 uint32_t *mmio
= opaque
;
105 mmio
[index
] |= value
;
108 mmio
[index
] &= ~value
;
111 mmio
[index
] ^= value
;
116 static const struct MemoryRegionOps imx7_set_clr_tog_ops
= {
117 .read
= imx7_set_clr_tog_read
,
118 .write
= imx7_set_clr_tog_write
,
119 .endianness
= DEVICE_NATIVE_ENDIAN
,
122 * Our device would not work correctly if the guest was doing
123 * unaligned access. This might not be a limitation on the real
124 * device but in practice there is no reason for a guest to access
125 * this device unaligned.
127 .min_access_size
= 4,
128 .max_access_size
= 4,
133 static const struct MemoryRegionOps imx7_digprog_ops
= {
134 .read
= imx7_set_clr_tog_read
,
135 .endianness
= DEVICE_NATIVE_ENDIAN
,
137 .min_access_size
= 4,
138 .max_access_size
= 4,
143 static void imx7_ccm_init(Object
*obj
)
145 SysBusDevice
*sd
= SYS_BUS_DEVICE(obj
);
146 IMX7CCMState
*s
= IMX7_CCM(obj
);
148 memory_region_init_io(&s
->iomem
,
150 &imx7_set_clr_tog_ops
,
152 TYPE_IMX7_CCM
".ccm",
155 sysbus_init_mmio(sd
, &s
->iomem
);
158 static void imx7_analog_init(Object
*obj
)
160 SysBusDevice
*sd
= SYS_BUS_DEVICE(obj
);
161 IMX7AnalogState
*s
= IMX7_ANALOG(obj
);
163 memory_region_init(&s
->mmio
.container
, obj
, TYPE_IMX7_ANALOG
,
166 memory_region_init_io(&s
->mmio
.analog
,
168 &imx7_set_clr_tog_ops
,
173 memory_region_add_subregion(&s
->mmio
.container
,
174 0x60, &s
->mmio
.analog
);
176 memory_region_init_io(&s
->mmio
.pmu
,
178 &imx7_set_clr_tog_ops
,
180 TYPE_IMX7_ANALOG
".pmu",
183 memory_region_add_subregion(&s
->mmio
.container
,
184 0x200, &s
->mmio
.pmu
);
186 memory_region_init_io(&s
->mmio
.digprog
,
189 &s
->analog
[ANALOG_DIGPROG
],
190 TYPE_IMX7_ANALOG
".digprog",
193 memory_region_add_subregion_overlap(&s
->mmio
.container
,
194 0x800, &s
->mmio
.digprog
, 10);
197 sysbus_init_mmio(sd
, &s
->mmio
.container
);
200 static const VMStateDescription vmstate_imx7_ccm
= {
201 .name
= TYPE_IMX7_CCM
,
203 .minimum_version_id
= 1,
204 .fields
= (VMStateField
[]) {
205 VMSTATE_UINT32_ARRAY(ccm
, IMX7CCMState
, CCM_MAX
),
206 VMSTATE_END_OF_LIST()
210 static uint32_t imx7_ccm_get_clock_frequency(IMXCCMState
*dev
, IMXClk clock
)
213 * This function is "consumed" by GPT emulation code, however on
214 * i.MX7 each GPT block can have their own clock root. This means
215 * that this functions needs somehow to know requester's identity
216 * and the way to pass it: be it via additional IMXClk constants
217 * or by adding another argument to this method needs to be
220 qemu_log_mask(LOG_GUEST_ERROR
, "[%s]%s: Not implemented\n",
221 TYPE_IMX7_CCM
, __func__
);
225 static void imx7_ccm_class_init(ObjectClass
*klass
, void *data
)
227 DeviceClass
*dc
= DEVICE_CLASS(klass
);
228 IMXCCMClass
*ccm
= IMX_CCM_CLASS(klass
);
230 dc
->reset
= imx7_ccm_reset
;
231 dc
->vmsd
= &vmstate_imx7_ccm
;
232 dc
->desc
= "i.MX7 Clock Control Module";
234 ccm
->get_clock_frequency
= imx7_ccm_get_clock_frequency
;
237 static const TypeInfo imx7_ccm_info
= {
238 .name
= TYPE_IMX7_CCM
,
239 .parent
= TYPE_IMX_CCM
,
240 .instance_size
= sizeof(IMX7CCMState
),
241 .instance_init
= imx7_ccm_init
,
242 .class_init
= imx7_ccm_class_init
,
245 static const VMStateDescription vmstate_imx7_analog
= {
246 .name
= TYPE_IMX7_ANALOG
,
248 .minimum_version_id
= 1,
249 .fields
= (VMStateField
[]) {
250 VMSTATE_UINT32_ARRAY(analog
, IMX7AnalogState
, ANALOG_MAX
),
251 VMSTATE_UINT32_ARRAY(pmu
, IMX7AnalogState
, PMU_MAX
),
252 VMSTATE_END_OF_LIST()
256 static void imx7_analog_class_init(ObjectClass
*klass
, void *data
)
258 DeviceClass
*dc
= DEVICE_CLASS(klass
);
260 dc
->reset
= imx7_analog_reset
;
261 dc
->vmsd
= &vmstate_imx7_analog
;
262 dc
->desc
= "i.MX7 Analog Module";
265 static const TypeInfo imx7_analog_info
= {
266 .name
= TYPE_IMX7_ANALOG
,
267 .parent
= TYPE_SYS_BUS_DEVICE
,
268 .instance_size
= sizeof(IMX7AnalogState
),
269 .instance_init
= imx7_analog_init
,
270 .class_init
= imx7_analog_class_init
,
273 static void imx7_ccm_register_type(void)
275 type_register_static(&imx7_ccm_info
);
276 type_register_static(&imx7_analog_info
);
278 type_init(imx7_ccm_register_type
)