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 <[email protected]>

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) */


-- 
http://www.hailfinger.org/


_______________________________________________
flashrom mailing list
[email protected]
http://www.flashrom.org/mailman/listinfo/flashrom

Reply via email to