Try to request the BIOS semaphore on SB700 family southbridges.
This is a really gross hack and should _not_ enter the tree as is. It is also potentially dangerous on SB600, and will slow down all flash accesses a lot. It is a really simple patch designed to test my assumptions about locking.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-sb700_spi_imc_flash_arbitration/sb600spi.c =================================================================== --- flashrom-sb700_spi_imc_flash_arbitration/sb600spi.c (Revision 1145) +++ flashrom-sb700_spi_imc_flash_arbitration/sb600spi.c (Arbeitskopie) @@ -42,6 +42,7 @@ */
static uint8_t *sb600_spibar = NULL; +static struct pci_dev *lpc_bridge = NULL;
int sb600_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) { @@ -100,6 +101,71 @@ ; }
+static int request_flash_access(void) +{ + uint8_t tmp; + int i = 0; + + tmp = pci_read_byte(lpc_bridge, 0x40); + if (tmp & (1 << 6)) { + msg_pspew("Waiting for SB600 IMC to release flash access.\n"); + while (pci_read_byte(lpc_bridge, 0x40) & (1 << 6)) { + if (++i > 1024) { + msg_perr("SB600 IMC did not release flash.\n"); + return 1; + } + } + msg_pspew("SB600 IMC released flash access after %i cycles.\n", + i); + i = 0; + } + + if (tmp & (1 << 5)) { + /* Is this an error? */ + msg_pdbg("Strange. SB600 flash access requested although it " + "was already granted.\n"); + return 0; + } + + /* Request BiosSemaphore. */ + tmp = pci_read_byte(lpc_bridge, 0x40); + tmp |= 1 << 5; + pci_write_byte(lpc_bridge, 0x40, tmp); + while (!(pci_read_byte(lpc_bridge, 0x40) & (1 << 5))) { + if (++i > 1024) { + msg_perr("SB600 flash access was not granted.\n"); + return 1; + } + } + tmp = pci_read_byte(lpc_bridge, 0x40); + if (tmp & (1 << 6)) { + msg_perr("Very strange. SB600 IMC has flash access although " + "we requested SB600 flash access.\n"); + return 1; + } + msg_pspew("SB600 flash access granted after %i cycles.\n", i); + return 0; +} + +static int release_flash_access(void) +{ + uint8_t tmp; + + tmp = pci_read_byte(lpc_bridge, 0x40); + if (tmp & (1 << 6)) { + /* Is this an error? */ + msg_pdbg("Strange. SB600 IMC already has flash access.\n"); + } + if (!(tmp & (1 << 5))) { + /* Is this an error? */ + msg_pdbg("Strange. SB600 already released flash access.\n"); + } + tmp &= ~(1 << 5); + pci_write_byte(lpc_bridge, 0x40, tmp); + + return 0; +} + int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr) { @@ -126,6 +192,13 @@ return SPI_INVALID_LENGTH; }
+ /* FIXME: Waiting for arbitration here is stupid. We need arbitration + * either at the start of a multicommand, or even at SB600 init. + * FIXME: Check if arbitration also is needed on SB600. + */ + if (request_flash_access()) + return SPI_PROGRAMMER_ERROR; + /* This is a workaround for a bug in SB600 and SB700. If we only send * an opcode and no additional data/address, the SPI controller will * read one byte too few from the chip. Basically, the last byte of @@ -199,6 +272,7 @@ "flash chip.\n"); return SPI_PROGRAMMER_ERROR; } + release_flash_access();
return 0; } @@ -212,6 +286,8 @@ "Reserved", "33", "22", "16.5" };
+ lpc_bridge = dev; + /* Read SPI_BaseAddr */ tmp = pci_read_long(dev, 0xa0); tmp &= 0xffffffe0; /* remove bits 4-0 (reserved) */