xref: /openbmc/qemu/hw/misc/max78000_gcr.c (revision a017f53e093a9018e33fb33bbdaa322c2de3dbe7)
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