19a52d999SPeter Maydell /* 29a52d999SPeter Maydell * ARM MPS2 AN505 FPGAIO emulation 39a52d999SPeter Maydell * 49a52d999SPeter Maydell * Copyright (c) 2018 Linaro Limited 59a52d999SPeter Maydell * Written by Peter Maydell 69a52d999SPeter Maydell * 79a52d999SPeter Maydell * This program is free software; you can redistribute it and/or modify 89a52d999SPeter Maydell * it under the terms of the GNU General Public License version 2 or 99a52d999SPeter Maydell * (at your option) any later version. 109a52d999SPeter Maydell */ 119a52d999SPeter Maydell 129a52d999SPeter Maydell /* This is a model of the "FPGA system control and I/O" block found 139a52d999SPeter Maydell * in the AN505 FPGA image for the MPS2 devboard. 149a52d999SPeter Maydell * It is documented in AN505: 159a52d999SPeter Maydell * http://infocenter.arm.com/help/topic/com.arm.doc.dai0505b/index.html 169a52d999SPeter Maydell */ 179a52d999SPeter Maydell 189a52d999SPeter Maydell #include "qemu/osdep.h" 199a52d999SPeter Maydell #include "qemu/log.h" 209a52d999SPeter Maydell #include "qapi/error.h" 219a52d999SPeter Maydell #include "trace.h" 229a52d999SPeter Maydell #include "hw/sysbus.h" 239a52d999SPeter Maydell #include "hw/registerfields.h" 249a52d999SPeter Maydell #include "hw/misc/mps2-fpgaio.h" 25*a1982f90SPeter Maydell #include "qemu/timer.h" 269a52d999SPeter Maydell 279a52d999SPeter Maydell REG32(LED0, 0) 289a52d999SPeter Maydell REG32(BUTTON, 8) 299a52d999SPeter Maydell REG32(CLK1HZ, 0x10) 309a52d999SPeter Maydell REG32(CLK100HZ, 0x14) 319a52d999SPeter Maydell REG32(COUNTER, 0x18) 329a52d999SPeter Maydell REG32(PRESCALE, 0x1c) 339a52d999SPeter Maydell REG32(PSCNTR, 0x20) 349a52d999SPeter Maydell REG32(MISC, 0x4c) 359a52d999SPeter Maydell 36*a1982f90SPeter Maydell static uint32_t counter_from_tickoff(int64_t now, int64_t tick_offset, int frq) 37*a1982f90SPeter Maydell { 38*a1982f90SPeter Maydell return muldiv64(now - tick_offset, frq, NANOSECONDS_PER_SECOND); 39*a1982f90SPeter Maydell } 40*a1982f90SPeter Maydell 41*a1982f90SPeter Maydell static int64_t tickoff_from_counter(int64_t now, uint32_t count, int frq) 42*a1982f90SPeter Maydell { 43*a1982f90SPeter Maydell return now - muldiv64(count, NANOSECONDS_PER_SECOND, frq); 44*a1982f90SPeter Maydell } 45*a1982f90SPeter Maydell 469a52d999SPeter Maydell static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size) 479a52d999SPeter Maydell { 489a52d999SPeter Maydell MPS2FPGAIO *s = MPS2_FPGAIO(opaque); 499a52d999SPeter Maydell uint64_t r; 50*a1982f90SPeter Maydell int64_t now; 519a52d999SPeter Maydell 529a52d999SPeter Maydell switch (offset) { 539a52d999SPeter Maydell case A_LED0: 549a52d999SPeter Maydell r = s->led0; 559a52d999SPeter Maydell break; 569a52d999SPeter Maydell case A_BUTTON: 579a52d999SPeter Maydell /* User-pressable board buttons. We don't model that, so just return 589a52d999SPeter Maydell * zeroes. 599a52d999SPeter Maydell */ 609a52d999SPeter Maydell r = 0; 619a52d999SPeter Maydell break; 629a52d999SPeter Maydell case A_PRESCALE: 639a52d999SPeter Maydell r = s->prescale; 649a52d999SPeter Maydell break; 659a52d999SPeter Maydell case A_MISC: 669a52d999SPeter Maydell r = s->misc; 679a52d999SPeter Maydell break; 689a52d999SPeter Maydell case A_CLK1HZ: 69*a1982f90SPeter Maydell now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 70*a1982f90SPeter Maydell r = counter_from_tickoff(now, s->clk1hz_tick_offset, 1); 71*a1982f90SPeter Maydell break; 729a52d999SPeter Maydell case A_CLK100HZ: 73*a1982f90SPeter Maydell now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 74*a1982f90SPeter Maydell r = counter_from_tickoff(now, s->clk100hz_tick_offset, 100); 75*a1982f90SPeter Maydell break; 769a52d999SPeter Maydell case A_COUNTER: 779a52d999SPeter Maydell case A_PSCNTR: 789a52d999SPeter Maydell qemu_log_mask(LOG_UNIMP, "MPS2 FPGAIO: counters unimplemented\n"); 799a52d999SPeter Maydell r = 0; 809a52d999SPeter Maydell break; 819a52d999SPeter Maydell default: 829a52d999SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 839a52d999SPeter Maydell "MPS2 FPGAIO read: bad offset %x\n", (int) offset); 849a52d999SPeter Maydell r = 0; 859a52d999SPeter Maydell break; 869a52d999SPeter Maydell } 879a52d999SPeter Maydell 889a52d999SPeter Maydell trace_mps2_fpgaio_read(offset, r, size); 899a52d999SPeter Maydell return r; 909a52d999SPeter Maydell } 919a52d999SPeter Maydell 929a52d999SPeter Maydell static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value, 939a52d999SPeter Maydell unsigned size) 949a52d999SPeter Maydell { 959a52d999SPeter Maydell MPS2FPGAIO *s = MPS2_FPGAIO(opaque); 96*a1982f90SPeter Maydell int64_t now; 979a52d999SPeter Maydell 989a52d999SPeter Maydell trace_mps2_fpgaio_write(offset, value, size); 999a52d999SPeter Maydell 1009a52d999SPeter Maydell switch (offset) { 1019a52d999SPeter Maydell case A_LED0: 1029a52d999SPeter Maydell /* LED bits [1:0] control board LEDs. We don't currently have 1039a52d999SPeter Maydell * a mechanism for displaying this graphically, so use a trace event. 1049a52d999SPeter Maydell */ 1059a52d999SPeter Maydell trace_mps2_fpgaio_leds(value & 0x02 ? '*' : '.', 1069a52d999SPeter Maydell value & 0x01 ? '*' : '.'); 1079a52d999SPeter Maydell s->led0 = value & 0x3; 1089a52d999SPeter Maydell break; 1099a52d999SPeter Maydell case A_PRESCALE: 1109a52d999SPeter Maydell s->prescale = value; 1119a52d999SPeter Maydell break; 1129a52d999SPeter Maydell case A_MISC: 1139a52d999SPeter Maydell /* These are control bits for some of the other devices on the 1149a52d999SPeter Maydell * board (SPI, CLCD, etc). We don't implement that yet, so just 1159a52d999SPeter Maydell * make the bits read as written. 1169a52d999SPeter Maydell */ 1179a52d999SPeter Maydell qemu_log_mask(LOG_UNIMP, 1189a52d999SPeter Maydell "MPS2 FPGAIO: MISC control bits unimplemented\n"); 1199a52d999SPeter Maydell s->misc = value; 1209a52d999SPeter Maydell break; 121*a1982f90SPeter Maydell case A_CLK1HZ: 122*a1982f90SPeter Maydell now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 123*a1982f90SPeter Maydell s->clk1hz_tick_offset = tickoff_from_counter(now, value, 1); 124*a1982f90SPeter Maydell break; 125*a1982f90SPeter Maydell case A_CLK100HZ: 126*a1982f90SPeter Maydell now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 127*a1982f90SPeter Maydell s->clk100hz_tick_offset = tickoff_from_counter(now, value, 100); 128*a1982f90SPeter Maydell break; 1299a52d999SPeter Maydell default: 1309a52d999SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 1319a52d999SPeter Maydell "MPS2 FPGAIO write: bad offset 0x%x\n", (int) offset); 1329a52d999SPeter Maydell break; 1339a52d999SPeter Maydell } 1349a52d999SPeter Maydell } 1359a52d999SPeter Maydell 1369a52d999SPeter Maydell static const MemoryRegionOps mps2_fpgaio_ops = { 1379a52d999SPeter Maydell .read = mps2_fpgaio_read, 1389a52d999SPeter Maydell .write = mps2_fpgaio_write, 1399a52d999SPeter Maydell .endianness = DEVICE_LITTLE_ENDIAN, 1409a52d999SPeter Maydell }; 1419a52d999SPeter Maydell 1429a52d999SPeter Maydell static void mps2_fpgaio_reset(DeviceState *dev) 1439a52d999SPeter Maydell { 1449a52d999SPeter Maydell MPS2FPGAIO *s = MPS2_FPGAIO(dev); 145*a1982f90SPeter Maydell int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 1469a52d999SPeter Maydell 1479a52d999SPeter Maydell trace_mps2_fpgaio_reset(); 1489a52d999SPeter Maydell s->led0 = 0; 1499a52d999SPeter Maydell s->prescale = 0; 1509a52d999SPeter Maydell s->misc = 0; 151*a1982f90SPeter Maydell s->clk1hz_tick_offset = tickoff_from_counter(now, 0, 1); 152*a1982f90SPeter Maydell s->clk100hz_tick_offset = tickoff_from_counter(now, 0, 100); 1539a52d999SPeter Maydell } 1549a52d999SPeter Maydell 1559a52d999SPeter Maydell static void mps2_fpgaio_init(Object *obj) 1569a52d999SPeter Maydell { 1579a52d999SPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 1589a52d999SPeter Maydell MPS2FPGAIO *s = MPS2_FPGAIO(obj); 1599a52d999SPeter Maydell 1609a52d999SPeter Maydell memory_region_init_io(&s->iomem, obj, &mps2_fpgaio_ops, s, 1619a52d999SPeter Maydell "mps2-fpgaio", 0x1000); 1629a52d999SPeter Maydell sysbus_init_mmio(sbd, &s->iomem); 1639a52d999SPeter Maydell } 1649a52d999SPeter Maydell 165*a1982f90SPeter Maydell static bool mps2_fpgaio_counters_needed(void *opaque) 166*a1982f90SPeter Maydell { 167*a1982f90SPeter Maydell /* Currently vmstate.c insists all subsections have a 'needed' function */ 168*a1982f90SPeter Maydell return true; 169*a1982f90SPeter Maydell } 170*a1982f90SPeter Maydell 171*a1982f90SPeter Maydell static const VMStateDescription mps2_fpgaio_counters_vmstate = { 172*a1982f90SPeter Maydell .name = "mps2-fpgaio/counters", 173*a1982f90SPeter Maydell .version_id = 1, 174*a1982f90SPeter Maydell .minimum_version_id = 1, 175*a1982f90SPeter Maydell .needed = mps2_fpgaio_counters_needed, 176*a1982f90SPeter Maydell .fields = (VMStateField[]) { 177*a1982f90SPeter Maydell VMSTATE_INT64(clk1hz_tick_offset, MPS2FPGAIO), 178*a1982f90SPeter Maydell VMSTATE_INT64(clk100hz_tick_offset, MPS2FPGAIO), 179*a1982f90SPeter Maydell VMSTATE_END_OF_LIST() 180*a1982f90SPeter Maydell } 181*a1982f90SPeter Maydell }; 182*a1982f90SPeter Maydell 1839a52d999SPeter Maydell static const VMStateDescription mps2_fpgaio_vmstate = { 1849a52d999SPeter Maydell .name = "mps2-fpgaio", 1859a52d999SPeter Maydell .version_id = 1, 1869a52d999SPeter Maydell .minimum_version_id = 1, 1879a52d999SPeter Maydell .fields = (VMStateField[]) { 1889a52d999SPeter Maydell VMSTATE_UINT32(led0, MPS2FPGAIO), 1899a52d999SPeter Maydell VMSTATE_UINT32(prescale, MPS2FPGAIO), 1909a52d999SPeter Maydell VMSTATE_UINT32(misc, MPS2FPGAIO), 1919a52d999SPeter Maydell VMSTATE_END_OF_LIST() 192*a1982f90SPeter Maydell }, 193*a1982f90SPeter Maydell .subsections = (const VMStateDescription*[]) { 194*a1982f90SPeter Maydell &mps2_fpgaio_counters_vmstate, 195*a1982f90SPeter Maydell NULL 1969a52d999SPeter Maydell } 1979a52d999SPeter Maydell }; 1989a52d999SPeter Maydell 1999a52d999SPeter Maydell static Property mps2_fpgaio_properties[] = { 2009a52d999SPeter Maydell /* Frequency of the prescale counter */ 2019a52d999SPeter Maydell DEFINE_PROP_UINT32("prescale-clk", MPS2FPGAIO, prescale_clk, 20000000), 2029a52d999SPeter Maydell DEFINE_PROP_END_OF_LIST(), 2039a52d999SPeter Maydell }; 2049a52d999SPeter Maydell 2059a52d999SPeter Maydell static void mps2_fpgaio_class_init(ObjectClass *klass, void *data) 2069a52d999SPeter Maydell { 2079a52d999SPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 2089a52d999SPeter Maydell 2099a52d999SPeter Maydell dc->vmsd = &mps2_fpgaio_vmstate; 2109a52d999SPeter Maydell dc->reset = mps2_fpgaio_reset; 2119a52d999SPeter Maydell dc->props = mps2_fpgaio_properties; 2129a52d999SPeter Maydell } 2139a52d999SPeter Maydell 2149a52d999SPeter Maydell static const TypeInfo mps2_fpgaio_info = { 2159a52d999SPeter Maydell .name = TYPE_MPS2_FPGAIO, 2169a52d999SPeter Maydell .parent = TYPE_SYS_BUS_DEVICE, 2179a52d999SPeter Maydell .instance_size = sizeof(MPS2FPGAIO), 2189a52d999SPeter Maydell .instance_init = mps2_fpgaio_init, 2199a52d999SPeter Maydell .class_init = mps2_fpgaio_class_init, 2209a52d999SPeter Maydell }; 2219a52d999SPeter Maydell 2229a52d999SPeter Maydell static void mps2_fpgaio_register_types(void) 2239a52d999SPeter Maydell { 2249a52d999SPeter Maydell type_register_static(&mps2_fpgaio_info); 2259a52d999SPeter Maydell } 2269a52d999SPeter Maydell 2279a52d999SPeter Maydell type_init(mps2_fpgaio_register_types); 228