summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chip/stm32/usb_pd_phy.c9
-rw-r--r--common/usb_pd_protocol.c115
-rw-r--r--include/usb_pd.h7
3 files changed, 124 insertions, 7 deletions
diff --git a/chip/stm32/usb_pd_phy.c b/chip/stm32/usb_pd_phy.c
index 44888163c1..051d2f0710 100644
--- a/chip/stm32/usb_pd_phy.c
+++ b/chip/stm32/usb_pd_phy.c
@@ -133,7 +133,7 @@ int pd_dequeue_bits(void *ctxt, int off, int len, uint32_t *val)
return -1;
}
stream_err:
- CPRINTS("PD Invalid %d @%d", cnt, off);
+ /* CPRINTS("PD Invalid %d @%d", cnt, off); */
return -1;
}
@@ -252,11 +252,16 @@ void pd_dump_packet(void *ctxt, const char *msg)
/* --- SPI TX operation --- */
-static const struct dma_option dma_tx_option = {
+static struct dma_option dma_tx_option = {
DMAC_SPI_TX, (void *)&SPI_REGS->dr,
STM32_DMA_CCR_MSIZE_8_BIT | STM32_DMA_CCR_PSIZE_8_BIT
};
+void pd_tx_set_circular_mode(void)
+{
+ dma_tx_option.flags |= STM32_DMA_CCR_CIRC;
+}
+
void pd_start_tx(void *ctxt, int polarity, int bit_len)
{
stm32_dma_chan_t *tx = dma_get_channel(DMAC_SPI_TX);
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index c42ed176a2..eb7804cc7a 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -265,6 +265,7 @@ static int prepare_message(void *ctxt, uint16_t header, uint8_t cnt,
}
static int analyze_rx(uint32_t *payload);
+static void analyze_rx_bist(void);
static void send_hard_reset(void *ctxt)
{
@@ -384,9 +385,10 @@ static int send_request(void *ctxt, uint32_t rdo)
}
#endif /* CONFIG_USB_PD_DUAL_ROLE */
-static int send_bist(void *ctxt)
+static int send_bist_cmd(void *ctxt)
{
- uint32_t bdo = BDO(BDO_MODE_TRANSMIT, 0);
+ /* currently only support sending bist carrier 2 */
+ uint32_t bdo = BDO(BDO_MODE_CARRIER2, 0);
int bit_len;
uint16_t header = PD_HEADER(PD_DATA_BIST, pd_role, pd_message_id, 1);
@@ -396,6 +398,56 @@ static int send_bist(void *ctxt)
return bit_len;
}
+static void bist_mode_2_tx(void *ctxt)
+{
+ int bit;
+
+ CPRINTF("BIST carrier 2 - sending\n");
+
+ /*
+ * build context buffer with 5 bytes, where the data is
+ * alternating 1's and 0's.
+ */
+ bit = pd_write_sym(ctxt, 0, BMC(0x15));
+ bit = pd_write_sym(ctxt, bit, BMC(0x0a));
+ bit = pd_write_sym(ctxt, bit, BMC(0x15));
+ bit = pd_write_sym(ctxt, bit, BMC(0x0a));
+
+ /* start a circular DMA transfer (will never end) */
+ pd_tx_set_circular_mode();
+ pd_start_tx(ctxt, pd_polarity, bit);
+
+ /* do not let pd task state machine run anymore */
+ while (1)
+ task_wait_event(-1);
+}
+
+static void bist_mode_2_rx(void)
+{
+ /* monitor for incoming packet */
+ pd_rx_enable_monitoring();
+
+ /* loop until we start receiving data */
+ while (1) {
+ task_wait_event(500*MSEC);
+ /* incoming packet ? */
+ if (pd_rx_started())
+ break;
+ }
+
+ /*
+ * once we start receiving bist data, do not
+ * let state machine run again. stay here, and
+ * analyze a chunk of data every 250ms.
+ */
+ while (1) {
+ analyze_rx_bist();
+ pd_rx_complete();
+ msleep(250);
+ pd_rx_enable_monitoring();
+ }
+}
+
static void handle_vdm_request(void *ctxt, int cnt, uint32_t *payload)
{
uint16_t vid = PD_VDO_VID(payload[0]);
@@ -457,7 +509,11 @@ static void handle_data_request(void *ctxt, uint16_t head, uint32_t *payload)
send_control(ctxt, PD_CTRL_REJECT);
break;
case PD_DATA_BIST:
- CPRINTF("BIST not supported\n");
+ /* currently only support sending bist carrier mode 2 */
+ if ((payload[0] >> 28) == 5)
+ /* bist data object mode is 2 */
+ bist_mode_2_tx(ctxt);
+
break;
case PD_DATA_SINK_CAP:
break;
@@ -554,6 +610,55 @@ static inline int decode_word(void *ctxt, int off, uint32_t *val32)
return decode_short(ctxt, off, ((uint16_t *)val32 + 1));
}
+static int count_set_bits(int n)
+{
+ int count = 0;
+ while (n) {
+ n &= (n - 1);
+ count++;
+ }
+ return count;
+}
+
+static void analyze_rx_bist(void)
+{
+ void *ctxt;
+ int i = 0, bit = -1;
+ uint32_t w, match;
+ int invalid_bits = 0;
+ static int total_invalid_bits;
+
+ ctxt = pd_init_dequeue();
+
+ /* dequeue bits until we see a full byte of alternating 1's and 0's */
+ while (i < 10 && (bit < 0 || (w != 0xaa && w != 0x55)))
+ bit = pd_dequeue_bits(ctxt, i++, 8, &w);
+
+ /* if we didn't find any bytes that match criteria, display error */
+ if (i == 10) {
+ CPRINTF("Could not find any bytes of alternating bits\n");
+ return;
+ }
+
+ /*
+ * now we know what matching byte we are looking for, dequeue a bunch
+ * more data and count how many bits differ from expectations.
+ */
+ match = w;
+ bit = i - 1;
+ for (i = 0; i < 40; i++) {
+ bit = pd_dequeue_bits(ctxt, bit, 8, &w);
+ if (i % 20 == 0)
+ CPRINTF("\n");
+ CPRINTF("%02x ", w);
+ invalid_bits += count_set_bits(w ^ match);
+ }
+
+ total_invalid_bits += invalid_bits;
+ CPRINTF("- incorrect bits: %d / %d\n", invalid_bits,
+ total_invalid_bits);
+}
+
static int analyze_rx(uint32_t *payload)
{
int bit;
@@ -812,8 +917,8 @@ void pd_task(void)
execute_hard_reset();
break;
case PD_STATE_BIST:
- send_bist(ctxt);
- pd_task_state = PD_STATE_DISABLED;
+ send_bist_cmd(ctxt);
+ bist_mode_2_rx();
break;
}
}
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 56c669373d..89229079a4 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -288,6 +288,13 @@ void pd_set_clock(int freq);
* @param bit_len size of the packet in bits.
*/
void pd_start_tx(void *ctxt, int polarity, int bit_len);
+
+/**
+ * Set PD TX DMA to use circular mode. Call this before pd_start_tx() to
+ * continually loop over the transmit buffer given in pd_start_tx().
+ */
+void pd_tx_set_circular_mode(void);
+
/**
* Call when we are done sending a packet.
*