On 03.02.2010 18:32, Michael Karcher wrote:
Am Montag, den 01.02.2010, 03:31 +0100 schrieb Carl-Daniel Hailfinger:
+/**
- The MCP67 code is guesswork based on cleanroom reverse engineering.
- Due to that, it only reads info and doesn't change any settings.
- It is assumed that LPC chips need the MCP55 code and SPI chips need the
- code provided in this function. Until we know for sure, call
- enable_flash_mcp55 from this function.
- */
We don't know whether we can switch the chip between SPI and LPC mode (does it support LPC at all?), and running correct initialization for SPI might make LPC inaccessible.
AFAIK at least one MCP67 machine used LPC flash and the MCP55 enable worked for it. I have added comments about possible LPC/SPI mutual exclusion to the function. Right now we only support LPC anyway, and all SPI information is dumped before touching LPC in any way.
- /* Locate the BAR where the GPIOs live. */
Maybe GPIO should be changed to something else, as the standard GPIOs are I/O mapped. Make that "where the SPI interface lives"
Done.
/* Map the BAR. We access bytewise and wordwise at 0x530. */
gpiobar = physmap("MCP67 GPIO", gpiobaraddr, 0x534);
We might need gpiobaraddr + 0x10 later. Some BIOSses access it, too. Go directly for 0x544.
Done.
Add error handling here [else msg_perr("bad base address of memory mapped interface")]
msg_pdbg since it may be zero on pure LPC boards, but yes.
+/* This is a shot in the dark. Even if the code is totally bogus for some
- chipsets, users will at least start to send in reports.
- */
Mostly a ripoff of the mcp67 function, bit without any writing. OK.
Yes, once we get reports from that function, we can maybe refactor them a bit and have the mcp67 function call the generic one.
Acked-By: Michael Karcher flashrom@mkarcher.dialup.fu-berlin.de
Thanks! Here's the new version.
Add SPI mode diagnostics for all post-MCP55 (nForce 5) chipsets from Nvidia.
Huge thanks to Michael Karcher for reverse engineering the MCP67 chipset and writing a spec. Due to this, we were able to use the chinese wall technique for 100% clean room reverse engineering.
This patch doesn't touch any of the new registers, it only reads them. Assuming that read has no side effects, this patch is a no-op and safe.
We need "flashrom -V" output from all post-MCP55 (nForce 5) chipset boards. Please indicate if your board uses SPI flash or LPC flash (if you know it). Note: That output is only helpful if it is created with patched flashrom and if is from the first run of flashrom after a cold boot (reset or Ctrl-Alt-Del is not sufficient). There is a pattern based on which we can probably detect which flash type is present on the board.
Thanks to Alessandro Polverini for testing earlier iterations of this patch.
Note: The MCP67 should work. I guessed that the other recent Nvidia chipsets would work in a similar way, and created a simplified do-nothing catchall chipset enable function which dumps some info and instructs the user to send more info.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-mcp67_spi_detect/chipset_enable.c =================================================================== --- flashrom-mcp67_spi_detect/chipset_enable.c (Revision 899) +++ flashrom-mcp67_spi_detect/chipset_enable.c (Arbeitskopie) @@ -1054,6 +1054,127 @@ return 0; }
+/** + * The MCP67 code is guesswork based on cleanroom reverse engineering. + * Due to that, it only reads info and doesn't change any settings. + * It is assumed that LPC chips need the MCP55 code and SPI chips need the + * code provided in this function. Until we know for sure, call + * enable_flash_mcp55 from this function. Warning: enable_flash_mcp55 + * might make SPI flash inaccessible. The same caveat applies to SPI init + * for LPC flash. + */ +static int enable_flash_mcp67(struct pci_dev *dev, const char *name) +{ + int result = 0; + uint8_t byte; + uint16_t status; + uint32_t mcp_spibaraddr; + void *mcp_spibar; + struct pci_dev *smbusdev; + + /* dev is the ISA bridge. No idea what the stuff below does. */ + byte = pci_read_byte(dev, 0x8a); + msg_pdbg("ISA bridge reg 0x8a contents: 0x%02x, bit 6 is %i, bit 5 is " + "%i\n", byte, (byte >> 6) & 0x1, (byte >> 5) & 0x1); + msg_pdbg("Guessed flash bus type is %s\n", ((byte >> 5) & 0x3) == 0x2 ? + "SPI" : "unknown, probably LPC"); + /* Disable the write code for now until we have more info. */ +#if 0 + byte |= (1 << 6); + byte &= ~(1 << 5); + pci_write_byte(dev, 0x8a, byte); +#endif + + /* Look for the SMBus device (SMBus PCI class) */ + smbusdev = pci_dev_find_vendorclass(0x10de, 0x0c05); + if (!smbusdev) { + msg_perr("ERROR: SMBus device not found. Aborting.\n"); + exit(1); + } + msg_pdbg("Found SMBus device %04x:%04x at %02x:%02x:%01x\n", + smbusdev->vendor_id, smbusdev->device_id, + smbusdev->bus, smbusdev->dev, smbusdev->func); + + /* Locate the BAR where the SPI interface lives. */ + mcp_spibaraddr = pci_read_long(smbusdev, 0x74); + msg_pdbg("SPI BAR is at 0x%08x, ", mcp_spibaraddr); + /* We hope this has native alignment. We know the SPI interface (well, + * a set of GPIOs that is connected to SPI flash) is at offset 0x530, + * so we expect a size of at least 0x800. Clear the lower bits. + * It is entirely possible that the BAR is 64k big and the low bits are + * reserved for an entirely different purpose. + */ + mcp_spibaraddr &= ~0x7ff; + msg_pdbg("after clearing low bits BAR is at 0x%08x\n", mcp_spibaraddr); + + /* Accessing a NULL pointer BAR is evil. Don't do it. */ + if (mcp_spibaraddr) { + /* Map the BAR. Bytewise/wordwise access at 0x530 and 0x540. */ + mcp_spibar = physmap("MCP67 SPI", mcp_spibaraddr, 0x544); + +/* Guessed. If this is correct, migrate to a separate MCP67 SPI driver. */ +#define MCP67_SPI_CS (1 << 1) +#define MCP67_SPI_SCK (1 << 2) +#define MCP67_SPI_MOSI (1 << 3) +#define MCP67_SPI_MISO (1 << 4) +#define MCP67_SPI_ENABLE (1 << 0) +#define MCP67_SPI_IDLE (1 << 8) + + status = mmio_readw(mcp_spibar + 0x530); + msg_pdbg("SPI control is 0x%04x, enable=%i, idle=%i\n", + status, status & 0x1, (status >> 8) & 0x1); + /* FIXME: Remove the physunmap once the SPI driver exists. */ + physunmap(mcp_spibar, 0x544); + } else { + msg_pdbg("Strange. MCP67 SPI BAR is invalid.\n"); + } + msg_pinfo("Please send the output of "flashrom -V" to " + "flashrom@flashrom.org to help us finish support for your " + "chipset. Thanks.\n"); + + /* Not sure if this is still correct. No docs as usual. */ + result = enable_flash_mcp55(dev, name); + + return result; +} + +/* This is a shot in the dark. Even if the code is totally bogus for some + * chipsets, users will at least start to send in reports. + */ +static int enable_flash_mcp7x(struct pci_dev *dev, const char *name) +{ + uint8_t byte; + uint32_t mcp_spibaraddr; + struct pci_dev *smbusdev; + + msg_pinfo("This chipset is not really supported yet. Guesswork...\n"); + + /* dev is the ISA bridge. No idea what the stuff below does. */ + byte = pci_read_byte(dev, 0x8a); + msg_pdbg("ISA/LPC bridge reg 0x8a contents: 0x%02x, bit 6 is %i, bit 5 " + "is %i\n", byte, (byte >> 6) & 0x1, (byte >> 5) & 0x1); + + /* Look for the SMBus device (SMBus PCI class) */ + smbusdev = pci_dev_find_vendorclass(0x10de, 0x0c05); + if (!smbusdev) { + msg_perr("ERROR: SMBus device not found. Aborting.\n"); + exit(1); + } + msg_pdbg("Found SMBus device %04x:%04x at %02x:%02x:%01x\n", + smbusdev->vendor_id, smbusdev->device_id, + smbusdev->bus, smbusdev->dev, smbusdev->func); + + /* Locate the BAR where the SPI interface lives. */ + mcp_spibaraddr = pci_read_long(smbusdev, 0x74); + msg_pdbg("SPI BAR is at 0x%08x, ", mcp_spibaraddr); + + msg_pinfo("Please send the output of "flashrom -V" to " + "flashrom@flashrom.org to help us finish support for your " + "chipset. Thanks.\n"); + + return 0; +} + static int enable_flash_ht1000(struct pci_dev *dev, const char *name) { uint8_t byte; @@ -1193,7 +1314,22 @@ {0x10de, 0x0365, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* LPC */ {0x10de, 0x0366, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* LPC */ {0x10de, 0x0367, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* Pro */ - {0x10de, 0x0548, OK, "NVIDIA", "MCP67", enable_flash_mcp55}, + {0x10de, 0x03e0, NT, "NVIDIA", "MCP61", enable_flash_mcp7x}, + {0x10de, 0x03e1, NT, "NVIDIA", "MCP61", enable_flash_mcp7x}, + {0x10de, 0x03e2, NT, "NVIDIA", "MCP61", enable_flash_mcp7x}, + {0x10de, 0x03e3, NT, "NVIDIA", "MCP61", enable_flash_mcp7x}, + {0x10de, 0x0440, NT, "NVIDIA", "MCP65", enable_flash_mcp7x}, + {0x10de, 0x0441, NT, "NVIDIA", "MCP65", enable_flash_mcp7x}, + {0x10de, 0x0442, NT, "NVIDIA", "MCP65", enable_flash_mcp7x}, + {0x10de, 0x0443, NT, "NVIDIA", "MCP65", enable_flash_mcp7x}, + {0x10de, 0x0548, OK, "NVIDIA", "MCP67", enable_flash_mcp67}, + {0x10de, 0x075c, NT, "NVIDIA", "MCP78S", enable_flash_mcp7x}, + {0x10de, 0x075d, NT, "NVIDIA", "MCP78S", enable_flash_mcp7x}, + {0x10de, 0x07d7, NT, "NVIDIA", "MCP73", enable_flash_mcp7x}, + {0x10de, 0x0aac, NT, "NVIDIA", "MCP79", enable_flash_mcp7x}, + {0x10de, 0x0aad, NT, "NVIDIA", "MCP79", enable_flash_mcp7x}, + {0x10de, 0x0aae, NT, "NVIDIA", "MCP79", enable_flash_mcp7x}, + {0x10de, 0x0aaf, NT, "NVIDIA", "MCP79", enable_flash_mcp7x}, {0x1039, 0x0496, NT, "SiS", "85C496+497", enable_flash_sis85c496}, {0x1039, 0x0406, NT, "SiS", "501/5101/5501", enable_flash_sis501}, {0x1039, 0x5511, NT, "SiS", "5511", enable_flash_sis5511},