summaryrefslogtreecommitdiff
path: root/chip/stm32/spi.c
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2013-06-13 20:18:14 -0700
committerChromeBot <chrome-bot@google.com>2013-06-20 13:55:11 -0700
commite74e60c4651111a66380d99683ecd5cf9d7dbfb2 (patch)
tree6c6b5e18a1b41d0a70e5b83c86262909d993a824 /chip/stm32/spi.c
parent4d4facda912767215d485bc83ddfa7ef9c060c2e (diff)
downloadchrome-ec-e74e60c4651111a66380d99683ecd5cf9d7dbfb2.tar.gz
Refactor host command interface to support version 3 packets
This will fix EC flash commands on pit, once the host side (u-boot and cros_ec driver) are upgraded to match. This change is backwards-compatible the EC still supports the existing version 2 protocols for talking to existing AP/kernel/ectool. Once the AP-side supports version 3 for SPI (and existing systems are upgraded), we will remove older SPI support since we haven't shipped a product which uses SPI. BUG=chrome-os-partner:20257 BRANCH=none TEST=disable cros_ec driver support in ectool; 'ectool hello' works on link And with an old ectool which predates this CL, 'ectool hello' also works. On pit, from u-boot prompt, 'crosec test' and 'crosec version' work, and keyboard works. Change-Id: I01f193e316e9aa442fe50d632dc8a4681723e282 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/58908 Reviewed-by: Simon Glass <sjg@chromium.org> Commit-Queue: Doug Anderson <dianders@chromium.org>
Diffstat (limited to 'chip/stm32/spi.c')
-rw-r--r--chip/stm32/spi.c102
1 files changed, 100 insertions, 2 deletions
diff --git a/chip/stm32/spi.c b/chip/stm32/spi.c
index f488eee801..51a8e50cfd 100644
--- a/chip/stm32/spi.c
+++ b/chip/stm32/spi.c
@@ -52,6 +52,8 @@ enum {
* We allow a preamble and a header byte so that SPI can function at all.
* We also add an 8-bit length so that we can tell that we got the whole
* message, since the master decides how many bytes to read.
+ *
+ * TODO: move these constants to ec_commands.h
*/
enum {
/* The bytes which appear before the header in a message */
@@ -85,6 +87,24 @@ static uint8_t in_msg[EC_HOST_PARAM_SIZE + SPI_MSG_PROTO_LEN];
static uint8_t active;
static uint8_t enabled;
static struct host_cmd_handler_args args;
+static struct host_packet spi_packet;
+
+/*
+ * The AP blindly clocks back bytes over the SPI interface looking for the
+ * header bytes. So this preamble must always precede the actual response
+ * packet. The preamble must be 32-bit aligned so that the response buffer is
+ * also 32-bit aligned.
+ *
+ * Really, only HEADER_BYTE2 matters, since the SPI driver ignores everything
+ * until it sees that byte code. Search for "spi-frame-header" in U-boot to
+ * see how that's implemented.
+ */
+static const uint8_t out_preamble[4] = {
+ SPI_MSG_PREAMBLE_BYTE,
+ SPI_MSG_PREAMBLE_BYTE,
+ SPI_MSG_HEADER_BYTE1,
+ SPI_MSG_HEADER_BYTE2, /* This is the byte which matters */
+};
/**
* Wait until we have received a certain number of bytes
@@ -249,6 +269,28 @@ static void spi_send_response(struct host_cmd_handler_args *args)
}
/**
+ * Called to send a response back to the host.
+ *
+ * Some commands can continue for a while. This function is called by
+ * host_command when it completes.
+ *
+ */
+static void spi_send_response_packet(struct host_packet *pkt)
+{
+ struct dma_channel *txdma;
+
+ /* If we are too late, don't bother */
+ if (!active)
+ return;
+
+ /* Transmit the reply */
+ txdma = dma_get_channel(DMAC_SPI1_TX);
+ dma_prepare_tx(&dma_tx_option,
+ sizeof(out_preamble) + pkt->response_size, out_msg);
+ dma_go(txdma);
+}
+
+/**
* Handle an event on the NSS pin
*
* A falling edge of NSS indicates that the master is starting a new
@@ -286,17 +328,73 @@ void spi_event(enum gpio_signal signal)
return;
}
- if (in_msg[0] >= EC_CMD_VERSION0) {
+ if (in_msg[0] == EC_HOST_REQUEST_VERSION) {
+ /* Protocol version 3 */
+ struct ec_host_request *r = (struct ec_host_request *)in_msg;
+ int pkt_size;
+
+ /* Wait for the rest of the command header */
+ if (wait_for_bytes(rxdma, sizeof(*r), nss_reg, nss_mask)) {
+ setup_for_transaction();
+ return;
+ }
+
+ /*
+ * Check how big the packet should be. We can't just wait to
+ * see how much data the host sends, because it will keep
+ * sending dummy data until we respond.
+ */
+ pkt_size = host_request_expected_size(r);
+ if (pkt_size == 0 || pkt_size > sizeof(in_msg)) {
+ setup_for_transaction();
+ return;
+ }
+
+ /* Wait for the packet data */
+ if (wait_for_bytes(rxdma, pkt_size, nss_reg, nss_mask)) {
+ setup_for_transaction();
+ return;
+ }
+
+ spi_packet.send_response = spi_send_response_packet;
+
+ spi_packet.request = in_msg;
+ spi_packet.request_temp = NULL;
+ spi_packet.request_max = sizeof(in_msg);
+ spi_packet.request_size = pkt_size;
+
+ /* Response must start with the preamble */
+ memcpy(out_msg, out_preamble, sizeof(out_preamble));
+ spi_packet.response = out_msg + sizeof(out_preamble);
+ spi_packet.response_max =
+ sizeof(out_msg) - sizeof(out_preamble);
+ spi_packet.response_size = 0;
+
+ spi_packet.driver_result = EC_RES_SUCCESS;
+
+ host_packet_receive(&spi_packet);
+ return;
+
+ } else if (in_msg[0] >= EC_CMD_VERSION0) {
+ /*
+ * Protocol version 2
+ *
+ * TODO: remove once all systems upgraded to version 3 */
args.version = in_msg[0] - EC_CMD_VERSION0;
args.command = in_msg[1];
args.params_size = in_msg[2];
args.params = in_msg + 3;
} else {
+ /*
+ * Protocol version 1
+ *
+ * TODO: remove; nothing sends this. Ignore this packet?
+ * Send back an error response?
+ */
args.version = 0;
args.command = in_msg[0];
args.params = in_msg + 1;
args.params_size = 0;
- args.version = 0;
}
/* Wait for parameters */