summaryrefslogtreecommitdiff
path: root/src/southbridge
diff options
context:
space:
mode:
authorMartin Roth <martin@se-eng.com>2012-12-05 16:22:54 -0700
committerMarc Jones <marcj303@gmail.com>2012-12-12 22:34:16 +0100
commit3316cf2ff80f379b609115f375f73ef4b9e7d8f4 (patch)
tree451e03092e92a06782e4b058004e123b51c69e58 /src/southbridge
parentcf5aaaf1d25429fa6270c7d91a3e072dcf989079 (diff)
downloadcoreboot-3316cf2ff80f379b609115f375f73ef4b9e7d8f4.tar.xz
Claim the SPI bus before writes if the IMC ROM is present
The SB800 and Hudson now support adding the IMC ROM which runs from the same chip as coreboot. When the IMC is running, write or erase commands sent to the spi bus will fail, and the IMC will die. To fix this, we send a request to the IMC to stop fetching from the SPI rom while we write to it. This process (in one form or another) is required for writes to the SPI bus while the IMC is running. Because the IMC can take up to 500ms to respond every time we claim the bus, this patch tries to keep the number of times we need to do that to a minimum. We only need to claim the bus on writes, and using a counter for the semaphore allows us to call in once to claim the bus at the beginning of a number of transactions and it will stay claimed until we release it at the end of the transactions. Claim() - takes up to 500ms hit claim() - no delay erase() release() claim() - no delay write() release() Release() Change-Id: I4e003c5122a2ed47abce57ab8b92dee6aa4713ed Signed-off-by: Martin Roth <martin@se-eng.com> Reviewed-on: http://review.coreboot.org/1976 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi <patrick@georgi-clan.de>
Diffstat (limited to 'src/southbridge')
-rw-r--r--src/southbridge/amd/agesa/hudson/spi.c25
-rw-r--r--src/southbridge/amd/cimx/sb800/spi.c57
2 files changed, 82 insertions, 0 deletions
diff --git a/src/southbridge/amd/agesa/hudson/spi.c b/src/southbridge/amd/agesa/hudson/spi.c
index 3b54490117..aebe4b5cec 100644
--- a/src/southbridge/amd/agesa/hudson/spi.c
+++ b/src/southbridge/amd/agesa/hudson/spi.c
@@ -25,6 +25,12 @@
#include <device/pci.h>
#include <device/pci_ops.h>
+#if defined (CONFIG_HUDSON_IMC_FWM)
+#include "FchPlatform.h"
+
+static int bus_claimed = 0;
+#endif
+
static u32 spibar;
static void reset_internal_fifo_pointer(void)
@@ -92,11 +98,30 @@ int spi_xfer(struct spi_slave *slave, const void *dout,
}
int spi_claim_bus(struct spi_slave *slave)
{
+#if defined (CONFIG_HUDSON_IMC_FWM)
+
+ if (slave->rw == SPI_WRITE_FLAG) {
+ bus_claimed++;
+ if (bus_claimed == 1)
+ ImcSleep(NULL);
+ }
+#endif
+
return 0;
}
void spi_release_bus(struct spi_slave *slave)
{
+#if defined (CONFIG_HUDSON_IMC_FWM)
+
+ if (slave->rw == SPI_WRITE_FLAG) {
+ bus_claimed--;
+ if (bus_claimed <= 0) {
+ bus_claimed = 0;
+ ImcWakeup(NULL);
+ }
+ }
+#endif
}
void spi_cs_activate(struct spi_slave *slave)
diff --git a/src/southbridge/amd/cimx/sb800/spi.c b/src/southbridge/amd/cimx/sb800/spi.c
index 3b54490117..46cc7419ba 100644
--- a/src/southbridge/amd/cimx/sb800/spi.c
+++ b/src/southbridge/amd/cimx/sb800/spi.c
@@ -25,6 +25,13 @@
#include <device/pci.h>
#include <device/pci_ops.h>
+#if defined (CONFIG_SB800_IMC_FWM)
+#include "SBPLATFORM.h"
+#include <vendorcode/amd/cimx/sb800/ECfan.h>
+
+static int bus_claimed = 0;
+#endif
+
static u32 spibar;
static void reset_internal_fifo_pointer(void)
@@ -90,13 +97,63 @@ int spi_xfer(struct spi_slave *slave, const void *dout,
return 0;
}
+
+#if defined (CONFIG_SB800_IMC_FWM)
+
+static void ImcSleep(void)
+{
+ u8 cmd_val = 0x96; /* Kick off IMC Mailbox command 96 */
+ u8 reg0_val = 0; /* clear response register */
+ u8 reg1_val = 0xB4; /* request ownership flag */
+
+ WriteECmsg (MSG_REG0, AccWidthUint8, &reg0_val);
+ WriteECmsg (MSG_REG1, AccWidthUint8, &reg1_val);
+ WriteECmsg (MSG_SYS_TO_IMC, AccWidthUint8, &cmd_val);
+
+ WaitForEcLDN9MailboxCmdAck();
+}
+
+
+static void ImcWakeup(void)
+{
+ u8 cmd_val = 0x96; /* Kick off IMC Mailbox command 96 */
+ u8 reg0_val = 0;; /* clear response register */
+ u8 reg1_val = 0xB5; /* release ownership flag */
+
+ WriteECmsg (MSG_REG0, AccWidthUint8, &reg0_val);
+ WriteECmsg (MSG_REG1, AccWidthUint8, &reg1_val);
+ WriteECmsg (MSG_SYS_TO_IMC, AccWidthUint8, &cmd_val);
+
+ WaitForEcLDN9MailboxCmdAck();
+}
+#endif
+
int spi_claim_bus(struct spi_slave *slave)
{
+#if defined (CONFIG_SB800_IMC_FWM)
+
+ if (slave->rw == SPI_WRITE_FLAG) {
+ bus_claimed++;
+ if (bus_claimed == 1)
+ ImcSleep();
+ }
+#endif
+
return 0;
}
void spi_release_bus(struct spi_slave *slave)
{
+#if defined (CONFIG_SB800_IMC_FWM)
+
+ if (slave->rw == SPI_WRITE_FLAG) {
+ bus_claimed--;
+ if (bus_claimed <= 0) {
+ bus_claimed = 0;
+ ImcWakeup();
+ }
+ }
+#endif
}
void spi_cs_activate(struct spi_slave *slave)