diff options
Diffstat (limited to 'chip/stm32/clock-stm32l.c')
-rw-r--r-- | chip/stm32/clock-stm32l.c | 384 |
1 files changed, 0 insertions, 384 deletions
diff --git a/chip/stm32/clock-stm32l.c b/chip/stm32/clock-stm32l.c deleted file mode 100644 index bb0da42d14..0000000000 --- a/chip/stm32/clock-stm32l.c +++ /dev/null @@ -1,384 +0,0 @@ -/* Copyright 2012 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* Clocks and power management settings */ - -#include "chipset.h" -#include "clock.h" -#include "common.h" -#include "console.h" -#include "cpu.h" -#include "hooks.h" -#include "registers.h" -#include "util.h" - -#ifdef CONFIG_STM32L_FAKE_HIBERNATE -#include "extpower.h" -#include "keyboard_config.h" -#include "lid_switch.h" -#include "power.h" -#include "power_button.h" -#include "system.h" -#include "task.h" - -static int fake_hibernate; -#endif - -/* High-speed oscillator is 16 MHz */ -#define HSI_CLOCK 16000000 -/* - * MSI is 2 MHz (default) 1 MHz, depending on ICSCR setting. We use 1 MHz - * because it's the lowest clock rate we can still run 115200 baud serial - * for the debug console. - */ -#define MSI_2MHZ_CLOCK BIT(21) -#define MSI_1MHZ_CLOCK BIT(20) - -enum clock_osc { - OSC_INIT = 0, /* Uninitialized */ - OSC_HSI, /* High-speed oscillator */ - OSC_MSI, /* Med-speed oscillator @ 1 MHz */ -}; - -static int freq; -static int current_osc; - -int clock_get_freq(void) -{ - return freq; -} - -int clock_get_timer_freq(void) -{ - return clock_get_freq(); -} - -void clock_wait_bus_cycles(enum bus_type bus, uint32_t cycles) -{ - volatile uint32_t unused __attribute__((unused)); - - if (bus == BUS_AHB) { - while (cycles--) - unused = STM32_DMA1_REGS->isr; - } else { /* APB */ - while (cycles--) - unused = STM32_USART_BRR(STM32_USART1_BASE); - } -} - -/** - * Set which oscillator is used for the clock - * - * @param osc Oscillator to use - */ -static void clock_set_osc(enum clock_osc osc) -{ - uint32_t tmp_acr; - - if (osc == current_osc) - return; - - if (current_osc != OSC_INIT) - hook_notify(HOOK_PRE_FREQ_CHANGE); - - switch (osc) { - case OSC_HSI: - /* Ensure that HSI is ON */ - wait_for_ready(&STM32_RCC_CR, - STM32_RCC_CR_HSION, STM32_RCC_CR_HSIRDY); - - /* Disable LPSDSR */ - STM32_PWR_CR &= ~STM32_PWR_CR_LPSDSR; - - /* - * Set the recommended flash settings for 16MHz clock. - * - * The 3 bits must be programmed strictly sequentially. - * Also, follow the RM to check 64-bit access and latency bit - * after writing those bits to the FLASH_ACR register. - */ - tmp_acr = STM32_FLASH_ACR; - /* Enable 64-bit access */ - tmp_acr |= STM32_FLASH_ACR_ACC64; - STM32_FLASH_ACR = tmp_acr; - /* Check ACC64 bit == 1 */ - while (!(STM32_FLASH_ACR & STM32_FLASH_ACR_ACC64)) - ; - - /* Enable Prefetch Buffer */ - tmp_acr |= STM32_FLASH_ACR_PRFTEN; - STM32_FLASH_ACR = tmp_acr; - - /* Flash 1 wait state */ - tmp_acr |= STM32_FLASH_ACR_LATENCY; - STM32_FLASH_ACR = tmp_acr; - /* Check LATENCY bit == 1 */ - while (!(STM32_FLASH_ACR & STM32_FLASH_ACR_LATENCY)) - ; - - /* Switch to HSI */ - STM32_RCC_CFGR = STM32_RCC_CFGR_SW_HSI; - /* RM says to check SWS bits to make sure HSI is the sysclock */ - while ((STM32_RCC_CFGR & STM32_RCC_CFGR_SWS_MASK) != - STM32_RCC_CFGR_SWS_HSI) - ; - - /* Disable MSI */ - STM32_RCC_CR &= ~STM32_RCC_CR_MSION; - - freq = HSI_CLOCK; - break; - - case OSC_MSI: - /* Switch to MSI @ 1MHz */ - STM32_RCC_ICSCR = - (STM32_RCC_ICSCR & ~STM32_RCC_ICSCR_MSIRANGE_MASK) | - STM32_RCC_ICSCR_MSIRANGE_1MHZ; - /* Ensure that MSI is ON */ - wait_for_ready(&STM32_RCC_CR, - STM32_RCC_CR_MSION, STM32_RCC_CR_MSIRDY); - - /* Switch to MSI */ - STM32_RCC_CFGR = STM32_RCC_CFGR_SW_MSI; - /* RM says to check SWS bits to make sure MSI is the sysclock */ - while ((STM32_RCC_CFGR & STM32_RCC_CFGR_SWS_MASK) != - STM32_RCC_CFGR_SWS_MSI) - ; - - /* - * Set the recommended flash settings for <= 2MHz clock. - * - * The 3 bits must be programmed strictly sequentially. - * Also, follow the RM to check 64-bit access and latency bit - * after writing those bits to the FLASH_ACR register. - */ - tmp_acr = STM32_FLASH_ACR; - /* Flash 0 wait state */ - tmp_acr &= ~STM32_FLASH_ACR_LATENCY; - STM32_FLASH_ACR = tmp_acr; - /* Check LATENCY bit == 0 */ - while (STM32_FLASH_ACR & STM32_FLASH_ACR_LATENCY) - ; - - /* Disable prefetch Buffer */ - tmp_acr &= ~STM32_FLASH_ACR_PRFTEN; - STM32_FLASH_ACR = tmp_acr; - - /* Disable 64-bit access */ - tmp_acr &= ~STM32_FLASH_ACR_ACC64; - STM32_FLASH_ACR = tmp_acr; - /* Check ACC64 bit == 0 */ - while (STM32_FLASH_ACR & STM32_FLASH_ACR_ACC64) - ; - - /* Disable HSI */ - STM32_RCC_CR &= ~STM32_RCC_CR_HSION; - - /* Enable LPSDSR */ - STM32_PWR_CR |= STM32_PWR_CR_LPSDSR; - - freq = MSI_1MHZ_CLOCK; - break; - - default: - break; - } - - /* Notify modules of frequency change unless we're initializing */ - if (current_osc != OSC_INIT) { - current_osc = osc; - hook_notify(HOOK_FREQ_CHANGE); - } else { - current_osc = osc; - } -} - -static uint64_t clock_mask; - -void clock_enable_module(enum module_id module, int enable) -{ - uint64_t new_mask; - - if (enable) - new_mask = clock_mask | BIT_ULL(module); - else - new_mask = clock_mask & ~BIT_ULL(module); - - /* Only change clock if needed */ - if ((!!new_mask) != (!!clock_mask)) { - - /* Flush UART before switching clock speed */ - cflush(); - - clock_set_osc(new_mask ? OSC_HSI : OSC_MSI); - } - - if (module == MODULE_USB) { - if (enable) - STM32_RCC_APB1ENR |= STM32_RCC_PB1_USB; - else - STM32_RCC_APB1ENR &= ~STM32_RCC_PB1_USB; - } - - clock_mask = new_mask; -} - -int clock_is_module_enabled(enum module_id module) -{ - return !!(clock_mask & BIT_ULL(module)); -} - -#ifdef CONFIG_STM32L_FAKE_HIBERNATE -/* - * This is for NOT having enough hibernate (more precisely, the stand-by mode) - * wake-up source pin. STM32L100 supports 3 wake-up source pins: - * - * WKUP1 (PA0) -- used for ACOK_PMU - * WKUP2 (PC13) -- used for LID_OPEN - * WKUP3 (PE6) -- cannot be used due to IC package. - * - * However, we need the power button as a wake-up source as well and there is - * no available pin for us (we don't want to move the ACOK_PMU pin). - * - * Fortunately, the STM32L is low-power enough so that we don't need the - * super-low-power mode. So, we fake this hibernate mode and accept the - * following wake-up source. - * - * RTC alarm (faked as well). - * Power button - * Lid open - * AC detected - * - * The original issue is here: crosbug.com/p/25435. - */ -void __enter_hibernate(uint32_t seconds, uint32_t microseconds) -{ - int i; - fake_hibernate = 1; - -#ifdef CONFIG_POWER_COMMON - /* - * A quick hack to stop annoying messages from charger task. - * - * When the battery is under 3%, the power task would call - * power_off() to shutdown AP. However, the power_off() would - * notify the HOOK_CHIPSET_SHUTDOWN, where the last hook is - * charge_shutdown() and it hibernates the power task (infinite - * loop -- not real CPU hibernate mode). Unfortunately, the - * charger task is still running. It keeps generating annoying - * log message. - * - * Thus, the hack is to set the power state machine (before we - * enter infinite loop) so that the charger task thinks the AP - * is off and stops generating messages. - */ - power_set_state(POWER_G3); -#endif - - /* - * Change keyboard outputs to high-Z to reduce power draw. - * We don't need corresponding code to change them back, - * because fake hibernate is always exited with a reboot. - * - * A little hacky to do this here. - */ - for (i = GPIO_KB_OUT00; i < GPIO_KB_OUT00 + KEYBOARD_COLS_MAX; i++) - gpio_set_flags(i, GPIO_INPUT); - - ccprints("fake hibernate. waits for power button/lid/RTC/AC"); - cflush(); - - if (seconds || microseconds) { - if (seconds) - sleep(seconds); - if (microseconds) - usleep(microseconds); - } else { - while (1) - task_wait_event(-1); - } - - ccprints("fake RTC alarm fires. resets EC"); - cflush(); - system_reset(SYSTEM_RESET_HARD); -} - -static void fake_hibernate_power_button_hook(void) -{ - if (fake_hibernate && lid_is_open() && !power_button_is_pressed()) { - ccprints("%s() resets EC", __func__); - cflush(); - system_reset(SYSTEM_RESET_HARD); - } -} -DECLARE_HOOK(HOOK_POWER_BUTTON_CHANGE, fake_hibernate_power_button_hook, - HOOK_PRIO_DEFAULT); - -static void fake_hibernate_lid_hook(void) -{ - if (fake_hibernate && lid_is_open()) { - ccprints("%s() resets EC", __func__); - cflush(); - system_reset(SYSTEM_RESET_HARD); - } -} -DECLARE_HOOK(HOOK_LID_CHANGE, fake_hibernate_lid_hook, HOOK_PRIO_DEFAULT); - -static void fake_hibernate_ac_hook(void) -{ - if (fake_hibernate && extpower_is_present()) { - ccprints("%s() resets EC", __func__); - cflush(); - system_reset(SYSTEM_RESET_HARD); - } -} -DECLARE_HOOK(HOOK_AC_CHANGE, fake_hibernate_ac_hook, HOOK_PRIO_DEFAULT); -#endif - -void clock_init(void) -{ - /* - * The initial state : - * SYSCLK from MSI (=2MHz), no divider on AHB, APB1, APB2 - * PLL unlocked, RTC enabled on LSE - */ - - /* Switch to high-speed oscillator */ - clock_set_osc(1); -} - -static void clock_chipset_startup(void) -{ - /* Return to full speed */ - clock_enable_module(MODULE_CHIPSET, 1); -} -DECLARE_HOOK(HOOK_CHIPSET_STARTUP, clock_chipset_startup, HOOK_PRIO_DEFAULT); -DECLARE_HOOK(HOOK_CHIPSET_RESUME, clock_chipset_startup, HOOK_PRIO_DEFAULT); - -static void clock_chipset_shutdown(void) -{ - /* Drop to lower clock speed if no other module requires full speed */ - clock_enable_module(MODULE_CHIPSET, 0); -} -DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, clock_chipset_shutdown, HOOK_PRIO_DEFAULT); -DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, clock_chipset_shutdown, HOOK_PRIO_DEFAULT); - -static int command_clock(int argc, char **argv) -{ - if (argc >= 2) { - if (!strcasecmp(argv[1], "hsi")) - clock_set_osc(OSC_HSI); - else if (!strcasecmp(argv[1], "msi")) - clock_set_osc(OSC_MSI); - else - return EC_ERROR_PARAM1; - } - - ccprintf("Clock frequency is now %d Hz\n", freq); - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(clock, command_clock, - "hsi | msi", - "Set clock frequency"); |