From 65c5afbeac3f8be9bd42713d38f5f0d3c1a7c8c1 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Tue, 26 Jun 2018 14:42:06 -0700 Subject: [PATCH] Fix Xbox SMBus devices --- hw/xbox/amd_smbus.c | 100 +++++++++++++++++++-------------------- hw/xbox/amd_smbus.h | 2 +- hw/xbox/smbus.h | 30 ++++++++++++ hw/xbox/smbus_adm1032.c | 20 ++++---- hw/xbox/smbus_cx25871.c | 14 +++--- hw/xbox/smbus_xbox_smc.c | 35 +++++++------- 6 files changed, 114 insertions(+), 87 deletions(-) create mode 100644 hw/xbox/smbus.h diff --git a/hw/xbox/amd_smbus.c b/hw/xbox/amd_smbus.c index ae097764d1..fbc6932e6c 100644 --- a/hw/xbox/amd_smbus.c +++ b/hw/xbox/amd_smbus.c @@ -5,6 +5,7 @@ * * Based on pm_smbus.c * Copyright (c) 2006 Fabrice Bellard + * * Based on Linux drivers/i2c/busses/i2c-amd756.c * Copyright (c) 1999-2002 Merlin Hughes * @@ -22,11 +23,19 @@ * along with this program; if not, see . */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "hw/i386/pc.h" #include "hw/xbox/amd_smbus.h" #include "hw/i2c/smbus.h" +// #define DEBUG +#ifdef DEBUG +# define SMBUS_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) +#else +# define SMBUS_DPRINTF(format, ...) do { } while (0) +#endif + /* AMD756 SMBus address offsets */ #define SMB_ADDR_OFFSET 0xE0 #define SMB_IOSIZE 16 @@ -50,47 +59,36 @@ #define AMD756_PROCESS_CALL 0x04 #define AMD756_BLOCK_DATA 0x05 -/* +/* SMBUS event = I/O 28-29 bit 11 see E0 for the status bits and enabled in E2 */ -#define GS_ABRT_STS (1 << 0) -#define GS_COL_STS (1 << 1) -#define GS_PRERR_STS (1 << 2) -#define GS_HST_STS (1 << 3) -#define GS_HCYC_STS (1 << 4) -#define GS_TO_STS (1 << 5) -#define GS_SMB_STS (1 << 11) +#define GS_ABRT_STS (1 << 0) +#define GS_COL_STS (1 << 1) +#define GS_PRERR_STS (1 << 2) +#define GS_HST_STS (1 << 3) +#define GS_HCYC_STS (1 << 4) +#define GS_TO_STS (1 << 5) +#define GS_SMB_STS (1 << 11) +#define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS \ + | GS_HCYC_STS | GS_TO_STS) -#define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \ - GS_HCYC_STS | GS_TO_STS ) - -#define GE_CYC_TYPE_MASK (7) -#define GE_HOST_STC (1 << 3) - -#define GE_HCYC_EN (1 << 4) -#define GE_ABORT (1 << 5) - - - -//#define DEBUG - -#ifdef DEBUG -# define SMBUS_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) -#else -# define SMBUS_DPRINTF(format, ...) do { } while (0) -#endif +#define GE_CYC_TYPE_MASK (7) +#define GE_HOST_STC (1 << 3) +#define GE_HCYC_EN (1 << 4) +#define GE_ABORT (1 << 5) static void amd756_smb_transaction(AMD756SMBus *s) { uint8_t prot = s->smb_ctl & GE_CYC_TYPE_MASK; uint8_t read = s->smb_addr & 0x01; - uint8_t cmd = s->smb_cmd; + uint8_t cmd = s->smb_cmd; uint8_t addr = (s->smb_addr >> 1) & 0x7f; - i2c_bus *bus = s->smbus; - + I2CBus *bus = s->smbus; + SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot); - switch(prot) { + + switch (prot) { case AMD756_QUICK: smbus_quick_command(bus, addr, read); break; @@ -128,24 +126,23 @@ static void amd756_smb_transaction(AMD756SMBus *s) default: goto error; } - + s->smb_stat |= GS_HCYC_STS; - return; - - - error: - s->smb_stat |= GS_PRERR_STS; + +error: + s->smb_stat |= GS_PRERR_STS; } void amd756_smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) { AMD756SMBus *s = opaque; addr &= 0x3f; - SMBUS_DPRINTF("SMB writeb port=0x%04x val=0x%02x\n", addr, val); - switch(addr) { - case SMB_GLOBAL_STATUS: + SMBUS_DPRINTF("SMB writeb port=0x%04x val=0x%02x\n", addr, val); + + switch (addr) { + case SMB_GLOBAL_STATUS: if (s->irq) { /* Raise an irq if interrupts are enabled and a new * status is being set */ @@ -173,8 +170,9 @@ void amd756_smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) break; case SMB_GLOBAL_ENABLE: s->smb_ctl = val; - if (val & GE_ABORT) + if (val & GE_ABORT) { s->smb_stat |= GS_ABRT_STS; + } if (val & GE_HOST_STC) { amd756_smb_transaction(s); @@ -195,13 +193,14 @@ void amd756_smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) case SMB_HOST_DATA: s->smb_data0 = val; break; - case SMB_HOST_DATA+1: + case SMB_HOST_DATA + 1: s->smb_data1 = val; break; case SMB_HOST_BLOCK_DATA: s->smb_data[s->smb_index++] = val; - if (s->smb_index > 31) + if (s->smb_index > 31) { s->smb_index = 0; + } break; default: break; @@ -214,12 +213,13 @@ uint32_t amd756_smb_ioport_readb(void *opaque, uint32_t addr) uint32_t val; addr &= 0x3f; - switch(addr) { + + switch (addr) { case SMB_GLOBAL_STATUS: val = s->smb_stat; break; case SMB_GLOBAL_ENABLE: - //s->smb_index = 0; + // s->smb_index = 0; val = s->smb_ctl & 0x1f; break; case SMB_HOST_COMMAND: @@ -231,13 +231,14 @@ uint32_t amd756_smb_ioport_readb(void *opaque, uint32_t addr) case SMB_HOST_DATA: val = s->smb_data0; break; - case SMB_HOST_DATA+1: + case SMB_HOST_DATA + 1: val = s->smb_data1; break; case SMB_HOST_BLOCK_DATA: val = s->smb_data[s->smb_index++]; - if (s->smb_index > 31) + if (s->smb_index > 31) { s->smb_index = 0; + } break; default: val = 0; @@ -249,8 +250,7 @@ uint32_t amd756_smb_ioport_readb(void *opaque, uint32_t addr) void amd756_smbus_init(DeviceState *parent, AMD756SMBus *smb, qemu_irq irq) { - smb->smbus = i2c_init_bus(parent, "i2c"); + smb->smbus = i2c_init_bus(parent, "i2c"); smb->smb_stat = 0; - - smb->irq = irq; -} \ No newline at end of file + smb->irq = irq; +} diff --git a/hw/xbox/amd_smbus.h b/hw/xbox/amd_smbus.h index 86df54c36e..4a3ec35bfb 100644 --- a/hw/xbox/amd_smbus.h +++ b/hw/xbox/amd_smbus.h @@ -24,7 +24,7 @@ #define AMD_SMBUS_H typedef struct AMD756SMBus { - i2c_bus *smbus; + I2CBus *smbus; uint8_t smb_stat; uint8_t smb_ctl; diff --git a/hw/xbox/smbus.h b/hw/xbox/smbus.h new file mode 100644 index 0000000000..0089fe759d --- /dev/null +++ b/hw/xbox/smbus.h @@ -0,0 +1,30 @@ +/* + * QEMU Xbox System Emulator + * + * Copyright (c) 2013 espes + * + * Based on pc.c + * Copyright (c) 2003-2004 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef HW_SMBUS_H +#define HW_SMBUS_H + +void smbus_xbox_smc_init(I2CBus *smbus, int address); +void smbus_cx25871_init(I2CBus *smbus, int address); +void smbus_adm1032_init(I2CBus *smbus, int address); + +#endif diff --git a/hw/xbox/smbus_adm1032.c b/hw/xbox/smbus_adm1032.c index b6f6ffd25d..a572c4f2e8 100644 --- a/hw/xbox/smbus_adm1032.c +++ b/hw/xbox/smbus_adm1032.c @@ -22,9 +22,11 @@ * THE SOFTWARE. */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "hw/i2c/i2c.h" #include "hw/i2c/smbus.h" +#include "smbus.h" #define DEBUG @@ -34,13 +36,13 @@ static uint8_t tm_read_data(SMBusDevice *dev, uint8_t cmd, int n) printf("tm_read_data: addr=0x%02x cmd=0x%02x n=%d\n", dev->i2c.address, cmd, n); #endif - + switch (cmd) { - case 0x0: - case 0x1: - return 50; - default: - break; + case 0x0: + case 0x1: + return 50; + default: + break; } return 0; @@ -51,10 +53,9 @@ static int tm_init(SMBusDevice *dev) return 0; } - static void smbus_adm1032_class_initfn(ObjectClass *klass, void *data) { - DeviceClass *dc = DEVICE_CLASS(klass); + // DeviceClass *dc = DEVICE_CLASS(klass); SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass); sc->init = tm_init; @@ -68,7 +69,6 @@ static TypeInfo smbus_adm1032_info = { .class_init = smbus_adm1032_class_initfn, }; - static void smbus_adm1032_register_devices(void) { type_register_static(&smbus_adm1032_info); @@ -77,7 +77,7 @@ static void smbus_adm1032_register_devices(void) type_init(smbus_adm1032_register_devices) -void smbus_adm1032_init(i2c_bus *smbus, int address) +void smbus_adm1032_init(I2CBus *smbus, int address) { DeviceState *tm; tm = qdev_create((BusState *)smbus, "smbus-adm1032"); diff --git a/hw/xbox/smbus_cx25871.c b/hw/xbox/smbus_cx25871.c index 9c1d78f26f..b0c4a224d9 100644 --- a/hw/xbox/smbus_cx25871.c +++ b/hw/xbox/smbus_cx25871.c @@ -17,9 +17,13 @@ * along with this program; if not, see . */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "hw/i2c/i2c.h" #include "hw/i2c/smbus.h" +#include "smbus.h" + +//#define DEBUG typedef struct SMBusCX25871Device { SMBusDevice smbusdev; @@ -27,8 +31,6 @@ typedef struct SMBusCX25871Device { uint8_t registers[256]; } SMBusCX25871Device; -//#define DEBUG - static void cx_quick_cmd(SMBusDevice *dev, uint8_t read) { #ifdef DEBUG @@ -61,7 +63,7 @@ static void cx_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len) dev->i2c.address, cmd, buf[0]); #endif - memcpy(cx->registers+cmd, buf, MIN(len, 256-cmd)); + memcpy(cx->registers + cmd, buf, MIN(len, 256 - cmd)); } static uint8_t cx_read_data(SMBusDevice *dev, uint8_t cmd, int n) @@ -71,7 +73,7 @@ static uint8_t cx_read_data(SMBusDevice *dev, uint8_t cmd, int n) printf("cx_read_data: addr=0x%02x cmd=0x%02x n=%d\n", dev->i2c.address, cmd, n); #endif - + return cx->registers[cmd]; } @@ -99,7 +101,6 @@ static TypeInfo smbus_cx25871_info = { .class_init = smbus_cx25871_class_initfn, }; - static void smbus_cx25871_register_devices(void) { type_register_static(&smbus_cx25871_info); @@ -107,8 +108,7 @@ static void smbus_cx25871_register_devices(void) type_init(smbus_cx25871_register_devices) - -void smbus_cx25871_init(i2c_bus *smbus, int address) +void smbus_cx25871_init(I2CBus *smbus, int address) { DeviceState *cx; cx = qdev_create((BusState *)smbus, "smbus-cx25871"); diff --git a/hw/xbox/smbus_xbox_smc.c b/hw/xbox/smbus_xbox_smc.c index 00a8b41a65..6ae16f4705 100644 --- a/hw/xbox/smbus_xbox_smc.c +++ b/hw/xbox/smbus_xbox_smc.c @@ -17,11 +17,16 @@ * along with this program; if not, see . */ +#include "qemu/osdep.h" +#include "qemu/option.h" #include "hw/hw.h" #include "hw/i2c/i2c.h" #include "hw/i2c/smbus.h" #include "qemu/config-file.h" #include "sysemu/sysemu.h" +#include "smbus.h" + +//#define DEBUG /* * Hardware is a PIC16LC @@ -62,10 +67,7 @@ #define SMC_REG_SCRATCH 0x1b #define SMC_REG_SCRATCH_SHORT_ANIMATION 0x04 -static const char* smc_version_string = "P01"; - - -//#define DEBUG +static const char *smc_version_string = "P01"; typedef struct SMBusSMCDevice { SMBusDevice smbusdev; @@ -105,17 +107,18 @@ static void smc_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len) dev->i2c.address, cmd, buf[0]); #endif - switch(cmd) { + switch (cmd) { case SMC_REG_VER: /* version string reset */ smc->version_string_index = buf[0]; break; case SMC_REG_POWER: - if (buf[0] & (SMC_REG_POWER_RESET | SMC_REG_POWER_CYCLE)) - qemu_system_reset_request(); - else if (buf[0] & SMC_REG_POWER_SHUTDOWN) - qemu_system_shutdown_request(); + if (buf[0] & (SMC_REG_POWER_RESET | SMC_REG_POWER_CYCLE)) { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + } else if (buf[0] & SMC_REG_POWER_SHUTDOWN) { + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); + } break; case SMC_REG_SCRATCH: @@ -142,10 +145,10 @@ static uint8_t smc_read_data(SMBusDevice *dev, uint8_t cmd, int n) dev->i2c.address, cmd, n); #endif - switch(cmd) { + switch (cmd) { case SMC_REG_VER: return smc_version_string[ - smc->version_string_index++%(sizeof(smc_version_string)-1)]; + smc->version_string_index++ % (sizeof(smc_version_string) - 1)]; case SMC_REG_AVPACK: /* pretend to have a composite av pack plugged in */ @@ -174,21 +177,18 @@ static uint8_t smc_read_data(SMBusDevice *dev, uint8_t cmd, int n) static int smbus_smc_init(SMBusDevice *dev) { - QemuOpts *opts; SMBusSMCDevice *smc = (SMBusSMCDevice *)dev; smc->version_string_index = 0; smc->scratch_reg = 0; - opts = qemu_opts_find(qemu_find_opts("machine"), NULL); - if (opts && qemu_opt_get_bool(opts, "short_animation", 0)) { + if (object_property_get_bool(qdev_get_machine(), "short-animation", NULL)) { smc->scratch_reg = SMC_REG_SCRATCH_SHORT_ANIMATION; } return 0; } - static void smbus_smc_class_initfn(ObjectClass *klass, void *data) { SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass); @@ -208,8 +208,6 @@ static TypeInfo smbus_smc_info = { .class_init = smbus_smc_class_initfn, }; - - static void smbus_smc_register_devices(void) { type_register_static(&smbus_smc_info); @@ -217,8 +215,7 @@ static void smbus_smc_register_devices(void) type_init(smbus_smc_register_devices) - -void smbus_xbox_smc_init(i2c_bus *smbus, int address) +void smbus_xbox_smc_init(I2CBus *smbus, int address) { DeviceState *smc; smc = qdev_create((BusState *)smbus, "smbus-xbox-smc");