summaryrefslogtreecommitdiff
path: root/chip
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2021-06-18 11:27:23 -0700
committerCommit Bot <commit-bot@chromium.org>2021-06-29 18:58:37 +0000
commite2655cb43fdc938d467018ccd5c3df9fb907c400 (patch)
tree51d4f02fa4d520e35c040136b3f49fc93cc67a36 /chip
parentc6b0971daa407213edc1f8ccc48a49994036c4d5 (diff)
downloadchrome-ec-e2655cb43fdc938d467018ccd5c3df9fb907c400.tar.gz
g: spi_controller: add the subtransaction capability
It is necessary to be able to send SPI transactions with sizes exceeding the SPI controller buffer size. This can be achieved by asserting CS before sending the first batch (data block) in a transaction and deasserting CS after the last batch. Let's add a SPI controller spi_sub_transaction() API, with an additional parameter indicating when the last batch is submitted for processing. The existing spi_transaction() API becomes a wrapper which always calls spi_sub_transaction() to send a full single batch transaction. BUG=b:79492818 TEST='flashrom --flash-name' still succeeds. Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Change-Id: Ia0c5114edd5caf6c6d0e22cab3bfa3c4d86ac79a Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2977964 Reviewed-by: Mary Ruthven <mruthven@chromium.org>
Diffstat (limited to 'chip')
-rw-r--r--chip/g/spi_controller.c42
1 files changed, 29 insertions, 13 deletions
diff --git a/chip/g/spi_controller.c b/chip/g/spi_controller.c
index 912520e52f..4f7a5ee512 100644
--- a/chip/g/spi_controller.c
+++ b/chip/g/spi_controller.c
@@ -33,10 +33,12 @@ static enum spi_clock_mode clock_mode[SPI_NUM_PORTS];
* The Cr50 SPI controller is not DMA auto-fill/drain capable, so async and
* flush are not defined on purpose.
*/
-int spi_transaction(const struct spi_device_t *spi_device,
- const uint8_t *txdata, int txlen,
- uint8_t *rxdata, int rxlen)
+int spi_sub_transaction(const struct spi_device_t *spi_device,
+ const uint8_t *txdata, int txlen, uint8_t *rxdata,
+ int rxlen, bool deassert_cs)
{
+ static bool cs_asserted;
+
int port = spi_device->port;
int rv = EC_SUCCESS;
timestamp_t timeout;
@@ -74,8 +76,9 @@ int spi_transaction(const struct spi_device_t *spi_device,
rxoffset = txlen;
}
- /* Grab the port's mutex. */
- mutex_lock(&spi_mutex[port]);
+ if (!cs_asserted)
+ /* Grab the port's mutex. */
+ mutex_lock(&spi_mutex[port]);
#ifdef CONFIG_STREAM_SIGNATURE
/*
@@ -88,10 +91,13 @@ int spi_transaction(const struct spi_device_t *spi_device,
/* Copy the txdata into the 128B Transmit Buffer. */
memmove((uint8_t *)GREG32_ADDR_I(SPI, port, TX_DATA), txdata, txlen);
+ if (!cs_asserted) {
#ifndef CONFIG_SPI_CONTROLLER_NO_CS_GPIOS
- /* Drive chip select low. */
- gpio_set_level(spi_device->gpio_cs, 0);
-#endif /* CONFIG_SPI_CONTROLLER_NO_CS_GPIOS */
+ /* Drive chip select low. */
+ gpio_set_level(spi_device->gpio_cs, 0);
+#endif
+ cs_asserted = true;
+ }
/* Initiate the transaction. */
GWRITE_FIELD_I(SPI, port, ISTATE_CLR, TXDONE, 1);
@@ -120,16 +126,26 @@ int spi_transaction(const struct spi_device_t *spi_device,
rxlen);
err_cs_high:
+ if ((rv != EC_SUCCESS) || deassert_cs) {
#ifndef CONFIG_SPI_CONTROLLER_NO_CS_GPIOS
- /* Drive chip select high. */
- gpio_set_level(spi_device->gpio_cs, 1);
+ /* Drive chip select high. */
+ gpio_set_level(spi_device->gpio_cs, 1);
#endif /* CONFIG_SPI_CONTROLLER_NO_CS_GPIOS */
-
- /* Release the port's mutex. */
- mutex_unlock(&spi_mutex[port]);
+ cs_asserted = false;
+ /* Release the port's mutex. */
+ mutex_unlock(&spi_mutex[port]);
+ }
return rv;
}
+int spi_transaction(const struct spi_device_t *spi_device,
+ const uint8_t *txdata, int txlen, uint8_t *rxdata,
+ int rxlen)
+{
+ return spi_sub_transaction(spi_device, txdata, txlen, rxdata, rxlen,
+ true);
+}
+
/*
* Configure the SPI port's clock mode. The SPI port must be re-enabled after
* changing the clocking mode.