diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index 39fd74d77a..9c28dfbab4 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -191,6 +191,27 @@ if(NOT BOOTLOADER_BUILD) "adc_hal_common.c" ) endif() + + if(${target} STREQUAL "esp32h2") + list(APPEND srcs + "spi_flash_hal_gpspi.c" + ) + + # TODO: IDF-5310 + list(REMOVE_ITEM srcs + "adc_oneshot_hal.c" + "adc_hal_common.c" + "spi_slave_hd_hal.c" + "spi_hal.c" + "spi_hal_iram.c" + "spi_slave_hal.c" + "spi_slave_hal_iram.c" + "esp32h2/brownout_hal.c" + "esp32h2/rtc_cntl_hal.c" + "timer_hal.c" + "timer_hal_iram.c" + ) + endif() endif() idf_component_register(SRCS ${srcs} diff --git a/components/hal/cache_hal.c b/components/hal/cache_hal.c index 04a5a006af..608fff08ef 100644 --- a/components/hal/cache_hal.c +++ b/components/hal/cache_hal.c @@ -26,6 +26,8 @@ #include "esp32h4/rom/cache.h" #elif CONFIG_IDF_TARGET_ESP32C6 #include "esp32c6/rom/cache.h" +#elif CONFIG_IDF_TARGET_ESP32H2 +#include "esp32h2/rom/cache.h" #endif /*------------------------------------------------------------------------------ diff --git a/components/hal/esp32h2/efuse_hal.c b/components/hal/esp32h2/efuse_hal.c index 44826a0fea..a967680eea 100644 --- a/components/hal/esp32h2/efuse_hal.c +++ b/components/hal/esp32h2/efuse_hal.c @@ -3,3 +3,91 @@ * * SPDX-License-Identifier: Apache-2.0 */ + +#include "sdkconfig.h" +#include +#include "soc/soc_caps.h" +#include "hal/assert.h" +#include "hal/efuse_hal.h" +#include "hal/efuse_ll.h" + +#define ESP_EFUSE_BLOCK_ERROR_BITS(error_reg, block) ((error_reg) & (0x08 << (4 * (block)))) +#define ESP_EFUSE_BLOCK_ERROR_NUM_BITS(error_reg, block) ((error_reg) & (0x07 << (4 * (block)))) + +uint32_t efuse_hal_get_major_chip_version(void) +{ + return efuse_ll_get_chip_wafer_version_major(); +} + +uint32_t efuse_hal_get_minor_chip_version(void) +{ + return efuse_ll_get_chip_wafer_version_minor(); +} + +/******************* eFuse control functions *************************/ + +void efuse_hal_set_timing(uint32_t apb_freq_hz) +{ + (void) apb_freq_hz; + efuse_ll_set_pwr_off_num(0x190); +} + +void efuse_hal_read(void) +{ + efuse_hal_set_timing(0); + + efuse_ll_set_conf_read_op_code(); + efuse_ll_set_read_cmd(); + + while (efuse_ll_get_read_cmd() != 0) { } + /*Due to a hardware error, we have to read READ_CMD again to make sure the efuse clock is normal*/ + while (efuse_ll_get_read_cmd() != 0) { } +} + +void efuse_hal_clear_program_registers(void) +{ + ets_efuse_clear_program_registers(); +} + +void efuse_hal_program(uint32_t block) +{ + efuse_hal_set_timing(0); + + efuse_ll_set_conf_write_op_code(); + efuse_ll_set_pgm_cmd(block); + + while (efuse_ll_get_pgm_cmd() != 0) { } + + efuse_hal_clear_program_registers(); + efuse_hal_read(); +} + +void efuse_hal_rs_calculate(const void *data, void *rs_values) +{ + ets_efuse_rs_calculate(data, rs_values); +} + +/******************* eFuse control functions *************************/ + +bool efuse_hal_is_coding_error_in_block(unsigned block) +{ + if (block == 0) { + for (unsigned i = 0; i < 5; i++) { + if (REG_READ(EFUSE_RD_REPEAT_ERR0_REG + i * 4)) { + return true; + } + } + } else if (block <= 10) { + // Fail bit (mask=0x8): + // EFUSE_RD_RS_ERR0_REG: (hi) BLOCK7, BLOCK6, BLOCK5, BLOCK4, BLOCK3, BLOCK2, BLOCK1, ------ (low) + // EFUSE_RD_RS_ERR1_REG: BLOCK9, BLOCK8 + // Error num bits (mask=0x7): + // EFUSE_RD_RS_ERR0_REG: (hi) BLOCK8, BLOCK7, BLOCK6, BLOCK5, BLOCK4, BLOCK3, BLOCK2, BLOCK1 (low) + // EFUSE_RD_RS_ERR1_REG: BLOCK10, BLOCK9 + // BLOCK10 is not presented in the error regs. + uint32_t err_fail_reg = REG_READ(EFUSE_RD_RS_ERR0_REG + (block / 8) * 4); + uint32_t err_num_reg = REG_READ(EFUSE_RD_RS_ERR0_REG + ((block - 1) / 8) * 4); + return (ESP_EFUSE_BLOCK_ERROR_BITS(err_fail_reg, block % 8) != 0) || (ESP_EFUSE_BLOCK_ERROR_NUM_BITS(err_num_reg, (block - 1) % 8) != 0); + } + return false; +} diff --git a/components/hal/esp32h2/include/.gitkeep b/components/hal/esp32h2/include/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/components/hal/esp32h2/include/hal/cache_ll.h b/components/hal/esp32h2/include/hal/cache_ll.h new file mode 100644 index 0000000000..63a95593cf --- /dev/null +++ b/components/hal/esp32h2/include/hal/cache_ll.h @@ -0,0 +1,197 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// The LL layer for Cache register operations + +#pragma once + +#include "soc/extmem_reg.h" +#include "soc/ext_mem_defs.h" +#include "hal/cache_types.h" +#include "hal/assert.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define CACHE_LL_DEFAULT_IBUS_MASK CACHE_BUS_IBUS0 +#define CACHE_LL_DEFAULT_DBUS_MASK CACHE_BUS_DBUS0 + +#define CACHE_LL_L1_ACCESS_EVENT_MASK (0x3f) +#define CACHE_LL_L1_ACCESS_EVENT_DBUS_WR_IC (1<<5) +#define CACHE_LL_L1_ACCESS_EVENT_DBUS_REJECT (1<<4) +#define CACHE_LL_L1_ACCESS_EVENT_DBUS_ACS_MSK_IC (1<<3) +#define CACHE_LL_L1_ACCESS_EVENT_IBUS_REJECT (1<<2) +#define CACHE_LL_L1_ACCESS_EVENT_IBUS_WR_IC (1<<1) +#define CACHE_LL_L1_ACCESS_EVENT_IBUS_ACS_MSK_IC (1<<0) + +#define CACHE_LL_L1_ILG_EVENT_MASK (0x23) +#define CACHE_LL_L1_ILG_EVENT_MMU_ENTRY_FAULT (1<<5) +#define CACHE_LL_L1_ILG_EVENT_PRELOAD_OP_FAULT (1<<1) +#define CACHE_LL_L1_ILG_EVENT_SYNC_OP_FAULT (1<<0) + + +/** + * @brief Get the buses of a particular cache that are mapped to a virtual address range + * + * External virtual address can only be accessed when the involved cache buses are enabled. + * This API is to get the cache buses where the memory region (from `vaddr_start` to `vaddr_start + len`) reside. + * + * @param cache_id cache ID (when l1 cache is per core) + * @param vaddr_start virtual address start + * @param len vaddr length + */ +#if !BOOTLOADER_BUILD +__attribute__((always_inline)) +#endif +static inline cache_bus_mask_t cache_ll_l1_get_bus(uint32_t cache_id, uint32_t vaddr_start, uint32_t len) +{ + HAL_ASSERT(cache_id == 0); + cache_bus_mask_t mask = 0; + + uint32_t vaddr_end = vaddr_start + len - 1; + if (vaddr_start >= IRAM0_CACHE_ADDRESS_LOW && vaddr_end < IRAM0_CACHE_ADDRESS_HIGH(CONFIG_MMU_PAGE_SIZE)) { + mask |= CACHE_BUS_IBUS0; + } else if (vaddr_start >= DRAM0_CACHE_ADDRESS_LOW && vaddr_end < DRAM0_CACHE_ADDRESS_HIGH(CONFIG_MMU_PAGE_SIZE)) { + mask |= CACHE_BUS_DBUS0; + } else { + HAL_ASSERT(0); //Out of region + } + + return mask; +} + +/** + * Enable the Cache Buses + * + * @param cache_id cache ID (when l1 cache is per core) + * @param mask To know which buses should be enabled + */ +#if !BOOTLOADER_BUILD +__attribute__((always_inline)) +#endif +static inline void cache_ll_l1_enable_bus(uint32_t cache_id, cache_bus_mask_t mask) +{ + HAL_ASSERT(cache_id == 0); + //On esp32h2, only `CACHE_BUS_IBUS0` and `CACHE_BUS_DBUS0` are supported. Use `cache_ll_l1_get_bus()` to get your bus first + HAL_ASSERT((mask & (CACHE_BUS_IBUS1 | CACHE_BUS_IBUS2| CACHE_BUS_DBUS1 | CACHE_BUS_DBUS2)) == 0); + + uint32_t ibus_mask = 0; + ibus_mask |= (mask & CACHE_BUS_IBUS0) ? EXTMEM_DCACHE_SHUT_DBUS0 : 0; + REG_CLR_BIT(EXTMEM_ICACHE_CTRL_REG, ibus_mask); + + uint32_t dbus_mask = 0; + dbus_mask |= (mask & CACHE_BUS_DBUS0) ? EXTMEM_DCACHE_SHUT_DBUS1 : 0; + REG_CLR_BIT(EXTMEM_ICACHE_CTRL_REG, dbus_mask); +} + +/** + * Disable the Cache Buses + * + * @param cache_id cache ID (when l1 cache is per core) + * @param mask To know which buses should be disabled + */ +__attribute__((always_inline)) +static inline void cache_ll_l1_disable_bus(uint32_t cache_id, cache_bus_mask_t mask) +{ + HAL_ASSERT(cache_id == 0); + //On esp32h2, only `CACHE_BUS_IBUS0` and `CACHE_BUS_DBUS0` are supported. Use `cache_ll_l1_get_bus()` to get your bus first + HAL_ASSERT((mask & (CACHE_BUS_IBUS1 | CACHE_BUS_IBUS2| CACHE_BUS_DBUS1 | CACHE_BUS_DBUS2)) == 0); + + uint32_t ibus_mask = 0; + ibus_mask |= (mask & CACHE_BUS_IBUS0) ? EXTMEM_DCACHE_SHUT_DBUS0 : 0; + REG_SET_BIT(EXTMEM_ICACHE_CTRL_REG, ibus_mask); + + uint32_t dbus_mask = 0; + dbus_mask |= (mask & CACHE_BUS_DBUS0) ? EXTMEM_DCACHE_SHUT_DBUS1 : 0; + REG_SET_BIT(EXTMEM_ICACHE_CTRL_REG, dbus_mask); +} + +/*------------------------------------------------------------------------------ + * Interrupt + *----------------------------------------------------------------------------*/ +/** + * @brief Enable Cache access error interrupt + * + * @param cache_id Cache ID, not used on H2. For compabitlity + * @param mask Interrupt mask + */ +static inline void cache_ll_l1_enable_access_error_intr(uint32_t cache_id, uint32_t mask) +{ + // ESP32H2-TODO + // SET_PERI_REG_MASK(EXTMEM_CORE0_ACS_CACHE_INT_ENA_REG, mask); +} + +/** + * @brief Clear Cache access error interrupt status + * + * @param cache_id Cache ID, not used on H2. For compabitlity + * @param mask Interrupt mask + */ +static inline void cache_ll_l1_clear_access_error_intr(uint32_t cache_id, uint32_t mask) +{ + // ESP32H2-TODO: IDF-6255 + // SET_PERI_REG_MASK(EXTMEM_CORE0_ACS_CACHE_INT_CLR_REG, mask); +} + +/** + * @brief Get Cache access error interrupt status + * + * @param cache_id Cache ID, not used on H2. For compabitlity + * @param mask Interrupt mask + * + * @return Status mask + */ +static inline uint32_t cache_ll_l1_get_access_error_intr_status(uint32_t cache_id, uint32_t mask) +{ + // ESP32H2-TODO: IDF-6255 + // return GET_PERI_REG_MASK(EXTMEM_CORE0_ACS_CACHE_INT_ST_REG, mask); + return 0; +} + +/** + * @brief Enable Cache illegal error interrupt + * + * @param cache_id Cache ID, not used on H2. For compabitlity + * @param mask Interrupt mask + */ +static inline void cache_ll_l1_enable_illegal_error_intr(uint32_t cache_id, uint32_t mask) +{ + // ESP32H2-TODO: IDF-6255 + // SET_PERI_REG_MASK(EXTMEM_CACHE_ILG_INT_ENA_REG, mask); +} + +/** + * @brief Clear Cache illegal error interrupt status + * + * @param cache_id Cache ID, not used on H2. For compabitlity + * @param mask Interrupt mask + */ +static inline void cache_ll_l1_clear_illegal_error_intr(uint32_t cache_id, uint32_t mask) +{ + // ESP32H2-TODO: IDF-6255 + // SET_PERI_REG_MASK(EXTMEM_CACHE_ILG_INT_CLR_REG, mask); +} + +/** + * @brief Get Cache illegal error interrupt status + * + * @param cache_id Cache ID, not used on H2. For compabitlity + * @param mask Interrupt mask + * + * @return Status mask + */ +static inline uint32_t cache_ll_l1_get_illegal_error_intr_status(uint32_t cache_id, uint32_t mask) +{ + // ESP32H2-TODO: IDF-6255 + // return GET_PERI_REG_MASK(EXTMEM_CACHE_ILG_INT_ST_REG, mask); + return 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/clk_gate_ll.h b/components/hal/esp32h2/include/hal/clk_gate_ll.h new file mode 100644 index 0000000000..c82a998091 --- /dev/null +++ b/components/hal/esp32h2/include/hal/clk_gate_ll.h @@ -0,0 +1,322 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "soc/periph_defs.h" +#include "soc/pcr_reg.h" +#include "soc/dport_access.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph) +{// ESP32H2-TODO: IDF-6400 + switch (periph) { + case PERIPH_SARADC_MODULE: + return PCR_SARADC_CLK_EN; + case PERIPH_RMT_MODULE: + return PCR_RMT_CLK_EN; + case PERIPH_LEDC_MODULE: + return PCR_LEDC_CLK_EN; + case PERIPH_UART0_MODULE: + return PCR_UART0_CLK_EN; + case PERIPH_UART1_MODULE: + return PCR_UART1_CLK_EN; + case PERIPH_I2C0_MODULE: + return PCR_I2C0_CLK_EN; + case PERIPH_I2C1_MODULE: + return PCR_I2C1_CLK_EN; + case PERIPH_I2S1_MODULE: + return PCR_I2S_CLK_EN; + case PERIPH_TIMG0_MODULE: + return PCR_TG0_CLK_EN; + case PERIPH_TIMG1_MODULE: + return PCR_TG1_CLK_EN; + case PERIPH_UHCI0_MODULE: + return PCR_UHCI_CLK_EN; + case PERIPH_SYSTIMER_MODULE: + return PCR_SYSTIMER_CLK_EN; + case PERIPH_SPI_MODULE: + return PCR_MSPI_CLK_EN; + case PERIPH_SPI2_MODULE: + return PCR_SPI2_CLK_EN; + case PERIPH_TWAI0_MODULE: + return PCR_TWAI0_CLK_EN; + case PERIPH_GDMA_MODULE: + return PCR_GDMA_CLK_EN; + case PERIPH_AES_MODULE: + return PCR_AES_CLK_EN; + case PERIPH_SHA_MODULE: + return PCR_SHA_CLK_EN; + case PERIPH_RSA_MODULE: + return PCR_RSA_CLK_EN; + case PERIPH_HMAC_MODULE: + return PCR_HMAC_CLK_EN; + case PERIPH_DS_MODULE: + return PCR_DS_CLK_EN; + // case PERIPH_RNG_MODULE: + // return PCR_WIFI_CLK_RNG_EN; + // case PERIPH_WIFI_MODULE: + // return PCR_WIFI_CLK_WIFI_EN_M; + // case PERIPH_BT_MODULE: + // return PCR_WIFI_CLK_BT_EN_M; + // case PERIPH_WIFI_BT_COMMON_MODULE: + // return PCR_WIFI_CLK_WIFI_BT_COMMON_M; + // case PERIPH_BT_BASEBAND_MODULE: + // return PCR_BT_BASEBAND_EN; + // case PERIPH_BT_LC_MODULE: + // return PCR_BT_LC_EN; + default: + return 0; + } +} + +static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool enable) +{ +// ESP32H2-TODO: IDF-6400 + (void)enable; // unused + + switch (periph) { + case PERIPH_SARADC_MODULE: + return PCR_SARADC_RST_EN; + case PERIPH_RMT_MODULE: + return PCR_RMT_RST_EN; + case PERIPH_LEDC_MODULE: + return PCR_LEDC_RST_EN; + case PERIPH_UART0_MODULE: + return PCR_UART0_RST_EN; + case PERIPH_UART1_MODULE: + return PCR_UART1_RST_EN; + case PERIPH_I2C0_MODULE: + return PCR_I2C0_RST_EN; + case PERIPH_I2C1_MODULE: + return PCR_I2C1_RST_EN; + case PERIPH_I2S1_MODULE: + return PCR_I2S_RST_EN; + case PERIPH_TIMG0_MODULE: + return PCR_TG0_RST_EN; + case PERIPH_TIMG1_MODULE: + return PCR_TG1_RST_EN; + case PERIPH_UHCI0_MODULE: + return PCR_UHCI_RST_EN; + case PERIPH_SYSTIMER_MODULE: + return PCR_SYSTIMER_RST_EN; + case PERIPH_SPI_MODULE: + return PCR_MSPI_RST_EN; + case PERIPH_SPI2_MODULE: + return PCR_SPI2_RST_EN; + case PERIPH_TWAI0_MODULE: + return PCR_TWAI0_RST_EN; + case PERIPH_GDMA_MODULE: + return PCR_GDMA_RST_EN; + case PERIPH_AES_MODULE: + if (enable == true) { + // Clear reset on digital signature, otherwise AES unit is held in reset also. + return (PCR_AES_RST_EN | PCR_DS_RST_EN); + } else { + //Don't return other units to reset, as this pulls reset on RSA & SHA units, respectively. + return PCR_AES_RST_EN; + } + case PERIPH_SHA_MODULE: + if (enable == true) { + // Clear reset on digital signature and HMAC, otherwise SHA is held in reset + return (PCR_SHA_RST_EN | PCR_DS_RST_EN | PCR_HMAC_RST_EN); + } else { + // Don't assert reset on secure boot, otherwise AES is held in reset + return PCR_SHA_RST_EN; + } + case PERIPH_RSA_MODULE: + if (enable == true) { + /* also clear reset on digital signature, otherwise RSA is held in reset */ + return (PCR_RSA_RST_EN | PCR_DS_RST_EN); + } else { + /* don't reset digital signature unit, as this resets AES also */ + return PCR_RSA_RST_EN; + } + case PERIPH_HMAC_MODULE: + return PCR_HMAC_RST_EN; + case PERIPH_DS_MODULE: + return PCR_DS_RST_EN; + // case PERIPH_RNG_MODULE: + // return PCR_WIFI_CLK_RNG_EN; + // case PERIPH_WIFI_MODULE: + // return PCR_WIFI_CLK_WIFI_EN_M; + // case PERIPH_BT_MODULE: + // return PCR_WIFI_CLK_BT_EN_M; + // case PERIPH_WIFI_BT_COMMON_MODULE: + // return PCR_WIFI_CLK_WIFI_BT_COMMON_M; + // case PERIPH_BT_BASEBAND_MODULE: + // return PCR_BT_BASEBAND_EN; + // case PERIPH_BT_LC_MODULE: + // return PCR_BT_LC_EN; + default: + return 0; + } +} + +static uint32_t periph_ll_get_clk_en_reg(periph_module_t periph) +{// ESP32H2-TODO: IDF-6400 + switch (periph) { + // case PERIPH_RNG_MODULE: + // case PERIPH_WIFI_MODULE: + // case PERIPH_BT_MODULE: + // case PERIPH_WIFI_BT_COMMON_MODULE: + // case PERIPH_BT_BASEBAND_MODULE: + // case PERIPH_BT_LC_MODULE: + // return SYSTEM_WIFI_CLK_EN_REG; + + case PERIPH_SARADC_MODULE: + return PCR_SARADC_CONF_REG; + case PERIPH_RMT_MODULE: + return PCR_RMT_CONF_REG; + case PERIPH_LEDC_MODULE: + return PCR_LEDC_CONF_REG; + case PERIPH_UART0_MODULE: + return PCR_UART0_CONF_REG; + case PERIPH_UART1_MODULE: + return PCR_UART1_CONF_REG; + case PERIPH_I2C0_MODULE: + return PCR_I2C0_CONF_REG; + case PERIPH_I2C1_MODULE: + return PCR_I2C1_CONF_REG; + case PERIPH_I2S1_MODULE: + return PCR_I2S_CONF_REG; + case PERIPH_TIMG0_MODULE: + return PCR_TIMERGROUP0_CONF_REG; + case PERIPH_TIMG1_MODULE: + return PCR_TIMERGROUP1_CONF_REG; + case PERIPH_UHCI0_MODULE: + return PCR_UHCI_CONF_REG; + case PERIPH_SYSTIMER_MODULE: + return PCR_SYSTIMER_CONF_REG; + case PERIPH_SPI_MODULE: + return PCR_MSPI_CONF_REG; + case PERIPH_SPI2_MODULE: + return PCR_SPI2_CONF_REG; + case PERIPH_TWAI0_MODULE: + return PCR_TWAI0_CONF_REG; + case PERIPH_GDMA_MODULE: + return PCR_GDMA_CONF_REG; + case PERIPH_AES_MODULE: + return PCR_AES_CONF_REG; + case PERIPH_SHA_MODULE: + return PCR_SHA_CONF_REG; + case PERIPH_RSA_MODULE: + return PCR_RSA_CONF_REG; + case PERIPH_HMAC_MODULE: + return PCR_HMAC_CONF_REG; + case PERIPH_DS_MODULE: + return PCR_DS_CONF_REG; + default: + return 0; + } +} + +static uint32_t periph_ll_get_rst_en_reg(periph_module_t periph) +{ + // ESP32H2-TODO: IDF-6400 + switch (periph) { + case PERIPH_SARADC_MODULE: + return PCR_SARADC_CONF_REG; + case PERIPH_RMT_MODULE: + return PCR_RMT_CONF_REG; + case PERIPH_LEDC_MODULE: + return PCR_LEDC_CONF_REG; + case PERIPH_UART0_MODULE: + return PCR_UART0_CONF_REG; + case PERIPH_UART1_MODULE: + return PCR_UART1_CONF_REG; + case PERIPH_I2C0_MODULE: + return PCR_I2C0_CONF_REG; + case PERIPH_I2C1_MODULE: + return PCR_I2C1_CONF_REG; + case PERIPH_I2S1_MODULE: + return PCR_I2S_CONF_REG; + case PERIPH_TIMG0_MODULE: + return PCR_TIMERGROUP0_CONF_REG; + case PERIPH_TIMG1_MODULE: + return PCR_TIMERGROUP1_CONF_REG; + case PERIPH_UHCI0_MODULE: + return PCR_UHCI_CONF_REG; + case PERIPH_SYSTIMER_MODULE: + return PCR_SYSTIMER_CONF_REG; + case PERIPH_SPI_MODULE: + return PCR_MSPI_CONF_REG; + case PERIPH_SPI2_MODULE: + return PCR_SPI2_CONF_REG; + case PERIPH_TWAI0_MODULE: + return PCR_TWAI0_CONF_REG; + case PERIPH_GDMA_MODULE: + return PCR_GDMA_CONF_REG; + case PERIPH_AES_MODULE: + return PCR_AES_CONF_REG; + case PERIPH_SHA_MODULE: + return PCR_SHA_CONF_REG; + case PERIPH_RSA_MODULE: + return PCR_RSA_CONF_REG; + case PERIPH_HMAC_MODULE: + return PCR_HMAC_CONF_REG; + case PERIPH_DS_MODULE: + return PCR_DS_CONF_REG; + default: + return 0; + } +} + +static inline void periph_ll_enable_clk_clear_rst(periph_module_t periph) +{ + DPORT_SET_PERI_REG_MASK(periph_ll_get_clk_en_reg(periph), periph_ll_get_clk_en_mask(periph)); + DPORT_CLEAR_PERI_REG_MASK(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, true)); +} + +static inline void periph_ll_disable_clk_set_rst(periph_module_t periph) +{ + DPORT_CLEAR_PERI_REG_MASK(periph_ll_get_clk_en_reg(periph), periph_ll_get_clk_en_mask(periph)); + DPORT_SET_PERI_REG_MASK(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, false)); +} + +static inline void periph_ll_wifi_bt_module_enable_clk_clear_rst(void) +{ + // DPORT_SET_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M);// ESP32H2-TODO: IDF-6400 + // DPORT_CLEAR_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, 0); +} + +static inline void periph_ll_wifi_bt_module_disable_clk_set_rst(void) +{ + // DPORT_CLEAR_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M);// ESP32H2-TODO: IDF-6400 + // DPORT_SET_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, 0); +} + +static inline void periph_ll_reset(periph_module_t periph) +{ + DPORT_SET_PERI_REG_MASK(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, false)); + DPORT_CLEAR_PERI_REG_MASK(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, false)); +} + +static inline bool periph_ll_periph_enabled(periph_module_t periph) +{ + return DPORT_REG_GET_BIT(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, false)) == 0 && + DPORT_REG_GET_BIT(periph_ll_get_clk_en_reg(periph), periph_ll_get_clk_en_mask(periph)) != 0; +} + +static inline void periph_ll_wifi_module_enable_clk_clear_rst(void) +{ + // DPORT_SET_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_WIFI_EN_M);// ESP32H2-TODO: IDF-6400 + // DPORT_CLEAR_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, 0); +} + +static inline void periph_ll_wifi_module_disable_clk_set_rst(void) +{ + // DPORT_CLEAR_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_WIFI_EN_M);// ESP32H2-TODO: IDF-6400 + // DPORT_SET_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, 0); +} +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/clk_tree_ll.h b/components/hal/esp32h2/include/hal/clk_tree_ll.h new file mode 100644 index 0000000000..36055eef6c --- /dev/null +++ b/components/hal/esp32h2/include/hal/clk_tree_ll.h @@ -0,0 +1,568 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "soc/soc.h" +#include "soc/clk_tree_defs.h" +#include "soc/rtc.h" +#include "soc/pcr_reg.h" +#include "hal/regi2c_ctrl.h" +#include "soc/regi2c_bbpll.h" +#include "hal/assert.h" +#include "hal/log.h" +#include "esp32h2/rom/rtc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MHZ (1000000) + +#define CLK_LL_PLL_80M_FREQ_MHZ (80) +#define CLK_LL_PLL_160M_FREQ_MHZ (160) + +#define CLK_LL_PLL_320M_FREQ_MHZ (320) +#define CLK_LL_PLL_480M_FREQ_MHZ (480) + +#define CLK_LL_XTAL32K_CONFIG_DEFAULT() { \ + .dac = 3, \ + .dres = 3, \ + .dgm = 3, \ + .dbuf = 1, \ +} + +/** + * @brief XTAL32K_CLK enable modes + */ +typedef enum { + CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL, //!< Enable the external 32kHz crystal for XTAL32K_CLK + CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL, //!< Enable the external clock signal for XTAL32K_CLK + CLK_LL_XTAL32K_ENABLE_MODE_BOOTSTRAP, //!< Bootstrap the crystal oscillator for faster XTAL32K_CLK start up */ +} clk_ll_xtal32k_enable_mode_t; + +/** + * @brief XTAL32K_CLK configuration structure + */ +typedef struct { + uint32_t dac : 6; + uint32_t dres : 3; + uint32_t dgm : 3; + uint32_t dbuf: 1; +} clk_ll_xtal32k_config_t; + +/** + * @brief Power up BBPLL circuit + */ +static inline __attribute__((always_inline)) void clk_ll_bbpll_enable(void) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Power down BBPLL circuit + */ +static inline __attribute__((always_inline)) void clk_ll_bbpll_disable(void) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Enable the 32kHz crystal oscillator + * + * @param mode Used to determine the xtal32k configuration parameters + */ +static inline void clk_ll_xtal32k_enable(clk_ll_xtal32k_enable_mode_t mode) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Disable the 32kHz crystal oscillator + */ +static inline void clk_ll_xtal32k_disable(void) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Get the state of the 32kHz crystal clock + * + * @return True if the 32kHz XTAL is enabled + */ +static inline bool clk_ll_xtal32k_is_enabled(void) +{ + // ESP32H2-TODO: IDF-6401 + return 0; +} + +/** + * @brief Enable the internal oscillator output for RC_FAST_CLK + */ +static inline __attribute__((always_inline)) void clk_ll_rc_fast_enable(void) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Disable the internal oscillator output for RC_FAST_CLK + */ +static inline __attribute__((always_inline)) void clk_ll_rc_fast_disable(void) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Get the state of the internal oscillator for RC_FAST_CLK + * + * @return True if the oscillator is enabled + */ +static inline bool clk_ll_rc_fast_is_enabled(void) +{ + // ESP32H2-TODO: IDF-6401 + return 1; +} + +/** + * @brief Enable the output from the internal oscillator to be passed into a configurable divider, + * which by default divides the input clock frequency by 256. i.e. RC_FAST_D256_CLK = RC_FAST_CLK / 256 + * + * Divider values other than 256 may be configured, but this facility is not currently needed, + * so is not exposed in the code. + * The output of the divider, RC_FAST_D256_CLK, is referred as 8md256 or simply d256 in reg. descriptions. + */ +static inline void clk_ll_rc_fast_d256_enable(void) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Disable the output from the internal oscillator to be passed into a configurable divider. + * i.e. RC_FAST_D256_CLK = RC_FAST_CLK / 256 + * + * Disabling this divider could reduce power consumption. + */ +static inline void clk_ll_rc_fast_d256_disable(void) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Get the state of the divider which is applied to the output from the internal oscillator (RC_FAST_CLK) + * + * @return True if the divided output is enabled + */ +static inline bool clk_ll_rc_fast_d256_is_enabled(void) +{ + // ESP32H2-TODO: IDF-6401 + return 1; +} + +/** + * @brief Enable the digital RC_FAST_CLK, which is used to support peripherals. + */ +static inline void clk_ll_rc_fast_digi_enable(void) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Disable the digital RC_FAST_CLK, which is used to support peripherals. + */ +static inline void clk_ll_rc_fast_digi_disable(void) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Get the state of the digital RC_FAST_CLK + * + * @return True if the digital RC_FAST_CLK is enabled + */ +static inline bool clk_ll_rc_fast_digi_is_enabled(void) +{ + // ESP32H2-TODO: IDF-6401 + return 0; +} + +/** + * @brief Enable the digital RC_FAST_D256_CLK, which is used to support peripherals. + */ +static inline void clk_ll_rc_fast_d256_digi_enable(void) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Disable the digital RC_FAST_D256_CLK, which is used to support peripherals. + */ +static inline void clk_ll_rc_fast_d256_digi_disable(void) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Enable the digital XTAL32K_CLK, which is used to support peripherals. + */ +static inline void clk_ll_xtal32k_digi_enable(void) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Disable the digital XTAL32K_CLK, which is used to support peripherals. + */ +static inline void clk_ll_xtal32k_digi_disable(void) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Get the state of the digital XTAL32K_CLK + * + * @return True if the digital XTAL32K_CLK is enabled + */ +static inline bool clk_ll_xtal32k_digi_is_enabled(void) +{ + // ESP32H2-TODO: IDF-6401 + return 0; +} + +/** + * @brief Get PLL_CLK frequency + * + * @return PLL clock frequency, in MHz. Returns 0 if register field value is invalid. + */ +static inline __attribute__((always_inline)) uint32_t clk_ll_bbpll_get_freq_mhz(void) +{ + // ESP32H2-TODO: IDF-6401 + return 0; +} + +/** + * @brief Set BBPLL frequency from XTAL source (Digital part) + * + * @param pll_freq_mhz PLL frequency, in MHz + */ +static inline __attribute__((always_inline)) void clk_ll_bbpll_set_freq_mhz(uint32_t pll_freq_mhz) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Set BBPLL frequency from XTAL source (Analog part) + * + * @param pll_freq_mhz PLL frequency, in MHz + * @param xtal_freq_mhz XTAL frequency, in MHz + */ +static inline __attribute__((always_inline)) void clk_ll_bbpll_set_config(uint32_t pll_freq_mhz, uint32_t xtal_freq_mhz) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Select the clock source for CPU_CLK + * + * @param in_sel One of the clock sources in soc_cpu_clk_src_t + */ +static inline __attribute__((always_inline)) void clk_ll_cpu_set_src(soc_cpu_clk_src_t in_sel) +{ + // ESP32H2-TODO: IDF-6401 + switch (in_sel) { + case SOC_CPU_CLK_SRC_XTAL: + REG_SET_FIELD(PCR_SYSCLK_CONF_REG, PCR_SOC_CLK_SEL, 0); + break; + case SOC_CPU_CLK_SRC_PLL: + REG_SET_FIELD(PCR_SYSCLK_CONF_REG, PCR_SOC_CLK_SEL, 1); + break; + case SOC_CPU_CLK_SRC_RC_FAST://FOSC + REG_SET_FIELD(PCR_SYSCLK_CONF_REG, PCR_SOC_CLK_SEL, 2); + break; + default: + // Unsupported CPU_CLK mux input sel + abort(); + } +} + +/** + * @brief Get the clock source for CPU_CLK + * + * @return Currently selected clock source (one of soc_cpu_clk_src_t values) + */ +static inline __attribute__((always_inline)) soc_cpu_clk_src_t clk_ll_cpu_get_src(void) +{ + // ESP32H2-TODO: IDF-6401 + uint32_t clk_sel = REG_GET_FIELD(PCR_SYSCLK_CONF_REG, PCR_SOC_CLK_SEL); + switch (clk_sel) { + case 0: + return SOC_CPU_CLK_SRC_XTAL; + case 1: + return SOC_CPU_CLK_SRC_PLL; + case 2://FOSC + return SOC_CPU_CLK_SRC_RC_FAST; + default: + // Invalid SOC_CLK_SEL value + return SOC_CPU_CLK_SRC_INVALID; + } +} + +#include "hal/uart_types.h" +static inline __attribute__((always_inline)) void clk_ll_uart_set_sclk(uint32_t uart_num, uart_sclk_t source_clk) +{ + // switch (source_clk) { + // default: + // case UART_SCLK_APB: + // REG_SET_FIELD(PCR_UART_SCLK_CONF_REG(uart_num), PCR_UART0_SCLK_SEL, 1); + // break; + // case UART_SCLK_RTC: + // REG_SET_FIELD(PCR_UART_SCLK_CONF_REG(uart_num), PCR_UART0_SCLK_SEL, 2); + // break; + // case UART_SCLK_XTAL: + // REG_SET_FIELD(PCR_UART_SCLK_CONF_REG(uart_num), PCR_UART0_SCLK_SEL, 3); + // break; + // } +} + +static inline __attribute__((always_inline)) void clk_ll_uart_get_sclk(uint32_t uart_num, uart_sclk_t *source_clk) +{ + // switch (REG_GET_FIELD(PCR_UART_SCLK_CONF_REG(uart_num), PCR_UART0_SCLK_SEL)) { + // default: + // case 1: + // *source_clk = UART_SCLK_APB; + // break; + // case 2: + // *source_clk = UART_SCLK_RTC; + // break; + // case 3: + // *source_clk = UART_SCLK_XTAL; + // break; + // } +} + +static inline uint32_t clk_ll_get_uart_sclk_freq(uint32_t uart_num) +{ + // switch (REG_GET_FIELD(PCR_UART_SCLK_CONF_REG(uart_num), PCR_UART0_SCLK_SEL)) { + // default: + // case 1: + // return APB_CLK_FREQ; + // case 2: + // return RTC_CLK_FREQ; + // case 3: + // return XTAL_CLK_FREQ; + // } + return 0; +} + +static inline __attribute__((always_inline)) void clk_ll_uart_set_sclk_div_num(uint8_t uart_num, uint32_t val) +{ + // REG_SET_FIELD(PCR_UART_SCLK_CONF_REG(uart_num), PCR_UART0_SCLK_DIV_NUM, val); +} + +static inline __attribute__((always_inline)) uint32_t clk_ll_uart_get_sclk_div_num(uint8_t uart_num) +{ + return 0;//REG_GET_FIELD(PCR_UART_SCLK_CONF_REG(uart_num), PCR_UART0_SCLK_DIV_NUM); +} + +/** + * @brief Set CPU frequency from PLL clock + * + * @param cpu_mhz CPU frequency value, in MHz + */ +static inline __attribute__((always_inline)) void clk_ll_cpu_set_freq_mhz_from_pll(uint32_t cpu_mhz) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Get CPU_CLK frequency from PLL_CLK source + * + * @return CPU clock frequency, in MHz. Returns 0 if register field value is invalid. + */ +static inline __attribute__((always_inline)) uint32_t clk_ll_cpu_get_freq_mhz_from_pll(void) +{ + // ESP32H2-TODO: IDF-6401 + return 0; +} + +/** + * @brief Set CPU_CLK's XTAL/FAST_RC clock source path divider + * + * @param divider Divider. Usually this divider is set to 1 in bootloader stage. PRE_DIV_CNT = divider - 1. + */ +static inline __attribute__((always_inline)) void clk_ll_cpu_set_divider(uint32_t divider) +{ + // ESP32H2-TODO: IDF-6401: not configurable for 761, fixed at 3 for HS, 1 for LS +} + +/** + * @brief Get CPU_CLK's XTAL/FAST_RC clock source path divider + * + * @return Divider. Divider = (PRE_DIV_CNT + 1). + */ +static inline __attribute__((always_inline)) uint32_t clk_ll_cpu_get_divider(void) +{ + // ESP32H2-TODO: IDF-6401 + return 0; +} + +/** + * @brief Select the clock source for RTC_SLOW_CLK + * + * @param in_sel One of the clock sources in soc_rtc_slow_clk_src_t + */ +static inline void clk_ll_rtc_slow_set_src(soc_rtc_slow_clk_src_t in_sel) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Get the clock source for RTC_SLOW_CLK + * + * @return Currently selected clock source (one of soc_rtc_slow_clk_src_t values) + */ +static inline soc_rtc_slow_clk_src_t clk_ll_rtc_slow_get_src(void) +{ + // ESP32H2-TODO: IDF-6401 + return 0; +} + +/** + * @brief Select the clock source for RTC_FAST_CLK + * + * @param in_sel One of the clock sources in soc_rtc_fast_clk_src_t + */ +static inline void clk_ll_rtc_fast_set_src(soc_rtc_fast_clk_src_t in_sel) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Get the clock source for RTC_FAST_CLK + * + * @return Currently selected clock source (one of soc_rtc_fast_clk_src_t values) + */ +static inline soc_rtc_fast_clk_src_t clk_ll_rtc_fast_get_src(void) +{ + // ESP32H2-TODO: IDF-6401 + return 0; +} + +/** + * @brief Set RC_FAST_CLK divider. The output from the divider is passed into rtc_fast_clk MUX. + * + * @param divider Divider of RC_FAST_CLK. Usually this divider is set to 1 (reg. value is 0) in bootloader stage. + */ +static inline void clk_ll_rc_fast_set_divider(uint32_t divider) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Get RC_FAST_CLK divider + * + * @return Divider. Divider = (CK8M_DIV_SEL + 1). + */ +static inline uint32_t clk_ll_rc_fast_get_divider(void) +{ + // ESP32H2-TODO: IDF-6401 + return 0; +} + +/** + * @brief Set RC_SLOW_CLK divider + * + * @param divider Divider of RC_SLOW_CLK. Usually this divider is set to 1 (reg. value is 0) in bootloader stage. + */ +static inline void clk_ll_rc_slow_set_divider(uint32_t divider) +{ + // ESP32H2-TODO: IDF-6401 +} + +/************************* RTC STORAGE REGISTER STORE/LOAD **************************/ +/** + * @brief Store XTAL_CLK frequency in RTC storage register + * + * Value of RTC_XTAL_FREQ_REG is stored as two copies in lower and upper 16-bit + * halves. These are the routines to work with that representation. + * + * @param xtal_freq_mhz XTAL frequency, in MHz + */ +static inline void clk_ll_xtal_store_freq_mhz(uint32_t xtal_freq_mhz) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Load XTAL_CLK frequency from RTC storage register + * + * Value of RTC_XTAL_FREQ_REG is stored as two copies in lower and upper 16-bit + * halves. These are the routines to work with that representation. + * + * @return XTAL frequency, in MHz. Returns 0 if value in reg is invalid. + */ +static inline __attribute__((always_inline)) uint32_t clk_ll_xtal_load_freq_mhz(void) +{ + // ESP32H2-TODO: IDF-6401 + return 0; +} + +/** + * @brief Store APB_CLK frequency in RTC storage register + * + * Value of RTC_APB_FREQ_REG is stored as two copies in lower and upper 16-bit + * halves. These are the routines to work with that representation. + * + * @param apb_freq_hz APB frequency, in Hz + */ +static inline __attribute__((always_inline)) void clk_ll_apb_store_freq_hz(uint32_t apb_freq_hz) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Load APB_CLK frequency from RTC storage register + * + * Value of RTC_APB_FREQ_REG is stored as two copies in lower and upper 16-bit + * halves. These are the routines to work with that representation. + * + * @return The stored APB frequency, in Hz + */ +static inline uint32_t clk_ll_apb_load_freq_hz(void) +{ + // ESP32H2-TODO: IDF-6401 + return 0; +} + +/** + * @brief Store RTC_SLOW_CLK calibration value in RTC storage register + * + * Value of RTC_SLOW_CLK_CAL_REG has to be in the same format as returned by rtc_clk_cal (microseconds, + * in Q13.19 fixed-point format). + * + * @param cal_value The calibration value of slow clock period in microseconds, in Q13.19 fixed point format + */ +static inline void clk_ll_rtc_slow_store_cal(uint32_t cal_value) +{ + // ESP32H2-TODO: IDF-6401 +} + +/** + * @brief Load the calibration value of RTC_SLOW_CLK frequency from RTC storage register + * + * This value gets updated (i.e. rtc slow clock gets calibrated) every time RTC_SLOW_CLK source switches + * + * @return The calibration value of slow clock period in microseconds, in Q13.19 fixed point format + */ +static inline uint32_t clk_ll_rtc_slow_load_cal(void) +{ + // ESP32H2-TODO: IDF-6401 + return 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/efuse_hal.h b/components/hal/esp32h2/include/hal/efuse_hal.h new file mode 100644 index 0000000000..b6c83d6da6 --- /dev/null +++ b/components/hal/esp32h2/include/hal/efuse_hal.h @@ -0,0 +1,69 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "soc/soc_caps.h" +#include "hal/efuse_ll.h" +#include_next "hal/efuse_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @brief get chip version + */ +uint32_t efuse_hal_get_chip_revision(void); + +/** + * @brief set eFuse timings + * + * @param apb_freq_hz APB frequency in Hz + */ +void efuse_hal_set_timing(uint32_t apb_freq_hz); + +/** + * @brief trigger eFuse read operation + */ +void efuse_hal_read(void); + +/** + * @brief clear registers for programming eFuses + */ +void efuse_hal_clear_program_registers(void); + +/** + * @brief burn eFuses written in programming registers (one block at once) + * + * @param block block number + */ +void efuse_hal_program(uint32_t block); + +/** + * @brief Calculate Reed-Solomon Encoding values for a block of efuse data. + * + * @param data Pointer to data buffer (length 32 bytes) + * @param rs_values Pointer to write encoded data to (length 12 bytes) + */ +void efuse_hal_rs_calculate(const void *data, void *rs_values); + +/** + * @brief Checks coding error in a block + * + * @param block Index of efuse block + * + * @return True - block has an error. + * False - no error. + */ +bool efuse_hal_is_coding_error_in_block(unsigned block); + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/efuse_ll.h b/components/hal/esp32h2/include/hal/efuse_ll.h new file mode 100644 index 0000000000..4de9295508 --- /dev/null +++ b/components/hal/esp32h2/include/hal/efuse_ll.h @@ -0,0 +1,129 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "soc/efuse_periph.h" +#include "hal/assert.h" +#include "esp32h2/rom/efuse.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Always inline these functions even no gcc optimization is applied. + +//// ESP32H2-TODO: efuse support IDF-6252 + +/******************* eFuse fields *************************/ + +__attribute__((always_inline)) static inline uint32_t efuse_ll_get_flash_crypt_cnt(void) +{ + return 0;//EFUSE.rd_repeat_data1.spi_boot_crypt_cnt; +} + +__attribute__((always_inline)) static inline uint32_t efuse_ll_get_wdt_delay_sel(void) +{ + return 0;//EFUSE.rd_repeat_data1.wdt_delay_sel; +} + +__attribute__((always_inline)) static inline uint32_t efuse_ll_get_mac0(void) +{ + return 0;//EFUSE.rd_mac_sys_0; +} + +__attribute__((always_inline)) static inline uint32_t efuse_ll_get_mac1(void) +{ + return 0;//EFUSE.rd_mac_sys_1.mac_1; +} + +__attribute__((always_inline)) static inline bool efuse_ll_get_secure_boot_v2_en(void) +{ + return 0;//EFUSE.rd_repeat_data2.secure_boot_en; +} + +// use efuse_hal_get_major_chip_version() to get major chip version +__attribute__((always_inline)) static inline uint32_t efuse_ll_get_chip_wafer_version_major(void) +{ + return 0;//EFUSE.rd_mac_sys_5.wafer_version_major; +} + +// use efuse_hal_get_minor_chip_version() to get minor chip version +__attribute__((always_inline)) static inline uint32_t efuse_ll_get_chip_wafer_version_minor(void) +{ + return 0;//(EFUSE.rd_mac_sys_5.wafer_version_minor_high << 3) + EFUSE.rd_mac_sys_3.wafer_version_minor_low; +} + +__attribute__((always_inline)) static inline bool efuse_ll_get_disable_wafer_version_major(void) +{ + return 0;//EFUSE.rd_repeat_data4.disable_wafer_version_major; +} + +__attribute__((always_inline)) static inline uint32_t efuse_ll_get_blk_version_major(void) +{ + return 0;//EFUSE.rd_sys_part1_data4.blk_version_major; +} + +__attribute__((always_inline)) static inline uint32_t efuse_ll_get_blk_version_minor(void) +{ + return 0;//EFUSE.rd_mac_sys_3.blk_version_minor; +} + +__attribute__((always_inline)) static inline bool efuse_ll_get_disable_blk_version_major(void) +{ + return 0;//EFUSE.rd_repeat_data4.disable_blk_version_major; +} + +__attribute__((always_inline)) static inline uint32_t efuse_ll_get_chip_ver_pkg(void) +{ + return 0;//EFUSE.rd_mac_sys_3.pkg_version; +} + +/******************* eFuse control functions *************************/ + +__attribute__((always_inline)) static inline bool efuse_ll_get_read_cmd(void) +{ + return 0;//EFUSE.cmd.read_cmd; +} + +__attribute__((always_inline)) static inline bool efuse_ll_get_pgm_cmd(void) +{ + return 0;//EFUSE.cmd.pgm_cmd; +} + +__attribute__((always_inline)) static inline void efuse_ll_set_read_cmd(void) +{ + // EFUSE.cmd.read_cmd = 1; +} + +__attribute__((always_inline)) static inline void efuse_ll_set_pgm_cmd(uint32_t block) +{ + // HAL_ASSERT(block < ETS_EFUSE_BLOCK_MAX); + // EFUSE.cmd.val = ((block << EFUSE_BLK_NUM_S) & EFUSE_BLK_NUM_M) | EFUSE_PGM_CMD; +} + +__attribute__((always_inline)) static inline void efuse_ll_set_conf_read_op_code(void) +{ + // EFUSE.conf.op_code = EFUSE_READ_OP_CODE; +} + +__attribute__((always_inline)) static inline void efuse_ll_set_conf_write_op_code(void) +{ + // EFUSE.conf.op_code = EFUSE_WRITE_OP_CODE; +} + +__attribute__((always_inline)) static inline void efuse_ll_set_pwr_off_num(uint16_t value) +{ + // EFUSE.wr_tim_conf2.pwr_off_num = value; +} + +/******************* eFuse control functions *************************/ + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/gpio_ll.h b/components/hal/esp32h2/include/hal/gpio_ll.h new file mode 100644 index 0000000000..b8a5f7cf4d --- /dev/null +++ b/components/hal/esp32h2/include/hal/gpio_ll.h @@ -0,0 +1,615 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/******************************************************************************* + * NOTICE + * The hal is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The LL layer for ESP32-H2 GPIO register operations + +#pragma once + +#include "soc/soc.h" +#include "soc/gpio_periph.h" +#include "soc/gpio_struct.h" +#include "soc/lp_aon_reg.h" +#include "soc/pmu_reg.h" +#include "hal/gpio_types.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// ESP32H2-TODO: comment some code, please add support on gpio, IDF-6227 + +/* + * The following defines are used to disable USB JTAG when pins 18 and pins 19 + * are set to be used as GPIO. + * See gpio_pad_select_gpio() below. + * + * TODO: Delete these definitions once the USB device registers definition is + * merged. + */ +#define USB_DEVICE_CONF0_REG (0x60043018) +#define USB_DEVICE_USB_PAD_ENABLE (BIT(14)) + +// Get GPIO hardware instance with giving gpio num +#define GPIO_LL_GET_HW(num) (((num) == 0) ? (&GPIO) : NULL) + +#define GPIO_LL_PRO_CPU_INTR_ENA (BIT(0)) +#define GPIO_LL_PRO_CPU_NMI_INTR_ENA (BIT(1)) +/** + * @brief Enable pull-up on GPIO. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_pullup_en(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + REG_SET_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PU); +} + +/** + * @brief Disable pull-up on GPIO. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + REG_CLR_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PU); +} + +/** + * @brief Enable pull-down on GPIO. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_pulldown_en(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + REG_SET_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PD); +} + +/** + * @brief Disable pull-down on GPIO. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_pulldown_dis(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + REG_CLR_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PD); +} + +/** + * @brief GPIO set interrupt trigger type + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number. If you want to set the trigger type of e.g. of GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param intr_type Interrupt type, select from gpio_int_type_t + */ +static inline void gpio_ll_set_intr_type(gpio_dev_t *hw, gpio_num_t gpio_num, gpio_int_type_t intr_type) +{ + // hw->pin[gpio_num].int_type = intr_type; + // ESP32H2-TODO: IDF-6227 updated struct file not support yet +} + +/** + * @brief Get GPIO interrupt status + * + * @param hw Peripheral GPIO hardware instance address. + * @param core_id interrupt core id + * @param status interrupt status + */ +static inline void gpio_ll_get_intr_status(gpio_dev_t *hw, uint32_t core_id, uint32_t *status) +{ + *status = hw->pcpu_int.val; +} + +/** + * @brief Get GPIO interrupt status high + * + * @param hw Peripheral GPIO hardware instance address. + * @param core_id interrupt core id + * @param status interrupt status high + */ +static inline void gpio_ll_get_intr_status_high(gpio_dev_t *hw, uint32_t core_id, uint32_t *status) +{ + *status = 0; // Less than 32 GPIOs in ESP32-H2 +} + +/** + * @brief Clear GPIO interrupt status + * + * @param hw Peripheral GPIO hardware instance address. + * @param mask interrupt status clear mask + */ +static inline void gpio_ll_clear_intr_status(gpio_dev_t *hw, uint32_t mask) +{ + // hw->status_w1tc = mask; +} + +/** + * @brief Clear GPIO interrupt status high + * + * @param hw Peripheral GPIO hardware instance address. + * @param mask interrupt status high clear mask + */ +static inline void gpio_ll_clear_intr_status_high(gpio_dev_t *hw, uint32_t mask) +{ + // Not supported on H2 +} + +/** + * @brief Enable GPIO module interrupt signal + * + * @param hw Peripheral GPIO hardware instance address. + * @param core_id Interrupt enabled CPU to corresponding ID + * @param gpio_num GPIO number. If you want to enable the interrupt of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16); + */ +static inline void gpio_ll_intr_enable_on_core(gpio_dev_t *hw, uint32_t core_id, gpio_num_t gpio_num) +{ +// ESP32H2-TODO: IDF-6227 updated struct file not support yet +#if 0 + if (core_id == 0) { + GPIO.pin[gpio_num].int_ena = GPIO_LL_PRO_CPU_INTR_ENA; //enable pro cpu intr + } else { + // GPIO.pin[gpio_num].int_ena = GPIO_APP_CPU_INTR_ENA; //enable pro cpu intr + } +#endif +} + +/** + * @brief Disable GPIO module interrupt signal + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number. If you want to disable the interrupt of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16); + */ +static inline void gpio_ll_intr_disable(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + // ESP32H2-TODO: IDF-6227 updated struct file not support yet + // hw->pin[gpio_num].int_ena = 0; //disable GPIO intr +} + +/** + * @brief Disable input mode on GPIO. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_input_disable(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_num]); +} + +/** + * @brief Enable input mode on GPIO. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_input_enable(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]); +} + +/** + * @brief Disable output mode on GPIO. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_output_disable(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + // hw->enable_w1tc = (0x1 << gpio_num); + // // Ensure no other output signal is routed via GPIO matrix to this pin + // REG_WRITE(GPIO_FUNC0_OUT_SEL_CFG_REG + (gpio_num * 4), + // SIG_GPIO_OUT_IDX); +} + +/** + * @brief Enable output mode on GPIO. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_output_enable(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + // hw->enable_w1ts = (0x1 << gpio_num); +} + +/** + * @brief Disable open-drain mode on GPIO. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_od_disable(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + // ESP32H2-TODO: IDF-6227 updated struct file not support yet + // hw->pin[gpio_num].pad_driver = 0; +} + +/** + * @brief Enable open-drain mode on GPIO. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_od_enable(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + // ESP32H2-TODO: IDF-6227 updated struct file not support yet + // hw->pin[gpio_num].pad_driver = 1; +} + +/** + * @brief GPIO set output level + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number. If you want to set the output level of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param level Output level. 0: low ; 1: high + */ +static inline void gpio_ll_set_level(gpio_dev_t *hw, gpio_num_t gpio_num, uint32_t level) +{ + // if (level) { + // hw->out_w1ts = (1 << gpio_num); + // } else { + // hw->out_w1tc = (1 << gpio_num); + // } +} + +/** + * @brief GPIO get input level + * + * @warning If the pad is not configured for input (or input and output) the returned value is always 0. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number. If you want to get the logic level of e.g. pin GPIO16, gpio_num should be GPIO_NUM_16 (16); + * + * @return + * - 0 the GPIO input level is 0 + * - 1 the GPIO input level is 1 + */ +static inline int gpio_ll_get_level(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + return 0;//(hw->in >> gpio_num) & 0x1; +} + +/** + * @brief Enable GPIO wake-up function. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number. + * @param intr_type GPIO wake-up type. Only GPIO_INTR_LOW_LEVEL or GPIO_INTR_HIGH_LEVEL can be used. + */ +static inline void gpio_ll_wakeup_enable(gpio_dev_t *hw, gpio_num_t gpio_num) +{ +// ESP32H2-TODO: IDF-6227 updated struct file not support yet +#if 0 + hw->pin[gpio_num].int_type = intr_type; + hw->pin[gpio_num].wakeup_enable = 0x1; +#endif +} + +/** + * @brief Disable GPIO wake-up function. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_wakeup_disable(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + // ESP32H2-TODO: IDF-6227 updated struct file not support yet + // hw->pin[gpio_num].wakeup_enable = 0; +} + +/** + * @brief Set GPIO pad drive capability + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number, only support output GPIOs + * @param strength Drive capability of the pad + */ +static inline void gpio_ll_set_drive_capability(gpio_dev_t *hw, gpio_num_t gpio_num, gpio_drive_cap_t strength) +{ + SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[gpio_num], FUN_DRV_V, strength, FUN_DRV_S); +} + +/** + * @brief Get GPIO pad drive capability + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number, only support output GPIOs + * @param strength Pointer to accept drive capability of the pad + */ +static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, gpio_num_t gpio_num, gpio_drive_cap_t *strength) +{ + *strength = (gpio_drive_cap_t)GET_PERI_REG_BITS2(GPIO_PIN_MUX_REG[gpio_num], FUN_DRV_V, FUN_DRV_S); +} + +/** + * @brief Enable all digital gpio pad hold function during Deep-sleep. + * + * @param hw Peripheral GPIO hardware instance address. + */ +static inline void gpio_ll_deep_sleep_hold_en(gpio_dev_t *hw) +{ + // ESP32H2 has removed deepsleep and replace with software backup sleep +} + +/** + * @brief Disable all digital gpio pad hold function during Deep-sleep. + * + * @param hw Peripheral GPIO hardware instance address. + */ +static inline void gpio_ll_deep_sleep_hold_dis(gpio_dev_t *hw) +{ + // ESP32H2 has removed deepsleep and replace with software backup sleep +} + +/** + * @brief Enable gpio pad hold function. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number, only support output GPIOs + */ +static inline void gpio_ll_hold_en(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + if (gpio_num <32){ + SET_PERI_REG_MASK(LP_AON_GPIO_HOLD0_REG, GPIO_HOLD_MASK[gpio_num]); + } else if (gpio_num <= MAX_PAD_GPIO_NUM){ + SET_PERI_REG_MASK(LP_AON_GPIO_HOLD1_REG, GPIO_HOLD_MASK[gpio_num]); + } +} + +/** + * @brief Disable gpio pad hold function. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number, only support output GPIOs + */ +static inline void gpio_ll_hold_dis(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + if (gpio_num <32){ + CLEAR_PERI_REG_MASK(LP_AON_GPIO_HOLD0_REG, GPIO_HOLD_MASK[gpio_num]); + } else if (gpio_num <= MAX_PAD_GPIO_NUM){ + CLEAR_PERI_REG_MASK(LP_AON_GPIO_HOLD1_REG, GPIO_HOLD_MASK[gpio_num]); + } +} + +/** + * @brief Set pad input to a peripheral signal through the IOMUX. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number of the pad. + * @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``. + */ +static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx) +{ + hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0; + PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio]); +} + +/** + * @brief Select a function for the pin in the IOMUX + * + * @param pin_name Pin name to configure + * @param func Function to assign to the pin + */ +static inline void gpio_ll_iomux_func_sel(uint32_t pin_name, uint32_t func) +{ + if (pin_name == IO_MUX_GPIO18_REG || pin_name == IO_MUX_GPIO19_REG) { + CLEAR_PERI_REG_MASK(USB_DEVICE_CONF0_REG, USB_DEVICE_USB_PAD_ENABLE); + } + PIN_FUNC_SELECT(pin_name, func); +} + +/** + * @brief Set peripheral output to an GPIO pad through the IOMUX. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num gpio_num GPIO number of the pad. + * @param func The function number of the peripheral pin to output pin. + * One of the ``FUNC_X_*`` of specified pin (X) in ``soc/io_mux_reg.h``. + * @param oen_inv True if the output enable needs to be inverted, otherwise False. + */ +static inline void gpio_ll_iomux_out(gpio_dev_t *hw, uint8_t gpio_num, int func, uint32_t oen_inv) +{ +#if 0 + hw->func_out_sel_cfg[gpio_num].oen_sel = 0; + hw->func_out_sel_cfg[gpio_num].oen_inv_sel = oen_inv; + gpio_ll_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], func); +#endif +} + +static inline void gpio_ll_force_hold_all(void) +{ + REG_SET_BIT(PMU_IMM_PAD_HOLD_ALL_REG, PMU_TIE_HIGH_HP_PAD_HOLD_ALL); + REG_SET_BIT(PMU_IMM_PAD_HOLD_ALL_REG, PMU_TIE_HIGH_LP_PAD_HOLD_ALL); +} + +static inline void gpio_ll_force_unhold_all(void) +{ + REG_SET_BIT(PMU_IMM_PAD_HOLD_ALL_REG, PMU_TIE_LOW_HP_PAD_HOLD_ALL); + REG_SET_BIT(PMU_IMM_PAD_HOLD_ALL_REG, PMU_TIE_LOW_LP_PAD_HOLD_ALL); +} + +/** + * @brief Enable GPIO pin used for wakeup from sleep. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_sleep_sel_en(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + // ESP32H2-TODO: IDF-6227 + // PIN_SLP_SEL_ENABLE(GPIO_PIN_MUX_REG[gpio_num]); +} + +/** + * @brief Disable GPIO pin used for wakeup from sleep. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_sleep_sel_dis(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + // ESP32H2-TODO: IDF-6227 + // PIN_SLP_SEL_DISABLE(GPIO_PIN_MUX_REG[gpio_num]); +} + +/** + * @brief Disable GPIO pull-up in sleep mode. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_sleep_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + // ESP32H2-TODO: IDF-6227 + // PIN_SLP_PULLUP_DISABLE(GPIO_PIN_MUX_REG[gpio_num]); +} + +/** + * @brief Enable GPIO pull-up in sleep mode. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_sleep_pullup_en(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + // ESP32H2-TODO: IDF-6227 + // PIN_SLP_PULLUP_ENABLE(GPIO_PIN_MUX_REG[gpio_num]); +} + +/** + * @brief Enable GPIO pull-down in sleep mode. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_sleep_pulldown_en(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + // ESP32H2-TODO: IDF-6227 + // PIN_SLP_PULLDOWN_ENABLE(GPIO_PIN_MUX_REG[gpio_num]); +} + +/** + * @brief Disable GPIO pull-down in sleep mode. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_sleep_pulldown_dis(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + // ESP32H2-TODO: IDF-6227 + // PIN_SLP_PULLDOWN_DISABLE(GPIO_PIN_MUX_REG[gpio_num]); +} + +/** + * @brief Disable GPIO input in sleep mode. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_sleep_input_disable(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + // ESP32H2-TODO: IDF-6227 + // PIN_SLP_INPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_num]); +} + +/** + * @brief Enable GPIO input in sleep mode. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_sleep_input_enable(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + // ESP32H2-TODO: IDF-6227 + // PIN_SLP_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]); +} + +/** + * @brief Disable GPIO output in sleep mode. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_sleep_output_disable(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + // ESP32H2-TODO: IDF-6227 + // PIN_SLP_OUTPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_num]); +} + +/** + * @brief Enable GPIO output in sleep mode. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_sleep_output_enable(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + // ESP32H2-TODO: IDF-6227 + // PIN_SLP_OUTPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]); +} + +/** + * @brief Enable GPIO deep-sleep wake-up function. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number. + * @param intr_type GPIO wake-up type. Only GPIO_INTR_LOW_LEVEL or GPIO_INTR_HIGH_LEVEL can be used. + */ +static inline void gpio_ll_deepsleep_wakeup_enable(gpio_dev_t *hw, gpio_num_t gpio_num, gpio_int_type_t intr_type) +{ + if (gpio_num > GPIO_NUM_5) { + abort(); // gpio lager than 5 doesn't support. + } + // SET_PERI_REG_MASK( LP_IO_PIN0_REG + 0x4 * gpio_num, LP_IO_LP_GPIO0_WAKEUP_ENABLE); + // REG_SET_FIELD( LP_IO_PIN0_REG + 0x4 * gpio_num, LP_IO_LP_GPIO0_INT_TYPE, intr_type); +} + +/** + * @brief Disable GPIO deep-sleep wake-up function. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + */ +static inline void gpio_ll_deepsleep_wakeup_disable(gpio_dev_t *hw, gpio_num_t gpio_num) +{ + if (gpio_num > GPIO_NUM_5) { + abort(); // gpio lager than 5 doesn't support. + } + // ESP32H2 LP_IO check: IDF-6403 + // CLEAR_PERI_REG_MASK(LP_IO_PIN0_REG + 0x4 * gpio_num, LP_IO_LP_GPIO0_WAKEUP_ENABLE); + // CLEAR_PERI_REG_MASK(LP_IO_PIN0_REG + 0x4 * gpio_num, LP_IO_LP_GPIO0_INT_TYPE); +} + +/** + * @brief Get the status of whether an IO is used for deep-sleep wake-up. + * + * @param hw Peripheral GPIO hardware instance address. + * @param gpio_num GPIO number + * @return True if the pin is enabled to wake up from deep-sleep + */ +static inline bool gpio_ll_deepsleep_wakeup_is_enabled(gpio_dev_t *hw, uint32_t gpio_num) +{ + // ESP32H2 LP_IO check: IDF-6403 + // HAL_ASSERT(gpio_num <= GPIO_NUM_7 && "gpio larger than 7 does not support deep sleep wake-up function"); + // On ESP32-H2, (lp_io pin number) == (gpio pin number) + return true;//LP_IO.pin[gpio_num].wakeup_enable; +} + + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/gpspi_flash_ll.h b/components/hal/esp32h2/include/hal/gpspi_flash_ll.h new file mode 100644 index 0000000000..91850dfd79 --- /dev/null +++ b/components/hal/esp32h2/include/hal/gpspi_flash_ll.h @@ -0,0 +1,409 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/******************************************************************************* + * NOTICE + * The ll is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The Lowlevel layer for SPI Flash + +#pragma once + +#include +#include "soc/spi_periph.h" +#include "soc/spi_struct.h" +#include "hal/spi_types.h" +#include "hal/spi_flash_types.h" +#include // For MIN/MAX +#include +#include +#include "hal/misc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//NOTE: These macros are changed on h2 for build. MODIFY these when bringup flash. +#define gpspi_flash_ll_get_hw(host_id) ( ((host_id)==SPI2_HOST) ? &GPSPI2 : ({abort();(spi_dev_t*)0;}) ) +#define gpspi_flash_ll_hw_get_id(dev) ( ((dev) == (void*)&GPSPI2) ? SPI2_HOST : -1 ) + +typedef typeof(GPSPI2.clock.val) gpspi_flash_ll_clock_reg_t; +#define GPSPI_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ (80) + +/*------------------------------------------------------------------------------ + * Control + *----------------------------------------------------------------------------*/ +/** + * Reset peripheral registers before configuration and starting control + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void gpspi_flash_ll_reset(spi_dev_t *dev) +{ + dev->user.val = 0; + dev->ctrl.val = 0; + + dev->clk_gate.clk_en = 1; + dev->clk_gate.mst_clk_active = 1; + dev->clk_gate.mst_clk_sel = 1; + + dev->dma_conf.val = 0; + // dev->dma_conf.tx_seg_trans_clr_en = 1; + // dev->dma_conf.rx_seg_trans_clr_en = 1; + // dev->dma_conf.dma_seg_trans_en = 0; +} + +/** + * Check whether the previous operation is done. + * + * @param dev Beginning address of the peripheral registers. + * + * @return true if last command is done, otherwise false. + */ +static inline bool gpspi_flash_ll_cmd_is_done(const spi_dev_t *dev) +{ + return (dev->cmd.usr == 0); +} + +/** + * Get the read data from the buffer after ``gpspi_flash_ll_read`` is done. + * + * @param dev Beginning address of the peripheral registers. + * @param buffer Buffer to hold the output data + * @param read_len Length to get out of the buffer + */ +static inline void gpspi_flash_ll_get_buffer_data(spi_dev_t *dev, void *buffer, uint32_t read_len) +{ + // if (((intptr_t)buffer % 4 == 0) && (read_len % 4 == 0)) { + // // If everything is word-aligned, do a faster memcpy + // memcpy(buffer, (void *)dev->data_buf, read_len); + // } else { + // // Otherwise, slow(er) path copies word by word + // int copy_len = read_len; + // for (int i = 0; i < (read_len + 3) / 4; i++) { + // int word_len = MIN(sizeof(uint32_t), copy_len); + // uint32_t word = dev->data_buf[i]; + // memcpy(buffer, &word, word_len); + // buffer = (void *)((intptr_t)buffer + word_len); + // copy_len -= word_len; + // } + // } +} + +/** + * Write a word to the data buffer. + * + * @param dev Beginning address of the peripheral registers. + * @param word Data to write at address 0. + */ +static inline void gpspi_flash_ll_write_word(spi_dev_t *dev, uint32_t word) +{ + // dev->data_buf[0] = word; +} + +/** + * Set the data to be written in the data buffer. + * + * @param dev Beginning address of the peripheral registers. + * @param buffer Buffer holding the data + * @param length Length of data in bytes. + */ +static inline void gpspi_flash_ll_set_buffer_data(spi_dev_t *dev, const void *buffer, uint32_t length) +{ + // Load data registers, word at a time + // int num_words = (length + 3) / 4; + // for (int i = 0; i < num_words; i++) { + // uint32_t word = 0; + // uint32_t word_len = MIN(length, sizeof(word)); + // memcpy(&word, buffer, word_len); + // dev->data_buf[i] = word; + // length -= word_len; + // buffer = (void *)((intptr_t)buffer + word_len); + // } +} + +/** + * Trigger a user defined transaction. All phases, including command, address, dummy, and the data phases, + * should be configured before this is called. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void gpspi_flash_ll_user_start(spi_dev_t *dev) +{ + dev->cmd.update = 1; + while (dev->cmd.update); + dev->cmd.usr = 1; +} + +/** + * Set HD pin high when flash work at spi mode. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void gpspi_flash_ll_set_hold_pol(spi_dev_t *dev, uint32_t pol_val) +{ + dev->ctrl.hold_pol = pol_val; +} + +/** + * Check whether the host is idle to perform new commands. + * + * @param dev Beginning address of the peripheral registers. + * + * @return true if the host is idle, otherwise false + */ +static inline bool gpspi_flash_ll_host_idle(const spi_dev_t *dev) +{ + return dev->cmd.usr == 0; +} + +/** + * Set phases for user-defined transaction to read + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void gpspi_flash_ll_read_phase(spi_dev_t *dev) +{ + typeof (dev->user) user = { + .usr_command = 1, + .usr_mosi = 0, + .usr_miso = 1, + .usr_addr = 1, + }; + dev->user = user; +} +/*------------------------------------------------------------------------------ + * Configs + *----------------------------------------------------------------------------*/ +/** + * Select which pin to use for the flash + * + * @param dev Beginning address of the peripheral registers. + * @param pin Pin ID to use, 0-2. Set to other values to disable all the CS pins. + */ +static inline void gpspi_flash_ll_set_cs_pin(spi_dev_t *dev, int pin) +{ + dev->misc.cs0_dis = (pin == 0) ? 0 : 1; + dev->misc.cs1_dis = (pin == 1) ? 0 : 1; +} + +/** + * Set the read io mode. + * + * @param dev Beginning address of the peripheral registers. + * @param read_mode I/O mode to use in the following transactions. + */ +static inline void gpspi_flash_ll_set_read_mode(spi_dev_t *dev, esp_flash_io_mode_t read_mode) +{ + typeof (dev->ctrl) ctrl = dev->ctrl; + typeof (dev->user) user = dev->user; + + ctrl.val &= ~(SPI_FCMD_QUAD_M | SPI_FADDR_QUAD_M | SPI_FREAD_QUAD_M | SPI_FCMD_DUAL_M | SPI_FADDR_DUAL_M | SPI_FREAD_DUAL_M); + user.val &= ~(SPI_FWRITE_QUAD_M | SPI_FWRITE_DUAL_M); + + switch (read_mode) { + case SPI_FLASH_FASTRD: + //the default option + case SPI_FLASH_SLOWRD: + break; + case SPI_FLASH_QIO: + ctrl.fread_quad = 1; + ctrl.faddr_quad = 1; + user.fwrite_quad = 1; + break; + case SPI_FLASH_QOUT: + ctrl.fread_quad = 1; + user.fwrite_quad = 1; + break; + case SPI_FLASH_DIO: + ctrl.fread_dual = 1; + ctrl.faddr_dual = 1; + user.fwrite_dual = 1; + break; + case SPI_FLASH_DOUT: + ctrl.fread_dual = 1; + user.fwrite_dual = 1; + break; + default: + abort(); + } + + dev->ctrl = ctrl; + dev->user = user; +} + +/** + * Set clock frequency to work at. + * + * @param dev Beginning address of the peripheral registers. + * @param clock_val pointer to the clock value to set + */ +static inline void gpspi_flash_ll_set_clock(spi_dev_t *dev, gpspi_flash_ll_clock_reg_t *clock_val) +{ + dev->clock.val = *clock_val; +} + +/** + * Set the input length, in bits. + * + * @param dev Beginning address of the peripheral registers. + * @param bitlen Length of input, in bits. + */ +static inline void gpspi_flash_ll_set_miso_bitlen(spi_dev_t *dev, uint32_t bitlen) +{ + dev->user.usr_miso = bitlen > 0; + if (bitlen) { + dev->ms_dlen.ms_data_bitlen = bitlen - 1; + } +} + +/** + * Set the output length, in bits (not including command, address and dummy + * phases) + * + * @param dev Beginning address of the peripheral registers. + * @param bitlen Length of output, in bits. + */ +static inline void gpspi_flash_ll_set_mosi_bitlen(spi_dev_t *dev, uint32_t bitlen) +{ + dev->user.usr_mosi = bitlen > 0; + if (bitlen) { + dev->ms_dlen.ms_data_bitlen = bitlen - 1; + } +} + +/** + * Set the command. + * + * @param dev Beginning address of the peripheral registers. + * @param command Command to send + * @param bitlen Length of the command + */ +static inline void gpspi_flash_ll_set_command(spi_dev_t *dev, uint8_t command, uint32_t bitlen) +{ + dev->user.usr_command = 1; + typeof(dev->user2) user2 = { + .usr_command_value = command, + .usr_command_bitlen = (bitlen - 1), + }; + dev->user2 = user2; +} + +/** + * Get the address length that is set in register, in bits. + * + * @param dev Beginning address of the peripheral registers. + * + */ +static inline int gpspi_flash_ll_get_addr_bitlen(spi_dev_t *dev) +{ + return dev->user.usr_addr ? dev->user1.usr_addr_bitlen + 1 : 0; +} + +/** + * Set the address length to send, in bits. Should be called before commands that requires the address e.g. erase sector, read, write... + * + * @param dev Beginning address of the peripheral registers. + * @param bitlen Length of the address, in bits + */ +static inline void gpspi_flash_ll_set_addr_bitlen(spi_dev_t *dev, uint32_t bitlen) +{ + dev->user1.usr_addr_bitlen = (bitlen - 1); + dev->user.usr_addr = bitlen ? 1 : 0; +} + +/** + * Set the address to send in user mode. Should be called before commands that requires the address e.g. erase sector, read, write... + * + * @param dev Beginning address of the peripheral registers. + * @param addr Address to send + */ +static inline void gpspi_flash_ll_set_usr_address(spi_dev_t *dev, uint32_t addr, uint32_t bitlen) +{ + // The blank region should be all ones + // uint32_t padding_ones = (bitlen == 32? 0 : UINT32_MAX >> bitlen); + // dev->addr = (addr << (32 - bitlen)) | padding_ones; +} + +/** + * Set the address to send. Should be called before commands that requires the address e.g. erase sector, read, write... + * + * @param dev Beginning address of the peripheral registers. + * @param addr Address to send + */ +static inline void gpspi_flash_ll_set_address(spi_dev_t *dev, uint32_t addr) +{ + // dev->addr = addr; +} + +/** + * Set the length of dummy cycles. + * + * @param dev Beginning address of the peripheral registers. + * @param dummy_n Cycles of dummy phases + */ +static inline void gpspi_flash_ll_set_dummy(spi_dev_t *dev, uint32_t dummy_n) +{ + dev->user.usr_dummy = dummy_n ? 1 : 0; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user1, usr_dummy_cyclelen, dummy_n - 1); +} + +/** + * Set D/Q output level during dummy phase + * + * @param dev Beginning address of the peripheral registers. + * @param out_en whether to enable IO output for dummy phase + * @param out_level dummy output level + */ +static inline void gpspi_flash_ll_set_dummy_out(spi_dev_t *dev, uint32_t out_en, uint32_t out_lev) +{ + dev->ctrl.dummy_out = out_en; + dev->ctrl.q_pol = out_lev; + dev->ctrl.d_pol = out_lev; +} + +/** + * Set extra hold time of CS after the clocks. + * + * @param dev Beginning address of the peripheral registers. + * @param hold_n Cycles of clocks before CS is inactive + */ +static inline void gpspi_flash_ll_set_hold(spi_dev_t *dev, uint32_t hold_n) +{ + dev->user1.cs_hold_time = hold_n - 1; + dev->user.cs_hold = (hold_n > 0? 1: 0); +} + +static inline void gpspi_flash_ll_set_cs_setup(spi_dev_t *dev, uint32_t cs_setup_time) +{ + dev->user.cs_setup = (cs_setup_time > 0 ? 1 : 0); + dev->user1.cs_setup_time = cs_setup_time - 1; +} + +/** + * Calculate spi_flash clock frequency division parameters for register. + * + * @param clkdiv frequency division factor + * + * @return Register setting for the given clock division factor. + */ +static inline uint32_t gpspi_flash_ll_calculate_clock_reg(uint8_t clkdiv) +{ + uint32_t div_parameter; + // See comments of `clock` in `spi_struct.h` + if (clkdiv == 1) { + div_parameter = (1 << 31); + } else { + div_parameter = ((clkdiv - 1) | (((clkdiv/2 - 1) & 0xff) << 6 ) | (((clkdiv - 1) & 0xff) << 12)); + } + return div_parameter; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/lpwdt_ll.h b/components/hal/esp32h2/include/hal/lpwdt_ll.h new file mode 100644 index 0000000000..b6009dbc7b --- /dev/null +++ b/components/hal/esp32h2/include/hal/lpwdt_ll.h @@ -0,0 +1,296 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// The LL layer for Timer Group register operations. +// Note that most of the register operations in this layer are non-atomic operations. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "hal/misc.h" +#include "hal/wdt_types.h" +#include "soc/rtc_cntl_periph.h" +#include "soc/efuse_reg.h" +#include "esp_attr.h" + +#include "esp32h2/rom/ets_sys.h" + +/** + * @brief Enable the RWDT + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void lpwdt_ll_enable(lp_wdt_dev_t *hw) +{ + // hw->config0.en = 1; +} + +/** + * @brief Disable the RWDT + * + * @param hw Start address of the peripheral registers. + * @note This function does not disable the flashboot mode. Therefore, given that + * the MWDT is disabled using this function, a timeout can still occur + * if the flashboot mode is simultaneously enabled. + */ +FORCE_INLINE_ATTR void lpwdt_ll_disable(lp_wdt_dev_t *hw) +{ + // hw->config0.en = 0; +} + +/** + * @brief Check if the RWDT is enabled + * + * @param hw Start address of the peripheral registers. + * @return True if RTC WDT is enabled + */ +FORCE_INLINE_ATTR bool lpwdt_ll_check_if_enabled(lp_wdt_dev_t *hw) +{ + return false;//(hw->config0.en) ? true : false; +} + +/** + * @brief Configure a particular stage of the RWDT + * + * @param hw Start address of the peripheral registers. + * @param stage Which stage to configure + * @param timeout Number of timer ticks for the stage to timeout (see note). + * @param behavior What action to take when the stage times out + * + * @note The value of of RWDT stage 0 timeout register is special, in + * that an implicit multiplier is applied to that value to produce + * and effective timeout tick value. The multiplier is dependent + * on an EFuse value. Therefore, when configuring stage 0, the valid + * values for the timeout argument are: + * - If Efuse value is 0, any even number between [2,2*UINT32_MAX] + * - If Efuse value is 1, any multiple of 4 between [4,4*UINT32_MAX] + * - If Efuse value is 2, any multiple of 8 between [8,8*UINT32_MAX] + * - If Efuse value is 3, any multiple of 16 between [16,16*UINT32_MAX] + */ +FORCE_INLINE_ATTR void lpwdt_ll_config_stage(lp_wdt_dev_t *hw, wdt_stage_t stage, uint32_t timeout_ticks, wdt_stage_action_t behavior) +{ + // switch (stage) { + // case WDT_STAGE0: + // hw->config0.stg0 = behavior; + // //Account of implicty multiplier applied to stage 0 timeout tick config value + // hw->config1 = timeout_ticks >> (1 + REG_GET_FIELD(EFUSE_RD_REPEAT_DATA1_REG, EFUSE_WDT_DELAY_SEL)); + // break; + // case WDT_STAGE1: + // hw->config0.stg1 = behavior; + // hw->config2 = timeout_ticks; + // break; + // case WDT_STAGE2: + // hw->config0.stg2 = behavior; + // hw->config3 = timeout_ticks; + // break; + // case WDT_STAGE3: + // hw->config0.stg3 = behavior; + // hw->config4 = timeout_ticks; + // break; + // default: + // abort(); + // } +} + +/** + * @brief Disable a particular stage of the RWDT + * + * @param hw Start address of the peripheral registers. + * @param stage Which stage to disable + */ +FORCE_INLINE_ATTR void lpwdt_ll_disable_stage(lp_wdt_dev_t *hw, wdt_stage_t stage) +{ + // switch (stage) { + // case WDT_STAGE0: + // hw->config0.stg0 = WDT_STAGE_ACTION_OFF; + // break; + // case WDT_STAGE1: + // hw->config0.stg1 = WDT_STAGE_ACTION_OFF; + // break; + // case WDT_STAGE2: + // hw->config0.stg2 = WDT_STAGE_ACTION_OFF; + // break; + // case WDT_STAGE3: + // hw->config0.stg3 = WDT_STAGE_ACTION_OFF; + // break; + // default: + // abort(); + // } +} + +/** + * @brief Set the length of the CPU reset action + * + * @param hw Start address of the peripheral registers. + * @param length Length of CPU reset signal + */ +FORCE_INLINE_ATTR void lpwdt_ll_set_cpu_reset_length(lp_wdt_dev_t *hw, wdt_reset_sig_length_t length) +{ + // hw->config0.cpu_reset_length = length; +} + +/** + * @brief Set the length of the system reset action + * + * @param hw Start address of the peripheral registers. + * @param length Length of system reset signal + */ +FORCE_INLINE_ATTR void lpwdt_ll_set_sys_reset_length(lp_wdt_dev_t *hw, wdt_reset_sig_length_t length) +{ + // hw->config0.sys_reset_length = length; +} + +/** + * @brief Enable/Disable the RWDT flashboot mode. + * + * @param hw Start address of the peripheral registers. + * @param enable True to enable RWDT flashboot mode, false to disable RWDT flashboot mode. + * + * @note Flashboot mode is independent and can trigger a WDT timeout event if the + * WDT's enable bit is set to 0. Flashboot mode for RWDT is automatically enabled + * on flashboot, and should be disabled by software when flashbooting completes. + */ +FORCE_INLINE_ATTR void lpwdt_ll_set_flashboot_en(lp_wdt_dev_t *hw, bool enable) +{ + // hw->config0.flashboot_mod_en = (enable) ? 1 : 0; +} + +/** + * @brief Enable/Disable the CPU0 to be reset on WDT_STAGE_ACTION_RESET_CPU + * + * @param hw Start address of the peripheral registers. + * @param enable True to enable CPU0 to be reset, false to disable. + */ +FORCE_INLINE_ATTR void lpwdt_ll_set_procpu_reset_en(lp_wdt_dev_t *hw, bool enable) +{ + // hw->config0.procpu_reset_en = (enable) ? 1 : 0; +} + +/** + * @brief Enable/Disable the CPU1 to be reset on WDT_STAGE_ACTION_RESET_CPU + * + * @param hw Start address of the peripheral registers. + * @param enable True to enable CPU1 to be reset, false to disable. + */ +FORCE_INLINE_ATTR void lpwdt_ll_set_appcpu_reset_en(lp_wdt_dev_t *hw, bool enable) +{ + // hw->config0.appcpu_reset_en = (enable) ? 1 : 0; +} + +/** + * @brief Enable/Disable the RWDT pause during sleep functionality + * + * @param hw Start address of the peripheral registers. + * @param enable True to enable, false to disable. + */ +FORCE_INLINE_ATTR void lpwdt_ll_set_pause_in_sleep_en(lp_wdt_dev_t *hw, bool enable) +{ + // hw->config0.pause_in_slp = (enable) ? 1 : 0; +} + +/** + * @brief Enable/Disable chip reset on RWDT timeout. + * + * A chip reset also resets the analog portion of the chip. It will appear as a + * POWERON reset rather than an RTC reset. + * + * @param hw Start address of the peripheral registers. + * @param enable True to enable, false to disable. + */ +FORCE_INLINE_ATTR void lpwdt_ll_set_chip_reset_en(lp_wdt_dev_t *hw, bool enable) +{ + // hw->config5.chip_reset_en = (enable) ? 1 : 0; +} + +/** + * @brief Set width of chip reset signal + * + * @param hw Start address of the peripheral registers. + * @param width Width of chip reset signal in terms of number of RTC_SLOW_CLK cycles + */ +FORCE_INLINE_ATTR void lpwdt_ll_set_chip_reset_width(lp_wdt_dev_t *hw, uint32_t width) +{ + // ESP32H2-TODO: IDF-6402 + // HAL_FORCE_MODIFY_U32_REG_FIELD(hw->config0, chip_reset_width, width); +} + +/** + * @brief Feed the RWDT + * + * Resets the current timer count and current stage. + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void lpwdt_ll_feed(lp_wdt_dev_t *hw) +{ + // ESP32H2-TODO: IDF-6402 + // hw->feed.rtc_wdt_feed = 1; +} + +/** + * @brief Enable write protection of the RWDT registers + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void lpwdt_ll_write_protect_enable(lp_wdt_dev_t *hw) +{ + // ESP32H2-TODO: IDF-6402 + // hw->wprotect = 0; +} + +/** + * @brief Disable write protection of the RWDT registers + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void lpwdt_ll_write_protect_disable(lp_wdt_dev_t *hw) +{ + // ESP32H2-TODO: IDF-6402 + // hw->wprotect = RTC_CNTL_WDT_WKEY_VALUE; +} + +/** + * @brief Enable the RWDT interrupt. + * + * @param hw Start address of the peripheral registers. + * @param enable True to enable RWDT interrupt, false to disable. + */ +FORCE_INLINE_ATTR void lpwdt_ll_set_intr_enable(lp_wdt_dev_t *hw, bool enable) +{ + // ESP32H2-TODO: IDF-6402 + // hw->int_ena.lp_wdt_int_ena = (enable) ? 1 : 0; +} + +/** + * @brief Check if the RWDT interrupt has been triggered + * + * @param hw Start address of the peripheral registers. + * @return True if the RWDT interrupt was triggered + */ +FORCE_INLINE_ATTR bool lpwdt_ll_check_intr_status(lp_wdt_dev_t *hw) +{ + return false;//(hw->int_st.lp_wdt_int_st) ? true : false; // ESP32H2-TODO: IDF-6402 +} + +/** + * @brief Clear the RWDT interrupt status. + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void lpwdt_ll_clear_intr_status(lp_wdt_dev_t *hw) +{ + // ESP32H2-TODO: IDF-6402 + // hw->int_clr.lp_wdt_int_clr = 1; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/mmu_ll.h b/components/hal/esp32h2/include/hal/mmu_ll.h new file mode 100644 index 0000000000..5a9ea6a90f --- /dev/null +++ b/components/hal/esp32h2/include/hal/mmu_ll.h @@ -0,0 +1,255 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// The LL layer for MMU register operations + +#pragma once + +#include "soc/spi_mem_reg.h" +#include "soc/ext_mem_defs.h" +#include "hal/assert.h" +#include "hal/mmu_types.h" +#include "hal/efuse_ll.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief The real MMU page size get from Kconfig. + * + * @note Only used in this file + */ +#define MMU_LL_PAGE_SIZE (CONFIG_MMU_PAGE_SIZE) + +__attribute__((always_inline)) static inline bool mmu_ll_cache_encryption_enabled(void) +{ + unsigned cnt = efuse_ll_get_flash_crypt_cnt(); + // 3 bits wide, any odd number - 1 or 3 - bits set means encryption is on + cnt = ((cnt >> 2) ^ (cnt >> 1) ^ cnt) & 0x1; + return (cnt == 1); +} + + +/** + * Get MMU page size + * + * @param mmu_id MMU ID + * + * @return MMU page size code + */ +__attribute__((always_inline)) +static inline mmu_page_size_t mmu_ll_get_page_size(uint32_t mmu_id) +{ + (void)mmu_id; + uint32_t page_size_code = REG_GET_FIELD(SPI_MEM_MMU_POWER_CTRL_REG(0), SPI_MEM_MMU_PAGE_SIZE); + return (page_size_code == 0) ? MMU_PAGE_64KB : \ + (page_size_code == 1) ? MMU_PAGE_32KB : \ + (page_size_code == 2) ? MMU_PAGE_16KB : \ + MMU_PAGE_8KB; +} + +/** + * Set MMU page size + * + * @param size MMU page size + */ +__attribute__((always_inline)) +static inline void mmu_ll_set_page_size(uint32_t mmu_id, uint32_t size) +{ + uint8_t reg_val = (size == MMU_PAGE_64KB) ? 0 : \ + (size == MMU_PAGE_32KB) ? 1 : \ + (size == MMU_PAGE_16KB) ? 2 : \ + (size == MMU_PAGE_8KB) ? 3 : 0; + REG_SET_FIELD(SPI_MEM_MMU_POWER_CTRL_REG(0), SPI_MEM_MMU_PAGE_SIZE, reg_val); +} + +/** + * Check if the external memory vaddr region is valid + * + * @param mmu_id MMU ID + * @param vaddr_start start of the virtual address + * @param len length, in bytes + * + * @return + * True for valid + */ +__attribute__((always_inline)) +static inline bool mmu_ll_check_valid_ext_vaddr_region(uint32_t mmu_id, uint32_t vaddr_start, uint32_t len) +{ + (void)mmu_id; + uint32_t vaddr_end = vaddr_start + len; + return (ADDRESS_IN_IRAM0_CACHE(vaddr_start, MMU_LL_PAGE_SIZE) && ADDRESS_IN_IRAM0_CACHE(vaddr_end, MMU_LL_PAGE_SIZE)) || (ADDRESS_IN_DRAM0_CACHE(vaddr_start, MMU_LL_PAGE_SIZE) && ADDRESS_IN_DRAM0_CACHE(vaddr_end, MMU_LL_PAGE_SIZE)); +} + +/** + * To get the MMU table entry id to be mapped + * + * @param mmu_id MMU ID + * @param vaddr virtual address to be mapped + * + * @return + * MMU table entry id + */ +__attribute__((always_inline)) +static inline uint32_t mmu_ll_get_entry_id(uint32_t mmu_id, uint32_t vaddr) +{ + (void)mmu_id; + + mmu_page_size_t page_size = mmu_ll_get_page_size(mmu_id); + uint32_t shift_code = 0; + switch (page_size) { + case MMU_PAGE_64KB: + shift_code = 16; + break; + case MMU_PAGE_32KB: + shift_code = 15; + break; + case MMU_PAGE_16KB: + shift_code = 14; + break; + case MMU_PAGE_8KB: + shift_code = 13; + break; + default: + HAL_ASSERT(shift_code); + } + + return ((vaddr & MMU_VADDR_MASK(page_size)) >> shift_code); +} + +/** + * Format the paddr to be mappable + * + * @param mmu_id MMU ID + * @param paddr physical address to be mapped + * + * @return + * mmu_val - paddr in MMU table supported format + */ +__attribute__((always_inline)) +static inline uint32_t mmu_ll_format_paddr(uint32_t mmu_id, uint32_t paddr) +{ + (void)mmu_id; + + mmu_page_size_t page_size = mmu_ll_get_page_size(mmu_id); + uint32_t shift_code = 0; + switch (page_size) { + case MMU_PAGE_64KB: + shift_code = 16; + break; + case MMU_PAGE_32KB: + shift_code = 15; + break; + case MMU_PAGE_16KB: + shift_code = 14; + break; + case MMU_PAGE_8KB: + shift_code = 13; + break; + default: + HAL_ASSERT(shift_code); + } + + return paddr >> shift_code; +} + +/** + * Write to the MMU table to map the virtual memory and the physical memory + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * @param mmu_val Value to be set into an MMU entry, for physical address + * @param target MMU target physical memory. + */ +__attribute__((always_inline)) static inline void mmu_ll_write_entry(uint32_t mmu_id, uint32_t entry_id, uint32_t mmu_val, uint32_t target) +{ + (void)mmu_id; + (void)target; + uint32_t mmu_raw_value; + if (mmu_ll_cache_encryption_enabled()) { + mmu_val |= MMU_SENSITIVE; + } + /* Note: for ESP32-H2, invert invalid bit for compatible with upper-layer software */ + mmu_raw_value = mmu_val ^ MMU_INVALID_MASK; + REG_WRITE(SPI_MEM_MMU_ITEM_INDEX_REG(0), entry_id); + REG_WRITE(SPI_MEM_MMU_ITEM_CONTENT_REG(0), mmu_raw_value); +} + +/** + * Read the raw value from MMU table + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * @param mmu_val Value to be read from MMU table + */ +__attribute__((always_inline)) static inline uint32_t mmu_ll_read_entry(uint32_t mmu_id, uint32_t entry_id) +{ + (void)mmu_id; + + uint32_t mmu_raw_value; + uint32_t ret; + REG_WRITE(SPI_MEM_MMU_ITEM_INDEX_REG(0), entry_id); + mmu_raw_value = REG_READ(SPI_MEM_MMU_ITEM_CONTENT_REG(0)); + if (mmu_ll_cache_encryption_enabled()) { + mmu_raw_value &= ~MMU_SENSITIVE; + } + /* Note: for ESP32-H2, invert invalid bit for compatible with upper-layer software */ + ret = mmu_raw_value ^ MMU_INVALID_MASK; + return ret; +} + +/** + * Set MMU table entry as invalid + * + * @param mmu_id MMU ID + * @param entry_id MMU entry + */ +__attribute__((always_inline)) static inline void mmu_ll_set_entry_invalid(uint32_t mmu_id, uint32_t entry_id) +{ + (void)mmu_id; + + REG_WRITE(SPI_MEM_MMU_ITEM_INDEX_REG(0), entry_id); + REG_WRITE(SPI_MEM_MMU_ITEM_CONTENT_REG(0), MMU_INVALID); +} + +/** + * Get MMU table entry is invalid + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * return ture for MMU entry is invalid, false for valid + */ +__attribute__((always_inline)) static inline bool mmu_ll_get_entry_is_invalid(uint32_t mmu_id, uint32_t entry_id) +{ + (void)mmu_id; + + uint32_t mmu_raw_value; + REG_WRITE(SPI_MEM_MMU_ITEM_INDEX_REG(0), entry_id); + mmu_raw_value = REG_READ(SPI_MEM_MMU_ITEM_CONTENT_REG(0)); + /* Note: for ESP32-H2, the invalid-bit of MMU: 0 for invalid, 1 for valid */ + return (mmu_raw_value & MMU_INVALID_MASK) ? false : true; +} + +#ifdef __cplusplus +} + +#endif + + +/** + * Unmap all the items in the MMU table + * + * @param mmu_id MMU ID + */ +__attribute__((always_inline)) +static inline void mmu_ll_unmap_all(uint32_t mmu_id) +{ + for (int i = 0; i < MMU_ENTRY_NUM; i++) { + mmu_ll_set_entry_invalid(mmu_id, i); + } +} diff --git a/components/hal/esp32h2/include/hal/mpu_ll.h b/components/hal/esp32h2/include/hal/mpu_ll.h new file mode 100644 index 0000000000..57d884a5a1 --- /dev/null +++ b/components/hal/esp32h2/include/hal/mpu_ll.h @@ -0,0 +1,45 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "soc/soc_caps.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* This LL is currently unused for ESP32-H2 - cleanup is TODO ESP32-H2 IDF-2375 */ + +static inline uint32_t mpu_ll_id_to_addr(unsigned id) +{ + abort(); +} + +static inline void mpu_ll_set_region_rw(uint32_t addr) +{ + abort(); +} + +static inline void mpu_ll_set_region_rwx(uint32_t addr) +{ + abort(); +} + +static inline void mpu_ll_set_region_x(uint32_t addr) +{ + abort(); +} + + +static inline void mpu_ll_set_region_illegal(uint32_t addr) +{ + abort(); +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/mwdt_ll.h b/components/hal/esp32h2/include/hal/mwdt_ll.h new file mode 100644 index 0000000000..6bc12709b8 --- /dev/null +++ b/components/hal/esp32h2/include/hal/mwdt_ll.h @@ -0,0 +1,253 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// The LL layer for Timer Group register operations. +// Note that most of the register operations in this layer are non-atomic operations. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "soc/timer_periph.h" +#include "soc/timer_group_struct.h" +#include "hal/wdt_types.h" +#include "hal/assert.h" +#include "esp_attr.h" +#include "hal/misc.h" + +//Type check wdt_stage_action_t +_Static_assert(WDT_STAGE_ACTION_OFF == TIMG_WDT_STG_SEL_OFF, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +_Static_assert(WDT_STAGE_ACTION_INT == TIMG_WDT_STG_SEL_INT, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +_Static_assert(WDT_STAGE_ACTION_RESET_CPU == TIMG_WDT_STG_SEL_RESET_CPU, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +_Static_assert(WDT_STAGE_ACTION_RESET_SYSTEM == TIMG_WDT_STG_SEL_RESET_SYSTEM, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +//Type check wdt_reset_sig_length_t +_Static_assert(WDT_RESET_SIG_LENGTH_100ns == TIMG_WDT_RESET_LENGTH_100_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_200ns == TIMG_WDT_RESET_LENGTH_200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_300ns == TIMG_WDT_RESET_LENGTH_300_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_400ns == TIMG_WDT_RESET_LENGTH_400_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_500ns == TIMG_WDT_RESET_LENGTH_500_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_800ns == TIMG_WDT_RESET_LENGTH_800_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_1_6us == TIMG_WDT_RESET_LENGTH_1600_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_3_2us == TIMG_WDT_RESET_LENGTH_3200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); + +/** + * @brief Enable the MWDT + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void mwdt_ll_enable(timg_dev_t *hw) +{ + hw->wdtconfig0.wdt_en = 1; +} + +/** + * @brief Disable the MWDT + * + * @param hw Start address of the peripheral registers. + * @note This function does not disable the flashboot mode. Therefore, given that + * the MWDT is disabled using this function, a timeout can still occur + * if the flashboot mode is simultaneously enabled. + */ +FORCE_INLINE_ATTR void mwdt_ll_disable(timg_dev_t *hw) +{ + hw->wdtconfig0.wdt_en = 0; +} + +/** + * Check if the MWDT is enabled + * + * @param hw Start address of the peripheral registers. + * @return True if the MWDT is enabled, false otherwise + */ +FORCE_INLINE_ATTR bool mwdt_ll_check_if_enabled(timg_dev_t *hw) +{ + return (hw->wdtconfig0.wdt_en) ? true : false; +} + +/** + * @brief Configure a particular stage of the MWDT + * + * @param hw Start address of the peripheral registers. + * @param stage Which stage to configure + * @param timeout Number of timer ticks for the stage to timeout + * @param behavior What action to take when the stage times out + */ +FORCE_INLINE_ATTR void mwdt_ll_config_stage(timg_dev_t *hw, wdt_stage_t stage, uint32_t timeout, wdt_stage_action_t behavior) +{ + switch (stage) { + case WDT_STAGE0: + hw->wdtconfig0.wdt_stg0 = behavior; + hw->wdtconfig2.wdt_stg0_hold = timeout; + break; + case WDT_STAGE1: + hw->wdtconfig0.wdt_stg1 = behavior; + hw->wdtconfig3.wdt_stg1_hold = timeout; + break; + case WDT_STAGE2: + hw->wdtconfig0.wdt_stg2 = behavior; + hw->wdtconfig4.wdt_stg2_hold = timeout; + break; + case WDT_STAGE3: + hw->wdtconfig0.wdt_stg3 = behavior; + hw->wdtconfig5.wdt_stg3_hold = timeout; + break; + default: + HAL_ASSERT(false && "unsupported WDT stage"); + break; + } + //Config registers are updated asynchronously + hw->wdtconfig0.wdt_conf_update_en = 1; +} + +/** + * @brief Disable a particular stage of the MWDT + * + * @param hw Start address of the peripheral registers. + * @param stage Which stage to disable + */ +FORCE_INLINE_ATTR void mwdt_ll_disable_stage(timg_dev_t *hw, uint32_t stage) +{ + switch (stage) { + case WDT_STAGE0: + hw->wdtconfig0.wdt_stg0 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE1: + hw->wdtconfig0.wdt_stg1 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE2: + hw->wdtconfig0.wdt_stg2 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE3: + hw->wdtconfig0.wdt_stg3 = WDT_STAGE_ACTION_OFF; + break; + default: + HAL_ASSERT(false && "unsupported WDT stage"); + break; + } + //Config registers are updated asynchronously + hw->wdtconfig0.wdt_conf_update_en = 1; +} + +/** + * @brief Set the length of the CPU reset action + * + * @param hw Start address of the peripheral registers. + * @param length Length of CPU reset signal + */ +FORCE_INLINE_ATTR void mwdt_ll_set_cpu_reset_length(timg_dev_t *hw, wdt_reset_sig_length_t length) +{ + hw->wdtconfig0.wdt_cpu_reset_length = length; + //Config registers are updated asynchronously + hw->wdtconfig0.wdt_conf_update_en = 1; +} + +/** + * @brief Set the length of the system reset action + * + * @param hw Start address of the peripheral registers. + * @param length Length of system reset signal + */ +FORCE_INLINE_ATTR void mwdt_ll_set_sys_reset_length(timg_dev_t *hw, wdt_reset_sig_length_t length) +{ + hw->wdtconfig0.wdt_sys_reset_length = length; + //Config registers are updated asynchronously + hw->wdtconfig0.wdt_conf_update_en = 1; +} + +/** + * @brief Enable/Disable the MWDT flashboot mode. + * + * @param hw Beginning address of the peripheral registers. + * @param enable True to enable WDT flashboot mode, false to disable WDT flashboot mode. + * + * @note Flashboot mode is independent and can trigger a WDT timeout event if the + * WDT's enable bit is set to 0. Flashboot mode for TG0 is automatically enabled + * on flashboot, and should be disabled by software when flashbooting completes. + */ +FORCE_INLINE_ATTR void mwdt_ll_set_flashboot_en(timg_dev_t *hw, bool enable) +{ + hw->wdtconfig0.wdt_flashboot_mod_en = (enable) ? 1 : 0; + //Config registers are updated asynchronously + hw->wdtconfig0.wdt_conf_update_en = 1; +} + +/** + * @brief Set the clock prescaler of the MWDT + * + * @param hw Start address of the peripheral registers. + * @param prescaler Prescaler value between 1 to 65535 + */ +FORCE_INLINE_ATTR void mwdt_ll_set_prescaler(timg_dev_t *hw, uint32_t prescaler) +{ + // In case the compiler optimise a 32bit instruction (e.g. s32i) into 8/16bit instruction (e.g. s8i, which is not allowed to access a register) + // We take care of the "read-modify-write" procedure by ourselves. + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wdtconfig1, wdt_clk_prescale, prescaler); + //Config registers are updated asynchronously + hw->wdtconfig0.wdt_conf_update_en = 1; +} + +/** + * @brief Feed the MWDT + * + * Resets the current timer count and current stage. + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void mwdt_ll_feed(timg_dev_t *hw) +{ + hw->wdtfeed.wdt_feed = 1; +} + +/** + * @brief Enable write protection of the MWDT registers + * + * Locking the MWDT will prevent any of the MWDT's registers from being modified + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void mwdt_ll_write_protect_enable(timg_dev_t *hw) +{ + hw->wdtwprotect.wdt_wkey = 0; +} + +/** + * @brief Disable write protection of the MWDT registers + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void mwdt_ll_write_protect_disable(timg_dev_t *hw) +{ + hw->wdtwprotect.wdt_wkey = TIMG_WDT_WKEY_VALUE; +} + +/** + * @brief Clear the MWDT interrupt status. + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void mwdt_ll_clear_intr_status(timg_dev_t *hw) +{ + hw->int_clr_timers.wdt_int_clr = 1; +} + +/** + * @brief Set the interrupt enable bit for the MWDT interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param enable Whether to enable the MWDT interrupt + */ +FORCE_INLINE_ATTR void mwdt_ll_set_intr_enable(timg_dev_t *hw, bool enable) +{ + hw->int_ena_timers.wdt_int_ena = (enable) ? 1 : 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/regi2c_ctrl_ll.h b/components/hal/esp32h2/include/hal/regi2c_ctrl_ll.h new file mode 100644 index 0000000000..627f9745e8 --- /dev/null +++ b/components/hal/esp32h2/include/hal/regi2c_ctrl_ll.h @@ -0,0 +1,62 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "soc/soc.h" +#include "soc/regi2c_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Reset (Disable) the I2C internal bus for all regi2c registers + */ +static inline void regi2c_ctrl_ll_i2c_reset(void) +{ + SET_PERI_REG_BITS(ANA_CONFIG_REG, ANA_CONFIG_M, ANA_CONFIG_M, ANA_CONFIG_S); +} + +/** + * @brief Enable the I2C internal bus to do I2C read/write operation to the BBPLL configuration register + */ +static inline void regi2c_ctrl_ll_i2c_bbpll_enable(void) +{ + CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, ANA_I2C_BBPLL_M); +} + +/** + * @brief Start BBPLL self-calibration + */ +static inline __attribute__((always_inline)) void regi2c_ctrl_ll_bbpll_calibration_start(void) +{ + REG_CLR_BIT(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_HIGH); + REG_SET_BIT(I2C_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_LOW); +} + +/** + * @brief Enable the I2C internal bus to do I2C read/write operation to the SAR_ADC register + */ +static inline void regi2c_ctrl_ll_i2c_saradc_enable(void) +{ + CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, ANA_I2C_SAR_FORCE_PD); + SET_PERI_REG_MASK(ANA_CONFIG2_REG, ANA_I2C_SAR_FORCE_PU); +} + +/** + * @brief Disable the I2C internal bus to do I2C read/write operation to the SAR_ADC register + */ +static inline void regi2c_ctrl_ll_i2c_saradc_disable(void) +{ + CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, ANA_I2C_SAR_FORCE_PU); + SET_PERI_REG_MASK(ANA_CONFIG2_REG, ANA_I2C_SAR_FORCE_PD); +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/rtc_cntl_ll.h b/components/hal/esp32h2/include/hal/rtc_cntl_ll.h new file mode 100644 index 0000000000..3817849cad --- /dev/null +++ b/components/hal/esp32h2/include/hal/rtc_cntl_ll.h @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "soc/soc.h" +#include "soc/rtc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static inline void rtc_cntl_ll_set_wakeup_timer(uint64_t t) +{ + // ESP32H2-TODO: IDF-6401 +} + +static inline uint32_t rtc_cntl_ll_gpio_get_wakeup_pins(void) +{ + return 0; + // ESP32H2-TODO: IDF-6401 +} + +static inline uint32_t rtc_cntl_ll_gpio_get_wakeup_status(void) +{ + // ESP32H2-TODO: IDF-6401 + return 0; +} + +static inline void rtc_cntl_ll_gpio_clear_wakeup_status(void) +{ + // ESP32H2-TODO: IDF-6401 +} + +static inline void rtc_cntl_ll_gpio_set_wakeup_pins(void) +{ + // ESP32H2-TODO: IDF-5718 +} + +static inline void rtc_cntl_ll_gpio_clear_wakeup_pins(void) +{ + // ESP32H2-TODO: IDF-5718 +} + +static inline void rtc_cntl_ll_set_cpu_retention_link_addr(uint32_t addr) +{ + // ESP32H2-TODO: IDF-5718 has removed the retention feature +} + +static inline void rtc_cntl_ll_enable_cpu_retention_clock(void) +{ + // ESP32H2-TODO: IDF-5718 has removed the retention feature +} + +static inline void rtc_cntl_ll_enable_cpu_retention(void) +{ + // ESP32H2-TODO: IDF-5718 has removed the retention feature +} + +static inline void rtc_cntl_ll_disable_cpu_retention(void) +{ + // ESP32H2-TODO: IDF-5718 has removed the retention feature +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/rwdt_ll.h b/components/hal/esp32h2/include/hal/rwdt_ll.h new file mode 100644 index 0000000000..b7ae35cc9e --- /dev/null +++ b/components/hal/esp32h2/include/hal/rwdt_ll.h @@ -0,0 +1,77 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +// The LL layer for Timer Group register operations. +// Note that most of the register operations in this layer are non-atomic operations. + + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "hal/lpwdt_ll.h" + +#define rwdt_ll_enable(hw) \ + lpwdt_ll_enable(hw) + +#define rwdt_ll_disable(hw) \ + lpwdt_ll_disable(hw) + +#define rwdt_ll_check_if_enabled(hw) \ + lpwdt_ll_check_if_enabled(hw) + +#define rwdt_ll_config_stage(hw, stage, timeout_ticks, behavior) \ + lpwdt_ll_config_stage(hw, stage, timeout_ticks, behavior) + +#define rwdt_ll_disable_stage(hw, stage) \ + lpwdt_ll_disable_stage(hw, stage) + +#define rwdt_ll_set_cpu_reset_length(hw, length) \ + lpwdt_ll_set_cpu_reset_length(hw, length) + +#define rwdt_ll_set_sys_reset_length(hw, length) \ + lpwdt_ll_set_sys_reset_length(hw, length) + +#define rwdt_ll_set_flashboot_en(hw, enable) \ + lpwdt_ll_set_flashboot_en(hw, enable) + +#define rwdt_ll_set_procpu_reset_en(hw, enable) \ + lpwdt_ll_set_procpu_reset_en(hw, enable) + +#define rwdt_ll_set_appcpu_reset_en(hw, enable) \ + lpwdt_ll_set_appcpu_reset_en(hw, enable) + +#define rwdt_ll_set_pause_in_sleep_en(hw, enable) \ + lpwdt_ll_set_pause_in_sleep_en(hw, enable) + +#define rwdt_ll_set_chip_reset_en(hw, enable) \ + lpwdt_ll_set_chip_reset_en(hw, enable) + +#define rwdt_ll_set_chip_reset_width(hw, width) \ + lpwdt_ll_set_chip_reset_width(hw, width) + +#define rwdt_ll_feed(hw) \ + lpwdt_ll_feed(hw) + +#define rwdt_ll_write_protect_enable(hw) \ + lpwdt_ll_write_protect_enable(hw) + +#define rwdt_ll_write_protect_disable(hw) \ + lpwdt_ll_write_protect_disable(hw) + +#define rwdt_ll_set_intr_enable(hw, enable) \ + lpwdt_ll_set_intr_enable(hw, enable) + +#define rwdt_ll_check_intr_status(hw) \ + lpwdt_ll_check_intr_status(hw) + +#define rwdt_ll_clear_intr_status(hw) \ + lpwdt_ll_clear_intr_status(hw) + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/spi_flash_encrypted_ll.h b/components/hal/esp32h2/include/hal/spi_flash_encrypted_ll.h new file mode 100644 index 0000000000..db90f252a3 --- /dev/null +++ b/components/hal/esp32h2/include/hal/spi_flash_encrypted_ll.h @@ -0,0 +1,149 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/******************************************************************************* + * NOTICE + * The ll is not public api, don't use in application code. + * See readme.md in hal/include/hal/readme.md + ******************************************************************************/ + +// The Lowlevel layer for SPI Flash Encryption. + +#include +#include +#include "soc/hp_system_reg.h" +#include "soc/spi_mem_reg.h" +#include "soc/soc.h" +#include "hal/assert.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Choose type of chip you want to encrypt manully +typedef enum +{ + FLASH_ENCRYPTION_MANU = 0, ///!< Manually encrypt the flash chip. + PSRAM_ENCRYPTION_MANU = 1 ///!< Manually encrypt the psram chip. +} flash_encrypt_ll_type_t; + +/** + * Enable the flash encryption function under spi boot mode and download boot mode. + */ +static inline void spi_flash_encrypt_ll_enable(void) +{ + // REG_SET_BIT(HP_SYSTEM_EXTERNAL_DEVICE_ENCRYPT_DECRYPT_CONTROL_REG, + // HP_SYSTEM_ENABLE_DOWNLOAD_MANUAL_ENCRYPT | + // HP_SYSTEM_ENABLE_SPI_MANUAL_ENCRYPT); +} + +/* + * Disable the flash encryption mode. + */ +static inline void spi_flash_encrypt_ll_disable(void) +{ + // REG_CLR_BIT(HP_SYSTEM_EXTERNAL_DEVICE_ENCRYPT_DECRYPT_CONTROL_REG, + // HP_SYSTEM_ENABLE_SPI_MANUAL_ENCRYPT); +} + +/** + * Choose type of chip you want to encrypt manully + * + * @param type The type of chip to be encrypted + * + * @note The hardware currently support flash encryption. + */ +static inline void spi_flash_encrypt_ll_type(flash_encrypt_ll_type_t type) +{ + // Our hardware only support flash encryption + // HAL_ASSERT(type == FLASH_ENCRYPTION_MANU); + // REG_SET_FIELD(SPI_MEM_XTS_DESTINATION_REG(0), SPI_MEM_XTS_DESTINATION, type); +} + +/** + * Configure the data size of a single encryption. + * + * @param block_size Size of the desired block. + */ +static inline void spi_flash_encrypt_ll_buffer_length(uint32_t size) +{ + // Desired block should not be larger than the block size. + // REG_SET_FIELD(SPI_MEM_XTS_LINESIZE_REG(0), SPI_MEM_XTS_LINESIZE, size >> 5); +} + +/** + * Save 32-bit piece of plaintext. + * + * @param address the address of written flash partition. + * @param buffer Buffer to store the input data. + * @param size Buffer size. + * + */ +static inline void spi_flash_encrypt_ll_plaintext_save(uint32_t address, const uint32_t* buffer, uint32_t size) +{ + // uint32_t plaintext_offs = (address % 64); + // memcpy((void *)(SPI_MEM_XTS_PLAIN_BASE_REG(0) + plaintext_offs), buffer, size); +} + +/** + * Copy the flash address to XTS_AES physical address + * + * @param flash_addr flash address to write. + */ +static inline void spi_flash_encrypt_ll_address_save(uint32_t flash_addr) +{ + // REG_SET_FIELD(SPI_MEM_XTS_PHYSICAL_ADDRESS_REG(0), SPI_MEM_XTS_PHYSICAL_ADDRESS, flash_addr); +} + +/** + * Start flash encryption + */ +static inline void spi_flash_encrypt_ll_calculate_start(void) +{ + // REG_SET_FIELD(SPI_MEM_XTS_TRIGGER_REG(0), SPI_MEM_XTS_TRIGGER, 1); +} + +/** + * Wait for flash encryption termination + */ +static inline void spi_flash_encrypt_ll_calculate_wait_idle(void) +{ + // while(REG_GET_FIELD(SPI_MEM_XTS_STATE_REG(0), SPI_MEM_XTS_STATE) == 0x1) { + // } +} + +/** + * Finish the flash encryption and make encrypted result accessible to SPI. + */ +static inline void spi_flash_encrypt_ll_done(void) +{ + // REG_SET_BIT(SPI_MEM_XTS_RELEASE_REG(0), SPI_MEM_XTS_RELEASE); + // while(REG_GET_FIELD(SPI_MEM_XTS_STATE_REG(0), SPI_MEM_XTS_STATE) != 0x3) { + // } +} + +/** + * Set to destroy encrypted result + */ +static inline void spi_flash_encrypt_ll_destroy(void) +{ + // REG_SET_BIT(SPI_MEM_XTS_DESTROY_REG(0), SPI_MEM_XTS_DESTROY); +} + +/** + * Check if is qualified to encrypt the buffer + * + * @param address the address of written flash partition. + * @param length Buffer size. + */ +static inline bool spi_flash_encrypt_ll_check(uint32_t address, uint32_t length) +{ + return false;//((address % length) == 0) ? true : false; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/spi_flash_ll.h b/components/hal/esp32h2/include/hal/spi_flash_ll.h new file mode 100644 index 0000000000..425695498d --- /dev/null +++ b/components/hal/esp32h2/include/hal/spi_flash_ll.h @@ -0,0 +1,100 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/******************************************************************************* + * NOTICE + * The ll is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The Lowlevel layer for SPI Flash + +#pragma once + +#include "gpspi_flash_ll.h" +#include "spimem_flash_ll.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define spi_flash_ll_calculate_clock_reg(host_id, clock_div) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_calculate_clock_reg(clock_div) \ + : gpspi_flash_ll_calculate_clock_reg(clock_div)) + +#define spi_flash_ll_get_source_clock_freq_mhz(host_id) (((host_id)<=SPI1_HOST) ? spimem_flash_ll_get_source_freq_mhz() : GPSPI_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ) + +#define spi_flash_ll_get_hw(host_id) (((host_id)<=SPI1_HOST ? (spi_dev_t*) spimem_flash_ll_get_hw(host_id) \ + : gpspi_flash_ll_get_hw(host_id))) + +#define spi_flash_ll_hw_get_id(dev) ({int dev_id = spimem_flash_ll_hw_get_id(dev); \ + if (dev_id < 0) {\ + dev_id = gpspi_flash_ll_hw_get_id(dev);\ + }\ + dev_id; \ + }) +// Since ESP32-H2, WB_mode is available, we extend 8 bits to occupy `Continuous Read Mode` bits. +#define SPI_FLASH_LL_CONTINUOUS_MODE_BIT_NUMS (8) + +typedef union { + gpspi_flash_ll_clock_reg_t gpspi; + spimem_flash_ll_clock_reg_t spimem; +} spi_flash_ll_clock_reg_t; + +#ifdef GPSPI_BUILD +#define spi_flash_ll_reset(dev) gpspi_flash_ll_reset((spi_dev_t*)dev) +#define spi_flash_ll_cmd_is_done(dev) gpspi_flash_ll_cmd_is_done((spi_dev_t*)dev) +#define spi_flash_ll_get_buffer_data(dev, buffer, read_len) gpspi_flash_ll_get_buffer_data((spi_dev_t*)dev, buffer, read_len) +#define spi_flash_ll_set_buffer_data(dev, buffer, len) gpspi_flash_ll_set_buffer_data((spi_dev_t*)dev, buffer, len) +#define spi_flash_ll_user_start(dev) gpspi_flash_ll_user_start((spi_dev_t*)dev) +#define spi_flash_ll_host_idle(dev) gpspi_flash_ll_host_idle((spi_dev_t*)dev) +#define spi_flash_ll_read_phase(dev) gpspi_flash_ll_read_phase((spi_dev_t*)dev) +#define spi_flash_ll_set_cs_pin(dev, pin) gpspi_flash_ll_set_cs_pin((spi_dev_t*)dev, pin) +#define spi_flash_ll_set_read_mode(dev, read_mode) gpspi_flash_ll_set_read_mode((spi_dev_t*)dev, read_mode) +#define spi_flash_ll_set_clock(dev, clk) gpspi_flash_ll_set_clock((spi_dev_t*)dev, (gpspi_flash_ll_clock_reg_t*)clk) +#define spi_flash_ll_set_miso_bitlen(dev, bitlen) gpspi_flash_ll_set_miso_bitlen((spi_dev_t*)dev, bitlen) +#define spi_flash_ll_set_mosi_bitlen(dev, bitlen) gpspi_flash_ll_set_mosi_bitlen((spi_dev_t*)dev, bitlen) +#define spi_flash_ll_set_command(dev, cmd, bitlen) gpspi_flash_ll_set_command((spi_dev_t*)dev, cmd, bitlen) +#define spi_flash_ll_set_addr_bitlen(dev, bitlen) gpspi_flash_ll_set_addr_bitlen((spi_dev_t*)dev, bitlen) +#define spi_flash_ll_get_addr_bitlen(dev) gpspi_flash_ll_get_addr_bitlen((spi_dev_t*)dev) +#define spi_flash_ll_set_address(dev, addr) gpspi_flash_ll_set_address((spi_dev_t*)dev, addr) +#define spi_flash_ll_set_usr_address(dev, addr, bitlen) gpspi_flash_ll_set_usr_address((spi_dev_t*)dev, addr, bitlen) +#define spi_flash_ll_set_dummy(dev, dummy) gpspi_flash_ll_set_dummy((spi_dev_t*)dev, dummy) +#define spi_flash_ll_set_hold(dev, hold_n) gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n) +#define spi_flash_ll_set_cs_setup(dev, cs_setup_time) gpspi_flash_ll_set_cs_setup((spi_dev_t*)dev, cs_setup_time) +#define spi_flash_ll_set_extra_address(dev, extra_addr) { /* Not supported on gpspi on ESP32-H2*/ } +#else +#define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev) +#define spi_flash_ll_cmd_is_done(dev) spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev) +#define spi_flash_ll_erase_chip(dev) spimem_flash_ll_erase_chip((spi_mem_dev_t*)dev) +#define spi_flash_ll_erase_sector(dev) spimem_flash_ll_erase_sector((spi_mem_dev_t*)dev) +#define spi_flash_ll_erase_block(dev) spimem_flash_ll_erase_block((spi_mem_dev_t*)dev) +#define spi_flash_ll_set_write_protect(dev, wp) spimem_flash_ll_set_write_protect((spi_mem_dev_t*)dev, wp) +#define spi_flash_ll_get_buffer_data(dev, buffer, read_len) spimem_flash_ll_get_buffer_data((spi_mem_dev_t*)dev, buffer, read_len) +#define spi_flash_ll_set_buffer_data(dev, buffer, len) spimem_flash_ll_set_buffer_data((spi_mem_dev_t*)dev, buffer, len) +#define spi_flash_ll_program_page(dev, buffer, len) spimem_flash_ll_program_page((spi_mem_dev_t*)dev, buffer, len) +#define spi_flash_ll_user_start(dev) spimem_flash_ll_user_start((spi_mem_dev_t*)dev) +#define spi_flash_ll_host_idle(dev) spimem_flash_ll_host_idle((spi_mem_dev_t*)dev) +#define spi_flash_ll_read_phase(dev) spimem_flash_ll_read_phase((spi_mem_dev_t*)dev) +#define spi_flash_ll_set_cs_pin(dev, pin) spimem_flash_ll_set_cs_pin((spi_mem_dev_t*)dev, pin) +#define spi_flash_ll_set_read_mode(dev, read_mode) spimem_flash_ll_set_read_mode((spi_mem_dev_t*)dev, read_mode) +#define spi_flash_ll_set_clock(dev, clk) spimem_flash_ll_set_clock((spi_mem_dev_t*)dev, (spimem_flash_ll_clock_reg_t*)clk) +#define spi_flash_ll_set_miso_bitlen(dev, bitlen) spimem_flash_ll_set_miso_bitlen((spi_mem_dev_t*)dev, bitlen) +#define spi_flash_ll_set_mosi_bitlen(dev, bitlen) spimem_flash_ll_set_mosi_bitlen((spi_mem_dev_t*)dev, bitlen) +#define spi_flash_ll_set_command(dev, cmd, bitlen) spimem_flash_ll_set_command((spi_mem_dev_t*)dev, cmd, bitlen) +#define spi_flash_ll_set_addr_bitlen(dev, bitlen) spimem_flash_ll_set_addr_bitlen((spi_mem_dev_t*)dev, bitlen) +#define spi_flash_ll_get_addr_bitlen(dev) spimem_flash_ll_get_addr_bitlen((spi_mem_dev_t*) dev) +#define spi_flash_ll_set_address(dev, addr) spimem_flash_ll_set_address((spi_mem_dev_t*)dev, addr) +#define spi_flash_ll_set_usr_address(dev, addr, bitlen) spimem_flash_ll_set_usr_address((spi_mem_dev_t*)dev, addr, bitlen) +#define spi_flash_ll_set_dummy(dev, dummy) spimem_flash_ll_set_dummy((spi_mem_dev_t*)dev, dummy) +#define spi_flash_ll_set_hold(dev, hold_n) spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n) +#define spi_flash_ll_set_cs_setup(dev, cs_setup_time) spimem_flash_ll_set_cs_setup((spi_mem_dev_t*)dev, cs_setup_time) +#define spi_flash_ll_set_extra_address(dev, extra_addr) spimem_flash_ll_set_extra_address((spi_mem_dev_t*)dev, extra_addr) + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/spi_ll.h b/components/hal/esp32h2/include/hal/spi_ll.h new file mode 100644 index 0000000000..ba54cc4e0d --- /dev/null +++ b/components/hal/esp32h2/include/hal/spi_ll.h @@ -0,0 +1,1081 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/******************************************************************************* + * NOTICE + * The hal is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The LL layer for SPI register operations + +#pragma once + +#include //for abs() +#include +#include "esp_attr.h" +#include "esp_types.h" +#include "soc/spi_periph.h" +#include "soc/spi_struct.h" +#include "soc/lldesc.h" +#include "hal/assert.h" +#include "hal/misc.h" +#include "hal/spi_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Interrupt not used. Don't use in app. +#define SPI_LL_UNUSED_INT_MASK (SPI_TRANS_DONE_INT_ENA | SPI_SLV_WR_DMA_DONE_INT_ENA | SPI_SLV_RD_DMA_DONE_INT_ENA | SPI_SLV_WR_BUF_DONE_INT_ENA | SPI_SLV_RD_BUF_DONE_INT_ENA) +/// These 2 masks together will set SPI transaction to one line mode +#define SPI_LL_ONE_LINE_CTRL_MASK (SPI_FREAD_QUAD | SPI_FREAD_DUAL | SPI_FCMD_QUAD | SPI_FCMD_DUAL | SPI_FADDR_QUAD | SPI_FADDR_DUAL) +#define SPI_LL_ONE_LINE_USER_MASK (SPI_FWRITE_QUAD | SPI_FWRITE_DUAL) +/// Swap the bit order to its correct place to send +#define HAL_SPI_SWAP_DATA_TX(data, len) HAL_SWAP32((uint32_t)(data) << (32 - len)) +/// This is the expected clock frequency +#define SPI_LL_PERIPH_CLK_FREQ (80 * 1000000) +#define SPI_LL_GET_HW(ID) ((ID)==0? ({abort();NULL;}):&GPSPI2) + +#define SPI_LL_DATA_MAX_BIT_LEN (1 << 18) + +/** + * The data structure holding calculated clock configuration. Since the + * calculation needs long time, it should be calculated during initialization and + * stored somewhere to be quickly used. + */ +typedef uint32_t spi_ll_clock_val_t; +typedef spi_dev_t spi_dma_dev_t; + +// Type definition of all supported interrupts +typedef enum { + SPI_LL_INTR_TRANS_DONE = BIT(0), ///< A transaction has done + SPI_LL_INTR_RDBUF = BIT(6), ///< Has received RDBUF command. Only available in slave HD. + SPI_LL_INTR_WRBUF = BIT(7), ///< Has received WRBUF command. Only available in slave HD. + SPI_LL_INTR_RDDMA = BIT(8), ///< Has received RDDMA command. Only available in slave HD. + SPI_LL_INTR_WRDMA = BIT(9), ///< Has received WRDMA command. Only available in slave HD. + SPI_LL_INTR_CMD7 = BIT(10), ///< Has received CMD7 command. Only available in slave HD. + SPI_LL_INTR_CMD8 = BIT(11), ///< Has received CMD8 command. Only available in slave HD. + SPI_LL_INTR_CMD9 = BIT(12), ///< Has received CMD9 command. Only available in slave HD. + SPI_LL_INTR_CMDA = BIT(13), ///< Has received CMDA command. Only available in slave HD. + SPI_LL_INTR_SEG_DONE = BIT(14), +} spi_ll_intr_t; +FLAG_ATTR(spi_ll_intr_t) + +// Flags for conditions under which the transaction length should be recorded +typedef enum { + SPI_LL_TRANS_LEN_COND_WRBUF = BIT(0), ///< WRBUF length will be recorded + SPI_LL_TRANS_LEN_COND_RDBUF = BIT(1), ///< RDBUF length will be recorded + SPI_LL_TRANS_LEN_COND_WRDMA = BIT(2), ///< WRDMA length will be recorded + SPI_LL_TRANS_LEN_COND_RDDMA = BIT(3), ///< RDDMA length will be recorded +} spi_ll_trans_len_cond_t; +FLAG_ATTR(spi_ll_trans_len_cond_t) + +/*------------------------------------------------------------------------------ + * Control + *----------------------------------------------------------------------------*/ +/** + * Initialize SPI peripheral (master). + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_master_init(spi_dev_t *hw) +{ + //Reset timing + hw->user1.cs_setup_time = 0; + hw->user1.cs_hold_time = 0; + + //use all 64 bytes of the buffer + hw->user.usr_miso_highpart = 0; + hw->user.usr_mosi_highpart = 0; + + //Disable unneeded ints + hw->slave.val = 0; + hw->user.val = 0; + + hw->clk_gate.clk_en = 1; + hw->clk_gate.mst_clk_active = 1; + hw->clk_gate.mst_clk_sel = 1; + + hw->dma_conf.val = 0; + hw->dma_conf.tx_seg_trans_clr_en = 1; + hw->dma_conf.rx_seg_trans_clr_en = 1; + hw->dma_conf.dma_seg_trans_en = 0; +} + +/** + * Initialize SPI peripheral (slave). + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_slave_init(spi_dev_t *hw) +{ + //Configure slave + hw->clock.val = 0; + hw->user.val = 0; + hw->ctrl.val = 0; + hw->user.doutdin = 1; //we only support full duplex + hw->user.sio = 0; + hw->slave.slave_mode = 1; + hw->slave.soft_reset = 1; + hw->slave.soft_reset = 0; + //use all 64 bytes of the buffer + hw->user.usr_miso_highpart = 0; + hw->user.usr_mosi_highpart = 0; + + // Configure DMA In-Link to not be terminated when transaction bit counter exceeds + hw->dma_conf.rx_eof_en = 0; + hw->dma_conf.dma_seg_trans_en = 0; + + //Disable unneeded ints + hw->dma_int_ena.val &= ~SPI_LL_UNUSED_INT_MASK; +} + +/** + * Initialize SPI peripheral (slave half duplex mode) + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_slave_hd_init(spi_dev_t *hw) +{ + hw->clock.val = 0; + hw->user.val = 0; + hw->ctrl.val = 0; + hw->user.doutdin = 0; + hw->user.sio = 0; + + hw->slave.soft_reset = 1; + hw->slave.soft_reset = 0; + hw->slave.slave_mode = 1; +} + +/** + * Check whether user-defined transaction is done. + * + * @param hw Beginning address of the peripheral registers. + * + * @return True if transaction is done, otherwise false. + */ +static inline bool spi_ll_usr_is_done(spi_dev_t *hw) +{ + return hw->dma_int_raw.trans_done; +} + +/** + * Trigger start of user-defined transaction for master. + * The synchronization between two clock domains is required in ESP32-S3 + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_master_user_start(spi_dev_t *hw) +{ + hw->cmd.update = 1; + while (hw->cmd.update); + hw->cmd.usr = 1; +} + +/** + * Trigger start of user-defined transaction for slave. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_slave_user_start(spi_dev_t *hw) +{ + hw->cmd.usr = 1; +} + +/** + * Get current running command bit-mask. (Preview) + * + * @param hw Beginning address of the peripheral registers. + * + * @return Bitmask of running command, see ``SPI_CMD_REG``. 0 if no in-flight command. + */ +static inline uint32_t spi_ll_get_running_cmd(spi_dev_t *hw) +{ + return hw->cmd.val; +} + +/** + * Reset the slave peripheral before next transaction. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_slave_reset(spi_dev_t *hw) +{ + hw->slave.soft_reset = 1; + hw->slave.soft_reset = 0; +} + +/** + * Reset SPI CPU TX FIFO + * + * On ESP32H2, this function is not seperated + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_cpu_tx_fifo_reset(spi_dev_t *hw) +{ + hw->dma_conf.buf_afifo_rst = 1; + hw->dma_conf.buf_afifo_rst = 0; +} + +/** + * Reset SPI CPU RX FIFO + * + * On ESP32H2, this function is not seperated + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_cpu_rx_fifo_reset(spi_dev_t *hw) +{ + hw->dma_conf.rx_afifo_rst = 1; + hw->dma_conf.rx_afifo_rst = 0; +} + +/** + * Reset SPI DMA TX FIFO + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_dma_tx_fifo_reset(spi_dev_t *hw) +{ + hw->dma_conf.dma_afifo_rst = 1; + hw->dma_conf.dma_afifo_rst = 0; +} + +/** + * Reset SPI DMA RX FIFO + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_dma_rx_fifo_reset(spi_dev_t *hw) +{ + hw->dma_conf.rx_afifo_rst = 1; + hw->dma_conf.rx_afifo_rst = 0; +} + +/** + * Clear in fifo full error + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_infifo_full_clr(spi_dev_t *hw) +{ + hw->dma_int_clr.infifo_full_err = 1; +} + +/** + * Clear out fifo empty error + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_outfifo_empty_clr(spi_dev_t *hw) +{ + hw->dma_int_clr.outfifo_empty_err = 1; +} + +/*------------------------------------------------------------------------------ + * DMA + *----------------------------------------------------------------------------*/ +/** + * Enable/Disable RX DMA (Peripherals->DMA->RAM) + * + * @param hw Beginning address of the peripheral registers. + * @param enable 1: enable; 2: disable + */ +static inline void spi_ll_dma_rx_enable(spi_dev_t *hw, bool enable) +{ + hw->dma_conf.dma_rx_ena = enable; +} + +/** + * Enable/Disable TX DMA (RAM->DMA->Peripherals) + * + * @param hw Beginning address of the peripheral registers. + * @param enable 1: enable; 2: disable + */ +static inline void spi_ll_dma_tx_enable(spi_dev_t *hw, bool enable) +{ + hw->dma_conf.dma_tx_ena = enable; +} + +/** + * Configuration of RX DMA EOF interrupt generation way + * + * @param hw Beginning address of the peripheral registers. + * @param enable 1: spi_dma_inlink_eof is set when the number of dma pushed data bytes is equal to the value of spi_slv/mst_dma_rd_bytelen[19:0] in spi dma transition. 0: spi_dma_inlink_eof is set by spi_trans_done in non-seg-trans or spi_dma_seg_trans_done in seg-trans. + */ +static inline void spi_ll_dma_set_rx_eof_generation(spi_dev_t *hw, bool enable) +{ + hw->dma_conf.rx_eof_en = enable; +} + +/*------------------------------------------------------------------------------ + * Buffer + *----------------------------------------------------------------------------*/ +/** + * Write to SPI hardware data buffer. + * + * @param hw Beginning address of the peripheral registers. + * @param buffer_to_send Address of the data to be written to the hardware data buffer. + * @param bitlen Length to write, in bits. + */ +static inline void spi_ll_write_buffer(spi_dev_t *hw, const uint8_t *buffer_to_send, size_t bitlen) +{ + for (int x = 0; x < bitlen; x += 32) { + //Use memcpy to get around alignment issues for txdata + uint32_t word; + memcpy(&word, &buffer_to_send[x / 8], 4); + hw->data_buf[(x / 32)] = word; + } +} + +/** + * Write to SPI hardware data buffer by buffer ID (address) + * + * @param hw Beginning address of the peripheral registers + * @param byte_id Start ID (address) of the hardware buffer to be written + * @param data Address of the data to be written to the hardware data buffer. + * @param len Length to write, in bytes. + */ +static inline void spi_ll_write_buffer_byte(spi_dev_t *hw, int byte_id, uint8_t *data, int len) +{ + HAL_ASSERT(byte_id + len <= 64); + HAL_ASSERT(len > 0); + HAL_ASSERT(byte_id >= 0); + + while (len > 0) { + uint32_t word; + int offset = byte_id % 4; + int copy_len = 4 - offset; + if (copy_len > len) { + copy_len = len; + } + + //read-modify-write + if (copy_len != 4) { + word = hw->data_buf[byte_id / 4]; //read + } + memcpy(((uint8_t *)&word) + offset, data, copy_len); //modify + hw->data_buf[byte_id / 4] = word; //write + + data += copy_len; + byte_id += copy_len; + len -= copy_len; + } +} + +/** + * Read from SPI hardware data buffer. + * + * @param hw Beginning address of the peripheral registers. + * @param buffer_to_rcv Address of a buffer to read data from hardware data buffer + * @param bitlen Length to read, in bits. + */ +static inline void spi_ll_read_buffer(spi_dev_t *hw, uint8_t *buffer_to_rcv, size_t bitlen) +{ + for (int x = 0; x < bitlen; x += 32) { + //Do a memcpy to get around possible alignment issues in rx_buffer + uint32_t word = hw->data_buf[x / 32]; + int len = bitlen - x; + if (len > 32) { + len = 32; + } + memcpy(&buffer_to_rcv[x / 8], &word, (len + 7) / 8); + } +} + +/** + * Read from SPI hardware data buffer by buffer ID (address) + * + * @param hw Beginning address of the peripheral registers + * @param byte_id Start ID (address) of the hardware buffer to be read + * @param data Address of a buffer to read data from hardware data buffer + * @param len Length to read, in bytes. + */ +static inline void spi_ll_read_buffer_byte(spi_dev_t *hw, int byte_id, uint8_t *out_data, int len) +{ + while (len > 0) { + uint32_t word = hw->data_buf[byte_id / 4]; + int offset = byte_id % 4; + int copy_len = 4 - offset; + if (copy_len > len) { + copy_len = len; + } + + memcpy(out_data, ((uint8_t *)&word) + offset, copy_len); + byte_id += copy_len; + out_data += copy_len; + len -= copy_len; + } +} + +/*------------------------------------------------------------------------------ + * Configs: mode + *----------------------------------------------------------------------------*/ +/** + * Enable/disable the postive-cs feature. + * + * @param hw Beginning address of the peripheral registers. + * @param cs One of the CS (0-2) to enable/disable the feature. + * @param pos_cs True to enable the feature, otherwise disable (default). + */ +static inline void spi_ll_master_set_pos_cs(spi_dev_t *hw, int cs, uint32_t pos_cs) +{ + if (pos_cs) { + hw->misc.master_cs_pol |= (1 << cs); + } else { + hw->misc.master_cs_pol &= ~(1 << cs); + } +} + +/** + * Enable/disable the LSBFIRST feature for TX data. + * + * @param hw Beginning address of the peripheral registers. + * @param lsbfirst True if LSB of TX data to be sent first, otherwise MSB is sent first (default). + */ +static inline void spi_ll_set_tx_lsbfirst(spi_dev_t *hw, bool lsbfirst) +{ + hw->ctrl.wr_bit_order = lsbfirst; +} + +/** + * Enable/disable the LSBFIRST feature for RX data. + * + * @param hw Beginning address of the peripheral registers. + * @param lsbfirst True if first bit received as LSB, otherwise as MSB (default). + */ +static inline void spi_ll_set_rx_lsbfirst(spi_dev_t *hw, bool lsbfirst) +{ + hw->ctrl.rd_bit_order = lsbfirst; +} + +/** + * Set SPI mode for the peripheral as master. + * + * @param hw Beginning address of the peripheral registers. + * @param mode SPI mode to work at, 0-3. + */ +static inline void spi_ll_master_set_mode(spi_dev_t *hw, uint8_t mode) +{ + //Configure polarity + if (mode == 0) { + hw->misc.ck_idle_edge = 0; + hw->user.ck_out_edge = 0; + } else if (mode == 1) { + hw->misc.ck_idle_edge = 0; + hw->user.ck_out_edge = 1; + } else if (mode == 2) { + hw->misc.ck_idle_edge = 1; + hw->user.ck_out_edge = 1; + } else if (mode == 3) { + hw->misc.ck_idle_edge = 1; + hw->user.ck_out_edge = 0; + } +} + +/** + * Set SPI mode for the peripheral as slave. + * + * @param hw Beginning address of the peripheral registers. + * @param mode SPI mode to work at, 0-3. + */ +static inline void spi_ll_slave_set_mode(spi_dev_t *hw, const int mode, bool dma_used) +{ + if (mode == 0) { + hw->misc.ck_idle_edge = 0; + hw->user.rsck_i_edge = 0; + hw->user.tsck_i_edge = 0; + hw->slave.clk_mode_13 = 0; + } else if (mode == 1) { + hw->misc.ck_idle_edge = 0; + hw->user.rsck_i_edge = 1; + hw->user.tsck_i_edge = 1; + hw->slave.clk_mode_13 = 1; + } else if (mode == 2) { + hw->misc.ck_idle_edge = 1; + hw->user.rsck_i_edge = 1; + hw->user.tsck_i_edge = 1; + hw->slave.clk_mode_13 = 0; + } else if (mode == 3) { + hw->misc.ck_idle_edge = 1; + hw->user.rsck_i_edge = 0; + hw->user.tsck_i_edge = 0; + hw->slave.clk_mode_13 = 1; + } + hw->slave.rsck_data_out = 0; +} + +/** + * Set SPI to work in full duplex or half duplex mode. + * + * @param hw Beginning address of the peripheral registers. + * @param half_duplex True to work in half duplex mode, otherwise in full duplex mode. + */ +static inline void spi_ll_set_half_duplex(spi_dev_t *hw, bool half_duplex) +{ + hw->user.doutdin = !half_duplex; +} + +/** + * Set SPI to work in SIO mode or not. + * + * SIO is a mode which MOSI and MISO share a line. The device MUST work in half-duplexmode. + * + * @param hw Beginning address of the peripheral registers. + * @param sio_mode True to work in SIO mode, otherwise false. + */ +static inline void spi_ll_set_sio_mode(spi_dev_t *hw, int sio_mode) +{ + hw->user.sio = sio_mode; +} + +/** + * Configure the SPI transaction line mode for the master to use. + * + * @param hw Beginning address of the peripheral registers. + * @param line_mode SPI transaction line mode to use, see ``spi_line_mode_t``. + */ +static inline void spi_ll_master_set_line_mode(spi_dev_t *hw, spi_line_mode_t line_mode) +{ + hw->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK; + hw->user.val &= ~SPI_LL_ONE_LINE_USER_MASK; + hw->ctrl.fcmd_dual = (line_mode.cmd_lines == 2); + hw->ctrl.fcmd_quad = (line_mode.cmd_lines == 4); + hw->ctrl.faddr_dual = (line_mode.addr_lines == 2); + hw->ctrl.faddr_quad = (line_mode.addr_lines == 4); + hw->ctrl.fread_dual = (line_mode.data_lines == 2); + hw->user.fwrite_dual = (line_mode.data_lines == 2); + hw->ctrl.fread_quad = (line_mode.data_lines == 4); + hw->user.fwrite_quad = (line_mode.data_lines == 4); +} + +/** + * Set the SPI slave to work in segment transaction mode + * + * @param hw Beginning address of the peripheral registers. + * @param seg_trans True to work in seg mode, otherwise false. + */ +static inline void spi_ll_slave_set_seg_mode(spi_dev_t *hw, bool seg_trans) +{ + hw->dma_conf.dma_seg_trans_en = seg_trans; +} + +/** + * Select one of the CS to use in current transaction. + * + * @param hw Beginning address of the peripheral registers. + * @param cs_id The cs to use, 0-2, otherwise none of them is used. + */ +static inline void spi_ll_master_select_cs(spi_dev_t *hw, int cs_id) +{ + hw->misc.cs0_dis = (cs_id == 0) ? 0 : 1; + hw->misc.cs1_dis = (cs_id == 1) ? 0 : 1; + hw->misc.cs2_dis = (cs_id == 2) ? 0 : 1; + hw->misc.cs3_dis = (cs_id == 3) ? 0 : 1; + hw->misc.cs4_dis = (cs_id == 4) ? 0 : 1; + hw->misc.cs5_dis = (cs_id == 5) ? 0 : 1; +} + +/** + * Keep Chip Select activated after the current transaction. + * + * @param hw Beginning address of the peripheral registers. + * @param keep_active if 0 don't keep CS activated, else keep CS activated + */ +static inline void spi_ll_master_keep_cs(spi_dev_t *hw, int keep_active) +{ + hw->misc.cs_keep_active = (keep_active != 0) ? 1 : 0; +} + +/*------------------------------------------------------------------------------ + * Configs: parameters + *----------------------------------------------------------------------------*/ +/** + * Set the clock for master by stored value. + * + * @param hw Beginning address of the peripheral registers. + * @param val Stored clock configuration calculated before (by ``spi_ll_cal_clock``). + */ +static inline void spi_ll_master_set_clock_by_reg(spi_dev_t *hw, const spi_ll_clock_val_t *val) +{ + hw->clock.val = *(uint32_t *)val; +} + +/** + * Get the frequency of given dividers. Don't use in app. + * + * @param fapb APB clock of the system. + * @param pre Pre devider. + * @param n Main divider. + * + * @return Frequency of given dividers. + */ +static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n) +{ + return (fapb / (pre * n)); +} + +/** + * Calculate the nearest frequency avaliable for master. + * + * @param fapb APB clock of the system. + * @param hz Frequncy desired. + * @param duty_cycle Duty cycle desired. + * @param out_reg Output address to store the calculated clock configurations for the return frequency. + * + * @return Actual (nearest) frequency. + */ +static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_ll_clock_val_t *out_reg) +{ + typeof(GPSPI2.clock) reg; + int eff_clk; + + //In hw, n, h and l are 1-64, pre is 1-8K. Value written to register is one lower than used value. + if (hz > ((fapb / 4) * 3)) { + //Using Fapb directly will give us the best result here. + reg.clkcnt_l = 0; + reg.clkcnt_h = 0; + reg.clkcnt_n = 0; + reg.clkdiv_pre = 0; + reg.clk_equ_sysclk = 1; + eff_clk = fapb; + } else { + //For best duty cycle resolution, we want n to be as close to 32 as possible, but + //we also need a pre/n combo that gets us as close as possible to the intended freq. + //To do this, we bruteforce n and calculate the best pre to go along with that. + //If there's a choice between pre/n combos that give the same result, use the one + //with the higher n. + int pre, n, h, l; + int bestn = -1; + int bestpre = -1; + int besterr = 0; + int errval; + for (n = 2; n <= 64; n++) { //Start at 2: we need to be able to set h/l so we have at least one high and one low pulse. + //Effectively, this does pre=round((fapb/n)/hz). + pre = ((fapb / n) + (hz / 2)) / hz; + if (pre <= 0) { + pre = 1; + } + if (pre > 16) { + pre = 16; + } + errval = abs(spi_ll_freq_for_pre_n(fapb, pre, n) - hz); + if (bestn == -1 || errval <= besterr) { + besterr = errval; + bestn = n; + bestpre = pre; + } + } + + n = bestn; + pre = bestpre; + l = n; + //This effectively does round((duty_cycle*n)/256) + h = (duty_cycle * n + 127) / 256; + if (h <= 0) { + h = 1; + } + + reg.clk_equ_sysclk = 0; + reg.clkcnt_n = n - 1; + reg.clkdiv_pre = pre - 1; + reg.clkcnt_h = h - 1; + reg.clkcnt_l = l - 1; + eff_clk = spi_ll_freq_for_pre_n(fapb, pre, n); + } + if (out_reg != NULL) { + *(uint32_t *)out_reg = reg.val; + } + return eff_clk; +} + +/** + * Calculate and set clock for SPI master according to desired parameters. + * + * This takes long, suggest to calculate the configuration during + * initialization by ``spi_ll_master_cal_clock`` and store the result, then + * configure the clock by stored value when used by + * ``spi_ll_msater_set_clock_by_reg``. + * + * @param hw Beginning address of the peripheral registers. + * @param fapb APB clock of the system. + * @param hz Frequncy desired. + * @param duty_cycle Duty cycle desired. + * + * @return Actual frequency that is used. + */ +static inline int spi_ll_master_set_clock(spi_dev_t *hw, int fapb, int hz, int duty_cycle) +{ + spi_ll_clock_val_t reg_val; + int freq = spi_ll_master_cal_clock(fapb, hz, duty_cycle, ®_val); + spi_ll_master_set_clock_by_reg(hw, ®_val); + return freq; +} + +/** + * Set the mosi delay after the output edge to the signal. (Preview) + * + * The delay mode/num is a Espressif conception, may change in the new chips. + * + * @param hw Beginning address of the peripheral registers. + * @param delay_mode Delay mode, see TRM. + * @param delay_num APB clocks to delay. + */ +static inline void spi_ll_set_mosi_delay(spi_dev_t *hw, int delay_mode, int delay_num) +{ +} + +/** + * Set the miso delay applied to the input signal before the internal peripheral. (Preview) + * + * The delay mode/num is a Espressif conception, may change in the new chips. + * + * @param hw Beginning address of the peripheral registers. + * @param delay_mode Delay mode, see TRM. + * @param delay_num APB clocks to delay. + */ +static inline void spi_ll_set_miso_delay(spi_dev_t *hw, int delay_mode, int delay_num) +{ +} + +/** + * Set the delay of SPI clocks before the CS inactive edge after the last SPI clock. + * + * @param hw Beginning address of the peripheral registers. + * @param hold Delay of SPI clocks after the last clock, 0 to disable the hold phase. + */ +static inline void spi_ll_master_set_cs_hold(spi_dev_t *hw, int hold) +{ + hw->user1.cs_hold_time = hold; + hw->user.cs_hold = hold ? 1 : 0; +} + +/** + * Set the delay of SPI clocks before the first SPI clock after the CS active edge. + * + * Note ESP32 doesn't support to use this feature when command/address phases + * are used in full duplex mode. + * + * @param hw Beginning address of the peripheral registers. + * @param setup Delay of SPI clocks after the CS active edge, 0 to disable the setup phase. + */ +static inline void spi_ll_master_set_cs_setup(spi_dev_t *hw, uint8_t setup) +{ + hw->user1.cs_setup_time = setup - 1; + hw->user.cs_setup = setup ? 1 : 0; +} + +/*------------------------------------------------------------------------------ + * Configs: data + *----------------------------------------------------------------------------*/ +/** + * Set the output length (master). + * This should be called before master setting MISO(input) length + * + * @param hw Beginning address of the peripheral registers. + * @param bitlen output length, in bits. + */ +static inline void spi_ll_set_mosi_bitlen(spi_dev_t *hw, size_t bitlen) +{ + if (bitlen > 0) { + hw->ms_dlen.ms_data_bitlen = bitlen - 1; + } +} + +/** + * Set the input length (master). + * + * @param hw Beginning address of the peripheral registers. + * @param bitlen input length, in bits. + */ +static inline void spi_ll_set_miso_bitlen(spi_dev_t *hw, size_t bitlen) +{ + if (bitlen > 0) { + hw->ms_dlen.ms_data_bitlen = bitlen - 1; + } +} + +/** + * Set the maximum input length (slave). + * + * @param hw Beginning address of the peripheral registers. + * @param bitlen Input length, in bits. + */ +static inline void spi_ll_slave_set_rx_bitlen(spi_dev_t *hw, size_t bitlen) +{ + //This is not used in esp32H2 +} + +/** + * Set the maximum output length (slave). + * + * @param hw Beginning address of the peripheral registers. + * @param bitlen Output length, in bits. + */ +static inline void spi_ll_slave_set_tx_bitlen(spi_dev_t *hw, size_t bitlen) +{ + //This is not used in esp32H2 +} + +/** + * Set the length of command phase. + * + * When in 4-bit mode, the SPI cycles of the phase will be shorter. E.g. 16-bit + * command phases takes 4 cycles in 4-bit mode. + * + * @param hw Beginning address of the peripheral registers. + * @param bitlen Length of command phase, in bits. 0 to disable the command phase. + */ +static inline void spi_ll_set_command_bitlen(spi_dev_t *hw, int bitlen) +{ + hw->user2.usr_command_bitlen = bitlen - 1; + hw->user.usr_command = bitlen ? 1 : 0; +} + +/** + * Set the length of address phase. + * + * When in 4-bit mode, the SPI cycles of the phase will be shorter. E.g. 16-bit + * address phases takes 4 cycles in 4-bit mode. + * + * @param hw Beginning address of the peripheral registers. + * @param bitlen Length of address phase, in bits. 0 to disable the address phase. + */ +static inline void spi_ll_set_addr_bitlen(spi_dev_t *hw, int bitlen) +{ + hw->user1.usr_addr_bitlen = bitlen - 1; + hw->user.usr_addr = bitlen ? 1 : 0; +} + +/** + * Set the address value in an intuitive way. + * + * The length and lsbfirst is required to shift and swap the address to the right place. + * + * @param hw Beginning address of the peripheral registers. + * @param address Address to set + * @param addrlen Length of the address phase + * @param lsbfirst Whether the LSB first feature is enabled. + */ +static inline void spi_ll_set_address(spi_dev_t *hw, uint64_t addr, int addrlen, uint32_t lsbfirst) +{ + if (lsbfirst) { + /* The output address start from the LSB of the highest byte, i.e. + * addr[24] -> addr[31] + * ... + * addr[0] -> addr[7] + * So swap the byte order to let the LSB sent first. + */ + addr = HAL_SWAP32(addr); + //otherwise only addr register is sent + hw->addr = addr; + } else { + // shift the address to MSB of addr register. + // output address will be sent from MSB to LSB of addr register + hw->addr = addr << (32 - addrlen); + } +} + +/** + * Set the command value in an intuitive way. + * + * The length and lsbfirst is required to shift and swap the command to the right place. + * + * @param hw Beginning command of the peripheral registers. + * @param command Command to set + * @param addrlen Length of the command phase + * @param lsbfirst Whether the LSB first feature is enabled. + */ +static inline void spi_ll_set_command(spi_dev_t *hw, uint16_t cmd, int cmdlen, bool lsbfirst) +{ + if (lsbfirst) { + // The output command start from bit0 to bit 15, kept as is. + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->user2, usr_command_value, cmd); + } else { + /* Output command will be sent from bit 7 to 0 of command_value, and + * then bit 15 to 8 of the same register field. Shift and swap to send + * more straightly. + */ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->user2, usr_command_value, HAL_SPI_SWAP_DATA_TX(cmd, cmdlen)); + } +} + +/** + * Set dummy clocks to output before RX phase (master), or clocks to skip + * before the data phase and after the address phase (slave). + * + * Note this phase is also used to compensate RX timing in half duplex mode. + * + * @param hw Beginning address of the peripheral registers. + * @param dummy_n Dummy cycles used. 0 to disable the dummy phase. + */ +static inline void spi_ll_set_dummy(spi_dev_t *hw, int dummy_n) +{ + hw->user.usr_dummy = dummy_n ? 1 : 0; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->user1, usr_dummy_cyclelen, dummy_n - 1); +} + +/** + * Enable/disable the RX data phase. + * + * @param hw Beginning address of the peripheral registers. + * @param enable True if RX phase exist, otherwise false. + */ +static inline void spi_ll_enable_miso(spi_dev_t *hw, int enable) +{ + hw->user.usr_miso = enable; +} + +/** + * Enable/disable the TX data phase. + * + * @param hw Beginning address of the peripheral registers. + * @param enable True if TX phase exist, otherwise false. + */ +static inline void spi_ll_enable_mosi(spi_dev_t *hw, int enable) +{ + hw->user.usr_mosi = enable; +} + +/** + * Get the received bit length of the slave. + * + * @param hw Beginning address of the peripheral registers. + * + * @return Received bits of the slave. + */ +static inline uint32_t spi_ll_slave_get_rcv_bitlen(spi_dev_t *hw) +{ + return hw->slave1.data_bitlen; +} + +/*------------------------------------------------------------------------------ + * Interrupts + *----------------------------------------------------------------------------*/ +//helper macros to generate code for each interrupts +#define FOR_EACH_ITEM(op, list) do { list(op) } while(0) +#define INTR_LIST(item) \ + item(SPI_LL_INTR_TRANS_DONE, dma_int_ena.trans_done, dma_int_raw.trans_done, dma_int_clr.trans_done=1) \ + item(SPI_LL_INTR_RDBUF, dma_int_ena.rd_buf_done, dma_int_raw.rd_buf_done, dma_int_clr.rd_buf_done=1) \ + item(SPI_LL_INTR_WRBUF, dma_int_ena.wr_buf_done, dma_int_raw.wr_buf_done, dma_int_clr.wr_buf_done=1) \ + item(SPI_LL_INTR_RDDMA, dma_int_ena.rd_dma_done, dma_int_raw.rd_dma_done, dma_int_clr.rd_dma_done=1) \ + item(SPI_LL_INTR_WRDMA, dma_int_ena.wr_dma_done, dma_int_raw.wr_dma_done, dma_int_clr.wr_dma_done=1) \ + item(SPI_LL_INTR_SEG_DONE, dma_int_ena.dma_seg_trans_done, dma_int_raw.dma_seg_trans_done, dma_int_clr.dma_seg_trans_done=1) \ + item(SPI_LL_INTR_CMD7, dma_int_ena.cmd7, dma_int_raw.cmd7, dma_int_clr.cmd7=1) \ + item(SPI_LL_INTR_CMD8, dma_int_ena.cmd8, dma_int_raw.cmd8, dma_int_clr.cmd8=1) \ + item(SPI_LL_INTR_CMD9, dma_int_ena.cmd9, dma_int_raw.cmd9, dma_int_clr.cmd9=1) \ + item(SPI_LL_INTR_CMDA, dma_int_ena.cmda, dma_int_raw.cmda, dma_int_clr.cmda=1) + + +static inline void spi_ll_enable_intr(spi_dev_t *hw, spi_ll_intr_t intr_mask) +{ +#define ENA_INTR(intr_bit, en_reg, ...) if (intr_mask & (intr_bit)) hw->en_reg = 1; + FOR_EACH_ITEM(ENA_INTR, INTR_LIST); +#undef ENA_INTR +} + +static inline void spi_ll_disable_intr(spi_dev_t *hw, spi_ll_intr_t intr_mask) +{ +#define DIS_INTR(intr_bit, en_reg, ...) if (intr_mask & (intr_bit)) hw->en_reg = 0; + FOR_EACH_ITEM(DIS_INTR, INTR_LIST); +#undef DIS_INTR +} + +static inline void spi_ll_set_intr(spi_dev_t *hw, spi_ll_intr_t intr_mask) +{ +#define SET_INTR(intr_bit, _, st_reg, ...) if (intr_mask & (intr_bit)) hw->st_reg = 1; + FOR_EACH_ITEM(SET_INTR, INTR_LIST); +#undef SET_INTR +} + +static inline void spi_ll_clear_intr(spi_dev_t *hw, spi_ll_intr_t intr_mask) +{ +#define CLR_INTR(intr_bit, _, __, clr_reg) if (intr_mask & (intr_bit)) hw->clr_reg; + FOR_EACH_ITEM(CLR_INTR, INTR_LIST); +#undef CLR_INTR +} + +static inline bool spi_ll_get_intr(spi_dev_t *hw, spi_ll_intr_t intr_mask) +{ +#define GET_INTR(intr_bit, _, st_reg, ...) if (intr_mask & (intr_bit) && hw->st_reg) return true; + FOR_EACH_ITEM(GET_INTR, INTR_LIST); + return false; +#undef GET_INTR +} + +#undef FOR_EACH_ITEM +#undef INTR_LIST + +/** + * Disable the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_disable_int(spi_dev_t *hw) +{ + hw->dma_int_ena.trans_done = 0; +} + +/** + * Clear the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_clear_int_stat(spi_dev_t *hw) +{ + hw->dma_int_raw.trans_done = 0; +} + +/** + * Set the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_set_int_stat(spi_dev_t *hw) +{ + hw->dma_int_raw.trans_done = 1; +} + +/** + * Enable the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_enable_int(spi_dev_t *hw) +{ + hw->dma_int_ena.trans_done = 1; +} + +/*------------------------------------------------------------------------------ + * Slave HD + *----------------------------------------------------------------------------*/ +static inline void spi_ll_slave_hd_set_len_cond(spi_dev_t *hw, spi_ll_trans_len_cond_t cond_mask) +{ + hw->slave.rdbuf_bitlen_en = (cond_mask & SPI_LL_TRANS_LEN_COND_RDBUF) ? 1 : 0; + hw->slave.wrbuf_bitlen_en = (cond_mask & SPI_LL_TRANS_LEN_COND_WRBUF) ? 1 : 0; + hw->slave.rddma_bitlen_en = (cond_mask & SPI_LL_TRANS_LEN_COND_RDDMA) ? 1 : 0; + hw->slave.wrdma_bitlen_en = (cond_mask & SPI_LL_TRANS_LEN_COND_WRDMA) ? 1 : 0; +} + +static inline int spi_ll_slave_get_rx_byte_len(spi_dev_t *hw) +{ + return hw->slave1.data_bitlen / 8; +} + +static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t *hw) +{ + return hw->slave1.last_addr; +} + +#undef SPI_LL_RST_MASK +#undef SPI_LL_UNUSED_INT_MASK + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/spimem_flash_ll.h b/components/hal/esp32h2/include/hal/spimem_flash_ll.h new file mode 100644 index 0000000000..29f0ddffa5 --- /dev/null +++ b/components/hal/esp32h2/include/hal/spimem_flash_ll.h @@ -0,0 +1,597 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/******************************************************************************* + * NOTICE + * The ll is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The Lowlevel layer for SPI Flash + +#pragma once + +#include +#include // For MIN/MAX +#include +#include + +#include "soc/spi_periph.h" +#include "soc/spi_mem_struct.h" +#include "hal/assert.h" +#include "hal/spi_types.h" +#include "hal/spi_flash_types.h" +#include "soc/pcr_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define spimem_flash_ll_get_hw(host_id) (((host_id)==SPI1_HOST ? &SPIMEM1 : NULL )) +#define spimem_flash_ll_hw_get_id(dev) ((dev) == (void*)&SPIMEM1? SPI1_HOST: -1) + +typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t; + +/*------------------------------------------------------------------------------ + * Control + *----------------------------------------------------------------------------*/ +/** + * Reset peripheral registers before configuration and starting control + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_reset(spi_mem_dev_t *dev) +{ + dev->user.val = 0; + dev->ctrl.val = 0; +} + +/** + * Check whether the previous operation is done. + * + * @param dev Beginning address of the peripheral registers. + * + * @return true if last command is done, otherwise false. + */ +static inline bool spimem_flash_ll_cmd_is_done(const spi_mem_dev_t *dev) +{ + return (dev->cmd.val == 0); +} + +/** + * Erase the flash chip. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_erase_chip(spi_mem_dev_t *dev) +{ + dev->cmd.flash_ce = 1; +} + +/** + * Erase the sector, the address should be set by spimem_flash_ll_set_address. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_erase_sector(spi_mem_dev_t *dev) +{ + dev->ctrl.val = 0; + dev->cmd.flash_se = 1; +} + +/** + * Erase the block, the address should be set by spimem_flash_ll_set_address. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_erase_block(spi_mem_dev_t *dev) +{ + dev->cmd.flash_be = 1; +} + +/** + * Suspend erase/program operation. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_suspend(spi_mem_dev_t *dev) +{ + dev->flash_sus_ctrl.flash_pes = 1; +} + +/** + * Resume suspended erase/program operation. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_resume(spi_mem_dev_t *dev) +{ + dev->flash_sus_ctrl.flash_per = 1; +} + +/** + * Initialize auto suspend mode, and esp32H2 doesn't support disable auto-suspend. + * + * @param dev Beginning address of the peripheral registers. + * @param auto_sus Enable/disable Flash Auto-Suspend. + */ +static inline void spimem_flash_ll_auto_suspend_init(spi_mem_dev_t *dev, bool auto_sus) +{ + dev->flash_sus_ctrl.flash_pes_en = auto_sus; +} + +/** + * Initialize auto resume mode + * + * @param dev Beginning address of the peripheral registers. + * @param auto_res Enable/Disable Flash Auto-Resume. + * + */ +static inline void spimem_flash_ll_auto_resume_init(spi_mem_dev_t *dev, bool auto_res) +{ + dev->flash_sus_ctrl.pes_per_en = auto_res; +} + +/** + * Setup the flash suspend command, may vary from chips to chips. + * + * @param dev Beginning address of the peripheral registers. + * @param sus_cmd Flash suspend command. + * + */ +static inline void spimem_flash_ll_suspend_cmd_setup(spi_mem_dev_t *dev, uint32_t sus_cmd) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_sus_cmd, flash_pes_command, sus_cmd); +} + +/** + * Setup the flash resume command, may vary from chips to chips. + * + * @param dev Beginning address of the peripheral registers. + * @param res_cmd Flash resume command. + * + */ +static inline void spimem_flash_ll_resume_cmd_setup(spi_mem_dev_t *dev, uint32_t res_cmd) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->sus_status, flash_per_command, res_cmd); +} + +/** + * Setup the flash read suspend status command, may vary from chips to chips. + * + * @param dev Beginning address of the peripheral registers. + * @param pesr_cmd Flash read suspend status command. + * + */ +static inline void spimem_flash_ll_rd_sus_cmd_setup(spi_mem_dev_t *dev, uint32_t pesr_cmd) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_sus_cmd, wait_pesr_command, pesr_cmd); +} + +/** + * Setup to check SUS/SUS1/SUS2 to ensure the suspend status of flashs. + * + * @param dev Beginning address of the peripheral registers. + * @param sus_check_sus_en 1: enable, 0: disable. + * + */ +static inline void spimem_flash_ll_sus_check_sus_setup(spi_mem_dev_t *dev, bool sus_check_sus_en) +{ + dev->flash_sus_ctrl.sus_timeout_cnt = 5; + dev->flash_sus_ctrl.pes_end_en = sus_check_sus_en; +} + +/** + * Setup to check SUS/SUS1/SUS2 to ensure the resume status of flashs. + * + * @param dev Beginning address of the peripheral registers. + * @param sus_check_sus_en 1: enable, 0: disable. + * + */ +static inline void spimem_flash_ll_res_check_sus_setup(spi_mem_dev_t *dev, bool res_check_sus_en) +{ + dev->flash_sus_ctrl.sus_timeout_cnt = 5; + dev->flash_sus_ctrl.per_end_en = res_check_sus_en; +} + +/** + * Set 8 bit command to read suspend status + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_set_read_sus_status(spi_mem_dev_t *dev, uint32_t sus_conf) +{ + dev->flash_sus_ctrl.frd_sus_2b = 0; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_sus_ctrl, pesr_end_msk, sus_conf); +} + +/** + * Initialize auto wait idle mode + * + * @param dev Beginning address of the peripheral registers. + * @param auto_waiti Enable/disable auto wait-idle function + */ +static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool auto_waiti) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_waiti_ctrl, waiti_cmd, 0x05); + dev->flash_sus_ctrl.flash_per_wait_en = auto_waiti; + dev->flash_sus_ctrl.flash_pes_wait_en = auto_waiti; +} + +/** + * Return the suspend status of erase or program operations. + * + * @param dev Beginning address of the peripheral registers. + * + * @return true if suspended, otherwise false. + */ +static inline bool spimem_flash_ll_sus_status(spi_mem_dev_t *dev) +{ + return dev->sus_status.flash_sus; +} + +/** + * Enable/disable write protection for the flash chip. + * + * @param dev Beginning address of the peripheral registers. + * @param wp true to enable the protection, false to disable (write enable). + */ +static inline void spimem_flash_ll_set_write_protect(spi_mem_dev_t *dev, bool wp) +{ + if (wp) { + dev->cmd.flash_wrdi = 1; + } else { + dev->cmd.flash_wren = 1; + } +} + +/** + * Get the read data from the buffer after ``spimem_flash_ll_read`` is done. + * + * @param dev Beginning address of the peripheral registers. + * @param buffer Buffer to hold the output data + * @param read_len Length to get out of the buffer + */ +static inline void spimem_flash_ll_get_buffer_data(spi_mem_dev_t *dev, void *buffer, uint32_t read_len) +{ + if (((intptr_t)buffer % 4 == 0) && (read_len % 4 == 0)) { + // If everything is word-aligned, do a faster memcpy + memcpy(buffer, (void *)dev->data_buf, read_len); + } else { + // Otherwise, slow(er) path copies word by word + int copy_len = read_len; + for (int i = 0; i < (read_len + 3) / 4; i++) { + int word_len = MIN(sizeof(uint32_t), copy_len); + uint32_t word = dev->data_buf[i]; + memcpy(buffer, &word, word_len); + buffer = (void *)((intptr_t)buffer + word_len); + copy_len -= word_len; + } + } +} + +/** + * Set the data to be written in the data buffer. + * + * @param dev Beginning address of the peripheral registers. + * @param buffer Buffer holding the data + * @param length Length of data in bytes. + */ +static inline void spimem_flash_ll_set_buffer_data(spi_mem_dev_t *dev, const void *buffer, uint32_t length) +{ + // Load data registers, word at a time + int num_words = (length + 3) / 4; + for (int i = 0; i < num_words; i++) { + uint32_t word = 0; + uint32_t word_len = MIN(length, sizeof(word)); + memcpy(&word, buffer, word_len); + dev->data_buf[i] = word; + length -= word_len; + buffer = (void *)((intptr_t)buffer + word_len); + } +} + + +/** + * Program a page of the flash chip. Call ``spimem_flash_ll_set_address`` before + * this to set the address to program. + * + * @param dev Beginning address of the peripheral registers. + * @param buffer Buffer holding the data to program + * @param length Length to program. + */ +static inline void spimem_flash_ll_program_page(spi_mem_dev_t *dev, const void *buffer, uint32_t length) +{ + dev->user.usr_dummy = 0; + spimem_flash_ll_set_buffer_data(dev, buffer, length); + dev->cmd.flash_pp = 1; +} + +/** + * Trigger a user defined transaction. All phases, including command, address, dummy, and the data phases, + * should be configured before this is called. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_user_start(spi_mem_dev_t *dev) +{ + dev->cmd.usr = 1; +} + +/** + * Check whether the host is idle to perform new commands. + * + * @param dev Beginning address of the peripheral registers. + * + * @return true if the host is idle, otherwise false + */ +static inline bool spimem_flash_ll_host_idle(const spi_mem_dev_t *dev) +{ + return dev->cmd.mst_st == 0; +} + +/** + * Set phases for user-defined transaction to read + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_read_phase(spi_mem_dev_t *dev) +{ + typeof (dev->user) user = { + .usr_command = 1, + .usr_mosi = 0, + .usr_miso = 1, + .usr_addr = 1, + }; + dev->user = user; +} +/*------------------------------------------------------------------------------ + * Configs + *----------------------------------------------------------------------------*/ +/** + * Select which pin to use for the flash + * + * @param dev Beginning address of the peripheral registers. + * @param pin Pin ID to use, 0-2. Set to other values to disable all the CS pins. + */ +static inline void spimem_flash_ll_set_cs_pin(spi_mem_dev_t *dev, int pin) +{ + dev->misc.cs0_dis = (pin == 0) ? 0 : 1; + dev->misc.cs1_dis = (pin == 1) ? 0 : 1; +} + +/** + * Set the read io mode. + * + * @param dev Beginning address of the peripheral registers. + * @param read_mode I/O mode to use in the following transactions. + */ +static inline void spimem_flash_ll_set_read_mode(spi_mem_dev_t *dev, esp_flash_io_mode_t read_mode) +{ + typeof (dev->ctrl) ctrl = dev->ctrl; + ctrl.val &= ~(SPI_MEM_FREAD_QIO_M | SPI_MEM_FREAD_QUAD_M | SPI_MEM_FREAD_DIO_M | SPI_MEM_FREAD_DUAL_M); + ctrl.val |= SPI_MEM_FASTRD_MODE_M; + switch (read_mode) { + case SPI_FLASH_FASTRD: + //the default option + break; + case SPI_FLASH_QIO: + ctrl.fread_qio = 1; + break; + case SPI_FLASH_QOUT: + ctrl.fread_quad = 1; + break; + case SPI_FLASH_DIO: + ctrl.fread_dio = 1; + break; + case SPI_FLASH_DOUT: + ctrl.fread_dual = 1; + break; + case SPI_FLASH_SLOWRD: + ctrl.fastrd_mode = 0; + break; + default: + abort(); + } + dev->ctrl = ctrl; +} + +/** + * Set clock frequency to work at. + * + * @param dev Beginning address of the peripheral registers. + * @param clock_val pointer to the clock value to set + */ +static inline void spimem_flash_ll_set_clock(spi_mem_dev_t *dev, spimem_flash_ll_clock_reg_t *clock_val) +{ + dev->clock.val = *clock_val; +} + +/** + * Set the input length, in bits. + * + * @param dev Beginning address of the peripheral registers. + * @param bitlen Length of input, in bits. + */ +static inline void spimem_flash_ll_set_miso_bitlen(spi_mem_dev_t *dev, uint32_t bitlen) +{ + dev->user.usr_miso = bitlen > 0; + dev->miso_dlen.usr_miso_bit_len = bitlen ? (bitlen - 1) : 0; +} + +/** + * Set the output length, in bits (not including command, address and dummy + * phases) + * + * @param dev Beginning address of the peripheral registers. + * @param bitlen Length of output, in bits. + */ +static inline void spimem_flash_ll_set_mosi_bitlen(spi_mem_dev_t *dev, uint32_t bitlen) +{ + dev->user.usr_mosi = bitlen > 0; + dev->mosi_dlen.usr_mosi_bit_len = bitlen ? (bitlen - 1) : 0; +} + +/** + * Set the command. + * + * @param dev Beginning address of the peripheral registers. + * @param command Command to send + * @param bitlen Length of the command + */ +static inline void spimem_flash_ll_set_command(spi_mem_dev_t *dev, uint32_t command, uint32_t bitlen) +{ + dev->user.usr_command = 1; + typeof(dev->user2) user2 = { + .usr_command_value = command, + .usr_command_bitlen = (bitlen - 1), + }; + dev->user2 = user2; +} + +/** + * Get the address length that is set in register, in bits. + * + * @param dev Beginning address of the peripheral registers. + * + */ +static inline int spimem_flash_ll_get_addr_bitlen(spi_mem_dev_t *dev) +{ + return dev->user.usr_addr ? dev->user1.usr_addr_bitlen + 1 : 0; +} + +/** + * Set the address length to send, in bits. Should be called before commands that requires the address e.g. erase sector, read, write... + * + * @param dev Beginning address of the peripheral registers. + * @param bitlen Length of the address, in bits + */ +static inline void spimem_flash_ll_set_addr_bitlen(spi_mem_dev_t *dev, uint32_t bitlen) +{ + dev->user1.usr_addr_bitlen = (bitlen - 1); + dev->user.usr_addr = bitlen ? 1 : 0; +} + +/** + * Set extra address for bits M0-M7 in DIO/QIO mode. + * + * @param dev Beginning address of the peripheral registers. + * @param extra_addr extra address(M0-M7) to send. + */ +static inline void spimem_flash_ll_set_extra_address(spi_mem_dev_t *dev, uint32_t extra_addr) +{ + dev->cache_fctrl.usr_addr_4byte = 0; + dev->rd_status.wb_mode = extra_addr; +} + +/** + * Set the address to send. Should be called before commands that requires the address e.g. erase sector, read, write... + * + * @param dev Beginning address of the peripheral registers. + * @param addr Address to send + */ +static inline void spimem_flash_ll_set_address(spi_mem_dev_t *dev, uint32_t addr) +{ + dev->addr = addr; +} + +/** + * Set the address to send in user mode. Should be called before commands that requires the address e.g. erase sector, read, write... + * + * @param dev Beginning address of the peripheral registers. + * @param addr Address to send + */ +static inline void spimem_flash_ll_set_usr_address(spi_mem_dev_t *dev, uint32_t addr, uint32_t bitlen) +{ + (void)bitlen; + spimem_flash_ll_set_address(dev, addr); +} + +/** + * Set the length of dummy cycles. + * + * @param dev Beginning address of the peripheral registers. + * @param dummy_n Cycles of dummy phases + */ +static inline void spimem_flash_ll_set_dummy(spi_mem_dev_t *dev, uint32_t dummy_n) +{ + dev->user.usr_dummy = dummy_n ? 1 : 0; + dev->user1.usr_dummy_cyclelen = dummy_n - 1; +} + +/** + * Set CS hold time. + * + * @param dev Beginning address of the peripheral registers. + * @param hold_n CS hold time config used by the host. + */ +static inline void spimem_flash_ll_set_hold(spi_mem_dev_t *dev, uint32_t hold_n) +{ + dev->ctrl2.cs_hold_time = hold_n - 1; + dev->user.cs_hold = (hold_n > 0? 1: 0); +} + +static inline void spimem_flash_ll_set_cs_setup(spi_mem_dev_t *dev, uint32_t cs_setup_time) +{ + dev->user.cs_setup = (cs_setup_time > 0 ? 1 : 0); + dev->ctrl2.cs_setup_time = cs_setup_time - 1; +} + +/** + * Get the spi flash source clock frequency. Used for calculating + * the divider parameters. + * + * @param None + * + * @return the frequency of spi flash clock source.(MHz) + */ +static inline uint8_t spimem_flash_ll_get_source_freq_mhz(void) +{ +// ESP32H2-TODO +#if 0 + // TODO: Default is PLL480M, this is hard-coded. + // In the future, we can get the CPU clock source by calling interface. + uint8_t clock_val = 0; + switch (SPIMEM0.core_clk_sel.spi01_clk_sel) { + case 0: + clock_val = 80; + break; + case 1: + clock_val = 120; + break; + case 2: + clock_val = 160; + break; + default: + abort(); + } + return clock_val; +#endif + return 80; +} + +/** + * Calculate spi_flash clock frequency division parameters for register. + * + * @param clkdiv frequency division factor + * + * @return Register setting for the given clock division factor. + */ +static inline uint32_t spimem_flash_ll_calculate_clock_reg(uint8_t clkdiv) +{ + uint32_t div_parameter; + // See comments of `clock` in `spi_mem_struct.h` + if (clkdiv == 1) { + div_parameter = (1 << 31); + } else { + div_parameter = ((clkdiv - 1) | (((clkdiv - 1) / 2 & 0xff) << 8 ) | (((clkdiv - 1) & 0xff) << 16)); + } + return div_parameter; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/systimer_ll.h b/components/hal/esp32h2/include/hal/systimer_ll.h new file mode 100644 index 0000000000..8119f902b1 --- /dev/null +++ b/components/hal/esp32h2/include/hal/systimer_ll.h @@ -0,0 +1,159 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include +#include "soc/systimer_struct.h" +#include "hal/assert.h" + +#define SYSTIMER_LL_COUNTER_CLOCK (0) // Counter used for "wallclock" time +#define SYSTIMER_LL_COUNTER_OS_TICK (1) // Counter used for OS tick +#define SYSTIMER_LL_ALARM_OS_TICK_CORE0 (0) // Alarm used for OS tick of CPU core 0 +#define SYSTIMER_LL_ALARM_CLOCK (2) // Alarm used for "wallclock" time + +#ifdef __cplusplus +extern "C" { +#endif + +// All these functions get invoked either from ISR or HAL that linked to IRAM. +// Always inline these functions even no gcc optimization is applied. + +/******************* Clock *************************/ + +__attribute__((always_inline)) static inline void systimer_ll_enable_clock(systimer_dev_t *dev, bool en) +{ + dev->conf.clk_en = en; +} + +/******************* Counter *************************/ + +__attribute__((always_inline)) static inline void systimer_ll_enable_counter(systimer_dev_t *dev, uint32_t counter_id, bool en) +{ + if (en) { + dev->conf.val |= 1 << (30 - counter_id); + } else { + dev->conf.val &= ~(1 << (30 - counter_id)); + } +} + +__attribute__((always_inline)) static inline void systimer_ll_counter_can_stall_by_cpu(systimer_dev_t *dev, uint32_t counter_id, uint32_t cpu_id, bool can) +{ + if (can) { + dev->conf.val |= 1 << ((28 - counter_id * 2) - cpu_id); + } else { + dev->conf.val &= ~(1 << ((28 - counter_id * 2) - cpu_id)); + } +} + +__attribute__((always_inline)) static inline void systimer_ll_counter_snapshot(systimer_dev_t *dev, uint32_t counter_id) +{ + dev->unit_op[counter_id].timer_unit_update = 1; +} + +__attribute__((always_inline)) static inline bool systimer_ll_is_counter_value_valid(systimer_dev_t *dev, uint32_t counter_id) +{ + return dev->unit_op[counter_id].timer_unit_value_valid; +} + +__attribute__((always_inline)) static inline void systimer_ll_set_counter_value(systimer_dev_t *dev, uint32_t counter_id, uint64_t value) +{ + dev->unit_load_val[counter_id].hi.timer_unit_load_hi = value >> 32; + dev->unit_load_val[counter_id].lo.timer_unit_load_lo = value & 0xFFFFFFFF; +} + +__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_low(systimer_dev_t *dev, uint32_t counter_id) +{ + return dev->unit_val[counter_id].lo.timer_unit_value_lo; +} + +__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_high(systimer_dev_t *dev, uint32_t counter_id) +{ + return dev->unit_val[counter_id].hi.timer_unit_value_hi; +} + +__attribute__((always_inline)) static inline void systimer_ll_apply_counter_value(systimer_dev_t *dev, uint32_t counter_id) +{ + dev->unit_load[counter_id].val = 0x01; +} + +/******************* Alarm *************************/ + +__attribute__((always_inline)) static inline void systimer_ll_set_alarm_target(systimer_dev_t *dev, uint32_t alarm_id, uint64_t value) +{ + dev->target_val[alarm_id].hi.timer_target_hi = value >> 32; + dev->target_val[alarm_id].lo.timer_target_lo = value & 0xFFFFFFFF; +} + +__attribute__((always_inline)) static inline uint64_t systimer_ll_get_alarm_target(systimer_dev_t *dev, uint32_t alarm_id) +{ + return ((uint64_t)(dev->target_val[alarm_id].hi.timer_target_hi) << 32) | dev->target_val[alarm_id].lo.timer_target_lo; +} + +__attribute__((always_inline)) static inline void systimer_ll_connect_alarm_counter(systimer_dev_t *dev, uint32_t alarm_id, uint32_t counter_id) +{ + dev->target_conf[alarm_id].target_timer_unit_sel = counter_id; +} + +__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_oneshot(systimer_dev_t *dev, uint32_t alarm_id) +{ + dev->target_conf[alarm_id].target_period_mode = 0; +} + +__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_period(systimer_dev_t *dev, uint32_t alarm_id) +{ + dev->target_conf[alarm_id].target_period_mode = 1; +} + +__attribute__((always_inline)) static inline void systimer_ll_set_alarm_period(systimer_dev_t *dev, uint32_t alarm_id, uint32_t period) +{ + HAL_ASSERT(period < (1 << 26)); + dev->target_conf[alarm_id].target_period = period; +} + +__attribute__((always_inline)) static inline uint32_t systimer_ll_get_alarm_period(systimer_dev_t *dev, uint32_t alarm_id) +{ + return dev->target_conf[alarm_id].target_period; +} + +__attribute__((always_inline)) static inline void systimer_ll_apply_alarm_value(systimer_dev_t *dev, uint32_t alarm_id) +{ + dev->comp_load[alarm_id].val = 0x01; +} + +__attribute__((always_inline)) static inline void systimer_ll_enable_alarm(systimer_dev_t *dev, uint32_t alarm_id, bool en) +{ + if (en) { + dev->conf.val |= 1 << (24 - alarm_id); + } else { + dev->conf.val &= ~(1 << (24 - alarm_id)); + } +} + +/******************* Interrupt *************************/ + +__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_int(systimer_dev_t *dev, uint32_t alarm_id, bool en) +{ + if (en) { + dev->int_ena.val |= 1 << alarm_id; + } else { + dev->int_ena.val &= ~(1 << alarm_id); + } +} + +__attribute__((always_inline)) static inline bool systimer_ll_is_alarm_int_fired(systimer_dev_t *dev, uint32_t alarm_id) +{ + return dev->int_st.val & (1 << alarm_id); +} + +__attribute__((always_inline)) static inline void systimer_ll_clear_alarm_int(systimer_dev_t *dev, uint32_t alarm_id) +{ + dev->int_clr.val |= 1 << alarm_id; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/uart_ll.h b/components/hal/esp32h2/include/hal/uart_ll.h new file mode 100644 index 0000000000..f1c5e57180 --- /dev/null +++ b/components/hal/esp32h2/include/hal/uart_ll.h @@ -0,0 +1,1087 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// The LL layer for UART register operations. +// Note that most of the register operations in this layer are non-atomic operations. + + +#pragma once + +#include "hal/misc.h" +#include "hal/uart_types.h" +#include "soc/uart_periph.h" +#include "soc/uart_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// The default fifo depth +#define UART_LL_FIFO_DEF_LEN (SOC_UART_FIFO_LEN) +// Get UART hardware instance with giving uart num +#define UART_LL_GET_HW(num) (((num) == 0) ? (&UART0) : (&UART1)) + +#define UART_LL_MIN_WAKEUP_THRESH (2) +#define UART_LL_INTR_MASK (0x7ffff) //All interrupt mask + +#define UART_LL_FSM_IDLE (0x0) +#define UART_LL_FSM_TX_WAIT_SEND (0xf) + +// Define UART interrupts +typedef enum { + UART_INTR_RXFIFO_FULL = (0x1 << 0), + UART_INTR_TXFIFO_EMPTY = (0x1 << 1), + UART_INTR_PARITY_ERR = (0x1 << 2), + UART_INTR_FRAM_ERR = (0x1 << 3), + UART_INTR_RXFIFO_OVF = (0x1 << 4), + UART_INTR_DSR_CHG = (0x1 << 5), + UART_INTR_CTS_CHG = (0x1 << 6), + UART_INTR_BRK_DET = (0x1 << 7), + UART_INTR_RXFIFO_TOUT = (0x1 << 8), + UART_INTR_SW_XON = (0x1 << 9), + UART_INTR_SW_XOFF = (0x1 << 10), + UART_INTR_GLITCH_DET = (0x1 << 11), + UART_INTR_TX_BRK_DONE = (0x1 << 12), + UART_INTR_TX_BRK_IDLE = (0x1 << 13), + UART_INTR_TX_DONE = (0x1 << 14), + UART_INTR_RS485_PARITY_ERR = (0x1 << 15), + UART_INTR_RS485_FRM_ERR = (0x1 << 16), + UART_INTR_RS485_CLASH = (0x1 << 17), + UART_INTR_CMD_CHAR_DET = (0x1 << 18), + // UART_INTR_WAKEUP = (0x1 << 19), // TODO: IDF-5338 +} uart_intr_t; + +static inline void uart_ll_update(int uart_no) // TODO: IDF-5338 should use uart_dev_t *hw +{ + // TODO: set a timeout ?? + while(1) { + int update = GET_PERI_REG_BITS2(UART_REG_UPDATE_REG(uart_no), UART_REG_UPDATE_V, UART_REG_UPDATE_S); + if (!update) { + break; + } + } + SET_PERI_REG_MASK(UART_REG_UPDATE_REG(uart_no), UART_REG_UPDATE_M); +} + +/** + * @brief Configure the UART core reset. + * + * @param hw Beginning address of the peripheral registers. + * @param core_rst_en True to enable the core reset, otherwise set it false. + * + * @return None. + */ +static inline void uart_ll_set_reset_core(uart_dev_t *hw, bool core_rst_en) +{ + hw->clk_conf.rst_core = core_rst_en; +} + +/** + * @brief Enable the UART clock. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None. + */ +static inline void uart_ll_sclk_enable(uart_dev_t *hw) +{ + hw->clk_conf.sclk_en = 1; + hw->clk_conf.rx_sclk_en = 1; + hw->clk_conf.tx_sclk_en = 1; +} + +/** + * @brief Disable the UART clock. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None. + */ +static inline void uart_ll_sclk_disable(uart_dev_t *hw) +{ + hw->clk_conf.sclk_en = 0; + hw->clk_conf.rx_sclk_en = 0; + hw->clk_conf.tx_sclk_en = 0; +} + +/** + * @brief Set the UART source clock. + * + * @param hw Beginning address of the peripheral registers. + * @param source_clk The UART source clock. The source clock can be APB clock, RTC clock or XTAL clock. + * If the source clock is RTC/XTAL, the UART can still work when the APB changes. + * + * @return None. + */ +static inline void uart_ll_set_sclk(uart_dev_t *hw, uart_sclk_t source_clk) +{ + switch (source_clk) { + default: + case UART_SCLK_APB: + hw->clk_conf.sclk_sel = 1; + break; + case UART_SCLK_RTC: + hw->clk_conf.sclk_sel = 2; + break; + case UART_SCLK_XTAL: + hw->clk_conf.sclk_sel = 3; + break; + } +} + +/** + * @brief Get the UART source clock type. + * + * @param hw Beginning address of the peripheral registers. + * @param source_clk The pointer to accept the UART source clock type. + * + * @return None. + */ +static inline void uart_ll_get_sclk(uart_dev_t *hw, uart_sclk_t *source_clk) +{ + switch (hw->clk_conf.sclk_sel) { + default: + case 1: + *source_clk = UART_SCLK_APB; + break; + case 2: + *source_clk = UART_SCLK_RTC; + break; + case 3: + *source_clk = UART_SCLK_XTAL; + break; + } +} + +/** + * @brief Configure the baud-rate. + * + * @param hw Beginning address of the peripheral registers. + * @param baud The baud rate to be set. + * @param sclk_freq Frequency of the clock source of UART, in Hz. + * + * @return None + */ +static inline void uart_ll_set_baudrate(uart_dev_t *hw, uint32_t baud, uint32_t sclk_freq) +{ +#define DIV_UP(a, b) (((a) + (b) - 1) / (b)) + const uint32_t max_div = BIT(12) - 1; // UART divider integer part only has 12 bits + int sclk_div = DIV_UP(sclk_freq, max_div * baud); + + uint32_t clk_div = ((sclk_freq) << 4) / (baud * sclk_div); + // The baud rate configuration register is divided into + // an integer part and a fractional part. + hw->clkdiv_sync.clkdiv_int = clk_div >> 4; + hw->clkdiv_sync.clkdiv_frag = clk_div & 0xf; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clk_conf, sclk_div_num, sclk_div - 1); +#undef DIV_UP + uart_ll_update(0); // TODO: IDF-5338 +} + +/** + * @brief Get the current baud-rate. + * + * @param hw Beginning address of the peripheral registers. + * @param sclk_freq Frequency of the clock source of UART, in Hz. + * + * @return The current baudrate + */ +static inline uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_freq) +{ + typeof(hw->clkdiv_sync) div_reg = hw->clkdiv_sync; + return ((sclk_freq << 4)) / (((div_reg.clkdiv_int << 4) | div_reg.clkdiv_frag) * (HAL_FORCE_READ_U32_REG_FIELD(hw->clk_conf, sclk_div_num) + 1)); +} + +/** + * @brief Enable the UART interrupt based on the given mask. + * + * @param hw Beginning address of the peripheral registers. + * @param mask The bitmap of the interrupts need to be enabled. + * + * @return None + */ +static inline void uart_ll_ena_intr_mask(uart_dev_t *hw, uint32_t mask) +{ + hw->int_ena.val |= mask; +} + +/** + * @brief Disable the UART interrupt based on the given mask. + * + * @param hw Beginning address of the peripheral registers. + * @param mask The bitmap of the interrupts need to be disabled. + * + * @return None + */ +static inline void uart_ll_disable_intr_mask(uart_dev_t *hw, uint32_t mask) +{ + hw->int_ena.val &= (~mask); +} + +/** + * @brief Get the UART interrupt status. + * + * @param hw Beginning address of the peripheral registers. + * + * @return The UART interrupt status. + */ +static inline uint32_t uart_ll_get_intsts_mask(uart_dev_t *hw) +{ + return hw->int_st.val; +} + +/** + * @brief Clear the UART interrupt status based on the given mask. + * + * @param hw Beginning address of the peripheral registers. + * @param mask The bitmap of the interrupts need to be cleared. + * + * @return None + */ +static inline void uart_ll_clr_intsts_mask(uart_dev_t *hw, uint32_t mask) +{ + hw->int_clr.val = mask; +} + +/** + * @brief Get status of enabled interrupt. + * + * @param hw Beginning address of the peripheral registers. + * + * @return interrupt enable value + */ +static inline uint32_t uart_ll_get_intr_ena_status(uart_dev_t *hw) +{ + return hw->int_ena.val; +} + +/** + * @brief Read the UART rxfifo. + * + * @param hw Beginning address of the peripheral registers. + * @param buf The data buffer. The buffer size should be large than 128 byts. + * @param rd_len The data length needs to be read. + * + * @return None. + */ +static inline void uart_ll_read_rxfifo(uart_dev_t *hw, uint8_t *buf, uint32_t rd_len) +{ + for (int i = 0; i < (int)rd_len; i++) { + buf[i] = HAL_FORCE_READ_U32_REG_FIELD(hw->fifo, rxfifo_rd_byte); + } +} + +/** + * @brief Write byte to the UART txfifo. + * + * @param hw Beginning address of the peripheral registers. + * @param buf The data buffer. + * @param wr_len The data length needs to be writen. + * + * @return None + */ +static inline void uart_ll_write_txfifo(uart_dev_t *hw, const uint8_t *buf, uint32_t wr_len) +{ + for (int i = 0; i < (int)wr_len; i++) { + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->fifo, rxfifo_rd_byte, buf[i]); + } +} + +/** + * @brief Reset the UART hw rxfifo. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None + */ +static inline void uart_ll_rxfifo_rst(uart_dev_t *hw) +{ + hw->conf0_sync.rxfifo_rst = 1; + uart_ll_update(0); // TODO: IDF-5338 + hw->conf0_sync.rxfifo_rst = 0; + uart_ll_update(0); // TODO: IDF-5338 +} + +/** + * @brief Reset the UART hw txfifo. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None + */ +static inline void uart_ll_txfifo_rst(uart_dev_t *hw) +{ + hw->conf0_sync.txfifo_rst = 1; + uart_ll_update(0); // TODO: IDF-5338 + hw->conf0_sync.txfifo_rst = 0; + uart_ll_update(0); // TODO: IDF-5338 +} + +/** + * @brief Get the length of readable data in UART rxfifo. + * + * @param hw Beginning address of the peripheral registers. + * + * @return The readable data length in rxfifo. + */ +static inline uint32_t uart_ll_get_rxfifo_len(uart_dev_t *hw) +{ + return hw->status.rxfifo_cnt; +} + +/** + * @brief Get the writable data length of UART txfifo. + * + * @param hw Beginning address of the peripheral registers. + * + * @return The data length of txfifo can be written. + */ +static inline uint32_t uart_ll_get_txfifo_len(uart_dev_t *hw) +{ + return UART_LL_FIFO_DEF_LEN - hw->status.txfifo_cnt; +} + +/** + * @brief Configure the UART stop bit. + * + * @param hw Beginning address of the peripheral registers. + * @param stop_bit The stop bit number to be set. + * + * @return None. + */ +static inline void uart_ll_set_stop_bits(uart_dev_t *hw, uart_stop_bits_t stop_bit) +{ + hw->conf0_sync.stop_bit_num = stop_bit; + uart_ll_update(0); // TODO: IDF-5338 +} + +/** + * @brief Get the configuration of the UART stop bit. + * + * @param hw Beginning address of the peripheral registers. + * @param stop_bit The pointer to accept the stop bit configuration + * + * @return None. + */ +static inline void uart_ll_get_stop_bits(uart_dev_t *hw, uart_stop_bits_t *stop_bit) +{ + *stop_bit = hw->conf0_sync.stop_bit_num; +} + +/** + * @brief Configure the UART parity check mode. + * + * @param hw Beginning address of the peripheral registers. + * @param parity_mode The parity check mode to be set. + * + * @return None. + */ +static inline void uart_ll_set_parity(uart_dev_t *hw, uart_parity_t parity_mode) +{ + if (parity_mode != UART_PARITY_DISABLE) { + hw->conf0_sync.parity = parity_mode & 0x1; + } + hw->conf0_sync.parity_en = (parity_mode >> 1) & 0x1; + uart_ll_update(0); // TODO: IDF-5338 +} + +/** + * @brief Get the UART parity check mode configuration. + * + * @param hw Beginning address of the peripheral registers. + * @param parity_mode The pointer to accept the parity check mode configuration. + * + * @return None. + */ +static inline void uart_ll_get_parity(uart_dev_t *hw, uart_parity_t *parity_mode) +{ + if (hw->conf0_sync.parity_en) { + *parity_mode = 0X2 | hw->conf0_sync.parity; + } else { + *parity_mode = UART_PARITY_DISABLE; + } +} + +/** + * @brief Set the UART rxfifo full threshold value. When the data in rxfifo is more than the threshold value, + * it will produce rxfifo_full_int_raw interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param full_thrhd The full threshold value of the rxfifo. `full_thrhd` should be less than `UART_LL_FIFO_DEF_LEN`. + * + * @return None. + */ +static inline void uart_ll_set_rxfifo_full_thr(uart_dev_t *hw, uint16_t full_thrhd) +{ + hw->conf1.rxfifo_full_thrhd = full_thrhd; +} + +/** + * @brief Set the txfifo empty threshold. when the data length in txfifo is less than threshold value, + * it will produce txfifo_empty_int_raw interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param empty_thrhd The empty threshold of txfifo. + * + * @return None. + */ +static inline void uart_ll_set_txfifo_empty_thr(uart_dev_t *hw, uint16_t empty_thrhd) +{ + hw->conf1.txfifo_empty_thrhd = empty_thrhd; +} + +/** + * @brief Set the UART rx-idle threshold value. when receiver takes more time than rx_idle_thrhd to receive a byte data, + * it will produce frame end signal for uhci to stop receiving data. + * + * @param hw Beginning address of the peripheral registers. + * @param rx_idle_thr The rx-idle threshold to be set. + * + * @return None. + */ +static inline void uart_ll_set_rx_idle_thr(uart_dev_t *hw, uint32_t rx_idle_thr) +{ + hw->idle_conf_sync.rx_idle_thrhd = rx_idle_thr; + uart_ll_update(0); // TODO: IDF-5338 +} + +/** + * @brief Configure the duration time between transfers. + * + * @param hw Beginning address of the peripheral registers. + * @param idle_num the duration time between transfers. + * + * @return None. + */ +static inline void uart_ll_set_tx_idle_num(uart_dev_t *hw, uint32_t idle_num) +{ + hw->idle_conf_sync.tx_idle_num = idle_num; + uart_ll_update(0); // TODO: IDF-5338 +} + +/** + * @brief Configure the transmiter to send break chars. + * + * @param hw Beginning address of the peripheral registers. + * @param break_num The number of the break chars need to be send. + * + * @return None. + */ +static inline void uart_ll_tx_break(uart_dev_t *hw, uint32_t break_num) +{ + if (break_num > 0) { + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->txbrk_conf_sync, tx_brk_num, break_num); + uart_ll_update(0); // TODO: IDF-5338 + hw->conf0_sync.txd_brk = 1; + uart_ll_update(0); // TODO: IDF-5338 + } else { + hw->conf0_sync.txd_brk = 0; + uart_ll_update(0); // TODO: IDF-5338 + } +} + +/** + * @brief Configure the UART hardware flow control. + * + * @param hw Beginning address of the peripheral registers. + * @param flow_ctrl The hw flow control configuration. + * @param rx_thrs The rx flow control signal will be active if the data length in rxfifo is more than this value. + * + * @return None. + */ +static inline void uart_ll_set_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcontrol_t flow_ctrl, uint32_t rx_thrs) +{ + //only when UART_HW_FLOWCTRL_RTS is set , will the rx_thresh value be set. + if (flow_ctrl & UART_HW_FLOWCTRL_RTS) { + hw->hwfc_conf_sync.rx_flow_thrhd = rx_thrs; + uart_ll_update(0); // TODO: IDF-5338 + hw->hwfc_conf_sync.rx_flow_en = 1; + uart_ll_update(0); // TODO: IDF-5338 + } else { + hw->hwfc_conf_sync.rx_flow_en = 0; + uart_ll_update(0); // TODO: IDF-5338 + } + if (flow_ctrl & UART_HW_FLOWCTRL_CTS) { + hw->conf0_sync.tx_flow_en = 1; + uart_ll_update(0); // TODO: IDF-5338 + } else { + hw->conf0_sync.tx_flow_en = 0; + uart_ll_update(0); // TODO: IDF-5338 + } +} + +/** + * @brief Configure the hardware flow control. + * + * @param hw Beginning address of the peripheral registers. + * @param flow_ctrl A pointer to accept the hw flow control configuration. + * + * @return None. + */ +static inline void uart_ll_get_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcontrol_t *flow_ctrl) +{ + *flow_ctrl = UART_HW_FLOWCTRL_DISABLE; + if (hw->hwfc_conf_sync.rx_flow_en) { + *flow_ctrl |= UART_HW_FLOWCTRL_RTS; + } + if (hw->conf0_sync.tx_flow_en) { + *flow_ctrl |= UART_HW_FLOWCTRL_CTS; + } +} + +/** + * @brief Configure the software flow control. + * + * @param hw Beginning address of the peripheral registers. + * @param flow_ctrl The UART sofware flow control settings. + * @param sw_flow_ctrl_en Set true to enable software flow control, otherwise set it false. + * + * @return None. + */ +static inline void uart_ll_set_sw_flow_ctrl(uart_dev_t *hw, uart_sw_flowctrl_t *flow_ctrl, bool sw_flow_ctrl_en) +{ + if (sw_flow_ctrl_en) { + hw->swfc_conf0_sync.xonoff_del = 1; + uart_ll_update(0); // TODO: IDF-5338 + hw->swfc_conf0_sync.sw_flow_con_en = 1; + uart_ll_update(0); // TODO: IDF-5338 + hw->swfc_conf1.xon_threshold = flow_ctrl->xon_thrd; + hw->swfc_conf1.xoff_threshold = flow_ctrl->xoff_thrd; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->swfc_conf0_sync, xon_char, flow_ctrl->xon_char); + uart_ll_update(0); // TODO: IDF-5338 + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->swfc_conf0_sync, xoff_char, flow_ctrl->xoff_char); + uart_ll_update(0); // TODO: IDF-5338 + } else { + hw->swfc_conf0_sync.sw_flow_con_en = 0; + uart_ll_update(0); // TODO: IDF-5338 + hw->swfc_conf0_sync.xonoff_del = 0; + uart_ll_update(0); // TODO: IDF-5338 + } +} + +/** + * @brief Configure the AT cmd char. When the receiver receives a continuous AT cmd char, it will produce at_cmd_char_det interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param cmd_char The AT cmd char configuration.The configuration member is: + * - cmd_char The AT cmd character + * - char_num The number of received AT cmd char must be equal to or greater than this value + * - gap_tout The interval between each AT cmd char, when the duration is less than this value, it will not take this data as AT cmd char + * - pre_idle The idle time before the first AT cmd char, when the duration is less than this value, it will not take the previous data as the last AT cmd char + * - post_idle The idle time after the last AT cmd char, when the duration is less than this value, it will not take this data as the first AT cmd char + * + * @return None. + */ +static inline void uart_ll_set_at_cmd_char(uart_dev_t *hw, uart_at_cmd_t *cmd_char) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->at_cmd_char_sync, data, cmd_char->cmd_char); + uart_ll_update(0); // TODO: IDF-5338 + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->at_cmd_char_sync, char_num, cmd_char->char_num); + uart_ll_update(0); // TODO: IDF-5338 + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->at_cmd_postcnt_sync, post_idle_num, cmd_char->post_idle); + uart_ll_update(0); // TODO: IDF-5338 + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->at_cmd_precnt_sync, pre_idle_num, cmd_char->pre_idle); + uart_ll_update(0); // TODO: IDF-5338 + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->at_cmd_gaptout_sync, rx_gap_tout, cmd_char->gap_tout); + uart_ll_update(0); // TODO: IDF-5338 +} + +/** + * @brief Set the UART data bit mode. + * + * @param hw Beginning address of the peripheral registers. + * @param data_bit The data bit mode to be set. + * + * @return None. + */ +static inline void uart_ll_set_data_bit_num(uart_dev_t *hw, uart_word_length_t data_bit) +{ + hw->conf0_sync.bit_num = data_bit; + uart_ll_update(0); // TODO: IDF-5338 +} + +/** + * @brief Set the rts active level. + * + * @param hw Beginning address of the peripheral registers. + * @param level The rts active level, 0 or 1. + * + * @return None. + */ +static inline void uart_ll_set_rts_active_level(uart_dev_t *hw, int level) +{ + hw->conf0_sync.sw_rts = level & 0x1; + uart_ll_update(0); // TODO: IDF-5338 +} + +/** + * @brief Set the dtr active level. + * + * @param hw Beginning address of the peripheral registers. + * @param level The dtr active level, 0 or 1. + * + * @return None. + */ +static inline void uart_ll_set_dtr_active_level(uart_dev_t *hw, int level) +{ + hw->conf1.sw_dtr = level & 0x1; +} + +/** + * @brief Set the UART wakeup threshold. + * + * @param hw Beginning address of the peripheral registers. + * @param wakeup_thrd The wakeup threshold value to be set. When the input rx edge changes more than this value, + * the UART will active from light sleeping mode. + * + * @return None. + */ +static inline void uart_ll_set_wakeup_thrd(uart_dev_t *hw, uint32_t wakeup_thrd) +{ + hw->sleep_conf2.active_threshold = wakeup_thrd - UART_LL_MIN_WAKEUP_THRESH; +} + +/** + * @brief Configure the UART work in normal mode. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None. + */ +static inline void uart_ll_set_mode_normal(uart_dev_t *hw) +{ + hw->rs485_conf_sync.rs485_en = 0; + uart_ll_update(0); // TODO: IDF-5338 + hw->rs485_conf_sync.rs485tx_rx_en = 0; + uart_ll_update(0); // TODO: IDF-5338 + hw->rs485_conf_sync.rs485rxby_tx_en = 0; + uart_ll_update(0); // TODO: IDF-5338 + hw->conf0_sync.irda_en = 0; + uart_ll_update(0); // TODO: IDF-5338 +} + +/** + * @brief Configure the UART work in rs485_app_ctrl mode. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None. + */ +static inline void uart_ll_set_mode_rs485_app_ctrl(uart_dev_t *hw) +{ + // Application software control, remove echo + hw->rs485_conf_sync.rs485rxby_tx_en = 1; + uart_ll_update(0); // TODO: IDF-5338 + hw->conf0_sync.irda_en = 0; + uart_ll_update(0); // TODO: IDF-5338 + hw->conf0_sync.sw_rts = 0; + uart_ll_update(0); // TODO: IDF-5338 + hw->conf0_sync.irda_en = 0; + uart_ll_update(0); // TODO: IDF-5338 + hw->rs485_conf_sync.dl0_en = 1; + uart_ll_update(0); // TODO: IDF-5338 + hw->rs485_conf_sync.dl1_en = 1; + uart_ll_update(0); // TODO: IDF-5338 + hw->rs485_conf_sync.rs485_en = 1; + uart_ll_update(0); // TODO: IDF-5338 +} + +/** + * @brief Configure the UART work in rs485_half_duplex mode. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None. + */ +static inline void uart_ll_set_mode_rs485_half_duplex(uart_dev_t *hw) +{ + // Enable receiver, sw_rts = 1 generates low level on RTS pin + hw->conf0_sync.sw_rts = 1; + uart_ll_update(0); // TODO: IDF-5338 + // Half duplex mode + hw->rs485_conf_sync.rs485tx_rx_en = 0; + uart_ll_update(0); // TODO: IDF-5338 + // Setting this bit will allow data to be transmitted while receiving data(full-duplex mode). + // But note that this full-duplex mode has no conflict detection function + hw->rs485_conf_sync.rs485rxby_tx_en = 0; + uart_ll_update(0); // TODO: IDF-5338 + hw->conf0_sync.irda_en = 0; + uart_ll_update(0); // TODO: IDF-5338 + hw->rs485_conf_sync.dl0_en = 1; + uart_ll_update(0); // TODO: IDF-5338 + hw->rs485_conf_sync.dl1_en = 1; + uart_ll_update(0); // TODO: IDF-5338 + hw->rs485_conf_sync.rs485_en = 1; + uart_ll_update(0); // TODO: IDF-5338 +} + +/** + * @brief Configure the UART work in collision_detect mode. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None. + */ +static inline void uart_ll_set_mode_collision_detect(uart_dev_t *hw) +{ + hw->conf0_sync.irda_en = 0; + uart_ll_update(0); // TODO: IDF-5338 + // Enable full-duplex mode + hw->rs485_conf_sync.rs485tx_rx_en = 1; + uart_ll_update(0); // TODO: IDF-5338 + // Transmitter should send data when the receiver is busy, + hw->rs485_conf_sync.rs485rxby_tx_en = 1; + uart_ll_update(0); // TODO: IDF-5338 + hw->rs485_conf_sync.dl0_en = 1; + uart_ll_update(0); // TODO: IDF-5338 + hw->rs485_conf_sync.dl1_en = 1; + uart_ll_update(0); // TODO: IDF-5338 + hw->conf0_sync.sw_rts = 0; + uart_ll_update(0); // TODO: IDF-5338 + hw->rs485_conf_sync.rs485_en = 1; + uart_ll_update(0); // TODO: IDF-5338 +} + +/** + * @brief Configure the UART work in irda mode. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None. + */ +static inline void uart_ll_set_mode_irda(uart_dev_t *hw) +{ + hw->rs485_conf_sync.rs485_en = 0; + uart_ll_update(0); // TODO: IDF-5338 + hw->rs485_conf_sync.rs485tx_rx_en = 0; + uart_ll_update(0); // TODO: IDF-5338 + hw->rs485_conf_sync.rs485rxby_tx_en = 0; + uart_ll_update(0); // TODO: IDF-5338 + hw->conf0_sync.sw_rts = 0; + uart_ll_update(0); // TODO: IDF-5338 + hw->conf0_sync.irda_en = 1; + uart_ll_update(0); // TODO: IDF-5338 +} + +/** + * @brief Set uart mode. + * + * @param hw Beginning address of the peripheral registers. + * @param mode The UART mode to be set. + * + * @return None. + */ +static inline void uart_ll_set_mode(uart_dev_t *hw, uart_mode_t mode) +{ + switch (mode) { + default: + case UART_MODE_UART: + uart_ll_set_mode_normal(hw); + break; + case UART_MODE_RS485_COLLISION_DETECT: + uart_ll_set_mode_collision_detect(hw); + break; + case UART_MODE_RS485_APP_CTRL: + uart_ll_set_mode_rs485_app_ctrl(hw); + break; + case UART_MODE_RS485_HALF_DUPLEX: + uart_ll_set_mode_rs485_half_duplex(hw); + break; + case UART_MODE_IRDA: + uart_ll_set_mode_irda(hw); + break; + } +} + +/** + * @brief Get the UART AT cmd char configuration. + * + * @param hw Beginning address of the peripheral registers. + * @param cmd_char The Pointer to accept value of UART AT cmd char. + * @param char_num Pointer to accept the repeat number of UART AT cmd char. + * + * @return None. + */ +static inline void uart_ll_get_at_cmd_char(uart_dev_t *hw, uint8_t *cmd_char, uint8_t *char_num) +{ + *cmd_char = HAL_FORCE_READ_U32_REG_FIELD(hw->at_cmd_char_sync, data); + uart_ll_update(0); // TODO: IDF-5338 + *char_num = HAL_FORCE_READ_U32_REG_FIELD(hw->at_cmd_char_sync, char_num); + uart_ll_update(0); // TODO: IDF-5338 +} + +/** + * @brief Get the UART wakeup threshold value. + * + * @param hw Beginning address of the peripheral registers. + * + * @return The UART wakeup threshold value. + */ +static inline uint32_t uart_ll_get_wakeup_thrd(uart_dev_t *hw) +{ + return hw->sleep_conf2.active_threshold + UART_LL_MIN_WAKEUP_THRESH; +} + +/** + * @brief Get the UART data bit configuration. + * + * @param hw Beginning address of the peripheral registers. + * @param data_bit The pointer to accept the UART data bit configuration. + * + * @return The bit mode. + */ +static inline void uart_ll_get_data_bit_num(uart_dev_t *hw, uart_word_length_t *data_bit) +{ + *data_bit = hw->conf0_sync.bit_num; +} + +/** + * @brief Check if the UART sending state machine is in the IDLE state. + * + * @param hw Beginning address of the peripheral registers. + * + * @return True if the state machine is in the IDLE state, otherwise false is returned. + */ +static inline bool uart_ll_is_tx_idle(uart_dev_t *hw) +{ + return ((hw->status.txfifo_cnt == 0) && (hw->fsm_status.st_utx_out == 0)); +} + +/** + * @brief Check if the UART rts flow control is enabled. + * + * @param hw Beginning address of the peripheral registers. + * + * @return True if hw rts flow control is enabled, otherwise false is returned. + */ +static inline bool uart_ll_is_hw_rts_en(uart_dev_t *hw) +{ + return hw->hwfc_conf_sync.rx_flow_en; +} + +/** + * @brief Check if the UART cts flow control is enabled. + * + * @param hw Beginning address of the peripheral registers. + * + * @return True if hw cts flow control is enabled, otherwise false is returned. + */ +static inline bool uart_ll_is_hw_cts_en(uart_dev_t *hw) +{ + return hw->conf0_sync.tx_flow_en; +} + +/** + * @brief Configure TX signal loop back to RX module, just for the testing purposes + * + * @param hw Beginning address of the peripheral registers. + * @param loop_back_en Set ture to enable the loop back function, else set it false. + * + * @return None + */ +static inline void uart_ll_set_loop_back(uart_dev_t *hw, bool loop_back_en) +{ + hw->conf0_sync.loopback = loop_back_en; +} + +static inline void uart_ll_xon_force_on(uart_dev_t *hw, bool always_on) +{ + hw->swfc_conf0_sync.force_xon = 1; + uart_ll_update(0); // TODO: IDF-5338 + if(!always_on) { + hw->swfc_conf0_sync.force_xon = 0; + uart_ll_update(0); // TODO: IDF-5338 + } +} + +/** + * @brief Inverse the UART signal with the given mask. + * + * @param hw Beginning address of the peripheral registers. + * @param inv_mask The UART signal bitmap needs to be inversed. + * Use the ORred mask of `uart_signal_inv_t`; + * + * @return None. + */ +static inline void uart_ll_inverse_signal(uart_dev_t *hw, uint32_t inv_mask) +{ + typeof(hw->conf0_sync) conf0_reg = hw->conf0_sync; + conf0_reg.irda_tx_inv = (inv_mask & UART_SIGNAL_IRDA_TX_INV) ? 1 : 0; + conf0_reg.irda_rx_inv = (inv_mask & UART_SIGNAL_IRDA_RX_INV) ? 1 : 0; + conf0_reg.rxd_inv = (inv_mask & UART_SIGNAL_RXD_INV) ? 1 : 0; + conf0_reg.txd_inv = (inv_mask & UART_SIGNAL_TXD_INV) ? 1 : 0; + hw->conf0_sync.val = conf0_reg.val; + uart_ll_update(0); // TODO: IDF-5338 + + typeof(hw->conf1) conf1_reg = hw->conf1; + conf1_reg.rts_inv = (inv_mask & UART_SIGNAL_RTS_INV) ? 1 : 0; + conf1_reg.dtr_inv = (inv_mask & UART_SIGNAL_DTR_INV) ? 1 : 0; + conf1_reg.cts_inv = (inv_mask & UART_SIGNAL_CTS_INV) ? 1 : 0; + conf1_reg.dsr_inv = (inv_mask & UART_SIGNAL_DSR_INV) ? 1 : 0; + hw->conf1.val = conf1_reg.val; +} + +/** + * @brief Configure the timeout value for receiver receiving a byte, and enable rx timeout function. + * + * @param hw Beginning address of the peripheral registers. + * @param tout_thrd The timeout value as UART bit time. The rx timeout function will be disabled if `tout_thrd == 0`. + * + * @return None. + */ +static inline void uart_ll_set_rx_tout(uart_dev_t *hw, uint16_t tout_thrd) +{ + uint16_t tout_val = tout_thrd; + if(tout_thrd > 0) { + hw->tout_conf_sync.rx_tout_thrhd = tout_val; + uart_ll_update(0); // TODO: IDF-5338 + hw->tout_conf_sync.rx_tout_en = 1; + uart_ll_update(0); // TODO: IDF-5338 + } else { + hw->tout_conf_sync.rx_tout_en = 0; + uart_ll_update(0); // TODO: IDF-5338 + } +} + +/** + * @brief Get the timeout value for receiver receiving a byte. + * + * @param hw Beginning address of the peripheral registers. + * + * @return tout_thr The timeout threshold value. If timeout feature is disabled returns 0. + */ +static inline uint16_t uart_ll_get_rx_tout_thr(uart_dev_t *hw) +{ + uint16_t tout_thrd = 0; + if(hw->tout_conf_sync.rx_tout_en > 0) { + tout_thrd = hw->tout_conf_sync.rx_tout_thrhd; + } + return tout_thrd; +} + +/** + * @brief Get UART maximum timeout threshold. + * + * @param hw Beginning address of the peripheral registers. + * + * @return maximum timeout threshold. + */ +static inline uint16_t uart_ll_max_tout_thrd(uart_dev_t *hw) +{ + return UART_RX_TOUT_THRHD_V; +} + +/** + * @brief Configure the auto baudrate. + * + * @param hw Beginning address of the peripheral registers. + * @param enable Boolean marking whether the auto baudrate should be enabled or not. + */ +static inline void uart_ll_set_autobaud_en(uart_dev_t *hw, bool enable) +{ + hw->conf0_sync.autobaud_en = enable ? 1 : 0; + uart_ll_update(0); // TODO: IDF-5338 +} + +/** + * @brief Get the RXD edge count. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline uint32_t uart_ll_get_rxd_edge_cnt(uart_dev_t *hw) +{ + return hw->rxd_cnt.rxd_edge_cnt; +} + +/** + * @brief Get the positive pulse minimum count. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline uint32_t uart_ll_get_pos_pulse_cnt(uart_dev_t *hw) +{ + return hw->pospulse.posedge_min_cnt; +} + +/** + * @brief Get the negative pulse minimum count. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline uint32_t uart_ll_get_neg_pulse_cnt(uart_dev_t *hw) +{ + return hw->negpulse.negedge_min_cnt; +} + +/** + * @brief Get the high pulse minimum count. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline uint32_t uart_ll_get_high_pulse_cnt(uart_dev_t *hw) +{ + return hw->highpulse.highpulse_min_cnt; +} + +/** + * @brief Get the low pulse minimum count. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline uint32_t uart_ll_get_low_pulse_cnt(uart_dev_t *hw) +{ + return hw->lowpulse.lowpulse_min_cnt; +} + +/** + * @brief Force UART xoff. + * + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). + * + * @return None. + */ +static inline void uart_ll_force_xoff(uart_port_t uart_num) +{ + REG_CLR_BIT(UART_SWFC_CONF0_SYNC_REG(uart_num), UART_FORCE_XON); + uart_ll_update(0); // TODO: IDF-5338 + REG_SET_BIT(UART_SWFC_CONF0_SYNC_REG(uart_num), UART_SW_FLOW_CON_EN | UART_FORCE_XOFF); + uart_ll_update(0); // TODO: IDF-5338 + // REG_SET_BIT(UART_ID_REG(uart_num), UART_UPDATE); +} + +/** + * @brief Force UART xon. + * + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). + * + * @return None. + */ +static inline void uart_ll_force_xon(uart_port_t uart_num) +{ + REG_CLR_BIT(UART_SWFC_CONF0_SYNC_REG(uart_num), UART_FORCE_XOFF); + uart_ll_update(0); // TODO: IDF-5338 + REG_SET_BIT(UART_SWFC_CONF0_SYNC_REG(uart_num), UART_FORCE_XON); + uart_ll_update(0); // TODO: IDF-5338 + REG_CLR_BIT(UART_SWFC_CONF0_SYNC_REG(uart_num), UART_SW_FLOW_CON_EN | UART_FORCE_XON); + uart_ll_update(0); // TODO: IDF-5338 + // REG_SET_BIT(UART_ID_REG(uart_num), UART_UPDATE); +} + +/** + * @brief Get UART finite-state machine status. + * + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). + * + * @return UART module FSM status. + */ +static inline uint32_t uart_ll_get_fsm_status(uart_port_t uart_num) +{ + return REG_GET_FIELD(UART_FSM_STATUS_REG(uart_num), UART_ST_UTX_OUT); +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/usb_serial_jtag_ll.h b/components/hal/esp32h2/include/hal/usb_serial_jtag_ll.h new file mode 100644 index 0000000000..06ade12c70 --- /dev/null +++ b/components/hal/esp32h2/include/hal/usb_serial_jtag_ll.h @@ -0,0 +1,164 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// The LL layer of the USB-serial-jtag controller + +#pragma once +#include "soc/usb_serial_jtag_reg.h" +#include "soc/usb_serial_jtag_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//The in and out endpoints are this long. +#define USB_SERIAL_JTAG_PACKET_SZ_BYTES 64 + +#define USB_SERIAL_JTAG_LL_INTR_MASK (0x7ffff) //All interrupt mask + +// Define USB_SERIAL_JTAG interrupts +// Note the hardware has more interrupts, but they're only useful for debugging +// the hardware. +typedef enum { + USB_SERIAL_JTAG_INTR_SOF = (1 << 1), + USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT = (1 << 2), + USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY = (1 << 3), + USB_SERIAL_JTAG_INTR_TOKEN_REC_IN_EP1 = (1 << 8), + USB_SERIAL_JTAG_INTR_BUS_RESET = (1 << 9), + USB_SERIAL_JTAG_INTR_EP1_ZERO_PAYLOAD = (1 << 10), +} usb_serial_jtag_ll_intr_t; + +/** + * @brief Enable the USB_SERIAL_JTAG interrupt based on the given mask. + * + * @param mask The bitmap of the interrupts need to be enabled. + * + * @return None + */ +static inline void usb_serial_jtag_ll_ena_intr_mask(uint32_t mask) +{ + USB_SERIAL_JTAG.int_ena.val |= mask; +} + +/** + * @brief Disable the USB_SERIAL_JTAG interrupt based on the given mask. + * + * @param mask The bitmap of the interrupts need to be disabled. + * + * @return None + */ +static inline void usb_serial_jtag_ll_disable_intr_mask(uint32_t mask) +{ + USB_SERIAL_JTAG.int_ena.val &= (~mask); +} + +/** + * @brief Get the USB_SERIAL_JTAG interrupt status. + * + * @return The USB_SERIAL_JTAG interrupt status. + */ +static inline uint32_t usb_serial_jtag_ll_get_intsts_mask(void) +{ + return USB_SERIAL_JTAG.int_st.val; +} + +/** + * @brief Clear the USB_SERIAL_JTAG interrupt status based on the given mask. + * + * @param mask The bitmap of the interrupts need to be cleared. + * + * @return None + */ +static inline void usb_serial_jtag_ll_clr_intsts_mask(uint32_t mask) +{ + USB_SERIAL_JTAG.int_clr.val = mask; +} + +/** + * @brief Get status of enabled interrupt. + * + * @return interrupt enable value + */ +static inline uint32_t usb_serial_jtag_ll_get_intr_ena_status(void) +{ + return USB_SERIAL_JTAG.int_ena.val; +} + +/** + * @brief Read the bytes from the USB_SERIAL_JTAG rxfifo. + * + * @param buf The data buffer. + * @param rd_len The data length needs to be read. + * + * @return amount of bytes read + */ +static inline int usb_serial_jtag_ll_read_rxfifo(uint8_t *buf, uint32_t rd_len) +{ + int i; + for (i = 0; i < (int)rd_len; i++) { + if (!USB_SERIAL_JTAG.ep1_conf.serial_out_ep_data_avail) break; + buf[i] = USB_SERIAL_JTAG.ep1.rdwr_byte; + } + return i; +} + +/** + * @brief Write byte to the USB_SERIAL_JTAG txfifo. Only writes bytes as long / if there + * is room in the buffer. + * + * @param buf The data buffer. + * @param wr_len The data length needs to be writen. + * + * @return Amount of bytes actually written. May be less than wr_len. + */ +static inline int usb_serial_jtag_ll_write_txfifo(const uint8_t *buf, uint32_t wr_len) +{ + int i; + for (i = 0; i < (int)wr_len; i++) { + if (!USB_SERIAL_JTAG.ep1_conf.serial_in_ep_data_free) break; + USB_SERIAL_JTAG.ep1.rdwr_byte = buf[i]; + } + return i; +} + +/** + * @brief Returns 1 if the USB_SERIAL_JTAG rxfifo has data available. + * + * @return 0 if no data available, 1 if data available + */ +static inline int usb_serial_jtag_ll_rxfifo_data_available(void) +{ + return USB_SERIAL_JTAG.ep1_conf.serial_out_ep_data_avail; +} + +/** + * @brief Returns 1 if the USB_SERIAL_JTAG txfifo has room. + * + * @return 0 if no data available, 1 if data available + */ +static inline int usb_serial_jtag_ll_txfifo_writable(void) +{ + return USB_SERIAL_JTAG.ep1_conf.serial_in_ep_data_free; +} + +/** + * @brief Flushes the TX buffer, that is, make it available for the + * host to pick up. + * + * @note When fifo is full (with 64 byte), HW will flush the buffer automatically. + * It won't be executed if there is nothing in the fifo. + * + * @return na + */ +static inline void usb_serial_jtag_ll_txfifo_flush(void) +{ + USB_SERIAL_JTAG.ep1_conf.wr_done=1; +} + + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/include/hal/gpio_types.h b/components/hal/include/hal/gpio_types.h index 8e35f6d9ea..ed667ff6f8 100644 --- a/components/hal/include/hal/gpio_types.h +++ b/components/hal/include/hal/gpio_types.h @@ -385,6 +385,40 @@ typedef enum { GPIO_NUM_MAX, /** @endcond */ } gpio_num_t; +#elif CONFIG_IDF_TARGET_ESP32H2 +typedef enum { + GPIO_NUM_NC = -1, /*!< Use to signal not connected to S/W */ + GPIO_NUM_0 = 0, /*!< GPIO0, input and output */ + GPIO_NUM_1 = 1, /*!< GPIO1, input and output */ + GPIO_NUM_2 = 2, /*!< GPIO2, input and output */ + GPIO_NUM_3 = 3, /*!< GPIO3, input and output */ + GPIO_NUM_4 = 4, /*!< GPIO4, input and output */ + GPIO_NUM_5 = 5, /*!< GPIO5, input and output */ + GPIO_NUM_6 = 6, /*!< GPIO6, input and output */ + GPIO_NUM_7 = 7, /*!< GPIO7, input and output */ + GPIO_NUM_8 = 8, /*!< GPIO8, input and output */ + GPIO_NUM_9 = 9, /*!< GPIO9, input and output */ + GPIO_NUM_10 = 10, /*!< GPIO10, input and output */ + GPIO_NUM_11 = 11, /*!< GPIO11, input and output */ + GPIO_NUM_12 = 12, /*!< GPIO12, input and output */ + GPIO_NUM_13 = 13, /*!< GPIO13, input and output */ + GPIO_NUM_14 = 14, /*!< GPIO14, input and output */ + GPIO_NUM_15 = 15, /*!< GPIO15, input and output */ + GPIO_NUM_16 = 16, /*!< GPIO16, input and output */ + GPIO_NUM_17 = 17, /*!< GPIO17, input and output */ + GPIO_NUM_18 = 18, /*!< GPIO18, input and output */ + GPIO_NUM_19 = 19, /*!< GPIO19, input and output */ + GPIO_NUM_20 = 20, /*!< GPIO20, input and output */ + GPIO_NUM_21 = 21, /*!< GPIO21, input and output */ + GPIO_NUM_22 = 22, /*!< GPIO22, input and output */ + GPIO_NUM_23 = 23, /*!< GPIO23, input and output */ + GPIO_NUM_24 = 24, /*!< GPIO24, input and output */ + GPIO_NUM_25 = 25, /*!< GPIO25, input and output */ + GPIO_NUM_26 = 26, /*!< GPIO26, input and output */ + GPIO_NUM_27 = 27, /*!< GPIO27, input and output */ + GPIO_NUM_MAX, +/** @endcond */ +} gpio_num_t; #endif typedef enum { diff --git a/components/hal/include/hal/sha_types.h b/components/hal/include/hal/sha_types.h index e8da1f0812..df3387c7c7 100644 --- a/components/hal/include/hal/sha_types.h +++ b/components/hal/include/hal/sha_types.h @@ -23,6 +23,8 @@ #include "esp32c2/rom/sha.h" #elif CONFIG_IDF_TARGET_ESP32C6 #include "esp32c6/rom/sha.h" +#elif CONFIG_IDF_TARGET_ESP32H2 +#include "esp32h2/rom/sha.h" #endif #ifdef __cplusplus diff --git a/components/hal/include/hal/wdt_hal.h b/components/hal/include/hal/wdt_hal.h index 527f146148..0fdca62f1d 100644 --- a/components/hal/include/hal/wdt_hal.h +++ b/components/hal/include/hal/wdt_hal.h @@ -29,7 +29,7 @@ typedef struct { wdt_inst_t inst; /**< Which WDT instance this HAL context is using (i.e. MWDT0, MWDT1, RWDT)*/ union { timg_dev_t *mwdt_dev; /**< Starting address of the MWDT */ -#if CONFIG_IDF_TARGET_ESP32C6 // TODO: IDF-5653 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 // TODO: IDF-5653 lp_wdt_dev_t *rwdt_dev; /**< Starting address of the RWDT*/ #else rtc_cntl_dev_t *rwdt_dev; /**< Starting address of the RWDT*/ diff --git a/components/hal/wdt_hal_iram.c b/components/hal/wdt_hal_iram.c index 8c6609b409..37c81f7a98 100644 --- a/components/hal/wdt_hal_iram.c +++ b/components/hal/wdt_hal_iram.c @@ -24,7 +24,7 @@ void wdt_hal_init(wdt_hal_context_t *hal, wdt_inst_t wdt_inst, uint32_t prescale } #endif else { -#if CONFIG_IDF_TARGET_ESP32C6 // TODO: IDF-5653 +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 // ESP32C6-TODO, ESP32H2-TODO: IDF-5653 hal->rwdt_dev = &LP_WDT; #else hal->rwdt_dev = &RTCCNTL; diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index a59ee41652..26d2bcaecd 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -3,26 +3,6 @@ # using gen_soc_caps_kconfig.py, do not edit manually ##################################################### -config SOC_DEDICATED_GPIO_SUPPORTED - bool - default y - -config SOC_GDMA_SUPPORTED - bool - default y - -config SOC_BT_SUPPORTED - bool - default y - -config SOC_ASYNC_MEMCPY_SUPPORTED - bool - default y - -config SOC_SUPPORTS_SECURE_DL_MODE - bool - default y - config SOC_EFUSE_KEY_PURPOSE_FIELD bool default y @@ -43,22 +23,6 @@ config SOC_SYSTIMER_SUPPORTED bool default y -config SOC_SUPPORT_COEXISTENCE - bool - default y - -config SOC_MPI_SUPPORTED - bool - default y - -config SOC_HMAC_SUPPORTED - bool - default y - -config SOC_SECURE_BOOT_SUPPORTED - bool - default y - config SOC_XTAL_SUPPORT_32M bool default y diff --git a/components/soc/esp32h2/include/soc/pcr_struct.h b/components/soc/esp32h2/include/soc/pcr_struct.h index a81e45de56..9eaaf9059e 100644 --- a/components/soc/esp32h2/include/soc/pcr_struct.h +++ b/components/soc/esp32h2/include/soc/pcr_struct.h @@ -1791,12 +1791,12 @@ typedef union { * This field indicates which one 32KHz clock will be used by timergroup. 0: * OSC32K(default), 1: XTAL32K, 2/3: 32KHz from pad GPIO0. */ - uint32_t 32k_sel:2; + uint32_t clk_32k_sel:2; /** 32k_modem_sel : R/W; bitpos: [3:2]; default: 0; * This field indicates which one 32KHz clock will be used by MODEM_SYSTEM. 0: * OSC32K(default), 1: XTAL32K, 2/3: 32KHz from pad GPIO0. */ - uint32_t 32k_modem_sel:2; + uint32_t clk_32k_modem_sel:2; uint32_t reserved_4:28; }; uint32_t val; diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 592b4ce133..31d2f9691c 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -26,16 +26,16 @@ /*-------------------------- COMMON CAPS ---------------------------------------*/ // #define SOC_ADC_SUPPORTED 1 // TODO: IDF-6214 -#define SOC_DEDICATED_GPIO_SUPPORTED 1 // TODO: IDF-6241 -#define SOC_GDMA_SUPPORTED 1 // TODO: IDF-6222 +// #define SOC_DEDICATED_GPIO_SUPPORTED 1 // TODO: IDF-6241 +// #define SOC_GDMA_SUPPORTED 1 // TODO: IDF-6222 // #define SOC_PCNT_SUPPORTED 1 // TODO: IDF-6221 // #define SOC_MCPWM_SUPPORTED 1 // TODO: IDF-6237 // #define SOC_TWAI_SUPPORTED 1 // TODO: IDF-6217 -#define SOC_BT_SUPPORTED 1 -#define SOC_ASYNC_MEMCPY_SUPPORTED 1 +// #define SOC_BT_SUPPORTED 1 // TODO: IDF-6416 +// #define SOC_ASYNC_MEMCPY_SUPPORTED 1 // TODO: IDF-6238 // #define SOC_USB_SERIAL_JTAG_SUPPORTED 1 // TODO: IDF-6239 // #define SOC_TEMP_SENSOR_SUPPORTED 1 // TODO: IDF-6229 -#define SOC_SUPPORTS_SECURE_DL_MODE 1 +// #define SOC_SUPPORTS_SECURE_DL_MODE 1 // TODO: IDF-6281 //#define SOC_RISCV_COPROC_SUPPORTED 1 // TODO: IDF-6272 #define SOC_EFUSE_KEY_PURPOSE_FIELD 1 #define SOC_EFUSE_HAS_EFUSE_RST_BUG 1 @@ -45,14 +45,14 @@ // #define SOC_RMT_SUPPORTED 1 // TODO: IDF-6224 // #define SOC_SDM_SUPPORTED 1 // TODO: IDF-6220 #define SOC_SYSTIMER_SUPPORTED 1 -#define SOC_SUPPORT_COEXISTENCE 1 +// #define SOC_SUPPORT_COEXISTENCE 1 // TODO: IDF-6416 // #define SOC_AES_SUPPORTED 1 // TODO: IDF-6280 -#define SOC_MPI_SUPPORTED 1 +// #define SOC_MPI_SUPPORTED 1 // TODO: IDF-6415 // #define SOC_SHA_SUPPORTED 1 // TODO: IDF-6275 -#define SOC_HMAC_SUPPORTED 1 // TODO: IDF-6279 +// #define SOC_HMAC_SUPPORTED 1 // TODO: IDF-6279 // #define SOC_DIG_SIGN_SUPPORTED 1 // TODO: IDF-6285 // #define SOC_FLASH_ENC_SUPPORTED 1 // TODO: IDF-6282 -#define SOC_SECURE_BOOT_SUPPORTED 1 +// #define SOC_SECURE_BOOT_SUPPORTED 1 // TODO: IDF-6281 /*-------------------------- XTAL CAPS ---------------------------------------*/ #define SOC_XTAL_SUPPORT_32M 1