coreboot-libre-fam15h-rdimm/3rdparty/chromeec/board/twinkie/simpletrace.c

287 lines
7.0 KiB
C
Raw Permalink Normal View History

2024-03-04 11:14:53 +01:00
/* Copyright 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_rx_errors err)
{
if (err == PD_RX_ERR_INVAL)
ccprintf("%T TMOUT\n");
else if (err == PD_RX_ERR_HARD_RESET)
ccprintf("%T HARD-RST\n");
else if (err == PD_RX_ERR_UNSUPPORTED_SOP)
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 */
#ifdef HAS_TASK_SNIFFER
task_set_event(TASK_ID_SNIFFER, 1 << i, 0);
#endif
/* 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;
}
}
}
#ifdef HAS_TASK_SNIFFER
DECLARE_IRQ(STM32_IRQ_COMP, rx_event, 1);
#endif
void trace_packets(void)
{
int head;
uint32_t payload[7];
#ifdef HAS_TASK_SNIFFER
/* 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 &= ~BIT(28);
#endif
/* "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 */
#ifdef HAS_TASK_SNIFFER
sniffer_init();
#endif
}
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 */
#ifdef HAS_TASK_SNIFFER
task_wake(TASK_ID_SNIFFER);
#endif
}