summaryrefslogtreecommitdiff
path: root/chip/g/spi_master.c
diff options
context:
space:
mode:
authorNick Sanders <nsanders@chromium.org>2017-02-03 11:54:22 -0800
committerchrome-bot <chrome-bot@chromium.org>2017-05-12 03:25:39 -0700
commit8df3b161e946b2b9aaa5e475766864d3fdb2a9ca (patch)
tree9bdd6dba80502c56582008c22a2bb78117fd4d0d /chip/g/spi_master.c
parent44b9f9df83b3c54b46eb09f593cce32fe822f30a (diff)
downloadchrome-ec-8df3b161e946b2b9aaa5e475766864d3fdb2a9ca.tar.gz
mn50: initial checkin
This firmware supports a board used to initialize firmware on new cr50 parts. BUG=b:36910757 BRANCH=None TEST=boots on scribe board, spi/usb/uart/i2c functionality works. TEST=cr50 boots on reef, CCD EC+AP SPI/UARTS work Change-Id: I48818225393a6fc0db0c30bc79ad9787de608361 Reviewed-on: https://chromium-review.googlesource.com/437627 Commit-Ready: Nick Sanders <nsanders@chromium.org> Tested-by: Nick Sanders <nsanders@chromium.org> Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
Diffstat (limited to 'chip/g/spi_master.c')
-rw-r--r--chip/g/spi_master.c32
1 files changed, 25 insertions, 7 deletions
diff --git a/chip/g/spi_master.c b/chip/g/spi_master.c
index a602c518e5..13d8e15b75 100644
--- a/chip/g/spi_master.c
+++ b/chip/g/spi_master.c
@@ -34,6 +34,8 @@ int spi_transaction(const struct spi_device_t *spi_device,
int port = spi_device->port;
int rv = EC_SUCCESS;
timestamp_t timeout;
+ int transaction_size = 0;
+ int rxoffset = 0;
/* If SPI0's passthrough is enabled, SPI0 is not available unless the
* SPS's BUSY bit is set. */
@@ -43,11 +45,26 @@ int spi_transaction(const struct spi_device_t *spi_device,
return EC_ERROR_BUSY;
}
- /* Ensure it'll fit inside of the RX and TX buffers. Note that although
- * the buffers are separate, the total transmission size must fit in
- * the rx buffer. */
- if (txlen + rxlen > SPI_BUF_SIZE)
- return EC_ERROR_INVAL;
+ if (rxlen == SPI_READBACK_ALL) {
+ /* Bidirectional SPI sends and receives a bit for each clock.
+ * We'll need to make sure the buffers for RX and TX are equal
+ * and return a bit received for every bit sent.
+ */
+ if (txlen > SPI_BUF_SIZE)
+ return EC_ERROR_INVAL;
+ rxlen = txlen;
+ transaction_size = txlen;
+ rxoffset = 0;
+ } else {
+ /* Ensure it'll fit inside of the RX and TX buffers. Note that
+ * although the buffers are separate, the total transmission
+ * size must fit in the rx buffer.
+ */
+ if (txlen + rxlen > SPI_BUF_SIZE)
+ return EC_ERROR_INVAL;
+ transaction_size = rxlen + txlen;
+ rxoffset = txlen;
+ }
/* Grab the port's mutex. */
mutex_lock(&spi_mutex[port]);
@@ -62,7 +79,7 @@ int spi_transaction(const struct spi_device_t *spi_device,
#endif /* CONFIG_SPI_MASTER_NO_CS_GPIOS */
/* Initiate the transaction. */
- GWRITE_FIELD_I(SPI, port, XACT, SIZE, rxlen + txlen - 1);
+ GWRITE_FIELD_I(SPI, port, XACT, SIZE, transaction_size - 1);
GWRITE_FIELD_I(SPI, port, XACT, START, 1);
/* Wait for the SPI master to finish the transaction. */
@@ -77,7 +94,8 @@ int spi_transaction(const struct spi_device_t *spi_device,
GWRITE_FIELD_I(SPI, port, ISTATE_CLR, TXDONE, 1);
/* Copy the result. */
- memmove(rxdata, &((uint8_t *)GREG32_ADDR_I(SPI, port, RX_DATA))[txlen],
+ memmove(rxdata,
+ &((uint8_t *)GREG32_ADDR_I(SPI, port, RX_DATA))[rxoffset],
rxlen);
err_cs_high: