diff options
-rw-r--r-- | board/fruitpie/usb_pd_config.h | 4 | ||||
-rw-r--r-- | chip/stm32/clock-stm32f0.c | 56 | ||||
-rw-r--r-- | chip/stm32/registers.h | 2 | ||||
-rw-r--r-- | chip/stm32/usb_pd_phy.c | 54 | ||||
-rw-r--r-- | include/config.h | 3 |
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 |