diff --git a/src/acpi.c b/src/acpi.c index db181cee8..2839aec3e 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -35,6 +35,7 @@ #include <86box/nvr.h> #include <86box/pit.h> #include <86box/apm.h> +#include <86box/tco.h> #include <86box/acpi.h> #include <86box/machine.h> #include <86box/i2c.h> @@ -160,6 +161,8 @@ acpi_raise_smi(void *priv, int do_smi) smi_raise(); } } + else if ((dev->vendor == VEN_INTEL_ICH2) && do_smi && (dev->regs.smi_en & 1)) + smi_line = 1; } @@ -346,6 +349,83 @@ acpi_reg_read_intel(int size, uint16_t addr, void *p) } +static uint32_t +acpi_reg_read_intel_ich2(int size, uint16_t addr, void *p) +{ + acpi_t *dev = (acpi_t *) p; + uint32_t ret = 0x00000000; + int shift16, shift32; + + addr &= 0x7f; + shift16 = (addr & 1) << 3; + shift32 = (addr & 3) << 3; + + switch (addr) { + case 0x10: case 0x11: case 0x12: case 0x13: + /* PROC_CNTProcessor Control Register */ + ret = (dev->regs.pcntrl >> shift32) & 0xff; + break; + case 0x28: case 0x29: + /* GPE0_STSGeneral Purpose Event 0 Status Register */ + ret = (dev->regs.gpsts >> shift16) & 0xff; + break; + case 0x2a: case 0x2b: + /* GPE0_ENGeneral Purpose Event 0 Enables Register */ + ret = (dev->regs.gpen >> shift16) & 0xff; + break; + case 0x2c: case 0x2d: + /* GPE1_STSGeneral Purpose Event 1 Status Register */ + ret = (dev->regs.gpsts1 >> shift16) & 0xff; + break; + case 0x2e: case 0x2f: + /* GPE1_ENGeneral Purpose Event 1 Enable Register */ + ret = (dev->regs.gpen1 >> shift16) & 0xff; + break; + case 0x30: case 0x31: case 0x32: case 0x33: + /* SMI_ENSMI Control and Enable Register */ + ret = (dev->regs.smi_en >> shift32) & 0xff; + break; + case 0x34: case 0x35: case 0x36: case 0x37: + /* SMI_STSSMI Status Register */ + ret = (dev->regs.smi_sts >> shift32) & 0xff; + break; + case 0x40: case 0x41: + /* MON_SMIDevice Monitor SMI Status and Enable Register */ + ret = (dev->regs.mon_smi >> shift16) & 0xff; + break; + case 0x44: case 0x45: + /* DEVACT_STSDevice Activity Status Register */ + ret = (dev->regs.devact_sts >> shift16) & 0xff; + break; + case 0x48: case 0x49: + /* DEVTRAP_ENDevice Trap Enable Register */ + ret = (dev->regs.devtrap_en >> shift16) & 0xff; + break; + case 0x4c ... 0x4d: + /* BUS_ADDR_TRACKBus Address Tracker Register */ + ret = (dev->regs.bus_addr_track >> shift16) & 0xff; + break; + case 0x4e: + /* BUS_CYC_TRACKBus Cycle Tracker Register */ + ret = dev->regs.bus_cyc_track; + break; + case 0x60 ... 0x70: + /* TCO Registers */ + ret = tco_read(addr, dev->tco); + break; + default: + ret = acpi_reg_read_common_regs(size, addr, p); + break; + } + +#ifdef ENABLE_ACPI_LOG + // if (size != 1) + // acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#endif + return ret; +} + + static uint32_t acpi_reg_read_via_common(int size, uint16_t addr, void *p) { @@ -605,7 +685,11 @@ acpi_reg_write_common_regs(int size, uint16_t addr, uint8_t val, void *p) break; case 0x04: case 0x05: /* PMCNTRL - Power Management Control Register (IO) */ - if ((addr == 0x05) && (val & 0x20)) { + if((addr == 0x05) && !!(val & 0x20) && !!(val & 4) && !!(dev->regs.smi_en & 0x00000010) && (dev->vendor == VEN_INTEL_ICH2)) { + dev->regs.smi_sts |= 0x00000010; /* ICH2 Specific. Trigger an SMI if SLP_SMI_EN bit is set instead of transistioning to a Sleep State. */ + acpi_raise_smi(dev, 1); + } + else if ((addr == 0x05) && (val & 0x20)) { sus_typ = dev->suspend_types[(val >> 2) & 7]; if (sus_typ & SUS_POWER_OFF) { @@ -796,6 +880,99 @@ acpi_reg_write_intel(int size, uint16_t addr, uint8_t val, void *p) } +static void +acpi_reg_write_intel_ich2(int size, uint16_t addr, uint8_t val, void *p) +{ + acpi_t *dev = (acpi_t *) p; + int shift16, shift32; + + addr &= 0x7f; +#ifdef ENABLE_ACPI_LOG + if (size != 1) + acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val); +#endif + shift16 = (addr & 1) << 3; + shift32 = (addr & 3) << 3; + + switch (addr) { + case 0x10: case 0x11: case 0x12: case 0x13: + /* PROC_CNTProcessor Control Register */ + dev->regs.pcntrl = ((dev->regs.pcntrl & ~(0xff << shift32)) | (val << shift32)) & 0x000201fe; + break; + case 0x28: case 0x29: + /* GPE0_STSGeneral Purpose Event 0 Status Register */ + dev->regs.gpsts &= ~((val << shift16) & 0x09fb); + break; + case 0x2a: case 0x2b: + /* GPE0_ENGeneral Purpose Event 0 Enables Register */ + dev->regs.gpen = ((dev->regs.gpen & ~(0xff << shift16)) | (val << shift16)) & 0x097d; + break; + case 0x2c: case 0x2d: + /* GPE1_STSGeneral Purpose Event 1 Status Register */ + dev->regs.gpsts1 &= ~((val << shift16) & 0x09fb); + break; + case 0x2e: case 0x2f: + /* GPE1_ENGeneral Purpose Event 1 Enable Register */ + dev->regs.gpen1 = ((dev->regs.gpen & ~(0xff << shift16)) | (val << shift16)) & 0x097d; + break; + case 0x30: case 0x31: case 0x32: case 0x33: + /* SMI_ENSMI Control and Enable Register */ + dev->regs.smi_en = ((dev->regs.smi_en & ~(0xff << shift32)) | (val << shift32)) & 0x0000867f; + + if(addr == 0x30) { + apm_set_do_smi(dev->apm, !!(val & 0x20)); + + if(val & 0x80) { + dev->regs.glbsts |= 0x0020; + acpi_update_irq(dev); + } + } + break; + case 0x34: case 0x35: case 0x36: case 0x37: + /* SMI_STSSMI Status Register */ + dev->regs.smi_sts &= ~((val << shift32) & 0x0001ff7c); + break; + case 0x40: case 0x41: + /* MON_SMIDevice Monitor SMI Status and Enable Register */ + dev->regs.mon_smi = ((dev->regs.mon_smi & ~(0xff << shift16)) | (val << shift16)) & 0x097d; + break; + case 0x44: case 0x45: + /* DEVACT_STSDevice Activity Status Register */ + dev->regs.devact_sts &= ~((val << shift16) & 0x3fef); + break; + case 0x48: case 0x49: + /* DEVTRAP_ENDevice Trap Enable Register */ + dev->regs.devtrap_en = ((dev->regs.devtrap_en & ~(0xff << shift16)) | (val << shift16)) & 0x3c2f; + if (dev->trap_update) + dev->trap_update(dev->trap_priv); + break; + case 0x4c ... 0x4d: + /* BUS_ADDR_TRACKBus Address Tracker Register */ + dev->regs.bus_addr_track = ((dev->regs.bus_addr_track & ~(0xff << shift16)) | (val << shift16)) & 0x097d; + break; + case 0x4e: + /* BUS_CYC_TRACKBus Cycle Tracker Register */ + dev->regs.bus_cyc_track = val; + break; + case 0x60 ... 0x70: + /* TCO Registers */ + tco_write(addr, val, dev->tco); + break; + default: + acpi_reg_write_common_regs(size, addr, val, p); + if((addr == 0x04) && !!(val & 4) && !!(dev->regs.smi_en & 4)) { + dev->regs.smi_sts = 0x00000004; + acpi_raise_smi(dev, 1); + } + + if((addr == 0x02) || !!(val & 0x20) || !!(dev->regs.glbsts & 0x0020)) + acpi_update_irq(dev); + + break; + } +} + + static void acpi_reg_write_via_common(int size, uint16_t addr, uint8_t val, void *p) { @@ -1063,6 +1240,8 @@ acpi_reg_read_common(int size, uint16_t addr, void *p) ret = acpi_reg_read_via_596b(size, addr, p); else if (dev->vendor == VEN_INTEL) ret = acpi_reg_read_intel(size, addr, p); + else if (dev->vendor == VEN_INTEL_ICH2) + ret = acpi_reg_read_intel_ich2(size, addr, p); else if (dev->vendor == VEN_SMC) ret = acpi_reg_read_smc(size, addr, p); @@ -1083,6 +1262,8 @@ acpi_reg_write_common(int size, uint16_t addr, uint8_t val, void *p) acpi_reg_write_via_596b(size, addr, val, p); else if (dev->vendor == VEN_INTEL) acpi_reg_write_intel(size, addr, val, p); + else if (dev->vendor == VEN_INTEL_ICH2) + acpi_reg_write_intel_ich2(size, addr, val, p); else if (dev->vendor == VEN_SMC) acpi_reg_write_smc(size, addr, val, p); } @@ -1276,6 +1457,7 @@ acpi_update_io_mapping(acpi_t *dev, uint32_t base, int chipset_en) case VEN_VIA: size = 0x100; break; + case VEN_INTEL_ICH2: case VEN_VIA_596B: size = 0x080; break; @@ -1412,6 +1594,13 @@ acpi_set_nvr(acpi_t *dev, nvr_t *nvr) } +void +acpi_set_tco(acpi_t *dev, tco_t *tco) +{ + dev->tco = tco; +} + + void acpi_set_trap_update(acpi_t *dev, void (*update)(void *priv), void *priv) { @@ -1458,6 +1647,8 @@ acpi_apm_out(uint16_t port, uint8_t val, void *p) dev->apm->cmd = val; if (dev->vendor == VEN_INTEL) dev->regs.glbsts |= 0x20; + else if (dev->vendor == VEN_INTEL_ICH2) + dev->regs.smi_sts |= 0x00000020; acpi_raise_smi(dev, dev->apm->do_smi); } else dev->apm->stat = val; @@ -1582,7 +1773,7 @@ acpi_init(const device_t *info) dev->irq_line = 9; - if ((dev->vendor == VEN_INTEL) || (dev->vendor == VEN_ALI)) { + if ((dev->vendor == VEN_INTEL) || (dev->vendor == VEN_ALI) || (dev->vendor == VEN_INTEL_ICH2)) { if (dev->vendor == VEN_ALI) dev->irq_mode = 2; dev->apm = device_add(&apm_pci_acpi_device); @@ -1624,6 +1815,13 @@ acpi_init(const device_t *info) dev->suspend_types[3] = SUS_SUSPEND | SUS_RESET_CACHE; dev->suspend_types[4] = SUS_SUSPEND; break; + + case VEN_INTEL_ICH2: + dev->suspend_types[1] = SUS_SUSPEND | SUS_RESET_CPU; + dev->suspend_types[5] = SUS_SUSPEND | SUS_NVR | SUS_RESET_CPU | SUS_RESET_PCI; + dev->suspend_types[6] = SUS_POWER_OFF; + dev->suspend_types[7] = SUS_POWER_OFF; + break; } timer_add(&dev->timer, acpi_timer_overflow, dev, 0); @@ -1662,6 +1860,20 @@ const device_t acpi_intel_device = { .config = NULL }; +const device_t acpi_intel_ich2_device = { + .name = "Intel ICH2 ACPI", + .internal_name = "acpi_intel_ich2", + .flags = DEVICE_PCI, + .local = VEN_INTEL_ICH2, + .init = acpi_init, + .close = acpi_close, + .reset = acpi_reset, + { .available = NULL }, + .speed_changed = acpi_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + const device_t acpi_via_device = { .name = "VIA ACPI", .internal_name = "acpi_via", diff --git a/src/chipset/CMakeLists.txt b/src/chipset/CMakeLists.txt index 517630ae4..3cb610bb5 100644 --- a/src/chipset/CMakeLists.txt +++ b/src/chipset/CMakeLists.txt @@ -15,9 +15,9 @@ add_library(chipset OBJECT 82c100.c acc2168.c cs8230.c ali1429.c ali1489.c ali1531.c ali1541.c ali1543.c ali1621.c ali6117.c headland.c ims8848.c intel_82335.c contaq_82c59x.c cs4031.c intel_420ex.c - intel_4x0.c intel_i450kx.c intel_sio.c intel_piix.c ../ioapic.c neat.c opti283.c opti291.c opti391.c - opti495.c opti822.c opti895.c opti5x7.c scamp.c scat.c sis_85c310.c sis_85c4xx.c - sis_85c496.c sis_85c50x.c sis_5511.c sis_5571.c via_vt82c49x.c via_vt82c505.c sis_85c310.c + intel_4x0.c intel_i450kx.c intel_sio.c intel_piix.c intel_815ep.c intel_ich2.c ../ioapic.c neat.c + opti283.c opti291.c opti391.c opti495.c opti822.c opti895.c opti5x7.c scamp.c scat.c sis_85c310.c + sis_85c4xx.c sis_85c496.c sis_85c50x.c sis_5511.c sis_5571.c via_vt82c49x.c via_vt82c505.c sis_85c310.c sis_85c4xx.c sis_85c496.c sis_85c50x.c gc100.c stpc.c umc_8886.c umc_hb4.c via_apollo.c via_pipc.c vl82c480.c wd76c10.c) diff --git a/src/chipset/intel_815ep.c b/src/chipset/intel_815ep.c new file mode 100644 index 000000000..d56045d08 --- /dev/null +++ b/src/chipset/intel_815ep.c @@ -0,0 +1,369 @@ +/* + * Intel 815EP MCH Bridge + * + * Authors: Tiseno100, + * + * Copyright 2022 Tiseno100. + */ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include "x86.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/device.h> + +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/smram.h> +#include <86box/spd.h> +#include <86box/chipset.h> + +#ifdef ENABLE_INTEL_815EP_LOG +int intel_815ep_do_log = ENABLE_INTEL_815EP_LOG; +static void +intel_815ep_log(const char *fmt, ...) +{ + va_list ap; + + if (intel_815ep_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define intel_815ep_log(fmt, ...) +#endif + +typedef struct intel_815ep_t +{ + uint8_t pci_conf[256]; + smram_t *lsmm_segment, *h_segment, *usmm_segment; +} intel_815ep_t; + +static void +intel_usmm_segment_recalc(intel_815ep_t *dev, uint8_t val) +{ + intel_815ep_log("Intel 815EP MCH: USMM update to status %d\n", val); /* Check the 815EP datasheet for status */ + + smram_disable(dev->h_segment); + smram_disable(dev->usmm_segment); + + if(val != 0) + smram_enable(dev->h_segment, 0xfeea0000, 0x000a0000, 0x20000, 0, 1); + + if(val >= 2) { /* TOM recalc based on intel_4x0.c by OBattler */ + uint32_t tom = (mem_size << 10); + mem_set_mem_state_smm(tom, 0x100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + uint32_t size = (val != 3) ? 0x100000 : 0x80000; + smram_enable(dev->usmm_segment, tom + 0x10000000, tom, size, 0, 1); + mem_set_mem_state_smm(tom, size, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } +} + +static void +intel_lsmm_segment_recalc(intel_815ep_t *dev, uint8_t val) +{ + intel_815ep_log("Intel 815EP MCH: LSMM update to status %d\n", val); /* Check the 815EP datasheet for status */ + + smram_disable(dev->lsmm_segment); + + switch(val) + { + case 1: + smram_enable(dev->lsmm_segment, 0x000a0000, 0x000a0000, 0x20000, 1, 0); + break; + + case 2: + smram_enable(dev->lsmm_segment, 0x000a0000, 0x000a0000, 0x20000, 0, 0); + break; + + case 3: + smram_enable(dev->lsmm_segment, 0x000a0000, 0x000a0000, 0x20000, 0, 1); + break; + } +} + +static void +intel_pam_recalc(int addr, uint8_t val) +{ + int region = 0xc0000 + ((addr - 0x5a) << 15); + + if(addr == 0x59) + mem_set_mem_state_both(0xf0000, 0x10000, ((val & 0x10) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((val & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); + else + { + mem_set_mem_state_both(region, 0x4000, ((val & 0x01) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((val & 0x02) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); + mem_set_mem_state_both(region + 0x4000, 0x4000, ((val & 0x10) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((val & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); + } +} + +static void +intel_815ep_write(int func, int addr, uint8_t val, void *priv) +{ + intel_815ep_t *dev = (intel_815ep_t *)priv; + + intel_815ep_log("Intel 815EP MCH: dev->regs[%02x] = %02x\n", addr, val); + + switch(addr) + { + case 0x05: + dev->pci_conf[addr] = val & 3; + break; + + case 0x07: + dev->pci_conf[addr] &= val & 0x70; + break; + + case 0x2c ... 0x2f: + if(dev->pci_conf[addr] != 0) + dev->pci_conf[addr] = val; + break; + + case 0x13: + dev->pci_conf[addr] = val & 0xfe; + break; + + case 0x50: + dev->pci_conf[addr] = val & 0xdc; + break; + + case 0x51: + dev->pci_conf[addr] = val & 2; // Brute force to AGP Mode + break; + + case 0x52: + case 0x54: + if (!(dev->pci_conf[0x70] & 2)) { + dev->pci_conf[addr] = val & ((addr & 4) ? 0x0f : 0xff); + spd_write_drbs_intel_815ep(dev->pci_conf); + } + break; + + case 0x53: + dev->pci_conf[addr] = val; + break; + + case 0x58: + dev->pci_conf[addr] = val & 0x80; + break; + + case 0x59 ... 0x5f: + dev->pci_conf[addr] = val; + intel_pam_recalc(addr, val); + break; + + case 0x70: + if(!(dev->pci_conf[0x70] & 2)) { + dev->pci_conf[addr] = val & 0xfe; + intel_usmm_segment_recalc(dev, (val >> 4) & 3); + } + else { + dev->pci_conf[addr] = (dev->pci_conf[addr] & 0xfa) | (val & 4); + } + + intel_lsmm_segment_recalc(dev, (val >> 2) & 3); + break; + + case 0x72: + dev->pci_conf[addr] = val & 0xfb; + break; + + case 0x73: + dev->pci_conf[addr] = val & 0xa8; + break; + + case 0x92 ... 0x93: + dev->pci_conf[addr] = val; + break; + + case 0x94: + dev->pci_conf[addr] = val & 0x3f; + break; + + case 0x98: + dev->pci_conf[addr] = val & 0x77; + break; + + case 0x99: + dev->pci_conf[addr] = val & 0x80; + break; + + case 0x9a: + dev->pci_conf[addr] = val & 0xef; + break; + + case 0x9b: + case 0x9d: + dev->pci_conf[addr] = val & 0x80; + break; + + case 0xa4: + dev->pci_conf[addr] = val & 7; + break; + + case 0xa8: + dev->pci_conf[addr] = val & 0x37; + break; + + case 0xa9: + dev->pci_conf[addr] = (val & 2) | 1; + break; + + case 0xb0: + dev->pci_conf[addr] = val & 0x81; + break; + + case 0xb4: + dev->pci_conf[addr] = val & 8; + break; + + case 0xb9: + dev->pci_conf[addr] = val & 0xf0; + break; + + case 0xba: + dev->pci_conf[addr] = val; + break; + + case 0xbb: + dev->pci_conf[addr] = val & 0x1f; + break; + + case 0xbc ... 0xbd: + dev->pci_conf[addr] = val & 0xf8; + break; + + case 0xbe: + dev->pci_conf[addr] = val & 0x28; + break; + + case 0xcb: + dev->pci_conf[addr] = val & 0x3f; + break; + } +} + + +static uint8_t +intel_815ep_read(int func, int addr, void *priv) +{ + intel_815ep_t *dev = (intel_815ep_t *)priv; + + intel_815ep_log("Intel 815EP MCH: dev->regs[%02x] (%02x)\n", addr, dev->pci_conf[addr]); + + if(addr == 0x51) // Bit 2 is Write Only. It cannot be read. + return dev->pci_conf[addr] & 3; + else + return dev->pci_conf[addr]; +} + + +static void +intel_815ep_reset(void *priv) +{ + intel_815ep_t *dev = (intel_815ep_t *)priv; + memset(dev->pci_conf, 0x00, sizeof(dev->pci_conf)); /* Wash out the registers */ + + dev->pci_conf[0x00] = 0x86; /* Intel */ + dev->pci_conf[0x01] = 0x80; + + dev->pci_conf[0x02] = 0x30; /* 815EP */ + dev->pci_conf[0x03] = 0x11; + + dev->pci_conf[0x04] = 0x06; + + dev->pci_conf[0x06] = 0x90; + dev->pci_conf[0x08] = 0x02; + dev->pci_conf[0x0b] = 0x06; + dev->pci_conf[0x10] = 0x03; + dev->pci_conf[0x34] = 0xa0; + dev->pci_conf[0x50] = 0x40; + + dev->pci_conf[0x88] = 0x09; + dev->pci_conf[0x89] = 0xa0; + dev->pci_conf[0x8a] = 0x04; + dev->pci_conf[0x8b] = 0xf1; + + dev->pci_conf[0x92] = 0xff; + dev->pci_conf[0x93] = 0xff; + dev->pci_conf[0x94] = 0xff; + dev->pci_conf[0x95] = 0xff; + + dev->pci_conf[0xa0] = 0x02; + dev->pci_conf[0xa2] = 0x20; + + dev->pci_conf[0xa4] = 0x07; + dev->pci_conf[0xa5] = 0x02; + dev->pci_conf[0xa7] = 0x1f; + + dev->pci_conf[0xa9] = 0x01; /* Hack: Brute Force AGP Enabled */ + + for(int i = 0x58; i <= 0x5f; i++) /* Reset PAM to defaults */ + intel_pam_recalc(i, 0); + + intel_lsmm_segment_recalc(dev, 0); /* Reset LSMM SMRAM to defaults */ + intel_usmm_segment_recalc(dev, 0); /* Reset USMM SMRAM to defaults */ + +} + + +static void +intel_815ep_close(void *priv) +{ + intel_815ep_t *dev = (intel_815ep_t *)priv; + + smram_del(dev->lsmm_segment); + smram_del(dev->h_segment); + smram_del(dev->usmm_segment); + free(dev); +} + + +static void * +intel_815ep_init(const device_t *info) +{ + intel_815ep_t *dev = (intel_815ep_t *)malloc(sizeof(intel_815ep_t)); + memset(dev, 0, sizeof(intel_815ep_t)); + + /* Device */ + pci_add_card(PCI_ADD_NORTHBRIDGE, intel_815ep_read, intel_815ep_write, dev); /* Device 0: Intel 815EP MCH */ + + /* AGP Bridge */ + device_add(&intel_815ep_agp_device); + + /* L1 & L2 Cache */ + cpu_cache_int_enabled = 1; + cpu_cache_ext_enabled = 1; + cpu_update_waitstates(); + + /* SMRAM Segments */ + dev->lsmm_segment = smram_add(); + dev->h_segment = smram_add(); + dev->usmm_segment = smram_add(); + + intel_815ep_reset(dev); + return dev; +} + +const device_t intel_815ep_device = { + .name = "Intel 815EP MCH Bridge", + .internal_name = "intel_815ep", + .flags = DEVICE_PCI, + .local = 0, + .init = intel_815ep_init, + .close = intel_815ep_close, + .reset = intel_815ep_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/intel_ich2.c b/src/chipset/intel_ich2.c new file mode 100644 index 000000000..aeb890232 --- /dev/null +++ b/src/chipset/intel_ich2.c @@ -0,0 +1,903 @@ +/* + * Intel ICH2 + * + * Authors: Tiseno100, + * + * Copyright 2022 Tiseno100. + */ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include "x86.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/device.h> + +#include <86box/apm.h> +#include <86box/nvr.h> + +#include <86box/acpi.h> +#include <86box/dma.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/hdc_ide_sff8038i.h> +#include <86box/intel_ich2_gpio.h> +#include <86box/intel_ich2_trap.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/pic.h> +#include <86box/port_92.h> +#include <86box/smbus.h> +#include <86box/tco.h> +#include <86box/usb.h> + +#include <86box/chipset.h> + +#ifdef ENABLE_INTEL_ICH2_LOG +int intel_ich2_do_log = ENABLE_INTEL_ICH2_LOG; +static void +intel_ich2_log(const char *fmt, ...) +{ + va_list ap; + + if (intel_ich2_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define intel_ich2_log(fmt, ...) +#endif + +typedef struct intel_ich2_t +{ + uint8_t pci_conf[5][256]; + + acpi_t *acpi; + intel_ich2_gpio_t *gpio; + intel_ich2_trap_t *trap_device[10]; + nvr_t *nvr; + sff8038i_t *ide_drive[2]; + smbus_piix4_t *smbus; + tco_t *tco; + usb_t *usb_hub[2]; + +} intel_ich2_t; + +/* LPC Bridge functions */ +static void +intel_ich2_acpi_setup(intel_ich2_t *dev) +{ + uint32_t base = (dev->pci_conf[0][0x41] << 8) | (dev->pci_conf[0][0x40] & 0x80); + int acpi_irq = ((dev->pci_conf[0][0x44] & 7) < 3) ? (9 + (dev->pci_conf[0][0x44] & 7)) : 9; /* Under APIC you can set this even higher but */ + int enable = !!(dev->pci_conf[0][0x44] & 0x10); /* as we lack it we are restricted with low. */ + + acpi_update_io_mapping(dev->acpi, base, enable); + acpi_set_irq_line(dev->acpi, acpi_irq); +} + +static void +intel_ich2_trap_update(void *priv) +{ + intel_ich2_t *dev = (intel_ich2_t *) priv; + uint16_t temp_addr = 0; + + /* Hard Drives */ + intel_ich2_device_trap_setup(1, 0x48, 0x01, 0x1f0, 8, 1, dev->trap_device[0]); // HDD's don't have a decode bit + intel_ich2_device_trap_setup(1, 0x48, 0x01, 0x3f6, 1, 1, dev->trap_device[0]); + + intel_ich2_device_trap_setup(1, 0x48, 0x02, 0x170, 8, 1, dev->trap_device[1]); + intel_ich2_device_trap_setup(1, 0x48, 0x02, 0x376, 1, 1, dev->trap_device[1]); + + /* COM A */ + switch(dev->pci_conf[0][0xe0] & 7) + { + case 0: + temp_addr = 0x3f8; + break; + + case 1: + temp_addr = 0x2f8; + break; + + case 2: + temp_addr = 0x220; + break; + + case 3: + temp_addr = 0x228; + break; + + case 4: + temp_addr = 0x238; + break; + + case 5: + temp_addr = 0x2e8; + break; + + case 6: + temp_addr = 0x338; + break; + + case 7: + temp_addr = 0x3e8; + break; + } + intel_ich2_device_trap_setup(!!(dev->pci_conf[0][0xe6] & 1), 0x48, 0x10, temp_addr, 8, 0, dev->trap_device[2]); + + /* COM B */ + switch((dev->pci_conf[0][0xe0] >> 4) & 7) + { + case 0: + temp_addr = 0x3f8; + break; + + case 1: + temp_addr = 0x2f8; + break; + + case 2: + temp_addr = 0x220; + break; + + case 3: + temp_addr = 0x228; + break; + + case 4: + temp_addr = 0x238; + break; + + case 5: + temp_addr = 0x2e8; + break; + + case 6: + temp_addr = 0x338; + break; + + case 7: + temp_addr = 0x3e8; + break; + } + intel_ich2_device_trap_setup(!!(dev->pci_conf[0][0xe6] & 2), 0x48, 0x10, temp_addr, 8, 0, dev->trap_device[3]); + + /* LPT */ + switch(dev->pci_conf[0][0xe1] & 3) + { + case 0: + temp_addr = 0x378; + break; + + case 1: + temp_addr = 0x278; + break; + + case 2: + temp_addr = 0x3bc; + break; + } + intel_ich2_device_trap_setup(!!(dev->pci_conf[0][0xe6] & 4), 0x48, 0x10, temp_addr, 8, 0, dev->trap_device[4]); + + /* FDC */ + temp_addr = (dev->pci_conf[0][0xe1] & 0x10) ? 0x3f0 : 0x370; + intel_ich2_device_trap_setup(!!(dev->pci_conf[0][0xe6] & 8), 0x48, 0x10, temp_addr, 8, 0, dev->trap_device[5]); + + /* MSS */ + switch((dev->pci_conf[0][0xe2] >> 4) & 3) + { + case 0: + temp_addr = 0x530; + break; + + case 1: + temp_addr = 0x604; + break; + + case 2: + temp_addr = 0xe80; + break; + + case 3: + temp_addr = 0xf40; + break; + } + intel_ich2_device_trap_setup(!!(dev->pci_conf[0][0xe6] & 0x40), 0x49, 0x04, 0x170, 8, 0, dev->trap_device[6]); + + /* MIDI */ + temp_addr = (dev->pci_conf[0][0xe2] & 8) ? 0x300 : 0x330; + intel_ich2_device_trap_setup(!!(dev->pci_conf[0][0xe6] & 0x20), 0x49, 0x08, temp_addr, 2, 0, dev->trap_device[7]); + + /* KBC */ + intel_ich2_device_trap_setup(1, 0x49, 0x10, 0x60, 4, 0, dev->trap_device[8]); // KBC doesn't have a decode bit + + /* Adlib */ + intel_ich2_device_trap_setup(!!(dev->pci_conf[0][0xe6] & 0x80), 0x49, 0x20, 0x388, 4, 0, dev->trap_device[9]); +} + +static void +intel_ich2_tco_interrupt(intel_ich2_t *dev) +{ + uint16_t tco_irq = ((dev->pci_conf[0][0x54] & 7) < 3) ? (9 + (dev->pci_conf[0][0x45] & 7)) : 9; /* Under APIC you can set this even higher but */ + /* as we lack it we are restricted with low. */ + tco_irq_update(dev->tco, tco_irq); +} + +static void +intel_ich2_gpio_setup(intel_ich2_t *dev) +{ + uint16_t base = (dev->pci_conf[0][0x59] << 8) | (dev->pci_conf[0][0x58] & 0xc0); + int enable = !!(dev->pci_conf[0][0x5c] & 0x10); + + intel_ich2_gpio_base(enable, base, dev->gpio); +} + +static int +intel_ich2_pirq_table(uint8_t val) +{ +switch(val) +{ + case 0 ... 2: + case 8: + case 13: + return PCI_IRQ_DISABLED; + + default: + return val; +} +} + +static void +intel_ich2_pirq_update(int reset, int addr, uint8_t val) +{ + int pirq = (addr >= 0x68) ? (addr - 0x63) : (addr - 0x5f); + + if(((val & 0x80) != 0x80) && !reset) { /* 86Box doesn't have an APIC yet. */ + intel_ich2_log("Intel ICH2 LPC: Update PIRQ %c to IRQ %d\n", '@' + pirq, val); /* Under normal circumstances on an APIC enabled motherboard*/ + pci_set_irq_routing(pirq, intel_ich2_pirq_table(val)); /* this remains disabled and the IRQ are handed by the APIC */ + } /* itself. */ + else if(reset) + for(int i = 1; i <= 8; i++) + pci_set_irq_routing(i, PCI_IRQ_DISABLED); +} + +static void +intel_ich2_nvr_handler(intel_ich2_t *dev) +{ + intel_ich2_log("Intel ICH2 LPC: Extended NVR Aliases %s\n", (dev->pci_conf[0][0xd8] & 4) ? "Enabled" : "Disabled"); + + nvr_at_handler(!!(dev->pci_conf[0][0xd8] & 4), 0x74, dev->nvr); + nvr_at_handler(!!(dev->pci_conf[0][0xd8] & 4), 0x76, dev->nvr); +} + +static void +intel_ich2_function_disable(intel_ich2_t *dev) +{ +uint16_t smbus_addr = (dev->pci_conf[3][0x21] << 8) | (dev->pci_conf[3][0x20] & 0xf0); // Hold the SMBus Base Address value + +/* Disable IDE */ +if(dev->pci_conf[0][0xf2] & 2) { + ide_pri_disable(); + ide_sec_disable(); +} + +/* Disable USB Hub 1 */ +if(dev->pci_conf[0][0xf2] & 4) { + uhci_update_io_mapping(dev->usb_hub[0], dev->pci_conf[2][0x20] & 0xe0, dev->pci_conf[0][0x21], 0); +} + +/* Disable SMBus */ +if(dev->pci_conf[0][0xf2] & 8) { //ICH2 Supports the ability of the SMBus Controller to be active even if it's PCI device is disabled + smbus_piix4_remap(dev->smbus, smbus_addr, dev->pci_conf[0][0xf3] & 1); +} + +/* Disable USB Hub 2 */ +if(dev->pci_conf[0][0xf2] & 0x10) { + uhci_update_io_mapping(dev->usb_hub[1], 0, 0, 0); +} +} + +/* IDE Controller functions */ +static void +intel_ich2_ide_setup(intel_ich2_t *dev) +{ + ide_pri_disable(); + ide_sec_disable(); + + intel_ich2_log("Intel ICH2 IDE: Primary Channel is %s.\n", !!(dev->pci_conf[1][0x41] & 0x80) ? "Enabled" : "Disabled"); + if(dev->pci_conf[1][0x41] & 0x80) { + ide_pri_enable(); + } + + intel_ich2_log("Intel ICH2 IDE: Secondary Channel is %s.\n", !!(dev->pci_conf[1][0x43] & 0x80) ? "Enabled" : "Disabled"); + if(dev->pci_conf[1][0x43] & 0x80) { + ide_sec_enable(); + } +} + +static void +intel_ich2_bus_master_setup(intel_ich2_t *dev) +{ + uint16_t bm_base = ((dev->pci_conf[1][0x21] & 0xf0) << 8) | (dev->pci_conf[1][0x20] & 0xf0); + intel_ich2_log("Intel ICH2 IDE: IDE Bus Master address is 0x%04x.\n", bm_base); + sff_bus_master_handler(dev->ide_drive[0], dev->pci_conf[1][0x04] & 1, bm_base); + sff_bus_master_handler(dev->ide_drive[1], dev->pci_conf[1][0x04] & 1, bm_base + 8); +} +/* USB Controller functions */ +static void +intel_ich2_usb_setup(int func, intel_ich2_t* dev) +{ + int current_hub = (func == 4) ? 4 : 2; + int hub_num = (func == 4); + uhci_update_io_mapping(dev->usb_hub[hub_num], dev->pci_conf[current_hub][0x20] & 0xe0, dev->pci_conf[current_hub][0x21], !!(dev->pci_conf[current_hub][0x04] & 1)); +} + +/* SMBus Controller functions */ +static void +intel_ich2_smbus_setup(intel_ich2_t *dev) +{ + uint16_t base = (dev->pci_conf[3][0x21] << 8) | (dev->pci_conf[3][0x20] & 0xf0); + + if((dev->pci_conf[3][0x40] & 1) && (dev->pci_conf[3][0x04] & 1)) + intel_ich2_log("Intel ICH2 SMBus: SMBus is enabled.\n"); + + smbus_piix4_remap(dev->smbus, base, (dev->pci_conf[3][0x40] & 1) && (dev->pci_conf[3][0x04] & 1)); +} + +/* ICH2 Registers */ +static void +intel_ich2_write(int func, int addr, uint8_t val, void *priv) +{ + intel_ich2_t *dev = (intel_ich2_t *)priv; + + if(func == 0) { + intel_ich2_log("Intel ICH2 LPC: dev->regs[%02x] = %02x\n", addr, val); + switch(addr) + { + case 0x04: + dev->pci_conf[func][addr] = (val & 0x40) | 0x0f; + break; + + case 0x05: + dev->pci_conf[func][addr] = val & 0x01; + break; + + case 0x07: + dev->pci_conf[func][addr] &= val & 0xf9; + break; + + case 0x40 ... 0x41: + dev->pci_conf[func][addr] = val & ((addr & 1) ? 0xff : (0x80 | 1)); + intel_ich2_acpi_setup(dev); + break; + + case 0x44: + dev->pci_conf[func][addr] = val & 0x17; + intel_ich2_acpi_setup(dev); + break; + + case 0x4e: + dev->pci_conf[func][addr] = val & 0x03; + if((val & 0x01) && ((val & 0x02) == 0x02)) + smi_line = 1; + break; + + case 0x54: + dev->pci_conf[func][addr] = val & 0x0f; + intel_ich2_tco_interrupt(dev); + break; + + case 0x58 ... 0x59: + dev->pci_conf[func][addr] = val & ((addr & 1) ? 0xff : (0xc0 | 1)); + intel_ich2_gpio_setup(dev); + break; + + case 0x5c: + dev->pci_conf[func][addr] = val & 0x10; + intel_ich2_gpio_setup(dev); + break; + + case 0x60 ... 0x63: + case 0x68 ... 0x6b: + dev->pci_conf[func][addr] = val & 0x8f; + intel_ich2_pirq_update(0, addr, val); + break; + + case 0x64: + dev->pci_conf[func][addr] = val; + break; + + case 0x88: + dev->pci_conf[func][addr] = val & 6; + break; + + case 0x8a: + dev->pci_conf[func][addr] &= val & 6; + break; + + case 0x90: + dev->pci_conf[func][addr] = val; + break; + + case 0x91: + dev->pci_conf[func][addr] = val & 0xfc; + break; + + case 0xd0: + dev->pci_conf[func][addr] = val & 0x4f; /* Brute force APIC support as disabled */ + break; + + case 0xd1: + dev->pci_conf[func][addr] = val & 0x38; /* Brute force APIC support as disabled */ + break; + + case 0xd3: + dev->pci_conf[func][addr] = val & 0x03; + break; + + case 0xd4: + dev->pci_conf[func][addr] = val & 0x02; + break; + + case 0xd5: + dev->pci_conf[func][addr] = val & 0x3f; + break; + + case 0xd8: + dev->pci_conf[func][addr] = val & 0x1c; + intel_ich2_nvr_handler(dev); + break; + + case 0xe0: + dev->pci_conf[func][addr] = val & 0x77; + break; + + case 0xe1: + dev->pci_conf[func][addr] = val & 0x13; + intel_ich2_trap_update(dev); + break; + + case 0xe2: + dev->pci_conf[func][addr] = val & 0x3b; + intel_ich2_trap_update(dev); + break; + + case 0xe3: + dev->pci_conf[func][addr] = val; + break; + + case 0xe4: + dev->pci_conf[func][addr] = val & 0x81; + break; + + case 0xe5 ... 0xe6: + dev->pci_conf[func][addr] = val; + + if(addr == 0xe6) + intel_ich2_trap_update(dev); + break; + + case 0xe7: + dev->pci_conf[func][addr] = val & 0x3f; + break; + + case 0xe8 ... 0xeb: + dev->pci_conf[func][addr] = val; + break; + + case 0xec: + dev->pci_conf[func][addr] = val & 0xf1; + break; + + case 0xed: + dev->pci_conf[func][addr] = val; + break; + + case 0xee ... 0xef: + dev->pci_conf[func][addr] = val; + break; + + case 0xf0: + dev->pci_conf[func][addr] = val & 0x0f; + break; + + case 0xf2 ... 0xf3: + dev->pci_conf[func][addr] = val & ((addr & 1) ? 0x01 : 0xfe); + intel_ich2_function_disable(dev); + break; + } + } + else if((func == 1) && !(dev->pci_conf[0][0xf2] & 2)) { + intel_ich2_log("Intel ICH2 IDE: dev->regs[%02x] = %02x\n", addr, val); + switch(addr) + { + case 0x04: + dev->pci_conf[func][addr] = val & 5; + intel_ich2_ide_setup(dev); + intel_ich2_bus_master_setup(dev); + break; + + case 0x07: + dev->pci_conf[func][addr] &= val & 0x2e; + break; + + case 0x20 ... 0x21: + dev->pci_conf[func][addr] = val & ((addr & 1) ? 0xff : (0xf0 | 1)); + intel_ich2_bus_master_setup(dev); + break; + + case 0x2c ... 0x2f: + if(dev->pci_conf[func][addr] != 0) + dev->pci_conf[func][addr] = val; + break; + + case 0x40 ... 0x43: + dev->pci_conf[func][addr] = val & ((addr & 1) ? 0xf3 : 0xff); + intel_ich2_ide_setup(dev); + break; + + case 0x44: + dev->pci_conf[func][addr] = val; + break; + + case 0x48: + dev->pci_conf[func][addr] = val & 0x0f; + break; + + case 0x4a ... 0x4b: + dev->pci_conf[func][addr] = val & 0x33; + break; + } + } + else if(((func == 2) && !(dev->pci_conf[0][0xf2] & 4)) || ((func == 4) && !(dev->pci_conf[0][0xf2] & 0x10))) { + intel_ich2_log("Intel ICH2 USB Hub %d: dev->regs[%02x] = %02x\n", (func == 4), addr, val); + switch(addr) + { + case 0x04: + dev->pci_conf[func][addr] = val & 5; + intel_ich2_usb_setup(func, dev); + break; + + case 0x07: + dev->pci_conf[func][addr] &= val & 0x2e; + break; + + case 0x20 ... 0x21: + dev->pci_conf[func][addr] = val & ((addr & 1) ? 0xff : (0xf0 | 1)); + intel_ich2_usb_setup(func, dev); + break; + + case 0xc0: + dev->pci_conf[func][addr] = val & 0xbf; + break; + + case 0xc1: + dev->pci_conf[func][addr] &= val & 0xaf; + break; + + case 0xc4: + dev->pci_conf[func][addr] = val & 3; + break; + } + } + else if((func == 3) && !(dev->pci_conf[0][0xf2] & 8)) { + intel_ich2_log("Intel ICH2 SMBus: dev->regs[%02x] = %02x\n", addr, val); + switch(addr) + { + case 0x04: + dev->pci_conf[func][addr] = val & 1; + intel_ich2_smbus_setup(dev); + break; + + case 0x07: + dev->pci_conf[func][addr] &= val & 0x0e; + break; + + case 0x20 ... 0x21: + dev->pci_conf[func][addr] = val & ((addr & 1) ? 0xff : (0xf0 | 1)); + intel_ich2_smbus_setup(dev); + break; + + case 0x3c: + dev->pci_conf[func][addr] = val; + smbus_piix4_get_irq(val, dev->smbus); + break; + + case 0x40: + dev->pci_conf[func][addr] = val & 7; + intel_ich2_smbus_setup(dev); + smbus_piix4_smi_en(!!(val & 2), dev->smbus); + break; + } + } +} + + +static uint8_t +intel_ich2_read(int func, int addr, void *priv) +{ + intel_ich2_t *dev = (intel_ich2_t *)priv; + + if(func == 0) { + intel_ich2_log("Intel ICH2 LPC: dev->regs[%02x] (%02x)\n", addr, dev->pci_conf[func][addr]); + return dev->pci_conf[func][addr]; + } + else if((func == 1) && !(dev->pci_conf[0][0xf2] & 2)) { + intel_ich2_log("Intel ICH2 IDE: dev->regs[%02x] (%02x)\n", addr, dev->pci_conf[func][addr]); + return dev->pci_conf[func][addr]; + } + else if(((func == 2) && !(dev->pci_conf[0][0xf2] & 4)) || ((func == 4) && !(dev->pci_conf[0][0xf2] & 0x10))) { + intel_ich2_log("Intel ICH2 USB Hub %d: dev->regs[%02x] (%02x)\n", (func == 4), addr, dev->pci_conf[func][addr]); + + if((addr >= 0x2c) && (addr <= 0x2f)) /* USB shares the same subsystem vendor info as the IDE */ + return dev->pci_conf[1][addr]; + + return dev->pci_conf[func][addr]; + } + else if((func == 3) && !(dev->pci_conf[0][0xf2] & 8)) { + intel_ich2_log("Intel ICH2 SMBus: dev->regs[%02x] (%02x)\n", addr, dev->pci_conf[func][addr]); + + if((addr >= 0x2c) && (addr <= 0x2f)) /* SMBus shares the same subsystem vendor info as the IDE */ + return dev->pci_conf[1][addr]; + + return dev->pci_conf[func][addr]; + } + else return 0xff; +} + + +static void +intel_ich2_reset(void *priv) +{ + intel_ich2_t *dev = (intel_ich2_t *)priv; + memset(dev->pci_conf, 0, sizeof(dev->pci_conf)); /* Wash out the Registers */ + + /* Function 0: LPC Bridge */ + dev->pci_conf[0][0x00] = 0x86; + dev->pci_conf[0][0x01] = 0x80; + + dev->pci_conf[0][0x02] = 0x40; + dev->pci_conf[0][0x03] = 0x24; + + dev->pci_conf[0][0x04] = 0x0f; + + dev->pci_conf[0][0x06] = 0x80; + dev->pci_conf[0][0x07] = 0x02; + + dev->pci_conf[0][0x08] = 0x02; + + dev->pci_conf[0][0x0a] = 0x01; + dev->pci_conf[0][0x0b] = 0x06; + + dev->pci_conf[0][0x0e] = 0x80; + + dev->pci_conf[0][0x40] = 0x01; + + dev->pci_conf[0][0x58] = 0x01; + + dev->pci_conf[0][0x60] = 0x80; + dev->pci_conf[0][0x61] = 0x80; + dev->pci_conf[0][0x62] = 0x80; + dev->pci_conf[0][0x63] = 0x80; + + dev->pci_conf[0][0x64] = 0x10; + + dev->pci_conf[0][0x68] = 0x80; + dev->pci_conf[0][0x69] = 0x80; + dev->pci_conf[0][0x6a] = 0x80; + dev->pci_conf[0][0x6b] = 0x80; + + dev->pci_conf[0][0xd5] = 0x0f; + + dev->pci_conf[0][0xe3] = 0xff; + + dev->pci_conf[0][0xe8] = 0x33; + dev->pci_conf[0][0xe9] = 0x22; + dev->pci_conf[0][0xea] = 0x11; + dev->pci_conf[0][0xeb] = 0x00; + + dev->pci_conf[0][0xee] = 0x78; + dev->pci_conf[0][0xef] = 0x56; + + dev->pci_conf[0][0xf0] = 0x0f; + + intel_ich2_acpi_setup(dev); /* Setup the ACPI Interface */ + intel_ich2_tco_interrupt(dev); /* Configure the TCO Interrupt */ + intel_ich2_gpio_setup(dev); /* Setup the GPIO */ + intel_ich2_pirq_update(1, 0, 0); /* Reset the PIRQ interrupts */ + intel_ich2_nvr_handler(dev); /* Set the NVR aliases */ + + /* Function 1: IDE Controller */ + dev->pci_conf[1][0x00] = 0x86; + dev->pci_conf[1][0x01] = 0x80; + + dev->pci_conf[1][0x02] = 0x4b; + dev->pci_conf[1][0x03] = 0x24; + + dev->pci_conf[1][0x06] = 0x80; + dev->pci_conf[1][0x07] = 0x02; + + dev->pci_conf[1][0x08] = 0x02; + + dev->pci_conf[1][0x09] = 0x80; + dev->pci_conf[1][0x0a] = 0x01; + dev->pci_conf[1][0x0b] = 0x01; + + dev->pci_conf[1][0x20] = 0x01; + + dev->pci_conf[1][0x54] = 0xff; /* Hack: Fake Cable Conductor & UltraDMA details */ + + if(cpu_busspeed >= 100000000) /* Go UltraDMA 100 if CPU is up for it. Not that it actually matters */ + dev->pci_conf[1][0x55] = 0xf0; + + sff_bus_master_reset(dev->ide_drive[0], 0); /* Setup the IDE */ + sff_bus_master_reset(dev->ide_drive[1], 8); + intel_ich2_ide_setup(dev); + + /* Function 2: USB Hub 0 */ + dev->pci_conf[2][0x00] = 0x86; + dev->pci_conf[2][0x01] = 0x80; + + dev->pci_conf[2][0x02] = 0x42; + dev->pci_conf[2][0x03] = 0x24; + + dev->pci_conf[2][0x06] = 0x80; + dev->pci_conf[2][0x07] = 0x02; + + dev->pci_conf[2][0x08] = 0x02; + + dev->pci_conf[2][0x0a] = 0x03; + dev->pci_conf[2][0x0b] = 0x0c; + + dev->pci_conf[2][0x20] = 0x01; + + dev->pci_conf[2][0x3d] = 0x03; + + dev->pci_conf[2][0x60] = 0x10; + + dev->pci_conf[2][0xc1] = 0x20; + + intel_ich2_usb_setup(2, dev); + + /* Function 3: SMBus Controller */ + dev->pci_conf[3][0x00] = 0x86; + dev->pci_conf[3][0x01] = 0x80; + + dev->pci_conf[3][0x02] = 0x43; + dev->pci_conf[3][0x03] = 0x24; + + dev->pci_conf[3][0x06] = 0x80; + dev->pci_conf[3][0x07] = 0x02; + + dev->pci_conf[3][0x08] = 0x02; + + dev->pci_conf[3][0x09] = 0x80; + dev->pci_conf[3][0x0a] = 0x05; + dev->pci_conf[3][0x0b] = 0x0c; + + dev->pci_conf[3][0x20] = 0x01; + + dev->pci_conf[3][0x3d] = 0x02; + + intel_ich2_smbus_setup(dev); /* Setup the SMBus */ + + /* Function 4: USB Hub 1*/ + dev->pci_conf[4][0x00] = 0x86; + dev->pci_conf[4][0x01] = 0x80; + + dev->pci_conf[4][0x02] = 0x44; + dev->pci_conf[4][0x03] = 0x24; + + dev->pci_conf[4][0x06] = 0x80; + dev->pci_conf[4][0x07] = 0x02; + + dev->pci_conf[4][0x08] = 0x02; + + dev->pci_conf[4][0x0a] = 0x03; + dev->pci_conf[4][0x0b] = 0x0c; + + dev->pci_conf[4][0x20] = 0x01; + + dev->pci_conf[4][0x3d] = 0x03; + + dev->pci_conf[4][0x60] = 0x10; + + dev->pci_conf[4][0xc1] = 0x20; + + intel_ich2_usb_setup(4, dev); +} + + +static void +intel_ich2_close(void *priv) +{ + intel_ich2_t *dev = (intel_ich2_t *)priv; + + free(dev); +} + + +static void * +intel_ich2_init(const device_t *info) +{ + intel_ich2_t *dev = (intel_ich2_t *)malloc(sizeof(intel_ich2_t)); + memset(dev, 0, sizeof(intel_ich2_t)); + int slot; + + /* Device */ + slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, intel_ich2_read, intel_ich2_write, dev); /* Device 31: Intel ICH2 */ + + /* ACPI Interface */ + dev->acpi = device_add(&acpi_intel_ich2_device); + acpi_set_slot(dev->acpi, slot); + + /* DMA */ + dma_alias_set_piix(); + dma_lpc_init(); + + /* GPIO */ + dev->gpio = device_add(&intel_ich2_gpio_device); + + /* NVR Handler */ + dev->nvr = device_add(&piix4_nvr_device); + acpi_set_nvr(dev->acpi, dev->nvr); + + /* Intel ICH2 Hub */ + device_add(&intel_ich2_hub_device); + + /* PIC */ + pic_set_pci(); + + /* SMBus */ + dev->smbus = device_add(&intel_ich2_smbus_device); + smbus_piix4_get_acpi(dev->smbus, dev->acpi); + + /* SFF Compatible IDE Drives */ + dev->ide_drive[0] = device_add_inst(&sff8038i_device, 1); + dev->ide_drive[1] = device_add_inst(&sff8038i_device, 2); + sff_set_slot(dev->ide_drive[0], slot); + sff_set_slot(dev->ide_drive[1], slot); + + /* TCO */ + dev->tco = device_add(&tco_device); + acpi_set_tco(dev->acpi, dev->tco); + + /* I/O Traps */ + acpi_set_trap_update(dev->acpi, intel_ich2_trap_update, dev); + + for (int i = 0; i < 10; i++) { + dev->trap_device[i] = device_add_inst(&intel_ich2_trap_device, i + 1); + intel_ich2_trap_set_acpi(dev->trap_device[i], dev->acpi); + } + + /* USB */ + dev->usb_hub[0] = device_add_inst(&usb_device, 1); + dev->usb_hub[1] = device_add_inst(&usb_device, 2); + + intel_ich2_reset(dev); + + return dev; +} + +const device_t intel_ich2_device = { + .name = "Intel ICH2", + .internal_name = "intel_ich2", + .flags = DEVICE_PCI, + .local = 0, + .init = intel_ich2_init, + .close = intel_ich2_close, + .reset = intel_ich2_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 68cf6c38f..46b9faf5c 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -2439,6 +2439,22 @@ amd_k_invalid_rdmsr: EAX = msr.ecx187 & 0xffffffff; EDX = msr.ecx187 >> 32; break; + case 0x198: + EAX = msr.ecx198 & 0xffffffff; + EDX = msr.ecx198 >> 32; + break; + case 0x19a: + EAX = msr.ecx19a & 0xffffffff; + EDX = msr.ecx19a >> 32; + break; + case 0x19d: + EAX = msr.ecx19d & 0xffffffff; + EDX = msr.ecx19d >> 32; + break; + case 0x1a0: + EAX = msr.ecx1a0 & 0xffffffff; + EDX = msr.ecx1a0 >> 32; + break; case 0x1e0: EAX = msr.ecx1e0 & 0xffffffff; EDX = msr.ecx1e0 >> 32; @@ -2814,6 +2830,18 @@ amd_k_invalid_wrmsr: case 0x187: msr.ecx187 = EAX | ((uint64_t)EDX << 32); break; + case 0x198: + msr.ecx198 = EAX | ((uint64_t)EDX << 32); + break; + case 0x19a: + msr.ecx19a = EAX | ((uint64_t)EDX << 32); + break; + case 0x19d: + msr.ecx19d = EAX | ((uint64_t)EDX << 32); + break; + case 0x1a0: + msr.ecx1a0 = EAX | ((uint64_t)EDX << 32); + break; case 0x1e0: msr.ecx1e0 = EAX | ((uint64_t)EDX << 32); break; diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index b6998162f..d866acdf6 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -284,6 +284,12 @@ typedef struct { on the VIA Cyrix III */ uint64_t mtrr_deftype; /* 0x000002ff */ + /* Pentium II/III/IV MSR's needed for late BIOS */ + uint64_t ecx1a0; /* 0x000001a0 */ + uint64_t ecx198; /* 0x00000198 */ + uint64_t ecx19a; /* 0x0000019a */ + uint64_t ecx19d; /* 0x0000019d */ + /* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */ uint64_t mca_ctl[5]; /* 0x00000400, 0x00000404, 0x00000408, 0x0000040c, 0x00000410 - Machine Check Architecture */ uint64_t ecx570; /* 0x00000570 */ diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt index 658da7280..358a63fa5 100644 --- a/src/device/CMakeLists.txt +++ b/src/device/CMakeLists.txt @@ -13,11 +13,12 @@ # Copyright 2020,2021 David Hrdlička. # -add_library(dev OBJECT bugger.c cassette.c cartridge.c hasp.c hwm.c hwm_lm75.c hwm_lm78.c hwm_gl518sm.c - hwm_vt82c686.c ibm_5161.c isamem.c isartc.c ../lpt.c pci_bridge.c +add_library(dev OBJECT bugger.c cassette.c cartridge.c hasp.c hwm.c hwm_lm75.c hwm_lm78.c hwm_gl518sm.c hwm_nsc366.c + hwm_vt82c686.c ibm_5161.c intel_ich2_gpio.c intel_ich2_trap.c isamem.c isartc.c ../lpt.c pci_bridge.c postcard.c serial.c clock_ics9xxx.c isapnp.c i2c.c i2c_gpio.c smbus_piix4.c smbus_ali7101.c keyboard.c keyboard_xt.c keyboard_at.c - mouse.c mouse_bus.c mouse_serial.c mouse_ps2.c phoenix_486_jumper.c) + mouse.c mouse_bus.c mouse_serial.c mouse_ps2.c phoenix_486_jumper.c + tco.c) if(ISAMEM_RAMPAGE) target_compile_definitions(dev PRIVATE USE_ISAMEM_RAMPAGE) diff --git a/src/device/hwm_nsc366.c b/src/device/hwm_nsc366.c new file mode 100644 index 000000000..e0cae6e29 --- /dev/null +++ b/src/device/hwm_nsc366.c @@ -0,0 +1,399 @@ +/* + * National Semiconductor PC87366(NSC366) Hardware Monitor + * + * Authors: Tiseno100, + * + * Copyright 2022 Tiseno100. + */ + +/* The conversion algorithms were taken by the pc87360.c driver of the Linux kernel. + Respective credits goes to the authors. */ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/device.h> + +#include <86box/hwm.h> +#include <86box/nsc366.h> + +#define FAN_TO_REG(val, div) ((val) <= 100 ? 0 : 480000 / ((val) * (div))) +#define FAN_DIV_FROM_REG(val) (1 << (((val) >> 5) & 0x03)) +#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : 480000 / ((val) * (div))) + +#define IN_TO_REG(val, ref) ((val) < 0 ? 0 : (val) * 256 >= (ref) * 255 ? 255 : ((val) * 256 + (ref) / 2) / (ref)) +#define IN_FROM_REG(val, ref) (((val) * (ref) + 128) / 256) +#define VREF (dev->vlm_config_global[0x08] & 2) ? 3025 : 2966 //VREF taken from pc87360.c +#define VLM_BANK dev->vlm_config_global[0x09] + +#define TEMP_TO_REG(val) ((val) < -55000 ? -55 : (val) > 127000 ? 127 : (val) < 0 ? ((val) - 500) / 1000 : ((val) + 500) / 1000) +#define TEMP_FROM_REG(val) ((val) * 1000) +#define TMS_BANK dev->tms_config_global[0x09] + +#ifdef ENABLE_NSC366_HWM_LOG +int nsc366_hwm_do_log = ENABLE_NSC366_HWM_LOG; +void +nsc366_hwm_log(const char *fmt, ...) +{ + va_list ap; + + if (nsc366_hwm_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define nsc366_hwm_log(fmt, ...) +#endif + +/* Fans */ +static void +nsc366_fscm_write(uint16_t addr, uint8_t val, void *priv) +{ + nsc366_hwm_t *dev = (nsc366_hwm_t *)priv; + + addr &= 0x0f; + + nsc366_hwm_log("NSC366 Fan Control: Write 0x%02x to register 0x%02x\n", val, addr); + + switch(addr) + { + case 0x00: + case 0x02: + case 0x04: + dev->fscm_config[addr] = val; + break; + + case 0x01: + case 0x03: + case 0x05: + dev->fscm_config[addr] = val; + break; + + case 0x06: + case 0x09: + case 0x0c: + dev->fscm_config[addr] = val; + break; + + case 0x08: + case 0x0b: + case 0x0d: + dev->fscm_config[addr] = (val & 0x78) | 1; + break; + } +} + +static uint8_t +nsc366_fscm_read(uint16_t addr, void *priv) +{ + nsc366_hwm_t *dev = (nsc366_hwm_t *)priv; + + addr &= 0x0f; + + switch(addr) + { + case 0x00 ... 0x06: + case 0x08 ... 0x09: + case 0x0b ... 0x0c: + return dev->fscm_config[addr]; + + case 0x07: + case 0x0a: + case 0x0d: + nsc366_hwm_log("NSC366 Fan Control: Reading %d RPM's from Bank %d\n", FAN_FROM_REG(dev->fscm_config[addr], FAN_DIV_FROM_REG(dev->fscm_config[0x06])), (addr - 7) / 3); + return dev->fscm_config[addr]; + + default: + return 0; + } +} + +void +nsc366_update_fscm_io(int enable, uint16_t addr, nsc366_hwm_t *dev) +{ + if(dev->fscm_addr != 0) + io_removehandler(dev->fscm_addr, 15, nsc366_fscm_read, NULL, NULL, nsc366_fscm_write, NULL, NULL, dev); + + dev->fscm_addr = addr; + + if((addr != 0) && enable) + io_sethandler(addr, 15, nsc366_fscm_read, NULL, NULL, nsc366_fscm_write, NULL, NULL, dev); +} + +/* Voltage */ +static void +nsc366_vlm_write(uint16_t addr, uint8_t val, void *priv) +{ + nsc366_hwm_t *dev = (nsc366_hwm_t *)priv; + + addr &= 0x0f; + + if(addr <= 9) + nsc366_hwm_log("NSC366 Voltage Monitor: Write 0x%02x to register 0x%02x\n", val, addr); + else + nsc366_hwm_log("NSC366 Voltage Monitor: Write 0x%02x to register 0x%02x of bank %d\n", val, addr, VLM_BANK); + + switch(addr) + { + case 0x02 ... 0x04: + dev->vlm_config_global[addr] = val; + break; + + case 0x05: + dev->vlm_config_global[addr] = val & 0x3f; + break; + + case 0x06: + dev->vlm_config_global[addr] = val & 0xc0; + break; + + case 0x07: + dev->vlm_config_global[addr] = val & 0x3f; + break; + + case 0x08: + dev->vlm_config_global[addr] = val & 3; + break; + + case 0x09: + dev->vlm_config_global[addr] = val & 0x1f; + break; + + case 0x0a: + if(VLM_BANK < 13) + dev->vlm_config_bank[VLM_BANK][addr - 0x0a] = val & 1; + break; + + case 0x0c ... 0x0e: + if(VLM_BANK < 13) + dev->vlm_config_bank[VLM_BANK][addr - 0x0a] = val; + break; + } +} + + +static uint8_t +nsc366_vlm_read(uint16_t addr, void *priv) +{ + nsc366_hwm_t *dev = (nsc366_hwm_t *)priv; + + addr &= 0x0f; + + switch(addr) + { + case 0x00 ... 0x09: + return dev->vlm_config_global[addr]; + + case 0x0a: + case 0x0c ... 0x0e: + if(VLM_BANK < 13) + return dev->vlm_config_bank[VLM_BANK][addr - 0x0a]; + else + return 0; + + case 0x0b: + if (VLM_BANK < 13) { + nsc366_hwm_log("NSC366 Voltage Monitor: Reading %d Volts from Bank %d\n", IN_FROM_REG(dev->vlm_config_bank[VLM_BANK][1], VREF), VLM_BANK); + return dev->vlm_config_bank[VLM_BANK][1]; + } + else + return 0; + + default: + return 0; + } +} + +void +nsc366_update_vlm_io(int enable, uint16_t addr, nsc366_hwm_t *dev) +{ + if(dev->vlm_addr != 0) + io_removehandler(dev->vlm_addr, 15, nsc366_vlm_read, NULL, NULL, nsc366_vlm_write, NULL, NULL, dev); + + dev->vlm_addr = addr; + + if((addr != 0) && enable) + io_sethandler(addr, 15, nsc366_vlm_read, NULL, NULL, nsc366_vlm_write, NULL, NULL, dev); +} + +/* Temperature */ +static void +nsc366_tms_write(uint16_t addr, uint8_t val, void *priv) +{ + nsc366_hwm_t *dev = (nsc366_hwm_t *)priv; + + addr &= 0x0f; + + if(addr <= 9) + nsc366_hwm_log("NSC366 Temperature Monitor: Write 0x%02x to register 0x%02x\n", val, addr); + else + nsc366_hwm_log("NSC366 Temperature Monitor: Write 0x%02x to register 0x%02x of bank %d\n", val, addr, TMS_BANK); + + switch(addr) + { + case 0x02: + dev->tms_config_global[addr] = val & 0x3f; + break; + + case 0x04: + dev->tms_config_global[addr] = val & 0x3f; + break; + + case 0x08: + dev->tms_config_global[addr] = val & 3; + break; + + case 0x09: + dev->tms_config_global[addr] = val & 3; + break; + + case 0x0a: + if(TMS_BANK < 3) + dev->tms_config_bank[TMS_BANK][addr - 0x0a] = val & 1; + break; + + case 0x0c ... 0x0e: + if(TMS_BANK < 13) + dev->tms_config_bank[TMS_BANK][addr - 0x0a] = val; + break; + } +} + + +static uint8_t +nsc366_tms_read(uint16_t addr, void *priv) +{ + nsc366_hwm_t *dev = (nsc366_hwm_t *)priv; + + addr &= 0x0f; + addr++; + pclog("Reading %02x\n", addr); + + switch(addr) + { + case 0x00 ... 0x09: + return dev->tms_config_global[addr]; + + case 0x0a: + case 0x0c ... 0x0e: + //return dev->tms_config_bank[TMS_BANK][addr - 0x0a]; + return 1; + + case 0x0b: + nsc366_hwm_log("NSC366 Temperature Monitor: Reading %d Degrees Celsius from Bank %d\n", TEMP_FROM_REG(dev->tms_config_bank[TMS_BANK][1]), TMS_BANK); + return dev->tms_config_bank[TMS_BANK][1]; + + default: + return 0; + } +} + +void +nsc366_update_tms_io(int enable, uint16_t addr, nsc366_hwm_t *dev) +{ + if(dev->vlm_addr != 0) + io_removehandler(dev->tms_addr, 15, nsc366_tms_read, NULL, NULL, nsc366_tms_write, NULL, NULL, dev); + + dev->tms_addr = addr; + + if((addr != 0) && enable) + io_sethandler(addr, 15, nsc366_tms_read, NULL, NULL, nsc366_tms_write, NULL, NULL, dev); +} + + #define TEMP_FROM_REG(val) ((val) * 1000) + +static void +nsc366_hwm_reset(void *priv) +{ + nsc366_hwm_t *dev = (nsc366_hwm_t *)priv; + memset(dev->fscm_config, 0, sizeof(dev->fscm_config)); + dev->fscm_addr = 0; + + /* Get fan reports from defaults */ + dev->fscm_config[0x07] = FAN_TO_REG(dev->values->fans[0], FAN_DIV_FROM_REG(dev->fscm_config[0x06])); + dev->fscm_config[0x0a] = FAN_TO_REG(dev->values->fans[1], FAN_DIV_FROM_REG(dev->fscm_config[0x06])); + dev->fscm_config[0x0d] = FAN_TO_REG(dev->values->fans[2], FAN_DIV_FROM_REG(dev->fscm_config[0x06])); + + memset(dev->vlm_config_global, 0, sizeof(dev->vlm_config_global)); + memset(dev->vlm_config_bank, 0, sizeof(dev->vlm_config_bank)); + dev->vlm_addr = 0; + dev->vlm_config_global[0x08] = 3; + + /* Get voltage reports from defaults */ + for(int i = 0; i < 13; i++) { + dev->vlm_config_bank[i][1] = IN_TO_REG(dev->values->voltages[i], VREF); + } + + memset(dev->tms_config_global, 0, sizeof(dev->tms_config_global)); + memset(dev->tms_config_bank, 0, sizeof(dev->tms_config_bank)); + dev->tms_addr = 0; + dev->tms_config_global[0x08] = 3; + + /* Get temperature reports from defaults */ + for(int i = 0; i < 4; i++) + dev->tms_config_bank[i][1] = TEMP_TO_REG(dev->values->temperatures[i]); +} + + +static void +nsc366_hwm_close(void *priv) +{ + nsc366_hwm_t *dev = (nsc366_hwm_t *)priv; + + free(dev); +} + + +static void * +nsc366_hwm_init(const device_t *info) +{ + nsc366_hwm_t *dev = (nsc366_hwm_t *)malloc(sizeof(nsc366_hwm_t)); + memset(dev, 0, sizeof(nsc366_hwm_t)); + + /* Initialize the default values */ + hwm_values_t defaults = { + { + 3000, /* FAN 0 */ + 3000, /* FAN 1 */ + 3000 /* FAN 2 */ + }, + { + 255, /* Temperature 0 */ + 255, + 255, + 155 + }, + { + 65535, + 65535, + 65535, + } + }; + hwm_values = defaults; + dev->values = &hwm_values; + + return dev; +} + +const device_t nsc366_hwm_device = { + .name = "National Semiconductor NSC366 Hardware Monitor", + .internal_name = "nsc366_hwm", + .flags = 0, + .local = 0, + .init = nsc366_hwm_init, + .close = nsc366_hwm_close, + .reset = nsc366_hwm_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/device/intel_ich2_gpio.c b/src/device/intel_ich2_gpio.c new file mode 100644 index 000000000..e14cdbaec --- /dev/null +++ b/src/device/intel_ich2_gpio.c @@ -0,0 +1,180 @@ +/* + * Intel ICH2 GPIO + * + * Authors: Tiseno100, + * + * Copyright 2022 Tiseno100. + */ + + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/intel_ich2_gpio.h> + +#ifdef ENABLE_INTEL_ICH2_GPIO_LOG +int intel_ich2_gpio_do_log = ENABLE_INTEL_ICH2_GPIO_LOG; +static void +intel_ich2_gpio_log(const char *fmt, ...) +{ + va_list ap; + + if (intel_ich2_gpio_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define intel_ich2_gpio_log(fmt, ...) +#endif + + +static void +intel_ich2_gpio_write(uint16_t addr, uint8_t val, void *priv) +{ + intel_ich2_gpio_t *dev = (intel_ich2_gpio_t *) priv; + + addr -= dev->gpio_addr; + + intel_ich2_gpio_log("Intel ICH2 GPIO: Write 0x%02x on GPIO Register 0x%02x\n", val, addr); + + switch(addr) + { + /* GPIO Use Enable */ + case 0x00: + dev->gpio_regs[addr] = val & 0x3f; + break; + + case 0x01: + dev->gpio_regs[addr] = val & 8; + break; + + case 0x02: + dev->gpio_regs[addr] = val & 0x20; + break; + + /* GPIO I/O Select */ + case 0x07: + dev->gpio_regs[addr] = val & 0x1b; + break; + + /* GPIO Level */ + case 0x0e: + dev->gpio_regs[addr] = val; + break; + + case 0x0f: + dev->gpio_regs[addr] = val & 0x1b; + dev->gpio_regs[addr] &= dev->gpio_regs[0x1b]; // Mask out whatever change if the bits aren't programmed as outputs. + break; + + /* GPIO Blink which is not Utilized */ + case 0x1a: + dev->gpio_regs[addr] = val & 6; + break; + + case 0x1b: + dev->gpio_regs[addr] = val & 0x1a; + break; + + /* GPIO Signal Inverter */ + case 0x2d: + dev->gpio_regs[addr] = val & 0x39; + break; + } +} + + +static uint8_t +intel_ich2_gpio_read(uint16_t addr, void *priv) +{ + intel_ich2_gpio_t *dev = (intel_ich2_gpio_t *) priv; + + addr -= dev->gpio_addr; + + intel_ich2_gpio_log("Intel ICH2 GPIO: Reading 0x%02x from Register 0x%02x\n", dev->gpio_regs[addr], addr); + + if(addr <= 0x2f) + return dev->gpio_regs[addr]; + else + return 0xff; +} + +void +intel_ich2_gpio_base(int enable, uint16_t addr, intel_ich2_gpio_t *dev) +{ + if(dev->gpio_addr != 0) + io_removehandler(dev->gpio_addr, 15, intel_ich2_gpio_read, NULL, NULL, intel_ich2_gpio_write, NULL, NULL, dev); + + dev->gpio_addr = addr; + + if((addr != 0) && enable) + io_sethandler(addr, 15, intel_ich2_gpio_read, NULL, NULL, intel_ich2_gpio_write, NULL, NULL, dev); +} + +static void +intel_ich2_gpio_reset(void *priv) +{ + intel_ich2_gpio_t *dev = (intel_ich2_gpio_t *) priv; + dev->gpio_addr = 0; + + /* Enabled GPIO's */ + dev->gpio_regs[0x00] = 0x80; + dev->gpio_regs[0x01] = 0x31; + dev->gpio_regs[0x03] = 0x1a; + + /* GPIO Drives (Input or Output) */ + dev->gpio_regs[0x04] = 0xff; + dev->gpio_regs[0x05] = 0xff; + + dev->gpio_regs[0x0e] = 0x3f; + dev->gpio_regs[0x0f] = 0x1b; + + dev->gpio_regs[0x16] = 0x63; + dev->gpio_regs[0x17] = 0x06; +} + + +static void +intel_ich2_gpio_close(void *priv) +{ + intel_ich2_gpio_t *dev = (intel_ich2_gpio_t *) priv; + + free(dev); +} + + +static void * +intel_ich2_gpio_init(const device_t *info) +{ + intel_ich2_gpio_t *dev = (intel_ich2_gpio_t *) malloc(sizeof(intel_ich2_gpio_t)); + memset(dev, 0, sizeof(intel_ich2_gpio_t)); + + intel_ich2_gpio_reset(dev); + + return dev; +} + +const device_t intel_ich2_gpio_device = { + .name = "Intel ICH2 GPIO", + .internal_name = "intel_ich2_gpio", + .flags = 0, + .local = 0, + .init = intel_ich2_gpio_init, + .close = intel_ich2_gpio_close, + .reset = intel_ich2_gpio_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/device/intel_ich2_trap.c b/src/device/intel_ich2_trap.c new file mode 100644 index 000000000..0030f9639 --- /dev/null +++ b/src/device/intel_ich2_trap.c @@ -0,0 +1,107 @@ +/* + * Intel ICH2 Trap Handler + * + * Authors: Tiseno100, + * + * Copyright 2022 Tiseno100. + */ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/device.h> + +#include <86box/apm.h> +#include <86box/nvr.h> +#include <86box/acpi.h> + +#include <86box/intel_ich2_trap.h> + +#ifdef ENABLE_INTEL_ICH2_TRAP_LOG +int intel_ich2_trap_do_log = ENABLE_INTEL_ICH2_TRAP_LOG; +static void +intel_ich2_trap_log(const char *fmt, ...) +{ + va_list ap; + + if (intel_ich2_trap_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define intel_ich2_trap_log(fmt, ...) +#endif + +void +intel_ich2_trap_set_acpi(intel_ich2_trap_t *trap, acpi_t *acpi) +{ + trap->acpi = acpi; +} + +static void +intel_ich2_trap_kick(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv) +{ + intel_ich2_trap_t *trap = (intel_ich2_trap_t *) priv; + intel_ich2_trap_log("Intel ICH2 Trap: Entered an I/O Trap. Provoking an SMI.\n"); + acpi_raise_smi(trap->acpi, 1); +} + +void +intel_ich2_device_trap_setup(int enable, uint8_t acpi_reg, uint8_t acpi_reg_val, uint16_t addr, uint16_t size, int is_hdd, intel_ich2_trap_t *trap) +{ +uint8_t acpi_trap_recieve = ((acpi_reg == 0x49) ? (trap->acpi->regs.devtrap_en >> 8) : (trap->acpi->regs.devtrap_en)) & 0xff; // Check if the decoded range is enabled on ACPIS +int acpi_enable = !!(acpi_trap_recieve & acpi_reg_val); +int trap_enabled = acpi_enable && enable; + +if(trap_enabled) +{ + intel_ich2_trap_log("Intel ICH2 Trap: An I/O has been enabled on range 0x%x\n", addr); + io_trap_add(intel_ich2_trap_kick, trap->trap); +} + +io_trap_remap(trap->trap, trap_enabled, addr, size); +} + +static void +intel_ich2_trap_close(void *priv) +{ + intel_ich2_trap_t *trap = (intel_ich2_trap_t *) priv; + + io_trap_remove(trap->trap); // Remove the I/O Trap + free(trap); +} + +static void * +intel_ich2_trap_init(const device_t *info) +{ + intel_ich2_trap_t *trap = (intel_ich2_trap_t *) malloc(sizeof(intel_ich2_trap_t)); + memset(trap, 0, sizeof(intel_ich2_trap_t)); + + intel_ich2_trap_log("Intel ICH2 Trap: Starting a new Trap handler."); + + return trap; +} + +const device_t intel_ich2_trap_device = { + .name = "Intel ICH2 Trap Hander", + .internal_name = "intel_ich2_trap", + .flags = 0, + .local = 0, + .init = intel_ich2_trap_init, + .close = intel_ich2_trap_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/device/pci_bridge.c b/src/device/pci_bridge.c index 73fd3d157..a1bdd2c77 100644 --- a/src/device/pci_bridge.c +++ b/src/device/pci_bridge.c @@ -33,20 +33,22 @@ #define PCI_BRIDGE_DEC_21150 0x10110022 +#define PCI_BRIDGE_INTEL_ICH2 0x8086244e #define AGP_BRIDGE_ALI_M5243 0x10b95243 #define AGP_BRIDGE_ALI_M5247 0x10b95247 #define AGP_BRIDGE_INTEL_440LX 0x80867181 #define AGP_BRIDGE_INTEL_440BX 0x80867191 #define AGP_BRIDGE_INTEL_440GX 0x808671a1 +#define AGP_BRIDGE_INTEL_815EP 0x80861131 #define AGP_BRIDGE_VIA_597 0x11068597 #define AGP_BRIDGE_VIA_598 0x11068598 #define AGP_BRIDGE_VIA_691 0x11068691 #define AGP_BRIDGE_VIA_8601 0x11068601 #define AGP_BRIDGE_ALI(x) (((x) >> 16) == 0x10b9) -#define AGP_BRIDGE_INTEL(x) (((x) >> 16) == 0x8086) +#define AGP_BRIDGE_INTEL(x) ((((x) >> 16) == 0x8086) && ((x) != PCI_BRIDGE_INTEL_ICH2)) #define AGP_BRIDGE_VIA(x) (((x) >> 16) == 0x1106) -#define AGP_BRIDGE(x) ((x) >= AGP_BRIDGE_ALI_M5243) +#define AGP_BRIDGE(x) (((x) >= AGP_BRIDGE_ALI_M5243) && ((x) != PCI_BRIDGE_INTEL_ICH2)) typedef struct @@ -116,6 +118,10 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) if (AGP_BRIDGE_INTEL(dev->local)) { if (dev->local == AGP_BRIDGE_INTEL_440BX) val &= 0x1f; + else if (dev->local == AGP_BRIDGE_INTEL_815EP) + val &= 0x17; + else if (dev->local == PCI_BRIDGE_INTEL_ICH2) + val &= 0x47; } else if (dev->local == AGP_BRIDGE_ALI_M5243) val |= 0x02; else if (dev->local == AGP_BRIDGE_ALI_M5247) @@ -129,13 +135,17 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) val &= 0x01; else if (AGP_BRIDGE_ALI(dev->local)) val &= 0x01; + else if (PCI_BRIDGE_INTEL_ICH2) + val &= 0x01; else val &= 0x03; break; case 0x07: - if (dev->local == AGP_BRIDGE_INTEL_440LX) + if ((dev->local == AGP_BRIDGE_INTEL_440LX) || (dev->local == AGP_BRIDGE_INTEL_815EP)) dev->regs[addr] &= ~(val & 0x40); + else if (dev->local == PCI_BRIDGE_INTEL_ICH2) + dev->regs[addr] &= ~(val & 0xf9); else if (dev->local == AGP_BRIDGE_ALI_M5243) dev->regs[addr] &= ~(val & 0xf8); else if (dev->local == AGP_BRIDGE_ALI_M5247) @@ -165,15 +175,22 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) case 0x1f: if (AGP_BRIDGE_INTEL(dev->local)) { - if (dev->local == AGP_BRIDGE_INTEL_440LX) + if ((dev->local == AGP_BRIDGE_INTEL_440LX) || (dev->local == PCI_BRIDGE_INTEL_ICH2)) dev->regs[addr] &= ~(val & 0xf1); else if ((dev->local == AGP_BRIDGE_INTEL_440BX) || (dev->local == AGP_BRIDGE_INTEL_440GX)) dev->regs[addr] &= ~(val & 0xf0); + else if (dev->local == AGP_BRIDGE_INTEL_815EP) + dev->regs[addr] &= ~(val & 0xb2); } else if (AGP_BRIDGE_ALI(dev->local)) dev->regs[addr] &= ~(val & 0xf0); return; + case 0x1b: + if ((dev->local == AGP_BRIDGE_INTEL_815EP) || (dev->local == PCI_BRIDGE_INTEL_ICH2)) + val &= 0xf8; + break; + case 0x1c: case 0x1d: case 0x20: case 0x22: case 0x24: case 0x26: val &= 0xf0; @@ -200,6 +217,8 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) } else if (dev->local == PCI_BRIDGE_DEC_21150) val &= 0xef; + else if (dev->local == PCI_BRIDGE_INTEL_ICH2) + val &= 0x2f; break; case 0x3f: @@ -219,6 +238,8 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) case 0x40: if (dev->local == PCI_BRIDGE_DEC_21150) val &= 0x32; + else if ((dev->local == AGP_BRIDGE_INTEL_815EP) || (dev->local == PCI_BRIDGE_INTEL_ICH2)) + val &= 0x01; break; case 0x41: @@ -238,6 +259,16 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) val &= 0x03; break; + case 0x50: + if (dev->local == PCI_BRIDGE_INTEL_ICH2) + val &= 0x06; + break; + + case 0x51: + if (dev->local == PCI_BRIDGE_INTEL_ICH2) + val &= 0x03; + break; + case 0x64: if (dev->local == PCI_BRIDGE_DEC_21150) val &= 0x7e; @@ -248,6 +279,11 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) val &= 0x3f; break; + case 0x70: + if (dev->local == PCI_BRIDGE_INTEL_ICH2) + val &= 0xf8; + break; + case 0x86: if (AGP_BRIDGE_ALI(dev->local)) val &= 0x3f; @@ -278,6 +314,16 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) return; break; + case 0x90: + if (dev->local == PCI_BRIDGE_INTEL_ICH2) + val &= 0x06; + break; + + case 0x91: + if (dev->local == PCI_BRIDGE_INTEL_ICH2) + dev->regs[addr] = ~(val & 0x06); + break; + case 0xe0: case 0xe1: if (AGP_BRIDGE_ALI(dev->local)) { if (!(dev->ctl & 0x20)) @@ -379,6 +425,11 @@ pci_bridge_reset(void *priv) dev->regs[0x07] = 0x02; break; + case PCI_BRIDGE_INTEL_ICH2: + dev->regs[0x04] = 0x01; + dev->regs[0x06] = 0x80; + break; + case AGP_BRIDGE_ALI_M5243: dev->regs[0x04] = 0x06; dev->regs[0x07] = 0x04; @@ -411,6 +462,11 @@ pci_bridge_reset(void *priv) dev->regs[0x07] = dev->regs[0x08] = 0x02; break; + case AGP_BRIDGE_INTEL_815EP: + dev->regs[0x06] = 0x20; + dev->regs[0x08] = 0x02; + break; + case AGP_BRIDGE_VIA_597: case AGP_BRIDGE_VIA_598: case AGP_BRIDGE_VIA_691: @@ -453,6 +509,9 @@ pci_bridge_reset(void *priv) dev->regs[0x43] = 0x02; dev->regs[0xdc] = dev->regs[0xde] = 0x01; } + + if (dev->local == PCI_BRIDGE_INTEL_ICH2) + dev->regs[0x70] = 0x20; } @@ -471,27 +530,32 @@ pci_bridge_init(const device_t *info) pci_bridge_reset(dev); dev->slot = pci_add_card(AGP_BRIDGE(dev->local) ? PCI_ADD_AGPBRIDGE : PCI_ADD_BRIDGE, pci_bridge_read, pci_bridge_write, dev); - interrupt_count = sizeof(interrupts); - interrupt_mask = interrupt_count - 1; - if (dev->slot < 32) { - for (i = 0; i < interrupt_count; i++) - interrupts[i] = pci_get_int(dev->slot, PCI_INTA + i); - } - pci_bridge_log("PCI Bridge %d: upstream bus %02X slot %02X interrupts %02X %02X %02X %02X\n", dev->bus_index, (dev->slot >> 5) & 0xff, dev->slot & 31, interrupts[0], interrupts[1], interrupts[2], interrupts[3]); - if (info->local == PCI_BRIDGE_DEC_21150) - slot_count = 9; /* 9 bus masters */ - else - slot_count = 1; /* AGP bridges always have 1 slot */ + if ((info->local != PCI_BRIDGE_INTEL_ICH2) && (info->local != AGP_BRIDGE_INTEL_815EP)) /* Let the machine configuration slot handle the absurd interrupt tables */ + { + interrupt_count = sizeof(interrupts); + interrupt_mask = interrupt_count - 1; + if (dev->slot < 32) { + for (i = 0; i < interrupt_count; i++) + interrupts[i] = pci_get_int(dev->slot, PCI_INTA + i); + } - for (i = 0; i < slot_count; i++) { - /* Interrupts for bridge slots are assigned in round-robin: ABCD, BCDA, CDAB and so on. */ - pci_bridge_log("PCI Bridge %d: downstream slot %02X interrupts %02X %02X %02X %02X\n", dev->bus_index, i, interrupts[i & interrupt_mask], interrupts[(i + 1) & interrupt_mask], interrupts[(i + 2) & interrupt_mask], interrupts[(i + 3) & interrupt_mask]); - pci_register_bus_slot(dev->bus_index, i, AGP_BRIDGE(dev->local) ? PCI_CARD_AGP : PCI_CARD_NORMAL, - interrupts[i & interrupt_mask], - interrupts[(i + 1) & interrupt_mask], - interrupts[(i + 2) & interrupt_mask], - interrupts[(i + 3) & interrupt_mask]); + pci_bridge_log("PCI Bridge %d: upstream bus %02X slot %02X interrupts %02X %02X %02X %02X\n", dev->bus_index, (dev->slot >> 5) & 0xff, dev->slot & 31, interrupts[0], interrupts[1], interrupts[2], interrupts[3]); + + if (info->local == PCI_BRIDGE_DEC_21150) + slot_count = 9; /* 9 bus masters */ + else + slot_count = 1; /* AGP bridges always have 1 slot */ + + for (i = 0; i < slot_count; i++) { + /* Interrupts for bridge slots are assigned in round-robin: ABCD, BCDA, CDAB and so on. */ + pci_bridge_log("PCI Bridge %d: downstream slot %02X interrupts %02X %02X %02X %02X\n", dev->bus_index, i, interrupts[i & interrupt_mask], interrupts[(i + 1) & interrupt_mask], interrupts[(i + 2) & interrupt_mask], interrupts[(i + 3) & interrupt_mask]); + pci_register_bus_slot(dev->bus_index, i, AGP_BRIDGE(dev->local) ? PCI_CARD_AGP : PCI_CARD_NORMAL, + interrupts[i & interrupt_mask], + interrupts[(i + 1) & interrupt_mask], + interrupts[(i + 2) & interrupt_mask], + interrupts[(i + 3) & interrupt_mask]); + } } return dev; @@ -584,6 +648,34 @@ const device_t i440gx_agp_device = { .config = NULL }; +const device_t intel_ich2_hub_device = { + .name = "Intel ICH2 Hub Bridge", + .internal_name = "intel_ich2_hub", + .flags = DEVICE_PCI, + .local = PCI_BRIDGE_INTEL_ICH2, + .init = pci_bridge_init, + .close = NULL, + .reset = pci_bridge_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t intel_815ep_agp_device = { + .name = "Intel 815EP MCH AGP Bridge", + .internal_name = "intel_815ep_agp", + .flags = DEVICE_PCI, + .local = AGP_BRIDGE_INTEL_815EP, + .init = pci_bridge_init, + .close = NULL, + .reset = pci_bridge_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t via_vp3_agp_device = { .name = "VIA Apollo VP3 AGP Bridge", .internal_name = "via_vp3_agp", diff --git a/src/device/smbus_piix4.c b/src/device/smbus_piix4.c index de26b061c..4673b39a0 100644 --- a/src/device/smbus_piix4.c +++ b/src/device/smbus_piix4.c @@ -24,11 +24,14 @@ #include <86box/86box.h> #include <86box/io.h> #include <86box/device.h> +#include <86box/pic.h> #include <86box/timer.h> #include <86box/i2c.h> +#include <86box/apm.h> +#include <86box/nvr.h> +#include <86box/acpi.h> #include <86box/smbus.h> - #ifdef ENABLE_SMBUS_PIIX4_LOG int smbus_piix4_do_log = ENABLE_SMBUS_PIIX4_LOG; @@ -48,6 +51,34 @@ smbus_piix4_log(const char *fmt, ...) #define smbus_piix4_log(fmt, ...) #endif +void +smbus_piix4_get_acpi(smbus_piix4_t *dev, acpi_t *acpi) +{ + dev->acpi = acpi; +} + +void +smbus_piix4_get_irq(uint8_t irq, smbus_piix4_t *dev) +{ + dev->irq = irq; +} + +void +smbus_piix4_smi_en(uint8_t smi_en, smbus_piix4_t *dev) +{ + dev->smi_en = smi_en; +} + +static void +smbus_piix4_raise_smi(smbus_piix4_t *dev) +{ + if (dev->smi_en) { /* Raise SMI when needed if it's enabled by the Chipset */ + dev->acpi->regs.smi_sts |= 0x00010000; + acpi_raise_smi(dev->acpi, 1); + } + else + picint(1 << dev->irq); +} static uint8_t smbus_piix4_read(uint16_t addr, void *priv) @@ -99,7 +130,7 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) { smbus_piix4_t *dev = (smbus_piix4_t *) priv; uint8_t smbus_addr, cmd, read, block_len, prev_stat; - uint16_t timer_bytes = 0, i; + uint16_t timer_bytes = 0, i = 0; smbus_piix4_log("SMBus PIIX4: write(%02X, %02X)\n", addr, val); @@ -107,7 +138,7 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) dev->next_stat = 0x00; switch (addr - dev->io_base) { case 0x00: - for (smbus_addr = 0x02; smbus_addr <= 0x10; smbus_addr <<= 1) { /* handle clearable bits */ + for (smbus_addr = 0x02; smbus_addr <= ((dev->local == SMBUS_INTEL_ICH2) ? 0x40 : 0x10); smbus_addr <<= 1) { /* handle clearable bits */ if (val & smbus_addr) dev->stat &= ~smbus_addr; } @@ -213,22 +244,52 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) /* fall-through */ case 0xd: /* I2C block R/W */ - i2c_write(i2c_smbus, smbus_addr, dev->cmd); - timer_bytes++; + if (dev->local == SMBUS_INTEL_ICH2) { + if (!dev->byte_rw) { + i2c_write(i2c_smbus, smbus_addr, dev->cmd); + if(read) + dev->data0 = i2c_read(i2c_smbus, smbus_addr); // For byte reads, the count is recieved and stored at the DATA0 register + else + i2c_write(i2c_smbus, smbus_addr, dev->data0); - if (read) { - /* block read [data0] (I2C) or [first byte] (SMBus) bytes */ - if (cmd == 0x5) - dev->data0 = i2c_read(i2c_smbus, smbus_addr); - for (i = 0; i < dev->data0; i++) - dev->data[i & SMBUS_PIIX4_BLOCK_DATA_MASK] = i2c_read(i2c_smbus, smbus_addr); - } else { - if (cmd == 0x5) /* send length [data0] as first byte on SMBus */ - i2c_write(i2c_smbus, smbus_addr, dev->data0); - /* block write [data0] bytes */ - for (i = 0; i < dev->data0; i++) { - if (!i2c_write(i2c_smbus, smbus_addr, dev->data[i & SMBUS_PIIX4_BLOCK_DATA_MASK])) - break; + dev->byte_rw = 1; + } + + if (read) { + dev->block_data_byte = i2c_read(i2c_smbus, smbus_addr); + dev->stat |= 0x80; + smbus_piix4_raise_smi(dev); + if(dev->ctl & 0x20) { /* Finish the Transfer */ + dev->byte_rw = 0; + dev->stat |= 2; + } + } + else { + i2c_write(i2c_smbus, smbus_addr, dev->cmd); + if (((dev->byte_rw >> 4) & 0xff) < dev->data0) { + i2c_write(i2c_smbus, smbus_addr, dev->block_data_byte); + dev->stat |= 0x80; + dev->byte_rw += 0x10000; + } + else dev->byte_rw = 0; + } + } + else { + if (read) { + timer_bytes++; + /* block read [data0] (I2C) or [first byte] (SMBus) bytes */ + if (cmd == 0x5) + dev->data0 = i2c_read(i2c_smbus, smbus_addr); + for (i = 0; i < dev->data0; i++) + dev->data[i & SMBUS_PIIX4_BLOCK_DATA_MASK] = i2c_read(i2c_smbus, smbus_addr); + } else { + if (cmd == 0x5) /* send length [data0] as first byte on SMBus */ + i2c_write(i2c_smbus, smbus_addr, dev->data0); + /* block write [data0] bytes */ + for (i = 0; i < dev->data0; i++) { + if (!i2c_write(i2c_smbus, smbus_addr, dev->data[i & SMBUS_PIIX4_BLOCK_DATA_MASK])) + break; + } } } timer_bytes += i; @@ -283,7 +344,12 @@ unknown_protocol: } /* Finish transfer. */ - i2c_stop(i2c_smbus, smbus_addr); + if (dev->local == SMBUS_INTEL_ICH2) { + /* ICH2 SMBus specific. Transfer on Byte command doesn't stop till their specific points. */ + if (!dev->byte_rw) + i2c_stop(i2c_smbus, smbus_addr); + } else + i2c_stop(i2c_smbus, smbus_addr); } break; @@ -304,9 +370,13 @@ unknown_protocol: break; case 0x07: - dev->data[dev->index++] = val; - if (dev->index >= SMBUS_PIIX4_BLOCK_DATA_SIZE) - dev->index = 0; + if (dev->local == SMBUS_INTEL_ICH2) + dev->block_data_byte = val; + else { + dev->data[dev->index++] = val; + if (dev->index >= SMBUS_PIIX4_BLOCK_DATA_SIZE) + dev->index = 0; + } break; } @@ -362,7 +432,20 @@ smbus_piix4_init(const device_t *info) dev->local = info->local; /* We save the I2C bus handle on dev but use i2c_smbus for all operations because dev and therefore dev->i2c will be invalidated if a device triggers a hard reset. */ - i2c_smbus = dev->i2c = i2c_addbus((dev->local == SMBUS_VIA) ? "smbus_vt82c686b" : "smbus_piix4"); + switch(dev->local) + { + case SMBUS_PIIX4: + i2c_smbus = dev->i2c = i2c_addbus("smbus_piix4"); + break; + + case SMBUS_INTEL_ICH2: + i2c_smbus = dev->i2c = i2c_addbus("smbus_intel_ich2"); + break; + + case SMBUS_VIA: + i2c_smbus = dev->i2c = i2c_addbus("smbus_vt82c686b"); + break; + } timer_add(&dev->response_timer, smbus_piix4_response, dev, 0); @@ -398,6 +481,20 @@ const device_t piix4_smbus_device = { .config = NULL }; +const device_t intel_ich2_smbus_device = { + .name = "Intel ICH2 SMBus Host Controller", + .internal_name = "intel_ich2_smbus", + .flags = DEVICE_AT, + .local = SMBUS_INTEL_ICH2, + .init = smbus_piix4_init, + .close = smbus_piix4_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t via_smbus_device = { .name = "VIA VT82C686B SMBus Host Controller", .internal_name = "via_smbus", diff --git a/src/device/tco.c b/src/device/tco.c new file mode 100644 index 000000000..dc54fe364 --- /dev/null +++ b/src/device/tco.c @@ -0,0 +1,198 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Intel TCO Handler. + * + * Note: There's a TCO Timer too but for now it's of no use thus + * not implemented + * + * Authors: Tiseno100, + * + * Copyright 2022 Tiseno100. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/nmi.h> +#include <86box/pic.h> +#include <86box/pit.h> +#include <86box/tco.h> + + +#ifdef ENABLE_TCO_LOG +int tco_do_log = ENABLE_TCO_LOG; + + +static void +tco_log(const char *fmt, ...) +{ + va_list ap; + + if (tco_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define tco_log(fmt, ...) +#endif + + +void +tco_timer_handler(void *priv) +{ + /* TODO: Implement the TCO timer. */ + // tco_t *dev = (tco_t *) priv; +} + + +void +tco_irq_update(tco_t *dev, uint16_t new_irq) +{ + tco_log("TCO: Update IRQ to %d\n", new_irq); + dev->tco_irq = new_irq; +} + + +void +tco_write(uint16_t addr, uint8_t val, tco_t *dev) +{ + addr -= 0x60; + tco_log("TCO: Write 0x%02x to Register 0x%02x\n", val, addr); + + switch(addr) { + case 0x00: + dev->regs[addr] = val; + break; + + case 0x01: + dev->regs[addr] = val & 0x3f; + break; + + case 0x02: /* TCO Data in */ + dev->regs[addr] = val; + dev->regs[0x04] |= 2; + smi_line = 1; + break; + + case 0x03: /* TCO Data out */ + dev->regs[addr] = val; + dev->regs[0x04] |= 4; + picint(dev->tco_irq); + break; + + case 0x04: + dev->regs[addr] &= 0x8f; + break; + + case 0x05: + dev->regs[addr] &= 0x1f; + break; + + case 0x06: + dev->regs[addr] &= 0x07; + break; + + case 0x09: + if (val & 1) { + if (!nmi) /* If we're already on NMI */ + nmi = 1; + + dev->regs[addr] = (dev->regs[addr] & 1) | val; + dev->regs[addr] &= val; + } else + dev->regs[addr] = 0x0f; + break; + + case 0x0a: + dev->regs[addr] = val & 0x06; // Intrusion Interrupt or SMI. We never get intruded so we never control it. + break; + + case 0x0c ... 0x0d: + dev->regs[addr] = val; + break; + + case 0x10: + dev->regs[addr] = val & 0x03; + break; + } +} + + +uint8_t +tco_read(uint16_t addr, tco_t *dev) +{ + addr -= 0x60; + uint8_t ret = 0x00; + + if (addr <= 0x10) { + tco_log("TCO: Read 0x%02x from Register 0x%02x\n", dev->regs[addr], addr); + ret = dev->regs[addr]; + } + + return ret; +} + + +static void +tco_reset(void *priv) +{ + tco_t *dev = (tco_t *) priv; + memset(dev->regs, 0, sizeof(dev->regs)); + + dev->tco_irq = 9; + + dev->regs[0x01] = 0x04; + dev->regs[0x10] = 0x03; +} + + +static void +tco_close(void *priv) +{ + tco_t *dev = (tco_t *) priv; + + free(dev); +} + + +static void * +tco_init(const device_t *info) +{ + tco_t *dev = (tco_t *) malloc(sizeof(tco_t)); + memset(dev, 0, sizeof(tco_t)); + + tco_reset(dev); + + return dev; +} + + +const device_t tco_device = { + .name = "Intel TCO", + .internal_name = "tco", + .flags = 0, + .local = 0, + .init = tco_init, + .close = tco_close, + .reset = tco_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/dma.c b/src/dma.c index c109f1b8d..8dfabd4fe 100644 --- a/src/dma.c +++ b/src/dma.c @@ -1171,6 +1171,28 @@ dma_alias_set_piix(void) } +void +dma_lpc_init(void) /* Addresses LPC DMA uses */ +{ + io_sethandler(0x1000, 16, + dma_read,NULL,NULL, dma_write,NULL,NULL, NULL); + io_sethandler(0x1080, 8, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); + io_sethandler(0x10C0, 32, + dma16_read,NULL,NULL, dma16_write,NULL,NULL, NULL); + io_sethandler(0x1088, 8, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); + io_sethandler(0x1090, 1, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); + io_sethandler(0x1094, 3, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); + io_sethandler(0x1098, 1, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); + io_sethandler(0x109C, 3, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); +} + + void dma_alias_remove(void) { diff --git a/src/include/86box/acpi.h b/src/include/86box/acpi.h index 94b2cd0fe..8c70bea78 100644 --- a/src/include/86box/acpi.h +++ b/src/include/86box/acpi.h @@ -22,6 +22,8 @@ extern "C" { #endif +#include <86box/tco.h> /* TCO Header. Needed for Intel ICH chipsets. */ + #define ACPI_TIMER_FREQ 3579545 #define PM_FREQ ACPI_TIMER_FREQ @@ -51,6 +53,7 @@ extern "C" { #define VEN_ALI 0x010b9 #define VEN_INTEL 0x08086 +#define VEN_INTEL_ICH2 0x18086 #define VEN_SIS 0x01039 #define VEN_SMC 0x01055 #define VEN_VIA 0x01106 @@ -59,18 +62,19 @@ extern "C" { typedef struct { - uint8_t acpitst, auxen, auxsts, plvl2, plvl3, + uint8_t acpitst, auxen, auxsts, bus_cyc_track, plvl2, plvl3, smicmd, gpio_dir, gpio_val, muxcntrl, ali_soft_smi, timer32, smireg, - gpireg[3], gporeg[4], + gpireg[3], gporeg[4], tco[17], extiotrapsts, extiotrapen; uint16_t pmsts, pmen, - pmcntrl, gpsts, gpsts1, + pmcntrl, bus_addr_track, devact_sts, + devtrap_en, gpsts, gpsts1, gpen, gpen1, gpscien, gpcntrl, gplvl, gpmux, gpsel, gpsmien, pscntrl, - gpscists; + gpscists, mon_smi; int smi_lock, smi_active; uint32_t pcntrl, p2cntrl, glbsts, devsts, glben, @@ -78,7 +82,7 @@ typedef struct padsts, paden, gptren, gptimer, gpo_val, gpi_val, - extsmi_val, pad0; + extsmi_val, smi_en, smi_sts, pad0; } acpi_regs_t; @@ -96,6 +100,7 @@ typedef struct pc_timer_t timer, resume_timer; nvr_t *nvr; apm_t *apm; + tco_t *tco; void *i2c, (*trap_update)(void *priv), *trap_priv; } acpi_t; @@ -106,6 +111,7 @@ extern int acpi_rtc_status; extern const device_t acpi_ali_device; extern const device_t acpi_intel_device; +extern const device_t acpi_intel_ich2_device; extern const device_t acpi_smc_device; extern const device_t acpi_via_device; extern const device_t acpi_via_596b_device; @@ -125,6 +131,7 @@ extern void acpi_set_irq_line(acpi_t *dev, int irq_line); extern void acpi_set_mirq_is_level(acpi_t *dev, int mirq_is_level); extern void acpi_set_gpireg2_default(acpi_t *dev, uint8_t gpireg2_default); extern void acpi_set_nvr(acpi_t *dev, nvr_t *nvr); +extern void acpi_set_tco(acpi_t *dev, tco_t *tco); extern void acpi_set_trap_update(acpi_t *dev, void (*update)(void *priv), void *priv); extern uint8_t acpi_ali_soft_smi_status_read(acpi_t *dev); extern void acpi_ali_soft_smi_status_write(acpi_t *dev, uint8_t soft_smi); diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index eddb37bff..8d3a663fb 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -99,6 +99,9 @@ extern const device_t slc90e66_device; extern const device_t ioapic_device; +extern const device_t intel_815ep_device; +extern const device_t intel_ich2_device; + /* OPTi */ extern const device_t opti283_device; extern const device_t opti291_device; diff --git a/src/include/86box/device.h b/src/include/86box/device.h index 04cc071c4..20a4babc5 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -52,6 +52,7 @@ #define CONFIG_HEX20 8 #define CONFIG_MAC 9 #define CONFIG_MIDI_IN 10 +#define CONFIG_BIOS 11 enum { @@ -77,6 +78,14 @@ typedef struct { int value; } device_config_selection_t; +typedef struct { + const char *name; + const char *internal_name; + int bios_type; + int files_no; + const char **files; +} device_config_bios_t; + typedef struct { int16_t min; int16_t max; @@ -92,6 +101,7 @@ typedef struct { const char *file_filter; const device_config_spinner_t spinner; const device_config_selection_t selection[16]; + const device_config_bios_t *bios; } device_config_t; typedef struct _device_ { @@ -161,6 +171,7 @@ extern void device_set_config_hex16(const char *s, int val); extern void device_set_config_hex20(const char *s, int val); extern void device_set_config_mac(const char *s, int val); extern const char *device_get_config_string(const char *name); +#define device_get_config_bios device_get_config_string extern char * device_get_internal_name(const device_t *d); diff --git a/src/include/86box/dma.h b/src/include/86box/dma.h index 585d77e95..2c7f63d57 100644 --- a/src/include/86box/dma.h +++ b/src/include/86box/dma.h @@ -93,6 +93,8 @@ extern void dma_alias_set_piix(void); extern void dma_alias_remove(void); extern void dma_alias_remove_piix(void); +extern void dma_lpc_init(void); + extern void dma_bm_read(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize, int TransferSize); extern void dma_bm_write(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize, int TransferSize); diff --git a/src/include/86box/flash.h b/src/include/86box/flash.h index 531cc7037..fc7482e66 100644 --- a/src/include/86box/flash.h +++ b/src/include/86box/flash.h @@ -30,4 +30,7 @@ extern const device_t sst_flash_39sf010_device; extern const device_t sst_flash_39sf020_device; extern const device_t sst_flash_39sf040_device; +extern const device_t sst_flash_49lf002_device; +extern const device_t sst_flash_49lf004_device; + #endif /*EMU_FLASH_H*/ diff --git a/src/include/86box/hwm.h b/src/include/86box/hwm.h index ef5621da6..6a642a697 100644 --- a/src/include/86box/hwm.h +++ b/src/include/86box/hwm.h @@ -55,6 +55,8 @@ extern uint8_t lm78_as99127f_write(void *priv, uint8_t reg, uint8_t val); /* hwm_vt82c686.c */ extern void vt82c686_hwm_write(uint8_t addr, uint8_t val, void *priv); +/* sio_w83627hf.c */ +extern void w83627hf_stabilizer(int vcoreb, int fan1, int fan2, int fan3); /* Refer to specific hardware monitor implementations for the meaning of hwm_values. */ extern hwm_values_t hwm_values; diff --git a/src/include/86box/intel_ich2_gpio.h b/src/include/86box/intel_ich2_gpio.h new file mode 100644 index 000000000..945b38d41 --- /dev/null +++ b/src/include/86box/intel_ich2_gpio.h @@ -0,0 +1,30 @@ +/* + * Intel ICH2 GPIO Header + * + * Authors: Tiseno100, + * + * Copyright 2022 Tiseno100. + */ + +#ifndef EMU_INTEL_ICH2_GPIO_H +# define EMU_INTEL_ICH2_GPIO_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct intel_ich2_gpio_t +{ + uint16_t gpio_addr; + uint8_t gpio_regs[48]; +} intel_ich2_gpio_t; + +void intel_ich2_gpio_base(int enable, uint16_t addr, intel_ich2_gpio_t *dev); + +extern const device_t intel_ich2_gpio_device; + +#ifdef __cplusplus +} +#endif + +#endif /*EMU_INTEL_ICH2_GPIO_H*/ diff --git a/src/include/86box/intel_ich2_trap.h b/src/include/86box/intel_ich2_trap.h new file mode 100644 index 000000000..0905bdb24 --- /dev/null +++ b/src/include/86box/intel_ich2_trap.h @@ -0,0 +1,31 @@ +/* + * Intel ICH2 Trap Header + * + * Authors: Tiseno100, + * + * Copyright 2022 Tiseno100. + */ + +#ifndef EMU_INTEL_ICH2_TRAP_H +# define EMU_INTEL_ICH2_TRAP_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct intel_ich2_trap_t +{ + acpi_t *acpi; + void *trap; +} intel_ich2_trap_t; + +extern void intel_ich2_trap_set_acpi(intel_ich2_trap_t *trap, acpi_t *acpi); +extern void intel_ich2_device_trap_setup(int enable, uint8_t acpi_reg, uint8_t acpi_reg_val, uint16_t addr, uint16_t size, int is_hdd, intel_ich2_trap_t *trap); + +extern const device_t intel_ich2_trap_device; + +#ifdef __cplusplus +} +#endif + +#endif /*EMU_INTEL_ICH2_TRAP_H*/ diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 3f887e7a9..422445bbc 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -161,6 +161,7 @@ enum { MACHINE_TYPE_SLOT1_370, MACHINE_TYPE_SLOT2, MACHINE_TYPE_SOCKET370, + MACHINE_TYPE_ICH2, MACHINE_TYPE_MISC, MACHINE_TYPE_MAX }; @@ -206,6 +207,7 @@ enum { MACHINE_CHIPSET_INTEL_440BX, MACHINE_CHIPSET_INTEL_440ZX, MACHINE_CHIPSET_INTEL_440GX, + MACHINE_CHIPSET_INTEL_I815EP, MACHINE_CHIPSET_OPTI_283, MACHINE_CHIPSET_OPTI_291, MACHINE_CHIPSET_OPTI_493, @@ -332,6 +334,11 @@ extern int machine_get_ram_granularity(int m); extern int machine_get_type(int m); extern void machine_close(void); +extern uint8_t machine_get_p1(void); +extern void machine_load_p1(int m); +extern uint32_t machine_get_gpi(void); +extern void machine_load_gpi(int m); +extern void machine_set_gpi(uint32_t gpi); /* Initialization functions for boards and systems. */ extern void machine_common_init(const machine_t *); @@ -696,6 +703,11 @@ extern int machine_at_p6bap_init(const machine_t *); /* m_at_misc.c */ extern int machine_at_vpc2007_init(const machine_t *); +/* m_at_ich2.c */ +extern int machine_at_m6tsl_init(const machine_t *); +extern int machine_at_m6tss_init(const machine_t *); +extern int machine_at_s2080_init(const machine_t *); + /* m_at_t3100e.c */ extern int machine_at_t3100e_init(const machine_t *); diff --git a/src/include/86box/nsc366.h b/src/include/86box/nsc366.h new file mode 100644 index 000000000..bf1e7063d --- /dev/null +++ b/src/include/86box/nsc366.h @@ -0,0 +1,44 @@ +/* + * National Semiconductor PC87366(NSC366) Header + * + * Authors: Tiseno100, + * + * Copyright 2022 Tiseno100. + */ + +#ifndef EMU_NSC_366_H +# define EMU_NSC_366_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + hwm_values_t *values; + + uint8_t fscm_enable; + uint16_t fscm_addr; + uint8_t fscm_config[15]; + + uint16_t vlm_addr; + uint8_t vlm_config_global[10]; + uint8_t vlm_config_bank[13][5]; + + uint16_t tms_addr; + uint8_t tms_config_global[10]; + uint8_t tms_config_bank[4][5]; +} nsc366_hwm_t; + +extern void nsc366_update_fscm_io(int enable, uint16_t addr, nsc366_hwm_t *dev); +extern void nsc366_update_vlm_io(int enable, uint16_t addr, nsc366_hwm_t *dev); +extern void nsc366_update_tms_io(int enable, uint16_t addr, nsc366_hwm_t *dev); + +/* The Hardware Monitor */ +extern const device_t nsc366_hwm_device; + +#ifdef __cplusplus +} +#endif + +#endif /*EMU_NSC_366_H*/ diff --git a/src/include/86box/pci.h b/src/include/86box/pci.h index 7908ea558..e464d9aa3 100644 --- a/src/include/86box/pci.h +++ b/src/include/86box/pci.h @@ -138,11 +138,14 @@ extern void pci_pic_reset(void); #ifdef EMU_DEVICE_H extern const device_t dec21150_device; +extern const device_t intel_ich2_hub_device; + extern const device_t ali5243_agp_device; extern const device_t ali5247_agp_device; extern const device_t i440lx_agp_device; extern const device_t i440bx_agp_device; extern const device_t i440gx_agp_device; +extern const device_t intel_815ep_agp_device; extern const device_t via_vp3_agp_device; extern const device_t via_mvp3_agp_device; extern const device_t via_apro_agp_device; diff --git a/src/include/86box/pit.h b/src/include/86box/pit.h index e823794df..aaaa1448c 100644 --- a/src/include/86box/pit.h +++ b/src/include/86box/pit.h @@ -70,7 +70,8 @@ extern uint64_t PITCONST, ISACONST, HERCCONST, VGACONST1, VGACONST2, - RTCCONST; + RTCCONST, + TCOCONST; extern int refresh_at_enable; diff --git a/src/include/86box/sio.h b/src/include/86box/sio.h index e0cf20fe0..53c675fb5 100644 --- a/src/include/86box/sio.h +++ b/src/include/86box/sio.h @@ -45,6 +45,8 @@ extern const device_t i82091aa_device; extern const device_t i82091aa_398_device; extern const device_t i82091aa_ide_pri_device; extern const device_t i82091aa_ide_device; +extern const device_t nsc366_device; +extern const device_t nsc366_4f_device; extern const device_t pc87306_device; extern const device_t pc87307_device; extern const device_t pc87307_15c_device; @@ -71,6 +73,8 @@ extern const device_t sio_detect_device; #endif extern const device_t um8669f_device; extern const device_t via_vt82c686_sio_device; +extern const device_t w83627hf_device; +extern const device_t w83627hf_no_hwm_device; extern const device_t w83787f_device; extern const device_t w83787f_ide_device; extern const device_t w83787f_ide_en_device; diff --git a/src/include/86box/smbus.h b/src/include/86box/smbus.h index 4c2c00c17..e365f38b9 100644 --- a/src/include/86box/smbus.h +++ b/src/include/86box/smbus.h @@ -18,6 +18,9 @@ #ifndef EMU_SMBUS_PIIX4_H # define EMU_SMBUS_PIIX4_H +#include <86box/apm.h> +#include <86box/nvr.h> +#include <86box/acpi.h> #define SMBUS_PIIX4_BLOCK_DATA_SIZE 32 #define SMBUS_PIIX4_BLOCK_DATA_MASK (SMBUS_PIIX4_BLOCK_DATA_SIZE - 1) @@ -28,17 +31,20 @@ enum { SMBUS_PIIX4 = 0, + SMBUS_INTEL_ICH2, SMBUS_VIA }; typedef struct { uint32_t local; - uint16_t io_base; + uint16_t io_base, byte_rw; int clock; double bit_period; uint8_t stat, next_stat, ctl, cmd, addr, data0, data1, - index, data[SMBUS_PIIX4_BLOCK_DATA_SIZE]; + index, data[SMBUS_PIIX4_BLOCK_DATA_SIZE], block_data_byte, + irq, smi_en; + acpi_t *acpi; pc_timer_t response_timer; void *i2c; } smbus_piix4_t; @@ -53,6 +59,9 @@ typedef struct { void *i2c; } smbus_ali7101_t; +extern void smbus_piix4_get_acpi(smbus_piix4_t *dev, acpi_t *acpi); +extern void smbus_piix4_get_irq(uint8_t irq, smbus_piix4_t *dev); +extern void smbus_piix4_smi_en(uint8_t smi_en, smbus_piix4_t *dev); extern void smbus_piix4_remap(smbus_piix4_t *dev, uint16_t new_io_base, uint8_t enable); extern void smbus_piix4_setclock(smbus_piix4_t *dev, int clock); @@ -62,6 +71,7 @@ extern void smbus_ali7101_remap(smbus_ali7101_t *dev, uint16_t new_io_base, uint #ifdef EMU_DEVICE_H extern const device_t piix4_smbus_device; +extern const device_t intel_ich2_smbus_device; extern const device_t via_smbus_device; extern const device_t ali7101_smbus_device; diff --git a/src/include/86box/spd.h b/src/include/86box/spd.h index 76a336d8b..71a250009 100644 --- a/src/include/86box/spd.h +++ b/src/include/86box/spd.h @@ -25,9 +25,11 @@ #define SPD_TYPE_FPM 0x01 #define SPD_TYPE_EDO 0x02 #define SPD_TYPE_SDRAM 0x04 +#define SPD_TYPE_DDR 0x07 #define SPD_MIN_SIZE_EDO 8 #define SPD_MIN_SIZE_SDRAM 8 +#define SPD_MIN_SIZE_DDR 8 #define SPD_SIGNAL_LVTTL 0x01 @@ -89,6 +91,29 @@ typedef struct { checksum2; } spd_sdram_t; +typedef struct { + uint8_t bytes_used, spd_size, mem_type, + row_bits, col_bits, rows, + data_width_lsb, data_width_msb, + signal_level, tclk, tac, + config, refresh_rate, + sdram_width, ecc_width, + tccd, burst, banks, cas, cslat, we, + mod_attr, dev_attr, + tclk2, tac2, tclk3, tac3, + trp, trrd, trcd, tras, + bank_density, + ca_setup, ca_hold, data_setup, data_hold, + reserved[26], + spd_rev, checksum, + mfg_jedec[8], mfg_loc; + char part_no[18]; + uint8_t rev_code[2], + mfg_year, mfg_week, serial[4], mfg_specific[27], + other_data[127], + checksum2; +} spd_ddr_t; + typedef struct { uint8_t slot; uint16_t size; @@ -99,6 +124,7 @@ typedef struct { uint8_t data[SPD_DATA_SIZE]; spd_edo_t edo_data; spd_sdram_t sdram_data; + spd_ddr_t ddr_data; }; void *eeprom; } spd_t; @@ -109,5 +135,6 @@ extern void spd_write_drbs(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint extern void spd_write_drbs_with_ext(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit); extern void spd_write_drbs_interleaved(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit); extern void spd_write_drbs_ali1621(uint8_t *regs, uint8_t reg_min, uint8_t reg_max); +extern void spd_write_drbs_intel_815ep(uint8_t *regs); #endif /*EMU_SPD_H*/ diff --git a/src/include/86box/tco.h b/src/include/86box/tco.h new file mode 100644 index 000000000..bd5c0a16f --- /dev/null +++ b/src/include/86box/tco.h @@ -0,0 +1,33 @@ +/* + * Intel TCO Header + * + * Authors: Tiseno100, + * + * Copyright 2022 Tiseno100. + */ + +#ifndef EMU_TCO_H +# define EMU_TCO_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + uint8_t regs[17]; + uint16_t tco_irq; + pc_timer_t *tco_timer; +} tco_t; + +extern const device_t tco_device; + +extern void tco_irq_update(tco_t *dev, uint16_t new_irq); +extern void tco_write(uint16_t addr, uint8_t val, tco_t *dev); +extern uint8_t tco_read(uint16_t addr, tco_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* EMU_TCO_H */ diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt index 62bd5c61f..e91f099fb 100644 --- a/src/machine/CMakeLists.txt +++ b/src/machine/CMakeLists.txt @@ -22,7 +22,7 @@ add_library(mch OBJECT machine.c machine_table.c m_xt.c m_xt_compaq.c m_ps2_mca.c m_at_compaq.c m_at_286_386sx.c m_at_386dx_486.c m_at_socket4.c m_at_socket5.c m_at_socket7_3v.c m_at_socket7.c m_at_sockets7.c m_at_socket8.c m_at_slot1.c m_at_slot2.c m_at_socket370.c - m_at_misc.c) + m_at_misc.c m_at_ich2.c) if(AN430TX) target_compile_definitions(mch PRIVATE USE_AN430TX) diff --git a/src/machine/m_at_ich2.c b/src/machine/m_at_ich2.c new file mode 100644 index 000000000..2a0617276 --- /dev/null +++ b/src/machine/m_at_ich2.c @@ -0,0 +1,148 @@ +/* + * Intel ICH2 based Motherboards + * + * Authors: Tiseno100, + * + * Copyright 2022 Tiseno100. + */ + +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/mem.h> +#include <86box/io.h> +#include <86box/rom.h> +#include <86box/pci.h> +#include <86box/device.h> +#include <86box/chipset.h> +#include <86box/flash.h> +#include <86box/sio.h> +#include <86box/spd.h> +#include <86box/clock.h> +#include "cpu.h" +#include <86box/machine.h> + +/* + * Biostar M6TSL + * + * North Bridge: Intel 815E + * Super I/O: National Semiconductor NSC366 (PC87366) + * BIOS: AwardBIOS 6.00PG + * Notes: No integrated ESS Solo & GPU +*/ +int +machine_at_m6tsl_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/m6tsl/tsl0425b.bin", + 0x00080000, 524288, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_bus_slot(0, 0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_bus_slot(0, 0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + pci_register_bus_slot(0, 0x1e, PCI_CARD_BRIDGE, 0, 0, 0, 0); + pci_register_bus_slot(0, 0x1f, PCI_CARD_SOUTHBRIDGE, 1, 2, 8, 4); + pci_register_bus_slot(1, 0x01, PCI_CARD_AGP, 1, 2, 3, 4); + pci_register_bus_slot(2, 0x03, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_bus_slot(2, 0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_bus_slot(2, 0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_bus_slot(2, 0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_bus_slot(2, 0x07, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_bus_slot(2, 0x08, PCI_CARD_NORMAL, 2, 3, 4, 1); + + device_add(&intel_815ep_device); /* Intel 815EP MCH (This board has normally an i815E but this doesn't matter on our implementation) */ + device_add(&intel_ich2_device); /* Intel ICH2 */ + device_add(&nsc366_device); /* National Semiconductor NSC366 */ + device_add(&sst_flash_49lf004_device); /* SST 4Mbit Firmware Hub */ + device_add(ics9xxx_get(ICS9250_08)); /* ICS Clock Chip */ + spd_register(SPD_TYPE_SDRAM, 0x7, 512); + + return ret; +} + +int +machine_at_m6tss_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/m6tss/tss0518b.bin", + 0x00080000, 524288, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_bus_slot(0, 0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_bus_slot(0, 0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + pci_register_bus_slot(0, 0x1e, PCI_CARD_BRIDGE, 0, 0, 0, 0); + pci_register_bus_slot(0, 0x1f, PCI_CARD_SOUTHBRIDGE, 1, 2, 8, 4); + pci_register_bus_slot(1, 0x01, PCI_CARD_AGP, 1, 2, 3, 4); + pci_register_bus_slot(2, 0x03, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_bus_slot(2, 0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_bus_slot(2, 0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_bus_slot(2, 0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); // 0x0a + pci_register_bus_slot(2, 0x07, PCI_CARD_NORMAL, 1, 2, 3, 4); + + device_add(&intel_815ep_device); /* Intel 815EP MCH */ + device_add(&intel_ich2_device); /* Intel ICH2 */ + device_add(&nsc366_device); /* National Semiconductor NSC366 */ + device_add(&sst_flash_49lf004_device); /* SST 4Mbit Firmware Hub */ + device_add(ics9xxx_get(ICS9250_08)); /* ICS Clock Chip */ + spd_register(SPD_TYPE_SDRAM, 0x7, 512); + + return ret; +} + +/* + * Tyan Tomcat 815T (S2080) + * + * North Bridge: Intel 815EP + * Super I/O: National Semiconductor NSC366 (PC87366) + * BIOS: AMIBIOS 7 (AMI Home BIOS Fork) + * Notes: None +*/ +int +machine_at_s2080_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/s2080/2080V110.ROM", + 0x00080000, 524288, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_bus_slot(0, 0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_bus_slot(0, 0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); + pci_register_bus_slot(0, 0x1e, PCI_CARD_BRIDGE, 0, 0, 0, 0); + pci_register_bus_slot(0, 0x1f, PCI_CARD_SOUTHBRIDGE, 1, 2, 8, 4); + pci_register_bus_slot(1, 0x01, PCI_CARD_AGP, 1, 2, 3, 4); + pci_register_bus_slot(2, 0x04, PCI_CARD_NORMAL, 2, 3, 4, 5); + pci_register_bus_slot(2, 0x05, PCI_CARD_NORMAL, 3, 4, 5, 6); + pci_register_bus_slot(2, 0x06, PCI_CARD_NORMAL, 4, 5, 6, 7); + pci_register_bus_slot(2, 0x07, PCI_CARD_NORMAL, 5, 6, 7, 8); + pci_register_bus_slot(2, 0x08, PCI_CARD_NORMAL, 6, 7, 8, 2); // 0x0a + pci_register_bus_slot(2, 0x09, PCI_CARD_NORMAL, 7, 8, 2, 3); + + device_add(&intel_815ep_device); /* Intel 815EP MCH */ + device_add(&intel_ich2_device); /* Intel ICH2 */ + device_add(&nsc366_device); /* National Semiconductor NSC366 */ + device_add(&sst_flash_49lf004_device); /* SST 4Mbit Firmware Hub */ + spd_register(SPD_TYPE_SDRAM, 0x7, 512); + + return ret; +} diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 91f9ddf76..6810c2510 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -77,6 +77,7 @@ const machine_filter_t machine_types[] = { { "Slot 1/Socket 370", MACHINE_TYPE_SLOT1_370 }, { "Slot 2", MACHINE_TYPE_SLOT2 }, { "Socket 370", MACHINE_TYPE_SOCKET370 }, + { "Intel ICH2", MACHINE_TYPE_ICH2 }, { "Miscellaneous", MACHINE_TYPE_MISC } }; @@ -121,6 +122,7 @@ const machine_filter_t machine_chipsets[] = { { "Intel 440BX", MACHINE_CHIPSET_INTEL_440BX }, { "Intel 440ZX", MACHINE_CHIPSET_INTEL_440ZX }, { "Intel 440GX", MACHINE_CHIPSET_INTEL_440GX }, + { "Intel i815EP", MACHINE_CHIPSET_INTEL_I815EP }, { "OPTi 283", MACHINE_CHIPSET_OPTI_283 }, { "OPTi 291", MACHINE_CHIPSET_OPTI_291 }, { "OPTi 493", MACHINE_CHIPSET_OPTI_493 }, @@ -10931,6 +10933,108 @@ const machine_t machines[] = { .vid_device = NULL }, + /* Intel ICH2 */ + /* Has a NSC PC87366 LPC Super I/O with on-chip AMIKey-2 KBC firmware*/ + { + .name = "[Intel i815E] Biostar M6TSL", + .internal_name = "m6tsl", + .type = MACHINE_TYPE_ICH2, + .chipset = MACHINE_CHIPSET_INTEL_I815EP, + .init = machine_at_m6tsl_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET370, + .block= CPU_BLOCK(CPU_CYRIX3S), + .min_bus = 66666667, + .max_bus = 133333333, + .min_voltage = 1300, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0, + }, + .bus_flags = MACHINE_PS2_NOISA, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 32768, + .max = 524288, + .step = 32768, + }, + .nvrmask = 255, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[Intel i815EP] Biostar M6TSS", + .internal_name = "m6tss", + .type = MACHINE_TYPE_ICH2, + .chipset = MACHINE_CHIPSET_INTEL_I815EP, + .init = machine_at_m6tss_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET370, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 133333333, + .min_voltage = 1300, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0, + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 32768, + .max = 524288, + .step = 32768, + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[Intel i815EP] Tyan Tomcat i815T", + .internal_name = "s2080", + .type = MACHINE_TYPE_ICH2, + .chipset = MACHINE_CHIPSET_INTEL_I815EP, + .init = machine_at_s2080_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET370, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 133333333, + .min_voltage = 1300, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0, + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 32768, + .max = 524288, + .step = 32768 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + { .name = NULL, .internal_name = NULL, @@ -10967,6 +11071,41 @@ const machine_t machines[] = { } }; +/* Saved copies - jumpers get applied to these. + We use also machine_gpio to store IBM PC/XT jumpers as they need more than one byte. */ +static uint16_t machine_p1; +static uint32_t machine_gpio; + +uint8_t +machine_get_p1(void) +{ + return machine_p1; +} + +void +machine_load_p1(int m) +{ + machine_p1 = machines[machine].kbc_p1; +} + +uint32_t +machine_get_gpio(void) +{ + return machine_gpio; +} + +void +machine_load_gpio(int m) +{ + machine_gpio = machines[machine].gpio; +} + +void +machine_set_gpio(uint32_t gpio) +{ + machine_gpio = gpio; +} + int machine_count(void) { diff --git a/src/mem/spd.c b/src/mem/spd.c index acc7ced9f..42346b76e 100644 --- a/src/mem/spd.c +++ b/src/mem/spd.c @@ -190,6 +190,7 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size) uint16_t min_module_size, rows[SPD_MAX_SLOTS], asym; spd_edo_t *edo_data; spd_sdram_t *sdram_data; + spd_ddr_t *ddr_data; /* Determine the minimum module size for this RAM type. */ switch (ram_type) { @@ -202,6 +203,10 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size) min_module_size = SPD_MIN_SIZE_SDRAM; break; + case SPD_TYPE_DDR: + min_module_size = SPD_MIN_SIZE_DDR; + break; + default: spd_log("SPD: unknown RAM type %02X\n", ram_type); return; @@ -335,6 +340,60 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size) for (i = 0; i < 129; i++) sdram_data->checksum2 += spd_modules[slot]->data[i]; break; + + case SPD_TYPE_DDR: + ddr_data = &spd_modules[slot]->ddr_data; + + ddr_data->bytes_used = 0x80; + ddr_data->spd_size = 0x08; + ddr_data->mem_type = ram_type; + ddr_data->row_bits = SPD_ROLLUP(6 + log2i(spd_modules[slot]->row1)); /* first row */ + ddr_data->col_bits = 9; + if (spd_modules[slot]->row1 != spd_modules[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */ + ddr_data->row_bits |= SPD_ROLLUP(6 + log2i(spd_modules[slot]->row2)) << 4; /* second row, if different from first */ + ddr_data->col_bits |= 9 << 4; /* same as first row, but just in case */ + } + ddr_data->rows = 2; + ddr_data->data_width_lsb = 64; + ddr_data->signal_level = SPD_SIGNAL_LVTTL; + ddr_data->tclk = 0x75; /* 7.5 ns = 133.3 MHz */ + ddr_data->tac = 0x10; + ddr_data->refresh_rate = SPD_SDR_REFRESH_SELF | SPD_REFRESH_NORMAL; + ddr_data->sdram_width = 8; + ddr_data->tccd = 1; + ddr_data->burst = SPD_SDR_BURST_PAGE | 1 | 2 | 4 | 8; + ddr_data->banks = 4; + ddr_data->cas = 0x7f; /* CAS Latency */ + ddr_data->cslat = ddr_data->we = 0x7f; + ddr_data->dev_attr = SPD_SDR_ATTR_EARLY_RAS | SPD_SDR_ATTR_AUTO_PC | SPD_SDR_ATTR_PC_ALL | SPD_SDR_ATTR_W1R_BURST; + ddr_data->tclk2 = 0xA0; /* 10 ns = 100 MHz */ + ddr_data->tclk3 = 0xF0; /* 15 ns = 66.7 MHz */ + ddr_data->tac2 = ddr_data->tac3 = 0x10; + ddr_data->trp = ddr_data->trrd = ddr_data->trcd = ddr_data->tras = 1; + if (spd_modules[slot]->row1 != spd_modules[slot]->row2) { + /* Utilities interpret bank_density a bit differently on asymmetric modules. */ + ddr_data->bank_density = 1 << (log2i(spd_modules[slot]->row1 >> 1) - 2); /* first row */ + ddr_data->bank_density |= 1 << (log2i(spd_modules[slot]->row2 >> 1) - 2); /* second row */ + } else { + ddr_data->bank_density = 1 << (log2i(spd_modules[slot]->row1 >> 1) - 1); /* symmetric module = only one bit is set */ + } + ddr_data->ca_setup = ddr_data->data_setup = 0x15; + ddr_data->ca_hold = ddr_data->data_hold = 0x08; + + ddr_data->spd_rev = 0x10; + for (i = spd_write_part_no(ddr_data->part_no, "DDR", rows[row]); + i < sizeof(ddr_data->part_no); i++) + ddr_data->part_no[i] = ' '; /* part number should be space-padded */ + ddr_data->rev_code[0] = BCD8(EMU_VERSION_MAJ); + ddr_data->rev_code[1] = BCD8(EMU_VERSION_MIN); + ddr_data->mfg_year = 20; + ddr_data->mfg_week = 13; + + for (i = 0; i < 63; i++) + ddr_data->checksum += spd_modules[slot]->data[i]; + for (i = 0; i < 129; i++) + ddr_data->checksum2 += spd_modules[slot]->data[i]; + break; } row++; @@ -518,7 +577,7 @@ spd_write_drbs_ali1621(uint8_t *regs, uint8_t reg_min, uint8_t reg_max) } /* Write DRBs for each row. */ - spd_log("SPD: Writing DRBs... regs=[%02X:%02X] unit=%d\n", reg_min, reg_max, drb_unit); +// spd_log("SPD: Writing DRBs... regs=[%02X:%02X] unit=%d\n", reg_min, reg_max, drb_unit); for (dimm = 0; dimm <= ((reg_max - reg_min) >> 2); dimm++) { size = 0; drb = reg_min + (dimm << 2); @@ -577,6 +636,84 @@ spd_write_drbs_ali1621(uint8_t *regs, uint8_t reg_min, uint8_t reg_max) } +void +spd_write_drbs_intel_815ep(uint8_t *regs) +{ + /* All Intel MCH based boards demand SPD so we ignore completely the non-SPD calculations */ + int size; + int reg_apply; + uint16_t rows[SPD_MAX_SLOTS]; + + if(!spd_present) + spd_populate(rows, 3, mem_size << 10, 32, 512, 0); + + /* Clear previous configurations */ + regs[0x52] = regs[0x54] = 0; + + /* Write DRBs for each row. */ + for (int slot = 0; slot < 3; slot++) { + size = spd_modules[slot]->row1 + spd_modules[slot]->row2; + spd_log("Intel 815EP SPD: Registering Slot %d with size %dMB.\n", slot, size); + + /* Calculate Size. Nullify if the size is illegal. */ + switch(size) + { + default: + reg_apply = 0; + spd_log("Intel 815EP SPD: Illegal Size on Slot %d. Size not divisible by 32.\n", slot); + break; + + case 32: + reg_apply = 1; + break; + + case 48: + reg_apply = 3; + break; + + case 64: + reg_apply = 4; + break; + + case 96: + reg_apply = 6; + break; + + case 128: + reg_apply = 7; + break; + + case 192: + reg_apply = 11; + break; + + case 256: + reg_apply = 12; + break; + + case 512: + reg_apply = 15; + break; + } + + /* Write on the representative register */ + switch(slot) + { + case 0: + regs[0x52] |= reg_apply; + break; + + case 1: + regs[0x52] |= reg_apply << 4; + break; + + case 2: + regs[0x54] |= reg_apply; + break; + } + } +} + static const device_t spd_device = { .name = "Serial Presence Detect ROMs", .internal_name = "spd", diff --git a/src/mem/sst_flash.c b/src/mem/sst_flash.c index 9aa0d4345..d132b8105 100644 --- a/src/mem/sst_flash.c +++ b/src/mem/sst_flash.c @@ -80,6 +80,9 @@ static char flash_path[1024]; #define SST39SF020 0xb600 #define SST39SF040 0xb700 +#define SST49LF002 0x5700 +#define SST49LF004 0x6000 + #define WINBOND 0xda /* Winbond Manufacturer's ID */ #define W29C020 0x4500 @@ -564,3 +567,39 @@ const device_t sst_flash_39sf040_device = { .force_redraw = NULL, .config = NULL }; + +/* + * Firmware Hubs. The FWH signals are not implemented yet. Firmware Hubs do write cycles + * to read/write on the flash. SST Flashes still do traditional flashing via PP Mode. Our + * BIOS firmwares don't seem to utilize FWH R/W thus the FWH ports remain unknown for an + * implementation. We just contain the ID's so the BIOS can do ESCD & DMI writes with no + * worries. +*/ +const device_t sst_flash_49lf002_device = { + .name = "SST 49LF002 Firmware Hub", + .internal_name = "sst_flash_49lf002", + .flags = 0, + .local = SST | SST49LF002 | SIZE_2M, + .init = sst_init, + .close = sst_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t sst_flash_49lf004_device = { + .name = "SST 49LF004 Firmware Hub", + .internal_name = "sst_flash_49lf004", + .flags = 0, + .local = SST | SST49LF004 | SIZE_4M, + + .init = sst_init, + .close = sst_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/pic.c b/src/pic.c index ca2bff2f7..f99b31901 100644 --- a/src/pic.c +++ b/src/pic.c @@ -540,6 +540,11 @@ pic_set_pci(void) io_sethandler(i, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic); io_sethandler(i + 0x0080, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2); } + + for (i = 0xff20; i < 0xff40; i += 4) { + io_sethandler(i, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic); + io_sethandler(i + 0x0080, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2); + } } diff --git a/src/sio/CMakeLists.txt b/src/sio/CMakeLists.txt index 5017295b1..f492f5fcb 100644 --- a/src/sio/CMakeLists.txt +++ b/src/sio/CMakeLists.txt @@ -15,10 +15,11 @@ add_library(sio OBJECT sio_acc3221.c sio_ali5123.c sio_f82c710.c sio_82091aa.c sio_fdc37c6xx.c sio_fdc37c67x.c sio_fdc37c669.c sio_fdc37c93x.c sio_fdc37m60x.c + sio_nsc366.c sio_it8661f.c sio_pc87306.c sio_pc87307.c sio_pc87309.c sio_pc87310.c sio_pc87311.c sio_pc87332.c sio_prime3b.c sio_prime3c.c - sio_w83787f.c sio_w83877f.c sio_w83977f.c sio_um8669f.c + sio_w83627hf.c sio_w83787f.c sio_w83877f.c sio_w83977f.c sio_um8669f.c sio_vt82c686.c) if(SIO_DETECT) diff --git a/src/sio/sio_nsc366.c b/src/sio/sio_nsc366.c new file mode 100644 index 000000000..91e40b72b --- /dev/null +++ b/src/sio/sio_nsc366.c @@ -0,0 +1,530 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the National Semiconductor PC87366 (NSC366) + * Super I/O chip. + * + * Author: Tiseno100, + * Copyright 2022 Tiseno100. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/hwm.h> +#include <86box/keyboard.h> +#include <86box/lpt.h> +#include <86box/nsc366.h> +#include <86box/serial.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/fdd_common.h> +#include <86box/port_92.h> +#include <86box/sio.h> + + +typedef struct +{ + fdc_t *fdc; + serial_t *uart[2]; + nsc366_hwm_t *hwm; + + uint8_t index, ldn, sio_config[14], + ld_activate[15], + io_base0[2][15], + io_base1[2][15], + int_num_irq[15], + irq[15], + dma_select0[15], + dma_select1[15], + dev_specific_config[3][15]; + + int siofc_lock; +} nsc366_t; + +#ifdef ENABLE_NSC366_LOG +int nsc366_do_log = ENABLE_NSC366_LOG; + + +void +nsc366_log(const char *fmt, ...) +{ + va_list ap; + + if (nsc366_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define nsc366_log(fmt, ...) +#endif + + +static void +nsc366_fdc(nsc366_t *dev) +{ + fdc_remove(dev->fdc); + int base = ((dev->io_base0[0][0] & 7) << 8) | (dev->io_base0[1][0] & 0xf8); + int irq = dev->int_num_irq[0] & 0x0f; + int dma_ch = dev->dma_select0[0] & 7; + + if (dev->ld_activate[0]) { + nsc366_log("NSC 366 FDC: Reconfigured with Base: 0x%04x IRQ: %d DMA Channel: %d\n", base, irq, dma_ch); + fdc_set_base(dev->fdc, base); + fdc_set_irq(dev->fdc, irq); + fdc_set_dma_ch(dev->fdc, dma_ch); + fdc_update_densel_polarity(dev->fdc, !!(dev->dev_specific_config[0][0] & 0x20)); + if (dev->dev_specific_config[0][0] & 8) + fdc_writeprotect(dev->fdc); + } +} + + +void +nsc366_lpt(nsc366_t *dev) +{ + lpt1_remove(); + int base = ((dev->io_base0[0][1] & 7) << 8) | (dev->io_base0[1][1] & 0xfc); + int irq = (dev->int_num_irq[1] & 0x0f); + + if (dev->ld_activate[1]) { + nsc366_log("NSC 366 LPT: Reconfigured with Base 0x%04x IRQ: %d\n", base ,irq); + lpt1_init(base); + lpt1_irq(irq); + } +} + + +static void +nsc366_uart(int uart, nsc366_t *dev) +{ + serial_remove(dev->uart[uart]); + int base = ((dev->io_base0[0][2 + uart] & 7) << 8) | (dev->io_base0[1][2 + uart] & 0xf8); + int irq = (dev->int_num_irq[2 + uart] & 0x0f); + + if (dev->ld_activate[2 + uart]) { + nsc366_log("NSC 366 UART Serial %d: Reconfigured with Base 0x%04x IRQ: %d\n", uart, base ,irq); + serial_setup(dev->uart[uart], base, irq); + } +} + + +static void +nsc366_fscm(nsc366_t *dev) +{ + uint16_t base = (dev->io_base0[0][9] << 8) | (dev->io_base0[1][9] & 0xf0); + + if (dev->ld_activate[9]) + nsc366_log("NSC 366 Fan Control: Reconfigured with Base 0x%04x\n", base); + + nsc366_update_fscm_io(dev->ld_activate[9], base, dev->hwm); +} + + +static void +nsc366_vlm(nsc366_t *dev) +{ + uint16_t base = (dev->io_base0[0][13] << 8) | (dev->io_base0[1][13] & 0xf0); + + if (dev->ld_activate[13]) + nsc366_log("NSC 366 Voltage Monitor: Reconfigured with Base 0x%04x\n", base); + + nsc366_update_vlm_io(dev->ld_activate[13], base, dev->hwm); +} + + +static void +nsc366_tms(nsc366_t *dev) +{ + uint16_t base = (dev->io_base0[0][14] << 8) | (dev->io_base0[1][14] & 0xf0); + + if (dev->ld_activate[14]) + nsc366_log("NSC 366 Temperature Monitor: Reconfigured with Base 0x%04x\n", base); + + nsc366_update_tms_io(dev->ld_activate[14], base, dev->hwm); +} + + +static void +nsc366_ldn_redirect(nsc366_t *dev) +{ + switch(dev->ldn) { + case 0: + nsc366_fdc(dev); + break; + + case 1: + nsc366_lpt(dev); + break; + + case 2 ... 3: + nsc366_uart(dev->ldn == 3, dev); + break; + + case 9: + nsc366_fscm(dev); + break; + + case 13: + nsc366_vlm(dev); + break; + + case 14: + nsc366_tms(dev); + break; + } +} + + +static void +nsc366_write(uint16_t addr, uint8_t val, void *priv) +{ + nsc366_t *dev = (nsc366_t *)priv; + + if (addr & 1) switch(dev->index) { + /* LDN */ + case 0x07: + if (val <= 0x0e) + dev->ldn = val; + break; + + /* Super I/O Configuration */ + case 0x21: + if (!dev->siofc_lock) { + if (val & 0x80) { + dev->sio_config[dev->index - 0x20] = val | 0x80; + dev->siofc_lock = 1; + } else + dev->sio_config[dev->index - 0x20] = val; + } + break; + + case 0x22: + if (!dev->siofc_lock) + dev->sio_config[dev->index - 0x20] = val; + break; + + case 0x23: + if (!dev->siofc_lock) + dev->sio_config[dev->index - 0x20] = val & 0xf7; + break; + + case 0x24: + if (!dev->siofc_lock) + dev->sio_config[dev->index - 0x20] = val; + break; + + case 0x25: + if (!dev->siofc_lock) + dev->sio_config[dev->index - 0x20] = val & 0xf3; + break; + + case 0x28: + dev->sio_config[dev->index - 0x20] = val & 0xf3; + break; + + case 0x2a: + if (!dev->siofc_lock) + dev->sio_config[dev->index - 0x20] = val; + break; + + case 0x2b: + if (!dev->siofc_lock) + /* Force Case Intrusion to always off */ + dev->sio_config[dev->index - 0x20] = val & 0x4f; + break; + + case 0x2c ... 0x2d: + dev->sio_config[dev->index - 0x20] = val & 0xf3; + break; + + /* Logical Devices */ + case 0x30: + dev->ld_activate[dev->ldn] = (val & 1) && (dev->sio_config[0] & 1); + nsc366_ldn_redirect(dev); + break; + + case 0x60 ... 0x61: + dev->io_base0[dev->index & 1][dev->ldn] = val; + nsc366_ldn_redirect(dev); + break; + + case 0x62 ... 0x63: + dev->io_base1[dev->index & 1][dev->ldn] = val; + nsc366_ldn_redirect(dev); + break; + + case 0x70: + dev->int_num_irq[dev->ldn] = val & 0x1f; + nsc366_ldn_redirect(dev); + break; + + case 0x71: + dev->irq[dev->ldn] = val; + nsc366_ldn_redirect(dev); + break; + + case 0x74: + dev->dma_select0[dev->ldn] = val & 0x1f; + nsc366_ldn_redirect(dev); + break; + + case 0x75: + dev->dma_select1[dev->ldn] = val & 0x1f; + nsc366_ldn_redirect(dev); + break; + + case 0xf0 ... 0xf2: + dev->dev_specific_config[dev->index - 0xf0][dev->ldn] = val; + nsc366_ldn_redirect(dev); + break; + } else + dev->index = val; +} + + +static uint8_t +nsc366_read(uint16_t addr, void *priv) +{ + nsc366_t *dev = (nsc366_t *)priv; + uint8_t ret = 0x00; + + if (addr & 1) { + switch (dev->index) { + case 0x07: + ret = dev->ldn; + break; + + case 0x20 ... 0x2d: + ret = dev->sio_config[dev->index - 0x20]; + break; + + case 0x30: + ret = dev->ld_activate[dev->ldn]; + break; + + case 0x60 ... 0x61: + ret = dev->io_base0[dev->index & 1][dev->ldn]; + break; + + case 0x62 ... 0x63: + ret = dev->io_base1[dev->index & 1][dev->ldn]; + break; + + case 0x70: + ret = dev->int_num_irq[dev->ldn]; + break; + + case 0x71: + ret = dev->irq[dev->ldn]; + break; + + case 0x74: + ret = dev->dma_select0[dev->ldn]; + break; + + case 0x75: + ret = dev->dma_select1[dev->ldn]; + break; + + case 0xf0 ... 0xf2: + ret = dev->dev_specific_config[dev->index - 0xf0][dev->ldn]; + break; + } + } else + ret = dev->index; + + return ret; +} + + +static void +nsc366_reset(void *priv) +{ + nsc366_t *dev = (nsc366_t *)priv; + + /* Basic Configuration */ + dev->ldn = 0; + dev->siofc_lock = 0; + memset(dev->sio_config, 0, sizeof(dev->sio_config)); + memset(dev->ld_activate, 0, sizeof(dev->ld_activate)); + memset(dev->io_base0, 0, sizeof(dev->io_base0)); + memset(dev->io_base1, 0, sizeof(dev->io_base1)); + memset(dev->int_num_irq, 0, sizeof(dev->int_num_irq)); + memset(dev->irq, 0, sizeof(dev->irq)); + memset(dev->dma_select0, 0, sizeof(dev->dma_select0)); + memset(dev->dma_select1, 0, sizeof(dev->dma_select1)); + memset(dev->dev_specific_config, 0, sizeof(dev->dev_specific_config)); + + /* SIO Config */ + dev->sio_config[0x00] = 0xe9; /* National Semiconductor NSC366 */ + dev->sio_config[0x07] = 0x01; + + /* FDC */ + fdc_reset(dev->fdc); + dev->io_base0[0][0] = 0x03; + dev->io_base0[1][0] = 0xf2; + dev->int_num_irq[0] = 0x06; + dev->irq[0] = 0x03; + dev->dma_select0[0] = 0x02; + dev->dma_select1[0] = 0x04; + dev->dev_specific_config[0][0] = 0x24; + + nsc366_fdc(dev); + + /* LPT */ + dev->io_base0[0][1] = 0x02; + dev->io_base0[1][1] = 0x78; + dev->int_num_irq[1] = 0x07; + dev->irq[1] = 0x02; + dev->dma_select0[1] = 0x04; + dev->dma_select1[1] = 0x04; + dev->dev_specific_config[0][1] = 0xf2; + + /* UART Serial 2 */ + dev->io_base0[0][2] = 0x02; + dev->io_base0[1][2] = 0xf8; + dev->int_num_irq[2] = 0x03; + dev->irq[2] = 0x03; + dev->dma_select0[2] = 0x04; + dev->dma_select1[2] = 0x04; + dev->dev_specific_config[0][2] = 0x02; + + nsc366_uart(1, dev); + + /* UART Serial 1 */ + dev->io_base0[0][3] = 0x03; + dev->io_base0[1][3] = 0xf8; + dev->int_num_irq[3] = 0x04; + dev->irq[3] = 0x03; + dev->dma_select0[3] = 0x04; + dev->dma_select1[3] = 0x04; + dev->dev_specific_config[0][3] = 0x02; + + /* SWC */ + dev->irq[4] = 0x03; + dev->dma_select0[4] = 0x04; + + /* Keyboard Controller */ + dev->int_num_irq[5] = 0x0c; + dev->irq[5] = 0x02; + + /* Mouse Controller */ + dev->io_base0[1][6] = 0x60; + dev->io_base1[1][6] = 0x64; + dev->int_num_irq[6] = 0x01; + dev->irq[6] = 0x02; + dev->dma_select0[6] = 0x04; + dev->dma_select1[6] = 0x04; + dev->dev_specific_config[0][6] = 0x40; + + /* GPIO */ + dev->irq[7] = 0x03; + dev->dma_select0[7] = 0x04; + dev->dma_select1[7] = 0x04; + + /* ACB */ + dev->irq[8] = 0x03; + dev->dma_select0[8] = 0x04; + dev->dma_select1[8] = 0x04; + + /* Fan Speed Monitor & Control */ + dev->irq[9] = 0x03; + dev->dma_select0[9] = 0x04; + dev->dma_select1[9] = 0x04; + nsc366_fscm(dev); + + /* Voltage Level Monitor */ + dev->irq[13] = 0x03; + dev->dma_select0[13] = 0x04; + dev->dma_select1[13] = 0x04; + nsc366_vlm(dev); + + /* Temperature Monitor */ + dev->irq[14] = 0x03; + dev->dma_select0[14] = 0x04; + dev->dma_select1[14] = 0x04; + nsc366_tms(dev); +} + + +static void +nsc366_close(void *priv) +{ + nsc366_t *dev = (nsc366_t *)priv; + + free(dev); +} + + +static void * +nsc366_init(const device_t *info) +{ + nsc366_t *dev = (nsc366_t *)malloc(sizeof(nsc366_t)); + memset(dev, 0, sizeof(nsc366_t)); + + io_sethandler(info->local, 2, nsc366_read, NULL, NULL, nsc366_write, NULL, NULL, dev); /* Ports 2E-2Fh(4E-4Fh if BADDR High): National Semiconductor NSC366 */ + + /* FDC */ + dev->fdc = device_add(&fdc_at_nsc_device); + + /* Hardware Monitor Setup */ + dev->hwm = device_add(&nsc366_hwm_device); + + /* Keyboard Controller */ + device_add(&keyboard_ps2_ami_pci_device); + + /* Port 92h */ + device_add(&port_92_pci_device); + + /* Serial */ + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + nsc366_reset(dev); + + return dev; +} + + +const device_t nsc366_device = { + .name = "National Semiconductor NSC366", + .internal_name = "nsc366", + .flags = 0, + .local = 0x2e, + .init = nsc366_init, + .close = nsc366_close, + .reset = nsc366_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t nsc366_4f_device = { + .name = "National Semiconductor NSC366 (With BADDR Pin High)", + .internal_name = "nsc366", + .flags = 0, + .local = 0x4e, + .init = nsc366_init, + .close = nsc366_close, + .reset = nsc366_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/sio/sio_w83627hf.c b/src/sio/sio_w83627hf.c new file mode 100644 index 000000000..48b846294 --- /dev/null +++ b/src/sio/sio_w83627hf.c @@ -0,0 +1,962 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Winbond W83627HF chipset. + * + * + * Authors: Tiseno100, + * Miran Grca, + * + * Copyright 2020,2021 Tiseno100. + * Copyright 2021,2021 Miran Grca. + */ + +/* + +Winbond W83627HF Register Summary for ISAPnP (potentially) + +Found on: https://github.com/koitsu/bsdhwmon/issues/6 + +Register dump: +idx 02 20 21 22 23 24 25 26 28 29 2a 2b 2c 2e 2f +val ff 52 41 ff fe c4 00 00 00 50 fc 00 ff 00 ff +def 00 52 NA ff 00 MM 00 00 00 00 7c c0 00 00 00 +LDN 0x00 (Floppy) +idx 30 60 61 70 74 f0 f1 f2 f4 f5 +val 00 00 00 06 02 0e 00 ff 00 00 +def 01 03 f0 06 02 0e 00 ff 00 00 +LDN 0x01 (Parallel port) +idx 30 60 61 70 74 f0 +val 00 00 00 07 03 3f +def 01 03 78 07 04 3f +LDN 0x02 (COM1) +idx 30 60 61 70 f0 +val 01 03 f8 04 00 +def 01 03 f8 04 00 +LDN 0x03 (COM2) +idx 30 60 61 70 f0 f1 +val 01 02 f8 03 00 40 +def 01 02 f8 03 00 00 +LDN 0x05 (Keyboard) +idx 30 60 61 62 63 70 72 f0 +val 01 00 60 00 64 01 00 80 +def 01 00 60 00 64 01 0c 80 +LDN 0x06 (Consumer IR) +idx 30 60 61 70 +val 00 00 00 00 +def 00 00 00 00 +LDN 0x07 (Game port, MIDI port, GPIO 1) +idx 30 60 61 62 63 70 f0 f1 f2 +val 01 00 00 00 00 00 ff ff 00 +def 00 02 01 03 30 09 ff 00 00 +LDN 0x08 (GPIO 2, watchdog timer) +idx 30 f0 f1 f2 f3 f5 f6 f6 f7 +val 00 ff ff ff 00 08 00 00 c0 +def 00 ff 00 00 00 00 00 00 00 +LDN 0x09 (GPIO 3) +idx 30 f0 f1 f2 f3 +val 01 ff 14 00 40 +def 00 ff 00 00 00 +LDN 0x0a (ACPI) +idx 30 70 e0 e1 e2 e3 e4 e5 e6 e7 f0 f1 f3 f4 f6 f7 f9 fe ff +val 01 00 00 00 f2 00 40 00 00 00 00 af 32 00 00 00 00 00 00 +def 00 00 00 00 NA NA 00 00 00 00 00 00 00 00 00 00 00 00 00 +LDN 0x0b (Hardware monitor) +idx 30 60 61 70 f0 +val 01 02 95 00 01 +def 00 00 00 00 00 +Hardware monitor (0x029a) + +*/ + +/* + +Notes : ISAPnP is missing and the Hardware Monitor I2C is not implemented. + +*/ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/device.h> + +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/i2c.h> +#include <86box/keyboard.h> +#include <86box/lpt.h> +#include <86box/port_92.h> +#include <86box/serial.h> + +#include <86box/hwm.h> +#include <86box/sio.h> + +#ifdef ENABLE_W83627HF_LOG +int w83627hf_do_log = ENABLE_W83627HF_LOG; + + +static void +w83627hf_log(const char *fmt, ...) +{ + va_list ap; + + if (w83627hf_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define w83627hf_log(fmt, ...) +#endif + + +typedef struct +{ + uint8_t hwm_index, hwm_regs[256]; + + uint8_t index, cfg_unlocked, + regs[48], dev_regs[12][256]; + + int has_hwm; + fdc_t *fdc_controller; + port_92_t *port_92; + serial_t *uart[2]; +} w83627hf_t; + +/* These differ per board and must be programmed manually */ +int fan1_rpm, fan2_rpm, fan3_rpm, vcorea_voltage, vcoreb_voltage; + +void +w83627hf_stabilizer(int vcoreb, int fan1, int fan2, int fan3) +{ + vcoreb_voltage = vcoreb; + fan1_rpm = fan1; + fan2_rpm = fan2; + fan3_rpm = fan3; +} + +static void +w83627hf_hwm_write(uint16_t addr, uint8_t val, void *priv) +{ + w83627hf_t *dev = (w83627hf_t *)priv; + + switch(addr) + { + case 0x295: + dev->hwm_index = val; + break; + + case 0x296: + w83627hf_log("W83627HF-HWM: dev->regs[%02x] = %02x\n", dev->hwm_index, val); + switch(dev->hwm_index) + { + case 0x2b ... 0x3f: + case 0x6b ... 0x7f: + dev->hwm_regs[dev->hwm_index & 0x1f] = val; + break; + + case 0x40: + dev->hwm_regs[dev->hwm_index] = val & 0x8b; + break; + + case 0x43: + dev->hwm_regs[dev->hwm_index] = val; + break; + + case 0x44: + dev->hwm_regs[dev->hwm_index] = val & 0x3f; + break; + + case 0x46: + dev->hwm_regs[dev->hwm_index] = val & 0x80; + if(val & 0x80) + dev->hwm_regs[dev->hwm_index] &= 0x10; + break; + + case 0x47: + dev->hwm_regs[dev->hwm_index] = val & 0x3f; + break; + + case 0x48: /* Serial Bus Address */ + dev->hwm_regs[dev->hwm_index] = val & 0x7f; + break; + + case 0x49: + dev->hwm_regs[dev->hwm_index] = val & 1; + break; + + case 0x4a: + dev->hwm_regs[dev->hwm_index] = val; + break; + + case 0x4b: + dev->hwm_regs[dev->hwm_index] = val & 0xfc; + break; + + case 0x4c: + dev->hwm_regs[dev->hwm_index] = val & 0x5c; + break; + + case 0x4d: + dev->hwm_regs[dev->hwm_index] = val & 0xbf; + break; + + case 0x4e: + dev->hwm_regs[dev->hwm_index] = val; + break; + + case 0x56: + dev->hwm_regs[dev->hwm_index] = val; + break; + + case 0x57: + dev->hwm_regs[dev->hwm_index] = val & 0xbf; + break; + + case 0x59: + dev->hwm_regs[dev->hwm_index] = val & 0x70; + break; + + case 0x5a ... 0x5b: + dev->hwm_regs[dev->hwm_index] = val; + break; + + case 0x5c: + dev->hwm_regs[dev->hwm_index] = val & 0x77; + break; + } + break; + } +} + +static uint8_t +w83627hf_hwm_read(uint16_t addr, void *priv) +{ + w83627hf_t *dev = (w83627hf_t *)priv; + + switch(addr) + { + case 0x295: + return dev->hwm_index; + + case 0x296: + switch(dev->hwm_index) + { + case 0x20 ... 0x3f: + case 0x60 ... 0x7f: + switch(dev->hwm_index & 0x1f) + { + case 0x00: /* VCOREA */ + return hwm_get_vcore() + 0x78; + + case 0x01: /* VCOREB */ + return vcoreb_voltage; + + case 0x02: /* +3.3V */ + return 0xd0; + + case 0x03: /* +5V */ + return 0xb9; + + case 0x04: /* +12V */ + return 0xc4; + + case 0x05: /* -12V */ + return 0x23; + + case 0x06: /* -5V */ + return 0x34; + + case 0x08: /* Fan 1 */ + return fan1_rpm; + + case 0x09: /* Fan 2 */ + return fan2_rpm; + + case 0x0a: /* Fan 3 */ + return fan3_rpm; + + case 0x0b ... 0x1f: + return dev->hwm_regs[dev->hwm_index & 0x1f]; + } + + case 0x4f: + if(dev->hwm_regs[0x4e] & 0x80) + return 0x5c; + else + return 0xa3; + + case 0x40 ... 0x4e: + case 0x50 ... 0x5c: + return dev->hwm_regs[dev->hwm_index]; + + default: + return 0xff; + } + + default: + return 0xff; + } +} + +static void +w83627hf_fdc_write(uint16_t cur_reg, uint8_t val, w83627hf_t *dev) +{ + + fdc_remove(dev->fdc_controller); + + switch(cur_reg) + { + case 0x30: + dev->dev_regs[0][cur_reg] = val & 1; + break; + + case 0x60 ... 0x61: + dev->dev_regs[0][cur_reg] = val; + break; + + case 0x70: + dev->dev_regs[0][cur_reg] = val & 0x0f; + break; + + case 0x74: + dev->dev_regs[0][cur_reg] = val & 7; + break; + + case 0xf0: + dev->dev_regs[0][cur_reg] = val; + break; + + case 0xf1: + dev->dev_regs[0][cur_reg] = val; + fdc_update_boot_drive(dev->fdc_controller, (val & 0xc0) >> 6); + + if(val & 2) + fdc_writeprotect(dev->fdc_controller); + + fdc_set_swwp(dev->fdc_controller, val & 1); + break; + + case 0xf2: + dev->dev_regs[0][cur_reg] = val; + break; + + case 0xf4: + case 0xf5: + dev->dev_regs[0][cur_reg] = val & 0x5b; + fdc_update_drvrate(dev->fdc_controller, cur_reg & 1, (val & 0x18) >> 3); + break; + } + + if(dev->dev_regs[0][0x30] & 1) + { + fdc_set_irq(dev->fdc_controller, dev->dev_regs[0][0x70]); + fdc_set_dma_ch(dev->fdc_controller, dev->dev_regs[0][0x74]); + fdc_set_base(dev->fdc_controller, (dev->dev_regs[0][0x60] << 8) | (dev->dev_regs[0][0x61])); + + w83627hf_log("W83627HF-FDC: BASE: %04x IRQ: %d DMA: %d\n", (dev->dev_regs[0][0x60] << 8) | (dev->dev_regs[0][0x61]), dev->dev_regs[0][0x70], dev->dev_regs[0][0x74]); + } +} + +static void +w83627hf_lpt_write(uint16_t cur_reg, uint8_t val, w83627hf_t *dev) +{ + lpt1_remove(); + + switch(cur_reg) + { + case 0x30: + dev->dev_regs[1][cur_reg] = val & 1; + break; + + case 0x60 ... 0x61: + dev->dev_regs[1][cur_reg] = val; + break; + + case 0x70: + dev->dev_regs[1][cur_reg] = val & 0x0f; + break; + + case 0xf0: + dev->dev_regs[1][cur_reg] = val & 0x7f; + break; + } + + if(dev->dev_regs[1][0x30] & 1) + { + lpt1_init((dev->dev_regs[1][0x60] << 8) | (dev->dev_regs[1][0x61])); + lpt1_irq(dev->dev_regs[1][0x70]); + w83627hf_log("W83627HF-LPT: BASE: %04x IRQ: %d\n", (dev->dev_regs[1][0x60] << 8) | (dev->dev_regs[1][0x61]), dev->dev_regs[1][0x70]); + } +} + +static void +w83627hf_uart_write(int uart, uint16_t cur_reg, uint8_t val, w83627hf_t *dev) +{ + double uart_clock = 24000000.0 / 13.0; + + serial_remove(dev->uart[uart]); + + switch(cur_reg) + { + case 0x30: + dev->dev_regs[2 + uart][cur_reg] = val & 1; + break; + + case 0x60 ... 0x61: + dev->dev_regs[2 + uart][cur_reg] = val; + break; + + case 0x70: + dev->dev_regs[2 + uart][cur_reg] = val & 0x0f; + break; + + case 0xf0: + dev->dev_regs[2 + uart][cur_reg] = val & 3; + switch(val & 3) + { + case 0: + uart_clock = 24000000.0 / 13.0; + break; + + case 1: + uart_clock = 24000000.0 / 12.0; + break; + + case 2: + uart_clock = 24000000.0 / 1.625; + break; + + case 3: + uart_clock = 24000000.0; + break; + } + break; + + case 0xf1: + if(uart) + dev->dev_regs[2 + uart][cur_reg] = val & 0x7f; + break; + } + + if(dev->dev_regs[2 + uart][0x30] & 1) + { + serial_setup(dev->uart[uart], (dev->dev_regs[2 + uart][0x60] << 8) | (dev->dev_regs[2 + uart][0x61]), dev->dev_regs[2 + uart][0x70]); + serial_set_clock_src(dev->uart[uart], uart_clock); + w83627hf_log("W83627HF-UART%s: BASE: %04x IRQ: %d\n", uart ? "B" : "A", (dev->dev_regs[2 + uart][0x60] << 8) | (dev->dev_regs[2 + uart][0x61]), dev->dev_regs[2 + uart][0x70]); + } +} + +static void +w83627hf_kbc_write(uint16_t cur_reg, uint8_t val, w83627hf_t *dev) +{ + switch(cur_reg) + { + case 0x30: + dev->dev_regs[5][cur_reg] = val & 1; + break; + + case 0x60 ... 0x61: /* See Notes on init */ + dev->dev_regs[5][cur_reg] = val; + break; + + case 0x62 ... 0x63: /* See Notes on init */ + dev->dev_regs[5][cur_reg] = val; + break; + + case 0x70: + dev->dev_regs[5][cur_reg] = val & 0x0f; + break; + + case 0x72: + dev->dev_regs[5][cur_reg] = val & 0x0f; + break; + + case 0xf0: + dev->dev_regs[5][cur_reg] = val & 0xc7; + break; + } + + if(dev->dev_regs[5][0x30] & 1) + { + /* We don't disable Port 92h as intended because the BIOSes never enable it back, causing issues. */ + port_92_set_features(dev->port_92, !!(dev->dev_regs[5][0xf0] & 1), !!(dev->dev_regs[5][0xf0] & 2)); + w83627hf_log("W83627HF-PORT92: FASTA20: %d FASTRESET: %d\n", !!(dev->dev_regs[5][0xf0] & 2), !!(dev->dev_regs[5][0xf0] & 1)); + } +} + +static void +w83627hf_cir_write(uint16_t cur_reg, uint8_t val, w83627hf_t *dev) +{ + /* Unimplemented Functionality */ + switch(cur_reg) + { + case 0x30: + dev->dev_regs[6][cur_reg] = val & 1; + break; + + case 0x60 ... 0x61: + dev->dev_regs[6][cur_reg] = val; + break; + + case 0x70: + dev->dev_regs[6][cur_reg] = val & 0x0f; + break; + } +} + +static void +w83627hf_gameport_midi_gpio1_write(uint16_t cur_reg, uint8_t val, w83627hf_t *dev) +{ + switch(cur_reg) + { + case 0x30: + dev->dev_regs[7][cur_reg] = val & 7; + break; + + case 0x60 ... 0x63: + dev->dev_regs[7][cur_reg] = val; + break; + + case 0x70: + dev->dev_regs[7][cur_reg] = val & 0x0f; + break; + + case 0xf0 ... 0xf2: + dev->dev_regs[7][cur_reg] = val; + break; + } +} + +static void +w83627hf_watchdog_timer_gpio2_write(uint16_t cur_reg, uint8_t val, w83627hf_t *dev) +{ + switch(cur_reg) + { + case 0x30: + dev->dev_regs[8][cur_reg] = val & 1; + break; + + case 0xf0 ... 0xf2: + dev->dev_regs[8][cur_reg] = val; + break; + + case 0xf5: + dev->dev_regs[8][cur_reg] = val & 0xcc; + break; + + case 0xf6 ... 0xf7: + dev->dev_regs[8][cur_reg] = val; + break; + } +} + +static void +w83627hf_gpio3_vsb_write(uint16_t cur_reg, uint8_t val, w83627hf_t *dev) +{ + switch(cur_reg) + { + case 0x30: + dev->dev_regs[9][cur_reg] = val & 1; + break; + + case 0xf0 ... 0xf2: + dev->dev_regs[9][cur_reg] = val; + break; + + case 0xf3: + dev->dev_regs[9][cur_reg] = val & 0xc0; + break; + } +} + +static void +w83627hf_acpi_write(uint16_t cur_reg, uint8_t val, w83627hf_t *dev) +{ + switch(cur_reg) + { + case 0x30: + dev->dev_regs[0x0a][cur_reg] = val & 1; + break; + + case 0x70: + dev->dev_regs[0x0a][cur_reg] = val & 0x0f; + break; + + case 0xe0: + dev->dev_regs[0x0a][cur_reg] = val & 0xc0; + break; + + case 0xe1 ... 0xe2: + dev->dev_regs[0x0a][cur_reg] = val; + break; + + case 0xe4: + dev->dev_regs[0x0a][cur_reg] = val & 0xfc; + break; + + case 0xe5 ... 0xe6: + dev->dev_regs[0x0a][cur_reg] = val & 0x7f; + + if(cur_reg == 0xe6) + if(val & 0x40) + dev->hwm_regs[0x42] &= 0x10; + break; + + case 0xe7: + dev->dev_regs[0x0a][cur_reg] = val & 0x0f; + break; + + case 0xf0: + dev->dev_regs[0x0a][cur_reg] = val; + break; + + case 0xf1: + dev->dev_regs[0x0a][cur_reg] = val & 0xef; + break; + + case 0xf3 ... 0xf4: + dev->dev_regs[0x0a][cur_reg] &= val & 0x3f; + break; + + case 0xf5: + case 0xf7: + dev->dev_regs[0x0a][cur_reg] = val & 0x3f; + break; + } +} + +static void +w83627hf_hwm_lpc_write(uint16_t cur_reg, uint8_t val, w83627hf_t *dev) +{ + switch(cur_reg) + { + case 0x30: + dev->dev_regs[0x0b][cur_reg] = val & 1; + break; + + case 0x70: + dev->dev_regs[0x0b][cur_reg] = val & 0x0f; + break; + + case 0xf0: + dev->dev_regs[0x0b][cur_reg] = val & 1; + break; + } +} + +static void +w83627hf_hwm_reset(w83627hf_t *dev) +{ + /* W83627HF Hardware Monitor */ + dev->hwm_regs[0x40] = 1; + dev->hwm_regs[0x47] = 0xa0; + dev->hwm_regs[0x48] = 0x2d; + dev->hwm_regs[0x49] = 1; + dev->hwm_regs[0x4a] = 1; + dev->hwm_regs[0x4b] = 0x44; + dev->hwm_regs[0x4d] = 0x15; + dev->hwm_regs[0x4e] = 0x80; + dev->hwm_regs[0x57] = 0x80; + dev->hwm_regs[0x58] = 0x21; + dev->hwm_regs[0x59] = 0x70; + dev->hwm_regs[0x5a] = 0xff; + dev->hwm_regs[0x5b] = 0xff; + dev->hwm_regs[0x5c] = 0x11; +} + +static void +w83627hf_reset(void *priv) +{ + w83627hf_t *dev = (w83627hf_t *)priv; + memset(dev->regs, 0, sizeof(dev->regs)); + dev->cfg_unlocked = 0; + + /* Proper W83627HF Registers */ + dev->regs[0x20] = 0x52; + dev->regs[0x21] = 0x17; + + /* FDC Registers */ + dev->dev_regs[0][0x30] = 1; + dev->dev_regs[0][0x60] = 3; + dev->dev_regs[0][0x61] = 0xf0; + dev->dev_regs[0][0x70] = 6; + dev->dev_regs[0][0x74] = 2; + dev->dev_regs[0][0xf0] = 0x0e; + dev->dev_regs[0][0xf2] = 0xff; + fdc_reset(dev->fdc_controller); + w83627hf_fdc_write(0, 0, dev); + + /* LPT Registers */ + dev->dev_regs[1][0x30] = 1; + dev->dev_regs[1][0x60] = 3; + dev->dev_regs[1][0x61] = 0x78; + dev->dev_regs[1][0x70] = 7; + dev->dev_regs[1][0x74] = 4; + dev->dev_regs[1][0xf0] = 0x3f; + w83627hf_lpt_write(0, 0, dev); + + /* UART A Registers */ + dev->dev_regs[2][0x30] = 1; + dev->dev_regs[2][0x60] = 3; + dev->dev_regs[2][0x61] = 0xf8; + dev->dev_regs[2][0x70] = 4; + w83627hf_uart_write(0, 0, 0, dev); + + /* UART B Registers */ + dev->dev_regs[3][0x30] = 1; + dev->dev_regs[3][0x60] = 2; + dev->dev_regs[3][0x61] = 0xf8; + dev->dev_regs[3][0x70] = 3; + w83627hf_uart_write(0, 0, 0, dev); + + /* Keyboard Controller */ + dev->dev_regs[5][0x30] = 1; + dev->dev_regs[5][0x61] = 0x60; + dev->dev_regs[5][0x63] = 0x64; + dev->dev_regs[5][0x70] = 1; + dev->dev_regs[5][0x72] = 0x0c; + dev->dev_regs[5][0xf0] = 0x80; + w83627hf_kbc_write(0, 0, dev); + + /* CIR */ + dev->dev_regs[6][0x30] = 1; + w83627hf_cir_write(0, 0, dev); + + /* Gameport, MIDI port and GPIO1 */ + dev->dev_regs[7][0x60] = 2; + dev->dev_regs[7][0x61] = 1; + dev->dev_regs[7][0x62] = 3; + dev->dev_regs[7][0x63] = 0x30; + dev->dev_regs[7][0x70] = 9; + dev->dev_regs[7][0xf0] = 0xff; + + /* GPIO3, VSB */ + dev->dev_regs[9][0xf0] = 0xff; + + /* W83627HF Hardware Monitor */ + if(dev->has_hwm) + w83627hf_hwm_reset(dev); +} + +static void +w83627hf_write(uint16_t addr, uint8_t val, void *priv) +{ + w83627hf_t *dev = (w83627hf_t *)priv; + + switch(addr & 0x0f) + { + case 0x0e: + if(!dev->cfg_unlocked) + { + dev->cfg_unlocked = (val == 0x87) && (dev->index == 0x87); + dev->index = val; + } + else dev->index = val; + break; + + case 0x0f: + if(dev->cfg_unlocked) + switch(dev->index) + { + case 0x02: /* LDN */ + if(val & 1) + w83627hf_reset(dev); + break; + + case 0x07: + dev->regs[dev->index] = val; + break; + + case 0x22: /* Manual Power Down */ + dev->regs[dev->index] = val & 0x7f; + break; + + case 0x23: /* Full Power Down */ + dev->regs[dev->index] = val & 1; + break; + + case 0x24: + dev->regs[dev->index] = val & 0xca; + break; + + case 0x25: + dev->regs[dev->index] = val & 0x39; + break; + + case 0x26: + dev->regs[dev->index] = val & 0xef; + break; + + case 0x28: + dev->regs[dev->index] = val & 7; + break; + + case 0x29: + dev->regs[dev->index] = val & 0xfc; + break; + + case 0x2a: + case 0x2b: + dev->regs[dev->index] = val; + break; + + case 0x30: /* Device Specific Registers */ + case 0x60 ... 0x63: + case 0x70: case 0x72:case 0x74: + case 0xe0 ... 0xe7: + case 0xf0 ... 0xf6: + switch(dev->regs[7]) + { + case 0: /* FDC */ + w83627hf_fdc_write(dev->index, val, dev); + break; + + case 1: /* LPT */ + w83627hf_lpt_write(dev->index, val, dev); + break; + + case 2: /* UART A */ + case 3: /* UART B */ + w83627hf_uart_write(dev->regs[7] & 1, dev->index, val, dev); + break; + + case 5: /* KBC */ + w83627hf_kbc_write(dev->index, val, dev); + break; + + case 6: /* CIR */ + w83627hf_cir_write(dev->index, val, dev); + break; + + case 7: /* GAMEPORT, MIDI & GPIO1 */ + w83627hf_gameport_midi_gpio1_write(dev->index, val, dev); + break; + + case 8: /* WATCHDOG TIMER & GPIO2 */ + w83627hf_watchdog_timer_gpio2_write(dev->index, val, dev); + break; + + case 9: /* GPIO3 & VSB */ + w83627hf_gpio3_vsb_write(dev->index, val, dev); + break; + + case 0x0a: /* ACPI */ + w83627hf_acpi_write(dev->index, val, dev); + break; + + case 0x0b: /* HWM LPC */ + w83627hf_hwm_lpc_write(dev->index, val, dev); + break; + + default: + w83627hf_log("W83627HF: Writings to unknown LDN: %02x\n", dev->regs[7]); + break; + } + break; + } + break; + } +} + + +static uint8_t +w83627hf_read(uint16_t addr, void *priv) +{ + w83627hf_t *dev = (w83627hf_t *)priv; + + if((dev->index >= 0x00) && (dev->index <= 0x2f)) + return dev->regs[dev->index]; + else if((dev->index >= 0x30) && (dev->index <= 0xff) && (dev->regs[7] >= 0) && (dev->regs[7] <= 0x0b)) + return dev->dev_regs[dev->regs[7]][dev->index]; + else + return 0xff; +} + + +static void +w83627hf_close(void *priv) +{ + w83627hf_t *dev = (w83627hf_t *)priv; + + free(dev); +} + + +static void * +w83627hf_init(const device_t *info) +{ + w83627hf_t *dev = (w83627hf_t *)malloc(sizeof(w83627hf_t)); + memset(dev, 0, sizeof(w83627hf_t)); + + /* Knock out the Hardware Monitor if needed(Mainly for ASUS TUSL2-C) */ + dev->has_hwm = info->local; + + /* I/O Ports */ + io_sethandler(0x002e, 2, w83627hf_read, NULL, NULL, w83627hf_write, NULL, NULL, dev); + io_sethandler(0x004e, 2, w83627hf_read, NULL, NULL, w83627hf_write, NULL, NULL, dev); + + if(dev->has_hwm) + io_sethandler(0x0295, 2, w83627hf_hwm_read, NULL, NULL, w83627hf_hwm_write, NULL, NULL, dev); + + /* Floppy Disk Controller */ + dev->fdc_controller = device_add(&fdc_at_smc_device); + + /* Hardware Monitor */ + fan1_rpm = fan2_rpm = fan3_rpm = vcorea_voltage = vcoreb_voltage = 0; + + /* Keyboard Controller (Based on AMIKEY-2) */ + /* Note: The base addresses and IRQ's of the Keyboard & PS/2 Mouse are remappable. Due to 86Box limitations we can't do that just yet */ + device_add(&keyboard_ps2_ami_pci_device); + + /* Port 92h */ + dev->port_92 = device_add(&port_92_device); + + /* UART */ + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + return dev; +} + +const device_t w83627hf_device = { + .name = "Winbond W83627HF", + .internal_name = "w83627hf", + .flags = 0, + .local = 1, + .init = w83627hf_init, + .close = w83627hf_close, + .reset = w83627hf_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t w83627hf_no_hwm_device = { + .name = "Winbond W83627HF with no Hardware Monitor", + .internal_name = "w83627hf_nohwm", + .flags = 0, + .local = 0, + .init = w83627hf_init, + .close = w83627hf_close, + .reset = w83627hf_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 50b2b820b..5d3b34d95 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -561,7 +561,8 @@ CHIPSETOBJ := 82c100.o acc2168.o \ wd76c10.o vl82c480.o \ umc_8886.o umc_hb4.o \ via_vt82c49x.o via_vt82c505.o via_apollo.o via_pipc.o \ - sis_85c310.o sis_85c4xx.o sis_85c496.o sis_85c50x.o sis_5511.o sis_5571.o + sis_85c310.o sis_85c4xx.o sis_85c496.o sis_85c50x.o sis_5511.o sis_5571.o \ + intel_ich2.o intel_815ep.o MCHOBJ := machine.o machine_table.o \ m_xt.o m_xt_compaq.o \ @@ -579,11 +580,11 @@ MCHOBJ := machine.o machine_table.o \ m_at_286_386sx.o m_at_386dx_486.o \ m_at_socket4.o m_at_socket5.o m_at_socket7_3v.o m_at_socket7.o m_at_sockets7.o \ m_at_socket8.o m_at_slot1.o m_at_slot2.o m_at_socket370.o \ - m_at_misc.o + m_at_misc.o m_at_ich2.o ifeq ($(NEW_KBC), y) -DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ - ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ +DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_nsc366.o hwm_vt82c686.o \ + ibm_5161.o intel_ich2_gpio.o intel_ich2_trap.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ clock_ics9xxx.o isapnp.o \ i2c.o i2c_gpio.o smbus_ali7101.o smbus_piix4.o \ keyboard.o \ @@ -591,10 +592,11 @@ DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hw mouse.o \ mouse_bus.o \ mouse_serial.o mouse_ps2.o \ - phoenix_486_jumper.o + phoenix_486_jumper.o \ + tco.o else -DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ - ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ +DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_nsc366.o hwm_vt82c686.o \ + ibm_5161.o intel_ich2_gpio.o intel_ich2_trap.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ clock_ics9xxx.o isapnp.o \ i2c.o i2c_gpio.o smbus_ali7101.o smbus_piix4.o \ keyboard.o \ @@ -602,7 +604,8 @@ DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hw mouse.o \ mouse_bus.o \ mouse_serial.o mouse_ps2.o \ - phoenix_486_jumper.o + phoenix_486_jumper.o \ + tco.o endif SIOOBJ := sio_acc3221.o sio_ali5123.o \ @@ -611,10 +614,11 @@ SIOOBJ := sio_acc3221.o sio_ali5123.o \ sio_it8661f.o \ sio_pc87306.o sio_pc87307.o sio_pc87309.o sio_pc87310.o sio_pc87311.o sio_pc87332.o \ sio_prime3b.o sio_prime3c.o \ - sio_w83787f.o \ + sio_w83627hf.o sio_w83787f.o \ sio_w83877f.o sio_w83977f.o \ sio_um8669f.o \ - sio_vt82c686.o + sio_vt82c686.o \ + sio_nsc366.o FDDOBJ := fdd.o fdc.o fdc_magitronic.o fdc_pii15xb.o \ fdi2raw.o \