xref: /qemu/hw/misc/mps2-scc.c (revision 50b52b18cdb9294ce83dd49bb60b8e55a6526ea0)
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:
16*50b52b18SPeter 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:
1138e4b4c1cSPeter Maydell         if (scc_partno(s) != 0x524) {
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:
1208e4b4c1cSPeter Maydell         if (scc_partno(s) == 0x524) {
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:
1338e4b4c1cSPeter Maydell         if (scc_partno(s) != 0x524) {
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:
188dd73185bSPeter Maydell         /* TODO on some boards bit 0 controls RAM remapping */
189dd73185bSPeter Maydell         s->cfg0 = value;
190dd73185bSPeter Maydell         break;
191dd73185bSPeter Maydell     case A_CFG1:
192dd73185bSPeter Maydell         s->cfg1 = value;
193435db7ebSPhilippe Mathieu-Daudé         for (size_t i = 0; i < ARRAY_SIZE(s->led); i++) {
194435db7ebSPhilippe Mathieu-Daudé             led_set_state(s->led[i], extract32(value, i, 1));
195435db7ebSPhilippe Mathieu-Daudé         }
196dd73185bSPeter Maydell         break;
1978e4b4c1cSPeter Maydell     case A_CFG2:
1988e4b4c1cSPeter Maydell         if (scc_partno(s) != 0x524) {
1998e4b4c1cSPeter Maydell             /* CFG2 reserved on other boards */
2008e4b4c1cSPeter Maydell             goto bad_offset;
2018e4b4c1cSPeter Maydell         }
2028e4b4c1cSPeter Maydell         /* AN524: QSPI Select signal */
2038e4b4c1cSPeter Maydell         s->cfg2 = value;
2048e4b4c1cSPeter Maydell         break;
2058e4b4c1cSPeter Maydell     case A_CFG5:
2068e4b4c1cSPeter Maydell         if (scc_partno(s) != 0x524) {
2078e4b4c1cSPeter Maydell             /* CFG5 reserved on other boards */
2088e4b4c1cSPeter Maydell             goto bad_offset;
2098e4b4c1cSPeter Maydell         }
2108e4b4c1cSPeter Maydell         /* AN524: ACLK frequency in Hz */
2118e4b4c1cSPeter Maydell         s->cfg5 = value;
2128e4b4c1cSPeter Maydell         break;
2138e4b4c1cSPeter Maydell     case A_CFG6:
2148e4b4c1cSPeter Maydell         if (scc_partno(s) != 0x524) {
2158e4b4c1cSPeter Maydell             /* CFG6 reserved on other boards */
2168e4b4c1cSPeter Maydell             goto bad_offset;
2178e4b4c1cSPeter Maydell         }
2188e4b4c1cSPeter Maydell         /* AN524: Clock divider for BRAM */
2198e4b4c1cSPeter Maydell         s->cfg6 = value;
2208e4b4c1cSPeter Maydell         break;
221dd73185bSPeter Maydell     case A_CFGDATA_OUT:
222dd73185bSPeter Maydell         s->cfgdata_out = value;
223dd73185bSPeter Maydell         break;
224dd73185bSPeter Maydell     case A_CFGCTRL:
225dd73185bSPeter Maydell         /* Writing to CFGCTRL clears SYS_CFGSTAT */
226dd73185bSPeter Maydell         s->cfgstat = 0;
227dd73185bSPeter Maydell         s->cfgctrl = value & ~(R_CFGCTRL_RES1_MASK |
228dd73185bSPeter Maydell                                R_CFGCTRL_RES2_MASK |
229dd73185bSPeter Maydell                                R_CFGCTRL_START_MASK);
230dd73185bSPeter Maydell 
231dd73185bSPeter Maydell         if (value & R_CFGCTRL_START_MASK) {
232dd73185bSPeter Maydell             /* Start bit set -- do a read or write (instantaneously) */
233dd73185bSPeter Maydell             int device = extract32(s->cfgctrl, R_CFGCTRL_DEVICE_SHIFT,
234dd73185bSPeter Maydell                                    R_CFGCTRL_DEVICE_LENGTH);
235dd73185bSPeter Maydell             int function = extract32(s->cfgctrl, R_CFGCTRL_FUNCTION_SHIFT,
236dd73185bSPeter Maydell                                      R_CFGCTRL_FUNCTION_LENGTH);
237dd73185bSPeter Maydell 
238dd73185bSPeter Maydell             s->cfgstat = R_CFGSTAT_DONE_MASK;
239dd73185bSPeter Maydell             if (s->cfgctrl & R_CFGCTRL_WRITE_MASK) {
240dd73185bSPeter Maydell                 if (!scc_cfg_write(s, function, device, s->cfgdata_out)) {
241dd73185bSPeter Maydell                     s->cfgstat |= R_CFGSTAT_ERROR_MASK;
242dd73185bSPeter Maydell                 }
243dd73185bSPeter Maydell             } else {
244dd73185bSPeter Maydell                 uint32_t result;
245dd73185bSPeter Maydell                 if (!scc_cfg_read(s, function, device, &result)) {
246dd73185bSPeter Maydell                     s->cfgstat |= R_CFGSTAT_ERROR_MASK;
247dd73185bSPeter Maydell                 } else {
248dd73185bSPeter Maydell                     s->cfgdata_rtn = result;
249dd73185bSPeter Maydell                 }
250dd73185bSPeter Maydell             }
251dd73185bSPeter Maydell         }
252dd73185bSPeter Maydell         break;
253dd73185bSPeter Maydell     case A_DLL:
254dd73185bSPeter Maydell         /* DLL stands for Digital Locked Loop.
255dd73185bSPeter Maydell          * Bits [31:24] (DLL_LOCK_MASK) are writable, and indicate a
256dd73185bSPeter Maydell          * mask of which of the DLL_LOCKED bits [16:23] should be ORed
257dd73185bSPeter Maydell          * together to determine the ALL_UNMASKED_DLLS_LOCKED bit [0].
258dd73185bSPeter Maydell          * For QEMU, our DLLs are always locked, so we can leave bit 0
259dd73185bSPeter Maydell          * as 1 always and don't need to recalculate it.
260dd73185bSPeter Maydell          */
261dd73185bSPeter Maydell         s->dll = deposit32(s->dll, 24, 8, extract32(value, 24, 8));
262dd73185bSPeter Maydell         break;
263dd73185bSPeter Maydell     default:
2648e4b4c1cSPeter Maydell     bad_offset:
265dd73185bSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
266dd73185bSPeter Maydell                       "MPS2 SCC write: bad offset 0x%x\n", (int) offset);
267dd73185bSPeter Maydell         break;
268dd73185bSPeter Maydell     }
269dd73185bSPeter Maydell }
270dd73185bSPeter Maydell 
271dd73185bSPeter Maydell static const MemoryRegionOps mps2_scc_ops = {
272dd73185bSPeter Maydell     .read = mps2_scc_read,
273dd73185bSPeter Maydell     .write = mps2_scc_write,
274dd73185bSPeter Maydell     .endianness = DEVICE_LITTLE_ENDIAN,
275dd73185bSPeter Maydell };
276dd73185bSPeter Maydell 
277dd73185bSPeter Maydell static void mps2_scc_reset(DeviceState *dev)
278dd73185bSPeter Maydell {
279dd73185bSPeter Maydell     MPS2SCC *s = MPS2_SCC(dev);
280dd73185bSPeter Maydell     int i;
281dd73185bSPeter Maydell 
282dd73185bSPeter Maydell     trace_mps2_scc_reset();
283dd73185bSPeter Maydell     s->cfg0 = 0;
284dd73185bSPeter Maydell     s->cfg1 = 0;
2858e4b4c1cSPeter Maydell     s->cfg2 = 0;
2868e4b4c1cSPeter Maydell     s->cfg5 = 0;
2878e4b4c1cSPeter Maydell     s->cfg6 = 0;
288dd73185bSPeter Maydell     s->cfgdata_rtn = 0;
289dd73185bSPeter Maydell     s->cfgdata_out = 0;
290dd73185bSPeter Maydell     s->cfgctrl = 0x100000;
291dd73185bSPeter Maydell     s->cfgstat = 0;
292dd73185bSPeter Maydell     s->dll = 0xffff0001;
2934fb013afSPeter Maydell     for (i = 0; i < s->num_oscclk; i++) {
294dd73185bSPeter Maydell         s->oscclk[i] = s->oscclk_reset[i];
295dd73185bSPeter Maydell     }
296435db7ebSPhilippe Mathieu-Daudé     for (i = 0; i < ARRAY_SIZE(s->led); i++) {
297435db7ebSPhilippe Mathieu-Daudé         device_cold_reset(DEVICE(s->led[i]));
298435db7ebSPhilippe Mathieu-Daudé     }
299dd73185bSPeter Maydell }
300dd73185bSPeter Maydell 
301dd73185bSPeter Maydell static void mps2_scc_init(Object *obj)
302dd73185bSPeter Maydell {
303dd73185bSPeter Maydell     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
304dd73185bSPeter Maydell     MPS2SCC *s = MPS2_SCC(obj);
305dd73185bSPeter Maydell 
306dd73185bSPeter Maydell     memory_region_init_io(&s->iomem, obj, &mps2_scc_ops, s, "mps2-scc", 0x1000);
307dd73185bSPeter Maydell     sysbus_init_mmio(sbd, &s->iomem);
308dd73185bSPeter Maydell }
309dd73185bSPeter Maydell 
310dd73185bSPeter Maydell static void mps2_scc_realize(DeviceState *dev, Error **errp)
311dd73185bSPeter Maydell {
312435db7ebSPhilippe Mathieu-Daudé     MPS2SCC *s = MPS2_SCC(dev);
313435db7ebSPhilippe Mathieu-Daudé 
314435db7ebSPhilippe Mathieu-Daudé     for (size_t i = 0; i < ARRAY_SIZE(s->led); i++) {
315435db7ebSPhilippe Mathieu-Daudé         char *name = g_strdup_printf("SCC LED%zu", i);
316435db7ebSPhilippe Mathieu-Daudé         s->led[i] = led_create_simple(OBJECT(dev), GPIO_POLARITY_ACTIVE_HIGH,
317435db7ebSPhilippe Mathieu-Daudé                                       LED_COLOR_GREEN, name);
318435db7ebSPhilippe Mathieu-Daudé         g_free(name);
319435db7ebSPhilippe Mathieu-Daudé     }
3204fb013afSPeter Maydell 
3214fb013afSPeter Maydell     s->oscclk = g_new0(uint32_t, s->num_oscclk);
322dd73185bSPeter Maydell }
323dd73185bSPeter Maydell 
324dd73185bSPeter Maydell static const VMStateDescription mps2_scc_vmstate = {
325dd73185bSPeter Maydell     .name = "mps2-scc",
3268e4b4c1cSPeter Maydell     .version_id = 3,
3278e4b4c1cSPeter Maydell     .minimum_version_id = 3,
328dd73185bSPeter Maydell     .fields = (VMStateField[]) {
329dd73185bSPeter Maydell         VMSTATE_UINT32(cfg0, MPS2SCC),
330dd73185bSPeter Maydell         VMSTATE_UINT32(cfg1, MPS2SCC),
3318e4b4c1cSPeter Maydell         VMSTATE_UINT32(cfg2, MPS2SCC),
3328e4b4c1cSPeter Maydell         /* cfg3, cfg4 are read-only so need not be migrated */
3338e4b4c1cSPeter Maydell         VMSTATE_UINT32(cfg5, MPS2SCC),
3348e4b4c1cSPeter Maydell         VMSTATE_UINT32(cfg6, MPS2SCC),
335dd73185bSPeter Maydell         VMSTATE_UINT32(cfgdata_rtn, MPS2SCC),
336dd73185bSPeter Maydell         VMSTATE_UINT32(cfgdata_out, MPS2SCC),
337dd73185bSPeter Maydell         VMSTATE_UINT32(cfgctrl, MPS2SCC),
338dd73185bSPeter Maydell         VMSTATE_UINT32(cfgstat, MPS2SCC),
339dd73185bSPeter Maydell         VMSTATE_UINT32(dll, MPS2SCC),
3404fb013afSPeter Maydell         VMSTATE_VARRAY_UINT32(oscclk, MPS2SCC, num_oscclk,
3414fb013afSPeter Maydell                               0, vmstate_info_uint32, uint32_t),
342dd73185bSPeter Maydell         VMSTATE_END_OF_LIST()
343dd73185bSPeter Maydell     }
344dd73185bSPeter Maydell };
345dd73185bSPeter Maydell 
346dd73185bSPeter Maydell static Property mps2_scc_properties[] = {
347dd73185bSPeter Maydell     /* Values for various read-only ID registers (which are specific
348dd73185bSPeter Maydell      * to the board model or FPGA image)
349dd73185bSPeter Maydell      */
35089cbc377SPhilippe Mathieu-Daudé     DEFINE_PROP_UINT32("scc-cfg4", MPS2SCC, cfg4, 0),
351dd73185bSPeter Maydell     DEFINE_PROP_UINT32("scc-aid", MPS2SCC, aid, 0),
35289cbc377SPhilippe Mathieu-Daudé     DEFINE_PROP_UINT32("scc-id", MPS2SCC, id, 0),
3534fb013afSPeter Maydell     /*
3544fb013afSPeter Maydell      * These are the initial settings for the source clocks on the board.
355dd73185bSPeter Maydell      * In hardware they can be configured via a config file read by the
356dd73185bSPeter Maydell      * motherboard configuration controller to suit the FPGA image.
357dd73185bSPeter Maydell      */
3584fb013afSPeter Maydell     DEFINE_PROP_ARRAY("oscclk", MPS2SCC, num_oscclk, oscclk_reset,
3594fb013afSPeter Maydell                       qdev_prop_uint32, uint32_t),
360dd73185bSPeter Maydell     DEFINE_PROP_END_OF_LIST(),
361dd73185bSPeter Maydell };
362dd73185bSPeter Maydell 
363dd73185bSPeter Maydell static void mps2_scc_class_init(ObjectClass *klass, void *data)
364dd73185bSPeter Maydell {
365dd73185bSPeter Maydell     DeviceClass *dc = DEVICE_CLASS(klass);
366dd73185bSPeter Maydell 
367dd73185bSPeter Maydell     dc->realize = mps2_scc_realize;
368dd73185bSPeter Maydell     dc->vmsd = &mps2_scc_vmstate;
369dd73185bSPeter Maydell     dc->reset = mps2_scc_reset;
3704f67d30bSMarc-André Lureau     device_class_set_props(dc, mps2_scc_properties);
371dd73185bSPeter Maydell }
372dd73185bSPeter Maydell 
373dd73185bSPeter Maydell static const TypeInfo mps2_scc_info = {
374dd73185bSPeter Maydell     .name = TYPE_MPS2_SCC,
375dd73185bSPeter Maydell     .parent = TYPE_SYS_BUS_DEVICE,
376dd73185bSPeter Maydell     .instance_size = sizeof(MPS2SCC),
377dd73185bSPeter Maydell     .instance_init = mps2_scc_init,
378dd73185bSPeter Maydell     .class_init = mps2_scc_class_init,
379dd73185bSPeter Maydell };
380dd73185bSPeter Maydell 
381dd73185bSPeter Maydell static void mps2_scc_register_types(void)
382dd73185bSPeter Maydell {
383dd73185bSPeter Maydell     type_register_static(&mps2_scc_info);
384dd73185bSPeter Maydell }
385dd73185bSPeter Maydell 
386dd73185bSPeter Maydell type_init(mps2_scc_register_types);
387