summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/firefly/usb_pd_config.h13
-rw-r--r--board/fruitpie/usb_pd_config.h11
-rw-r--r--board/samus_pd/usb_pd_config.h16
-rw-r--r--board/zinger/usb_pd_config.h12
-rw-r--r--chip/stm32/dma.c53
-rw-r--r--chip/stm32/usb_pd_phy.c119
6 files changed, 173 insertions, 51 deletions
diff --git a/board/firefly/usb_pd_config.h b/board/firefly/usb_pd_config.h
index 595b977d48..eea9688842 100644
--- a/board/firefly/usb_pd_config.h
+++ b/board/firefly/usb_pd_config.h
@@ -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 */
diff --git a/board/fruitpie/usb_pd_config.h b/board/fruitpie/usb_pd_config.h
index 0f51c87038..685d11af3b 100644
--- a/board/fruitpie/usb_pd_config.h
+++ b/board/fruitpie/usb_pd_config.h
@@ -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 */
diff --git a/board/samus_pd/usb_pd_config.h b/board/samus_pd/usb_pd_config.h
index 4381e81791..9f09ad5793 100644
--- a/board/samus_pd/usb_pd_config.h
+++ b/board/samus_pd/usb_pd_config.h
@@ -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 */
diff --git a/board/zinger/usb_pd_config.h b/board/zinger/usb_pd_config.h
index 4383e24e32..73959ff787 100644
--- a/board/zinger/usb_pd_config.h
+++ b/board/zinger/usb_pd_config.h
@@ -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 */
diff --git a/chip/stm32/dma.c b/chip/stm32/dma.c
index e648b7418e..75073b4db6 100644
--- a/chip/stm32/dma.c
+++ b/chip/stm32/dma.c
@@ -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 */
diff --git a/chip/stm32/usb_pd_phy.c b/chip/stm32/usb_pd_phy.c
index b4fefa8fa4..7d514840a1 100644
--- a/chip/stm32/usb_pd_phy.c
+++ b/chip/stm32/usb_pd_phy.c
@@ -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();
+
+ /* 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 :
- * - set the low level reference.
* - 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);
- /* Kick off the DMA to send the data */
- dma_go(tx);
-
#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);