Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zephyr: esp32c6: Add LP Core support #395

Open
wants to merge 3 commits into
base: zephyr
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions components/driver/gpio/include/driver/lp_io.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

#include "soc/soc_caps.h"
#include "esp_err.h"
#include "driver/gpio.h"

#ifdef __cplusplus
extern "C" {
#endif

#if SOC_LP_GPIO_MATRIX_SUPPORTED
/**
* @brief Connect a RTC(LP) GPIO input with a peripheral signal, which tagged as input attribute
*
* @note There's no limitation on the number of signals that a RTC(LP) GPIO can connect with
*
* @param gpio_num GPIO number, especially, `LP_GPIO_MATRIX_CONST_ZERO_INPUT` means connect logic 0 to signal
* `LP_GPIO_MATRIX_CONST_ONE_INPUT` means connect logic 1 to signal
* @param signal_idx LP peripheral signal index (tagged as input attribute)
* @param inv Whether the RTC(LP) GPIO input to be inverted or not
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t lp_gpio_connect_in_signal(gpio_num_t gpio_num, uint32_t signal_idx, bool inv);

/**
* @brief Connect a peripheral signal which tagged as output attribute with a RTC(LP) GPIO
*
* @note There's no limitation on the number of RTC(LP) GPIOs that a signal can connect with
*
* @param gpio_num GPIO number
* @param signal_idx LP peripheral signal index (tagged as input attribute), especially, `SIG_LP_GPIO_OUT_IDX` means disconnect RTC(LP) GPIO and other peripherals. Only the RTC GPIO driver can control the output level
* @param out_inv Whether to signal to be inverted or not
* @param out_en_inv Whether the output enable control is inverted or not
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t lp_gpio_connect_out_signal(gpio_num_t gpio_num, uint32_t signal_idx, bool out_inv, bool out_en_inv);
#endif // SOC_LP_GPIO_MATRIX_SUPPORTED

#ifdef __cplusplus
}
#endif
12 changes: 12 additions & 0 deletions components/driver/gpio/include/driver/rtc_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,18 @@ esp_err_t rtc_gpio_set_drive_capability(gpio_num_t gpio_num, gpio_drive_cap_t st
*/
esp_err_t rtc_gpio_get_drive_capability(gpio_num_t gpio_num, gpio_drive_cap_t* strength);

/**
* @brief Select a RTC IOMUX function for the RTC IO
*
* @param gpio_num GPIO number
* @param func Function to assign to the pin
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t rtc_gpio_iomux_func_sel(gpio_num_t gpio_num, int func);

#endif // SOC_RTCIO_INPUT_OUTPUT_SUPPORTED

#if SOC_RTCIO_HOLD_SUPPORTED
Expand Down
11 changes: 11 additions & 0 deletions components/driver/gpio/rtc_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,17 @@ esp_err_t rtc_gpio_pulldown_dis(gpio_num_t gpio_num)
return ESP_OK;
}

#ifdef CONFIG_SOC_SERIES_ESP32C6
esp_err_t rtc_gpio_iomux_func_sel(gpio_num_t gpio_num, int func)
{
ESP_RETURN_ON_FALSE(rtc_gpio_is_valid_gpio(gpio_num), ESP_ERR_INVALID_ARG, RTCIO_TAG, "RTCIO number error");
RTCIO_ENTER_CRITICAL();
rtcio_hal_iomux_func_sel(rtc_io_number_get(gpio_num), func);
RTCIO_EXIT_CRITICAL();

return ESP_OK;
}
#endif
#endif // SOC_RTCIO_INPUT_OUTPUT_SUPPORTED

#if SOC_RTCIO_HOLD_SUPPORTED
Expand Down
49 changes: 49 additions & 0 deletions components/esp_hw_support/include/esp_private/periph_ctrl.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,55 @@
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(rc_periph, rc_name) \
for (uint8_t rc_name, _rc_cnt = 1, __DECLARE_RCC_RC_ATOMIC_ENV; \
_rc_cnt ? (rc_name = periph_rcc_acquire_enter(rc_periph), 1) : 0; \
periph_rcc_acquire_exit(rc_periph, rc_name), _rc_cnt--)

/**
* @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 after the decrease from the `rc_name` local variable
*/
#define PERIPH_RCC_RELEASE_ATOMIC(rc_periph, rc_name) \
for (uint8_t rc_name, _rc_cnt = 1, __DECLARE_RCC_RC_ATOMIC_ENV; \
_rc_cnt ? (rc_name = periph_rcc_release_enter(rc_periph), 1) : 0; \
periph_rcc_release_exit(rc_periph, rc_name), _rc_cnt--)

/**
* @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 _rc_cnt = 1, __DECLARE_RCC_ATOMIC_ENV; \
_rc_cnt ? (periph_rcc_enter(), 1) : 0; \
periph_rcc_exit(), _rc_cnt--)

/** @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 */

/**
* @brief Enable peripheral module by un-gating the clock and de-asserting the reset signal.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

#include "soc/soc_caps.h"
#include "esp_private/periph_ctrl.h"

#ifdef __cplusplus
extern "C" {
#endif

#if SOC_PERIPH_CLK_CTRL_SHARED
#define HP_UART_SRC_CLK_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define HP_UART_SRC_CLK_ATOMIC()
#endif

#if SOC_RCC_IS_INDEPENDENT
#define HP_UART_BUS_CLK_ATOMIC()
#else
#define HP_UART_BUS_CLK_ATOMIC() PERIPH_RCC_ATOMIC()
#endif

#if (SOC_UART_LP_NUM >= 1)
#define LP_UART_SRC_CLK_ATOMIC() PERIPH_RCC_ATOMIC()
#define LP_UART_BUS_CLK_ATOMIC() PERIPH_RCC_ATOMIC()
#endif

#ifdef __cplusplus
}
#endif
34 changes: 34 additions & 0 deletions components/esp_hw_support/periph_ctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,40 @@ static int periph_spinlock;

static uint8_t ref_counts[PERIPH_MODULE_MAX] = {0};

IRAM_ATTR void periph_rcc_enter(void)
{
ENTER_CRITICAL_SECTION();
}

IRAM_ATTR void periph_rcc_exit(void)
{
LEAVE_CRITICAL_SECTION();
}

IRAM_ATTR uint8_t periph_rcc_acquire_enter(periph_module_t periph)
{
periph_rcc_enter();
return ref_counts[periph];
}

IRAM_ATTR void periph_rcc_acquire_exit(periph_module_t periph, uint8_t ref_count)
{
ref_counts[periph] = ++ref_count;
periph_rcc_exit();
}

IRAM_ATTR uint8_t periph_rcc_release_enter(periph_module_t periph)
{
periph_rcc_enter();
return ref_counts[periph] - 1;
}

IRAM_ATTR 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);
Expand Down
159 changes: 159 additions & 0 deletions components/hal/esp32c6/include/hal/lp_core_ll.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

/*******************************************************************************
* NOTICE
* The hal is not public api, don't use it in application code.
******************************************************************************/

#pragma once

#include <stdbool.h>
#include <stdint.h>
#include "soc/lpperi_struct.h"
#include "soc/pmu_struct.h"
#include "soc/lp_aon_struct.h"

#ifdef __cplusplus
extern "C" {
#endif


#define LP_CORE_LL_WAKEUP_SOURCE_HP_CPU BIT(0) // Started by HP core (1 single wakeup)
#define LP_CORE_LL_WAKEUP_SOURCE_LP_UART BIT(1) // Enable wake-up by a certain number of LP UART RX pulses
#define LP_CORE_LL_WAKEUP_SOURCE_LP_IO BIT(2) // Enable wake-up by LP IO interrupt
#define LP_CORE_LL_WAKEUP_SOURCE_ETM BIT(3) // Enable wake-up by ETM event
#define LP_CORE_LL_WAKEUP_SOURCE_LP_TIMER BIT(4) // Enable wake-up by LP timer

/**
* @brief Enable the bus clock for LP-core
*
* @param enable Enable if true, disable if false
*/
static inline void lp_core_ll_enable_bus_clock(bool enable)
{
/* ESP32C6 does not have clk/rst periph control for LP-core */
(void)enable;
}

/**
* @brief Reset the lp_core module
*
*/
static inline void lp_core_ll_reset_register(void)
{
/* ESP32C6 does not have clk/rst periph control for LP-core */
}

/**
* @brief Enable fast access of LP memory
*
* @note When fast access is activated, LP-core cannot access LP mem during deep sleep
*
* @param enable Enable if true, disable if false
*/
static inline void lp_core_ll_fast_lp_mem_enable(bool enable)
{
LP_AON.lpbus.fast_mem_mux_sel = enable;
LP_AON.lpbus.fast_mem_mux_sel_update = 1;
}

/**
* @brief Trigger a LP_CORE_LL_WAKEUP_SOURCE_HP_CPU wake-up on the LP-core
*
*/
static inline void lp_core_ll_hp_wake_lp(void)
{
PMU.hp_lp_cpu_comm.hp_trigger_lp = 1;
}

/**
* @brief Enable the debug module of LP-core, allowing JTAG to connect
*
* @param enable Enable if true, disable if false
*/
static inline void lp_core_ll_debug_module_enable(bool enable)
{
LPPERI.cpu.lpcore_dbgm_unavaliable = !enable;
}

/**
* @brief Enable CPU reset at sleep
*
* @param enable Enable if true, disable if false
*/
static inline void lp_core_ll_rst_at_sleep_enable(bool enable)
{
PMU.lp_ext.pwr0.slp_reset_en = enable;
}

/**
* @brief Stall LP-core at sleep requests
*
* @param enable Enable if true, disable if false
*/
static inline void lp_core_ll_stall_at_sleep_request(bool enable)
{
PMU.lp_ext.pwr0.slp_stall_en = enable;
}

/**
* @brief Set wake-up sources for the LP-core
*
* @param flags Wake-up sources
*/
static inline void lp_core_ll_set_wakeup_source(uint32_t flags)
{
PMU.lp_ext.pwr1.wakeup_en = flags;
}

/**
* @brief Get wake-up sources for the LP-core
*/
static inline uint32_t lp_core_ll_get_wakeup_source(void)
{
return PMU.lp_ext.pwr1.wakeup_en;
}

/**
* @brief Request PMU to put LP core to sleep
*/
static inline void lp_core_ll_request_sleep(void)
{
PMU.lp_ext.pwr1.sleep_req = 1;
}

/**
* @brief Get which interrupts have triggered on the LP core
*
* @return uint8_t bit mask of triggered LP interrupt sources
*/
static inline uint8_t lp_core_ll_get_triggered_interrupt_srcs(void)
{
return LPPERI.interrupt_source.lp_interrupt_source;
}

/**
* @brief Get the flag that marks whether LP CPU is awakened by ETM
*
* @return Return true if lpcore is woken up by soc_etm
*/
static inline bool lp_core_ll_get_etm_wakeup_flag(void)
{
return LP_AON.lpcore.lpcore_etm_wakeup_flag;
}

/**
* @brief Clear the flag that marks whether LP CPU is awakened by soc_etm
*/
static inline void lp_core_ll_clear_etm_wakeup_flag(void)
{
LP_AON.lpcore.lpcore_etm_wakeup_flag_clr = 0x01;
}

#ifdef __cplusplus
}
#endif
10 changes: 10 additions & 0 deletions components/hal/esp32c6/include/hal/pmu_ll.h
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,16 @@ FORCE_INLINE_ATTR void pmu_ll_lp_clear_intsts_mask(pmu_dev_t *hw, uint32_t mask)
hw->lp_ext.int_clr.val = mask;
}

FORCE_INLINE_ATTR void pmu_ll_lp_clear_sw_intr_status(pmu_dev_t *hw)
{
hw->lp_ext.int_clr.sw_trigger = 1;
}

FORCE_INLINE_ATTR void pmu_ll_lp_enable_sw_intr(pmu_dev_t *hw, bool enable)
{
hw->lp_ext.int_ena.sw_trigger = enable;
}

FORCE_INLINE_ATTR void pmu_ll_lp_set_min_sleep_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl3, lp_min_slp_val, slow_clk_cycle);
Expand Down
Loading