1 /* 2 * ARM MPS2 AN505 FPGAIO emulation 3 * 4 * Copyright (c) 2018 Linaro Limited 5 * Written by Peter Maydell 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 or 9 * (at your option) any later version. 10 */ 11 12 /* This is a model of the "FPGA system control and I/O" block found 13 * in the AN505 FPGA image for the MPS2 devboard. 14 * It is documented in AN505: 15 * http://infocenter.arm.com/help/topic/com.arm.doc.dai0505b/index.html 16 */ 17 18 #include "qemu/osdep.h" 19 #include "qemu/log.h" 20 #include "qapi/error.h" 21 #include "trace.h" 22 #include "hw/sysbus.h" 23 #include "hw/registerfields.h" 24 #include "hw/misc/mps2-fpgaio.h" 25 26 REG32(LED0, 0) 27 REG32(BUTTON, 8) 28 REG32(CLK1HZ, 0x10) 29 REG32(CLK100HZ, 0x14) 30 REG32(COUNTER, 0x18) 31 REG32(PRESCALE, 0x1c) 32 REG32(PSCNTR, 0x20) 33 REG32(MISC, 0x4c) 34 35 static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size) 36 { 37 MPS2FPGAIO *s = MPS2_FPGAIO(opaque); 38 uint64_t r; 39 40 switch (offset) { 41 case A_LED0: 42 r = s->led0; 43 break; 44 case A_BUTTON: 45 /* User-pressable board buttons. We don't model that, so just return 46 * zeroes. 47 */ 48 r = 0; 49 break; 50 case A_PRESCALE: 51 r = s->prescale; 52 break; 53 case A_MISC: 54 r = s->misc; 55 break; 56 case A_CLK1HZ: 57 case A_CLK100HZ: 58 case A_COUNTER: 59 case A_PSCNTR: 60 /* These are all upcounters of various frequencies. */ 61 qemu_log_mask(LOG_UNIMP, "MPS2 FPGAIO: counters unimplemented\n"); 62 r = 0; 63 break; 64 default: 65 qemu_log_mask(LOG_GUEST_ERROR, 66 "MPS2 FPGAIO read: bad offset %x\n", (int) offset); 67 r = 0; 68 break; 69 } 70 71 trace_mps2_fpgaio_read(offset, r, size); 72 return r; 73 } 74 75 static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value, 76 unsigned size) 77 { 78 MPS2FPGAIO *s = MPS2_FPGAIO(opaque); 79 80 trace_mps2_fpgaio_write(offset, value, size); 81 82 switch (offset) { 83 case A_LED0: 84 /* LED bits [1:0] control board LEDs. We don't currently have 85 * a mechanism for displaying this graphically, so use a trace event. 86 */ 87 trace_mps2_fpgaio_leds(value & 0x02 ? '*' : '.', 88 value & 0x01 ? '*' : '.'); 89 s->led0 = value & 0x3; 90 break; 91 case A_PRESCALE: 92 s->prescale = value; 93 break; 94 case A_MISC: 95 /* These are control bits for some of the other devices on the 96 * board (SPI, CLCD, etc). We don't implement that yet, so just 97 * make the bits read as written. 98 */ 99 qemu_log_mask(LOG_UNIMP, 100 "MPS2 FPGAIO: MISC control bits unimplemented\n"); 101 s->misc = value; 102 break; 103 default: 104 qemu_log_mask(LOG_GUEST_ERROR, 105 "MPS2 FPGAIO write: bad offset 0x%x\n", (int) offset); 106 break; 107 } 108 } 109 110 static const MemoryRegionOps mps2_fpgaio_ops = { 111 .read = mps2_fpgaio_read, 112 .write = mps2_fpgaio_write, 113 .endianness = DEVICE_LITTLE_ENDIAN, 114 }; 115 116 static void mps2_fpgaio_reset(DeviceState *dev) 117 { 118 MPS2FPGAIO *s = MPS2_FPGAIO(dev); 119 120 trace_mps2_fpgaio_reset(); 121 s->led0 = 0; 122 s->prescale = 0; 123 s->misc = 0; 124 } 125 126 static void mps2_fpgaio_init(Object *obj) 127 { 128 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 129 MPS2FPGAIO *s = MPS2_FPGAIO(obj); 130 131 memory_region_init_io(&s->iomem, obj, &mps2_fpgaio_ops, s, 132 "mps2-fpgaio", 0x1000); 133 sysbus_init_mmio(sbd, &s->iomem); 134 } 135 136 static const VMStateDescription mps2_fpgaio_vmstate = { 137 .name = "mps2-fpgaio", 138 .version_id = 1, 139 .minimum_version_id = 1, 140 .fields = (VMStateField[]) { 141 VMSTATE_UINT32(led0, MPS2FPGAIO), 142 VMSTATE_UINT32(prescale, MPS2FPGAIO), 143 VMSTATE_UINT32(misc, MPS2FPGAIO), 144 VMSTATE_END_OF_LIST() 145 } 146 }; 147 148 static Property mps2_fpgaio_properties[] = { 149 /* Frequency of the prescale counter */ 150 DEFINE_PROP_UINT32("prescale-clk", MPS2FPGAIO, prescale_clk, 20000000), 151 DEFINE_PROP_END_OF_LIST(), 152 }; 153 154 static void mps2_fpgaio_class_init(ObjectClass *klass, void *data) 155 { 156 DeviceClass *dc = DEVICE_CLASS(klass); 157 158 dc->vmsd = &mps2_fpgaio_vmstate; 159 dc->reset = mps2_fpgaio_reset; 160 dc->props = mps2_fpgaio_properties; 161 } 162 163 static const TypeInfo mps2_fpgaio_info = { 164 .name = TYPE_MPS2_FPGAIO, 165 .parent = TYPE_SYS_BUS_DEVICE, 166 .instance_size = sizeof(MPS2FPGAIO), 167 .instance_init = mps2_fpgaio_init, 168 .class_init = mps2_fpgaio_class_init, 169 }; 170 171 static void mps2_fpgaio_register_types(void) 172 { 173 type_register_static(&mps2_fpgaio_info); 174 } 175 176 type_init(mps2_fpgaio_register_types); 177