summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2014-12-20 18:03:47 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-04-10 23:29:31 +0000
commit15391709fd964e23d91deaf3db832a9d83da1ea5 (patch)
tree16c9bbcc696f810c7fbe2fc96f0cae9b901ccf72
parent686a23585e2bc8a357842bd30ea3cae0cc5648da (diff)
downloadchrome-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>
-rw-r--r--board/twinkie/board.h12
-rw-r--r--board/twinkie/build.mk2
-rw-r--r--board/twinkie/injector.c34
-rw-r--r--board/twinkie/injector.h9
-rw-r--r--board/twinkie/simpletrace.c276
-rw-r--r--board/twinkie/sniffer.c37
-rw-r--r--board/twinkie/usb_pd_config.h7
-rw-r--r--chip/stm32/usb_pd_phy.c113
-rw-r--r--common/usb_pd_protocol.c8
-rw-r--r--include/usb_pd.h20
10 files changed, 452 insertions, 66 deletions
diff --git a/board/twinkie/board.h b/board/twinkie/board.h
index b748104ad2..992eeb83f1 100644
--- a/board/twinkie/board.h
+++ b/board/twinkie/board.h
@@ -27,6 +27,8 @@
#ifndef HAS_TASK_PD /* PD sniffer mode */
#undef CONFIG_DMA_DEFAULT_HANDLERS
#define CONFIG_USB_PD_TX_PHY_ONLY
+/* override the comparator interrupt handler */
+#undef CONFIG_USB_PD_RX_COMP_IRQ
#endif
#define CONFIG_ADC
@@ -53,9 +55,17 @@
#ifndef __ASSEMBLER__
+void sniffer_init(void);
+
int wait_packet(int pol, uint32_t min_edges, uint32_t timeout_us);
-void recording_enable(uint8_t mask);
+int expect_packet(int pol, uint8_t cmd, uint32_t timeout_us);
+
+uint8_t recording_enable(uint8_t mask);
+
+void trace_packets(void);
+
+void set_trace_mode(int mode);
/* Timer selection */
#define TIM_CLOCK_MSB 3
diff --git a/board/twinkie/build.mk b/board/twinkie/build.mk
index ca503a7095..8179cbaaf3 100644
--- a/board/twinkie/build.mk
+++ b/board/twinkie/build.mk
@@ -11,4 +11,4 @@ CHIP_FAMILY:=stm32f0
CHIP_VARIANT:=stm32f07x
board-y=board.o usb_pd_policy.o
-board-$(HAS_TASK_SNIFFER)+=sniffer.o injector.o
+board-$(HAS_TASK_SNIFFER)+=sniffer.o injector.o simpletrace.o
diff --git a/board/twinkie/injector.c b/board/twinkie/injector.c
index 916bc1c65e..6c5116c9e6 100644
--- a/board/twinkie/injector.c
+++ b/board/twinkie/injector.c
@@ -189,6 +189,13 @@ static void fsm_wait(uint32_t w)
wait_packet(inj_polarity, min_edges, timeout_ms * 1000);
}
+static void fsm_expect(uint32_t w)
+{
+ uint32_t timeout_ms = INJ_ARG0(w);
+ uint8_t cmd = INJ_ARG2(w);
+
+ expect_packet(inj_polarity, cmd, timeout_ms * 1000);
+}
static void fsm_get(uint32_t w)
{
int store_idx = INJ_ARG0(w);
@@ -243,6 +250,9 @@ static void fsm_set(uint32_t w)
case INJ_SET_POLARITY:
inj_polarity = guess_polarity(val);
break;
+ case INJ_SET_TRACE:
+ set_trace_mode(val);
+ break;
default:
/* Do nothing */
break;
@@ -278,6 +288,9 @@ static int fsm_run(int index)
case INJ_CMD_JUMP:
index = INJ_ARG0(w);
continue; /* do not increment index */
+ case INJ_CMD_EXPCT:
+ fsm_expect(w);
+ break;
case INJ_CMD_NOP:
default:
/* Do nothing */
@@ -502,6 +515,25 @@ static int cmd_sink(int argc, char **argv)
return EC_SUCCESS;
}
+static int cmd_trace(int argc, char **argv)
+{
+ if (argc < 1)
+ return EC_ERROR_PARAM_COUNT;
+
+ if (!strcasecmp(argv[0], "on") ||
+ !strcasecmp(argv[0], "1"))
+ set_trace_mode(TRACE_MODE_ON);
+ else if (!strcasecmp(argv[0], "raw"))
+ set_trace_mode(TRACE_MODE_RAW);
+ else if (!strcasecmp(argv[0], "off") ||
+ !strcasecmp(argv[0], "0"))
+ set_trace_mode(TRACE_MODE_OFF);
+ else
+ return EC_ERROR_PARAM2;
+
+ return EC_SUCCESS;
+}
+
static int command_tw(int argc, char **argv)
{
if (!strcasecmp(argv[1], "send"))
@@ -518,6 +550,8 @@ static int command_tw(int argc, char **argv)
return cmd_resistor(argc - 2, argv + 2);
else if (!strcasecmp(argv[1], "sink"))
return cmd_sink(argc - 2, argv + 2);
+ else if (!strcasecmp(argv[1], "trace"))
+ return cmd_trace(argc - 2, argv + 2);
else if (!strcasecmp(argv[1], "txclock"))
return cmd_tx_clock(argc - 2, argv + 2);
else if (!strncasecmp(argv[1], "rxthresh", 8))
diff --git a/board/twinkie/injector.h b/board/twinkie/injector.h
index 0e360a2fdc..11c3c095f2 100644
--- a/board/twinkie/injector.h
+++ b/board/twinkie/injector.h
@@ -39,6 +39,8 @@ enum inj_cmd {
INJ_CMD_GET = 0x5, /* Get parameter arg1 (INJ_GET_x) at index arg0 */
INJ_CMD_SET = 0x6, /* Set parameter arg1 (INJ_SET_x) with arg0 */
INJ_CMD_JUMP = 0x8, /* Jump to index (as arg0) */
+ INJ_CMD_EXPCT = 0xC, /* Expect a packet with command arg2 */
+ /* and timeout after arg0 ms */
INJ_CMD_NOP = 0xF, /* No-Operation */
};
@@ -49,6 +51,7 @@ enum inj_set {
INJ_SET_TX_SPEED = 3, /* TX frequency is arg0 kHz */
INJ_SET_RX_THRESH = 4, /* RX voltage threshold is arg0 mV */
INJ_SET_POLARITY = 5, /* Polarity for other operations (INJ_POL_CC) */
+ INJ_SET_TRACE = 6, /* Text packet trace on/raw/off */
};
enum inj_get {
@@ -73,6 +76,12 @@ enum inj_pol {
INJ_POL_AUTO = 0xffff,
};
+enum trace_mode {
+ TRACE_MODE_OFF = 0,
+ TRACE_MODE_RAW = 1,
+ TRACE_MODE_ON = 2,
+};
+
/* Number of words in the FSM command/data buffer */
#define INJ_CMD_COUNT 128
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);
+}
diff --git a/board/twinkie/sniffer.c b/board/twinkie/sniffer.c
index f08bd8b68b..dfbf6d131d 100644
--- a/board/twinkie/sniffer.c
+++ b/board/twinkie/sniffer.c
@@ -11,6 +11,7 @@
#include "gpio.h"
#include "hwtimer.h"
#include "hooks.h"
+#include "injector.h"
#include "link_defs.h"
#include "registers.h"
#include "task.h"
@@ -29,6 +30,9 @@
/* Task event for the USB transfer interrupt */
#define USB_EVENTS TASK_EVENT_CUSTOM(3)
+/* Bitmap of enabled capture channels : CC1+CC2 by default */
+static uint8_t channel_mask = 0x3;
+
/* edge timing samples */
static uint8_t samples[2][RX_COUNT];
/* bitmap of the samples sub-buffer filled with DMA data */
@@ -233,7 +237,7 @@ static void rx_timer_init(int tim_id, timer_ctlr_t *tim, int ch_idx, int up_idx)
tim->sr = 0;
}
-static void sniffer_init(void)
+void sniffer_init(void)
{
/* remap TIM1 CH1/2/3 to DMA channel 6 */
STM32_SYSCFG_CFGR1 |= 1 << 28;
@@ -255,8 +259,6 @@ static void sniffer_init(void)
STM32_COMP_CMP2INSEL_VREF12 |
STM32_COMP_CMP2OUTSEL_TIM2_IC4 |
STM32_COMP_CMP2HYST_HI;
- ccprintf("Sniffer initialized\n");
-
/* start sampling the edges on the CC lines using the RX timers */
dma_start_rx(&dma_tim_cc1, RX_COUNT, samples[0]);
@@ -268,6 +270,9 @@ static void sniffer_init(void)
}
DECLARE_HOOK(HOOK_INIT, sniffer_init, HOOK_PRIO_DEFAULT);
+/* state of the simple text tracer */
+extern int trace_mode;
+
/* Task to post-process the samples and copy them the USB endpoint buffer */
void sniffer_task(void)
{
@@ -296,6 +301,12 @@ void sniffer_task(void)
atomic_clear((uint32_t *)&filled_dma, 1 << d);
}
led_reset_record();
+
+ if (trace_mode != TRACE_MODE_OFF) {
+ uint8_t curr = recording_enable(0);
+ trace_packets();
+ recording_enable(curr);
+ }
}
}
@@ -333,9 +344,25 @@ int wait_packet(int pol, uint32_t min_edges, uint32_t timeout_us)
return (__hw_clock_source_read() - t0 > timeout_us);
}
-void recording_enable(uint8_t mask)
+uint8_t recording_enable(uint8_t new_mask)
{
- /* TODO implement */
+ uint8_t old_mask = channel_mask;
+ uint8_t diff = channel_mask ^ new_mask;
+ /* start/stop RX timers according to the channel mask */
+ if (diff & 1) {
+ if (new_mask & 1)
+ STM32_TIM_CR1(TIM_RX1) |= 1;
+ else
+ STM32_TIM_CR1(TIM_RX1) &= ~1;
+ }
+ if (diff & 2) {
+ if (new_mask & 2)
+ STM32_TIM_CR1(TIM_RX2) |= 1;
+ else
+ STM32_TIM_CR1(TIM_RX2) &= ~1;
+ }
+ channel_mask = new_mask;
+ return old_mask;
}
static void sniffer_sysjump(void)
diff --git a/board/twinkie/usb_pd_config.h b/board/twinkie/usb_pd_config.h
index 466cc40905..6a5e18b128 100644
--- a/board/twinkie/usb_pd_config.h
+++ b/board/twinkie/usb_pd_config.h
@@ -167,11 +167,10 @@ static inline void pd_set_host_mode(int port, int enable)
static inline void pd_config_init(int port, uint8_t power_role)
{
- /*
- * Set CC pull resistors, and charge_en and vbus_en GPIOs to match
- * the initial role.
- */
+#ifndef CONFIG_USB_PD_TX_PHY_ONLY
+ /* Set CC pull resistors */
pd_set_host_mode(port, power_role);
+#endif /* CONFIG_USB_PD_TX_PHY_ONLY */
/* Initialize TX pins and put them in Hi-Z */
pd_tx_init();
diff --git a/chip/stm32/usb_pd_phy.c b/chip/stm32/usb_pd_phy.c
index 36d6228938..1db963c588 100644
--- a/chip/stm32/usb_pd_phy.c
+++ b/chip/stm32/usb_pd_phy.c
@@ -308,12 +308,14 @@ int pd_start_tx(int port, int polarity, int bit_len)
{
stm32_dma_chan_t *tx = dma_get_channel(DMAC_SPI_TX(port));
+#ifndef CONFIG_USB_PD_TX_PHY_ONLY
/* disable RX detection interrupt */
pd_rx_disable_monitoring(port);
/* Check that we are not receiving a frame to avoid collisions */
if (pd_rx_started(port))
return -5;
+#endif /* !CONFIG_USB_PD_TX_PHY_ONLY */
/* Initialize spi peripheral to prepare for transmission. */
pd_tx_spi_init(port);
@@ -504,62 +506,14 @@ void pd_hw_release(int port)
}
/* --- Startup initialization --- */
-void pd_hw_init(int port, int role)
+
+void pd_hw_init_rx(int port)
{
struct pd_physical *phy = &pd_phy[port];
- uint32_t val;
-
- /* Initialize all PD pins to default state based on desired role */
- pd_config_init(port, role);
-
- /* set 40 MHz pin speed on communication pins */
- pd_set_pins_speed(port);
-
- /* --- SPI init --- */
-
- /* Enable clocks to SPI module */
- spi_enable_clock(port);
-
- /* Initialize SPI peripheral registers */
- pd_tx_spi_init(port);
-
- /* configure TX DMA */
- phy->dma_tx_option.channel = DMAC_SPI_TX(port);
- phy->dma_tx_option.periph = (void *)&SPI_REGS(port)->dr;
- phy->dma_tx_option.flags = STM32_DMA_CCR_MSIZE_8_BIT |
- STM32_DMA_CCR_PSIZE_8_BIT;
- dma_prepare_tx(&(phy->dma_tx_option), PD_MAX_RAW_SIZE,
- phy->raw_samples);
/* configure registers used for timers */
- phy->tim_tx = (void *)TIM_REG_TX(port);
phy->tim_rx = (void *)TIM_REG_RX(port);
- /* --- set the TX timer with updates at 600KHz (BMC frequency) --- */
- __hw_timer_enable_clock(TIM_CLOCK_PD_TX(port), 1);
- /* Timer configuration */
- phy->tim_tx->cr1 = 0x0000;
- phy->tim_tx->cr2 = 0x0000;
- phy->tim_tx->dier = 0x0000;
- /* Auto-reload value : 600000 Khz overflow */
- phy->tim_tx->arr = TX_CLOCK_DIV;
- /* 50% duty cycle on the output */
- phy->tim_tx->ccr[TIM_TX_CCR_IDX(port)] = phy->tim_tx->arr / 2;
- /* Timer channel output configuration */
- val = (6 << 4) | (1 << 3);
- if ((TIM_TX_CCR_IDX(port) & 1) == 0) /* CH2 or CH4 */
- val <<= 8;
- if (TIM_TX_CCR_IDX(port) <= 2)
- phy->tim_tx->ccmr1 = val;
- else
- phy->tim_tx->ccmr2 = val;
- phy->tim_tx->ccer = 1 << ((TIM_TX_CCR_IDX(port) - 1) * 4);
- phy->tim_tx->bdtr = 0x8000;
- /* set prescaler to /1 */
- phy->tim_tx->psc = 0;
- /* Reload the pre-scaler and reset the counter */
- phy->tim_tx->egr = 0x0001;
-#ifndef CONFIG_USB_PD_TX_PHY_ONLY
/* configure RX DMA */
phy->dma_tim_option.channel = DMAC_TIM_RX(port);
phy->dma_tim_option.periph = (void *)(TIM_RX_CCR_REG(port));
@@ -640,6 +594,65 @@ void pd_hw_init(int port, int role)
EXTI_XTSR |= EXTI_COMP_MASK(port);
STM32_EXTI_IMR |= EXTI_COMP_MASK(port);
task_enable_irq(IRQ_COMP);
+}
+
+void pd_hw_init(int port, int role)
+{
+ struct pd_physical *phy = &pd_phy[port];
+ uint32_t val;
+
+ /* Initialize all PD pins to default state based on desired role */
+ pd_config_init(port, role);
+
+ /* set 40 MHz pin speed on communication pins */
+ pd_set_pins_speed(port);
+
+ /* --- SPI init --- */
+
+ /* Enable clocks to SPI module */
+ spi_enable_clock(port);
+
+ /* Initialize SPI peripheral registers */
+ pd_tx_spi_init(port);
+
+ /* configure TX DMA */
+ phy->dma_tx_option.channel = DMAC_SPI_TX(port);
+ phy->dma_tx_option.periph = (void *)&SPI_REGS(port)->dr;
+ phy->dma_tx_option.flags = STM32_DMA_CCR_MSIZE_8_BIT |
+ STM32_DMA_CCR_PSIZE_8_BIT;
+ dma_prepare_tx(&(phy->dma_tx_option), PD_MAX_RAW_SIZE,
+ phy->raw_samples);
+
+ /* configure registers used for timers */
+ phy->tim_tx = (void *)TIM_REG_TX(port);
+
+ /* --- set the TX timer with updates at 600KHz (BMC frequency) --- */
+ __hw_timer_enable_clock(TIM_CLOCK_PD_TX(port), 1);
+ /* Timer configuration */
+ phy->tim_tx->cr1 = 0x0000;
+ phy->tim_tx->cr2 = 0x0000;
+ phy->tim_tx->dier = 0x0000;
+ /* Auto-reload value : 600000 Khz overflow */
+ phy->tim_tx->arr = TX_CLOCK_DIV;
+ /* 50% duty cycle on the output */
+ phy->tim_tx->ccr[TIM_TX_CCR_IDX(port)] = phy->tim_tx->arr / 2;
+ /* Timer channel output configuration */
+ val = (6 << 4) | (1 << 3);
+ if ((TIM_TX_CCR_IDX(port) & 1) == 0) /* CH2 or CH4 */
+ val <<= 8;
+ if (TIM_TX_CCR_IDX(port) <= 2)
+ phy->tim_tx->ccmr1 = val;
+ else
+ phy->tim_tx->ccmr2 = val;
+ phy->tim_tx->ccer = 1 << ((TIM_TX_CCR_IDX(port) - 1) * 4);
+ phy->tim_tx->bdtr = 0x8000;
+ /* set prescaler to /1 */
+ phy->tim_tx->psc = 0;
+ /* Reload the pre-scaler and reset the counter */
+ phy->tim_tx->egr = 0x0001;
+#ifndef CONFIG_USB_PD_TX_PHY_ONLY
+ /* Configure the reception side : comparators + edge timer + DMA */
+ pd_hw_init_rx(port);
#endif /* CONFIG_USB_PD_TX_PHY_ONLY */
CPRINTS("USB PD initialized");
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 710db2b9ed..5cb8f4e13b 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -476,8 +476,6 @@ int prepare_message(int port, uint16_t header, uint8_t cnt,
return pd_write_last_edge(port, off);
}
-static int analyze_rx(int port, uint32_t *payload);
-
int send_hard_reset(int port)
{
int off;
@@ -560,7 +558,7 @@ static int send_validate_message(int port, uint16_t header,
pd_rx_start(port);
}
/* read the incoming packet if any */
- head = analyze_rx(port, payload);
+ head = pd_analyze_rx(port, payload);
pd_rx_complete(port);
/* keep RX monitoring on to avoid collisions */
pd_rx_enable_monitoring(port);
@@ -1404,7 +1402,7 @@ static int analyze_rx_bist(int port)
}
#endif
-static int analyze_rx(int port, uint32_t *payload)
+int pd_analyze_rx(int port, uint32_t *payload)
{
int bit;
char *msg = "---";
@@ -1879,7 +1877,7 @@ void pd_task(void)
/* incoming packet ? */
if (pd_rx_started(port) && pd_comm_enabled) {
incoming_packet = 1;
- head = analyze_rx(port, payload);
+ head = pd_analyze_rx(port, payload);
pd_rx_complete(port);
if (head > 0)
handle_request(port, head, payload);
diff --git a/include/usb_pd.h b/include/usb_pd.h
index e79e2d907c..0f226096b8 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -1324,7 +1324,27 @@ void pd_hw_release(int port);
*/
void pd_hw_init(int port, int role);
+/**
+ * Initialize the reception side of hardware used for PD.
+ *
+ * This is a subset of pd_hw_init() including only :
+ * the comparators + the RX edge delay timer + the RX DMA.
+ *
+ * @param port USB-C port number
+ */
+void pd_hw_init_rx(int port);
+
/* --- Protocol layer functions --- */
+
+/**
+ * Decode a raw packet in the RX buffer.
+ *
+ * @param port USB-C port number
+ * @param payload buffer to store the packet payload (must be 7x 32-bit)
+ * @return the packet header or <0 in case of error
+ */
+int pd_analyze_rx(int port, uint32_t *payload);
+
/**
* Get connected state
*