esp_hal/soc/esp32s3/
mod.rs

1//! # SOC (System-on-Chip) module (ESP32-S3)
2//!
3//! ## Overview
4//!
5//! The `SOC` module provides access, functions and structures that are useful
6//! for interacting with various system-related peripherals on `ESP32-S3` chip.
7//!
8//! Also few constants are defined in this module for `ESP32-S3` chip:
9//!    * I2S_SCLK: 160_000_000 - I2S clock frequency
10//!    * I2S_DEFAULT_CLK_SRC: 2 - I2S clock source
11
12use core::ptr::addr_of_mut;
13
14use crate::rtc_cntl::SocResetReason;
15
16crate::unstable_module! {
17    pub mod efuse;
18    #[cfg(feature = "psram")]
19    pub mod psram;
20    pub mod trng;
21    pub mod ulp_core;
22}
23pub mod cpu_control;
24pub mod gpio;
25pub mod peripherals;
26pub(crate) mod regi2c;
27
28/// The name of the chip ("esp32s3") as `&str`
29#[macro_export]
30macro_rules! chip {
31    () => {
32        "esp32s3"
33    };
34}
35
36/// A link to the Technical Reference Manual (TRM) for the chip.
37#[doc(hidden)]
38#[macro_export]
39macro_rules! trm_link {
40    () => { "https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf" };
41}
42
43#[cfg_attr(not(feature = "unstable"), allow(unused))]
44pub(crate) mod constants {
45    use crate::time::Rate;
46
47    /// The base clock frequency for the I2S peripheral (Hertz).
48    pub const I2S_SCLK: u32 = 160_000_000;
49    /// The default clock source for I2S operations.
50    pub const I2S_DEFAULT_CLK_SRC: u8 = 2;
51
52    /// The starting address of the Remote Control (RMT) module's RAM.
53    pub const RMT_RAM_START: usize = 0x60016800;
54    /// The size (number of pulse codes) of each RMT channel's dedicated RAM.
55    pub const RMT_CHANNEL_RAM_SIZE: usize = 48;
56    /// RMT Clock source value.
57    pub const RMT_CLOCK_SRC: u8 = 1;
58    /// RMT Clock source frequency.
59    pub const RMT_CLOCK_SRC_FREQ: Rate = Rate::from_mhz(80);
60
61    /// A reference clock tick of 1 MHz.
62    pub const RC_FAST_CLK: Rate = Rate::from_khz(17500);
63}
64
65#[doc(hidden)]
66#[unsafe(link_section = ".rwtext")]
67pub unsafe fn configure_cpu_caches() {
68    // this is just the bare minimum we need to run code from flash
69    // consider implementing more advanced configurations
70    // see https://github.com/apache/incubator-nuttx/blob/master/arch/xtensa/src/esp32s3/esp32s3_start.c
71
72    unsafe extern "C" {
73        fn rom_config_instruction_cache_mode(
74            cfg_cache_size: u32,
75            cfg_cache_ways: u8,
76            cfg_cache_line_size: u8,
77        );
78    }
79
80    // ideally these should be configurable
81    const CONFIG_ESP32S3_INSTRUCTION_CACHE_SIZE: u32 = 0x8000; // ESP32S3_INSTRUCTION_CACHE_32KB
82    const CONFIG_ESP32S3_ICACHE_ASSOCIATED_WAYS: u8 = 8; // ESP32S3_INSTRUCTION_CACHE_8WAYS
83    const CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_SIZE: u8 = 32; // ESP32S3_INSTRUCTION_CACHE_LINE_32B
84
85    // Configure the mode of instruction cache: cache size, cache line size.
86    unsafe {
87        rom_config_instruction_cache_mode(
88            CONFIG_ESP32S3_INSTRUCTION_CACHE_SIZE,
89            CONFIG_ESP32S3_ICACHE_ASSOCIATED_WAYS,
90            CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_SIZE,
91        );
92    }
93}
94
95/// Function initializes ESP32S3 specific memories (RTC slow and fast) and
96/// then calls original Reset function
97///
98/// ENTRY point is defined in memory.x
99/// *Note: the pre_init function is called in the original reset handler
100/// after the initializations done in this function*
101#[doc(hidden)]
102#[unsafe(no_mangle)]
103#[unsafe(link_section = ".rwtext")]
104pub unsafe extern "C" fn ESP32Reset() -> ! {
105    unsafe {
106        configure_cpu_caches();
107    }
108
109    // These symbols come from `memory.x`
110    unsafe extern "C" {
111        static mut _rtc_fast_bss_start: u32;
112        static mut _rtc_fast_bss_end: u32;
113        static mut _rtc_fast_persistent_start: u32;
114        static mut _rtc_fast_persistent_end: u32;
115
116        static mut _rtc_slow_bss_start: u32;
117        static mut _rtc_slow_bss_end: u32;
118        static mut _rtc_slow_persistent_start: u32;
119        static mut _rtc_slow_persistent_end: u32;
120
121        static mut _stack_start_cpu0: u32;
122
123        static mut __stack_chk_guard: u32;
124    }
125
126    // set stack pointer to end of memory: no need to retain stack up to this point
127    unsafe {
128        xtensa_lx::set_stack_pointer(addr_of_mut!(_stack_start_cpu0));
129    }
130
131    // copying data from flash to various data segments is done by the bootloader
132    // initialization to zero needs to be done by the application
133
134    // Initialize RTC RAM
135    unsafe {
136        xtensa_lx_rt::zero_bss(
137            addr_of_mut!(_rtc_fast_bss_start),
138            addr_of_mut!(_rtc_fast_bss_end),
139        );
140        xtensa_lx_rt::zero_bss(
141            addr_of_mut!(_rtc_slow_bss_start),
142            addr_of_mut!(_rtc_slow_bss_end),
143        );
144    }
145    if matches!(
146        crate::system::reset_reason(),
147        None | Some(SocResetReason::ChipPowerOn)
148    ) {
149        unsafe {
150            xtensa_lx_rt::zero_bss(
151                addr_of_mut!(_rtc_fast_persistent_start),
152                addr_of_mut!(_rtc_fast_persistent_end),
153            );
154            xtensa_lx_rt::zero_bss(
155                addr_of_mut!(_rtc_slow_persistent_start),
156                addr_of_mut!(_rtc_slow_persistent_end),
157            );
158        }
159    }
160
161    let stack_chk_guard = core::ptr::addr_of_mut!(__stack_chk_guard);
162    // we _should_ use a random value but we don't have a good source for random
163    // numbers here
164    unsafe {
165        stack_chk_guard.write_volatile(esp_config::esp_config_int!(
166            u32,
167            "ESP_HAL_CONFIG_STACK_GUARD_VALUE"
168        ));
169    }
170
171    crate::interrupt::setup_interrupts();
172
173    // continue with default reset handler
174    unsafe { xtensa_lx_rt::Reset() }
175}
176
177/// The ESP32 has a first stage bootloader that handles loading program data
178/// into the right place therefore we skip loading it again.
179#[doc(hidden)]
180#[unsafe(no_mangle)]
181#[rustfmt::skip]
182pub extern "Rust" fn __init_data() -> bool {
183    false
184}
185
186/// Write back a specific range of data in the cache.
187#[doc(hidden)]
188#[unsafe(link_section = ".rwtext")]
189pub unsafe fn cache_writeback_addr(addr: u32, size: u32) {
190    unsafe extern "C" {
191        fn rom_Cache_WriteBack_Addr(addr: u32, size: u32);
192        fn Cache_Suspend_DCache_Autoload() -> u32;
193        fn Cache_Resume_DCache_Autoload(value: u32);
194    }
195    // suspend autoload, avoid load cachelines being written back
196    unsafe {
197        let autoload = Cache_Suspend_DCache_Autoload();
198        rom_Cache_WriteBack_Addr(addr, size);
199        Cache_Resume_DCache_Autoload(autoload);
200    }
201}
202
203/// Invalidate a specific range of addresses in the cache.
204#[doc(hidden)]
205#[unsafe(link_section = ".rwtext")]
206pub unsafe fn cache_invalidate_addr(addr: u32, size: u32) {
207    unsafe extern "C" {
208        fn Cache_Invalidate_Addr(addr: u32, size: u32);
209    }
210    unsafe {
211        Cache_Invalidate_Addr(addr, size);
212    }
213}
214
215/// Get the size of a cache line in the DCache.
216#[doc(hidden)]
217#[unsafe(link_section = ".rwtext")]
218pub unsafe fn cache_get_dcache_line_size() -> u32 {
219    unsafe extern "C" {
220        fn Cache_Get_DCache_Line_Size() -> u32;
221    }
222    unsafe { Cache_Get_DCache_Line_Size() }
223}
224
225pub(crate) fn pre_init() {}