aboutsummaryrefslogtreecommitdiff
path: root/hw/misc
diff options
context:
space:
mode:
Diffstat (limited to 'hw/misc')
-rw-r--r--hw/misc/armsse-cpuid.c2
-rw-r--r--hw/misc/armsse-mhu.c2
-rw-r--r--hw/misc/iotkit-sysctl.c2
-rw-r--r--hw/misc/iotkit-sysinfo.c2
-rw-r--r--hw/misc/mps2-fpgaio.c43
-rw-r--r--hw/misc/mps2-scc.c93
6 files changed, 119 insertions, 25 deletions
diff --git a/hw/misc/armsse-cpuid.c b/hw/misc/armsse-cpuid.c
index d58138dc28..e785a09051 100644
--- a/hw/misc/armsse-cpuid.c
+++ b/hw/misc/armsse-cpuid.c
@@ -12,7 +12,7 @@
/*
* This is a model of the "CPU_IDENTITY" register block which is part of the
* Arm SSE-200 and documented in
- * http://infocenter.arm.com/help/topic/com.arm.doc.101104_0100_00_en/corelink_sse200_subsystem_for_embedded_technical_reference_manual_101104_0100_00_en.pdf
+ * https://developer.arm.com/documentation/101104/latest/
*
* It consists of one read-only CPUID register (set by QOM property), plus the
* usual ID registers.
diff --git a/hw/misc/armsse-mhu.c b/hw/misc/armsse-mhu.c
index a45d97fada..0be7f0fc87 100644
--- a/hw/misc/armsse-mhu.c
+++ b/hw/misc/armsse-mhu.c
@@ -12,7 +12,7 @@
/*
* This is a model of the Message Handling Unit (MHU) which is part of the
* Arm SSE-200 and documented in
- * http://infocenter.arm.com/help/topic/com.arm.doc.101104_0100_00_en/corelink_sse200_subsystem_for_embedded_technical_reference_manual_101104_0100_00_en.pdf
+ * https://developer.arm.com/documentation/101104/latest/
*/
#include "qemu/osdep.h"
diff --git a/hw/misc/iotkit-sysctl.c b/hw/misc/iotkit-sysctl.c
index 964b48c74d..222511c4b0 100644
--- a/hw/misc/iotkit-sysctl.c
+++ b/hw/misc/iotkit-sysctl.c
@@ -12,7 +12,7 @@
/*
* This is a model of the "system control element" which is part of the
* Arm IoTKit and documented in
- * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
+ * https://developer.arm.com/documentation/ecm0601256/latest
* Specifically, it implements the "system control register" blocks.
*/
diff --git a/hw/misc/iotkit-sysinfo.c b/hw/misc/iotkit-sysinfo.c
index b2dcfc4376..52e70053df 100644
--- a/hw/misc/iotkit-sysinfo.c
+++ b/hw/misc/iotkit-sysinfo.c
@@ -12,7 +12,7 @@
/*
* This is a model of the "system information block" which is part of the
* Arm IoTKit and documented in
- * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
+ * https://developer.arm.com/documentation/ecm0601256/latest
* It consists of 2 read-only version/config registers, plus the
* usual ID registers.
*/
diff --git a/hw/misc/mps2-fpgaio.c b/hw/misc/mps2-fpgaio.c
index 6af0e8f837..f3db88ddcc 100644
--- a/hw/misc/mps2-fpgaio.c
+++ b/hw/misc/mps2-fpgaio.c
@@ -12,7 +12,7 @@
/* This is a model of the "FPGA system control and I/O" block found
* in the AN505 FPGA image for the MPS2 devboard.
* It is documented in AN505:
- * http://infocenter.arm.com/help/topic/com.arm.doc.dai0505b/index.html
+ * https://developer.arm.com/documentation/dai0505/latest/
*/
#include "qemu/osdep.h"
@@ -35,6 +35,7 @@ REG32(CLK100HZ, 0x14)
REG32(COUNTER, 0x18)
REG32(PRESCALE, 0x1c)
REG32(PSCNTR, 0x20)
+REG32(SWITCH, 0x28)
REG32(MISC, 0x4c)
static uint32_t counter_from_tickoff(int64_t now, int64_t tick_offset, int frq)
@@ -156,7 +157,15 @@ static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
resync_counter(s);
r = s->pscntr;
break;
+ case A_SWITCH:
+ if (!s->has_switches) {
+ goto bad_offset;
+ }
+ /* User-togglable board switches. We don't model that, so report 0. */
+ r = 0;
+ break;
default:
+ bad_offset:
qemu_log_mask(LOG_GUEST_ERROR,
"MPS2 FPGAIO read: bad offset %x\n", (int) offset);
r = 0;
@@ -177,9 +186,14 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
switch (offset) {
case A_LED0:
- s->led0 = value & 0x3;
- led_set_state(s->led[0], value & 0x01);
- led_set_state(s->led[1], value & 0x02);
+ if (s->num_leds != 0) {
+ uint32_t i;
+
+ s->led0 = value & MAKE_64BIT_MASK(0, s->num_leds);
+ for (i = 0; i < s->num_leds; i++) {
+ led_set_state(s->led[i], value & (1 << i));
+ }
+ }
break;
case A_PRESCALE:
resync_counter(s);
@@ -238,7 +252,7 @@ static void mps2_fpgaio_reset(DeviceState *dev)
s->pscntr = 0;
s->pscntr_sync_ticks = now;
- for (size_t i = 0; i < ARRAY_SIZE(s->led); i++) {
+ for (size_t i = 0; i < s->num_leds; i++) {
device_cold_reset(DEVICE(s->led[i]));
}
}
@@ -256,11 +270,19 @@ static void mps2_fpgaio_init(Object *obj)
static void mps2_fpgaio_realize(DeviceState *dev, Error **errp)
{
MPS2FPGAIO *s = MPS2_FPGAIO(dev);
+ uint32_t i;
- s->led[0] = led_create_simple(OBJECT(dev), GPIO_POLARITY_ACTIVE_HIGH,
- LED_COLOR_GREEN, "USERLED0");
- s->led[1] = led_create_simple(OBJECT(dev), GPIO_POLARITY_ACTIVE_HIGH,
- LED_COLOR_GREEN, "USERLED1");
+ if (s->num_leds > MPS2FPGAIO_MAX_LEDS) {
+ error_setg(errp, "num-leds cannot be greater than %d",
+ MPS2FPGAIO_MAX_LEDS);
+ return;
+ }
+
+ for (i = 0; i < s->num_leds; i++) {
+ g_autofree char *ledname = g_strdup_printf("USERLED%d", i);
+ s->led[i] = led_create_simple(OBJECT(dev), GPIO_POLARITY_ACTIVE_HIGH,
+ LED_COLOR_GREEN, ledname);
+ }
}
static bool mps2_fpgaio_counters_needed(void *opaque)
@@ -303,6 +325,9 @@ static const VMStateDescription mps2_fpgaio_vmstate = {
static Property mps2_fpgaio_properties[] = {
/* Frequency of the prescale counter */
DEFINE_PROP_UINT32("prescale-clk", MPS2FPGAIO, prescale_clk, 20000000),
+ /* Number of LEDs controlled by LED0 register */
+ DEFINE_PROP_UINT32("num-leds", MPS2FPGAIO, num_leds, 2),
+ DEFINE_PROP_BOOL("has-switches", MPS2FPGAIO, has_switches, false),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/misc/mps2-scc.c b/hw/misc/mps2-scc.c
index ce1dfe9356..140a4b9ceb 100644
--- a/hw/misc/mps2-scc.c
+++ b/hw/misc/mps2-scc.c
@@ -13,7 +13,7 @@
* found in the FPGA images of MPS2 development boards.
*
* Documentation of it can be found in the MPS2 TRM:
- * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.100112_0100_03_en/index.html
+ * https://developer.arm.com/documentation/100112/latest/
* and also in the Application Notes documenting individual FPGA images.
*/
@@ -31,8 +31,11 @@
REG32(CFG0, 0)
REG32(CFG1, 4)
+REG32(CFG2, 8)
REG32(CFG3, 0xc)
REG32(CFG4, 0x10)
+REG32(CFG5, 0x14)
+REG32(CFG6, 0x18)
REG32(CFGDATA_RTN, 0xa0)
REG32(CFGDATA_OUT, 0xa4)
REG32(CFGCTRL, 0xa8)
@@ -49,6 +52,12 @@ REG32(DLL, 0x100)
REG32(AID, 0xFF8)
REG32(ID, 0xFFC)
+static int scc_partno(MPS2SCC *s)
+{
+ /* Return the partno field of the SCC_ID (0x524, 0x511, etc) */
+ return extract32(s->id, 4, 8);
+}
+
/* Handle a write via the SYS_CFG channel to the specified function/device.
* Return false on error (reported to guest via SYS_CFGCTRL ERROR bit).
*/
@@ -57,7 +66,7 @@ static bool scc_cfg_write(MPS2SCC *s, unsigned function,
{
trace_mps2_scc_cfg_write(function, device, value);
- if (function != 1 || device >= NUM_OSCCLK) {
+ if (function != 1 || device >= s->num_oscclk) {
qemu_log_mask(LOG_GUEST_ERROR,
"MPS2 SCC config write: bad function %d device %d\n",
function, device);
@@ -75,7 +84,7 @@ static bool scc_cfg_write(MPS2SCC *s, unsigned function,
static bool scc_cfg_read(MPS2SCC *s, unsigned function,
unsigned device, uint32_t *value)
{
- if (function != 1 || device >= NUM_OSCCLK) {
+ if (function != 1 || device >= s->num_oscclk) {
qemu_log_mask(LOG_GUEST_ERROR,
"MPS2 SCC config read: bad function %d device %d\n",
function, device);
@@ -100,7 +109,18 @@ static uint64_t mps2_scc_read(void *opaque, hwaddr offset, unsigned size)
case A_CFG1:
r = s->cfg1;
break;
+ case A_CFG2:
+ if (scc_partno(s) != 0x524) {
+ /* CFG2 reserved on other boards */
+ goto bad_offset;
+ }
+ r = s->cfg2;
+ break;
case A_CFG3:
+ if (scc_partno(s) == 0x524) {
+ /* CFG3 reserved on AN524 */
+ goto bad_offset;
+ }
/* These are user-settable DIP switches on the board. We don't
* model that, so just return zeroes.
*/
@@ -109,6 +129,20 @@ static uint64_t mps2_scc_read(void *opaque, hwaddr offset, unsigned size)
case A_CFG4:
r = s->cfg4;
break;
+ case A_CFG5:
+ if (scc_partno(s) != 0x524) {
+ /* CFG5 reserved on other boards */
+ goto bad_offset;
+ }
+ r = s->cfg5;
+ break;
+ case A_CFG6:
+ if (scc_partno(s) != 0x524) {
+ /* CFG6 reserved on other boards */
+ goto bad_offset;
+ }
+ r = s->cfg6;
+ break;
case A_CFGDATA_RTN:
r = s->cfgdata_rtn;
break;
@@ -131,6 +165,7 @@ static uint64_t mps2_scc_read(void *opaque, hwaddr offset, unsigned size)
r = s->id;
break;
default:
+ bad_offset:
qemu_log_mask(LOG_GUEST_ERROR,
"MPS2 SCC read: bad offset %x\n", (int) offset);
r = 0;
@@ -159,6 +194,30 @@ static void mps2_scc_write(void *opaque, hwaddr offset, uint64_t value,
led_set_state(s->led[i], extract32(value, i, 1));
}
break;
+ case A_CFG2:
+ if (scc_partno(s) != 0x524) {
+ /* CFG2 reserved on other boards */
+ goto bad_offset;
+ }
+ /* AN524: QSPI Select signal */
+ s->cfg2 = value;
+ break;
+ case A_CFG5:
+ if (scc_partno(s) != 0x524) {
+ /* CFG5 reserved on other boards */
+ goto bad_offset;
+ }
+ /* AN524: ACLK frequency in Hz */
+ s->cfg5 = value;
+ break;
+ case A_CFG6:
+ if (scc_partno(s) != 0x524) {
+ /* CFG6 reserved on other boards */
+ goto bad_offset;
+ }
+ /* AN524: Clock divider for BRAM */
+ s->cfg6 = value;
+ break;
case A_CFGDATA_OUT:
s->cfgdata_out = value;
break;
@@ -202,6 +261,7 @@ static void mps2_scc_write(void *opaque, hwaddr offset, uint64_t value,
s->dll = deposit32(s->dll, 24, 8, extract32(value, 24, 8));
break;
default:
+ bad_offset:
qemu_log_mask(LOG_GUEST_ERROR,
"MPS2 SCC write: bad offset 0x%x\n", (int) offset);
break;
@@ -222,12 +282,15 @@ static void mps2_scc_reset(DeviceState *dev)
trace_mps2_scc_reset();
s->cfg0 = 0;
s->cfg1 = 0;
+ s->cfg2 = 0;
+ s->cfg5 = 0;
+ s->cfg6 = 0;
s->cfgdata_rtn = 0;
s->cfgdata_out = 0;
s->cfgctrl = 0x100000;
s->cfgstat = 0;
s->dll = 0xffff0001;
- for (i = 0; i < NUM_OSCCLK; i++) {
+ for (i = 0; i < s->num_oscclk; i++) {
s->oscclk[i] = s->oscclk_reset[i];
}
for (i = 0; i < ARRAY_SIZE(s->led); i++) {
@@ -254,21 +317,28 @@ static void mps2_scc_realize(DeviceState *dev, Error **errp)
LED_COLOR_GREEN, name);
g_free(name);
}
+
+ s->oscclk = g_new0(uint32_t, s->num_oscclk);
}
static const VMStateDescription mps2_scc_vmstate = {
.name = "mps2-scc",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 3,
+ .minimum_version_id = 3,
.fields = (VMStateField[]) {
VMSTATE_UINT32(cfg0, MPS2SCC),
VMSTATE_UINT32(cfg1, MPS2SCC),
+ VMSTATE_UINT32(cfg2, MPS2SCC),
+ /* cfg3, cfg4 are read-only so need not be migrated */
+ VMSTATE_UINT32(cfg5, MPS2SCC),
+ VMSTATE_UINT32(cfg6, MPS2SCC),
VMSTATE_UINT32(cfgdata_rtn, MPS2SCC),
VMSTATE_UINT32(cfgdata_out, MPS2SCC),
VMSTATE_UINT32(cfgctrl, MPS2SCC),
VMSTATE_UINT32(cfgstat, MPS2SCC),
VMSTATE_UINT32(dll, MPS2SCC),
- VMSTATE_UINT32_ARRAY(oscclk, MPS2SCC, NUM_OSCCLK),
+ VMSTATE_VARRAY_UINT32(oscclk, MPS2SCC, num_oscclk,
+ 0, vmstate_info_uint32, uint32_t),
VMSTATE_END_OF_LIST()
}
};
@@ -280,14 +350,13 @@ static Property mps2_scc_properties[] = {
DEFINE_PROP_UINT32("scc-cfg4", MPS2SCC, cfg4, 0),
DEFINE_PROP_UINT32("scc-aid", MPS2SCC, aid, 0),
DEFINE_PROP_UINT32("scc-id", MPS2SCC, id, 0),
- /* These are the initial settings for the source clocks on the board.
+ /*
+ * These are the initial settings for the source clocks on the board.
* In hardware they can be configured via a config file read by the
* motherboard configuration controller to suit the FPGA image.
- * These default values are used by most of the standard FPGA images.
*/
- DEFINE_PROP_UINT32("oscclk0", MPS2SCC, oscclk_reset[0], 50000000),
- DEFINE_PROP_UINT32("oscclk1", MPS2SCC, oscclk_reset[1], 24576000),
- DEFINE_PROP_UINT32("oscclk2", MPS2SCC, oscclk_reset[2], 25000000),
+ DEFINE_PROP_ARRAY("oscclk", MPS2SCC, num_oscclk, oscclk_reset,
+ qdev_prop_uint32, uint32_t),
DEFINE_PROP_END_OF_LIST(),
};