From 2eba22295accee0fb8247c8e50d66fa1cdf4f464 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 8 Jul 2021 18:54:31 -0300 Subject: [PATCH] VIA southbridge fixes, including dynamic SMBus clock --- src/chipset/via_pipc.c | 162 ++++++++++++++++++++++++-------- src/device/smbus_piix4.c | 16 +++- src/include/86box/chipset.h | 3 +- src/include/86box/smbus_piix4.h | 3 + src/machine/m_at_slot1.c | 2 +- 5 files changed, 142 insertions(+), 44 deletions(-) diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index d488035ee..46d2f8597 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -16,7 +16,7 @@ * Copyright 2008-2020 Sarah Walker. * Copyright 2016-2020 Miran Grca. * Copyright 2020 Melissa Goad. - * Copyright 2020 RichardG. + * Copyright 2020-2021 RichardG. */ #include @@ -58,6 +58,7 @@ #define VIA_PIPC_596B 0x05962300 #define VIA_PIPC_686A 0x06861400 #define VIA_PIPC_686B 0x06864000 +#define VIA_PIPC_8231 0x82311000 typedef struct @@ -118,6 +119,7 @@ pipc_reset_hard(void *priv) memset(dev->power_regs, 0, 256); memset(dev->ac97_regs, 0, 512); + /* PCI-ISA bridge registers */ dev->pci_isa_regs[0x00] = 0x06; dev->pci_isa_regs[0x01] = 0x11; dev->pci_isa_regs[0x02] = dev->local >> 16; dev->pci_isa_regs[0x03] = dev->local >> 24; @@ -167,19 +169,23 @@ pipc_reset_hard(void *priv) if (dev->local <= VIA_PIPC_586B) dev->ide_regs[0x40] = 0x04; - dev->ide_regs[0x41] = (dev->local <= VIA_PIPC_686A) ? 0x06 : 0x02; + dev->ide_regs[0x41] = (dev->local == VIA_PIPC_686B) ? 0x06 : 0x02; dev->ide_regs[0x42] = 0x09; dev->ide_regs[0x43] = (dev->local >= VIA_PIPC_686A) ? 0x0a : 0x3a; dev->ide_regs[0x44] = 0x68; + if (dev->local == VIA_PIPC_686B) + dev->ide_regs[0x45] = 0x20; + else if (dev->local >= VIA_PIPC_8231) + dev->ide_regs[0x45] = 0x03; dev->ide_regs[0x46] = 0xc0; dev->ide_regs[0x48] = 0xa8; dev->ide_regs[0x49] = 0xa8; dev->ide_regs[0x4a] = 0xa8; dev->ide_regs[0x4b] = 0xa8; dev->ide_regs[0x4c] = 0xff; - dev->ide_regs[0x4e] = 0xff; - dev->ide_regs[0x4f] = 0xff; - dev->ide_regs[0x50] = dev->ide_regs[0x51] = dev->ide_regs[0x52] = dev->ide_regs[0x53] = (dev->local >= VIA_PIPC_686A) ? 0x07 : 0x03; + if (dev->local != VIA_PIPC_686B) + dev->ide_regs[0x4e] = dev->ide_regs[0x4f] = 0xff; + dev->ide_regs[0x50] = dev->ide_regs[0x51] = dev->ide_regs[0x52] = dev->ide_regs[0x53] = ((dev->local == VIA_PIPC_686A) || (dev->local == VIA_PIPC_686B)) ? 0x07 : 0x03; if (dev->local >= VIA_PIPC_596A) - dev->ide_regs[0x54] = 0x06; + dev->ide_regs[0x54] = ((dev->local == VIA_PIPC_686A) || (dev->local == VIA_PIPC_686B)) ? 0x04 : 0x06; dev->ide_regs[0x61] = 0x02; dev->ide_regs[0x69] = 0x02; @@ -189,6 +195,7 @@ pipc_reset_hard(void *priv) dev->ide_regs[0xc2] = 0x02; } + /* USB registers */ for (i = 0; i <= (dev->local >= VIA_PIPC_686A); i++) { dev->max_func++; dev->usb_regs[i][0x00] = 0x06; dev->usb_regs[i][0x01] = 0x11; @@ -213,6 +220,10 @@ pipc_reset_hard(void *priv) case VIA_PIPC_686B: dev->usb_regs[i][0x08] = 0x1a; break; + + case VIA_PIPC_8231: + dev->usb_regs[i][0x08] = 0x1e; + break; } dev->usb_regs[i][0x0a] = 0x03; @@ -220,6 +231,8 @@ pipc_reset_hard(void *priv) dev->usb_regs[i][0x0d] = 0x16; dev->usb_regs[i][0x20] = 0x01; dev->usb_regs[i][0x21] = 0x03; + if (dev->local == VIA_PIPC_686B) + dev->usb_regs[i][0x34] = 0x80; dev->usb_regs[i][0x3d] = 0x04; dev->usb_regs[i][0x60] = 0x10; @@ -230,21 +243,29 @@ pipc_reset_hard(void *priv) dev->usb_regs[i][0xc1] = 0x20; } + /* power management registers */ if (dev->acpi) { dev->max_func++; dev->power_regs[0x00] = 0x06; dev->power_regs[0x01] = 0x11; - if (dev->local <= VIA_PIPC_586B) - dev->power_regs[0x02] = 0x40; - else if (dev->local <= VIA_PIPC_596B) - dev->power_regs[0x02] = 0x50; - else - dev->power_regs[0x02] = 0x57; - dev->power_regs[0x03] = 0x30; + if (dev->local >= VIA_PIPC_8231) { + /* The VT8231 preliminary datasheet lists *two* inaccurate + device IDs (3068 and 3057). Real dumps have 8235. */ + dev->power_regs[0x02] = 0x35; dev->power_regs[0x03] = 0x82; + } else { + if (dev->local <= VIA_PIPC_586B) + dev->power_regs[0x02] = 0x40; + else if (dev->local <= VIA_PIPC_596B) + dev->power_regs[0x02] = 0x50; + else + dev->power_regs[0x02] = 0x57; + dev->power_regs[0x03] = 0x30; + } dev->power_regs[0x04] = 0x00; dev->power_regs[0x05] = 0x00; dev->power_regs[0x06] = (dev->local == VIA_PIPC_686B) ? 0x90 : 0x80; dev->power_regs[0x07] = 0x02; switch (dev->local) { case VIA_PIPC_586B: case VIA_PIPC_686A: + case VIA_PIPC_8231: dev->power_regs[0x08] = 0x10; break; @@ -260,11 +281,18 @@ pipc_reset_hard(void *priv) dev->power_regs[0x08] = 0x40; break; } + if (dev->local == VIA_PIPC_686B) + dev->power_regs[0x34] = 0x68; dev->power_regs[0x40] = 0x20; dev->power_regs[0x42] = 0xd0; dev->power_regs[0x48] = 0x01; + if (dev->local == VIA_PIPC_686B) { + dev->power_regs[0x68] = 0x01; + dev->power_regs[0x6a] = 0x02; + } + if (dev->local >= VIA_PIPC_686A) dev->power_regs[0x70] = 0x01; @@ -274,13 +302,26 @@ pipc_reset_hard(void *priv) dev->power_regs[0x90] = 0x01; } + /* AC97/MC97 registers */ if (dev->local >= VIA_PIPC_686A) { for (i = 0; i <= 1; i++) { dev->max_func++; dev->ac97_regs[i][0x00] = 0x06; dev->ac97_regs[i][0x01] = 0x11; dev->ac97_regs[i][0x02] = 0x58 + (0x10 * i); dev->ac97_regs[i][0x03] = 0x30; dev->ac97_regs[i][0x06] = 0x10 * (1 - i); dev->ac97_regs[i][0x07] = 0x02; - dev->ac97_regs[i][0x08] = (dev->local == VIA_PIPC_686A) ? 0x12 : 0x50; + switch (dev->local) { + case VIA_PIPC_686A: + dev->ac97_regs[i][0x08] = (i == 0) ? 0x12 : 0x01; + break; + + case VIA_PIPC_686B: + dev->ac97_regs[i][0x08] = (i == 0) ? 0x50 : 0x30; + break; + + case VIA_PIPC_8231: + dev->ac97_regs[i][0x08] = (i == 0) ? 0x40 : 0x20; + break; + } if (i == 0) { dev->ac97_regs[i][0x0a] = 0x01; @@ -291,7 +332,12 @@ pipc_reset_hard(void *priv) } dev->ac97_regs[i][0x10] = 0x01; - dev->ac97_regs[i][0x14] = 0x01; + dev->ac97_regs[i][(dev->local >= VIA_PIPC_8231) ? 0x1c : 0x14] = 0x01; + + if ((i == 0) && (dev->local >= VIA_PIPC_8231)) { + dev->ac97_regs[i][0x18] = 0x31; + dev->ac97_regs[i][0x19] = 0x03; + } dev->ac97_regs[i][0x3d] = 0x03; @@ -413,7 +459,7 @@ pipc_read(int func, int addr, void *priv) if (ret & 0x80) /* bit 7 set = use bit 6 */ c = ret & 0x40; else if (ide_drives[c]) /* bit 7 clear = use SET FEATURES mode */ - c = (ide_drives[c]->mdma_mode & 0xf00) == 0x300; + c = (ide_drives[c]->mdma_mode & 0x300) == 0x300; else /* no drive here */ c = 0; /* 586A/B datasheet claims bit 5 must be clear for UDMA, unlike later models where @@ -433,6 +479,12 @@ pipc_read(int func, int addr, void *priv) ret |= 0x10; else ret &= ~0x10; + } else if ((addr == 0xd2) && (dev->local == VIA_PIPC_686B)) { + /* SMBus clock select bit. */ + if (dev->smbus->clock == 16384) + ret &= ~0x10; + else + ret |= 0x10; } } else if ((func <= (pm_func + 2)) && !(dev->pci_isa_regs[0x85] & ((func == (pm_func + 1)) ? 0x04 : 0x08))) /* AC97 / MC97 */ @@ -512,9 +564,7 @@ pipc_write(int func, int addr, uint8_t val, void *priv) cpu_set_isa_pci_div(2); break; - case 0xa: - cpu_set_isa_pci_div(4); - break; + /* case 0xa: same as default */ case 0xb: cpu_set_isa_pci_div(6); @@ -532,7 +582,7 @@ pipc_write(int func, int addr, uint8_t val, void *priv) cpu_set_isa_pci_div(12); break; - /* Half PIT clock. */ + /* Half oscillator clock. */ case 0xf: cpu_set_isa_speed(7159091); break; @@ -735,6 +785,8 @@ pipc_write(int func, int addr, uint8_t val, void *priv) case 0x41: if (dev->local <= VIA_PIPC_686A) dev->ide_regs[0x41] = val; + else if (dev->local == VIA_PIPC_8231) + dev->ide_regs[0x41] = val & 0xf6; else dev->ide_regs[0x41] = val & 0xf2; break; @@ -755,7 +807,7 @@ pipc_write(int func, int addr, uint8_t val, void *priv) dev->ide_regs[0x44] = val & 0x7b; else if (dev->local <= VIA_PIPC_596B) dev->ide_regs[0x44] = val & 0x7f; - else if (dev->local <= VIA_PIPC_686A) + else if ((dev->local <= VIA_PIPC_686A) || (dev->local == VIA_PIPC_8231)) dev->ide_regs[0x44] = val & 0x69; else dev->ide_regs[0x44] = val & 0x7d; @@ -764,7 +816,7 @@ pipc_write(int func, int addr, uint8_t val, void *priv) case 0x45: if (dev->local <= VIA_PIPC_586B) dev->ide_regs[0x45] = val & 0x40; - else if (dev->local <= VIA_PIPC_596B) + else if ((dev->local <= VIA_PIPC_596B) || (dev->local == VIA_PIPC_8231)) dev->ide_regs[0x45] = val & 0x4f; else if (dev->local <= VIA_PIPC_686A) dev->ide_regs[0x45] = val & 0x5f; @@ -773,7 +825,7 @@ pipc_write(int func, int addr, uint8_t val, void *priv) break; case 0x46: - if (dev->local <= VIA_PIPC_686A) + if ((dev->local <= VIA_PIPC_686A) || (dev->local == VIA_PIPC_8231)) dev->ide_regs[0x46] = val & 0xf3; else dev->ide_regs[0x46] = val & 0xc0; @@ -784,7 +836,7 @@ pipc_write(int func, int addr, uint8_t val, void *priv) dev->ide_regs[addr] = val & 0xc3; else if (dev->local <= VIA_PIPC_596B) dev->ide_regs[addr] = val & ((addr & 1) ? 0xc3 : 0xcb); - else if (dev->local <= VIA_PIPC_686A) + else if ((dev->local <= VIA_PIPC_686A) || (dev->local == VIA_PIPC_8231)) dev->ide_regs[addr] = val & ((addr & 1) ? 0xc7 : 0xcf); else dev->ide_regs[addr] = val & 0xd7; @@ -803,13 +855,16 @@ pipc_write(int func, int addr, uint8_t val, void *priv) if ((addr < 4) || (addr == 5) || (addr == 6) || ((addr >= 8) && (addr < 0xd)) || ((addr >= 0xe) && (addr < 0x20)) || ((addr >= 0x22) && (addr < 0x3c)) || ((addr >= 0x3e) && (addr < 0x40)) || ((addr >= 0x42) && (addr < 0x44)) || - ((addr >= 0x46) && (addr < 0xc0)) || (addr >= 0xc2)) + ((addr >= 0x46) && (addr < 0x84)) || ((addr >= 0x85) && (addr < 0xc0)) || (addr >= 0xc2)) return; /* Check disable bits for both controllers */ if ((func == 2) ? (dev->pci_isa_regs[0x48] & 0x04) : (dev->pci_isa_regs[0x85] & 0x10)) return; + if ((dev->local <= VIA_PIPC_596B) && (addr == 0x84)) + return; + switch (addr) { case 0x04: dev->usb_regs[func - 2][0x04] = val & 0x97; @@ -872,6 +927,13 @@ pipc_write(int func, int addr, uint8_t val, void *priv) acpi_set_irq_line(dev->acpi, dev->power_regs[addr]); break; + case 0x54: + if (dev->local <= VIA_PIPC_596B) + dev->power_regs[addr] = val; /* write-only on 686A+ */ + else + smbus_piix4_setclock(dev->smbus, (val & 0x80) ? 65536 : 16384); /* final clock undocumented on 686A, assume RTC*2 like 686B */ + break; + case 0x61: case 0x62: case 0x63: dev->power_regs[(addr - 0x58)] = val; break; @@ -883,12 +945,17 @@ pipc_write(int func, int addr, uint8_t val, void *priv) vt82c686_hwm_write(addr, val, subdev); break; - case 0x80: case 0x81: case 0x84: /* 596(A) has the SMBus I/O base here instead. Enable bit is assumed. */ + case 0x80: case 0x81: case 0x84: /* 596A has the SMBus I/O base and enable bit here instead. */ dev->power_regs[addr] = val; smbus_piix4_remap(dev->smbus, (dev->power_regs[0x81] << 8) | (dev->power_regs[0x80] & 0xf0), dev->power_regs[0x84] & 0x01); break; - case 0x90: case 0x91: case 0xd2: + case 0xd2: + if (dev->local == VIA_PIPC_686B) + smbus_piix4_setclock(dev->smbus, (val & 0x04) ? 65536 : 16384); + /* fall-through */ + + case 0x90: case 0x91: dev->power_regs[addr] = val; smbus_piix4_remap(dev->smbus, (dev->power_regs[0x91] << 8) | (dev->power_regs[0x90] & 0xf0), dev->power_regs[0xd2] & 0x01); break; @@ -974,7 +1041,7 @@ pipc_init(const device_t *info) dev->nvr = device_add(&via_nvr_device); - if (dev->local >= VIA_PIPC_686B) + if (dev->local == VIA_PIPC_686B) dev->smbus = device_add(&via_smbus_device); else if (dev->local >= VIA_PIPC_596A) dev->smbus = device_add(&piix4_smbus_device); @@ -1030,8 +1097,8 @@ const device_t via_vt82c586b_device = "VIA VT82C586B", DEVICE_PCI, VIA_PIPC_586B, - pipc_init, - pipc_close, + pipc_init, + pipc_close, pipc_reset, { NULL }, NULL, @@ -1039,13 +1106,13 @@ const device_t via_vt82c586b_device = NULL }; -const device_t via_vt82c596_device = +const device_t via_vt82c596a_device = { - "VIA VT82C596(A)", + "VIA VT82C596A", DEVICE_PCI, VIA_PIPC_596A, - pipc_init, - pipc_close, + pipc_init, + pipc_close, pipc_reset, { NULL }, NULL, @@ -1059,8 +1126,8 @@ const device_t via_vt82c596b_device = "VIA VT82C596B", DEVICE_PCI, VIA_PIPC_596B, - pipc_init, - pipc_close, + pipc_init, + pipc_close, pipc_reset, { NULL }, NULL, @@ -1074,8 +1141,8 @@ const device_t via_vt82c686a_device = "VIA VT82C686A", DEVICE_PCI, VIA_PIPC_686A, - pipc_init, - pipc_close, + pipc_init, + pipc_close, pipc_reset, { NULL }, NULL, @@ -1089,8 +1156,23 @@ const device_t via_vt82c686b_device = "VIA VT82C686B", DEVICE_PCI, VIA_PIPC_686B, - pipc_init, - pipc_close, + pipc_init, + pipc_close, + pipc_reset, + { NULL }, + NULL, + NULL, + NULL +}; + + +const device_t via_vt8231_device = +{ + "VIA VT8231", + DEVICE_PCI, + VIA_PIPC_8231, + pipc_init, + pipc_close, pipc_reset, { NULL }, NULL, diff --git a/src/device/smbus_piix4.c b/src/device/smbus_piix4.c index f3b14eda0..91ee5566e 100644 --- a/src/device/smbus_piix4.c +++ b/src/device/smbus_piix4.c @@ -313,8 +313,8 @@ unknown_protocol: if (dev->next_stat) { /* schedule dispatch of any pending status register update */ dev->stat = 0x01; /* raise HOST_BUSY while waiting */ timer_disable(&dev->response_timer); - /* delay = ((half clock for start + half clock for stop) + (bytes * (8 bits + ack))) * 60us period measured on real VIA 686B */ - timer_set_delay_u64(&dev->response_timer, (1 + (timer_bytes * 9)) * 60 * TIMER_USEC); + /* delay = ((half clock for start + half clock for stop) + (bytes * (8 bits + ack))) * bit period in usecs */ + timer_set_delay_u64(&dev->response_timer, (1 + (timer_bytes * 9)) * dev->bit_period * TIMER_USEC); } } @@ -343,6 +343,16 @@ smbus_piix4_remap(smbus_piix4_t *dev, uint16_t new_io_base, uint8_t enable) } +void +smbus_piix4_setclock(smbus_piix4_t *dev, int clock) +{ + dev->clock = clock; + + /* Set the bit period in usecs. */ + dev->bit_period = 1000000.0 / dev->clock; +} + + static void * smbus_piix4_init(const device_t *info) { @@ -356,6 +366,8 @@ smbus_piix4_init(const device_t *info) timer_add(&dev->response_timer, smbus_piix4_response, dev, 0); + smbus_piix4_setclock(dev, 16384); /* default to 16.384 KHz */ + return dev; } diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index 2cc8078b1..6e9b04d24 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -144,10 +144,11 @@ extern const device_t via_apro133_device; extern const device_t via_apro133a_device; extern const device_t via_vt8601_device; extern const device_t via_vt82c586b_device; -extern const device_t via_vt82c596_device; +extern const device_t via_vt82c596a_device; extern const device_t via_vt82c596b_device; extern const device_t via_vt82c686a_device; extern const device_t via_vt82c686b_device; +extern const device_t via_vt8231_device; /* VLSI */ extern const device_t vl82c480_device; diff --git a/src/include/86box/smbus_piix4.h b/src/include/86box/smbus_piix4.h index 3173ead4e..cf55dd210 100644 --- a/src/include/86box/smbus_piix4.h +++ b/src/include/86box/smbus_piix4.h @@ -30,6 +30,8 @@ enum { typedef struct { uint32_t local; uint16_t io_base; + int clock; + double bit_period; uint8_t stat, next_stat, ctl, cmd, addr, data0, data1, index, data[SMBUS_PIIX4_BLOCK_DATA_SIZE]; @@ -39,6 +41,7 @@ typedef struct { 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); #ifdef EMU_DEVICE_H diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index 1ab48f7b4..a14d75cd7 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -540,7 +540,7 @@ machine_at_ficka6130_init(const machine_t *model) pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); device_add(&via_apro_device); - device_add(&via_vt82c596_device); + device_add(&via_vt82c596a_device); device_add(&w83877tf_device); device_add(&keyboard_ps2_ami_pci_device); device_add(&sst_flash_29ee020_device);