diff --git a/boards/riscv/esp32c3_devkitm/CMakeLists.txt b/boards/riscv/esp32c3_devkitm/CMakeLists.txt new file mode 100644 index 00000000000..d73115fec5b --- /dev/null +++ b/boards/riscv/esp32c3_devkitm/CMakeLists.txt @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_BOOTLOADER_ESP_IDF) + include(ExternalProject) + + ## we use hello-world project, but I think any can be used. + set(espidf_components_dir ${ESP_IDF_PATH}/components) + set(espidf_prefix ${CMAKE_BINARY_DIR}/esp-idf) + set(espidf_build_dir ${espidf_prefix}/build) + + ExternalProject_Add( + EspIdfBootloader + PREFIX ${espidf_prefix} + SOURCE_DIR ${espidf_components_dir}/bootloader/subproject + BINARY_DIR ${espidf_build_dir}/bootloader + CONFIGURE_COMMAND + ${CMAKE_COMMAND} -G${CMAKE_GENERATOR} + -S ${espidf_components_dir}/bootloader/subproject + -B ${espidf_build_dir}/bootloader -DSDKCONFIG=${espidf_build_dir}/sdkconfig + -DIDF_PATH=${ESP_IDF_PATH} -DIDF_TARGET=${CONFIG_SOC} + -DSDKCONFIG_DEFAULTS=${ESP_IDF_PATH}/zephyr/esp32c3/sdkconfig.defaults + -DPYTHON_DEPS_CHECKED=1 + BUILD_COMMAND + ${CMAKE_COMMAND} --build . + INSTALL_COMMAND "" # This particular build system has no install command + ) + + ExternalProject_Add( + EspPartitionTable + SOURCE_DIR ${espidf_components_dir}/partition_table + BINARY_DIR ${espidf_build_dir} + CONFIGURE_COMMAND "" + BUILD_COMMAND + python ${ESP_IDF_PATH}/components/partition_table/gen_esp32part.py -q + --offset 0x1000 --flash-size 4MB ${ESP_IDF_PATH}/components/partition_table/partitions_singleapp.csv ${espidf_build_dir}/partitions_singleapp.bin + INSTALL_COMMAND "" + ) + + if(CONFIG_BUILD_OUTPUT_BIN) + set_property(GLOBAL APPEND PROPERTY extra_post_build_commands + COMMAND python ${ESP_IDF_PATH}/components/esptool_py/esptool/esptool.py + ARGS --chip esp32c3 elf2image --flash_mode dio --flash_freq 40m + -o ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.bin + ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.elf) + endif() + + add_dependencies(app EspIdfBootloader EspPartitionTable) + + board_finalize_runner_args(esp32 "--esp-flash-bootloader=${espidf_build_dir}/bootloader/bootloader.bin") + + board_finalize_runner_args(esp32 "--esp-flash-partition_table=${espidf_build_dir}/partitions_singleapp.bin") + + board_finalize_runner_args(esp32 "--esp-boot-address=0x0000") + + board_finalize_runner_args(esp32 "--esp-partition-table-address=0x8000") + + board_finalize_runner_args(esp32 "--esp-app-address=0x10000") + +endif() diff --git a/boards/riscv/esp32c3_devkitm/Kconfig.board b/boards/riscv/esp32c3_devkitm/Kconfig.board new file mode 100644 index 00000000000..8f5157be8b9 --- /dev/null +++ b/boards/riscv/esp32c3_devkitm/Kconfig.board @@ -0,0 +1,9 @@ +# ESP32C3 devkitm board configuration + +# Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ESP32C3_DEVKITM + bool "ESP32C3 Devkit-M Board" + depends on SOC_ESP32C3 + select CONSOLE_HAS_DRIVER diff --git a/boards/riscv/esp32c3_devkitm/Kconfig.defconfig b/boards/riscv/esp32c3_devkitm/Kconfig.defconfig new file mode 100644 index 00000000000..4978542f4bd --- /dev/null +++ b/boards/riscv/esp32c3_devkitm/Kconfig.defconfig @@ -0,0 +1,8 @@ +# ESP32C3 devkitm board configuration + +# Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "esp32c3" + depends on BOARD_ESP32C3_DEVKITM diff --git a/boards/riscv/esp32c3_devkitm/board.cmake b/boards/riscv/esp32c3_devkitm/board.cmake new file mode 100644 index 00000000000..71735daa671 --- /dev/null +++ b/boards/riscv/esp32c3_devkitm/board.cmake @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +include(${ZEPHYR_BASE}/boards/common/esp32.board.cmake) diff --git a/boards/riscv/esp32c3_devkitm/doc/index.rst b/boards/riscv/esp32c3_devkitm/doc/index.rst new file mode 100644 index 00000000000..b0bfd71aa0f --- /dev/null +++ b/boards/riscv/esp32c3_devkitm/doc/index.rst @@ -0,0 +1,116 @@ +.. _esp32c3_devkitm: + +ESP32-C3 +##### + +Overview +******** + +ESP32-C3 is a single-core Wi-Fi and Bluetooth 5 (LE) microcontroller SoC, +based on the open-source RISC-V architecture. It strikes the right balance of power, +I/O capabilities and security, thus offering the optimal cost-effective +solution for connected devices. +The availability of Wi-Fi and Bluetooth 5 (LE) connectivity not only makes the device configuration easy, +but it also facilitates a variety of use-cases based on dual connectivity. [1]_ + +The features include the following: + +- 32-bit core RISC-V microcontroller with a maximum clock speed of 160 MHz +- 400 KB of internal RAM +- 802.11b/g/n/e/i +- A Bluetooth LE subsystem that supports features of Bluetooth 5 and Bluetooth mesh +- Various peripherals: + + - 12-bit ADC with up to 18 channels + - TWAI compatible with CAN bus 2.0 + - Temperature sensor + - 4x SPI + - 2x I2S + - 2x I2C + - 3x UART + - LED PWM with up to 16 channels + +- Cryptographic hardware acceleration (RNG, ECC, RSA, SHA-2, AES) + +System requirements +******************* + + +Build Environment Setup +======================= + +Retrieve required submodules to build this port. This might take a while for the first time: + +.. code-block:: console + + west espressif update + +.. note:: + + It is recommended running the command above after :file:`west update` so that submodules also get updated. + +Flashing +======== + +The usual ``flash`` target will work with the ``esp32c3_devkitm`` board +configuration. Here is an example for the :ref:`hello_world` +application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: esp32c3_devkitm + :goals: flash + +Refer to :ref:`build_an_application` and :ref:`application_run` for +more details. + +It's impossible to determine which serial port the ESP32 board is +connected to, as it uses a generic RS232-USB converter. The default of +``/dev/ttyUSB0`` is provided as that's often the assigned name on a Linux +machine without any other such converters. + +The baud rate of 921600bps is recommended. If experiencing issues when +flashing, try halving the value a few times (460800, 230400, 115200, +etc). It might be necessary to change the flash frequency or the flash +mode; please refer to the `esptool documentation`_ for guidance on these +settings. + +All flashing options are now handled by the :ref:`west` tool, including flashing +with custom options such as a different serial port. The ``west`` tool supports +specific options for the ESP32C3 board, as listed here: + + --esp-idf-path ESP_IDF_PATH + path to ESP-IDF + --esp-device ESP_DEVICE + serial port to flash, default /dev/ttyUSB0 + --esp-baud-rate ESP_BAUD_RATE + serial baud rate, default 921600 + --esp-flash-size ESP_FLASH_SIZE + flash size, default "detect" + --esp-flash-freq ESP_FLASH_FREQ + flash frequency, default "40m" + --esp-flash-mode ESP_FLASH_MODE + flash mode, default "dio" + --esp-tool ESP_TOOL if given, complete path to espidf. default is to + search for it in [ESP_IDF_PATH]/components/esptool_py/ + esptool/esptool.py + --esp-flash-bootloader ESP_FLASH_BOOTLOADER + Bootloader image to flash + --esp-flash-partition_table ESP_FLASH_PARTITION_TABLE + Partition table to flash + +For example, to flash to ``/dev/ttyUSB2``, use the following command after +having build the application in the ``build`` directory: + + +.. code-block:: console + + west flash -d build/ --skip-rebuild --esp-device /dev/ttyUSB2 + + +References +********** + +.. [1] https://www.espressif.com/en/products/socs/esp32-c3 +.. _`ESP32C3 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf +.. _`ESP32C3 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf diff --git a/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts b/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts new file mode 100644 index 00000000000..d78b261086b --- /dev/null +++ b/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + model = "esp32c3_devkitm"; + compatible = "espressif,esp32c3"; + + chosen { + zephyr,sram = &sram0; + }; +}; diff --git a/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.yaml b/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.yaml new file mode 100644 index 00000000000..ba178a6d6ec --- /dev/null +++ b/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.yaml @@ -0,0 +1,6 @@ +identifier: esp32c3 +name: ESP32-C3 +type: mcu +arch: riscv +toolchain: + - zephyr diff --git a/boards/riscv/esp32c3_devkitm/esp32c3_devkitm_defconfig b/boards/riscv/esp32c3_devkitm/esp32c3_devkitm_defconfig new file mode 100644 index 00000000000..b98871af4b2 --- /dev/null +++ b/boards/riscv/esp32c3_devkitm/esp32c3_devkitm_defconfig @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + + +CONFIG_BOARD_ESP32C3_DEVKITM=y +CONFIG_SOC_ESP32C3=y +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=1000000 +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_CONSOLE=y +CONFIG_XIP=n diff --git a/boards/xtensa/esp32/CMakeLists.txt b/boards/xtensa/esp32/CMakeLists.txt index 78c9146854c..bc72a5cdeb3 100644 --- a/boards/xtensa/esp32/CMakeLists.txt +++ b/boards/xtensa/esp32/CMakeLists.txt @@ -51,4 +51,10 @@ if(CONFIG_BOOTLOADER_ESP_IDF) board_finalize_runner_args(esp32 "--esp-flash-partition_table=${espidf_build_dir}/partitions_singleapp.bin") + board_finalize_runner_args(esp32 "--esp-boot-address=0x1000") + + board_finalize_runner_args(esp32 "--esp-partition-table-address=0x8000") + + board_finalize_runner_args(esp32 "--esp-app-address=0x10000") + endif() diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt index 532dc8f65cf..2df04181d8e 100644 --- a/drivers/timer/CMakeLists.txt +++ b/drivers/timer/CMakeLists.txt @@ -13,6 +13,7 @@ zephyr_sources_ifdef(CONFIG_RISCV_MACHINE_TIMER riscv_machine_timer.c) zephyr_sources_ifdef(CONFIG_RV32M1_LPTMR_TIMER rv32m1_lptmr_timer.c) zephyr_sources_ifdef(CONFIG_CORTEX_M_SYSTICK cortex_m_systick.c) zephyr_sources_ifdef(CONFIG_XTENSA_TIMER xtensa_sys_timer.c) +zephyr_sources_ifdef(CONFIG_ESP32C3_SYS_TIMER esp32c3_sys_timer.c) zephyr_sources_ifdef(CONFIG_NATIVE_POSIX_TIMER native_posix_timer.c) zephyr_sources_ifdef(CONFIG_SAM0_RTC_TIMER sam0_rtc_timer.c) zephyr_sources_ifdef(CONFIG_LITEX_TIMER litex_timer.c) diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 0988116ec0f..68561adddac 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -249,6 +249,14 @@ config XTENSA_TIMER Enables a system timer driver for Xtensa based on the CCOUNT and CCOMPARE special registers. +config ESP32C3_SYS_TIMER + bool "ESP32C3 sys-timer support" + depends on SOC_ESP32C3 + default y + help + This option enables the system timer driver for the Espressif ESP32C3 + and provides the standard "system clock driver" interface. + config XTENSA_TIMER_ID int "System timer CCOMPAREn register index" default 1 diff --git a/drivers/timer/esp32c3_sys_timer.c b/drivers/timer/esp32c3_sys_timer.c new file mode 100644 index 00000000000..59bc2e8b15f --- /dev/null +++ b/drivers/timer/esp32c3_sys_timer.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define SYS_TIMER_CPU_IRQ 1 + +static void sys_timer_isr(const void *arg) +{ + ARG_UNUSED(arg); + systimer_ll_clear_alarm_int(SYSTIMER_ALARM_0); + sys_clock_announce(1); +} + +int sys_clock_driver_init(const struct device *dev) +{ + ARG_UNUSED(dev); + + esp32c3_rom_intr_matrix_set(0, ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE, SYS_TIMER_CPU_IRQ); + IRQ_CONNECT(SYS_TIMER_CPU_IRQ, 0, sys_timer_isr, NULL, 0); + irq_enable(SYS_TIMER_CPU_IRQ); + + systimer_hal_init(); + systimer_hal_connect_alarm_counter(SYSTIMER_ALARM_0, SYSTIMER_COUNTER_1); + systimer_hal_enable_counter(SYSTIMER_COUNTER_1); + systimer_hal_counter_can_stall_by_cpu(SYSTIMER_COUNTER_1, 0, true); + systimer_hal_set_alarm_period(SYSTIMER_ALARM_0, + CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC); + systimer_hal_select_alarm_mode(SYSTIMER_ALARM_0, SYSTIMER_ALARM_MODE_PERIOD); + systimer_hal_enable_alarm_int(SYSTIMER_ALARM_0); + + return 0; +} + +void sys_clock_set_timeout(int32_t ticks, bool idle) +{ + ARG_UNUSED(idle); + ARG_UNUSED(ticks); +} + +uint32_t sys_clock_elapsed(void) +{ + /* Tickless is not supported yet */ + return 0; +} + +uint32_t sys_clock_cycle_get_32(void) +{ + return systimer_ll_get_counter_value_low(SYSTIMER_COUNTER_1); +} diff --git a/dts/riscv/espressif/esp32c3.dtsi b/dts/riscv/espressif/esp32c3.dtsi new file mode 100644 index 00000000000..e5a8f9a151b --- /dev/null +++ b/dts/riscv/espressif/esp32c3.dtsi @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "riscv"; + reg = <0>; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges; + + sram0: memory@3fc7c000 { + compatible = "espressif,esp32c3"; + reg = <0x3fc7c000 0x50000>; + }; + }; + +}; diff --git a/scripts/west_commands/runners/esp32.py b/scripts/west_commands/runners/esp32.py index e9db7ee61e3..b0e55cc8c98 100644 --- a/scripts/west_commands/runners/esp32.py +++ b/scripts/west_commands/runners/esp32.py @@ -15,12 +15,16 @@ import sys class Esp32BinaryRunner(ZephyrBinaryRunner): '''Runner front-end for espidf.''' - def __init__(self, cfg, device, baud=921600, flash_size='detect', + def __init__(self, cfg, device, boot_address, part_table_address, + app_address, baud=921600, flash_size='detect', flash_freq='40m', flash_mode='dio', espidf='espidf', bootloader_bin=None, partition_table_bin=None): super().__init__(cfg) self.elf = cfg.elf_file self.device = device + self.boot_address = boot_address + self.part_table_address = part_table_address + self.app_address = app_address self.baud = baud self.flash_size = flash_size self.flash_freq = flash_freq @@ -42,8 +46,13 @@ class Esp32BinaryRunner(ZephyrBinaryRunner): # Required parser.add_argument('--esp-idf-path', required=True, help='path to ESP-IDF') - # Optional + parser.add_argument('--esp-boot-address', default='0x1000', + help='bootloader load address') + parser.add_argument('--esp-partition-table-address', default='0x8000', + help='partition table load address') + parser.add_argument('--esp-app-address', default='0x10000', + help='application load address') parser.add_argument('--esp-device', default='/dev/ttyUSB0', help='serial port to flash, default /dev/ttyUSB0') parser.add_argument('--esp-baud-rate', default='921600', @@ -72,7 +81,9 @@ class Esp32BinaryRunner(ZephyrBinaryRunner): 'esptool', 'esptool.py') return Esp32BinaryRunner( - cfg, args.esp_device, baud=args.esp_baud_rate, + cfg, args.esp_device, boot_address=args.esp_boot_address, + part_table_address=args.esp_partition_table_address, + app_address=args.esp_app_address,baud=args.esp_baud_rate, flash_size=args.esp_flash_size, flash_freq=args.esp_flash_freq, flash_mode=args.esp_flash_mode, espidf=espidf, bootloader_bin=args.esp_flash_bootloader, @@ -81,7 +92,7 @@ class Esp32BinaryRunner(ZephyrBinaryRunner): def do_run(self, command, **kwargs): self.require(self.espidf) bin_name = path.splitext(self.elf)[0] + path.extsep + 'bin' - cmd_flash = [self.espidf, '--chip', 'esp32', '--port', self.device, + cmd_flash = [self.espidf, '--chip', 'auto', '--port', self.device, '--baud', self.baud, '--before', 'default_reset', '--after', 'hard_reset', 'write_flash', '-u', '--flash_mode', self.flash_mode, @@ -92,13 +103,13 @@ class Esp32BinaryRunner(ZephyrBinaryRunner): if self.espidf.lower().endswith(".py") and sys.executable: cmd_flash.insert(0, sys.executable) - if self.bootloader_bin: - cmd_flash.extend(['0x1000', self.bootloader_bin]) - cmd_flash.extend(['0x8000', self.partition_table_bin]) - cmd_flash.extend(['0x10000', bin_name]) - else: - cmd_flash.extend(['0x1000', bin_name]) + if self.bootloader_bin : + cmd_flash.extend([self.boot_address, self.bootloader_bin]) + cmd_flash.extend([self.part_table_address, self.partition_table_bin]) + cmd_flash.extend([self.app_address, bin_name]) + else : + cmd_flash.extend([self.boot_address, bin_name]) - self.logger.info("Flashing ESP32 on {} ({}bps)". + self.logger.info("Flashing esp32 chip on {} ({}bps)". format(self.device, self.baud)) self.check_call(cmd_flash) diff --git a/soc/riscv/esp32c3/CMakeLists.txt b/soc/riscv/esp32c3/CMakeLists.txt new file mode 100644 index 00000000000..b2fd9e65654 --- /dev/null +++ b/soc/riscv/esp32c3/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources( + idle.c + vectors.S + soc_irq.S + soc.c + ) diff --git a/soc/riscv/esp32c3/Kconfig.defconfig b/soc/riscv/esp32c3/Kconfig.defconfig new file mode 100644 index 00000000000..9e7510ea98e --- /dev/null +++ b/soc/riscv/esp32c3/Kconfig.defconfig @@ -0,0 +1,29 @@ +# ESP32C3 board configuration + +# Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_ESP32C3 + +config SOC + default "esp32c3" + +config NUM_IRQS + default 32 + +config GEN_ISR_TABLES + default y + +config GEN_SW_ISR_TABLE + default y + +config GEN_IRQ_VECTOR_TABLE + default n + +config XIP + default n + +config ISR_STACK_SIZE + default 2048 + +endif diff --git a/soc/riscv/esp32c3/Kconfig.soc b/soc/riscv/esp32c3/Kconfig.soc new file mode 100644 index 00000000000..ecb96fdc1f7 --- /dev/null +++ b/soc/riscv/esp32c3/Kconfig.soc @@ -0,0 +1,22 @@ +# Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_ESP32C3 + bool "ESP32C3" + select RISCV + select RISCV_SOC_INIT_GP_VALUE + +config IDF_TARGET_ESP32C3 + bool "ESP32C3 as target board" + default y + depends on SOC_ESP32C3 + +config ESPTOOLPY_FLASHFREQ_80M + bool + default y + depends on SOC_ESP32C3 + +config BOOTLOADER_ESP_IDF + bool "Use esp-idf 2nd stage bootloader" + default y + depends on SOC_ESP32C3 diff --git a/soc/riscv/esp32c3/idle.c b/soc/riscv/esp32c3/idle.c new file mode 100644 index 00000000000..38feb526201 --- /dev/null +++ b/soc/riscv/esp32c3/idle.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/** + * + * @brief Power save idle routine + * + * This function will be called by the kernel idle loop or possibly within + * an implementation of _pm_save_idle in the kernel when the + * '_pm_save_flag' variable is non-zero. + * + * @return N/A + */ +void arch_cpu_idle(void) +{ + /* curiously it arives here with the interrupts masked + * so umask it before wait for an event + */ + arch_irq_unlock(MSTATUS_IEN); + + /* Wait for interrupt */ + __asm__ volatile("wfi"); +} diff --git a/soc/riscv/esp32c3/linker.ld b/soc/riscv/esp32c3/linker.ld new file mode 100644 index 00000000000..4419c1708b6 --- /dev/null +++ b/soc/riscv/esp32c3/linker.ld @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Linker command/script file + * + * Linker script for the esp32c3 platform. + */ + +#include +#include +#include +#include +#include + +#define ROMABLE_REGION drom0_0_seg :drom0_0_phdr +#define RAMABLE_REGION dram0_0_seg :dram0_0_phdr +#define IRAM_REGION iram0_0_seg :iram0_0_phdr +#define FLASH_CODE_REGION irom0_0_seg :irom0_0_phdr + +#define SRAM_IRAM_START 0x4037C000 +#define SRAM_DRAM_START 0x3FC7C000 +#define ICACHE_SIZE 0x4000 /* ICache size is fixed to 16KB on ESP32-C3 */ +#define I_D_SRAM_OFFSET (SRAM_IRAM_START - SRAM_DRAM_START) +#define SRAM_DRAM_END 0x403D0000 - I_D_SRAM_OFFSET /* 2nd stage bootloader iram_loader_seg start address */ +#define SRAM_IRAM_ORG (SRAM_IRAM_START + ICACHE_SIZE) +#define SRAM_DRAM_ORG (SRAM_DRAM_START + ICACHE_SIZE) +#define I_D_SRAM_SIZE SRAM_DRAM_END - SRAM_DRAM_ORG + +/* Global symbols required for espressif hal build */ +MEMORY +{ + iram0_0_seg(RX): org = SRAM_IRAM_ORG, len = I_D_SRAM_SIZE + irom0_0_seg(RX): org = 0x42000020, len = 0x8000000-0x20 + + drom0_0_seg (R) : org = 0x3C000020, len = 0x8000000-0x20 + dram0_0_seg(RW): org = SRAM_DRAM_ORG, len = I_D_SRAM_SIZE + + rtc_iram_seg(RWX): org = 0x50000000, len = 0x2000 + +#ifdef CONFIG_GEN_ISR_TABLES + IDT_LIST(RW): org = 0x3ebfe010, len = 0x2000 +#endif +} + +PHDRS +{ + drom0_0_phdr PT_LOAD; + dram0_0_phdr PT_LOAD; + iram0_0_phdr PT_LOAD; + irom0_0_phdr PT_LOAD; +} + +/* Default entry point: */ +ENTRY(__start) + +_rom_store_table = 0; + +SECTIONS +{ + +#include + + .rtc.text : + { + . = ALIGN(4); + *(.rtc.literal .rtc.text) + *rtc_wake_stub*.o(.literal .text .literal.* .text.*) + } > rtc_iram_seg + + /* This section is required to skip rtc.text area because the text and + * data segments reflect the same address space on different buses. + */ + .rtc.dummy (NOLOAD): + { + . = SIZEOF(.rtc.text); + } > rtc_iram_seg + + .rtc.data : + { + _rtc_data_start = ABSOLUTE(.); + *(.rtc.data) + *(.rtc.rodata) + *rtc_wake_stub*.o(.data .rodata .data.* .rodata.* .bss .bss.*) + _rtc_data_end = ABSOLUTE(.); + } > rtc_iram_seg + + .rtc.bss (NOLOAD) : + { + _rtc_bss_start = ABSOLUTE(.); + *rtc_wake_stub*.o(.bss .bss.*) + *rtc_wake_stub*.o(COMMON) + _rtc_bss_end = ABSOLUTE(.); + } > rtc_iram_seg + + .iram0.text : ALIGN(4) + { + /* Vectors go to IRAM */ + _iram_start = ABSOLUTE(.); + _iram_text_start = ABSOLUTE(.); + _init_start = ABSOLUTE(.); + KEEP(*(.exception_vectors.text)); + . = ALIGN(256); + + KEEP(*(.exception.entry*)); /* contains __irq_wrapper */ + *(.exception.other*) + . = ALIGN(4); + + . = ALIGN (4); + *(.entry.text) + *(.init.literal) + *(.init) + . = ALIGN(4); + *(.iram1 .iram1.*) + *(.iram0.literal .iram.literal .iram.text.literal .iram0.text .iram.text) + *libkernel.a:(.literal .text .literal.* .text.*) + *libgcc.a:lib2funcs.*(.literal .text .literal.* .text.*) + *libzephyr.a:log_noos.*(.literal .text .literal.* .text.*) + *libzephyr.a:esp32c3_sys_timer.*(.literal .text .literal.* .text.*) + *libzephyr.a:log_core.*(.literal .text .literal.* .text.*) + *libzephyr.a:cbprintf_complete.*(.literal .text .literal.* .text.*) + *libzephyr.a:printk.*(.literal.printk .literal.vprintk .literal.char_out .text.printk .text.vprintk .text.char_out) + *libzephyr.a:log_msg.*(.literal .text .literal.* .text.*) + *libzephyr.a:log_list.*(.literal .text .literal.* .text.*) + *libzephyr.a:uart_console.*(.literal.console_out .text.console_out) + *libzephyr.a:log_output.*(.literal .text .literal.* .text.*) + *libzephyr.a:log_backend_uart.*(.literal .text .literal.* .text.*) + *liblib__libc__minimal.a:string.*(.literal .text .literal.* .text.*) + *libgcov.a:(.literal .text .literal.* .text.*) + . = ALIGN(4); + _init_end = ABSOLUTE(.); + _iram_text_end = ABSOLUTE(.); *(.srodata) + _iram_end = ABSOLUTE(.); + } GROUP_LINK_IN(IRAM_REGION) + + /** + * This section is required to skip .iram0.text area because iram0_0_seg and + * dram0_0_seg reflect the same address space on different buses. + */ + .dram0.dummy (NOLOAD): + { + . = ORIGIN(dram0_0_seg) + _iram_end - _iram_start; + } > dram0_0_seg + +#include + + .dram0.data : + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + __global_pointer$ = . + 0x800; + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *libkernel.a:fatal.*(.rodata .rodata.*) + *libkernel.a:init.*(.rodata .rodata.*) + *libzephyr.a:cbprintf_complete*(.rodata .rodata.*) + *libzephyr.a:log_core.*(.rodata .rodata.*) + *libzephyr.a:log_backend_uart.*(.rodata .rodata.*) + *libzephyr.a:log_output.*(.rodata .rodata.*) + . = ALIGN(4); + __esp_log_const_start = .; + KEEP(*(SORT(.log_const_*))); + __esp_log_const_end = .; + + . = ALIGN(4); + __esp_log_backends_start = .; + KEEP(*("._log_backend.*")); + __esp_log_backends_end = .; + + KEEP(*(.jcr)) + *(.dram1 .dram1.*) + _data_end = ABSOLUTE(.); + . = ALIGN(4); + } GROUP_LINK_IN(RAMABLE_REGION) + + /* Shared RAM */ + dram0.bss (NOLOAD) : + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.share.mem) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + } GROUP_LINK_IN(RAMABLE_REGION) + + SECTION_DATA_PROLOGUE(_NOINIT_SECTION_NAME, (NOLOAD),) + { + . = ALIGN (8); + *(.noinit) + *(".noinit.*") + . = ALIGN (8); + _heap_start = ABSOLUTE(.); + } GROUP_LINK_IN(RAMABLE_REGION) + + .flash.text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + + *(.literal .text .literal.* .text.*) + _text_end = ABSOLUTE(.); + _etext = .; + _flash_cache_start = ABSOLUTE(0); + } GROUP_LINK_IN(FLASH_CODE_REGION) + + .flash_rodata_dummy (NOLOAD): + { + . = SIZEOF(.flash.text); + . = ALIGN(0x10000) + 0x20; + _rodata_reserved_start = .; + } GROUP_LINK_IN(ROMABLE_REGION) + + .flash.rodata : ALIGN(0x10) + { + _rodata_start = ABSOLUTE(.); + + *(.rodata_desc .rodata_desc.*) /* Should be the first. App version info. DO NOT PUT ANYTHING BEFORE IT! */ + *(.rodata_custom_desc .rodata_custom_desc.*) /* Should be the second. Custom app version info. DO NOT PUT ANYTHING BEFORE IT! */ + *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE_ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table .gcc_except_table.*) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + . = (. + 3) & ~ 3; + __eh_frame = ABSOLUTE(.); + KEEP(*(.eh_frame)) + . = (. + 7) & ~ 3; + /* + * C++ constructor and destructor tables + * Don't include anything from crtbegin.o or crtend.o, as IDF doesn't use toolchain crt. + * + * RISC-V gcc is configured with --enable-initfini-array so it emits an .init_array section instead. + * But the init_priority sections will be sorted for iteration in ascending order during startup. + * The rest of the init_array sections is sorted for iteration in descending order during startup, however. + * Hence a different section is generated for the init_priority functions which is iterated in + * ascending order during startup. The corresponding code can be found in startup.c. + */ + __init_priority_array_start = ABSOLUTE(.); + KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array.*)) + __init_priority_array_end = ABSOLUTE(.); + __init_array_start = ABSOLUTE(.); + KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array)) + __init_array_end = ABSOLUTE(.); + KEEP (*crtbegin.*(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.*) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS_ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + /* Addresses of memory regions reserved via SOC_RESERVE_MEMORY_REGION() */ + soc_reserved_memory_region_start = ABSOLUTE(.); + KEEP (*(.reserved_memory_address)) + soc_reserved_memory_region_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + /* Literals are also RO data. */ + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + . = ALIGN(4); + _thread_local_start = ABSOLUTE(.); + *(.tdata) + *(.tdata.*) + *(.tbss) + *(.tbss.*) + *(.srodata) + *(".srodata.*") + *(.rodata) + *(.rodata.*) + _thread_local_end = ABSOLUTE(.); + _rodata_reserved_end = ABSOLUTE(.); + . = ALIGN(4); + } GROUP_LINK_IN(ROMABLE_REGION) + +#include + +#ifdef CONFIG_GEN_ISR_TABLES +#include +#endif + +#include + /DISCARD/ : { *(.note.GNU-stack) } + + SECTION_PROLOGUE(.riscv.attributes, 0,) + { + KEEP(*(.riscv.attributes)) + KEEP(*(.gnu.attributes)) + } +} diff --git a/soc/riscv/esp32c3/soc.c b/soc/riscv/esp32c3/soc.c new file mode 100644 index 00000000000..9ae5b8b0bea --- /dev/null +++ b/soc/riscv/esp32c3/soc.c @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Include esp-idf headers first to avoid redefining BIT() macro */ +#include +#include +#include +#include +#include +#include +#include "hal/soc_ll.h" +#include "esp_spi_flash.h" +#include + +#include +#include +#include +#include + +#define ESP32C3_INTC_DEFAULT_PRIO 15 + +extern void z_cstart(void); +extern void esprv_intc_int_set_threshold(int priority_threshold); + +/* + * This is written in C rather than assembly since, during the port bring up, + * Zephyr is being booted by the Espressif bootloader. With it, the C stack + * is already set up. + */ +void __attribute__((section(".iram1"))) __start(void) +{ + volatile uint32_t *wdt_rtc_protect = (uint32_t *)RTC_CNTL_WDTWPROTECT_REG; + volatile uint32_t *wdt_rtc_reg = (uint32_t *)RTC_CNTL_WDTCONFIG0_REG; + extern uint32_t _bss_start; + extern uint32_t _bss_end; + + /* Configure the global pointer register + * (This should be the first thing startup does, as any other piece of code could be + * relaxed by the linker to access something relative to __global_pointer$) + */ + __asm__ __volatile__(".option push\n" + ".option norelax\n" + "la gp, __global_pointer$\n" + ".option pop"); + + __asm__ __volatile__("la t0, _esp32c3_vector_table \n" + "csrw mtvec, t0 \n"); + + /* Disable normal interrupts. */ + csr_read_clear(mstatus, MSTATUS_MIE); + + /* Zero out BSS. Clobber _bss_start to avoid memset() elision. */ + (void)memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start)); + __asm__ __volatile__("" : : "g"(&_bss_start) : "memory"); + +#if !CONFIG_BOOTLOADER_ESP_IDF + /* The watchdog timer is enabled in the 1st stage (ROM) bootloader. + * We're done booting, so disable it. + * If 2nd stage bootloader from IDF is enabled, then that will take + * care of this. + */ + volatile uint32_t *wdt_timg_protect = (uint32_t *)TIMG_WDTWPROTECT_REG(0); + volatile uint32_t *wdt_timg_reg = (uint32_t *)TIMG_WDTCONFIG0_REG(0); + + *wdt_rtc_protect = RTC_CNTL_WDT_WKEY_VALUE; + *wdt_rtc_reg &= ~RTC_CNTL_WDT_FLASHBOOT_MOD_EN; + *wdt_rtc_protect = 0; + *wdt_timg_protect = TIMG_WDT_WKEY_VALUE; + *wdt_timg_reg &= ~TIMG_WDT_FLASHBOOT_MOD_EN; + *wdt_timg_protect = 0; +#endif + +#if CONFIG_BOOTLOADER_ESP_IDF + /* ESP-IDF 2nd stage bootloader enables RTC WDT to check on startup sequence + * related issues in application. Hence disable that as we are about to start + * Zephyr environment. + */ + *wdt_rtc_protect = RTC_CNTL_WDT_WKEY_VALUE; + *wdt_rtc_reg &= ~RTC_CNTL_WDT_EN; + *wdt_rtc_protect = 0; +#endif + + /* Configure the Cache MMU size for instruction and rodata in flash. */ + extern uint32_t esp32c3_rom_cache_set_idrom_mmu_size(uint32_t irom_size, uint32_t drom_size); + extern int _rodata_reserved_start; + 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); + + esp32c3_rom_cache_set_idrom_mmu_size(cache_mmu_irom_size, CACHE_DROM_MMU_MAX_END - cache_mmu_irom_size); + + /* set global esp32c3's INTC masking level */ + esprv_intc_int_set_threshold(1); + + /* Start Zephyr */ + z_cstart(); + + CODE_UNREACHABLE; +} + +/* Boot-time static default printk handler, possibly to be overridden later. */ +int IRAM_ATTR arch_printk_char_out(int c) +{ + if (c == '\n') { + esp32c3_rom_uart_tx_one_char('\r'); + } + esp32c3_rom_uart_tx_one_char(c); + return 0; +} + +void IRAM_ATTR esp_restart_noos(void) +{ + /* Disable interrupts */ + csr_read_clear(mstatus, MSTATUS_MIE); + + /* Flush any data left in UART FIFOs */ + esp32c3_rom_uart_tx_wait_idle(0); + esp32c3_rom_uart_tx_wait_idle(1); + esp32c3_rom_uart_tx_wait_idle(2); + + /* 2nd stage bootloader reconfigures SPI flash signals. */ + /* Reset them to the defaults expected by ROM */ + WRITE_PERI_REG(GPIO_FUNC0_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC1_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC2_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC3_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC4_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC5_IN_SEL_CFG_REG, 0x30); + + /* Reset wifi/bluetooth/ethernet/sdio (bb/mac) */ + SET_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, + SYSTEM_BB_RST | SYSTEM_FE_RST | SYSTEM_MAC_RST | SYSTEM_BT_RST | + SYSTEM_BTMAC_RST | SYSTEM_SDIO_RST | SYSTEM_EMAC_RST | + SYSTEM_MACPWR_RST | SYSTEM_RW_BTMAC_RST | SYSTEM_RW_BTLP_RST | + BLE_REG_REST_BIT | BLE_PWR_REG_REST_BIT | BLE_BB_REG_REST_BIT); + + REG_WRITE(SYSTEM_CORE_RST_EN_REG, 0); + + /* Reset timer/spi/uart */ + SET_PERI_REG_MASK(SYSTEM_PERIP_RST_EN0_REG, + SYSTEM_TIMERS_RST | SYSTEM_SPI01_RST | SYSTEM_UART_RST); + REG_WRITE(SYSTEM_PERIP_RST_EN0_REG, 0); + /* Reset dma */ + SET_PERI_REG_MASK(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_DMA_RST); + REG_WRITE(SYSTEM_PERIP_RST_EN1_REG, 0); + + /* Reset core */ + soc_ll_reset_core(0); + + while (true) { + ; + } +} + +void sys_arch_reboot(int type) +{ + esp_restart_noos(); +} + +void arch_irq_enable(unsigned int irq) +{ + uint32_t key = irq_lock(); + + esprv_intc_int_set_priority(irq, ESP32C3_INTC_DEFAULT_PRIO); + esprv_intc_int_set_type(irq, 0); + esprv_intc_int_enable(1 << irq); + + irq_unlock(key); +} + +void arch_irq_disable(unsigned int irq) +{ + esprv_intc_int_disable(1 << irq); +} + +int arch_irq_is_enabled(unsigned int irq) +{ + return (esprv_intc_get_interrupt_unmask() & (1 << irq)); +} diff --git a/soc/riscv/esp32c3/soc.h b/soc/riscv/esp32c3/soc.h new file mode 100644 index 00000000000..03c31d2b092 --- /dev/null +++ b/soc/riscv/esp32c3/soc.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __SOC_H__ +#define __SOC_H__ + +#ifndef _ASMLANGUAGE +#include +#include +#include +#include +#endif + +#include + +/* IRQ numbers */ +#define RISCV_MACHINE_SOFT_IRQ 3 /* Machine Software Interrupt */ +#define RISCV_MACHINE_TIMER_IRQ 7 /* Machine Timer Interrupt */ +#define RISCV_MACHINE_EXT_IRQ 11 /* Machine External Interrupt */ + +/* ECALL Exception numbers */ +#define SOC_MCAUSE_ECALL_EXP 11 /* Machine ECALL instruction */ +#define SOC_MCAUSE_USER_ECALL_EXP 8 /* User ECALL instruction */ + +/* Interrupt Mask */ +#define SOC_MCAUSE_IRQ_MASK (1 << 31) +/* Exception code Mask */ +#define SOC_MCAUSE_EXP_MASK 0x7FFFFFFF +/* SOC-Specific EXIT ISR command */ +#define SOC_ERET mret + +#ifndef _ASMLANGUAGE + +extern void esp32c3_rom_intr_matrix_set(int cpu_no, uint32_t model_num, uint32_t intr_num); +extern void esp32c3_rom_uart_attach(void); +extern void esp32c3_rom_uart_tx_wait_idle(uint8_t uart_no); +extern STATUS esp32c3_rom_uart_tx_one_char(uint8_t chr); +extern STATUS esp32c3_rom_uart_rx_one_char(uint8_t *chr); +extern void esp32c3_rom_ets_set_user_start(uint32_t start); + +#endif /* _ASMLANGUAGE */ + +#endif /* __SOC_H__ */ diff --git a/soc/riscv/esp32c3/soc_irq.S b/soc/riscv/esp32c3/soc_irq.S new file mode 100644 index 00000000000..7edbe136ee6 --- /dev/null +++ b/soc/riscv/esp32c3/soc_irq.S @@ -0,0 +1,19 @@ +/* Copyright 2021 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* Exports */ +GTEXT(__soc_is_irq) +GTEXT(__soc_handle_irq) + +SECTION_FUNC(exception.other, __soc_is_irq) + csrr a0, mcause + srli a0, a0, 31 + ret + +SECTION_FUNC(exception.other, __soc_handle_irq) + ret diff --git a/soc/riscv/esp32c3/vectors.S b/soc/riscv/esp32c3/vectors.S new file mode 100644 index 00000000000..67e81613e78 --- /dev/null +++ b/soc/riscv/esp32c3/vectors.S @@ -0,0 +1,35 @@ +/* Copyright 2020 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc.h" +#include "soc/interrupt_reg.h" +#include "riscv/rvruntime-frames.h" +#include "soc/soc_caps.h" +#include + +/* Imports */ +GTEXT(__irq_wrapper) + + /* This is the vector table. MTVEC points here. + * + * Use 4-byte intructions here. 1 instruction = 1 entry of the table. + * The CPU jumps to MTVEC (i.e. the first entry) in case of an exception, + * and (MTVEC & 0xfffffffc) + (mcause & 0x7fffffff) * 4, in case of an interrupt. + * + * Note: for our CPU, we need to place this on a 256-byte boundary, as CPU + * only uses the 24 MSBs of the MTVEC, i.e. (MTVEC & 0xffffff00). + */ + + .global _esp32c3_vector_table + .section .exception_vectors.text + .balign 0x100 + .type _esp32c3_vector_table, @function + +_esp32c3_vector_table: + .option push + .option norvc + .rept (32) + j __irq_wrapper /* 32 identical entries, all pointing to the interrupt handler */ + .endr