From 7d4b2617e13f363145046747a63f14d706a34f82 Mon Sep 17 00:00:00 2001 From: Shu Chen Date: Thu, 10 Jun 2021 13:39:15 +0800 Subject: [PATCH] esp32h2: copy esp_system and esp_hw_support from esp32c3 Copy the esp32c3 code without any change: * components/esp_hw_support/include/soc/esp32h2 * components/esp_hw_support/port/esp32h2 * components/esp_system/port/soc/esp32h2 --- .../esp_hw_support/include/soc/esp32h2/clk.h | 16 + .../port/esp32h2/CMakeLists.txt | 24 + .../esp_hw_support/port/esp32h2/Kconfig.mac | 43 ++ .../esp_hw_support/port/esp32h2/chip_info.c | 26 + .../port/esp32h2/cpu_util_esp32h2.c | 112 ++++ .../port/esp32h2/i2c_brownout.h | 30 + .../esp_hw_support/port/esp32h2/i2c_rtc_clk.h | 48 ++ .../esp32h2/private_include/regi2c_bbpll.h | 183 +++++++ .../esp32h2/private_include/regi2c_bias.h | 30 + .../esp32h2/private_include/regi2c_brownout.h | 30 + .../esp32h2/private_include/regi2c_dig_reg.h | 68 +++ .../esp32h2/private_include/regi2c_lp_bias.h | 63 +++ .../esp32h2/private_include/regi2c_saradc.h | 87 +++ .../esp_hw_support/port/esp32h2/regi2c_ctrl.h | 109 ++++ .../esp_hw_support/port/esp32h2/rtc_clk.c | 515 ++++++++++++++++++ .../port/esp32h2/rtc_clk_common.h | 57 ++ .../port/esp32h2/rtc_clk_init.c | 88 +++ .../esp_hw_support/port/esp32h2/rtc_init.c | 339 ++++++++++++ .../esp_hw_support/port/esp32h2/rtc_pm.c | 67 +++ .../esp_hw_support/port/esp32h2/rtc_sleep.c | 254 +++++++++ .../esp_hw_support/port/esp32h2/rtc_time.c | 189 +++++++ .../port/soc/esp32h2/CMakeLists.txt | 11 + .../port/soc/esp32h2/apb_backup_dma.c | 48 ++ .../port/soc/esp32h2/cache_err_int.c | 102 ++++ .../port/soc/esp32h2/cache_err_int.h | 2 + components/esp_system/port/soc/esp32h2/clk.c | 321 +++++++++++ .../port/soc/esp32h2/reset_reason.c | 119 ++++ .../port/soc/esp32h2/system_internal.c | 144 +++++ 28 files changed, 3125 insertions(+) create mode 100644 components/esp_hw_support/include/soc/esp32h2/clk.h create mode 100644 components/esp_hw_support/port/esp32h2/CMakeLists.txt create mode 100644 components/esp_hw_support/port/esp32h2/Kconfig.mac create mode 100644 components/esp_hw_support/port/esp32h2/chip_info.c create mode 100644 components/esp_hw_support/port/esp32h2/cpu_util_esp32h2.c create mode 100644 components/esp_hw_support/port/esp32h2/i2c_brownout.h create mode 100644 components/esp_hw_support/port/esp32h2/i2c_rtc_clk.h create mode 100644 components/esp_hw_support/port/esp32h2/private_include/regi2c_bbpll.h create mode 100644 components/esp_hw_support/port/esp32h2/private_include/regi2c_bias.h create mode 100644 components/esp_hw_support/port/esp32h2/private_include/regi2c_brownout.h create mode 100644 components/esp_hw_support/port/esp32h2/private_include/regi2c_dig_reg.h create mode 100644 components/esp_hw_support/port/esp32h2/private_include/regi2c_lp_bias.h create mode 100644 components/esp_hw_support/port/esp32h2/private_include/regi2c_saradc.h create mode 100644 components/esp_hw_support/port/esp32h2/regi2c_ctrl.h create mode 100644 components/esp_hw_support/port/esp32h2/rtc_clk.c create mode 100644 components/esp_hw_support/port/esp32h2/rtc_clk_common.h create mode 100644 components/esp_hw_support/port/esp32h2/rtc_clk_init.c create mode 100644 components/esp_hw_support/port/esp32h2/rtc_init.c create mode 100644 components/esp_hw_support/port/esp32h2/rtc_pm.c create mode 100644 components/esp_hw_support/port/esp32h2/rtc_sleep.c create mode 100644 components/esp_hw_support/port/esp32h2/rtc_time.c create mode 100644 components/esp_system/port/soc/esp32h2/CMakeLists.txt create mode 100644 components/esp_system/port/soc/esp32h2/apb_backup_dma.c create mode 100644 components/esp_system/port/soc/esp32h2/cache_err_int.c create mode 100644 components/esp_system/port/soc/esp32h2/cache_err_int.h create mode 100644 components/esp_system/port/soc/esp32h2/clk.c create mode 100644 components/esp_system/port/soc/esp32h2/reset_reason.c create mode 100644 components/esp_system/port/soc/esp32h2/system_internal.c diff --git a/components/esp_hw_support/include/soc/esp32h2/clk.h b/components/esp_hw_support/include/soc/esp32h2/clk.h new file mode 100644 index 0000000000..31902ebad0 --- /dev/null +++ b/components/esp_hw_support/include/soc/esp32h2/clk.h @@ -0,0 +1,16 @@ +// 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 "esp_private/esp_clk.h" diff --git a/components/esp_hw_support/port/esp32h2/CMakeLists.txt b/components/esp_hw_support/port/esp32h2/CMakeLists.txt new file mode 100644 index 0000000000..99b1f7929b --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/CMakeLists.txt @@ -0,0 +1,24 @@ +set(srcs "cpu_util_esp32c3.c" + "rtc_clk_init.c" + "rtc_clk.c" + "rtc_init.c" + "rtc_pm.c" + "rtc_sleep.c" + "rtc_time.c" + "chip_info.c" + ) + +if(NOT BOOTLOADER_BUILD) + list(APPEND srcs "../async_memcpy_impl_gdma.c") +endif() + +add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}") + +target_sources(${COMPONENT_LIB} PRIVATE "${srcs}") +target_include_directories(${COMPONENT_LIB} PUBLIC . private_include) +target_include_directories(${COMPONENT_LIB} PRIVATE ../hal) + +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() diff --git a/components/esp_hw_support/port/esp32h2/Kconfig.mac b/components/esp_hw_support/port/esp32h2/Kconfig.mac new file mode 100644 index 0000000000..ea53535782 --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/Kconfig.mac @@ -0,0 +1,43 @@ +choice ESP32C3_UNIVERSAL_MAC_ADDRESSES + bool "Number of universally administered (by IEEE) MAC address" + default ESP32C3_UNIVERSAL_MAC_ADDRESSES_FOUR + help + Configure the number of universally administered (by IEEE) MAC addresses. + + During initialization, MAC addresses for each network interface are generated or derived from a + single base MAC address. + + If the number of universal MAC addresses is four, all four interfaces (WiFi station, WiFi softap, + Bluetooth and Ethernet) receive a universally administered MAC address. These are generated + sequentially by adding 0, 1, 2 and 3 (respectively) to the final octet of the base MAC address. + + If the number of universal MAC addresses is two, only two interfaces (WiFi station and Bluetooth) + receive a universally administered MAC address. These are generated sequentially by adding 0 + and 1 (respectively) to the base MAC address. The remaining two interfaces (WiFi softap and Ethernet) + receive local MAC addresses. These are derived from the universal WiFi station and Bluetooth MAC + addresses, respectively. + + When using the default (Espressif-assigned) base MAC address, either setting can be used. When using + a custom universal MAC address range, the correct setting will depend on the allocation of MAC + addresses in this range (either 2 or 4 per device.) + + Note that ESP32-C3 has no integrated Ethernet MAC. Although it's possible to use the esp_read_mac() + API to return a MAC for Ethernet, this can only be used with an external MAC peripheral. + + config ESP32C3_UNIVERSAL_MAC_ADDRESSES_TWO + bool "Two" + select ESP_MAC_ADDR_UNIVERSE_WIFI_STA + select ESP_MAC_ADDR_UNIVERSE_BT + + config ESP32C3_UNIVERSAL_MAC_ADDRESSES_FOUR + bool "Four" + select ESP_MAC_ADDR_UNIVERSE_WIFI_STA + select ESP_MAC_ADDR_UNIVERSE_WIFI_AP + select ESP_MAC_ADDR_UNIVERSE_BT + select ESP_MAC_ADDR_UNIVERSE_ETH +endchoice + +config ESP32C3_UNIVERSAL_MAC_ADDRESSES + int + default 2 if ESP32C3_UNIVERSAL_MAC_ADDRESSES_TWO + default 4 if ESP32C3_UNIVERSAL_MAC_ADDRESSES_FOUR diff --git a/components/esp_hw_support/port/esp32h2/chip_info.c b/components/esp_hw_support/port/esp32h2/chip_info.c new file mode 100644 index 0000000000..ffd37a23c0 --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/chip_info.c @@ -0,0 +1,26 @@ +// Copyright 2013-2020 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 +#include "esp_chip_info.h" +#include "esp_efuse.h" + +void esp_chip_info(esp_chip_info_t *out_info) +{ + memset(out_info, 0, sizeof(*out_info)); + out_info->model = CHIP_ESP32C3; + out_info->revision = esp_efuse_get_chip_ver(); + out_info->cores = 1; + out_info->features = CHIP_FEATURE_WIFI_BGN | CHIP_FEATURE_BLE; +} diff --git a/components/esp_hw_support/port/esp32h2/cpu_util_esp32h2.c b/components/esp_hw_support/port/esp32h2/cpu_util_esp32h2.c new file mode 100644 index 0000000000..b070320bb2 --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/cpu_util_esp32h2.c @@ -0,0 +1,112 @@ +// Copyright 2020 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 +#include "soc/cpu.h" + +void esp_cpu_configure_region_protection(void) +{ + /* Notes on implementation: + * + * 1) Note: ESP32-C3 CPU doesn't support overlapping PMP regions + * + * 2) Therefore, we use TOR (top of range) entries to map the whole address + * space, bottom to top. + * + * 3) There are not enough entries to describe all the memory regions 100% accurately. + * + * 4) This means some gaps (invalid memory) are accessible. Priority for extending regions + * to cover gaps is to extend read-only or read-execute regions or read-only regions only + * (executing unmapped addresses should always fault with invalid instruction, read-only means + * stores will correctly fault even if reads may return some invalid value.) + * + * 5) Entries are grouped in order with some static asserts to try and verify everything is + * correct. + */ + const unsigned NONE = PMP_L | PMP_TOR; + const unsigned R = PMP_L | PMP_TOR | PMP_R; + const unsigned RW = PMP_L | PMP_TOR | PMP_R | PMP_W; + const unsigned RX = PMP_L | PMP_TOR | PMP_R | PMP_X; + const unsigned RWX = PMP_L | PMP_TOR | PMP_R | PMP_W | PMP_X; + + // 1. Gap at bottom of address space + PMP_ENTRY_SET(0, SOC_DEBUG_LOW, NONE); + + // 2. Debug region + PMP_ENTRY_SET(1, SOC_DEBUG_HIGH, RWX); + _Static_assert(SOC_DEBUG_LOW < SOC_DEBUG_HIGH, "Invalid CPU debug region"); + + // 3. Gap between debug region & DROM (flash cache) + PMP_ENTRY_SET(2, SOC_DROM_LOW, NONE); + _Static_assert(SOC_DEBUG_HIGH < SOC_DROM_LOW, "Invalid PMP entry order"); + + // 4. DROM (flash cache) + // 5. Gap between DROM & DRAM + // (Note: To save PMP entries these two are merged into one read-only region) + PMP_ENTRY_SET(3, SOC_DRAM_LOW, R); + _Static_assert(SOC_DROM_LOW < SOC_DROM_HIGH, "Invalid DROM region"); + _Static_assert(SOC_DROM_HIGH < SOC_DRAM_LOW, "Invalid PMP entry order"); + + // 6. DRAM + PMP_ENTRY_SET(4, SOC_DRAM_HIGH, RW); + _Static_assert(SOC_DRAM_LOW < SOC_DRAM_HIGH, "Invalid DRAM region"); + + // 7. Gap between DRAM and Mask DROM + // 8. Mask DROM + // (Note: to save PMP entries these two are merged into one read-only region) + PMP_ENTRY_SET(5, SOC_DROM_MASK_HIGH, R); + _Static_assert(SOC_DRAM_HIGH < SOC_DROM_MASK_LOW, "Invalid PMP entry order"); + _Static_assert(SOC_DROM_MASK_LOW < SOC_DROM_MASK_HIGH, "Invalid mask DROM region"); + + // 9. Gap between mask DROM and mask IROM + // 10. Mask IROM + // (Note: to save PMP entries these two are merged into one RX region) + PMP_ENTRY_SET(6, SOC_IROM_MASK_HIGH, RX); + _Static_assert(SOC_DROM_MASK_HIGH < SOC_IROM_MASK_LOW, "Invalid PMP entry order"); + _Static_assert(SOC_IROM_MASK_LOW < SOC_IROM_MASK_HIGH, "Invalid mask IROM region"); + + // 11. Gap between mask IROM & IRAM + PMP_ENTRY_SET(7, SOC_IRAM_LOW, NONE); + _Static_assert(SOC_IROM_MASK_HIGH < SOC_IRAM_LOW, "Invalid PMP entry order"); + + // 12. IRAM + PMP_ENTRY_SET(8, SOC_IRAM_HIGH, RWX); + _Static_assert(SOC_IRAM_LOW < SOC_IRAM_HIGH, "Invalid IRAM region"); + + // 13. Gap between IRAM and IROM + // 14. IROM (flash cache) + // (Note: to save PMP entries these two are merged into one RX region) + PMP_ENTRY_SET(9, SOC_IROM_HIGH, RX); + _Static_assert(SOC_IRAM_HIGH < SOC_IROM_LOW, "Invalid PMP entry order"); + _Static_assert(SOC_IROM_LOW < SOC_IROM_HIGH, "Invalid IROM region"); + + // 15. Gap between IROM & RTC slow memory + PMP_ENTRY_SET(10, SOC_RTC_IRAM_LOW, NONE); + _Static_assert(SOC_IROM_HIGH < SOC_RTC_IRAM_LOW, "Invalid PMP entry order"); + + // 16. RTC fast memory + PMP_ENTRY_SET(11, SOC_RTC_IRAM_HIGH, RWX); + _Static_assert(SOC_RTC_IRAM_LOW < SOC_RTC_IRAM_HIGH, "Invalid RTC IRAM region"); + + // 17. Gap between RTC fast memory & peripheral addresses + PMP_ENTRY_SET(12, SOC_PERIPHERAL_LOW, NONE); + _Static_assert(SOC_RTC_IRAM_HIGH < SOC_PERIPHERAL_LOW, "Invalid PMP entry order"); + + // 18. Peripheral addresses + PMP_ENTRY_SET(13, SOC_PERIPHERAL_HIGH, RW); + _Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region"); + + // 19. End of address space + PMP_ENTRY_SET(14, UINT32_MAX, NONE); // all but last 4 bytes + PMP_ENTRY_SET(15, UINT32_MAX, PMP_L | PMP_NA4); // last 4 bytes +} diff --git a/components/esp_hw_support/port/esp32h2/i2c_brownout.h b/components/esp_hw_support/port/esp32h2/i2c_brownout.h new file mode 100644 index 0000000000..5fac2c91b3 --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/i2c_brownout.h @@ -0,0 +1,30 @@ +// Copyright 2020 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 i2c_brownout.h + * @brief Register definitions for brownout detector + * + * This file lists register fields of the brownout detector, located on an internal configuration + * bus. These definitions are used via macros defined in i2c_rtc_clk.h. + */ + +#define I2C_BOD 0x61 +#define I2C_BOD_HOSTID 1 + +#define I2C_BOD_THRESHOLD 0x5 +#define I2C_BOD_THRESHOLD_MSB 2 +#define I2C_BOD_THRESHOLD_LSB 0 diff --git a/components/esp_hw_support/port/esp32h2/i2c_rtc_clk.h b/components/esp_hw_support/port/esp32h2/i2c_rtc_clk.h new file mode 100644 index 0000000000..0bbe0ee1a1 --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/i2c_rtc_clk.h @@ -0,0 +1,48 @@ +// Copyright 2020 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 +#include "regi2c_ctrl.h" + +/* 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 i2c_apll.h/i2c_bbpll.h header files. + */ +#define I2C_WRITEREG_MASK_RTC(block, reg_add, indata) \ + rom_i2c_writeReg_Mask(block, block##_HOSTID, reg_add, reg_add##_MSB, reg_add##_LSB, indata) + +#define I2C_READREG_MASK_RTC(block, reg_add) \ + rom_i2c_readReg_Mask(block, block##_HOSTID, reg_add, reg_add##_MSB, reg_add##_LSB) + +#define I2C_WRITEREG_RTC(block, reg_add, indata) \ + rom_i2c_writeReg(block, block##_HOSTID, reg_add, indata) + +#define I2C_READREG_RTC(block, reg_add) \ + rom_i2c_readReg(block, block##_HOSTID, reg_add) diff --git a/components/esp_hw_support/port/esp32h2/private_include/regi2c_bbpll.h b/components/esp_hw_support/port/esp32h2/private_include/regi2c_bbpll.h new file mode 100644 index 0000000000..842f702934 --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/private_include/regi2c_bbpll.h @@ -0,0 +1,183 @@ +// Copyright 2020 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_bbpll.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 0 + +#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_DCHGP 2 +#define I2C_BBPLL_OC_DCHGP_MSB 6 +#define I2C_BBPLL_OC_DCHGP_LSB 4 + +#define I2C_BBPLL_OC_ENB_FCAL 2 +#define I2C_BBPLL_OC_ENB_FCAL_MSB 7 +#define I2C_BBPLL_OC_ENB_FCAL_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_RSTB_DIV_ADC 4 +#define I2C_BBPLL_RSTB_DIV_ADC_MSB 0 +#define I2C_BBPLL_RSTB_DIV_ADC_LSB 0 + +#define I2C_BBPLL_MODE_HF 4 +#define I2C_BBPLL_MODE_HF_MSB 1 +#define I2C_BBPLL_MODE_HF_LSB 1 + +#define I2C_BBPLL_DIV_ADC 4 +#define I2C_BBPLL_DIV_ADC_MSB 3 +#define I2C_BBPLL_DIV_ADC_LSB 2 + +#define I2C_BBPLL_DIV_DAC 4 +#define I2C_BBPLL_DIV_DAC_MSB 4 +#define I2C_BBPLL_DIV_DAC_LSB 4 + +#define I2C_BBPLL_DIV_CPU 4 +#define I2C_BBPLL_DIV_CPU_MSB 5 +#define I2C_BBPLL_DIV_CPU_LSB 5 + +#define I2C_BBPLL_OC_ENB_VCON 4 +#define I2C_BBPLL_OC_ENB_VCON_MSB 6 +#define I2C_BBPLL_OC_ENB_VCON_LSB 6 + +#define I2C_BBPLL_OC_TSCHGP 4 +#define I2C_BBPLL_OC_TSCHGP_MSB 7 +#define I2C_BBPLL_OC_TSCHGP_LSB 7 + +#define I2C_BBPLL_OC_DR1 5 +#define I2C_BBPLL_OC_DR1_MSB 2 +#define I2C_BBPLL_OC_DR1_LSB 0 + +#define I2C_BBPLL_OC_DR3 5 +#define I2C_BBPLL_OC_DR3_MSB 6 +#define I2C_BBPLL_OC_DR3_LSB 4 + +#define I2C_BBPLL_EN_USB 5 +#define I2C_BBPLL_EN_USB_MSB 7 +#define I2C_BBPLL_EN_USB_LSB 7 + +#define I2C_BBPLL_OC_DCUR 6 +#define I2C_BBPLL_OC_DCUR_MSB 2 +#define I2C_BBPLL_OC_DCUR_LSB 0 + +#define I2C_BBPLL_INC_CUR 6 +#define I2C_BBPLL_INC_CUR_MSB 3 +#define I2C_BBPLL_INC_CUR_LSB 3 + +#define I2C_BBPLL_OC_DHREF_SEL 6 +#define I2C_BBPLL_OC_DHREF_SEL_MSB 5 +#define I2C_BBPLL_OC_DHREF_SEL_LSB 4 + +#define I2C_BBPLL_OC_DLREF_SEL 6 +#define I2C_BBPLL_OC_DLREF_SEL_MSB 7 +#define I2C_BBPLL_OC_DLREF_SEL_LSB 6 + +#define I2C_BBPLL_OR_CAL_CAP 8 +#define I2C_BBPLL_OR_CAL_CAP_MSB 3 +#define I2C_BBPLL_OR_CAL_CAP_LSB 0 + +#define I2C_BBPLL_OR_CAL_UDF 8 +#define I2C_BBPLL_OR_CAL_UDF_MSB 4 +#define I2C_BBPLL_OR_CAL_UDF_LSB 4 + +#define I2C_BBPLL_OR_CAL_OVF 8 +#define I2C_BBPLL_OR_CAL_OVF_MSB 5 +#define I2C_BBPLL_OR_CAL_OVF_LSB 5 + +#define I2C_BBPLL_OR_CAL_END 8 +#define I2C_BBPLL_OR_CAL_END_MSB 6 +#define I2C_BBPLL_OR_CAL_END_LSB 6 + +#define I2C_BBPLL_OR_LOCK 8 +#define I2C_BBPLL_OR_LOCK_MSB 7 +#define I2C_BBPLL_OR_LOCK_LSB 7 + +#define I2C_BBPLL_OC_VCO_DBIAS 9 +#define I2C_BBPLL_OC_VCO_DBIAS_MSB 1 +#define I2C_BBPLL_OC_VCO_DBIAS_LSB 0 + +#define I2C_BBPLL_BBADC_DELAY2 9 +#define I2C_BBPLL_BBADC_DELAY2_MSB 3 +#define I2C_BBPLL_BBADC_DELAY2_LSB 2 + +#define I2C_BBPLL_BBADC_DVDD 9 +#define I2C_BBPLL_BBADC_DVDD_MSB 5 +#define I2C_BBPLL_BBADC_DVDD_LSB 4 + +#define I2C_BBPLL_BBADC_DREF 9 +#define I2C_BBPLL_BBADC_DREF_MSB 7 +#define I2C_BBPLL_BBADC_DREF_LSB 6 + +#define I2C_BBPLL_BBADC_DCUR 10 +#define I2C_BBPLL_BBADC_DCUR_MSB 1 +#define I2C_BBPLL_BBADC_DCUR_LSB 0 + +#define I2C_BBPLL_BBADC_INPUT_SHORT 10 +#define I2C_BBPLL_BBADC_INPUT_SHORT_MSB 2 +#define I2C_BBPLL_BBADC_INPUT_SHORT_LSB 2 + +#define I2C_BBPLL_ENT_PLL 10 +#define I2C_BBPLL_ENT_PLL_MSB 3 +#define I2C_BBPLL_ENT_PLL_LSB 3 + +#define I2C_BBPLL_DTEST 10 +#define I2C_BBPLL_DTEST_MSB 5 +#define I2C_BBPLL_DTEST_LSB 4 + +#define I2C_BBPLL_ENT_ADC 10 +#define I2C_BBPLL_ENT_ADC_MSB 7 +#define I2C_BBPLL_ENT_ADC_LSB 6 diff --git a/components/esp_hw_support/port/esp32h2/private_include/regi2c_bias.h b/components/esp_hw_support/port/esp32h2/private_include/regi2c_bias.h new file mode 100644 index 0000000000..f459a344ba --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/private_include/regi2c_bias.h @@ -0,0 +1,30 @@ +// Copyright 2015-2020 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_bias.h + * @brief Register definitions for bias + * + * This file lists register fields of BIAS. These definitions are used via macros defined in regi2c_ctrl.h, by + * bootloader_hardware_init function in bootloader_esp32c3.c. + */ + +#define I2C_BIAS 0X6A +#define I2C_BIAS_HOSTID 0 + +#define I2C_BIAS_DREG_1P1_PVT 1 +#define I2C_BIAS_DREG_1P1_PVT_MSB 3 +#define I2C_BIAS_DREG_1P1_PVT_LSB 0 diff --git a/components/esp_hw_support/port/esp32h2/private_include/regi2c_brownout.h b/components/esp_hw_support/port/esp32h2/private_include/regi2c_brownout.h new file mode 100644 index 0000000000..d81751347c --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/private_include/regi2c_brownout.h @@ -0,0 +1,30 @@ +// Copyright 2020 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_brownout.h + * @brief Register definitions for brownout detector + * + * This file lists register fields of the brownout detector, located on an internal configuration + * bus. These definitions are used via macros defined in regi2c_ctrl.h. + */ + +#define I2C_BOD 0x61 +#define I2C_BOD_HOSTID 0 + +#define I2C_BOD_THRESHOLD 0x5 +#define I2C_BOD_THRESHOLD_MSB 2 +#define I2C_BOD_THRESHOLD_LSB 0 diff --git a/components/esp_hw_support/port/esp32h2/private_include/regi2c_dig_reg.h b/components/esp_hw_support/port/esp32h2/private_include/regi2c_dig_reg.h new file mode 100644 index 0000000000..2510f43ae5 --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/private_include/regi2c_dig_reg.h @@ -0,0 +1,68 @@ +// Copyright 2015-2020 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_dig_reg.h + * @brief Register definitions for digital to get rtc voltage & digital voltage + * by setting rtc_dbias_Wak & dig_dbias_wak or by analog self-calibration. + */ + +#define I2C_DIG_REG 0x6D +#define I2C_DIG_REG_HOSTID 0 + +#define I2C_DIG_REG_EXT_RTC_DREG 4 +#define I2C_DIG_REG_EXT_RTC_DREG_MSB 4 +#define I2C_DIG_REG_EXT_RTC_DREG_LSB 0 + +#define I2C_DIG_REG_ENX_RTC_DREG 4 +#define I2C_DIG_REG_ENX_RTC_DREG_MSB 7 +#define I2C_DIG_REG_ENX_RTC_DREG_LSB 7 + +#define I2C_DIG_REG_EXT_RTC_DREG_SLEEP 5 +#define I2C_DIG_REG_EXT_RTC_DREG_SLEEP_MSB 4 +#define I2C_DIG_REG_EXT_RTC_DREG_SLEEP_LSB 0 + +#define I2C_DIG_REG_ENX_RTC_DREG_SLEEP 5 +#define I2C_DIG_REG_ENX_RTC_DREG_SLEEP_MSB 7 +#define I2C_DIG_REG_ENX_RTC_DREG_SLEEP_LSB 7 + +#define I2C_DIG_REG_EXT_DIG_DREG 6 +#define I2C_DIG_REG_EXT_DIG_DREG_MSB 4 +#define I2C_DIG_REG_EXT_DIG_DREG_LSB 0 + +#define I2C_DIG_REG_ENX_DIG_DREG 6 +#define I2C_DIG_REG_ENX_DIG_DREG_MSB 7 +#define I2C_DIG_REG_ENX_DIG_DREG_LSB 7 + +#define I2C_DIG_REG_EXT_DIG_DREG_SLEEP 7 +#define I2C_DIG_REG_EXT_DIG_DREG_SLEEP_MSB 4 +#define I2C_DIG_REG_EXT_DIG_DREG_SLEEP_LSB 0 + +#define I2C_DIG_REG_ENX_DIG_DREG_SLEEP 7 +#define I2C_DIG_REG_ENX_DIG_DREG_SLEEP_MSB 7 +#define I2C_DIG_REG_ENX_DIG_DREG_SLEEP_LSB 7 + +#define I2C_DIG_REG_OR_EN_CONT_CAL 9 +#define I2C_DIG_REG_OR_EN_CONT_CAL_MSB 7 +#define I2C_DIG_REG_OR_EN_CONT_CAL_LSB 7 + +#define I2C_DIG_REG_XPD_RTC_REG 13 +#define I2C_DIG_REG_XPD_RTC_REG_MSB 2 +#define I2C_DIG_REG_XPD_RTC_REG_LSB 2 + +#define I2C_DIG_REG_XPD_DIG_REG 13 +#define I2C_DIG_REG_XPD_DIG_REG_MSB 3 +#define I2C_DIG_REG_XPD_DIG_REG_LSB 3 diff --git a/components/esp_hw_support/port/esp32h2/private_include/regi2c_lp_bias.h b/components/esp_hw_support/port/esp32h2/private_include/regi2c_lp_bias.h new file mode 100644 index 0000000000..0dae77107c --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/private_include/regi2c_lp_bias.h @@ -0,0 +1,63 @@ +// Copyright 2015-2020 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_lp_bias.h + * @brief Register definitions for analog to calibrate o_code for getting a more precise voltage. + * + * This file lists register fields of low power dbais, located on an internal configuration + * bus. These definitions are used via macros defined in regi2c_ctrl.h, by + * rtc_init function in rtc_init.c. + */ + +#define I2C_ULP 0x61 +#define I2C_ULP_HOSTID 0 + +#define I2C_ULP_IR_RESETB 0 +#define I2C_ULP_IR_RESETB_MSB 0 +#define I2C_ULP_IR_RESETB_LSB 0 + +#define I2C_ULP_IR_FORCE_XPD_CK 0 +#define I2C_ULP_IR_FORCE_XPD_CK_MSB 2 +#define I2C_ULP_IR_FORCE_XPD_CK_LSB 2 + +#define I2C_ULP_IR_FORCE_XPD_IPH 0 +#define I2C_ULP_IR_FORCE_XPD_IPH_MSB 4 +#define I2C_ULP_IR_FORCE_XPD_IPH_LSB 4 + +#define I2C_ULP_IR_DISABLE_WATCHDOG_CK 0 +#define I2C_ULP_IR_DISABLE_WATCHDOG_CK_MSB 6 +#define I2C_ULP_IR_DISABLE_WATCHDOG_CK_LSB 6 + +#define I2C_ULP_O_DONE_FLAG 3 +#define I2C_ULP_O_DONE_FLAG_MSB 0 +#define I2C_ULP_O_DONE_FLAG_LSB 0 + +#define I2C_ULP_BG_O_DONE_FLAG 3 +#define I2C_ULP_BG_O_DONE_FLAG_MSB 3 +#define I2C_ULP_BG_O_DONE_FLAG_LSB 3 + +#define I2C_ULP_OCODE 4 +#define I2C_ULP_OCODE_MSB 7 +#define I2C_ULP_OCODE_LSB 0 + +#define I2C_ULP_IR_FORCE_CODE 5 +#define I2C_ULP_IR_FORCE_CODE_MSB 6 +#define I2C_ULP_IR_FORCE_CODE_LSB 6 + +#define I2C_ULP_EXT_CODE 6 +#define I2C_ULP_EXT_CODE_MSB 7 +#define I2C_ULP_EXT_CODE_LSB 0 diff --git a/components/esp_hw_support/port/esp32h2/private_include/regi2c_saradc.h b/components/esp_hw_support/port/esp32h2/private_include/regi2c_saradc.h new file mode 100644 index 0000000000..e9def9583d --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/private_include/regi2c_saradc.h @@ -0,0 +1,87 @@ +// Copyright 2019-2020 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_saradc.h + * @brief Register definitions for analog to calibrate initial code for getting a more precise voltage of SAR ADC. + * + * This file lists register fields of SAR, located on an internal configuration + * bus. These definitions are used via macros defined in regi2c_ctrl.h, by + * function in adc_ll.h. + */ + +#define I2C_SAR_ADC 0X69 +#define I2C_SAR_ADC_HOSTID 0 + +#define ADC_SAR1_ENCAL_GND_ADDR 0x7 +#define ADC_SAR1_ENCAL_GND_ADDR_MSB 5 +#define ADC_SAR1_ENCAL_GND_ADDR_LSB 5 + +#define ADC_SAR2_ENCAL_GND_ADDR 0x7 +#define ADC_SAR2_ENCAL_GND_ADDR_MSB 7 +#define ADC_SAR2_ENCAL_GND_ADDR_LSB 7 + +#define ADC_SAR1_INITIAL_CODE_HIGH_ADDR 0x1 +#define ADC_SAR1_INITIAL_CODE_HIGH_ADDR_MSB 0x3 +#define ADC_SAR1_INITIAL_CODE_HIGH_ADDR_LSB 0x0 + +#define ADC_SAR1_INITIAL_CODE_LOW_ADDR 0x0 +#define ADC_SAR1_INITIAL_CODE_LOW_ADDR_MSB 0x7 +#define ADC_SAR1_INITIAL_CODE_LOW_ADDR_LSB 0x0 + +#define ADC_SAR2_INITIAL_CODE_HIGH_ADDR 0x4 +#define ADC_SAR2_INITIAL_CODE_HIGH_ADDR_MSB 0x3 +#define ADC_SAR2_INITIAL_CODE_HIGH_ADDR_LSB 0x0 + +#define ADC_SAR2_INITIAL_CODE_LOW_ADDR 0x3 +#define ADC_SAR2_INITIAL_CODE_LOW_ADDR_MSB 0x7 +#define ADC_SAR2_INITIAL_CODE_LOW_ADDR_LSB 0x0 + +#define ADC_SAR1_DREF_ADDR 0x2 +#define ADC_SAR1_DREF_ADDR_MSB 0x6 +#define ADC_SAR1_DREF_ADDR_LSB 0x4 + +#define ADC_SAR2_DREF_ADDR 0x5 +#define ADC_SAR2_DREF_ADDR_MSB 0x6 +#define ADC_SAR2_DREF_ADDR_LSB 0x4 + +#define ADC_SAR1_SAMPLE_CYCLE_ADDR 0x2 +#define ADC_SAR1_SAMPLE_CYCLE_ADDR_MSB 0x2 +#define ADC_SAR1_SAMPLE_CYCLE_ADDR_LSB 0x0 + +#define ADC_SARADC_DTEST_RTC_ADDR 0x7 +#define ADC_SARADC_DTEST_RTC_ADDR_MSB 1 +#define ADC_SARADC_DTEST_RTC_ADDR_LSB 0 + +#define ADC_SARADC_ENT_TSENS_ADDR 0x7 +#define ADC_SARADC_ENT_TSENS_ADDR_MSB 2 +#define ADC_SARADC_ENT_TSENS_ADDR_LSB 2 + +#define ADC_SARADC_ENT_RTC_ADDR 0x7 +#define ADC_SARADC_ENT_RTC_ADDR_MSB 3 +#define ADC_SARADC_ENT_RTC_ADDR_LSB 3 + +#define ADC_SARADC1_ENCAL_REF_ADDR 0x7 +#define ADC_SARADC1_ENCAL_REF_ADDR_MSB 4 +#define ADC_SARADC1_ENCAL_REF_ADDR_LSB 4 + +#define ADC_SARADC2_ENCAL_REF_ADDR 0x7 +#define ADC_SARADC2_ENCAL_REF_ADDR_MSB 6 +#define ADC_SARADC2_ENCAL_REF_ADDR_LSB 6 + +#define I2C_SARADC_TSENS_DAC 0x6 +#define I2C_SARADC_TSENS_DAC_MSB 3 +#define I2C_SARADC_TSENS_DAC_LSB 0 diff --git a/components/esp_hw_support/port/esp32h2/regi2c_ctrl.h b/components/esp_hw_support/port/esp32h2/regi2c_ctrl.h new file mode 100644 index 0000000000..95f2626656 --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/regi2c_ctrl.h @@ -0,0 +1,109 @@ +// Copyright 2020 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. + +// Copyright 2015-2020 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 +#include "regi2c_bbpll.h" +#include "regi2c_lp_bias.h" +#include "regi2c_dig_reg.h" +#include "regi2c_bias.h" +#include "regi2c_saradc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Analog function control register */ +#define I2C_MST_ANA_CONF0_REG 0x6000E040 +#define I2C_MST_BBPLL_STOP_FORCE_HIGH (BIT(2)) +#define I2C_MST_BBPLL_STOP_FORCE_LOW (BIT(3)) + +#define ANA_CONFIG_REG 0x6000E044 +#define ANA_CONFIG_S (8) +#define ANA_CONFIG_M (0x3FF) + +#define ANA_I2C_SAR_FORCE_PD BIT(18) +#define ANA_I2C_BBPLL_M BIT(17) /* Clear to enable BBPLL */ +#define ANA_I2C_APLL_M BIT(14) /* Clear to enable APLL */ + + +#define ANA_CONFIG2_REG 0x6000E048 +#define ANA_CONFIG2_M BIT(18) + +#define ANA_I2C_SAR_FORCE_PU BIT(16) + +/* 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); + +#ifdef BOOTLOADER_BUILD + +/** + * If compiling for the bootloader, ROM functions can be called directly, + * without the need of a lock. + */ +#define regi2c_ctrl_read_reg rom_i2c_readReg +#define regi2c_ctrl_read_reg_mask rom_i2c_readReg_Mask +#define regi2c_ctrl_write_reg rom_i2c_writeReg +#define regi2c_ctrl_write_reg_mask rom_i2c_writeReg_Mask + +#else + +#define i2c_read_reg_raw rom_i2c_readReg +#define i2c_read_reg_mask_raw rom_i2c_readReg_Mask +#define i2c_write_reg_raw rom_i2c_writeReg +#define i2c_write_reg_mask_raw rom_i2c_writeReg_Mask + +uint8_t regi2c_ctrl_read_reg(uint8_t block, uint8_t host_id, uint8_t reg_add); +uint8_t regi2c_ctrl_read_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb); +void regi2c_ctrl_write_reg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data); +void regi2c_ctrl_write_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb, uint8_t data); + +#endif // BOOTLOADER_BUILD + +/* Convenience macros for the above functions, these use register definitions + * from regi2c_bbpll.h/regi2c_dig_reg.h/regi2c_lp_bias.h/regi2c_bias.h header files. + */ +#define REGI2C_WRITE_MASK(block, reg_add, indata) \ + regi2c_ctrl_write_reg_mask(block, block##_HOSTID, reg_add, reg_add##_MSB, reg_add##_LSB, indata) + +#define REGI2C_READ_MASK(block, reg_add) \ + regi2c_ctrl_read_reg_mask(block, block##_HOSTID, reg_add, reg_add##_MSB, reg_add##_LSB) + +#define REGI2C_WRITE(block, reg_add, indata) \ + regi2c_ctrl_write_reg(block, block##_HOSTID, reg_add, indata) + +#define REGI2C_READ(block, reg_add) \ + regi2c_ctrl_read_reg(block, block##_HOSTID, reg_add) + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/port/esp32h2/rtc_clk.c b/components/esp_hw_support/port/esp32h2/rtc_clk.c new file mode 100644 index 0000000000..f47848a523 --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/rtc_clk.c @@ -0,0 +1,515 @@ +// Copyright 2020 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 +#include +#include +#include +#include +#include "sdkconfig.h" +#include "esp32c3/rom/ets_sys.h" +#include "esp32c3/rom/rtc.h" +#include "esp32c3/rom/uart.h" +#include "esp32c3/rom/gpio.h" +#include "soc/rtc.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/efuse_reg.h" +#include "soc/syscon_reg.h" +#include "soc/system_reg.h" +#include "regi2c_ctrl.h" +#include "soc_log.h" +#include "rtc_clk_common.h" +#include "esp_rom_sys.h" + +static const char *TAG = "rtc_clk"; + +#define RTC_PLL_FREQ_320M 320 +#define RTC_PLL_FREQ_480M 480 +#define DELAY_RTC_CLK_SWITCH 5 + +// Current PLL frequency, in MHZ (320 or 480). Zero if PLL is not enabled. +static int s_cur_pll_freq; + +static void rtc_clk_cpu_freq_to_8m(void); + +void rtc_clk_32k_enable_internal(x32k_config_t cfg) +{ + REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DAC_XTAL_32K, cfg.dac); + REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DRES_XTAL_32K, cfg.dres); + REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DGM_XTAL_32K, cfg.dgm); + REG_SET_FIELD(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_DBUF_XTAL_32K, cfg.dbuf); + SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K); +} + +void rtc_clk_32k_enable(bool enable) +{ + if (enable) { + x32k_config_t cfg = X32K_CONFIG_DEFAULT(); + rtc_clk_32k_enable_internal(cfg); + } else { + SET_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XTAL32K_XPD_FORCE); + CLEAR_PERI_REG_MASK(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K); + } +} + +void rtc_clk_32k_enable_external(void) +{ + /* TODO ESP32-C3 IDF-2408: external 32k source may need different settings */ + x32k_config_t cfg = X32K_CONFIG_DEFAULT(); + rtc_clk_32k_enable_internal(cfg); +} + +void rtc_clk_32k_bootstrap(uint32_t cycle) +{ + /* No special bootstrapping needed for ESP32-C3, 'cycle' argument is to keep the signature + * same as for the ESP32. Just enable the XTAL here. + */ + (void) cycle; + rtc_clk_32k_enable(true); +} + +bool rtc_clk_32k_enabled(void) +{ + uint32_t xtal_conf = READ_PERI_REG(RTC_CNTL_EXT_XTL_CONF_REG); + /* If xtal xpd is controlled by software */ + bool xtal_xpd_sw = (xtal_conf & RTC_CNTL_XTAL32K_XPD_FORCE) >> RTC_CNTL_XTAL32K_XPD_FORCE_S; + /* If xtal xpd software control is on */ + bool xtal_xpd_st = (xtal_conf & RTC_CNTL_XPD_XTAL_32K) >> RTC_CNTL_XPD_XTAL_32K_S; + bool disabled = xtal_xpd_sw && !xtal_xpd_st; + return !disabled; +} + +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, RTC_CK8M_ENABLE_WAIT_DEFAULT); + 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); + } + /* d256 should be independent configured with 8M + * Maybe we can split this function into 8m and dmd256 + */ + 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); + } +} + +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_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); + + /* Why we need to connect this clock to digital? + * Or maybe this clock should be connected to digital when xtal 32k clock is enabled instead? + */ + REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_XTAL32K_EN, + (slow_freq == RTC_SLOW_FREQ_32K_XTAL) ? 1 : 0); + + /* The clk_8m_d256 will be closed when rtc_state in SLEEP, + so if the slow_clk is 8md256, clk_8m must be force power on + */ + REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PU, (slow_freq == RTC_SLOW_FREQ_8MD256) ? 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); +} + +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; +} + +static void rtc_clk_bbpll_enable(void) +{ + CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD | + RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD); +} + +void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq) +{ + uint8_t div_ref; + uint8_t div7_0; + uint8_t dr1; + uint8_t dr3; + uint8_t dchgp; + uint8_t dcur; + uint8_t dbias; + + CLEAR_PERI_REG_MASK(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_HIGH); + SET_PERI_REG_MASK(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_LOW); + if (pll_freq == RTC_PLL_FREQ_480M) { + /* Set this register to let the digital part know 480M PLL is used */ + SET_PERI_REG_MASK(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL); + /* Configure 480M PLL */ + switch (xtal_freq) { + case RTC_XTAL_FREQ_40M: + div_ref = 0; + div7_0 = 8; + dr1 = 0; + dr3 = 0; + dchgp = 5; + dcur = 3; + dbias = 2; + break; + case RTC_XTAL_FREQ_32M: + div_ref = 1; + div7_0 = 26; + dr1 = 1; + dr3 = 1; + dchgp = 4; + dcur = 0; + dbias = 2; + break; + default: + div_ref = 0; + div7_0 = 8; + dr1 = 0; + dr3 = 0; + dchgp = 5; + dcur = 3; + dbias = 2; + break; + } + REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x6B); + } else { + /* Clear this register to let the digital part know 320M PLL is used */ + CLEAR_PERI_REG_MASK(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL); + /* Configure 320M PLL */ + switch (xtal_freq) { + case RTC_XTAL_FREQ_40M: + div_ref = 0; + div7_0 = 4; + dr1 = 0; + dr3 = 0; + dchgp = 5; + dcur = 3; + dbias = 2; + break; + case RTC_XTAL_FREQ_32M: + div_ref = 1; + div7_0 = 6; + dr1 = 0; + dr3 = 0; + dchgp = 5; + dcur = 3; + dbias = 2; + break; + default: + div_ref = 0; + div7_0 = 4; + dr1 = 0; + dr3 = 0; + dchgp = 5; + dcur = 3; + dbias = 2; + break; + } + REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_MODE_HF, 0x69); + } + uint8_t i2c_bbpll_lref = (dchgp << I2C_BBPLL_OC_DCHGP_LSB) | (div_ref); + uint8_t i2c_bbpll_div_7_0 = div7_0; + uint8_t i2c_bbpll_dcur = (2 << I2C_BBPLL_OC_DLREF_SEL_LSB ) | (1 << I2C_BBPLL_OC_DHREF_SEL_LSB) | dcur; + REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_REF_DIV, i2c_bbpll_lref); + REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DIV_7_0, i2c_bbpll_div_7_0); + REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR1, dr1); + REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DR3, dr3); + REGI2C_WRITE(I2C_BBPLL, I2C_BBPLL_OC_DCUR, i2c_bbpll_dcur); + REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_VCO_DBIAS, dbias); + REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DHREF_SEL, 2); + REGI2C_WRITE_MASK(I2C_BBPLL, I2C_BBPLL_OC_DLREF_SEL, 1); + + s_cur_pll_freq = pll_freq; +} + +/** + * 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 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 { + SOC_LOGE(TAG, "invalid frequency"); + abort(); + } + REG_SET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL, per_conf); + REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0); + REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_PLL); + rtc_clk_apb_freq_update(80 * MHZ); + ets_update_cpu_frequency(cpu_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_480M; + divider = 6; + } else if (freq_mhz == 160) { + real_freq_mhz = freq_mhz; + source = RTC_CPU_FREQ_SRC_PLL; + source_freq_mhz = RTC_PLL_FREQ_480M; + divider = 3; + } 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) +{ + uint32_t soc_clk_sel = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL); + if (config->source == RTC_CPU_FREQ_SRC_XTAL) { + rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div); + if (soc_clk_sel == DPORT_SOC_CLK_SEL_PLL) { + rtc_clk_bbpll_disable(); + } + } else if (config->source == RTC_CPU_FREQ_SRC_PLL) { + if (soc_clk_sel != DPORT_SOC_CLK_SEL_PLL) { + rtc_clk_bbpll_enable(); + 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(); + if (soc_clk_sel == DPORT_SOC_CLK_SEL_PLL) { + rtc_clk_bbpll_disable(); + } + } +} + +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(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL); + switch (soc_clk_sel) { + case DPORT_SOC_CLK_SEL_XTAL: { + source = RTC_CPU_FREQ_SRC_XTAL; + div = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT) + 1; + source_freq_mhz = (uint32_t) rtc_clk_xtal_freq_get(); + freq_mhz = source_freq_mhz / div; + } + break; + case DPORT_SOC_CLK_SEL_PLL: { + source = RTC_CPU_FREQ_SRC_PLL; + uint32_t cpuperiod_sel = REG_GET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPUPERIOD_SEL); + uint32_t pllfreq_sel = REG_GET_FIELD(SYSTEM_CPU_PER_CONF_REG, SYSTEM_PLL_FREQ_SEL); + source_freq_mhz = (pllfreq_sel) ? RTC_PLL_FREQ_480M : RTC_PLL_FREQ_320M; + if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_80) { + div = (source_freq_mhz == RTC_PLL_FREQ_480M) ? 6 : 4; + freq_mhz = 80; + } else if (cpuperiod_sel == DPORT_CPUPERIOD_SEL_160) { + div = (source_freq_mhz == RTC_PLL_FREQ_480M) ? 3 : 2; + div = 3; + freq_mhz = 160; + } else { + SOC_LOGE(TAG, "unsupported frequency configuration"); + abort(); + } + break; + } + case DPORT_SOC_CLK_SEL_8M: + source = RTC_CPU_FREQ_SRC_8M; + source_freq_mhz = 8; + div = 1; + freq_mhz = source_freq_mhz; + break; + 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); + } +} + +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_bbpll_disable(); +} + +/** + * 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. Need to set divider to 1 (reg. value 0) first. */ + REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0); + REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, div - 1); + /* no need to adjust the REF_TICK */ + /* switch clock source */ + REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_XTAL); + rtc_clk_apb_freq_update(freq * MHZ); +} + +static void rtc_clk_cpu_freq_to_8m(void) +{ + ets_update_cpu_frequency(8); + REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT, 0); + REG_SET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_SOC_CLK_SEL, DPORT_SOC_CLK_SEL_8M); + rtc_clk_apb_freq_update(RTC_FAST_CLK_FREQ_8M); +} + +rtc_xtal_freq_t rtc_clk_xtal_freq_get(void) +{ + uint32_t xtal_freq_reg = READ_PERI_REG(RTC_XTAL_FREQ_REG); + if (!clk_val_is_valid(xtal_freq_reg)) { + SOC_LOGW(TAG, "invalid RTC_XTAL_FREQ_REG value: 0x%08x", xtal_freq_reg); + return RTC_XTAL_FREQ_40M; + } + return reg_val_to_clk_val(xtal_freq_reg); +} + +void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq) +{ + 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; +} + +void rtc_clk_divider_set(uint32_t div) +{ + CLEAR_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD); + REG_SET_FIELD(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV, div); + SET_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_ANA_CLK_DIV_VLD); +} + +void rtc_clk_8m_divider_set(uint32_t div) +{ + CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD); + REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, div); + SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD); +} + +void rtc_dig_clk8m_enable(void) +{ + SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M); + esp_rom_delay_us(DELAY_RTC_CLK_SWITCH); +} + +void rtc_dig_clk8m_disable(void) +{ + CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M); + esp_rom_delay_us(DELAY_RTC_CLK_SWITCH); +} + +/* 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"))); diff --git a/components/esp_hw_support/port/esp32h2/rtc_clk_common.h b/components/esp_hw_support/port/esp32h2/rtc_clk_common.h new file mode 100644 index 0000000000..c3e8a86e09 --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/rtc_clk_common.h @@ -0,0 +1,57 @@ +// Copyright 2020 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 + +#define MHZ (1000000) + +#define DPORT_CPUPERIOD_SEL_80 0 +#define DPORT_CPUPERIOD_SEL_160 1 + +#define DPORT_SOC_CLK_SEL_XTAL 0 +#define DPORT_SOC_CLK_SEL_PLL 1 +#define DPORT_SOC_CLK_SEL_8M 2 + +#define RTC_FAST_CLK_FREQ_8M 8500000 + +#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 diff --git a/components/esp_hw_support/port/esp32h2/rtc_clk_init.c b/components/esp_hw_support/port/esp32h2/rtc_clk_init.c new file mode 100644 index 0000000000..ca9dd74cba --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/rtc_clk_init.c @@ -0,0 +1,88 @@ +// Copyright 2020 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 +#include +#include +#include +#include "esp32c3/rom/ets_sys.h" +#include "esp32c3/rom/rtc.h" +#include "esp32c3/rom/uart.h" +#include "soc/rtc.h" +#include "soc/rtc_periph.h" +#include "soc/efuse_periph.h" +#include "soc/apb_ctrl_reg.h" +#include "hal/cpu_hal.h" +#include "regi2c_ctrl.h" +#include "soc_log.h" +#include "sdkconfig.h" +#include "rtc_clk_common.h" +#include "esp_rom_uart.h" + +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; + + /* 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 150k clock division */ + rtc_clk_divider_set(cfg.clk_rtc_clk_div); + + /* Configure 8M clock division */ + rtc_clk_8m_divider_set(cfg.clk_8m_clk_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, ANA_I2C_APLL_M | ANA_I2C_BBPLL_M); + + rtc_xtal_freq_t xtal_freq = cfg.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); + + /* Re-calculate the ccount to make time calculation correct. */ + cpu_hal_set_cycle_count( (uint64_t)cpu_hal_get_cycle_count() * 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); +} diff --git a/components/esp_hw_support/port/esp32h2/rtc_init.c b/components/esp_hw_support/port/esp32h2/rtc_init.c new file mode 100644 index 0000000000..7a33720bea --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/rtc_init.c @@ -0,0 +1,339 @@ +// Copyright 2020 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 +#include "sdkconfig.h" +#include "soc/soc.h" +#include "soc/rtc.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/efuse_periph.h" +#include "soc/gpio_reg.h" +#include "soc/spi_mem_reg.h" +#include "soc/extmem_reg.h" +#include "soc/system_reg.h" +#include "regi2c_ctrl.h" +#include "soc_log.h" +#include "esp_efuse.h" +#include "esp_efuse_table.h" + +static const char *TAG = "rtc_init"; + +static void set_ocode_by_efuse(int calib_version); +static void calibrate_ocode(void); +static void set_rtc_dig_dbias(void); + +void rtc_init(rtc_config_t cfg) +{ + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_XPD_DIG_REG, 0); + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_XPD_RTC_REG, 0); + + CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PVTMON_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_CK8M_WAIT, cfg.ck8m_wait); + REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_MIN_SLP_VAL, RTC_CNTL_MIN_SLP_VAL_MIN); + + // set default powerup & wait time + rtc_init_config_t rtc_init_cfg = RTC_INIT_CONFIG_DEFAULT(); + REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_WIFI_POWERUP_TIMER, rtc_init_cfg.wifi_powerup_cycles); + REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_WIFI_WAIT_TIMER, rtc_init_cfg.wifi_wait_cycles); + REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_BT_POWERUP_TIMER, rtc_init_cfg.bt_powerup_cycles); + REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_BT_WAIT_TIMER, rtc_init_cfg.bt_wait_cycles); + REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_CPU_TOP_POWERUP_TIMER, rtc_init_cfg.cpu_top_powerup_cycles); + REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_CPU_TOP_WAIT_TIMER, rtc_init_cfg.cpu_top_wait_cycles); + REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_DG_WRAP_POWERUP_TIMER, rtc_init_cfg.dg_wrap_powerup_cycles); + REG_SET_FIELD(RTC_CNTL_TIMER4_REG, RTC_CNTL_DG_WRAP_WAIT_TIMER, rtc_init_cfg.dg_wrap_wait_cycles); + REG_SET_FIELD(RTC_CNTL_TIMER6_REG, RTC_CNTL_DG_PERI_POWERUP_TIMER, rtc_init_cfg.dg_peri_powerup_cycles); + REG_SET_FIELD(RTC_CNTL_TIMER6_REG, RTC_CNTL_DG_PERI_WAIT_TIMER, rtc_init_cfg.dg_peri_wait_cycles); + + if (cfg.cali_ocode) { + uint32_t rtc_calib_version = 0; + esp_err_t err = esp_efuse_read_field_blob(ESP_EFUSE_BLOCK2_VERSION, &rtc_calib_version, 3); + if (err != ESP_OK) { + rtc_calib_version = 0; + SOC_LOGW(TAG, "efuse read fail, set default rtc_calib_version: %d\n", rtc_calib_version); + } + if (rtc_calib_version == 1) { + set_ocode_by_efuse(rtc_calib_version); + } else { + calibrate_ocode(); + } + } + + set_rtc_dig_dbias(); + + if (cfg.clkctl_init) { + //clear CMMU clock force on + CLEAR_PERI_REG_MASK(EXTMEM_CACHE_MMU_POWER_CTRL_REG, EXTMEM_CACHE_MMU_MEM_FORCE_ON); + //clear tag clock force on + CLEAR_PERI_REG_MASK(EXTMEM_ICACHE_TAG_POWER_CTRL_REG, EXTMEM_ICACHE_TAG_MEM_FORCE_ON); + //clear register clock force on + CLEAR_PERI_REG_MASK(SPI_MEM_CLOCK_GATE_REG(0), SPI_MEM_CLK_EN); + CLEAR_PERI_REG_MASK(SPI_MEM_CLOCK_GATE_REG(1), SPI_MEM_CLK_EN); + } + + if (cfg.pwrctl_init) { + CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PU); + //cancel xtal force pu if no need to force power up + //cannot cancel xtal force pu if pll is force power on + if (!(cfg.xtal_fpu | cfg.bbpll_fpu)) { + CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_XTL_FORCE_PU); + } else { + SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_XTL_FORCE_PU); + } + // force pd APLL + 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); + + //open sar_i2c protect function to avoid sar_i2c reset when rtc_ldo is low. + CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_I2C_RESET_POR_FORCE_PD); + + //cancel bbpll force pu if setting no force power up + if (!cfg.bbpll_fpu) { + 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); + CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PU); + } else { + SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BBPLL_FORCE_PU); + SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BBPLL_I2C_FORCE_PU); + SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PU); + } + + CLEAR_PERI_REG_MASK(RTC_CNTL_REG, RTC_CNTL_REGULATOR_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); + } + + //clear i2c_reset_protect pd force, need tested in low temperature. + //CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG,RTC_CNTL_I2C_RESET_POR_FORCE_PD); + + /* If this mask is enabled, all soc memories cannot enter power down mode */ + /* We should control soc memory power down mode from RTC, so we will not touch this register any more */ + CLEAR_PERI_REG_MASK(SYSTEM_MEM_PD_MASK_REG, SYSTEM_LSLP_MEM_PD_MASK); + + /* If this pd_cfg is set to 1, all memory won't enter low power mode during light sleep */ + /* If this pd_cfg is set to 0, all memory will enter low power mode during light sleep */ + rtc_sleep_pu_config_t pu_cfg = RTC_SLEEP_PU_CONFIG_ALL(0); + rtc_sleep_pu(pu_cfg); + + 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_BT_FORCE_PU); + CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_CPU_TOP_FORCE_PU); + CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_DG_PERI_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_BT_FORCE_NOISO); + CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_CPU_TOP_FORCE_NOISO); + CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PERI_FORCE_NOISO); + //cancel digital PADS force no iso + if (cfg.cpu_waiti_clk_gate) { + CLEAR_PERI_REG_MASK(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPU_WAIT_MODE_FORCE_ON); + } else { + SET_PERI_REG_MASK(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPU_WAIT_MODE_FORCE_ON); + } + /*if SYSTEM_CPU_WAIT_MODE_FORCE_ON == 0 , the cpu clk will be closed when cpu enter WAITI mode*/ + 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); + } + REG_WRITE(RTC_CNTL_INT_ENA_REG, 0); + REG_WRITE(RTC_CNTL_INT_CLR_REG, UINT32_MAX); +} + +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; + } else { + result.force = 0; + } + + // 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); +} + +static void set_ocode_by_efuse(int calib_version) +{ + assert(calib_version == 1); + // use efuse ocode. + uint32_t ocode; + esp_err_t err = esp_efuse_read_field_blob(ESP_EFUSE_OCODE, &ocode, 8); + assert(err == ESP_OK); + (void) err; + REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_EXT_CODE, ocode); + REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_FORCE_CODE, 1); +} + +static void calibrate_ocode(void) +{ + /* + Bandgap output voltage is not precise when calibrate o-code by hardware sometimes, so need software o-code calibration (must turn off PLL). + Method: + 1. read current cpu config, save in old_config; + 2. switch cpu to xtal because PLL will be closed when o-code calibration; + 3. begin o-code calibration; + 4. wait o-code calibration done flag(odone_flag & bg_odone_flag) or timeout; + 5. set cpu to old-config. + */ + rtc_slow_freq_t slow_clk_freq = rtc_clk_slow_freq_get(); + rtc_slow_freq_t rtc_slow_freq_x32k = RTC_SLOW_FREQ_32K_XTAL; + rtc_slow_freq_t rtc_slow_freq_8MD256 = RTC_SLOW_FREQ_8MD256; + rtc_cal_sel_t cal_clk = RTC_CAL_RTC_MUX; + if (slow_clk_freq == (rtc_slow_freq_x32k)) { + cal_clk = RTC_CAL_32K_XTAL; + } else if (slow_clk_freq == rtc_slow_freq_8MD256) { + cal_clk = RTC_CAL_8MD256; + } + + uint64_t max_delay_time_us = 10000; + uint32_t slow_clk_period = rtc_clk_cal(cal_clk, 100); + uint64_t max_delay_cycle = rtc_time_us_to_slowclk(max_delay_time_us, slow_clk_period); + uint64_t cycle0 = rtc_time_get(); + uint64_t timeout_cycle = cycle0 + max_delay_cycle; + uint64_t cycle1 = 0; + + rtc_cpu_freq_config_t old_config; + rtc_clk_cpu_freq_get_config(&old_config); + rtc_clk_cpu_freq_set_xtal(); + + REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 0); + REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 1); + bool odone_flag = 0; + bool bg_odone_flag = 0; + while (1) { + odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_O_DONE_FLAG); + bg_odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_BG_O_DONE_FLAG); + cycle1 = rtc_time_get(); + if (odone_flag && bg_odone_flag) { + break; + } + if (cycle1 >= timeout_cycle) { + SOC_LOGW(TAG, "o_code calibration fail\n"); + break; + } + } + rtc_clk_cpu_freq_set_config(&old_config); +} + +static uint32_t get_dig_dbias_by_efuse(uint8_t chip_version) +{ + assert(chip_version >= 3); + uint32_t dig_dbias = 28; + esp_err_t err = esp_efuse_read_field_blob(ESP_EFUSE_DIG_DBIAS_HVT, &dig_dbias, 5); + if (err != ESP_OK) { + dig_dbias = 28; + SOC_LOGW(TAG, "efuse read fail, set default dig_dbias value: %d\n", dig_dbias); + } + return dig_dbias; +} + +uint32_t get_rtc_dbias_by_efuse(uint8_t chip_version, uint32_t dig_dbias) +{ + assert(chip_version >= 3); + uint32_t rtc_dbias = 0; + signed int k_rtc_ldo = 0, k_dig_ldo = 0, v_rtc_bias20 = 0, v_dig_bias20 = 0; + esp_err_t err0 = esp_efuse_read_field_blob(ESP_EFUSE_K_RTC_LDO, &k_rtc_ldo, 7); + esp_err_t err1 = esp_efuse_read_field_blob(ESP_EFUSE_K_DIG_LDO, &k_dig_ldo, 7); + esp_err_t err2 = esp_efuse_read_field_blob(ESP_EFUSE_V_RTC_DBIAS20, &v_rtc_bias20, 8); + esp_err_t err3 = esp_efuse_read_field_blob(ESP_EFUSE_V_DIG_DBIAS20, &v_dig_bias20, 8); + if ((err0 != ESP_OK) | (err1 != ESP_OK) | (err2 != ESP_OK) | (err3 != ESP_OK)) { + k_rtc_ldo = 0; + k_dig_ldo = 0; + v_rtc_bias20 = 0; + v_dig_bias20 = 0; + SOC_LOGW(TAG, "efuse read fail, k_rtc_ldo: %d, k_dig_ldo: %d, v_rtc_bias20: %d, v_dig_bias20: %d\n", k_rtc_ldo, k_dig_ldo, v_rtc_bias20, v_dig_bias20); + } + + k_rtc_ldo = ((k_rtc_ldo & BIT(6)) != 0)? -(k_rtc_ldo & 0x3f): k_rtc_ldo; + k_dig_ldo = ((k_dig_ldo & BIT(6)) != 0)? -(k_dig_ldo & 0x3f): (uint8_t)k_dig_ldo; + v_rtc_bias20 = ((v_rtc_bias20 & BIT(7)) != 0)? -(v_rtc_bias20 & 0x7f): (uint8_t)v_rtc_bias20; + v_dig_bias20 = ((v_dig_bias20 & BIT(7)) != 0)? -(v_dig_bias20 & 0x7f): (uint8_t)v_dig_bias20; + + uint32_t v_rtc_dbias20_real_mul10000 = V_RTC_MID_MUL10000 + v_rtc_bias20 * 10000 / 500; + uint32_t v_dig_dbias20_real_mul10000 = V_DIG_MID_MUL10000 + v_dig_bias20 * 10000 / 500; + signed int k_rtc_ldo_real_mul10000 = K_RTC_MID_MUL10000 + k_rtc_ldo; + signed int k_dig_ldo_real_mul10000 = K_DIG_MID_MUL10000 + k_dig_ldo; + uint32_t v_dig_nearest_1v15_mul10000 = v_dig_dbias20_real_mul10000 + k_dig_ldo_real_mul10000 * (dig_dbias - 20); + uint32_t v_rtc_nearest_1v15_mul10000 = 0; + for (rtc_dbias = 15; rtc_dbias < 32; rtc_dbias++) { + v_rtc_nearest_1v15_mul10000 = v_rtc_dbias20_real_mul10000 + k_rtc_ldo_real_mul10000 * (rtc_dbias - 20); + if (v_rtc_nearest_1v15_mul10000 >= v_dig_nearest_1v15_mul10000 - 250) + break; + } + return rtc_dbias; +} + +static void set_rtc_dig_dbias() +{ + /* + 1. a reasonable dig_dbias which by scaning pvt to make 160 CPU run successful stored in efuse; + 2. also we store some value in efuse, include: + k_rtc_ldo (slope of rtc voltage & rtc_dbias); + k_dig_ldo (slope of digital voltage & digital_dbias); + v_rtc_bias20 (rtc voltage when rtc dbais is 20); + v_dig_bias20 (digital voltage when digital dbais is 20). + 3. a reasonable rtc_dbias can be calculated by a certion formula. + */ + uint32_t rtc_dbias = 28, dig_dbias = 28; + uint8_t chip_version = esp_efuse_get_chip_ver(); + if (chip_version >= 3) { + dig_dbias = get_dig_dbias_by_efuse(chip_version); + if (dig_dbias != 0) { + if (dig_dbias + 4 > 28) { + dig_dbias = 28; + } else { + dig_dbias += 4; + } + rtc_dbias = get_rtc_dbias_by_efuse(chip_version, dig_dbias); // already burn dig_dbias in efuse + } else { + dig_dbias = 28; + SOC_LOGD(TAG, "not burn core voltage in efuse or burn wrong voltage value in chip version: 0%d\n", chip_version); + } + } + else { + SOC_LOGD(TAG, "chip_version is less than 3, not burn core voltage in efuse\n"); + } + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_RTC_DREG, rtc_dbias); + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_DIG_DREG, dig_dbias); +} diff --git a/components/esp_hw_support/port/esp32h2/rtc_pm.c b/components/esp_hw_support/port/esp32h2/rtc_pm.c new file mode 100644 index 0000000000..58f2719418 --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/rtc_pm.c @@ -0,0 +1,67 @@ +// Copyright 2020 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 +#include +#include "soc/rtc.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/apb_ctrl_reg.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; + rtc_sleep_init(cfg); + break; + + default: + assert(0 && "unsupported sleep mode"); + } + return PM_SW_NOREJECT; +} diff --git a/components/esp_hw_support/port/esp32h2/rtc_sleep.c b/components/esp_hw_support/port/esp32h2/rtc_sleep.c new file mode 100644 index 0000000000..1cdc56f2d3 --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/rtc_sleep.c @@ -0,0 +1,254 @@ +// Copyright 2020 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 +#include +#include "soc/soc.h" +#include "soc/rtc.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/apb_ctrl_reg.h" +#include "soc/rtc.h" +#include "soc/i2s_reg.h" +#include "soc/bb_reg.h" +#include "soc/nrx_reg.h" +#include "soc/fe_reg.h" +#include "soc/timer_group_reg.h" +#include "soc/system_reg.h" +#include "soc/rtc.h" +#include "esp32c3/rom/ets_sys.h" +#include "esp32c3/rom/rtc.h" +#include "regi2c_ctrl.h" +#include "esp_efuse.h" + +/** + * Configure whether certain peripherals are powered down in deep sleep + * @param cfg power down flags as rtc_sleep_pu_config_t structure + */ +void rtc_sleep_pu(rtc_sleep_pu_config_t cfg) +{ + REG_SET_FIELD(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_LSLP_MEM_FORCE_PU, cfg.dig_fpu); + REG_SET_FIELD(RTC_CNTL_PWC_REG, RTC_CNTL_FASTMEM_FORCE_LPU, cfg.rtc_fpu); + REG_SET_FIELD(APB_CTRL_FRONT_END_MEM_PD_REG, APB_CTRL_DC_MEM_FORCE_PU, cfg.fe_fpu); + REG_SET_FIELD(APB_CTRL_FRONT_END_MEM_PD_REG, APB_CTRL_PBUS_MEM_FORCE_PU, cfg.fe_fpu); + REG_SET_FIELD(APB_CTRL_FRONT_END_MEM_PD_REG, APB_CTRL_AGC_MEM_FORCE_PU, cfg.fe_fpu); + REG_SET_FIELD(BBPD_CTRL, BB_FFT_FORCE_PU, cfg.bb_fpu); + REG_SET_FIELD(BBPD_CTRL, BB_DC_EST_FORCE_PU, cfg.bb_fpu); + REG_SET_FIELD(NRXPD_CTRL, NRX_RX_ROT_FORCE_PU, cfg.nrx_fpu); + REG_SET_FIELD(NRXPD_CTRL, NRX_VIT_FORCE_PU, cfg.nrx_fpu); + REG_SET_FIELD(NRXPD_CTRL, NRX_DEMAP_FORCE_PU, cfg.nrx_fpu); + REG_SET_FIELD(FE_GEN_CTRL, FE_IQ_EST_FORCE_PU, cfg.fe_fpu); + REG_SET_FIELD(FE2_TX_INTERP_CTRL, FE2_TX_INF_FORCE_PU, cfg.fe_fpu); + if (cfg.sram_fpu) { + REG_SET_FIELD(APB_CTRL_MEM_POWER_UP_REG, APB_CTRL_SRAM_POWER_UP, APB_CTRL_SRAM_POWER_UP); + } else { + REG_SET_FIELD(APB_CTRL_MEM_POWER_UP_REG, APB_CTRL_SRAM_POWER_UP, 0); + } + if (cfg.rom_ram_fpu) { + REG_SET_FIELD(APB_CTRL_MEM_POWER_UP_REG, APB_CTRL_ROM_POWER_UP, APB_CTRL_ROM_POWER_UP); + } else { + REG_SET_FIELD(APB_CTRL_MEM_POWER_UP_REG, APB_CTRL_ROM_POWER_UP, 0); + } +} + +void rtc_sleep_init(rtc_sleep_config_t cfg) +{ + if (cfg.lslp_mem_inf_fpu) { + rtc_sleep_pu_config_t pu_cfg = RTC_SLEEP_PU_CONFIG_ALL(1); + rtc_sleep_pu(pu_cfg); + } + 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.bt_pd_en) { + SET_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_BT_PD_EN); + } else { + CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_BT_PD_EN); + } + if (cfg.cpu_pd_en) { + SET_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_CPU_TOP_PD_EN); + } else { + CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_CPU_TOP_PD_EN); + } + if (cfg.dig_peri_pd_en) { + SET_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_DG_PERI_PD_EN); + } else { + CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_DG_PERI_PD_EN); + } + + REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN_MONITOR, RTC_CNTL_DBG_ATTEN_MONITOR_DEFAULT); + REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_BIAS_SLEEP_MONITOR, RTC_CNTL_BIASSLP_MONITOR_DEFAULT); + REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_BIAS_SLEEP_DEEP_SLP, RTC_CNTL_BIASSLP_SLEEP_DEFAULT); + REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_PD_CUR_MONITOR, RTC_CNTL_PD_CUR_MONITOR_DEFAULT); + REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_PD_CUR_DEEP_SLP, RTC_CNTL_PD_CUR_SLEEP_DEFAULT); + if (cfg.deep_slp) { + REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_FORCE_XPD_CK, 0); + CLEAR_PERI_REG_MASK(RTC_CNTL_REG, RTC_CNTL_REGULATOR_FORCE_PU); + unsigned atten_deep_sleep = RTC_CNTL_DBG_ATTEN_DEEPSLEEP_DEFAULT; + #if CONFIG_ESP32C3_REV_MIN < 3 + if (esp_efuse_get_chip_ver() < 3) { + atten_deep_sleep = 0; /* workaround for deep sleep issue in high temp on ECO2 and below */ + } + #endif + REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN_DEEP_SLP, atten_deep_sleep); + SET_PERI_REG_MASK(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_DG_WRAP_PD_EN); + 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); + CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PU); + } else { + SET_PERI_REG_MASK(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DG_VDD_DRV_B_SLP_EN); + REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DG_VDD_DRV_B_SLP, RTC_CNTL_DG_VDD_DRV_B_SLP_DEFAULT); + SET_PERI_REG_MASK(RTC_CNTL_REG, RTC_CNTL_REGULATOR_FORCE_PU); + 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_DEEP_SLP, RTC_CNTL_DBG_ATTEN_LIGHTSLEEP_DEFAULT); + } + + /* 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); + + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_RTC_DREG_SLEEP, cfg.rtc_dbias_slp); + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_DIG_DREG_SLEEP, cfg.dig_dbias_slp); + + REG_SET_FIELD(RTC_CNTL_SLP_REJECT_CONF_REG, RTC_CNTL_DEEP_SLP_REJECT_EN, cfg.deep_slp_reject); + REG_SET_FIELD(RTC_CNTL_SLP_REJECT_CONF_REG, RTC_CNTL_LIGHT_SLP_REJECT_EN, cfg.light_slp_reject); + + /* gating XTAL clock */ + REG_CLR_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_XTAL_GLOBAL_FORCE_NOGATING); +} + +void rtc_sleep_low_init(uint32_t slowclk_period) +{ + // 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_CYCLES); + REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_XTL_BUF_WAIT, rtc_time_us_to_slowclk(RTC_CNTL_XTL_BUF_WAIT_SLP_US, slowclk_period)); + REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_SLP_CYCLES); +} + +void rtc_sleep_set_wakeup_time(uint64_t t) +{ + WRITE_PERI_REG(RTC_CNTL_SLP_TIMER0_REG, t & UINT32_MAX); + WRITE_PERI_REG(RTC_CNTL_SLP_TIMER1_REG, t >> 32); +} + +static uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu); + +uint32_t rtc_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu) +{ + REG_SET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_ENA, wakeup_opt); + REG_SET_FIELD(RTC_CNTL_SLP_REJECT_CONF_REG, RTC_CNTL_SLEEP_REJECT_ENA, 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(lslp_mem_inf_fpu); +} + +#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 will spill to stack, corrupting the CRC). + + Instead, load all the values we need into registers 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 SYSTEM_RTC_FASTMEM_CONFIG_REG value */ + const unsigned CRC_START_ADDR = 0; + const unsigned CRC_LEN = 0x7ff; + + asm volatile( + /* Start CRC calculation */ + "sw %1, 0(%0)\n" // set RTC_MEM_CRC_ADDR & RTC_MEM_CRC_LEN + "or t0, %1, %2\n" + "sw t0, 0(%0)\n" // set RTC_MEM_CRC_START + + /* Wait for the CRC calculation to finish */ + ".Lwaitcrc:\n" + "fence\n" + "lw t0, 0(%0)\n" + "li t1, "STR(SYSTEM_RTC_MEM_CRC_FINISH)"\n" + "and t0, t0, t1\n" + "beqz t0, .Lwaitcrc\n" + "not %2, %2\n" // %2 -> ~DPORT_RTC_MEM_CRC_START + "and t0, t0, %2\n" + "sw t0, 0(%0)\n" // clear RTC_MEM_CRC_START + "fence\n" + "not %2, %2\n" // %2 -> DPORT_RTC_MEM_CRC_START, probably unnecessary but gcc assumes inputs unchanged + + /* Store the calculated value in RTC_MEM_CRC_REG */ + "lw t0, 0(%3)\n" + "sw t0, 0(%4)\n" + "fence\n" + + /* Set register bit to go into deep sleep */ + "lw t0, 0(%5)\n" + "or t0, t0, %6\n" + "sw t0, 0(%5)\n" + "fence\n" + + /* Wait for sleep reject interrupt (never finishes if successful) */ + ".Lwaitsleep:" + "fence\n" + "lw t0, 0(%7)\n" + "and t0, t0, %8\n" + "beqz t0, .Lwaitsleep\n" + + : + : + "r" (SYSTEM_RTC_FASTMEM_CONFIG_REG), // %0 + "r" ( (CRC_START_ADDR << SYSTEM_RTC_MEM_CRC_START_S) + | (CRC_LEN << SYSTEM_RTC_MEM_CRC_LEN_S)), // %1 + "r" (SYSTEM_RTC_MEM_CRC_START), // %2 + "r" (SYSTEM_RTC_FASTMEM_CRC_REG), // %3 + "r" (RTC_MEMORY_CRC_REG), // %4 + "r" (RTC_CNTL_STATE0_REG), // %5 + "r" (RTC_CNTL_SLEEP_EN), // %6 + "r" (RTC_CNTL_INT_RAW_REG), // %7 + "r" (RTC_CNTL_SLP_REJECT_INT_RAW | RTC_CNTL_SLP_WAKEUP_INT_RAW) // %8 + : "t0", "t1" // working registers + ); + + return rtc_sleep_finish(0); +} + +static uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu) +{ + /* 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 config if it is a light sleep */ + if (lslp_mem_inf_fpu) { + rtc_sleep_pu_config_t pu_cfg = RTC_SLEEP_PU_CONFIG_ALL(1); + rtc_sleep_pu(pu_cfg); + } + return reject; +} diff --git a/components/esp_hw_support/port/esp32h2/rtc_time.c b/components/esp_hw_support/port/esp32h2/rtc_time.c new file mode 100644 index 0000000000..7792d5cf13 --- /dev/null +++ b/components/esp_hw_support/port/esp32h2/rtc_time.c @@ -0,0 +1,189 @@ +// Copyright 2020 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 +#include "esp32c3/rom/ets_sys.h" +#include "soc/rtc.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/timer_group_reg.h" +#include "esp_rom_sys.h" + +/* 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 + * @return number of XTAL clock cycles within the given number of slow clock cycles + */ +uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles) +{ + /* On ESP32C3, choosing RTC_CAL_RTC_MUX results in calibration of + * the 150k RTC clock regardless of the currenlty selected SLOW_CLK. + * On the ESP32, it used the currently selected SLOW_CLK. + * The following code emulates ESP32 behavior: + */ + if (cal_clk == RTC_CAL_RTC_MUX) { + rtc_slow_freq_t slow_freq = rtc_clk_slow_freq_get(); + if (slow_freq == RTC_SLOW_FREQ_32K_XTAL) { + cal_clk = RTC_CAL_32K_XTAL; + } else if (slow_freq == RTC_SLOW_FREQ_8MD256) { + cal_clk = RTC_CAL_8MD256; + } + } + /* 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); + /* There may be another calibration process already running during we call this function, + * so we should wait the last process is done. + */ + if (!GET_PERI_REG_MASK(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT)) { + if (GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING)) { + while (!GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_RDY)); + } + } + 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 */ + + /* Set timeout reg and expect time delay*/ + uint32_t expected_freq; + if (cal_clk == RTC_CAL_32K_XTAL) { + REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_X32K_CAL_TIMEOUT_THRES(slowclk_cycles)); + expected_freq = RTC_SLOW_CLK_FREQ_32K; + } else if (cal_clk == RTC_CAL_8MD256) { + REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_8MD256_CAL_TIMEOUT_THRES(slowclk_cycles)); + expected_freq = RTC_SLOW_CLK_FREQ_8MD256; + } else { + REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_150K_CAL_TIMEOUT_THRES(slowclk_cycles)); + expected_freq = RTC_SLOW_CLK_FREQ_150K; + } + uint32_t us_time_estimate = (uint32_t) (((uint64_t) slowclk_cycles) * MHZ / expected_freq); + /* 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 for calibration to finish up to another us_time_estimate */ + esp_rom_delay_us(us_time_estimate); + uint32_t cal_val; + while (true) { + if (GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_RDY)) { + cal_val = REG_GET_FIELD(TIMG_RTCCALICFG1_REG(0), TIMG_RTC_CALI_VALUE); + break; + } + if (GET_PERI_REG_MASK(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT)) { + cal_val = 0; + break; + } + } + CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START); + + 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); + } + + return cal_val; +} + +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); + uint64_t t = READ_PERI_REG(RTC_CNTL_TIME0_REG); + t |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME1_REG)) << 32; + return t; +} + +uint64_t rtc_light_slp_time_get(void) +{ + uint64_t t_wake = READ_PERI_REG(RTC_CNTL_TIME_LOW0_REG); + t_wake |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME_HIGH0_REG)) << 32; + uint64_t t_slp = READ_PERI_REG(RTC_CNTL_TIME_LOW1_REG); + t_slp |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME_HIGH1_REG)) << 32; + return (t_wake - t_slp); +} + +uint64_t rtc_deep_slp_time_get(void) +{ + uint64_t t_slp = READ_PERI_REG(RTC_CNTL_TIME_LOW1_REG); + t_slp |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME_HIGH1_REG)) << 32; + uint64_t t_wake = rtc_time_get(); + return (t_wake - t_slp); +} + +void rtc_clk_wait_for_slow_cycle(void) //This function may not by useful any more +{ + SET_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_SLOW_CLK_NEXT_EDGE); + while (GET_PERI_REG_MASK(RTC_CNTL_SLOW_CLK_CONF_REG, RTC_CNTL_SLOW_CLK_NEXT_EDGE)) { + esp_rom_delay_us(1); + } +} + +uint32_t rtc_clk_freq_cal(uint32_t cal_val) +{ + if (cal_val == 0) { + return 0; // cal_val will be denominator, return 0 as the symbol of failure. + } + return 1000000ULL * (1 << RTC_CLK_CAL_FRACT) / cal_val; +} diff --git a/components/esp_system/port/soc/esp32h2/CMakeLists.txt b/components/esp_system/port/soc/esp32h2/CMakeLists.txt new file mode 100644 index 0000000000..0725e3f02a --- /dev/null +++ b/components/esp_system/port/soc/esp32h2/CMakeLists.txt @@ -0,0 +1,11 @@ +set(srcs "clk.c" + "reset_reason.c" + "system_internal.c" + "cache_err_int.c" + "apb_backup_dma.c" + "../../arch/riscv/expression_with_stack.c" + "../../arch/riscv/expression_with_stack_asm.S" + "../../arch/riscv/panic_arch.c") +add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs}) + +target_sources(${COMPONENT_LIB} PRIVATE ${srcs}) diff --git a/components/esp_system/port/soc/esp32h2/apb_backup_dma.c b/components/esp_system/port/soc/esp32h2/apb_backup_dma.c new file mode 100644 index 0000000000..24b0ad0e04 --- /dev/null +++ b/components/esp_system/port/soc/esp32h2/apb_backup_dma.c @@ -0,0 +1,48 @@ + +// Copyright 2015-2020 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/soc_caps.h" + +#if SOC_APB_BACKUP_DMA +#include "esp_attr.h" +#include "freertos/FreeRTOS.h" +#include "freertos/portmacro.h" +#include "esp32c3/rom/apb_backup_dma.h" + +static portMUX_TYPE s_apb_backup_dma_mutex = portMUX_INITIALIZER_UNLOCKED; + +static void IRAM_ATTR apb_backup_dma_lock(void) +{ + if (xPortInIsrContext()) { + portENTER_CRITICAL_ISR(&s_apb_backup_dma_mutex); + } else { + portENTER_CRITICAL(&s_apb_backup_dma_mutex); + } +} + +static void IRAM_ATTR apb_backup_dma_unlock(void) +{ + if (xPortInIsrContext()) { + portEXIT_CRITICAL_ISR(&s_apb_backup_dma_mutex); + } else { + portEXIT_CRITICAL(&s_apb_backup_dma_mutex); + } +} + +void esp_apb_backup_dma_lock_init(void) +{ + ets_apb_backup_init_lock_func(apb_backup_dma_lock, apb_backup_dma_unlock); +} +#endif diff --git a/components/esp_system/port/soc/esp32h2/cache_err_int.c b/components/esp_system/port/soc/esp32h2/cache_err_int.c new file mode 100644 index 0000000000..20cf2be2a2 --- /dev/null +++ b/components/esp_system/port/soc/esp32h2/cache_err_int.c @@ -0,0 +1,102 @@ +// Copyright 2015-2020 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. + +/* + The cache has an interrupt that can be raised as soon as an access to a cached + region (flash) is done without the cache being enabled. We use that here + to panic the CPU, which from a debugging perspective is better than grabbing bad + data from the bus. +*/ +#include "esp32c3/rom/ets_sys.h" +#include "esp_attr.h" +#include "esp_intr_alloc.h" +#include "soc/extmem_reg.h" +#include "soc/periph_defs.h" +#include "riscv/interrupt.h" + +void esp_cache_err_int_init(void) +{ + const uint32_t core_id = 0; + + /* Disable cache interrupts if enabled. */ + ESP_INTR_DISABLE(ETS_CACHEERR_INUM); + + /** + * Bind all cache errors to ETS_CACHEERR_INUM interrupt. we will deal with + * them in handler by different types + * I) Cache access error + * 1. dbus trying to write to icache + * 2. dbus authentication fail + * 3. cpu access icache while dbus is disabled [1] + * 4. ibus authentication fail + * 5. ibus trying to write icache + * 6. cpu access icache while ibus is disabled + * II) Cache illegal error + * 1. dbus counter overflow + * 2. ibus counter overflow + * 3. mmu entry fault + * 4. icache preload configurations fault + * 5. icache sync configuration fault + * + * [1]: On ESP32C3 boards, the caches are shared but buses are still + * distinct. So, we have an ibus and a dbus sharing the same cache. + * This error can occur if the dbus performs a request but the icache + * (or simply cache) is disabled. + */ + intr_matrix_set(core_id, ETS_CACHE_IA_INTR_SOURCE, ETS_CACHEERR_INUM); + intr_matrix_set(core_id, ETS_CACHE_CORE0_ACS_INTR_SOURCE, ETS_CACHEERR_INUM); + + /* Set the type and priority to cache error interrupts. */ + esprv_intc_int_set_type(BIT(ETS_CACHEERR_INUM), INTR_TYPE_LEVEL); + esprv_intc_int_set_priority(ETS_CACHEERR_INUM, SOC_INTERRUPT_LEVEL_MEDIUM); + + /* On the hardware side, stat by clearing all the bits reponsible for + * enabling cache access error interrupts. */ + SET_PERI_REG_MASK(EXTMEM_CORE0_ACS_CACHE_INT_CLR_REG, + EXTMEM_CORE0_DBUS_WR_IC_INT_CLR | + EXTMEM_CORE0_DBUS_REJECT_INT_CLR | + EXTMEM_CORE0_DBUS_ACS_MSK_IC_INT_CLR | + EXTMEM_CORE0_IBUS_REJECT_INT_CLR | + EXTMEM_CORE0_IBUS_WR_IC_INT_CLR | + EXTMEM_CORE0_IBUS_ACS_MSK_IC_INT_CLR); + + /* Enable these interrupts. */ + SET_PERI_REG_MASK(EXTMEM_CORE0_ACS_CACHE_INT_ENA_REG, + EXTMEM_CORE0_DBUS_WR_IC_INT_ENA | + EXTMEM_CORE0_DBUS_REJECT_INT_ENA | + EXTMEM_CORE0_DBUS_ACS_MSK_IC_INT_ENA | + EXTMEM_CORE0_IBUS_REJECT_INT_ENA | + EXTMEM_CORE0_IBUS_WR_IC_INT_ENA | + EXTMEM_CORE0_IBUS_ACS_MSK_IC_INT_ENA); + + /* Same goes for cache illegal error: start by clearing the bits and then + * set them back. */ + SET_PERI_REG_MASK(EXTMEM_CACHE_ILG_INT_CLR_REG, + EXTMEM_MMU_ENTRY_FAULT_INT_CLR | + EXTMEM_ICACHE_PRELOAD_OP_FAULT_INT_CLR | + EXTMEM_ICACHE_SYNC_OP_FAULT_INT_CLR); + + SET_PERI_REG_MASK(EXTMEM_CACHE_ILG_INT_ENA_REG, + EXTMEM_MMU_ENTRY_FAULT_INT_ENA | + EXTMEM_ICACHE_PRELOAD_OP_FAULT_INT_ENA | + EXTMEM_ICACHE_SYNC_OP_FAULT_INT_ENA); + + /* Enable the interrupts for cache error. */ + ESP_INTR_ENABLE(ETS_CACHEERR_INUM); +} + +int IRAM_ATTR esp_cache_err_get_cpuid(void) +{ + return 0; +} diff --git a/components/esp_system/port/soc/esp32h2/cache_err_int.h b/components/esp_system/port/soc/esp32h2/cache_err_int.h new file mode 100644 index 0000000000..07085f5309 --- /dev/null +++ b/components/esp_system/port/soc/esp32h2/cache_err_int.h @@ -0,0 +1,2 @@ +#pragma once +#include "cache_err_int.h" diff --git a/components/esp_system/port/soc/esp32h2/clk.c b/components/esp_system/port/soc/esp32h2/clk.c new file mode 100644 index 0000000000..ca993ddf4c --- /dev/null +++ b/components/esp_system/port/soc/esp32h2/clk.c @@ -0,0 +1,321 @@ +// Copyright 2015-2020 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 +#include +#include +#include +#include "sdkconfig.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp32c3/clk.h" +#include "esp_clk_internal.h" +#include "esp32c3/rom/ets_sys.h" +#include "esp32c3/rom/uart.h" +#include "esp32c3/rom/rtc.h" +#include "soc/system_reg.h" +#include "soc/dport_access.h" +#include "soc/soc.h" +#include "soc/rtc.h" +#include "soc/rtc_periph.h" +#include "soc/i2s_reg.h" +#include "hal/cpu_hal.h" +#include "hal/wdt_hal.h" +#include "driver/periph_ctrl.h" +#include "bootloader_clock.h" +#include "soc/syscon_reg.h" +#include "esp_rom_uart.h" + +/* Number of cycles to wait from the 32k XTAL oscillator to consider it running. + * Larger values increase startup delay. Smaller values may cause false positive + * detection (i.e. oscillator runs for a few cycles and then stops). + */ +#define SLOW_CLK_CAL_CYCLES CONFIG_ESP32C3_RTC_CLK_CAL_CYCLES + +#define MHZ (1000000) + +/* Lower threshold for a reasonably-looking calibration value for a 32k XTAL. + * The ideal value (assuming 32768 Hz frequency) is 1000000/32768*(2**19) = 16*10^6. + */ +#define MIN_32K_XTAL_CAL_VAL 15000000L + +/* Indicates that this 32k oscillator gets input from external oscillator, rather + * than a crystal. + */ +#define EXT_OSC_FLAG BIT(3) + +/* This is almost the same as rtc_slow_freq_t, except that we define + * an extra enum member for the external 32k oscillator. + * For convenience, lower 2 bits should correspond to rtc_slow_freq_t values. + */ +typedef enum { + SLOW_CLK_RTC = RTC_SLOW_FREQ_RTC, //!< Internal 150 kHz RC oscillator + SLOW_CLK_32K_XTAL = RTC_SLOW_FREQ_32K_XTAL, //!< External 32 kHz XTAL + SLOW_CLK_8MD256 = RTC_SLOW_FREQ_8MD256, //!< Internal 8 MHz RC oscillator, divided by 256 + SLOW_CLK_32K_EXT_OSC = RTC_SLOW_FREQ_32K_XTAL | EXT_OSC_FLAG //!< External 32k oscillator connected to 32K_XP pin +} slow_clk_sel_t; + +static void select_rtc_slow_clk(slow_clk_sel_t slow_clk); + +static const char *TAG = "clk"; + + + __attribute__((weak)) void esp_clk_init(void) +{ +#if !CONFIG_IDF_ENV_FPGA + rtc_config_t cfg = RTC_CONFIG_DEFAULT(); + RESET_REASON rst_reas; + rst_reas = rtc_get_reset_reason(0); + if (rst_reas == POWERON_RESET) { + cfg.cali_ocode = 1; + } + rtc_init(cfg); + + assert(rtc_clk_xtal_freq_get() == RTC_XTAL_FREQ_40M); + + rtc_clk_fast_freq_set(RTC_FAST_FREQ_8M); +#endif + +#ifdef CONFIG_BOOTLOADER_WDT_ENABLE + // WDT uses a SLOW_CLK clock source. After a function select_rtc_slow_clk a frequency of this source can changed. + // If the frequency changes from 150kHz to 32kHz, then the timeout set for the WDT will increase 4.6 times. + // Therefore, for the time of frequency change, set a new lower timeout value (1.6 sec). + // This prevents excessive delay before resetting in case the supply voltage is drawdown. + // (If frequency is changed from 150kHz to 32kHz then WDT timeout will increased to 1.6sec * 150/32 = 7.5 sec). + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; + uint32_t stage_timeout_ticks = (uint32_t)(1600ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + //Bootloader has enabled RTC WDT until now. We're only modifying timeout, so keep the stage and timeout action the same + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif + +#if defined(CONFIG_ESP32C3_RTC_CLK_SRC_EXT_CRYS) + select_rtc_slow_clk(SLOW_CLK_32K_XTAL); +#elif defined(CONFIG_ESP32C3_RTC_CLK_SRC_EXT_OSC) + select_rtc_slow_clk(SLOW_CLK_32K_EXT_OSC); +#elif defined(CONFIG_ESP32C3_RTC_CLK_SRC_INT_8MD256) + select_rtc_slow_clk(SLOW_CLK_8MD256); +#else + select_rtc_slow_clk(RTC_SLOW_FREQ_RTC); +#endif + +#ifdef CONFIG_BOOTLOADER_WDT_ENABLE + // After changing a frequency WDT timeout needs to be set for new frequency. + stage_timeout_ticks = (uint32_t)((uint64_t)CONFIG_BOOTLOADER_WDT_TIME_MS * rtc_clk_slow_freq_get_hz() / 1000); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif + + rtc_cpu_freq_config_t old_config, new_config; + rtc_clk_cpu_freq_get_config(&old_config); + const uint32_t old_freq_mhz = old_config.freq_mhz; + const uint32_t new_freq_mhz = CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ; + + bool res = rtc_clk_cpu_freq_mhz_to_config(new_freq_mhz, &new_config); + assert(res); + + // Wait for UART TX to finish, otherwise some UART output will be lost + // when switching APB frequency + esp_rom_uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); + + if (res) { + rtc_clk_cpu_freq_set_config(&new_config); + } + + // Re calculate the ccount to make time calculation correct. + cpu_hal_set_cycle_count( (uint64_t)cpu_hal_get_cycle_count() * new_freq_mhz / old_freq_mhz ); +} + +static void select_rtc_slow_clk(slow_clk_sel_t slow_clk) +{ + rtc_slow_freq_t rtc_slow_freq = slow_clk & RTC_CNTL_ANA_CLK_RTC_SEL_V; + uint32_t cal_val = 0; + /* number of times to repeat 32k XTAL calibration + * before giving up and switching to the internal RC + */ + int retry_32k_xtal = 3; + + do { + if (rtc_slow_freq == RTC_SLOW_FREQ_32K_XTAL) { + /* 32k XTAL oscillator needs to be enabled and running before it can + * be used. Hardware doesn't have a direct way of checking if the + * oscillator is running. Here we use rtc_clk_cal function to count + * the number of main XTAL cycles in the given number of 32k XTAL + * oscillator cycles. If the 32k XTAL has not started up, calibration + * will time out, returning 0. + */ + ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up"); + if (slow_clk == SLOW_CLK_32K_XTAL) { + rtc_clk_32k_enable(true); + } else if (slow_clk == SLOW_CLK_32K_EXT_OSC) { + rtc_clk_32k_enable_external(); + } + // When SLOW_CLK_CAL_CYCLES is set to 0, clock calibration will not be performed at startup. + if (SLOW_CLK_CAL_CYCLES > 0) { + cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES); + if (cal_val == 0 || cal_val < MIN_32K_XTAL_CAL_VAL) { + if (retry_32k_xtal-- > 0) { + continue; + } + ESP_EARLY_LOGW(TAG, "32 kHz XTAL not found, switching to internal 150 kHz oscillator"); + rtc_slow_freq = RTC_SLOW_FREQ_RTC; + } + } + } else if (rtc_slow_freq == RTC_SLOW_FREQ_8MD256) { + rtc_clk_8m_enable(true, true); + } + rtc_clk_slow_freq_set(rtc_slow_freq); + + if (SLOW_CLK_CAL_CYCLES > 0) { + /* TODO: 32k XTAL oscillator has some frequency drift at startup. + * Improve calibration routine to wait until the frequency is stable. + */ + cal_val = rtc_clk_cal(RTC_CAL_RTC_MUX, SLOW_CLK_CAL_CYCLES); + } else { + const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL; + cal_val = (uint32_t) (cal_dividend / rtc_clk_slow_freq_get_hz()); + } + } while (cal_val == 0); + ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val); + esp_clk_slowclk_cal_set(cal_val); +} + +void rtc_clk_select_rtc_slow_clk(void) +{ + select_rtc_slow_clk(RTC_SLOW_FREQ_32K_XTAL); +} + +/* This function is not exposed as an API at this point. + * All peripheral clocks are default enabled after chip is powered on. + * This function disables some peripheral clocks when cpu starts. + * These peripheral clocks are enabled when the peripherals are initialized + * and disabled when they are de-initialized. + */ +__attribute__((weak)) void esp_perip_clk_init(void) +{ + uint32_t common_perip_clk, hwcrypto_perip_clk, wifi_bt_sdio_clk = 0; + uint32_t common_perip_clk1 = 0; + +#if CONFIG_FREERTOS_UNICORE + RESET_REASON rst_reas[1]; +#else + RESET_REASON rst_reas[2]; +#endif + + rst_reas[0] = rtc_get_reset_reason(0); +#if !CONFIG_FREERTOS_UNICORE + rst_reas[1] = rtc_get_reset_reason(1); +#endif + + /* For reason that only reset CPU, do not disable the clocks + * that have been enabled before reset. + */ + /* For reason that only reset CPU, do not disable the clocks + * that have been enabled before reset. + */ + if ((rst_reas[0] >= TG0WDT_CPU_RESET && rst_reas[0] <= TG0WDT_CPU_RESET && rst_reas[0] != RTCWDT_BROWN_OUT_RESET) +#if !CONFIG_FREERTOS_UNICORE + || (rst_reas[1] >= TG0WDT_CPU_RESET && rst_reas[1] <= RTCWDT_CPU_RESET) +#endif + ) { + common_perip_clk = ~READ_PERI_REG(SYSTEM_PERIP_CLK_EN0_REG); + hwcrypto_perip_clk = ~READ_PERI_REG(SYSTEM_PERIP_CLK_EN1_REG); + wifi_bt_sdio_clk = ~READ_PERI_REG(SYSTEM_WIFI_CLK_EN_REG); + } else { + common_perip_clk = SYSTEM_WDG_CLK_EN | + SYSTEM_I2S0_CLK_EN | +#if CONFIG_CONSOLE_UART_NUM != 0 + SYSTEM_UART_CLK_EN | +#endif +#if CONFIG_CONSOLE_UART_NUM != 1 + SYSTEM_UART1_CLK_EN | +#endif + SYSTEM_SPI2_CLK_EN | + SYSTEM_I2C_EXT0_CLK_EN | + SYSTEM_UHCI0_CLK_EN | + SYSTEM_RMT_CLK_EN | + SYSTEM_LEDC_CLK_EN | + SYSTEM_TIMERGROUP1_CLK_EN | + SYSTEM_SPI3_CLK_EN | + SYSTEM_SPI4_CLK_EN | + SYSTEM_TWAI_CLK_EN | + SYSTEM_I2S1_CLK_EN | + SYSTEM_SPI2_DMA_CLK_EN | + SYSTEM_SPI3_DMA_CLK_EN; + + common_perip_clk1 = 0; + hwcrypto_perip_clk = SYSTEM_CRYPTO_AES_CLK_EN | + SYSTEM_CRYPTO_SHA_CLK_EN | + SYSTEM_CRYPTO_RSA_CLK_EN; + wifi_bt_sdio_clk = SYSTEM_WIFI_CLK_WIFI_EN | + SYSTEM_WIFI_CLK_BT_EN_M | + SYSTEM_WIFI_CLK_UNUSED_BIT5 | + SYSTEM_WIFI_CLK_UNUSED_BIT12; + } + + //Reset the communication peripherals like I2C, SPI, UART, I2S and bring them to known state. + common_perip_clk |= SYSTEM_I2S0_CLK_EN | +#if CONFIG_CONSOLE_UART_NUM != 0 + SYSTEM_UART_CLK_EN | +#endif +#if CONFIG_CONSOLE_UART_NUM != 1 + SYSTEM_UART1_CLK_EN | +#endif + SYSTEM_SPI2_CLK_EN | + SYSTEM_I2C_EXT0_CLK_EN | + SYSTEM_UHCI0_CLK_EN | + SYSTEM_RMT_CLK_EN | + SYSTEM_UHCI1_CLK_EN | + SYSTEM_SPI3_CLK_EN | + SYSTEM_SPI4_CLK_EN | + SYSTEM_I2C_EXT1_CLK_EN | + SYSTEM_I2S1_CLK_EN | + SYSTEM_SPI2_DMA_CLK_EN | + SYSTEM_SPI3_DMA_CLK_EN; + common_perip_clk1 = 0; + + /* Change I2S clock to audio PLL first. Because if I2S uses 160MHz clock, + * the current is not reduced when disable I2S clock. + */ + // TOCK(check replacement) + // REG_SET_FIELD(I2S_CLKM_CONF_REG(0), I2S_CLK_SEL, I2S_CLK_AUDIO_PLL); + // REG_SET_FIELD(I2S_CLKM_CONF_REG(1), I2S_CLK_SEL, I2S_CLK_AUDIO_PLL); + + /* Disable some peripheral clocks. */ + CLEAR_PERI_REG_MASK(SYSTEM_PERIP_CLK_EN0_REG, common_perip_clk); + SET_PERI_REG_MASK(SYSTEM_PERIP_RST_EN0_REG, common_perip_clk); + + CLEAR_PERI_REG_MASK(SYSTEM_PERIP_CLK_EN1_REG, common_perip_clk1); + SET_PERI_REG_MASK(SYSTEM_PERIP_RST_EN1_REG, common_perip_clk1); + + /* Disable hardware crypto clocks. */ + CLEAR_PERI_REG_MASK(SYSTEM_PERIP_CLK_EN1_REG, hwcrypto_perip_clk); + SET_PERI_REG_MASK(SYSTEM_PERIP_RST_EN1_REG, hwcrypto_perip_clk); + + /* Disable WiFi/BT/SDIO clocks. */ + CLEAR_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, wifi_bt_sdio_clk); + SET_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_EN); + + /* Set WiFi light sleep clock source to RTC slow clock */ + REG_SET_FIELD(SYSTEM_BT_LPCK_DIV_INT_REG, SYSTEM_BT_LPCK_DIV_NUM, 0); + CLEAR_PERI_REG_MASK(SYSTEM_BT_LPCK_DIV_FRAC_REG, SYSTEM_LPCLK_SEL_8M); + SET_PERI_REG_MASK(SYSTEM_BT_LPCK_DIV_FRAC_REG, SYSTEM_LPCLK_SEL_RTC_SLOW); + + /* Enable RNG clock. */ + periph_module_enable(PERIPH_RNG_MODULE); +} diff --git a/components/esp_system/port/soc/esp32h2/reset_reason.c b/components/esp_system/port/soc/esp32h2/reset_reason.c new file mode 100644 index 0000000000..7487eb682a --- /dev/null +++ b/components/esp_system/port/soc/esp32h2/reset_reason.c @@ -0,0 +1,119 @@ +// 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 "esp_system.h" +#include "esp32c3/rom/rtc.h" +#include "esp_private/system_internal.h" +#include "soc/rtc_periph.h" + +static void esp_reset_reason_clear_hint(void); + +static esp_reset_reason_t s_reset_reason; + +static esp_reset_reason_t get_reset_reason(RESET_REASON rtc_reset_reason, esp_reset_reason_t reset_reason_hint) +{ + switch (rtc_reset_reason) { + case POWERON_RESET: + return ESP_RST_POWERON; + + case RTC_SW_CPU_RESET: + case RTC_SW_SYS_RESET: + if (reset_reason_hint == ESP_RST_PANIC || + reset_reason_hint == ESP_RST_BROWNOUT || + reset_reason_hint == ESP_RST_TASK_WDT || + reset_reason_hint == ESP_RST_INT_WDT) { + return reset_reason_hint; + } + return ESP_RST_SW; + + case DEEPSLEEP_RESET: + return ESP_RST_DEEPSLEEP; + + case TG0WDT_SYS_RESET: + return ESP_RST_TASK_WDT; + + case TG1WDT_SYS_RESET: + return ESP_RST_INT_WDT; + + case RTCWDT_SYS_RESET: + case RTCWDT_RTC_RESET: + case SUPER_WDT_RESET: + case RTCWDT_CPU_RESET: /* unused */ + case TG0WDT_CPU_RESET: /* unused */ + case TG1WDT_CPU_RESET: /* unused */ + return ESP_RST_WDT; + + case RTCWDT_BROWN_OUT_RESET: + return ESP_RST_BROWNOUT; + + case INTRUSION_RESET: /* unused */ + default: + return ESP_RST_UNKNOWN; + } +} + +static void __attribute__((constructor)) esp_reset_reason_init(void) +{ + esp_reset_reason_t hint = esp_reset_reason_get_hint(); + s_reset_reason = get_reset_reason(rtc_get_reset_reason(PRO_CPU_NUM), + hint); + if (hint != ESP_RST_UNKNOWN) { + esp_reset_reason_clear_hint(); + } +} + +esp_reset_reason_t esp_reset_reason(void) +{ + return s_reset_reason; +} + +/* Reset reason hint is stored in RTC_RESET_CAUSE_REG, a.k.a. RTC_CNTL_STORE6_REG, + * a.k.a. RTC_ENTRY_ADDR_REG. It is safe to use this register both for the + * deep sleep wake stub entry address and for reset reason hint, since wake stub + * is only used for deep sleep reset, and in this case the reason provided by + * rtc_get_reset_reason is unambiguous. + * + * Same layout is used as for RTC_APB_FREQ_REG (a.k.a. RTC_CNTL_STORE5_REG): + * the value is replicated in low and high half-words. In addition to that, + * MSB is set to 1, which doesn't happen when RTC_CNTL_STORE6_REG contains + * deep sleep wake stub address. + */ + +#define RST_REASON_BIT 0x80000000 +#define RST_REASON_MASK 0x7FFF +#define RST_REASON_SHIFT 16 + +/* in IRAM, can be called from panic handler */ +void IRAM_ATTR esp_reset_reason_set_hint(esp_reset_reason_t hint) +{ + assert((hint & (~RST_REASON_MASK)) == 0); + uint32_t val = hint | (hint << RST_REASON_SHIFT) | RST_REASON_BIT; + REG_WRITE(RTC_RESET_CAUSE_REG, val); +} + +/* in IRAM, can be called from panic handler */ +esp_reset_reason_t IRAM_ATTR esp_reset_reason_get_hint(void) +{ + uint32_t reset_reason_hint = REG_READ(RTC_RESET_CAUSE_REG); + uint32_t high = (reset_reason_hint >> RST_REASON_SHIFT) & RST_REASON_MASK; + uint32_t low = reset_reason_hint & RST_REASON_MASK; + if ((reset_reason_hint & RST_REASON_BIT) == 0 || high != low) { + return ESP_RST_UNKNOWN; + } + return (esp_reset_reason_t) low; +} +static inline void esp_reset_reason_clear_hint(void) +{ + REG_WRITE(RTC_RESET_CAUSE_REG, 0); +} diff --git a/components/esp_system/port/soc/esp32h2/system_internal.c b/components/esp_system/port/soc/esp32h2/system_internal.c new file mode 100644 index 0000000000..2dd27c0bf6 --- /dev/null +++ b/components/esp_system/port/soc/esp32h2/system_internal.c @@ -0,0 +1,144 @@ +// 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 +#include "sdkconfig.h" +#include "esp_system.h" +#include "esp_private/system_internal.h" +#include "esp_attr.h" +#include "esp_efuse.h" +#include "esp_log.h" +#include "riscv/riscv_interrupts.h" +#include "riscv/interrupt.h" +#include "esp_rom_uart.h" +#include "soc/gpio_reg.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/timer_group_reg.h" +#include "soc/cpu.h" +#include "soc/rtc.h" +#include "soc/rtc_periph.h" +#include "soc/syscon_reg.h" +#include "soc/system_reg.h" +#include "hal/wdt_hal.h" +#include "cache_err_int.h" + +#include "esp32c3/rom/cache.h" +#include "esp32c3/rom/rtc.h" + +/* "inner" restart function for after RTOS, interrupts & anything else on this + * core are already stopped. Stalls other core, resets hardware, + * triggers restart. +*/ +void IRAM_ATTR esp_restart_noos(void) +{ + // Disable interrupts + riscv_global_interrupts_disable(); + // Enable RTC watchdog for 1 second + wdt_hal_context_t rtc_wdt_ctx; + wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); + uint32_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE1, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + //Enable flash boot mode so that flash booting after restart is protected by the RTC WDT. + wdt_hal_set_flashboot_en(&rtc_wdt_ctx, true); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); + + // Reset and stall the other CPU. + // CPU must be reset before stalling, in case it was running a s32c1i + // instruction. This would cause memory pool to be locked by arbiter + // to the stalled CPU, preventing current CPU from accessing this pool. + const uint32_t core_id = cpu_hal_get_core_id(); +#if !CONFIG_FREERTOS_UNICORE + const uint32_t other_core_id = (core_id == 0) ? 1 : 0; + esp_cpu_reset(other_core_id); + esp_cpu_stall(other_core_id); +#endif + + // Disable TG0/TG1 watchdogs + wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; + wdt_hal_write_protect_disable(&wdt0_context); + wdt_hal_disable(&wdt0_context); + wdt_hal_write_protect_enable(&wdt0_context); + + wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1}; + wdt_hal_write_protect_disable(&wdt1_context); + wdt_hal_disable(&wdt1_context); + wdt_hal_write_protect_enable(&wdt1_context); + + // Flush any data left in UART FIFOs + esp_rom_uart_tx_wait_idle(0); + esp_rom_uart_tx_wait_idle(1); + // Disable cache + Cache_Disable_ICache(); + + // 2nd stage bootloader reconfigures SPI flash signals. + // Reset them to the defaults expected by ROM. + WRITE_PERI_REG(GPIO_FUNC0_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC1_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC2_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC3_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC4_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC5_IN_SEL_CFG_REG, 0x30); + + // Reset wifi/bluetooth/ethernet/sdio (bb/mac) + SET_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, + SYSTEM_BB_RST | SYSTEM_FE_RST | SYSTEM_MAC_RST | + SYSTEM_BT_RST | SYSTEM_BTMAC_RST | SYSTEM_SDIO_RST | + SYSTEM_EMAC_RST | SYSTEM_MACPWR_RST | + SYSTEM_RW_BTMAC_RST | SYSTEM_RW_BTLP_RST | BLE_REG_REST_BIT + |BLE_PWR_REG_REST_BIT | BLE_BB_REG_REST_BIT); + + + REG_WRITE(SYSTEM_CORE_RST_EN_REG, 0); + + // Reset timer/spi/uart + SET_PERI_REG_MASK(SYSTEM_PERIP_RST_EN0_REG, + SYSTEM_TIMERS_RST | SYSTEM_SPI01_RST | SYSTEM_UART_RST); + REG_WRITE(SYSTEM_PERIP_RST_EN0_REG, 0); + // Reset dma + SET_PERI_REG_MASK(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_DMA_RST); + REG_WRITE(SYSTEM_PERIP_RST_EN1_REG, 0); + + // Set CPU back to XTAL source, no PLL, same as hard reset +#if !CONFIG_IDF_ENV_FPGA + rtc_clk_cpu_freq_set_xtal(); +#endif + +#if !CONFIG_FREERTOS_UNICORE + // Clear entry point for APP CPU + REG_WRITE(SYSTEM_CORE_1_CONTROL_1_REG, 0); +#endif + + // Reset CPUs + if (core_id == 0) { + // Running on PRO CPU: APP CPU is stalled. Can reset both CPUs. +#if !CONFIG_FREERTOS_UNICORE + esp_cpu_reset(1); +#endif + esp_cpu_reset(0); + } +#if !CONFIG_FREERTOS_UNICORE + else { + // Running on APP CPU: need to reset PRO CPU and unstall it, + // then reset APP CPU + esp_cpu_reset(0); + esp_cpu_unstall(0); + esp_cpu_reset(1); + } +#endif + while (true) { + ; + } +}