master
c 170 lines 6.13 KB
Raw
1 /*
2 * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
3 *
4 * i.MX 8M Plus ANALOG IP block emulation code
5 *
6 * Based on hw/misc/imx7_ccm.c
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "qemu/osdep.h"
12 #include "qemu/log.h"
13
14 #include "hw/misc/imx8mp_analog.h"
15 #include "hw/core/qdev-properties.h"
16 #include "migration/vmstate.h"
17
18 #define ANALOG_PLL_LOCK BIT(31)
19
20 static void imx8mp_analog_reset(DeviceState *dev)
21 {
22 IMX8MPAnalogState *s = IMX8MP_ANALOG(dev);
23
24 memset(s->analog, 0, sizeof(s->analog));
25
26 s->analog[ANALOG_AUDIO_PLL1_GEN_CTRL] = 0x00002010;
27 s->analog[ANALOG_AUDIO_PLL1_FDIV_CTL0] = 0x00145032;
28 s->analog[ANALOG_AUDIO_PLL1_FDIV_CTL1] = 0x00000000;
29 s->analog[ANALOG_AUDIO_PLL1_SSCG_CTRL] = 0x00000000;
30 s->analog[ANALOG_AUDIO_PLL1_MNIT_CTRL] = 0x00100103;
31 s->analog[ANALOG_AUDIO_PLL2_GEN_CTRL] = 0x00002010;
32 s->analog[ANALOG_AUDIO_PLL2_FDIV_CTL0] = 0x00145032;
33 s->analog[ANALOG_AUDIO_PLL2_FDIV_CTL1] = 0x00000000;
34 s->analog[ANALOG_AUDIO_PLL2_SSCG_CTRL] = 0x00000000;
35 s->analog[ANALOG_AUDIO_PLL2_MNIT_CTRL] = 0x00100103;
36 s->analog[ANALOG_VIDEO_PLL1_GEN_CTRL] = 0x00002010;
37 s->analog[ANALOG_VIDEO_PLL1_FDIV_CTL0] = 0x00145032;
38 s->analog[ANALOG_VIDEO_PLL1_FDIV_CTL1] = 0x00000000;
39 s->analog[ANALOG_VIDEO_PLL1_SSCG_CTRL] = 0x00000000;
40 s->analog[ANALOG_VIDEO_PLL1_MNIT_CTRL] = 0x00100103;
41 s->analog[ANALOG_DRAM_PLL_GEN_CTRL] = 0x00002010;
42 s->analog[ANALOG_DRAM_PLL_FDIV_CTL0] = 0x0012c032;
43 s->analog[ANALOG_DRAM_PLL_FDIV_CTL1] = 0x00000000;
44 s->analog[ANALOG_DRAM_PLL_SSCG_CTRL] = 0x00000000;
45 s->analog[ANALOG_DRAM_PLL_MNIT_CTRL] = 0x00100103;
46 s->analog[ANALOG_GPU_PLL_GEN_CTRL] = 0x00000810;
47 s->analog[ANALOG_GPU_PLL_FDIV_CTL0] = 0x000c8031;
48 s->analog[ANALOG_GPU_PLL_LOCKD_CTRL] = 0x0010003f;
49 s->analog[ANALOG_GPU_PLL_MNIT_CTRL] = 0x00280081;
50 s->analog[ANALOG_VPU_PLL_GEN_CTRL] = 0x00000810;
51 s->analog[ANALOG_VPU_PLL_FDIV_CTL0] = 0x0012c032;
52 s->analog[ANALOG_VPU_PLL_LOCKD_CTRL] = 0x0010003f;
53 s->analog[ANALOG_VPU_PLL_MNIT_CTRL] = 0x00280081;
54 s->analog[ANALOG_ARM_PLL_GEN_CTRL] = 0x00000810;
55
56 /* Use property value instead of hardcoded */
57 s->analog[ANALOG_ARM_PLL_FDIV_CTL0] = s->arm_pll_fdiv_ctl0_reset;
58
59 s->analog[ANALOG_ARM_PLL_LOCKD_CTRL] = 0x0010003f;
60 s->analog[ANALOG_ARM_PLL_MNIT_CTRL] = 0x00280081;
61 s->analog[ANALOG_SYS_PLL1_GEN_CTRL] = 0x0aaaa810;
62 s->analog[ANALOG_SYS_PLL1_FDIV_CTL0] = 0x00190032;
63 s->analog[ANALOG_SYS_PLL1_LOCKD_CTRL] = 0x0010003f;
64 s->analog[ANALOG_SYS_PLL1_MNIT_CTRL] = 0x00280081;
65 s->analog[ANALOG_SYS_PLL2_GEN_CTRL] = 0x0aaaa810;
66 s->analog[ANALOG_SYS_PLL2_FDIV_CTL0] = 0x000fa031;
67 s->analog[ANALOG_SYS_PLL2_LOCKD_CTRL] = 0x0010003f;
68 s->analog[ANALOG_SYS_PLL2_MNIT_CTRL] = 0x00280081;
69 s->analog[ANALOG_SYS_PLL3_GEN_CTRL] = 0x00000810;
70 s->analog[ANALOG_SYS_PLL3_FDIV_CTL0] = 0x000fa031;
71 s->analog[ANALOG_SYS_PLL3_LOCKD_CTRL] = 0x0010003f;
72 s->analog[ANALOG_SYS_PLL3_MNIT_CTRL] = 0x00280081;
73 s->analog[ANALOG_OSC_MISC_CFG] = 0x00000000;
74 s->analog[ANALOG_ANAMIX_PLL_MNIT_CTL] = 0x00000000;
75 s->analog[ANALOG_DIGPROG] = 0x00824010;
76
77 /* all PLLs need to be locked */
78 s->analog[ANALOG_AUDIO_PLL1_GEN_CTRL] |= ANALOG_PLL_LOCK;
79 s->analog[ANALOG_AUDIO_PLL2_GEN_CTRL] |= ANALOG_PLL_LOCK;
80 s->analog[ANALOG_VIDEO_PLL1_GEN_CTRL] |= ANALOG_PLL_LOCK;
81 s->analog[ANALOG_DRAM_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
82 s->analog[ANALOG_GPU_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
83 s->analog[ANALOG_VPU_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
84 s->analog[ANALOG_ARM_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
85 s->analog[ANALOG_SYS_PLL1_GEN_CTRL] |= ANALOG_PLL_LOCK;
86 s->analog[ANALOG_SYS_PLL2_GEN_CTRL] |= ANALOG_PLL_LOCK;
87 s->analog[ANALOG_SYS_PLL3_GEN_CTRL] |= ANALOG_PLL_LOCK;
88 }
89
90 static uint64_t imx8mp_analog_read(void *opaque, hwaddr offset, unsigned size)
91 {
92 IMX8MPAnalogState *s = opaque;
93
94 return s->analog[offset >> 2];
95 }
96
97 static void imx8mp_analog_write(void *opaque, hwaddr offset,
98 uint64_t value, unsigned size)
99 {
100 IMX8MPAnalogState *s = opaque;
101
102 if (offset >> 2 == ANALOG_DIGPROG) {
103 qemu_log_mask(LOG_GUEST_ERROR,
104 "Guest write to read-only ANALOG_DIGPROG register\n");
105 } else {
106 s->analog[offset >> 2] = value;
107 }
108 }
109
110 static const struct MemoryRegionOps imx8mp_analog_ops = {
111 .read = imx8mp_analog_read,
112 .write = imx8mp_analog_write,
113 .endianness = DEVICE_NATIVE_ENDIAN,
114 .impl = {
115 .min_access_size = 4,
116 .max_access_size = 4,
117 .unaligned = false,
118 },
119 };
120
121 static void imx8mp_analog_init(Object *obj)
122 {
123 IMX8MPAnalogState *s = IMX8MP_ANALOG(obj);
124 SysBusDevice *sd = SYS_BUS_DEVICE(obj);
125
126 memory_region_init(&s->mmio.container, obj, TYPE_IMX8MP_ANALOG, 0x10000);
127
128 memory_region_init_io(&s->mmio.analog, obj, &imx8mp_analog_ops, s,
129 TYPE_IMX8MP_ANALOG, sizeof(s->analog));
130 memory_region_add_subregion(&s->mmio.container, 0, &s->mmio.analog);
131
132 sysbus_init_mmio(sd, &s->mmio.container);
133 }
134
135 static const VMStateDescription imx8mp_analog_vmstate = {
136 .name = TYPE_IMX8MP_ANALOG,
137 .version_id = 1,
138 .minimum_version_id = 1,
139 .fields = (const VMStateField[]) {
140 VMSTATE_UINT32_ARRAY(analog, IMX8MPAnalogState, ANALOG_MAX),
141 VMSTATE_END_OF_LIST()
142 },
143 };
144
145 static const Property imx8mp_analog_properties[] = {
146 DEFINE_PROP_UINT32("arm-pll-fdiv-ctl0-reset", IMX8MPAnalogState,
147 arm_pll_fdiv_ctl0_reset, 0x000fa031), /* imx8mp default */
148 };
149
150 static void imx8mp_analog_class_init(ObjectClass *klass, const void *data)
151 {
152 DeviceClass *dc = DEVICE_CLASS(klass);
153
154 device_class_set_legacy_reset(dc, imx8mp_analog_reset);
155 device_class_set_props(dc, imx8mp_analog_properties);
156 dc->vmsd = &imx8mp_analog_vmstate;
157 dc->desc = "i.MX 8M Plus Analog Module";
158 }
159
160 static const TypeInfo imx8mp_analog_types[] = {
161 {
162 .name = TYPE_IMX8MP_ANALOG,
163 .parent = TYPE_SYS_BUS_DEVICE,
164 .instance_size = sizeof(IMX8MPAnalogState),
165 .instance_init = imx8mp_analog_init,
166 .class_init = imx8mp_analog_class_init,
167 }
168 };
169
170 DEFINE_TYPES(imx8mp_analog_types);