xref: /qemu/hw/misc/mps2-scc.c (revision 6ac80818941829c01363e9feeefe08e8bc693ab7)
1dd73185bSPeter Maydell /*
2dd73185bSPeter Maydell  * ARM MPS2 SCC emulation
3dd73185bSPeter Maydell  *
4dd73185bSPeter Maydell  * Copyright (c) 2017 Linaro Limited
5dd73185bSPeter Maydell  * Written by Peter Maydell
6dd73185bSPeter Maydell  *
7dd73185bSPeter Maydell  *  This program is free software; you can redistribute it and/or modify
8dd73185bSPeter Maydell  *  it under the terms of the GNU General Public License version 2 or
9dd73185bSPeter Maydell  *  (at your option) any later version.
10dd73185bSPeter Maydell  */
11dd73185bSPeter Maydell 
12dd73185bSPeter Maydell /* This is a model of the SCC (Serial Communication Controller)
13dd73185bSPeter Maydell  * found in the FPGA images of MPS2 development boards.
14dd73185bSPeter Maydell  *
15dd73185bSPeter Maydell  * Documentation of it can be found in the MPS2 TRM:
1650b52b18SPeter Maydell  * https://developer.arm.com/documentation/100112/latest/
17dd73185bSPeter Maydell  * and also in the Application Notes documenting individual FPGA images.
18dd73185bSPeter Maydell  */
19dd73185bSPeter Maydell 
20dd73185bSPeter Maydell #include "qemu/osdep.h"
21dd73185bSPeter Maydell #include "qemu/log.h"
220b8fa32fSMarkus Armbruster #include "qemu/module.h"
23435db7ebSPhilippe Mathieu-Daudé #include "qemu/bitops.h"
24dd73185bSPeter Maydell #include "trace.h"
25dd73185bSPeter Maydell #include "hw/sysbus.h"
26d6454270SMarkus Armbruster #include "migration/vmstate.h"
27dd73185bSPeter Maydell #include "hw/registerfields.h"
28dd73185bSPeter Maydell #include "hw/misc/mps2-scc.h"
29435db7ebSPhilippe Mathieu-Daudé #include "hw/misc/led.h"
30a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
31dd73185bSPeter Maydell 
32dd73185bSPeter Maydell REG32(CFG0, 0)
33dd73185bSPeter Maydell REG32(CFG1, 4)
348e4b4c1cSPeter Maydell REG32(CFG2, 8)
35dd73185bSPeter Maydell REG32(CFG3, 0xc)
36dd73185bSPeter Maydell REG32(CFG4, 0x10)
378e4b4c1cSPeter Maydell REG32(CFG5, 0x14)
388e4b4c1cSPeter Maydell REG32(CFG6, 0x18)
39dd73185bSPeter Maydell REG32(CFGDATA_RTN, 0xa0)
40dd73185bSPeter Maydell REG32(CFGDATA_OUT, 0xa4)
41dd73185bSPeter Maydell REG32(CFGCTRL, 0xa8)
42dd73185bSPeter Maydell     FIELD(CFGCTRL, DEVICE, 0, 12)
43dd73185bSPeter Maydell     FIELD(CFGCTRL, RES1, 12, 8)
44dd73185bSPeter Maydell     FIELD(CFGCTRL, FUNCTION, 20, 6)
45dd73185bSPeter Maydell     FIELD(CFGCTRL, RES2, 26, 4)
46dd73185bSPeter Maydell     FIELD(CFGCTRL, WRITE, 30, 1)
47dd73185bSPeter Maydell     FIELD(CFGCTRL, START, 31, 1)
48dd73185bSPeter Maydell REG32(CFGSTAT, 0xac)
49dd73185bSPeter Maydell     FIELD(CFGSTAT, DONE, 0, 1)
50dd73185bSPeter Maydell     FIELD(CFGSTAT, ERROR, 1, 1)
51dd73185bSPeter Maydell REG32(DLL, 0x100)
52dd73185bSPeter Maydell REG32(AID, 0xFF8)
53dd73185bSPeter Maydell REG32(ID, 0xFFC)
54dd73185bSPeter Maydell 
558e4b4c1cSPeter Maydell static int scc_partno(MPS2SCC *s)
568e4b4c1cSPeter Maydell {
578e4b4c1cSPeter Maydell     /* Return the partno field of the SCC_ID (0x524, 0x511, etc) */
588e4b4c1cSPeter Maydell     return extract32(s->id, 4, 8);
598e4b4c1cSPeter Maydell }
608e4b4c1cSPeter Maydell 
61dd73185bSPeter Maydell /* Handle a write via the SYS_CFG channel to the specified function/device.
62dd73185bSPeter Maydell  * Return false on error (reported to guest via SYS_CFGCTRL ERROR bit).
63dd73185bSPeter Maydell  */
64dd73185bSPeter Maydell static bool scc_cfg_write(MPS2SCC *s, unsigned function,
65dd73185bSPeter Maydell                           unsigned device, uint32_t value)
66dd73185bSPeter Maydell {
67dd73185bSPeter Maydell     trace_mps2_scc_cfg_write(function, device, value);
68dd73185bSPeter Maydell 
694fb013afSPeter Maydell     if (function != 1 || device >= s->num_oscclk) {
70dd73185bSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
71dd73185bSPeter Maydell                       "MPS2 SCC config write: bad function %d device %d\n",
72dd73185bSPeter Maydell                       function, device);
73dd73185bSPeter Maydell         return false;
74dd73185bSPeter Maydell     }
75dd73185bSPeter Maydell 
76dd73185bSPeter Maydell     s->oscclk[device] = value;
77dd73185bSPeter Maydell     return true;
78dd73185bSPeter Maydell }
79dd73185bSPeter Maydell 
80dd73185bSPeter Maydell /* Handle a read via the SYS_CFG channel to the specified function/device.
81dd73185bSPeter Maydell  * Return false on error (reported to guest via SYS_CFGCTRL ERROR bit),
82dd73185bSPeter Maydell  * or set *value on success.
83dd73185bSPeter Maydell  */
84dd73185bSPeter Maydell static bool scc_cfg_read(MPS2SCC *s, unsigned function,
85dd73185bSPeter Maydell                          unsigned device, uint32_t *value)
86dd73185bSPeter Maydell {
874fb013afSPeter Maydell     if (function != 1 || device >= s->num_oscclk) {
88dd73185bSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
89dd73185bSPeter Maydell                       "MPS2 SCC config read: bad function %d device %d\n",
90dd73185bSPeter Maydell                       function, device);
91dd73185bSPeter Maydell         return false;
92dd73185bSPeter Maydell     }
93dd73185bSPeter Maydell 
94dd73185bSPeter Maydell     *value = s->oscclk[device];
95dd73185bSPeter Maydell 
96dd73185bSPeter Maydell     trace_mps2_scc_cfg_read(function, device, *value);
97dd73185bSPeter Maydell     return true;
98dd73185bSPeter Maydell }
99dd73185bSPeter Maydell 
100dd73185bSPeter Maydell static uint64_t mps2_scc_read(void *opaque, hwaddr offset, unsigned size)
101dd73185bSPeter Maydell {
102dd73185bSPeter Maydell     MPS2SCC *s = MPS2_SCC(opaque);
103dd73185bSPeter Maydell     uint64_t r;
104dd73185bSPeter Maydell 
105dd73185bSPeter Maydell     switch (offset) {
106dd73185bSPeter Maydell     case A_CFG0:
107dd73185bSPeter Maydell         r = s->cfg0;
108dd73185bSPeter Maydell         break;
109dd73185bSPeter Maydell     case A_CFG1:
110dd73185bSPeter Maydell         r = s->cfg1;
111dd73185bSPeter Maydell         break;
1128e4b4c1cSPeter Maydell     case A_CFG2:
113*6ac80818SPeter Maydell         if (scc_partno(s) != 0x524 && scc_partno(s) != 0x547) {
1148e4b4c1cSPeter Maydell             /* CFG2 reserved on other boards */
1158e4b4c1cSPeter Maydell             goto bad_offset;
1168e4b4c1cSPeter Maydell         }
1178e4b4c1cSPeter Maydell         r = s->cfg2;
1188e4b4c1cSPeter Maydell         break;
119dd73185bSPeter Maydell     case A_CFG3:
120*6ac80818SPeter Maydell         if (scc_partno(s) == 0x524 && scc_partno(s) == 0x547) {
1218e4b4c1cSPeter Maydell             /* CFG3 reserved on AN524 */
1228e4b4c1cSPeter Maydell             goto bad_offset;
1238e4b4c1cSPeter Maydell         }
124dd73185bSPeter Maydell         /* These are user-settable DIP switches on the board. We don't
125dd73185bSPeter Maydell          * model that, so just return zeroes.
126dd73185bSPeter Maydell          */
127dd73185bSPeter Maydell         r = 0;
128dd73185bSPeter Maydell         break;
129dd73185bSPeter Maydell     case A_CFG4:
130dd73185bSPeter Maydell         r = s->cfg4;
131dd73185bSPeter Maydell         break;
1328e4b4c1cSPeter Maydell     case A_CFG5:
133*6ac80818SPeter Maydell         if (scc_partno(s) != 0x524 && scc_partno(s) != 0x547) {
1348e4b4c1cSPeter Maydell             /* CFG5 reserved on other boards */
1358e4b4c1cSPeter Maydell             goto bad_offset;
1368e4b4c1cSPeter Maydell         }
1378e4b4c1cSPeter Maydell         r = s->cfg5;
1388e4b4c1cSPeter Maydell         break;
1398e4b4c1cSPeter Maydell     case A_CFG6:
1408e4b4c1cSPeter Maydell         if (scc_partno(s) != 0x524) {
1418e4b4c1cSPeter Maydell             /* CFG6 reserved on other boards */
1428e4b4c1cSPeter Maydell             goto bad_offset;
1438e4b4c1cSPeter Maydell         }
1448e4b4c1cSPeter Maydell         r = s->cfg6;
1458e4b4c1cSPeter Maydell         break;
146dd73185bSPeter Maydell     case A_CFGDATA_RTN:
147dd73185bSPeter Maydell         r = s->cfgdata_rtn;
148dd73185bSPeter Maydell         break;
149dd73185bSPeter Maydell     case A_CFGDATA_OUT:
150dd73185bSPeter Maydell         r = s->cfgdata_out;
151dd73185bSPeter Maydell         break;
152dd73185bSPeter Maydell     case A_CFGCTRL:
153dd73185bSPeter Maydell         r = s->cfgctrl;
154dd73185bSPeter Maydell         break;
155dd73185bSPeter Maydell     case A_CFGSTAT:
156dd73185bSPeter Maydell         r = s->cfgstat;
157dd73185bSPeter Maydell         break;
158dd73185bSPeter Maydell     case A_DLL:
159dd73185bSPeter Maydell         r = s->dll;
160dd73185bSPeter Maydell         break;
161dd73185bSPeter Maydell     case A_AID:
162dd73185bSPeter Maydell         r = s->aid;
163dd73185bSPeter Maydell         break;
164dd73185bSPeter Maydell     case A_ID:
165dd73185bSPeter Maydell         r = s->id;
166dd73185bSPeter Maydell         break;
167dd73185bSPeter Maydell     default:
1688e4b4c1cSPeter Maydell     bad_offset:
169dd73185bSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
170dd73185bSPeter Maydell                       "MPS2 SCC read: bad offset %x\n", (int) offset);
171dd73185bSPeter Maydell         r = 0;
172dd73185bSPeter Maydell         break;
173dd73185bSPeter Maydell     }
174dd73185bSPeter Maydell 
175dd73185bSPeter Maydell     trace_mps2_scc_read(offset, r, size);
176dd73185bSPeter Maydell     return r;
177dd73185bSPeter Maydell }
178dd73185bSPeter Maydell 
179dd73185bSPeter Maydell static void mps2_scc_write(void *opaque, hwaddr offset, uint64_t value,
180dd73185bSPeter Maydell                            unsigned size)
181dd73185bSPeter Maydell {
182dd73185bSPeter Maydell     MPS2SCC *s = MPS2_SCC(opaque);
183dd73185bSPeter Maydell 
184dd73185bSPeter Maydell     trace_mps2_scc_write(offset, value, size);
185dd73185bSPeter Maydell 
186dd73185bSPeter Maydell     switch (offset) {
187dd73185bSPeter Maydell     case A_CFG0:
188*6ac80818SPeter Maydell         /*
189*6ac80818SPeter Maydell          * TODO on some boards bit 0 controls RAM remapping;
190*6ac80818SPeter Maydell          * on others bit 1 is CPU_WAIT.
191*6ac80818SPeter Maydell          */
192dd73185bSPeter Maydell         s->cfg0 = value;
193dd73185bSPeter Maydell         break;
194dd73185bSPeter Maydell     case A_CFG1:
195dd73185bSPeter Maydell         s->cfg1 = value;
196435db7ebSPhilippe Mathieu-Daudé         for (size_t i = 0; i < ARRAY_SIZE(s->led); i++) {
197435db7ebSPhilippe Mathieu-Daudé             led_set_state(s->led[i], extract32(value, i, 1));
198435db7ebSPhilippe Mathieu-Daudé         }
199dd73185bSPeter Maydell         break;
2008e4b4c1cSPeter Maydell     case A_CFG2:
201*6ac80818SPeter Maydell         if (scc_partno(s) != 0x524 && scc_partno(s) != 0x547) {
2028e4b4c1cSPeter Maydell             /* CFG2 reserved on other boards */
2038e4b4c1cSPeter Maydell             goto bad_offset;
2048e4b4c1cSPeter Maydell         }
2058e4b4c1cSPeter Maydell         /* AN524: QSPI Select signal */
2068e4b4c1cSPeter Maydell         s->cfg2 = value;
2078e4b4c1cSPeter Maydell         break;
2088e4b4c1cSPeter Maydell     case A_CFG5:
209*6ac80818SPeter Maydell         if (scc_partno(s) != 0x524 && scc_partno(s) != 0x547) {
2108e4b4c1cSPeter Maydell             /* CFG5 reserved on other boards */
2118e4b4c1cSPeter Maydell             goto bad_offset;
2128e4b4c1cSPeter Maydell         }
2138e4b4c1cSPeter Maydell         /* AN524: ACLK frequency in Hz */
2148e4b4c1cSPeter Maydell         s->cfg5 = value;
2158e4b4c1cSPeter Maydell         break;
2168e4b4c1cSPeter Maydell     case A_CFG6:
2178e4b4c1cSPeter Maydell         if (scc_partno(s) != 0x524) {
2188e4b4c1cSPeter Maydell             /* CFG6 reserved on other boards */
2198e4b4c1cSPeter Maydell             goto bad_offset;
2208e4b4c1cSPeter Maydell         }
2218e4b4c1cSPeter Maydell         /* AN524: Clock divider for BRAM */
2228e4b4c1cSPeter Maydell         s->cfg6 = value;
2238e4b4c1cSPeter Maydell         break;
224dd73185bSPeter Maydell     case A_CFGDATA_OUT:
225dd73185bSPeter Maydell         s->cfgdata_out = value;
226dd73185bSPeter Maydell         break;
227dd73185bSPeter Maydell     case A_CFGCTRL:
228dd73185bSPeter Maydell         /* Writing to CFGCTRL clears SYS_CFGSTAT */
229dd73185bSPeter Maydell         s->cfgstat = 0;
230dd73185bSPeter Maydell         s->cfgctrl = value & ~(R_CFGCTRL_RES1_MASK |
231dd73185bSPeter Maydell                                R_CFGCTRL_RES2_MASK |
232dd73185bSPeter Maydell                                R_CFGCTRL_START_MASK);
233dd73185bSPeter Maydell 
234dd73185bSPeter Maydell         if (value & R_CFGCTRL_START_MASK) {
235dd73185bSPeter Maydell             /* Start bit set -- do a read or write (instantaneously) */
236dd73185bSPeter Maydell             int device = extract32(s->cfgctrl, R_CFGCTRL_DEVICE_SHIFT,
237dd73185bSPeter Maydell                                    R_CFGCTRL_DEVICE_LENGTH);
238dd73185bSPeter Maydell             int function = extract32(s->cfgctrl, R_CFGCTRL_FUNCTION_SHIFT,
239dd73185bSPeter Maydell                                      R_CFGCTRL_FUNCTION_LENGTH);
240dd73185bSPeter Maydell 
241dd73185bSPeter Maydell             s->cfgstat = R_CFGSTAT_DONE_MASK;
242dd73185bSPeter Maydell             if (s->cfgctrl & R_CFGCTRL_WRITE_MASK) {
243dd73185bSPeter Maydell                 if (!scc_cfg_write(s, function, device, s->cfgdata_out)) {
244dd73185bSPeter Maydell                     s->cfgstat |= R_CFGSTAT_ERROR_MASK;
245dd73185bSPeter Maydell                 }
246dd73185bSPeter Maydell             } else {
247dd73185bSPeter Maydell                 uint32_t result;
248dd73185bSPeter Maydell                 if (!scc_cfg_read(s, function, device, &result)) {
249dd73185bSPeter Maydell                     s->cfgstat |= R_CFGSTAT_ERROR_MASK;
250dd73185bSPeter Maydell                 } else {
251dd73185bSPeter Maydell                     s->cfgdata_rtn = result;
252dd73185bSPeter Maydell                 }
253dd73185bSPeter Maydell             }
254dd73185bSPeter Maydell         }
255dd73185bSPeter Maydell         break;
256dd73185bSPeter Maydell     case A_DLL:
257dd73185bSPeter Maydell         /* DLL stands for Digital Locked Loop.
258dd73185bSPeter Maydell          * Bits [31:24] (DLL_LOCK_MASK) are writable, and indicate a
259dd73185bSPeter Maydell          * mask of which of the DLL_LOCKED bits [16:23] should be ORed
260dd73185bSPeter Maydell          * together to determine the ALL_UNMASKED_DLLS_LOCKED bit [0].
261dd73185bSPeter Maydell          * For QEMU, our DLLs are always locked, so we can leave bit 0
262dd73185bSPeter Maydell          * as 1 always and don't need to recalculate it.
263dd73185bSPeter Maydell          */
264dd73185bSPeter Maydell         s->dll = deposit32(s->dll, 24, 8, extract32(value, 24, 8));
265dd73185bSPeter Maydell         break;
266dd73185bSPeter Maydell     default:
2678e4b4c1cSPeter Maydell     bad_offset:
268dd73185bSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
269dd73185bSPeter Maydell                       "MPS2 SCC write: bad offset 0x%x\n", (int) offset);
270dd73185bSPeter Maydell         break;
271dd73185bSPeter Maydell     }
272dd73185bSPeter Maydell }
273dd73185bSPeter Maydell 
274dd73185bSPeter Maydell static const MemoryRegionOps mps2_scc_ops = {
275dd73185bSPeter Maydell     .read = mps2_scc_read,
276dd73185bSPeter Maydell     .write = mps2_scc_write,
277dd73185bSPeter Maydell     .endianness = DEVICE_LITTLE_ENDIAN,
278dd73185bSPeter Maydell };
279dd73185bSPeter Maydell 
280dd73185bSPeter Maydell static void mps2_scc_reset(DeviceState *dev)
281dd73185bSPeter Maydell {
282dd73185bSPeter Maydell     MPS2SCC *s = MPS2_SCC(dev);
283dd73185bSPeter Maydell     int i;
284dd73185bSPeter Maydell 
285dd73185bSPeter Maydell     trace_mps2_scc_reset();
286dd73185bSPeter Maydell     s->cfg0 = 0;
287dd73185bSPeter Maydell     s->cfg1 = 0;
2888e4b4c1cSPeter Maydell     s->cfg2 = 0;
2898e4b4c1cSPeter Maydell     s->cfg5 = 0;
2908e4b4c1cSPeter Maydell     s->cfg6 = 0;
291dd73185bSPeter Maydell     s->cfgdata_rtn = 0;
292dd73185bSPeter Maydell     s->cfgdata_out = 0;
293dd73185bSPeter Maydell     s->cfgctrl = 0x100000;
294dd73185bSPeter Maydell     s->cfgstat = 0;
295dd73185bSPeter Maydell     s->dll = 0xffff0001;
2964fb013afSPeter Maydell     for (i = 0; i < s->num_oscclk; i++) {
297dd73185bSPeter Maydell         s->oscclk[i] = s->oscclk_reset[i];
298dd73185bSPeter Maydell     }
299435db7ebSPhilippe Mathieu-Daudé     for (i = 0; i < ARRAY_SIZE(s->led); i++) {
300435db7ebSPhilippe Mathieu-Daudé         device_cold_reset(DEVICE(s->led[i]));
301435db7ebSPhilippe Mathieu-Daudé     }
302dd73185bSPeter Maydell }
303dd73185bSPeter Maydell 
304dd73185bSPeter Maydell static void mps2_scc_init(Object *obj)
305dd73185bSPeter Maydell {
306dd73185bSPeter Maydell     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
307dd73185bSPeter Maydell     MPS2SCC *s = MPS2_SCC(obj);
308dd73185bSPeter Maydell 
309dd73185bSPeter Maydell     memory_region_init_io(&s->iomem, obj, &mps2_scc_ops, s, "mps2-scc", 0x1000);
310dd73185bSPeter Maydell     sysbus_init_mmio(sbd, &s->iomem);
311dd73185bSPeter Maydell }
312dd73185bSPeter Maydell 
313dd73185bSPeter Maydell static void mps2_scc_realize(DeviceState *dev, Error **errp)
314dd73185bSPeter Maydell {
315435db7ebSPhilippe Mathieu-Daudé     MPS2SCC *s = MPS2_SCC(dev);
316435db7ebSPhilippe Mathieu-Daudé 
317435db7ebSPhilippe Mathieu-Daudé     for (size_t i = 0; i < ARRAY_SIZE(s->led); i++) {
318435db7ebSPhilippe Mathieu-Daudé         char *name = g_strdup_printf("SCC LED%zu", i);
319435db7ebSPhilippe Mathieu-Daudé         s->led[i] = led_create_simple(OBJECT(dev), GPIO_POLARITY_ACTIVE_HIGH,
320435db7ebSPhilippe Mathieu-Daudé                                       LED_COLOR_GREEN, name);
321435db7ebSPhilippe Mathieu-Daudé         g_free(name);
322435db7ebSPhilippe Mathieu-Daudé     }
3234fb013afSPeter Maydell 
3244fb013afSPeter Maydell     s->oscclk = g_new0(uint32_t, s->num_oscclk);
325dd73185bSPeter Maydell }
326dd73185bSPeter Maydell 
327dd73185bSPeter Maydell static const VMStateDescription mps2_scc_vmstate = {
328dd73185bSPeter Maydell     .name = "mps2-scc",
3298e4b4c1cSPeter Maydell     .version_id = 3,
3308e4b4c1cSPeter Maydell     .minimum_version_id = 3,
331dd73185bSPeter Maydell     .fields = (VMStateField[]) {
332dd73185bSPeter Maydell         VMSTATE_UINT32(cfg0, MPS2SCC),
333dd73185bSPeter Maydell         VMSTATE_UINT32(cfg1, MPS2SCC),
3348e4b4c1cSPeter Maydell         VMSTATE_UINT32(cfg2, MPS2SCC),
3358e4b4c1cSPeter Maydell         /* cfg3, cfg4 are read-only so need not be migrated */
3368e4b4c1cSPeter Maydell         VMSTATE_UINT32(cfg5, MPS2SCC),
3378e4b4c1cSPeter Maydell         VMSTATE_UINT32(cfg6, MPS2SCC),
338dd73185bSPeter Maydell         VMSTATE_UINT32(cfgdata_rtn, MPS2SCC),
339dd73185bSPeter Maydell         VMSTATE_UINT32(cfgdata_out, MPS2SCC),
340dd73185bSPeter Maydell         VMSTATE_UINT32(cfgctrl, MPS2SCC),
341dd73185bSPeter Maydell         VMSTATE_UINT32(cfgstat, MPS2SCC),
342dd73185bSPeter Maydell         VMSTATE_UINT32(dll, MPS2SCC),
3434fb013afSPeter Maydell         VMSTATE_VARRAY_UINT32(oscclk, MPS2SCC, num_oscclk,
3444fb013afSPeter Maydell                               0, vmstate_info_uint32, uint32_t),
345dd73185bSPeter Maydell         VMSTATE_END_OF_LIST()
346dd73185bSPeter Maydell     }
347dd73185bSPeter Maydell };
348dd73185bSPeter Maydell 
349dd73185bSPeter Maydell static Property mps2_scc_properties[] = {
350dd73185bSPeter Maydell     /* Values for various read-only ID registers (which are specific
351dd73185bSPeter Maydell      * to the board model or FPGA image)
352dd73185bSPeter Maydell      */
35389cbc377SPhilippe Mathieu-Daudé     DEFINE_PROP_UINT32("scc-cfg4", MPS2SCC, cfg4, 0),
354dd73185bSPeter Maydell     DEFINE_PROP_UINT32("scc-aid", MPS2SCC, aid, 0),
35589cbc377SPhilippe Mathieu-Daudé     DEFINE_PROP_UINT32("scc-id", MPS2SCC, id, 0),
3564fb013afSPeter Maydell     /*
3574fb013afSPeter Maydell      * These are the initial settings for the source clocks on the board.
358dd73185bSPeter Maydell      * In hardware they can be configured via a config file read by the
359dd73185bSPeter Maydell      * motherboard configuration controller to suit the FPGA image.
360dd73185bSPeter Maydell      */
3614fb013afSPeter Maydell     DEFINE_PROP_ARRAY("oscclk", MPS2SCC, num_oscclk, oscclk_reset,
3624fb013afSPeter Maydell                       qdev_prop_uint32, uint32_t),
363dd73185bSPeter Maydell     DEFINE_PROP_END_OF_LIST(),
364dd73185bSPeter Maydell };
365dd73185bSPeter Maydell 
366dd73185bSPeter Maydell static void mps2_scc_class_init(ObjectClass *klass, void *data)
367dd73185bSPeter Maydell {
368dd73185bSPeter Maydell     DeviceClass *dc = DEVICE_CLASS(klass);
369dd73185bSPeter Maydell 
370dd73185bSPeter Maydell     dc->realize = mps2_scc_realize;
371dd73185bSPeter Maydell     dc->vmsd = &mps2_scc_vmstate;
372dd73185bSPeter Maydell     dc->reset = mps2_scc_reset;
3734f67d30bSMarc-André Lureau     device_class_set_props(dc, mps2_scc_properties);
374dd73185bSPeter Maydell }
375dd73185bSPeter Maydell 
376dd73185bSPeter Maydell static const TypeInfo mps2_scc_info = {
377dd73185bSPeter Maydell     .name = TYPE_MPS2_SCC,
378dd73185bSPeter Maydell     .parent = TYPE_SYS_BUS_DEVICE,
379dd73185bSPeter Maydell     .instance_size = sizeof(MPS2SCC),
380dd73185bSPeter Maydell     .instance_init = mps2_scc_init,
381dd73185bSPeter Maydell     .class_init = mps2_scc_class_init,
382dd73185bSPeter Maydell };
383dd73185bSPeter Maydell 
384dd73185bSPeter Maydell static void mps2_scc_register_types(void)
385dd73185bSPeter Maydell {
386dd73185bSPeter Maydell     type_register_static(&mps2_scc_info);
387dd73185bSPeter Maydell }
388dd73185bSPeter Maydell 
389dd73185bSPeter Maydell type_init(mps2_scc_register_types);
390