diff options
author | Vincent Palatin <vpalatin@chromium.org> | 2014-12-20 18:03:47 -0800 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-04-10 23:29:31 +0000 |
commit | 15391709fd964e23d91deaf3db832a9d83da1ea5 (patch) | |
tree | 16c9bbcc696f810c7fbe2fc96f0cae9b901ccf72 /board/twinkie/simpletrace.c | |
parent | 686a23585e2bc8a357842bd30ea3cae0cc5648da (diff) | |
download | chrome-ec-15391709fd964e23d91deaf3db832a9d83da1ea5.tar.gz |
twinkie: add simple text tracing mechanism
When using the Twinkie dongle without a protocol decoder on the host,
add a simple text tracing mechanism, so the user can get the timestamped traces
of the packets on the wire (in a best effort fashion).
Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
BRANCH=none
BUG=none
TEST=On Twinkie command-line, type "tw trace on"
then plug a DingDong to Samus through Twinkie and
see the PD message traces on the console.
Change-Id: I4fa35d6783cc6279c95209c86f37e6d717de7301
Reviewed-on: https://chromium-review.googlesource.com/237222
Reviewed-by: Alec Berg <alecaberg@chromium.org>
Reviewed-by: Todd Broch <tbroch@chromium.org>
Trybot-Ready: Vincent Palatin <vpalatin@chromium.org>
Tested-by: Vincent Palatin <vpalatin@chromium.org>
Commit-Queue: Vincent Palatin <vpalatin@chromium.org>
Diffstat (limited to 'board/twinkie/simpletrace.c')
-rw-r--r-- | board/twinkie/simpletrace.c | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/board/twinkie/simpletrace.c b/board/twinkie/simpletrace.c new file mode 100644 index 0000000000..f3ff5d3487 --- /dev/null +++ b/board/twinkie/simpletrace.c @@ -0,0 +1,276 @@ +/* Copyright (c) 2014 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 "adc.h" +#include "common.h" +#include "console.h" +#include "dma.h" +#include "gpio.h" +#include "hooks.h" +#include "hwtimer.h" +#include "injector.h" +#include "registers.h" +#include "system.h" +#include "task.h" +#include "timer.h" +#include "usb_pd.h" +#include "usb_pd_config.h" +#include "util.h" + +/* PD packet text tracing state : TRACE_MODE_OFF/RAW/ON */ +int trace_mode; + +/* The FSM is waiting for the following command (0 == None) */ +uint8_t expected_cmd; + +static const char * const ctrl_msg_name[] = { + [0] = "RSVD-C0", + [PD_CTRL_GOOD_CRC] = "GOODCRC", + [PD_CTRL_GOTO_MIN] = "GOTOMIN", + [PD_CTRL_ACCEPT] = "ACCEPT", + [PD_CTRL_REJECT] = "REJECT", + [PD_CTRL_PING] = "PING", + [PD_CTRL_PS_RDY] = "PSRDY", + [PD_CTRL_GET_SOURCE_CAP] = "GSRCCAP", + [PD_CTRL_GET_SINK_CAP] = "GSNKCAP", + [PD_CTRL_DR_SWAP] = "DRSWAP", + [PD_CTRL_PR_SWAP] = "PRSWAP", + [PD_CTRL_VCONN_SWAP] = "VCONNSW", + [PD_CTRL_WAIT] = "WAIT", + [PD_CTRL_SOFT_RESET] = "SFT-RST", + [14] = "RSVD-C14", + [15] = "RSVD-C15", +}; + +static const char * const data_msg_name[] = { + [0] = "RSVD-D0", + [PD_DATA_SOURCE_CAP] = "SRCCAP", + [PD_DATA_REQUEST] = "REQUEST", + [PD_DATA_BIST] = "BIST", + [PD_DATA_SINK_CAP] = "SNKCAP", + /* 5-14 Reserved */ + [PD_DATA_VENDOR_DEF] = "VDM", +}; + +static const char * const svdm_cmd_name[] = { + [CMD_DISCOVER_IDENT] = "DISCID", + [CMD_DISCOVER_SVID] = "DISCSVID", + [CMD_DISCOVER_MODES] = "DISCMODE", + [CMD_ENTER_MODE] = "ENTER", + [CMD_EXIT_MODE] = "EXIT", + [CMD_ATTENTION] = "ATTN", + [CMD_DP_STATUS] = "DPSTAT", + [CMD_DP_CONFIG] = "DPCFG", +}; + +static const char * const svdm_cmdt_name[] = { + [CMDT_INIT] = "INI", + [CMDT_RSP_ACK] = "ACK", + [CMDT_RSP_NAK] = "NAK", + [CMDT_RSP_BUSY] = "BSY", +}; + +static void print_pdo(uint32_t word) +{ + if ((word & PDO_TYPE_MASK) == PDO_TYPE_BATTERY) + ccprintf(" %dmV/%dmW", ((word>>10)&0x3ff)*50, + (word&0x3ff)*250); + else + ccprintf(" %dmV/%dmA", ((word>>10)&0x3ff)*50, + (word&0x3ff)*10); +} + +static void print_rdo(uint32_t word) +{ + ccprintf("{%d} %08x", RDO_POS(word), word); +} + +static void print_vdo(int idx, uint32_t word) +{ + if (idx == 0 && (word & VDO_SVDM_TYPE)) { + const char *cmd = svdm_cmd_name[PD_VDO_CMD(word)]; + const char *cmdt = svdm_cmdt_name[PD_VDO_CMDT(word)]; + uint16_t vid = PD_VDO_VID(word); + if (!cmd) + cmd = "????"; + ccprintf(" V%04x:%s,%s:%08x", vid, cmd, cmdt, word); + } else { + ccprintf(" %08x", word); + } +} + +static void print_packet(int head, uint32_t *payload) +{ + int i; + int cnt = PD_HEADER_CNT(head); + int typ = PD_HEADER_TYPE(head); + int id = PD_HEADER_ID(head); + const char *name; + const char *prole; + + if (trace_mode == TRACE_MODE_RAW) { + ccprintf("%T[%04x]", head); + for (i = 0; i < cnt; i++) + ccprintf(" %08x", payload[i]); + ccputs("\n"); + return; + } + name = cnt ? data_msg_name[typ] : ctrl_msg_name[typ]; + prole = head & (PD_ROLE_SOURCE << 8) ? "SRC" : "SNK"; + ccprintf("%T %s/%d [%04x]%s", prole, id, head, name); + if (!cnt) { /* Control message : we are done */ + ccputs("\n"); + return; + } + /* Print payload for data message */ + for (i = 0; i < cnt; i++) + switch (typ) { + case PD_DATA_SOURCE_CAP: + case PD_DATA_SINK_CAP: + print_pdo(payload[i]); + break; + case PD_DATA_REQUEST: + print_rdo(payload[i]); + break; + case PD_DATA_BIST: + ccprintf("mode %d cnt %04x", payload[i] >> 28, + payload[i] & 0xffff); + break; + case PD_DATA_VENDOR_DEF: + print_vdo(i, payload[i]); + break; + default: + ccprintf(" %08x", payload[i]); + } + ccputs("\n"); +} + +static void print_error(enum pd_errors err) +{ + if (err == PD_ERR_INVAL) + ccprintf("%T TMOUT\n"); + else if (err == PD_ERR_HARD_RESET) + ccprintf("%T HARD-RST\n"); + else if (err == -5) + ccprintf("%T SOP*\n"); + else + ccprintf("ERR %d\n", err); +} + +/* keep track of RX edge timing in order to trigger receive */ +static timestamp_t rx_edge_ts[2][PD_RX_TRANSITION_COUNT]; +static int rx_edge_ts_idx[2]; + +void rx_event(void) +{ + int pending, i; + int next_idx; + pending = STM32_EXTI_PR; + + /* Iterate over the 2 CC lines */ + for (i = 0; i < 2; i++) { + if (pending & (1 << (21 + i))) { + rx_edge_ts[i][rx_edge_ts_idx[i]].val = get_time().val; + next_idx = (rx_edge_ts_idx[i] == + PD_RX_TRANSITION_COUNT - 1) ? + 0 : rx_edge_ts_idx[i] + 1; + + /* + * If we have seen enough edges in a certain amount of + * time, then trigger RX start. + */ + if ((rx_edge_ts[i][rx_edge_ts_idx[i]].val - + rx_edge_ts[i][next_idx].val) + < PD_RX_TRANSITION_WINDOW) { + /* acquire the message only on the active CC */ + STM32_COMP_CSR &= ~(i ? STM32_COMP_CMP1EN + : STM32_COMP_CMP2EN); + /* start sampling */ + pd_rx_start(0); + /* + * ignore the comparator IRQ until we are done + * with current message + */ + pd_rx_disable_monitoring(0); + /* trigger the analysis in the task */ + task_set_event(TASK_ID_SNIFFER, 1 << i, 0); + /* start reception only one CC line */ + break; + } else { + /* do not trigger RX start, just clear int */ + STM32_EXTI_PR = EXTI_COMP_MASK(0); + } + rx_edge_ts_idx[i] = next_idx; + } + } +} +DECLARE_IRQ(STM32_IRQ_COMP, rx_event, 1); + +void trace_packets(void) +{ + int head; + uint32_t payload[7]; + + /* Disable sniffer DMA configuration */ + dma_disable(STM32_DMAC_CH6); + dma_disable(STM32_DMAC_CH7); + task_disable_irq(STM32_IRQ_DMA_CHANNEL_4_7); + /* remove TIM1 CH1/2/3 DMA remapping */ + STM32_SYSCFG_CFGR1 &= ~(1 << 28); + + /* "classical" PD RX configuration */ + pd_hw_init_rx(0); + pd_select_polarity(0, 0); + /* detect messages on both CCx lines */ + STM32_COMP_CSR |= STM32_COMP_CMP2EN | STM32_COMP_CMP1EN; + /* Enable the RX interrupts */ + pd_rx_enable_monitoring(0); + + while (1) { + task_wait_event(-1); + if (trace_mode == TRACE_MODE_OFF) + break; + /* incoming packet processing */ + head = pd_analyze_rx(0, payload); + pd_rx_complete(0); + /* re-enabled detection on both CCx lines */ + STM32_COMP_CSR |= STM32_COMP_CMP2EN | STM32_COMP_CMP1EN; + pd_rx_enable_monitoring(0); + /* print the last packet content */ + if (head > 0) + print_packet(head, payload); + else + print_error(head); + if (head > 0 && expected_cmd == PD_HEADER_TYPE(head)) + task_wake(TASK_ID_CONSOLE); + } + + task_disable_irq(STM32_IRQ_COMP); + /* Disable tracer DMA configuration */ + dma_disable(STM32_DMAC_CH2); + /* Put back : sniffer RX hardware configuration */ + sniffer_init(); +} + +int expect_packet(int pol, uint8_t cmd, uint32_t timeout_us) +{ + uint32_t evt; + + expected_cmd = cmd; + evt = task_wait_event(timeout_us); + + return !(evt == TASK_EVENT_TIMER); +} + +void set_trace_mode(int mode) +{ + /* No change */ + if (mode == trace_mode) + return; + + trace_mode = mode; + /* kick the task to take into account the new value */ + task_wake(TASK_ID_SNIFFER); +} |