xref: /qemu/hw/misc/imx8mp_analog.c (revision 06b40d250ecfa1633209c2e431a7a38acfd03a98)
186c2dff9SBernhard Beschow /*
286c2dff9SBernhard Beschow  * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
386c2dff9SBernhard Beschow  *
486c2dff9SBernhard Beschow  * i.MX 8M Plus ANALOG IP block emulation code
586c2dff9SBernhard Beschow  *
686c2dff9SBernhard Beschow  * Based on hw/misc/imx7_ccm.c
786c2dff9SBernhard Beschow  *
886c2dff9SBernhard Beschow  * SPDX-License-Identifier: GPL-2.0-or-later
986c2dff9SBernhard Beschow  */
1086c2dff9SBernhard Beschow 
1186c2dff9SBernhard Beschow #include "qemu/osdep.h"
1286c2dff9SBernhard Beschow #include "qemu/log.h"
1386c2dff9SBernhard Beschow 
1486c2dff9SBernhard Beschow #include "hw/misc/imx8mp_analog.h"
1586c2dff9SBernhard Beschow #include "migration/vmstate.h"
1686c2dff9SBernhard Beschow 
1786c2dff9SBernhard Beschow #define ANALOG_PLL_LOCK BIT(31)
1886c2dff9SBernhard Beschow 
imx8mp_analog_reset(DeviceState * dev)1986c2dff9SBernhard Beschow static void imx8mp_analog_reset(DeviceState *dev)
2086c2dff9SBernhard Beschow {
2186c2dff9SBernhard Beschow     IMX8MPAnalogState *s = IMX8MP_ANALOG(dev);
2286c2dff9SBernhard Beschow 
2386c2dff9SBernhard Beschow     memset(s->analog, 0, sizeof(s->analog));
2486c2dff9SBernhard Beschow 
2586c2dff9SBernhard Beschow     s->analog[ANALOG_AUDIO_PLL1_GEN_CTRL] = 0x00002010;
2686c2dff9SBernhard Beschow     s->analog[ANALOG_AUDIO_PLL1_FDIV_CTL0] = 0x00145032;
2786c2dff9SBernhard Beschow     s->analog[ANALOG_AUDIO_PLL1_FDIV_CTL1] = 0x00000000;
2886c2dff9SBernhard Beschow     s->analog[ANALOG_AUDIO_PLL1_SSCG_CTRL] = 0x00000000;
2986c2dff9SBernhard Beschow     s->analog[ANALOG_AUDIO_PLL1_MNIT_CTRL] = 0x00100103;
3086c2dff9SBernhard Beschow     s->analog[ANALOG_AUDIO_PLL2_GEN_CTRL] = 0x00002010;
3186c2dff9SBernhard Beschow     s->analog[ANALOG_AUDIO_PLL2_FDIV_CTL0] = 0x00145032;
3286c2dff9SBernhard Beschow     s->analog[ANALOG_AUDIO_PLL2_FDIV_CTL1] = 0x00000000;
3386c2dff9SBernhard Beschow     s->analog[ANALOG_AUDIO_PLL2_SSCG_CTRL] = 0x00000000;
3486c2dff9SBernhard Beschow     s->analog[ANALOG_AUDIO_PLL2_MNIT_CTRL] = 0x00100103;
3586c2dff9SBernhard Beschow     s->analog[ANALOG_VIDEO_PLL1_GEN_CTRL] = 0x00002010;
3686c2dff9SBernhard Beschow     s->analog[ANALOG_VIDEO_PLL1_FDIV_CTL0] = 0x00145032;
3786c2dff9SBernhard Beschow     s->analog[ANALOG_VIDEO_PLL1_FDIV_CTL1] = 0x00000000;
3886c2dff9SBernhard Beschow     s->analog[ANALOG_VIDEO_PLL1_SSCG_CTRL] = 0x00000000;
3986c2dff9SBernhard Beschow     s->analog[ANALOG_VIDEO_PLL1_MNIT_CTRL] = 0x00100103;
4086c2dff9SBernhard Beschow     s->analog[ANALOG_DRAM_PLL_GEN_CTRL] = 0x00002010;
4186c2dff9SBernhard Beschow     s->analog[ANALOG_DRAM_PLL_FDIV_CTL0] = 0x0012c032;
4286c2dff9SBernhard Beschow     s->analog[ANALOG_DRAM_PLL_FDIV_CTL1] = 0x00000000;
4386c2dff9SBernhard Beschow     s->analog[ANALOG_DRAM_PLL_SSCG_CTRL] = 0x00000000;
4486c2dff9SBernhard Beschow     s->analog[ANALOG_DRAM_PLL_MNIT_CTRL] = 0x00100103;
4586c2dff9SBernhard Beschow     s->analog[ANALOG_GPU_PLL_GEN_CTRL] = 0x00000810;
4686c2dff9SBernhard Beschow     s->analog[ANALOG_GPU_PLL_FDIV_CTL0] = 0x000c8031;
4786c2dff9SBernhard Beschow     s->analog[ANALOG_GPU_PLL_LOCKD_CTRL] = 0x0010003f;
4886c2dff9SBernhard Beschow     s->analog[ANALOG_GPU_PLL_MNIT_CTRL] = 0x00280081;
4986c2dff9SBernhard Beschow     s->analog[ANALOG_VPU_PLL_GEN_CTRL] = 0x00000810;
5086c2dff9SBernhard Beschow     s->analog[ANALOG_VPU_PLL_FDIV_CTL0] = 0x0012c032;
5186c2dff9SBernhard Beschow     s->analog[ANALOG_VPU_PLL_LOCKD_CTRL] = 0x0010003f;
5286c2dff9SBernhard Beschow     s->analog[ANALOG_VPU_PLL_MNIT_CTRL] = 0x00280081;
5386c2dff9SBernhard Beschow     s->analog[ANALOG_ARM_PLL_GEN_CTRL] = 0x00000810;
5486c2dff9SBernhard Beschow     s->analog[ANALOG_ARM_PLL_FDIV_CTL0] = 0x000fa031;
5586c2dff9SBernhard Beschow     s->analog[ANALOG_ARM_PLL_LOCKD_CTRL] = 0x0010003f;
5686c2dff9SBernhard Beschow     s->analog[ANALOG_ARM_PLL_MNIT_CTRL] = 0x00280081;
5786c2dff9SBernhard Beschow     s->analog[ANALOG_SYS_PLL1_GEN_CTRL] = 0x0aaaa810;
5886c2dff9SBernhard Beschow     s->analog[ANALOG_SYS_PLL1_FDIV_CTL0] = 0x00190032;
5986c2dff9SBernhard Beschow     s->analog[ANALOG_SYS_PLL1_LOCKD_CTRL] = 0x0010003f;
6086c2dff9SBernhard Beschow     s->analog[ANALOG_SYS_PLL1_MNIT_CTRL] = 0x00280081;
6186c2dff9SBernhard Beschow     s->analog[ANALOG_SYS_PLL2_GEN_CTRL] = 0x0aaaa810;
6286c2dff9SBernhard Beschow     s->analog[ANALOG_SYS_PLL2_FDIV_CTL0] = 0x000fa031;
6386c2dff9SBernhard Beschow     s->analog[ANALOG_SYS_PLL2_LOCKD_CTRL] = 0x0010003f;
6486c2dff9SBernhard Beschow     s->analog[ANALOG_SYS_PLL2_MNIT_CTRL] = 0x00280081;
6586c2dff9SBernhard Beschow     s->analog[ANALOG_SYS_PLL3_GEN_CTRL] = 0x00000810;
6686c2dff9SBernhard Beschow     s->analog[ANALOG_SYS_PLL3_FDIV_CTL0] = 0x000fa031;
6786c2dff9SBernhard Beschow     s->analog[ANALOG_SYS_PLL3_LOCKD_CTRL] = 0x0010003f;
6886c2dff9SBernhard Beschow     s->analog[ANALOG_SYS_PLL3_MNIT_CTRL] = 0x00280081;
6986c2dff9SBernhard Beschow     s->analog[ANALOG_OSC_MISC_CFG] = 0x00000000;
7086c2dff9SBernhard Beschow     s->analog[ANALOG_ANAMIX_PLL_MNIT_CTL] = 0x00000000;
7186c2dff9SBernhard Beschow     s->analog[ANALOG_DIGPROG] = 0x00824010;
7286c2dff9SBernhard Beschow 
7386c2dff9SBernhard Beschow     /* all PLLs need to be locked */
7486c2dff9SBernhard Beschow     s->analog[ANALOG_AUDIO_PLL1_GEN_CTRL] |= ANALOG_PLL_LOCK;
7586c2dff9SBernhard Beschow     s->analog[ANALOG_AUDIO_PLL2_GEN_CTRL] |= ANALOG_PLL_LOCK;
7686c2dff9SBernhard Beschow     s->analog[ANALOG_VIDEO_PLL1_GEN_CTRL] |= ANALOG_PLL_LOCK;
7786c2dff9SBernhard Beschow     s->analog[ANALOG_DRAM_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
7886c2dff9SBernhard Beschow     s->analog[ANALOG_GPU_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
7986c2dff9SBernhard Beschow     s->analog[ANALOG_VPU_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
8086c2dff9SBernhard Beschow     s->analog[ANALOG_ARM_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
8186c2dff9SBernhard Beschow     s->analog[ANALOG_SYS_PLL1_GEN_CTRL] |= ANALOG_PLL_LOCK;
8286c2dff9SBernhard Beschow     s->analog[ANALOG_SYS_PLL2_GEN_CTRL] |= ANALOG_PLL_LOCK;
8386c2dff9SBernhard Beschow     s->analog[ANALOG_SYS_PLL3_GEN_CTRL] |= ANALOG_PLL_LOCK;
8486c2dff9SBernhard Beschow }
8586c2dff9SBernhard Beschow 
imx8mp_analog_read(void * opaque,hwaddr offset,unsigned size)8686c2dff9SBernhard Beschow static uint64_t imx8mp_analog_read(void *opaque, hwaddr offset, unsigned size)
8786c2dff9SBernhard Beschow {
8886c2dff9SBernhard Beschow     IMX8MPAnalogState *s = opaque;
8986c2dff9SBernhard Beschow 
9086c2dff9SBernhard Beschow     return s->analog[offset >> 2];
9186c2dff9SBernhard Beschow }
9286c2dff9SBernhard Beschow 
imx8mp_analog_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)9386c2dff9SBernhard Beschow static void imx8mp_analog_write(void *opaque, hwaddr offset,
9486c2dff9SBernhard Beschow                                 uint64_t value, unsigned size)
9586c2dff9SBernhard Beschow {
9686c2dff9SBernhard Beschow     IMX8MPAnalogState *s = opaque;
9786c2dff9SBernhard Beschow 
9886c2dff9SBernhard Beschow     if (offset >> 2 == ANALOG_DIGPROG) {
9986c2dff9SBernhard Beschow         qemu_log_mask(LOG_GUEST_ERROR,
10086c2dff9SBernhard Beschow                       "Guest write to read-only ANALOG_DIGPROG register\n");
10186c2dff9SBernhard Beschow     } else {
10286c2dff9SBernhard Beschow         s->analog[offset >> 2] = value;
10386c2dff9SBernhard Beschow     }
10486c2dff9SBernhard Beschow }
10586c2dff9SBernhard Beschow 
10686c2dff9SBernhard Beschow static const struct MemoryRegionOps imx8mp_analog_ops = {
10786c2dff9SBernhard Beschow     .read = imx8mp_analog_read,
10886c2dff9SBernhard Beschow     .write = imx8mp_analog_write,
10986c2dff9SBernhard Beschow     .endianness = DEVICE_NATIVE_ENDIAN,
11086c2dff9SBernhard Beschow     .impl = {
11186c2dff9SBernhard Beschow         .min_access_size = 4,
11286c2dff9SBernhard Beschow         .max_access_size = 4,
11386c2dff9SBernhard Beschow         .unaligned = false,
11486c2dff9SBernhard Beschow     },
11586c2dff9SBernhard Beschow };
11686c2dff9SBernhard Beschow 
imx8mp_analog_init(Object * obj)11786c2dff9SBernhard Beschow static void imx8mp_analog_init(Object *obj)
11886c2dff9SBernhard Beschow {
11986c2dff9SBernhard Beschow     IMX8MPAnalogState *s = IMX8MP_ANALOG(obj);
12086c2dff9SBernhard Beschow     SysBusDevice *sd = SYS_BUS_DEVICE(obj);
12186c2dff9SBernhard Beschow 
12286c2dff9SBernhard Beschow     memory_region_init(&s->mmio.container, obj, TYPE_IMX8MP_ANALOG, 0x10000);
12386c2dff9SBernhard Beschow 
12486c2dff9SBernhard Beschow     memory_region_init_io(&s->mmio.analog, obj, &imx8mp_analog_ops, s,
12586c2dff9SBernhard Beschow                           TYPE_IMX8MP_ANALOG, sizeof(s->analog));
12686c2dff9SBernhard Beschow     memory_region_add_subregion(&s->mmio.container, 0, &s->mmio.analog);
12786c2dff9SBernhard Beschow 
12886c2dff9SBernhard Beschow     sysbus_init_mmio(sd, &s->mmio.container);
12986c2dff9SBernhard Beschow }
13086c2dff9SBernhard Beschow 
13186c2dff9SBernhard Beschow static const VMStateDescription imx8mp_analog_vmstate = {
13286c2dff9SBernhard Beschow     .name = TYPE_IMX8MP_ANALOG,
13386c2dff9SBernhard Beschow     .version_id = 1,
13486c2dff9SBernhard Beschow     .minimum_version_id = 1,
13586c2dff9SBernhard Beschow     .fields = (const VMStateField[]) {
13686c2dff9SBernhard Beschow         VMSTATE_UINT32_ARRAY(analog, IMX8MPAnalogState, ANALOG_MAX),
13786c2dff9SBernhard Beschow         VMSTATE_END_OF_LIST()
13886c2dff9SBernhard Beschow     },
13986c2dff9SBernhard Beschow };
14086c2dff9SBernhard Beschow 
imx8mp_analog_class_init(ObjectClass * klass,const void * data)141*12d1a768SPhilippe Mathieu-Daudé static void imx8mp_analog_class_init(ObjectClass *klass, const void *data)
14286c2dff9SBernhard Beschow {
14386c2dff9SBernhard Beschow     DeviceClass *dc = DEVICE_CLASS(klass);
14486c2dff9SBernhard Beschow 
14586c2dff9SBernhard Beschow     device_class_set_legacy_reset(dc, imx8mp_analog_reset);
14686c2dff9SBernhard Beschow     dc->vmsd  = &imx8mp_analog_vmstate;
14786c2dff9SBernhard Beschow     dc->desc  = "i.MX 8M Plus Analog Module";
14886c2dff9SBernhard Beschow }
14986c2dff9SBernhard Beschow 
15086c2dff9SBernhard Beschow static const TypeInfo imx8mp_analog_types[] = {
15186c2dff9SBernhard Beschow     {
15286c2dff9SBernhard Beschow         .name          = TYPE_IMX8MP_ANALOG,
15386c2dff9SBernhard Beschow         .parent        = TYPE_SYS_BUS_DEVICE,
15486c2dff9SBernhard Beschow         .instance_size = sizeof(IMX8MPAnalogState),
15586c2dff9SBernhard Beschow         .instance_init = imx8mp_analog_init,
15686c2dff9SBernhard Beschow         .class_init    = imx8mp_analog_class_init,
15786c2dff9SBernhard Beschow     }
15886c2dff9SBernhard Beschow };
15986c2dff9SBernhard Beschow 
16086c2dff9SBernhard Beschow DEFINE_TYPES(imx8mp_analog_types);
161