diff options
author | Bill Richardson <wfrichar@chromium.org> | 2015-07-10 15:37:20 -0700 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-07-14 00:51:10 +0000 |
commit | 7070b426825a0857c4bf55e29c824181bfd25af7 (patch) | |
tree | a053979f115a95e84c347342e802477ceea0c472 /chip | |
parent | 693bf0e40b72665c1d72c8397bb9acf3f59e7b45 (diff) | |
download | chrome-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.mk | 1 | ||||
-rw-r--r-- | chip/g/sps.c | 18 | ||||
-rw-r--r-- | chip/g/sps.h | 5 | ||||
-rw-r--r-- | chip/g/sps_test.c | 172 |
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); |