mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-30 19:19:21 +00:00
soc: move implementations to esp_hw_support
This commit is contained in:
19
components/esp_hw_support/port/esp32/CMakeLists.txt
Normal file
19
components/esp_hw_support/port/esp32/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
target_include_directories(${COMPONENT_LIB} PUBLIC .)
|
||||
target_include_directories(${COMPONENT_LIB} PRIVATE private_include)
|
||||
|
||||
set(srcs
|
||||
"rtc_clk.c"
|
||||
"rtc_clk_init.c"
|
||||
"rtc_init.c"
|
||||
"rtc_pm.c"
|
||||
"rtc_sleep.c"
|
||||
"rtc_time.c"
|
||||
"rtc_wdt.c")
|
||||
|
||||
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}")
|
||||
target_sources(${COMPONENT_LIB} PRIVATE "${srcs}")
|
||||
|
||||
if(NOT CMAKE_BUILD_EARLY_EXPANSION)
|
||||
set_source_files_properties("${CMAKE_CURRENT_LIST_DIR}/rtc_clk.c" PROPERTIES
|
||||
COMPILE_FLAGS "-fno-jump-tables -fno-tree-switch-conversion")
|
||||
endif()
|
@@ -0,0 +1,136 @@
|
||||
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @file regi2c_apll.h
|
||||
* @brief Register definitions for audio PLL (APLL)
|
||||
*
|
||||
* This file lists register fields of APLL, located on an internal configuration
|
||||
* bus. These definitions are used via macros defined in regi2c_ctrl.h, by
|
||||
* rtc_clk_apll_enable function in rtc_clk.c.
|
||||
*/
|
||||
|
||||
#define I2C_APLL 0X6D
|
||||
#define I2C_APLL_HOSTID 3
|
||||
|
||||
#define I2C_APLL_IR_CAL_DELAY 0
|
||||
#define I2C_APLL_IR_CAL_DELAY_MSB 3
|
||||
#define I2C_APLL_IR_CAL_DELAY_LSB 0
|
||||
|
||||
#define I2C_APLL_IR_CAL_RSTB 0
|
||||
#define I2C_APLL_IR_CAL_RSTB_MSB 4
|
||||
#define I2C_APLL_IR_CAL_RSTB_LSB 4
|
||||
|
||||
#define I2C_APLL_IR_CAL_START 0
|
||||
#define I2C_APLL_IR_CAL_START_MSB 5
|
||||
#define I2C_APLL_IR_CAL_START_LSB 5
|
||||
|
||||
#define I2C_APLL_IR_CAL_UNSTOP 0
|
||||
#define I2C_APLL_IR_CAL_UNSTOP_MSB 6
|
||||
#define I2C_APLL_IR_CAL_UNSTOP_LSB 6
|
||||
|
||||
#define I2C_APLL_OC_ENB_FCAL 0
|
||||
#define I2C_APLL_OC_ENB_FCAL_MSB 7
|
||||
#define I2C_APLL_OC_ENB_FCAL_LSB 7
|
||||
|
||||
#define I2C_APLL_IR_CAL_EXT_CAP 1
|
||||
#define I2C_APLL_IR_CAL_EXT_CAP_MSB 4
|
||||
#define I2C_APLL_IR_CAL_EXT_CAP_LSB 0
|
||||
|
||||
#define I2C_APLL_IR_CAL_ENX_CAP 1
|
||||
#define I2C_APLL_IR_CAL_ENX_CAP_MSB 5
|
||||
#define I2C_APLL_IR_CAL_ENX_CAP_LSB 5
|
||||
|
||||
#define I2C_APLL_OC_LBW 1
|
||||
#define I2C_APLL_OC_LBW_MSB 6
|
||||
#define I2C_APLL_OC_LBW_LSB 6
|
||||
|
||||
#define I2C_APLL_IR_CAL_CK_DIV 2
|
||||
#define I2C_APLL_IR_CAL_CK_DIV_MSB 3
|
||||
#define I2C_APLL_IR_CAL_CK_DIV_LSB 0
|
||||
|
||||
#define I2C_APLL_OC_DCHGP 2
|
||||
#define I2C_APLL_OC_DCHGP_MSB 6
|
||||
#define I2C_APLL_OC_DCHGP_LSB 4
|
||||
|
||||
#define I2C_APLL_OC_ENB_VCON 2
|
||||
#define I2C_APLL_OC_ENB_VCON_MSB 7
|
||||
#define I2C_APLL_OC_ENB_VCON_LSB 7
|
||||
|
||||
#define I2C_APLL_OR_CAL_CAP 3
|
||||
#define I2C_APLL_OR_CAL_CAP_MSB 4
|
||||
#define I2C_APLL_OR_CAL_CAP_LSB 0
|
||||
|
||||
#define I2C_APLL_OR_CAL_UDF 3
|
||||
#define I2C_APLL_OR_CAL_UDF_MSB 5
|
||||
#define I2C_APLL_OR_CAL_UDF_LSB 5
|
||||
|
||||
#define I2C_APLL_OR_CAL_OVF 3
|
||||
#define I2C_APLL_OR_CAL_OVF_MSB 6
|
||||
#define I2C_APLL_OR_CAL_OVF_LSB 6
|
||||
|
||||
#define I2C_APLL_OR_CAL_END 3
|
||||
#define I2C_APLL_OR_CAL_END_MSB 7
|
||||
#define I2C_APLL_OR_CAL_END_LSB 7
|
||||
|
||||
#define I2C_APLL_OR_OUTPUT_DIV 4
|
||||
#define I2C_APLL_OR_OUTPUT_DIV_MSB 4
|
||||
#define I2C_APLL_OR_OUTPUT_DIV_LSB 0
|
||||
|
||||
#define I2C_APLL_OC_TSCHGP 4
|
||||
#define I2C_APLL_OC_TSCHGP_MSB 6
|
||||
#define I2C_APLL_OC_TSCHGP_LSB 6
|
||||
|
||||
#define I2C_APLL_EN_FAST_CAL 4
|
||||
#define I2C_APLL_EN_FAST_CAL_MSB 7
|
||||
#define I2C_APLL_EN_FAST_CAL_LSB 7
|
||||
|
||||
#define I2C_APLL_OC_DHREF_SEL 5
|
||||
#define I2C_APLL_OC_DHREF_SEL_MSB 1
|
||||
#define I2C_APLL_OC_DHREF_SEL_LSB 0
|
||||
|
||||
#define I2C_APLL_OC_DLREF_SEL 5
|
||||
#define I2C_APLL_OC_DLREF_SEL_MSB 3
|
||||
#define I2C_APLL_OC_DLREF_SEL_LSB 2
|
||||
|
||||
#define I2C_APLL_SDM_DITHER 5
|
||||
#define I2C_APLL_SDM_DITHER_MSB 4
|
||||
#define I2C_APLL_SDM_DITHER_LSB 4
|
||||
|
||||
#define I2C_APLL_SDM_STOP 5
|
||||
#define I2C_APLL_SDM_STOP_MSB 5
|
||||
#define I2C_APLL_SDM_STOP_LSB 5
|
||||
|
||||
#define I2C_APLL_SDM_RSTB 5
|
||||
#define I2C_APLL_SDM_RSTB_MSB 6
|
||||
#define I2C_APLL_SDM_RSTB_LSB 6
|
||||
|
||||
#define I2C_APLL_OC_DVDD 6
|
||||
#define I2C_APLL_OC_DVDD_MSB 4
|
||||
#define I2C_APLL_OC_DVDD_LSB 0
|
||||
|
||||
#define I2C_APLL_DSDM2 7
|
||||
#define I2C_APLL_DSDM2_MSB 5
|
||||
#define I2C_APLL_DSDM2_LSB 0
|
||||
|
||||
#define I2C_APLL_DSDM1 8
|
||||
#define I2C_APLL_DSDM1_MSB 7
|
||||
#define I2C_APLL_DSDM1_LSB 0
|
||||
|
||||
#define I2C_APLL_DSDM0 9
|
||||
#define I2C_APLL_DSDM0_MSB 7
|
||||
#define I2C_APLL_DSDM0_LSB 0
|
||||
|
@@ -0,0 +1,208 @@
|
||||
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @file regi2c_apll.h
|
||||
* @brief Register definitions for digital PLL (BBPLL)
|
||||
*
|
||||
* This file lists register fields of BBPLL, located on an internal configuration
|
||||
* bus. These definitions are used via macros defined in regi2c_ctrl.h, by
|
||||
* rtc_clk_cpu_freq_set function in rtc_clk.c.
|
||||
*/
|
||||
|
||||
#define I2C_BBPLL 0x66
|
||||
#define I2C_BBPLL_HOSTID 4
|
||||
|
||||
#define I2C_BBPLL_IR_CAL_DELAY 0
|
||||
#define I2C_BBPLL_IR_CAL_DELAY_MSB 3
|
||||
#define I2C_BBPLL_IR_CAL_DELAY_LSB 0
|
||||
|
||||
#define I2C_BBPLL_IR_CAL_CK_DIV 0
|
||||
#define I2C_BBPLL_IR_CAL_CK_DIV_MSB 7
|
||||
#define I2C_BBPLL_IR_CAL_CK_DIV_LSB 4
|
||||
|
||||
#define I2C_BBPLL_IR_CAL_EXT_CAP 1
|
||||
#define I2C_BBPLL_IR_CAL_EXT_CAP_MSB 3
|
||||
#define I2C_BBPLL_IR_CAL_EXT_CAP_LSB 0
|
||||
|
||||
#define I2C_BBPLL_IR_CAL_ENX_CAP 1
|
||||
#define I2C_BBPLL_IR_CAL_ENX_CAP_MSB 4
|
||||
#define I2C_BBPLL_IR_CAL_ENX_CAP_LSB 4
|
||||
|
||||
#define I2C_BBPLL_IR_CAL_RSTB 1
|
||||
#define I2C_BBPLL_IR_CAL_RSTB_MSB 5
|
||||
#define I2C_BBPLL_IR_CAL_RSTB_LSB 5
|
||||
|
||||
#define I2C_BBPLL_IR_CAL_START 1
|
||||
#define I2C_BBPLL_IR_CAL_START_MSB 6
|
||||
#define I2C_BBPLL_IR_CAL_START_LSB 6
|
||||
|
||||
#define I2C_BBPLL_IR_CAL_UNSTOP 1
|
||||
#define I2C_BBPLL_IR_CAL_UNSTOP_MSB 7
|
||||
#define I2C_BBPLL_IR_CAL_UNSTOP_LSB 7
|
||||
|
||||
#define I2C_BBPLL_OC_REF_DIV 2
|
||||
#define I2C_BBPLL_OC_REF_DIV_MSB 3
|
||||
#define I2C_BBPLL_OC_REF_DIV_LSB 0
|
||||
|
||||
#define I2C_BBPLL_OC_DIV_10_8 2
|
||||
#define I2C_BBPLL_OC_DIV_10_8_MSB 6
|
||||
#define I2C_BBPLL_OC_DIV_10_8_LSB 4
|
||||
|
||||
#define I2C_BBPLL_OC_LREF 2
|
||||
#define I2C_BBPLL_OC_LREF_MSB 7
|
||||
#define I2C_BBPLL_OC_LREF_LSB 7
|
||||
|
||||
#define I2C_BBPLL_OC_DIV_7_0 3
|
||||
#define I2C_BBPLL_OC_DIV_7_0_MSB 7
|
||||
#define I2C_BBPLL_OC_DIV_7_0_LSB 0
|
||||
|
||||
#define I2C_BBPLL_OC_ENB_FCAL 4
|
||||
#define I2C_BBPLL_OC_ENB_FCAL_MSB 0
|
||||
#define I2C_BBPLL_OC_ENB_FCAL_LSB 0
|
||||
|
||||
#define I2C_BBPLL_OC_DCHGP 4
|
||||
#define I2C_BBPLL_OC_DCHGP_MSB 3
|
||||
#define I2C_BBPLL_OC_DCHGP_LSB 1
|
||||
|
||||
#define I2C_BBPLL_OC_DHREF_SEL 4
|
||||
#define I2C_BBPLL_OC_DHREF_SEL_MSB 5
|
||||
#define I2C_BBPLL_OC_DHREF_SEL_LSB 4
|
||||
|
||||
#define I2C_BBPLL_OC_DLREF_SEL 4
|
||||
#define I2C_BBPLL_OC_DLREF_SEL_MSB 7
|
||||
#define I2C_BBPLL_OC_DLREF_SEL_LSB 6
|
||||
|
||||
#define I2C_BBPLL_OC_DCUR 5
|
||||
#define I2C_BBPLL_OC_DCUR_MSB 2
|
||||
#define I2C_BBPLL_OC_DCUR_LSB 0
|
||||
|
||||
#define I2C_BBPLL_OC_BST_DIV 5
|
||||
#define I2C_BBPLL_OC_BST_DIV_MSB 3
|
||||
#define I2C_BBPLL_OC_BST_DIV_LSB 3
|
||||
|
||||
#define I2C_BBPLL_OC_BST_E2C 5
|
||||
#define I2C_BBPLL_OC_BST_E2C_MSB 4
|
||||
#define I2C_BBPLL_OC_BST_E2C_LSB 4
|
||||
|
||||
#define I2C_BBPLL_OC_TSCHGP 5
|
||||
#define I2C_BBPLL_OC_TSCHGP_MSB 5
|
||||
#define I2C_BBPLL_OC_TSCHGP_LSB 5
|
||||
|
||||
#define I2C_BBPLL_OC_BW 5
|
||||
#define I2C_BBPLL_OC_BW_MSB 7
|
||||
#define I2C_BBPLL_OC_BW_LSB 6
|
||||
|
||||
#define I2C_BBPLL_OR_LOCK1 6
|
||||
#define I2C_BBPLL_OR_LOCK1_MSB 0
|
||||
#define I2C_BBPLL_OR_LOCK1_LSB 0
|
||||
|
||||
#define I2C_BBPLL_OR_LOCK2 6
|
||||
#define I2C_BBPLL_OR_LOCK2_MSB 1
|
||||
#define I2C_BBPLL_OR_LOCK2_LSB 1
|
||||
|
||||
#define I2C_BBPLL_OR_CAL_CAP 7
|
||||
#define I2C_BBPLL_OR_CAL_CAP_MSB 3
|
||||
#define I2C_BBPLL_OR_CAL_CAP_LSB 0
|
||||
|
||||
#define I2C_BBPLL_OR_CAL_UDF 7
|
||||
#define I2C_BBPLL_OR_CAL_UDF_MSB 4
|
||||
#define I2C_BBPLL_OR_CAL_UDF_LSB 4
|
||||
|
||||
#define I2C_BBPLL_OR_CAL_OVF 7
|
||||
#define I2C_BBPLL_OR_CAL_OVF_MSB 5
|
||||
#define I2C_BBPLL_OR_CAL_OVF_LSB 5
|
||||
|
||||
#define I2C_BBPLL_OR_CAL_END 7
|
||||
#define I2C_BBPLL_OR_CAL_END_MSB 6
|
||||
#define I2C_BBPLL_OR_CAL_END_LSB 6
|
||||
|
||||
#define I2C_BBPLL_BBADC_DELAY1 8
|
||||
#define I2C_BBPLL_BBADC_DELAY1_MSB 1
|
||||
#define I2C_BBPLL_BBADC_DELAY1_LSB 0
|
||||
|
||||
#define I2C_BBPLL_BBADC_DELAY2 8
|
||||
#define I2C_BBPLL_BBADC_DELAY2_MSB 3
|
||||
#define I2C_BBPLL_BBADC_DELAY2_LSB 2
|
||||
|
||||
#define I2C_BBPLL_BBADC_DELAY3 8
|
||||
#define I2C_BBPLL_BBADC_DELAY3_MSB 5
|
||||
#define I2C_BBPLL_BBADC_DELAY3_LSB 4
|
||||
|
||||
#define I2C_BBPLL_BBADC_DELAY4 8
|
||||
#define I2C_BBPLL_BBADC_DELAY4_MSB 7
|
||||
#define I2C_BBPLL_BBADC_DELAY4_LSB 6
|
||||
|
||||
#define I2C_BBPLL_BBADC_DELAY5 9
|
||||
#define I2C_BBPLL_BBADC_DELAY5_MSB 1
|
||||
#define I2C_BBPLL_BBADC_DELAY5_LSB 0
|
||||
|
||||
#define I2C_BBPLL_BBADC_DELAY6 9
|
||||
#define I2C_BBPLL_BBADC_DELAY6_MSB 3
|
||||
#define I2C_BBPLL_BBADC_DELAY6_LSB 2
|
||||
|
||||
#define I2C_BBPLL_BBADC_DSMP 9
|
||||
#define I2C_BBPLL_BBADC_DSMP_MSB 7
|
||||
#define I2C_BBPLL_BBADC_DSMP_LSB 4
|
||||
|
||||
#define I2C_BBPLL_DTEST 10
|
||||
#define I2C_BBPLL_DTEST_MSB 1
|
||||
#define I2C_BBPLL_DTEST_LSB 0
|
||||
|
||||
#define I2C_BBPLL_ENT_ADC 10
|
||||
#define I2C_BBPLL_ENT_ADC_MSB 3
|
||||
#define I2C_BBPLL_ENT_ADC_LSB 2
|
||||
|
||||
#define I2C_BBPLL_BBADC_DIV 10
|
||||
#define I2C_BBPLL_BBADC_DIV_MSB 5
|
||||
#define I2C_BBPLL_BBADC_DIV_LSB 4
|
||||
|
||||
#define I2C_BBPLL_ENT_PLL 10
|
||||
#define I2C_BBPLL_ENT_PLL_MSB 6
|
||||
#define I2C_BBPLL_ENT_PLL_LSB 6
|
||||
|
||||
#define I2C_BBPLL_OC_ENB_VCON 10
|
||||
#define I2C_BBPLL_OC_ENB_VCON_MSB 7
|
||||
#define I2C_BBPLL_OC_ENB_VCON_LSB 7
|
||||
|
||||
#define I2C_BBPLL_DIV_DAC 11
|
||||
#define I2C_BBPLL_DIV_DAC_MSB 0
|
||||
#define I2C_BBPLL_DIV_DAC_LSB 0
|
||||
|
||||
#define I2C_BBPLL_DIV_CPU 11
|
||||
#define I2C_BBPLL_DIV_CPU_MSB 1
|
||||
#define I2C_BBPLL_DIV_CPU_LSB 1
|
||||
|
||||
#define I2C_BBPLL_BBADC_INPUT_SHORT 11
|
||||
#define I2C_BBPLL_BBADC_INPUT_SHORT_MSB 2
|
||||
#define I2C_BBPLL_BBADC_INPUT_SHORT_LSB 2
|
||||
|
||||
#define I2C_BBPLL_BBADC_CAL_9_8 11
|
||||
#define I2C_BBPLL_BBADC_CAL_9_8_MSB 4
|
||||
#define I2C_BBPLL_BBADC_CAL_9_8_LSB 3
|
||||
|
||||
#define I2C_BBPLL_BBADC_DCM 11
|
||||
#define I2C_BBPLL_BBADC_DCM_MSB 6
|
||||
#define I2C_BBPLL_BBADC_DCM_LSB 5
|
||||
|
||||
#define I2C_BBPLL_ENDIV5 11
|
||||
#define I2C_BBPLL_ENDIV5_MSB 7
|
||||
#define I2C_BBPLL_ENDIV5_LSB 7
|
||||
|
||||
#define I2C_BBPLL_BBADC_CAL_7_0 12
|
||||
#define I2C_BBPLL_BBADC_CAL_7_0_MSB 7
|
||||
#define I2C_BBPLL_BBADC_CAL_7_0_LSB 0
|
||||
|
58
components/esp_hw_support/port/esp32/regi2c_ctrl.h
Normal file
58
components/esp_hw_support/port/esp32/regi2c_ctrl.h
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "regi2c_apll.h"
|
||||
#include "regi2c_bbpll.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Analog function control register */
|
||||
#define ANA_CONFIG_REG 0x6000E044
|
||||
#define ANA_CONFIG_S (8)
|
||||
#define ANA_CONFIG_M (0x3FF)
|
||||
/* Clear to enable APLL */
|
||||
#define I2C_APLL_M (BIT(14))
|
||||
/* Clear to enable BBPLL */
|
||||
#define I2C_BBPLL_M (BIT(17))
|
||||
|
||||
/* ROM functions which read/write internal control bus */
|
||||
uint8_t rom_i2c_readReg(uint8_t block, uint8_t host_id, uint8_t reg_add);
|
||||
uint8_t rom_i2c_readReg_Mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb);
|
||||
void rom_i2c_writeReg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data);
|
||||
void rom_i2c_writeReg_Mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb, uint8_t data);
|
||||
|
||||
/* Convenience macros for the above functions, these use register definitions
|
||||
* from regi2c_apll.h/regi2c_bbpll.h header files.
|
||||
*/
|
||||
#define REGI2C_WRITE_MASK(block, reg_add, indata) \
|
||||
rom_i2c_writeReg_Mask(block, block##_HOSTID, reg_add, reg_add##_MSB, reg_add##_LSB, indata)
|
||||
|
||||
#define REGI2C_READ_MASK(block, reg_add) \
|
||||
rom_i2c_readReg_Mask(block, block##_HOSTID, reg_add, reg_add##_MSB, reg_add##_LSB)
|
||||
|
||||
#define REGI2C_WRITE(block, reg_add, indata) \
|
||||
rom_i2c_writeReg(block, block##_HOSTID, reg_add, indata)
|
||||
|
||||
#define REGI2C_READ(block, reg_add) \
|
||||
rom_i2c_readReg(block, block##_HOSTID, reg_add)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
744
components/esp_hw_support/port/esp32/rtc_clk.c
Normal file
744
components/esp_hw_support/port/esp32/rtc_clk.c
Normal file
@@ -0,0 +1,744 @@
|
||||
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include "esp32/rom/ets_sys.h" // for ets_update_cpu_frequency
|
||||
#include "esp32/rom/rtc.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/rtc_periph.h"
|
||||
#include "soc/sens_periph.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/efuse_periph.h"
|
||||
#include "soc/apb_ctrl_reg.h"
|
||||
#include "soc/gpio_struct.h"
|
||||
#include "hal/gpio_ll.h"
|
||||
#include "regi2c_ctrl.h"
|
||||
#include "soc_log.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "xtensa/core-macros.h"
|
||||
#include "rtc_clk_common.h"
|
||||
|
||||
/* Frequency of the 8M oscillator is 8.5MHz +/- 5%, at the default DCAP setting */
|
||||
#define RTC_FAST_CLK_FREQ_8M 8500000
|
||||
#define RTC_SLOW_CLK_FREQ_150K 150000
|
||||
#define RTC_SLOW_CLK_FREQ_8MD256 (RTC_FAST_CLK_FREQ_8M / 256)
|
||||
#define RTC_SLOW_CLK_FREQ_32K 32768
|
||||
|
||||
/* BBPLL configuration values */
|
||||
#define BBPLL_ENDIV5_VAL_320M 0x43
|
||||
#define BBPLL_BBADC_DSMP_VAL_320M 0x84
|
||||
#define BBPLL_ENDIV5_VAL_480M 0xc3
|
||||
#define BBPLL_BBADC_DSMP_VAL_480M 0x74
|
||||
#define BBPLL_IR_CAL_DELAY_VAL 0x18
|
||||
#define BBPLL_IR_CAL_EXT_CAP_VAL 0x20
|
||||
#define BBPLL_OC_ENB_FCAL_VAL 0x9a
|
||||
#define BBPLL_OC_ENB_VCON_VAL 0x00
|
||||
#define BBPLL_BBADC_CAL_7_0_VAL 0x00
|
||||
|
||||
#define APLL_SDM_STOP_VAL_1 0x09
|
||||
#define APLL_SDM_STOP_VAL_2_REV0 0x69
|
||||
#define APLL_SDM_STOP_VAL_2_REV1 0x49
|
||||
|
||||
#define APLL_CAL_DELAY_1 0x0f
|
||||
#define APLL_CAL_DELAY_2 0x3f
|
||||
#define APLL_CAL_DELAY_3 0x1f
|
||||
|
||||
#define XTAL_32K_DAC_VAL 3
|
||||
#define XTAL_32K_DRES_VAL 3
|
||||
#define XTAL_32K_DBIAS_VAL 0
|
||||
|
||||
#define XTAL_32K_BOOTSTRAP_DAC_VAL 3
|
||||
#define XTAL_32K_BOOTSTRAP_DRES_VAL 3
|
||||
#define XTAL_32K_BOOTSTRAP_DBIAS_VAL 0
|
||||
#define XTAL_32K_BOOTSTRAP_TIME_US 7
|
||||
|
||||
#define XTAL_32K_EXT_DAC_VAL 2
|
||||
#define XTAL_32K_EXT_DRES_VAL 3
|
||||
#define XTAL_32K_EXT_DBIAS_VAL 1
|
||||
|
||||
/* Delays for various clock sources to be enabled/switched.
|
||||
* All values are in microseconds.
|
||||
* TODO: some of these are excessive, and should be reduced.
|
||||
*/
|
||||
#define DELAY_PLL_DBIAS_RAISE 3
|
||||
#define DELAY_PLL_ENABLE_WITH_150K 80
|
||||
#define DELAY_PLL_ENABLE_WITH_32K 160
|
||||
#define DELAY_FAST_CLK_SWITCH 3
|
||||
#define DELAY_SLOW_CLK_SWITCH 300
|
||||
#define DELAY_8M_ENABLE 50
|
||||
|
||||
/* Core voltage needs to be increased in two cases:
|
||||
* 1. running at 240 MHz
|
||||
* 2. running with 80MHz Flash frequency
|
||||
*
|
||||
* There is a record in efuse which indicates the proper voltage for these two cases.
|
||||
*/
|
||||
#define RTC_CNTL_DBIAS_HP_VOLT (RTC_CNTL_DBIAS_1V25 - (REG_GET_FIELD(EFUSE_BLK0_RDATA5_REG, EFUSE_RD_VOL_LEVEL_HP_INV)))
|
||||
#ifdef CONFIG_ESPTOOLPY_FLASHFREQ_80M
|
||||
#define DIG_DBIAS_80M_160M RTC_CNTL_DBIAS_HP_VOLT
|
||||
#else
|
||||
#define DIG_DBIAS_80M_160M RTC_CNTL_DBIAS_1V10
|
||||
#endif
|
||||
#define DIG_DBIAS_240M RTC_CNTL_DBIAS_HP_VOLT
|
||||
#define DIG_DBIAS_XTAL RTC_CNTL_DBIAS_1V10
|
||||
#define DIG_DBIAS_2M RTC_CNTL_DBIAS_1V00
|
||||
|
||||
#define RTC_PLL_FREQ_320M 320
|
||||
#define RTC_PLL_FREQ_480M 480
|
||||
|
||||
static void rtc_clk_cpu_freq_to_8m(void);
|
||||
static void rtc_clk_bbpll_disable(void);
|
||||
static void rtc_clk_bbpll_enable(void);
|
||||
static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz);
|
||||
|
||||
// Current PLL frequency, in MHZ (320 or 480). Zero if PLL is not enabled.
|
||||
static int s_cur_pll_freq;
|
||||
|
||||
static const char* TAG = "rtc_clk";
|
||||
|
||||
static void rtc_clk_32k_enable_common(int dac, int dres, int dbias)
|
||||
{
|
||||
CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG,
|
||||
RTC_IO_X32P_RDE | RTC_IO_X32P_RUE | RTC_IO_X32N_RUE |
|
||||
RTC_IO_X32N_RDE | RTC_IO_X32N_FUN_IE | RTC_IO_X32P_FUN_IE);
|
||||
SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL | RTC_IO_X32P_MUX_SEL);
|
||||
/* Set the parameters of xtal
|
||||
dac --> current
|
||||
dres --> resistance
|
||||
dbias --> bais voltage
|
||||
*/
|
||||
REG_SET_FIELD(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DAC_XTAL_32K, dac);
|
||||
REG_SET_FIELD(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DRES_XTAL_32K, dres);
|
||||
REG_SET_FIELD(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DBIAS_XTAL_32K, dbias);
|
||||
|
||||
#ifdef CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT
|
||||
/* TOUCH sensor can provide additional current to external XTAL.
|
||||
In some case, X32N and X32P PAD don't have enough drive capability to start XTAL */
|
||||
SET_PERI_REG_MASK(RTC_IO_TOUCH_CFG_REG, RTC_IO_TOUCH_XPD_BIAS_M);
|
||||
/* Tie PAD Touch8 to VDD
|
||||
NOTE: TOUCH8 and TOUCH9 register settings are reversed except for DAC, so we set RTC_IO_TOUCH_PAD9_REG here instead
|
||||
*/
|
||||
SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_TIE_OPT_M);
|
||||
/* Set the current used to compensate TOUCH PAD8 */
|
||||
SET_PERI_REG_BITS(RTC_IO_TOUCH_PAD8_REG, RTC_IO_TOUCH_PAD8_DAC, 4, RTC_IO_TOUCH_PAD8_DAC_S);
|
||||
/* Power up TOUCH8
|
||||
So the Touch DAC start to drive some current from VDD to TOUCH8(which is also XTAL-N)
|
||||
*/
|
||||
SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_XPD_M);
|
||||
#endif // CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT
|
||||
/* Power up external xtal */
|
||||
SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K_M);
|
||||
}
|
||||
|
||||
void rtc_clk_32k_enable(bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
rtc_clk_32k_enable_common(XTAL_32K_DAC_VAL, XTAL_32K_DRES_VAL, XTAL_32K_DBIAS_VAL);
|
||||
} else {
|
||||
/* Disable X32N and X32P pad drive external xtal */
|
||||
CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K_M);
|
||||
CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL | RTC_IO_X32P_MUX_SEL);
|
||||
|
||||
#ifdef CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT
|
||||
/* Power down TOUCH */
|
||||
CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_XPD_M);
|
||||
#endif // CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT
|
||||
}
|
||||
}
|
||||
|
||||
void rtc_clk_32k_enable_external(void)
|
||||
{
|
||||
rtc_clk_32k_enable_common(XTAL_32K_EXT_DAC_VAL, XTAL_32K_EXT_DRES_VAL, XTAL_32K_EXT_DBIAS_VAL);
|
||||
}
|
||||
|
||||
/* Helping external 32kHz crystal to start up.
|
||||
* External crystal connected to outputs GPIO32 GPIO33.
|
||||
* Forms N pulses with a frequency of about 32KHz on the outputs of the crystal.
|
||||
*/
|
||||
void rtc_clk_32k_bootstrap(uint32_t cycle)
|
||||
{
|
||||
if (cycle){
|
||||
const uint32_t pin_32 = 32;
|
||||
const uint32_t pin_33 = 33;
|
||||
|
||||
esp_rom_gpio_pad_select_gpio(pin_32);
|
||||
esp_rom_gpio_pad_select_gpio(pin_33);
|
||||
gpio_ll_output_enable(&GPIO, pin_32);
|
||||
gpio_ll_output_enable(&GPIO, pin_33);
|
||||
gpio_ll_set_level(&GPIO, pin_32, 1);
|
||||
gpio_ll_set_level(&GPIO, pin_33, 0);
|
||||
|
||||
const uint32_t delay_us = (1000000 / RTC_SLOW_CLK_FREQ_32K / 2);
|
||||
while(cycle){
|
||||
gpio_ll_set_level(&GPIO, pin_32, 1);
|
||||
gpio_ll_set_level(&GPIO, pin_33, 0);
|
||||
esp_rom_delay_us(delay_us);
|
||||
gpio_ll_set_level(&GPIO, pin_33, 1);
|
||||
gpio_ll_set_level(&GPIO, pin_32, 0);
|
||||
esp_rom_delay_us(delay_us);
|
||||
cycle--;
|
||||
}
|
||||
// disable pins
|
||||
gpio_ll_output_disable(&GPIO, pin_32);
|
||||
gpio_ll_output_disable(&GPIO, pin_33);
|
||||
}
|
||||
|
||||
CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K);
|
||||
SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_RUE | RTC_IO_X32N_RDE);
|
||||
esp_rom_delay_us(XTAL_32K_BOOTSTRAP_TIME_US);
|
||||
|
||||
rtc_clk_32k_enable_common(XTAL_32K_BOOTSTRAP_DAC_VAL,
|
||||
XTAL_32K_BOOTSTRAP_DRES_VAL, XTAL_32K_BOOTSTRAP_DBIAS_VAL);
|
||||
}
|
||||
|
||||
bool rtc_clk_32k_enabled(void)
|
||||
{
|
||||
return GET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K) != 0;
|
||||
}
|
||||
|
||||
void rtc_clk_8m_enable(bool clk_8m_en, bool d256_en)
|
||||
{
|
||||
if (clk_8m_en) {
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
|
||||
/* no need to wait once enabled by software */
|
||||
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, 1);
|
||||
if (d256_en) {
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
|
||||
} else {
|
||||
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV);
|
||||
}
|
||||
esp_rom_delay_us(DELAY_8M_ENABLE);
|
||||
} else {
|
||||
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M);
|
||||
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
bool rtc_clk_8m_enabled(void)
|
||||
{
|
||||
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M) == 0;
|
||||
}
|
||||
|
||||
bool rtc_clk_8md256_enabled(void)
|
||||
{
|
||||
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0;
|
||||
}
|
||||
|
||||
void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2, uint32_t o_div)
|
||||
{
|
||||
REG_SET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD, enable ? 0 : 1);
|
||||
REG_SET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PU, enable ? 1 : 0);
|
||||
|
||||
if (!enable &&
|
||||
REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL) != RTC_CNTL_SOC_CLK_SEL_PLL) {
|
||||
REG_SET_BIT(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FORCE_PD);
|
||||
} else {
|
||||
REG_CLR_BIT(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FORCE_PD);
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
uint8_t sdm_stop_val_2 = APLL_SDM_STOP_VAL_2_REV1;
|
||||
uint32_t is_rev0 = (GET_PERI_REG_BITS2(EFUSE_BLK0_RDATA3_REG, 1, 15) == 0);
|
||||
if (is_rev0) {
|
||||
sdm0 = 0;
|
||||
sdm1 = 0;
|
||||
sdm_stop_val_2 = APLL_SDM_STOP_VAL_2_REV0;
|
||||
}
|
||||
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM2, sdm2);
|
||||
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM0, sdm0);
|
||||
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM1, sdm1);
|
||||
REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, APLL_SDM_STOP_VAL_1);
|
||||
REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, sdm_stop_val_2);
|
||||
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_OR_OUTPUT_DIV, o_div);
|
||||
|
||||
/* calibration */
|
||||
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_1);
|
||||
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_2);
|
||||
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_3);
|
||||
|
||||
/* wait for calibration end */
|
||||
while (!(REGI2C_READ_MASK(I2C_APLL, I2C_APLL_OR_CAL_END))) {
|
||||
/* use esp_rom_delay_us so the RTC bus doesn't get flooded */
|
||||
esp_rom_delay_us(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rtc_clk_slow_freq_set(rtc_slow_freq_t slow_freq)
|
||||
{
|
||||
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, slow_freq);
|
||||
|
||||
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN,
|
||||
(slow_freq == RTC_SLOW_FREQ_32K_XTAL) ? 1 : 0);
|
||||
|
||||
esp_rom_delay_us(DELAY_SLOW_CLK_SWITCH);
|
||||
}
|
||||
|
||||
rtc_slow_freq_t rtc_clk_slow_freq_get(void)
|
||||
{
|
||||
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL);
|
||||
}
|
||||
|
||||
uint32_t rtc_clk_slow_freq_get_hz(void)
|
||||
{
|
||||
switch(rtc_clk_slow_freq_get()) {
|
||||
case RTC_SLOW_FREQ_RTC: return RTC_SLOW_CLK_FREQ_150K;
|
||||
case RTC_SLOW_FREQ_32K_XTAL: return RTC_SLOW_CLK_FREQ_32K;
|
||||
case RTC_SLOW_FREQ_8MD256: return RTC_SLOW_CLK_FREQ_8MD256;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rtc_clk_fast_freq_set(rtc_fast_freq_t fast_freq)
|
||||
{
|
||||
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL, fast_freq);
|
||||
esp_rom_delay_us(DELAY_FAST_CLK_SWITCH);
|
||||
}
|
||||
|
||||
rtc_fast_freq_t rtc_clk_fast_freq_get(void)
|
||||
{
|
||||
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_FAST_CLK_RTC_SEL);
|
||||
}
|
||||
|
||||
void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
|
||||
{
|
||||
uint8_t div_ref;
|
||||
uint8_t div7_0;
|
||||
uint8_t div10_8;
|
||||
uint8_t lref;
|
||||
uint8_t dcur;
|
||||
uint8_t bw;
|
||||
|
||||
if (pll_freq == RTC_PLL_FREQ_320M) {
|
||||
/* Raise the voltage, if needed */
|
||||
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_80M_160M);
|
||||
/* Configure 320M PLL */
|
||||
switch (xtal_freq) {
|
||||
case RTC_XTAL_FREQ_40M:
|
||||
div_ref = 0;
|
||||
div7_0 = 32;
|
||||
div10_8 = 0;
|
||||
lref = 0;
|
||||
dcur = 6;
|
||||
bw = 3;
|
||||
break;
|
||||
case RTC_XTAL_FREQ_26M:
|
||||
div_ref = 12;
|
||||
div7_0 = 224;
|
||||
div10_8 = 4;
|
||||
lref = 1;
|
||||
dcur = 0;
|
||||
bw = 1;
|
||||
break;
|
||||
case RTC_XTAL_FREQ_24M:
|
||||
div_ref = 11;
|
||||
div7_0 = 224;
|
||||
div10_8 = 4;
|
||||
lref = 1;
|
||||
dcur = 0;
|
||||
bw = 1;
|
||||
break;
|
||||
default:
|
||||
div_ref = 12;
|
||||
div7_0 = 224;
|
||||
div10_8 = 4;
|
||||
lref = 0;
|
||||
dcur = 0;
|
||||
bw = 0;
|
||||
break;
|
||||
}
|
||||
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_ENDIV5, BBPLL_ENDIV5_VAL_320M);
|
||||
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_BBADC_DSMP, BBPLL_BBADC_DSMP_VAL_320M);
|
||||
} else {
|
||||
/* Raise the voltage */
|
||||
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_240M);
|
||||
esp_rom_delay_us(DELAY_PLL_DBIAS_RAISE);
|
||||
/* Configure 480M PLL */
|
||||
switch (xtal_freq) {
|
||||
case RTC_XTAL_FREQ_40M:
|
||||
div_ref = 0;
|
||||
div7_0 = 28;
|
||||
div10_8 = 0;
|
||||
lref = 0;
|
||||
dcur = 6;
|
||||
bw = 3;
|
||||
break;
|
||||
case RTC_XTAL_FREQ_26M:
|
||||
div_ref = 12;
|
||||
div7_0 = 144;
|
||||
div10_8 = 4;
|
||||
lref = 1;
|
||||
dcur = 0;
|
||||
bw = 1;
|
||||
break;
|
||||
case RTC_XTAL_FREQ_24M:
|
||||
div_ref = 11;
|
||||
div7_0 = 144;
|
||||
div10_8 = 4;
|
||||
lref = 1;
|
||||
dcur = 0;
|
||||
bw = 1;
|
||||
break;
|
||||
default:
|
||||
div_ref = 12;
|
||||
div7_0 = 224;
|
||||
div10_8 = 4;
|
||||
lref = 0;
|
||||
dcur = 0;
|
||||
bw = 0;
|
||||
break;
|
||||
}
|
||||
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_ENDIV5, BBPLL_ENDIV5_VAL_480M);
|
||||
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_BBADC_DSMP, BBPLL_BBADC_DSMP_VAL_480M);
|
||||
}
|
||||
|
||||
uint8_t i2c_bbpll_lref = (lref << 7) | (div10_8 << 4) | (div_ref);
|
||||
uint8_t i2c_bbpll_div_7_0 = div7_0;
|
||||
uint8_t i2c_bbpll_dcur = (bw << 6) | dcur;
|
||||
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_LREF, i2c_bbpll_lref);
|
||||
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DIV_7_0, i2c_bbpll_div_7_0);
|
||||
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DCUR, i2c_bbpll_dcur);
|
||||
uint32_t delay_pll_en = (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_RTC) ?
|
||||
DELAY_PLL_ENABLE_WITH_150K : DELAY_PLL_ENABLE_WITH_32K;
|
||||
esp_rom_delay_us(delay_pll_en);
|
||||
s_cur_pll_freq = pll_freq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to XTAL frequency. Does not disable the PLL.
|
||||
*/
|
||||
void rtc_clk_cpu_freq_to_xtal(int freq, int div)
|
||||
{
|
||||
ets_update_cpu_frequency(freq);
|
||||
/* set divider from XTAL to APB clock */
|
||||
REG_SET_FIELD(APB_CTRL_SYSCLK_CONF_REG, APB_CTRL_PRE_DIV_CNT, div - 1);
|
||||
/* adjust ref_tick */
|
||||
REG_WRITE(APB_CTRL_XTAL_TICK_CONF_REG, freq * MHZ / REF_CLK_FREQ - 1);
|
||||
/* switch clock source */
|
||||
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, RTC_CNTL_SOC_CLK_SEL_XTL);
|
||||
rtc_clk_apb_freq_update(freq * MHZ);
|
||||
/* lower the voltage */
|
||||
if (freq <= 2) {
|
||||
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_2M);
|
||||
} else {
|
||||
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_XTAL);
|
||||
}
|
||||
}
|
||||
|
||||
static void rtc_clk_cpu_freq_to_8m(void)
|
||||
{
|
||||
ets_update_cpu_frequency(8);
|
||||
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_XTAL);
|
||||
REG_SET_FIELD(APB_CTRL_SYSCLK_CONF_REG, APB_CTRL_PRE_DIV_CNT, 0);
|
||||
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, RTC_CNTL_SOC_CLK_SEL_8M);
|
||||
rtc_clk_apb_freq_update(RTC_FAST_CLK_FREQ_8M);
|
||||
}
|
||||
|
||||
static void rtc_clk_bbpll_disable(void)
|
||||
{
|
||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG,
|
||||
RTC_CNTL_BB_I2C_FORCE_PD | RTC_CNTL_BBPLL_FORCE_PD |
|
||||
RTC_CNTL_BBPLL_I2C_FORCE_PD);
|
||||
s_cur_pll_freq = 0;
|
||||
|
||||
/* is APLL under force power down? */
|
||||
uint32_t apll_fpd = REG_GET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD);
|
||||
if (apll_fpd) {
|
||||
/* then also power down the internal I2C bus */
|
||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FORCE_PD);
|
||||
}
|
||||
}
|
||||
|
||||
static void rtc_clk_bbpll_enable(void)
|
||||
{
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG,
|
||||
RTC_CNTL_BIAS_I2C_FORCE_PD | RTC_CNTL_BB_I2C_FORCE_PD |
|
||||
RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD);
|
||||
|
||||
/* reset BBPLL configuration */
|
||||
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_IR_CAL_DELAY, BBPLL_IR_CAL_DELAY_VAL);
|
||||
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_IR_CAL_EXT_CAP, BBPLL_IR_CAL_EXT_CAP_VAL);
|
||||
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_ENB_FCAL, BBPLL_OC_ENB_FCAL_VAL);
|
||||
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_ENB_VCON, BBPLL_OC_ENB_VCON_VAL);
|
||||
REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_BBADC_CAL_7_0, BBPLL_BBADC_CAL_7_0_VAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to one of PLL-based frequencies. Current frequency can be XTAL or PLL.
|
||||
* PLL must already be enabled.
|
||||
* @param cpu_freq new CPU frequency
|
||||
*/
|
||||
static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)
|
||||
{
|
||||
int dbias = DIG_DBIAS_80M_160M;
|
||||
int per_conf = DPORT_CPUPERIOD_SEL_80;
|
||||
if (cpu_freq_mhz == 80) {
|
||||
/* nothing to do */
|
||||
} else if (cpu_freq_mhz == 160) {
|
||||
per_conf = DPORT_CPUPERIOD_SEL_160;
|
||||
} else if (cpu_freq_mhz == 240) {
|
||||
dbias = DIG_DBIAS_240M;
|
||||
per_conf = DPORT_CPUPERIOD_SEL_240;
|
||||
} else {
|
||||
SOC_LOGE(TAG, "invalid frequency");
|
||||
abort();
|
||||
}
|
||||
DPORT_REG_WRITE(DPORT_CPU_PER_CONF_REG, per_conf);
|
||||
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, dbias);
|
||||
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, RTC_CNTL_SOC_CLK_SEL_PLL);
|
||||
rtc_clk_apb_freq_update(80 * MHZ);
|
||||
ets_update_cpu_frequency(cpu_freq_mhz);
|
||||
rtc_clk_wait_for_slow_cycle();
|
||||
}
|
||||
|
||||
void rtc_clk_cpu_freq_set_xtal(void)
|
||||
{
|
||||
int freq_mhz = (int) rtc_clk_xtal_freq_get();
|
||||
|
||||
rtc_clk_cpu_freq_to_xtal(freq_mhz, 1);
|
||||
rtc_clk_wait_for_slow_cycle();
|
||||
rtc_clk_bbpll_disable();
|
||||
}
|
||||
|
||||
void rtc_clk_cpu_freq_to_config(rtc_cpu_freq_t cpu_freq, rtc_cpu_freq_config_t* out_config)
|
||||
{
|
||||
uint32_t source_freq_mhz;
|
||||
rtc_cpu_freq_src_t source;
|
||||
uint32_t freq_mhz;
|
||||
uint32_t divider;
|
||||
|
||||
switch (cpu_freq) {
|
||||
case RTC_CPU_FREQ_XTAL:
|
||||
case RTC_CPU_FREQ_2M:
|
||||
source_freq_mhz = rtc_clk_xtal_freq_get();
|
||||
source = RTC_CPU_FREQ_SRC_XTAL;
|
||||
if (cpu_freq == RTC_CPU_FREQ_2M) {
|
||||
freq_mhz = 2;
|
||||
divider = source_freq_mhz / 2;
|
||||
} else {
|
||||
freq_mhz = source_freq_mhz;
|
||||
divider = 1;
|
||||
}
|
||||
break;
|
||||
case RTC_CPU_FREQ_80M:
|
||||
source = RTC_CPU_FREQ_SRC_PLL;
|
||||
source_freq_mhz = RTC_PLL_FREQ_320M;
|
||||
divider = 4;
|
||||
freq_mhz = 80;
|
||||
break;
|
||||
case RTC_CPU_FREQ_160M:
|
||||
source = RTC_CPU_FREQ_SRC_PLL;
|
||||
source_freq_mhz = RTC_PLL_FREQ_320M;
|
||||
divider = 2;
|
||||
freq_mhz = 160;
|
||||
break;
|
||||
case RTC_CPU_FREQ_240M:
|
||||
source = RTC_CPU_FREQ_SRC_PLL;
|
||||
source_freq_mhz = RTC_PLL_FREQ_480M;
|
||||
divider = 2;
|
||||
freq_mhz = 240;
|
||||
break;
|
||||
default:
|
||||
SOC_LOGE(TAG, "invalid rtc_cpu_freq_t value");
|
||||
abort();
|
||||
}
|
||||
|
||||
*out_config = (rtc_cpu_freq_config_t) {
|
||||
.source = source,
|
||||
.source_freq_mhz = source_freq_mhz,
|
||||
.div = divider,
|
||||
.freq_mhz = freq_mhz
|
||||
};
|
||||
}
|
||||
|
||||
bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t* out_config)
|
||||
{
|
||||
uint32_t source_freq_mhz;
|
||||
rtc_cpu_freq_src_t source;
|
||||
uint32_t divider;
|
||||
uint32_t real_freq_mhz;
|
||||
|
||||
uint32_t xtal_freq = (uint32_t) rtc_clk_xtal_freq_get();
|
||||
if (freq_mhz <= xtal_freq) {
|
||||
divider = xtal_freq / freq_mhz;
|
||||
real_freq_mhz = (xtal_freq + divider / 2) / divider; /* round */
|
||||
if (real_freq_mhz != freq_mhz) {
|
||||
// no suitable divider
|
||||
return false;
|
||||
}
|
||||
|
||||
source_freq_mhz = xtal_freq;
|
||||
source = RTC_CPU_FREQ_SRC_XTAL;
|
||||
} else if (freq_mhz == 80) {
|
||||
real_freq_mhz = freq_mhz;
|
||||
source = RTC_CPU_FREQ_SRC_PLL;
|
||||
source_freq_mhz = RTC_PLL_FREQ_320M;
|
||||
divider = 4;
|
||||
} else if (freq_mhz == 160) {
|
||||
real_freq_mhz = freq_mhz;
|
||||
source = RTC_CPU_FREQ_SRC_PLL;
|
||||
source_freq_mhz = RTC_PLL_FREQ_320M;
|
||||
divider = 2;
|
||||
} else if (freq_mhz == 240) {
|
||||
real_freq_mhz = freq_mhz;
|
||||
source = RTC_CPU_FREQ_SRC_PLL;
|
||||
source_freq_mhz = RTC_PLL_FREQ_480M;
|
||||
divider = 2;
|
||||
} else {
|
||||
// unsupported frequency
|
||||
return false;
|
||||
}
|
||||
*out_config = (rtc_cpu_freq_config_t) {
|
||||
.source = source,
|
||||
.div = divider,
|
||||
.source_freq_mhz = source_freq_mhz,
|
||||
.freq_mhz = real_freq_mhz
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t* config)
|
||||
{
|
||||
rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
|
||||
uint32_t soc_clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL);
|
||||
if (soc_clk_sel != RTC_CNTL_SOC_CLK_SEL_XTL) {
|
||||
rtc_clk_cpu_freq_to_xtal(xtal_freq, 1);
|
||||
rtc_clk_wait_for_slow_cycle();
|
||||
}
|
||||
if (soc_clk_sel == RTC_CNTL_SOC_CLK_SEL_PLL) {
|
||||
rtc_clk_bbpll_disable();
|
||||
}
|
||||
if (config->source == RTC_CPU_FREQ_SRC_XTAL) {
|
||||
if (config->div > 1) {
|
||||
rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div);
|
||||
}
|
||||
} else if (config->source == RTC_CPU_FREQ_SRC_PLL) {
|
||||
rtc_clk_bbpll_enable();
|
||||
rtc_clk_wait_for_slow_cycle();
|
||||
rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), config->source_freq_mhz);
|
||||
rtc_clk_cpu_freq_to_pll_mhz(config->freq_mhz);
|
||||
} else if (config->source == RTC_CPU_FREQ_SRC_8M) {
|
||||
rtc_clk_cpu_freq_to_8m();
|
||||
}
|
||||
}
|
||||
|
||||
void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t* out_config)
|
||||
{
|
||||
rtc_cpu_freq_src_t source;
|
||||
uint32_t source_freq_mhz;
|
||||
uint32_t div;
|
||||
uint32_t freq_mhz;
|
||||
uint32_t soc_clk_sel = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL);
|
||||
switch (soc_clk_sel) {
|
||||
case RTC_CNTL_SOC_CLK_SEL_XTL: {
|
||||
source = RTC_CPU_FREQ_SRC_XTAL;
|
||||
div = REG_GET_FIELD(APB_CTRL_SYSCLK_CONF_REG, APB_CTRL_PRE_DIV_CNT) + 1;
|
||||
source_freq_mhz = (uint32_t) rtc_clk_xtal_freq_get();
|
||||
freq_mhz = source_freq_mhz / div;
|
||||
}
|
||||
break;
|
||||
case RTC_CNTL_SOC_CLK_SEL_PLL: {
|
||||
source = RTC_CPU_FREQ_SRC_PLL;
|
||||
uint32_t cpuperiod_sel = DPORT_REG_GET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL);
|
||||
if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_80) {
|
||||
source_freq_mhz = RTC_PLL_FREQ_320M;
|
||||
div = 4;
|
||||
freq_mhz = 80;
|
||||
} else if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_160) {
|
||||
source_freq_mhz = RTC_PLL_FREQ_320M;
|
||||
div = 2;
|
||||
freq_mhz = 160;
|
||||
} else if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_240) {
|
||||
source_freq_mhz = RTC_PLL_FREQ_480M;
|
||||
div = 2;
|
||||
freq_mhz = 240;
|
||||
} else {
|
||||
SOC_LOGE(TAG, "unsupported frequency configuration");
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RTC_CNTL_SOC_CLK_SEL_8M:
|
||||
source = RTC_CPU_FREQ_SRC_8M;
|
||||
source_freq_mhz = 8;
|
||||
div = 1;
|
||||
freq_mhz = source_freq_mhz;
|
||||
break;
|
||||
case RTC_CNTL_SOC_CLK_SEL_APLL:
|
||||
default:
|
||||
SOC_LOGE(TAG, "unsupported frequency configuration");
|
||||
abort();
|
||||
}
|
||||
*out_config = (rtc_cpu_freq_config_t) {
|
||||
.source = source,
|
||||
.source_freq_mhz = source_freq_mhz,
|
||||
.div = div,
|
||||
.freq_mhz = freq_mhz
|
||||
};
|
||||
}
|
||||
|
||||
void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t* config)
|
||||
{
|
||||
if (config->source == RTC_CPU_FREQ_SRC_XTAL) {
|
||||
rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div);
|
||||
} else if (config->source == RTC_CPU_FREQ_SRC_PLL &&
|
||||
s_cur_pll_freq == config->source_freq_mhz) {
|
||||
rtc_clk_cpu_freq_to_pll_mhz(config->freq_mhz);
|
||||
} else {
|
||||
/* fallback */
|
||||
rtc_clk_cpu_freq_set_config(config);
|
||||
}
|
||||
}
|
||||
|
||||
rtc_xtal_freq_t rtc_clk_xtal_freq_get(void)
|
||||
{
|
||||
/* We may have already written XTAL value into RTC_XTAL_FREQ_REG */
|
||||
uint32_t xtal_freq_reg = READ_PERI_REG(RTC_XTAL_FREQ_REG);
|
||||
if (!clk_val_is_valid(xtal_freq_reg)) {
|
||||
return RTC_XTAL_FREQ_AUTO;
|
||||
}
|
||||
return reg_val_to_clk_val(xtal_freq_reg & ~RTC_DISABLE_ROM_LOG);
|
||||
}
|
||||
|
||||
void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq)
|
||||
{
|
||||
uint32_t reg = READ_PERI_REG(RTC_XTAL_FREQ_REG) & RTC_DISABLE_ROM_LOG;
|
||||
if (reg == RTC_DISABLE_ROM_LOG) {
|
||||
xtal_freq |= 1;
|
||||
}
|
||||
WRITE_PERI_REG(RTC_XTAL_FREQ_REG, clk_val_to_reg_val(xtal_freq));
|
||||
}
|
||||
|
||||
void rtc_clk_apb_freq_update(uint32_t apb_freq)
|
||||
{
|
||||
WRITE_PERI_REG(RTC_APB_FREQ_REG, clk_val_to_reg_val(apb_freq >> 12));
|
||||
}
|
||||
|
||||
uint32_t rtc_clk_apb_freq_get(void)
|
||||
{
|
||||
uint32_t freq_hz = reg_val_to_clk_val(READ_PERI_REG(RTC_APB_FREQ_REG)) << 12;
|
||||
// round to the nearest MHz
|
||||
freq_hz += MHZ / 2;
|
||||
uint32_t remainder = freq_hz % MHZ;
|
||||
return freq_hz - remainder;
|
||||
}
|
||||
|
||||
/* Name used in libphy.a:phy_chip_v7.o
|
||||
* TODO: update the library to use rtc_clk_xtal_freq_get
|
||||
*/
|
||||
rtc_xtal_freq_t rtc_get_xtal(void) __attribute__((alias("rtc_clk_xtal_freq_get")));
|
48
components/esp_hw_support/port/esp32/rtc_clk_common.h
Normal file
48
components/esp_hw_support/port/esp32/rtc_clk_common.h
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define MHZ (1000000)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void rtc_clk_cpu_freq_to_xtal(int freq, int div);
|
||||
|
||||
/* Values of RTC_XTAL_FREQ_REG and RTC_APB_FREQ_REG are stored as two copies in
|
||||
* lower and upper 16-bit halves. These are the routines to work with such a
|
||||
* representation.
|
||||
*/
|
||||
static inline bool clk_val_is_valid(uint32_t val) {
|
||||
return (val & 0xffff) == ((val >> 16) & 0xffff) &&
|
||||
val != 0 &&
|
||||
val != UINT32_MAX;
|
||||
}
|
||||
|
||||
static inline uint32_t reg_val_to_clk_val(uint32_t val) {
|
||||
return val & UINT16_MAX;
|
||||
}
|
||||
|
||||
static inline uint32_t clk_val_to_reg_val(uint32_t val) {
|
||||
return (val & UINT16_MAX) | ((val & UINT16_MAX) << 16);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
175
components/esp_hw_support/port/esp32/rtc_clk_init.c
Normal file
175
components/esp_hw_support/port/esp32/rtc_clk_init.c
Normal file
@@ -0,0 +1,175 @@
|
||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include "esp32/rom/rtc.h"
|
||||
#include "esp_rom_uart.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/rtc_periph.h"
|
||||
#include "soc/sens_periph.h"
|
||||
#include "soc/efuse_periph.h"
|
||||
#include "soc/apb_ctrl_reg.h"
|
||||
#include "regi2c_ctrl.h"
|
||||
#include "soc_log.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "xtensa/core-macros.h"
|
||||
#include "rtc_clk_common.h"
|
||||
|
||||
/* Number of 8M/256 clock cycles to use for XTAL frequency estimation.
|
||||
* 10 cycles will take approximately 300 microseconds.
|
||||
*/
|
||||
#define XTAL_FREQ_EST_CYCLES 10
|
||||
|
||||
static rtc_xtal_freq_t rtc_clk_xtal_freq_estimate(void);
|
||||
|
||||
static const char* TAG = "rtc_clk_init";
|
||||
|
||||
void rtc_clk_init(rtc_clk_config_t cfg)
|
||||
{
|
||||
rtc_cpu_freq_config_t old_config, new_config;
|
||||
|
||||
/* If we get a TG WDT system reset while running at 240MHz,
|
||||
* DPORT_CPUPERIOD_SEL register will be reset to 0 resulting in 120MHz
|
||||
* APB and CPU frequencies after reset. This will cause issues with XTAL
|
||||
* frequency estimation, so we switch to XTAL frequency first.
|
||||
*
|
||||
* Ideally we would only do this if RTC_CNTL_SOC_CLK_SEL == PLL and
|
||||
* PLL is configured for 480M, but it takes less time to switch to 40M and
|
||||
* run the following code than querying the PLL does.
|
||||
*/
|
||||
if (REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL) == RTC_CNTL_SOC_CLK_SEL_PLL) {
|
||||
/* We don't know actual XTAL frequency yet, assume 40MHz.
|
||||
* REF_TICK divider will be corrected below, once XTAL frequency is
|
||||
* determined.
|
||||
*/
|
||||
rtc_clk_cpu_freq_to_xtal(40, 1);
|
||||
}
|
||||
|
||||
/* Set tuning parameters for 8M and 150k clocks.
|
||||
* Note: this doesn't attempt to set the clocks to precise frequencies.
|
||||
* Instead, we calibrate these clocks against XTAL frequency later, when necessary.
|
||||
* - SCK_DCAP value controls tuning of 150k clock.
|
||||
* The higher the value of DCAP is, the lower is the frequency.
|
||||
* - CK8M_DFREQ value controls tuning of 8M clock.
|
||||
* CLK_8M_DFREQ constant gives the best temperature characteristics.
|
||||
*/
|
||||
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_SCK_DCAP, cfg.slow_clk_dcap);
|
||||
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DFREQ, cfg.clk_8m_dfreq);
|
||||
|
||||
/* Configure 8M clock division */
|
||||
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, cfg.clk_8m_div);
|
||||
|
||||
/* Enable the internal bus used to configure PLLs */
|
||||
SET_PERI_REG_BITS(ANA_CONFIG_REG, ANA_CONFIG_M, ANA_CONFIG_M, ANA_CONFIG_S);
|
||||
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, I2C_APLL_M | I2C_BBPLL_M);
|
||||
|
||||
/* Estimate XTAL frequency */
|
||||
rtc_xtal_freq_t xtal_freq = cfg.xtal_freq;
|
||||
if (xtal_freq == RTC_XTAL_FREQ_AUTO) {
|
||||
if (clk_val_is_valid(READ_PERI_REG(RTC_XTAL_FREQ_REG))) {
|
||||
/* XTAL frequency has already been set, use existing value */
|
||||
xtal_freq = rtc_clk_xtal_freq_get();
|
||||
} else {
|
||||
/* Not set yet, estimate XTAL frequency based on RTC_FAST_CLK */
|
||||
xtal_freq = rtc_clk_xtal_freq_estimate();
|
||||
if (xtal_freq == RTC_XTAL_FREQ_AUTO) {
|
||||
SOC_LOGW(TAG, "Can't estimate XTAL frequency, assuming 26MHz");
|
||||
xtal_freq = RTC_XTAL_FREQ_26M;
|
||||
}
|
||||
}
|
||||
} else if (!clk_val_is_valid(READ_PERI_REG(RTC_XTAL_FREQ_REG))) {
|
||||
/* Exact frequency was set in sdkconfig, but still warn if autodetected
|
||||
* frequency is different. If autodetection failed, worst case we get a
|
||||
* bit of garbage output.
|
||||
*/
|
||||
|
||||
rtc_xtal_freq_t est_xtal_freq = rtc_clk_xtal_freq_estimate();
|
||||
if (est_xtal_freq != xtal_freq) {
|
||||
SOC_LOGW(TAG, "Possibly invalid CONFIG_ESP32_XTAL_FREQ setting (%dMHz). Detected %d MHz.",
|
||||
xtal_freq, est_xtal_freq);
|
||||
}
|
||||
}
|
||||
esp_rom_uart_tx_wait_idle(0);
|
||||
rtc_clk_xtal_freq_update(xtal_freq);
|
||||
rtc_clk_apb_freq_update(xtal_freq * MHZ);
|
||||
|
||||
/* Set CPU frequency */
|
||||
|
||||
rtc_clk_cpu_freq_get_config(&old_config);
|
||||
uint32_t freq_before = old_config.freq_mhz;
|
||||
|
||||
bool res = rtc_clk_cpu_freq_mhz_to_config(cfg.cpu_freq_mhz, &new_config);
|
||||
if (!res) {
|
||||
SOC_LOGE(TAG, "invalid CPU frequency value");
|
||||
abort();
|
||||
}
|
||||
rtc_clk_cpu_freq_set_config(&new_config);
|
||||
|
||||
/* Configure REF_TICK */
|
||||
REG_WRITE(APB_CTRL_XTAL_TICK_CONF_REG, xtal_freq - 1);
|
||||
REG_WRITE(APB_CTRL_PLL_TICK_CONF_REG, APB_CLK_FREQ / MHZ - 1); /* Under PLL, APB frequency is always 80MHz */
|
||||
|
||||
/* Re-calculate the ccount to make time calculation correct. */
|
||||
XTHAL_SET_CCOUNT( (uint64_t)XTHAL_GET_CCOUNT() * cfg.cpu_freq_mhz / freq_before );
|
||||
|
||||
/* Slow & fast clocks setup */
|
||||
if (cfg.slow_freq == RTC_SLOW_FREQ_32K_XTAL) {
|
||||
rtc_clk_32k_enable(true);
|
||||
}
|
||||
if (cfg.fast_freq == RTC_FAST_FREQ_8M) {
|
||||
bool need_8md256 = cfg.slow_freq == RTC_SLOW_FREQ_8MD256;
|
||||
rtc_clk_8m_enable(true, need_8md256);
|
||||
}
|
||||
rtc_clk_fast_freq_set(cfg.fast_freq);
|
||||
rtc_clk_slow_freq_set(cfg.slow_freq);
|
||||
}
|
||||
|
||||
static rtc_xtal_freq_t rtc_clk_xtal_freq_estimate(void)
|
||||
{
|
||||
/* Enable 8M/256 clock if needed */
|
||||
const bool clk_8m_enabled = rtc_clk_8m_enabled();
|
||||
const bool clk_8md256_enabled = rtc_clk_8md256_enabled();
|
||||
if (!clk_8md256_enabled) {
|
||||
rtc_clk_8m_enable(true, true);
|
||||
}
|
||||
|
||||
uint64_t cal_val = rtc_clk_cal_ratio(RTC_CAL_8MD256, XTAL_FREQ_EST_CYCLES);
|
||||
/* cal_val contains period of 8M/256 clock in XTAL clock cycles
|
||||
* (shifted by RTC_CLK_CAL_FRACT bits).
|
||||
* Xtal frequency will be (cal_val * 8M / 256) / 2^19
|
||||
*/
|
||||
uint32_t freq_mhz = (cal_val * RTC_FAST_CLK_FREQ_APPROX / MHZ / 256 ) >> RTC_CLK_CAL_FRACT;
|
||||
/* Guess the XTAL type. For now, only 40 and 26MHz are supported.
|
||||
*/
|
||||
switch (freq_mhz) {
|
||||
case 21 ... 31:
|
||||
return RTC_XTAL_FREQ_26M;
|
||||
case 32 ... 33:
|
||||
SOC_LOGW(TAG, "Potentially bogus XTAL frequency: %d MHz, guessing 26 MHz", freq_mhz);
|
||||
return RTC_XTAL_FREQ_26M;
|
||||
case 34 ... 35:
|
||||
SOC_LOGW(TAG, "Potentially bogus XTAL frequency: %d MHz, guessing 40 MHz", freq_mhz);
|
||||
return RTC_XTAL_FREQ_40M;
|
||||
case 36 ... 45:
|
||||
return RTC_XTAL_FREQ_40M;
|
||||
default:
|
||||
SOC_LOGW(TAG, "Bogus XTAL frequency: %d MHz", freq_mhz);
|
||||
return RTC_XTAL_FREQ_AUTO;
|
||||
}
|
||||
/* Restore 8M and 8md256 clocks to original state */
|
||||
rtc_clk_8m_enable(clk_8m_enabled, clk_8md256_enabled);
|
||||
}
|
152
components/esp_hw_support/port/esp32/rtc_init.c
Normal file
152
components/esp_hw_support/port/esp32/rtc_init.c
Normal file
@@ -0,0 +1,152 @@
|
||||
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "soc/soc.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/rtc_periph.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/efuse_periph.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
|
||||
|
||||
void rtc_init(rtc_config_t cfg)
|
||||
{
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PVTMON_PU | RTC_CNTL_TXRF_I2C_PU |
|
||||
RTC_CNTL_RFRX_PBUS_PU | RTC_CNTL_CKGEN_I2C_PU | RTC_CNTL_PLL_I2C_PU);
|
||||
|
||||
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_PLL_BUF_WAIT, cfg.pll_wait);
|
||||
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_XTL_BUF_WAIT, cfg.xtal_wait);
|
||||
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, cfg.ck8m_wait);
|
||||
|
||||
REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN, RTC_CNTL_DBG_ATTEN_DEFAULT);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_BIAS_CONF_REG,
|
||||
RTC_CNTL_DEC_HEARTBEAT_WIDTH | RTC_CNTL_INC_HEARTBEAT_PERIOD);
|
||||
|
||||
/* Reset RTC bias to default value (needed if waking up from deep sleep) */
|
||||
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DBIAS_WAK, RTC_CNTL_DBIAS_1V10);
|
||||
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DBIAS_SLP, RTC_CNTL_DBIAS_1V10);
|
||||
|
||||
if (cfg.clkctl_init) {
|
||||
//clear CMMU clock force on
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CMMU_FORCE_ON);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CMMU_FORCE_ON);
|
||||
//clear rom clock force on
|
||||
DPORT_SET_PERI_REG_BITS(DPORT_ROM_FO_CTRL_REG, DPORT_SHARE_ROM_FO, 0, DPORT_SHARE_ROM_FO_S);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_ROM_FO_CTRL_REG, DPORT_APP_ROM_FO);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_ROM_FO_CTRL_REG, DPORT_PRO_ROM_FO);
|
||||
//clear sram clock force on
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_SRAM_FO_CTRL_0_REG, DPORT_SRAM_FO_0);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_SRAM_FO_CTRL_1_REG, DPORT_SRAM_FO_1);
|
||||
//clear tag clock force on
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_TAG_FO_CTRL_REG, DPORT_APP_CACHE_TAG_FORCE_ON);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_TAG_FO_CTRL_REG, DPORT_PRO_CACHE_TAG_FORCE_ON);
|
||||
}
|
||||
|
||||
if (cfg.pwrctl_init) {
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PU);
|
||||
//cancel xtal force pu
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_XTL_FORCE_PU);
|
||||
//cancel BIAS force pu
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_CORE_FORCE_PU);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FORCE_PU);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_FORCE_NOSLEEP);
|
||||
// bias follow 8M
|
||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_CORE_FOLW_8M);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FOLW_8M);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_SLEEP_FOLW_8M);
|
||||
// CLEAR APLL close
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PU);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BBPLL_FORCE_PU);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BBPLL_I2C_FORCE_PU);
|
||||
//cancel RTC REG force PU
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_REG, RTC_CNTL_FORCE_PU);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_REG, RTC_CNTL_DBOOST_FORCE_PU);
|
||||
if (cfg.rtc_dboost_fpd) {
|
||||
SET_PERI_REG_MASK(RTC_CNTL_REG, RTC_CNTL_DBOOST_FORCE_PD);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_REG, RTC_CNTL_DBOOST_FORCE_PD);
|
||||
}
|
||||
//cancel digital pu force
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_LSLP_MEM_FORCE_PU);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_DG_WRAP_FORCE_PU);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_WIFI_FORCE_PU);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_CPU_ROM_RAM_FORCE_PU);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_MEM_FORCE_PU);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_PWC_FORCE_PU);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_WRAP_FORCE_NOISO);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_WIFI_FORCE_NOISO);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_CPU_ROM_RAM_FORCE_NOISO);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_MEM_FORCE_NOISO);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_FORCE_NOISO);
|
||||
//cancel digital PADS force no iso
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_UNHOLD);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_NOISO);
|
||||
}
|
||||
}
|
||||
|
||||
rtc_vddsdio_config_t rtc_vddsdio_get_config(void)
|
||||
{
|
||||
rtc_vddsdio_config_t result;
|
||||
uint32_t sdio_conf_reg = REG_READ(RTC_CNTL_SDIO_CONF_REG);
|
||||
result.drefh = (sdio_conf_reg & RTC_CNTL_DREFH_SDIO_M) >> RTC_CNTL_DREFH_SDIO_S;
|
||||
result.drefm = (sdio_conf_reg & RTC_CNTL_DREFM_SDIO_M) >> RTC_CNTL_DREFM_SDIO_S;
|
||||
result.drefl = (sdio_conf_reg & RTC_CNTL_DREFL_SDIO_M) >> RTC_CNTL_DREFL_SDIO_S;
|
||||
if (sdio_conf_reg & RTC_CNTL_SDIO_FORCE) {
|
||||
// Get configuration from RTC
|
||||
result.force = 1;
|
||||
result.enable = (sdio_conf_reg & RTC_CNTL_XPD_SDIO_REG_M) >> RTC_CNTL_XPD_SDIO_REG_S;
|
||||
result.tieh = (sdio_conf_reg & RTC_CNTL_SDIO_TIEH_M) >> RTC_CNTL_SDIO_TIEH_S;
|
||||
return result;
|
||||
}
|
||||
uint32_t efuse_reg = REG_READ(EFUSE_BLK0_RDATA4_REG);
|
||||
if (efuse_reg & EFUSE_RD_SDIO_FORCE) {
|
||||
// Get configuration from EFUSE
|
||||
result.force = 0;
|
||||
result.enable = (efuse_reg & EFUSE_RD_XPD_SDIO_REG_M) >> EFUSE_RD_XPD_SDIO_REG_S;
|
||||
result.tieh = (efuse_reg & EFUSE_RD_SDIO_TIEH_M) >> EFUSE_RD_SDIO_TIEH_S;
|
||||
//DREFH/M/L eFuse are used for EFUSE_ADC_VREF instead. Therefore tuning
|
||||
//will only be available on older chips that don't have EFUSE_ADC_VREF
|
||||
if(REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG ,EFUSE_RD_BLK3_PART_RESERVE) == 0){
|
||||
//BLK3_PART_RESERVE indicates the presence of EFUSE_ADC_VREF
|
||||
// in this case, DREFH/M/L are also set from EFUSE
|
||||
result.drefh = (efuse_reg & EFUSE_RD_SDIO_DREFH_M) >> EFUSE_RD_SDIO_DREFH_S;
|
||||
result.drefm = (efuse_reg & EFUSE_RD_SDIO_DREFM_M) >> EFUSE_RD_SDIO_DREFM_S;
|
||||
result.drefl = (efuse_reg & EFUSE_RD_SDIO_DREFL_M) >> EFUSE_RD_SDIO_DREFL_S;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Otherwise, VDD_SDIO is controlled by bootstrapping pin
|
||||
uint32_t strap_reg = REG_READ(GPIO_STRAP_REG);
|
||||
result.force = 0;
|
||||
result.tieh = (strap_reg & BIT(5)) ? RTC_VDDSDIO_TIEH_1_8V : RTC_VDDSDIO_TIEH_3_3V;
|
||||
result.enable = 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
void rtc_vddsdio_set_config(rtc_vddsdio_config_t config)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
val |= (config.force << RTC_CNTL_SDIO_FORCE_S);
|
||||
val |= (config.enable << RTC_CNTL_XPD_SDIO_REG_S);
|
||||
val |= (config.drefh << RTC_CNTL_DREFH_SDIO_S);
|
||||
val |= (config.drefm << RTC_CNTL_DREFM_SDIO_S);
|
||||
val |= (config.drefl << RTC_CNTL_DREFL_SDIO_S);
|
||||
val |= (config.tieh << RTC_CNTL_SDIO_TIEH_S);
|
||||
val |= RTC_CNTL_SDIO_PD_EN;
|
||||
REG_WRITE(RTC_CNTL_SDIO_CONF_REG, val);
|
||||
}
|
66
components/esp_hw_support/port/esp32/rtc_pm.c
Normal file
66
components/esp_hw_support/port/esp32/rtc_pm.c
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include "soc/rtc.h"
|
||||
|
||||
typedef enum {
|
||||
PM_LIGHT_SLEEP = BIT(2), /*!< WiFi PD, memory in light sleep */
|
||||
} pm_sleep_mode_t;
|
||||
|
||||
typedef enum{
|
||||
PM_SW_NOREJECT = 0,
|
||||
PM_SW_REJECT = 1
|
||||
} pm_sw_reject_t;
|
||||
|
||||
|
||||
/* These MAC-related functions are defined in the closed source part of
|
||||
* RTC library
|
||||
*/
|
||||
extern void pm_mac_init(void);
|
||||
extern int pm_check_mac_idle(void);
|
||||
extern void pm_mac_deinit(void);
|
||||
|
||||
/* This sleep-related function is called from the closed source part of RTC
|
||||
* library.
|
||||
*/
|
||||
pm_sw_reject_t pm_set_sleep_mode(pm_sleep_mode_t sleep_mode, void(*pmac_save_params)(void))
|
||||
{
|
||||
(void) pmac_save_params; /* unused */
|
||||
|
||||
pm_mac_deinit();
|
||||
if (pm_check_mac_idle()) {
|
||||
pm_mac_init();
|
||||
return PM_SW_REJECT;
|
||||
}
|
||||
|
||||
rtc_sleep_config_t cfg = { 0 };
|
||||
|
||||
switch (sleep_mode) {
|
||||
case PM_LIGHT_SLEEP:
|
||||
cfg.wifi_pd_en = 1;
|
||||
cfg.dig_dbias_wak = 4;
|
||||
cfg.dig_dbias_slp = 0;
|
||||
cfg.rtc_dbias_wak = 0;
|
||||
cfg.rtc_dbias_slp = 0;
|
||||
cfg.lslp_meminf_pd = 1;
|
||||
rtc_sleep_init(cfg);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0 && "unsupported sleep mode");
|
||||
}
|
||||
return PM_SW_NOREJECT;
|
||||
}
|
334
components/esp_hw_support/port/esp32/rtc_sleep.c
Normal file
334
components/esp_hw_support/port/esp32/rtc_sleep.c
Normal file
@@ -0,0 +1,334 @@
|
||||
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdint.h>
|
||||
#include "soc/soc.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/i2s_periph.h"
|
||||
#include "soc/timer_periph.h"
|
||||
#include "soc/bb_reg.h"
|
||||
#include "soc/nrx_reg.h"
|
||||
#include "soc/fe_reg.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#include "esp32/rom/rtc.h"
|
||||
#include "hal/rtc_cntl_ll.h"
|
||||
#include "esp_rom_sys.h"
|
||||
|
||||
#define MHZ (1000000)
|
||||
|
||||
/* Various delays to be programmed into power control state machines */
|
||||
#define RTC_CNTL_XTL_BUF_WAIT_SLP 2
|
||||
#define RTC_CNTL_PLL_BUF_WAIT_SLP 2
|
||||
#define RTC_CNTL_CK8M_WAIT_SLP 4
|
||||
#define OTHER_BLOCKS_POWERUP 1
|
||||
#define OTHER_BLOCKS_WAIT 1
|
||||
|
||||
#define ROM_RAM_POWERUP_CYCLES OTHER_BLOCKS_POWERUP
|
||||
#define ROM_RAM_WAIT_CYCLES OTHER_BLOCKS_WAIT
|
||||
|
||||
#define WIFI_POWERUP_CYCLES OTHER_BLOCKS_POWERUP
|
||||
#define WIFI_WAIT_CYCLES OTHER_BLOCKS_WAIT
|
||||
|
||||
#define RTC_POWERUP_CYCLES OTHER_BLOCKS_POWERUP
|
||||
#define RTC_WAIT_CYCLES OTHER_BLOCKS_WAIT
|
||||
|
||||
#define DG_WRAP_POWERUP_CYCLES OTHER_BLOCKS_POWERUP
|
||||
#define DG_WRAP_WAIT_CYCLES OTHER_BLOCKS_WAIT
|
||||
|
||||
#define RTC_MEM_POWERUP_CYCLES OTHER_BLOCKS_POWERUP
|
||||
#define RTC_MEM_WAIT_CYCLES OTHER_BLOCKS_WAIT
|
||||
|
||||
/**
|
||||
* @brief Power down flags for rtc_sleep_pd function
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t dig_pd : 1; //!< Set to 1 to power down digital part in sleep
|
||||
uint32_t rtc_pd : 1; //!< Set to 1 to power down RTC memories in sleep
|
||||
uint32_t cpu_pd : 1; //!< Set to 1 to power down digital memories and CPU in sleep
|
||||
uint32_t i2s_pd : 1; //!< Set to 1 to power down I2S in sleep
|
||||
uint32_t bb_pd : 1; //!< Set to 1 to power down WiFi in sleep
|
||||
uint32_t nrx_pd : 1; //!< Set to 1 to power down WiFi in sleep
|
||||
uint32_t fe_pd : 1; //!< Set to 1 to power down WiFi in sleep
|
||||
} rtc_sleep_pd_config_t;
|
||||
|
||||
/**
|
||||
* Initializer for rtc_sleep_pd_config_t which sets all flags to the same value
|
||||
*/
|
||||
#define RTC_SLEEP_PD_CONFIG_ALL(val) {\
|
||||
.dig_pd = (val), \
|
||||
.rtc_pd = (val), \
|
||||
.cpu_pd = (val), \
|
||||
.i2s_pd = (val), \
|
||||
.bb_pd = (val), \
|
||||
.nrx_pd = (val), \
|
||||
.fe_pd = (val), \
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure whether certain peripherals are powered down in deep sleep
|
||||
* @param cfg power down flags as rtc_sleep_pd_config_t structure
|
||||
*/
|
||||
static void rtc_sleep_pd(rtc_sleep_pd_config_t cfg)
|
||||
{
|
||||
REG_SET_FIELD(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_LSLP_MEM_FORCE_PU, ~cfg.dig_pd);
|
||||
REG_SET_FIELD(RTC_CNTL_PWC_REG, RTC_CNTL_SLOWMEM_FORCE_LPU, ~cfg.rtc_pd);
|
||||
REG_SET_FIELD(RTC_CNTL_PWC_REG, RTC_CNTL_FASTMEM_FORCE_LPU, ~cfg.rtc_pd);
|
||||
DPORT_REG_SET_FIELD(DPORT_MEM_PD_MASK_REG, DPORT_LSLP_MEM_PD_MASK, ~cfg.cpu_pd);
|
||||
REG_SET_FIELD(I2S_PD_CONF_REG(0), I2S_PLC_MEM_FORCE_PU, ~cfg.i2s_pd);
|
||||
REG_SET_FIELD(I2S_PD_CONF_REG(0), I2S_FIFO_FORCE_PU, ~cfg.i2s_pd);
|
||||
REG_SET_FIELD(BBPD_CTRL, BB_FFT_FORCE_PU, ~cfg.bb_pd);
|
||||
REG_SET_FIELD(BBPD_CTRL, BB_DC_EST_FORCE_PU, ~cfg.bb_pd);
|
||||
REG_SET_FIELD(NRXPD_CTRL, NRX_RX_ROT_FORCE_PU, ~cfg.nrx_pd);
|
||||
REG_SET_FIELD(NRXPD_CTRL, NRX_VIT_FORCE_PU, ~cfg.nrx_pd);
|
||||
REG_SET_FIELD(NRXPD_CTRL, NRX_DEMAP_FORCE_PU, ~cfg.nrx_pd);
|
||||
REG_SET_FIELD(FE_GEN_CTRL, FE_IQ_EST_FORCE_PU, ~cfg.fe_pd);
|
||||
REG_SET_FIELD(FE2_TX_INTERP_CTRL, FE2_TX_INF_FORCE_PU, ~cfg.fe_pd);
|
||||
}
|
||||
|
||||
void rtc_sleep_init(rtc_sleep_config_t cfg)
|
||||
{
|
||||
// set 5 PWC state machine times to fit in main state machine time
|
||||
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_PLL_BUF_WAIT, RTC_CNTL_PLL_BUF_WAIT_SLP);
|
||||
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_XTL_BUF_WAIT, RTC_CNTL_XTL_BUF_WAIT_SLP);
|
||||
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_SLP);
|
||||
|
||||
// set shortest possible sleep time limit
|
||||
REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_MIN_SLP_VAL, RTC_CNTL_MIN_SLP_VAL_MIN);
|
||||
|
||||
// set rom&ram timer
|
||||
REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_ROM_RAM_POWERUP_TIMER, ROM_RAM_POWERUP_CYCLES);
|
||||
REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_ROM_RAM_WAIT_TIMER, ROM_RAM_WAIT_CYCLES);
|
||||
// set wifi timer
|
||||
REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_WIFI_POWERUP_TIMER, WIFI_POWERUP_CYCLES);
|
||||
REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_WIFI_WAIT_TIMER, WIFI_WAIT_CYCLES);
|
||||
// set rtc peri timer
|
||||
REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_POWERUP_TIMER, RTC_POWERUP_CYCLES);
|
||||
REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_WAIT_TIMER, RTC_WAIT_CYCLES);
|
||||
// set digital wrap timer
|
||||
REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_DG_WRAP_POWERUP_TIMER, DG_WRAP_POWERUP_CYCLES);
|
||||
REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_DG_WRAP_WAIT_TIMER, DG_WRAP_WAIT_CYCLES);
|
||||
// set rtc memory timer
|
||||
REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_RTCMEM_POWERUP_TIMER, RTC_MEM_POWERUP_CYCLES);
|
||||
REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_RTCMEM_WAIT_TIMER, RTC_MEM_WAIT_CYCLES);
|
||||
|
||||
REG_SET_FIELD(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_LSLP_MEM_FORCE_PU, cfg.lslp_mem_inf_fpu);
|
||||
|
||||
rtc_sleep_pd_config_t pd_cfg = RTC_SLEEP_PD_CONFIG_ALL(cfg.lslp_meminf_pd);
|
||||
rtc_sleep_pd(pd_cfg);
|
||||
|
||||
if (cfg.rtc_mem_inf_fpu) {
|
||||
SET_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_MEM_FORCE_PU);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_MEM_FORCE_PU);
|
||||
}
|
||||
|
||||
if (cfg.rtc_mem_inf_follow_cpu) {
|
||||
SET_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_MEM_FOLW_CPU);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_MEM_FOLW_CPU);
|
||||
}
|
||||
|
||||
if (cfg.rtc_fastmem_pd_en) {
|
||||
SET_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_FASTMEM_PD_EN);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_FASTMEM_FORCE_PU);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_FASTMEM_FORCE_NOISO);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_FASTMEM_PD_EN);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_FASTMEM_FORCE_PU);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_FASTMEM_FORCE_NOISO);
|
||||
}
|
||||
|
||||
if (cfg.rtc_slowmem_pd_en) {
|
||||
SET_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_SLOWMEM_PD_EN);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_SLOWMEM_FORCE_PU);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_SLOWMEM_FORCE_NOISO);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_SLOWMEM_PD_EN);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_SLOWMEM_FORCE_PU);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_SLOWMEM_FORCE_NOISO);
|
||||
}
|
||||
|
||||
if (cfg.rtc_peri_pd_en) {
|
||||
SET_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_PD_EN);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_PD_EN);
|
||||
}
|
||||
|
||||
if (cfg.wifi_pd_en) {
|
||||
SET_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_WIFI_PD_EN);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_WIFI_PD_EN);
|
||||
}
|
||||
|
||||
if (cfg.rom_mem_pd_en) {
|
||||
SET_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_CPU_ROM_RAM_PD_EN);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_CPU_ROM_RAM_PD_EN);
|
||||
}
|
||||
|
||||
if (cfg.deep_slp) {
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG,
|
||||
RTC_CNTL_DG_PAD_FORCE_ISO | RTC_CNTL_DG_PAD_FORCE_NOISO);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_DG_WRAP_PD_EN);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG,
|
||||
RTC_CNTL_DG_WRAP_FORCE_PU | RTC_CNTL_DG_WRAP_FORCE_PD);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_FORCE_NOSLEEP);
|
||||
|
||||
// Shut down parts of RTC which may have been left enabled by the wireless drivers
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG,
|
||||
RTC_CNTL_CKGEN_I2C_PU | RTC_CNTL_PLL_I2C_PU |
|
||||
RTC_CNTL_RFRX_PBUS_PU | RTC_CNTL_TXRF_I2C_PU);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_DG_WRAP_PD_EN);
|
||||
REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN, 0);
|
||||
}
|
||||
|
||||
REG_SET_FIELD(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_XTL_FORCE_PU, cfg.xtal_fpu);
|
||||
|
||||
if (REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL) == RTC_SLOW_FREQ_8MD256) {
|
||||
REG_SET_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PU);
|
||||
} else {
|
||||
REG_CLR_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PU);
|
||||
}
|
||||
//Keep the RTC8M_CLK on in light_sleep mode if the ledc low-speed channel is clocked by RTC8M_CLK.
|
||||
if (!cfg.deep_slp && GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M)) {
|
||||
REG_CLR_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PD);
|
||||
REG_SET_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PU);
|
||||
}
|
||||
|
||||
/* enable VDDSDIO control by state machine */
|
||||
REG_CLR_BIT(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_FORCE);
|
||||
REG_SET_FIELD(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_PD_EN, cfg.vddsdio_pd_en);
|
||||
|
||||
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DBIAS_SLP, cfg.rtc_dbias_slp);
|
||||
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DBIAS_WAK, cfg.rtc_dbias_wak);
|
||||
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, cfg.dig_dbias_wak);
|
||||
REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_SLP, cfg.dig_dbias_slp);
|
||||
}
|
||||
|
||||
void rtc_sleep_set_wakeup_time(uint64_t t)
|
||||
{
|
||||
rtc_cntl_ll_set_wakeup_timer(t);
|
||||
}
|
||||
|
||||
/* Read back 'reject' status when waking from light or deep sleep */
|
||||
static uint32_t rtc_sleep_finish(void);
|
||||
|
||||
uint32_t rtc_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt)
|
||||
{
|
||||
REG_SET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_ENA, wakeup_opt);
|
||||
WRITE_PERI_REG(RTC_CNTL_SLP_REJECT_CONF_REG, reject_opt);
|
||||
|
||||
/* Start entry into sleep mode */
|
||||
SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN);
|
||||
|
||||
while (GET_PERI_REG_MASK(RTC_CNTL_INT_RAW_REG,
|
||||
RTC_CNTL_SLP_REJECT_INT_RAW | RTC_CNTL_SLP_WAKEUP_INT_RAW) == 0) {
|
||||
;
|
||||
}
|
||||
|
||||
return rtc_sleep_finish();
|
||||
}
|
||||
|
||||
#define STR2(X) #X
|
||||
#define STR(X) STR2(X)
|
||||
|
||||
uint32_t rtc_deep_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt)
|
||||
{
|
||||
REG_SET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_ENA, wakeup_opt);
|
||||
WRITE_PERI_REG(RTC_CNTL_SLP_REJECT_CONF_REG, reject_opt);
|
||||
|
||||
/* Calculate RTC Fast Memory CRC (for wake stub) & go to deep sleep
|
||||
|
||||
Because we may be running from RTC memory as stack, we can't easily call any
|
||||
functions to do this (as registers may spill to stack, corrupting the CRC).
|
||||
|
||||
Instead, load all the values we need into registers (triggering any stack spills)
|
||||
then use register ops only to calculate the CRC value, write it to the RTC CRC value
|
||||
register, and immediately go into deep sleep.
|
||||
*/
|
||||
|
||||
/* Values used to set the RTC_MEM_CONFG value */
|
||||
const unsigned CRC_START_ADDR = 0;
|
||||
const unsigned CRC_LEN = 0x7ff;
|
||||
const unsigned RTC_MEM_PID = 1;
|
||||
|
||||
asm volatile(
|
||||
"movi a2, 0\n" // trigger a stack spill on working register if needed
|
||||
|
||||
/* Start CRC calculation */
|
||||
"s32i %1, %0, 0\n" // set RTC_MEM_CRC_ADDR & RTC_MEM_CRC_LEN
|
||||
"or a2, %1, %2\n"
|
||||
"s32i a2, %0, 0\n" // set RTC_MEM_CRC_START
|
||||
|
||||
/* Wait for the CRC calculation to finish */
|
||||
".Lwaitcrc:\n"
|
||||
"memw\n"
|
||||
"l32i a2, %0, 0\n"
|
||||
"bbci a2, "STR(RTC_MEM_CRC_FINISH_S)", .Lwaitcrc\n"
|
||||
"and a2, a2, %3\n" // clear RTC_MEM_CRC_START
|
||||
"s32i a2, %0, 0\n"
|
||||
"memw\n"
|
||||
|
||||
/* Store the calculated value in RTC_MEM_CRC_REG */
|
||||
"l32i a2, %4, 0\n"
|
||||
"s32i a2, %5, 0\n"
|
||||
"memw\n"
|
||||
|
||||
/* Set register bit to go into deep sleep */
|
||||
"l32i a2, %6, 0\n"
|
||||
"or a2, a2, %7\n"
|
||||
"s32i a2, %6, 0\n"
|
||||
"memw\n"
|
||||
|
||||
/* Set wait cycle for touch or COCPU after deep sleep. */
|
||||
".Lwaitsleep:"
|
||||
"memw\n"
|
||||
"l32i a2, %8, 0\n"
|
||||
"and a2, a2, %9\n"
|
||||
"beqz a2, .Lwaitsleep\n"
|
||||
|
||||
:
|
||||
: "r" (RTC_MEM_CONF), // %0
|
||||
"r" ( (CRC_START_ADDR << RTC_MEM_CRC_ADDR_S)
|
||||
| (CRC_LEN << RTC_MEM_CRC_LEN_S)
|
||||
| (RTC_MEM_PID << RTC_MEM_PID_CONF_S) ), // %1
|
||||
"r" (RTC_MEM_CRC_START), // %2
|
||||
"r" (~RTC_MEM_CRC_START), // %3
|
||||
"r" (RTC_MEM_CRC_RES), // %4
|
||||
"r" (RTC_MEMORY_CRC_REG), // %5
|
||||
"r" (RTC_CNTL_STATE0_REG), // %6
|
||||
"r" (RTC_CNTL_SLEEP_EN), // %7
|
||||
"r" (RTC_CNTL_INT_RAW_REG), // %8
|
||||
"r" (RTC_CNTL_SLP_REJECT_INT_RAW | RTC_CNTL_SLP_WAKEUP_INT_RAW) // %9
|
||||
: "a2" // working register
|
||||
);
|
||||
|
||||
return rtc_sleep_finish();
|
||||
}
|
||||
|
||||
static uint32_t rtc_sleep_finish(void)
|
||||
{
|
||||
/* In deep sleep mode, we never get here */
|
||||
uint32_t reject = REG_GET_FIELD(RTC_CNTL_INT_RAW_REG, RTC_CNTL_SLP_REJECT_INT_RAW);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_INT_CLR_REG,
|
||||
RTC_CNTL_SLP_REJECT_INT_CLR | RTC_CNTL_SLP_WAKEUP_INT_CLR);
|
||||
|
||||
/* restore DBG_ATTEN to the default value */
|
||||
REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN, RTC_CNTL_DBG_ATTEN_DEFAULT);
|
||||
return reject;
|
||||
}
|
170
components/esp_hw_support/port/esp32/rtc_time.c
Normal file
170
components/esp_hw_support/port/esp32/rtc_time.c
Normal file
@@ -0,0 +1,170 @@
|
||||
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_rom_sys.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/timer_periph.h"
|
||||
#include "soc_log.h"
|
||||
|
||||
#define MHZ (1000000)
|
||||
|
||||
static const char* TAG = "rtc_time";
|
||||
|
||||
/* Calibration of RTC_SLOW_CLK is performed using a special feature of TIMG0.
|
||||
* This feature counts the number of XTAL clock cycles within a given number of
|
||||
* RTC_SLOW_CLK cycles.
|
||||
*
|
||||
* Slow clock calibration feature has two modes of operation: one-off and cycling.
|
||||
* In cycling mode (which is enabled by default on SoC reset), counting of XTAL
|
||||
* cycles within RTC_SLOW_CLK cycle is done continuously. Cycling mode is enabled
|
||||
* using TIMG_RTC_CALI_START_CYCLING bit. In one-off mode counting is performed
|
||||
* once, and TIMG_RTC_CALI_RDY bit is set when counting is done. One-off mode is
|
||||
* enabled using TIMG_RTC_CALI_START bit.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Clock calibration function used by rtc_clk_cal and rtc_clk_cal_ratio
|
||||
* @param cal_clk which clock to calibrate
|
||||
* @param slowclk_cycles number of slow clock cycles to count. Max value is 32766.
|
||||
* @return number of XTAL clock cycles within the given number of slow clock cycles
|
||||
*/
|
||||
static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
|
||||
{
|
||||
assert(slowclk_cycles < 32767);
|
||||
/* Enable requested clock (150k clock is always on) */
|
||||
int dig_32k_xtal_state = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN);
|
||||
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_state) {
|
||||
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, 1);
|
||||
}
|
||||
|
||||
if (cal_clk == RTC_CAL_8MD256) {
|
||||
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN);
|
||||
}
|
||||
/* Prepare calibration */
|
||||
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, cal_clk);
|
||||
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING);
|
||||
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_MAX, slowclk_cycles);
|
||||
/* Figure out how long to wait for calibration to finish */
|
||||
uint32_t expected_freq;
|
||||
rtc_slow_freq_t slow_freq = REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL);
|
||||
if (cal_clk == RTC_CAL_32K_XTAL ||
|
||||
(cal_clk == RTC_CAL_RTC_MUX && slow_freq == RTC_SLOW_FREQ_32K_XTAL)) {
|
||||
expected_freq = 32768; /* standard 32k XTAL */
|
||||
} else if (cal_clk == RTC_CAL_8MD256 ||
|
||||
(cal_clk == RTC_CAL_RTC_MUX && slow_freq == RTC_SLOW_FREQ_8MD256)) {
|
||||
expected_freq = RTC_FAST_CLK_FREQ_APPROX / 256;
|
||||
} else {
|
||||
expected_freq = 150000; /* 150k internal oscillator */
|
||||
}
|
||||
uint32_t us_time_estimate = (uint32_t) (((uint64_t) slowclk_cycles) * MHZ / expected_freq);
|
||||
/* Check if the required number of slowclk_cycles may result in an overflow of TIMG_RTC_CALI_VALUE */
|
||||
rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
|
||||
if (xtal_freq == RTC_XTAL_FREQ_AUTO) {
|
||||
/* XTAL frequency is not known yet; assume worst case (40 MHz) */
|
||||
xtal_freq = RTC_XTAL_FREQ_40M;
|
||||
}
|
||||
const uint32_t us_timer_max = TIMG_RTC_CALI_VALUE / (uint32_t) xtal_freq;
|
||||
if (us_time_estimate >= us_timer_max) {
|
||||
SOC_LOGE(TAG, "slowclk_cycles value too large, possible overflow");
|
||||
return 0;
|
||||
}
|
||||
/* Start calibration */
|
||||
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
|
||||
SET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
|
||||
/* Wait the expected time calibration should take.
|
||||
* TODO: if running under RTOS, and us_time_estimate > RTOS tick, use the
|
||||
* RTOS delay function.
|
||||
*/
|
||||
esp_rom_delay_us(us_time_estimate);
|
||||
/* Wait for calibration to finish up to another us_time_estimate */
|
||||
int timeout_us = us_time_estimate;
|
||||
while (!GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_RDY) &&
|
||||
timeout_us > 0) {
|
||||
timeout_us--;
|
||||
esp_rom_delay_us(1);
|
||||
}
|
||||
|
||||
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, dig_32k_xtal_state);
|
||||
|
||||
if (cal_clk == RTC_CAL_8MD256) {
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_D256_EN);
|
||||
}
|
||||
if (timeout_us == 0) {
|
||||
/* timed out waiting for calibration */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return REG_GET_FIELD(TIMG_RTCCALICFG1_REG(0), TIMG_RTC_CALI_VALUE);
|
||||
}
|
||||
|
||||
uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
|
||||
{
|
||||
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
|
||||
uint64_t ratio_64 = ((xtal_cycles << RTC_CLK_CAL_FRACT)) / slowclk_cycles;
|
||||
uint32_t ratio = (uint32_t)(ratio_64 & UINT32_MAX);
|
||||
return ratio;
|
||||
}
|
||||
|
||||
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
|
||||
{
|
||||
rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
|
||||
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
|
||||
uint64_t divider = ((uint64_t)xtal_freq) * slowclk_cycles;
|
||||
uint64_t period_64 = ((xtal_cycles << RTC_CLK_CAL_FRACT) + divider / 2 - 1) / divider;
|
||||
uint32_t period = (uint32_t)(period_64 & UINT32_MAX);
|
||||
return period;
|
||||
}
|
||||
|
||||
uint64_t rtc_time_us_to_slowclk(uint64_t time_in_us, uint32_t period)
|
||||
{
|
||||
/* Overflow will happen in this function if time_in_us >= 2^45, which is about 400 days.
|
||||
* TODO: fix overflow.
|
||||
*/
|
||||
return (time_in_us << RTC_CLK_CAL_FRACT) / period;
|
||||
}
|
||||
|
||||
uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period)
|
||||
{
|
||||
return (rtc_cycles * period) >> RTC_CLK_CAL_FRACT;
|
||||
}
|
||||
|
||||
uint64_t rtc_time_get(void)
|
||||
{
|
||||
SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE);
|
||||
while (GET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_VALID) == 0) {
|
||||
esp_rom_delay_us(1); // might take 1 RTC slowclk period, don't flood RTC bus
|
||||
}
|
||||
SET_PERI_REG_MASK(RTC_CNTL_INT_CLR_REG, RTC_CNTL_TIME_VALID_INT_CLR);
|
||||
uint64_t t = READ_PERI_REG(RTC_CNTL_TIME0_REG);
|
||||
t |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME1_REG)) << 32;
|
||||
return t;
|
||||
}
|
||||
|
||||
void rtc_clk_wait_for_slow_cycle(void)
|
||||
{
|
||||
REG_CLR_BIT(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING | TIMG_RTC_CALI_START);
|
||||
REG_CLR_BIT(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_RDY);
|
||||
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, RTC_CAL_RTC_MUX);
|
||||
/* Request to run calibration for 0 slow clock cycles.
|
||||
* RDY bit will be set on the nearest slow clock cycle.
|
||||
*/
|
||||
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_MAX, 0);
|
||||
REG_SET_BIT(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
|
||||
esp_rom_delay_us(1); /* RDY needs some time to go low */
|
||||
while (!GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_RDY)) {
|
||||
esp_rom_delay_us(1);
|
||||
}
|
||||
}
|
||||
|
151
components/esp_hw_support/port/esp32/rtc_wdt.c
Normal file
151
components/esp_hw_support/port/esp32/rtc_wdt.c
Normal file
@@ -0,0 +1,151 @@
|
||||
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "soc/rtc_wdt.h"
|
||||
#include "soc/rtc.h"
|
||||
|
||||
|
||||
bool rtc_wdt_get_protect_status(void)
|
||||
{
|
||||
return READ_PERI_REG(RTC_CNTL_WDTWPROTECT_REG) != RTC_CNTL_WDT_WKEY_VALUE;
|
||||
}
|
||||
|
||||
void rtc_wdt_protect_off(void)
|
||||
{
|
||||
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
|
||||
}
|
||||
|
||||
void rtc_wdt_protect_on(void)
|
||||
{
|
||||
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
|
||||
}
|
||||
|
||||
|
||||
void rtc_wdt_enable(void)
|
||||
{
|
||||
REG_SET_BIT(RTC_CNTL_WDTFEED_REG, RTC_CNTL_WDT_FEED);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN | RTC_CNTL_WDT_PAUSE_IN_SLP);
|
||||
}
|
||||
|
||||
void rtc_wdt_flashboot_mode_enable(void)
|
||||
{
|
||||
REG_SET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
|
||||
}
|
||||
|
||||
void rtc_wdt_disable(void)
|
||||
{
|
||||
bool protect = rtc_wdt_get_protect_status();
|
||||
if (protect) {
|
||||
rtc_wdt_protect_off();
|
||||
}
|
||||
REG_SET_BIT(RTC_CNTL_WDTFEED_REG, RTC_CNTL_WDT_FEED);
|
||||
rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_OFF);
|
||||
rtc_wdt_set_stage(RTC_WDT_STAGE1, RTC_WDT_STAGE_ACTION_OFF);
|
||||
rtc_wdt_set_stage(RTC_WDT_STAGE2, RTC_WDT_STAGE_ACTION_OFF);
|
||||
rtc_wdt_set_stage(RTC_WDT_STAGE3, RTC_WDT_STAGE_ACTION_OFF);
|
||||
REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
|
||||
REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN);
|
||||
if (protect) {
|
||||
rtc_wdt_protect_on();
|
||||
}
|
||||
}
|
||||
|
||||
void rtc_wdt_feed(void)
|
||||
{
|
||||
bool protect = rtc_wdt_get_protect_status();
|
||||
if (protect) {
|
||||
rtc_wdt_protect_off();
|
||||
}
|
||||
REG_SET_BIT(RTC_CNTL_WDTFEED_REG, RTC_CNTL_WDT_FEED);
|
||||
if (protect) {
|
||||
rtc_wdt_protect_on();
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t rtc_wdt_set_time(rtc_wdt_stage_t stage, unsigned int timeout_ms)
|
||||
{
|
||||
if (stage > 3) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
uint32_t timeout = (uint32_t) ((uint64_t) rtc_clk_slow_freq_get_hz() * timeout_ms / 1000);
|
||||
if (stage == RTC_WDT_STAGE0) {
|
||||
WRITE_PERI_REG(RTC_CNTL_WDTCONFIG1_REG, timeout);
|
||||
} else if (stage == RTC_WDT_STAGE1) {
|
||||
WRITE_PERI_REG(RTC_CNTL_WDTCONFIG2_REG, timeout);
|
||||
} else if (stage == RTC_WDT_STAGE2) {
|
||||
WRITE_PERI_REG(RTC_CNTL_WDTCONFIG3_REG, timeout);
|
||||
} else {
|
||||
WRITE_PERI_REG(RTC_CNTL_WDTCONFIG4_REG, timeout);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rtc_wdt_get_timeout(rtc_wdt_stage_t stage, unsigned int* timeout_ms)
|
||||
{
|
||||
if (stage > 3) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
uint32_t time_tick;
|
||||
if (stage == RTC_WDT_STAGE0) {
|
||||
time_tick = READ_PERI_REG(RTC_CNTL_WDTCONFIG1_REG);
|
||||
} else if (stage == RTC_WDT_STAGE1) {
|
||||
time_tick = READ_PERI_REG(RTC_CNTL_WDTCONFIG2_REG);
|
||||
} else if (stage == RTC_WDT_STAGE2) {
|
||||
time_tick = READ_PERI_REG(RTC_CNTL_WDTCONFIG3_REG);
|
||||
} else {
|
||||
time_tick = READ_PERI_REG(RTC_CNTL_WDTCONFIG4_REG);
|
||||
}
|
||||
|
||||
*timeout_ms = time_tick * 1000 / rtc_clk_slow_freq_get_hz();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rtc_wdt_set_stage(rtc_wdt_stage_t stage, rtc_wdt_stage_action_t stage_sel)
|
||||
{
|
||||
if (stage > 3 || stage_sel > 4) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (stage == RTC_WDT_STAGE0) {
|
||||
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, stage_sel);
|
||||
} else if (stage == RTC_WDT_STAGE1) {
|
||||
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG1, stage_sel);
|
||||
} else if (stage == RTC_WDT_STAGE2) {
|
||||
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG2, stage_sel);
|
||||
} else {
|
||||
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG3, stage_sel);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rtc_wdt_set_length_of_reset_signal(rtc_wdt_reset_sig_t reset_src, rtc_wdt_length_sig_t reset_signal_length)
|
||||
{
|
||||
if (reset_src > 1 || reset_signal_length > 7) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (reset_src == 0) {
|
||||
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_SYS_RESET_LENGTH, reset_signal_length);
|
||||
} else {
|
||||
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_CPU_RESET_LENGTH, reset_signal_length);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
bool rtc_wdt_is_on(void)
|
||||
{
|
||||
return (REG_GET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN) != 0) || (REG_GET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN) != 0);
|
||||
}
|
Reference in New Issue
Block a user