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>
This commit is contained in:
parent
cf5aaaf1d2
commit
3316cf2ff8
|
@ -165,6 +165,9 @@ void OemAgesaSaveMtrr(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flash->spi->rw = SPI_WRITE_FLAG;
|
||||||
|
spi_claim_bus(flash->spi);
|
||||||
|
|
||||||
/* Enable access to AMD RdDram and WrDram extension bits */
|
/* Enable access to AMD RdDram and WrDram extension bits */
|
||||||
msr_data = rdmsr(SYS_CFG);
|
msr_data = rdmsr(SYS_CFG);
|
||||||
msr_data.lo |= SYSCFG_MSR_MtrrFixDramModEn;
|
msr_data.lo |= SYSCFG_MSR_MtrrFixDramModEn;
|
||||||
|
@ -233,6 +236,9 @@ void OemAgesaSaveMtrr(void)
|
||||||
flash->write(flash, nvram_pos, 4, &msr_data.hi);
|
flash->write(flash, nvram_pos, 4, &msr_data.hi);
|
||||||
nvram_pos += 4;
|
nvram_pos += 4;
|
||||||
|
|
||||||
|
flash->spi->rw = SPI_WRITE_FLAG;
|
||||||
|
spi_release_bus(flash->spi);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,6 +279,9 @@ u32 OemAgesaSaveS3Info(S3_DATA_TYPE S3DataType, u32 DataSize, void *Data)
|
||||||
return AGESA_SUCCESS;
|
return AGESA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flash->spi->rw = SPI_WRITE_FLAG;
|
||||||
|
spi_claim_bus(flash->spi);
|
||||||
|
|
||||||
if (S3DataType == S3DataTypeNonVolatile) {
|
if (S3DataType == S3DataTypeNonVolatile) {
|
||||||
flash->erase(flash, S3_DATA_NONVOLATILE_POS, 0x1000);
|
flash->erase(flash, S3_DATA_NONVOLATILE_POS, 0x1000);
|
||||||
} else {
|
} else {
|
||||||
|
@ -287,6 +296,9 @@ u32 OemAgesaSaveS3Info(S3_DATA_TYPE S3DataType, u32 DataSize, void *Data)
|
||||||
flash->write(flash, nvram_pos + pos + 4, sizeof(u32), (u32 *)(Data + nvram_pos));
|
flash->write(flash, nvram_pos + pos + 4, sizeof(u32), (u32 *)(Data + nvram_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flash->spi->rw = SPI_WRITE_FLAG;
|
||||||
|
spi_release_bus(flash->spi);
|
||||||
|
|
||||||
return AGESA_SUCCESS;
|
return AGESA_SUCCESS;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -70,6 +70,7 @@ static int eon_write(struct spi_flash *flash,
|
||||||
page_addr = offset / page_size;
|
page_addr = offset / page_size;
|
||||||
byte_addr = offset % page_size;
|
byte_addr = offset % page_size;
|
||||||
|
|
||||||
|
flash->spi->rw = SPI_WRITE_FLAG;
|
||||||
ret = spi_claim_bus(flash->spi);
|
ret = spi_claim_bus(flash->spi);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n");
|
printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n");
|
||||||
|
|
|
@ -131,6 +131,7 @@ static int gigadevice_write(struct spi_flash *flash, u32 offset,
|
||||||
page_size = min(1 << stm->params->l2_page_size, CONTROLLER_PAGE_LIMIT);
|
page_size = min(1 << stm->params->l2_page_size, CONTROLLER_PAGE_LIMIT);
|
||||||
byte_addr = offset % page_size;
|
byte_addr = offset % page_size;
|
||||||
|
|
||||||
|
flash->spi->rw = SPI_WRITE_FLAG;
|
||||||
ret = spi_claim_bus(flash->spi);
|
ret = spi_claim_bus(flash->spi);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(BIOS_WARNING,
|
printk(BIOS_WARNING,
|
||||||
|
|
|
@ -134,6 +134,7 @@ static int macronix_write(struct spi_flash *flash,
|
||||||
page_size = min(mcx->params->page_size, CONTROLLER_PAGE_LIMIT);
|
page_size = min(mcx->params->page_size, CONTROLLER_PAGE_LIMIT);
|
||||||
byte_addr = offset % page_size;
|
byte_addr = offset % page_size;
|
||||||
|
|
||||||
|
flash->spi->rw = SPI_WRITE_FLAG;
|
||||||
ret = spi_claim_bus(flash->spi);
|
ret = spi_claim_bus(flash->spi);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n");
|
printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n");
|
||||||
|
|
|
@ -147,6 +147,7 @@ static int spansion_write(struct spi_flash *flash,
|
||||||
page_addr = offset / page_size;
|
page_addr = offset / page_size;
|
||||||
byte_addr = offset % page_size;
|
byte_addr = offset % page_size;
|
||||||
|
|
||||||
|
flash->spi->rw = SPI_WRITE_FLAG;
|
||||||
ret = spi_claim_bus(flash->spi);
|
ret = spi_claim_bus(flash->spi);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n");
|
printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n");
|
||||||
|
|
|
@ -69,6 +69,7 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
|
||||||
struct spi_slave *spi = flash->spi;
|
struct spi_slave *spi = flash->spi;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
spi->rw = SPI_READ_FLAG;
|
||||||
spi_claim_bus(spi);
|
spi_claim_bus(spi);
|
||||||
ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len);
|
ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len);
|
||||||
spi_release_bus(spi);
|
spi_release_bus(spi);
|
||||||
|
@ -148,6 +149,7 @@ int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flash->spi->rw = SPI_WRITE_FLAG;
|
||||||
ret = spi_claim_bus(flash->spi);
|
ret = spi_claim_bus(flash->spi);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n");
|
printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n");
|
||||||
|
@ -258,6 +260,7 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spi->rw = SPI_READ_FLAG;
|
||||||
ret = spi_claim_bus(spi);
|
ret = spi_claim_bus(spi);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(BIOS_WARNING, "SF: Failed to claim SPI bus: %d\n", ret);
|
printk(BIOS_WARNING, "SF: Failed to claim SPI bus: %d\n", ret);
|
||||||
|
|
|
@ -153,6 +153,7 @@ sst_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf)
|
||||||
int ret;
|
int ret;
|
||||||
u8 cmd[4];
|
u8 cmd[4];
|
||||||
|
|
||||||
|
flash->spi->rw = SPI_WRITE_FLAG;
|
||||||
ret = spi_claim_bus(flash->spi);
|
ret = spi_claim_bus(flash->spi);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n");
|
printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n");
|
||||||
|
|
|
@ -148,6 +148,7 @@ static int stmicro_write(struct spi_flash *flash,
|
||||||
page_addr = offset / page_size;
|
page_addr = offset / page_size;
|
||||||
byte_addr = offset % page_size;
|
byte_addr = offset % page_size;
|
||||||
|
|
||||||
|
flash->spi->rw = SPI_WRITE_FLAG;
|
||||||
ret = spi_claim_bus(flash->spi);
|
ret = spi_claim_bus(flash->spi);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n");
|
printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n");
|
||||||
|
|
|
@ -117,6 +117,7 @@ static int winbond_write(struct spi_flash *flash,
|
||||||
page_size = min(1 << stm->params->l2_page_size, CONTROLLER_PAGE_LIMIT);
|
page_size = min(1 << stm->params->l2_page_size, CONTROLLER_PAGE_LIMIT);
|
||||||
byte_addr = offset % page_size;
|
byte_addr = offset % page_size;
|
||||||
|
|
||||||
|
flash->spi->rw = SPI_WRITE_FLAG;
|
||||||
ret = spi_claim_bus(flash->spi);
|
ret = spi_claim_bus(flash->spi);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n");
|
printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n");
|
||||||
|
|
|
@ -48,6 +48,9 @@
|
||||||
#define SPI_OPCODE_WREN 0x06
|
#define SPI_OPCODE_WREN 0x06
|
||||||
#define SPI_OPCODE_FAST_READ 0x0b
|
#define SPI_OPCODE_FAST_READ 0x0b
|
||||||
|
|
||||||
|
#define SPI_READ_FLAG 0x01
|
||||||
|
#define SPI_WRITE_FLAG 0x02
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------
|
/*-----------------------------------------------------------------------
|
||||||
* Representation of a SPI slave, i.e. what we're communicating with.
|
* Representation of a SPI slave, i.e. what we're communicating with.
|
||||||
*
|
*
|
||||||
|
@ -55,16 +58,17 @@
|
||||||
*
|
*
|
||||||
* bus: ID of the bus that the slave is attached to.
|
* bus: ID of the bus that the slave is attached to.
|
||||||
* cs: ID of the chip select connected to the slave.
|
* cs: ID of the chip select connected to the slave.
|
||||||
|
* rw: Read or Write flag
|
||||||
*/
|
*/
|
||||||
struct spi_slave {
|
struct spi_slave {
|
||||||
unsigned int bus;
|
unsigned int bus;
|
||||||
unsigned int cs;
|
unsigned int cs;
|
||||||
|
unsigned int rw;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------
|
/*-----------------------------------------------------------------------
|
||||||
* Initialization, must be called once on start up.
|
* Initialization, must be called once on start up.
|
||||||
*
|
*
|
||||||
* TODO: I don't think we really need this.
|
|
||||||
*/
|
*/
|
||||||
void spi_init(void);
|
void spi_init(void);
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,12 @@
|
||||||
#include <device/pci.h>
|
#include <device/pci.h>
|
||||||
#include <device/pci_ops.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 u32 spibar;
|
||||||
|
|
||||||
static void reset_internal_fifo_pointer(void)
|
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)
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void spi_release_bus(struct spi_slave *slave)
|
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)
|
void spi_cs_activate(struct spi_slave *slave)
|
||||||
|
|
|
@ -25,6 +25,13 @@
|
||||||
#include <device/pci.h>
|
#include <device/pci.h>
|
||||||
#include <device/pci_ops.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 u32 spibar;
|
||||||
|
|
||||||
static void reset_internal_fifo_pointer(void)
|
static void reset_internal_fifo_pointer(void)
|
||||||
|
@ -90,13 +97,63 @@ int spi_xfer(struct spi_slave *slave, const void *dout,
|
||||||
|
|
||||||
return 0;
|
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, ®0_val);
|
||||||
|
WriteECmsg (MSG_REG1, AccWidthUint8, ®1_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, ®0_val);
|
||||||
|
WriteECmsg (MSG_REG1, AccWidthUint8, ®1_val);
|
||||||
|
WriteECmsg (MSG_SYS_TO_IMC, AccWidthUint8, &cmd_val);
|
||||||
|
|
||||||
|
WaitForEcLDN9MailboxCmdAck();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int spi_claim_bus(struct spi_slave *slave)
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void spi_release_bus(struct spi_slave *slave)
|
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)
|
void spi_cs_activate(struct spi_slave *slave)
|
||||||
|
|
Loading…
Reference in New Issue