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 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJbGnhVAAoJEDwlJe0UNgzeDyoQAJf16U/dMWs44t7HVcsuJ1YN /G4lrIWSYuucIZd/EUZgB856NrjSA6lsZM85hXOpo0NwWFWS4mk2Mgt4/xyV9F+L 5giUwVW/1Lwbi+4I29OoZk0NHMLWwK+aQDOIl6K6IlBBXC7r2k7n6r98trpgiIHA BOcVVqa0HBFPNTKQbcguvTbHK3IiG9DF7r63pBpDe8rS2VotL1h/hmbJLFOv1c/L uivKkyGfTva7yXrzLgbIByMZKRGznsTMAibhS7e6dQckcHDaqHYvNgQGExYFjaCO /Of6BCEqUeHPEpgsVeU3otVz38Bk08C43k8mIAKOdo+sEj7epADzG24kIwV83dXk joDLqqgaIEIPzN3DlArvkG4kmRfnqFEzprGlOE6Joz++jI0obYvK4xVcPkS1/STR 1BXHbQt3LoPZxCs/7TH8zRbQT33BvHsnTF7wxxBL2Rl//rUVOij9yDTVc0kn85Rn z7SnvrG+ceeFtpUM+Kwehwy0Rcbu98ajwRMlPMnBoSh56VzgZZ1j1Kb1TYbAnRMh aKZJKzMHAummK2TlanyovCj9Syj3coHW0suRxB/ftrMtyiIPOFWXCRxTT3/TsW74 f0b7u151DnvUz1V4qNPB42B/jH0rCJpx2OU0W4Ayc4g22Rlzo7sPb25MGvtGpOnx PAYywwLENo8wSxUlkoYp =LLFc -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
0d2fa03dae
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
7
hw/i2c/trace-events
Normal file
7
hw/i2c/trace-events
Normal file
@ -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"
|
@ -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,
|
||||
|
@ -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, ®, 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, ®, 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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
240
hw/misc/pca9552.c
Normal file
240
hw/misc/pca9552.c
Normal file
@ -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)
|
@ -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 = {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
50
hw/sd/sd.c
50
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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
32
include/hw/misc/pca9552.h
Normal file
32
include/hw/misc/pca9552.h
Normal file
@ -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
|
32
include/hw/misc/pca9552_regs.h
Normal file
32
include/hw/misc/pca9552_regs.h
Normal file
@ -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
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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) */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
116
tests/pca9552-test.c
Normal file
116
tests/pca9552-test.c
Normal file
@ -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, ®, 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, ®, 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;
|
||||
}
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user