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>
This commit is contained in:
Bill Richardson
2015-07-10 15:37:20 -07:00
committed by ChromeOS Commit Bot
parent 693bf0e40b
commit 7070b42682
4 changed files with 196 additions and 0 deletions

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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 */

172
chip/g/sps_test.c Normal file
View File

@@ -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);