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 <victoryang@google.com>
Reviewed-on: https://chromium-review.googlesource.com/246181
Reviewed-by: Alec Berg <alecaberg@chromium.org>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Tested-by: Vic Yang <victoryang@chromium.org>
Commit-Queue: Vic Yang <victoryang@chromium.org>
This commit is contained in:
Vic Yang
2015-02-04 11:28:53 -08:00
committed by ChromeOS Commit Bot
parent a9ae00b101
commit 049463f8ad
22 changed files with 129 additions and 1 deletions

View File

@@ -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

View File

@@ -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 :

View File

@@ -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 */

View File

@@ -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)
{
/*

View File

@@ -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)
{
}

View File

@@ -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
*

View File

@@ -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;

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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();

View File

@@ -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.

View File

@@ -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

View File

@@ -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 */

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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.

View File

@@ -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 |

View File

@@ -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)