xtensa/esp32s3: Enable SMP support
Signed-off-by: Gustavo Henrique Nihei <gustavo.nihei@espressif.com>
This commit is contained in:
parent
4888be37e3
commit
4a29fa903b
16 changed files with 1032 additions and 78 deletions
|
|
@ -52,6 +52,10 @@ ifeq ($(CONFIG_SPINLOCK),y)
|
|||
CMN_CSRCS += xtensa_testset.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SMP),y)
|
||||
CMN_CSRCS += xtensa_cpupause.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_STACK_COLORATION),y)
|
||||
CMN_CSRCS += xtensa_checkstack.c
|
||||
endif
|
||||
|
|
@ -73,6 +77,11 @@ ifneq ($(CONFIG_ARCH_IDLE_CUSTOM),y)
|
|||
CHIP_CSRCS += esp32s3_idle.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SMP),y)
|
||||
CHIP_ASRCS = esp32s3_cpuindex.S
|
||||
CHIP_CSRCS += esp32s3_cpuidlestack.c esp32s3_cpustart.c esp32s3_intercpu_interrupt.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SCHED_TICKLESS),y)
|
||||
CHIP_CSRCS += esp32s3_tickless.c
|
||||
else
|
||||
|
|
|
|||
|
|
@ -27,6 +27,12 @@
|
|||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
|
@ -41,6 +47,14 @@
|
|||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
|
||||
#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15
|
||||
.global g_cpu_intstack_top
|
||||
#endif /* CONFIG_SMP && CONFIG_ARCH_INTERRUPTSTACK > 15 */
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
/****************************************************************************
|
||||
* Assembly Language Macros
|
||||
****************************************************************************/
|
||||
|
|
@ -48,22 +62,34 @@
|
|||
#ifdef __ASSEMBLY__
|
||||
|
||||
/* Macro to get the current core ID. Only uses the reg given as an argument.
|
||||
* Reading PRID on the ESP108 architecture gives us 0xcdcd on the PRO
|
||||
* processor and 0xabab on the APP CPU. We distinguish between the two by
|
||||
* simply checking bit 1: it's 1 on the APP and 0 on the PRO processor.
|
||||
* Reading PRID on the ESP32 gives us 0xCDCD on the PRO processor (0)
|
||||
* and 0xABAB on the APP CPU (1). We can distinguish between the two by
|
||||
* checking bit 13: it's 1 on the APP and 0 on the PRO processor.
|
||||
*/
|
||||
|
||||
.macro getcoreid reg
|
||||
rsr.prid \reg
|
||||
bbci \reg, 1, 1f
|
||||
movi \reg, 1
|
||||
j 2f
|
||||
1:
|
||||
movi \reg, 0
|
||||
2:
|
||||
.macro getcoreid reg
|
||||
rsr.prid \reg
|
||||
extui \reg,\reg,13,1
|
||||
.endm
|
||||
|
||||
#endif /* __ASSEMBLY */
|
||||
/****************************************************************************
|
||||
* Name: setintstack
|
||||
*
|
||||
* Description:
|
||||
* Set the current stack pointer to the "top" of the correct interrupt
|
||||
* stack for the current CPU.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15
|
||||
.macro setintstack tmp1 tmp2
|
||||
getcoreid \tmp1 /* tmp1 = Core ID (0 or 1) */
|
||||
movi \tmp2, g_cpu_intstack_top /* tmp2 = Array of stack pointers */
|
||||
addx4 \tmp2, \tmp1, \tmp2 /* tmp2 = tmp2 + (tmp1 << 2) */
|
||||
l32i a1, \tmp2, 0 /* a1 = *tmp2 */
|
||||
.endm
|
||||
#endif
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
|
|
@ -82,6 +108,11 @@ extern "C"
|
|||
* Public Functions Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15
|
||||
uintptr_t xtensa_intstack_alloc(void);
|
||||
uintptr_t xtensa_intstack_top(void);
|
||||
#endif
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
|
|
|||
106
arch/xtensa/src/esp32s3/esp32s3_cpuidlestack.c
Normal file
106
arch/xtensa/src/esp32s3/esp32s3_cpuidlestack.c
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/****************************************************************************
|
||||
* arch/xtensa/src/esp32s3/esp32s3_cpuidlestack.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/arch.h>
|
||||
|
||||
#include "xtensa.h"
|
||||
#include "esp32s3_smp.h"
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/* Address of the CPU1 IDLE thread */
|
||||
|
||||
uint32_t g_cpu1_idlestack[CPU1_IDLETHREAD_STACKWORDS]
|
||||
aligned_data(16) locate_data(".noinit");
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_cpu_idlestack
|
||||
*
|
||||
* Description:
|
||||
* Allocate a stack for the CPU[n] IDLE task (n > 0) if appropriate and
|
||||
* setup up stack-related information in the IDLE task's TCB. This
|
||||
* function is always called before up_cpu_start(). This function is
|
||||
* only called for the CPU's initial IDLE task; up_create_task is used for
|
||||
* all normal tasks, pthreads, and kernel threads for all CPUs.
|
||||
*
|
||||
* The initial IDLE task is a special case because the CPUs can be started
|
||||
* in different wans in different environments:
|
||||
*
|
||||
* 1. The CPU may already have been started and waiting in a low power
|
||||
* state for up_cpu_start(). In this case, the IDLE thread's stack
|
||||
* has already been allocated and is already in use. Here
|
||||
* up_cpu_idlestack() only has to provide information about the
|
||||
* already allocated stack.
|
||||
*
|
||||
* 2. The CPU may be disabled but started when up_cpu_start() is called.
|
||||
* In this case, a new stack will need to be created for the IDLE
|
||||
* thread and this function is then equivalent to:
|
||||
*
|
||||
* return up_create_stack(tcb, stack_size, TCB_FLAG_TTYPE_KERNEL);
|
||||
*
|
||||
* The following TCB fields must be initialized by this function:
|
||||
*
|
||||
* - adj_stack_size: Stack size after adjustment for hardware, processor,
|
||||
* etc. This value is retained only for debug purposes.
|
||||
* - stack_alloc_ptr: Pointer to allocated stack
|
||||
* - stack_base_ptr: Adjusted stack base pointer after the TLS Data and
|
||||
* Arguments has been removed from the stack allocation.
|
||||
*
|
||||
* Input Parameters:
|
||||
* - cpu: CPU index that indicates which CPU the IDLE task is
|
||||
* being created for.
|
||||
* - tcb: The TCB of new CPU IDLE task
|
||||
* - stack_size: The requested stack size for the IDLE task. At least
|
||||
* this much must be allocated. This should be
|
||||
* CONFIG_IDLETHREAD_STACKSIZE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_cpu_idlestack(int cpu, struct tcb_s *tcb, size_t stack_size)
|
||||
{
|
||||
/* XTENSA uses a push-down stack: the stack grows toward lower* addresses
|
||||
* in memory. The stack pointer register points to the lowest, valid
|
||||
* working address (the "top" of the stack). Items on the stack are
|
||||
* referenced as positive word offsets from sp.
|
||||
*/
|
||||
|
||||
/* Save information about pre-allocated IDLE thread stack */
|
||||
|
||||
tcb->stack_alloc_ptr = g_cpu1_idlestack;
|
||||
tcb->adj_stack_size = CPU1_IDLETHREAD_STACKSIZE;
|
||||
tcb->stack_base_ptr = tcb->stack_alloc_ptr;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SMP */
|
||||
64
arch/xtensa/src/esp32s3/esp32s3_cpuindex.S
Normal file
64
arch/xtensa/src/esp32s3/esp32s3_cpuindex.S
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/****************************************************************************
|
||||
* arch/xtensa/src/esp32s3/esp32s3_cpuindex.S
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
.file "esp32s3_cpuindex.S"
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <arch/xtensa/xtensa_abi.h>
|
||||
#include "chip_macros.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_cpu_index
|
||||
*
|
||||
* Description:
|
||||
* Return an index in the range of 0 through (CONFIG_SMP_NCPUS-1) that
|
||||
* corresponds to the currently executing CPU.
|
||||
*
|
||||
* If TLS is enabled, then the RTOS can get this information from the TLS
|
||||
* info structure. Otherwise, the MCU-specific logic must provide some
|
||||
* mechanism to provide the CPU index.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* An integer index in the range of 0 through (CONFIG_SMP_NCPUS-1) that
|
||||
* corresponds to the currently executing CPU.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
.text
|
||||
.align 4
|
||||
.global up_cpu_index
|
||||
.type up_cpu_index, @function
|
||||
|
||||
up_cpu_index:
|
||||
ENTRY(16)
|
||||
getcoreid a2
|
||||
RET(16)
|
||||
|
||||
.size up_cpu_index, . - up_cpu_index
|
||||
286
arch/xtensa/src/esp32s3/esp32s3_cpustart.c
Normal file
286
arch/xtensa/src/esp32s3/esp32s3_cpustart.c
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
/****************************************************************************
|
||||
* arch/xtensa/src/esp32s3/esp32s3_cpustart.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/sched.h>
|
||||
#include <nuttx/sched_note.h>
|
||||
#include <nuttx/spinlock.h>
|
||||
#include <sched/sched.h>
|
||||
|
||||
#include "xtensa.h"
|
||||
#include "esp32s3_irq.h"
|
||||
#include "esp32s3_region.h"
|
||||
#include "esp32s3_smp.h"
|
||||
#include "hardware/esp32s3_rtccntl.h"
|
||||
#include "hardware/esp32s3_system.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static volatile bool g_appcpu_started;
|
||||
static volatile spinlock_t g_appcpu_interlock;
|
||||
|
||||
/****************************************************************************
|
||||
* ROM function prototypes
|
||||
****************************************************************************/
|
||||
|
||||
extern void ets_set_appcpu_boot_addr(uint32_t start);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: xtensa_attach_fromcpu0_interrupt
|
||||
****************************************************************************/
|
||||
|
||||
static inline void xtensa_attach_fromcpu0_interrupt(void)
|
||||
{
|
||||
int cpuint;
|
||||
|
||||
/* Connect all CPU peripheral source to allocated CPU interrupt */
|
||||
|
||||
cpuint = esp32s3_setup_irq(1, ESP32S3_PERIPH_INT_FROM_CPU0, 1,
|
||||
ESP32S3_CPUINT_LEVEL);
|
||||
DEBUGASSERT(cpuint >= 0);
|
||||
|
||||
/* Attach the inter-CPU interrupt. */
|
||||
|
||||
irq_attach(ESP32S3_IRQ_INT_FROM_CPU0, (xcpt_t)esp32s3_fromcpu0_interrupt,
|
||||
NULL);
|
||||
|
||||
/* Enable the inter 0 CPU interrupts. */
|
||||
|
||||
up_enable_irq(ESP32S3_IRQ_INT_FROM_CPU0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: xtensa_appcpu_start
|
||||
*
|
||||
* Description:
|
||||
* This is the entry point used for the APP CPU when it's started via
|
||||
* up_cpu_start(). The actual start-up logic is in ROM and we boot up
|
||||
* in C code.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* None, does not return
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void xtensa_appcpu_start(void)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
register uint32_t sp;
|
||||
|
||||
#ifdef CONFIG_STACK_COLORATION
|
||||
{
|
||||
register uint32_t *ptr;
|
||||
register int i;
|
||||
|
||||
/* If stack debug is enabled, then fill the stack with a recognizable
|
||||
* value that we can use later to test for high water marks.
|
||||
*/
|
||||
|
||||
for (i = 0, ptr = (uint32_t *)tcb->stack_alloc_ptr;
|
||||
i < tcb->adj_stack_size;
|
||||
i += sizeof(uint32_t))
|
||||
{
|
||||
*ptr++ = STACK_COLOR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Move to the stack assigned to us by up_smp_start immediately. Although
|
||||
* we were give a stack pointer at start-up, we don't know where that stack
|
||||
* pointer is positioned respect to our memory map. The only safe option
|
||||
* is to switch to a well-known IDLE thread stack.
|
||||
*/
|
||||
|
||||
sp = (uint32_t)tcb->stack_base_ptr + tcb->adj_stack_size;
|
||||
__asm__ __volatile__("mov sp, %0\n" : : "r"(sp));
|
||||
|
||||
sinfo("CPU%d Started\n", up_cpu_index());
|
||||
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION
|
||||
/* Notify that this CPU has started */
|
||||
|
||||
sched_note_cpu_started(tcb);
|
||||
#endif
|
||||
|
||||
/* Release the spinlock to signal to the PRO CPU that the APP CPU has
|
||||
* started.
|
||||
*/
|
||||
|
||||
g_appcpu_started = true;
|
||||
spin_unlock(&g_appcpu_interlock);
|
||||
|
||||
/* Reset scheduler parameters */
|
||||
|
||||
nxsched_resume_scheduler(tcb);
|
||||
|
||||
/* Move CPU0 exception vectors to IRAM */
|
||||
|
||||
__asm__ __volatile__ ("wsr %0, vecbase\n"::"r" (&_init_start));
|
||||
|
||||
/* Make page 0 access raise an exception */
|
||||
|
||||
esp32s3_region_protection();
|
||||
|
||||
/* Initialize CPU interrupts */
|
||||
|
||||
esp32s3_cpuint_initialize();
|
||||
|
||||
/* Attach and enable the inter-CPU interrupt */
|
||||
|
||||
xtensa_attach_fromcpu0_interrupt();
|
||||
|
||||
/* Enable the software interrupt */
|
||||
|
||||
up_enable_irq(XTENSA_IRQ_SWINT);
|
||||
|
||||
#ifndef CONFIG_SUPPRESS_INTERRUPTS
|
||||
/* And Enable interrupts */
|
||||
|
||||
up_irq_enable();
|
||||
#endif
|
||||
|
||||
/* Then switch contexts. This instantiates the exception context of the
|
||||
* tcb at the head of the assigned task list. In this case, this should
|
||||
* be the CPUs NULL task.
|
||||
*/
|
||||
|
||||
xtensa_context_restore(tcb->xcp.regs);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_cpu_start
|
||||
*
|
||||
* Description:
|
||||
* In an SMP configuration, only one CPU is initially active (CPU 0).
|
||||
* System initialization occurs on that single thread. At the completion of
|
||||
* the initialization of the OS, just before beginning normal multitasking,
|
||||
* the additional CPUs would be started by calling this function.
|
||||
*
|
||||
* Each CPU is provided the entry point to its IDLE task when started. A
|
||||
* TCB for each CPU's IDLE task has been initialized and placed in the
|
||||
* CPU's g_assignedtasks[cpu] list. No stack has been allocated or
|
||||
* initialized.
|
||||
*
|
||||
* The OS initialization logic calls this function repeatedly until each
|
||||
* CPU has been started, 1 through (CONFIG_SMP_NCPUS-1).
|
||||
*
|
||||
* Input Parameters:
|
||||
* cpu - The index of the CPU being started. This will be a numeric
|
||||
* value in the range of one to (CONFIG_SMP_NCPUS-1).
|
||||
* (CPU 0 is already active)
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_cpu_start(int cpu)
|
||||
{
|
||||
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu());
|
||||
|
||||
if (!g_appcpu_started)
|
||||
{
|
||||
uint32_t regval;
|
||||
|
||||
/* Start CPU1 */
|
||||
|
||||
sinfo("Starting CPU%d\n", cpu);
|
||||
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION
|
||||
/* Notify of the start event */
|
||||
|
||||
sched_note_cpu_start(this_task(), cpu);
|
||||
#endif
|
||||
|
||||
/* This spinlock will be used as a handshake between the two CPUs.
|
||||
* It's first initialized to its locked state, later the PRO CPU will
|
||||
* try to lock it but spins until the APP CPU starts and unlocks it.
|
||||
*/
|
||||
|
||||
spin_initialize(&g_appcpu_interlock, SP_LOCKED);
|
||||
|
||||
/* Unstall the APP CPU */
|
||||
|
||||
regval = getreg32(RTC_CNTL_RTC_SW_CPU_STALL_REG);
|
||||
regval &= ~RTC_CNTL_SW_STALL_APPCPU_C1_M;
|
||||
putreg32(regval, RTC_CNTL_RTC_SW_CPU_STALL_REG);
|
||||
|
||||
regval = getreg32(RTC_CNTL_RTC_OPTIONS0_REG);
|
||||
regval &= ~RTC_CNTL_SW_STALL_APPCPU_C0_M;
|
||||
putreg32(regval, RTC_CNTL_RTC_OPTIONS0_REG);
|
||||
|
||||
/* Enable clock gating for the APP CPU */
|
||||
|
||||
regval = getreg32(SYSTEM_CORE_1_CONTROL_0_REG);
|
||||
regval |= SYSTEM_CONTROL_CORE_1_CLKGATE_EN;
|
||||
putreg32(regval, SYSTEM_CORE_1_CONTROL_0_REG);
|
||||
|
||||
regval = getreg32(SYSTEM_CORE_1_CONTROL_0_REG);
|
||||
regval &= ~SYSTEM_CONTROL_CORE_1_RUNSTALL;
|
||||
putreg32(regval, SYSTEM_CORE_1_CONTROL_0_REG);
|
||||
|
||||
/* Reset the APP CPU */
|
||||
|
||||
regval = getreg32(SYSTEM_CORE_1_CONTROL_0_REG);
|
||||
regval |= SYSTEM_CONTROL_CORE_1_RESETING;
|
||||
putreg32(regval, SYSTEM_CORE_1_CONTROL_0_REG);
|
||||
|
||||
regval = getreg32(SYSTEM_CORE_1_CONTROL_0_REG);
|
||||
regval &= ~SYSTEM_CONTROL_CORE_1_RESETING;
|
||||
putreg32(regval, SYSTEM_CORE_1_CONTROL_0_REG);
|
||||
|
||||
/* Set the CPU1 start address */
|
||||
|
||||
ets_set_appcpu_boot_addr((uint32_t)xtensa_appcpu_start);
|
||||
|
||||
/* And wait until the APP CPU starts and releases the spinlock. */
|
||||
|
||||
spin_lock(&g_appcpu_interlock);
|
||||
DEBUGASSERT(g_appcpu_started);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
|
@ -34,9 +34,10 @@
|
|||
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/clock.h>
|
||||
#include <nuttx/spinlock.h>
|
||||
|
||||
#include "esp32s3_freerun.h"
|
||||
#include "esp32s3_clockconfig.h"
|
||||
#include "esp32s3_freerun.h"
|
||||
#include "esp32s3_gpio.h"
|
||||
|
||||
#ifdef CONFIG_ESP32S3_FREERUN
|
||||
|
|
@ -59,6 +60,12 @@
|
|||
|
||||
#define TIMER_WIDTH 54 /* ESP32-S3 timer has 54-bit counter */
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static spinlock_t g_lock; /* Device specific lock */
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
|
@ -209,9 +216,9 @@ int esp32s3_freerun_initialize(struct esp32s3_freerun_s *freerun, int chan,
|
|||
/* Register the handler */
|
||||
|
||||
{
|
||||
irqstate_t flags = enter_critical_section();
|
||||
irqstate_t flags = spin_lock_irqsave(&g_lock);
|
||||
ret = ESP32S3_TIM_SETISR(freerun->tch, freerun_handler, freerun);
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&g_lock, flags);
|
||||
}
|
||||
|
||||
if (ret == OK)
|
||||
|
|
@ -266,7 +273,7 @@ int esp32s3_freerun_counter(struct esp32s3_freerun_s *freerun,
|
|||
|
||||
/* Temporarily disable the overflow counter. */
|
||||
|
||||
flags = enter_critical_section();
|
||||
flags = spin_lock_irqsave(&g_lock);
|
||||
|
||||
overflow = freerun->overflow;
|
||||
ESP32S3_TIM_GETCTR(freerun->tch, &counter);
|
||||
|
|
@ -293,7 +300,7 @@ int esp32s3_freerun_counter(struct esp32s3_freerun_s *freerun,
|
|||
freerun->overflow = overflow;
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&g_lock, flags);
|
||||
|
||||
tmrinfo("counter=%" PRIu64 " (%" PRIu64 ") overflow=%" PRIu32
|
||||
", pending=%i\n",
|
||||
|
|
|
|||
127
arch/xtensa/src/esp32s3/esp32s3_intercpu_interrupt.c
Normal file
127
arch/xtensa/src/esp32s3/esp32s3_intercpu_interrupt.c
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/****************************************************************************
|
||||
* arch/xtensa/src/esp32s3/esp32s3_intercpu_interrupt.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/spinlock.h>
|
||||
|
||||
#include "xtensa.h"
|
||||
#include "hardware/esp32s3_system.h"
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_fromcpu_interrupt
|
||||
*
|
||||
* Description:
|
||||
* Common logic called to handle the from CPU0/1 interrupts.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int IRAM_ATTR esp32s3_fromcpu_interrupt(int fromcpu)
|
||||
{
|
||||
uintptr_t regaddr;
|
||||
|
||||
DEBUGASSERT((unsigned)fromcpu < CONFIG_SMP_NCPUS);
|
||||
DEBUGASSERT(fromcpu != up_cpu_index());
|
||||
|
||||
/* Clear the interrupt from the other CPU */
|
||||
|
||||
regaddr = (fromcpu == 0) ? SYSTEM_CPU_INTR_FROM_CPU_0_REG :
|
||||
SYSTEM_CPU_INTR_FROM_CPU_1_REG;
|
||||
putreg32(0, regaddr);
|
||||
|
||||
/* Call pause handler */
|
||||
|
||||
xtensa_pause_handler();
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_fromcpu[0,1]_interrupt
|
||||
*
|
||||
* Description:
|
||||
* Called to handle the from CPU0/1 interrupts.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int IRAM_ATTR esp32s3_fromcpu0_interrupt(int irq, void *context, void *arg)
|
||||
{
|
||||
return esp32s3_fromcpu_interrupt(0);
|
||||
}
|
||||
|
||||
int IRAM_ATTR esp32s3_fromcpu1_interrupt(int irq, void *context, void *arg)
|
||||
{
|
||||
return esp32s3_fromcpu_interrupt(1);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: xtensa_intercpu_interrupt
|
||||
*
|
||||
* Description:
|
||||
* Called to trigger a CPU interrupt
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int IRAM_ATTR xtensa_intercpu_interrupt(int tocpu, int intcode)
|
||||
{
|
||||
int fromcpu;
|
||||
|
||||
DEBUGASSERT((unsigned)tocpu < CONFIG_SMP_NCPUS &&
|
||||
(unsigned)intcode <= UINT8_MAX);
|
||||
|
||||
fromcpu = up_cpu_index();
|
||||
DEBUGASSERT(fromcpu != tocpu);
|
||||
|
||||
/* Generate an Inter-Processor Interrupt */
|
||||
|
||||
if (fromcpu == 0)
|
||||
{
|
||||
putreg32(SYSTEM_CPU_INTR_FROM_CPU_0, SYSTEM_CPU_INTR_FROM_CPU_0_REG);
|
||||
}
|
||||
else
|
||||
{
|
||||
putreg32(SYSTEM_CPU_INTR_FROM_CPU_1, SYSTEM_CPU_INTR_FROM_CPU_1_REG);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SMP */
|
||||
|
|
@ -38,16 +38,27 @@
|
|||
|
||||
#include "xtensa.h"
|
||||
|
||||
#include "esp32s3_irq.h"
|
||||
#ifdef CONFIG_SMP
|
||||
#include "esp32s3_smp.h"
|
||||
#endif
|
||||
#include "hardware/esp32s3_interrupt_core0.h"
|
||||
#ifdef CONFIG_SMP
|
||||
#include "hardware/esp32s3_interrupt_core1.h"
|
||||
#endif
|
||||
#include "hardware/esp32s3_soc.h"
|
||||
#include "hardware/esp32s3_system.h"
|
||||
#include "hardware/esp32s3_interrupt_core0.h"
|
||||
|
||||
#include "esp32s3_irq.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Interrupt stack definitions for SMP */
|
||||
|
||||
#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15
|
||||
# define INTSTACK_ALLOC (CONFIG_SMP_NCPUS * INTSTACK_SIZE)
|
||||
#endif
|
||||
|
||||
/* IRQ to CPU and CPU interrupts mapping:
|
||||
*
|
||||
* Encoding: CIIIIIII
|
||||
|
|
@ -77,6 +88,9 @@
|
|||
/* Mapping Peripheral IDs to map register addresses. */
|
||||
|
||||
#define CORE0_MAP_REGADDR(n) (DR_REG_INTERRUPT_CORE0_BASE + ((n) << 2))
|
||||
#ifdef CONFIG_SMP
|
||||
# define CORE1_MAP_REGADDR(n) (DR_REG_INTERRUPT_CORE1_BASE + ((n) << 2))
|
||||
#endif
|
||||
|
||||
/* CPU interrupts can be detached from any peripheral source by setting the
|
||||
* map register to an internal CPU interrupt (6, 7, 11, 15, 16, or 29).
|
||||
|
|
@ -100,7 +114,29 @@
|
|||
* CURRENT_REGS for portability.
|
||||
*/
|
||||
|
||||
volatile uint32_t *g_current_regs[1];
|
||||
/* For the case of architectures with multiple CPUs, then there must be one
|
||||
* such value for each processor that can receive an interrupt.
|
||||
*/
|
||||
|
||||
volatile uint32_t *g_current_regs[CONFIG_SMP_NCPUS];
|
||||
|
||||
#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15
|
||||
/* In the SMP configuration, we will need custom interrupt stacks.
|
||||
* These definitions provide the aligned stack allocations.
|
||||
*/
|
||||
|
||||
static uint32_t g_intstackalloc[INTSTACK_ALLOC >> 2];
|
||||
|
||||
/* These definitions provide the "top" of the push-down stacks. */
|
||||
|
||||
uintptr_t g_cpu_intstack_top[CONFIG_SMP_NCPUS] =
|
||||
{
|
||||
(uintptr_t)g_intstackalloc + INTSTACK_SIZE,
|
||||
#if CONFIG_SMP_NCPUS > 1
|
||||
(uintptr_t)g_intstackalloc + (2 * INTSTACK_SIZE),
|
||||
#endif /* CONFIG_SMP_NCPUS > 1 */
|
||||
};
|
||||
#endif /* defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15 */
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
|
|
@ -109,6 +145,9 @@ volatile uint32_t *g_current_regs[1];
|
|||
/* Maps a CPU interrupt to the IRQ of the attached peripheral interrupt */
|
||||
|
||||
static uint8_t g_cpu0_intmap[ESP32S3_NCPUINTS];
|
||||
#ifdef CONFIG_SMP
|
||||
static uint8_t g_cpu1_intmap[ESP32S3_NCPUINTS];
|
||||
#endif
|
||||
|
||||
static volatile uint8_t g_irqmap[NR_IRQS];
|
||||
|
||||
|
|
@ -116,13 +155,16 @@ static volatile uint8_t g_irqmap[NR_IRQS];
|
|||
* content.
|
||||
*/
|
||||
|
||||
static uint32_t g_intenable[1];
|
||||
static uint32_t g_intenable[CONFIG_SMP_NCPUS];
|
||||
|
||||
/* Bitsets for free, unallocated CPU interrupts available to peripheral
|
||||
* devices.
|
||||
*/
|
||||
|
||||
static uint32_t g_cpu0_freeints = ESP32S3_CPUINT_PERIPHSET;
|
||||
#ifdef CONFIG_SMP
|
||||
static uint32_t g_cpu1_freeints = ESP32S3_CPUINT_PERIPHSET;
|
||||
#endif
|
||||
|
||||
/* Bitsets for each interrupt priority 1-5 */
|
||||
|
||||
|
|
@ -139,6 +181,32 @@ static const uint32_t g_priority[5] =
|
|||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: xtensa_attach_fromcpu1_interrupt
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static inline void xtensa_attach_fromcpu1_interrupt(void)
|
||||
{
|
||||
int cpuint;
|
||||
|
||||
/* Connect all CPU peripheral source to allocated CPU interrupt */
|
||||
|
||||
cpuint = esp32s3_setup_irq(0, ESP32S3_PERIPH_INT_FROM_CPU1, 1,
|
||||
ESP32S3_CPUINT_LEVEL);
|
||||
DEBUGASSERT(cpuint >= 0);
|
||||
|
||||
/* Attach the inter-CPU interrupt. */
|
||||
|
||||
irq_attach(ESP32S3_IRQ_INT_FROM_CPU1, (xcpt_t)esp32s3_fromcpu1_interrupt,
|
||||
NULL);
|
||||
|
||||
/* Enable the inter-CPU interrupt. */
|
||||
|
||||
up_enable_irq(ESP32S3_IRQ_INT_FROM_CPU1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_intinfo
|
||||
*
|
||||
|
|
@ -151,8 +219,20 @@ static const uint32_t g_priority[5] =
|
|||
static void esp32s3_intinfo(int cpu, int periphid,
|
||||
uintptr_t *regaddr, uint8_t **intmap)
|
||||
{
|
||||
*regaddr = CORE0_MAP_REGADDR(periphid);
|
||||
*intmap = g_cpu0_intmap;
|
||||
#ifdef CONFIG_SMP
|
||||
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS);
|
||||
|
||||
if (cpu != 0)
|
||||
{
|
||||
*regaddr = CORE1_MAP_REGADDR(periphid);
|
||||
*intmap = g_cpu1_intmap;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
*regaddr = CORE0_MAP_REGADDR(periphid);
|
||||
*intmap = g_cpu0_intmap;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -187,7 +267,16 @@ static int esp32s3_getcpuint(uint32_t intmask)
|
|||
*/
|
||||
|
||||
cpu = up_cpu_index();
|
||||
freeints = &g_cpu0_freeints;
|
||||
#ifdef CONFIG_SMP
|
||||
if (cpu != 0)
|
||||
{
|
||||
freeints = &g_cpu1_freeints;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
freeints = &g_cpu0_freeints;
|
||||
}
|
||||
|
||||
intset = *freeints & intmask;
|
||||
if (intset != 0)
|
||||
|
|
@ -308,7 +397,16 @@ static void esp32s3_free_cpuint(int cpuint)
|
|||
|
||||
bitmask = 1ul << cpuint;
|
||||
|
||||
freeints = &g_cpu0_freeints;
|
||||
#ifdef CONFIG_SMP
|
||||
if (up_cpu_index() != 0)
|
||||
{
|
||||
freeints = &g_cpu1_freeints;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
freeints = &g_cpu0_freeints;
|
||||
}
|
||||
|
||||
DEBUGASSERT((*freeints & bitmask) == 0);
|
||||
*freeints |= bitmask;
|
||||
|
|
@ -342,6 +440,12 @@ void up_irqinitialize(void)
|
|||
|
||||
esp32s3_cpuint_initialize();
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* Attach and enable the inter-CPU interrupt */
|
||||
|
||||
xtensa_attach_fromcpu1_interrupt();
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SUPPRESS_INTERRUPTS
|
||||
/* And finally, enable interrupts. Also clears PS.EXCM */
|
||||
|
||||
|
|
@ -378,7 +482,7 @@ void up_disable_irq(int irq)
|
|||
}
|
||||
|
||||
DEBUGASSERT(cpuint >= 0 && cpuint <= ESP32S3_CPUINT_MAX);
|
||||
DEBUGASSERT(cpu == 0);
|
||||
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS);
|
||||
|
||||
if (irq < XTENSA_NIRQ_INTERNAL)
|
||||
{
|
||||
|
|
@ -386,6 +490,16 @@ void up_disable_irq(int irq)
|
|||
* the Interrupt Matrix.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
int me = up_cpu_index();
|
||||
if (me != cpu)
|
||||
{
|
||||
/* It was the other CPU that enabled this interrupt. */
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
xtensa_disable_cpuint(&g_intenable[cpu], 1ul << cpuint);
|
||||
}
|
||||
else
|
||||
|
|
@ -444,7 +558,7 @@ void up_enable_irq(int irq)
|
|||
|
||||
int cpu = IRQ_GETCPU(g_irqmap[irq]);
|
||||
|
||||
DEBUGASSERT(cpu == 0);
|
||||
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS);
|
||||
|
||||
/* For peripheral interrupts, attach the interrupt to the peripheral;
|
||||
* the CPU interrupt was already enabled when allocated.
|
||||
|
|
@ -463,6 +577,36 @@ void up_enable_irq(int irq)
|
|||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: xtensa_intstack_top
|
||||
*
|
||||
* Description:
|
||||
* Return a pointer to the top of the correct interrupt stack for the
|
||||
* given CPU.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15
|
||||
uintptr_t xtensa_intstack_top(void)
|
||||
{
|
||||
return g_cpu_intstack_top[up_cpu_index()];
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: xtensa_intstack_alloc
|
||||
*
|
||||
* Description:
|
||||
* Return a pointer to the "alloc" the correct interrupt stack allocation
|
||||
* for the current CPU.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uintptr_t xtensa_intstack_alloc(void)
|
||||
{
|
||||
return g_cpu_intstack_top[up_cpu_index()] - INTSTACK_SIZE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_cpuint_initialize
|
||||
*
|
||||
|
|
@ -482,8 +626,18 @@ int esp32s3_cpuint_initialize(void)
|
|||
{
|
||||
uintptr_t regaddr;
|
||||
uint8_t *intmap;
|
||||
#ifdef CONFIG_SMP
|
||||
int cpu;
|
||||
#endif
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* Which CPU are we initializing */
|
||||
|
||||
cpu = up_cpu_index();
|
||||
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS);
|
||||
#endif
|
||||
|
||||
/* Disable all CPU interrupts on this CPU */
|
||||
|
||||
xtensa_disable_all();
|
||||
|
|
@ -492,14 +646,32 @@ int esp32s3_cpuint_initialize(void)
|
|||
|
||||
for (i = 0; i < ESP32S3_NPERIPHERALS; i++)
|
||||
{
|
||||
regaddr = CORE0_MAP_REGADDR(i);
|
||||
#ifdef CONFIG_SMP
|
||||
if (cpu != 0)
|
||||
{
|
||||
regaddr = CORE1_MAP_REGADDR(i);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
regaddr = CORE0_MAP_REGADDR(i);
|
||||
}
|
||||
|
||||
putreg32(NO_CPUINT, regaddr);
|
||||
}
|
||||
|
||||
/* Initialize CPU interrupt-to-IRQ mapping table */
|
||||
|
||||
intmap = g_cpu0_intmap;
|
||||
#ifdef CONFIG_SMP
|
||||
if (cpu != 0)
|
||||
{
|
||||
intmap = g_cpu1_intmap;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
intmap = g_cpu0_intmap;
|
||||
}
|
||||
|
||||
/* Indicate that no peripheral interrupts are assigned to CPU interrupts */
|
||||
|
||||
|
|
@ -665,12 +837,27 @@ uint32_t *xtensa_int_decode(uint32_t cpuints, uint32_t *regs)
|
|||
uint8_t *intmap;
|
||||
uint32_t mask;
|
||||
int bit;
|
||||
#ifdef CONFIG_SMP
|
||||
int cpu;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_LEDS_CPU_ACTIVITY
|
||||
board_autoled_on(LED_CPU);
|
||||
#endif
|
||||
|
||||
intmap = g_cpu0_intmap;
|
||||
#ifdef CONFIG_SMP
|
||||
/* Select PRO or APP CPU interrupt mapping table */
|
||||
|
||||
cpu = up_cpu_index();
|
||||
if (cpu != 0)
|
||||
{
|
||||
intmap = g_cpu1_intmap;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
intmap = g_cpu0_intmap;
|
||||
}
|
||||
|
||||
/* Skip over zero bits, eight at a time */
|
||||
|
||||
|
|
|
|||
|
|
@ -676,12 +676,12 @@ void esp32s3_lowputc_rst_rxfifo(const struct esp32s3_uart_s *priv)
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
void esp32s3_lowputc_disable_all_uart_int(const struct esp32s3_uart_s *priv,
|
||||
void esp32s3_lowputc_disable_all_uart_int(struct esp32s3_uart_s *priv,
|
||||
uint32_t *current_status)
|
||||
{
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
flags = spin_lock_irqsave(&priv->lock);
|
||||
|
||||
if (current_status != NULL)
|
||||
{
|
||||
|
|
@ -698,7 +698,7 @@ void esp32s3_lowputc_disable_all_uart_int(const struct esp32s3_uart_s *priv,
|
|||
|
||||
putreg32(0xffffffff, UART_INT_CLR_REG(priv->id));
|
||||
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
|||
|
|
@ -26,24 +26,24 @@
|
|||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/irq.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
#include <nuttx/spinlock.h>
|
||||
|
||||
#include "chip.h"
|
||||
|
||||
#include "esp32s3_irq.h"
|
||||
#include "hardware/esp32s3_uart.h"
|
||||
#include "hardware/esp32s3_gpio_sigmap.h"
|
||||
|
||||
#include "esp32s3_irq.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
|
@ -116,6 +116,7 @@ struct esp32s3_uart_s
|
|||
uint8_t ctssig; /* CTS signal */
|
||||
bool oflow; /* Output flow control (CTS) enabled */
|
||||
#endif
|
||||
spinlock_t lock; /* Device-specific lock */
|
||||
};
|
||||
|
||||
extern struct esp32s3_uart_s g_uart0_config;
|
||||
|
|
@ -424,7 +425,7 @@ void esp32s3_lowputc_rst_rxfifo(const struct esp32s3_uart_s *priv);
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
void esp32s3_lowputc_disable_all_uart_int(const struct esp32s3_uart_s *priv,
|
||||
void esp32s3_lowputc_disable_all_uart_int(struct esp32s3_uart_s *priv,
|
||||
uint32_t *current_status);
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
|||
|
|
@ -24,17 +24,18 @@
|
|||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/timers/oneshot.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/spinlock.h>
|
||||
#include <nuttx/timers/oneshot.h>
|
||||
|
||||
#include "esp32s3_oneshot.h"
|
||||
|
||||
|
|
@ -58,7 +59,8 @@ struct esp32s3_oneshot_lowerhalf_s
|
|||
struct esp32s3_oneshot_s oneshot; /* ESP32-S3-specific oneshot state */
|
||||
oneshot_callback_t callback; /* Upper-half Interrupt callback */
|
||||
void *arg; /* Argument passed to handler */
|
||||
uint16_t resolution;
|
||||
uint16_t resolution; /* Timer's resolution in microseconds */
|
||||
spinlock_t lock; /* Device-specific lock */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -210,12 +212,12 @@ static int oneshot_lh_start(struct oneshot_lowerhalf_s *lower,
|
|||
|
||||
/* Save the callback information and start the timer */
|
||||
|
||||
flags = enter_critical_section();
|
||||
flags = spin_lock_irqsave(&priv->lock);
|
||||
priv->callback = callback;
|
||||
priv->arg = arg;
|
||||
ret = esp32s3_oneshot_start(&priv->oneshot, oneshot_lh_handler,
|
||||
priv, ts);
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
|
|
@ -261,11 +263,11 @@ static int oneshot_lh_cancel(struct oneshot_lowerhalf_s *lower,
|
|||
|
||||
/* Cancel the timer */
|
||||
|
||||
flags = enter_critical_section();
|
||||
flags = spin_lock_irqsave(&priv->lock);
|
||||
ret = esp32s3_oneshot_cancel(&priv->oneshot, ts);
|
||||
priv->callback = NULL;
|
||||
priv->arg = NULL;
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -533,6 +533,7 @@ static void esp32s3_txint(struct uart_dev_s *dev, bool enable)
|
|||
{
|
||||
struct esp32s3_uart_s *priv = dev->priv;
|
||||
uint32_t ints_mask = UART_TXFIFO_EMPTY_INT_ENA_M | UART_TX_DONE_INT_ENA_M;
|
||||
irqstate_t flags = spin_lock_irqsave(&priv->lock);
|
||||
|
||||
if (enable)
|
||||
{
|
||||
|
|
@ -550,6 +551,8 @@ static void esp32s3_txint(struct uart_dev_s *dev, bool enable)
|
|||
|
||||
modifyreg32(UART_INT_ENA_REG(priv->id), ints_mask, 0);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -569,6 +572,7 @@ static void esp32s3_rxint(struct uart_dev_s *dev, bool enable)
|
|||
struct esp32s3_uart_s *priv = dev->priv;
|
||||
uint32_t ints_mask = UART_RXFIFO_TOUT_INT_ENA_M |
|
||||
UART_RXFIFO_FULL_INT_ENA_M;
|
||||
irqstate_t flags = spin_lock_irqsave(&priv->lock);
|
||||
|
||||
if (enable)
|
||||
{
|
||||
|
|
@ -590,6 +594,8 @@ static void esp32s3_rxint(struct uart_dev_s *dev, bool enable)
|
|||
|
||||
modifyreg32(UART_INT_ENA_REG(priv->id), ints_mask, 0);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
|||
71
arch/xtensa/src/esp32s3/esp32s3_smp.h
Normal file
71
arch/xtensa/src/esp32s3/esp32s3_smp.h
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/****************************************************************************
|
||||
* arch/xtensa/src/esp32s3/esp32s3_smp.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_SMP_H
|
||||
#define __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_SMP_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-procesor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* An IDLE thread stack size for CPU0 must be defined */
|
||||
|
||||
#if !defined(CONFIG_IDLETHREAD_STACKSIZE)
|
||||
# error CONFIG_IDLETHREAD_STACKSIZE is not defined
|
||||
#elif CONFIG_IDLETHREAD_STACKSIZE < 16
|
||||
# error CONFIG_IDLETHREAD_STACKSIZE is to small
|
||||
#endif
|
||||
|
||||
#define CPU1_IDLETHREAD_STACKSIZE ((CONFIG_IDLETHREAD_STACKSIZE + 15) & ~15)
|
||||
#define CPU1_IDLETHREAD_STACKWORDS (CPU1_IDLETHREAD_STACKSIZE >> 2)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/* This is the CPU1 IDLE stack */
|
||||
|
||||
extern uint32_t g_cpu1_idlestack[CPU1_IDLETHREAD_STACKWORDS];
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_fromcpu[0,1]_interrupt
|
||||
*
|
||||
* Description:
|
||||
* Called to handle the from CPU0/1 interrupts.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int esp32s3_fromcpu0_interrupt(int irq, void *context, void *arg);
|
||||
int esp32s3_fromcpu1_interrupt(int irq, void *context, void *arg);
|
||||
|
||||
#endif /* CONFIG_SMP */
|
||||
#endif /* __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_SMP_H */
|
||||
|
|
@ -34,6 +34,7 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/spinlock.h>
|
||||
#include <nuttx/timers/timer.h>
|
||||
|
||||
#include "hardware/esp32s3_soc.h"
|
||||
|
|
@ -62,6 +63,7 @@ struct esp32s3_timer_lowerhalf_s
|
|||
void *arg; /* Argument passed to upper half callback */
|
||||
bool started; /* True: Timer has been started */
|
||||
void *upper; /* Pointer to watchdog_upperhalf_s */
|
||||
spinlock_t lock; /* Device-specific lock */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -250,9 +252,9 @@ static int timer_lh_start(struct timer_lowerhalf_s *lower)
|
|||
|
||||
if (priv->callback != NULL)
|
||||
{
|
||||
irqstate_t flags = enter_critical_section();
|
||||
irqstate_t flags = spin_lock_irqsave(&priv->lock);
|
||||
ret = ESP32S3_TIM_SETISR(priv->tim, timer_lh_handler, priv);
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
if (ret != OK)
|
||||
{
|
||||
|
|
@ -305,9 +307,9 @@ static int timer_lh_stop(struct timer_lowerhalf_s *lower)
|
|||
|
||||
ESP32S3_TIM_DISABLEINT(priv->tim);
|
||||
|
||||
flags = enter_critical_section();
|
||||
flags = spin_lock_irqsave(&priv->lock);
|
||||
ret = ESP32S3_TIM_SETISR(priv->tim, NULL, NULL);
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
ESP32S3_TIM_STOP(priv->tim);
|
||||
|
||||
|
|
@ -473,7 +475,7 @@ static void timer_lh_setcallback(struct timer_lowerhalf_s *lower,
|
|||
priv->callback = callback;
|
||||
priv->arg = arg;
|
||||
|
||||
flags = enter_critical_section();
|
||||
flags = spin_lock_irqsave(&priv->lock);
|
||||
|
||||
/* There is a user callback and the timer has already been started */
|
||||
|
||||
|
|
@ -488,7 +490,7 @@ static void timer_lh_setcallback(struct timer_lowerhalf_s *lower,
|
|||
ret = ESP32S3_TIM_SETISR(priv->tim, NULL, NULL);
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
if (ret != OK)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -24,22 +24,22 @@
|
|||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/clock.h>
|
||||
#include <nuttx/spinlock.h>
|
||||
#include <nuttx/timers/watchdog.h>
|
||||
|
||||
#include "xtensa.h"
|
||||
#include "hardware/esp32s3_soc.h"
|
||||
|
||||
#include "esp32s3_wdt.h"
|
||||
#include "esp32s3_wdt_lowerhalf.h"
|
||||
#include "hardware/esp32s3_soc.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
|
|
@ -94,6 +94,7 @@ struct esp32s3_wdt_lowerhalf_s
|
|||
bool started; /* True: Timer has been started */
|
||||
xcpt_t handler; /* User Handler */
|
||||
void *upper; /* Pointer to watchdog_upperhalf_s */
|
||||
spinlock_t lock; /* Device-specific lock */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -236,16 +237,16 @@ static int wdt_lh_start(struct watchdog_lowerhalf_s *lower)
|
|||
|
||||
/* Set the lower-half handler and enable interrupt */
|
||||
|
||||
flags = enter_critical_section();
|
||||
flags = spin_lock_irqsave(&priv->lock);
|
||||
ESP32S3_WDT_SETISR(priv->wdt, wdt_handler, priv);
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
ESP32S3_WDT_ENABLEINT(priv->wdt);
|
||||
}
|
||||
|
||||
flags = enter_critical_section();
|
||||
flags = spin_lock_irqsave(&priv->lock);
|
||||
priv->lastreset = clock_systime_ticks();
|
||||
ESP32S3_WDT_START(priv->wdt);
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
/* Lock it again */
|
||||
|
||||
|
|
@ -290,9 +291,9 @@ static int wdt_lh_stop(struct watchdog_lowerhalf_s *lower)
|
|||
|
||||
ESP32S3_WDT_DISABLEINT(priv->wdt);
|
||||
|
||||
flags = enter_critical_section();
|
||||
flags = spin_lock_irqsave(&priv->lock);
|
||||
ESP32S3_WDT_SETISR(priv->wdt, NULL, NULL);
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
/* Lock it again */
|
||||
|
|
@ -333,10 +334,10 @@ static int wdt_lh_keepalive(struct watchdog_lowerhalf_s *lower)
|
|||
|
||||
/* Feed the dog and updates the lastreset variable */
|
||||
|
||||
flags = enter_critical_section();
|
||||
flags = spin_lock_irqsave(&priv->lock);
|
||||
priv->lastreset = clock_systime_ticks();
|
||||
ESP32S3_WDT_FEED(priv->wdt);
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
/* Lock */
|
||||
|
||||
|
|
@ -540,7 +541,7 @@ static xcpt_t wdt_lh_capture(struct watchdog_lowerhalf_s *lower,
|
|||
|
||||
ESP32S3_WDT_UNLOCK(priv->wdt);
|
||||
|
||||
flags = enter_critical_section();
|
||||
flags = spin_lock_irqsave(&priv->lock);
|
||||
|
||||
/* Save the new user handler */
|
||||
|
||||
|
|
@ -598,7 +599,7 @@ static xcpt_t wdt_lh_capture(struct watchdog_lowerhalf_s *lower,
|
|||
}
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
ESP32S3_WDT_LOCK(priv->wdt);
|
||||
return oldhandler;
|
||||
}
|
||||
|
|
|
|||
54
boards/xtensa/esp32s3/esp32s3-devkit/configs/smp/defconfig
Normal file
54
boards/xtensa/esp32s3/esp32s3-devkit/configs/smp/defconfig
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
#
|
||||
# This file is autogenerated: PLEASE DO NOT EDIT IT.
|
||||
#
|
||||
# You can use "make menuconfig" to make any modifications to the installed .config file.
|
||||
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
|
||||
# modifications.
|
||||
#
|
||||
# CONFIG_ARCH_LEDS is not set
|
||||
# CONFIG_NSH_ARGCAT is not set
|
||||
# CONFIG_NSH_CMDOPT_HEXDUMP is not set
|
||||
# CONFIG_NSH_CMDPARMS is not set
|
||||
CONFIG_ARCH="xtensa"
|
||||
CONFIG_ARCH_BOARD="esp32s3-devkit"
|
||||
CONFIG_ARCH_BOARD_ESP32S3_DEVKIT=y
|
||||
CONFIG_ARCH_CHIP="esp32s3"
|
||||
CONFIG_ARCH_CHIP_ESP32S3=y
|
||||
CONFIG_ARCH_CHIP_ESP32S3WROOM1=y
|
||||
CONFIG_ARCH_INTERRUPTSTACK=2048
|
||||
CONFIG_ARCH_STACKDUMP=y
|
||||
CONFIG_ARCH_XTENSA=y
|
||||
CONFIG_BOARD_LOOPSPERMSEC=16717
|
||||
CONFIG_BUILTIN=y
|
||||
CONFIG_DEBUG_FULLOPT=y
|
||||
CONFIG_DEBUG_SYMBOLS=y
|
||||
CONFIG_ESP32S3_UART0=y
|
||||
CONFIG_FS_PROCFS=y
|
||||
CONFIG_HAVE_CXX=y
|
||||
CONFIG_HAVE_CXXINITIALIZE=y
|
||||
CONFIG_IDLETHREAD_STACKSIZE=3072
|
||||
CONFIG_INIT_ENTRYPOINT="nsh_main"
|
||||
CONFIG_INIT_STACKSIZE=3072
|
||||
CONFIG_INTELHEX_BINARY=y
|
||||
CONFIG_NSH_ARCHINIT=y
|
||||
CONFIG_NSH_BUILTIN_APPS=y
|
||||
CONFIG_NSH_FILEIOSIZE=512
|
||||
CONFIG_NSH_LINELEN=64
|
||||
CONFIG_NSH_READLINE=y
|
||||
CONFIG_PREALLOC_TIMERS=4
|
||||
CONFIG_RAM_SIZE=114688
|
||||
CONFIG_RAM_START=0x20000000
|
||||
CONFIG_RAW_BINARY=y
|
||||
CONFIG_RR_INTERVAL=200
|
||||
CONFIG_SCHED_WAITPID=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_SMP_NCPUS=2
|
||||
CONFIG_STACK_COLORATION=y
|
||||
CONFIG_START_DAY=8
|
||||
CONFIG_START_MONTH=3
|
||||
CONFIG_START_YEAR=2022
|
||||
CONFIG_SYSTEM_NSH=y
|
||||
CONFIG_TESTING_GETPRIME=y
|
||||
CONFIG_TESTING_OSTEST=y
|
||||
CONFIG_TESTING_SMP=y
|
||||
CONFIG_UART0_SERIAL_CONSOLE=y
|
||||
Loading…
Add table
Reference in a new issue