summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chipset_enable.c38
-rw-r--r--flash.h1
-rw-r--r--sb600spi.c38
-rw-r--r--spi.c4
4 files changed, 53 insertions, 28 deletions
diff --git a/chipset_enable.c b/chipset_enable.c
index 6220e36..6452f82 100644
--- a/chipset_enable.c
+++ b/chipset_enable.c
@@ -692,25 +692,49 @@ static int enable_flash_sb600(struct pci_dev *dev, const char *name)
/* Read SPI_BaseAddr */
tmp = pci_read_long(dev, 0xa0);
- tmp &= 0xfffffff0; /* remove low 4 bits (reserved) */
+ tmp &= 0xffffffe0; /* remove bits 4-0 (reserved) */
printf_debug("SPI base address is at 0x%x\n", tmp);
/* If the BAR has address 0, it is unlikely SPI is used. */
if (!tmp)
has_spi = 0;
- /* Physical memory can only be mapped at page (4k) boundaries */
- sb600_spibar = physmap("SB600 SPI registers", tmp & 0xfffff000, 0x1000);
- /* The low bits of the SPI base address are used as offset into the mapped page */
- sb600_spibar += tmp & 0xfff;
+ if (has_spi) {
+ /* Physical memory has to be mapped at page (4k) boundaries. */
+ sb600_spibar = physmap("SB600 SPI registers", tmp & 0xfffff000,
+ 0x1000);
+ /* The low bits of the SPI base address are used as offset into
+ * the mapped page.
+ */
+ sb600_spibar += tmp & 0xfff;
+
+ tmp = pci_read_long(dev, 0xa0);
+ printf_debug("AltSpiCSEnable=%i, SpiRomEnable=%i, "
+ "AbortEnable=%i\n", tmp & 0x1, (tmp & 0x2) >> 1,
+ (tmp & 0x4) >> 2);
+ tmp = (pci_read_byte(dev, 0xba) & 0x4) >> 2;
+ printf_debug("PrefetchEnSPIFromIMC=%i, ", tmp);
+
+ tmp = pci_read_byte(dev, 0xbb);
+ printf_debug("PrefetchEnSPIFromHost=%i, SpiOpEnInLpcMode=%i\n",
+ tmp & 0x1, (tmp & 0x20) >> 5);
+ tmp = mmio_readl(sb600_spibar);
+ printf_debug("SpiArbEnable=%i, SpiAccessMacRomEn=%i, "
+ "SpiHostAccessRomEn=%i, ArbWaitCount=%i, "
+ "SpiBridgeDisable=%i, DropOneClkOnRd=%i\n",
+ (tmp >> 19) & 0x1, (tmp >> 22) & 0x1,
+ (tmp >> 23) & 0x1, (tmp >> 24) & 0x7,
+ (tmp >> 27) & 0x1, (tmp >> 28) & 0x1);
+ }
/* Look for the SMBus device. */
smbus_dev = pci_dev_find(0x1002, 0x4385);
- if (!smbus_dev) {
+ if (has_spi && !smbus_dev) {
fprintf(stderr, "ERROR: SMBus device not found. Not enabling SPI.\n");
has_spi = 0;
- } else {
+ }
+ if (has_spi) {
/* Note about the bit tests below: If a bit is zero, the GPIO is SPI. */
/* GPIO11/SPI_DO and GPIO12/SPI_DI status */
reg = pci_read_byte(smbus_dev, 0xAB);
diff --git a/flash.h b/flash.h
index 0da4293..d8454ff 100644
--- a/flash.h
+++ b/flash.h
@@ -511,7 +511,6 @@ int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr, unsigned char *readarr);
int sb600_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
int sb600_spi_write_1(struct flashchip *flash, uint8_t *buf);
-uint8_t sb600_read_status_register(void);
extern uint8_t *sb600_spibar;
/* jedec.c */
diff --git a/sb600spi.c b/sb600spi.c
index 865a8c3..2088b08 100644
--- a/sb600spi.c
+++ b/sb600spi.c
@@ -38,7 +38,7 @@
*};
*/
-uint8_t *sb600_spibar;
+uint8_t *sb600_spibar = NULL;
int sb600_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
{
@@ -46,16 +46,6 @@ int sb600_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
return spi_read_chunked(flash, buf, start, len, 8);
}
-uint8_t sb600_read_status_register(void)
-{
- const unsigned char cmd[0x02] = { JEDEC_RDSR, 0x00 };
- unsigned char readarr[JEDEC_RDSR_INSIZE];
-
- /* Read Status Register */
- spi_send_command(sizeof(cmd), sizeof(readarr), cmd, readarr);
- return readarr[0];
-}
-
int sb600_spi_write_1(struct flashchip *flash, uint8_t *buf)
{
int rc = 0, i;
@@ -106,6 +96,7 @@ int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt,
int count;
/* First byte is cmd which can not being sent through FIFO. */
unsigned char cmd = *writearr++;
+ unsigned int readoffby1;
writecnt--;
@@ -124,8 +115,15 @@ int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt,
return SPI_INVALID_LENGTH;
}
+ /* 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
+ * the chip response is discarded and will not end up in the FIFO.
+ * It is unclear if the CS# line is set high too early as well.
+ */
+ readoffby1 = (writecnt) ? 0 : 1;
+ mmio_writeb((readcnt + readoffby1) << 4 | (writecnt), sb600_spibar + 1);
mmio_writeb(cmd, sb600_spibar + 0);
- mmio_writeb(readcnt << 4 | (writecnt), sb600_spibar + 1);
/* Before we use the FIFO, reset it first. */
reset_internal_fifo_pointer();
@@ -147,17 +145,25 @@ int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt,
/*
* After the command executed, we should find out the index of the
- * received byte. Here we just reset the FIFO pointer, skip the
- * writecnt, is there anyone who have anther method to replace it?
+ * received byte. Here we just reset the FIFO pointer and skip the
+ * writecnt.
+ * It would be possible to increase the FIFO pointer by one instead
+ * of reading and discarding one byte from the FIFO.
+ * The FIFO is implemented on top of an 8 byte ring buffer and the
+ * buffer is never cleared. For every byte that is shifted out after
+ * the opcode, the FIFO already stores the response from the chip.
+ * Usually, the chip will respond with 0x00 or 0xff.
*/
reset_internal_fifo_pointer();
+ /* Skip the bytes we sent. */
for (count = 0; count < writecnt; count++) {
- cmd = mmio_readb(sb600_spibar + 0xC); /* Skip the byte we send. */
+ cmd = mmio_readb(sb600_spibar + 0xC);
printf_debug("[ %2x]", cmd);
}
- printf_debug("The FIFO pointer 6 is %d.\n", mmio_readb(sb600_spibar + 0xd) & 0x07);
+ printf_debug("The FIFO pointer after skipping is %d.\n",
+ mmio_readb(sb600_spibar + 0xd) & 0x07);
for (count = 0; count < readcnt; count++, readarr++) {
*readarr = mmio_readb(sb600_spibar + 0xC);
printf_debug("[%02x]", *readarr);
diff --git a/spi.c b/spi.c
index 8d82c4e..c177fb0 100644
--- a/spi.c
+++ b/spi.c
@@ -367,10 +367,6 @@ uint8_t spi_read_status_register(void)
int ret;
/* Read Status Register */
- if (spi_controller == SPI_CONTROLLER_SB600) { /* FIXME */
- /* Workaround for SB600 hardware bug. Can be killed later. */
- return sb600_read_status_register();
- }
ret = spi_send_command(sizeof(cmd), sizeof(readarr), cmd, readarr);
if (ret)
fprintf(stderr, "RDSR failed!\n");
OpenPOWER on IntegriCloud