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