diff options
author | Alec Berg <alecaberg@chromium.org> | 2014-10-28 14:26:51 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-12-17 03:27:17 +0000 |
commit | 6c980a4dbf2e37b83e868c0eb12774190ea8c94d (patch) | |
tree | da414fe9f2f5609525ba950d5a05c54accfee475 /chip/stm32/usb_pd_phy.c | |
parent | 3b101e56a9e058aee19933f9adfae1c8bb2dbedd (diff) | |
download | chrome-ec-6c980a4dbf2e37b83e868c0eb12774190ea8c94d.tar.gz |
pd: check for collisions before transmitting
Added check for collision just before transmitting on CC line.
To check for collision, RX monitoring is left on all the time
(except when in the act of receiving or transmitting, or in
between receiving and sending a goodCRC), and a
simple check for RX transmission started is used to see if the
CC line is idle or not.
RX monitoring is also changed to only trigger on 3 edges within
20us, as per the PD spec.
When a collision is detected by seeing that CC is not idle, the
transmitting packet is dropped.
BUG=chrome-os-partner:30135
BRANCH=samus
TEST=load onto samus and zinger. make sure we negotiate and make
sure custom VDMs succeed. enabled pings and made sure we stay
alive with pings for a few min.
Also added code to pd_rx_handler to toggle a test point on EVT
board to verify the timing of when we get RX interrupts:
Change-Id: I22d172163319437d3d901e019eda79d4d592f6b8
Signed-off-by: Alec Berg <alecaberg@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/226118
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Diffstat (limited to 'chip/stm32/usb_pd_phy.c')
-rw-r--r-- | chip/stm32/usb_pd_phy.c | 67 |
1 files changed, 56 insertions, 11 deletions
diff --git a/chip/stm32/usb_pd_phy.c b/chip/stm32/usb_pd_phy.c index 7079709e99..55c465986d 100644 --- a/chip/stm32/usb_pd_phy.c +++ b/chip/stm32/usb_pd_phy.c @@ -13,6 +13,7 @@ #include "hwtimer.h" #include "hooks.h" #include "registers.h" +#include "system.h" #include "task.h" #include "timer.h" #include "util.h" @@ -71,6 +72,10 @@ static struct pd_physical { timer_ctlr_t *tim_rx; } pd_phy[PD_PORT_COUNT]; +/* keep track of RX edge timing in order to trigger receive */ +static timestamp_t rx_edge_ts[PD_PORT_COUNT][PD_RX_TRANSITION_COUNT]; +static int rx_edge_ts_idx[PD_PORT_COUNT]; + void pd_init_dequeue(int port) { /* preamble ends with 1 */ @@ -295,10 +300,17 @@ void pd_tx_set_circular_mode(int port) pd_phy[port].dma_tx_option.flags |= STM32_DMA_CCR_CIRC; } -void pd_start_tx(int port, int polarity, int bit_len) +int pd_start_tx(int port, int polarity, int bit_len) { stm32_dma_chan_t *tx = dma_get_channel(DMAC_SPI_TX(port)); + /* 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; + /* Initialize spi peripheral to prepare for transmission. */ pd_tx_spi_init(port); @@ -315,9 +327,6 @@ void pd_start_tx(int port, int polarity, int bit_len) /* Flush data in write buffer so that DMA can get the latest data */ asm volatile("dmb;"); - /* disable RX detection interrupt */ - pd_rx_disable_monitoring(port); - /* Kick off the DMA to send the data */ dma_clear_isr(DMAC_SPI_TX(port)); #ifdef CONFIG_COMMON_RUNTIME @@ -338,6 +347,8 @@ void pd_start_tx(int port, int polarity, int bit_len) /* Start counting at 300Khz*/ pd_phy[port].tim_tx->cr1 |= 1; #endif + + return bit_len; } void pd_tx_done(int port, int polarity) @@ -436,23 +447,57 @@ void pd_rx_disable_monitoring(int port) STM32_EXTI_PR = EXTI_COMP_MASK(port); } +uint64_t get_time_since_last_edge(int port) +{ + int prev_idx = (rx_edge_ts_idx[port] == 0) ? + PD_RX_TRANSITION_COUNT - 1 : + rx_edge_ts_idx[port] - 1; + return get_time().val - rx_edge_ts[port][prev_idx].val; +} + /* detect an edge on the PD RX pin */ void pd_rx_handler(void) { int pending, i; + int next_idx; pending = STM32_EXTI_PR; for (i = 0; i < PD_PORT_COUNT; i++) { if (pending & EXTI_COMP_MASK(i)) { - /* start sampling */ - pd_rx_start(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; + /* - * ignore the comparator IRQ until we are done with - * current message + * Do not deep sleep while waiting for more edges. For + * most boards, sleep is already disabled due to being + * in PD connected state, but other boards can sleep + * while connected. */ - pd_rx_disable_monitoring(i); - /* trigger the analysis in the task */ - pd_rx_event(i); + disable_sleep(SLEEP_MASK_USB_PD); + + /* + * 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) { + /* start sampling */ + pd_rx_start(i); + /* + * ignore the comparator IRQ until we are done + * with current message + */ + pd_rx_disable_monitoring(i); + /* trigger the analysis in the task */ + pd_rx_event(i); + } else { + /* do not trigger RX start, just clear int */ + STM32_EXTI_PR = EXTI_COMP_MASK(i); + } + rx_edge_ts_idx[i] = next_idx; } } } |