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: 16dd73185bSPeter Maydell * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.100112_0100_03_en/index.html 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" 23dd73185bSPeter Maydell #include "trace.h" 24dd73185bSPeter Maydell #include "hw/sysbus.h" 25*d6454270SMarkus Armbruster #include "migration/vmstate.h" 26dd73185bSPeter Maydell #include "hw/registerfields.h" 27dd73185bSPeter Maydell #include "hw/misc/mps2-scc.h" 28dd73185bSPeter Maydell 29dd73185bSPeter Maydell REG32(CFG0, 0) 30dd73185bSPeter Maydell REG32(CFG1, 4) 31dd73185bSPeter Maydell REG32(CFG3, 0xc) 32dd73185bSPeter Maydell REG32(CFG4, 0x10) 33dd73185bSPeter Maydell REG32(CFGDATA_RTN, 0xa0) 34dd73185bSPeter Maydell REG32(CFGDATA_OUT, 0xa4) 35dd73185bSPeter Maydell REG32(CFGCTRL, 0xa8) 36dd73185bSPeter Maydell FIELD(CFGCTRL, DEVICE, 0, 12) 37dd73185bSPeter Maydell FIELD(CFGCTRL, RES1, 12, 8) 38dd73185bSPeter Maydell FIELD(CFGCTRL, FUNCTION, 20, 6) 39dd73185bSPeter Maydell FIELD(CFGCTRL, RES2, 26, 4) 40dd73185bSPeter Maydell FIELD(CFGCTRL, WRITE, 30, 1) 41dd73185bSPeter Maydell FIELD(CFGCTRL, START, 31, 1) 42dd73185bSPeter Maydell REG32(CFGSTAT, 0xac) 43dd73185bSPeter Maydell FIELD(CFGSTAT, DONE, 0, 1) 44dd73185bSPeter Maydell FIELD(CFGSTAT, ERROR, 1, 1) 45dd73185bSPeter Maydell REG32(DLL, 0x100) 46dd73185bSPeter Maydell REG32(AID, 0xFF8) 47dd73185bSPeter Maydell REG32(ID, 0xFFC) 48dd73185bSPeter Maydell 49dd73185bSPeter Maydell /* Handle a write via the SYS_CFG channel to the specified function/device. 50dd73185bSPeter Maydell * Return false on error (reported to guest via SYS_CFGCTRL ERROR bit). 51dd73185bSPeter Maydell */ 52dd73185bSPeter Maydell static bool scc_cfg_write(MPS2SCC *s, unsigned function, 53dd73185bSPeter Maydell unsigned device, uint32_t value) 54dd73185bSPeter Maydell { 55dd73185bSPeter Maydell trace_mps2_scc_cfg_write(function, device, value); 56dd73185bSPeter Maydell 57dd73185bSPeter Maydell if (function != 1 || device >= NUM_OSCCLK) { 58dd73185bSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 59dd73185bSPeter Maydell "MPS2 SCC config write: bad function %d device %d\n", 60dd73185bSPeter Maydell function, device); 61dd73185bSPeter Maydell return false; 62dd73185bSPeter Maydell } 63dd73185bSPeter Maydell 64dd73185bSPeter Maydell s->oscclk[device] = value; 65dd73185bSPeter Maydell return true; 66dd73185bSPeter Maydell } 67dd73185bSPeter Maydell 68dd73185bSPeter Maydell /* Handle a read via the SYS_CFG channel to the specified function/device. 69dd73185bSPeter Maydell * Return false on error (reported to guest via SYS_CFGCTRL ERROR bit), 70dd73185bSPeter Maydell * or set *value on success. 71dd73185bSPeter Maydell */ 72dd73185bSPeter Maydell static bool scc_cfg_read(MPS2SCC *s, unsigned function, 73dd73185bSPeter Maydell unsigned device, uint32_t *value) 74dd73185bSPeter Maydell { 75dd73185bSPeter Maydell if (function != 1 || device >= NUM_OSCCLK) { 76dd73185bSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 77dd73185bSPeter Maydell "MPS2 SCC config read: bad function %d device %d\n", 78dd73185bSPeter Maydell function, device); 79dd73185bSPeter Maydell return false; 80dd73185bSPeter Maydell } 81dd73185bSPeter Maydell 82dd73185bSPeter Maydell *value = s->oscclk[device]; 83dd73185bSPeter Maydell 84dd73185bSPeter Maydell trace_mps2_scc_cfg_read(function, device, *value); 85dd73185bSPeter Maydell return true; 86dd73185bSPeter Maydell } 87dd73185bSPeter Maydell 88dd73185bSPeter Maydell static uint64_t mps2_scc_read(void *opaque, hwaddr offset, unsigned size) 89dd73185bSPeter Maydell { 90dd73185bSPeter Maydell MPS2SCC *s = MPS2_SCC(opaque); 91dd73185bSPeter Maydell uint64_t r; 92dd73185bSPeter Maydell 93dd73185bSPeter Maydell switch (offset) { 94dd73185bSPeter Maydell case A_CFG0: 95dd73185bSPeter Maydell r = s->cfg0; 96dd73185bSPeter Maydell break; 97dd73185bSPeter Maydell case A_CFG1: 98dd73185bSPeter Maydell r = s->cfg1; 99dd73185bSPeter Maydell break; 100dd73185bSPeter Maydell case A_CFG3: 101dd73185bSPeter Maydell /* These are user-settable DIP switches on the board. We don't 102dd73185bSPeter Maydell * model that, so just return zeroes. 103dd73185bSPeter Maydell */ 104dd73185bSPeter Maydell r = 0; 105dd73185bSPeter Maydell break; 106dd73185bSPeter Maydell case A_CFG4: 107dd73185bSPeter Maydell r = s->cfg4; 108dd73185bSPeter Maydell break; 109dd73185bSPeter Maydell case A_CFGDATA_RTN: 110dd73185bSPeter Maydell r = s->cfgdata_rtn; 111dd73185bSPeter Maydell break; 112dd73185bSPeter Maydell case A_CFGDATA_OUT: 113dd73185bSPeter Maydell r = s->cfgdata_out; 114dd73185bSPeter Maydell break; 115dd73185bSPeter Maydell case A_CFGCTRL: 116dd73185bSPeter Maydell r = s->cfgctrl; 117dd73185bSPeter Maydell break; 118dd73185bSPeter Maydell case A_CFGSTAT: 119dd73185bSPeter Maydell r = s->cfgstat; 120dd73185bSPeter Maydell break; 121dd73185bSPeter Maydell case A_DLL: 122dd73185bSPeter Maydell r = s->dll; 123dd73185bSPeter Maydell break; 124dd73185bSPeter Maydell case A_AID: 125dd73185bSPeter Maydell r = s->aid; 126dd73185bSPeter Maydell break; 127dd73185bSPeter Maydell case A_ID: 128dd73185bSPeter Maydell r = s->id; 129dd73185bSPeter Maydell break; 130dd73185bSPeter Maydell default: 131dd73185bSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 132dd73185bSPeter Maydell "MPS2 SCC read: bad offset %x\n", (int) offset); 133dd73185bSPeter Maydell r = 0; 134dd73185bSPeter Maydell break; 135dd73185bSPeter Maydell } 136dd73185bSPeter Maydell 137dd73185bSPeter Maydell trace_mps2_scc_read(offset, r, size); 138dd73185bSPeter Maydell return r; 139dd73185bSPeter Maydell } 140dd73185bSPeter Maydell 141dd73185bSPeter Maydell static void mps2_scc_write(void *opaque, hwaddr offset, uint64_t value, 142dd73185bSPeter Maydell unsigned size) 143dd73185bSPeter Maydell { 144dd73185bSPeter Maydell MPS2SCC *s = MPS2_SCC(opaque); 145dd73185bSPeter Maydell 146dd73185bSPeter Maydell trace_mps2_scc_write(offset, value, size); 147dd73185bSPeter Maydell 148dd73185bSPeter Maydell switch (offset) { 149dd73185bSPeter Maydell case A_CFG0: 150dd73185bSPeter Maydell /* TODO on some boards bit 0 controls RAM remapping */ 151dd73185bSPeter Maydell s->cfg0 = value; 152dd73185bSPeter Maydell break; 153dd73185bSPeter Maydell case A_CFG1: 154dd73185bSPeter Maydell /* CFG1 bits [7:0] control the board LEDs. We don't currently have 155dd73185bSPeter Maydell * a mechanism for displaying this graphically, so use a trace event. 156dd73185bSPeter Maydell */ 157dd73185bSPeter Maydell trace_mps2_scc_leds(value & 0x80 ? '*' : '.', 158dd73185bSPeter Maydell value & 0x40 ? '*' : '.', 159dd73185bSPeter Maydell value & 0x20 ? '*' : '.', 160dd73185bSPeter Maydell value & 0x10 ? '*' : '.', 161dd73185bSPeter Maydell value & 0x08 ? '*' : '.', 162dd73185bSPeter Maydell value & 0x04 ? '*' : '.', 163dd73185bSPeter Maydell value & 0x02 ? '*' : '.', 164dd73185bSPeter Maydell value & 0x01 ? '*' : '.'); 165dd73185bSPeter Maydell s->cfg1 = value; 166dd73185bSPeter Maydell break; 167dd73185bSPeter Maydell case A_CFGDATA_OUT: 168dd73185bSPeter Maydell s->cfgdata_out = value; 169dd73185bSPeter Maydell break; 170dd73185bSPeter Maydell case A_CFGCTRL: 171dd73185bSPeter Maydell /* Writing to CFGCTRL clears SYS_CFGSTAT */ 172dd73185bSPeter Maydell s->cfgstat = 0; 173dd73185bSPeter Maydell s->cfgctrl = value & ~(R_CFGCTRL_RES1_MASK | 174dd73185bSPeter Maydell R_CFGCTRL_RES2_MASK | 175dd73185bSPeter Maydell R_CFGCTRL_START_MASK); 176dd73185bSPeter Maydell 177dd73185bSPeter Maydell if (value & R_CFGCTRL_START_MASK) { 178dd73185bSPeter Maydell /* Start bit set -- do a read or write (instantaneously) */ 179dd73185bSPeter Maydell int device = extract32(s->cfgctrl, R_CFGCTRL_DEVICE_SHIFT, 180dd73185bSPeter Maydell R_CFGCTRL_DEVICE_LENGTH); 181dd73185bSPeter Maydell int function = extract32(s->cfgctrl, R_CFGCTRL_FUNCTION_SHIFT, 182dd73185bSPeter Maydell R_CFGCTRL_FUNCTION_LENGTH); 183dd73185bSPeter Maydell 184dd73185bSPeter Maydell s->cfgstat = R_CFGSTAT_DONE_MASK; 185dd73185bSPeter Maydell if (s->cfgctrl & R_CFGCTRL_WRITE_MASK) { 186dd73185bSPeter Maydell if (!scc_cfg_write(s, function, device, s->cfgdata_out)) { 187dd73185bSPeter Maydell s->cfgstat |= R_CFGSTAT_ERROR_MASK; 188dd73185bSPeter Maydell } 189dd73185bSPeter Maydell } else { 190dd73185bSPeter Maydell uint32_t result; 191dd73185bSPeter Maydell if (!scc_cfg_read(s, function, device, &result)) { 192dd73185bSPeter Maydell s->cfgstat |= R_CFGSTAT_ERROR_MASK; 193dd73185bSPeter Maydell } else { 194dd73185bSPeter Maydell s->cfgdata_rtn = result; 195dd73185bSPeter Maydell } 196dd73185bSPeter Maydell } 197dd73185bSPeter Maydell } 198dd73185bSPeter Maydell break; 199dd73185bSPeter Maydell case A_DLL: 200dd73185bSPeter Maydell /* DLL stands for Digital Locked Loop. 201dd73185bSPeter Maydell * Bits [31:24] (DLL_LOCK_MASK) are writable, and indicate a 202dd73185bSPeter Maydell * mask of which of the DLL_LOCKED bits [16:23] should be ORed 203dd73185bSPeter Maydell * together to determine the ALL_UNMASKED_DLLS_LOCKED bit [0]. 204dd73185bSPeter Maydell * For QEMU, our DLLs are always locked, so we can leave bit 0 205dd73185bSPeter Maydell * as 1 always and don't need to recalculate it. 206dd73185bSPeter Maydell */ 207dd73185bSPeter Maydell s->dll = deposit32(s->dll, 24, 8, extract32(value, 24, 8)); 208dd73185bSPeter Maydell break; 209dd73185bSPeter Maydell default: 210dd73185bSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 211dd73185bSPeter Maydell "MPS2 SCC write: bad offset 0x%x\n", (int) offset); 212dd73185bSPeter Maydell break; 213dd73185bSPeter Maydell } 214dd73185bSPeter Maydell } 215dd73185bSPeter Maydell 216dd73185bSPeter Maydell static const MemoryRegionOps mps2_scc_ops = { 217dd73185bSPeter Maydell .read = mps2_scc_read, 218dd73185bSPeter Maydell .write = mps2_scc_write, 219dd73185bSPeter Maydell .endianness = DEVICE_LITTLE_ENDIAN, 220dd73185bSPeter Maydell }; 221dd73185bSPeter Maydell 222dd73185bSPeter Maydell static void mps2_scc_reset(DeviceState *dev) 223dd73185bSPeter Maydell { 224dd73185bSPeter Maydell MPS2SCC *s = MPS2_SCC(dev); 225dd73185bSPeter Maydell int i; 226dd73185bSPeter Maydell 227dd73185bSPeter Maydell trace_mps2_scc_reset(); 228dd73185bSPeter Maydell s->cfg0 = 0; 229dd73185bSPeter Maydell s->cfg1 = 0; 230dd73185bSPeter Maydell s->cfgdata_rtn = 0; 231dd73185bSPeter Maydell s->cfgdata_out = 0; 232dd73185bSPeter Maydell s->cfgctrl = 0x100000; 233dd73185bSPeter Maydell s->cfgstat = 0; 234dd73185bSPeter Maydell s->dll = 0xffff0001; 235dd73185bSPeter Maydell for (i = 0; i < NUM_OSCCLK; i++) { 236dd73185bSPeter Maydell s->oscclk[i] = s->oscclk_reset[i]; 237dd73185bSPeter Maydell } 238dd73185bSPeter Maydell } 239dd73185bSPeter Maydell 240dd73185bSPeter Maydell static void mps2_scc_init(Object *obj) 241dd73185bSPeter Maydell { 242dd73185bSPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 243dd73185bSPeter Maydell MPS2SCC *s = MPS2_SCC(obj); 244dd73185bSPeter Maydell 245dd73185bSPeter Maydell memory_region_init_io(&s->iomem, obj, &mps2_scc_ops, s, "mps2-scc", 0x1000); 246dd73185bSPeter Maydell sysbus_init_mmio(sbd, &s->iomem); 247dd73185bSPeter Maydell } 248dd73185bSPeter Maydell 249dd73185bSPeter Maydell static void mps2_scc_realize(DeviceState *dev, Error **errp) 250dd73185bSPeter Maydell { 251dd73185bSPeter Maydell } 252dd73185bSPeter Maydell 253dd73185bSPeter Maydell static const VMStateDescription mps2_scc_vmstate = { 254dd73185bSPeter Maydell .name = "mps2-scc", 255dd73185bSPeter Maydell .version_id = 1, 256dd73185bSPeter Maydell .minimum_version_id = 1, 257dd73185bSPeter Maydell .fields = (VMStateField[]) { 258dd73185bSPeter Maydell VMSTATE_UINT32(cfg0, MPS2SCC), 259dd73185bSPeter Maydell VMSTATE_UINT32(cfg1, MPS2SCC), 260dd73185bSPeter Maydell VMSTATE_UINT32(cfgdata_rtn, MPS2SCC), 261dd73185bSPeter Maydell VMSTATE_UINT32(cfgdata_out, MPS2SCC), 262dd73185bSPeter Maydell VMSTATE_UINT32(cfgctrl, MPS2SCC), 263dd73185bSPeter Maydell VMSTATE_UINT32(cfgstat, MPS2SCC), 264dd73185bSPeter Maydell VMSTATE_UINT32(dll, MPS2SCC), 265dd73185bSPeter Maydell VMSTATE_UINT32_ARRAY(oscclk, MPS2SCC, NUM_OSCCLK), 266dd73185bSPeter Maydell VMSTATE_END_OF_LIST() 267dd73185bSPeter Maydell } 268dd73185bSPeter Maydell }; 269dd73185bSPeter Maydell 270dd73185bSPeter Maydell static Property mps2_scc_properties[] = { 271dd73185bSPeter Maydell /* Values for various read-only ID registers (which are specific 272dd73185bSPeter Maydell * to the board model or FPGA image) 273dd73185bSPeter Maydell */ 27489cbc377SPhilippe Mathieu-Daudé DEFINE_PROP_UINT32("scc-cfg4", MPS2SCC, cfg4, 0), 275dd73185bSPeter Maydell DEFINE_PROP_UINT32("scc-aid", MPS2SCC, aid, 0), 27689cbc377SPhilippe Mathieu-Daudé DEFINE_PROP_UINT32("scc-id", MPS2SCC, id, 0), 277dd73185bSPeter Maydell /* These are the initial settings for the source clocks on the board. 278dd73185bSPeter Maydell * In hardware they can be configured via a config file read by the 279dd73185bSPeter Maydell * motherboard configuration controller to suit the FPGA image. 280dd73185bSPeter Maydell * These default values are used by most of the standard FPGA images. 281dd73185bSPeter Maydell */ 282dd73185bSPeter Maydell DEFINE_PROP_UINT32("oscclk0", MPS2SCC, oscclk_reset[0], 50000000), 283dd73185bSPeter Maydell DEFINE_PROP_UINT32("oscclk1", MPS2SCC, oscclk_reset[1], 24576000), 284dd73185bSPeter Maydell DEFINE_PROP_UINT32("oscclk2", MPS2SCC, oscclk_reset[2], 25000000), 285dd73185bSPeter Maydell DEFINE_PROP_END_OF_LIST(), 286dd73185bSPeter Maydell }; 287dd73185bSPeter Maydell 288dd73185bSPeter Maydell static void mps2_scc_class_init(ObjectClass *klass, void *data) 289dd73185bSPeter Maydell { 290dd73185bSPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 291dd73185bSPeter Maydell 292dd73185bSPeter Maydell dc->realize = mps2_scc_realize; 293dd73185bSPeter Maydell dc->vmsd = &mps2_scc_vmstate; 294dd73185bSPeter Maydell dc->reset = mps2_scc_reset; 295dd73185bSPeter Maydell dc->props = mps2_scc_properties; 296dd73185bSPeter Maydell } 297dd73185bSPeter Maydell 298dd73185bSPeter Maydell static const TypeInfo mps2_scc_info = { 299dd73185bSPeter Maydell .name = TYPE_MPS2_SCC, 300dd73185bSPeter Maydell .parent = TYPE_SYS_BUS_DEVICE, 301dd73185bSPeter Maydell .instance_size = sizeof(MPS2SCC), 302dd73185bSPeter Maydell .instance_init = mps2_scc_init, 303dd73185bSPeter Maydell .class_init = mps2_scc_class_init, 304dd73185bSPeter Maydell }; 305dd73185bSPeter Maydell 306dd73185bSPeter Maydell static void mps2_scc_register_types(void) 307dd73185bSPeter Maydell { 308dd73185bSPeter Maydell type_register_static(&mps2_scc_info); 309dd73185bSPeter Maydell } 310dd73185bSPeter Maydell 311dd73185bSPeter Maydell type_init(mps2_scc_register_types); 312