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.