summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/fruitpie/usb_pd_config.h4
-rw-r--r--chip/stm32/clock-stm32f0.c56
-rw-r--r--chip/stm32/registers.h2
-rw-r--r--chip/stm32/usb_pd_phy.c54
-rw-r--r--include/config.h3
5 files changed, 99 insertions, 20 deletions
diff --git a/board/fruitpie/usb_pd_config.h b/board/fruitpie/usb_pd_config.h
index e810c4025a..59c9852719 100644
--- a/board/fruitpie/usb_pd_config.h
+++ b/board/fruitpie/usb_pd_config.h
@@ -34,10 +34,6 @@ static inline void spi_enable_clock(void)
/* triggers packet detection on comparator falling edge */
#define EXTI_XTSR STM32_EXTI_FTSR
-
-/* Clock divider for RX edges timings (2.4Mhz counter from 48Mhz clock) */
-#define RX_CLOCK_DIV (20 - 1)
-
/* the pins used for communication need to be hi-speed */
static inline void pd_set_pins_speed(void)
{
diff --git a/chip/stm32/clock-stm32f0.c b/chip/stm32/clock-stm32f0.c
index df09e5b67b..3f503caad0 100644
--- a/chip/stm32/clock-stm32f0.c
+++ b/chip/stm32/clock-stm32f0.c
@@ -17,22 +17,18 @@
/* use 48Mhz USB-synchronized High-speed oscillator */
#define HSI48_CLOCK 48000000
+/* use PLL at 38.4MHz as system clock. */
+#define PLL_CLOCK 38400000
+
int clock_get_freq(void)
{
- return HSI48_CLOCK;
+ return CPU_CLOCK;
}
void clock_enable_module(enum module_id module, int enable)
{
}
-/*
- * system closk is HSI48 = 48MHz,
- * no prescaler, no MCO, no PLL
- * USB clock = HSI48
- */
-BUILD_ASSERT(CPU_CLOCK == HSI48_CLOCK);
-
void clock_init(void)
{
/*
@@ -52,10 +48,54 @@ void clock_init(void)
while (!(STM32_RCC_CR2 & (1 << 17)))
;
}
+
+#if (CPU_CLOCK == HSI48_CLOCK)
+ /*
+ * HSI48 = 48MHz, no prescaler, no MCO, no PLL
+ * therefore PCLK = FCLK = SYSCLK = 48MHz
+ * USB uses HSI48 = 48MHz
+ */
+
/* switch SYSCLK to HSI48 */
STM32_RCC_CFGR = 0x00000003;
/* wait until the HSI48 is the clock source */
while ((STM32_RCC_CFGR & 0xc) != 0xc)
;
+
+#elif (CPU_CLOCK == PLL_CLOCK)
+ /*
+ * HSI48 = 48MHz, no prescalar, no MCO, with PLL *4/5 => 38.4MHz SYSCLK
+ * therefore PCLK = FCLK = SYSCLK = 38.4MHz
+ * USB uses HSI48 = 48MHz
+ */
+
+ /* If PLL is the clock source, PLL has already been set up. */
+ if ((STM32_RCC_CFGR & 0xc) == 0x8)
+ return;
+
+ /*
+ * Specify HSI48 clock as input clock to PLL and set PLL multiplier
+ * and divider.
+ */
+ STM32_RCC_CFGR = 0x00098000;
+ STM32_RCC_CFGR2 = 0x4;
+
+ /* Enable the PLL. */
+ STM32_RCC_CR |= 0x01000000;
+
+ /* Wait until PLL is ready. */
+ while (!(STM32_RCC_CR & 0x02000000))
+ ;
+
+ /* Switch SYSCLK to PLL. */
+ STM32_RCC_CFGR |= 0x2;
+
+ /* wait until the PLL is the clock source */
+ while ((STM32_RCC_CFGR & 0xc) != 0x8)
+ ;
+
+#else
+#error "CPU_CLOCK must be either 48MHz or 38.4MHz"
+#endif
}
diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h
index 0752416a2f..9195fd3f81 100644
--- a/chip/stm32/registers.h
+++ b/chip/stm32/registers.h
@@ -686,6 +686,8 @@ typedef volatile struct stm32_spi_regs stm32_spi_regs_t;
#define STM32_SPI_CR1_BR_DIV64R (5 << 3)
#define STM32_SPI_CR1_BR_DIV4R (1 << 3)
#define STM32_SPI_CR1_MSTR (1 << 2)
+#define STM32_SPI_CR1_CPOL (1 << 1)
+#define STM32_SPI_CR1_CPHA (1 << 0)
#define STM32_SPI_CR2_RXNEIE (1 << 6)
#define STM32_SPI_CR2_SSOE (1 << 2)
#define STM32_SPI_CR2_RXDMAEN (1 << 0)
diff --git a/chip/stm32/usb_pd_phy.c b/chip/stm32/usb_pd_phy.c
index f325c1be05..a3e78ef0da 100644
--- a/chip/stm32/usb_pd_phy.c
+++ b/chip/stm32/usb_pd_phy.c
@@ -263,10 +263,8 @@ void pd_start_tx(void *ctxt, int bit_len)
/* 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 lastest data */
+ /* Flush data in write buffer so that DMA can get the latest data */
asm volatile("dmb;");
- /* Kick off the DMA to send the data */
- dma_go(tx);
/* disable RX detection interrupt */
pd_rx_disable_monitoring();
@@ -277,8 +275,13 @@ void pd_start_tx(void *ctxt, int bit_len)
*/
pd_tx_enable();
+ /* 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;
+#endif
}
void pd_tx_done(void)
@@ -294,14 +297,31 @@ void pd_tx_done(void)
while (!(spi->sr & (1<<1)))
; /* wait for TXE == 1 */
#endif
+
while (spi->sr & (1<<7))
; /* 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
+ * until pd_tx_disable().
+ *
+ * When using SPI slave mode for TX, this is done by writing out dummy
+ * 0 byte at end.
+ * When using SPI master mode, the CPOL and CPHA are set high, which
+ * means that after the last bit is transmitted there are no more
+ * clock edges. Hopefully, this is sufficient to guarantee that the
+ * MOSI line does not change before pd_tx_disable().
+ */
+#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;
- /* clear tranfer flag */
+#endif
+ /* clear transfer flag */
dma_clear_isr(DMAC_SPI_TX);
+
/* put TX pins and reference in Hi-Z */
pd_tx_disable();
}
@@ -380,14 +400,31 @@ void *pd_hw_init(void)
/* Enable Tx DMA for our first transaction */
spi->cr2 = STM32_SPI_CR2_TXDMAEN | STM32_SPI_CR2_DATASIZE(8);
- /* Enable the salve SPI: LSB first, force NSS, TX only */
+#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
/* configure TX DMA */
dma_prepare_tx(&dma_tx_option, PD_MAX_RAW_SIZE, raw_samples);
+#ifndef CONFIG_USB_PD_TX_USES_SPI_MASTER
/* --- set the TX timer with updates at 600KHz (BMC frequency) --- */
__hw_timer_enable_clock(TIM_TX, 1);
/* Timer configuration */
@@ -406,6 +443,7 @@ void *pd_hw_init(void)
STM32_TIM_PSC(TIM_TX) = 0;
/* Reload the pre-scaler and reset the counter */
STM32_TIM_EGR(TIM_TX) = 0x0001;
+#endif
/* --- set counter for RX timing : 2.4Mhz rate, free-running --- */
__hw_timer_enable_clock(TIM_RX, 1);
@@ -415,9 +453,9 @@ void *pd_hw_init(void)
STM32_TIM_DIER(TIM_RX) = 0x0000;
/* Auto-reload value : 16-bit free running counter */
STM32_TIM_ARR(TIM_RX) = 0xFFFF;
+
/* Timeout for message receive : 2.7ms */
- STM32_TIM_CCR2(TIM_RX) = clock_get_freq() / (RX_CLOCK_DIV + 1)
- * 27 / 10000 /* 2.7 ms */;
+ STM32_TIM_CCR2(TIM_RX) = 2400000 * 27 / 10000;
/* Timer ICx input configuration */
#if TIM_CCR_IDX == 1
STM32_TIM_CCMR1(TIM_RX) = TIM_CCR_CS << 0;
@@ -430,7 +468,7 @@ void *pd_hw_init(void)
/* configure DMA request on CCRx update */
STM32_TIM_DIER(TIM_RX) |= 1 << (8 + TIM_CCR_IDX); /* CCxDE */;
/* set prescaler to /26 (F=1.2Mhz, T=0.8us) */
- STM32_TIM_PSC(TIM_RX) = RX_CLOCK_DIV;
+ STM32_TIM_PSC(TIM_RX) = (clock_get_freq() / 2400000) - 1;
/* Reload the pre-scaler and reset the counter */
STM32_TIM_EGR(TIM_RX) = 0x0001 | (1 << TIM_CCR_IDX) /* clear CCRx */;
/* clear update event from reloading */
diff --git a/include/config.h b/include/config.h
index 56d18d26bb..ae51b24c26 100644
--- a/include/config.h
+++ b/include/config.h
@@ -843,6 +843,9 @@
/*****************************************************************************/
+/* USB PD transmit uses SPI master */
+#undef CONFIG_USB_PD_TX_USES_SPI_MASTER
+
/* Support simple control of power to the device's USB ports */
#undef CONFIG_USB_PORT_POWER_DUMB