summaryrefslogtreecommitdiff
path: root/chip
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2015-07-10 15:37:20 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-07-14 00:51:10 +0000
commit7070b426825a0857c4bf55e29c824181bfd25af7 (patch)
treea053979f115a95e84c347342e802477ceea0c472 /chip
parent693bf0e40b72665c1d72c8397bb9acf3f59e7b45 (diff)
downloadchrome-ec-7070b426825a0857c4bf55e29c824181bfd25af7.tar.gz
Cr50: Restore spstest command
I accidentally removed this when poking around with the SPS driver. This adds it back as a separate file. Enabling CONFIG_SPS_TEST will restore the "spstest" console command to use for low-level driver tests. Note that invoking it will replace any other registered SPS handler. BUG=chrome-os-partner:40969 BRANCH=none TEST=manual Connect the EC to the build host with an FTDI USB-to-SPI adapter. On the EC console, invoke spstest Build and run the external ftdi_dongle test: git clone sso://user/vbendeb/ftdi_dongle cd ftdi_dongle/src make ./examples/spiraw.py -l 10 -f 2000000 Change-Id: Ia6165e3be06d976c59c3e849349da0f7f5006f56 Signed-off-by: Bill Richardson <wfrichar@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/284943 Reviewed-by: Vadim Bendebury <vbendeb@google.com>
Diffstat (limited to 'chip')
-rw-r--r--chip/g/build.mk1
-rw-r--r--chip/g/sps.c18
-rw-r--r--chip/g/sps.h5
-rw-r--r--chip/g/sps_test.c172
4 files changed, 196 insertions, 0 deletions
diff --git a/chip/g/build.mk b/chip/g/build.mk
index 40a9ed2ba8..b45525366f 100644
--- a/chip/g/build.mk
+++ b/chip/g/build.mk
@@ -19,6 +19,7 @@ CPPFLAGS+= -DGC_REVISION="$(ver_str)"
chip-y=clock.o gpio.o hwtimer.o jtag.o system.o uart.o
chip-y+= pmu.o
chip-$(CONFIG_SPI)+= sps.o
+chip-$(CONFIG_SPS_TEST)+=sps_test.o
chip-$(CONFIG_HOSTCMD_SPI)+=sps_hc.o
chip-$(CONFIG_WATCHDOG)+=watchdog.o
diff --git a/chip/g/sps.c b/chip/g/sps.c
index 5e8f1ffc2e..219fc5e8cd 100644
--- a/chip/g/sps.c
+++ b/chip/g/sps.c
@@ -41,6 +41,11 @@ static uint32_t fifo_count(uint32_t readptr, uint32_t writeptr)
#define SPS_TX_FIFO_BASE_ADDR (GBASE(SPS) + 0x1000)
#define SPS_RX_FIFO_BASE_ADDR (SPS_TX_FIFO_BASE_ADDR + SPS_FIFO_SIZE)
+#ifdef CONFIG_SPS_TEST
+/* Statistics counters. Not always present, to save space & time. */
+uint32_t sps_tx_count, sps_rx_count, sps_tx_empty_count, sps_max_rx_batch;
+#endif
+
void sps_tx_status(uint8_t byte)
{
GREG32(SPS, DUMMY_WORD) = byte;
@@ -54,6 +59,11 @@ int sps_transmit(uint8_t *data, size_t data_size)
uint32_t fifo_room;
int bytes_sent;
+#ifdef CONFIG_SPS_TEST
+ if (GREAD_FIELD(SPS, ISTATE, TXFIFO_EMPTY))
+ sps_tx_empty_count++;
+#endif
+
wptr = GREG32(SPS, TXFIFO_WPTR);
rptr = GREG32(SPS, TXFIFO_RPTR);
fifo_room = SPS_FIFO_SIZE - fifo_count(rptr, wptr);
@@ -113,6 +123,9 @@ int sps_transmit(uint8_t *data, size_t data_size)
SPS_TX_FIFO_BASE_ADDR;
}
+#ifdef CONFIG_SPS_TEST
+ sps_tx_count += bytes_sent;
+#endif
return bytes_sent;
}
@@ -224,6 +237,11 @@ static void sps_rx_interrupt(int cs_enabled)
if (sps_rx_handler)
sps_rx_handler(received_data, data_size, cs_enabled);
sps_advance_rx(data_size);
+#ifdef CONFIG_SPS_TEST
+ sps_rx_count += data_size;
+ if (data_size > sps_max_rx_batch)
+ sps_max_rx_batch = data_size;
+#endif
} while (data_size);
}
diff --git a/chip/g/sps.h b/chip/g/sps.h
index c4c96d77df..d10c41dc42 100644
--- a/chip/g/sps.h
+++ b/chip/g/sps.h
@@ -77,4 +77,9 @@ void sps_register_rx_handler(enum spi_clock_mode m_spi,
*/
void sps_unregister_rx_handler(void);
+
+/* Statistics counters, present only with CONFIG_SPS_TEST. */
+extern uint32_t sps_tx_count, sps_rx_count,
+ sps_tx_empty_count, sps_max_rx_batch;
+
#endif /* __CROS_EC_SPS_H */
diff --git a/chip/g/sps_test.c b/chip/g/sps_test.c
new file mode 100644
index 0000000000..d9a8f58c7a
--- /dev/null
+++ b/chip/g/sps_test.c
@@ -0,0 +1,172 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "common.h"
+#include "console.h"
+#include "sps.h"
+#include "timer.h"
+#include "util.h"
+#include "watchdog.h"
+
+/* Function to test SPS driver. It expects the host to send SPI frames of size
+ * <size> (not exceeding 1100) of the following format:
+ *
+ * <size/256> <size%256> [<size> bytes of payload]
+ *
+ * Once the frame is received, it is sent back. The host can receive it and
+ * compare with the original.
+ */
+
+ /*
+ * Receive callback implemets a simple state machine, it could be in one of
+ * three states: not started, receiving frame, frame finished.
+ */
+
+enum sps_test_rx_state {
+ spstrx_not_started,
+ spstrx_receiving,
+ spstrx_finished
+};
+
+static enum sps_test_rx_state rx_state;
+/* Storage for the received frame. Size chosen arbitrarily to match the
+ * external test code. */
+static uint8_t test_frame[1100];
+
+/*
+ * To verify different alignment cases, the frame is saved in the buffer
+ * starting with a certain offset (in range 0..3).
+ */
+static size_t frame_base;
+/*
+ * This is the index of the next location where received data will be added
+ * to. Points to the end of the received frame once it has been pulled in.
+ */
+static size_t frame_index;
+
+static void sps_receive_callback(uint8_t *data, size_t data_size,
+ int cs_enabled)
+{
+ static size_t frame_size; /* Total size of the frame being received. */
+ size_t to_go; /* Number of bytes still to receive. */
+
+ if (rx_state == spstrx_not_started) {
+ if (data_size < 2)
+ return; /* Something went wrong.*/
+
+ frame_size = data[0] * 256 + data[1] + 2;
+ frame_base = (frame_base + 1) % 3;
+ frame_index = frame_base;
+
+ if ((frame_index + frame_size) <= sizeof(test_frame))
+ /* Enter 'receiving frame' state. */
+ rx_state = spstrx_receiving;
+ else
+ /*
+ * If we won't be able to receve this much, enter the
+ * 'frame finished' state.
+ */
+ rx_state = spstrx_finished;
+ }
+
+ if (rx_state == spstrx_finished) {
+ /*
+ * If CS was deasserted, prepare to start receiving the next
+ * frame.
+ */
+ if (!cs_enabled)
+ rx_state = spstrx_not_started;
+ return;
+ }
+
+ if (frame_size > data_size)
+ to_go = data_size;
+ else
+ to_go = frame_size;
+
+ memcpy(test_frame + frame_index, data, to_go);
+ frame_index += to_go;
+ frame_size -= to_go;
+
+ if (!frame_size)
+ rx_state = spstrx_finished; /* Frame finished.*/
+}
+
+static int command_sps(int argc, char **argv)
+{
+ int count = 0;
+ int target = 10; /* Expect 10 frames by default.*/
+ char *e;
+
+ rx_state = spstrx_not_started;
+
+ sps_register_rx_handler(SPI_CLOCK_MODE0, SPS_GENERIC_MODE,
+ sps_receive_callback);
+
+ if (argc > 1) {
+ target = strtoi(argv[1], &e, 10);
+ if (*e)
+ return EC_ERROR_PARAM1;
+ }
+
+ /* reset statistic counters */
+ sps_rx_count = sps_tx_count = 0;
+ sps_tx_empty_count = sps_max_rx_batch = 0;
+
+ while (count++ < target) {
+ size_t transmitted;
+ size_t to_go;
+ size_t index;
+
+ /* Wait for a frame to be received.*/
+ while (rx_state != spstrx_finished) {
+ watchdog_reload();
+ usleep(10);
+ }
+
+ /* Transmit the frame back to the host.*/
+ index = frame_base;
+ to_go = frame_index - frame_base;
+ do {
+ if ((index == frame_base) && (to_go > 8)) {
+ /*
+ * This is the first transmit attempt for this
+ * frame. Send a little just to prime the
+ * transmit FIFO.
+ */
+ transmitted = sps_transmit(
+ test_frame + index, 8);
+ } else {
+ transmitted = sps_transmit(
+ test_frame + index, to_go);
+ }
+ index += transmitted;
+ to_go -= transmitted;
+ } while (to_go);
+
+ /*
+ * Wait for receive state machine to transition out of 'frame
+ * finised' state.
+ */
+ while (rx_state == spstrx_finished) {
+ watchdog_reload();
+ usleep(10);
+ }
+ }
+
+ sps_unregister_rx_handler();
+
+ ccprintf("Processed %d frames\n", count - 1);
+ ccprintf("rx count %d, tx count %d, tx_empty %d, max rx batch %d\n",
+ sps_rx_count, sps_tx_count,
+ sps_tx_empty_count, sps_max_rx_batch);
+
+ return EC_SUCCESS;
+}
+
+DECLARE_CONSOLE_COMMAND(spstest, command_sps,
+ "<num of frames>",
+ "Loop back frames (10 by default) back to the host",
+ NULL);