Kaynağa Gözat

feat(hw_support): add atomic code block for peripheral bus clock and reset

morris 2 yıl önce
ebeveyn
işleme
a9c813ca3e

+ 58 - 1
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 <stdint.h>
 #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.
  *

+ 36 - 0
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);