From 049463f8ad985f9cb996caa7dbc5438383bd3084 Mon Sep 17 00:00:00 2001 From: Vic Yang Date: Wed, 4 Feb 2015 11:28:53 -0800 Subject: stm32: Add delay after enabling peripheral clock We need a dummy read after enabling AHB peripheral clock before we can access the peripheral. For APB, we also need a dummy read for STM32F3. BRANCH=All affected BUG=chrome-os-partner:33007 TEST=make buildall Change-Id: I47f4a024dca294f555428c3f2053c1d32835ebe0 Signed-off-by: Vic Yang Reviewed-on: https://chromium-review.googlesource.com/246181 Reviewed-by: Alec Berg Reviewed-by: Randall Spangler Tested-by: Vic Yang Commit-Queue: Vic Yang --- board/ryu/usb_pd_config.h | 3 +++ board/ryu_sh/board.c | 3 +++ chip/stm32/adc-stm32f.c | 6 ++++++ chip/stm32/clock-stm32f.c | 13 +++++++++++++ chip/stm32/clock-stm32f0.c | 13 +++++++++++++ chip/stm32/clock-stm32l.c | 13 +++++++++++++ chip/stm32/crc_hw.h | 3 +++ chip/stm32/dma.c | 3 +++ chip/stm32/gpio-stm32f.c | 4 ++++ chip/stm32/gpio-stm32f0.c | 4 ++++ chip/stm32/gpio-stm32f3.c | 4 ++++ chip/stm32/gpio-stm32l.c | 4 ++++ chip/stm32/gpio.c | 4 ++++ chip/stm32/hwtimer.c | 6 ++++++ chip/stm32/hwtimer32.c | 4 ++++ chip/stm32/i2c-stm32f.c | 3 +++ chip/stm32/spi.c | 4 ++++ chip/stm32/system.c | 3 +++ chip/stm32/uart.c | 6 ++++++ chip/stm32/usart.c | 6 ++++++ chip/stm32/usb_pd_phy.c | 4 ++++ include/clock.h | 17 ++++++++++++++++- 22 files changed, 129 insertions(+), 1 deletion(-) diff --git a/board/ryu/usb_pd_config.h b/board/ryu/usb_pd_config.h index 4985454675..d5992e3335 100644 --- a/board/ryu/usb_pd_config.h +++ b/board/ryu/usb_pd_config.h @@ -9,6 +9,7 @@ #define __USB_PD_CONFIG_H #include "charge_state.h" +#include "clock.h" #include "registers.h" /* Port and task configuration */ @@ -46,6 +47,8 @@ static inline void spi_enable_clock(int port) { STM32_RCC_APB2ENR |= STM32_RCC_PB2_SPI1; + /* Delay 1 APB clock cycle after the clock is enabled */ + clock_wait_bus_cycles(BUS_APB, 1); } #define DMAC_SPI_TX(p) STM32_DMAC_CH3 diff --git a/board/ryu_sh/board.c b/board/ryu_sh/board.c index 34ed7df7e2..2266e7d95a 100644 --- a/board/ryu_sh/board.c +++ b/board/ryu_sh/board.c @@ -4,6 +4,7 @@ */ /* ryu sensor hub configuration */ +#include "clock.h" #include "common.h" #include "console.h" #include "driver/accelgyro_lsm6ds0.h" @@ -64,6 +65,8 @@ void board_config_pre_init(void) * and the register write as no effect. */ STM32_RCC_APB2ENR |= 1 << 0; + /* Delay 1 APB clock cycle after the clock is enabled */ + clock_wait_bus_cycles(BUS_APB, 1); /* * Remap USART DMA to match the USART driver * the DMA mapping is : diff --git a/chip/stm32/adc-stm32f.c b/chip/stm32/adc-stm32f.c index 7a92130ece..d6ff369ef9 100644 --- a/chip/stm32/adc-stm32f.c +++ b/chip/stm32/adc-stm32f.c @@ -266,6 +266,12 @@ static void adc_init(void) */ STM32_RCC_APB2ENR |= (1 << 9); + /* + * ADC clock is divided with respect to AHB, so no delay needed + * here. If ADC clock is the same as AHB, a dummy read on ADC + * register is needed here. + */ + if (!adc_powered()) { /* Power on ADC module */ STM32_ADC_CR2 |= (1 << 0); /* ADON */ diff --git a/chip/stm32/clock-stm32f.c b/chip/stm32/clock-stm32f.c index 76278c9c01..029c34bd09 100644 --- a/chip/stm32/clock-stm32f.c +++ b/chip/stm32/clock-stm32f.c @@ -265,6 +265,19 @@ int clock_get_freq(void) return CPU_CLOCK; } +void clock_wait_bus_cycles(enum bus_type bus, uint32_t cycles) +{ + volatile uint32_t dummy __attribute__((unused)); + + if (bus == BUS_AHB) { + while (cycles--) + dummy = STM32_DMA1_REGS->isr; + } else { /* APB */ + while (cycles--) + dummy = STM32_USART_BRR(STM32_USART1_BASE); + } +} + void clock_init(void) { /* diff --git a/chip/stm32/clock-stm32f0.c b/chip/stm32/clock-stm32f0.c index 74534eee3a..6dfe0a1447 100644 --- a/chip/stm32/clock-stm32f0.c +++ b/chip/stm32/clock-stm32f0.c @@ -418,6 +418,19 @@ int clock_get_freq(void) return CPU_CLOCK; } +void clock_wait_bus_cycles(enum bus_type bus, uint32_t cycles) +{ + volatile uint32_t dummy __attribute__((unused)); + + if (bus == BUS_AHB) { + while (cycles--) + dummy = STM32_DMA1_REGS->isr; + } else { /* APB */ + while (cycles--) + dummy = STM32_USART_BRR(STM32_USART1_BASE); + } +} + void clock_enable_module(enum module_id module, int enable) { } diff --git a/chip/stm32/clock-stm32l.c b/chip/stm32/clock-stm32l.c index e0c7ebc747..c8b8bc0683 100644 --- a/chip/stm32/clock-stm32l.c +++ b/chip/stm32/clock-stm32l.c @@ -50,6 +50,19 @@ int clock_get_freq(void) return freq; } +void clock_wait_bus_cycles(enum bus_type bus, uint32_t cycles) +{ + volatile uint32_t dummy __attribute__((unused)); + + if (bus == BUS_AHB) { + while (cycles--) + dummy = STM32_DMA1_REGS->isr; + } else { /* APB */ + while (cycles--) + dummy = STM32_USART_BRR(STM32_USART1_BASE); + } +} + /** * Set which oscillator is used for the clock * diff --git a/chip/stm32/crc_hw.h b/chip/stm32/crc_hw.h index c1a97da842..edaf3b5d32 100644 --- a/chip/stm32/crc_hw.h +++ b/chip/stm32/crc_hw.h @@ -7,12 +7,15 @@ #define _CRC_HW_H /* CRC-32 hardware implementation with USB constants */ +#include "clock.h" #include "registers.h" static inline void crc32_init(void) { /* switch on CRC controller */ STM32_RCC_AHBENR |= 1 << 6; /* switch on CRC controller */ + /* Delay 1 AHB clock cycle after the clock is enabled */ + clock_wait_bus_cycles(BUS_AHB, 1); /* reset CRC state */ STM32_CRC_CR = STM32_CRC_CR_RESET | STM32_CRC_CR_REV_OUT | STM32_CRC_CR_REV_IN_WORD; diff --git a/chip/stm32/dma.c b/chip/stm32/dma.c index 096ec45186..2a4f4aeb4a 100644 --- a/chip/stm32/dma.c +++ b/chip/stm32/dma.c @@ -3,6 +3,7 @@ * found in the LICENSE file. */ +#include "clock.h" #include "common.h" #include "console.h" #include "dma.h" @@ -211,6 +212,8 @@ void dma_init(void) { /* Enable DMA1; current chips don't have DMA2 */ STM32_RCC_AHBENR |= STM32_RCC_HB_DMA1; + /* Delay 1 AHB clock cycle after the clock is enabled */ + clock_wait_bus_cycles(BUS_AHB, 1); } int dma_wait(enum dma_channel channel) diff --git a/chip/stm32/gpio-stm32f.c b/chip/stm32/gpio-stm32f.c index 147f461528..9a381edfee 100644 --- a/chip/stm32/gpio-stm32f.c +++ b/chip/stm32/gpio-stm32f.c @@ -5,6 +5,7 @@ /* GPIO module for Chrome EC */ +#include "clock.h" #include "common.h" #include "gpio.h" #include "hooks.h" @@ -116,6 +117,9 @@ void gpio_enable_clocks(void) #else STM32_RCC_APB2ENR |= 0x1fd; #endif + + /* Delay 1 APB clock cycle after the clock is enabled */ + clock_wait_bus_cycles(BUS_APB, 1); } void gpio_set_alternate_function(uint32_t port, uint32_t mask, int func) diff --git a/chip/stm32/gpio-stm32f0.c b/chip/stm32/gpio-stm32f0.c index 58a28a25f1..5418399595 100644 --- a/chip/stm32/gpio-stm32f0.c +++ b/chip/stm32/gpio-stm32f0.c @@ -5,6 +5,7 @@ /* GPIO module for Chrome EC */ +#include "clock.h" #include "common.h" #include "gpio.h" #include "hooks.h" @@ -26,6 +27,9 @@ void gpio_enable_clocks(void) * and support disabling some of them in low-power idle. */ STM32_RCC_AHBENR |= 0x7e0000; + + /* Delay 1 AHB clock cycle after the clock is enabled */ + clock_wait_bus_cycles(BUS_AHB, 1); } static void gpio_init(void) diff --git a/chip/stm32/gpio-stm32f3.c b/chip/stm32/gpio-stm32f3.c index 462a5be859..9efddab7fc 100644 --- a/chip/stm32/gpio-stm32f3.c +++ b/chip/stm32/gpio-stm32f3.c @@ -5,6 +5,7 @@ /* GPIO module for Chrome EC */ +#include "clock.h" #include "common.h" #include "gpio.h" #include "hooks.h" @@ -26,6 +27,9 @@ void gpio_enable_clocks(void) * and support disabling some of them in low-power idle. */ STM32_RCC_AHBENR |= 0x7e0000; + + /* Delay 1 AHB clock cycle after the clock is enabled */ + clock_wait_bus_cycles(BUS_AHB, 1); } static void gpio_init(void) diff --git a/chip/stm32/gpio-stm32l.c b/chip/stm32/gpio-stm32l.c index 44282fc5c0..c015112503 100644 --- a/chip/stm32/gpio-stm32l.c +++ b/chip/stm32/gpio-stm32l.c @@ -5,6 +5,7 @@ /* GPIO module for Chrome EC */ +#include "clock.h" #include "common.h" #include "gpio.h" #include "hooks.h" @@ -26,6 +27,9 @@ void gpio_enable_clocks(void) * and support disabling some of them in low-power idle. */ STM32_RCC_AHBENR |= 0x3f; + + /* Delay 1 AHB clock cycle after the clock is enabled */ + clock_wait_bus_cycles(BUS_AHB, 1); } static void gpio_init(void) diff --git a/chip/stm32/gpio.c b/chip/stm32/gpio.c index 0c73081b42..6715e540b0 100644 --- a/chip/stm32/gpio.c +++ b/chip/stm32/gpio.c @@ -5,6 +5,7 @@ /* GPIO module for Chrome EC */ +#include "clock.h" #include "common.h" #include "console.h" #include "gpio.h" @@ -28,6 +29,9 @@ void gpio_pre_init(void) /* Required to configure external IRQ lines (SYSCFG_EXTICRn) */ STM32_RCC_APB2ENR |= 1 << 0; + /* Delay 1 APB clock cycle after the clock is enabled */ + clock_wait_bus_cycles(BUS_APB, 1); + if (!is_warm) gpio_enable_clocks(); diff --git a/chip/stm32/hwtimer.c b/chip/stm32/hwtimer.c index 14a9bc7f2b..9e8f959553 100644 --- a/chip/stm32/hwtimer.c +++ b/chip/stm32/hwtimer.c @@ -320,6 +320,9 @@ int __hw_clock_source_init(uint32_t start_t) __hw_timer_enable_clock(TIM_CLOCK_MSB, 1); __hw_timer_enable_clock(TIM_CLOCK_LSB, 1); + /* Delay 1 APB clock cycle after the clock is enabled */ + clock_wait_bus_cycles(BUS_APB, 1); + /* * Timer configuration : Upcounter, counter disabled, update event only * on overflow. @@ -405,6 +408,9 @@ void hwtimer_setup_watchdog(void) /* Enable clock */ __hw_timer_enable_clock(TIM_WATCHDOG, 1); + /* Delay 1 APB clock cycle after the clock is enabled */ + clock_wait_bus_cycles(BUS_APB, 1); + /* * Timer configuration : Down counter, counter disabled, update * event only on overflow. diff --git a/chip/stm32/hwtimer32.c b/chip/stm32/hwtimer32.c index 4dc4c8cdb7..691e2f90f7 100644 --- a/chip/stm32/hwtimer32.c +++ b/chip/stm32/hwtimer32.c @@ -148,6 +148,8 @@ int __hw_clock_source_init(uint32_t start_t) { /* Enable TIM peripheral block clocks */ __hw_timer_enable_clock(TIM_CLOCK32, 1); + /* Delay 1 APB clock cycle after the clock is enabled */ + clock_wait_bus_cycles(BUS_APB, 1); /* * Timer configuration : Upcounter, counter disabled, update event only @@ -218,6 +220,8 @@ void hwtimer_setup_watchdog(void) { /* Enable clock */ __hw_timer_enable_clock(TIM_WATCHDOG, 1); + /* Delay 1 APB clock cycle after the clock is enabled */ + clock_wait_bus_cycles(BUS_APB, 1); /* * Timer configuration : Up counter, counter disabled, update diff --git a/chip/stm32/i2c-stm32f.c b/chip/stm32/i2c-stm32f.c index 88728f1eb1..75d1587c76 100644 --- a/chip/stm32/i2c-stm32f.c +++ b/chip/stm32/i2c-stm32f.c @@ -343,6 +343,9 @@ static void i2c_init_port(unsigned int port) /* enable I2C2 clock */ STM32_RCC_APB1ENR |= 1 << i2c_clock_bit[port]; + + /* Delay 1 APB clock cycle after the clock is enabled */ + clock_wait_bus_cycles(BUS_APB, 1); } /* force reset of the i2c peripheral */ diff --git a/chip/stm32/spi.c b/chip/stm32/spi.c index d8c88ba34f..21984618be 100644 --- a/chip/stm32/spi.c +++ b/chip/stm32/spi.c @@ -9,6 +9,7 @@ */ #include "chipset.h" +#include "clock.h" #include "console.h" #include "dma.h" #include "gpio.h" @@ -630,6 +631,9 @@ static void spi_init(void) /* Enable clocks to SPI1 module */ STM32_RCC_APB2ENR |= STM32_RCC_PB2_SPI1; + /* Delay 1 APB clock cycle after the clock is enabled */ + clock_wait_bus_cycles(BUS_APB, 1); + /* * Enable rx/tx DMA and get ready to receive our first transaction and * "disable" FIFO by setting event to happen after only 1 byte diff --git a/chip/stm32/system.c b/chip/stm32/system.c index 52b200ea11..890c704924 100644 --- a/chip/stm32/system.c +++ b/chip/stm32/system.c @@ -5,6 +5,7 @@ /* System module for Chrome EC : hardware specific implementation */ +#include "clock.h" #include "console.h" #include "cpu.h" #include "flash.h" @@ -165,6 +166,8 @@ void system_pre_init(void) STM32_RCC_APB1ENR |= 1 << 28; /* enable backup registers */ STM32_RCC_APB1ENR |= 1 << 27; + /* Delay 1 APB clock cycle after the clock is enabled */ + clock_wait_bus_cycles(BUS_APB, 1); /* Enable access to RCC CSR register and RTC backup registers */ STM32_PWR_CR |= 1 << 8; diff --git a/chip/stm32/uart.c b/chip/stm32/uart.c index 3544b95efe..33ef1064f0 100644 --- a/chip/stm32/uart.c +++ b/chip/stm32/uart.c @@ -279,6 +279,12 @@ void uart_init(void) STM32_RCC_APB1ENR |= CONCAT2(STM32_RCC_PB1_USART, UARTN); #endif + /* + * For STM32F3, A delay of 1 APB clock cycles is needed before we + * can access any USART register. Fortunately, we have + * gpio_config_module() below and thus don't need to add the delay. + */ + /* Configure GPIOs */ gpio_config_module(MODULE_UART, 1); diff --git a/chip/stm32/usart.c b/chip/stm32/usart.c index 264fa35a75..29cb0b705f 100644 --- a/chip/stm32/usart.c +++ b/chip/stm32/usart.c @@ -75,6 +75,12 @@ void usart_init(struct usart_config const *config) */ *(config->hw->clock_register) |= config->hw->clock_enable; + /* + * For STM32F3, A delay of 1 APB clock cycles is needed before we + * can access any USART register. Fortunately, we have + * gpio_config_module() below and thus don't need to add the delay. + */ + /* * Switch all GPIOs assigned to the USART module over to their USART * alternate functions. diff --git a/chip/stm32/usb_pd_phy.c b/chip/stm32/usb_pd_phy.c index 1a09b8e07a..e0f3204b1b 100644 --- a/chip/stm32/usb_pd_phy.c +++ b/chip/stm32/usb_pd_phy.c @@ -582,6 +582,8 @@ void pd_hw_init(int port) #ifdef CONFIG_PD_USE_DAC_AS_REF /* Enable DAC interface clock. */ STM32_RCC_APB1ENR |= (1 << 29); + /* Delay 1 APB clock cycle after the clock is enabled */ + clock_wait_bus_cycles(BUS_APB, 1); /* set voltage Vout=0.850V (Vref = 3.0V) */ STM32_DAC_DHR12RD = 850 * 4096 / 3000; /* Start DAC channel 1 */ @@ -593,6 +595,8 @@ void pd_hw_init(int port) #if defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32F3) /* turn on COMP/SYSCFG */ STM32_RCC_APB2ENR |= 1 << 0; + /* Delay 1 APB clock cycle after the clock is enabled */ + clock_wait_bus_cycles(BUS_APB, 1); /* currently in hi-speed mode : TODO revisit later, INM = PA0(INM6) */ STM32_COMP_CSR = STM32_COMP_CMP1MODE_LSPEED | STM32_COMP_CMP1INSEL_INM6 | diff --git a/include/clock.h b/include/clock.h index 62c38bcd6a..7702ca85eb 100644 --- a/include/clock.h +++ b/include/clock.h @@ -47,7 +47,7 @@ void clock_enable_module(enum module_id module, int enable); void clock_enable_pll(int enable, int notify); /** - * Wait for a number of clock cycles. + * Wait for a number of CPU clock cycles. * * Simple busy waiting for use before clocks/timers are initialized. * @@ -55,6 +55,21 @@ void clock_enable_pll(int enable, int notify); */ void clock_wait_cycles(uint32_t cycles); +enum bus_type { + BUS_AHB, + BUS_APB, +}; + +/** + * Wait for a number of peripheral bus clock cycles. + * + * Dummy read on peripherals for delay. + * + * @param bus Which bus clock cycle to use. + * @param cycles Number of cycles to wait. + */ +void clock_wait_bus_cycles(enum bus_type bus, uint32_t cycles); + /* Clock gate control modes for clock_enable_peripheral() */ #define CGC_MODE_RUN (1 << 0) #define CGC_MODE_SLEEP (1 << 1) -- cgit v1.2.1