From e86b04a14a884910f3271d83ffe9d8c1f256c6da Mon Sep 17 00:00:00 2001 From: Lionel Debroux Date: Mon, 6 Jun 2022 10:24:45 +0200 Subject: [PATCH] Perform major simplification in smbus.c to reduce code size while keeping the functions readable, removing several unused strings and unnecessary arguments passed to several functions. Add a bunch of PCI device IDs and driver indications for other SMBus controllers, so as to avoid other persons having to do that work again. Add support for two PIIX4 devices: the standard PIIX4 PCI device ID, and the ServerWorks CSB5, which has a slight twist. Co-authored-by: Lionel Debroux Co-authored-by: Sam Demeulemeester --- system/smbus.c | 431 +++++++++++++++++++++++++++++++++---------------- system/smbus.h | 12 +- 2 files changed, 305 insertions(+), 138 deletions(-) diff --git a/system/smbus.c b/system/smbus.c index 50b1463..6ca4f7d 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -22,6 +22,7 @@ ram_info ram = { 0, 0, 0, 0, 0, "N/A"}; int smbdev, smbfun; unsigned short smbusbase = 0; uint32_t smbus_id; +static uint16_t extra_initial_sleep_for_smb_transaction = 0; static int8_t spd_page = -1; static int8_t last_adr = -1; @@ -37,117 +38,22 @@ static spd_info parse_spd_ddr4 (uint8_t slot_idx); static spd_info parse_spd_ddr5 (uint8_t slot_idx); static void print_spdi(spd_info spdi, uint8_t lidx); -static int find_smb_controller(void); +static bool setup_smb_controller(void); +static bool find_smb_controller(uint16_t vid, uint16_t did); + static uint8_t get_spd(uint8_t slot_idx, uint16_t spd_adr); -static void nv_mcp_get_smb(void); -static void amd_sb_get_smb(void); -static void fch_zen_get_smb(void); -static void piix4_get_smb(void); -static void ich5_get_smb(void); +static bool nv_mcp_get_smb(void); +static bool amd_sb_get_smb(void); +static bool fch_zen_get_smb(void); +static bool piix4_get_smb(void); +static bool ich5_get_smb(void); static uint8_t ich5_process(void); static uint8_t ich5_read_spd_byte(uint8_t adr, uint16_t cmd); static uint8_t nf_read_spd_byte(uint8_t smbus_adr, uint8_t spd_adr); -// ---------------------------------------------------------- -// WARNING: Be careful when adding a controller ID! -// Incorrect SMB accesses (ie: on bank switch) can brick your -// motherboard or your memory module. -// ---- -// No Pull Request including a new SMBUS Controller will be -// accepted without a proof (screenshot) that it has been -// tested successfully on a real motherboard. -// ---------------------------------------------------------- - -static const struct pci_smbus_controller smbcontrollers[] = { - {0x8086, 0x2413, ich5_get_smb}, // 82801AA (ICH) - {0x8086, 0x2423, ich5_get_smb}, // 82801AB (ICH) - {0x8086, 0x2443, ich5_get_smb}, // 82801BA (ICH2) - {0x8086, 0x2483, ich5_get_smb}, // 82801CA (ICH3) - {0x8086, 0x24C3, ich5_get_smb}, // 82801DB (ICH4) - {0x8086, 0x24D3, ich5_get_smb}, // 82801E (ICH5) - {0x8086, 0x25A4, ich5_get_smb}, // 6300ESB - {0x8086, 0x266A, ich5_get_smb}, // 82801F (ICH6) - {0x8086, 0x269B, ich5_get_smb}, // 6310ESB/6320ESB - {0x8086, 0x27DA, ich5_get_smb}, // 82801G (ICH7) - {0x8086, 0x283E, ich5_get_smb}, // 82801H (ICH8) - {0x8086, 0x2930, ich5_get_smb}, // 82801I (ICH9) - {0x8086, 0x5032, ich5_get_smb}, // EP80579 (Tolapai) - {0x8086, 0x3A30, ich5_get_smb}, // ICH10 - {0x8086, 0x3A60, ich5_get_smb}, // ICH10 - {0x8086, 0x3B30, ich5_get_smb}, // 5/3400 Series (PCH) - {0x8086, 0x1C22, ich5_get_smb}, // 6 Series (PCH) - {0x8086, 0x1D22, ich5_get_smb}, // Patsburg (PCH) - {0x8086, 0x1D70, ich5_get_smb}, // Patsburg (PCH) IDF - {0x8086, 0x1D71, ich5_get_smb}, // Patsburg (PCH) IDF - {0x8086, 0x1D72, ich5_get_smb}, // Patsburg (PCH) IDF - {0x8086, 0x2330, ich5_get_smb}, // DH89xxCC (PCH) - {0x8086, 0x1E22, ich5_get_smb}, // Panther Point (PCH) - {0x8086, 0x8C22, ich5_get_smb}, // Lynx Point (PCH) - {0x8086, 0x9C22, ich5_get_smb}, // Lynx Point-LP (PCH) - {0x8086, 0x1F3C, ich5_get_smb}, // Avoton (SOC) - {0x8086, 0x8D22, ich5_get_smb}, // Wellsburg (PCH) - {0x8086, 0x8D7D, ich5_get_smb}, // Wellsburg (PCH) MS - {0x8086, 0x8D7E, ich5_get_smb}, // Wellsburg (PCH) MS - {0x8086, 0x8D7F, ich5_get_smb}, // Wellsburg (PCH) MS - {0x8086, 0x23B0, ich5_get_smb}, // Coleto Creek (PCH) - {0x8086, 0x8CA2, ich5_get_smb}, // Wildcat Point (PCH) - {0x8086, 0x9CA2, ich5_get_smb}, // Wildcat Point-LP (PCH) - {0x8086, 0x0F12, ich5_get_smb}, // BayTrail (SOC) - {0x8086, 0x2292, ich5_get_smb}, // Braswell (SOC) - {0x8086, 0xA123, ich5_get_smb}, // Sunrise Point-H (PCH) - {0x8086, 0x9D23, ich5_get_smb}, // Sunrise Point-LP (PCH) - {0x8086, 0x19DF, ich5_get_smb}, // Denverton (SOC) - {0x8086, 0x1BC9, ich5_get_smb}, // Emmitsburg (PCH) - {0x8086, 0xA1A3, ich5_get_smb}, // Lewisburg (PCH) - {0x8086, 0xA223, ich5_get_smb}, // Lewisburg Super (PCH) - {0x8086, 0xA2A3, ich5_get_smb}, // Kaby Lake (PCH-H) - {0x8086, 0x31D4, ich5_get_smb}, // Gemini Lake (SOC) - {0x8086, 0xA323, ich5_get_smb}, // Cannon Lake-H (PCH) - {0x8086, 0x9DA3, ich5_get_smb}, // Cannon Lake-LP (PCH) - {0x8086, 0x18DF, ich5_get_smb}, // Cedar Fork (PCH) - {0x8086, 0x34A3, ich5_get_smb}, // Ice Lake-LP (PCH) - {0x8086, 0x38A3, ich5_get_smb}, // Ice Lake-N (PCH) - {0x8086, 0x02A3, ich5_get_smb}, // Comet Lake (PCH) - {0x8086, 0x06A3, ich5_get_smb}, // Comet Lake-H (PCH) - {0x8086, 0x4B23, ich5_get_smb}, // Elkhart Lake (PCH) - {0x8086, 0xA0A3, ich5_get_smb}, // Tiger Lake-LP (PCH) - {0x8086, 0x43A3, ich5_get_smb}, // Tiger Lake-H (PCH) - {0x8086, 0x4DA3, ich5_get_smb}, // Jasper Lake (SOC) - {0x8086, 0xA3A3, ich5_get_smb}, // Comet Lake-V (PCH) - {0x8086, 0x7AA3, ich5_get_smb}, // Alder Lake-S (PCH) - {0x8086, 0x51A3, ich5_get_smb}, // Alder Lake-P (PCH) - {0x8086, 0x54A3, ich5_get_smb}, // Alder Lake-M (PCH) - {0x8086, 0x7A23, ich5_get_smb}, // Raptor Lake-S (PCH) - - // ATI SMBUS - {0x1002, 0x4385, amd_sb_get_smb}, // ATI SB600+ (Now AMD) - - // AMD SMBUS - {0x1022, 0x780B, amd_sb_get_smb}, // AMD FCH (Pre-Zen) - {0x1022, 0x790B, fch_zen_get_smb}, // AMD FCH (Zen) - - // nVidia SMBUS - // {0x10DE, 0x01B4, nv_mcp_get_smb}, // nForce - {0x10DE, 0x0064, nv_mcp_get_smb}, // nForce 2 - // {0x10DE, 0x0084, nv_mcp_get_smb}, // nForce 2 Mobile - // {0x10DE, 0x00E4, nv_mcp_get_smb}, // nForce 3 - // {0x10DE, 0x0052, nv_mcp_get_smb}, // nForce 4 - // {0x10DE, 0x0264, nv_mcp_get_smb}, // nForce 410/430 MCP - // {0x10DE, 0x0446, nv_mcp_get_smb}, // nForce 520 - // {0x10DE, 0x0542, nv_mcp_get_smb}, // nForce 560 - // {0x10DE, 0x07D8, nv_mcp_get_smb}, // nForce 630i - {0x10DE, 0x03EB, nv_mcp_get_smb}, // nForce 630a - {0x10DE, 0x0752, nv_mcp_get_smb}, // nForce 720a - // {0x10DE, 0x0AA2, nv_mcp_get_smb}, // nForce 730i - // {0x10DE, 0x0368, nv_mcp_get_smb}, // nForce 790i Ultra - - {0, 0, NULL} -}; - -void print_smbus_startup_info(void) { - - int8_t index; +void print_smbus_startup_info(void) +{ uint8_t spdidx = 0, spd_line_idx = 0; spd_info curspd; @@ -158,15 +64,7 @@ void print_smbus_startup_info(void) { quirk.process(); } - index = find_smb_controller(); - - if (index == -1) { - return; - } - - smbcontrollers[index].get_adr(); - - if (smbusbase == 0) { + if (!setup_smb_controller() || smbusbase == 0) { return; } @@ -1236,52 +1134,295 @@ static spd_info parse_spd_sdram(uint8_t slot_idx) return spdi; } + // -------------------------- // SMBUS Controller Functions // -------------------------- -static int find_smb_controller(void) +static bool setup_smb_controller(void) { - int i = 0; - unsigned long valuev, valued; + uint16_t vid, did; for (smbdev = 0; smbdev < 32; smbdev++) { for (smbfun = 0; smbfun < 8; smbfun++) { - valuev = pci_config_read16(0, smbdev, smbfun, 0); - if (valuev != 0xFFFF) { - for (i = 0; smbcontrollers[i].vendor > 0; i++) { - if (valuev == smbcontrollers[i].vendor) { - valued = pci_config_read16(0, smbdev, smbfun, 2); - if (valued == smbcontrollers[i].device) { - smbus_id = (valuev << 16) | valued; - return i; - } + vid = pci_config_read16(0, smbdev, smbfun, 0); + if (vid != 0xFFFF) { + did = pci_config_read16(0, smbdev, smbfun, 2); + if (did != 0xFFFF) { + if (find_smb_controller(vid, did)) { + return true; } } } } } - return -1; + return false; +} + +// ---------------------------------------------------------- +// WARNING: Be careful when adding a controller ID! +// Incorrect SMB accesses (ie: on bank switch) can brick your +// motherboard or your memory module. +// ---- +// No Pull Request including a new SMBUS Controller will be +// accepted without a proof (screenshot) that it has been +// tested successfully on a real motherboard. +// ---------------------------------------------------------- + +// PCI device IDs for Intel i801 SMBus controller. +static const uint16_t intel_ich5_dids[] = +{ + 0x2413, // 82801AA (ICH) + 0x2423, // 82801AB (ICH) + 0x2443, // 82801BA (ICH2) + 0x2483, // 82801CA (ICH3) + 0x24C3, // 82801DB (ICH4) + 0x24D3, // 82801E (ICH5) + 0x25A4, // 6300ESB + 0x266A, // 82801F (ICH6) + 0x269B, // 6310ESB/6320ESB + 0x27DA, // 82801G (ICH7) + 0x283E, // 82801H (ICH8) + 0x2930, // 82801I (ICH9) + 0x5032, // EP80579 (Tolapai) + 0x3A30, // ICH10 + 0x3A60, // ICH10 + 0x3B30, // 5/3400 Series (PCH) + 0x1C22, // 6 Series (PCH) + 0x1D22, // Patsburg (PCH) + 0x1D70, // Patsburg (PCH) IDF + 0x1D71, // Patsburg (PCH) IDF + 0x1D72, // Patsburg (PCH) IDF + 0x2330, // DH89xxCC (PCH) + 0x1E22, // Panther Point (PCH) + 0x8C22, // Lynx Point (PCH) + 0x9C22, // Lynx Point-LP (PCH) + 0x1F3C, // Avoton (SOC) + 0x8D22, // Wellsburg (PCH) + 0x8D7D, // Wellsburg (PCH) MS + 0x8D7E, // Wellsburg (PCH) MS + 0x8D7F, // Wellsburg (PCH) MS + 0x23B0, // Coleto Creek (PCH) + 0x8CA2, // Wildcat Point (PCH) + 0x9CA2, // Wildcat Point-LP (PCH) + 0x0F12, // BayTrail (SOC) + 0x2292, // Braswell (SOC) + 0xA123, // Sunrise Point-H (PCH) + 0x9D23, // Sunrise Point-LP (PCH) + 0x19DF, // Denverton (SOC) + 0x1BC9, // Emmitsburg (PCH) + 0xA1A3, // Lewisburg (PCH) + 0xA223, // Lewisburg Super (PCH) + 0xA2A3, // Kaby Lake (PCH-H) + 0x31D4, // Gemini Lake (SOC) + 0xA323, // Cannon Lake-H (PCH) + 0x9DA3, // Cannon Lake-LP (PCH) + 0x18DF, // Cedar Fork (PCH) + 0x34A3, // Ice Lake-LP (PCH) + 0x38A3, // Ice Lake-N (PCH) + 0x02A3, // Comet Lake (PCH) + 0x06A3, // Comet Lake-H (PCH) + 0x4B23, // Elkhart Lake (PCH) + 0xA0A3, // Tiger Lake-LP (PCH) + 0x43A3, // Tiger Lake-H (PCH) + 0x4DA3, // Jasper Lake (SOC) + 0xA3A3, // Comet Lake-V (PCH) + 0x7AA3, // Alder Lake-S (PCH) + 0x51A3, // Alder Lake-P (PCH) + 0x54A3, // Alder Lake-M (PCH) + 0x7A23, // Raptor Lake-S (PCH) +}; + +static bool find_in_did_array(uint16_t did, const uint16_t * ids, unsigned int size) +{ + for (unsigned int i = 0; i < size; i++) { + if (*ids++ == did) { + return true; + } + } + return false; +} + +static bool find_smb_controller(uint16_t vid, uint16_t did) +{ + switch(vid) + { + case VID_INTEL: + { + if (find_in_did_array(did, intel_ich5_dids, sizeof(intel_ich5_dids) / sizeof(intel_ich5_dids[0]))) { + return ich5_get_smb(); + } + if ( did == 0x7113 // 82371AB/EB/MB PIIX4 +// || did == 0x719B // 82440/82443MX PMC + ) { + return piix4_get_smb(); + } + // 0x0C59-0x0C5E, 0x18AC, 0x19AC, 0x1BFF, 0x1F15, 0x1F3D Atom S1200 / C2000 / C3000 SMBus controllers may not be SPD-related. + // 0x0F13 ValleyView SMBus Controller ? + // 0x7603 82372FB PIIX5 ? + // 0x8119 US15W ? + return false; + } + + case VID_AMD: + switch(did) + { +#if 0 + case 0x740B: // AMD756 + case 0x7413: // AMD766 + case 0x7443: // AMD768 + case 0x746B: // AMD8111_SMBUS + // amd756 / nforce SMB controller + case 0x746A: // AMD8111_SMBUS2 + // amd8111 SMB controller +#endif + case 0x780B: // AMD FCH (Pre-Zen) + return amd_sb_get_smb(); + case 0x790B: // AMD FCH (Zen 2/3) + return fch_zen_get_smb(); + default: + return false; + } + break; + + case VID_HYGON: + switch(did) + { + case 0x780B: // AMD FCH (Pre-Zen) + return amd_sb_get_smb(); + case 0x790B: // AMD FCH (Zen 2/3) + return fch_zen_get_smb(); + default: + return false; + } + break; + + case VID_ATI: + switch(did) + { + // case 0x4353: // SB200 + // case 0x4363: // SB300 + // case 0x4372: // IXP SB4x0 + case 0x4385: // SB600+ + return amd_sb_get_smb(); + default: + return false; + } + break; + + case VID_NVIDIA: + switch(did) + { +#if 0 + case 0x01B4: // nForce + // amd756 / nforce SMB controller +#endif + // case 0x0034: // MCP04 + // case 0x0052: // CK804 + case 0x0064: // nForce2 (MCP) + // case 0x0084: // MCP2A + // case 0x00D4: // nForce3 + // case 0x0264: // MCP51 + // case 0x0368: // MCP55 + case 0x03EB: // MCP61 + // case 0x0446: // MCP65 + // case 0x0542: // MCP67 + case 0x0752: // MCP78S + // case 0x07D8: // MCP73 + // case 0x0AA2: // MCP79 + // case 0x0D79: // MCP89 + return nv_mcp_get_smb(); + default: + return false; + } + break; +#if 0 + case VID_SIS: + switch(did) + { + case 0x0016: // SiS961/2/3 + // sis96x SMBus controller. + // There are also sis630 and sis5595 SMBus controllers. + default: + return false; + } + break; +#endif +#if 0 + case VID_VIA: + switch(did) + { + case 0x3040: // 82C586_3 + // via SMBus controller. + case 0x3050: // 82C596_3 + // Try SMB base address = 0x90, then SMB base address = 0x80 + // viapro SMBus controller. + case 0x3051: // 82C596B_3 + case 0x3057: // 82C686_4 + case 0x8235: // 8231_4 + // SMB base address = 0x90 + // viapro SMBus controller. + case 0x3074: // 8233_0 + case 0x3147: // 8233A + case 0x3177: // 8235 + case 0x3227: // 8237 + case 0x3337: // 8237A + case 0x3372: // 8237S + case 0x3287: // 8251 + case 0x8324: // CX700 + case 0x8353: // VX800 + case 0x8409: // VX855 + case 0x8410: // VX900 + // SMB base address = 0xD0 + // viapro I2C controller. + default: + return false; + } + break; +#endif + case VID_SERVERWORKS: + switch(did) + { + case 0x0201: // CSB5 + // From Linux i2c-piix4 driver: unlike its siblings, this model needs a quirk. + extra_initial_sleep_for_smb_transaction = 2100 - 500; + // Fall through. + // case 0x0200: // OSB4 + // case 0x0203: // CSB6 + // case 0x0205: // HT1000SB + // case 0x0408: // HT1100LD + return piix4_get_smb(); + default: + return false; + } + break; + default: + return false; + } + return false; } // ---------------------- // PIIX4 SMBUS Controller // ---------------------- -static void piix4_get_smb(void) +static bool piix4_get_smb(void) { uint16_t x = pci_config_read16(0, smbdev, smbfun, 0x90) & 0xFFF0; if (x != 0) { smbusbase = x; + return true; } + + return false; } // ---------------------------- // i801 / ICH5 SMBUS Controller // ---------------------------- -static void ich5_get_smb(void) +static bool ich5_get_smb(void) { uint16_t x; @@ -1297,13 +1438,15 @@ static void ich5_get_smb(void) // Reset SMBUS Controller __outb(__inb(SMBHSTSTS) & 0x1F, SMBHSTSTS); usleep(1000); + + return (smbusbase != 0); } // -------------------- // AMD SMBUS Controller // -------------------- -static void amd_sb_get_smb(void) +static bool amd_sb_get_smb(void) { uint8_t rev_id; uint16_t pm_reg; @@ -1312,10 +1455,10 @@ static void amd_sb_get_smb(void) if ((smbus_id & 0xFFFF) == 0x4385 && rev_id <= 0x3D) { // Older AMD SouthBridge (SB700 & older) use PIIX4 registers - piix4_get_smb(); + return piix4_get_smb(); } else if ((smbus_id & 0xFFFF) == 0x780B && rev_id == 0x42) { // Latest Pre-Zen APUs use the newer Zen PM registers - fch_zen_get_smb(); + return fch_zen_get_smb(); } else { // AMD SB (SB800 up to pre-FT3/FP4/AM4) uses specific registers __outb(AMD_SMBUS_BASE_REG + 1, AMD_INDEX_IO_PORT); @@ -1325,11 +1468,14 @@ static void amd_sb_get_smb(void) if (pm_reg != 0xFFE0 && pm_reg != 0) { smbusbase = pm_reg; + return true; } } + + return false; } -static void fch_zen_get_smb(void) +static bool fch_zen_get_smb(void) { uint16_t pm_reg; @@ -1341,24 +1487,27 @@ static void fch_zen_get_smb(void) // Special case for AMD Cezanne (get smb address in memory) if (imc_type == IMC_K19_CZN && pm_reg == 0xFFFF) { smbusbase = ((*(const uint32_t *)(0xFED80000 + 0x300) >> 8) & 0xFF) << 8; - return; + return true; } // Check if IO Smbus is enabled. if ((pm_reg & 0x10) == 0) { - return; + return false; } if ((pm_reg & 0xFF00) != 0) { smbusbase = pm_reg & 0xFF00; + return true; } + + return false; } // ----------------------- // nVidia SMBUS Controller // ----------------------- -static void nv_mcp_get_smb(void) +static bool nv_mcp_get_smb(void) { int smbus_base_adr; @@ -1373,7 +1522,10 @@ static void nv_mcp_get_smb(void) if (x != 0) { smbusbase = x; + return true; } + + return false; } // ------------------ @@ -1383,7 +1535,7 @@ static void nv_mcp_get_smb(void) static uint8_t get_spd(uint8_t slot_idx, uint16_t spd_adr) { switch ((smbus_id >> 16) & 0xFFFF) { - case 0x10DE: + case VID_NVIDIA: return nf_read_spd_byte(slot_idx, (uint8_t)spd_adr); default: return ich5_read_spd_byte(slot_idx, spd_adr); @@ -1470,6 +1622,11 @@ static uint8_t ich5_process(void) __outb(__inb(SMBHSTCNT) | SMBHSTCNT_START, SMBHSTCNT); + // Some SMB controllers need this quirk. + if (extra_initial_sleep_for_smb_transaction) { + usleep(extra_initial_sleep_for_smb_transaction); + } + do { usleep(500); status = __inb(SMBHSTSTS); diff --git a/system/smbus.h b/system/smbus.h index f950cbc..669e8a5 100644 --- a/system/smbus.h +++ b/system/smbus.h @@ -10,6 +10,16 @@ * Copyright (C) 2004-2022 Samuel Demeulemeester. */ +/* Vendor IDs */ +#define VID_ATI 0x1002 +#define VID_AMD 0x1022 +#define VID_SIS 0x1039 +#define VID_NVIDIA 0x10DE +#define VID_VIA 0x1106 +#define VID_SERVERWORKS 0x1166 +#define VID_HYGON 0x1D94 +#define VID_INTEL 0x8086 + #define I2C_WRITE 0 #define I2C_READ 1 @@ -74,7 +84,7 @@ #define NVSMBSTS_RES 0x20 #define NVSMBSTS_STATUS 0x1f -struct pci_smbus_controller{ +struct pci_smbus_controller { unsigned vendor; unsigned device; void (*get_adr)(void);