mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-29 18:11:05 +00:00
pd: clean up beg/end transitions of PD comms
Fix the beginning and end of BMC PD communication: - Initial transmission within 1us of taking control of CC line - CC line released between 1us and 23us after last edge - If final bit is a 0, then add two 1 bits to the end - No garbage after the final bit BUG=chrome-os-partner:30132 BRANCH=none TEST=tested with a fruitpie, samus, and zinger. verified timing on scope. Change-Id: Ie45695eb367a7554cf5d5b76b6fbdf1e3fc85d29 Signed-off-by: Alec Berg <alecaberg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/206453 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
This commit is contained in:
committed by
chrome-internal-fetch
parent
6473343075
commit
9ba7bd4284
@@ -44,16 +44,25 @@ static inline void pd_set_pins_speed(void)
|
||||
STM32_GPIO_OSPEEDR(GPIO_B) |= 0x000C0000;
|
||||
}
|
||||
|
||||
/* Reset SPI peripheral used for TX */
|
||||
static inline void pd_tx_spi_reset(void)
|
||||
{
|
||||
/* Reset SPI1 */
|
||||
STM32_RCC_APB2RSTR |= (1 << 12);
|
||||
STM32_RCC_APB2RSTR &= ~(1 << 12);
|
||||
}
|
||||
|
||||
/* Drive the CC line from the TX block */
|
||||
static inline void pd_tx_enable(int polarity)
|
||||
{
|
||||
/* set the low level reference */
|
||||
gpio_set_level(polarity ? GPIO_PD_CC2_TX_EN : GPIO_PD_CC1_TX_EN, 0);
|
||||
/* put SPI function on TX pin */
|
||||
if (polarity) /* PB4 is SPI1 MISO */
|
||||
gpio_set_alternate_function(GPIO_B, 0x0010, 0);
|
||||
else /* PA6 is SPI1 MISO */
|
||||
gpio_set_alternate_function(GPIO_A, 0x0040, 0);
|
||||
|
||||
/* set the low level reference */
|
||||
gpio_set_level(polarity ? GPIO_PD_CC2_TX_EN : GPIO_PD_CC1_TX_EN, 0);
|
||||
}
|
||||
|
||||
/* Put the TX driver in Hi-Z state */
|
||||
|
||||
@@ -43,12 +43,21 @@ static inline void pd_set_pins_speed(void)
|
||||
STM32_GPIO_OSPEEDR(GPIO_B) |= 0x000C0000;
|
||||
}
|
||||
|
||||
/* Reset SPI peripheral used for TX */
|
||||
static inline void pd_tx_spi_reset(void)
|
||||
{
|
||||
/* Reset SPI2 */
|
||||
STM32_RCC_APB1RSTR |= (1 << 14);
|
||||
STM32_RCC_APB1RSTR &= ~(1 << 14);
|
||||
}
|
||||
|
||||
/* Drive the CC line from the TX block */
|
||||
static inline void pd_tx_enable(int polarity)
|
||||
{
|
||||
gpio_set_level(GPIO_PD_TX_EN, 1);
|
||||
/* TX_DATA on PB14 is now connected to SPI2 */
|
||||
gpio_set_alternate_function(GPIO_B, 0x4000, 0);
|
||||
|
||||
gpio_set_level(GPIO_PD_TX_EN, 1);
|
||||
}
|
||||
|
||||
/* Put the TX driver in Hi-Z state */
|
||||
|
||||
@@ -42,18 +42,26 @@ static inline void pd_set_pins_speed(void)
|
||||
STM32_GPIO_OSPEEDR(GPIO_B) |= 0x0000000C;
|
||||
}
|
||||
|
||||
/* Reset SPI peripheral used for TX */
|
||||
static inline void pd_tx_spi_reset(void)
|
||||
{
|
||||
/* Reset SPI1 */
|
||||
STM32_RCC_APB2RSTR |= (1 << 12);
|
||||
STM32_RCC_APB2RSTR &= ~(1 << 12);
|
||||
}
|
||||
|
||||
/* Drive the CC line from the TX block */
|
||||
static inline void pd_tx_enable(int polarity)
|
||||
{
|
||||
/* set the low level reference */
|
||||
gpio_set_level(polarity ? GPIO_USB_C0_CC2_TX_EN :
|
||||
GPIO_USB_C0_CC1_TX_EN, 1);
|
||||
|
||||
/* put SPI function on TX pin */
|
||||
if (polarity) /* PE14 is SPI1 MISO */
|
||||
gpio_set_alternate_function(GPIO_E, 0x4000, 1);
|
||||
else /* PB4 is SPI1 MISO */
|
||||
gpio_set_alternate_function(GPIO_B, 0x0010, 0);
|
||||
|
||||
/* set the low level reference */
|
||||
gpio_set_level(polarity ? GPIO_USB_C0_CC2_TX_EN :
|
||||
GPIO_USB_C0_CC1_TX_EN, 1);
|
||||
}
|
||||
|
||||
/* Put the TX driver in Hi-Z state */
|
||||
|
||||
@@ -43,13 +43,21 @@ static inline void pd_set_pins_speed(void)
|
||||
/* Already done in hardware_init() */
|
||||
}
|
||||
|
||||
/* Reset SPI peripheral used for TX */
|
||||
static inline void pd_tx_spi_reset(void)
|
||||
{
|
||||
/* Reset SPI1 */
|
||||
STM32_RCC_APB2RSTR |= (1 << 12);
|
||||
STM32_RCC_APB2RSTR &= ~(1 << 12);
|
||||
}
|
||||
|
||||
/* Drive the CC line from the TX block */
|
||||
static inline void pd_tx_enable(int polarity)
|
||||
{
|
||||
/* Drive TX GND on PA4 */
|
||||
STM32_GPIO_BSRR(GPIO_A) = 1 << (4 + 16 /* Reset */);
|
||||
/* Drive SPI MISO on PA6 by putting it in AF mode */
|
||||
STM32_GPIO_MODER(GPIO_A) |= 0x2 << (2*6);
|
||||
/* Drive TX GND on PA4 */
|
||||
STM32_GPIO_BSRR(GPIO_A) = 1 << (4 + 16 /* Reset */);
|
||||
}
|
||||
|
||||
/* Put the TX driver in Hi-Z state */
|
||||
|
||||
@@ -27,7 +27,16 @@ static task_id_t id[STM32_DMAC_COUNT];
|
||||
*/
|
||||
static int dma_get_irq(enum dma_channel channel)
|
||||
{
|
||||
#ifdef CHIP_FAMILY_STM32F0
|
||||
if (channel == STM32_DMAC_CH1)
|
||||
return STM32_IRQ_DMA_CHANNEL_1;
|
||||
|
||||
return channel > STM32_DMAC_CH3 ?
|
||||
STM32_IRQ_DMA_CHANNEL_4_7 :
|
||||
STM32_IRQ_DMA_CHANNEL_2_3;
|
||||
#else
|
||||
return STM32_IRQ_DMA_CHANNEL_1 + channel;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -241,7 +250,47 @@ void dma_clear_isr(enum dma_channel channel)
|
||||
dma->ifcr |= STM32_DMA_ISR_ALL(channel);
|
||||
}
|
||||
|
||||
#ifndef CHIP_FAMILY_STM32F0
|
||||
#ifdef CHIP_FAMILY_STM32F0
|
||||
void dma_event_interrupt_channel_1(void)
|
||||
{
|
||||
if (STM32_DMA1_REGS->isr & STM32_DMA_ISR_TCIF(STM32_DMAC_CH1)) {
|
||||
dma_clear_isr(STM32_DMAC_CH1);
|
||||
if (id[STM32_DMAC_CH1] != TASK_ID_INVALID)
|
||||
task_wake(id[STM32_DMAC_CH1]);
|
||||
}
|
||||
}
|
||||
DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_1, dma_event_interrupt_channel_1, 3);
|
||||
|
||||
void dma_event_interrupt_channel_2_3(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = STM32_DMAC_CH2; i <= STM32_DMAC_CH3; i++) {
|
||||
if (STM32_DMA1_REGS->isr & STM32_DMA_ISR_TCIF(i)) {
|
||||
dma_clear_isr(i);
|
||||
if (id[i] != TASK_ID_INVALID)
|
||||
task_wake(id[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_2_3, dma_event_interrupt_channel_2_3, 3);
|
||||
|
||||
void dma_event_interrupt_channel_4_7(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = STM32_DMAC_CH4; i <= STM32_DMAC_CH7; i++) {
|
||||
if (STM32_DMA1_REGS->isr & STM32_DMA_ISR_TCIF(i)) {
|
||||
dma_clear_isr(i);
|
||||
if (id[i] != TASK_ID_INVALID)
|
||||
task_wake(id[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_4_7, dma_event_interrupt_channel_4_7, 3);
|
||||
|
||||
#else /* !CHIP_FAMILY_STM32F0 */
|
||||
|
||||
void dma_event_interrupt_channel_4(void)
|
||||
{
|
||||
dma_clear_isr(STM32_DMAC_CH4);
|
||||
@@ -273,4 +322,4 @@ void dma_event_interrupt_channel_7(void)
|
||||
task_wake(id[STM32_DMAC_CH7]);
|
||||
}
|
||||
DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_7, dma_event_interrupt_channel_7, 3);
|
||||
#endif /* !CHIP_FAMILY_STM32F0 */
|
||||
#endif /* CHIP_FAMILY_STM32F0 */
|
||||
|
||||
@@ -214,14 +214,20 @@ int pd_write_last_edge(void *ctxt, int bit_off)
|
||||
|
||||
if (bit_idx == 0)
|
||||
msg[word_idx] = 0;
|
||||
|
||||
if (!b_toggle /* last bit was 0 */) {
|
||||
/* transition to 1, then 0 */
|
||||
msg[word_idx] |= 1 << bit_idx;
|
||||
/* transition to 1, another 1, then 0 */
|
||||
if (bit_idx == 31) {
|
||||
msg[word_idx++] |= 1 << bit_idx;
|
||||
msg[word_idx] = 1;
|
||||
} else {
|
||||
msg[word_idx] |= 3 << bit_idx;
|
||||
}
|
||||
}
|
||||
/* ensure that the trailer is 0 */
|
||||
msg[word_idx+1] = 0;
|
||||
|
||||
return bit_off + 2;
|
||||
return bit_off + 3;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMMON_RUNTIME
|
||||
@@ -257,6 +263,35 @@ static struct dma_option dma_tx_option = {
|
||||
STM32_DMA_CCR_MSIZE_8_BIT | STM32_DMA_CCR_PSIZE_8_BIT
|
||||
};
|
||||
|
||||
void pd_tx_spi_init(void)
|
||||
{
|
||||
stm32_spi_regs_t *spi = SPI_REGS;
|
||||
|
||||
/* Enable Tx DMA for our first transaction */
|
||||
spi->cr2 = STM32_SPI_CR2_TXDMAEN | STM32_SPI_CR2_DATASIZE(8);
|
||||
|
||||
#ifdef CONFIG_USB_PD_TX_USES_SPI_MASTER
|
||||
/*
|
||||
* Enable the master SPI: LSB first, force NSS, TX only, CPOL and CPHA
|
||||
* high.
|
||||
*/
|
||||
spi->cr1 = STM32_SPI_CR1_LSBFIRST | STM32_SPI_CR1_BIDIMODE
|
||||
| STM32_SPI_CR1_SSM | STM32_SPI_CR1_SSI
|
||||
| STM32_SPI_CR1_BIDIOE | STM32_SPI_CR1_MSTR
|
||||
| STM32_SPI_CR1_BR_DIV64R | STM32_SPI_CR1_SPE
|
||||
| STM32_SPI_CR1_CPOL | STM32_SPI_CR1_CPHA;
|
||||
|
||||
#if CPU_CLOCK != 38400000
|
||||
#error "CPU_CLOCK must be 38.4MHz to use SPI master for USB PD Tx"
|
||||
#endif
|
||||
#else
|
||||
/* Enable the slave SPI: LSB first, force NSS, TX only, CPHA */
|
||||
spi->cr1 = STM32_SPI_CR1_SPE | STM32_SPI_CR1_LSBFIRST
|
||||
| STM32_SPI_CR1_SSM | STM32_SPI_CR1_BIDIMODE
|
||||
| STM32_SPI_CR1_BIDIOE | STM32_SPI_CR1_CPHA;
|
||||
#endif
|
||||
}
|
||||
|
||||
void pd_tx_set_circular_mode(void)
|
||||
{
|
||||
dma_tx_option.flags |= STM32_DMA_CCR_CIRC;
|
||||
@@ -266,6 +301,15 @@ void pd_start_tx(void *ctxt, int polarity, int bit_len)
|
||||
{
|
||||
stm32_dma_chan_t *tx = dma_get_channel(DMAC_SPI_TX);
|
||||
|
||||
/* Initialize spi peripheral to prepare for transmission. */
|
||||
pd_tx_spi_init();
|
||||
|
||||
/*
|
||||
* Set timer to one tick before reset so that the first tick causes
|
||||
* a rising edge on the output.
|
||||
*/
|
||||
STM32_TIM_CNT(TIM_TX) = TX_CLOCK_DIV - 1;
|
||||
|
||||
/* update DMA configuration */
|
||||
dma_prepare_tx(&dma_tx_option, DIV_ROUND_UP(bit_len, 8), ctxt);
|
||||
/* Flush data in write buffer so that DMA can get the latest data */
|
||||
@@ -273,16 +317,23 @@ void pd_start_tx(void *ctxt, int polarity, int bit_len)
|
||||
|
||||
/* disable RX detection interrupt */
|
||||
pd_rx_disable_monitoring();
|
||||
/*
|
||||
* Drive the CC line from the TX block :
|
||||
* - set the low level reference.
|
||||
* - put SPI function on TX pin.
|
||||
*/
|
||||
pd_tx_enable(polarity);
|
||||
|
||||
/* Kick off the DMA to send the data */
|
||||
dma_clear_isr(DMAC_SPI_TX);
|
||||
#ifdef CONFIG_COMMON_RUNTIME
|
||||
dma_enable_tc_interrupt(DMAC_SPI_TX);
|
||||
#endif
|
||||
dma_go(tx);
|
||||
|
||||
/*
|
||||
* Drive the CC line from the TX block :
|
||||
* - put SPI function on TX pin.
|
||||
* - set the low level reference.
|
||||
* Call this last before enabling timer in order to meet spec on
|
||||
* timing between enabling TX and clocking out bits.
|
||||
*/
|
||||
pd_tx_enable(polarity);
|
||||
|
||||
#ifndef CONFIG_USB_PD_TX_USES_SPI_MASTER
|
||||
/* Start counting at 300Khz*/
|
||||
STM32_TIM_CR1(TIM_TX) |= 1;
|
||||
@@ -293,7 +344,12 @@ void pd_tx_done(int polarity)
|
||||
{
|
||||
stm32_spi_regs_t *spi = SPI_REGS;
|
||||
|
||||
dma_wait(DMAC_SPI_TX);
|
||||
/* wait for DMA */
|
||||
#ifdef CONFIG_COMMON_RUNTIME
|
||||
task_wait_event(DMA_TRANSFER_TIMEOUT_US);
|
||||
dma_disable_tc_interrupt(DMAC_SPI_TX);
|
||||
#endif
|
||||
|
||||
/* wait for real end of transmission */
|
||||
#ifdef CHIP_FAMILY_STM32F0
|
||||
while (spi->sr & STM32_SPI_SR_FTLVL)
|
||||
@@ -303,9 +359,6 @@ void pd_tx_done(int polarity)
|
||||
; /* wait for TXE == 1 */
|
||||
#endif
|
||||
|
||||
while (spi->sr & STM32_SPI_SR_BSY)
|
||||
; /* wait for BSY == 0 */
|
||||
|
||||
/*
|
||||
* At the end of transmitting, the last bit is guaranteed by the
|
||||
* protocol to be low, and it is necessary that the TX line stay low
|
||||
@@ -321,14 +374,23 @@ void pd_tx_done(int polarity)
|
||||
#ifndef CONFIG_USB_PD_TX_USES_SPI_MASTER
|
||||
/* ensure that we are not pushing out junk */
|
||||
*(uint8_t *)&spi->dr = 0;
|
||||
/* Stop counting */
|
||||
STM32_TIM_CR1(TIM_TX) &= ~1;
|
||||
while (spi->sr & STM32_SPI_SR_FTLVL)
|
||||
; /* wait for TX FIFO empty */
|
||||
#else
|
||||
while (spi->sr & STM32_SPI_SR_BSY)
|
||||
; /* wait for BSY == 0 */
|
||||
#endif
|
||||
/* clear transfer flag */
|
||||
dma_clear_isr(DMAC_SPI_TX);
|
||||
|
||||
/* put TX pins and reference in Hi-Z */
|
||||
pd_tx_disable(polarity);
|
||||
|
||||
#ifndef CONFIG_USB_PD_TX_USES_SPI_MASTER
|
||||
/* Stop counting */
|
||||
STM32_TIM_CR1(TIM_TX) &= ~1;
|
||||
|
||||
/* Reset SPI to clear remaining data in buffer */
|
||||
pd_tx_spi_reset();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --- RX operation using comparator linked to timer --- */
|
||||
@@ -405,8 +467,6 @@ void pd_hw_release(void)
|
||||
/* --- Startup initialization --- */
|
||||
void *pd_hw_init(void)
|
||||
{
|
||||
stm32_spi_regs_t *spi = SPI_REGS;
|
||||
|
||||
/* set 40 MHz pin speed on communication pins */
|
||||
pd_set_pins_speed();
|
||||
|
||||
@@ -418,29 +478,8 @@ void *pd_hw_init(void)
|
||||
/* Initialize TX pins and put them in Hi-Z */
|
||||
pd_tx_init();
|
||||
|
||||
/* Enable Tx DMA for our first transaction */
|
||||
spi->cr2 = STM32_SPI_CR2_TXDMAEN | STM32_SPI_CR2_DATASIZE(8);
|
||||
|
||||
#ifdef CONFIG_USB_PD_TX_USES_SPI_MASTER
|
||||
/*
|
||||
* Enable the master SPI: LSB first, force NSS, TX only, CPOL and CPHA
|
||||
* high.
|
||||
*/
|
||||
spi->cr1 = STM32_SPI_CR1_LSBFIRST | STM32_SPI_CR1_BIDIMODE
|
||||
| STM32_SPI_CR1_SSM | STM32_SPI_CR1_SSI
|
||||
| STM32_SPI_CR1_BIDIOE | STM32_SPI_CR1_MSTR
|
||||
| STM32_SPI_CR1_BR_DIV64R | STM32_SPI_CR1_SPE
|
||||
| STM32_SPI_CR1_CPOL | STM32_SPI_CR1_CPHA;
|
||||
|
||||
#if CPU_CLOCK != 38400000
|
||||
#error "CPU_CLOCK must be 38.4MHz to use SPI master for USB PD Tx"
|
||||
#endif
|
||||
#else
|
||||
/* Enable the slave SPI: LSB first, force NSS, TX only */
|
||||
spi->cr1 = STM32_SPI_CR1_SPE | STM32_SPI_CR1_LSBFIRST
|
||||
| STM32_SPI_CR1_SSM | STM32_SPI_CR1_BIDIMODE
|
||||
| STM32_SPI_CR1_BIDIOE;
|
||||
#endif
|
||||
/* Initialize SPI peripheral registers */
|
||||
pd_tx_spi_init();
|
||||
|
||||
/* configure TX DMA */
|
||||
dma_prepare_tx(&dma_tx_option, PD_MAX_RAW_SIZE, raw_samples);
|
||||
|
||||
Reference in New Issue
Block a user