diff options
author | Nick Sanders <nsanders@chromium.org> | 2017-02-03 11:54:22 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-05-12 03:25:39 -0700 |
commit | 8df3b161e946b2b9aaa5e475766864d3fdb2a9ca (patch) | |
tree | 9bdd6dba80502c56582008c22a2bb78117fd4d0d /chip/g/spi_master.c | |
parent | 44b9f9df83b3c54b46eb09f593cce32fe822f30a (diff) | |
download | chrome-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.c | 32 |
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: |