diff --git a/hw/acpi_mcpx.c b/hw/acpi_mcpx.c new file mode 100644 index 0000000000..7f5e39474f --- /dev/null +++ b/hw/acpi_mcpx.c @@ -0,0 +1,132 @@ +/* + * ACPI implementation + * + * Copyright (c) 2006 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + /* + * Copyright (C) 2012 espes + * + * Based on acpi.c, acpi_ich9.c, acpi_piix4.c + */ + +#include "hw.h" +#include "pc.h" +#include "pci.h" +#include "qemu-timer.h" +#include "sysemu.h" +#include "acpi.h" + +#include "acpi_mcpx.h" + +#define DEBUG + +#ifdef DEBUG +# define MCPX_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) +#else +# define MCPX_DPRINTF(format, ...) do { } while (0) +#endif + + + +static void mcpx_pm_update_sci_gn(ACPIREGS *regs) +{ + MCPX_PMRegs *pm = container_of(regs, MCPX_PMRegs, acpi_regs); + //pm_update_sci(pm); +} + + +#define MCPX_PMIO_PM1_STS 0x0 +#define MCPX_PMIO_PM1_EN 0x2 +#define MCPX_PMIO_PM1_CNT 0x4 +#define MCPX_PMIO_PM_TMR 0x8 + +static void mcpx_pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width, + uint64_t val) +{ + MCPX_PMRegs *pm = container_of(ioport, MCPX_PMRegs, ioport); + + switch (addr) { + case MCPX_PMIO_PM1_STS: + acpi_pm1_evt_write_sts(&pm->acpi_regs, val); + //pm_update_sci(pm); + break; + case MCPX_PMIO_PM1_EN: + pm->acpi_regs.pm1.evt.en = val; + //pm_update_sci(pm); + break; + case MCPX_PMIO_PM1_CNT: + acpi_pm1_cnt_write(&pm->acpi_regs, val, 0); + break; + default: + break; + } + MCPX_DPRINTF("PM: write port=0x%04x val=0x%04x\n", + (unsigned int)addr, (unsigned int)val); +} + +static void mcpx_pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width, + uint64_t *data) +{ + MCPX_PMRegs *pm = container_of(ioport, MCPX_PMRegs, ioport); + uint32_t val; + + switch (addr) { + case MCPX_PMIO_PM1_STS: + val = acpi_pm1_evt_get_sts(&pm->acpi_regs); + break; + case MCPX_PMIO_PM1_EN: + val = pm->acpi_regs.pm1.evt.en; + break; + case MCPX_PMIO_PM1_CNT: + val = pm->acpi_regs.pm1.cnt.cnt; + break; + case MCPX_PMIO_PM_TMR: + val = acpi_pm_tmr_get(&pm->acpi_regs); + break; + default: + val = 0; + break; + } + MCPX_DPRINTF("PM: read port=0x%04x val=0x%04x\n", + (unsigned int)addr, (unsigned int)val); + *data = val; +} + +static const IORangeOps mcpx_iorange_ops = { + .read = mcpx_pm_ioport_read, + .write = mcpx_pm_ioport_write, +}; + + +void mcpx_pm_iospace_update(MCPX_PMRegs *pm, uint32_t pm_io_base) { + MCPX_DPRINTF("PM: iospace update to 0x%x\n", pm_io_base); + + //Disabled when 0 + if (pm_io_base != 0) { + iorange_init(&pm->ioport, &mcpx_iorange_ops, pm_io_base, 256); + ioport_register(&pm->ioport); + } +} + +void mcpx_pm_init(MCPX_PMRegs *pm/*, qemu_irq sci_irq*/) { + acpi_pm_tmr_init(&pm->acpi_regs, mcpx_pm_update_sci_gn); + acpi_pm1_cnt_init(&pm->acpi_regs); + //acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN); + + //pm->irq = sci_irq; +} \ No newline at end of file diff --git a/hw/acpi_mcpx.h b/hw/acpi_mcpx.h new file mode 100644 index 0000000000..021400ae60 --- /dev/null +++ b/hw/acpi_mcpx.h @@ -0,0 +1,36 @@ +/* + * QEMU MCPX PM Emulation + * + * Copyright (c) 2012 espes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +#ifndef HW_ACPI_MCPX_H +#define HW_ACPI_MCPX_H + +#include "acpi.h" + +typedef struct MCPX_PMRegs { + IORange ioport; + ACPIREGS acpi_regs; + + qemu_irq irq; +} MCPX_PMRegs; + +void mcpx_pm_init(MCPX_PMRegs *pm /*, qemu_irq sci_irq*/); +void mcpx_pm_iospace_update(MCPX_PMRegs *pm, uint32_t pm_io_base); + + +#endif \ No newline at end of file diff --git a/hw/amd_smbus.c b/hw/amd_smbus.c new file mode 100644 index 0000000000..301a008234 --- /dev/null +++ b/hw/amd_smbus.c @@ -0,0 +1,206 @@ +#include "hw.h" +#include "pc.h" +#include "amd_smbus.h" +#include "smbus.h" + +/* AMD756 SMBus address offsets */ +#define SMB_ADDR_OFFSET 0xE0 +#define SMB_IOSIZE 16 +#define SMB_GLOBAL_STATUS 0x0 +#define SMB_GLOBAL_ENABLE 0x2 +#define SMB_HOST_ADDRESS 0x4 +#define SMB_HOST_DATA 0x6 +#define SMB_HOST_COMMAND 0x8 +#define SMB_HOST_BLOCK_DATA 0x9 +#define SMB_HAS_DATA 0xA +#define SMB_HAS_DEVICE_ADDRESS 0xC +#define SMB_HAS_HOST_ADDRESS 0xE +#define SMB_SNOOP_ADDRESS 0xF + +/* AMD756 constants */ +#define AMD756_QUICK 0x00 +#define AMD756_BYTE 0x01 +#define AMD756_BYTE_DATA 0x02 +#define AMD756_WORD_DATA 0x03 +#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_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_ABORT (1 << 5) + + + +#define DEBUG + +#ifdef DEBUG +# define SMBUS_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) +#else +# define SMBUS_DPRINTF(format, ...) do { } while (0) +#endif + +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 addr = (s->smb_addr >> 1) & 0x7f; + i2c_bus *bus = s->smbus; + + SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot); + switch(prot) { + case AMD756_QUICK: + smbus_quick_command(bus, addr, read); + break; + case AMD756_BYTE: + if (read) { + s->smb_data0 = smbus_receive_byte(bus, addr); + } else { + smbus_send_byte(bus, addr, cmd); + } + break; + case AMD756_BYTE_DATA: + if (read) { + s->smb_data0 = smbus_read_byte(bus, addr, cmd); + } else { + smbus_write_byte(bus, addr, cmd, s->smb_data0); + } + break; + case AMD756_WORD_DATA: + if (read) { + uint16_t val; + val = smbus_read_word(bus, addr, cmd); + s->smb_data0 = val; + //s->smb_data1 = val >> 8; + } else { + smbus_write_word(bus, addr, cmd, s->smb_data0); + } + break; + case AMD756_BLOCK_DATA: + if (read) { + s->smb_data0 = smbus_read_block(bus, addr, cmd, s->smb_data); + } else { + smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0); + } + break; + default: + goto error; + } + + s->smb_stat |= GS_HCYC_STS; + + return; + + + 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: + //s->smb_stat = 0; + if (val & GS_CLEAR_STS) { + s->smb_stat = 0; + s->smb_index = 0; + } else if (val & GS_HCYC_STS) { + s->smb_stat = GS_HCYC_STS; + s->smb_index = 0; + } else { + s->smb_stat = GS_HCYC_STS; + s->smb_index = 0; + } + + break; + case SMB_GLOBAL_ENABLE: + s->smb_ctl = val; + if (val & GE_ABORT) + s->smb_stat |= GS_ABRT_STS; + if (val & GE_HOST_STC) + amd756_smb_transaction(s); + break; + case SMB_HOST_COMMAND: + s->smb_cmd = val; + break; + case SMB_HOST_ADDRESS: + s->smb_addr = val; + break; + case SMB_HOST_DATA: + s->smb_data0 = val; + break; + /*case SMBHSTDAT1: + s->smb_data1 = val; + break;*/ + case SMB_HOST_BLOCK_DATA: + s->smb_data[s->smb_index++] = val; + if (s->smb_index > 31) + s->smb_index = 0; + break; + default: + break; + } +} + +uint32_t amd756_smb_ioport_readb(void *opaque, uint32_t addr) +{ + AMD756SMBus *s = opaque; + uint32_t val; + + addr &= 0x3f; + switch(addr) { + case SMB_GLOBAL_STATUS: + val = s->smb_stat; + break; + case SMB_GLOBAL_ENABLE: + //s->smb_index = 0; + val = s->smb_ctl & 0x1f; + break; + case SMB_HOST_COMMAND: + val = s->smb_cmd; + break; + case SMB_HOST_ADDRESS: + val = s->smb_addr; + break; + case SMB_HOST_DATA: + val = s->smb_data0; + break; + /*case SMBHSTDAT1: + val = s->smb_data1; + break;*/ + case SMB_HOST_BLOCK_DATA: + val = s->smb_data[s->smb_index++]; + if (s->smb_index > 31) + s->smb_index = 0; + break; + default: + val = 0; + break; + } + SMBUS_DPRINTF("SMB readb port=0x%04x val=0x%02x\n", addr, val); + return val; +} + +void amd756_smbus_init(DeviceState *parent, AMD756SMBus *smb) +{ + smb->smbus = i2c_init_bus(parent, "i2c"); + smb->smb_stat = 0; +} \ No newline at end of file diff --git a/hw/amd_smbus.h b/hw/amd_smbus.h new file mode 100644 index 0000000000..9a4d8ad390 --- /dev/null +++ b/hw/amd_smbus.h @@ -0,0 +1,21 @@ +#ifndef AMD_SMBUS_H +#define AMD_SMBUS_H + +typedef struct AMD756SMBus { + i2c_bus *smbus; + + uint8_t smb_stat; + uint8_t smb_ctl; + uint8_t smb_cmd; + uint8_t smb_addr; + uint8_t smb_data0; + //uint8_t smb_data1; + uint8_t smb_data[32]; + uint8_t smb_index; +} AMD756SMBus; + +void amd756_smbus_init(DeviceState *parent, AMD756SMBus *smb); +void amd756_smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val); +uint32_t amd756_smb_ioport_readb(void *opaque, uint32_t addr); + +#endif /* !AMD_SMBUS_H */ diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 8c764bbfef..0a34a48278 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -12,4 +12,6 @@ obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o obj-y += kvm/ obj-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o +obj-$(CONFIG_XBOX) += xbox.o xbox_pci.o acpi_mcpx.o amd_smbus.o nv2a.o smbus_pic16lc.o smbus_cx25871.o smbus_adm1032.o + obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/nv2a.c b/hw/nv2a.c new file mode 100644 index 0000000000..a352aa984d --- /dev/null +++ b/hw/nv2a.c @@ -0,0 +1,569 @@ +/* + * QEMU Geforce NV2A implementation + * + * Copyright (c) 2012 espes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ +#include "hw.h" +#include "pc.h" +#include "console.h" +#include "pci.h" +#include "vga_int.h" + +#include "nv2a.h" + +#define DEBUG_NV2A +#ifdef DEBUG_NV2A +# define NV2A_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) +#else +# define NV2A_DPRINTF(format, ...) do { } while (0) +#endif + + +#define NV_NUM_BLOCKS 20 +#define NV_PMC 0 /* card master control */ +#define NV_PBUS 1 /* bus control */ +#define NV_PFIFO 2 /* MMIO and DMA FIFO submission to PGRAPH and VPE */ +#define NV_PFIFO_CACHE 3 +#define NV_PRMA 4 /* access to BAR0/BAR1 from real mode */ +#define NV_PVIDEO 5 /* video overlay */ +#define NV_PTIMER 6 /* time measurement and time-based alarms */ +#define NV_PCOUNTER 7 /* performance monitoring counters */ +#define NV_PVPE 8 /* MPEG2 decoding engine */ +#define NV_PTV 9 /* TV encoder */ +#define NV_PRMFB 10 /* aliases VGA memory window */ +#define NV_PRMVIO 11 /* aliases VGA sequencer and graphics controller registers */ +#define NV_PSTRAPS 12 /* straps readout / override */ +#define NV_PGRAPH 13 /* accelerated 2d/3d drawing engine */ +#define NV_PCRTC 14 /* more CRTC controls */ +#define NV_PRMCIO 15 /* aliases VGA CRTC and attribute controller registers */ +#define NV_PRAMDAC 16 /* RAMDAC, cursor, and PLL control */ +#define NV_PRMDIO 17 /* aliases VGA palette registers */ +#define NV_PRAMIN 18 /* RAMIN access */ +#define NV_USER 19 /* PFIFO MMIO and DMA submission area */ + + +typedef struct NV2AState { + PCIDevice dev; + VGACommonState vga; + + MemoryRegion vram; + MemoryRegion mmio; + + MemoryRegion block_mmio[NV_NUM_BLOCKS]; +} NV2AState; + + + + +static uint64_t nv2a_pmc_read(void *opaque, + target_phys_addr_t addr, unsigned int size) +{ + NV2A_DPRINTF("nv2a PMC: read [0x%llx]\n", addr); + return 0; +} +static void nv2a_pmc_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) +{ + NV2A_DPRINTF("nv2a PMC: [0x%llx] = 0x%02llx\n", addr, val); +} + + +static uint64_t nv2a_pbus_read(void *opaque, + target_phys_addr_t addr, unsigned int size) +{ + NV2A_DPRINTF("nv2a PBUS: read [0x%llx]\n", addr); + return 0; +} +static void nv2a_pbus_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) +{ + NV2A_DPRINTF("nv2a PBUS: [0x%llx] = 0x%02llx\n", addr, val); +} + + +static uint64_t nv2a_pfifo_read(void *opaque, + target_phys_addr_t addr, unsigned int size) +{ + NV2A_DPRINTF("nv2a PFIFO: read [0x%llx]\n", addr); + return 0; +} +static void nv2a_pfifo_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) +{ + NV2A_DPRINTF("nv2a PFIFO: [0x%llx] = 0x%02llx\n", addr, val); +} + + +static uint64_t nv2a_prma_read(void *opaque, + target_phys_addr_t addr, unsigned int size) +{ + NV2A_DPRINTF("nv2a PRMA: read [0x%llx]\n", addr); + return 0; +} +static void nv2a_prma_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) +{ + NV2A_DPRINTF("nv2a PRMA: [0x%llx] = 0x%02llx\n", addr, val); +} + + +static uint64_t nv2a_pvideo_read(void *opaque, + target_phys_addr_t addr, unsigned int size) +{ + NV2A_DPRINTF("nv2a PVIDEO: read [0x%llx]\n", addr); + return 0; +} +static void nv2a_pvideo_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) +{ + NV2A_DPRINTF("nv2a PVIDEO: [0x%llx] = 0x%02llx\n", addr, val); +} + + +static uint64_t nv2a_ptimer_read(void *opaque, + target_phys_addr_t addr, unsigned int size) +{ + NV2A_DPRINTF("nv2a PTIMER: read [0x%llx]\n", addr); + return 0; +} +static void nv2a_ptimer_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) +{ + NV2A_DPRINTF("nv2a PTIMER: [0x%llx] = 0x%02llx\n", addr, val); +} + + +static uint64_t nv2a_pcounter_read(void *opaque, + target_phys_addr_t addr, unsigned int size) +{ + NV2A_DPRINTF("nv2a PCOUNTER: read [0x%llx]\n", addr); + return 0; +} +static void nv2a_pcounter_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) +{ + NV2A_DPRINTF("nv2a PCOUNTER: [0x%llx] = 0x%02llx\n", addr, val); +} + + +static uint64_t nv2a_pvpe_read(void *opaque, + target_phys_addr_t addr, unsigned int size) +{ + NV2A_DPRINTF("nv2a PVPE: read [0x%llx]\n", addr); + return 0; +} +static void nv2a_pvpe_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) +{ + NV2A_DPRINTF("nv2a PVPE: [0x%llx] = 0x%02llx\n", addr, val); +} + + +static uint64_t nv2a_ptv_read(void *opaque, + target_phys_addr_t addr, unsigned int size) +{ + NV2A_DPRINTF("nv2a PTV: read [0x%llx]\n", addr); + return 0; +} +static void nv2a_ptv_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) +{ + NV2A_DPRINTF("nv2a PTV: [0x%llx] = 0x%02llx\n", addr, val); +} + + +static uint64_t nv2a_prmfb_read(void *opaque, + target_phys_addr_t addr, unsigned int size) +{ + NV2A_DPRINTF("nv2a PRMFB: read [0x%llx]\n", addr); + return 0; +} +static void nv2a_prmfb_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) +{ + NV2A_DPRINTF("nv2a PRMFB: [0x%llx] = 0x%02llx\n", addr, val); +} + + +static uint64_t nv2a_prmvio_read(void *opaque, + target_phys_addr_t addr, unsigned int size) +{ + NV2A_DPRINTF("nv2a PRMVIO: read [0x%llx]\n", addr); + return 0; +} +static void nv2a_prmvio_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) +{ + NV2A_DPRINTF("nv2a PRMVIO: [0x%llx] = 0x%02llx\n", addr, val); +} + + +static uint64_t nv2a_pstraps_read(void *opaque, + target_phys_addr_t addr, unsigned int size) +{ + NV2A_DPRINTF("nv2a PSTRAPS: read [0x%llx]\n", addr); + return 0; +} +static void nv2a_pstraps_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) +{ + NV2A_DPRINTF("nv2a PSTRAPS: [0x%llx] = 0x%02llx\n", addr, val); +} + + +static uint64_t nv2a_pgraph_read(void *opaque, + target_phys_addr_t addr, unsigned int size) +{ + NV2A_DPRINTF("nv2a PGRAPH: read [0x%llx]\n", addr); + return 0; +} +static void nv2a_pgraph_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) +{ + NV2A_DPRINTF("nv2a PGRAPH: [0x%llx] = 0x%02llx\n", addr, val); +} + + +static uint64_t nv2a_pcrtc_read(void *opaque, + target_phys_addr_t addr, unsigned int size) +{ + NV2A_DPRINTF("nv2a PCRTC: read [0x%llx]\n", addr); + return 0; +} +static void nv2a_pcrtc_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) +{ + NV2A_DPRINTF("nv2a PCRTC: [0x%llx] = 0x%02llx\n", addr, val); +} + + +static uint64_t nv2a_prmcio_read(void *opaque, + target_phys_addr_t addr, unsigned int size) +{ + NV2A_DPRINTF("nv2a PRMCIO: read [0x%llx]\n", addr); + return 0; +} +static void nv2a_prmcio_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) +{ + NV2A_DPRINTF("nv2a PRMCIO: [0x%llx] = 0x%02llx\n", addr, val); +} + + +static uint64_t nv2a_pramdac_read(void *opaque, + target_phys_addr_t addr, unsigned int size) +{ + NV2A_DPRINTF("nv2a PRAMDAC: read [0x%llx]\n", addr); + return 0; +} +static void nv2a_pramdac_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) +{ + NV2A_DPRINTF("nv2a PRAMDAC: [0x%llx] = 0x%02llx\n", addr, val); +} + + +static uint64_t nv2a_prmdio_read(void *opaque, + target_phys_addr_t addr, unsigned int size) +{ + NV2A_DPRINTF("nv2a PRMDIO: read [0x%llx]\n", addr); + return 0; +} +static void nv2a_prmdio_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) +{ + NV2A_DPRINTF("nv2a PRMDIO: [0x%llx] = 0x%02llx\n", addr, val); +} + + +static uint64_t nv2a_pramin_read(void *opaque, + target_phys_addr_t addr, unsigned int size) +{ + NV2A_DPRINTF("nv2a PRAMIN: read [0x%llx]\n", addr); + return 0; +} +static void nv2a_pramin_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) +{ + NV2A_DPRINTF("nv2a PRAMIN: [0x%llx] = 0x%02llx\n", addr, val); +} + + +static uint64_t nv2a_user_read(void *opaque, + target_phys_addr_t addr, unsigned int size) +{ + NV2A_DPRINTF("nv2a USER: read [0x%llx]\n", addr); + return 0; +} +static void nv2a_user_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) +{ + NV2A_DPRINTF("nv2a USER: [0x%llx] = 0x%02llx\n", addr, val); +} + + + + +typedef struct NV2ABlockInfo { + const char* name; + target_phys_addr_t offset; + uint64_t size; + MemoryRegionOps ops; +} NV2ABlockInfo; + +static const struct NV2ABlockInfo blocktable[] = { + [ NV_PMC ] = { + .name = "PMC", + .offset = 0x000000, + .size = 0x001000, + .ops = { + .read = nv2a_pmc_read, + .write = nv2a_pmc_write, + }, + }, + [ NV_PBUS ] = { + .name = "PBUS", + .offset = 0x001000, + .size = 0x001000, + .ops = { + .read = nv2a_pbus_read, + .write = nv2a_pbus_write, + }, + }, + [ NV_PFIFO ] = { + .name = "PFIFO", + .offset = 0x002000, + .size = 0x002000, + .ops = { + .read = nv2a_pfifo_read, + .write = nv2a_pfifo_write, + }, + }, + [ NV_PRMA ] = { + .name = "PRMA", + .offset = 0x007000, + .size = 0x001000, + .ops = { + .read = nv2a_prma_read, + .write = nv2a_prma_write, + }, + }, + [ NV_PVIDEO ] = { + .name = "PVIDEO", + .offset = 0x008000, + .size = 0x001000, + .ops = { + .read = nv2a_pvideo_read, + .write = nv2a_pvideo_write, + }, + }, + [ NV_PTIMER ] = { + .name = "PTIMER", + .offset = 0x009000, + .size = 0x001000, + .ops = { + .read = nv2a_ptimer_read, + .write = nv2a_ptimer_write, + }, + }, + [ NV_PCOUNTER ] = { + .name = "PCOUNTER", + .offset = 0x00a000, + .size = 0x001000, + .ops = { + .read = nv2a_pcounter_read, + .write = nv2a_pcounter_write, + }, + }, + [ NV_PVPE ] = { + .name = "PVPE", + .offset = 0x00b000, + .size = 0x001000, + .ops = { + .read = nv2a_pvpe_read, + .write = nv2a_pvpe_write, + }, + }, + [ NV_PTV ] = { + .name = "PTV", + .offset = 0x00d000, + .size = 0x001000, + .ops = { + .read = nv2a_ptv_read, + .write = nv2a_ptv_write, + }, + }, + [ NV_PRMFB ] = { + .name = "PRMFB", + .offset = 0x0a0000, + .size = 0x020000, + .ops = { + .read = nv2a_prmfb_read, + .write = nv2a_prmfb_write, + }, + }, + [ NV_PRMVIO ] = { + .name = "PRMVIO", + .offset = 0x0c0000, + .size = 0x001000, + .ops = { + .read = nv2a_prmvio_read, + .write = nv2a_prmvio_write, + }, + }, + [ NV_PSTRAPS ] = { + .name = "PSTRAPS", + .offset = 0x101000, + .size = 0x001000, + .ops = { + .read = nv2a_pstraps_read, + .write = nv2a_pstraps_write, + }, + }, + [ NV_PGRAPH ] = { + .name = "PGRAPH", + .offset = 0x400000, + .size = 0x002000, + .ops = { + .read = nv2a_pgraph_read, + .write = nv2a_pgraph_write, + }, + }, + [ NV_PCRTC ] = { + .name = "PCRTC", + .offset = 0x600000, + .size = 0x001000, + .ops = { + .read = nv2a_pcrtc_read, + .write = nv2a_pcrtc_write, + }, + }, + [ NV_PRMCIO ] = { + .name = "PRMCIO", + .offset = 0x601000, + .size = 0x001000, + .ops = { + .read = nv2a_prmcio_read, + .write = nv2a_prmcio_write, + }, + }, + [ NV_PRAMDAC ] = { + .name = "PRAMDAC", + .offset = 0x680000, + .size = 0x001000, + .ops = { + .read = nv2a_pramdac_read, + .write = nv2a_pramdac_write, + }, + }, + [ NV_PRMDIO ] = { + .name = "PRMDIO", + .offset = 0x681000, + .size = 0x001000, + .ops = { + .read = nv2a_prmdio_read, + .write = nv2a_prmdio_write, + }, + }, + [ NV_PRAMIN ] = { + .name = "PRAMIN", + .offset = 0x700000, + .size = 0x100000, + .ops = { + .read = nv2a_pramin_read, + .write = nv2a_pramin_write, + }, + }, + [ NV_USER ] = { + .name = "USER", + .offset = 0x800000, + .size = 0x800000, + .ops = { + .read = nv2a_user_read, + .write = nv2a_user_write, + }, + }, +}; + + + + +static int nv2a_initfn(PCIDevice *dev) +{ + int i; + NV2AState *d = DO_UPCAST(NV2AState, dev, dev); + //uint8_t *pci_conf = d->dev.config; + + /* setup legacy VGA */ + //d->vga.vram_size_mb = 16; + //vga_common_init(&d->vga); + + memory_region_init(&d->mmio, "nv2a-mmio", 0x1000000); + + pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio); + + memory_region_init_ram(&d->vram, "nv2a-vram", 128 * 0x100000); + pci_register_bar(&d->dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH, &d->vram); + + for (i=0; iblock_mmio[i], &blocktable[i].ops, d, + blocktable[i].name, blocktable[i].size); + memory_region_add_subregion(&d->mmio, blocktable[i].offset, + &d->block_mmio[i]); + } + + + return 0; +} + +static void nv2a_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->vendor_id = PCI_VENDOR_ID_NVIDIA; + k->device_id = PCI_DEVICE_ID_NVIDIA_GEFORCE_NV2A; + k->revision = 161; + k->class_id = PCI_CLASS_DISPLAY_3D; + k->init = nv2a_initfn; + + dc->desc = "GeForce NV2A Integrated Graphics"; +} + +static const TypeInfo nv2a_info = { + .name = "nv2a", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(NV2AState), + .class_init = nv2a_class_init, +}; + +static void nv2a_register(void) +{ + type_register_static(&nv2a_info); +} +type_init(nv2a_register); + + + + + +void nv2a_init(PCIBus *bus, int devfn) +{ + pci_create_simple(bus, devfn, "nv2a"); +} \ No newline at end of file diff --git a/hw/nv2a.h b/hw/nv2a.h new file mode 100644 index 0000000000..8438e9adc9 --- /dev/null +++ b/hw/nv2a.h @@ -0,0 +1,27 @@ +/* + * QEMU Geforce NV2A implementation + * + * Copyright (c) 2012 espes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#ifndef HW_NV2A_H +#define HW_NV2A_H + +void nv2a_init(PCIBus *bus, int devfn); + +#endif \ No newline at end of file diff --git a/hw/pci_ids.h b/hw/pci_ids.h index 301bf1cd86..fdff5541f0 100644 --- a/hw/pci_ids.h +++ b/hw/pci_ids.h @@ -22,6 +22,7 @@ #define PCI_CLASS_NETWORK_ETHERNET 0x0200 #define PCI_CLASS_DISPLAY_VGA 0x0300 +#define PCI_CLASS_DISPLAY_3D 0x0302 #define PCI_CLASS_DISPLAY_OTHER 0x0380 #define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401 @@ -31,6 +32,7 @@ #define PCI_CLASS_SYSTEM_OTHER 0x0880 #define PCI_CLASS_SERIAL_USB 0x0c03 +#define PCI_CLASS_SERIAL_SMBUS 0x0c05 #define PCI_CLASS_BRIDGE_HOST 0x0600 #define PCI_CLASS_BRIDGE_ISA 0x0601 @@ -128,3 +130,12 @@ #define PCI_VENDOR_ID_NEC 0x1033 #define PCI_DEVICE_ID_NEC_UPD720200 0x0194 + +#define PCI_VENDOR_ID_NVIDIA 0x10de +#define PCI_DEVICE_ID_NVIDIA_NFORCE_LPC 0x01b2 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS 0x01b4 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_AGP 0x01b7 + +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_NV2A 0x02a0 +#define PCI_DEVICE_ID_NVIDIA_XBOX_PCHB 0x02a5 + diff --git a/hw/smbus.h b/hw/smbus.h index 6ed45bd03d..9dafd32d9a 100644 --- a/hw/smbus.h +++ b/hw/smbus.h @@ -77,7 +77,14 @@ int smbus_read_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data) void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data, int len); +void smbus_eeprom_init_single(i2c_bus *smbus, int address, + uint8_t *eeprom_buf); void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom, const uint8_t *eeprom_spd, int size); + +void smbus_pic16lc_init(i2c_bus *smbus, int address); +void smbus_cx25871_init(i2c_bus *smbus, int address); +void smbus_adm1032_init(i2c_bus *smbus, int address); + #endif diff --git a/hw/smbus_adm1032.c b/hw/smbus_adm1032.c new file mode 100644 index 0000000000..178f762664 --- /dev/null +++ b/hw/smbus_adm1032.c @@ -0,0 +1,86 @@ +/* + * QEMU SMBus ADM1032 Temperature Monitor + * + * Copyright (c) 2012 espes + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw.h" +#include "i2c.h" +#include "smbus.h" + +#define DEBUG + +static uint8_t tm_read_data(SMBusDevice *dev, uint8_t cmd, int n) +{ + #ifdef DEBUG + 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; + } + + return 0; +} + +static int tm_init(SMBusDevice *dev) +{ + return 0; +} + + +static void smbus_adm1032_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass); + + sc->init = tm_init; + sc->read_data = tm_read_data; +} + +static TypeInfo smbus_adm1032_info = { + .name = "smbus-adm1032", + .parent = TYPE_SMBUS_DEVICE, + .instance_size = sizeof(SMBusDevice), + .class_init = smbus_adm1032_class_initfn, +}; + + +static void smbus_adm1032_register_devices(void) +{ + type_register_static(&smbus_adm1032_info); +} + +type_init(smbus_adm1032_register_devices) + + +void smbus_adm1032_init(i2c_bus *smbus, int address) +{ + DeviceState *tm; + tm = qdev_create((BusState *)smbus, "smbus-adm1032"); + qdev_prop_set_uint8(tm, "address", address); + qdev_init_nofail(tm); +} diff --git a/hw/smbus_cx25871.c b/hw/smbus_cx25871.c new file mode 100644 index 0000000000..385dd3d860 --- /dev/null +++ b/hw/smbus_cx25871.c @@ -0,0 +1,127 @@ +/* + * QEMU SMBus Conexant CX25871 Video Encoder + * + * Copyright (c) 2012 espes + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw.h" +#include "i2c.h" +#include "smbus.h" + +typedef struct SMBusCX25871Device { + SMBusDevice smbusdev; + + uint8_t registers[256]; +} SMBusCX25871Device; + +#define DEBUG + +static void cx_quick_cmd(SMBusDevice *dev, uint8_t read) +{ +#ifdef DEBUG + printf("cx_quick_cmd: addr=0x%02x read=%d\n", dev->i2c.address, read); +#endif +} + +static void cx_send_byte(SMBusDevice *dev, uint8_t val) +{ + SMBusCX25871Device *cx = (SMBusCX25871Device *) dev; +#ifdef DEBUG + printf("cx_send_byte: addr=0x%02x val=0x%02x\n", + dev->i2c.address, val); +#endif +} + +static uint8_t cx_receive_byte(SMBusDevice *dev) +{ + SMBusCX25871Device *cx = (SMBusCX25871Device *) dev; +#ifdef DEBUG + printf("cx_receive_byte: addr=0x%02x\n", + dev->i2c.address); +#endif + return 0; +} + +static void cx_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len) +{ + SMBusCX25871Device *cx = (SMBusCX25871Device *) dev; +#ifdef DEBUG + printf("cx_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n", + dev->i2c.address, cmd, buf[0]); +#endif + + memcpy(cx->registers+cmd, buf, MIN(len, 256-cmd)); +} + +static uint8_t cx_read_data(SMBusDevice *dev, uint8_t cmd, int n) +{ + SMBusCX25871Device *cx = (SMBusCX25871Device *) dev; + #ifdef DEBUG + printf("cx_read_data: addr=0x%02x cmd=0x%02x n=%d\n", + dev->i2c.address, cmd, n); + #endif + + return cx->registers[cmd]; +} + +static int smbus_cx_init(SMBusDevice *dev) +{ + SMBusCX25871Device *cx = (SMBusCX25871Device *)dev; + + return 0; +} + +static void smbus_cx25871_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass); + + sc->init = smbus_cx_init; + sc->quick_cmd = cx_quick_cmd; + sc->send_byte = cx_send_byte; + sc->receive_byte = cx_receive_byte; + sc->write_data = cx_write_data; + sc->read_data = cx_read_data; +} + +static TypeInfo smbus_cx25871_info = { + .name = "smbus-cx25871", + .parent = TYPE_SMBUS_DEVICE, + .instance_size = sizeof(SMBusCX25871Device), + .class_init = smbus_cx25871_class_initfn, +}; + + +static void smbus_cx25871_register_devices(void) +{ + type_register_static(&smbus_cx25871_info); +} + +type_init(smbus_cx25871_register_devices) + + +void smbus_cx25871_init(i2c_bus *smbus, int address) +{ + DeviceState *cx; + cx = qdev_create((BusState *)smbus, "smbus-cx25871"); + qdev_prop_set_uint8(cx, "address", address); + qdev_init_nofail(cx); +} diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c index 11adab01b8..26d4d0ad8a 100644 --- a/hw/smbus_eeprom.c +++ b/hw/smbus_eeprom.c @@ -26,7 +26,7 @@ #include "i2c.h" #include "smbus.h" -//#define DEBUG +#define DEBUG typedef struct SMBusEEPROMDevice { SMBusDevice smbusdev; @@ -137,6 +137,16 @@ static void smbus_eeprom_register_types(void) type_init(smbus_eeprom_register_types) +void smbus_eeprom_init_single(i2c_bus *smbus, int address, + uint8_t *eeprom_buf) +{ + DeviceState *eeprom; + eeprom = qdev_create((BusState *)smbus, "smbus-eeprom"); + qdev_prop_set_uint8(eeprom, "address", address); + qdev_prop_set_ptr(eeprom, "data", eeprom_buf); + qdev_init_nofail(eeprom); +} + void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom, const uint8_t *eeprom_spd, int eeprom_spd_size) { @@ -147,10 +157,7 @@ void smbus_eeprom_init(i2c_bus *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_single(smbus, + 0x50 + i, eeprom_buf + (i * 256)); } } diff --git a/hw/smbus_pic16lc.c b/hw/smbus_pic16lc.c new file mode 100644 index 0000000000..e83021a59c --- /dev/null +++ b/hw/smbus_pic16lc.c @@ -0,0 +1,183 @@ +/* + * QEMU SMBus PIC16LC System Monitor + * + * Copyright (c) 2011 espes + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw.h" +#include "i2c.h" +#include "smbus.h" + + +#define PIC16LC_REG_VER 0x01 +#define PIC16LC_REG_POWER 0x02 +#define PIC16LC_REG_POWER_RESET 0x01 +#define PIC16LC_REG_POWER_CYCLE 0x40 +#define PIC16LC_REG_POWER_SHUTDOWN 0x80 +#define PIC16LC_REG_TRAYSTATE 0x03 +#define PIC16LC_REG_AVPACK 0x04 +#define PIC16LC_REG_AVPACK_SCART 0x00 +#define PIC16LC_REG_AVPACK_HDTV 0x01 +#define PIC16LC_REG_AVPACK_VGA_SOG 0x02 +#define PIC16LC_REG_AVPACK_SVIDEO 0x04 +#define PIC16LC_REG_AVPACK_COMPOSITE 0x06 +#define PIC16LC_REG_AVPACK_VGA 0x07 +#define PIC16LC_REG_FANMODE 0x05 +#define PIC16LC_REG_FANSPEED 0x06 +#define PIC16LC_REG_LEDMODE 0x07 +#define PIC16LC_REG_LEDSEQ 0x08 +#define PIC16LC_REG_CPUTEMP 0x09 +#define PIC16LC_REG_BOARDTEMP 0x0a +#define PIC16LC_REG_TRAYEJECT 0x0c +#define PIC16LC_REG_INTACK 0x0d +#define PIC16LC_REG_INTSTATUS 0x11 +#define PIC16LC_REG_INTSTATUS_POWER 0x01 +#define PIC16LC_REG_INTSTATUS_TRAYCLOSED 0x02 +#define PIC16LC_REG_INTSTATUS_TRAYOPENING 0x04 +#define PIC16LC_REG_INTSTATUS_AVPACK_PLUG 0x08 +#define PIC16LC_REG_INTSTATUS_AVPACK_UNPLUG 0x10 +#define PIC16LC_REG_INTSTATUS_EJECT_BUTTON 0x20 +#define PIC16LC_REG_INTSTATUS_TRAYCLOSING 0x40 +#define PIC16LC_REG_RESETONEJECT 0x19 +#define PIC16LC_REG_INTEN 0x1a + +static const char* pic_version_string = "P01"; + + +#define DEBUG + +typedef struct SMBusPIC16LCDevice { + SMBusDevice smbusdev; + int versionStringIndex; +} SMBusPIC16LCDevice; + +static void pic_quick_cmd(SMBusDevice *dev, uint8_t read) +{ +#ifdef DEBUG + printf("pic_quick_cmd: addr=0x%02x read=%d\n", dev->i2c.address, read); +#endif +} + +static void pic_send_byte(SMBusDevice *dev, uint8_t val) +{ + SMBusPIC16LCDevice *pic = (SMBusPIC16LCDevice *) dev; +#ifdef DEBUG + printf("pic_send_byte: addr=0x%02x val=0x%02x\n", + dev->i2c.address, val); +#endif +} + +static uint8_t pic_receive_byte(SMBusDevice *dev) +{ + SMBusPIC16LCDevice *pic = (SMBusPIC16LCDevice *) dev; +#ifdef DEBUG + printf("pic_receive_byte: addr=0x%02x\n", + dev->i2c.address); +#endif + return 0; +} + +static void pic_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len) +{ + SMBusPIC16LCDevice *pic = (SMBusPIC16LCDevice *) dev; +#ifdef DEBUG + printf("pic_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n", + dev->i2c.address, cmd, buf[0]); +#endif + + switch(cmd) { + case PIC16LC_REG_VER: + //pic version string reset + pic->versionStringIndex = buf[0]; + break; + default: + break; + } +} + +static uint8_t pic_read_data(SMBusDevice *dev, uint8_t cmd, int n) +{ + SMBusPIC16LCDevice *pic = (SMBusPIC16LCDevice *) dev; + #ifdef DEBUG + printf("pic_read_data: addr=0x%02x cmd=0x%02x n=%d\n", + dev->i2c.address, cmd, n); + #endif + + switch(cmd) { + case PIC16LC_REG_VER: + return pic_version_string[ + pic->versionStringIndex++%(sizeof(pic_version_string)-1)]; + case PIC16LC_REG_AVPACK: + //pretend to ave a composite av pack plugged in + return PIC16LC_REG_AVPACK_COMPOSITE; + default: + break; + } + + return 0; +} + +static int smbus_pic_init(SMBusDevice *dev) +{ + SMBusPIC16LCDevice *pic = (SMBusPIC16LCDevice *)dev; + + pic->versionStringIndex = 0; + return 0; +} + + +static void smbus_pic_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass); + + sc->init = smbus_pic_init; + sc->quick_cmd = pic_quick_cmd; + sc->send_byte = pic_send_byte; + sc->receive_byte = pic_receive_byte; + sc->write_data = pic_write_data; + sc->read_data = pic_read_data; +} + +static TypeInfo smbus_pic_info = { + .name = "smbus-pic16lc", + .parent = TYPE_SMBUS_DEVICE, + .instance_size = sizeof(SMBusPIC16LCDevice), + .class_init = smbus_pic_class_initfn, +}; + + + +static void smbus_pic_register_devices(void) +{ + type_register_static(&smbus_pic_info); +} + +type_init(smbus_pic_register_devices) + + +void smbus_pic16lc_init(i2c_bus *smbus, int address) +{ + DeviceState *pic; + pic = qdev_create((BusState *)smbus, "smbus-pic16lc"); + qdev_prop_set_uint8(pic, "address", address); + qdev_init_nofail(pic); +} diff --git a/hw/xbox.c b/hw/xbox.c new file mode 100644 index 0000000000..5bc134cd20 --- /dev/null +++ b/hw/xbox.c @@ -0,0 +1,276 @@ +/* + * QEMU Xbox System Emulator + * + * Copyright (c) 2012 espes + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw.h" +#include "arch_init.h" +#include "pc.h" +#include "pci.h" +#include "net.h" +#include "boards.h" +#include "ide.h" +#include "mc146818rtc.h" +#include "i8254.h" +#include "pcspk.h" +#include "kvm.h" +#include "sysemu.h" +#include "sysbus.h" +#include "smbus.h" +#include "blockdev.h" +#include "loader.h" +#include "exec-memory.h" + +#include "xbox_pci.h" +#include "nv2a.h" + + +/* mostly from pc_memory_init */ +static void xbox_memory_init(MemoryRegion *system_memory, + ram_addr_t mem_size, + MemoryRegion *rom_memory, + MemoryRegion **ram_memory) +{ + MemoryRegion *ram; + MemoryRegion *ram_below_4g; + + int ret; + char *filename; + int bios_size, isa_bios_size; + MemoryRegion *bios, *isa_bios; + + MemoryRegion *map_bios; + uint32_t map_loc; + + /* Allocate RAM. We allocate it as a single memory region and use + * aliases to address portions of it, mostly for backwards compatibility + * with older qemus that used qemu_ram_alloc(). + */ + ram = g_malloc(sizeof(*ram)); + memory_region_init_ram(ram, "pc.ram", mem_size); + vmstate_register_ram_global(ram); + *ram_memory = ram; + ram_below_4g = g_malloc(sizeof(*ram_below_4g)); + memory_region_init_alias(ram_below_4g, "ram-below-4g", ram, + 0, mem_size); + memory_region_add_subregion(system_memory, 0, ram_below_4g); + + + /* Load the bios. (mostly from pc_sysfw) + * Can't use it verbatim, since we need the bios repeated\ + * over top 1MB of memory. + */ + if (bios_name == NULL) { + bios_name = "bios.bin"; + } + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (filename) { + bios_size = get_image_size(filename); + } else { + bios_size = -1; + } + bios = g_malloc(sizeof(*bios)); + memory_region_init_ram(bios, "pc.bios", bios_size); + vmstate_register_ram_global(bios); + memory_region_set_readonly(bios, true); + ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1); + if (ret != 0) { + fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name); + exit(1); + } + if (filename) { + g_free(filename); + } + + + + /* map the last 128KB of the BIOS in ISA space */ + isa_bios_size = bios_size; + if (isa_bios_size > (128 * 1024)) { + isa_bios_size = 128 * 1024; + } + isa_bios = g_malloc(sizeof(*isa_bios)); + memory_region_init_alias(isa_bios, "isa-bios", bios, + bios_size - isa_bios_size, isa_bios_size); + memory_region_add_subregion_overlap(rom_memory, + 0x100000 - isa_bios_size, + isa_bios, + 1); + memory_region_set_readonly(isa_bios, true); + + + /* map the bios repeated at the top of memory */ + for (map_loc=(uint32_t)(-bios_size); map_loc >= 0xff000000; map_loc-=bios_size) { + map_bios = g_malloc(sizeof(*map_bios)); + memory_region_init_alias(map_bios, NULL, bios, 0, bios_size); + + memory_region_add_subregion(rom_memory, map_loc, map_bios); + memory_region_set_readonly(map_bios, true); + } + + /*memory_region_add_subregion(rom_memory, + (uint32_t)(-bios_size), + bios); + */ + +} + + + +static void ioapic_init(GSIState *gsi_state) +{ + DeviceState *dev; + SysBusDevice *d; + unsigned int i; + + dev = qdev_create(NULL, "ioapic"); + + qdev_init_nofail(dev); + d = sysbus_from_qdev(dev); + sysbus_mmio_map(d, 0, 0xfec00000); + + for (i = 0; i < IOAPIC_NUM_PINS; i++) { + gsi_state->ioapic_irq[i] = qdev_get_gpio_in(dev, i); + } +} + + +#define MAX_IDE_BUS 2 + +/* mostly from pc_init1 */ +static void xbox_init(ram_addr_t ram_size, + const char *boot_device, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *cpu_model) +{ + int i; + PCIBus *host_bus; + ISABus *isa_bus; + qemu_irq *cpu_irq; + qemu_irq *gsi; + qemu_irq *i8259; + GSIState *gsi_state; + PCIDevice *ide_dev; + DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + BusState *idebus[MAX_IDE_BUS]; + ISADevice *rtc_state; + ISADevice *pit; + MemoryRegion *ram_memory; + MemoryRegion *pci_memory; + + DeviceState *xboxpci_host; + i2c_bus *smbus; + PCIBus *agp_bus; + + + pc_cpus_init(cpu_model); + + pci_memory = g_new(MemoryRegion, 1); + memory_region_init(pci_memory, "pci", INT64_MAX); + + /* allocate ram and load rom/bios */ + xbox_memory_init(get_system_memory(), ram_size, + pci_memory, &ram_memory); + + + gsi_state = g_malloc0(sizeof(*gsi_state)); + gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS); + + + /* init buses */ + host_bus = xbox_pci_init(&xboxpci_host, gsi, + get_system_memory(), get_system_io(), + pci_memory, ram_memory); + + + /* bridges */ + agp_bus = xbox_agp_init(xboxpci_host, host_bus); + isa_bus = mcpx_lpc_init(xboxpci_host, host_bus); + smbus = mcpx_smbus_init(xboxpci_host, host_bus); + + + /* irq shit */ + isa_bus_irqs(isa_bus, gsi); + cpu_irq = pc_allocate_cpu_irq(); + i8259 = i8259_init(isa_bus, cpu_irq[0]); + + for (i = 0; i < ISA_NUM_IRQS; i++) { + gsi_state->i8259_irq[i] = i8259[i]; + } + ioapic_init(gsi_state); + + + /* basic device init */ + rtc_state = rtc_init(isa_bus, 2000, NULL); + pit = pit_init(isa_bus, 0x40, 0, NULL); + + /* does apparently have a pc speaker, though not used? */ + pcspk_init(isa_bus, pit); + + + /* TODO: ethernet */ + + /* TODO: USB */ + + /* hdd shit + * piix3's ide be right for now, maybe + */ + + + ide_drive_get(hd, MAX_IDE_BUS); + ide_dev = pci_piix4_ide_init(host_bus, hd, PCI_DEVFN(9, 0)); + + idebus[0] = qdev_get_child_bus(&ide_dev->qdev, "ide.0"); + idebus[1] = qdev_get_child_bus(&ide_dev->qdev, "ide.1"); + + + pc_cmos_init(ram_size, 0, boot_device, + NULL, idebus[0], idebus[1], rtc_state); + + + /* TODO: Populate SPD eeprom data. */ + uint8_t *eeprom_buf = g_malloc0(256); + smbus_eeprom_init_single(smbus, 0x54, eeprom_buf); + + smbus_pic16lc_init(smbus, 0x10); + smbus_cx25871_init(smbus, 0x45); + smbus_adm1032_init(smbus, 0x4c); + + + + /* GPU! */ + nv2a_init(agp_bus, PCI_DEVFN(0, 0)); +} + +static QEMUMachine xbox_machine = { + .name = "xbox", + .desc = "Microsoft Xbox", + .init = xbox_init, +}; + +static void xbox_machine_init(void) { + qemu_register_machine(&xbox_machine); +} + +machine_init(xbox_machine_init); \ No newline at end of file diff --git a/hw/xbox_pci.c b/hw/xbox_pci.c new file mode 100644 index 0000000000..b46a970e37 --- /dev/null +++ b/hw/xbox_pci.c @@ -0,0 +1,404 @@ +/* + * QEMU Xbox PCI buses implementation + * + * Copyright (c) 2012 espes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ +#include "hw.h" +#include "range.h" +#include "isa.h" +#include "sysbus.h" +#include "pc.h" +#include "pci.h" +#include "pci_bridge.h" +#include "pci_internals.h" +#include "exec-memory.h" +#include "acpi_mcpx.h" +#include "amd_smbus.h" +#include "qemu-common.h" + +#include "xbox_pci.h" + + + /* + * xbox chipset based on nForce 420, which was based on AMD-760 + * + * http://support.amd.com/us/ChipsetMotherboard_TechDocs/24494.pdf + * http://support.amd.com/us/ChipsetMotherboard_TechDocs/24416.pdf + * http://support.amd.com/us/ChipsetMotherboard_TechDocs/24467.pdf + * + * http://support.amd.com/us/ChipsetMotherboard_TechDocs/24462.pdf + * + * - 'NV2A' combination northbridge/gpu + * - 'MCPX' combination southbridge/apu + */ + + +#define DEBUG + +#ifdef DEBUG +# define XBOXPCI_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) +#else +# define XBOXPCI_DPRINTF(format, ...) do { } while (0) +#endif + + + + + +PCIBus *xbox_pci_init(DeviceState **xbox_pci_hostp, + qemu_irq *pic, + MemoryRegion *address_space_mem, + MemoryRegion *address_space_io, + MemoryRegion *pci_memory, + MemoryRegion *ram_memory) + +{ + DeviceState *dev; + PCIHostState *hostState; + PCIBus *hostBus; + PCIDevice *bridgeDev; + XBOX_PCIState *bridge; + + /* pci host bus */ + dev = qdev_create(NULL, "xbox-pcihost"); + hostState = PCI_HOST_BRIDGE(dev); + hostState->address_space = address_space_mem; + + + hostBus = pci_bus_new(dev, NULL, pci_memory, + address_space_io, 0); + hostState->bus = hostBus; + + //pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, + // PIIX_NUM_PIRQS); + + qdev_init_nofail(dev); + + bridgeDev = pci_create_simple_multifunction(hostBus, PCI_DEVFN(0, 0), + true, "xbox-pci"); + bridge = XBOX_PCI_DEVICE(bridgeDev); + bridge->ram_memory = ram_memory; + bridge->pci_address_space = pci_memory; + bridge->system_memory = address_space_mem; + + /* PCI hole */ + memory_region_init_alias(&bridge->pci_hole, "pci-hole", + bridge->pci_address_space, + ram_size, + 0x100000000ULL - ram_size); + memory_region_add_subregion(bridge->system_memory, ram_size, + &bridge->pci_hole); + + + *xbox_pci_hostp = dev; + return hostBus; +} + + +PCIBus *xbox_agp_init(DeviceState *host, PCIBus *bus) +{ + PCIDevice *d; + PCIBridge *br; + //DeviceState *qdev; + + /* AGP bus */ + d = pci_create_simple(bus, PCI_DEVFN(30, 0), "xbox-agp"); + if (!d) { + return NULL; + } + + br = DO_UPCAST(PCIBridge, dev, d); + //qdev = &br->dev.qdev; + //qdev_init_nofail(qdev); + + return pci_bridge_get_sec_bus(br); +} + + +ISABus *mcpx_lpc_init(DeviceState *host, PCIBus *bus) +{ + PCIDevice *d; + MCPX_LPCState *s; + //qemu_irq *sci_irq; + + d = pci_create_simple_multifunction(bus, PCI_DEVFN(1, 0), + true, "mcpx-lpc"); + + s = MCPX_LPC_DEVICE(d); + + //sci_irq = qemu_allocate_irqs(mcpx_set_sci, &s->irq_state, 1); + mcpx_pm_init(&s->pm /*, sci_irq[0]*/); + //mcpx_lpc_reset(&s->dev.qdev); + + return s->isa_bus; +} + + +i2c_bus *mcpx_smbus_init(DeviceState *host, PCIBus *bus) +{ + PCIDevice *d; + MCPX_SMBState *s; + + d = pci_create_simple_multifunction(bus, PCI_DEVFN(1, 1), + true, "mcpx-smbus"); + + s = MCPX_SMBUS_DEVICE(d); + + return s->smb.smbus; +} + + + + + +static int mcpx_smbus_initfn(PCIDevice *dev) +{ + MCPX_SMBState *s = MCPX_SMBUS_DEVICE(dev); + + //presumably configurable, but can't find docs... + const uint32_t smb_io_base = 0xc000; + register_ioport_write(smb_io_base, 64, 1, amd756_smb_ioport_writeb, &s->smb); + register_ioport_read(smb_io_base, 64, 1, amd756_smb_ioport_readb, &s->smb); + + amd756_smbus_init(&dev->qdev, &s->smb); + + return 0; +} + + +static void mcpx_smbus_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = mcpx_smbus_initfn; + k->vendor_id = PCI_VENDOR_ID_NVIDIA; + k->device_id = PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS; + k->revision = 161; + k->class_id = PCI_CLASS_SERIAL_SMBUS; + + dc->desc = "nForce PCI System Management"; + dc->no_user = 1; +} + +static const TypeInfo mcpx_smbus_info = { + .name = "mcpx-smbus", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = mcpx_smbus_class_init, +}; + + + + +#define MCPX_LPC_PMBASE 0x84 +#define MCPX_LPC_PMBASE_ADDRESS_MASK 0xff00 +#define MCPX_LPC_PMBASE_DEFAULT 0x1 + +static int mcpx_lpc_initfn(PCIDevice *d) +{ + MCPX_LPCState *lpc = MCPX_LPC_DEVICE(d); + ISABus *isa_bus; + + isa_bus = isa_bus_new(&d->qdev, get_system_io()); + lpc->isa_bus = isa_bus; + + return 0; +} + +static void mcpx_lpc_pmbase_update(MCPX_LPCState *s) +{ + uint32_t pm_io_base = pci_get_long(s->dev.config + MCPX_LPC_PMBASE); + pm_io_base &= MCPX_LPC_PMBASE_ADDRESS_MASK; + + mcpx_pm_iospace_update(&s->pm, pm_io_base); +} + +static void mcpx_lpc_reset(DeviceState *dev) +{ + PCIDevice *d = PCI_DEVICE(dev); + MCPX_LPCState *s = MCPX_LPC_DEVICE(d); + + pci_set_long(s->dev.config + MCPX_LPC_PMBASE, MCPX_LPC_PMBASE_DEFAULT); + mcpx_lpc_pmbase_update(s); +} + +static void mcpx_lpc_config_write(PCIDevice *dev, + uint32_t addr, uint32_t val, int len) +{ + MCPX_LPCState *s = MCPX_LPC_DEVICE(dev); + + pci_default_write_config(dev, addr, val, len); + if (ranges_overlap(addr, len, MCPX_LPC_PMBASE, 2)) { + mcpx_lpc_pmbase_update(s); + } +} + +static int mcpx_lpc_post_load(void *opaque, int version_id) +{ + MCPX_LPCState *s = opaque; + mcpx_lpc_pmbase_update(s); + return 0; +} + +static const VMStateDescription vmstate_mcpx_lpc = { + .name = "MCPX LPC", + .version_id = 1, + .post_load = mcpx_lpc_post_load, +}; + +static void mcpx_lpc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->no_hotplug = 1; + k->init = mcpx_lpc_initfn; + k->config_write = mcpx_lpc_config_write; + k->vendor_id = PCI_VENDOR_ID_NVIDIA; + k->device_id = PCI_DEVICE_ID_NVIDIA_NFORCE_LPC; + k->revision = 212; + k->class_id = PCI_CLASS_BRIDGE_ISA; + + dc->desc = "nForce LPC Bridge"; + dc->no_user = 1; + dc->reset = mcpx_lpc_reset; + dc->vmsd = &vmstate_mcpx_lpc; +} + +static const TypeInfo mcpx_lpc_info = { + .name = "mcpx-lpc", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = mcpx_lpc_class_init, +}; + + + + +static void xbox_agp_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = pci_bridge_initfn; + k->exit = pci_bridge_exitfn; + k->config_write = pci_bridge_write_config; + k->is_bridge = 1; + k->vendor_id = PCI_VENDOR_ID_NVIDIA; + k->device_id = PCI_DEVICE_ID_NVIDIA_NFORCE_AGP; + k->revision = 161; + + dc->desc = "nForce AGP to PCI Bridge"; + dc->reset = pci_bridge_reset; +} + +static const TypeInfo xbox_agp_info = { + .name = "xbox-agp", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIBridge), + .class_init = xbox_agp_class_init, +}; + + + + + + +static int xbox_pci_initfn(PCIDevice *d) +{ + //XBOX_PCIState *s = DO_UPCAST(XBOX_PCIState, dev, dev); + + return 0; +} + +static void xbox_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->no_hotplug = 1; + k->init = xbox_pci_initfn; + //k->config_write = xbox_pci_write_config; + k->vendor_id = PCI_VENDOR_ID_NVIDIA; + k->device_id = PCI_DEVICE_ID_NVIDIA_XBOX_PCHB; + k->revision = 161; + k->class_id = PCI_CLASS_BRIDGE_HOST; + + dc->desc = "Xbox PCI Host"; + dc->no_user = 1; +} + +static const TypeInfo xbox_pci_info = { + .name = "xbox-pci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(XBOX_PCIState), + .class_init = xbox_pci_class_init, +}; + + + +#define CONFIG_ADDR 0xcf8 +#define CONFIG_DATA 0xcfc + +static int xbox_pcihost_initfn(SysBusDevice *dev) +{ + PCIHostState *s = PCI_HOST_BRIDGE(dev); + + memory_region_init_io(&s->conf_mem, &pci_host_conf_le_ops, s, + "pci-conf-idx", 4); + sysbus_add_io(dev, CONFIG_ADDR, &s->conf_mem); + sysbus_init_ioports(&s->busdev, CONFIG_ADDR, 4); + + memory_region_init_io(&s->data_mem, &pci_host_data_le_ops, s, + "pci-conf-data", 4); + sysbus_add_io(dev, CONFIG_DATA, &s->data_mem); + sysbus_init_ioports(&s->busdev, CONFIG_DATA, 4); + + return 0; +} + + +static void xbox_pcihost_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = xbox_pcihost_initfn; + dc->no_user = 1; +} + +static const TypeInfo xbox_pcihost_info = { + .name = "xbox-pcihost", + .parent = TYPE_PCI_HOST_BRIDGE, + .instance_size = sizeof(PCIHostState), + .class_init = xbox_pcihost_class_init, +}; + + +static void xboxpci_register_types(void) +{ + type_register(&xbox_pcihost_info); + type_register(&xbox_pci_info); + type_register(&xbox_agp_info); + + type_register(&mcpx_lpc_info); + type_register(&mcpx_smbus_info); +} + +type_init(xboxpci_register_types) diff --git a/hw/xbox_pci.h b/hw/xbox_pci.h new file mode 100644 index 0000000000..3e805ef56a --- /dev/null +++ b/hw/xbox_pci.h @@ -0,0 +1,81 @@ +/* + * QEMU Xbox PCI buses implementation + * + * Copyright (c) 2012 espes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#ifndef HW_XBOX_PCI_H +#define HW_XBOX_PCI_H + +#include "hw.h" +#include "isa.h" +#include "pci.h" +#include "pci_host.h" +#include "amd_smbus.h" +#include "acpi.h" +#include "acpi_mcpx.h" + + +typedef struct XBOX_PCIState { + PCIDevice dev; + + MemoryRegion *ram_memory; + MemoryRegion *pci_address_space; + MemoryRegion *system_memory; + MemoryRegion pci_hole; +} XBOX_PCIState; + +typedef struct MCPX_SMBState { + PCIDevice dev; + + AMD756SMBus smb; +} MCPX_SMBState; + +typedef struct MCPX_LPCState { + PCIDevice dev; + + ISABus *isa_bus; + MCPX_PMRegs pm; +} MCPX_LPCState; + +#define XBOX_PCI_DEVICE(obj) \ + OBJECT_CHECK(XBOX_PCIState, (obj), "xbox-pci") + +#define MCPX_SMBUS_DEVICE(obj) \ + OBJECT_CHECK(MCPX_SMBState, (obj), "mcpx-smbus") + +#define MCPX_LPC_DEVICE(obj) \ + OBJECT_CHECK(MCPX_LPCState, (obj), "mcpx-lpc") + + + +PCIBus *xbox_pci_init(DeviceState **xbox_pci_hostp, + qemu_irq *pic, + MemoryRegion *address_space_mem, + MemoryRegion *address_space_io, + MemoryRegion *pci_memory, + MemoryRegion *ram_memory); + +PCIBus *xbox_agp_init(DeviceState *host, PCIBus *bus); + +ISABus *mcpx_lpc_init(DeviceState *host, PCIBus *bus); + +i2c_bus *mcpx_smbus_init(DeviceState *host, PCIBus *bus); + + +#endif \ No newline at end of file