aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2018-06-08 16:26:51 +0100
committerPeter Maydell <peter.maydell@linaro.org>2018-06-08 16:26:51 +0100
commit0d2fa03dae4fbe185a082f361342b1e30aed4582 (patch)
tree2ee9e184f32e4884cf78078841e31df7f15ffea5
parented6b018ef7667f73aa25190b04e1fe3a4a87c323 (diff)
parent113f31c06c6bf16451892b2459d83c9b9c5e9844 (diff)
downloadqemu-0d2fa03dae4fbe185a082f361342b1e30aed4582.zip
qemu-0d2fa03dae4fbe185a082f361342b1e30aed4582.tar.gz
qemu-0d2fa03dae4fbe185a082f361342b1e30aed4582.tar.bz2
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20180608' into staging
target-arm queue: * arm_gicv3_kvm: fix migration of registers corresponding to IRQs 992 to 1020 in the KVM GIC * aspeed: remove ignore_memory_transaction_failures on all boards * aspeed: add support for the witherspoon-bmc board * aspeed: add an I2C RTC device and EEPROM I2C devices * aspeed: add the pc9552 chips to the witherspoon machine * ftgmac100: fix various bugs * hw/arm: Remove the deprecated xlnx-ep108 machine * hw/i2c: Add trace events * add missing '\n' on various qemu_log() logging strings * sdcard: clean up spec version support so we report the right spec version to the guest and only implement the commands that are supposed to be present in that version # gpg: Signature made Fri 08 Jun 2018 13:36:37 BST # gpg: using RSA key 3C2525ED14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20180608: (31 commits) sdcard: Disable CMD19/CMD23 for Spec v2 sdcard: Reflect when the Spec v3 is supported in the Config Register (SCR) sdcard: Disable SEND_IF_COND (CMD8) for Spec v1 sdcard: Add a 'spec_version' property, default to Spec v2.00 sdcard: Allow commands valid in SPI mode sdcard: Update the Configuration Register (SCR) to Spec Version 1.10 target/xtensa: Add trailing '\n' to qemu_log() calls RISC-V: Add trailing '\n' to qemu_log() calls target/m68k: Add trailing '\n' to qemu_log() call target/arm: Add trailing '\n' to qemu_log() calls stellaris: Add trailing '\n' to qemu_log() calls hw/mips/boston: Add trailing '\n' to qemu_log() calls hw/core/register: Add trailing '\n' to qemu_log() call ppc/pnv: Add trailing '\n' to qemu_log() calls xilinx-dp: Add trailing '\n' to qemu_log() call hw/digic: Add trailing '\n' to qemu_log() calls hw/sd/milkymist-memcard: Add trailing '\n' to qemu_log() call hw/i2c: Add trace events hw/arm: Remove the deprecated xlnx-ep108 machine ftgmac100: remove check on runt messages ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--Makefile.objs1
-rw-r--r--default-configs/arm-softmmu.mak1
-rw-r--r--hw/arm/aspeed.c88
-rw-r--r--hw/arm/stellaris.c11
-rw-r--r--hw/arm/xlnx-zcu102.c62
-rw-r--r--hw/char/digic-uart.c4
-rw-r--r--hw/core/register.c2
-rw-r--r--hw/display/xlnx_dp.c4
-rw-r--r--hw/i2c/core.c25
-rw-r--r--hw/i2c/smbus_eeprom.c16
-rw-r--r--hw/i2c/trace-events7
-rw-r--r--hw/intc/arm_gicv3_common.c79
-rw-r--r--hw/intc/arm_gicv3_kvm.c38
-rw-r--r--hw/mips/boston.c8
-rw-r--r--hw/misc/Makefile.objs1
-rw-r--r--hw/misc/pca9552.c240
-rw-r--r--hw/net/ftgmac100.c64
-rw-r--r--hw/ppc/pnv_core.c4
-rw-r--r--hw/sd/milkymist-memcard.c2
-rw-r--r--hw/sd/sd.c50
-rw-r--r--hw/timer/digic-timer.c4
-rw-r--r--include/hw/i2c/smbus.h1
-rw-r--r--include/hw/intc/arm_gicv3_common.h1
-rw-r--r--include/hw/misc/pca9552.h32
-rw-r--r--include/hw/misc/pca9552_regs.h32
-rw-r--r--include/hw/net/ftgmac100.h7
-rw-r--r--include/hw/sd/sd.h6
-rw-r--r--qemu-doc.texi5
-rw-r--r--target/arm/helper.c4
-rw-r--r--target/m68k/translate.c2
-rw-r--r--target/riscv/op_helper.c6
-rw-r--r--target/xtensa/translate.c6
-rw-r--r--tests/Makefile.include2
-rw-r--r--tests/libqos/i2c.h2
-rw-r--r--tests/pca9552-test.c116
-rw-r--r--tests/tmp105-test.c2
36 files changed, 788 insertions, 147 deletions
diff --git a/Makefile.objs b/Makefile.objs
index 2c8cb72..7a9828d 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -213,6 +213,7 @@ trace-events-subdirs += hw/char
trace-events-subdirs += hw/display
trace-events-subdirs += hw/dma
trace-events-subdirs += hw/hppa
+trace-events-subdirs += hw/i2c
trace-events-subdirs += hw/i386
trace-events-subdirs += hw/i386/xen
trace-events-subdirs += hw/ide
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 8ba2558..7cf73d2 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -16,6 +16,7 @@ CONFIG_TSC2005=y
CONFIG_LM832X=y
CONFIG_TMP105=y
CONFIG_TMP421=y
+CONFIG_PCA9552=y
CONFIG_STELLARIS=y
CONFIG_STELLARIS_INPUT=y
CONFIG_STELLARIS_ENET=y
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index a7110a7..bb9d338 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -17,6 +17,7 @@
#include "hw/arm/arm.h"
#include "hw/arm/aspeed_soc.h"
#include "hw/boards.h"
+#include "hw/i2c/smbus.h"
#include "qemu/log.h"
#include "sysemu/block-backend.h"
#include "hw/loader.h"
@@ -45,6 +46,7 @@ enum {
PALMETTO_BMC,
AST2500_EVB,
ROMULUS_BMC,
+ WITHERSPOON_BMC,
};
/* Palmetto hardware value: 0x120CE416 */
@@ -82,8 +84,13 @@ enum {
SCU_AST2500_HW_STRAP_ACPI_ENABLE | \
SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER))
+/* Witherspoon hardware value: 0xF10AD216 (but use romulus definition) */
+#define WITHERSPOON_BMC_HW_STRAP1 ROMULUS_BMC_HW_STRAP1
+
static void palmetto_bmc_i2c_init(AspeedBoardState *bmc);
static void ast2500_evb_i2c_init(AspeedBoardState *bmc);
+static void romulus_bmc_i2c_init(AspeedBoardState *bmc);
+static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc);
static const AspeedBoardConfig aspeed_boards[] = {
[PALMETTO_BMC] = {
@@ -108,6 +115,15 @@ static const AspeedBoardConfig aspeed_boards[] = {
.fmc_model = "n25q256a",
.spi_model = "mx66l1g45g",
.num_cs = 2,
+ .i2c_init = romulus_bmc_i2c_init,
+ },
+ [WITHERSPOON_BMC] = {
+ .soc_name = "ast2500-a1",
+ .hw_strap1 = WITHERSPOON_BMC_HW_STRAP1,
+ .fmc_model = "mx25l25635e",
+ .spi_model = "mx66l1g45g",
+ .num_cs = 2,
+ .i2c_init = witherspoon_bmc_i2c_init,
},
};
@@ -248,11 +264,15 @@ static void palmetto_bmc_i2c_init(AspeedBoardState *bmc)
{
AspeedSoCState *soc = &bmc->soc;
DeviceState *dev;
+ uint8_t *eeprom_buf = g_malloc0(32 * 1024);
/* The palmetto platform expects a ds3231 RTC but a ds1338 is
* enough to provide basic RTC features. Alarms will be missing */
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 0), "ds1338", 0x68);
+ smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 0), 0x50,
+ eeprom_buf);
+
/* add a TMP423 temperature sensor */
dev = i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 2),
"tmp423", 0x4c);
@@ -278,7 +298,6 @@ static void palmetto_bmc_class_init(ObjectClass *oc, void *data)
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->no_parallel = 1;
- mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo palmetto_bmc_type = {
@@ -290,9 +309,17 @@ static const TypeInfo palmetto_bmc_type = {
static void ast2500_evb_i2c_init(AspeedBoardState *bmc)
{
AspeedSoCState *soc = &bmc->soc;
+ uint8_t *eeprom_buf = g_malloc0(8 * 1024);
+
+ smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 3), 0x50,
+ eeprom_buf);
/* The AST2500 EVB expects a LM75 but a TMP105 is compatible */
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 7), "tmp105", 0x4d);
+
+ /* The AST2500 EVB does not have an RTC. Let's pretend that one is
+ * plugged on the I2C bus header */
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32);
}
static void ast2500_evb_init(MachineState *machine)
@@ -311,7 +338,6 @@ static void ast2500_evb_class_init(ObjectClass *oc, void *data)
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->no_parallel = 1;
- mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo ast2500_evb_type = {
@@ -320,6 +346,15 @@ static const TypeInfo ast2500_evb_type = {
.class_init = ast2500_evb_class_init,
};
+static void romulus_bmc_i2c_init(AspeedBoardState *bmc)
+{
+ AspeedSoCState *soc = &bmc->soc;
+
+ /* The romulus board expects Epson RX8900 I2C RTC but a ds1338 is
+ * good enough */
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32);
+}
+
static void romulus_bmc_init(MachineState *machine)
{
aspeed_board_init(machine, &aspeed_boards[ROMULUS_BMC]);
@@ -336,7 +371,6 @@ static void romulus_bmc_class_init(ObjectClass *oc, void *data)
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->no_parallel = 1;
- mc->ignore_memory_transaction_failures = true;
}
static const TypeInfo romulus_bmc_type = {
@@ -345,11 +379,59 @@ static const TypeInfo romulus_bmc_type = {
.class_init = romulus_bmc_class_init,
};
+static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc)
+{
+ AspeedSoCState *soc = &bmc->soc;
+ uint8_t *eeprom_buf = g_malloc0(8 * 1024);
+
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 3), "pca9552", 0x60);
+
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 4), "tmp423", 0x4c);
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 5), "tmp423", 0x4c);
+
+ /* The Witherspoon expects a TMP275 but a TMP105 is compatible */
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 9), "tmp105", 0x4a);
+
+ /* The witherspoon board expects Epson RX8900 I2C RTC but a ds1338 is
+ * good enough */
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32);
+
+ smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), 0x51,
+ eeprom_buf);
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "pca9552",
+ 0x60);
+}
+
+static void witherspoon_bmc_init(MachineState *machine)
+{
+ aspeed_board_init(machine, &aspeed_boards[WITHERSPOON_BMC]);
+}
+
+static void witherspoon_bmc_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->desc = "OpenPOWER Witherspoon BMC (ARM1176)";
+ mc->init = witherspoon_bmc_init;
+ mc->max_cpus = 1;
+ mc->no_sdcard = 1;
+ mc->no_floppy = 1;
+ mc->no_cdrom = 1;
+ mc->no_parallel = 1;
+}
+
+static const TypeInfo witherspoon_bmc_type = {
+ .name = MACHINE_TYPE_NAME("witherspoon-bmc"),
+ .parent = TYPE_MACHINE,
+ .class_init = witherspoon_bmc_class_init,
+};
+
static void aspeed_machine_init(void)
{
type_register_static(&palmetto_bmc_type);
type_register_static(&ast2500_evb_type);
type_register_static(&romulus_bmc_type);
+ type_register_static(&witherspoon_bmc_type);
}
type_init(aspeed_machine_init)
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
index e886f54..502a208 100644
--- a/hw/arm/stellaris.c
+++ b/hw/arm/stellaris.c
@@ -203,11 +203,11 @@ static uint64_t gptm_read(void *opaque, hwaddr offset,
return s->rtc;
}
qemu_log_mask(LOG_UNIMP,
- "GPTM: read of TAR but timer read not supported");
+ "GPTM: read of TAR but timer read not supported\n");
return 0;
case 0x4c: /* TBR */
qemu_log_mask(LOG_UNIMP,
- "GPTM: read of TBR but timer read not supported");
+ "GPTM: read of TBR but timer read not supported\n");
return 0;
default:
qemu_log_mask(LOG_GUEST_ERROR,
@@ -836,11 +836,12 @@ static void stellaris_i2c_write(void *opaque, hwaddr offset,
break;
case 0x20: /* MCR */
if (value & 1) {
- qemu_log_mask(LOG_UNIMP, "stellaris_i2c: Loopback not implemented");
+ qemu_log_mask(LOG_UNIMP,
+ "stellaris_i2c: Loopback not implemented\n");
}
if (value & 0x20) {
qemu_log_mask(LOG_UNIMP,
- "stellaris_i2c: Slave mode not implemented");
+ "stellaris_i2c: Slave mode not implemented\n");
}
s->mcr = value & 0x31;
break;
@@ -1124,7 +1125,7 @@ static void stellaris_adc_write(void *opaque, hwaddr offset,
s->sspri = value;
break;
case 0x28: /* PSSI */
- qemu_log_mask(LOG_UNIMP, "ADC: sample initiate unimplemented");
+ qemu_log_mask(LOG_UNIMP, "ADC: sample initiate unimplemented\n");
break;
case 0x30: /* SAC */
s->sac = value;
diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c
index c70278c..f26fd8e 100644
--- a/hw/arm/xlnx-zcu102.c
+++ b/hw/arm/xlnx-zcu102.c
@@ -39,10 +39,6 @@ typedef struct XlnxZCU102 {
#define ZCU102_MACHINE(obj) \
OBJECT_CHECK(XlnxZCU102, (obj), TYPE_ZCU102_MACHINE)
-#define TYPE_EP108_MACHINE MACHINE_TYPE_NAME("xlnx-ep108")
-#define EP108_MACHINE(obj) \
- OBJECT_CHECK(XlnxZCU102, (obj), TYPE_EP108_MACHINE)
-
static struct arm_boot_info xlnx_zcu102_binfo;
static bool zcu102_get_secure(Object *obj, Error **errp)
@@ -73,8 +69,9 @@ static void zcu102_set_virt(Object *obj, bool value, Error **errp)
s->virt = value;
}
-static void xlnx_zynqmp_init(XlnxZCU102 *s, MachineState *machine)
+static void xlnx_zcu102_init(MachineState *machine)
{
+ XlnxZCU102 *s = ZCU102_MACHINE(machine);
int i;
uint64_t ram_size = machine->ram_size;
@@ -183,60 +180,6 @@ static void xlnx_zynqmp_init(XlnxZCU102 *s, MachineState *machine)
arm_load_kernel(s->soc.boot_cpu_ptr, &xlnx_zcu102_binfo);
}
-static void xlnx_ep108_init(MachineState *machine)
-{
- XlnxZCU102 *s = EP108_MACHINE(machine);
-
- if (!qtest_enabled()) {
- info_report("The Xilinx EP108 machine is deprecated, please use the "
- "ZCU102 machine (which has the same features) instead.");
- }
-
- xlnx_zynqmp_init(s, machine);
-}
-
-static void xlnx_ep108_machine_instance_init(Object *obj)
-{
- XlnxZCU102 *s = EP108_MACHINE(obj);
-
- /* EP108, we don't support setting secure or virt */
- s->secure = false;
- s->virt = false;
-}
-
-static void xlnx_ep108_machine_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Xilinx ZynqMP EP108 board (Deprecated, please use xlnx-zcu102)";
- mc->init = xlnx_ep108_init;
- mc->block_default_type = IF_IDE;
- mc->units_per_default_bus = 1;
- mc->ignore_memory_transaction_failures = true;
- mc->max_cpus = XLNX_ZYNQMP_NUM_APU_CPUS + XLNX_ZYNQMP_NUM_RPU_CPUS;
- mc->default_cpus = XLNX_ZYNQMP_NUM_APU_CPUS;
-}
-
-static const TypeInfo xlnx_ep108_machine_init_typeinfo = {
- .name = MACHINE_TYPE_NAME("xlnx-ep108"),
- .parent = TYPE_MACHINE,
- .class_init = xlnx_ep108_machine_class_init,
- .instance_init = xlnx_ep108_machine_instance_init,
- .instance_size = sizeof(XlnxZCU102),
-};
-
-static void xlnx_ep108_machine_init_register_types(void)
-{
- type_register_static(&xlnx_ep108_machine_init_typeinfo);
-}
-
-static void xlnx_zcu102_init(MachineState *machine)
-{
- XlnxZCU102 *s = ZCU102_MACHINE(machine);
-
- xlnx_zynqmp_init(s, machine);
-}
-
static void xlnx_zcu102_machine_instance_init(Object *obj)
{
XlnxZCU102 *s = ZCU102_MACHINE(obj);
@@ -289,4 +232,3 @@ static void xlnx_zcu102_machine_init_register_types(void)
}
type_init(xlnx_zcu102_machine_init_register_types)
-type_init(xlnx_ep108_machine_init_register_types)
diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c
index 6ebcb87..ccc75ea 100644
--- a/hw/char/digic-uart.c
+++ b/hw/char/digic-uart.c
@@ -60,7 +60,7 @@ static uint64_t digic_uart_read(void *opaque, hwaddr addr,
default:
qemu_log_mask(LOG_UNIMP,
"digic-uart: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
+ TARGET_FMT_plx "\n", addr << 2);
}
return ret;
@@ -98,7 +98,7 @@ static void digic_uart_write(void *opaque, hwaddr addr, uint64_t value,
default:
qemu_log_mask(LOG_UNIMP,
"digic-uart: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
+ TARGET_FMT_plx "\n", addr << 2);
}
}
diff --git a/hw/core/register.c b/hw/core/register.c
index 0741a1a..d2d1636 100644
--- a/hw/core/register.c
+++ b/hw/core/register.c
@@ -96,7 +96,7 @@ void register_write(RegisterInfo *reg, uint64_t val, uint64_t we,
if (test) {
qemu_log_mask(LOG_UNIMP,
"%s:%s writing %#" PRIx64 " to unimplemented bits:" \
- " %#" PRIx64 "",
+ " %#" PRIx64 "\n",
prefix, reg->access->name, val, ac->unimp);
}
diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c
index 6715b9c..c32ab08 100644
--- a/hw/display/xlnx_dp.c
+++ b/hw/display/xlnx_dp.c
@@ -1074,7 +1074,9 @@ static void xlnx_dp_avbufm_write(void *opaque, hwaddr offset, uint64_t value,
case AV_BUF_STC_SNAPSHOT1:
case AV_BUF_HCOUNT_VCOUNT_INT0:
case AV_BUF_HCOUNT_VCOUNT_INT1:
- qemu_log_mask(LOG_UNIMP, "avbufm: unimplmented");
+ qemu_log_mask(LOG_UNIMP, "avbufm: unimplemented register 0x%04"
+ PRIx64 "\n",
+ offset << 2);
break;
default:
s->avbufm_registers[offset] = value;
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index ab72d5b..b547259 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -9,6 +9,7 @@
#include "qemu/osdep.h"
#include "hw/i2c/i2c.h"
+#include "trace.h"
#define I2C_BROADCAST 0x00
@@ -130,14 +131,16 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv)
}
QLIST_FOREACH(node, &bus->current_devs, next) {
+ I2CSlave *s = node->elt;
int rv;
- sc = I2C_SLAVE_GET_CLASS(node->elt);
+ sc = I2C_SLAVE_GET_CLASS(s);
/* If the bus is already busy, assume this is a repeated
start condition. */
if (sc->event) {
- rv = sc->event(node->elt, recv ? I2C_START_RECV : I2C_START_SEND);
+ trace_i2c_event("start", s->address);
+ rv = sc->event(s, recv ? I2C_START_RECV : I2C_START_SEND);
if (rv && !bus->broadcast) {
if (bus_scanned) {
/* First call, terminate the transfer. */
@@ -156,9 +159,11 @@ void i2c_end_transfer(I2CBus *bus)
I2CNode *node, *next;
QLIST_FOREACH_SAFE(node, &bus->current_devs, next, next) {
- sc = I2C_SLAVE_GET_CLASS(node->elt);
+ I2CSlave *s = node->elt;
+ sc = I2C_SLAVE_GET_CLASS(s);
if (sc->event) {
- sc->event(node->elt, I2C_FINISH);
+ trace_i2c_event("finish", s->address);
+ sc->event(s, I2C_FINISH);
}
QLIST_REMOVE(node, next);
g_free(node);
@@ -169,14 +174,17 @@ void i2c_end_transfer(I2CBus *bus)
int i2c_send_recv(I2CBus *bus, uint8_t *data, bool send)
{
I2CSlaveClass *sc;
+ I2CSlave *s;
I2CNode *node;
int ret = 0;
if (send) {
QLIST_FOREACH(node, &bus->current_devs, next) {
- sc = I2C_SLAVE_GET_CLASS(node->elt);
+ s = node->elt;
+ sc = I2C_SLAVE_GET_CLASS(s);
if (sc->send) {
- ret = ret || sc->send(node->elt, *data);
+ trace_i2c_send(s->address, *data);
+ ret = ret || sc->send(s, *data);
} else {
ret = -1;
}
@@ -189,7 +197,9 @@ int i2c_send_recv(I2CBus *bus, uint8_t *data, bool send)
sc = I2C_SLAVE_GET_CLASS(QLIST_FIRST(&bus->current_devs)->elt);
if (sc->recv) {
- ret = sc->recv(QLIST_FIRST(&bus->current_devs)->elt);
+ s = QLIST_FIRST(&bus->current_devs)->elt;
+ ret = sc->recv(s);
+ trace_i2c_recv(s->address, ret);
if (ret < 0) {
return ret;
} else {
@@ -226,6 +236,7 @@ void i2c_nack(I2CBus *bus)
QLIST_FOREACH(node, &bus->current_devs, next) {
sc = I2C_SLAVE_GET_CLASS(node->elt);
if (sc->event) {
+ trace_i2c_event("nack", node->elt->address);
sc->event(node->elt, I2C_NACK);
}
}
diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c
index 125c887..f18aa3d 100644
--- a/hw/i2c/smbus_eeprom.c
+++ b/hw/i2c/smbus_eeprom.c
@@ -139,6 +139,16 @@ static void smbus_eeprom_register_types(void)
type_init(smbus_eeprom_register_types)
+void smbus_eeprom_init_one(I2CBus *smbus, uint8_t address, uint8_t *eeprom_buf)
+{
+ DeviceState *dev;
+
+ dev = qdev_create((BusState *) smbus, "smbus-eeprom");
+ qdev_prop_set_uint8(dev, "address", address);
+ qdev_prop_set_ptr(dev, "data", eeprom_buf);
+ qdev_init_nofail(dev);
+}
+
void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom,
const uint8_t *eeprom_spd, int eeprom_spd_size)
{
@@ -149,10 +159,6 @@ void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom,
}
for (i = 0; i < nb_eeprom; i++) {
- DeviceState *eeprom;
- eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
- qdev_prop_set_uint8(eeprom, "address", 0x50 + i);
- qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256));
- qdev_init_nofail(eeprom);
+ smbus_eeprom_init_one(smbus, 0x50 + i, eeprom_buf + (i * 256));
}
}
diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events
new file mode 100644
index 0000000..d339b61
--- /dev/null
+++ b/hw/i2c/trace-events
@@ -0,0 +1,7 @@
+# See docs/devel/tracing.txt for syntax documentation.
+
+# hw/i2c/core.c
+
+i2c_event(const char *event, uint8_t address) "%s(addr:0x%02x)"
+i2c_send(uint8_t address, uint8_t data) "send(addr:0x%02x) data:0x%02x"
+i2c_recv(uint8_t address, uint8_t data) "recv(addr:0x%02x) data:0x%02x"
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 7b54d52..864b7c6 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -27,6 +27,7 @@
#include "hw/intc/arm_gicv3_common.h"
#include "gicv3_internal.h"
#include "hw/arm/linux-boot-if.h"
+#include "sysemu/kvm.h"
static int gicv3_pre_save(void *opaque)
{
@@ -141,6 +142,79 @@ static const VMStateDescription vmstate_gicv3_cpu = {
}
};
+static int gicv3_gicd_no_migration_shift_bug_pre_load(void *opaque)
+{
+ GICv3State *cs = opaque;
+
+ /*
+ * The gicd_no_migration_shift_bug flag is used for migration compatibility
+ * for old version QEMU which may have the GICD bmp shift bug under KVM mode.
+ * Strictly, what we want to know is whether the migration source is using
+ * KVM. Since we don't have any way to determine that, we look at whether the
+ * destination is using KVM; this is close enough because for the older QEMU
+ * versions with this bug KVM -> TCG migration didn't work anyway. If the
+ * source is a newer QEMU without this bug it will transmit the migration
+ * subsection which sets the flag to true; otherwise it will remain set to
+ * the value we select here.
+ */
+ if (kvm_enabled()) {
+ cs->gicd_no_migration_shift_bug = false;
+ }
+
+ return 0;
+}
+
+static int gicv3_gicd_no_migration_shift_bug_post_load(void *opaque,
+ int version_id)
+{
+ GICv3State *cs = opaque;
+
+ if (cs->gicd_no_migration_shift_bug) {
+ return 0;
+ }
+
+ /* Older versions of QEMU had a bug in the handling of state save/restore
+ * to the KVM GICv3: they got the offset in the bitmap arrays wrong,
+ * so that instead of the data for external interrupts 32 and up
+ * starting at bit position 32 in the bitmap, it started at bit
+ * position 64. If we're receiving data from a QEMU with that bug,
+ * we must move the data down into the right place.
+ */
+ memmove(cs->group, (uint8_t *)cs->group + GIC_INTERNAL / 8,
+ sizeof(cs->group) - GIC_INTERNAL / 8);
+ memmove(cs->grpmod, (uint8_t *)cs->grpmod + GIC_INTERNAL / 8,
+ sizeof(cs->grpmod) - GIC_INTERNAL / 8);
+ memmove(cs->enabled, (uint8_t *)cs->enabled + GIC_INTERNAL / 8,
+ sizeof(cs->enabled) - GIC_INTERNAL / 8);
+ memmove(cs->pending, (uint8_t *)cs->pending + GIC_INTERNAL / 8,
+ sizeof(cs->pending) - GIC_INTERNAL / 8);
+ memmove(cs->active, (uint8_t *)cs->active + GIC_INTERNAL / 8,
+ sizeof(cs->active) - GIC_INTERNAL / 8);
+ memmove(cs->edge_trigger, (uint8_t *)cs->edge_trigger + GIC_INTERNAL / 8,
+ sizeof(cs->edge_trigger) - GIC_INTERNAL / 8);
+
+ /*
+ * While this new version QEMU doesn't have this kind of bug as we fix it,
+ * so it needs to set the flag to true to indicate that and it's necessary
+ * for next migration to work from this new version QEMU.
+ */
+ cs->gicd_no_migration_shift_bug = true;
+
+ return 0;
+}
+
+const VMStateDescription vmstate_gicv3_gicd_no_migration_shift_bug = {
+ .name = "arm_gicv3/gicd_no_migration_shift_bug",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_load = gicv3_gicd_no_migration_shift_bug_pre_load,
+ .post_load = gicv3_gicd_no_migration_shift_bug_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(gicd_no_migration_shift_bug, GICv3State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_gicv3 = {
.name = "arm_gicv3",
.version_id = 1,
@@ -165,6 +239,10 @@ static const VMStateDescription vmstate_gicv3 = {
VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, GICv3State, num_cpu,
vmstate_gicv3_cpu, GICv3CPUState),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription * []) {
+ &vmstate_gicv3_gicd_no_migration_shift_bug,
+ NULL
}
};
@@ -364,6 +442,7 @@ static void arm_gicv3_common_reset(DeviceState *dev)
gicv3_gicd_group_set(s, i);
}
}
+ s->gicd_no_migration_shift_bug = true;
}
static void arm_gic_common_linux_init(ARMLinuxBootIf *obj,
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index 0279b86..5649cac 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -164,6 +164,14 @@ static void kvm_dist_get_edge_trigger(GICv3State *s, uint32_t offset,
uint32_t reg;
int irq;
+ /* For the KVM GICv3, affinity routing is always enabled, and the first 2
+ * GICD_ICFGR<n> registers are always RAZ/WI. The corresponding
+ * functionality is replaced by GICR_ICFGR<n>. It doesn't need to sync
+ * them. So it should increase the offset to skip GIC_INTERNAL irqs.
+ * This matches the for_each_dist_irq_reg() macro which also skips the
+ * first GIC_INTERNAL irqs.
+ */
+ offset += (GIC_INTERNAL * 2) / 8;
for_each_dist_irq_reg(irq, s->num_irq, 2) {
kvm_gicd_access(s, offset, &reg, false);
reg = half_unshuffle32(reg >> 1);
@@ -181,6 +189,14 @@ static void kvm_dist_put_edge_trigger(GICv3State *s, uint32_t offset,
uint32_t reg;
int irq;
+ /* For the KVM GICv3, affinity routing is always enabled, and the first 2
+ * GICD_ICFGR<n> registers are always RAZ/WI. The corresponding
+ * functionality is replaced by GICR_ICFGR<n>. It doesn't need to sync
+ * them. So it should increase the offset to skip GIC_INTERNAL irqs.
+ * This matches the for_each_dist_irq_reg() macro which also skips the
+ * first GIC_INTERNAL irqs.
+ */
+ offset += (GIC_INTERNAL * 2) / 8;
for_each_dist_irq_reg(irq, s->num_irq, 2) {
reg = *gic_bmp_ptr32(bmp, irq);
if (irq % 32 != 0) {
@@ -222,6 +238,15 @@ static void kvm_dist_getbmp(GICv3State *s, uint32_t offset, uint32_t *bmp)
uint32_t reg;
int irq;
+ /* For the KVM GICv3, affinity routing is always enabled, and the
+ * GICD_IGROUPR0/GICD_IGRPMODR0/GICD_ISENABLER0/GICD_ISPENDR0/
+ * GICD_ISACTIVER0 registers are always RAZ/WI. The corresponding
+ * functionality is replaced by the GICR registers. It doesn't need to sync
+ * them. So it should increase the offset to skip GIC_INTERNAL irqs.
+ * This matches the for_each_dist_irq_reg() macro which also skips the
+ * first GIC_INTERNAL irqs.
+ */
+ offset += (GIC_INTERNAL * 1) / 8;
for_each_dist_irq_reg(irq, s->num_irq, 1) {
kvm_gicd_access(s, offset, &reg, false);
*gic_bmp_ptr32(bmp, irq) = reg;
@@ -235,6 +260,19 @@ static void kvm_dist_putbmp(GICv3State *s, uint32_t offset,
uint32_t reg;
int irq;
+ /* For the KVM GICv3, affinity routing is always enabled, and the
+ * GICD_IGROUPR0/GICD_IGRPMODR0/GICD_ISENABLER0/GICD_ISPENDR0/
+ * GICD_ISACTIVER0 registers are always RAZ/WI. The corresponding
+ * functionality is replaced by the GICR registers. It doesn't need to sync
+ * them. So it should increase the offset and clroffset to skip GIC_INTERNAL
+ * irqs. This matches the for_each_dist_irq_reg() macro which also skips the
+ * first GIC_INTERNAL irqs.
+ */
+ offset += (GIC_INTERNAL * 1) / 8;
+ if (clroffset != 0) {
+ clroffset += (GIC_INTERNAL * 1) / 8;
+ }
+
for_each_dist_irq_reg(irq, s->num_irq, 1) {
/* If this bitmap is a set/clear register pair, first write to the
* clear-reg to clear all bits before using the set-reg to write
diff --git a/hw/mips/boston.c b/hw/mips/boston.c
index 5302e5c..52cce19 100644
--- a/hw/mips/boston.c
+++ b/hw/mips/boston.c
@@ -176,7 +176,7 @@ static uint64_t boston_platreg_read(void *opaque, hwaddr addr,
uint32_t gic_freq, val;
if (size != 4) {
- qemu_log_mask(LOG_UNIMP, "%uB platform register read", size);
+ qemu_log_mask(LOG_UNIMP, "%uB platform register read\n", size);
return 0;
}
@@ -205,7 +205,7 @@ static uint64_t boston_platreg_read(void *opaque, hwaddr addr,
val |= PLAT_DDR_CFG_MHZ;
return val;
default:
- qemu_log_mask(LOG_UNIMP, "Read platform register 0x%" HWADDR_PRIx,
+ qemu_log_mask(LOG_UNIMP, "Read platform register 0x%" HWADDR_PRIx "\n",
addr & 0xffff);
return 0;
}
@@ -215,7 +215,7 @@ static void boston_platreg_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
if (size != 4) {
- qemu_log_mask(LOG_UNIMP, "%uB platform register write", size);
+ qemu_log_mask(LOG_UNIMP, "%uB platform register write\n", size);
return;
}
@@ -237,7 +237,7 @@ static void boston_platreg_write(void *opaque, hwaddr addr,
break;
default:
qemu_log_mask(LOG_UNIMP, "Write platform register 0x%" HWADDR_PRIx
- " = 0x%" PRIx64, addr & 0xffff, val);
+ " = 0x%" PRIx64 "\n", addr & 0xffff, val);
break;
}
}
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 00e834d..ecd8d61 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -7,6 +7,7 @@ common-obj-$(CONFIG_SGA) += sga.o
common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o
common-obj-$(CONFIG_PCI_TESTDEV) += pci-testdev.o
common-obj-$(CONFIG_EDU) += edu.o
+common-obj-$(CONFIG_PCA9552) += pca9552.o
common-obj-y += unimp.o
common-obj-$(CONFIG_FW_CFG_DMA) += vmcoreinfo.o
diff --git a/hw/misc/pca9552.c b/hw/misc/pca9552.c
new file mode 100644
index 0000000..9775d52
--- /dev/null
+++ b/hw/misc/pca9552.c
@@ -0,0 +1,240 @@
+/*
+ * PCA9552 I2C LED blinker
+ *
+ * https://www.nxp.com/docs/en/application-note/AN264.pdf
+ *
+ * Copyright (c) 2017-2018, IBM Corporation.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/hw.h"
+#include "hw/misc/pca9552.h"
+#include "hw/misc/pca9552_regs.h"
+
+#define PCA9552_LED_ON 0x0
+#define PCA9552_LED_OFF 0x1
+#define PCA9552_LED_PWM0 0x2
+#define PCA9552_LED_PWM1 0x3
+
+static uint8_t pca9552_pin_get_config(PCA9552State *s, int pin)
+{
+ uint8_t reg = PCA9552_LS0 + (pin / 4);
+ uint8_t shift = (pin % 4) << 1;
+
+ return extract32(s->regs[reg], shift, 2);
+}
+
+static void pca9552_update_pin_input(PCA9552State *s)
+{
+ int i;
+
+ for (i = 0; i < s->nr_leds; i++) {
+ uint8_t input_reg = PCA9552_INPUT0 + (i / 8);
+ uint8_t input_shift = (i % 8);
+ uint8_t config = pca9552_pin_get_config(s, i);
+
+ switch (config) {
+ case PCA9552_LED_ON:
+ s->regs[input_reg] |= 1 << input_shift;
+ break;
+ case PCA9552_LED_OFF:
+ s->regs[input_reg] &= ~(1 << input_shift);
+ break;
+ case PCA9552_LED_PWM0:
+ case PCA9552_LED_PWM1:
+ /* TODO */
+ default:
+ break;
+ }
+ }
+}
+
+static uint8_t pca9552_read(PCA9552State *s, uint8_t reg)
+{
+ switch (reg) {
+ case PCA9552_INPUT0:
+ case PCA9552_INPUT1:
+ case PCA9552_PSC0:
+ case PCA9552_PWM0:
+ case PCA9552_PSC1:
+ case PCA9552_PWM1:
+ case PCA9552_LS0:
+ case PCA9552_LS1:
+ case PCA9552_LS2:
+ case PCA9552_LS3:
+ return s->regs[reg];
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: unexpected read to register %d\n",
+ __func__, reg);
+ return 0xFF;
+ }
+}
+
+static void pca9552_write(PCA9552State *s, uint8_t reg, uint8_t data)
+{
+ switch (reg) {
+ case PCA9552_PSC0:
+ case PCA9552_PWM0:
+ case PCA9552_PSC1:
+ case PCA9552_PWM1:
+ s->regs[reg] = data;
+ break;
+
+ case PCA9552_LS0:
+ case PCA9552_LS1:
+ case PCA9552_LS2:
+ case PCA9552_LS3:
+ s->regs[reg] = data;
+ pca9552_update_pin_input(s);
+ break;
+
+ case PCA9552_INPUT0:
+ case PCA9552_INPUT1:
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: unexpected write to register %d\n",
+ __func__, reg);
+ }
+}
+
+/*
+ * When Auto-Increment is on, the register address is incremented
+ * after each byte is sent to or received by the device. The index
+ * rollovers to 0 when the maximum register address is reached.
+ */
+static void pca9552_autoinc(PCA9552State *s)
+{
+ if (s->pointer != 0xFF && s->pointer & PCA9552_AUTOINC) {
+ uint8_t reg = s->pointer & 0xf;
+
+ reg = (reg + 1) % (s->max_reg + 1);
+ s->pointer = reg | PCA9552_AUTOINC;
+ }
+}
+
+static int pca9552_recv(I2CSlave *i2c)
+{
+ PCA9552State *s = PCA9552(i2c);
+ uint8_t ret;
+
+ ret = pca9552_read(s, s->pointer & 0xf);
+
+ /*
+ * From the Specs:
+ *
+ * Important Note: When a Read sequence is initiated and the
+ * AI bit is set to Logic Level 1, the Read Sequence MUST
+ * start by a register different from 0.
+ *
+ * I don't know what should be done in this case, so throw an
+ * error.
+ */
+ if (s->pointer == PCA9552_AUTOINC) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Autoincrement read starting with register 0\n",
+ __func__);
+ }
+
+ pca9552_autoinc(s);
+
+ return ret;
+}
+
+static int pca9552_send(I2CSlave *i2c, uint8_t data)
+{
+ PCA9552State *s = PCA9552(i2c);
+
+ /* First byte sent by is the register address */
+ if (s->len == 0) {
+ s->pointer = data;
+ s->len++;
+ } else {
+ pca9552_write(s, s->pointer & 0xf, data);
+
+ pca9552_autoinc(s);
+ }
+
+ return 0;
+}
+
+static int pca9552_event(I2CSlave *i2c, enum i2c_event event)
+{
+ PCA9552State *s = PCA9552(i2c);
+
+ s->len = 0;
+ return 0;
+}
+
+static const VMStateDescription pca9552_vmstate = {
+ .name = "PCA9552",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(len, PCA9552State),
+ VMSTATE_UINT8(pointer, PCA9552State),
+ VMSTATE_UINT8_ARRAY(regs, PCA9552State, PCA9552_NR_REGS),
+ VMSTATE_I2C_SLAVE(i2c, PCA9552State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void pca9552_reset(DeviceState *dev)
+{
+ PCA9552State *s = PCA9552(dev);
+
+ s->regs[PCA9552_PSC0] = 0xFF;
+ s->regs[PCA9552_PWM0] = 0x80;
+ s->regs[PCA9552_PSC1] = 0xFF;
+ s->regs[PCA9552_PWM1] = 0x80;
+ s->regs[PCA9552_LS0] = 0x55; /* all OFF */
+ s->regs[PCA9552_LS1] = 0x55;
+ s->regs[PCA9552_LS2] = 0x55;
+ s->regs[PCA9552_LS3] = 0x55;
+
+ pca9552_update_pin_input(s);
+
+ s->pointer = 0xFF;
+ s->len = 0;
+}
+
+static void pca9552_initfn(Object *obj)
+{
+ PCA9552State *s = PCA9552(obj);
+
+ /* If support for the other PCA955X devices are implemented, these
+ * constant values might be part of class structure describing the
+ * PCA955X device
+ */
+ s->max_reg = PCA9552_LS3;
+ s->nr_leds = 16;
+}
+
+static void pca9552_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->event = pca9552_event;
+ k->recv = pca9552_recv;
+ k->send = pca9552_send;
+ dc->reset = pca9552_reset;
+ dc->vmsd = &pca9552_vmstate;
+}
+
+static const TypeInfo pca9552_info = {
+ .name = TYPE_PCA9552,
+ .parent = TYPE_I2C_SLAVE,
+ .instance_init = pca9552_initfn,
+ .instance_size = sizeof(PCA9552State),
+ .class_init = pca9552_class_init,
+};
+
+static void pca9552_register_types(void)
+{
+ type_register_static(&pca9552_info);
+}
+
+type_init(pca9552_register_types)
diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c
index 3300e8e..909c118 100644
--- a/hw/net/ftgmac100.c
+++ b/hw/net/ftgmac100.c
@@ -207,16 +207,18 @@ typedef struct {
/*
* Max frame size for the receiving buffer
*/
-#define FTGMAC100_MAX_FRAME_SIZE 10240
+#define FTGMAC100_MAX_FRAME_SIZE 9220
/* Limits depending on the type of the frame
*
* 9216 for Jumbo frames (+ 4 for VLAN)
* 1518 for other frames (+ 4 for VLAN)
*/
-static int ftgmac100_max_frame_size(FTGMAC100State *s)
+static int ftgmac100_max_frame_size(FTGMAC100State *s, uint16_t proto)
{
- return (s->maccr & FTGMAC100_MACCR_JUMBO_LF ? 9216 : 1518) + 4;
+ int max = (s->maccr & FTGMAC100_MACCR_JUMBO_LF ? 9216 : 1518);
+
+ return max + (proto == ETH_P_VLAN ? 4 : 0);
}
static void ftgmac100_update_irq(FTGMAC100State *s)
@@ -408,7 +410,6 @@ static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring,
uint8_t *ptr = s->frame;
uint32_t addr = tx_descriptor;
uint32_t flags = 0;
- int max_frame_size = ftgmac100_max_frame_size(s);
while (1) {
FTGMAC100Desc bd;
@@ -427,11 +428,12 @@ static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring,
flags = bd.des1;
}
- len = bd.des0 & 0x3FFF;
- if (frame_size + len > max_frame_size) {
+ len = FTGMAC100_TXDES0_TXBUF_SIZE(bd.des0);
+ if (frame_size + len > sizeof(s->frame)) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: frame too big : %d bytes\n",
__func__, len);
- len = max_frame_size - frame_size;
+ s->isr |= FTGMAC100_INT_XPKT_LOST;
+ len = sizeof(s->frame) - frame_size;
}
if (dma_memory_read(&address_space_memory, bd.des3, ptr, len)) {
@@ -441,6 +443,22 @@ static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring,
break;
}
+ /* Check for VLAN */
+ if (bd.des0 & FTGMAC100_TXDES0_FTS &&
+ bd.des1 & FTGMAC100_TXDES1_INS_VLANTAG &&
+ be16_to_cpu(PKT_GET_ETH_HDR(ptr)->h_proto) != ETH_P_VLAN) {
+ if (frame_size + len + 4 > sizeof(s->frame)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: frame too big : %d bytes\n",
+ __func__, len);
+ s->isr |= FTGMAC100_INT_XPKT_LOST;
+ len = sizeof(s->frame) - frame_size - 4;
+ }
+ memmove(ptr + 16, ptr + 12, len - 12);
+ stw_be_p(ptr + 12, ETH_P_VLAN);
+ stw_be_p(ptr + 14, bd.des1);
+ len += 4;
+ }
+
ptr += len;
frame_size += len;
if (bd.des0 & FTGMAC100_TXDES0_LTS) {
@@ -758,8 +776,8 @@ static int ftgmac100_filter(FTGMAC100State *s, const uint8_t *buf, size_t len)
return 0;
}
- /* TODO: this does not seem to work for ftgmac100 */
- mcast_idx = net_crc32(buf, ETH_ALEN) >> 26;
+ mcast_idx = net_crc32_le(buf, ETH_ALEN);
+ mcast_idx = (~(mcast_idx >> 2)) & 0x3f;
if (!(s->math[mcast_idx / 32] & (1 << (mcast_idx % 32)))) {
return 0;
}
@@ -788,7 +806,8 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf,
uint32_t buf_len;
size_t size = len;
uint32_t first = FTGMAC100_RXDES0_FRS;
- int max_frame_size = ftgmac100_max_frame_size(s);
+ uint16_t proto = be16_to_cpu(PKT_GET_ETH_HDR(buf)->h_proto);
+ int max_frame_size = ftgmac100_max_frame_size(s, proto);
if ((s->maccr & (FTGMAC100_MACCR_RXDMA_EN | FTGMAC100_MACCR_RXMAC_EN))
!= (FTGMAC100_MACCR_RXDMA_EN | FTGMAC100_MACCR_RXMAC_EN)) {
@@ -803,12 +822,6 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf,
return size;
}
- if (size < 64 && !(s->maccr & FTGMAC100_MACCR_RX_RUNT)) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: dropped runt frame of %zd bytes\n",
- __func__, size);
- return size;
- }
-
if (!ftgmac100_filter(s, buf, size)) {
return size;
}
@@ -820,9 +833,9 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf,
/* Huge frames are truncated. */
if (size > max_frame_size) {
- size = max_frame_size;
qemu_log_mask(LOG_GUEST_ERROR, "%s: frame too big : %zd bytes\n",
__func__, size);
+ size = max_frame_size;
flags |= FTGMAC100_RXDES0_FTL;
}
@@ -861,7 +874,20 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf,
buf_len += size - 4;
}
buf_addr = bd.des3;
- dma_memory_write(&address_space_memory, buf_addr, buf, buf_len);
+ if (first && proto == ETH_P_VLAN && buf_len >= 18) {
+ bd.des1 = lduw_be_p(buf + 14) | FTGMAC100_RXDES1_VLANTAG_AVAIL;
+
+ if (s->maccr & FTGMAC100_MACCR_RM_VLAN) {
+ dma_memory_write(&address_space_memory, buf_addr, buf, 12);
+ dma_memory_write(&address_space_memory, buf_addr + 12, buf + 16,
+ buf_len - 16);
+ } else {
+ dma_memory_write(&address_space_memory, buf_addr, buf, buf_len);
+ }
+ } else {
+ bd.des1 = 0;
+ dma_memory_write(&address_space_memory, buf_addr, buf, buf_len);
+ }
buf += buf_len;
if (size < 4) {
dma_memory_write(&address_space_memory, buf_addr + buf_len,
@@ -940,8 +966,6 @@ static void ftgmac100_realize(DeviceState *dev, Error **errp)
object_get_typename(OBJECT(dev)), DEVICE(dev)->id,
s);
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
- s->frame = g_malloc(FTGMAC100_MAX_FRAME_SIZE);
}
static const VMStateDescription vmstate_ftgmac100 = {
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index cbb64ad..13ad7d9 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -97,7 +97,7 @@ static uint64_t pnv_core_xscom_read(void *opaque, hwaddr addr,
val = 0x24f000000000000ull;
break;
default:
- qemu_log_mask(LOG_UNIMP, "Warning: reading reg=0x%" HWADDR_PRIx,
+ qemu_log_mask(LOG_UNIMP, "Warning: reading reg=0x%" HWADDR_PRIx "\n",
addr);
}
@@ -107,7 +107,7 @@ static uint64_t pnv_core_xscom_read(void *opaque, hwaddr addr,
static void pnv_core_xscom_write(void *opaque, hwaddr addr, uint64_t val,
unsigned int width)
{
- qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx,
+ qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx "\n",
addr);
}
diff --git a/hw/sd/milkymist-memcard.c b/hw/sd/milkymist-memcard.c
index fe1cccc..fcbccf5 100644
--- a/hw/sd/milkymist-memcard.c
+++ b/hw/sd/milkymist-memcard.c
@@ -140,7 +140,7 @@ static uint64_t memcard_read(void *opaque, hwaddr addr,
r = s->response[s->response_read_ptr++];
if (s->response_read_ptr > s->response_len) {
qemu_log_mask(LOG_GUEST_ERROR, "milkymist_memcard: "
- "read more cmd bytes than available. Clipping.");
+ "read more cmd bytes than available: clipping\n");
s->response_read_ptr = 0;
}
}
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 7af19fa..540bccb 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -1,9 +1,10 @@
/*
* SD Memory Card emulation as defined in the "SD Memory Card Physical
- * layer specification, Version 1.10."
+ * layer specification, Version 2.00."
*
* Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
* Copyright (c) 2007 CodeSourcery
+ * Copyright (c) 2018 Philippe Mathieu-Daudé <f4bug@amsat.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -91,6 +92,7 @@ struct SDState {
uint8_t sd_status[64];
/* Configurable properties */
+ uint8_t spec_version;
BlockBackend *blk;
bool spi;
@@ -310,11 +312,18 @@ static void sd_ocr_powerup(void *opaque)
static void sd_set_scr(SDState *sd)
{
- sd->scr[0] = (0 << 4) /* SCR version 1.0 */
- | 0; /* Spec Versions 1.0 and 1.01 */
+ sd->scr[0] = 0 << 4; /* SCR structure version 1.0 */
+ if (sd->spec_version == SD_PHY_SPECv1_10_VERS) {
+ sd->scr[0] |= 1; /* Spec Version 1.10 */
+ } else {
+ sd->scr[0] |= 2; /* Spec Version 2.00 or Version 3.0X */
+ }
sd->scr[1] = (2 << 4) /* SDSC Card (Security Version 1.01) */
| 0b0101; /* 1-bit or 4-bit width bus modes */
sd->scr[2] = 0x00; /* Extended Security is not supported. */
+ if (sd->spec_version >= SD_PHY_SPECv3_01_VERS) {
+ sd->scr[2] |= 1 << 7; /* Spec Version 3.0X */
+ }
sd->scr[3] = 0x00;
/* reserved for manufacturer usage */
sd->scr[4] = 0x00;
@@ -960,8 +969,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
return sd_illegal;
case 6: /* CMD6: SWITCH_FUNCTION */
- if (sd->spi)
- goto bad_cmd;
switch (sd->mode) {
case sd_data_transfer_mode:
sd_function_switch(sd, req.arg);
@@ -1014,7 +1021,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
break;
case 8: /* CMD8: SEND_IF_COND */
- /* Physical Layer Specification Version 2.00 command */
+ if (sd->spec_version < SD_PHY_SPECv2_00_VERS) {
+ break;
+ }
if (sd->state != sd_idle_state) {
break;
}
@@ -1170,6 +1179,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
break;
case 19: /* CMD19: SEND_TUNING_BLOCK (SD) */
+ if (sd->spec_version < SD_PHY_SPECv3_01_VERS) {
+ break;
+ }
if (sd->state == sd_transfer_state) {
sd->state = sd_sendingdata_state;
sd->data_offset = 0;
@@ -1178,6 +1190,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
break;
case 23: /* CMD23: SET_BLOCK_COUNT */
+ if (sd->spec_version < SD_PHY_SPECv3_01_VERS) {
+ break;
+ }
switch (sd->state) {
case sd_transfer_state:
sd->multi_blk_cnt = req.arg;
@@ -1190,9 +1205,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
/* Block write commands (Class 4) */
case 24: /* CMD24: WRITE_SINGLE_BLOCK */
- if (sd->spi) {
- goto unimplemented_spi_cmd;
- }
switch (sd->state) {
case sd_transfer_state:
/* Writing in SPI mode not implemented. */
@@ -1217,9 +1229,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
break;
case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */
- if (sd->spi) {
- goto unimplemented_spi_cmd;
- }
switch (sd->state) {
case sd_transfer_state:
/* Writing in SPI mode not implemented. */
@@ -1259,9 +1268,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
break;
case 27: /* CMD27: PROGRAM_CSD */
- if (sd->spi) {
- goto unimplemented_spi_cmd;
- }
switch (sd->state) {
case sd_transfer_state:
sd->state = sd_receivingdata_state;
@@ -1371,9 +1377,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
/* Lock card commands (Class 7) */
case 42: /* CMD42: LOCK_UNLOCK */
- if (sd->spi) {
- goto unimplemented_spi_cmd;
- }
switch (sd->state) {
case sd_transfer_state:
sd->state = sd_receivingdata_state;
@@ -2072,6 +2075,15 @@ static void sd_realize(DeviceState *dev, Error **errp)
sd->proto_name = sd->spi ? "SPI" : "SD";
+ switch (sd->spec_version) {
+ case SD_PHY_SPECv1_10_VERS
+ ... SD_PHY_SPECv3_01_VERS:
+ break;
+ default:
+ error_setg(errp, "Invalid SD card Spec version: %u", sd->spec_version);
+ return;
+ }
+
if (sd->blk && blk_is_read_only(sd->blk)) {
error_setg(errp, "Cannot use read-only drive as SD card");
return;
@@ -2088,6 +2100,8 @@ static void sd_realize(DeviceState *dev, Error **errp)
}
static Property sd_properties[] = {
+ DEFINE_PROP_UINT8("spec_version", SDState,
+ spec_version, SD_PHY_SPECv2_00_VERS),
DEFINE_PROP_DRIVE("drive", SDState, blk),
/* We do not model the chip select pin, so allow the board to select
* whether card should be in SSI or MMC/SD mode. It is also up to the
diff --git a/hw/timer/digic-timer.c b/hw/timer/digic-timer.c
index e1fcf73..4d73077 100644
--- a/hw/timer/digic-timer.c
+++ b/hw/timer/digic-timer.c
@@ -73,7 +73,7 @@ static uint64_t digic_timer_read(void *opaque, hwaddr offset, unsigned size)
default:
qemu_log_mask(LOG_UNIMP,
"digic-timer: read access to unknown register 0x"
- TARGET_FMT_plx, offset);
+ TARGET_FMT_plx "\n", offset);
}
return ret;
@@ -109,7 +109,7 @@ static void digic_timer_write(void *opaque, hwaddr offset,
default:
qemu_log_mask(LOG_UNIMP,
"digic-timer: read access to unknown register 0x"
- TARGET_FMT_plx, offset);
+ TARGET_FMT_plx "\n", offset);
}
}
diff --git a/include/hw/i2c/smbus.h b/include/hw/i2c/smbus.h
index cfe3fa6..4fdba02 100644
--- a/include/hw/i2c/smbus.h
+++ b/include/hw/i2c/smbus.h
@@ -76,6 +76,7 @@ int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data);
int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
int len);
+void smbus_eeprom_init_one(I2CBus *smbus, uint8_t address, uint8_t *eeprom_buf);
void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom,
const uint8_t *eeprom_spd, int size);
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index bccdfe1..d75b49d 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -217,6 +217,7 @@ struct GICv3State {
uint32_t revision;
bool security_extn;
bool irq_reset_nonsecure;
+ bool gicd_no_migration_shift_bug;
int dev_fd; /* kvm device fd if backed by kvm vgic support */
Error *migration_blocker;
diff --git a/include/hw/misc/pca9552.h b/include/hw/misc/pca9552.h
new file mode 100644
index 0000000..ebb43c6
--- /dev/null
+++ b/include/hw/misc/pca9552.h
@@ -0,0 +1,32 @@
+/*
+ * PCA9552 I2C LED blinker
+ *
+ * Copyright (c) 2017-2018, IBM Corporation.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+#ifndef PCA9552_H
+#define PCA9552_H
+
+#include "hw/i2c/i2c.h"
+
+#define TYPE_PCA9552 "pca9552"
+#define PCA9552(obj) OBJECT_CHECK(PCA9552State, (obj), TYPE_PCA9552)
+
+#define PCA9552_NR_REGS 10
+
+typedef struct PCA9552State {
+ /*< private >*/
+ I2CSlave i2c;
+ /*< public >*/
+
+ uint8_t len;
+ uint8_t pointer;
+
+ uint8_t regs[PCA9552_NR_REGS];
+ uint8_t max_reg;
+ uint8_t nr_leds;
+} PCA9552State;
+
+#endif
diff --git a/include/hw/misc/pca9552_regs.h b/include/hw/misc/pca9552_regs.h
new file mode 100644
index 0000000..d8051cf
--- /dev/null
+++ b/include/hw/misc/pca9552_regs.h
@@ -0,0 +1,32 @@
+/*
+ * PCA9552 I2C LED blinker registers
+ *
+ * Copyright (c) 2017-2018, IBM Corporation.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+#ifndef PCA9552_REGS_H
+#define PCA9552_REGS_H
+
+/*
+ * Bits [0:3] are used to address a specific register.
+ */
+#define PCA9552_INPUT0 0 /* read only input register 0 */
+#define PCA9552_INPUT1 1 /* read only input register 1 */
+#define PCA9552_PSC0 2 /* read/write frequency prescaler 0 */
+#define PCA9552_PWM0 3 /* read/write PWM register 0 */
+#define PCA9552_PSC1 4 /* read/write frequency prescaler 1 */
+#define PCA9552_PWM1 5 /* read/write PWM register 1 */
+#define PCA9552_LS0 6 /* read/write LED0 to LED3 selector */
+#define PCA9552_LS1 7 /* read/write LED4 to LED7 selector */
+#define PCA9552_LS2 8 /* read/write LED8 to LED11 selector */
+#define PCA9552_LS3 9 /* read/write LED12 to LED15 selector */
+
+/*
+ * Bit [4] is used to activate the Auto-Increment option of the
+ * register address
+ */
+#define PCA9552_AUTOINC (1 << 4)
+
+#endif
diff --git a/include/hw/net/ftgmac100.h b/include/hw/net/ftgmac100.h
index d9bc589..94cfe05 100644
--- a/include/hw/net/ftgmac100.h
+++ b/include/hw/net/ftgmac100.h
@@ -16,6 +16,11 @@
#include "hw/sysbus.h"
#include "net/net.h"
+/*
+ * Max frame size for the receiving buffer
+ */
+#define FTGMAC100_MAX_FRAME_SIZE 9220
+
typedef struct FTGMAC100State {
/*< private >*/
SysBusDevice parent_obj;
@@ -26,7 +31,7 @@ typedef struct FTGMAC100State {
qemu_irq irq;
MemoryRegion iomem;
- uint8_t *frame;
+ uint8_t frame[FTGMAC100_MAX_FRAME_SIZE];
uint32_t irq_state;
uint32_t isr;
diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h
index 9bdb3c9..b865aaf 100644
--- a/include/hw/sd/sd.h
+++ b/include/hw/sd/sd.h
@@ -54,6 +54,12 @@
#define APP_CMD (1 << 5)
#define AKE_SEQ_ERROR (1 << 3)
+enum SDPhySpecificationVersion {
+ SD_PHY_SPECv1_10_VERS = 1,
+ SD_PHY_SPECv2_00_VERS = 2,
+ SD_PHY_SPECv3_01_VERS = 3,
+};
+
typedef enum {
SD_VOLTAGE_0_4V = 400, /* currently not supported */
SD_VOLTAGE_1_8V = 1800,
diff --git a/qemu-doc.texi b/qemu-doc.texi
index f00706b..2effe66 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -2965,11 +2965,6 @@ support page sizes < 4096 any longer.
@section System emulator machines
-@subsection Xilinx EP108 (since 2.11.0)
-
-The ``xlnx-ep108'' machine has been replaced by the ``xlnx-zcu102'' machine.
-The ``xlnx-zcu102'' machine has the same features and capabilites in QEMU.
-
@section Block device options
@subsection "backing": "" (since 2.12.0)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index f75aa6e..1248d84 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -4570,7 +4570,7 @@ void hw_breakpoint_update(ARMCPU *cpu, int n)
case 4: /* unlinked address mismatch (reserved if AArch64) */
case 5: /* linked address mismatch (reserved if AArch64) */
qemu_log_mask(LOG_UNIMP,
- "arm: address mismatch breakpoint types not implemented");
+ "arm: address mismatch breakpoint types not implemented\n");
return;
case 0: /* unlinked address match */
case 1: /* linked address match */
@@ -4604,7 +4604,7 @@ void hw_breakpoint_update(ARMCPU *cpu, int n)
case 8: /* unlinked VMID match (reserved if no EL2) */
case 10: /* unlinked context ID and VMID match (reserved if no EL2) */
qemu_log_mask(LOG_UNIMP,
- "arm: unlinked context breakpoint types not implemented");
+ "arm: unlinked context breakpoint types not implemented\n");
return;
case 9: /* linked VMID match (reserved if no EL2) */
case 11: /* linked context ID and VMID match (reserved if no EL2) */
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 37d6ffd..4b5dbdb 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -1556,7 +1556,7 @@ DISAS_INSN(undef)
/* ??? This is both instructions that are as yet unimplemented
for the 680x0 series, as well as those that are implemented
but actually illegal for CPU32 or pre-68020. */
- qemu_log_mask(LOG_UNIMP, "Illegal instruction: %04x @ %08x",
+ qemu_log_mask(LOG_UNIMP, "Illegal instruction: %04x @ %08x\n",
insn, s->insn_pc);
gen_exception(s, s->insn_pc, EXCP_UNSUPPORTED);
}
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 3abf524..aec7558 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -293,7 +293,8 @@ void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
if ((val_to_write & 3) == 0) {
env->stvec = val_to_write >> 2 << 2;
} else {
- qemu_log_mask(LOG_UNIMP, "CSR_STVEC: vectored traps not supported");
+ qemu_log_mask(LOG_UNIMP,
+ "CSR_STVEC: vectored traps not supported\n");
}
break;
case CSR_SCOUNTEREN:
@@ -320,7 +321,8 @@ void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
if ((val_to_write & 3) == 0) {
env->mtvec = val_to_write >> 2 << 2;
} else {
- qemu_log_mask(LOG_UNIMP, "CSR_MTVEC: vectored traps not supported");
+ qemu_log_mask(LOG_UNIMP,
+ "CSR_MTVEC: vectored traps not supported\n");
}
break;
case CSR_MCOUNTEREN:
diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
index 89db238..a11162e 100644
--- a/target/xtensa/translate.c
+++ b/target/xtensa/translate.c
@@ -2234,7 +2234,7 @@ static void translate_rur(DisasContext *dc, const uint32_t arg[],
if (uregnames[par[0]].name) {
tcg_gen_mov_i32(cpu_R[arg[0]], cpu_UR[par[0]]);
} else {
- qemu_log_mask(LOG_UNIMP, "RUR %d not implemented, ", par[0]);
+ qemu_log_mask(LOG_UNIMP, "RUR %d not implemented\n", par[0]);
}
}
}
@@ -2375,7 +2375,7 @@ static void translate_slli(DisasContext *dc, const uint32_t arg[],
{
if (gen_window_check2(dc, arg[0], arg[1])) {
if (arg[2] == 32) {
- qemu_log_mask(LOG_GUEST_ERROR, "slli a%d, a%d, 32 is undefined",
+ qemu_log_mask(LOG_GUEST_ERROR, "slli a%d, a%d, 32 is undefined\n",
arg[0], arg[1]);
}
tcg_gen_shli_i32(cpu_R[arg[0]], cpu_R[arg[1]], arg[2] & 0x1f);
@@ -2571,7 +2571,7 @@ static void translate_wur(DisasContext *dc, const uint32_t arg[],
if (uregnames[par[0]].name) {
gen_wur(par[0], cpu_R[arg[0]]);
} else {
- qemu_log_mask(LOG_UNIMP, "WUR %d not implemented, ", par[0]);
+ qemu_log_mask(LOG_UNIMP, "WUR %d not implemented\n", par[0]);
}
}
}
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 0eaa835..400d889 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -373,6 +373,7 @@ check-qtest-sparc64-y += tests/prom-env-test$(EXESUF)
check-qtest-sparc64-y += tests/boot-serial-test$(EXESUF)
check-qtest-arm-y = tests/tmp105-test$(EXESUF)
+check-qtest-arm-y += tests/pca9552-test$(EXESUF)
check-qtest-arm-y += tests/ds1338-test$(EXESUF)
check-qtest-arm-y += tests/m25p80-test$(EXESUF)
gcov-files-arm-y += hw/misc/tmp105.c
@@ -778,6 +779,7 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \
tests/boot-sector.o tests/acpi-utils.o $(libqos-obj-y)
tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
+tests/pca9552-test$(EXESUF): tests/pca9552-test.o $(libqos-omap-obj-y)
tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
tests/m25p80-test$(EXESUF): tests/m25p80-test.o
tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
diff --git a/tests/libqos/i2c.h b/tests/libqos/i2c.h
index eb40b80..cc01358 100644
--- a/tests/libqos/i2c.h
+++ b/tests/libqos/i2c.h
@@ -21,6 +21,8 @@ struct I2CAdapter {
QTestState *qts;
};
+#define OMAP2_I2C_1_BASE 0x48070000
+
void i2c_send(I2CAdapter *i2c, uint8_t addr,
const uint8_t *buf, uint16_t len);
void i2c_recv(I2CAdapter *i2c, uint8_t addr,
diff --git a/tests/pca9552-test.c b/tests/pca9552-test.c
new file mode 100644
index 0000000..5466a67
--- /dev/null
+++ b/tests/pca9552-test.c
@@ -0,0 +1,116 @@
+/*
+ * QTest testcase for the PCA9552 LED blinker
+ *
+ * Copyright (c) 2017-2018, IBM Corporation.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "libqtest.h"
+#include "libqos/i2c.h"
+#include "hw/misc/pca9552_regs.h"
+
+#define PCA9552_TEST_ID "pca9552-test"
+#define PCA9552_TEST_ADDR 0x60
+
+static I2CAdapter *i2c;
+
+static uint8_t pca9552_get8(I2CAdapter *i2c, uint8_t addr, uint8_t reg)
+{
+ uint8_t resp[1];
+ i2c_send(i2c, addr, &reg, 1);
+ i2c_recv(i2c, addr, resp, 1);
+ return resp[0];
+}
+
+static void pca9552_set8(I2CAdapter *i2c, uint8_t addr, uint8_t reg,
+ uint8_t value)
+{
+ uint8_t cmd[2];
+ uint8_t resp[1];
+
+ cmd[0] = reg;
+ cmd[1] = value;
+ i2c_send(i2c, addr, cmd, 2);
+ i2c_recv(i2c, addr, resp, 1);
+ g_assert_cmphex(resp[0], ==, cmd[1]);
+}
+
+static void receive_autoinc(void)
+{
+ uint8_t resp;
+ uint8_t reg = PCA9552_LS0 | PCA9552_AUTOINC;
+
+ i2c_send(i2c, PCA9552_TEST_ADDR, &reg, 1);
+
+ /* PCA9552_LS0 */
+ i2c_recv(i2c, PCA9552_TEST_ADDR, &resp, 1);
+ g_assert_cmphex(resp, ==, 0x54);
+
+ /* PCA9552_LS1 */
+ i2c_recv(i2c, PCA9552_TEST_ADDR, &resp, 1);
+ g_assert_cmphex(resp, ==, 0x55);
+
+ /* PCA9552_LS2 */
+ i2c_recv(i2c, PCA9552_TEST_ADDR, &resp, 1);
+ g_assert_cmphex(resp, ==, 0x55);
+
+ /* PCA9552_LS3 */
+ i2c_recv(i2c, PCA9552_TEST_ADDR, &resp, 1);
+ g_assert_cmphex(resp, ==, 0x54);
+}
+
+static void send_and_receive(void)
+{
+ uint8_t value;
+
+ value = pca9552_get8(i2c, PCA9552_TEST_ADDR, PCA9552_LS0);
+ g_assert_cmphex(value, ==, 0x55);
+
+ value = pca9552_get8(i2c, PCA9552_TEST_ADDR, PCA9552_INPUT0);
+ g_assert_cmphex(value, ==, 0x0);
+
+ /* Switch on LED 0 */
+ pca9552_set8(i2c, PCA9552_TEST_ADDR, PCA9552_LS0, 0x54);
+ value = pca9552_get8(i2c, PCA9552_TEST_ADDR, PCA9552_LS0);
+ g_assert_cmphex(value, ==, 0x54);
+
+ value = pca9552_get8(i2c, PCA9552_TEST_ADDR, PCA9552_INPUT0);
+ g_assert_cmphex(value, ==, 0x01);
+
+ /* Switch on LED 12 */
+ pca9552_set8(i2c, PCA9552_TEST_ADDR, PCA9552_LS3, 0x54);
+ value = pca9552_get8(i2c, PCA9552_TEST_ADDR, PCA9552_LS3);
+ g_assert_cmphex(value, ==, 0x54);
+
+ value = pca9552_get8(i2c, PCA9552_TEST_ADDR, PCA9552_INPUT1);
+ g_assert_cmphex(value, ==, 0x10);
+}
+
+int main(int argc, char **argv)
+{
+ QTestState *s = NULL;
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+
+ s = qtest_start("-machine n800 "
+ "-device pca9552,bus=i2c-bus.0,id=" PCA9552_TEST_ID
+ ",address=0x60");
+ i2c = omap_i2c_create(s, OMAP2_I2C_1_BASE);
+
+ qtest_add_func("/pca9552/tx-rx", send_and_receive);
+ qtest_add_func("/pca9552/rx-autoinc", receive_autoinc);
+
+ ret = g_test_run();
+
+ if (s) {
+ qtest_quit(s);
+ }
+ g_free(i2c);
+
+ return ret;
+}
diff --git a/tests/tmp105-test.c b/tests/tmp105-test.c
index d093cff..34cae7a 100644
--- a/tests/tmp105-test.c
+++ b/tests/tmp105-test.c
@@ -14,8 +14,6 @@
#include "qapi/qmp/qdict.h"
#include "hw/misc/tmp105_regs.h"
-#define OMAP2_I2C_1_BASE 0x48070000
-
#define TMP105_TEST_ID "tmp105-test"
#define TMP105_TEST_ADDR 0x49