diff options
author | Vadim Bendebury <vbendeb@chromium.org> | 2021-06-18 11:27:23 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-10-19 22:24:14 +0000 |
commit | 35e5bfd701834596a2c2cdd9eb63e7e2c2c9f45f (patch) | |
tree | bfd9d569c41fe44abb6c3e383aeafb172579ca78 | |
parent | b53ed419205dd624922d9f18e8a6b16c7d8a2f27 (diff) | |
download | chrome-ec-35e5bfd701834596a2c2cdd9eb63e7e2c2c9f45f.tar.gz |
Reland "g: spi_controller: add the subtransaction capability"
This is a reland of 87e229413d52a4c2b7cca7e1aede3a8dcb5532c1
Original change's description:
> 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>
> (cherry picked from commit e2655cb43fdc938d467018ccd5c3df9fb907c400)
> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3004086
> Reviewed-by: Andrey Pronin <apronin@chromium.org>
> Tested-by: Mary Ruthven <mruthven@chromium.org>
> Commit-Queue: Mary Ruthven <mruthven@chromium.org>
Bug: b:79492818
Change-Id: Ib04478faf626c26800235e27d77f13f41286f1fb
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3229784
Reviewed-by: Andrey Pronin <apronin@chromium.org>
Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
Tested-by: Mary Ruthven <mruthven@chromium.org>
Commit-Queue: Mary Ruthven <mruthven@chromium.org>
-rw-r--r-- | chip/g/spi_controller.c | 42 | ||||
-rw-r--r-- | include/spi.h | 23 |
2 files changed, 52 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. diff --git a/include/spi.h b/include/spi.h index f5a06b54e5..589dc5b551 100644 --- a/include/spi.h +++ b/include/spi.h @@ -85,6 +85,29 @@ int spi_transaction(const struct spi_device_t *spi_device, const uint8_t *txdata, int txlen, uint8_t *rxdata, int rxlen); +/* Issue a part of SPI transaction. Assumes SPI port has already been enabled. + * + * If CS is not asserted, asserts it first. + * Transmits <txlen> bytes from <txdata>, throwing away the corresponding + * received data, then transmits <rxlen> unused bytes, saving the received data + * in <rxdata>. + * If SPI_READBACK_ALL is set in <rxlen>, the received data during transmission + * is recorded in rxdata buffer and it assumes that the real <rxlen> is equal + * to <txlen>. + * If 'final' is true, deasserts CS once transfer is completed. + * + * @param spi_device the SPI device to use + * @param txdata buffer to transmit + * @param txlen number of bytes in txdata. + * @param rxdata receive buffer. + * @param rxlen number of bytes in rxdata or SPI_READBACK_ALL. + * @param deassert_cs flag indicating that CS needs to be deasserted in the + * end of this sub transaction. + */ +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); + /* Similar to spi_transaction(), but hands over to DMA for reading response. * Must call spi_transaction_flush() after this to make sure the response is * received. |