blob: 658789489f58fbb7853b2f9a8c110c0339374a4f [file] [log] [blame]
/****************************************************************************
* arch/xtensa/src/esp32s3/chip_macros.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_CHIP_MACROS_H
#define __ARCH_XTENSA_SRC_ESP32S3_CHIP_MACROS_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#ifndef __ASSEMBLY__
#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15
#include <stdint.h>
#endif
#endif
#if defined(CONFIG_ESP32S3_WCL) && defined(CONFIG_BUILD_PROTECTED)
#include "hardware/esp32s3_wcl_core.h"
#endif
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* This is the name of the section containing the Xtensa low level handlers
* that is used by the board linker scripts.
*/
#define HANDLER_SECTION .iram1
#if defined(CONFIG_ESP32S3_WCL) && defined(CONFIG_BUILD_PROTECTED)
/* Definitions for the Worlds reserved for Kernel and Userspace */
#define WCL_WORLD_KERNEL 0 /* Privileged */
#define WCL_WORLD_USER 1 /* Non-privileged */
/* Macros for privilege handling with the World Controller peripheral */
#define xtensa_saveprivilege(regs,var) ((var) = (regs)[REG_INT_CTX])
#define xtensa_restoreprivilege(regs,var) ((regs)[REG_INT_CTX] = (var))
#define xtensa_lowerprivilege(regs) ((regs)[REG_INT_CTX] = WCL_WORLD_USER)
#define xtensa_raiseprivilege(regs) ((regs)[REG_INT_CTX] = WCL_WORLD_KERNEL)
#endif
/****************************************************************************
* 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
****************************************************************************/
#ifdef __ASSEMBLY__
/* Macro to get the current core ID. Only uses the reg given as an argument.
* 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
extui \reg,\reg,13,1
.endm
/****************************************************************************
* 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
/****************************************************************************
* Name: clear_wcl_write_buffer
*
* Description:
* Clear World Controller write buffer upon World 0 entry.
*
* Entry Conditions:
* tmp - Temporary register
*
****************************************************************************/
.macro clear_wcl_write_buffer tmp
/* Refer to ESP32-S3 Technical Reference Manual, section 16.4.3, for a
* detailed description of the write buffer clearing process.
*/
wsr a2, DEPC
movi \tmp, SOC_RTC_DATA_LOW
movi a2, 0
s32i a2, \tmp, 0
addi a2, a2, 1
s32i a2, \tmp, 0
addi a2, a2, 1
s32i a2, \tmp, 0
addi a2, a2, 1
s32i a2, \tmp, 0
addi a2, a2, 1
s32i a2, \tmp, 0
addi a2, a2, 1
s32i a2, \tmp, 0
addi a2, a2, 1
s32i a2, \tmp, 0
l32i \tmp, \tmp, 0
memw
rsr a2, DEPC
.endm
/****************************************************************************
* Name: get_prev_world
*
* Description:
* Retrieve World information from interruptee.
*
* Entry Conditions:
* level - Interrupt level
* out - Temporary and output register
*
* Exit Conditions:
* World number to be returned will be written to "out" register.
*
****************************************************************************/
.macro get_prev_world level out
.ifeq (\level - 1) * (\level - 3)
.ifeq (\level - 1)
movi \out, WCL_CORE_0_STATUSTABLE1_REG
.endif
.ifeq (\level - 3)
movi \out, WCL_CORE_0_STATUSTABLE2_REG
.endif
l32i \out, \out, 0
extui \out, \out, 0, 1
.endif
.endm
/****************************************************************************
* Name: set_next_world
*
* Description:
* Configure the World Controller for the new execution context.
*
* Entry Conditions:
* reg_sp - Stack pointer
* tmp1 - Temporary register 1
* tmp2 - Temporary register 2
*
****************************************************************************/
.macro set_next_world reg_sp tmp1 tmp2
movi \tmp1, BIT(1)
movi \tmp2, WCL_CORE_0_WORLD_PREPARE_REG
s32i \tmp1, \tmp2, 0 /* Prepare execution on World 1 */
l32i \tmp1, \reg_sp, (4 * REG_PC)
movi \tmp2, WCL_CORE_0_WORLD_TRIGGER_ADDR_REG
s32i \tmp1, \tmp2, 0
movi \tmp1, BIT(0)
movi \tmp2, WCL_CORE_0_WORLD_UPDATE_REG
s32i \tmp1, \tmp2, 0
.endm
/****************************************************************************
* Name: exception_entry_hook
*
* Description:
* Perform chip-specific exception entry operations.
*
* Entry Conditions:
* level - Interrupt level
* reg_sp - Stack pointer
* tmp - Temporary register
*
****************************************************************************/
#ifdef CONFIG_XTENSA_HAVE_GENERAL_EXCEPTION_HOOKS
.macro exception_entry_hook level reg_sp tmp
.ifeq (\level - 1) * (\level - 3)
clear_wcl_write_buffer \tmp
/* Save World information from interruptee when handling User Exceptions
* (Level 1) and Software-triggered interrupts (Level 3).
*/
get_prev_world \level \tmp
s32i \tmp, \reg_sp, (4 * REG_INT_CTX) /* Save World into context */
.endif
.endm
#endif
/****************************************************************************
* Name: exception_exit_hook
*
* Description:
* Perform chip-specific exception exit operations.
*
* Entry Conditions:
* level - Interrupt level
* reg_sp - Stack pointer
* tmp1 - Temporary register 1
* tmp2 - Temporary register 2
*
****************************************************************************/
#ifdef CONFIG_XTENSA_HAVE_GENERAL_EXCEPTION_HOOKS
.macro exception_exit_hook level reg_sp tmp1 tmp2
/* Configure the World Controller for the new execution context before
* returning from User Exceptions (Level 1) and Software-triggered
* interrupts (Level 3).
*/
.ifeq (\level - 1) * (\level - 3)
movi \tmp1, 0x0
.ifeq (\level - 1)
movi \tmp2, WCL_CORE_0_STATUSTABLE1_REG
.endif
.ifeq (\level - 3)
movi \tmp2, WCL_CORE_0_STATUSTABLE2_REG
.endif
s32i \tmp1, \tmp2, 0 /* Clear the table entry */
l32i \tmp1, \reg_sp, (4 * REG_INT_CTX)
beqz \tmp1, 1f
set_next_world \reg_sp \tmp1 \tmp2
1:
memw
.endif
.endm
#endif
#endif /* __ASSEMBLY */
/****************************************************************************
* Public Data
****************************************************************************/
#ifndef __ASSEMBLY__
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Functions Prototypes
****************************************************************************/
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_XTENSA_SRC_ESP32S3_CHIP_MACROS_H */