summaryrefslogtreecommitdiff
path: root/drivers/spi/ich.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/ich.c')
-rw-r--r--drivers/spi/ich.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c
index fa05a9a6ea0..7a168e9310c 100644
--- a/drivers/spi/ich.c
+++ b/drivers/spi/ich.c
@@ -85,6 +85,7 @@ typedef struct ich_spi_controller {
uint8_t *opmenu;
int menubytes;
+ uint16_t *preop;
uint16_t *optype;
uint32_t *addr;
uint8_t *data;
@@ -343,6 +344,7 @@ void spi_init(void)
cntlr.status = (uint8_t *)&ich7_spi->spis;
cntlr.control = &ich7_spi->spic;
cntlr.bbar = &ich7_spi->bbar;
+ cntlr.preop = &ich7_spi->preop;
break;
}
case 9:
@@ -360,6 +362,7 @@ void spi_init(void)
cntlr.status = &ich9_spi->ssfs;
cntlr.control = (uint16_t *)ich9_spi->ssfc;
cntlr.bbar = &ich9_spi->bbar;
+ cntlr.preop = &ich9_spi->preop;
break;
}
default:
@@ -590,9 +593,23 @@ int spi_xfer(struct spi_slave *slave, const void *dout,
if ((with_address = spi_setup_offset(&trans)) < 0)
return -1;
+ if (!ichspi_lock && trans.opcode == 0x06) {
+ /*
+ * Treat Write Enable as Atomic Pre-Op if possible
+ * in order to prevent the Management Engine from
+ * issuing a transaction between WREN and DATA.
+ */
+ writew_(trans.opcode, cntlr.preop);
+ return 0;
+ }
+
/* Preset control fields */
control = SPIC_SCGO | ((opcode_index & 0x07) << 4);
+ /* Issue atomic preop cycle if needed */
+ if (readw_(cntlr.preop))
+ control |= SPIC_ACS;
+
if (!trans.bytesout && !trans.bytesin) {
/*
* This is a 'no data' command (like Write Enable), its
@@ -676,5 +693,9 @@ int spi_xfer(struct spi_slave *slave, const void *dout,
trans.offset += data_length;
}
}
+
+ /* Clear atomic preop now that xfer is done */
+ writew_(0, cntlr.preop);
+
return 0;
}