From a9c813ca3ee7f0b6b6d8d2c2c6f12b758de9c30c Mon Sep 17 00:00:00 2001 From: morris Date: Wed, 16 Aug 2023 18:53:14 +0800 Subject: [PATCH] feat(hw_support): add atomic code block for peripheral bus clock and reset --- .../include/esp_private/periph_ctrl.h | 59 ++++++++++++++++++- components/esp_hw_support/periph_ctrl.c | 36 +++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/components/esp_hw_support/include/esp_private/periph_ctrl.h b/components/esp_hw_support/include/esp_private/periph_ctrl.h index a20364bd51..c73c789cf7 100644 --- a/components/esp_hw_support/include/esp_private/periph_ctrl.h +++ b/components/esp_hw_support/include/esp_private/periph_ctrl.h @@ -1,16 +1,73 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once +#include #include "soc/periph_defs.h" #ifdef __cplusplus extern "C" { #endif +/** + * @defgroup Reset and Clock Control APIs + * @{ + */ + +/** + * @brief Acquire the RCC lock for a peripheral module + * + * @note User code protected by this macro should be as short as possible, because it's a critical section + * @note This macro will increase the reference lock of that peripheral. + * You can get the value before the increment from the `rc_name` local variable + */ +#define PERIPH_RCC_ACQUIRE_ATOMIC(periph, rc_name) \ + for (uint8_t rc_name, i = 1, __DECLARE_RCC_RC_ATOMIC_ENV; \ + i ? (rc_name = periph_rcc_acquire_enter(periph), 1) : 0; \ + periph_rcc_acquire_exit(periph, rc_name), i--) + +/** + * @brief Release the RCC lock for a peripheral module + * + * @note User code protected by this macro should be as short as possible, because it's a critical section + * @note This macro will decrease the reference lock of that peripheral. + * You can get the value before the increment from the `rc_name` local variable + */ +#define PERIPH_RCC_RELEASE_ATOMIC(periph, rc_name) \ + for (uint8_t rc_name, i = 1, __DECLARE_RCC_RC_ATOMIC_ENV; \ + i ? (rc_name = periph_rcc_release_enter(periph), 1) : 0; \ + periph_rcc_release_exit(periph, rc_name), i--) + +/** + * @brief A simplified version of `PERIPH_RCC_ACQUIRE/RELEASE_ATOMIC`, without a reference count + * + * @note User code protected by this macro should be as short as possible, because it's a critical section + */ +#define PERIPH_RCC_ATOMIC() \ + for (int i = 1, __DECLARE_RCC_ATOMIC_ENV; \ + i ? (periph_rcc_enter(), 1) : 0; \ + periph_rcc_exit(), i--) + +/** @cond */ +// The following functions are not intended to be used directly by the developers +uint8_t periph_rcc_acquire_enter(periph_module_t periph); +void periph_rcc_acquire_exit(periph_module_t periph, uint8_t ref_count); +uint8_t periph_rcc_release_enter(periph_module_t periph); +void periph_rcc_release_exit(periph_module_t periph, uint8_t ref_count); +void periph_rcc_enter(void); +void periph_rcc_exit(void); +/** @endcond */ + +/** + * @} + */ + +/************************************************************************************************************* + * @note The following APIs are no longer supported since ESP32P4, please use the RCC lock macros instead. + *************************************************************************************************************/ /** * @brief Enable peripheral module by un-gating the clock and de-asserting the reset signal. * diff --git a/components/esp_hw_support/periph_ctrl.c b/components/esp_hw_support/periph_ctrl.c index 8c24824716..6db2d8fa1f 100644 --- a/components/esp_hw_support/periph_ctrl.c +++ b/components/esp_hw_support/periph_ctrl.c @@ -13,10 +13,46 @@ #include "esp_private/esp_modem_clock.h" #endif +/// @brief For simplicity and backward compatible, we are using the same spin lock for both bus clock on/off and reset +/// @note We may want to split them into two spin locks in the future static portMUX_TYPE periph_spinlock = portMUX_INITIALIZER_UNLOCKED; static uint8_t ref_counts[PERIPH_MODULE_MAX] = {0}; +void periph_rcc_enter(void) +{ + portENTER_CRITICAL_SAFE(&periph_spinlock); +} + +void periph_rcc_exit(void) +{ + portEXIT_CRITICAL_SAFE(&periph_spinlock); +} + +uint8_t periph_rcc_acquire_enter(periph_module_t periph) +{ + periph_rcc_enter(); + return ref_counts[periph]; +} + +void periph_rcc_acquire_exit(periph_module_t periph, uint8_t ref_count) +{ + ref_counts[periph] = ++ref_count; + periph_rcc_exit(); +} + +uint8_t periph_rcc_release_enter(periph_module_t periph) +{ + periph_rcc_enter(); + return ref_counts[periph] - 1; +} + +void periph_rcc_release_exit(periph_module_t periph, uint8_t ref_count) +{ + ref_counts[periph] = ref_count; + periph_rcc_exit(); +} + void periph_module_enable(periph_module_t periph) { assert(periph < PERIPH_MODULE_MAX);