diff --git a/src/device/hwm_gl518sm.c b/src/device/hwm_gl518sm.c index aca9f95a4..4bfc6c455 100644 --- a/src/device/hwm_gl518sm.c +++ b/src/device/hwm_gl518sm.c @@ -122,19 +122,45 @@ gl518sm_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv) static uint16_t gl518sm_read(gl518sm_t *dev, uint8_t reg) { - uint16_t ret = dev->regs[reg & 0x1f]; + uint16_t ret; + + reg &= 0x1f; switch (reg) { - case 0x07: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: - /* two-byte registers: leave as-is */ + case 0x04: /* temperature */ + ret = (dev->values->temperatures[0] + 119) & 0xff; break; - default: - /* single-byte registers: duplicate low byte to high byte (real hardware behavior unknown) */ - ret |= (ret << 8); + case 0x07: /* fan speeds */ + ret = GL518SM_RPM_TO_REG(dev->values->fans[0], 1 << ((dev->regs[0x0f] >> 6) & 0x3)) << 8; + ret |= GL518SM_RPM_TO_REG(dev->values->fans[1], 1 << ((dev->regs[0x0f] >> 4) & 0x3)); + break; + + case 0x0d: /* VIN3 - AOpen System Monitor requires an approximate voltage offset of 13 at least here */ + ret = 13 + GL518SM_VOLTAGE_TO_REG(dev->values->voltages[2]); + break; + + case 0x13: /* VIN2 */ + ret = 13 + GL518SM_VOLTAGE_TO_REG(dev->values->voltages[1]); + break; + + case 0x14: /* VIN1 */ + ret = 13 + GL518SM_VOLTAGE_TO_REG(dev->values->voltages[0]); + break; + + case 0x15: /* VDD */ + ret = 13 + GL518SM_VDD_TO_REG(dev->values->voltages[3]); + break; + + default: /* other registers */ + ret = dev->regs[reg]; break; } + /* Duplicate the low byte to the high byte on single-byte registers, although real hardware behavior is undefined. */ + if ((reg < 0x07) || (reg > 0x0c)) + ret |= ret << 8; + gl518sm_log("GL518SM: read(%02X) = %04X\n", reg, ret); return ret; @@ -176,26 +202,22 @@ gl518sm_write(gl518sm_t *dev, uint8_t reg, uint16_t val) return 0; case 0x0a: - dev->regs[0x13] = (val & 0xff); + dev->regs[0x13] = val & 0xff; break; case 0x03: - dev->regs[reg] = (val & 0xfc); + dev->regs[reg] = val & 0xfc; if (val & 0x80) /* Init */ gl518sm_reset(dev); break; case 0x0f: - dev->regs[reg] = (val & 0xf8); - - /* update fan values to match the new divisor */ - dev->regs[0x07] = (GL518SM_RPM_TO_REG(dev->values->fans[0], 1 << ((dev->regs[0x0f] >> 6) & 0x3)) << 8); - dev->regs[0x07] |= GL518SM_RPM_TO_REG(dev->values->fans[1], 1 << ((dev->regs[0x0f] >> 4) & 0x3)); + dev->regs[reg] = val & 0xf8; break; case 0x11: - dev->regs[reg] = (val & 0x7f); + dev->regs[reg] = val & 0x7f; break; default: @@ -214,21 +236,14 @@ gl518sm_reset(gl518sm_t *dev) dev->regs[0x00] = 0x80; dev->regs[0x01] = 0x80; /* revision 0x80 can read all voltages */ - dev->regs[0x04] = ((dev->values->temperatures[0] + 119) & 0xff); dev->regs[0x05] = 0xc7; dev->regs[0x06] = 0xc2; - dev->regs[0x07] = ((GL518SM_RPM_TO_REG(dev->values->fans[0], 8) << 8) | GL518SM_RPM_TO_REG(dev->values->fans[1], 8)); dev->regs[0x08] = 0x6464; dev->regs[0x09] = 0xdac5; dev->regs[0x0a] = 0xdac5; dev->regs[0x0b] = 0xdac5; dev->regs[0x0c] = 0xdac5; - /* AOpen System Monitor requires an approximate voltage offset of 13 at least on 3.3V (voltages[2]) */ - dev->regs[0x0d] = 13 + GL518SM_VOLTAGE_TO_REG(dev->values->voltages[2]); dev->regs[0x0f] = 0xf8; - dev->regs[0x13] = 13 + GL518SM_VOLTAGE_TO_REG(dev->values->voltages[1]); - dev->regs[0x14] = 13 + GL518SM_VOLTAGE_TO_REG(dev->values->voltages[0]); - dev->regs[0x15] = 13 + GL518SM_VDD_TO_REG(5000); } @@ -254,14 +269,15 @@ gl518sm_init(const device_t *info) /* Set default values. */ hwm_values_t defaults = { { /* fan speeds */ - 3000, /* System */ - 3000 /* CPU */ + 3000, /* usually Chassis */ + 3000 /* usually CPU */ }, { /* temperatures */ - 30 /* CPU */ + 30 /* usually CPU */ }, { /* voltages */ hwm_get_vcore(), /* Vcore */ - RESISTOR_DIVIDER(12000, 150, 47), /* +12V (15K/4.7K divider suggested in the GL518SM datasheet) */ - 3300 /* +3.3V */ + RESISTOR_DIVIDER(12000, 150, 47), /* +12V (15K/4.7K divider suggested in the datasheet) */ + 3300, /* +3.3V */ + 5000 /* +5V */ } }; hwm_values = defaults; diff --git a/src/device/hwm_lm78.c b/src/device/hwm_lm78.c index 28d97909c..8b95bbade 100644 --- a/src/device/hwm_lm78.c +++ b/src/device/hwm_lm78.c @@ -37,10 +37,13 @@ #define LM78_AS99127F (LM78_AS99127F_REV1 | LM78_AS99127F_REV2) /* special mask covering both _REV1 and _REV2 */ #define LM78_WINBOND (LM78_W83781D | LM78_AS99127F | LM78_W83782D) /* special mask covering all Winbond variants */ #define LM78_WINBOND_VENDOR_ID ((dev->local & LM78_AS99127F_REV1) ? 0x12c3 : 0x5ca3) +#define LM78_WINBOND_BANK (dev->regs[0x4e] & 0x07) #define CLAMP(a, min, max) (((a) < (min)) ? (min) : (((a) > (max)) ? (max) : (a))) #define LM78_RPM_TO_REG(r, d) ((r) ? CLAMP(1350000 / (r * d), 1, 255) : 0) #define LM78_VOLTAGE_TO_REG(v) ((v) >> 4) +#define LM78_NEG_VOLTAGE(v, r) (v * (604.0 / ((double) r))) /* negative voltage formula from the W83781D datasheet */ +#define LM78_NEG_VOLTAGE2(v, r) (((3600 + v) * (((double) r) / (((double) r) + 56.0))) - v) /* negative voltage formula from the W83782D datasheet */ typedef struct { @@ -54,8 +57,6 @@ typedef struct { uint8_t data_register; uint8_t smbus_addr; - uint8_t hbacs; - uint8_t active_bank; } lm78_t; @@ -135,17 +136,19 @@ lm78_isa_read(uint16_t port, void *priv) case 0x5: ret = (dev->addr_register & 0x7f); break; - case 0x6: - ret = lm78_read(dev, dev->addr_register, dev->active_bank); - if (((dev->active_bank == 0) && + case 0x6: + ret = lm78_read(dev, dev->addr_register, LM78_WINBOND_BANK); + + if (((LM78_WINBOND_BANK == 0) && ((dev->addr_register == 0x41) || (dev->addr_register == 0x43) || (dev->addr_register == 0x45) || (dev->addr_register == 0x56) || ((dev->addr_register >= 0x60) && (dev->addr_register < 0x7f)))) || - ((dev->local & LM78_W83782D) && (dev->active_bank == 5) && (dev->addr_register >= 0x50) && (dev->addr_register < 0x58))) { + ((dev->local & LM78_W83782D) && (LM78_WINBOND_BANK == 5) && (dev->addr_register >= 0x50) && (dev->addr_register < 0x58))) { /* auto-increment registers */ dev->addr_register++; } break; + default: lm78_log("LM78: Read from unknown ISA port %d\n", port & 0x7); break; @@ -159,7 +162,7 @@ static uint8_t lm78_smbus_read_byte(uint8_t addr, void *priv) { lm78_t *dev = (lm78_t *) priv; - return lm78_read(dev, dev->addr_register, dev->active_bank); + return lm78_read(dev, dev->addr_register, LM78_WINBOND_BANK); } @@ -167,7 +170,7 @@ static uint8_t lm78_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv) { lm78_t *dev = (lm78_t *) priv; - return lm78_read(dev, cmd, dev->active_bank); + return lm78_read(dev, cmd, LM78_WINBOND_BANK); } @@ -175,22 +178,22 @@ static uint16_t lm78_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv) { lm78_t *dev = (lm78_t *) priv; - return (lm78_read(dev, cmd, dev->active_bank) << 8) | lm78_read(dev, cmd, dev->active_bank); + return (lm78_read(dev, cmd, LM78_WINBOND_BANK) << 8) | lm78_read(dev, cmd, LM78_WINBOND_BANK); } static uint8_t lm78_read(lm78_t *dev, uint8_t reg, uint8_t bank) { - uint8_t ret = 0, masked_reg = reg; + uint8_t ret = 0, masked_reg = reg, bankswitched = ((reg & 0xf8) == 0x50); lm75_t *lm75; - if (((reg & 0xf8) == 0x50) && ((bank == 1) || (bank == 2))) { + if (bankswitched && ((bank == 1) || (bank == 2))) { /* LM75 registers */ lm75 = device_get_priv(dev->lm75[bank - 1]); if (lm75) ret = lm75_read(lm75, reg); - } else if (((reg & 0xf8) == 0x50) && ((bank == 4) || (bank == 5) || (bank == 6))) { + } else if (bankswitched && ((bank == 4) || (bank == 5) || (bank == 6))) { /* W83782D additional registers */ if (dev->local & LM78_W83782D) { if ((bank == 5) && ((reg == 0x50) || (reg == 0x51))) /* voltages */ @@ -210,7 +213,7 @@ lm78_read(lm78_t *dev, uint8_t reg, uint8_t bank) else if ((masked_reg >= 0x28) && (masked_reg <= 0x2a)) /* fan speeds */ ret = LM78_RPM_TO_REG(dev->values->fans[reg & 3], 1 << ((dev->regs[((reg & 3) == 2) ? 0x4b : 0x47] >> ((reg & 3) ? 6 : 4)) & 0x3)); else if ((reg == 0x4f) && (dev->local & LM78_WINBOND)) /* two-byte vendor ID register */ - ret = (dev->hbacs ? (LM78_WINBOND_VENDOR_ID >> 8) : LM78_WINBOND_VENDOR_ID); + ret = ((dev->regs[0x4e] & 0x80) ? (LM78_WINBOND_VENDOR_ID >> 8) : LM78_WINBOND_VENDOR_ID); else if ((reg >= 0x60) && (reg <= 0x7f)) /* read auto-increment value RAM registers from their non-auto-increment locations */ ret = dev->regs[reg & 0x3f]; else if (dev->local & LM78_AS99127F) { /* AS99127F mirrored registers */ @@ -244,12 +247,12 @@ lm78_isa_write(uint16_t port, uint8_t val, void *priv) dev->addr_register = (val & 0x7f); break; case 0x6: - lm78_write(dev, dev->addr_register, val, dev->active_bank); + lm78_write(dev, dev->addr_register, val, LM78_WINBOND_BANK); - if (((dev->active_bank == 0) && + if (((LM78_WINBOND_BANK == 0) && ((dev->addr_register == 0x41) || (dev->addr_register == 0x43) || (dev->addr_register == 0x45) || (dev->addr_register == 0x56) || ((dev->addr_register >= 0x60) && (dev->addr_register < 0x7f)))) || - ((dev->local & LM78_W83782D) && (dev->active_bank == 5) && (dev->addr_register >= 0x50) && (dev->addr_register < 0x58))) { + ((dev->local & LM78_W83782D) && (LM78_WINBOND_BANK == 5) && (dev->addr_register >= 0x50) && (dev->addr_register < 0x58))) { /* auto-increment registers */ dev->addr_register++; } @@ -273,7 +276,7 @@ static void lm78_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv) { lm78_t *dev = (lm78_t *) priv; - lm78_write(dev, cmd, val, dev->active_bank); + lm78_write(dev, cmd, val, LM78_WINBOND_BANK); } @@ -281,7 +284,7 @@ static void lm78_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv) { lm78_t *dev = (lm78_t *) priv; - lm78_write(dev, cmd, val, dev->active_bank); + lm78_write(dev, cmd, val, LM78_WINBOND_BANK); } @@ -387,12 +390,6 @@ lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank) } break; - case 0x4e: - dev->hbacs = (dev->regs[0x4e] & 0x80); - /* BANKSEL[0:2] is a bitfield according to the datasheet, but not in reality */ - dev->active_bank = (dev->regs[0x4e] & 0x07); - break; - case 0x87: /* AS99127F boards perform a soft reset through this register */ if ((dev->local & LM78_AS99127F) && (val == 0x01)) { @@ -432,7 +429,6 @@ lm78_reset(lm78_t *dev, uint8_t initialization) dev->regs[0x4c] = 0x01; dev->regs[0x4d] = 0x15; dev->regs[0x4e] = 0x80; - dev->hbacs = (dev->regs[0x4e] & 0x80); dev->regs[0x4f] = (LM78_WINBOND_VENDOR_ID >> 8); dev->regs[0x57] = 0x80; @@ -482,7 +478,7 @@ lm78_close(void *priv) { lm78_t *dev = (lm78_t *) priv; - uint16_t isa_io = (dev->local & 0xffff); + uint16_t isa_io = dev->local & 0xffff; if (isa_io) io_removehandler(isa_io, 8, lm78_isa_read, NULL, NULL, lm78_isa_write, NULL, NULL, dev); @@ -498,7 +494,7 @@ lm78_init(const device_t *info) dev->local = info->local; - /* Set default values. */ + /* Set global default values. */ hwm_values_t defaults = { { /* fan speeds */ 3000, /* usually Chassis, sometimes CPU */ @@ -509,25 +505,26 @@ lm78_init(const device_t *info) 30, /* Winbond only: usually CPU, sometimes Probe */ 30 /* Winbond only: usually CPU when not the one above */ }, { /* voltages */ - hwm_get_vcore(), /* Vcore */ - 0, /* sometimes Vtt, Vio or second CPU */ - 3300, /* +3.3V */ - RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */ - RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */ - 12000 * (604.0 / 2100.0), /* -12V (Rf/Rin negative voltage formula from the W83781D datasheet) */ - 5000 * (604.0 / 909.0), /* -5V (Rf/Rin negative voltage formula from the W83781D datasheet) */ - RESISTOR_DIVIDER(5000, 51, 75), /* W83782D only: +5VSB (5.1K/7.5K divider suggested in the datasheet) */ - 3000 /* W83782D only: VBAT */ + hwm_get_vcore(), /* Vcore */ + 0, /* sometimes Vtt, Vio or second CPU */ + 3300, /* +3.3V */ + RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */ + RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */ + LM78_NEG_VOLTAGE(12000, 2100), /* -12V */ + LM78_NEG_VOLTAGE(5000, 909), /* -5V */ + RESISTOR_DIVIDER(5000, 51, 75), /* W83782D only: +5VSB (5.1K/7.5K divider suggested in the datasheet) */ + 3000 /* W83782D only: Vbat */ } }; - /* Set per-chip defaults. */ + /* Set chip-specific default values. */ if (dev->local & LM78_AS99127F) { - defaults.voltages[5] = 12000 * (604.0 / 2400.0); /* different -12V Rin value for AS99127F (bruteforced) */ + /* AS99127: different -12V Rin value (bruteforced) */ + defaults.voltages[5] = LM78_NEG_VOLTAGE(12000, 2400); } else if (dev->local & LM78_W83782D) { - /* different negative voltage formula for W83782D (from the datasheet) */ - defaults.voltages[5] = ((3600 + 12000) * (232.0 / (232.0 + 56.0))) - 12000; - defaults.voltages[6] = ((3600 + 5000) * (120.0 / (120.0 + 56.0))) - 5000; + /* W83782D: different negative voltage formula */ + defaults.voltages[5] = LM78_NEG_VOLTAGE2(12000, 232); + defaults.voltages[6] = LM78_NEG_VOLTAGE2(5000, 120); } hwm_values = defaults; @@ -538,9 +535,9 @@ lm78_init(const device_t *info) if (dev->local & LM78_WINBOND) { dev->lm75[i] = (device_t *) malloc(sizeof(device_t)); memcpy(dev->lm75[i], &lm75_w83781d_device, sizeof(device_t)); - dev->lm75[i]->local = ((i + 1) << 8); + dev->lm75[i]->local = (i + 1) << 8; if (dev->local & LM78_SMBUS) - dev->lm75[i]->local |= (0x48 + i); + dev->lm75[i]->local |= 0x48 + i; device_add(dev->lm75[i]); } else { dev->lm75[i] = NULL; @@ -549,7 +546,7 @@ lm78_init(const device_t *info) lm78_reset(dev, 0); - uint16_t isa_io = (dev->local & 0xffff); + uint16_t isa_io = dev->local & 0xffff; if (isa_io) io_sethandler(isa_io, 8, lm78_isa_read, NULL, NULL, lm78_isa_write, NULL, NULL, dev); diff --git a/src/device/hwm_vt82c686.c b/src/device/hwm_vt82c686.c index 6c79cdb55..734aabfe4 100644 --- a/src/device/hwm_vt82c686.c +++ b/src/device/hwm_vt82c686.c @@ -45,6 +45,9 @@ typedef struct { } vt82c686_t; +static double voltage_factors[5] = {1.25, 1.25, 1.67, 2.6, 6.3}; + + static void vt82c686_reset(vt82c686_t *dev, uint8_t initialization); @@ -52,7 +55,29 @@ static uint8_t vt82c686_read(uint16_t addr, void *priv) { vt82c686_t *dev = (vt82c686_t *) priv; - return dev->regs[addr - dev->io_base]; + uint8_t ret; + + addr -= dev->io_base; + + switch (addr) { + case 0x1f: case 0x20: case 0x21: /* temperatures */ + ret = VT82C686_TEMP_TO_REG(dev->values->temperatures[(addr == 0x1f) ? 2 : (addr & 1)]); + break; + + case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: /* voltages */ + ret = VT82C686_VOLTAGE_TO_REG(dev->values->voltages[addr - 0x22], voltage_factors[addr - 0x22]); + break; + + case 0x29: case 0x2a: /* fan speeds */ + ret = VT82C686_RPM_TO_REG(dev->values->fans[addr - 0x29], 1 << ((dev->regs[0x47] >> ((addr == 0x29) ? 4 : 6)) & 0x3)); + break; + + default: /* other registers */ + ret = dev->regs[addr]; + break; + } + + return ret; } @@ -65,18 +90,9 @@ vt82c686_write(uint16_t port, uint8_t val, void *priv) if ((reg == 0x41) || (reg == 0x42) || (reg == 0x45) || (reg == 0x46) || (reg == 0x48) || (reg == 0x4a) || (reg >= 0x4c)) return; - switch (reg) { - case 0x40: - if (val & 0x80) - vt82c686_reset(dev, 1); - break; - - case 0x47: - val &= 0xf0; - /* update FAN1/FAN2 values to match the new divisor */ - dev->regs[0x29] = VT82C686_RPM_TO_REG(dev->values->fans[0], 1 << ((dev->regs[0x47] >> 4) & 0x3)); - dev->regs[0x2a] = VT82C686_RPM_TO_REG(dev->values->fans[1], 1 << ((dev->regs[0x47] >> 6) & 0x3)); - break; + if ((reg == 0x40) && (val & 0x80)) { + val &= 0x7f; + vt82c686_reset(dev, 1); } dev->regs[reg] = val; @@ -121,28 +137,12 @@ vt82c686_reset(vt82c686_t *dev, uint8_t initialization) { memset(dev->regs, 0, 80); - dev->regs[0x1f] = VT82C686_TEMP_TO_REG(dev->values->temperatures[2]); - dev->regs[0x20] = VT82C686_TEMP_TO_REG(dev->values->temperatures[0]); - dev->regs[0x21] = VT82C686_TEMP_TO_REG(dev->values->temperatures[1]); - - dev->regs[0x22] = VT82C686_VOLTAGE_TO_REG(dev->values->voltages[0], 1.25); - dev->regs[0x23] = VT82C686_VOLTAGE_TO_REG(dev->values->voltages[1], 1.25); - dev->regs[0x24] = VT82C686_VOLTAGE_TO_REG(dev->values->voltages[2], 1.67); - dev->regs[0x25] = VT82C686_VOLTAGE_TO_REG(dev->values->voltages[3], 2.6); - dev->regs[0x26] = VT82C686_VOLTAGE_TO_REG(dev->values->voltages[4], 6.3); - - dev->regs[0x29] = VT82C686_RPM_TO_REG(dev->values->fans[0], 2); - dev->regs[0x2a] = VT82C686_RPM_TO_REG(dev->values->fans[1], 2); - dev->regs[0x40] = 0x08; dev->regs[0x47] = 0x50; - dev->regs[0x49] = (dev->values->temperatures[2] & 0x3) << 6; - dev->regs[0x49] |= (dev->values->temperatures[1] & 0x3) << 4; - dev->regs[0x4b] = (dev->values->temperatures[0] & 0x3) << 6; - dev->regs[0x4b] |= 0x15; + dev->regs[0x4b] = 0x15; if (!initialization) - vt82c686_hwm_write(0x85, 0x00, dev); + vt82c686_hwm_write(0x74, 0x00, dev); } @@ -165,18 +165,18 @@ vt82c686_init(const device_t *info) the values struct contains voltage values *before* applying their respective factors. */ hwm_values_t defaults = { { /* fan speeds */ - 3000, /* CPU */ - 3000 /* Chassis */ + 3000, /* usually CPU */ + 3000 /* usually Chassis */ }, { /* temperatures */ - 30, /* CPU */ - 30, /* System */ - 0 /* unused */ + 30, /* usually CPU */ + 30, /* usually System */ + 30 }, { /* voltages */ hwm_get_vcore(), /* Vcore */ - 2500, /* 2.5V */ - 3300, /* 3.3V */ - 5000, /* 5V */ - 12000 /* 12V */ + 2500, /* +2.5V */ + 3300, /* +3.3V */ + 5000, /* +5V */ + 12000 /* +12V */ } }; hwm_values = defaults; diff --git a/src/include/86box/hwm.h b/src/include/86box/hwm.h index 72d5cc208..27cb4a921 100644 --- a/src/include/86box/hwm.h +++ b/src/include/86box/hwm.h @@ -25,7 +25,7 @@ typedef struct { uint16_t fans[4]; uint8_t temperatures[4]; - uint16_t voltages[9]; + uint16_t voltages[10]; } hwm_values_t; typedef struct { diff --git a/src/machine/m_at_sockets7.c b/src/machine/m_at_sockets7.c index 5c433c7a6..a03f348e2 100644 --- a/src/machine/m_at_sockets7.c +++ b/src/machine/m_at_sockets7.c @@ -135,7 +135,10 @@ machine_at_ficva503a_init(const machine_t *model) device_add(&via_vt82c686_sio_device); device_add(&sst_flash_39sf020_device); spd_register(SPD_TYPE_SDRAM, 0x7, 256); - device_add(&via_vt82c686_hwm_device); + device_add(&via_vt82c686_hwm_device); /* fans: CPU1, Chassis; temperatures: CPU, System, unused */ + hwm_values.temperatures[0] += 2; /* CPU offset */ + hwm_values.temperatures[1] += 2; /* System offset */ + hwm_values.temperatures[2] = 0; /* unused */ return ret; }