summaryrefslogtreecommitdiff
path: root/board/twinkie
diff options
context:
space:
mode:
Diffstat (limited to 'board/twinkie')
-rw-r--r--board/twinkie/board.h9
-rw-r--r--board/twinkie/build.mk2
-rw-r--r--board/twinkie/ec.tasklist2
-rw-r--r--board/twinkie/injector.c515
-rw-r--r--board/twinkie/injector.h79
-rw-r--r--board/twinkie/sniffer.c39
-rw-r--r--board/twinkie/usb_pd_config.h4
7 files changed, 646 insertions, 4 deletions
diff --git a/board/twinkie/board.h b/board/twinkie/board.h
index edfcc4800b..b748104ad2 100644
--- a/board/twinkie/board.h
+++ b/board/twinkie/board.h
@@ -18,14 +18,15 @@
#define CONFIG_USB
#define CONFIG_USB_CONSOLE
-#ifdef HAS_TASK_PD /* PD message injector mode */
#define CONFIG_USB_POWER_DELIVERY
#define CONFIG_USB_PD_DUAL_ROLE
#define CONFIG_USB_PD_INTERNAL_COMP
#define CONFIG_PD_USE_DAC_AS_REF
#define CONFIG_HW_CRC
-#else /* PD sniffer mode */
+
+#ifndef HAS_TASK_PD /* PD sniffer mode */
#undef CONFIG_DMA_DEFAULT_HANDLERS
+#define CONFIG_USB_PD_TX_PHY_ONLY
#endif
#define CONFIG_ADC
@@ -52,6 +53,10 @@
#ifndef __ASSEMBLER__
+int wait_packet(int pol, uint32_t min_edges, uint32_t timeout_us);
+
+void recording_enable(uint8_t mask);
+
/* Timer selection */
#define TIM_CLOCK_MSB 3
#define TIM_CLOCK_LSB 15
diff --git a/board/twinkie/build.mk b/board/twinkie/build.mk
index d920169312..f9b5e7d973 100644
--- a/board/twinkie/build.mk
+++ b/board/twinkie/build.mk
@@ -11,5 +11,5 @@ CHIP_FAMILY:=stm32f0
CHIP_VARIANT:=stm32f07x
board-y=board.o
-board-$(HAS_TASK_SNIFFER)+=sniffer.o
+board-$(HAS_TASK_SNIFFER)+=sniffer.o injector.o
board-$(HAS_TASK_PD)+=usb_pd_policy.o
diff --git a/board/twinkie/ec.tasklist b/board/twinkie/ec.tasklist
index a766187877..1bc0b5212c 100644
--- a/board/twinkie/ec.tasklist
+++ b/board/twinkie/ec.tasklist
@@ -18,8 +18,8 @@
*/
#define CONFIG_TASK_LIST \
TASK_ALWAYS(HOOKS, hook_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) \
TASK_ALWAYS(SNIFFER, sniffer_task, NULL, TASK_STACK_SIZE) \
- TASK_ALWAYS(CONSOLE, console_task, NULL, TASK_STACK_SIZE) \
/*Disabled: TASK_ALWAYS(PD, pd_task, NULL, LARGER_TASK_STACK_SIZE) */
/*
* To get Twinkie to behave as a USB Power Delivery consumer/provider
diff --git a/board/twinkie/injector.c b/board/twinkie/injector.c
new file mode 100644
index 0000000000..4f1ece6f78
--- /dev/null
+++ b/board/twinkie/injector.c
@@ -0,0 +1,515 @@
+/* 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 "task.h"
+#include "timer.h"
+#include "usb_pd.h"
+#include "usb_pd_config.h"
+#include "util.h"
+#include "watchdog.h"
+
+/* FSM command/data buffer */
+static uint32_t inj_cmds[INJ_CMD_COUNT];
+
+/* Current polarity for sending operations */
+static enum inj_pol inj_polarity = INJ_POL_CC1;
+
+/*
+ * CCx Resistors control definition
+ *
+ * Resistor control GPIOs :
+ * CC1_RA A8
+ * CC1_RPUSB A13
+ * CC1_RP1A5 A14
+ * CC1_RP3A0 A15
+ * CC2_RPUSB B0
+ * CC1_RD B5
+ * CC2_RD B8
+ * CC2_RA B15
+ * CC2_RP1A5 C14
+ * CC2_RP3A0 C15
+ */
+static const struct res_cfg {
+ const char *name;
+ struct config {
+ uint32_t port;
+ uint32_t mask;
+ uint32_t flags;
+ } cfgs[2];
+} res_cfg[] = {
+ [INJ_RES_NONE] = {"NONE"},
+ [INJ_RES_RA] = {"RA", {{GPIO_A, 0x0100, GPIO_ODR_LOW},
+ {GPIO_B, 0x8000, GPIO_ODR_LOW} } },
+ [INJ_RES_RD] = {"RD", {{GPIO_B, 0x0020, GPIO_ODR_LOW},
+ {GPIO_B, 0x0100, GPIO_ODR_LOW} } },
+ [INJ_RES_RPUSB] = {"RPUSB", {{GPIO_A, 0x2000, GPIO_OUT_HIGH},
+ {GPIO_B, 0x0001, GPIO_OUT_HIGH} } },
+ [INJ_RES_RP1A5] = {"RP1A5", {{GPIO_A, 0x4000, GPIO_OUT_HIGH},
+ {GPIO_C, 0x4000, GPIO_OUT_HIGH} } },
+ [INJ_RES_RP3A0] = {"RP3A0", {{GPIO_A, 0x8000, GPIO_OUT_HIGH},
+ {GPIO_C, 0x8000, GPIO_OUT_HIGH} } },
+};
+
+#define PD_SRC_RD_THRESHOLD 200 /* mV */
+#define CC_RA(cc) (cc < PD_SRC_RD_THRESHOLD)
+#define CC_RD(cc) ((cc > PD_SRC_RD_THRESHOLD) && (cc < PD_SRC_VNC))
+#define GET_POLARITY(cc1, cc2) (CC_RD(cc2) || CC_RA(cc1))
+
+/* Stub the function as we are not using the RX path */
+void pd_set_max_voltage(unsigned mv)
+{
+}
+
+/* we don't have the default DMA handlers */
+void dma_event_interrupt_channel_3(void)
+{
+ if (STM32_DMA1_REGS->isr & STM32_DMA_ISR_TCIF(STM32_DMAC_CH3)) {
+ dma_clear_isr(STM32_DMAC_CH3);
+ task_wake(TASK_ID_CONSOLE);
+ }
+}
+DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_2_3, dma_event_interrupt_channel_3, 3);
+
+static void twinkie_init(void)
+{
+ /* configure TX clock pins */
+ gpio_config_module(MODULE_USB_PD, 1);
+ /* Initialize physical layer */
+ pd_hw_init(0);
+}
+DECLARE_HOOK(HOOK_INIT, twinkie_init, HOOK_PRIO_DEFAULT);
+
+/* ------ Helper functions ------ */
+
+static int send_message(int polarity, uint16_t header,
+ uint8_t cnt, const uint32_t *data)
+{
+ int bit_len;
+
+ bit_len = prepare_message(0, header, cnt, data);
+ /* Transmit the packet */
+ pd_start_tx(0, polarity, bit_len);
+ pd_tx_done(0, polarity);
+
+ return bit_len;
+}
+
+static int send_hrst(int polarity)
+{
+ int off;
+ /* 64-bit preamble */
+ off = pd_write_preamble(0);
+ /* Hard-Reset: 3x RST-1 + 1x RST-2 */
+ off = pd_write_sym(0, off, 0b0011010101); /* RST-1 = 00111 */
+ off = pd_write_sym(0, off, 0b0011010101); /* RST-1 = 00111 */
+ off = pd_write_sym(0, off, 0b0011010101); /* RST-1 = 00111 */
+ off = pd_write_sym(0, off, 0b0101001101); /* RST-2 = 11001 */
+ /* Ensure that we have a final edge */
+ off = pd_write_last_edge(0, off);
+ /* Transmit the packet */
+ pd_start_tx(0, polarity, off);
+ pd_tx_done(0, polarity);
+
+ return off;
+}
+
+static void set_resistor(int pol, enum inj_res res)
+{
+ /* reset everything on one CC to high impedance */
+ gpio_set_flags_by_mask(GPIO_A, pol ? 0x0000 : 0xE100, GPIO_ODR_HIGH);
+ gpio_set_flags_by_mask(GPIO_B, pol ? 0x8101 : 0x0020, GPIO_ODR_HIGH);
+ gpio_set_flags_by_mask(GPIO_C, pol ? 0xC000 : 0x0000, GPIO_ODR_HIGH);
+ /* connect the resistor if needed */
+ if (res_cfg[res].cfgs[pol].mask)
+ gpio_set_flags_by_mask(res_cfg[res].cfgs[pol].port,
+ res_cfg[res].cfgs[pol].mask,
+ res_cfg[res].cfgs[pol].flags);
+}
+
+static enum inj_pol guess_polarity(enum inj_pol pol)
+{
+ int cc1_volt, cc2_volt;
+ /* polarity forced by the user */
+ if (pol == INJ_POL_CC1 || pol == INJ_POL_CC2)
+ return pol;
+ /* Auto-detection */
+ cc1_volt = pd_adc_read(0, 0);
+ cc2_volt = pd_adc_read(0, 1);
+ return GET_POLARITY(cc1_volt, cc2_volt);
+}
+
+/* ------ FSM commands ------ */
+
+static void fsm_send(uint32_t w)
+{
+ uint16_t header = INJ_ARG0(w);
+ int idx = INJ_ARG1(w);
+ uint8_t cnt = INJ_ARG2(w);
+
+ /* Buffer overflow */
+ if (idx > INJ_CMD_COUNT)
+ return;
+
+ send_message(inj_polarity, header, cnt, inj_cmds + idx);
+}
+
+static void fsm_wave(uint32_t w)
+{
+ uint16_t bit_len = INJ_ARG0(w);
+ int idx = INJ_ARG1(w);
+ int off = 0;
+ int nbwords = DIV_ROUND_UP(bit_len, 32);
+ int i;
+
+ /* Buffer overflow */
+ if (idx + nbwords > INJ_CMD_COUNT)
+ return;
+
+ for (i = idx; i < idx + nbwords; i++)
+ off = encode_word(0, off, inj_cmds[i]);
+ /* Ensure that we have a final edge */
+ off = pd_write_last_edge(0, bit_len);
+ /* Transmit the packet */
+ pd_start_tx(0, inj_polarity, off);
+ pd_tx_done(0, inj_polarity);
+}
+
+static void fsm_wait(uint32_t w)
+{
+ uint32_t timeout_ms = INJ_ARG0(w);
+ uint32_t min_edges = INJ_ARG12(w);
+
+ wait_packet(inj_polarity, min_edges, timeout_ms * 1000);
+}
+
+static void fsm_get(uint32_t w)
+{
+ int store_idx = INJ_ARG0(w);
+ int param_idx = INJ_ARG1(w);
+ uint32_t *store_ptr = inj_cmds + store_idx;
+
+ /* Buffer overflow */
+ if (store_idx > INJ_CMD_COUNT)
+ return;
+
+ switch (param_idx) {
+ case INJ_GET_CC:
+ *store_ptr = pd_adc_read(0, 0) | (pd_adc_read(0, 1) << 16);
+ break;
+ case INJ_GET_VBUS:
+ *store_ptr = (ina2xx_get_voltage(0) & 0xffff) |
+ ((ina2xx_get_current(0) & 0xffff) << 16);
+ break;
+ case INJ_GET_VCONN:
+ *store_ptr = (ina2xx_get_voltage(1) & 0xffff) |
+ ((ina2xx_get_current(1) & 0xffff) << 16);
+ break;
+ case INJ_GET_POLARITY:
+ *store_ptr = inj_polarity;
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+}
+
+static void fsm_set(uint32_t w)
+{
+ int val = INJ_ARG0(w);
+ int idx = INJ_ARG1(w);
+
+ switch (idx) {
+ case INJ_SET_RESISTOR1:
+ case INJ_SET_RESISTOR2:
+ set_resistor(idx - INJ_SET_RESISTOR1, val);
+ break;
+ case INJ_SET_RECORD:
+ recording_enable(val);
+ break;
+ case INJ_SET_TX_SPEED:
+ pd_set_clock(0, val * 1000);
+ break;
+ case INJ_SET_RX_THRESH:
+ /* set DAC voltage (Vref = 3.3V) */
+ STM32_DAC_DHR12RD = val * 4096 / 3300;
+ break;
+ case INJ_SET_POLARITY:
+ inj_polarity = guess_polarity(val);
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+}
+
+static int fsm_run(int index)
+{
+ while (index < INJ_CMD_COUNT) {
+ uint32_t w = inj_cmds[index];
+ int cmd = INJ_CMD(w);
+ switch (cmd) {
+ case INJ_CMD_END:
+ return index;
+ case INJ_CMD_SEND:
+ fsm_send(w);
+ break;
+ case INJ_CMD_WAVE:
+ fsm_wave(w);
+ break;
+ case INJ_CMD_HRST:
+ send_hrst(inj_polarity);
+ break;
+ case INJ_CMD_WAIT:
+ fsm_wait(w);
+ break;
+ case INJ_CMD_GET:
+ fsm_get(w);
+ break;
+ case INJ_CMD_SET:
+ fsm_set(w);
+ break;
+ case INJ_CMD_JUMP:
+ index = INJ_ARG0(w);
+ continue; /* do not increment index */
+ case INJ_CMD_NOP:
+ default:
+ /* Do nothing */
+ break;
+ }
+ index += 1;
+ watchdog_reload();
+ }
+ return index;
+}
+
+/* ------ Console commands ------ */
+
+static int hex8tou32(char *str, uint32_t *val)
+{
+ char *ptr = str;
+ uint32_t tmp = 0;
+
+ while (*ptr) {
+ char c = *ptr++;
+ if (c >= '0' && c <= '9')
+ tmp = (tmp << 4) + (c - '0');
+ else if (c >= 'A' && c <= 'F')
+ tmp = (tmp << 4) + (c - 'A' + 10);
+ else if (c >= 'a' && c <= 'f')
+ tmp = (tmp << 4) + (c - 'a' + 10);
+ else
+ return EC_ERROR_INVAL;
+ }
+ if (ptr != str + 8)
+ return EC_ERROR_INVAL;
+ *val = tmp;
+ return EC_SUCCESS;
+}
+
+static int cmd_fsm(int argc, char **argv)
+{
+ int index;
+ char *e;
+
+ if (argc < 1)
+ return EC_ERROR_PARAM2;
+
+ index = strtoi(argv[0], &e, 10);
+ if (*e)
+ return EC_ERROR_PARAM2;
+ index = fsm_run(index);
+ ccprintf("FSM Done %d\n", index);
+
+ return EC_SUCCESS;
+}
+
+
+static int cmd_send(int argc, char **argv)
+{
+ int pol, cnt, i;
+ uint16_t header;
+ uint32_t data[VDO_MAX_SIZE-1];
+ char *e;
+ int bit_len;
+
+ cnt = argc - 2;
+ if (argc < 2 || cnt > VDO_MAX_SIZE)
+ return EC_ERROR_PARAM_COUNT;
+
+ pol = strtoi(argv[0], &e, 10) - 1;
+ if (*e || pol > 1 || pol < 0)
+ return EC_ERROR_PARAM2;
+ header = strtoi(argv[1], &e, 16);
+ if (*e)
+ return EC_ERROR_PARAM3;
+
+ for (i = 0; i < cnt; i++)
+ if (hex8tou32(argv[i+2], data + i))
+ return EC_ERROR_INVAL;
+
+ bit_len = send_message(pol, header, cnt, data);
+ ccprintf("Sent CC%d %04x + %d = %d\n", pol + 1, header, cnt, bit_len);
+
+ return EC_SUCCESS;
+}
+
+static int cmd_cc_level(int argc, char **argv)
+{
+ ccprintf("CC1 = %d mV ; CC2 = %d mV\n",
+ pd_adc_read(0, 0), pd_adc_read(0, 1));
+
+ return EC_SUCCESS;
+}
+
+static int cmd_resistor(int argc, char **argv)
+{
+ int p, r;
+
+ if (argc < 2)
+ return EC_ERROR_PARAM_COUNT;
+
+ for (p = 0; p < 2; p++) {
+ int is_set = 0;
+ for (r = 0; r < ARRAY_SIZE(res_cfg); r++)
+ if (strcasecmp(res_cfg[r].name, argv[p]) == 0) {
+ set_resistor(p, r);
+ is_set = 1;
+ break;
+ }
+ /* Unknown name : set to No resistor */
+ if (!is_set)
+ set_resistor(p, INJ_RES_NONE);
+ }
+ return EC_SUCCESS;
+}
+
+static int cmd_tx_clock(int argc, char **argv)
+{
+ int freq;
+ char *e;
+
+ if (argc < 1)
+ return EC_ERROR_PARAM2;
+
+ freq = strtoi(argv[0], &e, 10);
+ if (*e)
+ return EC_ERROR_PARAM2;
+ pd_set_clock(0, freq);
+ ccprintf("TX frequency = %d Hz\n", freq);
+
+ return EC_SUCCESS;
+}
+
+static int cmd_rx_threshold(int argc, char **argv)
+{
+ int mv;
+ char *e;
+
+ if (argc < 1)
+ return EC_ERROR_PARAM2;
+
+ mv = strtoi(argv[0], &e, 10);
+ if (*e)
+ return EC_ERROR_PARAM2;
+
+ /* set DAC voltage (Vref = 3.3V) */
+ STM32_DAC_DHR12RD = mv * 4096 / 3300;
+ ccprintf("RX threshold = %d mV\n", mv);
+
+ return EC_SUCCESS;
+}
+
+static int cmd_ina_dump(int argc, char **argv, int index)
+{
+ ccprintf("%s = %d mV ; %d mA\n", index == 0 ? "VBUS" : "VCONN",
+ ina2xx_get_voltage(index), ina2xx_get_current(index));
+
+ return EC_SUCCESS;
+}
+
+static int cmd_bufwr(int argc, char **argv)
+{
+ int idx, cnt, i;
+ char *e;
+
+ cnt = argc - 1;
+ if (argc < 2 || cnt > INJ_CMD_COUNT)
+ return EC_ERROR_PARAM_COUNT;
+
+ idx = strtoi(argv[0], &e, 10);
+ if (*e || idx + cnt > INJ_CMD_COUNT)
+ return EC_ERROR_PARAM2;
+
+ for (i = 0; i < cnt; i++)
+ if (hex8tou32(argv[i+1], inj_cmds + idx + i))
+ return EC_ERROR_INVAL;
+
+ return EC_SUCCESS;
+}
+
+static int cmd_bufrd(int argc, char **argv)
+{
+ int idx, i;
+ int cnt = 1;
+ char *e;
+
+ if (argc < 1)
+ return EC_ERROR_PARAM_COUNT;
+
+ idx = strtoi(argv[0], &e, 10);
+ if (*e || idx > INJ_CMD_COUNT)
+ return EC_ERROR_PARAM2;
+
+ if (argc >= 2)
+ cnt = strtoi(argv[0], &e, 10);
+ if (*e || idx + cnt > INJ_CMD_COUNT)
+ return EC_ERROR_PARAM3;
+
+ for (i = idx; i < idx + cnt; i++)
+ ccprintf("%08x ", inj_cmds[i]);
+ ccprintf("\n");
+
+ return EC_SUCCESS;
+}
+
+static int command_tw(int argc, char **argv)
+{
+ if (!strcasecmp(argv[1], "send"))
+ return cmd_send(argc - 2, argv + 2);
+ else if (!strcasecmp(argv[1], "fsm"))
+ return cmd_fsm(argc - 2, argv + 2);
+ else if (!strcasecmp(argv[1], "bufwr"))
+ return cmd_bufwr(argc - 2, argv + 2);
+ else if (!strcasecmp(argv[1], "bufrd"))
+ return cmd_bufrd(argc - 2, argv + 2);
+ else if (!strcasecmp(argv[1], "cc"))
+ return cmd_cc_level(argc - 2, argv + 2);
+ else if (!strncasecmp(argv[1], "resistor", 3))
+ return cmd_resistor(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))
+ return cmd_rx_threshold(argc - 2, argv + 2);
+ else if (!strcasecmp(argv[1], "vbus"))
+ return cmd_ina_dump(argc - 2, argv + 2, 0);
+ else if (!strcasecmp(argv[1], "vconn"))
+ return cmd_ina_dump(argc - 2, argv + 2, 1);
+ else
+ return EC_ERROR_PARAM1;
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(twinkie, command_tw,
+ "[send|fsm|cc|resistor|txclock|rxthresh|vbus|vconn]",
+ "Manual Twinkie tweaking", NULL);
diff --git a/board/twinkie/injector.h b/board/twinkie/injector.h
new file mode 100644
index 0000000000..0e360a2fdc
--- /dev/null
+++ b/board/twinkie/injector.h
@@ -0,0 +1,79 @@
+/* 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.
+ */
+
+#ifndef __INJECTOR_H
+#define __INJECTOR_H
+
+/*
+ * Finite state machine definition for sending complex sequences
+ *
+ * the 32-bit commands have the following definition :
+ * [31:28] [27:0]
+ * Command arg
+ * INJ_CMD_x
+ * [27:16] [15:0]
+ * arg12 arg0
+ * [27:24] [23:16] [15:0]
+ * arg2 arg1 arg0
+ */
+
+/* Macros to extract values from FSM command words */
+#define INJ_CMD(w) ((w) >> 28)
+#define INJ_ARG(w) ((w) & 0x0FFFFFFF)
+#define INJ_ARG0(w) ((w) & 0x0000FFFF)
+#define INJ_ARG1(w) (((w) >> 16) & 0xFF)
+#define INJ_ARG2(w) (((w) >> 24) & 0xF)
+#define INJ_ARG12(w) (((w) >> 16) & 0xFFF)
+
+enum inj_cmd {
+ INJ_CMD_END = 0x0, /* stop the FSM */
+ INJ_CMD_SEND = 0x1, /* Send message on CCx */
+ /* arg0: header arg1/2:payload index/count */
+ INJ_CMD_WAVE = 0x2, /* Send arbitrary waveform */
+ /* stored at index arg1 of len arg0 */
+ INJ_CMD_HRST = 0x3, /* Send Hard Reset on CCx */
+ INJ_CMD_WAIT = 0x4, /* Wait for arg12 edges if arg12 != 0 */
+ /* and timeout after arg0 ms */
+ 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_NOP = 0xF, /* No-Operation */
+};
+
+enum inj_set {
+ INJ_SET_RESISTOR1 = 0, /* CC1 resistor as arg0 (INJ_RES_x) */
+ INJ_SET_RESISTOR2 = 1, /* CC2 resistor as arg0 (INJ_RES_x) */
+ INJ_SET_RECORD = 2, /* Recording on/off */
+ 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) */
+};
+
+enum inj_get {
+ INJ_GET_CC = 0, /* CC1/CC2 voltages in mV */
+ INJ_GET_VBUS = 1, /* VBUS voltage in mV and current in mA */
+ INJ_GET_VCONN = 2, /* VCONN voltage in mV and current in mA */
+ INJ_GET_POLARITY = 3, /* Current polarity (INJ_POL_CC) */
+};
+
+enum inj_res {
+ INJ_RES_NONE = 0,
+ INJ_RES_RA = 1,
+ INJ_RES_RD = 2,
+ INJ_RES_RPUSB = 3,
+ INJ_RES_RP1A5 = 4,
+ INJ_RES_RP3A0 = 5,
+};
+
+enum inj_pol {
+ INJ_POL_CC1 = 0,
+ INJ_POL_CC2 = 1,
+ INJ_POL_AUTO = 0xffff,
+};
+
+/* Number of words in the FSM command/data buffer */
+#define INJ_CMD_COUNT 128
+
+#endif /* __INJECTOR_H */
diff --git a/board/twinkie/sniffer.c b/board/twinkie/sniffer.c
index 136cc1b01a..e6a0cff0a4 100644
--- a/board/twinkie/sniffer.c
+++ b/board/twinkie/sniffer.c
@@ -299,6 +299,45 @@ void sniffer_task(void)
}
}
+int wait_packet(int pol, uint32_t min_edges, uint32_t timeout_us)
+{
+ stm32_dma_chan_t *chan = dma_get_channel(pol ? DMAC_TIM_RX2
+ : DMAC_TIM_RX1);
+ uint32_t t0 = __hw_clock_source_read();
+ uint32_t c0 = chan->cndtr;
+ uint32_t t_gap = t0;
+ uint32_t c_gap = c0;
+ uint32_t total_edges = 0;
+
+ while (1) {
+ uint32_t t = __hw_clock_source_read();
+ uint32_t c = chan->cndtr;
+ if (t - t0 > timeout_us) /* Timeout */
+ break;
+ if (min_edges) { /* real packet detection */
+ int nb = (int)c_gap - (int)c;
+ if (nb < 0)
+ nb = RX_COUNT - nb;
+ if (nb > 3) { /* NOT IDLE */
+ t_gap = t;
+ c_gap = c;
+ total_edges += nb;
+ } else {
+ if ((t - t_gap) > 20 &&
+ (total_edges - (t - t0)/256) >= min_edges)
+ /* real gap after the packet */
+ break;
+ }
+ }
+ }
+ return (__hw_clock_source_read() - t0 > timeout_us);
+}
+
+void recording_enable(uint8_t mask)
+{
+ /* TODO implement */
+}
+
static int command_sniffer(int argc, char **argv)
{
ccprintf("Seq number:%d Overflows: %d\n", seq, oflow);
diff --git a/board/twinkie/usb_pd_config.h b/board/twinkie/usb_pd_config.h
index e32b29fd67..8e5768a8c4 100644
--- a/board/twinkie/usb_pd_config.h
+++ b/board/twinkie/usb_pd_config.h
@@ -12,7 +12,11 @@
/* Port and task configuration */
#define PD_PORT_COUNT 1
+#ifdef HAS_TASK_PD /* PD message injector mode */
#define PORT_TO_TASK_ID(port) TASK_ID_PD
+#else
+#define PORT_TO_TASK_ID(port) -1
+#endif
#define TASK_ID_TO_PORT(id) 0
/* Timer selection for baseband PD communication */