From 211c3c0e054224be81788695479f967935ad9aa2 Mon Sep 17 00:00:00 2001 From: Armando Date: Mon, 17 Jul 2023 17:10:52 +0800 Subject: [PATCH 01/13] feat(esp_timer): added esp_timer p4 base support --- components/esp_timer/src/esp_timer.c | 2 ++ components/esp_timer/src/esp_timer_impl_systimer.c | 7 +++++++ components/esp_timer/src/ets_timer_legacy.c | 2 ++ components/esp_timer/src/system_time.c | 2 ++ 4 files changed, 13 insertions(+) diff --git a/components/esp_timer/src/esp_timer.c b/components/esp_timer/src/esp_timer.c index 180de74c57..5fffae5770 100644 --- a/components/esp_timer/src/esp_timer.c +++ b/components/esp_timer/src/esp_timer.c @@ -37,6 +37,8 @@ #include "esp32c6/rtc.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32P4 +#include "esp32p4/rtc.h" #endif #include "sdkconfig.h" diff --git a/components/esp_timer/src/esp_timer_impl_systimer.c b/components/esp_timer/src/esp_timer_impl_systimer.c index 7471b2b3b8..ea79ebcfb8 100644 --- a/components/esp_timer/src/esp_timer_impl_systimer.c +++ b/components/esp_timer/src/esp_timer_impl_systimer.c @@ -192,9 +192,16 @@ esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler) #endif | ESP_INTR_FLAG_IRAM; +#if !CONFIG_IDF_TARGET_ESP32P4 +//TODO: IDF-7486 esp_err_t err = esp_intr_alloc(ETS_SYSTIMER_TARGET2_EDGE_INTR_SOURCE, isr_flags, &timer_alarm_isr, NULL, &s_timer_interrupt_handle[(ISR_HANDLERS == 1) ? 0 : xPortGetCoreID()]); +#else + esp_err_t err = esp_intr_alloc(ETS_SYSTIMER_TARGET2_INTR_SOURCE, isr_flags, + &timer_alarm_isr, NULL, + &s_timer_interrupt_handle[(ISR_HANDLERS == 1) ? 0 : xPortGetCoreID()]); +#endif if (err != ESP_OK) { ESP_EARLY_LOGE(TAG, "esp_intr_alloc failed (0x%x)", err); return err; diff --git a/components/esp_timer/src/ets_timer_legacy.c b/components/esp_timer/src/ets_timer_legacy.c index 5ba2868e1d..dc80901a43 100644 --- a/components/esp_timer/src/ets_timer_legacy.c +++ b/components/esp_timer/src/ets_timer_legacy.c @@ -36,6 +36,8 @@ #include "esp32c6/rom/ets_sys.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rom/ets_sys.h" +#elif CONFIG_IDF_TARGET_ESP32P4 +#include "esp32p4/rom/ets_sys.h" #endif /* We abuse 'timer_arg' field of ETSTimer structure to hold a pointer to esp_timer */ diff --git a/components/esp_timer/src/system_time.c b/components/esp_timer/src/system_time.c index e7844a2ccd..253ea56c76 100644 --- a/components/esp_timer/src/system_time.c +++ b/components/esp_timer/src/system_time.c @@ -31,6 +31,8 @@ #include "esp32c6/rtc.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32P4 +#include "esp32p4/rtc.h" #endif __attribute__((unused)) static const char* TAG = "system_time"; From bc182ef010b09f72b85d428859e1e071eb3bad1b Mon Sep 17 00:00:00 2001 From: Armando Date: Fri, 21 Jul 2023 11:51:38 +0800 Subject: [PATCH 02/13] feat(brc_predictor): p4 base support for branch predictor --- components/esp_hw_support/include/esp_cpu.h | 12 +++++++++++- components/esp_system/port/cpu_start.c | 9 ++++++++- components/riscv/include/riscv/rv_utils.h | 13 ++++++++++++- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/components/esp_hw_support/include/esp_cpu.h b/components/esp_hw_support/include/esp_cpu.h index 1d62ebcad6..2f81e3f293 100644 --- a/components/esp_hw_support/include/esp_cpu.h +++ b/components/esp_hw_support/include/esp_cpu.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -550,6 +550,16 @@ FORCE_INLINE_ATTR intptr_t esp_cpu_get_call_addr(intptr_t return_address) */ bool esp_cpu_compare_and_set(volatile uint32_t *addr, uint32_t compare_value, uint32_t new_value); +#if SOC_BRANCH_PREDICTOR_SUPPORTED +/** + * @brief Enable branch prediction + */ +FORCE_INLINE_ATTR void esp_cpu_branch_prediction_enable(void) +{ + rv_utils_en_branch_predictor(); +} +#endif //#if SOC_BRANCH_PREDICTOR_SUPPORTED + #ifdef __cplusplus } #endif diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 5b0503808e..a9579cd88c 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -152,6 +152,10 @@ void startup_resume_other_cores(void) void IRAM_ATTR call_start_cpu1(void) { +#if SOC_BRANCH_PREDICTOR_SUPPORTED + esp_cpu_branch_prediction_enable(); +#endif //#if SOC_BRANCH_PREDICTOR_SUPPORTED + esp_cpu_intr_set_ivt_addr(&_vector_table); ets_set_appcpu_boot_addr(0); @@ -317,6 +321,9 @@ void IRAM_ATTR call_start_cpu0(void) ); #endif +#if SOC_BRANCH_PREDICTOR_SUPPORTED + esp_cpu_branch_prediction_enable(); +#endif // Move exception vectors to IRAM esp_cpu_intr_set_ivt_addr(&_vector_table); diff --git a/components/riscv/include/riscv/rv_utils.h b/components/riscv/include/riscv/rv_utils.h index 2b0a9a95a1..609c271fc7 100644 --- a/components/riscv/include/riscv/rv_utils.h +++ b/components/riscv/include/riscv/rv_utils.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -229,6 +229,17 @@ FORCE_INLINE_ATTR bool rv_utils_compare_and_set(volatile uint32_t *addr, uint32_ return (old_value == compare_value); } +#if SOC_BRANCH_PREDICTOR_SUPPORTED +FORCE_INLINE_ATTR void rv_utils_en_branch_predictor(void) +{ +#define MHCR 0x7c1 +#define MHCR_RS (1<<4) /* R/W, address return stack set bit */ +#define MHCR_BFE (1<<5) /* R/W, allow predictive jump set bit */ +#define MHCR_BTB (1<<12) /* R/W, branch target prediction enable bit */ + RV_SET_CSR(MHCR, MHCR_RS|MHCR_BFE|MHCR_BTB); +} +#endif + #ifdef __cplusplus } #endif From c76de79f4c7b5cbf40d4af0effc9b34d700efb97 Mon Sep 17 00:00:00 2001 From: Armando Date: Wed, 19 Jul 2023 16:02:33 +0800 Subject: [PATCH 03/13] feat(cpu): added cpu utils base support on p4 --- components/esp_hw_support/cpu.c | 30 ++++++++++++++++++++--- components/riscv/include/riscv/rv_utils.h | 10 ++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/components/esp_hw_support/cpu.c b/components/esp_hw_support/cpu.c index c3b7dd4121..642c13e21d 100644 --- a/components/esp_hw_support/cpu.c +++ b/components/esp_hw_support/cpu.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,6 +16,9 @@ #include "soc/pcr_reg.h" #define SYSTEM_CPU_PER_CONF_REG PCR_CPU_WAITI_CONF_REG #define SYSTEM_CPU_WAIT_MODE_FORCE_ON PCR_CPU_WAIT_MODE_FORCE_ON +#elif CONFIG_IDF_TARGET_ESP32P4 +#include "soc/lp_clkrst_reg.h" +#include "soc/pmu_reg.h" #else #include "soc/rtc_cntl_reg.h" #endif @@ -45,6 +48,10 @@ void esp_cpu_stall(int core_id) { assert(core_id >= 0 && core_id < SOC_CPU_CORES_NUM); #if SOC_CPU_CORES_NUM > 1 // We don't allow stalling of the current core +#if CONFIG_IDF_TARGET_ESP32P4 + //TODO: IDF-7848 + REG_SET_FIELD(PMU_CPU_SW_STALL_REG, core_id ? PMU_HPCORE1_SW_STALL_CODE : PMU_HPCORE0_SW_STALL_CODE, 0x86); +#else /* We need to write the value "0x86" to stall a particular core. The write location is split into two separate bit fields named "c0" and "c1", and the two fields are located in different registers. Each core has its own pair of @@ -62,13 +69,18 @@ void esp_cpu_stall(int core_id) SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, 2 << rtc_cntl_c0_s); CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, rtc_cntl_c1_m); SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 0x21 << rtc_cntl_c1_s); -#endif +#endif // CONFIG_IDF_TARGET_ESP32P4 +#endif // SOC_CPU_CORES_NUM > 1 } void esp_cpu_unstall(int core_id) { assert(core_id >= 0 && core_id < SOC_CPU_CORES_NUM); #if SOC_CPU_CORES_NUM > 1 // We don't allow stalling of the current core +#if CONFIG_IDF_TARGET_ESP32P4 + //TODO: IDF-7848 + REG_SET_FIELD(PMU_CPU_SW_STALL_REG, core_id ? PMU_HPCORE1_SW_STALL_CODE : PMU_HPCORE0_SW_STALL_CODE, 0); +#else /* We need to write clear the value "0x86" to unstall a particular core. The location of this value is split into two separate bit fields named "c0" and "c1", and the two fields are located in different registers. Each core has @@ -82,11 +94,19 @@ void esp_cpu_unstall(int core_id) int rtc_cntl_c1_m = (core_id == 0) ? RTC_CNTL_SW_STALL_PROCPU_C1_M : RTC_CNTL_SW_STALL_APPCPU_C1_M; CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, rtc_cntl_c0_m); CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, rtc_cntl_c1_m); -#endif +#endif // CONFIG_IDF_TARGET_ESP32P4 +#endif // SOC_CPU_CORES_NUM > 1 } void esp_cpu_reset(int core_id) { +#if CONFIG_IDF_TARGET_ESP32P4 + //TODO: IDF-7848 + if (core_id == 0) + REG_SET_BIT(LP_CLKRST_HPCPU_RESET_CTRL0_REG, LP_CLKRST_HPCORE0_SW_RESET); + else + REG_SET_BIT(LP_CLKRST_HPCPU_RESET_CTRL0_REG, LP_CLKRST_HPCORE1_SW_RESET); +#else #if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2// TODO: IDF-5645 SET_PERI_REG_MASK(LP_AON_CPUCORE0_CFG_REG, LP_AON_CPU_CORE0_SW_RESET); #else @@ -103,6 +123,7 @@ void esp_cpu_reset(int core_id) #endif // SOC_CPU_CORES_NUM > 1 SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, rtc_cntl_rst_m); #endif +#endif // CONFIG_IDF_TARGET_ESP32P4 } void esp_cpu_wait_for_intr(void) @@ -110,12 +131,15 @@ void esp_cpu_wait_for_intr(void) #if __XTENSA__ xt_utils_wait_for_intr(); #else +//TODO: IDF-7848 +#if !CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-5645 (better to implement with ll) C6 register names converted in the #include section at the top if (esp_cpu_dbgr_is_attached() && DPORT_REG_GET_BIT(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPU_WAIT_MODE_FORCE_ON) == 0) { /* when SYSTEM_CPU_WAIT_MODE_FORCE_ON is disabled in WFI mode SBA access to memory does not work for debugger, so do not enter that mode when debugger is connected */ return; } +#endif rv_utils_wait_for_intr(); #endif // __XTENSA__ } diff --git a/components/riscv/include/riscv/rv_utils.h b/components/riscv/include/riscv/rv_utils.h index 609c271fc7..524f71f173 100644 --- a/components/riscv/include/riscv/rv_utils.h +++ b/components/riscv/include/riscv/rv_utils.h @@ -57,12 +57,22 @@ FORCE_INLINE_ATTR void *rv_utils_get_sp(void) FORCE_INLINE_ATTR uint32_t __attribute__((always_inline)) rv_utils_get_cycle_count(void) { +#if SOC_INT_CLIC_SUPPORTED + //TODO: IDF-7848 + return RV_READ_CSR(mcycle); +#else return RV_READ_CSR(CSR_PCCR_MACHINE); +#endif } FORCE_INLINE_ATTR void __attribute__((always_inline)) rv_utils_set_cycle_count(uint32_t ccount) { +#if SOC_INT_CLIC_SUPPORTED + //TODO: IDF-7848 + RV_WRITE_CSR(mcycle, ccount); +#else RV_WRITE_CSR(CSR_PCCR_MACHINE, ccount); +#endif } /* ------------------------------------------------- CPU Interrupts ---------------------------------------------------- From 019e68bb1581d19450202f4c3656c2ed10db3c0a Mon Sep 17 00:00:00 2001 From: Armando Date: Wed, 19 Jul 2023 16:06:02 +0800 Subject: [PATCH 04/13] feat(interrupt): added clic support on p4 --- components/esp_hw_support/cpu.c | 4 ++ components/riscv/include/riscv/rv_utils.h | 38 +++++++++++ components/riscv/interrupt.c | 80 ++++++++++++++++++++++- 3 files changed, 121 insertions(+), 1 deletion(-) diff --git a/components/esp_hw_support/cpu.c b/components/esp_hw_support/cpu.c index 642c13e21d..1e629c25f9 100644 --- a/components/esp_hw_support/cpu.c +++ b/components/esp_hw_support/cpu.c @@ -167,6 +167,10 @@ static bool is_intr_num_resv(int intr_num) reserved |= BIT(0) | BIT(3) | BIT(4) | BIT(7); #endif +#if SOC_INT_CLIC_SUPPORTED + //TODO: IDF-7795 + return false; +#endif if (reserved & BIT(intr_num)) { return true; } diff --git a/components/riscv/include/riscv/rv_utils.h b/components/riscv/include/riscv/rv_utils.h index 524f71f173..125f6caef5 100644 --- a/components/riscv/include/riscv/rv_utils.h +++ b/components/riscv/include/riscv/rv_utils.h @@ -107,14 +107,52 @@ FORCE_INLINE_ATTR void rv_utils_intr_disable(uint32_t intr_mask) RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE); } +//TODO: IDF-7795, clic related +#if (SOC_CPU_CORES_NUM > 1) +FORCE_INLINE_ATTR void __attribute__((always_inline)) rv_utils_restore_intlevel(uint32_t restoreval) +{ + REG_SET_FIELD(CLIC_INT_THRESH_REG, CLIC_CPU_INT_THRESH, ((restoreval << (8 - NLBITS))) | 0x1f); +} + +FORCE_INLINE_ATTR uint32_t __attribute__((always_inline)) rv_utils_set_intlevel(uint32_t intlevel) +{ + uint32_t old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE); + uint32_t old_thresh; + + old_thresh = REG_READ(CLIC_INT_THRESH_REG); + old_thresh = old_thresh >> (24 + (8 - NLBITS)); + + REG_SET_FIELD(CLIC_INT_THRESH_REG, CLIC_CPU_INT_THRESH, ((intlevel << (8 - NLBITS))) | 0x1f); + RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE); + + return old_thresh; +} +#endif //#if (SOC_CPU_CORES_NUM > 1) + FORCE_INLINE_ATTR uint32_t rv_utils_intr_get_enabled_mask(void) { +//TODO: IDF-7795 +#if SOC_INT_CLIC_SUPPORTED + unsigned intr_ena_mask = 0; + unsigned intr_num; + for (intr_num = 0; intr_num < 32; intr_num++) { + if (REG_GET_BIT(CLIC_INT_CTRL_REG(intr_num + CLIC_EXT_INTR_NUM_OFFSET), CLIC_INT_IE)) + intr_ena_mask |= BIT(intr_num); + } + return intr_ena_mask; +#else return REG_READ(INTERRUPT_CORE0_CPU_INT_ENABLE_REG); +#endif } FORCE_INLINE_ATTR void rv_utils_intr_edge_ack(unsigned int intr_num) { +//TODO: IDF-7795 +#if SOC_INT_CLIC_SUPPORTED + REG_SET_BIT(CLIC_INT_CTRL_REG(intr_num + CLIC_EXT_INTR_NUM_OFFSET) , CLIC_INT_IP); +#else REG_SET_BIT(INTERRUPT_CORE0_CPU_INT_CLEAR_REG, intr_num); +#endif } FORCE_INLINE_ATTR void rv_utils_intr_global_enable(void) diff --git a/components/riscv/interrupt.c b/components/riscv/interrupt.c index 5984d0d374..cf754dcbab 100644 --- a/components/riscv/interrupt.c +++ b/components/riscv/interrupt.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,12 +11,21 @@ #include "soc/interrupt_reg.h" #include "riscv/csr.h" #include "esp_attr.h" +#include "riscv/rv_utils.h" + + +//TODO: IDF-7795, P4, see jira to know what changed and what need to be checked + #define RV_INT_COUNT 32 static inline void assert_valid_rv_int_num(int rv_int_num) { +#if SOC_INT_CLIC_SUPPORTED + assert(rv_int_num < RV_INT_COUNT && "Invalid CPU interrupt number"); +#else assert(rv_int_num != 0 && rv_int_num < RV_INT_COUNT && "Invalid CPU interrupt number"); +#endif } /*************************** Software interrupt dispatcher ***************************/ @@ -27,63 +36,132 @@ typedef struct { void *arg; } intr_handler_item_t; +#if SOC_INT_CLIC_SUPPORTED +static intr_handler_item_t s_intr_handlers_core0[48]; +static intr_handler_item_t s_intr_handlers_core1[48]; +#else static intr_handler_item_t s_intr_handlers[32]; +#endif void intr_handler_set(int int_no, intr_handler_t fn, void *arg) { assert_valid_rv_int_num(int_no); +#if SOC_INT_CLIC_SUPPORTED + if (rv_utils_get_core_id() == 0) { + s_intr_handlers_core0[int_no + CLIC_EXT_INTR_NUM_OFFSET] = (intr_handler_item_t) { + .handler = fn, + .arg = arg, + }; + } else { + s_intr_handlers_core1[int_no + CLIC_EXT_INTR_NUM_OFFSET] = (intr_handler_item_t) { + .handler = fn, + .arg = arg, + }; + } +#else s_intr_handlers[int_no] = (intr_handler_item_t) { .handler = fn, .arg = arg }; +#endif } intr_handler_t intr_handler_get(int rv_int_num) { +#if SOC_INT_CLIC_SUPPORTED + if (rv_utils_get_core_id() == 0) + return s_intr_handlers_core0[rv_int_num + CLIC_EXT_INTR_NUM_OFFSET].handler; + else + return s_intr_handlers_core1[rv_int_num + CLIC_EXT_INTR_NUM_OFFSET].handler; +#else return s_intr_handlers[rv_int_num].handler; +#endif } void *intr_handler_get_arg(int rv_int_num) { +#if SOC_INT_CLIC_SUPPORTED + if (rv_utils_get_core_id() == 0) + return s_intr_handlers_core0[rv_int_num + CLIC_EXT_INTR_NUM_OFFSET].arg; + else + return s_intr_handlers_core1[rv_int_num + CLIC_EXT_INTR_NUM_OFFSET].arg; +#else return s_intr_handlers[rv_int_num].arg; +#endif } /* called from vectors.S */ void _global_interrupt_handler(intptr_t sp, int mcause) { +#if SOC_INT_CLIC_SUPPORTED + if (rv_utils_get_core_id() == 0) { + intr_handler_item_t it = s_intr_handlers_core0[mcause]; + if (it.handler) { + (*it.handler)(it.arg); + } + } else { + intr_handler_item_t it = s_intr_handlers_core1[mcause]; + if (it.handler) { + (*it.handler)(it.arg); + } + } +#else intr_handler_item_t it = s_intr_handlers[mcause]; if (it.handler) { (*it.handler)(it.arg); } +#endif } /*************************** RISC-V interrupt enable/disable ***************************/ void intr_matrix_route(int intr_src, int intr_num) { +#if !SOC_INT_CLIC_SUPPORTED assert(intr_num != 0); REG_WRITE(DR_REG_INTERRUPT_BASE + 4 * intr_src, intr_num); +#else + if (rv_utils_get_core_id() == 0) + REG_WRITE(DR_REG_INTERRUPT_CORE0_BASE + 4 * intr_src, intr_num + CLIC_EXT_INTR_NUM_OFFSET); + else + REG_WRITE(DR_REG_INTERRUPT_CORE1_BASE + 4 * intr_src, intr_num + CLIC_EXT_INTR_NUM_OFFSET); +#endif } +// CLIC for each interrupt line provides a IE register +// this api is not used +#if !SOC_INT_CLIC_SUPPORTED uint32_t esprv_intc_get_interrupt_unmask(void) { return REG_READ(INTERRUPT_CORE0_CPU_INT_ENABLE_REG); } +#endif /*************************** ESP-RV Interrupt Controller ***************************/ enum intr_type esprv_intc_int_get_type(int intr_num) { +#if SOC_INT_CLIC_SUPPORTED + uint32_t intr_type_reg = REG_GET_FIELD(CLIC_INT_CTRL_REG(intr_num + CLIC_EXT_INTR_NUM_OFFSET), CLIC_INT_ATTR_TRIG); + return (intr_type_reg & 1) ? INTR_TYPE_EDGE : INTR_TYPE_LEVEL; + // May also support rising edge and falling edge. +#else uint32_t intr_type_reg = REG_READ(INTERRUPT_CORE0_CPU_INT_TYPE_REG); return (intr_type_reg & (1 << intr_num)) ? INTR_TYPE_EDGE : INTR_TYPE_LEVEL; +#endif } int esprv_intc_int_get_priority(int rv_int_num) { +#if SOC_INT_CLIC_SUPPORTED + uint32_t intr_priority_reg = REG_GET_FIELD(CLIC_INT_CTRL_REG(rv_int_num + CLIC_EXT_INTR_NUM_OFFSET), CLIC_INT_CTL); + return (intr_priority_reg >> (8 - NLBITS)); +#else uint32_t intr_priority_reg = REG_READ(INTC_INT_PRIO_REG(rv_int_num)); return intr_priority_reg; +#endif } /*************************** Exception names. Used in .gdbinit file. ***************************/ From c156e56684c3597c711b3c68cfba0d3951645191 Mon Sep 17 00:00:00 2001 From: Armando Date: Fri, 21 Jul 2023 11:36:28 +0800 Subject: [PATCH 05/13] feat(spinlock): added spinlock base support on p4 --- components/esp_hw_support/cpu.c | 25 +++++++++++++- components/esp_hw_support/include/spinlock.h | 34 ++++++++++++++++++-- components/riscv/include/riscv/rv_utils.h | 3 ++ 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/components/esp_hw_support/cpu.c b/components/esp_hw_support/cpu.c index 1e629c25f9..80ed61b5d5 100644 --- a/components/esp_hw_support/cpu.c +++ b/components/esp_hw_support/cpu.c @@ -466,8 +466,31 @@ exit: ret = xt_utils_compare_and_set(addr, compare_value, new_value); } return ret; -#else // __XTENSA__ + +//TODO: IDF-7771 +#else // __riscv +#if SOC_CPU_CORES_NUM > 1 + /* We use lr.w and sc.w pair for riscv TAS. lr.w will read the memory and register a cpu lock signal + * The state of the lock signal is internal to core, and it is not possible for another core to + * interface. sc.w will assert the address is registered. Then write memory and release the lock + * signal. During the lr.w and sc.w time, if other core acquires the same address, will wait + */ + volatile uint32_t old_value = 0xB33FFFFF; + volatile int error = 1; + + __asm__ __volatile__( + "0: lr.w %0, 0(%2) \n" + " bne %0, %3, 1f \n" + " sc.w %1, %4, 0(%2) \n" + " bnez %1, 0b \n" + "1: \n" + : "+r" (old_value), "+r" (error) + : "r" (addr), "r" (compare_value), "r" (new_value) + ); + return (old_value == compare_value); +#else // Single core targets don't have atomic CAS instruction. So access method is the same for internal and external RAM return rv_utils_compare_and_set(addr, compare_value, new_value); #endif +#endif } diff --git a/components/esp_hw_support/include/spinlock.h b/components/esp_hw_support/include/spinlock.h index ac5cb1ad52..3a5a3dcc4c 100644 --- a/components/esp_hw_support/include/spinlock.h +++ b/components/esp_hw_support/include/spinlock.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,8 +13,13 @@ #if __XTENSA__ #include "xtensa/xtruntime.h" #include "xt_utils.h" +#else +#include "riscv/rv_utils.h" #endif + +//TODO: IDF-7771, P4, see jira to know what changed and what need to be checked + #ifdef __cplusplus extern "C" { #endif @@ -72,11 +77,18 @@ static inline bool __attribute__((always_inline)) spinlock_acquire(spinlock_t *l esp_cpu_cycle_count_t start_count; assert(lock); +#if __XTENSA__ irq_status = XTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL); // Note: The core IDs are the full 32 bit (CORE_ID_REGVAL_PRO/CORE_ID_REGVAL_APP) values core_id = xt_utils_get_raw_core_id(); other_core_id = CORE_ID_REGVAL_XOR_SWAP ^ core_id; +#else //__riscv + irq_status = rv_utils_set_intlevel(RVHAL_EXCM_LEVEL); + + core_id = rv_utils_get_core_id(); + other_core_id = 1 - core_id; +#endif /* lock->owner should be one of SPINLOCK_FREE, CORE_ID_REGVAL_PRO, * CORE_ID_REGVAL_APP: @@ -89,7 +101,11 @@ static inline bool __attribute__((always_inline)) spinlock_acquire(spinlock_t *l if (lock->owner == core_id) { assert(lock->count > 0 && lock->count < 0xFF); // Bad count value implies memory corruption lock->count++; +#if __XTENSA__ XTOS_RESTORE_INTLEVEL(irq_status); +#else + rv_utils_restore_intlevel(irq_status); +#endif return true; } @@ -126,7 +142,11 @@ exit: assert(lock->count < 0xFF); // Bad count value implies memory corruption } +#if __XTENSA__ XTOS_RESTORE_INTLEVEL(irq_status); +#else + rv_utils_restore_intlevel(irq_status); +#endif return lock_set; #else // !CONFIG_FREERTOS_UNICORE @@ -154,9 +174,15 @@ static inline void __attribute__((always_inline)) spinlock_release(spinlock_t *l uint32_t core_id; assert(lock); +#if __XTENSA__ irq_status = XTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL); core_id = xt_utils_get_raw_core_id(); +#else + irq_status = rv_utils_set_intlevel(RVHAL_EXCM_LEVEL); + + core_id = rv_utils_get_core_id(); +#endif assert(core_id == lock->owner); // This is a lock that we didn't acquire, or the lock is corrupt lock->count--; @@ -166,8 +192,12 @@ static inline void __attribute__((always_inline)) spinlock_release(spinlock_t *l assert(lock->count < 0x100); // Indicates memory corruption } +#if __XTENSA__ XTOS_RESTORE_INTLEVEL(irq_status); -#endif +#else + rv_utils_restore_intlevel(irq_status); +#endif //#if __XTENSA__ +#endif //#if !CONFIG_FREERTOS_UNICORE && !BOOTLOADER_BUILD } #ifdef __cplusplus diff --git a/components/riscv/include/riscv/rv_utils.h b/components/riscv/include/riscv/rv_utils.h index 125f6caef5..e1525bd764 100644 --- a/components/riscv/include/riscv/rv_utils.h +++ b/components/riscv/include/riscv/rv_utils.h @@ -24,6 +24,9 @@ extern "C" { #define CSR_PCMR_MACHINE 0x7e1 #define CSR_PCCR_MACHINE 0x7e2 +//TODO: IDF-7771 +#define RVHAL_EXCM_LEVEL 4 + /* --------------------------------------------------- CPU Control ----------------------------------------------------- * * ------------------------------------------------------------------------------------------------------------------ */ From e11b154c99145f0aad6eee8db38e026f6c6a19af Mon Sep 17 00:00:00 2001 From: Armando Date: Fri, 21 Jul 2023 11:54:29 +0800 Subject: [PATCH 06/13] feat(interrupt): mtvt, mtvec base support on p4 --- components/esp_hw_support/include/esp_cpu.h | 14 +++++ components/esp_system/port/cpu_start.c | 19 ++++++ components/riscv/include/riscv/rv_utils.h | 13 ++++ components/riscv/vectors.S | 67 ++++++++++++++++++++- 4 files changed, 111 insertions(+), 2 deletions(-) diff --git a/components/esp_hw_support/include/esp_cpu.h b/components/esp_hw_support/include/esp_cpu.h index 2f81e3f293..f64c37191f 100644 --- a/components/esp_hw_support/include/esp_cpu.h +++ b/components/esp_hw_support/include/esp_cpu.h @@ -233,6 +233,20 @@ FORCE_INLINE_ATTR void esp_cpu_intr_set_ivt_addr(const void *ivt_addr) #endif } +#if CONFIG_IDF_TARGET_ESP32P4 +//TODO: IDF-7863 +//"MTVT is only implemented in RISC-V arch" +/** + * @brief Set the base address of the current CPU's Interrupt Vector Table (MTVT) + * + * @param ivt_addr Interrupt Vector Table's base address + */ +FORCE_INLINE_ATTR void esp_cpu_intr_set_mtvt_addr(const void *mtvt_addr) +{ + rv_utils_set_mtvt((uint32_t)mtvt_addr); +} +#endif //#if CONFIG_IDF_TARGET_ESP32P4 + #if SOC_CPU_HAS_FLEXIBLE_INTC /** * @brief Set the interrupt type of a particular interrupt diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index a9579cd88c..bca7937f79 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -115,6 +115,9 @@ extern int _rodata_reserved_start; extern int _rodata_reserved_end; extern int _vector_table; +#if SOC_INT_CLIC_SUPPORTED +extern int _mtvt_table; +#endif static const char *TAG = "cpu_start"; @@ -140,7 +143,15 @@ static void core_intr_matrix_clear(void) uint32_t core_id = esp_cpu_get_core_id(); for (int i = 0; i < ETS_MAX_INTR_SOURCE; i++) { +#if CONFIG_IDF_TARGET_ESP32P4 + if (core_id == 0) { + REG_WRITE(INTERRUPT_CORE0_LP_RTC_INT_MAP_REG + 4 * i, 0); + } else { + REG_WRITE(INTERRUPT_CORE1_LP_RTC_INT_MAP_REG + 4 * i, 0); + } +#else esp_rom_route_intr_matrix(core_id, i, ETS_INVALID_INUM); +#endif } } @@ -157,6 +168,10 @@ void IRAM_ATTR call_start_cpu1(void) #endif //#if SOC_BRANCH_PREDICTOR_SUPPORTED esp_cpu_intr_set_ivt_addr(&_vector_table); +#if SOC_INT_CLIC_SUPPORTED + //TODO: IDF-7863 + esp_cpu_intr_set_mtvt_addr(&_mtvt_table); +#endif ets_set_appcpu_boot_addr(0); @@ -326,6 +341,10 @@ void IRAM_ATTR call_start_cpu0(void) #endif // Move exception vectors to IRAM esp_cpu_intr_set_ivt_addr(&_vector_table); +#if SOC_INT_CLIC_SUPPORTED + //TODO: IDF-7863 + esp_cpu_intr_set_mtvt_addr(&_mtvt_table); +#endif rst_reas[0] = esp_rom_get_reset_reason(0); #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE diff --git a/components/riscv/include/riscv/rv_utils.h b/components/riscv/include/riscv/rv_utils.h index e1525bd764..baa5b7de26 100644 --- a/components/riscv/include/riscv/rv_utils.h +++ b/components/riscv/include/riscv/rv_utils.h @@ -85,10 +85,23 @@ FORCE_INLINE_ATTR void __attribute__((always_inline)) rv_utils_set_cycle_count(u // ---------------- Interrupt Descriptors ------------------ // --------------- Interrupt Configuration ----------------- +#if SOC_INT_CLIC_SUPPORTED +//TODO: IDF-7863 +FORCE_INLINE_ATTR void rv_utils_set_mtvt(uint32_t mtvt_val) +{ +#define MTVT 0x307 + RV_WRITE_CSR(MTVT, mtvt_val); +} +#endif FORCE_INLINE_ATTR void rv_utils_set_mtvec(uint32_t mtvec_val) { +#if SOC_INT_CLIC_SUPPORTED + //TODO: IDF-7863 + mtvec_val |= 3; +#else mtvec_val |= 1; // Set MODE field to treat MTVEC as a vector base address +#endif RV_WRITE_CSR(mtvec, mtvec_val); } diff --git a/components/riscv/vectors.S b/components/riscv/vectors.S index b475910ad5..b3c59c8e98 100644 --- a/components/riscv/vectors.S +++ b/components/riscv/vectors.S @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -117,12 +117,23 @@ * only uses the 24 MSBs of the MTVEC, i.e. (MTVEC & 0xffffff00). */ + /** + * TODO: IDF-7863, P4, see jira to know what changed and what need to be checked + */ + +#if SOC_INT_CLIC_SUPPORTED + .balign 0x40 +#else .balign 0x100 +#endif .global _vector_table .type _vector_table, @function _vector_table: .option push .option norvc +#if SOC_INT_CLIC_SUPPORTED + j _trap_handler +#else j _panic_handler /* exception handler, entry 0 */ #if ETS_INT_WDT_INUM != 24 #error "ETS_INT_WDT_INUM expected to be 24" @@ -145,10 +156,41 @@ _vector_table: .rept (ETS_MAX_INUM - ETS_ASSIST_DEBUG_INUM) j _interrupt_handler /* remain entries are identical, all pointing to the interrupt handler */ .endr - +#endif .option pop .size _vector_table, .-_vector_table +#if SOC_INT_CLIC_SUPPORTED + .balign 0x40 + .global _mtvt_table + .type _mtvt_table, @function +_mtvt_table: + .option push + .option norvc + .rept 48 + .word _interrupt_handler + .endr + .option pop + .size _mtvt_table, .-_mtvt_table +#endif + +#if SOC_INT_CLIC_SUPPORTED + .type _trap_handler, @function +_trap_handler: + addi sp, sp, -RV_STK_FRMSZ + sw t0, RV_STK_T0(sp) + sw t1, RV_STK_T1(sp) + csrr t0, mcause + li t1, 0x80000000 + bltu t0, t1, _panic_handler + lw t0, RV_STK_T0(sp) + lw t1, RV_STK_T1(sp) + addi sp, sp, RV_STK_FRMSZ + //ESP32P4-TODO: ETS_T1_WDT_INUM/ETS_CACHEERR_INUM/ETS_MEMPROT_ERR_INUM + j _interrupt_handler + .size _trap_handler, .-_trap_handler +#endif + /* Exception handler.*/ .type _panic_handler, @function _panic_handler: @@ -182,6 +224,15 @@ _panic_handler: mv a0, sp csrr a1, mcause + /* + * MINHV[30]: CPU is fetching vector interrupt entry address or not + * MPP[29:28]: MSTATUS.MPP[1:0] + * MPIL[23:16]: interrupt level before entrering interrupt isr + */ +#if SOC_INT_CLIC_SUPPORTED + la t1, 0x80000fff + and a1, a1, t1 +#endif /* Branches instructions don't accept immediates values, so use t1 to * store our comparator */ li t0, 0x80000000 @@ -256,6 +307,7 @@ _interrupt_handler: csrr s1, mcause csrr s2, mstatus +#if !SOC_INT_CLIC_SUPPORTED /* Save the interrupt threshold level */ li t0, INTERRUPT_CORE0_CPU_INT_THRESH_REG lw s3, 0(t0) @@ -270,6 +322,7 @@ _interrupt_handler: addi t2, t2, 1 /* t2 = t2 +1 */ sw t2, 0(t0) /* INTERRUPT_CORE0_CPU_INT_THRESH_REG = t2 */ fence +#endif li t0, 0x8 csrrs t0, mstatus, t0 @@ -295,7 +348,11 @@ _interrupt_handler: mv a0, sp /* argument 1, stack pointer */ mv a1, s1 /* argument 2, interrupt number (mcause) */ /* mask off the interrupt flag of mcause */ +#if !SOC_INT_CLIC_SUPPORTED li t0, 0x7fffffff +#else + li t0, 0x00000fff +#endif and a1, a1, t0 jal _global_interrupt_handler @@ -305,11 +362,17 @@ _interrupt_handler: csrrc t0, mstatus, t0 /* MIE cleared. Nested interrupts are disabled */ +#if !SOC_INT_CLIC_SUPPORTED /* restore the interrupt threshold level */ li t0, INTERRUPT_CORE0_CPU_INT_THRESH_REG sw s3, 0(t0) fence +#endif +#if SOC_INT_CLIC_SUPPORTED + /* Yield to the next task is needed: */ + mv a0, sp +#endif call rtos_int_exit /* restore the rest of the registers */ From 48ee1ba36e6f04a1abc7e50d27ef21fc042301a8 Mon Sep 17 00:00:00 2001 From: Armando Date: Tue, 18 Jul 2023 16:21:15 +0800 Subject: [PATCH 07/13] feat(freertos): base support on p4 --- .../riscv/include/freertos/portmacro.h | 42 ++++++- .../FreeRTOS-Kernel/portable/riscv/port.c | 118 +++++++++++++++++- .../FreeRTOS-Kernel/portable/riscv/portasm.S | 91 +++++++++++++- components/freertos/FreeRTOS-Kernel/tasks.c | 15 ++- components/freertos/Kconfig | 1 + components/freertos/app_startup.c | 11 +- components/freertos/port_systick.c | 12 +- 7 files changed, 279 insertions(+), 11 deletions(-) diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h b/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h index ba2b45b217..e273ef97b6 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: MIT * - * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2016-2023 Espressif Systems (Shanghai) CO LTD */ /* * FreeRTOS Kernel V10.4.3 @@ -160,6 +160,8 @@ BaseType_t xPortInterruptedFromISRContext(void); * @note [refactor-todo] Refactor critical section API so that this is no longer required * ------------------------------------------------------ */ +//TODO: IDF-7566 +#if !CONFIG_IDF_TARGET_ESP32P4 /** * @brief Spinlock object * Owner: @@ -178,6 +180,11 @@ typedef struct { uint32_t owner; uint32_t count; } portMUX_TYPE; + +#else +typedef spinlock_t portMUX_TYPE; /**< Spinlock type used by FreeRTOS critical sections */ +#endif + /**< Spinlock initializer */ #define portMUX_INITIALIZER_UNLOCKED { \ .owner = portMUX_FREE_VAL, \ @@ -199,7 +206,12 @@ typedef struct { * - Simply disable interrupts * - Can be nested */ +//TODO: IDF-7566 +#if !CONFIG_IDF_TARGET_ESP32P4 void vPortEnterCritical(void); +#else +void vPortEnterCritical(portMUX_TYPE *mux); +#endif /** * @brief Exit a critical section @@ -207,7 +219,12 @@ void vPortEnterCritical(void); * - Reenables interrupts * - Can be nested */ +//TODO: IDF-7566 +#if !CONFIG_IDF_TARGET_ESP32P4 void vPortExitCritical(void); +#else +void vPortExitCritical(portMUX_TYPE *mux); +#endif // ---------------------- Yielding ------------------------- @@ -320,6 +337,8 @@ FORCE_INLINE_ATTR BaseType_t xPortGetCoreID(void) // ------------------ Critical Sections -------------------- +//TODO: IDF-7566 +#if !CONFIG_IDF_TARGET_ESP32P4 #define portENTER_CRITICAL(mux) {(void)mux; vPortEnterCritical();} #define portEXIT_CRITICAL(mux) {(void)mux; vPortExitCritical();} #define portTRY_ENTER_CRITICAL(mux, timeout) ({ \ @@ -328,6 +347,17 @@ FORCE_INLINE_ATTR BaseType_t xPortGetCoreID(void) BaseType_t ret = pdPASS; \ ret; \ }) +#else +#define portENTER_CRITICAL(mux) {vPortEnterCritical(mux);} +#define portEXIT_CRITICAL(mux) {vPortExitCritical(mux);} +#define portTRY_ENTER_CRITICAL(mux, timeout) ({ \ + (void)timeout; \ + vPortEnterCritical(mux); \ + BaseType_t ret = pdPASS; \ + ret; \ +}) +#endif + //In single-core RISC-V, we can use the same critical section API #define portENTER_CRITICAL_ISR(mux) portENTER_CRITICAL(mux) #define portEXIT_CRITICAL_ISR(mux) portEXIT_CRITICAL(mux) @@ -350,6 +380,10 @@ FORCE_INLINE_ATTR BaseType_t xPortGetCoreID(void) }) #define portTRY_ENTER_CRITICAL_SAFE(mux, timeout) portENTER_CRITICAL_SAFE(mux, timeout) +//TODO: IDF-7566 +#if CONFIG_IDF_TARGET_ESP32P4 +#define portCHECK_IF_IN_ISR() xPortInIsrContext() +#endif // ---------------------- Yielding ------------------------- #define portYIELD() vPortYield() @@ -428,7 +462,13 @@ extern void vPortCleanUpTCB ( void *pxTCB ); FORCE_INLINE_ATTR bool xPortCanYield(void) { +//TODO: IDF-7566 +#if SOC_INT_CLIC_SUPPORTED + uint32_t threshold = REG_READ(INTERRUPT_CORE0_CPU_INT_THRESH_REG + 0x10000 * xPortGetCoreID()); + threshold = threshold >> (24 + (8 - NLBITS)); +#else uint32_t threshold = REG_READ(INTERRUPT_CORE0_CPU_INT_THRESH_REG); +#endif /* when enter critical code, FreeRTOS will mask threshold to RVHAL_EXCM_LEVEL * and exit critical code, will recover threshold value (1). so threshold <= 1 * means not in critical code diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c index ba2a29e8b7..9ea3244250 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: MIT * - * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2016-2023 Espressif Systems (Shanghai) CO LTD */ /* * FreeRTOS Kernel V10.4.3 @@ -56,6 +56,10 @@ #include "portmacro.h" #include "port_systick.h" #include "esp_memory_utils.h" +#if CONFIG_IDF_TARGET_ESP32P4 +//TODO: IDF-7566 +#include "soc/hp_system_reg.h" +#endif _Static_assert(portBYTE_ALIGNMENT == 16, "portBYTE_ALIGNMENT must be set to 16"); #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD @@ -74,6 +78,8 @@ _Static_assert(offsetof( StaticTask_t, pxDummy8 ) == PORT_OFFSET_PX_END_OF_STACK * * ------------------------------------------------------------------------------------------------------------------ */ +//TODO: IDF-7566 +#if !CONFIG_IDF_TARGET_ESP32P4 /** * @brief A variable is used to keep track of the critical section nesting. * @note This variable has to be stored as part of the task context and must be initialized to a non zero value @@ -88,6 +94,25 @@ BaseType_t xPortSwitchFlag = 0; __attribute__((aligned(16))) StackType_t xIsrStack[configISR_STACK_SIZE]; StackType_t *xIsrStackTop = &xIsrStack[0] + (configISR_STACK_SIZE & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK))); +#else +/* uxCriticalNesting will be increased by 1 each time one processor is entering a critical section + * and will be decreased by 1 each time one processor is exiting a critical section + */ +volatile UBaseType_t uxCriticalNesting[portNUM_PROCESSORS] = {0}; +volatile UBaseType_t uxSavedInterruptState[portNUM_PROCESSORS] = {0}; +volatile BaseType_t uxSchedulerRunning[portNUM_PROCESSORS] = {0}; +volatile UBaseType_t uxInterruptNesting[portNUM_PROCESSORS] = {0}; +volatile BaseType_t xPortSwitchFlag[portNUM_PROCESSORS] = {0}; +/* core0 interrupt stack space */ +__attribute__((aligned(16))) static StackType_t xIsrStack[configISR_STACK_SIZE]; +/* core1 interrupt stack space */ +__attribute__((aligned(16))) static StackType_t xIsrStack1[configISR_STACK_SIZE]; +/* core0 interrupt stack top, passed to sp */ +StackType_t *xIsrStackTop = &xIsrStack[0] + (configISR_STACK_SIZE & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK))); +/* core1 interrupt stack top, passed to sp */ +StackType_t *xIsrStackTop1 = &xIsrStack1[0] + (configISR_STACK_SIZE & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK))); +#endif + /* ------------------------------------------------ FreeRTOS Portable -------------------------------------------------- @@ -97,11 +122,19 @@ StackType_t *xIsrStackTop = &xIsrStack[0] + (configISR_STACK_SIZE & (~((portPOIN // ----------------- Scheduler Start/End ------------------- +//TODO: IDF-7566 BaseType_t xPortStartScheduler(void) { +#if !CONFIG_IDF_TARGET_ESP32P4 uxInterruptNesting = 0; uxCriticalNesting = 0; uxSchedulerRunning = 0; +#else + BaseType_t coreID = xPortGetCoreID(); + uxInterruptNesting[coreID] = 0; + uxCriticalNesting[coreID] = 0; + uxSchedulerRunning[coreID] = 0; +#endif /* Setup the hardware to generate the tick. */ vPortSetupTimer(); @@ -312,15 +345,26 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC // --------------------- Interrupts ------------------------ +//TODO: IDF-7566 BaseType_t xPortInIsrContext(void) { +#if !CONFIG_IDF_TARGET_ESP32P4 return uxInterruptNesting; +#else + BaseType_t coreID = xPortGetCoreID(); + return uxInterruptNesting[coreID]; +#endif } BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void) { /* For single core, this can be the same as xPortInIsrContext() because reading it is atomic */ +#if !CONFIG_IDF_TARGET_ESP32P4 return uxInterruptNesting; +#else + BaseType_t coreID = xPortGetCoreID(); + return uxInterruptNesting[coreID]; +#endif } // ---------------------- Spinlocks ------------------------ @@ -329,6 +373,8 @@ BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void) // ------------------ Critical Sections -------------------- +//TODO: IDF-7566 +#if !CONFIG_IDF_TARGET_ESP32P4 void vPortEnterCritical(void) { BaseType_t state = portSET_INTERRUPT_MASK_FROM_ISR(); @@ -349,15 +395,52 @@ void vPortExitCritical(void) } } +#else +void vPortEnterCritical(portMUX_TYPE *mux) +{ + BaseType_t coreID = xPortGetCoreID(); + BaseType_t state = portSET_INTERRUPT_MASK_FROM_ISR(); + + spinlock_acquire((spinlock_t *)mux, SPINLOCK_WAIT_FOREVER); + uxCriticalNesting[coreID]++; + + if (uxCriticalNesting[coreID] == 1) { + uxSavedInterruptState[coreID] = state; + } +} + +void vPortExitCritical(portMUX_TYPE *mux) +{ + spinlock_release((spinlock_t *)mux); + + BaseType_t coreID = xPortGetCoreID(); + if (uxCriticalNesting[coreID] > 0) { + uxCriticalNesting[coreID]--; + if (uxCriticalNesting[coreID] == 0) { + portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptState[coreID]); + } + } +} +#endif + // ---------------------- Yielding ------------------------- +//TODO: IDF-7566 int vPortSetInterruptMask(void) { int ret; unsigned old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE); ret = REG_READ(INTERRUPT_CORE0_CPU_INT_THRESH_REG); + +#if !CONFIG_IDF_TARGET_ESP32P4 REG_WRITE(INTERRUPT_CORE0_CPU_INT_THRESH_REG, RVHAL_EXCM_LEVEL); RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE); +#else + #define RVHAL_EXCM_THRESHOLD_VALUE (((RVHAL_EXCM_LEVEL << (8 - NLBITS)) | 0x1f) << CLIC_CPU_INT_THRESH_S) + + REG_WRITE(INTERRUPT_CORE0_CPU_INT_THRESH_REG, RVHAL_EXCM_THRESHOLD_VALUE); + RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE); +#endif /** * In theory, this function should not return immediately as there is a * delay between the moment we mask the interrupt threshold register and @@ -395,6 +478,8 @@ void vPortClearInterruptMask(int mask) asm volatile ( "nop" ); } +//TODO: IDF-7566 +#if !CONFIG_IDF_TARGET_ESP32P4 void vPortYield(void) { if (uxInterruptNesting) { @@ -423,6 +508,37 @@ void vPortYieldFromISR( void ) xPortSwitchFlag = 1; } +#else +void vPortYield(void) +{ + BaseType_t coreID = xPortGetCoreID(); + if (uxInterruptNesting[coreID]) { + vPortYieldFromISR(); + } else { + esp_crosscore_int_send_yield(coreID); + /* There are 3-4 instructions of latency between triggering the software + interrupt and the CPU interrupt happening. Make sure it happened before + we return, otherwise vTaskDelay() may return and execute 1-2 + instructions before the delay actually happens. + + (We could use the WFI instruction here, but there is a chance that + the interrupt will happen while evaluating the other two conditions + for an instant yield, and if that happens then the WFI would be + waiting for the next interrupt to occur...) + */ + while (uxSchedulerRunning[coreID] && uxCriticalNesting[coreID] == 0 && REG_READ(HP_SYSTEM_CPU_INT_FROM_CPU_0_REG + 4*coreID) != 0) {} + } +} + +void vPortYieldFromISR( void ) +{ + traceISR_EXIT_TO_SCHEDULER(); + BaseType_t coreID = xPortGetCoreID(); + uxSchedulerRunning[coreID] = 1; + xPortSwitchFlag[coreID] = 1; +} +#endif + void vPortYieldOtherCore(BaseType_t coreid) { esp_crosscore_int_send_yield(coreid); diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S b/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S index fc1c33042d..519c76da12 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +12,10 @@ .global uxInterruptNesting .global uxSchedulerRunning .global xIsrStackTop +#if CONFIG_IDF_TARGET_ESP32P4 +//TODO: IDF-7566 + .global xIsrStackTop1 +#endif .global pxCurrentTCB .global vTaskSwitchContext .global xPortSwitchFlag @@ -35,18 +39,40 @@ .global rtos_int_enter .type rtos_int_enter, @function rtos_int_enter: +#if CONFIG_IDF_TARGET_ESP32P4 + /* needs jira for p4 */ + /* preserve the return address */ + mv t1, ra + mv t2, a0 +#endif + +//TODO: IDF-7566 +#if !CONFIG_IDF_TARGET_ESP32P4 /* scheduler not enabled, jump directly to ISR handler */ lw t0, uxSchedulerRunning beq t0,zero, rtos_enter_end +#else + /* scheduler not enabled, jump directly to ISR handler */ + csrr t6, mhartid /* t6 = coreID */ + slli t6, t6, 2 /* t6 = coreID * 4 */ + la t0, uxSchedulerRunning /* t0 = &uxSchedulerRunning */ + add t0, t0, t6 /* t0 = &uxSchedulerRunning[coreID] */ + lw t0, (t0) /* t0 = uxSchedulerRunning[coreID] */ + beq t0,zero, rtos_enter_end +#endif /* increments the ISR nesting count */ - la t3, uxInterruptNesting - lw t4, 0x0(t3) - addi t5,t4,1 - sw t5, 0x0(t3) + la t3, uxInterruptNesting +#if CONFIG_IDF_TARGET_ESP32P4 +//TODO: IDF-7566 + add t3, t3, t6 +#endif + lw t4, 0x0(t3) + addi t5,t4,1 + sw t5, 0x0(t3) /* If reached here from another low-prio ISR, skip stack pushing to TCB */ - bne t4,zero, rtos_enter_end + bne t4,zero, rtos_enter_end #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD /* esp_hw_stack_guard_monitor_stop(); */ @@ -54,9 +80,21 @@ rtos_int_enter: #endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */ /* Save current TCB and load the ISR stack */ +//TODO: IDF-7566 +#if !CONFIG_IDF_TARGET_ESP32P4 lw t0, pxCurrentTCB sw sp, 0x0(t0) lw sp, xIsrStackTop +#else + la t0, pxCurrentTCB /* t0 = &pxCurrentTCB */ + add t0, t0, t6 /* t0 = &pxCurrentTCB[coreID] */ + lw t0, (t0) /* t0 = pxCurrentTCB[coreID] */ + sw t2, 0x0(t0) + lw sp, xIsrStackTop + csrr t6, mhartid + beq t6, zero, rtos_enter_end + lw sp, xIsrStackTop1 +#endif #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD /* esp_hw_stack_guard_set_bounds(xIsrStack, xIsrStackTop); */ @@ -67,6 +105,10 @@ rtos_int_enter: #endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */ rtos_enter_end: +#if CONFIG_IDF_TARGET_ESP32P4 + /* needs jira for p4 */ + mv ra, t1 +#endif ret /** @@ -76,11 +118,25 @@ rtos_enter_end: .type rtos_int_exit, @function rtos_int_exit: /* may skip RTOS aware interrupt since scheduler was not started */ + +//TODO: IDF-7566 +#if !CONFIG_IDF_TARGET_ESP32P4 lw t0, uxSchedulerRunning +#else + csrr t1, mhartid + slli t1, t1, 2 + la t0, uxSchedulerRunning /* t0 = &uxSchedulerRunning */ + add t0, t0, t1 /* t0 = &uxSchedulerRunning[coreID] */ + lw t0, (t0) +#endif beq t0,zero, rtos_exit_end /* update nesting interrupts counter */ la t2, uxInterruptNesting +#if CONFIG_IDF_TARGET_ESP32P4 +//TODO: IDF-7566 + add t2, t2, t1 +#endif lw t3, 0x0(t2) /* Already zero, protect against underflow */ @@ -95,6 +151,10 @@ isr_skip_decrement: /* Schedule the next task if a yield is pending */ la t0, xPortSwitchFlag +#if CONFIG_IDF_TARGET_ESP32P4 +//TODO: IDF-7566 + add t0, t0, t1 +#endif lw t2, 0x0(t0) beq t2, zero, no_switch @@ -108,11 +168,19 @@ isr_skip_decrement: /* Clears the switch pending flag */ la t0, xPortSwitchFlag +#if CONFIG_IDF_TARGET_ESP32P4 +//TODO: IDF-7566 + /* c routine vTaskSwitchContext may change the temp registers, so we read again */ + csrr t3, mhartid + slli t3, t3, 2 + add t0, t0, t3 +#endif mv t2, zero sw t2, 0x0(t0) no_switch: +#if !CONFIG_IDF_TARGET_ESP32P4 //TODO: IDF-7566 #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD /* esp_hw_stack_guard_monitor_stop(); */ ESP_HW_STACK_GUARD_MONITOR_STOP_CPU0 @@ -133,5 +201,16 @@ no_switch: ESP_HW_STACK_GUARD_MONITOR_START_CPU0 #endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */ +#else + /* Recover the stack of next task and prepare to exit : */ + la a0, pxCurrentTCB + /* We may come here from a branch, so we re-cal here */ + csrr t3, mhartid + slli t3, t3, 2 + add a0, a0, t3 /* a0 = &pxCurrentTCB[coreID] */ + lw a0, (a0) /* a0 = pxCurrentTCB[coreID] */ + lw a0, 0x0(a0) /* a0 = previous sp */ +#endif //#if !CONFIG_IDF_TARGET_ESP32P4 + rtos_exit_end: ret diff --git a/components/freertos/FreeRTOS-Kernel/tasks.c b/components/freertos/FreeRTOS-Kernel/tasks.c index 53e519a141..8131043fb2 100644 --- a/components/freertos/FreeRTOS-Kernel/tasks.c +++ b/components/freertos/FreeRTOS-Kernel/tasks.c @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: MIT * - * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2016-2023 Espressif Systems (Shanghai) CO LTD */ /* @@ -185,6 +185,8 @@ /*-----------------------------------------------------------*/ +//TODO: IDF-7566 +#if !CONFIG_IDF_TARGET_ESP32P4 #define taskSELECT_HIGHEST_PRIORITY_TASK() \ { \ UBaseType_t uxTopPriority; \ @@ -194,6 +196,17 @@ configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \ listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB[ 0 ], &( pxReadyTasksLists[ uxTopPriority ] ) ); \ } /* taskSELECT_HIGHEST_PRIORITY_TASK() */ +#else + #define taskSELECT_HIGHEST_PRIORITY_TASK() \ + { \ + UBaseType_t uxTopPriority; \ + \ + /* Find the highest priority list that contains ready tasks. */ \ + portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \ + configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \ + listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB[ xPortGetCoreID() ], &( pxReadyTasksLists[ uxTopPriority ] ) ); \ + } /* taskSELECT_HIGHEST_PRIORITY_TASK() */ +#endif /*-----------------------------------------------------------*/ diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index 5fcc598b43..fb4d79cfb8 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -30,6 +30,7 @@ menu "FreeRTOS" # Todo: Replace with CONFIG_NUM_CORES (IDF-4986) bool "Run FreeRTOS only on first core" default "y" if IDF_TARGET_ESP32S2 || IDF_TARGET_LINUX + default "y" if IDF_TARGET_ESP32P4 #TODO: IDF-7566 select ESP_SYSTEM_SINGLE_CORE_MODE help This version of FreeRTOS normally takes control of all cores of the CPU. Select this if you only want diff --git a/components/freertos/app_startup.c b/components/freertos/app_startup.c index 996848d87d..cd1731b474 100644 --- a/components/freertos/app_startup.c +++ b/components/freertos/app_startup.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -111,10 +111,19 @@ void esp_startup_start_app_other_cores(void) } // Wait for CPU0 to start FreeRTOS before progressing + //TODO: IDF-7566 +#if !CONFIG_IDF_TARGET_ESP32P4 extern volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS]; while (port_xSchedulerRunning[0] == 0) { ; } +#else + extern volatile unsigned uxSchedulerRunning[portNUM_PROCESSORS]; + while (uxSchedulerRunning[0] == 0) { + ; + } +#endif + #if CONFIG_APPTRACE_ENABLE // [refactor-todo] move to esp_system initialization diff --git a/components/freertos/port_systick.c b/components/freertos/port_systick.c index ed9bd6c37c..eedafc750b 100644 --- a/components/freertos/port_systick.c +++ b/components/freertos/port_systick.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -64,7 +64,17 @@ void vSystimerSetup(void) /* Systimer HAL layer object */ static systimer_hal_context_t systimer_hal; /* set system timer interrupt vector */ + + /** + * TODO: IDF-7487 + * ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE is renamed to ETS_SYSTIMER_TARGET0_INTR_SOURCE. + * It's said that this interrupt is never an edge type, for previous all chips. You may need to check this and unify the name. + */ +#if !CONFIG_IDF_TARGET_ESP32P4 ESP_ERROR_CHECK(esp_intr_alloc(ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE + cpuid, ESP_INTR_FLAG_IRAM | level, SysTickIsrHandler, &systimer_hal, NULL)); +#else + ESP_ERROR_CHECK(esp_intr_alloc(ETS_SYSTIMER_TARGET0_INTR_SOURCE + cpuid, ESP_INTR_FLAG_IRAM | level, SysTickIsrHandler, &systimer_hal, NULL)); +#endif if (cpuid == 0) { periph_module_enable(PERIPH_SYSTIMER_MODULE); From 5986e63c47578369dadd802c44307c9a1ee2603c Mon Sep 17 00:00:00 2001 From: Armando Date: Tue, 18 Jul 2023 14:38:41 +0800 Subject: [PATCH 08/13] change(riscv): added fence after CLIC_INT_THRESH_REG is set --- .../FreeRTOS-Kernel/portable/riscv/port.c | 10 ++++++++++ components/riscv/include/riscv/rv_utils.h | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c index 9ea3244250..6933664a95 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c @@ -439,6 +439,16 @@ int vPortSetInterruptMask(void) #define RVHAL_EXCM_THRESHOLD_VALUE (((RVHAL_EXCM_LEVEL << (8 - NLBITS)) | 0x1f) << CLIC_CPU_INT_THRESH_S) REG_WRITE(INTERRUPT_CORE0_CPU_INT_THRESH_REG, RVHAL_EXCM_THRESHOLD_VALUE); + /** + * TODO: IDF-7898 + * Here is an issue that, + * 1. Set the CLIC_INT_THRESH_REG to mask off interrupts whose level is lower than `intlevel`. + * 2. Set MSTATUS_MIE (global interrupt), then program may jump to interrupt vector. + * 3. The register value change in Step 1 may happen during Step 2. + * + * To prevent this, here a fence is used + */ + rv_utils_memory_barrier(); RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE); #endif /** diff --git a/components/riscv/include/riscv/rv_utils.h b/components/riscv/include/riscv/rv_utils.h index baa5b7de26..247ff54971 100644 --- a/components/riscv/include/riscv/rv_utils.h +++ b/components/riscv/include/riscv/rv_utils.h @@ -36,6 +36,15 @@ FORCE_INLINE_ATTR void __attribute__((always_inline)) rv_utils_wait_for_intr(voi asm volatile ("wfi\n"); } +/* ------------------------------------------------- Memory Barrier ---------------------------------------------------- + * + * ------------------------------------------------------------------------------------------------------------------ */ +//TODO: IDF-7898 +FORCE_INLINE_ATTR void rv_utils_memory_barrier(void) +{ + asm volatile("fence iorw, iorw" : : : "memory"); +} + /* -------------------------------------------------- CPU Registers ---------------------------------------------------- * * ------------------------------------------------------------------------------------------------------------------ */ @@ -139,6 +148,16 @@ FORCE_INLINE_ATTR uint32_t __attribute__((always_inline)) rv_utils_set_intlevel( old_thresh = old_thresh >> (24 + (8 - NLBITS)); REG_SET_FIELD(CLIC_INT_THRESH_REG, CLIC_CPU_INT_THRESH, ((intlevel << (8 - NLBITS))) | 0x1f); + /** + * TODO: IDF-7898 + * Here is an issue that, + * 1. Set the CLIC_INT_THRESH_REG to mask off interrupts whose level is lower than `intlevel`. + * 2. Set MSTATUS_MIE (global interrupt), then program may jump to interrupt vector. + * 3. The register value change in Step 1 may happen during Step 2. + * + * To prevent this, here a fence is used + */ + rv_utils_memory_barrier(); RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE); return old_thresh; From ecf1461f1cf784c90f6a9a3479ce7c8a97ae7dc6 Mon Sep 17 00:00:00 2001 From: Armando Date: Wed, 19 Jul 2023 16:28:03 +0800 Subject: [PATCH 09/13] feat(panic): base support on p4 --- components/esp_system/port/arch/riscv/panic_arch.c | 11 ++++++++--- components/riscv/include/esp_private/panic_reason.h | 9 +++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/components/esp_system/port/arch/riscv/panic_arch.c b/components/esp_system/port/arch/riscv/panic_arch.c index f1ddd51030..f0cd09b0f7 100644 --- a/components/esp_system/port/arch/riscv/panic_arch.c +++ b/components/esp_system/port/arch/riscv/panic_arch.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,10 +8,15 @@ #include "spi_flash_mmap.h" +#if CONFIG_IDF_TARGET_ESP32P4 +#include "soc/cache_reg.h" +#else #include "soc/extmem_reg.h" +#endif #include "esp_private/panic_internal.h" #include "esp_private/panic_reason.h" #include "riscv/rvruntime-frames.h" +#include "riscv/rv_utils.h" #include "esp_private/cache_err_int.h" #include "soc/timer_periph.h" @@ -80,7 +85,7 @@ static inline bool test_and_print_register_bits(const uint32_t status, */ static inline void print_cache_err_details(const void *frame) { -#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 // ESP32C6-TODO, ESP32H2-TODO: IDF-5657 +#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32P4 // ESP32P4-TODO, ESP32C6-TODO, ESP32H2-TODO: IDF-5657 /* Define the array that contains the status (bits) to test on the register * EXTMEM_CORE0_ACS_CACHE_INT_ST_REG. each bit is accompanied by a small * message. @@ -344,7 +349,7 @@ void panic_soc_fill_info(void *f, panic_info_t *info) void panic_arch_fill_info(void *frame, panic_info_t *info) { RvExcFrame *regs = (RvExcFrame *) frame; - info->core = 0; + info->core = rv_utils_get_core_id(); info->exception = PANIC_EXCEPTION_FAULT; static const char *reason[] = { diff --git a/components/riscv/include/esp_private/panic_reason.h b/components/riscv/include/esp_private/panic_reason.h index 5981bae0c7..1a9e1101cb 100644 --- a/components/riscv/include/esp_private/panic_reason.h +++ b/components/riscv/include/esp_private/panic_reason.h @@ -1,13 +1,18 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once -#include "soc/soc.h" /* Since riscv does not replace mcause with "pseudo_reason" as it xtensa does * PANIC_RSN_* defined with original interrupt numbers to make it work in * common code */ #define PANIC_RSN_INTWDT_CPU0 ETS_INT_WDT_INUM + +//TODO: IDF-7511 +#if SOC_CPU_CORES_NUM > 1 +#define PANIC_RSN_INTWDT_CPU1 ETS_INT_WDT_INUM +#endif +#define PANIC_RSN_CACHEERR 3 From fd096c012d78c43f818230b32801db202baf0fd0 Mon Sep 17 00:00:00 2001 From: Armando Date: Wed, 19 Jul 2023 16:26:14 +0800 Subject: [PATCH 10/13] change(vector.S): port hw stack guard change to p4 --- .../FreeRTOS-Kernel/portable/riscv/portasm.S | 4 ++-- components/riscv/vectors.S | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S b/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S index 519c76da12..d3f24f27d2 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S @@ -40,7 +40,7 @@ .type rtos_int_enter, @function rtos_int_enter: #if CONFIG_IDF_TARGET_ESP32P4 - /* needs jira for p4 */ + //TODO: IDF-7861 /* preserve the return address */ mv t1, ra mv t2, a0 @@ -106,7 +106,7 @@ rtos_int_enter: rtos_enter_end: #if CONFIG_IDF_TARGET_ESP32P4 - /* needs jira for p4 */ + //TODO: IDF-7861 mv ra, t1 #endif ret diff --git a/components/riscv/vectors.S b/components/riscv/vectors.S index b3c59c8e98..1e055433a3 100644 --- a/components/riscv/vectors.S +++ b/components/riscv/vectors.S @@ -300,6 +300,12 @@ _interrupt_handler: /* Save SP */ sw t0, RV_STK_SP(sp) +#if CONFIG_IDF_TARGET_ESP32P4 + //TODO: IDF-7861 + /* Before doing anythig preserve the stack pointer */ + /* It will be saved in current TCB, if needed */ + mv a0, sp +#endif //#if CONFIG_IDF_TARGET_ESP32P4 call rtos_int_enter /* If this is a non-nested interrupt, SP now points to the interrupt stack */ @@ -375,6 +381,12 @@ _interrupt_handler: #endif call rtos_int_exit +#if CONFIG_IDF_TARGET_ESP32P4 + //TODO: IDF-7861 + /* The next (or current) stack pointer is returned in a0 */ + mv sp, a0 +#endif //#if CONFIG_IDF_TARGET_ESP32P4 + /* restore the rest of the registers */ csrw mcause, s1 csrw mstatus, s2 From a336b94527bfee54eb23405d5e1f556350c5c316 Mon Sep 17 00:00:00 2001 From: Armando Date: Fri, 21 Jul 2023 12:36:57 +0800 Subject: [PATCH 11/13] feat(esp_system): base support on p4 --- components/esp_system/Kconfig | 4 + components/esp_system/crosscore_int.c | 17 +- components/esp_system/fpga_overrides.c | 2 + .../include/esp_private/critical_section.h | 2 +- components/esp_system/int_wdt.c | 2 +- components/esp_system/ld/esp32p4/memory.ld.in | 131 ++++++ .../esp_system/ld/esp32p4/sections.ld.in | 441 ++++++++++++++++++ components/esp_system/port/cpu_start.c | 55 +++ .../port/soc/esp32p4/CMakeLists.txt | 11 + .../esp_system/port/soc/esp32p4/Kconfig.cache | 43 ++ .../port/soc/esp32p4/cache_err_int.c | 61 +++ components/esp_system/port/soc/esp32p4/clk.c | 277 +++++++++++ .../port/soc/esp32p4/reset_reason.c | 110 +++++ .../port/soc/esp32p4/system_internal.c | 143 ++++++ components/esp_system/system_time.c | 2 + .../task_wdt/task_wdt_impl_timergroup.c | 2 +- .../soc/esp32p4/include/soc/interrupts.h | 14 +- 17 files changed, 1306 insertions(+), 11 deletions(-) create mode 100644 components/esp_system/ld/esp32p4/sections.ld.in create mode 100644 components/esp_system/port/soc/esp32p4/Kconfig.cache create mode 100644 components/esp_system/port/soc/esp32p4/cache_err_int.c create mode 100644 components/esp_system/port/soc/esp32p4/clk.c create mode 100644 components/esp_system/port/soc/esp32p4/reset_reason.c create mode 100644 components/esp_system/port/soc/esp32p4/system_internal.c diff --git a/components/esp_system/Kconfig b/components/esp_system/Kconfig index 7f9f0a2727..37ad0f4676 100644 --- a/components/esp_system/Kconfig +++ b/components/esp_system/Kconfig @@ -101,6 +101,7 @@ menu "ESP System Settings" default y if IDF_TARGET_ESP32S3 default y if IDF_TARGET_ESP32C6 default n if IDF_TARGET_ESP32H2 # IDF-5667 + default y if IDF_TARGET_ESP32P4 depends on SOC_RTC_FAST_MEM_SUPPORTED config ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP @@ -316,6 +317,7 @@ menu "ESP System Settings" default 20 if IDF_TARGET_ESP32C2 default 21 if IDF_TARGET_ESP32C3 default 16 if IDF_TARGET_ESP32C6 + default 37 if IDF_TARGET_ESP32P4 default 24 if IDF_TARGET_ESP32H2 default 43 help @@ -333,6 +335,7 @@ menu "ESP System Settings" default 19 if IDF_TARGET_ESP32C2 default 20 if IDF_TARGET_ESP32C3 default 17 if IDF_TARGET_ESP32C6 + default 38 if IDF_TARGET_ESP32P4 default 23 if IDF_TARGET_ESP32H2 default 44 help @@ -596,6 +599,7 @@ menu "IPC (Inter-Processor Call)" config ESP_IPC_ISR_ENABLE bool + default n if IDF_TARGET_ESP32P4 # TODO: IDF-7769 default y if !FREERTOS_UNICORE help The IPC ISR feature is similar to the IPC feature except that the callback function is executed in the diff --git a/components/esp_system/crosscore_int.c b/components/esp_system/crosscore_int.c index 03e0fa650f..2602c1354e 100644 --- a/components/esp_system/crosscore_int.c +++ b/components/esp_system/crosscore_int.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -24,6 +24,9 @@ #else #include "soc/system_reg.h" #endif +#if CONFIG_IDF_TARGET_ESP32P4 +#include "soc/hp_system_reg.h" +#endif #define REASON_YIELD BIT(0) #define REASON_FREQ_SWITCH BIT(1) @@ -66,6 +69,12 @@ static void IRAM_ATTR esp_crosscore_isr(void *arg) { } else { WRITE_PERI_REG(SYSTEM_CPU_INTR_FROM_CPU_1_REG, 0); } +#elif CONFIG_IDF_TARGET_ESP32P4 + if (esp_cpu_get_core_id() == 0) { + WRITE_PERI_REG(HP_SYSTEM_CPU_INT_FROM_CPU_0_REG, 0); + } else { + WRITE_PERI_REG(HP_SYSTEM_CPU_INT_FROM_CPU_1_REG, 0); + } #elif CONFIG_IDF_TARGET_ARCH_RISCV WRITE_PERI_REG(SYSTEM_CPU_INTR_FROM_CPU_0_REG, 0); #endif @@ -147,6 +156,12 @@ static void IRAM_ATTR esp_crosscore_int_send(int core_id, uint32_t reason_mask) } else { WRITE_PERI_REG(SYSTEM_CPU_INTR_FROM_CPU_1_REG, SYSTEM_CPU_INTR_FROM_CPU_1); } +#elif CONFIG_IDF_TARGET_ESP32P4 + if (core_id==0) { + WRITE_PERI_REG(HP_SYSTEM_CPU_INT_FROM_CPU_0_REG, HP_SYSTEM_CPU_INT_FROM_CPU_0); + } else { + WRITE_PERI_REG(HP_SYSTEM_CPU_INT_FROM_CPU_1_REG, HP_SYSTEM_CPU_INT_FROM_CPU_1); + } #elif CONFIG_IDF_TARGET_ARCH_RISCV WRITE_PERI_REG(SYSTEM_CPU_INTR_FROM_CPU_0_REG, SYSTEM_CPU_INTR_FROM_CPU_0); #endif diff --git a/components/esp_system/fpga_overrides.c b/components/esp_system/fpga_overrides.c index 24e5e2f909..9ef5cea90d 100644 --- a/components/esp_system/fpga_overrides.c +++ b/components/esp_system/fpga_overrides.c @@ -24,6 +24,8 @@ #include "esp_private/esp_pmu.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32P4 +#include "esp32p4/rom/rtc.h" #endif #include "esp_log.h" #include "esp_rom_sys.h" diff --git a/components/esp_system/include/esp_private/critical_section.h b/components/esp_system/include/esp_private/critical_section.h index 9d784d2a91..f22fa53fda 100644 --- a/components/esp_system/include/esp_private/critical_section.h +++ b/components/esp_system/include/esp_private/critical_section.h @@ -20,7 +20,7 @@ extern "C" { #endif -#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32S2 +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32P4 /** * This macro also helps users switching between spinlock declarations/definitions for multi-/single core environments * if the macros below aren't sufficient. diff --git a/components/esp_system/int_wdt.c b/components/esp_system/int_wdt.c index a6d4ff6afd..e079948f09 100644 --- a/components/esp_system/int_wdt.c +++ b/components/esp_system/int_wdt.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/esp_system/ld/esp32p4/memory.ld.in b/components/esp_system/ld/esp32p4/memory.ld.in index e69de29bb2..40fed30cf1 100644 --- a/components/esp_system/ld/esp32p4/memory.ld.in +++ b/components/esp_system/ld/esp32p4/memory.ld.in @@ -0,0 +1,131 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * ESP32-P4 Linker Script Memory Layout + * This file describes the memory layout (memory blocks) by virtual memory addresses. + * This linker script is passed through the C preprocessor to include configuration options. + * Please use preprocessor features sparingly! + * Restrict to simple macros with numeric values, and/or #if/#endif blocks. + */ + +#include "sdkconfig.h" +#include "ld.common" + +/** + * physical memory is mapped twice to the vritual address (IRAM and DRAM). + * `I_D_SRAM_OFFSET` is the offset between the two locations of the same physical memory + */ +#define SRAM_IRAM_START 0x4ff00000 +#define SRAM_DRAM_START 0x4ff00000 + +#define I_D_SRAM_OFFSET (SRAM_IRAM_START - SRAM_DRAM_START) +#define SRAM_DRAM_END 0x4ff30bd0 - I_D_SRAM_OFFSET /* 2nd stage bootloader iram_loader_seg start address */ + +#define SRAM_IRAM_ORG (SRAM_IRAM_START) +#define SRAM_DRAM_ORG (SRAM_DRAM_START) + +#define I_D_SRAM_SIZE SRAM_DRAM_END - SRAM_DRAM_ORG + +#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS +/** + * TODO: IDF-7890 + */ +#define IDROM_SEG_SIZE (CONFIG_MMU_PAGE_SIZE << 10) +#endif + +#define DRAM0_0_SEG_LEN I_D_SRAM_SIZE + +MEMORY +{ + /** + * All these values assume the flash cache is on, and have the blocks this uses subtracted from the length + * of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but + * are connected to the data port of the CPU and eg allow byte-wise access. + */ + /* TCM */ + tcm_idram_seg (RX) : org = 0x30100000, len = 0x2000 + + /* IRAM for PRO CPU. */ + iram0_0_seg (RX) : org = SRAM_IRAM_ORG, len = I_D_SRAM_SIZE + +#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS + /* Flash mapped instruction data */ + irom_seg (RX) : org = 0x40000020, len = IDROM_SEG_SIZE - 0x20 + + /** + * (0x20 offset above is a convenience for the app binary image generation. + * Flash cache has 64KB pages. The .bin file which is flashed to the chip + * has a 0x18 byte file header, and each segment has a 0x08 byte segment + * header. Setting this offset makes it simple to meet the flash cache MMU's + * constraint that (paddr % 64KB == vaddr % 64KB).) + */ +#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS + + /** + * Shared data RAM, excluding memory reserved for ROM bss/data/stack. + * Enabling Bluetooth & Trace Memory features in menuconfig will decrease the amount of RAM available. + */ + dram0_0_seg (RW) : org = SRAM_DRAM_ORG, len = DRAM0_0_SEG_LEN + +#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS + /* Flash mapped constant data */ + drom_seg (R) : org = 0x40000020, len = IDROM_SEG_SIZE - 0x20 + + /* (See irom_seg for meaning of 0x20 offset in the above.) */ +#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS + + /** + * lp ram memory (RWX). Persists over deep sleep. // TODO: IDF-5667 + */ +#if CONFIG_ULP_COPROC_ENABLED + lp_ram_seg(RW) : org = 0x50108000 + CONFIG_ULP_COPROC_RESERVE_MEM, + len = 0x8000 - CONFIG_ULP_COPROC_RESERVE_MEM +#else + lp_ram_seg(RW) : org = 0x50108000 , len = 0x8000 +#endif // CONFIG_ULP_COPROC_ENABLED +} + +/* Heap ends at top of dram0_0_seg */ +_heap_end = 0x50000000; + +_data_seg_org = ORIGIN(rtc_data_seg); + +/** + * The lines below define location alias for .rtc.data section + * P4 has no distinguished LP(RTC) fast and slow memory sections, instead, there is a unified LP_RAM section + * Thus, the following region segments are not configurable like on other targets + */ +REGION_ALIAS("rtc_iram_seg", lp_ram_seg ); +REGION_ALIAS("rtc_data_seg", rtc_iram_seg ); +REGION_ALIAS("rtc_slow_seg", rtc_iram_seg ); +REGION_ALIAS("rtc_data_location", rtc_iram_seg ); + +#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS + REGION_ALIAS("default_code_seg", irom_seg); +#else + REGION_ALIAS("default_code_seg", iram0_0_seg); +#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS + +#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS + REGION_ALIAS("default_rodata_seg", drom_seg); +#else + REGION_ALIAS("default_rodata_seg", dram0_0_seg); +#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS + +/** + * If rodata default segment is placed in `drom_seg`, then flash's first rodata section must + * also be first in the segment. + */ +#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS + ASSERT(_flash_rodata_dummy_start == ORIGIN(default_rodata_seg), + ".flash_rodata_dummy section must be placed at the beginning of the rodata segment.") +#endif + +#if CONFIG_ESP_SYSTEM_USE_EH_FRAME + ASSERT ((__eh_frame_end > __eh_frame), "Error: eh_frame size is null!"); + ASSERT ((__eh_frame_hdr_end > __eh_frame_hdr), "Error: eh_frame_hdr size is null!"); +#endif diff --git a/components/esp_system/ld/esp32p4/sections.ld.in b/components/esp_system/ld/esp32p4/sections.ld.in new file mode 100644 index 0000000000..50c7dfd3e4 --- /dev/null +++ b/components/esp_system/ld/esp32p4/sections.ld.in @@ -0,0 +1,441 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Default entry point */ +ENTRY(call_start_cpu0); + +SECTIONS +{ + /** + * RTC fast memory holds RTC wake stub code, + * including from any source file named rtc_wake_stub*.c + */ + .rtc.text : + { + . = ALIGN(4); + _rtc_fast_start = ABSOLUTE(.); + + mapping[rtc_text] + + *rtc_wake_stub*.*(.literal .text .literal.* .text.*) + *(.rtc_text_end_test) + + /* 16B padding for possible CPU prefetch and 4B alignment for PMS split lines */ + . += _esp_memprot_prefetch_pad_size; + . = ALIGN(4); + + _rtc_text_end = ABSOLUTE(.); + } > lp_ram_seg + + /** + * This section located in RTC FAST Memory area. + * It holds data marked with RTC_FAST_ATTR attribute. + * See the file "esp_attr.h" for more information. + */ + .rtc.force_fast : + { + . = ALIGN(4); + _rtc_force_fast_start = ABSOLUTE(.); + + mapping[rtc_force_fast] + + *(.rtc.force_fast .rtc.force_fast.*) + . = ALIGN(4) ; + _rtc_force_fast_end = ABSOLUTE(.); + } > lp_ram_seg + + /** + * RTC data section holds RTC wake stub + * data/rodata, including from any source file + * named rtc_wake_stub*.c and the data marked with + * RTC_DATA_ATTR, RTC_RODATA_ATTR attributes. + */ + .rtc.data : + { + _rtc_data_start = ABSOLUTE(.); + + mapping[rtc_data] + + *rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .srodata.*) + _rtc_data_end = ABSOLUTE(.); + } > lp_ram_seg + + /* RTC bss, from any source file named rtc_wake_stub*.c */ + .rtc.bss (NOLOAD) : + { + _rtc_bss_start = ABSOLUTE(.); + *rtc_wake_stub*.*(.bss .bss.* .sbss .sbss.*) + *rtc_wake_stub*.*(COMMON) + + mapping[rtc_bss] + + _rtc_bss_end = ABSOLUTE(.); + } > lp_ram_seg + + /** + * This section holds data that should not be initialized at power up + * and will be retained during deep sleep. + * User data marked with RTC_NOINIT_ATTR will be placed + * into this section. See the file "esp_attr.h" for more information. + */ + .rtc_noinit (NOLOAD): + { + . = ALIGN(4); + _rtc_noinit_start = ABSOLUTE(.); + *(.rtc_noinit .rtc_noinit.*) + . = ALIGN(4) ; + _rtc_noinit_end = ABSOLUTE(.); + } > lp_ram_seg + + /** + * This section located in RTC SLOW Memory area. + * It holds data marked with RTC_SLOW_ATTR attribute. + * See the file "esp_attr.h" for more information. + */ + .rtc.force_slow : + { + . = ALIGN(4); + _rtc_force_slow_start = ABSOLUTE(.); + *(.rtc.force_slow .rtc.force_slow.*) + . = ALIGN(4) ; + _rtc_force_slow_end = ABSOLUTE(.); + } > lp_ram_seg + + /* Get size of rtc slow data based on rtc_data_location alias */ + _rtc_slow_length = (ORIGIN(rtc_slow_seg) == ORIGIN(rtc_data_location)) + ? (_rtc_force_slow_end - _rtc_data_start) + : (_rtc_force_slow_end - _rtc_force_slow_start); + + _rtc_fast_length = (ORIGIN(rtc_slow_seg) == ORIGIN(rtc_data_location)) + ? (_rtc_force_fast_end - _rtc_fast_start) + : (_rtc_noinit_end - _rtc_fast_start); + + ASSERT((_rtc_slow_length <= LENGTH(rtc_slow_seg)), + "RTC_SLOW segment data does not fit.") + + ASSERT((_rtc_fast_length <= LENGTH(rtc_data_seg)), + "RTC_FAST segment data does not fit.") + + .tcm.text : + { + /* Code marked as running out of TCM */ + _tcm_text_start = ABSOLUTE(.); + + mapping[tcm_text] + + _tcm_text_end = ABSOLUTE(.); + + } > tcm_idram_seg + + .tcm.data : + { + _tcm_data_start = ABSOLUTE(.); + + mapping[tcm_data] + + _tcm_data_end = ABSOLUTE(.); + + . = ALIGN(4); + + } > tcm_idram_seg + + .iram0.text : + { + _iram_start = ABSOLUTE(.); + /* Vectors go to start of IRAM */ + ASSERT(ABSOLUTE(.) % 0x100 == 0, "vector address must be 256 byte aligned"); + KEEP(*(.exception_vectors.text)); + . = ALIGN(4); + + _invalid_pc_placeholder = ABSOLUTE(.); + + /* Code marked as running out of IRAM */ + _iram_text_start = ABSOLUTE(.); + + mapping[iram0_text] + + } > iram0_0_seg + + /* Marks the end of IRAM code segment */ + .iram0.text_end (NOLOAD) : + { + /* ESP32-C6 memprot requires 16B padding for possible CPU prefetch and 512B alignment for PMS split lines */ + . += _esp_memprot_prefetch_pad_size; + . = ALIGN(_esp_memprot_align_size); + /* iram_end_test section exists for use by memprot unit tests only */ + *(.iram_end_test) + _iram_text_end = ABSOLUTE(.); + } > iram0_0_seg + + .iram0.data : + { + . = ALIGN(16); + _iram_data_start = ABSOLUTE(.); + + mapping[iram0_data] + + _iram_data_end = ABSOLUTE(.); + } > iram0_0_seg + + .iram0.bss (NOLOAD) : + { + . = ALIGN(16); + _iram_bss_start = ABSOLUTE(.); + + mapping[iram0_bss] + + _iram_bss_end = ABSOLUTE(.); + . = ALIGN(16); + _iram_end = ABSOLUTE(.); + } > iram0_0_seg + + /** + * This section is required to skip .iram0.text area because iram0_0_seg and + * dram0_0_seg reflect the same address space on different buses. + */ + .dram0.dummy (NOLOAD): + { + . = ORIGIN(dram0_0_seg) + _iram_end - _iram_start; + } > dram0_0_seg + + .dram0.data : + { + _data_start = ABSOLUTE(.); + *(.gnu.linkonce.d.*) + *(.data1) + __global_pointer$ = . + 0x800; + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + + mapping[dram0_data] + + _data_end = ABSOLUTE(.); + . = ALIGN(4); + } > dram0_0_seg + + /** + * This section holds data that should not be initialized at power up. + * The section located in Internal SRAM memory region. The macro _NOINIT + * can be used as attribute to place data into this section. + * See the "esp_attr.h" file for more information. + */ + .noinit (NOLOAD): + { + . = ALIGN(4); + _noinit_start = ABSOLUTE(.); + *(.noinit .noinit.*) + . = ALIGN(4) ; + _noinit_end = ABSOLUTE(.); + } > dram0_0_seg + + /* Shared RAM */ + .dram0.bss (NOLOAD) : + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + + mapping[dram0_bss] + + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.share.mem) + *(.gnu.linkonce.b.*) + + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + } > dram0_0_seg + + ASSERT(((_bss_end - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)), "DRAM segment data does not fit.") + + .flash.text : + { + _stext = .; + _instruction_reserved_start = ABSOLUTE(.); /* This is a symbol marking the flash.text start, this can be used for mmu driver to maintain virtual address */ + _text_start = ABSOLUTE(.); + + mapping[flash_text] + + *(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.irom0.text) /* catch stray ICACHE_RODATA_ATTR */ + *(.fini.literal) + *(.fini) + *(.gnu.version) + + /** CPU will try to prefetch up to 16 bytes of + * of instructions. This means that any configuration (e.g. MMU, PMS) must allow + * safe access to up to 16 bytes after the last real instruction, add + * dummy bytes to ensure this + */ + . += _esp_flash_mmap_prefetch_pad_size; + + _text_end = ABSOLUTE(.); + _instruction_reserved_end = ABSOLUTE(.); /* This is a symbol marking the flash.text end, this can be used for mmu driver to maintain virtual address */ + _etext = .; + + /** + * Similar to _iram_start, this symbol goes here so it is + * resolved by addr2line in preference to the first symbol in + * the flash.text segment. + */ + _flash_cache_start = ABSOLUTE(0); + } > default_code_seg + + /** + * This dummy section represents the .flash.text section but in default_rodata_seg. + * Thus, it must have its alignment and (at least) its size. + */ + .flash_rodata_dummy (NOLOAD): + { + _flash_rodata_dummy_start = .; + /* Start at the same alignment constraint than .flash.text */ + . = ALIGN(ALIGNOF(.flash.text)); + /* Create an empty gap as big as .flash.text section */ + . = . + SIZEOF(.flash.text); + /* Prepare the alignment of the section above. Few bytes (0x20) must be + * added for the mapping header. */ + . = ALIGN(_esp_mmu_block_size) + 0x20; + } > default_rodata_seg + + .flash.appdesc : ALIGN(0x10) + { + _rodata_reserved_start = ABSOLUTE(.); /* This is a symbol marking the flash.rodata start, this can be used for mmu driver to maintain virtual address */ + _rodata_start = ABSOLUTE(.); + + *(.rodata_desc .rodata_desc.*) /* Should be the first. App version info. DO NOT PUT ANYTHING BEFORE IT! */ + *(.rodata_custom_desc .rodata_custom_desc.*) /* Should be the second. Custom app version info. DO NOT PUT ANYTHING BEFORE IT! */ + + /* Create an empty gap within this section. Thanks to this, the end of this + * section will match .flash.rodata's begin address. Thus, both sections + * will be merged when creating the final bin image. */ + . = ALIGN(ALIGNOF(.flash.rodata)); + } > default_rodata_seg + + .flash.rodata : ALIGN(0x10) + { + _flash_rodata_start = ABSOLUTE(.); + + mapping[flash_rodata] + + *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE_ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table .gcc_except_table.*) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + . = (. + 7) & ~ 3; + /* + * C++ constructor and destructor tables + * Don't include anything from crtbegin.o or crtend.o, as IDF doesn't use toolchain crt. + * + * RISC-V gcc is configured with --enable-initfini-array so it emits an .init_array section instead. + * But the init_priority sections will be sorted for iteration in ascending order during startup. + * The rest of the init_array sections is sorted for iteration in descending order during startup, however. + * Hence a different section is generated for the init_priority functions which is iterated in + * ascending order during startup. The corresponding code can be found in startup.c. + */ + __init_priority_array_start = ABSOLUTE(.); + KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array.*)) + __init_priority_array_end = ABSOLUTE(.); + __init_array_start = ABSOLUTE(.); + KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array)) + __init_array_end = ABSOLUTE(.); + KEEP (*crtbegin.*(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.*) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS_ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + /* Addresses of memory regions reserved via SOC_RESERVE_MEMORY_REGION() */ + soc_reserved_memory_region_start = ABSOLUTE(.); + KEEP (*(.reserved_memory_address)) + soc_reserved_memory_region_end = ABSOLUTE(.); + /* System init functions registered via ESP_SYSTEM_INIT_FN */ + _esp_system_init_fn_array_start = ABSOLUTE(.); + KEEP (*(SORT_BY_INIT_PRIORITY(.esp_system_init_fn.*))) + _esp_system_init_fn_array_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + /* Literals are also RO data. */ + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + . = ALIGN(4); + _thread_local_start = ABSOLUTE(.); + *(.tdata) + *(.tdata.*) + *(.tbss) + *(.tbss.*) + _thread_local_end = ABSOLUTE(.); + . = ALIGN(ALIGNOF(.eh_frame)); + } > default_rodata_seg + + /* Keep this section shall be at least aligned on 4 */ + .eh_frame : ALIGN(8) + { + __eh_frame = ABSOLUTE(.); + KEEP (*(.eh_frame)) + __eh_frame_end = ABSOLUTE(.); + /* Guarantee that this section and the next one will be merged by making + * them adjacent. */ + . = ALIGN(ALIGNOF(.eh_frame_hdr)); + } > default_rodata_seg + + /* To avoid any exception in C++ exception frame unwinding code, this section + * shall be aligned on 8. */ + .eh_frame_hdr : ALIGN(8) + { + __eh_frame_hdr = ABSOLUTE(.); + KEEP (*(.eh_frame_hdr)) + __eh_frame_hdr_end = ABSOLUTE(.); + } > default_rodata_seg + + /* + This section is a place where we dump all the rodata which aren't used at runtime, + so as to avoid binary size increase + */ + .flash.rodata_noload (NOLOAD) : + { + /* + This is a symbol marking the flash.rodata end, this can be used for mmu driver to maintain virtual address + We don't need to include the noload rodata in this section + */ + _rodata_reserved_end = ABSOLUTE(.); + . = ALIGN (4); + mapping[rodata_noload] + } > default_rodata_seg + + /* Marks the end of data, bss and possibly rodata */ + .dram0.heap_start (NOLOAD) : + { + . = ALIGN (16); + _heap_start = ABSOLUTE(.); + } > dram0_0_seg +} + +ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), + "IRAM0 segment data does not fit.") + +ASSERT(((_heap_start - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)), + "DRAM segment data does not fit.") diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index bca7937f79..bb4b44f11c 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -61,6 +61,11 @@ #include "esp32c2/rom/cache.h" #include "esp32c2/rom/rtc.h" #include "esp32c2/rom/secure_boot.h" +#elif CONFIG_IDF_TARGET_ESP32P4 +#include "esp32p4/rtc.h" +#include "soc/hp_sys_clkrst_reg.h" +#include "soc/interrupt_core0_reg.h" +#include "soc/interrupt_core1_reg.h" #endif #include "esp_private/esp_mmu_map_private.h" @@ -163,6 +168,28 @@ void startup_resume_other_cores(void) void IRAM_ATTR call_start_cpu1(void) { +#ifdef __riscv + // Configure the global pointer register + // (This should be the first thing IDF app does, as any other piece of code could be + // relaxed by the linker to access something relative to __global_pointer$) + __asm__ __volatile__ ( + ".option push\n" + ".option norelax\n" + "la gp, __global_pointer$\n" + ".option pop" + ); +#endif //#ifdef __riscv + +#if CONFIG_IDF_TARGET_ESP32P4 + //TODO: IDF-7770 + //set mstatus.fs=2'b01, floating-point unit in the initialization state + asm volatile( + "li t0, 0x2000\n" + "csrrs t0, mstatus, t0\n" + :::"t0" + ); +#endif //#if CONFIG_IDF_TARGET_ESP32P4 + #if SOC_BRANCH_PREDICTOR_SUPPORTED esp_cpu_branch_prediction_enable(); #endif //#if SOC_BRANCH_PREDICTOR_SUPPORTED @@ -188,6 +215,8 @@ void IRAM_ATTR call_start_cpu1(void) #if CONFIG_IDF_TARGET_ESP32 DPORT_REG_SET_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_PDEBUG_ENABLE | DPORT_APP_CPU_RECORD_ENABLE); DPORT_REG_CLR_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_RECORD_ENABLE); +#elif CONFIG_IDF_TARGET_ESP32P4 + //TODO: IDF-7688 #else REG_WRITE(ASSIST_DEBUG_CORE_1_RCD_PDEBUGENABLE_REG, 1); REG_WRITE(ASSIST_DEBUG_CORE_1_RCD_RECORDING_REG, 1); @@ -259,6 +288,13 @@ static void start_other_core(void) REG_SET_BIT(SYSTEM_CORE_1_CONTROL_0_REG, SYSTEM_CONTROL_CORE_1_RESETING); REG_CLR_BIT(SYSTEM_CORE_1_CONTROL_0_REG, SYSTEM_CONTROL_CORE_1_RESETING); } +#elif CONFIG_IDF_TARGET_ESP32P4 + if (!REG_GET_BIT(HP_SYS_CLKRST_SOC_CLK_CTRL0_REG, HP_SYS_CLKRST_REG_CORE1_CPU_CLK_EN)) { + REG_SET_BIT(HP_SYS_CLKRST_SOC_CLK_CTRL0_REG, HP_SYS_CLKRST_REG_CORE1_CPU_CLK_EN); + } + if(REG_GET_BIT(HP_SYS_CLKRST_HP_RST_EN0_REG, HP_SYS_CLKRST_REG_RST_EN_CORE1_GLOBAL)){ + REG_CLR_BIT(HP_SYS_CLKRST_HP_RST_EN0_REG, HP_SYS_CLKRST_REG_RST_EN_CORE1_GLOBAL); + } #endif ets_set_appcpu_boot_addr((uint32_t)call_start_cpu1); @@ -269,10 +305,13 @@ static void start_other_core(void) for (int i = 0; i < SOC_CPU_CORES_NUM; i++) { cpus_up &= s_cpu_up[i]; } + //TODO: IDF-7891, check mixing logs esp_rom_delay_us(100); } } +#if !CONFIG_IDF_TARGET_ESP32P4 +//TODO: IDF-7692 // This function is needed to make the multicore app runnable on a unicore bootloader (built with FREERTOS UNICORE). // It does some cache settings for other CPUs. void IRAM_ATTR do_multicore_settings(void) @@ -303,6 +342,7 @@ void IRAM_ATTR do_multicore_settings(void) cache_hal_enable(CACHE_TYPE_ALL); #endif } +#endif //#if !CONFIG_IDF_TARGET_ESP32P4 #endif // !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE /* @@ -336,6 +376,16 @@ void IRAM_ATTR call_start_cpu0(void) ); #endif +#if CONFIG_IDF_TARGET_ESP32P4 + //TODO: IDF-7770 + //set mstatus.fs=2'b01, floating-point unit in the initialization state + asm volatile( + "li t0, 0x2000\n" + "csrrs t0, mstatus, t0\n" + :::"t0" + ); +#endif //#if CONFIG_IDF_TARGET_ESP32P4 + #if SOC_BRANCH_PREDICTOR_SUPPORTED esp_cpu_branch_prediction_enable(); #endif @@ -371,8 +421,11 @@ void IRAM_ATTR call_start_cpu0(void) ESP_EARLY_LOGI(TAG, "Unicore app"); #else ESP_EARLY_LOGI(TAG, "Multicore app"); +#if !CONFIG_IDF_TARGET_ESP32P4 + //TODO: IDF-7692 // It helps to fix missed cache settings for other cores. It happens when bootloader is unicore. do_multicore_settings(); +#endif //#if !CONFIG_IDF_TARGET_ESP32P4 #endif #endif // !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP @@ -617,10 +670,12 @@ void IRAM_ATTR call_start_cpu0(void) #endif #endif +#if !CONFIG_IDF_TARGET_ESP32P4 //TODO: IDF-7529 // Need to unhold the IOs that were hold right before entering deep sleep, which are used as wakeup pins if (rst_reas[0] == RESET_REASON_CORE_DEEP_SLEEP) { esp_deep_sleep_wakeup_io_reset(); } +#endif //#if !CONFIG_IDF_TARGET_ESP32P4 #if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP esp_cache_err_int_init(); diff --git a/components/esp_system/port/soc/esp32p4/CMakeLists.txt b/components/esp_system/port/soc/esp32p4/CMakeLists.txt index e69de29bb2..09b915cd7e 100644 --- a/components/esp_system/port/soc/esp32p4/CMakeLists.txt +++ b/components/esp_system/port/soc/esp32p4/CMakeLists.txt @@ -0,0 +1,11 @@ +set(srcs "clk.c" + "reset_reason.c" + "system_internal.c" + "cache_err_int.c" + "../../arch/riscv/expression_with_stack.c" + "../../arch/riscv/panic_arch.c" + "../../arch/riscv/debug_stubs.c") + +add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs}) + +target_sources(${COMPONENT_LIB} PRIVATE ${srcs}) diff --git a/components/esp_system/port/soc/esp32p4/Kconfig.cache b/components/esp_system/port/soc/esp32p4/Kconfig.cache new file mode 100644 index 0000000000..46b88d7309 --- /dev/null +++ b/components/esp_system/port/soc/esp32p4/Kconfig.cache @@ -0,0 +1,43 @@ +menu "Cache config" + + choice ESP32P4_L2_CACHE_SIZE + prompt "L2 cache size" + default ESP32P4_L2_CACHE_128KB + help + L2 cache size to be set on application startup. + + config ESP32P4_L2_CACHE_128KB + bool "128KB" + config ESP32P4_L2_CACHE_256KB + bool "256KB" + config ESP32P4_L2_CACHE_512KB + bool "512KB" + endchoice + + config ESP32P4_L2_CACHE_SIZE + hex + default 0x20000 if ESP32P4_L2_CACHE_128KB + default 0x40000 if ESP32P4_L2_CACHE_256KB + default 0x80000 if ESP32P4_L2_CACHE_512KB + + choice ESP32P4_L2_CACHE_LINE_SIZE + prompt "L2 cache line size" + default ESP32P4_L2_CACHE_LINE_64B if ESP32P4_L2_CACHE_128KB + default ESP32P4_L2_CACHE_LINE_64B if ESP32P4_L2_CACHE_256KB + default ESP32P4_L2_CACHE_LINE_128B if ESP32P4_L2_CACHE_512KB + help + L2 cache line size to be set on application startup. + + config ESP32P4_L2_CACHE_LINE_64B + bool "64 Bytes" + depends on ESP32P4_L2_CACHE_128KB || ESP32P4_L2_CACHE_256KB + config ESP32P4_L2_CACHE_LINE_128B + bool "128 Bytes" + endchoice + + config ESP32P4_L2_CACHE_LINE_SIZE + int + default 64 if ESP32P4_L2_CACHE_LINE_64B + default 128 if ESP32P4_L2_CACHE_LINE_128B + +endmenu # Cache config diff --git a/components/esp_system/port/soc/esp32p4/cache_err_int.c b/components/esp_system/port/soc/esp32p4/cache_err_int.c new file mode 100644 index 0000000000..673953660d --- /dev/null +++ b/components/esp_system/port/soc/esp32p4/cache_err_int.c @@ -0,0 +1,61 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + The cache has an interrupt that can be raised as soon as an access to a cached + region (flash) is done without the cache being enabled. We use that here + to panic the CPU, which from a debugging perspective is better than grabbing bad + data from the bus. +*/ +#include "esp_rom_sys.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp_intr_alloc.h" +#include "soc/periph_defs.h" +#include "riscv/interrupt.h" +#include "hal/cache_ll.h" + +static const char *TAG = "CACHE_ERR"; + +//TODO: IDF-7515 +void esp_cache_err_int_init(void) +{ + const uint32_t core_id = 0; + + /* Disable cache interrupts if enabled. */ + ESP_INTR_DISABLE(ETS_CACHEERR_INUM); + + /** + * Bind all cache errors to ETS_CACHEERR_INUM interrupt. we will deal with + * them in handler by different types + * + * On ESP32P4 boards, the cache is a shared one but buses are still + * distinct. So, we have an bus0 and a bus1 sharing the same cache. + * This error can occur if a bus performs a request but the cache + * is disabled. + */ + esp_rom_route_intr_matrix(core_id, ETS_CACHE_INTR_SOURCE, ETS_CACHEERR_INUM); + + /* Set the type and priority to cache error interrupts. */ + esprv_intc_int_set_type(ETS_CACHEERR_INUM, INTR_TYPE_LEVEL); + esprv_intc_int_set_priority(ETS_CACHEERR_INUM, SOC_INTERRUPT_LEVEL_MEDIUM); + + ESP_DRAM_LOGV(TAG, "access error intr clr & ena mask is: 0x%x", CACHE_LL_L1_ACCESS_EVENT_MASK); + /* On the hardware side, start by clearing all the bits reponsible for cache access error */ + cache_ll_l1_clear_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); + /* Then enable cache access error interrupts. */ + cache_ll_l1_enable_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); + + /* Enable the interrupts for cache error. */ + ESP_INTR_ENABLE(ETS_CACHEERR_INUM); +} + +int IRAM_ATTR esp_cache_err_get_cpuid(void) +{ + //TODO: IDF-7515 + //Should return hart ID according to the cache error + return 0; +} diff --git a/components/esp_system/port/soc/esp32p4/clk.c b/components/esp_system/port/soc/esp32p4/clk.c new file mode 100644 index 0000000000..b5ecc7e6dd --- /dev/null +++ b/components/esp_system/port/soc/esp32p4/clk.c @@ -0,0 +1,277 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "sdkconfig.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp_clk_internal.h" +#include "esp32p4/rom/ets_sys.h" +#include "esp32p4/rom/uart.h" +#include "soc/soc.h" +#include "soc/rtc.h" +#include "soc/rtc_periph.h" +#include "soc/i2s_reg.h" +#include "esp_cpu.h" +#include "hal/wdt_hal.h" +#include "esp_private/esp_modem_clock.h" +#include "esp_private/periph_ctrl.h" +#include "esp_private/esp_clk.h" +#include "esp_private/esp_pmu.h" +#include "esp_rom_uart.h" +#include "esp_rom_sys.h" + +/* Number of cycles to wait from the 32k XTAL oscillator to consider it running. + * Larger values increase startup delay. Smaller values may cause false positive + * detection (i.e. oscillator runs for a few cycles and then stops). + */ +#define SLOW_CLK_CAL_CYCLES CONFIG_RTC_CLK_CAL_CYCLES + +#define MHZ (1000000) + +static void select_rtc_slow_clk(soc_rtc_slow_clk_src_t rtc_slow_clk_src); + +static const char *TAG = "clk"; + + + __attribute__((weak)) void esp_clk_init(void) +{ +#if SOC_PMU_SUPPORTED + pmu_init(); +#endif //SOC_PMU_SUPPORTED + + assert(rtc_clk_xtal_freq_get() == RTC_XTAL_FREQ_40M); + + rtc_clk_8m_enable(true); + rtc_clk_fast_src_set(SOC_RTC_FAST_CLK_SRC_RC_FAST); + +#ifdef CONFIG_BOOTLOADER_WDT_ENABLE + // WDT uses a SLOW_CLK clock source. After a function select_rtc_slow_clk a frequency of this source can changed. + // If the frequency changes from 150kHz to 32kHz, then the timeout set for the WDT will increase 4.6 times. + // Therefore, for the time of frequency change, set a new lower timeout value (1.6 sec). + // This prevents excessive delay before resetting in case the supply voltage is drawdown. + // (If frequency is changed from 150kHz to 32kHz then WDT timeout will increased to 1.6sec * 150/32 = 7.5 sec). + wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT(); + uint32_t stage_timeout_ticks = (uint32_t)(1600ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + //Bootloader has enabled RTC WDT until now. We're only modifying timeout, so keep the stage and timeout action the same + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif + +#if defined(CONFIG_RTC_CLK_SRC_EXT_CRYS) + select_rtc_slow_clk(SOC_RTC_SLOW_CLK_SRC_XTAL32K); +#elif defined(CONFIG_RTC_CLK_SRC_EXT_OSC) + select_rtc_slow_clk(SOC_RTC_SLOW_CLK_SRC_OSC_SLOW); +#elif defined(CONFIG_RTC_CLK_SRC_INT_RC32K) + select_rtc_slow_clk(SOC_RTC_SLOW_CLK_SRC_RC32K); +#else + select_rtc_slow_clk(SOC_RTC_SLOW_CLK_SRC_RC_SLOW); +#endif + +#ifdef CONFIG_BOOTLOADER_WDT_ENABLE + // After changing a frequency WDT timeout needs to be set for new frequency. + stage_timeout_ticks = (uint32_t)((uint64_t)CONFIG_BOOTLOADER_WDT_TIME_MS * rtc_clk_slow_freq_get_hz() / 1000); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif + + rtc_cpu_freq_config_t old_config, new_config; + rtc_clk_cpu_freq_get_config(&old_config); + const uint32_t old_freq_mhz = old_config.freq_mhz; + const uint32_t new_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ; + + bool res = rtc_clk_cpu_freq_mhz_to_config(new_freq_mhz, &new_config); + assert(res); + + // Wait for UART TX to finish, otherwise some UART output will be lost + // when switching APB frequency + esp_rom_uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); + + if (res) { + rtc_clk_cpu_freq_set_config(&new_config); + } + + // Re calculate the ccount to make time calculation correct. + esp_cpu_set_cycle_count( (uint64_t)esp_cpu_get_cycle_count() * new_freq_mhz / old_freq_mhz ); +} + +static void select_rtc_slow_clk(soc_rtc_slow_clk_src_t rtc_slow_clk_src) +{ + uint32_t cal_val = 0; + /* number of times to repeat 32k XTAL calibration + * before giving up and switching to the internal RC + */ + int retry_32k_xtal = 3; + + do { + if (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K || rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) { + /* 32k XTAL oscillator needs to be enabled and running before it can + * be used. Hardware doesn't have a direct way of checking if the + * oscillator is running. Here we use rtc_clk_cal function to count + * the number of main XTAL cycles in the given number of 32k XTAL + * oscillator cycles. If the 32k XTAL has not started up, calibration + * will time out, returning 0. + */ + ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up"); + rtc_cal_sel_t cal_sel = 0; + if (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) { + rtc_clk_32k_enable(true); + cal_sel = RTC_CAL_32K_XTAL; + } else if (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) { + rtc_clk_32k_enable_external(); + cal_sel = RTC_CAL_32K_OSC_SLOW; + } + // When SLOW_CLK_CAL_CYCLES is set to 0, clock calibration will not be performed at startup. + if (SLOW_CLK_CAL_CYCLES > 0) { + cal_val = rtc_clk_cal(cal_sel, SLOW_CLK_CAL_CYCLES); + if (cal_val == 0) { + if (retry_32k_xtal-- > 0) { + continue; + } + ESP_EARLY_LOGW(TAG, "32 kHz clock not found, switching to internal 150 kHz oscillator"); + rtc_slow_clk_src = SOC_RTC_SLOW_CLK_SRC_RC_SLOW; + } + } + } else if (rtc_slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC32K) { + rtc_clk_rc32k_enable(true); + } + rtc_clk_slow_src_set(rtc_slow_clk_src); + + if (SLOW_CLK_CAL_CYCLES > 0) { + /* TODO: 32k XTAL oscillator has some frequency drift at startup. + * Improve calibration routine to wait until the frequency is stable. + */ + cal_val = rtc_clk_cal(RTC_CAL_RTC_MUX, SLOW_CLK_CAL_CYCLES); + } else { + const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL; + cal_val = (uint32_t) (cal_dividend / rtc_clk_slow_freq_get_hz()); + } + } while (cal_val == 0); + ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val); + esp_clk_slowclk_cal_set(cal_val); +} + +void rtc_clk_select_rtc_slow_clk(void) +{ + select_rtc_slow_clk(SOC_RTC_SLOW_CLK_SRC_XTAL32K); +} + +/* This function is not exposed as an API at this point. + * All peripheral clocks are default enabled after chip is powered on. + * This function disables some peripheral clocks when cpu starts. + * These peripheral clocks are enabled when the peripherals are initialized + * and disabled when they are de-initialized. + */ +__attribute__((weak)) void esp_perip_clk_init(void) +{ + modem_clock_domain_pmu_state_icg_map_init(); + + ESP_EARLY_LOGW(TAG, "esp_perip_clk_init() has not been implemented yet"); +#if 0 // TODO: IDF-5658 + uint32_t common_perip_clk, hwcrypto_perip_clk, wifi_bt_sdio_clk = 0; + uint32_t common_perip_clk1 = 0; + + soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0); + + /* For reason that only reset CPU, do not disable the clocks + * that have been enabled before reset. + */ + if (rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_SW || + rst_reason == RESET_REASON_CPU0_RTC_WDT || rst_reason == RESET_REASON_CPU0_MWDT1) { + common_perip_clk = ~READ_PERI_REG(SYSTEM_PERIP_CLK_EN0_REG); + hwcrypto_perip_clk = ~READ_PERI_REG(SYSTEM_PERIP_CLK_EN1_REG); + wifi_bt_sdio_clk = ~READ_PERI_REG(SYSTEM_WIFI_CLK_EN_REG); + } else { + common_perip_clk = SYSTEM_WDG_CLK_EN | + SYSTEM_I2S0_CLK_EN | +#if CONFIG_ESP_CONSOLE_UART_NUM != 0 + SYSTEM_UART_CLK_EN | +#endif +#if CONFIG_ESP_CONSOLE_UART_NUM != 1 + SYSTEM_UART1_CLK_EN | +#endif + SYSTEM_SPI2_CLK_EN | + SYSTEM_I2C_EXT0_CLK_EN | + SYSTEM_UHCI0_CLK_EN | + SYSTEM_RMT_CLK_EN | + SYSTEM_LEDC_CLK_EN | + SYSTEM_TIMERGROUP1_CLK_EN | + SYSTEM_SPI3_CLK_EN | + SYSTEM_SPI4_CLK_EN | + SYSTEM_TWAI_CLK_EN | + SYSTEM_I2S1_CLK_EN | + SYSTEM_SPI2_DMA_CLK_EN | + SYSTEM_SPI3_DMA_CLK_EN; + + common_perip_clk1 = 0; + hwcrypto_perip_clk = SYSTEM_CRYPTO_AES_CLK_EN | + SYSTEM_CRYPTO_SHA_CLK_EN | + SYSTEM_CRYPTO_RSA_CLK_EN; + wifi_bt_sdio_clk = SYSTEM_WIFI_CLK_WIFI_EN | + SYSTEM_WIFI_CLK_BT_EN_M | + SYSTEM_WIFI_CLK_UNUSED_BIT5 | + SYSTEM_WIFI_CLK_UNUSED_BIT12; + } + + //Reset the communication peripherals like I2C, SPI, UART, I2S and bring them to known state. + common_perip_clk |= SYSTEM_I2S0_CLK_EN | +#if CONFIG_ESP_CONSOLE_UART_NUM != 0 + SYSTEM_UART_CLK_EN | +#endif +#if CONFIG_ESP_CONSOLE_UART_NUM != 1 + SYSTEM_UART1_CLK_EN | +#endif + SYSTEM_SPI2_CLK_EN | + SYSTEM_I2C_EXT0_CLK_EN | + SYSTEM_UHCI0_CLK_EN | + SYSTEM_RMT_CLK_EN | + SYSTEM_UHCI1_CLK_EN | + SYSTEM_SPI3_CLK_EN | + SYSTEM_SPI4_CLK_EN | + SYSTEM_I2C_EXT1_CLK_EN | + SYSTEM_I2S1_CLK_EN | + SYSTEM_SPI2_DMA_CLK_EN | + SYSTEM_SPI3_DMA_CLK_EN; + common_perip_clk1 = 0; + + /* Change I2S clock to audio PLL first. Because if I2S uses 160MHz clock, + * the current is not reduced when disable I2S clock. + */ + // TOCK(check replacement) + // REG_SET_FIELD(I2S_CLKM_CONF_REG(0), I2S_CLK_SEL, I2S_CLK_AUDIO_PLL); + // REG_SET_FIELD(I2S_CLKM_CONF_REG(1), I2S_CLK_SEL, I2S_CLK_AUDIO_PLL); + + /* Disable some peripheral clocks. */ + CLEAR_PERI_REG_MASK(SYSTEM_PERIP_CLK_EN0_REG, common_perip_clk); + SET_PERI_REG_MASK(SYSTEM_PERIP_RST_EN0_REG, common_perip_clk); + + CLEAR_PERI_REG_MASK(SYSTEM_PERIP_CLK_EN1_REG, common_perip_clk1); + SET_PERI_REG_MASK(SYSTEM_PERIP_RST_EN1_REG, common_perip_clk1); + + /* Disable hardware crypto clocks. */ + CLEAR_PERI_REG_MASK(SYSTEM_PERIP_CLK_EN1_REG, hwcrypto_perip_clk); + SET_PERI_REG_MASK(SYSTEM_PERIP_RST_EN1_REG, hwcrypto_perip_clk); + + /* Disable WiFi/BT/SDIO clocks. */ + CLEAR_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, wifi_bt_sdio_clk); + SET_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_EN); + + /* Set WiFi light sleep clock source to RTC slow clock */ + REG_SET_FIELD(SYSTEM_BT_LPCK_DIV_INT_REG, SYSTEM_BT_LPCK_DIV_NUM, 0); + CLEAR_PERI_REG_MASK(SYSTEM_BT_LPCK_DIV_FRAC_REG, SYSTEM_LPCLK_SEL_8M); + SET_PERI_REG_MASK(SYSTEM_BT_LPCK_DIV_FRAC_REG, SYSTEM_LPCLK_SEL_RTC_SLOW); + + /* Enable RNG clock. */ + periph_module_enable(PERIPH_RNG_MODULE); +#endif +} diff --git a/components/esp_system/port/soc/esp32p4/reset_reason.c b/components/esp_system/port/soc/esp32p4/reset_reason.c new file mode 100644 index 0000000000..4f29b512f3 --- /dev/null +++ b/components/esp_system/port/soc/esp32p4/reset_reason.c @@ -0,0 +1,110 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_system.h" +#include "esp_rom_sys.h" +#include "esp_private/system_internal.h" +#include "soc/rtc_periph.h" +#include "esp32p4/rom/rtc.h" + +static void esp_reset_reason_clear_hint(void); + +static esp_reset_reason_t s_reset_reason; + +static esp_reset_reason_t get_reset_reason(soc_reset_reason_t rtc_reset_reason, esp_reset_reason_t reset_reason_hint) +{ + switch (rtc_reset_reason) { + case RESET_REASON_CHIP_POWER_ON: + return ESP_RST_POWERON; + + case RESET_REASON_CPU0_SW: + case RESET_REASON_CORE_SW: + if (reset_reason_hint == ESP_RST_PANIC || + reset_reason_hint == ESP_RST_BROWNOUT || + reset_reason_hint == ESP_RST_TASK_WDT || + reset_reason_hint == ESP_RST_INT_WDT) { + return reset_reason_hint; + } + return ESP_RST_SW; + + case RESET_REASON_CORE_DEEP_SLEEP: + return ESP_RST_DEEPSLEEP; + + case RESET_REASON_CORE_MWDT0: + return ESP_RST_TASK_WDT; + + case RESET_REASON_CORE_MWDT1: + return ESP_RST_INT_WDT; + + case RESET_REASON_CORE_RTC_WDT: + case RESET_REASON_SYS_RTC_WDT: + case RESET_REASON_SYS_SUPER_WDT: + case RESET_REASON_CPU0_RTC_WDT: + case RESET_REASON_CPU0_MWDT0: + case RESET_REASON_CPU0_MWDT1: + return ESP_RST_WDT; + + case RESET_REASON_SYS_BROWN_OUT: + return ESP_RST_BROWNOUT; + + default: + return ESP_RST_UNKNOWN; + } +} + +static void __attribute__((constructor)) esp_reset_reason_init(void) +{ + esp_reset_reason_t hint = esp_reset_reason_get_hint(); + s_reset_reason = get_reset_reason(esp_rom_get_reset_reason(PRO_CPU_NUM), hint); + if (hint != ESP_RST_UNKNOWN) { + esp_reset_reason_clear_hint(); + } +} + +esp_reset_reason_t esp_reset_reason(void) +{ + return s_reset_reason; +} + +/* Reset reason hint is stored in RTC_RESET_CAUSE_REG, a.k.a. RTC_CNTL_STORE6_REG, + * a.k.a. RTC_ENTRY_ADDR_REG. It is safe to use this register both for the + * deep sleep wake stub entry address and for reset reason hint, since wake stub + * is only used for deep sleep reset, and in this case the reason provided by + * esp_rom_get_reset_reason is unambiguous. + * + * Same layout is used as for RTC_APB_FREQ_REG (a.k.a. RTC_CNTL_STORE5_REG): + * the value is replicated in low and high half-words. In addition to that, + * MSB is set to 1, which doesn't happen when RTC_CNTL_STORE6_REG contains + * deep sleep wake stub address. + */ + +#define RST_REASON_BIT 0x80000000 +#define RST_REASON_MASK 0x7FFF +#define RST_REASON_SHIFT 16 + +/* in IRAM, can be called from panic handler */ +void IRAM_ATTR esp_reset_reason_set_hint(esp_reset_reason_t hint) +{ + assert((hint & (~RST_REASON_MASK)) == 0); + uint32_t val = hint | (hint << RST_REASON_SHIFT) | RST_REASON_BIT; + REG_WRITE(RTC_RESET_CAUSE_REG, val); +} + +/* in IRAM, can be called from panic handler */ +esp_reset_reason_t IRAM_ATTR esp_reset_reason_get_hint(void) +{ + uint32_t reset_reason_hint = REG_READ(RTC_RESET_CAUSE_REG); + uint32_t high = (reset_reason_hint >> RST_REASON_SHIFT) & RST_REASON_MASK; + uint32_t low = reset_reason_hint & RST_REASON_MASK; + if ((reset_reason_hint & RST_REASON_BIT) == 0 || high != low) { + return ESP_RST_UNKNOWN; + } + return (esp_reset_reason_t) low; +} +static inline void esp_reset_reason_clear_hint(void) +{ + REG_WRITE(RTC_RESET_CAUSE_REG, 0); +} diff --git a/components/esp_system/port/soc/esp32p4/system_internal.c b/components/esp_system/port/soc/esp32p4/system_internal.c new file mode 100644 index 0000000000..288483c5c7 --- /dev/null +++ b/components/esp_system/port/soc/esp32p4/system_internal.c @@ -0,0 +1,143 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "esp_system.h" +#include "esp_private/system_internal.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp_rom_sys.h" +#include "riscv/rv_utils.h" +#include "esp_rom_uart.h" +#include "soc/gpio_reg.h" +#include "esp_cpu.h" +#include "soc/rtc.h" +#include "esp_private/rtc_clk.h" +#include "soc/rtc_periph.h" +#include "soc/uart_reg.h" +#include "hal/wdt_hal.h" +#include "esp_private/cache_err_int.h" + +#include "esp32p4/rom/cache.h" +#include "esp32p4/rom/rtc.h" +#include "soc/hp_sys_clkrst_reg.h" +#include "soc/lp_clkrst_reg.h" +#include "soc/hp_system_reg.h" + +void IRAM_ATTR esp_system_reset_modules_on_exit(void) +{ + // Flush any data left in UART FIFOs + esp_rom_uart_tx_wait_idle(0); + esp_rom_uart_tx_wait_idle(1); + + // Set Peripheral clk rst + SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_TIMERGRP0); + SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_TIMERGRP1); + SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_STIMER); + SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN0_REG, HP_SYS_CLKRST_REG_RST_EN_DUAL_MSPI_AXI); + SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN0_REG, HP_SYS_CLKRST_REG_RST_EN_MSPI_AXI); + SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART0_CORE); + SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART1_CORE); + SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART2_CORE); + SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART3_CORE); + SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART4_CORE); + SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN0_REG, HP_SYS_CLKRST_REG_RST_EN_GDMA); + + // Clear Peripheral clk rst + CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_TIMERGRP0); + CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_TIMERGRP1); + CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_STIMER); + CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN0_REG, HP_SYS_CLKRST_REG_RST_EN_DUAL_MSPI_AXI); + CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN0_REG, HP_SYS_CLKRST_REG_RST_EN_MSPI_AXI); + CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART0_CORE); + CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART1_CORE); + CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART2_CORE); + CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART3_CORE); + CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART4_CORE); + CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN0_REG, HP_SYS_CLKRST_REG_RST_EN_GDMA); +} + +/* "inner" restart function for after RTOS, interrupts & anything else on this + * core are already stopped. Stalls other core, resets hardware, + * triggers restart. +*/ +void IRAM_ATTR esp_restart_noos(void) +{ + // Disable interrupts + rv_utils_intr_global_disable(); + // Enable RTC watchdog for 1 second + wdt_hal_context_t rtc_wdt_ctx; + wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); + uint32_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE1, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + //Enable flash boot mode so that flash booting after restart is protected by the RTC WDT. + wdt_hal_set_flashboot_en(&rtc_wdt_ctx, true); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); + + const uint32_t core_id = esp_cpu_get_core_id(); +#if !CONFIG_FREERTOS_UNICORE + const uint32_t other_core_id = (core_id == 0) ? 1 : 0; + esp_cpu_reset(other_core_id); + esp_cpu_stall(other_core_id); +#endif + + // Disable TG0/TG1 watchdogs + wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; + wdt_hal_write_protect_disable(&wdt0_context); + wdt_hal_disable(&wdt0_context); + wdt_hal_write_protect_enable(&wdt0_context); + + wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1}; + wdt_hal_write_protect_disable(&wdt1_context); + wdt_hal_disable(&wdt1_context); + wdt_hal_write_protect_enable(&wdt1_context); + + // Disable cache + Cache_Disable_L2_Cache(); + + esp_system_reset_modules_on_exit(); + + // Set CPU back to XTAL source, no PLL, same as hard reset +#if !CONFIG_IDF_ENV_FPGA + rtc_clk_cpu_freq_set_xtal(); +#endif + +#if !CONFIG_FREERTOS_UNICORE + // clear entry point for APP CPU + ets_set_appcpu_boot_addr(0); +#endif + +#if CONFIG_SPIRAM_INSTRUCTIONS_RODATA + //TODO: IDF-7556 + // disable remap if enabled in menuconfig + REG_CLR_BIT(HP_SYS_HP_PSRAM_FLASH_ADDR_INTERCHANGE_REG, HP_SYS_HP_PSRAM_FLASH_ADDR_INTERCHANGE_DMA | HP_SYS_HP_PSRAM_FLASH_ADDR_INTERCHANGE_CPU); +#endif + + // Reset CPUs + if (core_id == 0) { + // Running on PRO CPU: APP CPU is stalled. Can reset both CPUs. +#if !CONFIG_FREERTOS_UNICORE + esp_cpu_reset(1); +#endif + esp_cpu_reset(0); + } +#if !CONFIG_FREERTOS_UNICORE + else { + // Running on APP CPU: need to reset PRO CPU and unstall it, + // then reset APP CPU + esp_cpu_reset(0); + esp_cpu_unstall(0); + esp_cpu_reset(1); + } +#endif + + while (true) { + ; + } +} diff --git a/components/esp_system/system_time.c b/components/esp_system/system_time.c index 2ff7107978..f712239948 100644 --- a/components/esp_system/system_time.c +++ b/components/esp_system/system_time.c @@ -27,6 +27,8 @@ #include "esp32c6/rtc.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32P4 +#include "esp32p4/rtc.h" #endif #include "esp_private/startup_internal.h" diff --git a/components/esp_system/task_wdt/task_wdt_impl_timergroup.c b/components/esp_system/task_wdt/task_wdt_impl_timergroup.c index 2414004fa4..ebf8e4c1d0 100644 --- a/components/esp_system/task_wdt/task_wdt_impl_timergroup.c +++ b/components/esp_system/task_wdt/task_wdt_impl_timergroup.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/soc/esp32p4/include/soc/interrupts.h b/components/soc/esp32p4/include/soc/interrupts.h index 9595519827..bb3fd7c4b5 100644 --- a/components/soc/esp32p4/include/soc/interrupts.h +++ b/components/soc/esp32p4/include/soc/interrupts.h @@ -61,9 +61,9 @@ typedef enum { ETS_RMT_INTR_SOURCE, ETS_I2C0_INTR_SOURCE, ETS_I2C1_INTR_SOURCE, - ETS_TIMERGROUP0_T0_INTR_SOURCE, - ETS_TIMERGROUP0_T1_INTR_SOURCE, - ETS_TIMERGROUP0_WDT_INTR_SOURCE, + ETS_TG0_WDT_LEVEL_INTR_SOURCE, + ETS_TG1_WDT_LEVEL_INTR_SOURCE, + ETS_TG0_WDT_INTR_SOURCE, ETS_TIMERGROUP1_T0_INTR_SOURCE, ETS_TIMERGROUP1_T1_INTR_SOURCE, ETS_TIMERGROUP1_WDT_INTR_SOURCE, @@ -96,10 +96,10 @@ typedef enum { ETS_GPIO_INTR2_SOURCE, ETS_GPIO_INTR3_SOURCE, ETS_GPIO_PAD_COMP_INTR_SOURCE, - ETS_CPU_INT_FROM_CPU0_INTR_SOURCE, - ETS_CPU_INT_FROM_CPU1_INTR_SOURCE, - ETS_CPU_INT_FROM_CPU2_INTR_SOURCE, - ETS_CPU_INT_FROM_CPU3_INTR_SOURCE, + ETS_FROM_CPU_INTR0_SOURCE, + ETS_FROM_CPU_INTR1_SOURCE, + ETS_FROM_CPU_INTR2_SOURCE, + ETS_FROM_CPU_INTR3_SOURCE, ETS_CACHE_INTR_SOURCE, ETS_MSPI_INTR_SOURCE, ETS_CSI_BRIDGE_INTR_SOURCE, From 756c36504a61e60e33402d480b372a689021e404 Mon Sep 17 00:00:00 2001 From: Armando Date: Tue, 11 Jul 2023 16:07:39 +0800 Subject: [PATCH 12/13] feat(tcm): added tcm basic support on esp32p4 --- components/esp_common/include/esp_attr.h | 3 +++ components/esp_common/soc.lf | 12 ++++++++++++ components/esp_system/app.lf | 10 ++++++++++ 3 files changed, 25 insertions(+) diff --git a/components/esp_common/include/esp_attr.h b/components/esp_common/include/esp_attr.h index ade3b3d903..bf067862d4 100644 --- a/components/esp_common/include/esp_attr.h +++ b/components/esp_common/include/esp_attr.h @@ -25,6 +25,9 @@ extern "C" { // Forces data into DRAM instead of flash #define DRAM_ATTR _SECTION_ATTR_IMPL(".dram1", __COUNTER__) +// Forces code into TCM instead of flash +#define TCM_IRAM_ATTR _SECTION_ATTR_IMPL(".tcm.text", __COUNTER__) + // IRAM can only be accessed as an 8-bit memory on ESP32, when CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY is set #define IRAM_8BIT_ACCESSIBLE (CONFIG_IDF_TARGET_ESP32 && CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY) diff --git a/components/esp_common/soc.lf b/components/esp_common/soc.lf index 46193323e5..99f81a2a74 100644 --- a/components/esp_common/soc.lf +++ b/components/esp_common/soc.lf @@ -41,3 +41,15 @@ entries: [sections:extram_bss] entries: .ext_ram.bss+ + +[sections:tcm_text] +entries: + .tcm.text+ + +[sections:tcm_data] +entries: + .tcm.data+ + +[sections:tcm_bss] +entries: + .tcm.bss+ diff --git a/components/esp_system/app.lf b/components/esp_system/app.lf index 15484115d0..d9f6b73e44 100644 --- a/components/esp_system/app.lf +++ b/components/esp_system/app.lf @@ -22,6 +22,8 @@ entries: rtc_data -> rtc_data rtc_rodata -> rtc_data rtc_bss -> rtc_bss + tcm_text -> tcm_text + tcm_data -> tcm_data [scheme:rtc] entries: @@ -44,6 +46,14 @@ entries: entries: text -> iram0_text +[scheme:tcm] +entries: + text -> tcm_text + data -> tcm_data + rodata -> tcm_data + bss -> tcm_bss + common -> tcm_bss + [mapping:default] archive: * entries: From e8bbb490ec5e58d62432c35333f4a139ea505907 Mon Sep 17 00:00:00 2001 From: Armando Date: Fri, 21 Jul 2023 12:37:06 +0800 Subject: [PATCH 13/13] feat(cache): added cache init configurations on p4 --- components/esp_system/port/cpu_start.c | 5 +++++ components/spi_flash/cache_utils.c | 29 +++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index bb4b44f11c..4ec955061e 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -483,6 +483,11 @@ void IRAM_ATTR call_start_cpu0(void) Cache_Resume_DCache(0); #endif // CONFIG_IDF_TARGET_ESP32S3 +#if CONFIG_IDF_TARGET_ESP32P4 + //TODO: IDF-7516, add cache init API + extern void esp_config_llc_mode(void); + esp_config_llc_mode(); +#endif if (esp_efuse_check_errors() != ESP_OK) { esp_restart(); } diff --git a/components/spi_flash/cache_utils.c b/components/spi_flash/cache_utils.c index b74834a20e..84047dacee 100644 --- a/components/spi_flash/cache_utils.c +++ b/components/spi_flash/cache_utils.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -39,6 +39,8 @@ #include "esp32h2/rom/cache.h" #include "soc/extmem_reg.h" #include "soc/ext_mem_defs.h" +#elif CONFIG_IDF_TARGET_ESP32P4 +#include "esp32p4/rom/cache.h" #endif #include "esp_rom_spiflash.h" #include "hal/cache_hal.h" @@ -914,3 +916,28 @@ esp_err_t esp_enable_cache_wrap(bool icache_wrap_enable) return ESP_OK; } #endif // CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 + +#if CONFIG_IDF_TARGET_ESP32P4 +//TODO: IDF-5670 +TCM_IRAM_ATTR void esp_config_llc_mode(void) +{ + cache_size_t cache_size; + cache_line_size_t cache_line_size; +#if CONFIG_ESP32P4_L2_CACHE_128KB + cache_size = CACHE_SIZE_128K; +#elif CONFIG_ESP32P4_L2_CACHE_256KB + cache_size = CACHE_SIZE_256K; +#else + cache_size = CACHE_SIZE_512K; +#endif + +#if CONFIG_ESP32P4_L2_CACHE_LINE_64B + cache_line_size = CACHE_LINE_SIZE_64B; +#else + cache_line_size = CACHE_LINE_SIZE_128B; +#endif + + Cache_Set_L2_Cache_Mode(cache_size, 8, cache_line_size); + Cache_Invalidate_All(CACHE_MAP_L2_CACHE); +} +#endif