soc: xtensa: esp32: reenable SMP for esp32
By enabling SMP option plus the APPCPU, also
completes the SMP port by adding the esp32
specific arch_sched_ipi() function
Signed-off-by: Felipe Neves <felipe.neves@espressif.com>
diff --git a/dts/xtensa/espressif/esp32.dtsi b/dts/xtensa/espressif/esp32.dtsi
index 89bb61f..cf94df4 100644
--- a/dts/xtensa/espressif/esp32.dtsi
+++ b/dts/xtensa/espressif/esp32.dtsi
@@ -81,6 +81,22 @@
};
};
+ ipi0: ipi@3f4c0058 {
+ compatible = "espressif,crosscore-interrupt";
+ label = "IPI0";
+ reg = <0x3f4c0058 0x4>;
+ interrupts = <FROM_CPU_INTR0_SOURCE>;
+ interrupt-parent = <&intc>;
+ };
+
+ ipi1: ipi@3f4c005c {
+ compatible = "espressif,crosscore-interrupt";
+ label = "IPI1";
+ reg = <0x3f4c005c 0x4>;
+ interrupts = <FROM_CPU_INTR1_SOURCE>;
+ interrupt-parent = <&intc>;
+ };
+
uart0: uart@3ff40000 {
compatible = "espressif,esp32-uart";
reg = <0x3ff40000 0x400>;
diff --git a/soc/xtensa/esp32/Kconfig.defconfig b/soc/xtensa/esp32/Kconfig.defconfig
index 50132a0..21edc07 100644
--- a/soc/xtensa/esp32/Kconfig.defconfig
+++ b/soc/xtensa/esp32/Kconfig.defconfig
@@ -11,8 +11,21 @@
config IRQ_OFFLOAD_INTNUM
default 7
+config SMP
+ default n
+
+if SMP
+
+config SCHED_IPI_SUPPORTED
+ default y
+
+config SCHED_CPU_MASK
+ default y
+
config MP_NUM_CPUS
- default 1
+ default 2
+
+endif
config MINIMAL_LIBC_OPTIMIZE_STRING_FOR_SIZE
default n
diff --git a/soc/xtensa/esp32/esp32-mp.c b/soc/xtensa/esp32/esp32-mp.c
index 63cc4b0..857ae29 100644
--- a/soc/xtensa/esp32/esp32-mp.c
+++ b/soc/xtensa/esp32/esp32-mp.c
@@ -5,8 +5,13 @@
*/
/* Include esp-idf headers first to avoid redefining BIT() macro */
-#include <soc.h>
+#include "soc/dport_reg.h"
+#include "soc/gpio_periph.h"
+#include "soc/rtc_periph.h"
+#include <drivers/interrupt_controller/intc_esp32.h>
+#include <soc.h>
+#include <device.h>
#include <zephyr.h>
#include <spinlock.h>
#include <kernel_structs.h>
@@ -33,9 +38,11 @@
volatile struct cpustart_rec *start_rec;
static void *appcpu_top;
-
+static bool cpus_active[CONFIG_MP_NUM_CPUS];
static struct k_spinlock loglock;
+extern void z_sched_ipi(void);
+
/* Note that the logging done here is ACTUALLY REQUIRED FOR RELIABLE
* OPERATION! At least one particular board will experience spurious
* hangs during initialization (usually the APPCPU fails to start at
@@ -67,7 +74,6 @@
static void appcpu_entry2(void)
{
volatile int ps, ie;
- smp_log("ESP32: APPCPU running");
/* Copy over VECBASE from the main CPU for an initial value
* (will need to revisit this if we ever allow a user API to
@@ -92,6 +98,8 @@
__asm__ volatile("wsr.MISC0 %0" : : "r"(cpu));
+ smp_log("ESP32: APPCPU running");
+
*start_rec->alive = 1;
start_rec->fn(start_rec->arg);
}
@@ -190,6 +198,34 @@
smp_log("ESP32: APPCPU start sequence complete");
}
+IRAM_ATTR static inline uint32_t prid(void)
+{
+ uint32_t id;
+
+ __asm__ volatile (
+ "rsr.prid %0\n"
+ "extui %0,%0,13,1" : "=r" (id));
+ return id;
+}
+
+IRAM_ATTR static void esp_crosscore_isr(void *arg)
+{
+ ARG_UNUSED(arg);
+
+#ifdef CONFIG_SMP
+ /* Right now this interrupt is only used for IPIs */
+ z_sched_ipi();
+#endif
+
+ const int core_id = prid();
+
+ if (core_id == 0) {
+ DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, 0);
+ } else {
+ DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_1_REG, 0);
+ }
+}
+
void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz,
arch_cpustart_t fn, void *arg)
{
@@ -219,5 +255,36 @@
while (!alive_flag) {
}
+ cpus_active[0] = true;
+ cpus_active[CONFIG_MP_NUM_CPUS - 1] = true;
+
+ esp_intr_alloc(DT_IRQN(DT_NODELABEL(ipi0)),
+ ESP_INTR_FLAG_IRAM,
+ esp_crosscore_isr,
+ NULL,
+ NULL);
+
+ esp_intr_alloc(DT_IRQN(DT_NODELABEL(ipi1)),
+ ESP_INTR_FLAG_IRAM,
+ esp_crosscore_isr,
+ NULL,
+ NULL);
+
smp_log("ESP32: APPCPU initialized");
}
+
+void arch_sched_ipi(void)
+{
+ const int core_id = prid();
+
+ if (core_id == 0) {
+ DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, DPORT_CPU_INTR_FROM_CPU_0);
+ } else {
+ DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_1_REG, DPORT_CPU_INTR_FROM_CPU_1);
+ }
+}
+
+IRAM_ATTR bool arch_cpu_active(int cpu_num)
+{
+ return cpus_active[cpu_num];
+}
diff --git a/soc/xtensa/esp32/linker.ld b/soc/xtensa/esp32/linker.ld
index a11ed04..8947470 100644
--- a/soc/xtensa/esp32/linker.ld
+++ b/soc/xtensa/esp32/linker.ld
@@ -41,7 +41,7 @@
* - Utilize available memory regions to full capacity
*/
dram0_0_seg(RW): org = 0x3FFB0000 + CONFIG_ESP32_BT_RESERVE_DRAM, len = 0x2c200 - CONFIG_ESP32_BT_RESERVE_DRAM
- dram0_1_seg(RW): org = 0x3FFE4350, len = 0x1BCB0
+ dram0_1_seg(RW): org = 0x3FFE5230, len = 0x1BCB0 - 0xEE0 /* skip data for APP CPU initialization usage */
drom0_0_seg(R): org = 0x3F400020, len = 0x400000-0x20
rtc_iram_seg(RWX): org = 0x400C0000, len = 0x2000
rtc_slow_seg(RW): org = 0x50000000, len = 0x1000
@@ -488,7 +488,7 @@
{
. = ALIGN (8);
*(.noinit)
- *(".noinit.*")
+ *(.noinit.*)
. = ALIGN (8);
} GROUP_LINK_IN(RAMABLE_REGION_1)
diff --git a/soc/xtensa/esp32/soc.c b/soc/xtensa/esp32/soc.c
index b43fd7e..c739de7 100644
--- a/soc/xtensa/esp32/soc.c
+++ b/soc/xtensa/esp32/soc.c
@@ -81,9 +81,6 @@
:
: "r"(PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE));
- /* Disable CPU1 while we figure out how to have SMP in Zephyr. */
- *app_cpu_config_reg &= ~DPORT_APPCPU_CLKGATE_EN;
-
/* Initialize the architecture CPU pointer. Some of the
* initialization code wants a valid _current before
* arch_kernel_init() is invoked.