blob: 891d7a58a35921e3bc63dc59f8b702d97bbd93fc [file] [log] [blame]
/****************************************************************************
* arch/xtensa/src/esp32s3/esp32s3_start.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 <stdint.h>
#include <string.h>
#include <nuttx/init.h>
#include <nuttx/irq.h>
#include "xtensa.h"
#include "xtensa_attr.h"
#include "esp32s3_start.h"
#include "esp32s3_lowputc.h"
#include "esp32s3_clockconfig.h"
#include "esp32s3_region.h"
#include "esp32s3_periph.h"
#include "esp32s3_rtc.h"
#include "esp32s3_spiram.h"
#include "esp32s3_wdt.h"
#ifdef CONFIG_BUILD_PROTECTED
# include "esp32s3_userspace.h"
#endif
#include "esp32s3_spi_timing.h"
#include "hardware/esp32s3_cache_memory.h"
#include "hardware/esp32s3_system.h"
#include "hardware/esp32s3_extmem.h"
#include "rom/esp32s3_libc_stubs.h"
#include "rom/esp32s3_spiflash.h"
#include "rom/esp32s3_opi_flash.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifdef CONFIG_DEBUG_FEATURES
# define showprogress(c) xtensa_lowputc(c)
#else
# define showprogress(c)
#endif
#ifdef CONFIG_ESP32S3_APP_FORMAT_MCUBOOT
#define PRIMARY_SLOT_OFFSET CONFIG_ESP32S3_OTA_PRIMARY_SLOT_OFFSET
#define HDR_ATTR locate_code(".entry_addr") used_code
/* Cache MMU address mask (MMU tables ignore bits which are zero) */
#define MMU_FLASH_MASK (~(MMU_PAGE_SIZE - 1))
#endif
/****************************************************************************
* Private Types
****************************************************************************/
#ifdef CONFIG_ESP32S3_APP_FORMAT_MCUBOOT
extern uint8_t _image_irom_vma[];
extern uint8_t _image_irom_lma[];
extern uint8_t _image_irom_size[];
extern uint8_t _image_drom_vma[];
extern uint8_t _image_drom_lma[];
extern uint8_t _image_drom_size[];
#endif
/****************************************************************************
* ROM Function Prototypes
****************************************************************************/
#ifdef CONFIG_ESP32S3_APP_FORMAT_MCUBOOT
extern int ets_printf(const char *fmt, ...) printf_like(1, 2);
extern int cache_dbus_mmu_set(uint32_t ext_ram, uint32_t vaddr,
uint32_t paddr, uint32_t psize, uint32_t num,
uint32_t fixed);
extern int cache_ibus_mmu_set(uint32_t ext_ram, uint32_t vaddr,
uint32_t paddr, uint32_t psize, uint32_t num,
uint32_t fixed);
#endif
extern void rom_config_instruction_cache_mode(uint32_t cfg_cache_size,
uint8_t cfg_cache_ways,
uint8_t cfg_cache_line_size);
extern void rom_config_data_cache_mode(uint32_t cfg_cache_size,
uint8_t cfg_cache_ways,
uint8_t cfg_cache_line_size);
extern void cache_invalidate_dcache_all(void);
extern uint32_t cache_suspend_dcache(void);
extern void cache_resume_dcache(uint32_t val);
extern uint32_t cache_set_idrom_mmu_size(uint32_t irom_size,
uint32_t drom_size);
extern void cache_set_idrom_mmu_info(uint32_t instr_page_num,
uint32_t rodata_page_num,
uint32_t rodata_start,
uint32_t rodata_end,
int i_off,
int ro_off);
#ifdef CONFIG_ESP32S3_DATA_CACHE_16KB
extern void cache_invalidate_dcache_all(void);
extern int cache_occupy_addr(uint32_t addr, uint32_t size);
#endif
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
#ifdef CONFIG_ESP32S3_APP_FORMAT_MCUBOOT
noreturn_function void __start(void);
#endif
/****************************************************************************
* Private Data
****************************************************************************/
#ifdef CONFIG_ESP32S3_APP_FORMAT_MCUBOOT
HDR_ATTR static void (*_entry_point)(void) = __start;
#endif
/****************************************************************************
* Public Data
****************************************************************************/
extern uint8_t _rodata_reserved_start[];
extern uint8_t _rodata_reserved_end[];
/* Address of the CPU0 IDLE thread */
uint32_t g_idlestack[IDLETHREAD_STACKWORDS]
aligned_data(16) locate_data(".noinit");
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: configure_cpu_caches
*
* Description:
* Configure the Instruction and Data CPU caches.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
noinstrument_function static void IRAM_ATTR configure_cpu_caches(void)
{
int s_instr_flash2spiram_off = 0;
int s_rodata_flash2spiram_off = 0;
/* Configure the mode of instruction cache: cache size, cache line size. */
rom_config_instruction_cache_mode(CONFIG_ESP32S3_INSTRUCTION_CACHE_SIZE,
CONFIG_ESP32S3_ICACHE_ASSOCIATED_WAYS,
CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_SIZE);
/* If we need to use SPIRAM, we should use data cache.
* Configure the mode of data cache: cache size, cache line size.
*/
cache_suspend_dcache();
rom_config_data_cache_mode(CONFIG_ESP32S3_DATA_CACHE_SIZE,
CONFIG_ESP32S3_DCACHE_ASSOCIATED_WAYS,
CONFIG_ESP32S3_DATA_CACHE_LINE_SIZE);
cache_resume_dcache(0);
/* Configure the Cache MMU size for instruction and rodata in flash. */
uint32_t rodata_reserved_start_align =
(uint32_t)_rodata_reserved_start & ~(MMU_PAGE_SIZE - 1);
uint32_t cache_mmu_irom_size =
((rodata_reserved_start_align - SOC_DROM_LOW) / MMU_PAGE_SIZE) *
sizeof(uint32_t);
uint32_t cache_mmu_drom_size =
(((uint32_t)_rodata_reserved_end - rodata_reserved_start_align +
MMU_PAGE_SIZE - 1) /
MMU_PAGE_SIZE) * sizeof(uint32_t);
cache_set_idrom_mmu_size(cache_mmu_irom_size,
CACHE_DROM_MMU_MAX_END - cache_mmu_irom_size);
cache_set_idrom_mmu_info(cache_mmu_irom_size / sizeof(uint32_t),
cache_mmu_drom_size / sizeof(uint32_t),
(uint32_t)_rodata_reserved_start,
(uint32_t)_rodata_reserved_end,
s_instr_flash2spiram_off,
s_rodata_flash2spiram_off);
#ifdef CONFIG_ESP32S3_DATA_CACHE_16KB
cache_invalidate_dcache_all();
cache_occupy_addr(SOC_DROM_LOW, 0x4000);
#endif
}
/****************************************************************************
* Name: disable_app_cpu
*
* Description:
* Disable the APP CPU (Core 1).
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#ifndef CONFIG_SMP
static void IRAM_ATTR disable_app_cpu(void)
{
uint32_t regval;
regval = getreg32(SYSTEM_CORE_1_CONTROL_0_REG);
regval &= ~SYSTEM_CONTROL_CORE_1_CLKGATE_EN;
putreg32(regval, SYSTEM_CORE_1_CONTROL_0_REG);
/* The clock gating signal of the App core is invalid.
* We use RUNSTALL and RESETING signals to ensure that the App core stops
* running in single-core mode.
*/
regval = getreg32(SYSTEM_CORE_1_CONTROL_0_REG);
regval |= SYSTEM_CONTROL_CORE_1_RUNSTALL;
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);
}
#endif
/****************************************************************************
* Name: __esp32s3_start
*
* Description:
* Perform base configuration of the chip for code execution.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
noinstrument_function void noreturn_function IRAM_ATTR __esp32s3_start(void)
{
uint32_t sp;
/* Make sure that normal interrupts are disabled. This is really only an
* issue when we are started in un-usual ways (such as from IRAM). In this
* case, we can at least defer some unexpected interrupts left over from
* the last program execution.
*/
up_irq_disable();
/* Move the stack to a known location. Although we were given a stack
* pointer at start-up, we don't know where that stack pointer is
* positioned with respect to our memory map. The only safe option is to
* switch to a well-known IDLE thread stack.
*/
sp = (uint32_t)g_idlestack + IDLETHREAD_STACKSIZE;
__asm__ __volatile__("mov sp, %0\n" : : "r"(sp));
/* Raise an exception in case page 0 is accessed */
esp32s3_region_protection();
/* Move CPU0 exception vectors to IRAM */
__asm__ __volatile__ ("wsr %0, vecbase\n"::"r" (_init_start));
/* Clear .bss. We'll do this inline (vs. calling memset) just to be
* certain that there are no issues with the state of global variables.
*/
for (uint32_t *dest = (uint32_t *)_sbss; dest < (uint32_t *)_ebss; )
{
*dest++ = 0;
}
#ifndef CONFIG_SMP
/* Make sure that the APP_CPU is disabled for now */
disable_app_cpu();
#endif
/* The 2nd stage bootloader enables RTC WDT to check on startup sequence
* related issues in application. Hence disable that as we are about to
* start the NuttX environment.
*/
esp32s3_wdt_early_deinit();
/* Initialize RTC controller parameters */
esp32s3_rtc_init();
esp32s3_rtc_clk_set();
/* Set CPU frequency configured in board.h */
esp32s3_clockconfig();
/* Initialize peripherals parameters */
esp32s3_perip_clk_init();
#ifndef CONFIG_SUPPRESS_UART_CONFIG
/* Configure the UART so we can get debug output */
esp32s3_lowsetup();
#endif
#ifdef USE_EARLYSERIALINIT
/* Perform early serial initialization */
xtensa_earlyserialinit();
#endif
showprogress('A');
#if defined(CONFIG_ESP32S3_FLASH_MODE_OCT) || \
defined(CONFIG_ESP32S3_SPIRAM_MODE_OCT)
esp_rom_opiflash_pin_config();
esp32s3_spi_timing_set_pin_drive_strength();
#endif
/* The PLL provided by bootloader is not stable enough, do calibration
* again here so that we can use better clock for the timing tuning.
*/
#ifdef CONFIG_ESP32S3_SYSTEM_BBPLL_RECALIB
esp32s3_rtc_recalib_bbpll();
#endif
esp32s3_spi_timing_set_mspi_flash_tuning();
#if defined(CONFIG_ESP32S3_SPIRAM_BOOT_INIT)
if (esp_spiram_init() != OK)
{
# if defined(ESP32S3_SPIRAM_IGNORE_NOTFOUND)
mwarn("SPIRAM Initialization failed!\n");
# else
PANIC();
# endif
}
else
{
esp_spiram_init_cache();
esp_spiram_test();
}
#endif
/* Setup the syscall table needed by the ROM code */
esp_setup_syscall_table();
/* Initialize onboard resources */
esp32s3_board_initialize();
showprogress('B');
#ifdef CONFIG_BUILD_PROTECTED
/* For the case of the separate user-/kernel-space build, perform whatever
* platform specific initialization of the user memory is required.
* Normally this just means initializing the user space .data and .bss
* segments.
*/
esp32s3_userspace();
showprogress('C');
#endif
/* Bring up NuttX */
nx_start();
for (; ; ); /* Should not return */
}
/****************************************************************************
* Name: calc_mmu_pages
*
* Description:
* Calculate the number of cache pages to map.
*
* Input Parameters:
* size - Size of data to map
* vaddr - Virtual address where data will be mapped
*
* Returned Value:
* Number of cache MMU pages required to do the mapping.
*
****************************************************************************/
#ifdef CONFIG_ESP32S3_APP_FORMAT_MCUBOOT
static inline uint32_t calc_mmu_pages(uint32_t size, uint32_t vaddr)
{
return (size + (vaddr - (vaddr & MMU_FLASH_MASK)) + MMU_PAGE_SIZE - 1) /
MMU_PAGE_SIZE;
}
#endif
/****************************************************************************
* Name: map_rom_segments
*
* Description:
* Configure the MMU and Cache peripherals for accessing ROM code and data.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#ifdef CONFIG_ESP32S3_APP_FORMAT_MCUBOOT
static int map_rom_segments(void)
{
uint32_t rc = 0;
uint32_t regval;
uint32_t drom_lma_aligned;
uint32_t drom_vma_aligned;
uint32_t drom_page_count;
uint32_t irom_lma_aligned;
uint32_t irom_vma_aligned;
uint32_t irom_page_count;
size_t partition_offset = PRIMARY_SLOT_OFFSET;
uint32_t app_irom_lma = partition_offset + (uint32_t)_image_irom_lma;
uint32_t app_irom_size = (uint32_t)_image_irom_size;
uint32_t app_irom_vma = (uint32_t)_image_irom_vma;
uint32_t app_drom_lma = partition_offset + (uint32_t)_image_drom_lma;
uint32_t app_drom_size = (uint32_t)_image_drom_size;
uint32_t app_drom_vma = (uint32_t)_image_drom_vma;
uint32_t autoload = cache_suspend_dcache();
cache_invalidate_dcache_all();
/* Clear the MMU entries that are already set up, so the new app only has
* the mappings it creates.
*/
for (size_t i = 0; i < FLASH_MMU_TABLE_SIZE; i++)
{
FLASH_MMU_TABLE[i] = MMU_TABLE_INVALID_VAL;
}
drom_lma_aligned = app_drom_lma & MMU_FLASH_MASK;
drom_vma_aligned = app_drom_vma & MMU_FLASH_MASK;
drom_page_count = calc_mmu_pages(app_drom_size, app_drom_vma);
rc = cache_dbus_mmu_set(MMU_ACCESS_FLASH, drom_vma_aligned,
drom_lma_aligned, 64, drom_page_count, 0);
irom_lma_aligned = app_irom_lma & MMU_FLASH_MASK;
irom_vma_aligned = app_irom_vma & MMU_FLASH_MASK;
irom_page_count = calc_mmu_pages(app_irom_size, app_irom_vma);
rc = cache_ibus_mmu_set(MMU_ACCESS_FLASH, irom_vma_aligned,
irom_lma_aligned, 64, irom_page_count, 0);
regval = getreg32(EXTMEM_DCACHE_CTRL1_REG);
regval &= EXTMEM_DCACHE_SHUT_CORE0_BUS;
putreg32(regval, EXTMEM_DCACHE_CTRL1_REG);
cache_resume_dcache(autoload);
return (int)rc;
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: __start
*
* Description:
* We arrive here after the bootloader finished loading the program from
* flash. The hardware is mostly uninitialized, and the app CPU is in
* reset. We do have a stack, so we can do the initialization in C.
*
* The app CPU will remain in reset unless CONFIG_SMP is selected and
* up_cpu_start() is called later in the bring-up sequence.
*
****************************************************************************/
noinstrument_function void IRAM_ATTR __start(void)
{
#ifdef CONFIG_ESP32S3_APP_FORMAT_MCUBOOT
if (map_rom_segments() != 0)
{
ets_printf("Failed to setup XIP, aborting\n");
while (true);
}
#endif
configure_cpu_caches();
__esp32s3_start();
while (true); /* Should not return */
}