1*a017f53eSJackson Donaldson /* 2*a017f53eSJackson Donaldson * MAX78000 Global Control Registers 3*a017f53eSJackson Donaldson * 4*a017f53eSJackson Donaldson * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com> 5*a017f53eSJackson Donaldson * 6*a017f53eSJackson Donaldson * SPDX-License-Identifier: GPL-2.0-or-later 7*a017f53eSJackson Donaldson */ 8*a017f53eSJackson Donaldson 9*a017f53eSJackson Donaldson #include "qemu/osdep.h" 10*a017f53eSJackson Donaldson #include "qemu/log.h" 11*a017f53eSJackson Donaldson #include "trace.h" 12*a017f53eSJackson Donaldson #include "hw/irq.h" 13*a017f53eSJackson Donaldson #include "system/runstate.h" 14*a017f53eSJackson Donaldson #include "migration/vmstate.h" 15*a017f53eSJackson Donaldson #include "hw/qdev-properties.h" 16*a017f53eSJackson Donaldson #include "hw/char/max78000_uart.h" 17*a017f53eSJackson Donaldson #include "hw/misc/max78000_gcr.h" 18*a017f53eSJackson Donaldson 19*a017f53eSJackson Donaldson 20*a017f53eSJackson Donaldson static void max78000_gcr_reset_hold(Object *obj, ResetType type) 21*a017f53eSJackson Donaldson { 22*a017f53eSJackson Donaldson DeviceState *dev = DEVICE(obj); 23*a017f53eSJackson Donaldson Max78000GcrState *s = MAX78000_GCR(dev); 24*a017f53eSJackson Donaldson s->sysctrl = 0x21002; 25*a017f53eSJackson Donaldson s->rst0 = 0; 26*a017f53eSJackson Donaldson /* All clocks are always ready */ 27*a017f53eSJackson Donaldson s->clkctrl = 0x3e140008; 28*a017f53eSJackson Donaldson s->pm = 0x3f000; 29*a017f53eSJackson Donaldson s->pclkdiv = 0; 30*a017f53eSJackson Donaldson s->pclkdis0 = 0xffffffff; 31*a017f53eSJackson Donaldson s->memctrl = 0x5; 32*a017f53eSJackson Donaldson s->memz = 0; 33*a017f53eSJackson Donaldson s->sysst = 0; 34*a017f53eSJackson Donaldson s->rst1 = 0; 35*a017f53eSJackson Donaldson s->pckdis1 = 0xffffffff; 36*a017f53eSJackson Donaldson s->eventen = 0; 37*a017f53eSJackson Donaldson s->revision = 0xa1; 38*a017f53eSJackson Donaldson s->sysie = 0; 39*a017f53eSJackson Donaldson s->eccerr = 0; 40*a017f53eSJackson Donaldson s->ecced = 0; 41*a017f53eSJackson Donaldson s->eccie = 0; 42*a017f53eSJackson Donaldson s->eccaddr = 0; 43*a017f53eSJackson Donaldson } 44*a017f53eSJackson Donaldson 45*a017f53eSJackson Donaldson static uint64_t max78000_gcr_read(void *opaque, hwaddr addr, 46*a017f53eSJackson Donaldson unsigned int size) 47*a017f53eSJackson Donaldson { 48*a017f53eSJackson Donaldson Max78000GcrState *s = opaque; 49*a017f53eSJackson Donaldson 50*a017f53eSJackson Donaldson switch (addr) { 51*a017f53eSJackson Donaldson case SYSCTRL: 52*a017f53eSJackson Donaldson return s->sysctrl; 53*a017f53eSJackson Donaldson 54*a017f53eSJackson Donaldson case RST0: 55*a017f53eSJackson Donaldson return s->rst0; 56*a017f53eSJackson Donaldson 57*a017f53eSJackson Donaldson case CLKCTRL: 58*a017f53eSJackson Donaldson return s->clkctrl; 59*a017f53eSJackson Donaldson 60*a017f53eSJackson Donaldson case PM: 61*a017f53eSJackson Donaldson return s->pm; 62*a017f53eSJackson Donaldson 63*a017f53eSJackson Donaldson case PCLKDIV: 64*a017f53eSJackson Donaldson return s->pclkdiv; 65*a017f53eSJackson Donaldson 66*a017f53eSJackson Donaldson case PCLKDIS0: 67*a017f53eSJackson Donaldson return s->pclkdis0; 68*a017f53eSJackson Donaldson 69*a017f53eSJackson Donaldson case MEMCTRL: 70*a017f53eSJackson Donaldson return s->memctrl; 71*a017f53eSJackson Donaldson 72*a017f53eSJackson Donaldson case MEMZ: 73*a017f53eSJackson Donaldson return s->memz; 74*a017f53eSJackson Donaldson 75*a017f53eSJackson Donaldson case SYSST: 76*a017f53eSJackson Donaldson return s->sysst; 77*a017f53eSJackson Donaldson 78*a017f53eSJackson Donaldson case RST1: 79*a017f53eSJackson Donaldson return s->rst1; 80*a017f53eSJackson Donaldson 81*a017f53eSJackson Donaldson case PCKDIS1: 82*a017f53eSJackson Donaldson return s->pckdis1; 83*a017f53eSJackson Donaldson 84*a017f53eSJackson Donaldson case EVENTEN: 85*a017f53eSJackson Donaldson return s->eventen; 86*a017f53eSJackson Donaldson 87*a017f53eSJackson Donaldson case REVISION: 88*a017f53eSJackson Donaldson return s->revision; 89*a017f53eSJackson Donaldson 90*a017f53eSJackson Donaldson case SYSIE: 91*a017f53eSJackson Donaldson return s->sysie; 92*a017f53eSJackson Donaldson 93*a017f53eSJackson Donaldson case ECCERR: 94*a017f53eSJackson Donaldson return s->eccerr; 95*a017f53eSJackson Donaldson 96*a017f53eSJackson Donaldson case ECCED: 97*a017f53eSJackson Donaldson return s->ecced; 98*a017f53eSJackson Donaldson 99*a017f53eSJackson Donaldson case ECCIE: 100*a017f53eSJackson Donaldson return s->eccie; 101*a017f53eSJackson Donaldson 102*a017f53eSJackson Donaldson case ECCADDR: 103*a017f53eSJackson Donaldson return s->eccaddr; 104*a017f53eSJackson Donaldson 105*a017f53eSJackson Donaldson default: 106*a017f53eSJackson Donaldson qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" 107*a017f53eSJackson Donaldson HWADDR_PRIx "\n", __func__, addr); 108*a017f53eSJackson Donaldson return 0; 109*a017f53eSJackson Donaldson 110*a017f53eSJackson Donaldson } 111*a017f53eSJackson Donaldson } 112*a017f53eSJackson Donaldson 113*a017f53eSJackson Donaldson static void max78000_gcr_write(void *opaque, hwaddr addr, 114*a017f53eSJackson Donaldson uint64_t val64, unsigned int size) 115*a017f53eSJackson Donaldson { 116*a017f53eSJackson Donaldson Max78000GcrState *s = opaque; 117*a017f53eSJackson Donaldson uint32_t val = val64; 118*a017f53eSJackson Donaldson uint8_t zero[0xc000] = {0}; 119*a017f53eSJackson Donaldson switch (addr) { 120*a017f53eSJackson Donaldson case SYSCTRL: 121*a017f53eSJackson Donaldson /* Checksum calculations always pass immediately */ 122*a017f53eSJackson Donaldson s->sysctrl = (val & 0x30000) | 0x1002; 123*a017f53eSJackson Donaldson break; 124*a017f53eSJackson Donaldson 125*a017f53eSJackson Donaldson case RST0: 126*a017f53eSJackson Donaldson if (val & SYSTEM_RESET) { 127*a017f53eSJackson Donaldson qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 128*a017f53eSJackson Donaldson } 129*a017f53eSJackson Donaldson if (val & PERIPHERAL_RESET) { 130*a017f53eSJackson Donaldson /* 131*a017f53eSJackson Donaldson * Peripheral reset resets all peripherals. The CPU 132*a017f53eSJackson Donaldson * retains its state. The GPIO, watchdog timers, AoD, 133*a017f53eSJackson Donaldson * RAM retention, and general control registers (GCR), 134*a017f53eSJackson Donaldson * including the clock configuration, are unaffected. 135*a017f53eSJackson Donaldson */ 136*a017f53eSJackson Donaldson val = UART2_RESET | UART1_RESET | UART0_RESET | 137*a017f53eSJackson Donaldson ADC_RESET | CNN_RESET | TRNG_RESET | 138*a017f53eSJackson Donaldson RTC_RESET | I2C0_RESET | SPI1_RESET | 139*a017f53eSJackson Donaldson TMR3_RESET | TMR2_RESET | TMR1_RESET | 140*a017f53eSJackson Donaldson TMR0_RESET | WDT0_RESET | DMA_RESET; 141*a017f53eSJackson Donaldson } 142*a017f53eSJackson Donaldson if (val & SOFT_RESET) { 143*a017f53eSJackson Donaldson /* Soft reset also resets GPIO */ 144*a017f53eSJackson Donaldson val = UART2_RESET | UART1_RESET | UART0_RESET | 145*a017f53eSJackson Donaldson ADC_RESET | CNN_RESET | TRNG_RESET | 146*a017f53eSJackson Donaldson RTC_RESET | I2C0_RESET | SPI1_RESET | 147*a017f53eSJackson Donaldson TMR3_RESET | TMR2_RESET | TMR1_RESET | 148*a017f53eSJackson Donaldson TMR0_RESET | GPIO1_RESET | GPIO0_RESET | 149*a017f53eSJackson Donaldson DMA_RESET; 150*a017f53eSJackson Donaldson } 151*a017f53eSJackson Donaldson if (val & UART2_RESET) { 152*a017f53eSJackson Donaldson device_cold_reset(s->uart2); 153*a017f53eSJackson Donaldson } 154*a017f53eSJackson Donaldson if (val & UART1_RESET) { 155*a017f53eSJackson Donaldson device_cold_reset(s->uart1); 156*a017f53eSJackson Donaldson } 157*a017f53eSJackson Donaldson if (val & UART0_RESET) { 158*a017f53eSJackson Donaldson device_cold_reset(s->uart0); 159*a017f53eSJackson Donaldson } 160*a017f53eSJackson Donaldson /* TODO: As other devices are implemented, add them here */ 161*a017f53eSJackson Donaldson break; 162*a017f53eSJackson Donaldson 163*a017f53eSJackson Donaldson case CLKCTRL: 164*a017f53eSJackson Donaldson s->clkctrl = val | SYSCLK_RDY; 165*a017f53eSJackson Donaldson break; 166*a017f53eSJackson Donaldson 167*a017f53eSJackson Donaldson case PM: 168*a017f53eSJackson Donaldson s->pm = val; 169*a017f53eSJackson Donaldson break; 170*a017f53eSJackson Donaldson 171*a017f53eSJackson Donaldson case PCLKDIV: 172*a017f53eSJackson Donaldson s->pclkdiv = val; 173*a017f53eSJackson Donaldson break; 174*a017f53eSJackson Donaldson 175*a017f53eSJackson Donaldson case PCLKDIS0: 176*a017f53eSJackson Donaldson s->pclkdis0 = val; 177*a017f53eSJackson Donaldson break; 178*a017f53eSJackson Donaldson 179*a017f53eSJackson Donaldson case MEMCTRL: 180*a017f53eSJackson Donaldson s->memctrl = val; 181*a017f53eSJackson Donaldson break; 182*a017f53eSJackson Donaldson 183*a017f53eSJackson Donaldson case MEMZ: 184*a017f53eSJackson Donaldson if (val & ram0) { 185*a017f53eSJackson Donaldson address_space_write(&s->sram_as, SYSRAM0_START, 186*a017f53eSJackson Donaldson MEMTXATTRS_UNSPECIFIED, zero, 0x8000); 187*a017f53eSJackson Donaldson } 188*a017f53eSJackson Donaldson if (val & ram1) { 189*a017f53eSJackson Donaldson address_space_write(&s->sram_as, SYSRAM1_START, 190*a017f53eSJackson Donaldson MEMTXATTRS_UNSPECIFIED, zero, 0x8000); 191*a017f53eSJackson Donaldson } 192*a017f53eSJackson Donaldson if (val & ram2) { 193*a017f53eSJackson Donaldson address_space_write(&s->sram_as, SYSRAM2_START, 194*a017f53eSJackson Donaldson MEMTXATTRS_UNSPECIFIED, zero, 0xC000); 195*a017f53eSJackson Donaldson } 196*a017f53eSJackson Donaldson if (val & ram3) { 197*a017f53eSJackson Donaldson address_space_write(&s->sram_as, SYSRAM3_START, 198*a017f53eSJackson Donaldson MEMTXATTRS_UNSPECIFIED, zero, 0x4000); 199*a017f53eSJackson Donaldson } 200*a017f53eSJackson Donaldson break; 201*a017f53eSJackson Donaldson 202*a017f53eSJackson Donaldson case SYSST: 203*a017f53eSJackson Donaldson s->sysst = val; 204*a017f53eSJackson Donaldson break; 205*a017f53eSJackson Donaldson 206*a017f53eSJackson Donaldson case RST1: 207*a017f53eSJackson Donaldson /* TODO: As other devices are implemented, add them here */ 208*a017f53eSJackson Donaldson s->rst1 = val; 209*a017f53eSJackson Donaldson break; 210*a017f53eSJackson Donaldson 211*a017f53eSJackson Donaldson case PCKDIS1: 212*a017f53eSJackson Donaldson s->pckdis1 = val; 213*a017f53eSJackson Donaldson break; 214*a017f53eSJackson Donaldson 215*a017f53eSJackson Donaldson case EVENTEN: 216*a017f53eSJackson Donaldson s->eventen = val; 217*a017f53eSJackson Donaldson break; 218*a017f53eSJackson Donaldson 219*a017f53eSJackson Donaldson case REVISION: 220*a017f53eSJackson Donaldson s->revision = val; 221*a017f53eSJackson Donaldson break; 222*a017f53eSJackson Donaldson 223*a017f53eSJackson Donaldson case SYSIE: 224*a017f53eSJackson Donaldson s->sysie = val; 225*a017f53eSJackson Donaldson break; 226*a017f53eSJackson Donaldson 227*a017f53eSJackson Donaldson case ECCERR: 228*a017f53eSJackson Donaldson s->eccerr = val; 229*a017f53eSJackson Donaldson break; 230*a017f53eSJackson Donaldson 231*a017f53eSJackson Donaldson case ECCED: 232*a017f53eSJackson Donaldson s->ecced = val; 233*a017f53eSJackson Donaldson break; 234*a017f53eSJackson Donaldson 235*a017f53eSJackson Donaldson case ECCIE: 236*a017f53eSJackson Donaldson s->eccie = val; 237*a017f53eSJackson Donaldson break; 238*a017f53eSJackson Donaldson 239*a017f53eSJackson Donaldson case ECCADDR: 240*a017f53eSJackson Donaldson s->eccaddr = val; 241*a017f53eSJackson Donaldson break; 242*a017f53eSJackson Donaldson 243*a017f53eSJackson Donaldson default: 244*a017f53eSJackson Donaldson qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 245*a017f53eSJackson Donaldson __func__, addr); 246*a017f53eSJackson Donaldson break; 247*a017f53eSJackson Donaldson 248*a017f53eSJackson Donaldson } 249*a017f53eSJackson Donaldson } 250*a017f53eSJackson Donaldson 251*a017f53eSJackson Donaldson static const Property max78000_gcr_properties[] = { 252*a017f53eSJackson Donaldson DEFINE_PROP_LINK("sram", Max78000GcrState, sram, 253*a017f53eSJackson Donaldson TYPE_MEMORY_REGION, MemoryRegion*), 254*a017f53eSJackson Donaldson DEFINE_PROP_LINK("uart0", Max78000GcrState, uart0, 255*a017f53eSJackson Donaldson TYPE_MAX78000_UART, DeviceState*), 256*a017f53eSJackson Donaldson DEFINE_PROP_LINK("uart1", Max78000GcrState, uart1, 257*a017f53eSJackson Donaldson TYPE_MAX78000_UART, DeviceState*), 258*a017f53eSJackson Donaldson DEFINE_PROP_LINK("uart2", Max78000GcrState, uart2, 259*a017f53eSJackson Donaldson TYPE_MAX78000_UART, DeviceState*), 260*a017f53eSJackson Donaldson }; 261*a017f53eSJackson Donaldson 262*a017f53eSJackson Donaldson static const MemoryRegionOps max78000_gcr_ops = { 263*a017f53eSJackson Donaldson .read = max78000_gcr_read, 264*a017f53eSJackson Donaldson .write = max78000_gcr_write, 265*a017f53eSJackson Donaldson .endianness = DEVICE_LITTLE_ENDIAN, 266*a017f53eSJackson Donaldson .valid.min_access_size = 4, 267*a017f53eSJackson Donaldson .valid.max_access_size = 4, 268*a017f53eSJackson Donaldson }; 269*a017f53eSJackson Donaldson 270*a017f53eSJackson Donaldson static const VMStateDescription vmstate_max78000_gcr = { 271*a017f53eSJackson Donaldson .name = TYPE_MAX78000_GCR, 272*a017f53eSJackson Donaldson .version_id = 1, 273*a017f53eSJackson Donaldson .minimum_version_id = 1, 274*a017f53eSJackson Donaldson .fields = (const VMStateField[]) { 275*a017f53eSJackson Donaldson VMSTATE_UINT32(sysctrl, Max78000GcrState), 276*a017f53eSJackson Donaldson VMSTATE_UINT32(rst0, Max78000GcrState), 277*a017f53eSJackson Donaldson VMSTATE_UINT32(clkctrl, Max78000GcrState), 278*a017f53eSJackson Donaldson VMSTATE_UINT32(pm, Max78000GcrState), 279*a017f53eSJackson Donaldson VMSTATE_UINT32(pclkdiv, Max78000GcrState), 280*a017f53eSJackson Donaldson VMSTATE_UINT32(pclkdis0, Max78000GcrState), 281*a017f53eSJackson Donaldson VMSTATE_UINT32(memctrl, Max78000GcrState), 282*a017f53eSJackson Donaldson VMSTATE_UINT32(memz, Max78000GcrState), 283*a017f53eSJackson Donaldson VMSTATE_UINT32(sysst, Max78000GcrState), 284*a017f53eSJackson Donaldson VMSTATE_UINT32(rst1, Max78000GcrState), 285*a017f53eSJackson Donaldson VMSTATE_UINT32(pckdis1, Max78000GcrState), 286*a017f53eSJackson Donaldson VMSTATE_UINT32(eventen, Max78000GcrState), 287*a017f53eSJackson Donaldson VMSTATE_UINT32(revision, Max78000GcrState), 288*a017f53eSJackson Donaldson VMSTATE_UINT32(sysie, Max78000GcrState), 289*a017f53eSJackson Donaldson VMSTATE_UINT32(eccerr, Max78000GcrState), 290*a017f53eSJackson Donaldson VMSTATE_UINT32(ecced, Max78000GcrState), 291*a017f53eSJackson Donaldson VMSTATE_UINT32(eccie, Max78000GcrState), 292*a017f53eSJackson Donaldson VMSTATE_UINT32(eccaddr, Max78000GcrState), 293*a017f53eSJackson Donaldson VMSTATE_END_OF_LIST() 294*a017f53eSJackson Donaldson } 295*a017f53eSJackson Donaldson }; 296*a017f53eSJackson Donaldson 297*a017f53eSJackson Donaldson static void max78000_gcr_init(Object *obj) 298*a017f53eSJackson Donaldson { 299*a017f53eSJackson Donaldson Max78000GcrState *s = MAX78000_GCR(obj); 300*a017f53eSJackson Donaldson 301*a017f53eSJackson Donaldson memory_region_init_io(&s->mmio, obj, &max78000_gcr_ops, s, 302*a017f53eSJackson Donaldson TYPE_MAX78000_GCR, 0x400); 303*a017f53eSJackson Donaldson sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 304*a017f53eSJackson Donaldson 305*a017f53eSJackson Donaldson } 306*a017f53eSJackson Donaldson 307*a017f53eSJackson Donaldson static void max78000_gcr_realize(DeviceState *dev, Error **errp) 308*a017f53eSJackson Donaldson { 309*a017f53eSJackson Donaldson Max78000GcrState *s = MAX78000_GCR(dev); 310*a017f53eSJackson Donaldson 311*a017f53eSJackson Donaldson address_space_init(&s->sram_as, s->sram, "sram"); 312*a017f53eSJackson Donaldson } 313*a017f53eSJackson Donaldson 314*a017f53eSJackson Donaldson static void max78000_gcr_class_init(ObjectClass *klass, const void *data) 315*a017f53eSJackson Donaldson { 316*a017f53eSJackson Donaldson DeviceClass *dc = DEVICE_CLASS(klass); 317*a017f53eSJackson Donaldson ResettableClass *rc = RESETTABLE_CLASS(klass); 318*a017f53eSJackson Donaldson 319*a017f53eSJackson Donaldson device_class_set_props(dc, max78000_gcr_properties); 320*a017f53eSJackson Donaldson 321*a017f53eSJackson Donaldson dc->realize = max78000_gcr_realize; 322*a017f53eSJackson Donaldson dc->vmsd = &vmstate_max78000_gcr; 323*a017f53eSJackson Donaldson rc->phases.hold = max78000_gcr_reset_hold; 324*a017f53eSJackson Donaldson } 325*a017f53eSJackson Donaldson 326*a017f53eSJackson Donaldson static const TypeInfo max78000_gcr_info = { 327*a017f53eSJackson Donaldson .name = TYPE_MAX78000_GCR, 328*a017f53eSJackson Donaldson .parent = TYPE_SYS_BUS_DEVICE, 329*a017f53eSJackson Donaldson .instance_size = sizeof(Max78000GcrState), 330*a017f53eSJackson Donaldson .instance_init = max78000_gcr_init, 331*a017f53eSJackson Donaldson .class_init = max78000_gcr_class_init, 332*a017f53eSJackson Donaldson }; 333*a017f53eSJackson Donaldson 334*a017f53eSJackson Donaldson static void max78000_gcr_register_types(void) 335*a017f53eSJackson Donaldson { 336*a017f53eSJackson Donaldson type_register_static(&max78000_gcr_info); 337*a017f53eSJackson Donaldson } 338*a017f53eSJackson Donaldson 339*a017f53eSJackson Donaldson type_init(max78000_gcr_register_types) 340