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