/*************************************************************************** * * Copyright 2015-2019 BES. * All rights reserved. All unpublished rights reserved. * * No part of this work may be used or reproduced in any form or by any * means, or stored in a database or retrieval system, without prior written * permission of BES. * * Use of this work is governed by a license granted by BES. * This work contains confidential and proprietary information of * BES. which is protected by copyright, trade secret, * trademark and other intellectual property rights. * ****************************************************************************/ #include "plat_addr_map.h" #include CHIP_SPECIFIC_HDR(reg_cmu) #include CHIP_SPECIFIC_HDR(reg_aoncmu) #include CHIP_SPECIFIC_HDR(reg_btcmu) #include "hal_cmu.h" #include "hal_aud.h" #include "hal_bootmode.h" #include "hal_chipid.h" #include "hal_codec.h" #include "hal_location.h" #include "hal_psc.h" #include "hal_sleep_core_pd.h" #include "hal_sysfreq.h" #include "hal_timer.h" #include "hal_trace.h" #include "cmsis_nvic.h" #include "pmu.h" #include "system_cp.h" #ifdef USB_HIGH_SPEED #ifndef USB_USE_USBPLL #define USB_USE_USBPLL #endif #endif #define CODEC_CLK_FROM_ANA #define HAL_CMU_USB_PLL_CLOCK (192 * 1000 * 1000) #define HAL_CMU_AUD_PLL_CLOCK (CODEC_FREQ_48K_SERIES * CODEC_CMU_DIV) #define HAL_CMU_USB_CLOCK_60M (60 * 1000 * 1000) #define HAL_CMU_USB_CLOCK_48M (48 * 1000 * 1000) #define HAL_CMU_PLL_LOCKED_TIMEOUT US_TO_TICKS(200) #define HAL_CMU_26M_READY_TIMEOUT MS_TO_TICKS(4) #define HAL_CMU_LPU_EXTRA_TIMEOUT MS_TO_TICKS(1) #ifdef CORE_SLEEP_POWER_DOWN #define TIMER1_SEL_LOC BOOT_TEXT_SRAM_LOC #else #define TIMER1_SEL_LOC BOOT_TEXT_FLASH_LOC #endif enum CMU_USB_CLK_SRC_T { CMU_USB_CLK_SRC_PLL_60M = 0, CMU_USB_CLK_SRC_PLL_60M_ALT = 1, CMU_USB_CLK_SRC_PLL_48M = 2, CMU_USB_CLK_SRC_TS = 3, CMU_USB_CLK_SRC_OSC_48M = 4, CMU_USB_CLK_SRC_OSC_24M_X2 = 5, CMU_USB_CLK_SRC_OSC_26M_X4 = 6, CMU_USB_CLK_SRC_OSC_26M_X2 = 7, }; enum CMU_AUD_26M_X4_USER_T { CMU_AUD_26M_X4_USER_IIR, CMU_AUD_26M_X4_USER_RS, CMU_AUD_26M_X4_USER_QTY, }; enum CMU_DEBUG_REG_SEL_T { CMU_DEBUG_REG_SEL_MCU_PC = 0, CMU_DEBUG_REG_SEL_MCU_LR = 1, CMU_DEBUG_REG_SEL_MCU_SP = 2, CMU_DEBUG_REG_SEL_CP_PC = 3, CMU_DEBUG_REG_SEL_CP_LR = 4, CMU_DEBUG_REG_SEL_CP_SP = 5, CMU_DEBUG_REG_SEL_DEBUG = 7, }; struct CP_STARTUP_CFG_T { __IO uint32_t stack; __IO uint32_t reset_hdlr; __IO uint32_t entry; }; static struct CMU_T * const cmu = (struct CMU_T *)CMU_BASE; static struct AONCMU_T * const aoncmu = (struct AONCMU_T *)AON_CMU_BASE; static struct BTCMU_T * const POSSIBLY_UNUSED btcmu = (struct BTCMU_T *)BT_CMU_BASE; static struct CP_STARTUP_CFG_T * const cp_cfg = (struct CP_STARTUP_CFG_T *)0x200F7FE0; #define HAL_CMU_PLL_USB_HS HAL_CMU_PLL_QTY #ifdef USB_USE_USBPLL #define PLL_USER_MAP_NUM (HAL_CMU_PLL_QTY + 1) #else #define PLL_USER_MAP_NUM HAL_CMU_PLL_QTY #endif static uint8_t BOOT_BSS_LOC pll_user_map[PLL_USER_MAP_NUM]; STATIC_ASSERT(HAL_CMU_PLL_USER_QTY <= sizeof(pll_user_map[0]) * 8, "Too many PLL users"); #ifdef ROM_BUILD static enum HAL_CMU_USB_CLOCK_SEL_T usb_clk_sel; #endif static bool anc_enabled; #ifdef __AUDIO_RESAMPLE__ static bool aud_resample_en = true; #ifdef ANA_26M_X4_ENABLE static uint8_t aud_26m_x4_map; STATIC_ASSERT(CMU_AUD_26M_X4_USER_QTY <= sizeof(aud_26m_x4_map) * 8, "Too many aud_26m_x4 users"); #endif #endif #ifdef LOW_SYS_FREQ static enum HAL_CMU_LOW_SYS_FREQ_T BOOT_BSS_LOC low_sys_freq; static bool BOOT_BSS_LOC low_sys_freq_en; #endif void hal_cmu_audio_resample_enable(void) { #ifdef __AUDIO_RESAMPLE__ aud_resample_en = true; #endif } void hal_cmu_audio_resample_disable(void) { #ifdef __AUDIO_RESAMPLE__ aud_resample_en = false; #endif } int hal_cmu_get_audio_resample_status(void) { #ifdef __AUDIO_RESAMPLE__ return aud_resample_en; #else return false; #endif } static inline void aocmu_reg_update_wait(void) { // Make sure AOCMU (26M clock domain) write opertions finish before return aoncmu->CHIP_ID; } int hal_cmu_clock_enable(enum HAL_CMU_MOD_ID_T id) { if (id >= HAL_CMU_AON_MCU) { return 1; } if (id < HAL_CMU_MOD_P_CMU) { cmu->HCLK_ENABLE = (1 << id); } else if (id < HAL_CMU_MOD_O_SLEEP) { cmu->PCLK_ENABLE = (1 << (id - HAL_CMU_MOD_P_CMU)); } else if (id < HAL_CMU_AON_A_CMU) { cmu->OCLK_ENABLE = (1 << (id - HAL_CMU_MOD_O_SLEEP)); } else { aoncmu->MOD_CLK_ENABLE = (1 << (id - HAL_CMU_AON_A_CMU)); aocmu_reg_update_wait(); } return 0; } int hal_cmu_clock_disable(enum HAL_CMU_MOD_ID_T id) { if (id >= HAL_CMU_AON_MCU) { return 1; } if (id < HAL_CMU_MOD_P_CMU) { cmu->HCLK_DISABLE = (1 << id); } else if (id < HAL_CMU_MOD_O_SLEEP) { cmu->PCLK_DISABLE = (1 << (id - HAL_CMU_MOD_P_CMU)); } else if (id < HAL_CMU_AON_A_CMU) { cmu->OCLK_DISABLE = (1 << (id - HAL_CMU_MOD_O_SLEEP)); } else { aoncmu->MOD_CLK_DISABLE = (1 << (id - HAL_CMU_AON_A_CMU)); } return 0; } enum HAL_CMU_CLK_STATUS_T hal_cmu_clock_get_status(enum HAL_CMU_MOD_ID_T id) { uint32_t status; if (id >= HAL_CMU_AON_MCU) { return HAL_CMU_CLK_DISABLED; } if (id < HAL_CMU_MOD_P_CMU) { status = cmu->HCLK_ENABLE & (1 << id); } else if (id < HAL_CMU_MOD_O_SLEEP) { status = cmu->PCLK_ENABLE & (1 << (id - HAL_CMU_MOD_P_CMU)); } else if (id < HAL_CMU_AON_A_CMU) { status = cmu->OCLK_ENABLE & (1 << (id - HAL_CMU_MOD_O_SLEEP)); } else { status = aoncmu->MOD_CLK_ENABLE & (1 << (id - HAL_CMU_AON_A_CMU)); } return status ? HAL_CMU_CLK_ENABLED : HAL_CMU_CLK_DISABLED; } int hal_cmu_clock_set_mode(enum HAL_CMU_MOD_ID_T id, enum HAL_CMU_CLK_MODE_T mode) { __IO uint32_t *reg; uint32_t val; uint32_t lock; if (id >= HAL_CMU_AON_MCU) { return 1; } if (id < HAL_CMU_MOD_P_CMU) { reg = &cmu->HCLK_MODE; val = (1 << id); } else if (id < HAL_CMU_MOD_O_SLEEP) { reg = &cmu->PCLK_MODE; val = (1 << (id - HAL_CMU_MOD_P_CMU)); } else if (id < HAL_CMU_AON_A_CMU) { reg = &cmu->OCLK_MODE; val = (1 << (id - HAL_CMU_MOD_O_SLEEP)); } else { reg = &aoncmu->MOD_CLK_MODE; val = (1 << (id - HAL_CMU_AON_A_CMU)); } lock = int_lock(); if (mode == HAL_CMU_CLK_MANUAL) { *reg |= val; } else { *reg &= ~val; } int_unlock(lock); return 0; } enum HAL_CMU_CLK_MODE_T hal_cmu_clock_get_mode(enum HAL_CMU_MOD_ID_T id) { uint32_t mode; if (id >= HAL_CMU_AON_MCU) { return HAL_CMU_CLK_AUTO; } if (id < HAL_CMU_MOD_P_CMU) { mode = cmu->HCLK_MODE & (1 << id); } else if (id < HAL_CMU_MOD_O_SLEEP) { mode = cmu->PCLK_MODE & (1 << (id - HAL_CMU_MOD_P_CMU)); } else if (id < HAL_CMU_AON_A_CMU) { mode = cmu->OCLK_MODE & (1 << (id - HAL_CMU_MOD_O_SLEEP)); } else { mode = aoncmu->MOD_CLK_MODE & (1 << (id - HAL_CMU_AON_A_CMU)); } return mode ? HAL_CMU_CLK_MANUAL : HAL_CMU_CLK_AUTO; } int hal_cmu_reset_set(enum HAL_CMU_MOD_ID_T id) { if (id >= HAL_CMU_MOD_QTY) { return 1; } if (id < HAL_CMU_MOD_P_CMU) { cmu->HRESET_SET = (1 << id); } else if (id < HAL_CMU_MOD_O_SLEEP) { cmu->PRESET_SET = (1 << (id - HAL_CMU_MOD_P_CMU)); } else if (id < HAL_CMU_AON_A_CMU) { cmu->ORESET_SET = (1 << (id - HAL_CMU_MOD_O_SLEEP)); } else { aoncmu->RESET_SET = (1 << (id - HAL_CMU_AON_A_CMU)); } return 0; } int hal_cmu_reset_clear(enum HAL_CMU_MOD_ID_T id) { if (id >= HAL_CMU_MOD_QTY) { return 1; } if (id < HAL_CMU_MOD_P_CMU) { cmu->HRESET_CLR = (1 << id); asm volatile("nop; nop;"); } else if (id < HAL_CMU_MOD_O_SLEEP) { cmu->PRESET_CLR = (1 << (id - HAL_CMU_MOD_P_CMU)); asm volatile("nop; nop; nop; nop;"); } else if (id < HAL_CMU_AON_A_CMU) { cmu->ORESET_CLR = (1 << (id - HAL_CMU_MOD_O_SLEEP)); } else { aoncmu->RESET_CLR = (1 << (id - HAL_CMU_AON_A_CMU)); aocmu_reg_update_wait(); } return 0; } enum HAL_CMU_RST_STATUS_T hal_cmu_reset_get_status(enum HAL_CMU_MOD_ID_T id) { uint32_t status; if (id >= HAL_CMU_MOD_QTY) { return HAL_CMU_RST_SET; } if (id < HAL_CMU_MOD_P_CMU) { status = cmu->HRESET_SET & (1 << id); } else if (id < HAL_CMU_MOD_O_SLEEP) { status = cmu->PRESET_SET & (1 << (id - HAL_CMU_MOD_P_CMU)); } else if (id < HAL_CMU_AON_A_CMU) { status = cmu->ORESET_SET & (1 << (id - HAL_CMU_MOD_O_SLEEP)); } else { status = aoncmu->RESET_SET & (1 << (id - HAL_CMU_AON_A_CMU)); } return status ? HAL_CMU_RST_CLR : HAL_CMU_RST_SET; } int hal_cmu_reset_pulse(enum HAL_CMU_MOD_ID_T id) { volatile int i; if (id >= HAL_CMU_MOD_QTY) { return 1; } if (hal_cmu_reset_get_status(id) == HAL_CMU_RST_SET) { return hal_cmu_reset_clear(id); } if (id < HAL_CMU_MOD_P_CMU) { cmu->HRESET_PULSE = (1 << id); } else if (id < HAL_CMU_MOD_O_SLEEP) { cmu->PRESET_PULSE = (1 << (id - HAL_CMU_MOD_P_CMU)); } else if (id < HAL_CMU_AON_A_CMU) { cmu->ORESET_PULSE = (1 << (id - HAL_CMU_MOD_O_SLEEP)); } else { aoncmu->RESET_PULSE = (1 << (id - HAL_CMU_AON_A_CMU)); // Total 3 CLK-26M cycles needed // AOCMU runs in 26M clock domain and its read operations consume at least 1 26M-clock cycle. // (Whereas its write operations will finish at 1 HCLK cycle -- finish once in async bridge fifo) aoncmu->CHIP_ID; aoncmu->CHIP_ID; aoncmu->CHIP_ID; } // Delay 5+ PCLK cycles (10+ HCLK cycles) for (i = 0; i < 3; i++); return 0; } int hal_cmu_timer_set_div(enum HAL_CMU_TIMER_ID_T id, uint32_t div) { uint32_t lock; if (div < 1) { return 1; } div -= 1; if ((div & (CMU_CFG_DIV_TIMER00_MASK >> CMU_CFG_DIV_TIMER00_SHIFT)) != div) { return 1; } lock = int_lock(); if (id == HAL_CMU_TIMER_ID_00) { cmu->TIMER0_CLK = SET_BITFIELD(cmu->TIMER0_CLK, CMU_CFG_DIV_TIMER00, div); } else if (id == HAL_CMU_TIMER_ID_01) { cmu->TIMER0_CLK = SET_BITFIELD(cmu->TIMER0_CLK, CMU_CFG_DIV_TIMER01, div); } else if (id == HAL_CMU_TIMER_ID_10) { cmu->TIMER1_CLK = SET_BITFIELD(cmu->TIMER1_CLK, CMU_CFG_DIV_TIMER10, div); } else if (id == HAL_CMU_TIMER_ID_11) { cmu->TIMER1_CLK = SET_BITFIELD(cmu->TIMER1_CLK, CMU_CFG_DIV_TIMER11, div); } else if (id == HAL_CMU_TIMER_ID_20) { cmu->TIMER2_CLK = SET_BITFIELD(cmu->TIMER2_CLK, CMU_CFG_DIV_TIMER20, div); } else if (id == HAL_CMU_TIMER_ID_21) { cmu->TIMER2_CLK = SET_BITFIELD(cmu->TIMER2_CLK, CMU_CFG_DIV_TIMER21, div); } int_unlock(lock); return 0; } void BOOT_TEXT_FLASH_LOC hal_cmu_timer0_select_fast(void) { uint32_t lock; lock = int_lock(); // 6.5M cmu->PERIPH_CLK |= (1 << CMU_SEL_TIMER_FAST_SHIFT); // AON Timer aoncmu->CLK_SELECT |= AON_CMU_SEL_TIMER_FAST; int_unlock(lock); } void BOOT_TEXT_FLASH_LOC hal_cmu_timer0_select_slow(void) { uint32_t lock; lock = int_lock(); // 16K cmu->PERIPH_CLK &= ~(1 << CMU_SEL_TIMER_FAST_SHIFT); // AON Timer aoncmu->CLK_SELECT &= ~AON_CMU_SEL_TIMER_FAST; int_unlock(lock); } void TIMER1_SEL_LOC hal_cmu_timer1_select_fast(void) { uint32_t lock; lock = int_lock(); // 6.5M cmu->PERIPH_CLK |= (1 << (CMU_SEL_TIMER_FAST_SHIFT + 1)); int_unlock(lock); } void TIMER1_SEL_LOC hal_cmu_timer1_select_slow(void) { uint32_t lock; lock = int_lock(); // 16K cmu->PERIPH_CLK &= ~(1 << (CMU_SEL_TIMER_FAST_SHIFT + 1)); int_unlock(lock); } void hal_cmu_timer2_select_fast(void) { uint32_t lock; lock = int_lock(); // 6.5M cmu->PERIPH_CLK |= (1 << (CMU_SEL_TIMER_FAST_SHIFT + 2)); int_unlock(lock); } void hal_cmu_timer2_select_slow(void) { uint32_t lock; lock = int_lock(); // 16K cmu->PERIPH_CLK &= ~(1 << (CMU_SEL_TIMER_FAST_SHIFT + 2)); int_unlock(lock); } int hal_cmu_sdmmc_set_pll_div(uint32_t div) { uint32_t lock; if (div < 2) { return 1; } div -= 2; if ((div & (CMU_CFG_DIV_SDMMC_MASK >> CMU_CFG_DIV_SDMMC_SHIFT)) != div) { return 1; } lock = int_lock(); cmu->PERIPH_CLK = SET_BITFIELD(cmu->PERIPH_CLK, CMU_CFG_DIV_SDMMC, div) | CMU_SEL_OSCX2_SDMMC | CMU_SEL_PLL_SDMMC | CMU_EN_PLL_SDMMC; int_unlock(lock); return 0; } #ifdef OSC_26M_X4_AUD2BB // Any of 78M/104M/208M is changed to 26M x4 (104M) #define SYS_SET_FREQ_FUNC(f, F, CLK_OV) \ int hal_cmu_ ##f## _set_freq(enum HAL_CMU_FREQ_T freq) \ { \ uint32_t enable; \ uint32_t disable; \ if (freq >= HAL_CMU_FREQ_QTY) { \ return 1; \ } \ if (freq == HAL_CMU_FREQ_32K) { \ enable = 0; \ disable = CMU_SEL_OSC_ ##F## _DISABLE | CMU_SEL_OSCX2_ ##F## _DISABLE | \ CMU_SEL_PLL_ ##F## _DISABLE | CMU_RSTN_DIV_ ##F## _DISABLE | CMU_BYPASS_DIV_ ##F## _DISABLE; \ } else if (freq == HAL_CMU_FREQ_26M) { \ enable = CMU_SEL_OSC_ ##F## _ENABLE; \ disable = CMU_SEL_OSCX2_ ##F## _DISABLE | \ CMU_SEL_PLL_ ##F## _DISABLE | CMU_RSTN_DIV_ ##F## _DISABLE | CMU_BYPASS_DIV_ ##F## _DISABLE; \ } else if (freq == HAL_CMU_FREQ_52M) { \ enable = CMU_SEL_OSCX2_ ##F## _ENABLE; \ disable = CMU_SEL_PLL_ ##F## _DISABLE | CMU_RSTN_DIV_ ##F## _DISABLE | CMU_BYPASS_DIV_ ##F## _DISABLE; \ } else { \ enable = CMU_SEL_PLL_ ##F## _ENABLE | CMU_BYPASS_DIV_ ##F## _ENABLE; \ disable = CMU_RSTN_DIV_ ##F## _DISABLE; \ } \ if (enable & CMU_SEL_PLL_ ##F## _ENABLE) { \ CLK_OV; \ cmu->SYS_CLK_ENABLE = CMU_RSTN_DIV_ ##F## _ENABLE; \ if (enable & CMU_BYPASS_DIV_ ##F## _ENABLE) { \ cmu->SYS_CLK_ENABLE = CMU_BYPASS_DIV_ ##F## _ENABLE; \ } else { \ cmu->SYS_CLK_DISABLE = CMU_BYPASS_DIV_ ##F## _DISABLE; \ } \ } \ cmu->SYS_CLK_ENABLE = enable; \ if (enable & CMU_SEL_PLL_ ##F## _ENABLE) { \ cmu->SYS_CLK_DISABLE = disable; \ } else { \ cmu->SYS_CLK_DISABLE = disable & ~(CMU_RSTN_DIV_ ##F## _DISABLE | CMU_BYPASS_DIV_ ##F## _DISABLE); \ cmu->SYS_CLK_DISABLE = CMU_BYPASS_DIV_ ##F## _DISABLE; \ cmu->SYS_CLK_DISABLE = CMU_RSTN_DIV_ ##F## _DISABLE; \ } \ return 0; \ } #else // !OSC_26M_X4_AUD2BB #define SYS_SET_FREQ_FUNC(f, F, CLK_OV) \ int hal_cmu_ ##f## _set_freq(enum HAL_CMU_FREQ_T freq) \ { \ uint32_t lock; \ uint32_t enable; \ uint32_t disable; \ int div = -1; \ if (freq >= HAL_CMU_FREQ_QTY) { \ return 1; \ } \ if (freq == HAL_CMU_FREQ_32K) { \ enable = 0; \ disable = CMU_SEL_OSC_ ##F## _DISABLE | CMU_SEL_OSCX2_ ##F## _DISABLE | \ CMU_SEL_PLL_ ##F## _DISABLE | CMU_RSTN_DIV_ ##F## _DISABLE | CMU_BYPASS_DIV_ ##F## _DISABLE; \ } else if (freq == HAL_CMU_FREQ_26M) { \ enable = CMU_SEL_OSC_ ##F## _ENABLE; \ disable = CMU_SEL_OSCX2_ ##F## _DISABLE | \ CMU_SEL_PLL_ ##F## _DISABLE | CMU_RSTN_DIV_ ##F## _DISABLE | CMU_BYPASS_DIV_ ##F## _DISABLE; \ } else if (freq == HAL_CMU_FREQ_52M) { \ enable = CMU_SEL_OSCX2_ ##F## _ENABLE; \ disable = CMU_SEL_PLL_ ##F## _DISABLE | CMU_RSTN_DIV_ ##F## _DISABLE | CMU_BYPASS_DIV_ ##F## _DISABLE; \ } else if (freq == HAL_CMU_FREQ_78M) { \ enable = CMU_SEL_PLL_ ##F## _ENABLE | CMU_RSTN_DIV_ ##F## _ENABLE; \ disable = CMU_BYPASS_DIV_ ##F## _DISABLE; \ div = 1; \ } else if (freq == HAL_CMU_FREQ_104M) { \ enable = CMU_SEL_PLL_ ##F## _ENABLE | CMU_RSTN_DIV_ ##F## _ENABLE; \ disable = CMU_BYPASS_DIV_ ##F## _DISABLE; \ div = 0; \ } else { \ enable = CMU_SEL_PLL_ ##F## _ENABLE | CMU_BYPASS_DIV_ ##F## _ENABLE; \ disable = CMU_RSTN_DIV_ ##F## _DISABLE; \ } \ if (div >= 0) { \ CLK_OV; \ lock = int_lock(); \ cmu->SYS_DIV = SET_BITFIELD(cmu->SYS_DIV, CMU_CFG_DIV_ ##F, div); \ int_unlock(lock); \ } \ if (enable & CMU_SEL_PLL_ ##F## _ENABLE) { \ cmu->SYS_CLK_ENABLE = CMU_RSTN_DIV_ ##F## _ENABLE; \ if (enable & CMU_BYPASS_DIV_ ##F## _ENABLE) { \ cmu->SYS_CLK_ENABLE = CMU_BYPASS_DIV_ ##F## _ENABLE; \ } else { \ cmu->SYS_CLK_DISABLE = CMU_BYPASS_DIV_ ##F## _DISABLE; \ } \ } \ cmu->SYS_CLK_ENABLE = enable; \ if (enable & CMU_SEL_PLL_ ##F## _ENABLE) { \ cmu->SYS_CLK_DISABLE = disable; \ } else { \ cmu->SYS_CLK_DISABLE = disable & ~(CMU_RSTN_DIV_ ##F## _DISABLE | CMU_BYPASS_DIV_ ##F## _DISABLE); \ cmu->SYS_CLK_DISABLE = CMU_BYPASS_DIV_ ##F## _DISABLE; \ cmu->SYS_CLK_DISABLE = CMU_RSTN_DIV_ ##F## _DISABLE; \ } \ return 0; \ } #endif // !OSC_26M_X4_AUD2BB #ifdef MCU_SYS_CLOCK_400M #define FLASH_DIV_OFFSET 2 #elif defined(MCU_SYS_CLOCK_300M) #define FLASH_DIV_OFFSET 1 #else #define FLASH_DIV_OFFSET 0 #endif #ifdef OSC_26M_X4_AUD2BB #define FLASH_FREQ_OV { aoncmu->CLK_OUT |= AON_CMU_SEL_X4_FLS; } #else #define FLASH_FREQ_OV { div += FLASH_DIV_OFFSET; } #endif BOOT_TEXT_SRAM_LOC SYS_SET_FREQ_FUNC(flash, FLS, FLASH_FREQ_OV); #ifdef LOW_SYS_FREQ void hal_cmu_low_sys_clock_set(enum HAL_CMU_LOW_SYS_FREQ_T freq) { uint32_t lock; if (hal_get_chip_metal_id() == HAL_CHIP_METAL_ID_0) { return; } lock = int_lock(); low_sys_freq = freq; hal_cmu_sys_set_freq(hal_sysfreq_get_hw_freq()); int_unlock(lock); } int hal_cmu_fast_timer_offline(void) { return low_sys_freq_en && low_sys_freq != HAL_CMU_LOW_SYS_FREQ_13M; } static void hal_cmu_osc_to_dig_x4_enable(void) { aoncmu->TOP_CLK_ENABLE = AON_CMU_EN_X4_ANA_ENABLE; aoncmu->CLK_SELECT |= AON_CMU_SEL_X4_SYS; aoncmu->CLK_SELECT |= AON_CMU_SEL_X4_DIG; aoncmu->RESERVED_03C |= AON_CMU_OSC_TO_DIG_X4; } static void hal_cmu_osc_to_dig_x4_disable(void) { aoncmu->CLK_SELECT &= ~AON_CMU_SEL_X4_DIG; aoncmu->RESERVED_03C &= ~AON_CMU_OSC_TO_DIG_X4; #ifndef OSC_26M_X4_AUD2BB aoncmu->CLK_SELECT &= ~AON_CMU_SEL_X4_SYS; #endif #ifndef ANA_26M_X4_ENABLE aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_X4_ANA_DISABLE; #endif } int hal_cmu_sys_set_freq(enum HAL_CMU_FREQ_T freq) { uint32_t lock; uint32_t enable; uint32_t disable; int div = -1; bool low_sys_set, low_sys_clr; if (freq >= HAL_CMU_FREQ_QTY) { return 1; } low_sys_set = false; low_sys_clr = false; lock = int_lock(); if (low_sys_freq == HAL_CMU_LOW_SYS_FREQ_NONE) { if (aoncmu->RESERVED_03C & AON_CMU_OSC_TO_DIG_X4) { low_sys_clr = true; } } else { if (freq == HAL_CMU_FREQ_26M) { low_sys_set = true; } else if (freq > HAL_CMU_FREQ_26M) { if (aoncmu->RESERVED_03C & AON_CMU_OSC_TO_DIG_X4) { low_sys_clr = true; } } } if (low_sys_clr) { low_sys_freq_en = false; cmu->SYS_CLK_ENABLE = CMU_SEL_OSC_SYS_ENABLE; cmu->SYS_CLK_DISABLE = CMU_SEL_OSCX2_SYS_DISABLE | CMU_SEL_PLL_SYS_DISABLE; hal_cmu_osc_to_dig_x4_disable(); } if (low_sys_set) { low_sys_freq_en = true; cmu->SYS_CLK_ENABLE = CMU_SEL_OSC_SYS_ENABLE; cmu->SYS_CLK_DISABLE = CMU_SEL_OSCX2_SYS_DISABLE | CMU_SEL_PLL_SYS_DISABLE; hal_cmu_osc_to_dig_x4_enable(); freq = HAL_CMU_FREQ_208M; } if (freq == HAL_CMU_FREQ_32K) { enable = 0; disable = CMU_SEL_OSC_SYS_DISABLE | CMU_SEL_OSCX2_SYS_DISABLE | CMU_SEL_PLL_SYS_DISABLE | CMU_RSTN_DIV_SYS_DISABLE | CMU_BYPASS_DIV_SYS_DISABLE; } else if (freq == HAL_CMU_FREQ_26M) { enable = CMU_SEL_OSC_SYS_ENABLE; disable = CMU_SEL_OSCX2_SYS_DISABLE | CMU_SEL_PLL_SYS_DISABLE | CMU_RSTN_DIV_SYS_DISABLE | CMU_BYPASS_DIV_SYS_DISABLE; } else if (freq == HAL_CMU_FREQ_52M) { enable = CMU_SEL_OSCX2_SYS_ENABLE; disable = CMU_SEL_PLL_SYS_DISABLE | CMU_RSTN_DIV_SYS_DISABLE | CMU_BYPASS_DIV_SYS_DISABLE; #ifndef OSC_26M_X4_AUD2BB } else if (freq == HAL_CMU_FREQ_78M) { enable = CMU_SEL_PLL_SYS_ENABLE | CMU_RSTN_DIV_SYS_ENABLE; disable = CMU_BYPASS_DIV_SYS_DISABLE; div = 1; } else if (freq == HAL_CMU_FREQ_104M) { enable = CMU_SEL_PLL_SYS_ENABLE | CMU_RSTN_DIV_SYS_ENABLE; disable = CMU_BYPASS_DIV_SYS_DISABLE; div = 0; #endif } else { if (low_sys_set) { if (low_sys_freq == HAL_CMU_LOW_SYS_FREQ_13M) { enable = CMU_SEL_PLL_SYS_ENABLE | CMU_BYPASS_DIV_SYS_ENABLE; disable = CMU_RSTN_DIV_SYS_DISABLE; } else { enable = CMU_SEL_PLL_SYS_ENABLE | CMU_RSTN_DIV_SYS_ENABLE; disable = CMU_BYPASS_DIV_SYS_DISABLE; if (low_sys_freq == HAL_CMU_LOW_SYS_FREQ_6P5M) { div = 0; } else if (low_sys_freq == HAL_CMU_LOW_SYS_FREQ_4P33M) { div = 1; } else { div = 2; } } } else { enable = CMU_SEL_PLL_SYS_ENABLE | CMU_BYPASS_DIV_SYS_ENABLE; disable = CMU_RSTN_DIV_SYS_DISABLE; } } if (div >= 0) { cmu->SYS_DIV = SET_BITFIELD(cmu->SYS_DIV, CMU_CFG_DIV_SYS, div); } if (enable & CMU_SEL_PLL_SYS_ENABLE) { cmu->SYS_CLK_ENABLE = CMU_RSTN_DIV_SYS_ENABLE; if (enable & CMU_BYPASS_DIV_SYS_ENABLE) { cmu->SYS_CLK_ENABLE = CMU_BYPASS_DIV_SYS_ENABLE; } else { cmu->SYS_CLK_DISABLE = CMU_BYPASS_DIV_SYS_DISABLE; } } cmu->SYS_CLK_ENABLE = enable; if (enable & CMU_SEL_PLL_SYS_ENABLE) { cmu->SYS_CLK_DISABLE = disable; } else { cmu->SYS_CLK_DISABLE = disable & ~(CMU_RSTN_DIV_SYS_DISABLE | CMU_BYPASS_DIV_SYS_DISABLE); cmu->SYS_CLK_DISABLE = CMU_BYPASS_DIV_SYS_DISABLE; cmu->SYS_CLK_DISABLE = CMU_RSTN_DIV_SYS_DISABLE; } int_unlock(lock); return 0; } #else SYS_SET_FREQ_FUNC(sys, SYS, {}); #endif int hal_cmu_mem_set_freq(enum HAL_CMU_FREQ_T freq) { return 0; } enum HAL_CMU_FREQ_T BOOT_TEXT_SRAM_LOC hal_cmu_sys_get_freq(void) { uint32_t sys_clk; uint32_t div; sys_clk = cmu->SYS_CLK_ENABLE; if (sys_clk & CMU_SEL_PLL_SYS_ENABLE) { if (sys_clk & CMU_BYPASS_DIV_SYS_ENABLE) { return HAL_CMU_FREQ_208M; } else { div = GET_BITFIELD(cmu->SYS_DIV, CMU_CFG_DIV_SYS); if (div == 0) { return HAL_CMU_FREQ_104M; } else if (div == 1) { // (div == 1): 69M return HAL_CMU_FREQ_78M; } else { // (div == 2): 52M // (div == 3): 42M return HAL_CMU_FREQ_52M; } } } else if (sys_clk & CMU_SEL_OSCX2_SYS_ENABLE) { return HAL_CMU_FREQ_52M; } else if (sys_clk & CMU_SEL_OSC_SYS_ENABLE) { return HAL_CMU_FREQ_26M; } else { return HAL_CMU_FREQ_32K; } } int BOOT_TEXT_SRAM_LOC hal_cmu_flash_select_pll(enum HAL_CMU_PLL_T pll) { return hal_cmu_sys_select_pll(pll); } int hal_cmu_mem_select_pll(enum HAL_CMU_PLL_T pll) { return hal_cmu_sys_select_pll(pll); } // hal_cmu_flash_select_pll() requires in BOOT_TEXT_SRAM_LOC int BOOT_TEXT_SRAM_LOC hal_cmu_sys_select_pll(enum HAL_CMU_PLL_T pll) { uint32_t lock; uint32_t sel; if (pll >= HAL_CMU_PLL_QTY) { return 1; } lock = int_lock(); // 0/1:bbpll, 2:audpll, 3:usbpll sel = (pll == HAL_CMU_PLL_AUD) ? 2 : 0; aoncmu->CLK_SELECT = SET_BITFIELD(aoncmu->CLK_SELECT, AON_CMU_SEL_PLL_SYS, sel); int_unlock(lock); return 0; } int hal_cmu_get_pll_status(enum HAL_CMU_PLL_T pll) { return !!(aoncmu->TOP_CLK_ENABLE & ((pll == HAL_CMU_PLL_AUD) ? AON_CMU_EN_CLK_TOP_PLLAUD_ENABLE : AON_CMU_EN_CLK_TOP_PLLUSB_ENABLE)); } int hal_cmu_pll_enable(enum HAL_CMU_PLL_T pll, enum HAL_CMU_PLL_USER_T user) { uint32_t pu_val; uint32_t en_val; uint32_t check; uint32_t lock; uint32_t sel; uint32_t start; uint32_t timeout; if (pll >= HAL_CMU_PLL_QTY) { return 1; } if (user >= HAL_CMU_PLL_USER_QTY && user != HAL_CMU_PLL_USER_ALL) { return 2; } #ifdef USB_USE_USBPLL if (pll == HAL_CMU_PLL_USB && user == HAL_CMU_PLL_USER_USB) { pll = HAL_CMU_PLL_USB_HS; } #endif if (pll == HAL_CMU_PLL_AUD) { pu_val = AON_CMU_PU_PLLAUD_ENABLE; en_val = AON_CMU_EN_CLK_TOP_PLLAUD_ENABLE; check = AON_CMU_LOCK_PLLAUD; #ifdef USB_USE_USBPLL } else if (pll == HAL_CMU_PLL_USB_HS) { pu_val = AON_CMU_PU_PLLUSB_ENABLE; en_val = AON_CMU_EN_CLK_TOP_PLLUSB_ENABLE; check = AON_CMU_LOCK_PLLUSB; #endif } else { pu_val = AON_CMU_PU_PLLBB_ENABLE; en_val = AON_CMU_EN_CLK_TOP_PLLBB_ENABLE; check = AON_CMU_LOCK_PLLBB; } lock = int_lock(); if (pll_user_map[pll] == 0 || user == HAL_CMU_PLL_USER_ALL) { #ifndef ROM_BUILD pmu_pll_div_reset_set(pll); #endif aoncmu->TOP_CLK_ENABLE = pu_val; #ifndef ROM_BUILD hal_sys_timer_delay_us(20); pmu_pll_div_reset_clear(pll); // Wait at least 10us for clock ready #endif } else { check = 0; } if (user < HAL_CMU_PLL_USER_QTY) { pll_user_map[pll] |= (1 << user); } if (user == HAL_CMU_PLL_USER_AUD) { // 0/1:audpll, 2:bbpll, 3:usbpll sel = (pll == HAL_CMU_PLL_AUD) ? 0 : 2; aoncmu->CLK_SELECT = SET_BITFIELD(aoncmu->CLK_SELECT, AON_CMU_SEL_PLL_AUD, sel); } // HAL_CMU_PLL_USER_SYS selects PLL in hal_cmu_sys_select_pll() int_unlock(lock); start = hal_sys_timer_get(); timeout = HAL_CMU_PLL_LOCKED_TIMEOUT; do { if (check) { if (aoncmu->CODEC_DIV & check) { //break; } } else { if (aoncmu->TOP_CLK_ENABLE & en_val) { break; } } } while ((hal_sys_timer_get() - start) < timeout); aoncmu->TOP_CLK_ENABLE = en_val; #ifndef USB_USE_USBPLL if (pll == HAL_CMU_PLL_USB && user == HAL_CMU_PLL_USER_USB) { aoncmu->TOP_CLK_ENABLE = AON_CMU_EN_CLK_TOP_PLLBB2_ENABLE; } #endif return (aoncmu->CODEC_DIV & check) ? 0 : 2; } int hal_cmu_pll_disable(enum HAL_CMU_PLL_T pll, enum HAL_CMU_PLL_USER_T user) { uint32_t lock; if (pll >= HAL_CMU_PLL_QTY) { return 1; } if (user >= HAL_CMU_PLL_USER_QTY && user != HAL_CMU_PLL_USER_ALL) { return 2; } if (pll == HAL_CMU_PLL_USB && user == HAL_CMU_PLL_USER_USB) { #ifdef USB_USE_USBPLL pll = HAL_CMU_PLL_USB_HS; #else aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_CLK_TOP_PLLBB2_DISABLE; #endif } lock = int_lock(); if (user < HAL_CMU_PLL_USER_ALL) { pll_user_map[pll] &= ~(1 << user); } if (pll_user_map[pll] == 0 || user == HAL_CMU_PLL_USER_ALL) { if (pll == HAL_CMU_PLL_AUD) { aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_CLK_TOP_PLLAUD_DISABLE; aoncmu->TOP_CLK_DISABLE = AON_CMU_PU_PLLAUD_DISABLE; #ifdef USB_USE_USBPLL } else if (pll == HAL_CMU_PLL_USB_HS) { aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_CLK_TOP_PLLUSB_DISABLE; aoncmu->TOP_CLK_DISABLE = AON_CMU_PU_PLLUSB_DISABLE; #endif } else { aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_CLK_TOP_PLLBB_DISABLE; aoncmu->TOP_CLK_DISABLE = AON_CMU_PU_PLLBB_DISABLE; } } int_unlock(lock); return 0; } void BOOT_TEXT_FLASH_LOC hal_cmu_low_freq_mode_init(void) { #if defined(MCU_HIGH_PERFORMANCE_MODE) hal_cmu_sys_select_pll(HAL_CMU_PLL_USB); #else // No need to switch to USB PLL, for there is a clock gate and a clock mux // in front of the AUD/USB switch hal_cmu_sys_select_pll(HAL_CMU_PLL_AUD); #endif //#ifdef FLASH_LOW_SPEED #ifdef OSC_26M_X4_AUD2BB aoncmu->CLK_SELECT &= ~AON_CMU_SEL_X4_SYS; #endif //#endif } void hal_cmu_low_freq_mode_enable(enum HAL_CMU_FREQ_T old_freq, enum HAL_CMU_FREQ_T new_freq) { // TODO: Need to lock irq? enum HAL_CMU_PLL_T POSSIBLY_UNUSED pll; #if defined(MCU_HIGH_PERFORMANCE_MODE) pll = HAL_CMU_PLL_USB; #else pll = HAL_CMU_PLL_AUD; #endif #ifdef OSC_26M_X4_AUD2BB if (new_freq <= HAL_CMU_FREQ_52M) { aoncmu->CLK_SELECT &= ~AON_CMU_SEL_X4_SYS; } if (new_freq <= HAL_CMU_FREQ_104M && old_freq > HAL_CMU_FREQ_104M) { if (new_freq > HAL_CMU_FREQ_52M) { // PLL is in use now. Switch to X2 first. hal_cmu_sys_set_freq(HAL_CMU_FREQ_52M); aoncmu->CLK_SELECT |= AON_CMU_SEL_X4_SYS; // X4 is in use now hal_cmu_sys_set_freq(new_freq); } hal_cmu_pll_disable(pll, HAL_CMU_PLL_USER_SYS); } #else #ifdef FLASH_LOW_SPEED if (old_freq > HAL_CMU_FREQ_52M && new_freq <= HAL_CMU_FREQ_52M) { hal_cmu_pll_disable(pll, HAL_CMU_PLL_USER_SYS); } #endif #endif } void hal_cmu_low_freq_mode_disable(enum HAL_CMU_FREQ_T old_freq, enum HAL_CMU_FREQ_T new_freq) { // TODO: Need to lock irq? enum HAL_CMU_PLL_T POSSIBLY_UNUSED pll; #if defined(MCU_HIGH_PERFORMANCE_MODE) pll = HAL_CMU_PLL_USB; #else pll = HAL_CMU_PLL_AUD; #endif #ifdef OSC_26M_X4_AUD2BB if (new_freq <= HAL_CMU_FREQ_52M) { aoncmu->CLK_SELECT &= ~AON_CMU_SEL_X4_SYS; } else if (new_freq <= HAL_CMU_FREQ_104M) { aoncmu->CLK_SELECT |= AON_CMU_SEL_X4_SYS; } else { if (old_freq <= HAL_CMU_FREQ_104M) { hal_cmu_pll_enable(pll, HAL_CMU_PLL_USER_SYS); if (old_freq > HAL_CMU_FREQ_52M) { // X4 is in use now. Switch to X2 before stopping X4 hal_cmu_sys_set_freq(HAL_CMU_FREQ_52M); } aoncmu->CLK_SELECT &= ~AON_CMU_SEL_X4_SYS; } } #else #ifdef FLASH_LOW_SPEED if (old_freq <= HAL_CMU_FREQ_52M && new_freq > HAL_CMU_FREQ_52M) { hal_cmu_pll_enable(pll, HAL_CMU_PLL_USER_SYS); } #endif #endif } int hal_cmu_codec_adc_set_div(uint32_t div) { uint32_t lock; if (div < 2) { return 1; } div -= 2; lock = int_lock(); aoncmu->CODEC_DIV = SET_BITFIELD(aoncmu->CODEC_DIV, AON_CMU_CFG_DIV_CODEC, div); int_unlock(lock); return 0; } uint32_t hal_cmu_codec_adc_get_div(void) { return GET_BITFIELD(aoncmu->CODEC_DIV, AON_CMU_CFG_DIV_CODEC) + 2; } int hal_cmu_codec_dac_set_div(uint32_t div) { return hal_cmu_codec_adc_set_div(div); } uint32_t hal_cmu_codec_dac_get_div(void) { return hal_cmu_codec_adc_get_div();; } #if defined(__AUDIO_RESAMPLE__) && defined(ANA_26M_X4_ENABLE) void hal_cmu_audio_26m_x4_enable(enum CMU_AUD_26M_X4_USER_T user) { uint32_t lock; if (user >= CMU_AUD_26M_X4_USER_QTY) { return; } lock = int_lock(); if (aud_26m_x4_map == 0) { aoncmu->CLK_SELECT |= AON_CMU_SEL_X4_AUD; } aud_26m_x4_map |= (1 << user); int_unlock(lock); } void hal_cmu_audio_26m_x4_disable(enum CMU_AUD_26M_X4_USER_T user) { uint32_t lock; if (user >= CMU_AUD_26M_X4_USER_QTY) { return; } lock = int_lock(); if (aud_26m_x4_map & (1 << user)) { aud_26m_x4_map &= ~(1 << user); if (aud_26m_x4_map == 0) { aoncmu->CLK_SELECT &= ~AON_CMU_SEL_X4_AUD; } } int_unlock(lock); } #endif void hal_cmu_codec_iir_enable(uint32_t speed) { uint32_t lock; uint32_t mask; uint32_t val; uint32_t div; uint32_t cfg_speed = 0; mask = AON_CMU_SEL_OSC_CODECIIR | AON_CMU_SEL_OSCX2_CODECIIR | AON_CMU_BYPASS_DIV_CODECIIR; val = 0; if (speed <= 26000000) { val |= AON_CMU_SEL_OSC_CODECIIR | AON_CMU_SEL_OSCX2_CODECIIR; cfg_speed = 26000000; } else if (speed <= 52000000) { val |= AON_CMU_SEL_OSCX2_CODECIIR; cfg_speed = 52000000; } else { #if defined(__AUDIO_RESAMPLE__) && defined(ANA_26M_X4_ENABLE) if (hal_cmu_get_audio_resample_status()) { hal_cmu_audio_26m_x4_enable(CMU_AUD_26M_X4_USER_IIR); val |= AON_CMU_BYPASS_DIV_CODECIIR; cfg_speed = 104000000; } else #endif { // Assume audio stream is one of 48K series div = HAL_CMU_AUD_PLL_CLOCK / speed; if (div >= 2) { hal_cmu_codec_iir_set_div(div); cfg_speed = HAL_CMU_AUD_PLL_CLOCK / div; } else { val |= AON_CMU_BYPASS_DIV_CODECIIR; cfg_speed = HAL_CMU_AUD_PLL_CLOCK; } } } ASSERT(speed <= cfg_speed, "%s: speed %u should <= cfg_speed %u", __func__, speed, cfg_speed); lock = int_lock(); aoncmu->CODEC_IIR = (aoncmu->CODEC_IIR & ~mask) | val; int_unlock(lock); aoncmu->TOP_CLK_ENABLE = AON_CMU_EN_CLK_CODEC_IIR_ENABLE; aocmu_reg_update_wait(); } void hal_cmu_codec_iir_disable(void) { uint32_t lock; uint32_t val; aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_CLK_CODEC_IIR_DISABLE; #if defined(__AUDIO_RESAMPLE__) && defined(ANA_26M_X4_ENABLE) hal_cmu_audio_26m_x4_disable(CMU_AUD_26M_X4_USER_IIR); #endif val = AON_CMU_SEL_OSC_CODECIIR | AON_CMU_SEL_OSCX2_CODECIIR; lock = int_lock(); aoncmu->CODEC_IIR |= val; int_unlock(lock); } int hal_cmu_codec_iir_set_div(uint32_t div) { uint32_t lock; if (div < 2) { return 1; } div -= 2; lock = int_lock(); aoncmu->CODEC_IIR = SET_BITFIELD(aoncmu->CODEC_IIR, AON_CMU_CFG_DIV_CODECIIR, div); int_unlock(lock); return 0; } void hal_cmu_codec_rs_enable(uint32_t speed) { uint32_t lock; uint32_t mask; uint32_t val; uint32_t div; uint32_t cfg_speed = 0; mask = AON_CMU_SEL_OSC_CODECRS | AON_CMU_SEL_OSCX2_CODECRS | AON_CMU_BYPASS_DIV_CODECRS; val = 0; if (speed <= 26000000) { val |= AON_CMU_SEL_OSC_CODECRS | AON_CMU_SEL_OSCX2_CODECRS; cfg_speed = 26000000; } else if (speed <= 52000000) { val |= AON_CMU_SEL_OSCX2_CODECRS; cfg_speed = 52000000; } else { #if defined(__AUDIO_RESAMPLE__) && defined(ANA_26M_X4_ENABLE) if (hal_cmu_get_audio_resample_status()) { hal_cmu_audio_26m_x4_enable(CMU_AUD_26M_X4_USER_RS); val |= AON_CMU_BYPASS_DIV_CODECRS; cfg_speed = 104000000; } else #endif { // Assume audio stream is one of 48K series div = HAL_CMU_AUD_PLL_CLOCK / speed; if (div >= 2) { hal_cmu_codec_rs_set_div(div); cfg_speed = HAL_CMU_AUD_PLL_CLOCK / div; } else { val |= AON_CMU_BYPASS_DIV_CODECRS; cfg_speed = HAL_CMU_AUD_PLL_CLOCK; } } pmu_rs_freq_config(cfg_speed); } ASSERT(speed <= cfg_speed, "%s: speed %u should <= cfg_speed %u", __func__, speed, cfg_speed); lock = int_lock(); aoncmu->CODEC_IIR = (aoncmu->CODEC_IIR & ~mask) | val; int_unlock(lock); aoncmu->TOP_CLK_ENABLE = AON_CMU_EN_CLK_CODEC_RS_ENABLE; aocmu_reg_update_wait(); } void hal_cmu_codec_rs_disable(void) { uint32_t lock; bool high_speed; aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_CLK_CODEC_RS_DISABLE; #if defined(__AUDIO_RESAMPLE__) && defined(ANA_26M_X4_ENABLE) hal_cmu_audio_26m_x4_disable(CMU_AUD_26M_X4_USER_RS); #endif high_speed = !(aoncmu->CODEC_IIR & AON_CMU_SEL_OSC_CODECRS); lock = int_lock(); aoncmu->CODEC_IIR |= AON_CMU_SEL_OSC_CODECRS | AON_CMU_SEL_OSCX2_CODECRS; int_unlock(lock); if (high_speed) { pmu_rs_freq_config(0); } } int hal_cmu_codec_rs_set_div(uint32_t div) { uint32_t lock; if (div < 2) { return 1; } div -= 2; lock = int_lock(); aoncmu->CODEC_IIR = SET_BITFIELD(aoncmu->CODEC_IIR, AON_CMU_CFG_DIV_CODECRS, div); int_unlock(lock); return 0; } void hal_cmu_anc_enable(enum HAL_CMU_ANC_CLK_USER_T user) { anc_enabled = true; } void hal_cmu_anc_disable(enum HAL_CMU_ANC_CLK_USER_T user) { anc_enabled = false; } int hal_cmu_anc_get_status(enum HAL_CMU_ANC_CLK_USER_T user) { return anc_enabled; } void hal_cmu_codec_clock_enable(void) { uint32_t clk; #ifdef CODEC_CLK_FROM_ANA // Always use ANA clock clk = AON_CMU_EN_CLK_CODEC_HCLK_ENABLE | AON_CMU_EN_CLK_CODEC_ENABLE; #else #ifdef __AUDIO_RESAMPLE__ if (hal_cmu_get_audio_resample_status()) { uint32_t lock; lock = int_lock(); aoncmu->CODEC_DIV |= AON_CMU_SEL_OSC_CODEC; int_unlock(lock); #ifdef RESAMPLE_CODEC_CLK_ANA clk = AON_CMU_EN_CLK_CODEC_HCLK_ENABLE | AON_CMU_EN_CLK_CODEC_ENABLE; #else clk = AON_CMU_EN_CLK_PLL_CODEC_ENABLE | AON_CMU_EN_CLK_CODEC_HCLK_ENABLE | AON_CMU_EN_CLK_CODEC_ENABLE; if (hal_get_chip_metal_id() == HAL_CHIP_METAL_ID_0) { // Force codec to use analog clock clk &= ~AON_CMU_EN_CLK_PLL_CODEC_ENABLE; } #endif } else #endif { clk = AON_CMU_EN_CLK_PLL_CODEC_ENABLE | AON_CMU_EN_CLK_CODEC_HCLK_ENABLE | AON_CMU_EN_CLK_CODEC_ENABLE; } #endif aoncmu->TOP_CLK_ENABLE = clk; hal_cmu_clock_enable(HAL_CMU_MOD_H_CODEC); } void hal_cmu_codec_clock_disable(void) { uint32_t clk; hal_cmu_clock_disable(HAL_CMU_MOD_H_CODEC); #ifdef CODEC_CLK_FROM_ANA clk = AON_CMU_EN_CLK_CODEC_HCLK_DISABLE | AON_CMU_EN_CLK_CODEC_DISABLE; #else #ifdef __AUDIO_RESAMPLE__ if (hal_cmu_get_audio_resample_status()) { uint32_t lock; lock = int_lock(); aoncmu->CODEC_DIV &= ~AON_CMU_SEL_OSC_CODEC; int_unlock(lock); clk = AON_CMU_EN_CLK_CODEC_HCLK_DISABLE | AON_CMU_EN_CLK_CODEC_DISABLE; } else #endif { clk = AON_CMU_EN_CLK_PLL_CODEC_DISABLE | AON_CMU_EN_CLK_CODEC_HCLK_DISABLE | AON_CMU_EN_CLK_CODEC_DISABLE; } #endif aoncmu->TOP_CLK_DISABLE = clk; } void hal_cmu_codec_vad_clock_enable(uint32_t enabled) { if (enabled) { aoncmu->TOP_CLK_ENABLE = AON_CMU_EN_CLK_TOP_OSC_ENABLE | AON_CMU_EN_CLK_32K_CODEC_ENABLE; } else { aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_CLK_TOP_OSC_DISABLE | AON_CMU_EN_CLK_32K_CODEC_DISABLE; } } void hal_cmu_codec_reset_set(void) { aoncmu->RESET_SET = AON_CMU_SOFT_RSTN_CODEC_SET; } void hal_cmu_codec_reset_clear(void) { aoncmu->RESET_CLR = AON_CMU_SOFT_RSTN_CODEC_CLR; aocmu_reg_update_wait(); } void hal_cmu_codec_set_fault_mask(uint32_t msk) { uint32_t lock; lock = int_lock(); // If bit set 1, DAC will be muted when some faults occur cmu->PERIPH_CLK = SET_BITFIELD(cmu->PERIPH_CLK, CMU_MASK_OBS, msk); int_unlock(lock); } void hal_cmu_i2s_clock_out_enable(enum HAL_I2S_ID_T id) { uint32_t lock; uint32_t val; if (id == HAL_I2S_ID_0) { val = CMU_EN_CLK_I2S0_OUT; } else { val = CMU_EN_CLK_I2S1_OUT; } lock = int_lock(); cmu->I2C_CLK |= val; int_unlock(lock); } void hal_cmu_i2s_clock_out_disable(enum HAL_I2S_ID_T id) { uint32_t lock; uint32_t val; if (id == HAL_I2S_ID_0) { val = CMU_EN_CLK_I2S0_OUT; } else { val = CMU_EN_CLK_I2S1_OUT; } lock = int_lock(); cmu->I2C_CLK &= ~val; int_unlock(lock); } void hal_cmu_i2s_set_slave_mode(enum HAL_I2S_ID_T id) { uint32_t lock; uint32_t val; if (id == HAL_I2S_ID_0) { val = CMU_SEL_I2S0_CLKIN; } else { val = CMU_SEL_I2S1_CLKIN; } lock = int_lock(); cmu->I2C_CLK |= val; int_unlock(lock); } void hal_cmu_i2s_set_master_mode(enum HAL_I2S_ID_T id) { uint32_t lock; uint32_t val; if (id == HAL_I2S_ID_0) { val = CMU_SEL_I2S0_CLKIN; } else { val = CMU_SEL_I2S1_CLKIN; } lock = int_lock(); cmu->I2C_CLK &= ~val; int_unlock(lock); } void hal_cmu_i2s_clock_enable(enum HAL_I2S_ID_T id) { uint32_t lock; uint32_t val; volatile uint32_t *reg; if (id == HAL_I2S_ID_0) { val = AON_CMU_EN_CLK_PLL_I2S0; reg = &aoncmu->PCM_I2S_CLK; } else { val = AON_CMU_EN_CLK_PLL_I2S1; reg = &aoncmu->SPDIF_CLK; } lock = int_lock(); *reg |= val; int_unlock(lock); } void hal_cmu_i2s_clock_disable(enum HAL_I2S_ID_T id) { uint32_t lock; uint32_t val; volatile uint32_t *reg; if (id == HAL_I2S_ID_0) { val = AON_CMU_EN_CLK_PLL_I2S0; reg = &aoncmu->PCM_I2S_CLK; } else { val = AON_CMU_EN_CLK_PLL_I2S1; reg = &aoncmu->SPDIF_CLK; } lock = int_lock(); *reg &= ~val; int_unlock(lock); } int hal_cmu_i2s_set_div(enum HAL_I2S_ID_T id, uint32_t div) { uint32_t lock; if (div < 2) { return 1; } div -= 2; if ((div & (AON_CMU_CFG_DIV_I2S0_MASK >> AON_CMU_CFG_DIV_I2S0_SHIFT)) != div) { return 1; } lock = int_lock(); if (id == HAL_I2S_ID_0) { aoncmu->PCM_I2S_CLK = SET_BITFIELD(aoncmu->PCM_I2S_CLK, AON_CMU_CFG_DIV_I2S0, div); } else { aoncmu->SPDIF_CLK = SET_BITFIELD(aoncmu->SPDIF_CLK, AON_CMU_CFG_DIV_I2S1, div); } int_unlock(lock); return 0; } void hal_cmu_pcm_clock_out_enable(void) { uint32_t lock; lock = int_lock(); cmu->I2C_CLK |= CMU_EN_CLK_PCM_OUT; int_unlock(lock); } void hal_cmu_pcm_clock_out_disable(void) { uint32_t lock; lock = int_lock(); cmu->I2C_CLK &= ~CMU_EN_CLK_PCM_OUT; int_unlock(lock); } void hal_cmu_pcm_set_slave_mode(int clk_pol) { uint32_t lock; uint32_t mask; uint32_t cfg; mask = CMU_SEL_PCM_CLKIN | CMU_POL_CLK_PCM_IN; if (clk_pol) { cfg = CMU_SEL_PCM_CLKIN | CMU_POL_CLK_PCM_IN; } else { cfg = CMU_SEL_PCM_CLKIN; } lock = int_lock(); cmu->I2C_CLK = (cmu->I2C_CLK & ~mask) | cfg; int_unlock(lock); } void hal_cmu_pcm_set_master_mode(void) { uint32_t lock; lock = int_lock(); cmu->I2C_CLK &= ~CMU_SEL_PCM_CLKIN; int_unlock(lock); } void hal_cmu_pcm_clock_enable(void) { uint32_t lock; lock = int_lock(); aoncmu->PCM_I2S_CLK |= AON_CMU_EN_CLK_PLL_PCM; int_unlock(lock); } void hal_cmu_pcm_clock_disable(void) { uint32_t lock; lock = int_lock(); aoncmu->PCM_I2S_CLK &= ~AON_CMU_EN_CLK_PLL_PCM; int_unlock(lock); } int hal_cmu_pcm_set_div(uint32_t div) { uint32_t lock; if (div < 2) { return 1; } div -= 2; if ((div & (AON_CMU_CFG_DIV_PCM_MASK >> AON_CMU_CFG_DIV_PCM_SHIFT)) != div) { return 1; } lock = int_lock(); aoncmu->PCM_I2S_CLK = SET_BITFIELD(aoncmu->PCM_I2S_CLK, AON_CMU_CFG_DIV_PCM, div); int_unlock(lock); return 0; } int hal_cmu_spdif_clock_enable(enum HAL_SPDIF_ID_T id) { uint32_t lock; uint32_t mask; if (id >= HAL_SPDIF_ID_QTY) { return 1; } mask = AON_CMU_EN_CLK_PLL_SPDIF0; lock = int_lock(); aoncmu->SPDIF_CLK |= mask; int_unlock(lock); return 0; } int hal_cmu_spdif_clock_disable(enum HAL_SPDIF_ID_T id) { uint32_t lock; uint32_t mask; if (id >= HAL_SPDIF_ID_QTY) { return 1; } mask = AON_CMU_EN_CLK_PLL_SPDIF0; lock = int_lock(); aoncmu->SPDIF_CLK &= ~mask; int_unlock(lock); return 0; } int hal_cmu_spdif_set_div(enum HAL_SPDIF_ID_T id, uint32_t div) { uint32_t lock; if (id >= HAL_SPDIF_ID_QTY) { return 1; } if (div < 2) { return 2; } div -= 2; if ((div & (AON_CMU_CFG_DIV_SPDIF0_MASK >> AON_CMU_CFG_DIV_SPDIF0_SHIFT)) != div) { return 2; } lock = int_lock(); aoncmu->SPDIF_CLK = SET_BITFIELD(aoncmu->SPDIF_CLK, AON_CMU_CFG_DIV_SPDIF0, div); int_unlock(lock); return 0; } #ifdef CHIP_HAS_USB void hal_cmu_usb_set_device_mode(void) { uint32_t lock; lock = int_lock(); cmu->SYS_DIV |= CMU_USB_ID; int_unlock(lock); } void hal_cmu_usb_set_host_mode(void) { uint32_t lock; lock = int_lock(); cmu->SYS_DIV &= ~CMU_USB_ID; int_unlock(lock); } #ifdef ROM_BUILD void hal_cmu_usb_rom_set_clock_source(enum HAL_CMU_USB_CLOCK_SEL_T sel) { usb_clk_sel = sel; } #endif static uint32_t hal_cmu_usb_get_clock_source(void) { uint32_t src; #if defined(USB_CLK_SRC_26M_X4) || defined(USB_CLK_SRC_26M_X2) || defined(USB_CLK_SRC_24M_X2) || defined(USB_CLK_SRC_48M) #ifdef USB_HIGH_SPEED #error "USB HIGH-SPEED must use PLL" #endif #if defined(USB_CLK_SRC_26M_X4) && !defined(ANA_26M_X4_ENABLE) #error "USB_CLK_SRC_26M_X4 must use ANA_26M_X4_ENABLE" #endif #endif #ifdef ROM_BUILD #ifdef USB_USE_USBPLL src = CMU_USB_CLK_SRC_PLL_60M; #else if (usb_clk_sel == HAL_CMU_USB_CLOCK_SEL_24M_X2) { src = CMU_USB_CLK_SRC_OSC_24M_X2; } else if (usb_clk_sel == HAL_CMU_USB_CLOCK_SEL_48M) { src = CMU_USB_CLK_SRC_OSC_48M; } else if (usb_clk_sel == HAL_CMU_USB_CLOCK_SEL_26M_X2) { src = CMU_USB_CLK_SRC_OSC_26M_X2; } else if (usb_clk_sel == HAL_CMU_USB_CLOCK_SEL_26M_X4) { src = CMU_USB_CLK_SRC_OSC_26M_X4; } else { src = CMU_USB_CLK_SRC_PLL_48M; } #endif #else // !ROM_BUILD #ifdef USB_USE_USBPLL src = CMU_USB_CLK_SRC_PLL_60M; #else #ifdef USB_CLK_SRC_24M_X2 src = CMU_USB_CLK_SRC_OSC_24M_X2; #elif defined(USB_CLK_SRC_48M) src = CMU_USB_CLK_SRC_OSC_48M; #elif defined(USB_CLK_SRC_26M_X4) src = CMU_USB_CLK_SRC_OSC_26M_X4; #elif defined(USB_CLK_SRC_26M_X2) src = CMU_USB_CLK_SRC_OSC_26M_X2; #else src = CMU_USB_CLK_SRC_PLL_48M; #endif #endif #endif // !ROM_BUILD return src; } void hal_cmu_usb_clock_enable(void) { enum HAL_CMU_PLL_T pll; uint32_t lock; uint32_t src; pll = HAL_CMU_PLL_USB; src = hal_cmu_usb_get_clock_source(); if (src == CMU_USB_CLK_SRC_PLL_60M || src == CMU_USB_CLK_SRC_PLL_60M_ALT || src == CMU_USB_CLK_SRC_PLL_48M) { hal_cmu_pll_enable(pll, HAL_CMU_PLL_USER_USB); } lock = int_lock(); #ifdef USB_CLK_SRC_26M_X4 aoncmu->CLK_SELECT |= AON_CMU_SEL_X4_USB; #endif cmu->SYS_DIV = SET_BITFIELD(cmu->SYS_DIV, CMU_SEL_USB_SRC, src); int_unlock(lock); hal_cmu_clock_enable(HAL_CMU_MOD_H_USBC); #ifdef USB_HIGH_SPEED hal_cmu_clock_enable(HAL_CMU_MOD_H_USBH); #endif hal_cmu_clock_enable(HAL_CMU_MOD_O_USB32K); hal_cmu_clock_enable(HAL_CMU_MOD_O_USB); hal_cmu_reset_set(HAL_CMU_MOD_O_USB); hal_cmu_reset_set(HAL_CMU_MOD_O_USB32K); #ifdef USB_HIGH_SPEED hal_cmu_reset_set(HAL_CMU_MOD_H_USBH); #endif hal_cmu_reset_set(HAL_CMU_MOD_H_USBC); hal_sys_timer_delay(US_TO_TICKS(60)); hal_cmu_reset_clear(HAL_CMU_MOD_H_USBC); #ifdef USB_HIGH_SPEED hal_cmu_reset_clear(HAL_CMU_MOD_H_USBH); #endif hal_cmu_reset_clear(HAL_CMU_MOD_O_USB32K); hal_cmu_reset_clear(HAL_CMU_MOD_O_USB); } void hal_cmu_usb_clock_disable(void) { enum HAL_CMU_PLL_T pll; uint32_t src; pll = HAL_CMU_PLL_USB; src = hal_cmu_usb_get_clock_source(); hal_cmu_reset_set(HAL_CMU_MOD_O_USB); hal_cmu_reset_set(HAL_CMU_MOD_O_USB32K); #ifdef USB_HIGH_SPEED hal_cmu_reset_set(HAL_CMU_MOD_H_USBH); #endif hal_cmu_reset_set(HAL_CMU_MOD_H_USBC); hal_cmu_clock_disable(HAL_CMU_MOD_O_USB); hal_cmu_clock_disable(HAL_CMU_MOD_O_USB32K); #ifdef USB_HIGH_SPEED hal_cmu_clock_disable(HAL_CMU_MOD_H_USBH); #endif hal_cmu_clock_disable(HAL_CMU_MOD_H_USBC); if (src == CMU_USB_CLK_SRC_PLL_60M || src == CMU_USB_CLK_SRC_PLL_60M_ALT || src == CMU_USB_CLK_SRC_PLL_48M) { hal_cmu_pll_disable(pll, HAL_CMU_PLL_USER_USB); } } #endif void BOOT_TEXT_FLASH_LOC hal_cmu_apb_init_div(void) { // Divider defaults to 2 (reg_val = div - 2) //cmu->SYS_DIV = SET_BITFIELD(cmu->SYS_DIV, CMU_CFG_DIV_PCLK, 0); } int hal_cmu_periph_set_div(uint32_t div) { uint32_t lock; int ret = 0; if (div == 0 || div > ((AON_CMU_CFG_DIV_PER_MASK >> AON_CMU_CFG_DIV_PER_SHIFT) + 2)) { aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_CLK_PLL_PER_DISABLE; if (div > ((AON_CMU_CFG_DIV_PER_MASK >> AON_CMU_CFG_DIV_PER_SHIFT) + 2)) { ret = 1; } } else { lock = int_lock(); if (div == 1) { aoncmu->CLK_SELECT |= AON_CMU_BYPASS_DIV_PER; } else { div -= 2; aoncmu->CLK_SELECT = (aoncmu->CLK_SELECT & ~(AON_CMU_CFG_DIV_PER_MASK | AON_CMU_BYPASS_DIV_PER)) | AON_CMU_CFG_DIV_PER(div); } int_unlock(lock); aoncmu->TOP_CLK_ENABLE = AON_CMU_EN_CLK_PLL_PER_ENABLE; } return ret; } #define PERPH_SET_DIV_FUNC(f, F, r) \ int hal_cmu_ ##f## _set_div(uint32_t div) \ { \ uint32_t lock; \ int ret = 0; \ lock = int_lock(); \ if (div < 2 || div > ((CMU_CFG_DIV_ ##F## _MASK >> CMU_CFG_DIV_ ##F## _SHIFT) + 2)) { \ cmu->r &= ~(CMU_SEL_OSCX2_ ##F | CMU_SEL_PLL_ ##F | CMU_EN_PLL_ ##F); \ ret = 1; \ } else { \ div -= 2; \ cmu->r = (cmu->r & ~(CMU_CFG_DIV_ ##F## _MASK)) | CMU_SEL_OSCX2_ ##F | CMU_SEL_PLL_ ##F | \ CMU_CFG_DIV_ ##F(div); \ cmu->r |= CMU_EN_PLL_ ##F; \ } \ int_unlock(lock); \ return ret; \ } PERPH_SET_DIV_FUNC(uart0, UART0, UART_CLK); PERPH_SET_DIV_FUNC(uart1, UART1, UART_CLK); PERPH_SET_DIV_FUNC(uart2, UART2, UART_CLK); PERPH_SET_DIV_FUNC(spi, SPI1, SYS_DIV); PERPH_SET_DIV_FUNC(slcd, SPI0, SYS_DIV); PERPH_SET_DIV_FUNC(sdmmc, SDMMC, PERIPH_CLK); PERPH_SET_DIV_FUNC(i2c, I2C, I2C_CLK); #define PERPH_SET_FREQ_FUNC(f, F, r) \ int hal_cmu_ ##f## _set_freq(enum HAL_CMU_PERIPH_FREQ_T freq) \ { \ uint32_t lock; \ int ret = 0; \ lock = int_lock(); \ if (freq == HAL_CMU_PERIPH_FREQ_26M) { \ cmu->r &= ~(CMU_SEL_OSCX2_ ##F | CMU_SEL_PLL_ ##F | CMU_EN_PLL_ ##F); \ } else if (freq == HAL_CMU_PERIPH_FREQ_52M) { \ cmu->r = (cmu->r & ~(CMU_SEL_PLL_ ##F | CMU_EN_PLL_ ##F)) | CMU_SEL_OSCX2_ ##F; \ } else { \ ret = 1; \ } \ int_unlock(lock); \ return ret; \ } PERPH_SET_FREQ_FUNC(uart0, UART0, UART_CLK); PERPH_SET_FREQ_FUNC(uart1, UART1, UART_CLK); PERPH_SET_FREQ_FUNC(uart2, UART2, UART_CLK); PERPH_SET_FREQ_FUNC(spi, SPI1, SYS_DIV); PERPH_SET_FREQ_FUNC(slcd, SPI0, SYS_DIV); PERPH_SET_FREQ_FUNC(sdmmc, SDMMC, PERIPH_CLK); PERPH_SET_FREQ_FUNC(i2c, I2C, I2C_CLK); int hal_cmu_ispi_set_freq(enum HAL_CMU_PERIPH_FREQ_T freq) { uint32_t lock; int ret = 0; lock = int_lock(); if (freq == HAL_CMU_PERIPH_FREQ_26M) { cmu->SYS_DIV &= ~CMU_SEL_OSCX2_SPI2; } else if (freq == HAL_CMU_PERIPH_FREQ_52M) { cmu->SYS_DIV |= CMU_SEL_OSCX2_SPI2; } else { ret = 1; } int_unlock(lock); return ret; } int hal_cmu_clock_out_enable(enum HAL_CMU_CLOCK_OUT_ID_T id) { uint32_t lock; uint32_t sel; uint32_t cfg; enum CMU_CLK_OUT_SEL_T { CMU_CLK_OUT_SEL_AON = 0, CMU_CLK_OUT_SEL_CODEC = 1, CMU_CLK_OUT_SEL_BT = 2, CMU_CLK_OUT_SEL_MCU = 3, CMU_CLK_OUT_SEL_QTY }; sel = CMU_CLK_OUT_SEL_QTY; cfg = 0; if (id <= HAL_CMU_CLOCK_OUT_AON_SYS) { sel = CMU_CLK_OUT_SEL_AON; cfg = id - HAL_CMU_CLOCK_OUT_AON_32K; } else if (HAL_CMU_CLOCK_OUT_MCU_32K <= id && id <= HAL_CMU_CLOCK_OUT_MCU_SPI1) { sel = CMU_CLK_OUT_SEL_MCU; lock = int_lock(); cmu->PERIPH_CLK = SET_BITFIELD(cmu->PERIPH_CLK, CMU_CFG_CLK_OUT, id - HAL_CMU_CLOCK_OUT_MCU_32K); int_unlock(lock); } else if (HAL_CMU_CLOCK_OUT_CODEC_ADC_ANA <= id && id <= HAL_CMU_CLOCK_OUT_CODEC_HCLK) { sel = CMU_CLK_OUT_SEL_CODEC; hal_codec_select_clock_out(id - HAL_CMU_CLOCK_OUT_CODEC_ADC_ANA); } else if (HAL_CMU_CLOCK_OUT_BT_32K <= id && id <= HAL_CMU_CLOCK_OUT_BT_26M) { sel = CMU_CLK_OUT_SEL_BT; btcmu->CLK_OUT = SET_BITFIELD(btcmu->CLK_OUT, BT_CMU_CFG_CLK_OUT, id - HAL_CMU_CLOCK_OUT_BT_32K); } if (sel < CMU_CLK_OUT_SEL_QTY) { lock = int_lock(); aoncmu->CLK_OUT = (aoncmu->CLK_OUT & ~(AON_CMU_SEL_CLK_OUT_MASK | AON_CMU_CFG_CLK_OUT_MASK)) | AON_CMU_SEL_CLK_OUT(sel) | AON_CMU_CFG_CLK_OUT(cfg) | AON_CMU_EN_CLK_OUT; int_unlock(lock); return 0; } return 1; } void hal_cmu_clock_out_disable(void) { uint32_t lock; lock = int_lock(); aoncmu->CLK_OUT &= ~AON_CMU_EN_CLK_OUT; int_unlock(lock); } int hal_cmu_i2s_mclk_enable(enum HAL_CMU_I2S_MCLK_ID_T id) { uint32_t lock; lock = int_lock(); aoncmu->PCM_I2S_CLK = SET_BITFIELD(aoncmu->PCM_I2S_CLK, AON_CMU_SEL_I2S_MCLK, id) | AON_CMU_EN_I2S_MCLK; int_unlock(lock); return 0; } void hal_cmu_i2s_mclk_disable(void) { uint32_t lock; lock = int_lock(); aoncmu->PCM_I2S_CLK &= ~AON_CMU_EN_I2S_MCLK; int_unlock(lock); } int hal_cmu_pwm_set_freq(enum HAL_PWM_ID_T id, uint32_t freq) { uint32_t lock; int clk_32k; uint32_t div; if (id >= HAL_PWM_ID_QTY) { return 1; } if (freq == 0) { clk_32k = 1; div = 0; } else { clk_32k = 0; div = hal_cmu_get_crystal_freq() / freq; if (div < 2) { return 1; } div -= 2; if ((div & (AON_CMU_CFG_DIV_PWM0_MASK >> AON_CMU_CFG_DIV_PWM0_SHIFT)) != div) { return 1; } } lock = int_lock(); if (id == HAL_PWM_ID_0) { aoncmu->PWM01_CLK = (aoncmu->PWM01_CLK & ~(AON_CMU_CFG_DIV_PWM0_MASK | AON_CMU_SEL_OSC_PWM0 | AON_CMU_EN_OSC_PWM0)) | AON_CMU_CFG_DIV_PWM0(div) | (clk_32k ? 0 : (AON_CMU_SEL_OSC_PWM0 | AON_CMU_EN_OSC_PWM0)); } else if (id == HAL_PWM_ID_1) { aoncmu->PWM01_CLK = (aoncmu->PWM01_CLK & ~(AON_CMU_CFG_DIV_PWM1_MASK | AON_CMU_SEL_OSC_PWM1 | AON_CMU_EN_OSC_PWM1)) | AON_CMU_CFG_DIV_PWM1(div) | (clk_32k ? 0 : (AON_CMU_SEL_OSC_PWM1 | AON_CMU_EN_OSC_PWM1)); } else if (id == HAL_PWM_ID_2) { aoncmu->PWM23_CLK = (aoncmu->PWM23_CLK & ~(AON_CMU_CFG_DIV_PWM2_MASK | AON_CMU_SEL_OSC_PWM2 | AON_CMU_EN_OSC_PWM2)) | AON_CMU_CFG_DIV_PWM2(div) | (clk_32k ? 0 : (AON_CMU_SEL_OSC_PWM2 | AON_CMU_EN_OSC_PWM2)); } else { aoncmu->PWM23_CLK = (aoncmu->PWM23_CLK & ~(AON_CMU_CFG_DIV_PWM3_MASK | AON_CMU_SEL_OSC_PWM3 | AON_CMU_EN_OSC_PWM3)) | AON_CMU_CFG_DIV_PWM3(div) | (clk_32k ? 0 : (AON_CMU_SEL_OSC_PWM3 | AON_CMU_EN_OSC_PWM3)); } int_unlock(lock); return 0; } void hal_cmu_jtag_enable(void) { uint32_t lock; lock = int_lock(); cmu->MCU_TIMER &= ~(CMU_SECURE_BOOT_JTAG | CMU_SECURE_BOOT_I2C); int_unlock(lock); } void hal_cmu_jtag_disable(void) { uint32_t lock; lock = int_lock(); cmu->MCU_TIMER |= (CMU_SECURE_BOOT_JTAG | CMU_SECURE_BOOT_I2C); int_unlock(lock); } void hal_cmu_jtag_clock_enable(void) { aoncmu->TOP_CLK_ENABLE = AON_CMU_EN_CLK_TOP_JTAG_ENABLE; } void hal_cmu_jtag_clock_disable(void) { aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_CLK_TOP_JTAG_DISABLE; } void hal_cmu_rom_clock_init(void) { aoncmu->CODEC_DIV = (aoncmu->CODEC_DIV & ~AON_CMU_SEL_CLK_OSCX2) | AON_CMU_BYPASS_LOCK_PLLBB | AON_CMU_BYPASS_LOCK_PLLAUD | AON_CMU_SEL_CLK_OSC; // Enable PMU fast clock aoncmu->CLK_OUT &= ~(AON_CMU_SEL_DCDC_PLL | AON_CMU_SEL_DCDC_OSCX2); aoncmu->CLK_OUT |= AON_CMU_BYPASS_DIV_DCDC; aoncmu->TOP_CLK_ENABLE = AON_CMU_EN_CLK_DCDC0_ENABLE; } void hal_cmu_init_chip_feature(uint16_t feature) { aoncmu->CHIP_FEATURE = feature | AON_CMU_EFUSE_LOCK; } void BOOT_TEXT_FLASH_LOC hal_cmu_osc_x2_enable(void) { // Debug Select CMU REG F4 cmu->MCU_TIMER = SET_BITFIELD(cmu->MCU_TIMER, CMU_DEBUG_REG_SEL, CMU_DEBUG_REG_SEL_DEBUG); // Enable OSCX2 for MCU peripheral aoncmu->TOP_CLK_ENABLE = AON_CMU_EN_CLK_OSCX2_MCU_ENABLE; } void BOOT_TEXT_FLASH_LOC hal_cmu_osc_x4_enable(void) { #ifdef ANA_26M_X4_ENABLE aoncmu->TOP_CLK_ENABLE = AON_CMU_EN_X4_ANA_ENABLE; #endif #ifdef OSC_26M_X4_AUD2BB aoncmu->CLK_SELECT |= AON_CMU_SEL_X4_SYS; aoncmu->CLK_SELECT &= ~AON_CMU_SEL_X4_DIG; #endif } void BOOT_TEXT_FLASH_LOC hal_cmu_module_init_state(void) { aoncmu->CODEC_DIV = (aoncmu->CODEC_DIV & ~AON_CMU_SEL_CLK_OSCX2) | AON_CMU_BYPASS_LOCK_PLLBB | AON_CMU_BYPASS_LOCK_PLLAUD | AON_CMU_SEL_CLK_OSC; // Slow down PMU fast clock aoncmu->CLK_OUT = (aoncmu->CLK_OUT & ~(AON_CMU_BYPASS_DIV_DCDC | AON_CMU_CFG_DIV_DCDC_MASK)) | AON_CMU_CFG_DIV_DCDC(2); // DMA channel config cmu->ADMA_CH0_4_REQ = // codec CMU_ADMA_CH0_REQ_IDX(0) | CMU_ADMA_CH1_REQ_IDX(1) | #ifdef CODEC_DSD // codec_dsd CMU_ADMA_CH2_REQ_IDX(16) | CMU_ADMA_CH3_REQ_IDX(17) | #else // btpcm CMU_ADMA_CH2_REQ_IDX(2) | CMU_ADMA_CH3_REQ_IDX(3) | #endif // i2s0 CMU_ADMA_CH4_REQ_IDX(4); cmu->ADMA_CH5_9_REQ = // i2s0 CMU_ADMA_CH5_REQ_IDX(5) | // fir CMU_ADMA_CH6_REQ_IDX(6) | CMU_ADMA_CH7_REQ_IDX(7) | // spdif CMU_ADMA_CH8_REQ_IDX(8) | CMU_ADMA_CH9_REQ_IDX(9); cmu->ADMA_CH10_14_REQ = // iir CMU_ADMA_CH10_REQ_IDX(10) | CMU_ADMA_CH11_REQ_IDX(11) | // btdump CMU_ADMA_CH12_REQ_IDX(12) | // mc CMU_ADMA_CH13_REQ_IDX(13) | // i2s1 CMU_ADMA_CH14_REQ_IDX(18); cmu->ADMA_CH15_REQ = // i2s1 CMU_ADMA_CH15_REQ_IDX(19); cmu->GDMA_CH0_4_REQ = // flash CMU_GDMA_CH0_REQ_IDX(20) | // sdmmc CMU_GDMA_CH1_REQ_IDX(21) | // i2c0 CMU_GDMA_CH2_REQ_IDX(22) | CMU_GDMA_CH3_REQ_IDX(23) | // spi CMU_GDMA_CH4_REQ_IDX(24); cmu->GDMA_CH5_9_REQ = // spi CMU_GDMA_CH5_REQ_IDX(25) | // spilcd CMU_GDMA_CH6_REQ_IDX(26) | CMU_GDMA_CH7_REQ_IDX(27) | // uart0 CMU_GDMA_CH8_REQ_IDX(28) | CMU_GDMA_CH9_REQ_IDX(29); cmu->GDMA_CH10_14_REQ = // uart1 CMU_GDMA_CH10_REQ_IDX(30) | CMU_GDMA_CH11_REQ_IDX(31) | // i2c1 CMU_GDMA_CH12_REQ_IDX(32) | CMU_GDMA_CH13_REQ_IDX(33) | // uart2 CMU_GDMA_CH14_REQ_IDX(34); cmu->GDMA_CH15_REQ = // uart2 CMU_GDMA_CH15_REQ_IDX(35); #ifndef SIMU cmu->ORESET_SET = SYS_ORST_USB | SYS_ORST_SDMMC | SYS_ORST_WDT | SYS_ORST_TIMER2 | SYS_ORST_I2C0 | SYS_ORST_I2C1 | SYS_ORST_SPI | SYS_ORST_SLCD | SYS_ORST_SPI_PHY | SYS_ORST_UART0 | SYS_ORST_UART1 | SYS_ORST_UART2 | SYS_ORST_I2S0 | SYS_ORST_SPDIF0 | SYS_ORST_PCM | SYS_ORST_USB32K | SYS_ORST_I2S1; cmu->PRESET_SET = SYS_PRST_WDT | SYS_PRST_TIMER2 | SYS_PRST_I2C0 | SYS_PRST_I2C1 | SYS_PRST_SPI | SYS_PRST_SLCD | SYS_PRST_SPI_PHY | SYS_PRST_UART0 | SYS_PRST_UART1 | SYS_PRST_UART2 | SYS_PRST_PCM | SYS_PRST_I2S0 | SYS_PRST_SPDIF0 | SYS_PRST_I2S1 | SYS_PRST_BCM; cmu->HRESET_SET = SYS_HRST_SDMMC | SYS_HRST_USBC | SYS_HRST_CODEC | SYS_HRST_FFT | SYS_HRST_USBH | SYS_HRST_SENSOR_HUB | SYS_HRST_BT_DUMP | SYS_HRST_CP | SYS_HRST_BCM | SYS_HRST_ICACHE0; cmu->OCLK_DISABLE = SYS_OCLK_USB | SYS_OCLK_SDMMC | SYS_OCLK_WDT | SYS_OCLK_TIMER2 | SYS_OCLK_I2C0 | SYS_OCLK_I2C1 | SYS_OCLK_SPI | SYS_OCLK_SLCD | SYS_OCLK_SPI_PHY | SYS_OCLK_UART0 | SYS_OCLK_UART1 | SYS_OCLK_UART2 | SYS_OCLK_I2S0 | SYS_OCLK_SPDIF0 | SYS_OCLK_PCM | SYS_OCLK_USB32K | SYS_OCLK_I2S1; cmu->PCLK_DISABLE = SYS_PCLK_WDT | SYS_PCLK_TIMER2 | SYS_PCLK_I2C0 | SYS_PCLK_I2C1 | SYS_PCLK_SPI | SYS_PCLK_SLCD | SYS_PCLK_SPI_PHY | SYS_PCLK_UART0 | SYS_PCLK_UART1 | SYS_PCLK_UART2 | SYS_PCLK_PCM | SYS_PCLK_I2S0 | SYS_PCLK_SPDIF0 | SYS_PCLK_I2S1 | SYS_PCLK_BCM; cmu->HCLK_DISABLE = SYS_HCLK_SDMMC | SYS_HCLK_USBC | SYS_HCLK_CODEC | SYS_HCLK_FFT | SYS_HCLK_USBH | SYS_HCLK_SENSOR_HUB | SYS_HCLK_BT_DUMP | SYS_HCLK_CP | SYS_HCLK_BCM | SYS_HCLK_ICACHE0; aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_CLK_PLL_CODEC_DISABLE | AON_CMU_EN_CLK_CODEC_HCLK_DISABLE | AON_CMU_EN_CLK_CODEC_DISABLE | AON_CMU_EN_CLK_CODEC_IIR_DISABLE | AON_CMU_EN_CLK_PLL_BT_DISABLE | AON_CMU_EN_CLK_60M_BT_DISABLE | AON_CMU_EN_CLK_OSCX2_BT_DISABLE | AON_CMU_EN_CLK_OSC_BT_DISABLE | AON_CMU_EN_CLK_32K_BT_DISABLE | AON_CMU_EN_CLK_PLL_PER_DISABLE; aoncmu->RESET_SET = AON_CMU_ARESETN_SET(AON_ARST_PWM) | AON_CMU_ORESETN_SET(AON_ORST_PWM0 | AON_ORST_PWM1 | AON_ORST_PWM2 | AON_ORST_PWM3) | AON_CMU_SOFT_RSTN_CODEC_SET | AON_CMU_SOFT_RSTN_BT_SET | AON_CMU_SOFT_RSTN_BTCPU_SET; aoncmu->MOD_CLK_DISABLE = AON_CMU_MANUAL_ACLK_DISABLE(AON_ACLK_PWM) | AON_CMU_MANUAL_OCLK_DISABLE(AON_OCLK_PWM0 | AON_OCLK_PWM1 | AON_OCLK_PWM2 | AON_OCLK_PWM3); aoncmu->MOD_CLK_MODE &= ~AON_CMU_MODE_ACLK(AON_ACLK_CMU | AON_ACLK_GPIO_INT | AON_ACLK_WDT | AON_ACLK_PWM | AON_ACLK_TIMER | AON_ACLK_PSC | AON_ACLK_IOMUX); cmu->PCLK_MODE &= ~(SYS_PCLK_CMU | SYS_PCLK_WDT | SYS_PCLK_TIMER0 | SYS_PCLK_TIMER1 | SYS_PCLK_TIMER2); //cmu->HCLK_MODE = 0; //cmu->PCLK_MODE = SYS_PCLK_UART0 | SYS_PCLK_UART1 | SYS_PCLK_UART2; //cmu->OCLK_MODE = 0; #endif #ifdef CORE_SLEEP_POWER_DOWN hal_cmu_set_wakeup_pc((uint32_t)hal_sleep_core_power_up); #endif hal_psc_init(); } void BOOT_TEXT_FLASH_LOC hal_cmu_ema_init(void) { // Never change EMA in best2300 } void hal_cmu_lpu_wait_26m_ready(void) { while ((cmu->WAKEUP_CLK_CFG & CMU_LPU_STATUS_26M) == 0); } int hal_cmu_lpu_busy(void) { if ((cmu->WAKEUP_CLK_CFG & CMU_LPU_AUTO_SWITCH26) && (cmu->WAKEUP_CLK_CFG & CMU_LPU_STATUS_26M) == 0) { return 1; } if ((cmu->WAKEUP_CLK_CFG & CMU_LPU_AUTO_SWITCHPLL) && (cmu->WAKEUP_CLK_CFG & CMU_LPU_STATUS_PLL) == 0) { return 1; } return 0; } int BOOT_TEXT_FLASH_LOC hal_cmu_lpu_init(enum HAL_CMU_LPU_CLK_CFG_T cfg) { uint32_t lpu_clk; uint32_t timer_26m; uint32_t timer_pll; timer_26m = LPU_TIMER_US(TICKS_TO_US(HAL_CMU_26M_READY_TIMEOUT)); timer_pll = LPU_TIMER_US(TICKS_TO_US(HAL_CMU_PLL_LOCKED_TIMEOUT)); if (cfg >= HAL_CMU_LPU_CLK_QTY) { return 1; } if ((timer_26m & (CMU_TIMER_WT26_MASK >> CMU_TIMER_WT26_SHIFT)) != timer_26m) { return 2; } if ((timer_pll & (CMU_TIMER_WTPLL_MASK >> CMU_TIMER_WTPLL_SHIFT)) != timer_pll) { return 3; } if (hal_cmu_lpu_busy()) { return -1; } if (cfg == HAL_CMU_LPU_CLK_26M) { lpu_clk = CMU_LPU_AUTO_SWITCH26; } else if (cfg == HAL_CMU_LPU_CLK_PLL) { lpu_clk = CMU_LPU_AUTO_SWITCHPLL | CMU_LPU_AUTO_SWITCH26; } else { lpu_clk = 0; } if (lpu_clk & CMU_LPU_AUTO_SWITCH26) { // Disable RAM wakeup early cmu->MCU_TIMER &= ~CMU_RAM_RETN_UP_EARLY; // MCU/ROM/RAM auto clock gating (which depends on RAM gating signal) cmu->HCLK_MODE &= ~(SYS_HCLK_MCU | SYS_HCLK_ROM0 | SYS_HCLK_ROM1 | SYS_HCLK_ROM2 | SYS_HCLK_RAM0 | SYS_HCLK_RAM1 | SYS_HCLK_RAM2 | SYS_HCLK_RAMRET | SYS_HCLK_RAM3 | SYS_HCLK_RAM4 | SYS_HCLK_RAM5 | SYS_HCLK_RAM6); // AON_CMU enable auto switch 26M (AON_CMU must have selected 26M and disabled 52M/32K already) aoncmu->CLK_SELECT |= AON_CMU_LPU_AUTO_SWITCH26; } else { // AON_CMU disable auto switch 26M aoncmu->CLK_SELECT &= ~AON_CMU_LPU_AUTO_SWITCH26; } cmu->WAKEUP_CLK_CFG = CMU_TIMER_WT26(timer_26m) | CMU_TIMER_WTPLL(0) | lpu_clk; if (timer_pll) { hal_sys_timer_delay(US_TO_TICKS(60)); cmu->WAKEUP_CLK_CFG = CMU_TIMER_WT26(timer_26m) | CMU_TIMER_WTPLL(timer_pll) | lpu_clk; } return 0; } #ifdef CORE_SLEEP_POWER_DOWN static int SRAM_TEXT_LOC hal_cmu_lpu_sleep_pd(void) { uint32_t start; uint32_t timeout; uint32_t saved_hclk; uint32_t saved_oclk; uint32_t saved_top_clk; uint32_t saved_clk_cfg; uint32_t saved_periph_clk; uint32_t saved_sys_div; uint32_t saved_uart_clk; uint32_t saved_codec_div; uint32_t pll_locked; uint32_t saved_cpu_regs[50]; register uint32_t sp asm("sp"); uint32_t stack_limit; #ifdef ROM_BUILD extern uint32_t __rom_StackLimit[]; stack_limit = (uint32_t)__rom_StackLimit; #else extern uint32_t __StackLimit[]; stack_limit = (uint32_t)__StackLimit; #endif if (sp < stack_limit + 20 * 4) { do { asm volatile("nop; nop; nop; nop"); } while (1); } NVIC_PowerDownSleep(saved_cpu_regs, ARRAY_SIZE(saved_cpu_regs)); saved_hclk = cmu->HCLK_ENABLE; saved_oclk = cmu->OCLK_ENABLE; saved_periph_clk = cmu->PERIPH_CLK; saved_sys_div = cmu->SYS_DIV; saved_uart_clk = cmu->UART_CLK; saved_codec_div = aoncmu->CODEC_DIV; saved_top_clk = aoncmu->TOP_CLK_ENABLE; saved_clk_cfg = cmu->SYS_CLK_ENABLE; // Switch VAD clock to AON and disable codec HCLK aoncmu->CODEC_DIV |= AON_CMU_SEL_CODEC_HCLK_AON; aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_CLK_CODEC_HCLK_DISABLE; // Disable memory/flash clock cmu->OCLK_DISABLE = SYS_OCLK_FLASH; cmu->HCLK_DISABLE = SYS_HCLK_FLASH; #ifndef ROM_BUILD // Reset pll div if pll is enabled if (saved_top_clk & AON_CMU_PU_PLLAUD_ENABLE) { pmu_pll_div_reset_set(HAL_CMU_PLL_AUD); } if (saved_top_clk & AON_CMU_PU_PLLBB_ENABLE) { pmu_pll_div_reset_set(HAL_CMU_PLL_USB); } #endif // Switch system freq to 26M cmu->SYS_CLK_ENABLE = CMU_SEL_OSC_SYS_ENABLE; cmu->SYS_CLK_DISABLE = CMU_SEL_OSCX2_SYS_DISABLE | CMU_SEL_PLL_SYS_DISABLE; cmu->SYS_CLK_DISABLE = CMU_RSTN_DIV_SYS_DISABLE; // Shutdown PLLs if (saved_top_clk & AON_CMU_PU_PLLAUD_ENABLE) { aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_CLK_TOP_PLLAUD_DISABLE; aoncmu->TOP_CLK_DISABLE = AON_CMU_PU_PLLAUD_DISABLE; } if (saved_top_clk & AON_CMU_PU_PLLBB_ENABLE) { aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_CLK_TOP_PLLBB_DISABLE; aoncmu->TOP_CLK_DISABLE = AON_CMU_PU_PLLBB_DISABLE; } if (saved_top_clk & AON_CMU_PU_PLLUSB_ENABLE) { aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_CLK_TOP_PLLUSB_DISABLE; aoncmu->TOP_CLK_DISABLE = AON_CMU_PU_PLLUSB_DISABLE; } // Set power down wakeup bootmode aoncmu->BOOTMODE = (aoncmu->BOOTMODE | HAL_SW_BOOTMODE_POWER_DOWN_WAKEUP) & HAL_SW_BOOTMODE_MASK; // Set AON_CMU clock to 32K aoncmu->CODEC_DIV &= ~(AON_CMU_SEL_CLK_OSC | AON_CMU_SEL_CLK_OSCX2); hal_sleep_core_power_down(); while ((cmu->WAKEUP_CLK_CFG & CMU_LPU_STATUS_26M) == 0); // Restore AON_CMU clock aoncmu->CODEC_DIV = saved_codec_div; // Clear power down wakeup bootmode aoncmu->BOOTMODE = (aoncmu->BOOTMODE & ~HAL_SW_BOOTMODE_POWER_DOWN_WAKEUP) & HAL_SW_BOOTMODE_MASK; // Disable memory/flash clock cmu->OCLK_DISABLE = SYS_OCLK_FLASH; cmu->HCLK_DISABLE = SYS_HCLK_FLASH; // Restore PLLs if (saved_top_clk & (AON_CMU_PU_PLLAUD_ENABLE | AON_CMU_PU_PLLUSB_ENABLE | AON_CMU_PU_PLLBB_ENABLE)) { pll_locked = 0; if (saved_top_clk & AON_CMU_PU_PLLAUD_ENABLE) { aoncmu->TOP_CLK_ENABLE = AON_CMU_PU_PLLAUD_ENABLE; pll_locked |= AON_CMU_LOCK_PLLAUD; } if (saved_top_clk & AON_CMU_PU_PLLBB_ENABLE) { aoncmu->TOP_CLK_ENABLE = AON_CMU_PU_PLLBB_ENABLE; pll_locked |= AON_CMU_LOCK_PLLBB; } if (saved_top_clk & AON_CMU_PU_PLLUSB_ENABLE) { aoncmu->TOP_CLK_ENABLE = AON_CMU_PU_PLLUSB_ENABLE; pll_locked |= AON_CMU_LOCK_PLLUSB; } #ifndef ROM_BUILD hal_sys_timer_delay_us(10); // Clear pll div reset if pll is enabled if (saved_top_clk & AON_CMU_PU_PLLAUD_ENABLE) { pmu_pll_div_reset_clear(HAL_CMU_PLL_AUD); } if (saved_top_clk & AON_CMU_PU_PLLBB_ENABLE) { pmu_pll_div_reset_clear(HAL_CMU_PLL_USB); } #endif start = hal_sys_timer_get(); timeout = HAL_CMU_PLL_LOCKED_TIMEOUT; while (//(aoncmu->CODEC_DIV & pll_locked) != pll_locked && (hal_sys_timer_get() - start) < timeout); if (saved_top_clk & AON_CMU_EN_CLK_TOP_PLLAUD_ENABLE) { aoncmu->TOP_CLK_ENABLE = AON_CMU_EN_CLK_TOP_PLLAUD_ENABLE; } if (saved_top_clk & AON_CMU_EN_CLK_TOP_PLLBB_ENABLE) { aoncmu->TOP_CLK_ENABLE = AON_CMU_EN_CLK_TOP_PLLBB_ENABLE; } if (saved_top_clk & AON_CMU_EN_CLK_TOP_PLLUSB_ENABLE) { aoncmu->TOP_CLK_ENABLE = AON_CMU_EN_CLK_TOP_PLLUSB_ENABLE; } } // Restore system freq cmu->SYS_CLK_ENABLE = saved_clk_cfg & (CMU_RSTN_DIV_FLS_ENABLE | CMU_RSTN_DIV_SYS_ENABLE); cmu->SYS_CLK_ENABLE = saved_clk_cfg; // The original system freq are at least 26M //cmu->SYS_CLK_DISABLE = ~saved_clk_cfg; cmu->PERIPH_CLK = saved_periph_clk; cmu->SYS_DIV = saved_sys_div; cmu->UART_CLK = saved_uart_clk; // Switch VAD clock to MCU and enable codec HCLK if it is on before entering sleep //aoncmu->CODEC_DIV &= ~AON_CMU_SEL_CODEC_HCLK_AON; aoncmu->TOP_CLK_ENABLE = saved_top_clk & AON_CMU_EN_CLK_CODEC_HCLK_ENABLE; int_lock(); NVIC_PowerDownWakeup(saved_cpu_regs, ARRAY_SIZE(saved_cpu_regs)); // TODO: // 1) Restore hardware modules, e.g., timer, cache, flash, psram, dma, usb, uart, spi, i2c, sdmmc, codec // 2) Recover system timer in rt_suspend() and rt_resume() // 3) Dynamically select 32K sleep or power down sleep if (saved_oclk & SYS_OCLK_FLASH) { // Enable memory/flash clock cmu->HCLK_ENABLE = saved_hclk; cmu->OCLK_ENABLE = saved_oclk; // Wait until memory/flash clock ready hal_sys_timer_delay_us(2); } return 0; } #endif __STATIC_FORCEINLINE void cpu_sleep(uint32_t wakeup_cfg) { __DSB(); if (wakeup_cfg & (CMU_LPU_AUTO_SWITCHPLL | CMU_LPU_AUTO_SWITCH26)) { // 1) Avoid race condition between LPU state machine entry and IRQ wakeup: // wait 4 (at least 2) cycles of 32K clock, or 3248 cycles of 26M clock // 2) Avoid race condition between CPU clock gating and RAM access when waiting: // No consecutive RAM access is allowed (all instructions must be 16-bit and must have no data access) asm volatile ( "wfi;" "movs.n r0, #0x3;" "lsls r0, #8;" "adds.n r0, #0x2c;" "1:;" "nop;" "nop;" "subs r0, 1;" "bne.n 1b;" : : : "r0", "cc" ); } else { __WFI(); } } static int SRAM_TEXT_LOC hal_cmu_lpu_sleep_normal(enum HAL_CMU_LPU_SLEEP_MODE_T mode) { uint32_t start; uint32_t timeout; uint32_t saved_hclk; uint32_t saved_oclk; uint32_t saved_top_clk; uint32_t saved_clk_cfg; uint32_t saved_codec_div; uint32_t wakeup_cfg; bool pd_aud_pll; bool pd_bb_pll; bool wait_pll_locked; pd_aud_pll = true; pd_bb_pll = true; saved_hclk = cmu->HCLK_ENABLE; saved_oclk = cmu->OCLK_ENABLE; saved_codec_div = aoncmu->CODEC_DIV; saved_top_clk = aoncmu->TOP_CLK_ENABLE; saved_clk_cfg = cmu->SYS_CLK_ENABLE; if (mode == HAL_CMU_LPU_SLEEP_MODE_CHIP) { wakeup_cfg = cmu->WAKEUP_CLK_CFG; } else { wakeup_cfg = 0; if (pll_user_map[HAL_CMU_PLL_AUD] & (1 << HAL_CMU_PLL_USER_AUD)) { pd_aud_pll = false; } if (pll_user_map[HAL_CMU_PLL_USB] & (1 << HAL_CMU_PLL_USER_AUD)) { pd_bb_pll = false; } } // Switch VAD clock to AON and disable codec HCLK aoncmu->CODEC_DIV |= AON_CMU_SEL_CODEC_HCLK_AON; if (mode == HAL_CMU_LPU_SLEEP_MODE_CHIP) { aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_CLK_CODEC_HCLK_DISABLE; } // Disable memory/flash clock cmu->OCLK_DISABLE = SYS_OCLK_FLASH; cmu->HCLK_DISABLE = SYS_HCLK_FLASH; #ifndef ROM_BUILD // Reset pll div if pll is enabled if (pd_aud_pll && (saved_top_clk & AON_CMU_PU_PLLAUD_ENABLE)) { pmu_pll_div_reset_set(HAL_CMU_PLL_AUD); } if (pd_bb_pll && (saved_top_clk & AON_CMU_PU_PLLBB_ENABLE)) { pmu_pll_div_reset_set(HAL_CMU_PLL_USB); } #endif // Setup wakeup mask cmu->WAKEUP_MASK0 = NVIC->ISER[0]; cmu->WAKEUP_MASK1 = NVIC->ISER[1]; if (wakeup_cfg & CMU_LPU_AUTO_SWITCHPLL) { // Do nothing // Hardware will switch system freq to 32K and shutdown PLLs automatically } else { // Switch system freq to 26M cmu->SYS_CLK_ENABLE = CMU_SEL_OSC_SYS_ENABLE; cmu->SYS_CLK_DISABLE = CMU_SEL_OSCX2_SYS_DISABLE | CMU_SEL_PLL_SYS_DISABLE; cmu->SYS_CLK_DISABLE = CMU_RSTN_DIV_SYS_DISABLE; // Shutdown PLLs if (pd_aud_pll && (saved_top_clk & AON_CMU_PU_PLLAUD_ENABLE)) { aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_CLK_TOP_PLLAUD_DISABLE; aoncmu->TOP_CLK_DISABLE = AON_CMU_PU_PLLAUD_DISABLE; } if (pd_bb_pll && (saved_top_clk & AON_CMU_PU_PLLBB_ENABLE)) { aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_CLK_TOP_PLLBB_DISABLE; aoncmu->TOP_CLK_DISABLE = AON_CMU_PU_PLLBB_DISABLE; } if (saved_top_clk & AON_CMU_PU_PLLUSB_ENABLE) { aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_CLK_TOP_PLLUSB_DISABLE; aoncmu->TOP_CLK_DISABLE = AON_CMU_PU_PLLUSB_DISABLE; } if (wakeup_cfg & CMU_LPU_AUTO_SWITCH26) { // Do nothing // Hardware will switch system freq to 32K automatically } else { // Manually switch AON_CMU clock to 32K aoncmu->CODEC_DIV &= ~(AON_CMU_SEL_CLK_OSC | AON_CMU_SEL_CLK_OSCX2); // Switch system freq to 32K cmu->SYS_CLK_DISABLE = CMU_SEL_OSC_SYS_DISABLE; } } if (wakeup_cfg & CMU_LPU_AUTO_SWITCH26) { // Enable auto memory retention cmu->SLEEP = (cmu->SLEEP & ~CMU_MANUAL_RAM_RETN) | CMU_DEEPSLEEP_EN | CMU_DEEPSLEEP_ROMRAM_EN | CMU_DEEPSLEEP_START; } else { // Disable auto memory retention cmu->SLEEP = (cmu->SLEEP & ~CMU_DEEPSLEEP_ROMRAM_EN) | CMU_DEEPSLEEP_EN | CMU_MANUAL_RAM_RETN | CMU_DEEPSLEEP_START; } if (mode == HAL_CMU_LPU_SLEEP_MODE_CHIP) { SCB->SCR = SCB_SCR_SLEEPDEEP_Msk; } else { SCB->SCR = 0; } cpu_sleep(wakeup_cfg); if (wakeup_cfg & CMU_LPU_AUTO_SWITCHPLL) { start = hal_sys_timer_get(); timeout = HAL_CMU_26M_READY_TIMEOUT + HAL_CMU_PLL_LOCKED_TIMEOUT + HAL_CMU_LPU_EXTRA_TIMEOUT; while ((cmu->WAKEUP_CLK_CFG & CMU_LPU_STATUS_PLL) == 0 && (hal_sys_timer_get() - start) < timeout); // !!! CAUTION !!! // Hardware will switch system freq to PLL divider and enable PLLs automatically #ifndef ROM_BUILD hal_sys_timer_delay_us(10); // Clear pll div reset if pll is enabled if (saved_top_clk & AON_CMU_PU_PLLAUD_ENABLE) { pmu_pll_div_reset_clear(HAL_CMU_PLL_AUD); } if (saved_top_clk & AON_CMU_PU_PLLBB_ENABLE) { pmu_pll_div_reset_clear(HAL_CMU_PLL_USB); } #endif } else { // Wait for 26M ready if (wakeup_cfg & CMU_LPU_AUTO_SWITCH26) { start = hal_sys_timer_get(); timeout = HAL_CMU_26M_READY_TIMEOUT + HAL_CMU_LPU_EXTRA_TIMEOUT; while ((cmu->WAKEUP_CLK_CFG & CMU_LPU_STATUS_26M) == 0 && (hal_sys_timer_get() - start) < timeout); // Hardware will switch system freq to 26M automatically } else { if (mode == HAL_CMU_LPU_SLEEP_MODE_CHIP) { timeout = HAL_CMU_26M_READY_TIMEOUT; hal_sys_timer_delay(timeout); } // Switch system freq to 26M cmu->SYS_CLK_ENABLE = CMU_SEL_OSC_SYS_ENABLE; // Restore AON_CMU clock aoncmu->CODEC_DIV = saved_codec_div; } // System freq is 26M now and will be restored later // Restore PLLs if (saved_top_clk & (AON_CMU_PU_PLLAUD_ENABLE | AON_CMU_PU_PLLUSB_ENABLE | AON_CMU_PU_PLLBB_ENABLE)) { wait_pll_locked = false; if (pd_aud_pll && (saved_top_clk & AON_CMU_PU_PLLAUD_ENABLE)) { aoncmu->TOP_CLK_ENABLE = AON_CMU_PU_PLLAUD_ENABLE; wait_pll_locked = true; } if (pd_bb_pll && (saved_top_clk & AON_CMU_PU_PLLBB_ENABLE)) { aoncmu->TOP_CLK_ENABLE = AON_CMU_PU_PLLBB_ENABLE; wait_pll_locked = true; } if (saved_top_clk & AON_CMU_PU_PLLUSB_ENABLE) { aoncmu->TOP_CLK_ENABLE = AON_CMU_PU_PLLUSB_ENABLE; wait_pll_locked = true; } if (wait_pll_locked) { #ifndef ROM_BUILD hal_sys_timer_delay_us(10); // Clear pll div reset if pll is enabled if (pd_aud_pll && (saved_top_clk & AON_CMU_PU_PLLAUD_ENABLE)) { pmu_pll_div_reset_clear(HAL_CMU_PLL_AUD); } if (pd_bb_pll && (saved_top_clk & AON_CMU_PU_PLLBB_ENABLE)) { pmu_pll_div_reset_clear(HAL_CMU_PLL_USB); } #endif start = hal_sys_timer_get(); timeout = HAL_CMU_PLL_LOCKED_TIMEOUT; while ((hal_sys_timer_get() - start) < timeout); } if (pd_aud_pll && (saved_top_clk & AON_CMU_EN_CLK_TOP_PLLAUD_ENABLE)) { aoncmu->TOP_CLK_ENABLE = AON_CMU_EN_CLK_TOP_PLLAUD_ENABLE; } if (pd_bb_pll && (saved_top_clk & AON_CMU_EN_CLK_TOP_PLLBB_ENABLE)) { aoncmu->TOP_CLK_ENABLE = AON_CMU_EN_CLK_TOP_PLLBB_ENABLE; } if (saved_top_clk & AON_CMU_EN_CLK_TOP_PLLUSB_ENABLE) { aoncmu->TOP_CLK_ENABLE = AON_CMU_EN_CLK_TOP_PLLUSB_ENABLE; } } } // Restore system freq cmu->SYS_CLK_ENABLE = saved_clk_cfg & (CMU_RSTN_DIV_FLS_ENABLE | CMU_RSTN_DIV_SYS_ENABLE); cmu->SYS_CLK_ENABLE = saved_clk_cfg; // The original system freq are at least 26M //cmu->SYS_CLK_DISABLE = ~saved_clk_cfg; // Switch VAD clock to MCU and enable codec HCLK if it is on before entering sleep aoncmu->CODEC_DIV &= ~AON_CMU_SEL_CODEC_HCLK_AON; if (mode == HAL_CMU_LPU_SLEEP_MODE_CHIP) { aoncmu->TOP_CLK_ENABLE = saved_top_clk & AON_CMU_EN_CLK_CODEC_HCLK_ENABLE; } if (saved_oclk & SYS_OCLK_FLASH) { // Enable memory/flash clock cmu->HCLK_ENABLE = saved_hclk; cmu->OCLK_ENABLE = saved_oclk; // Wait until memory/flash clock ready hal_sys_timer_delay_us(2); } return 0; } int SRAM_TEXT_LOC hal_cmu_lpu_sleep(enum HAL_CMU_LPU_SLEEP_MODE_T mode) { #ifdef CORE_SLEEP_POWER_DOWN if (mode == HAL_CMU_LPU_SLEEP_MODE_POWER_DOWN) { return hal_cmu_lpu_sleep_pd(); } #endif return hal_cmu_lpu_sleep_normal(mode); } volatile uint32_t *hal_cmu_get_bootmode_addr(void) { return &aoncmu->BOOTMODE; } SRAM_TEXT_LOC volatile uint32_t *hal_cmu_get_memsc_addr(void) { return &aoncmu->MEMSC[0]; } void hal_cmu_bt_clock_enable(void) { aoncmu->TOP_CLK_ENABLE = AON_CMU_EN_CLK_OSCX2_BT_ENABLE | AON_CMU_EN_CLK_OSC_BT_ENABLE | AON_CMU_EN_CLK_32K_BT_ENABLE; aocmu_reg_update_wait(); } void hal_cmu_bt_clock_disable(void) { aoncmu->TOP_CLK_DISABLE = AON_CMU_EN_CLK_OSCX2_BT_DISABLE | AON_CMU_EN_CLK_OSC_BT_DISABLE | AON_CMU_EN_CLK_32K_BT_DISABLE; } void hal_cmu_bt_reset_set(void) { aoncmu->RESET_SET = AON_CMU_SOFT_RSTN_BT_SET | AON_CMU_SOFT_RSTN_BTCPU_SET; } void hal_cmu_bt_reset_clear(void) { aoncmu->RESET_CLR = AON_CMU_SOFT_RSTN_BT_CLR | AON_CMU_SOFT_RSTN_BTCPU_CLR; aocmu_reg_update_wait(); } void hal_cmu_bt_module_init(void) { //btcmu->CLK_MODE = 0; } uint32_t hal_cmu_get_aon_chip_id(void) { return aoncmu->CHIP_ID; } uint32_t hal_cmu_get_aon_revision_id(void) { return GET_BITFIELD(aoncmu->CHIP_ID, AON_CMU_REVISION_ID); } void hal_cmu_cp_enable(uint32_t sp, uint32_t entry) { cp_cfg->stack = sp; cp_cfg->reset_hdlr = (uint32_t)system_cp_reset_handler; cp_cfg->entry = entry; hal_cmu_clock_enable(HAL_CMU_MOD_H_CP); hal_cmu_reset_clear(HAL_CMU_MOD_H_CP); } void hal_cmu_cp_disable(void) { hal_cmu_reset_set(HAL_CMU_MOD_H_CP); hal_cmu_clock_disable(HAL_CMU_MOD_H_CP); } uint32_t hal_cmu_cp_get_entry_addr(void) { return cp_cfg->entry; }