diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 8c3cf94481e..edaf96e88f0 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -15,6 +15,7 @@ Bare-metal `no_std` Rust HAL for Espressif SoCs. MSRV: **1.88.0** (source: `MSRV | esp32c6 | RISC-V | `riscv32imac-unknown-none-elf` | `--toolchain stable` | | esp32c61 | RISC-V | `riscv32imac-unknown-none-elf` | `--toolchain stable` | | esp32h2 | RISC-V | `riscv32imac-unknown-none-elf` | `--toolchain stable` | +| esp32p4 | RISC-V | `riscv32imafc-unknown-none-elf` | `--toolchain stable` | ## Commands diff --git a/.github/workflows/api-baseline-check.yml b/.github/workflows/api-baseline-check.yml index 7bdecd0b691..200911ab5cf 100644 --- a/.github/workflows/api-baseline-check.yml +++ b/.github/workflows/api-baseline-check.yml @@ -48,7 +48,7 @@ jobs: - uses: dtolnay/rust-toolchain@v1 if: env.SKIP_CI != 'true' with: - target: riscv32imc-unknown-none-elf,riscv32imac-unknown-none-elf + target: riscv32imc-unknown-none-elf,riscv32imac-unknown-none-elf,riscv32imafc-unknown-none-elf toolchain: stable components: rust-src diff --git a/.github/workflows/binary-size.yml b/.github/workflows/binary-size.yml index d62c6410129..424805b0b8d 100644 --- a/.github/workflows/binary-size.yml +++ b/.github/workflows/binary-size.yml @@ -49,6 +49,9 @@ jobs: esp32c5|esp32c6|esp32c61|esp32h2) echo "rust-target=riscv32imac-unknown-none-elf" >> $GITHUB_OUTPUT ;; + esp32p4) + echo "rust-target=riscv32imafc-unknown-none-elf" >> $GITHUB_OUTPUT + ;; *) echo "Error: Unknown SoC: ${{ matrix.soc }}" exit 1 diff --git a/.github/workflows/ci-nightly.yml b/.github/workflows/ci-nightly.yml index 1f3b85d7820..0884f20aaf3 100644 --- a/.github/workflows/ci-nightly.yml +++ b/.github/workflows/ci-nightly.yml @@ -33,6 +33,7 @@ jobs: "esp32c6", "esp32c61", "esp32h2", + "esp32p4", ] steps: - uses: actions/checkout@v6 @@ -40,7 +41,7 @@ jobs: # Install the Rust nightly toolchain for RISC-V devices: - uses: dtolnay/rust-toolchain@v1 with: - target: riscv32imc-unknown-none-elf,riscv32imac-unknown-none-elf + target: riscv32imc-unknown-none-elf,riscv32imac-unknown-none-elf,riscv32imafc-unknown-none-elf toolchain: nightly components: rust-src, clippy, rustfmt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0d9eac78c0e..f535df1079e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,7 +77,7 @@ jobs: - uses: dtolnay/rust-toolchain@v1 if: env.SKIP_CI != 'true' with: - target: riscv32imc-unknown-none-elf,riscv32imac-unknown-none-elf + target: riscv32imc-unknown-none-elf,riscv32imac-unknown-none-elf,riscv32imafc-unknown-none-elf toolchain: stable components: rust-src @@ -108,6 +108,7 @@ jobs: cargo xcheck ci esp32c6 --toolchain stable --no-lint --no-docs cargo xcheck ci esp32c61 --toolchain stable --no-lint --no-docs cargo xcheck ci esp32h2 --toolchain stable --no-lint --no-docs + cargo xcheck ci esp32p4 --toolchain stable --no-lint --no-docs detect-extras-runner: needs: get-labels @@ -166,13 +167,13 @@ jobs: # Install the Rust stable toolchain for RISC-V devices: - uses: dtolnay/rust-toolchain@v1 with: - target: riscv32imc-unknown-none-elf,riscv32imac-unknown-none-elf + target: riscv32imc-unknown-none-elf,riscv32imac-unknown-none-elf,riscv32imafc-unknown-none-elf toolchain: stable components: rust-src # Install the Rust nightly toolchain for RISC-V devices: - uses: dtolnay/rust-toolchain@v1 with: - target: riscv32imc-unknown-none-elf,riscv32imac-unknown-none-elf + target: riscv32imc-unknown-none-elf,riscv32imac-unknown-none-elf,riscv32imafc-unknown-none-elf toolchain: nightly components: rust-src @@ -184,7 +185,7 @@ jobs: - name: Build RISC-V docs if: matrix.group == 'riscv' shell: bash - run: cargo xtask build documentation --chips esp32c2,esp32c3,esp32c5,esp32c6,esp32c61,esp32h2 + run: cargo xtask build documentation --chips esp32c2,esp32c3,esp32c5,esp32c6,esp32c61,esp32h2,esp32p4 # -------------------------------------------------------------------------- # MSRV @@ -223,7 +224,7 @@ jobs: - uses: dtolnay/rust-toolchain@v1 if: env.SKIP_CI != 'true' && matrix.group == 'riscv' with: - target: riscv32imc-unknown-none-elf,riscv32imac-unknown-none-elf,x86_64-unknown-linux-gnu + target: riscv32imc-unknown-none-elf,riscv32imac-unknown-none-elf,riscv32imafc-unknown-none-elf,x86_64-unknown-linux-gnu toolchain: ${{ env.MSRV }} components: rust-src,clippy @@ -235,7 +236,7 @@ jobs: - name: msrv RISC-V (esp-hal) if: env.SKIP_CI != 'true' && matrix.group == 'riscv' run: | - cargo xtask lint-packages --chips esp32c2,esp32c3,esp32c5,esp32c6,esp32c61,esp32h2 --toolchain ${{ env.MSRV }} + cargo xtask lint-packages --chips esp32c2,esp32c3,esp32c5,esp32c6,esp32c61,esp32h2,esp32p4 --toolchain ${{ env.MSRV }} - name: msrv Xtensa (esp-hal) if: env.SKIP_CI != 'true' && matrix.group == 'xtensa' diff --git a/.github/workflows/dispatch.yml b/.github/workflows/dispatch.yml index bf5e96c382a..bf3c4ae0ebc 100644 --- a/.github/workflows/dispatch.yml +++ b/.github/workflows/dispatch.yml @@ -603,7 +603,7 @@ jobs: fi # Known chips — everything matching these is a chip, first token is the example - KNOWN_CHIPS="esp32 esp32c2 esp32c3 esp32c5 esp32c6 esp32c61 esp32s2 esp32s3" + KNOWN_CHIPS="esp32 esp32c2 esp32c3 esp32c5 esp32c6 esp32c61 esp32s2 esp32s3 esp32p4" EXAMPLE_NAME="" CHIPS_JSON="[" diff --git a/.github/workflows/hil.yml b/.github/workflows/hil.yml index 66365df1441..613a96a4067 100644 --- a/.github/workflows/hil.yml +++ b/.github/workflows/hil.yml @@ -146,6 +146,10 @@ jobs: rust-target: riscv32imac-unknown-none-elf runner: esp32h2-usb host: armv7 + - soc: esp32p4 + rust-target: riscv32imafc-unknown-none-elf + runner: esp32p4 + host: aarch64 - soc: esp32 rust-target: xtensa-esp32-none-elf runner: esp32-jtag @@ -244,6 +248,10 @@ jobs: rust-target: riscv32imac-unknown-none-elf runner: esp32h2-usb host: armv7 + - soc: esp32p4 + rust-target: riscv32imafc-unknown-none-elf + runner: esp32p4 + host: aarch64 - soc: esp32 rust-target: xtensa-esp32-none-elf runner: esp32-jtag @@ -392,6 +400,10 @@ jobs: rust-target: riscv32imac-unknown-none-elf runner: esp32h2-usb host: armv7 + - soc: esp32p4 + rust-target: riscv32imafc-unknown-none-elf + runner: esp32p4 + host: aarch64 - soc: esp32 rust-target: xtensa-esp32-none-elf runner: esp32-jtag @@ -482,6 +494,10 @@ jobs: rust-target: riscv32imac-unknown-none-elf runner: esp32h2-usb host: armv7 + - soc: esp32p4 + rust-target: riscv32imafc-unknown-none-elf + runner: esp32p4 + host: aarch64 - soc: esp32 rust-target: xtensa-esp32-none-elf runner: esp32-jtag diff --git a/.github/workflows/pre-rel-check.yml b/.github/workflows/pre-rel-check.yml index 20195203e18..2031d8fac12 100644 --- a/.github/workflows/pre-rel-check.yml +++ b/.github/workflows/pre-rel-check.yml @@ -30,14 +30,14 @@ jobs: # Install the Rust stable toolchain for RISC-V devices: - uses: dtolnay/rust-toolchain@v1 with: - target: riscv32imc-unknown-none-elf,riscv32imac-unknown-none-elf + target: riscv32imc-unknown-none-elf,riscv32imac-unknown-none-elf,riscv32imafc-unknown-none-elf toolchain: stable components: rust-src # Install the Rust nightly toolchain for RISC-V devices: - uses: dtolnay/rust-toolchain@v1 with: - target: riscv32imc-unknown-none-elf,riscv32imac-unknown-none-elf + target: riscv32imc-unknown-none-elf,riscv32imac-unknown-none-elf,riscv32imafc-unknown-none-elf toolchain: nightly components: rust-src @@ -79,5 +79,8 @@ jobs: cargo xcheck ci esp32c61 --toolchain stable --steps=lp-examples,examples,qa-test,tests cargo xtask build examples --toolchain stable --package=compile-tests all --chip=esp32c61 + cargo xcheck ci esp32p4 --toolchain stable --steps=lp-examples,examples,qa-test,tests + cargo xtask build examples --toolchain stable --package=compile-tests all --chip=esp32p4 + cargo xcheck ci esp32h2 --toolchain stable --steps=lp-examples,examples,qa-test,tests cargo xtask build examples --toolchain stable --package=compile-tests all --chip=esp32h2 diff --git a/esp-alloc/CHANGELOG.md b/esp-alloc/CHANGELOG.md index 8fa306a9067..e367cbed386 100644 --- a/esp-alloc/CHANGELOG.md +++ b/esp-alloc/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Support for ESP32-P4 (#5523) ### Changed diff --git a/esp-alloc/Cargo.toml b/esp-alloc/Cargo.toml index 17bc6bd2e00..6ce3f92fe6f 100644 --- a/esp-alloc/Cargo.toml +++ b/esp-alloc/Cargo.toml @@ -120,6 +120,8 @@ esp32c61 = ["esp-sync/esp32c61"] ## esp32h2 = ["esp-sync/esp32h2"] ## +esp32p4 = ["esp-sync/esp32p4"] +## esp32 = ["esp-sync/esp32"] ## esp32s2 = ["esp-sync/esp32s2"] diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 3c8429e7fdc..0137f55e4b0 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - C5 and C61: Enable RTC timekeeping (#5449) - C61: usb-serial-jtag and debug-assist (#5427) - C61: dedicated gpio (#5426) -- Initial ESP32-P4 (chip revision v3.0+) support (#5400) +- Initial ESP32-P4 (chip revision v3.0+) support (#5400, #5523) - P4: Initial peripheral support for GPIO, UART, I2C, SPI, DMA, USB Serial/JTAG, eFuse, SYSTIMER (#5400) - P4: AP-HEX PSRAM driver stub with configurable HP L2MEM cache/RAM split via `ESP_HAL_CONFIG_L2_CACHE_SIZE` (#5400) - C5 and C61: I2S support (#5483) diff --git a/esp-hal/Cargo.toml b/esp-hal/Cargo.toml index 3917c20535c..86b01ae3cfa 100644 --- a/esp-hal/Cargo.toml +++ b/esp-hal/Cargo.toml @@ -111,10 +111,7 @@ esp32c61 = { version = "0.3", features = ["critical-section", "rt"], optional = esp32h2 = { version = "0.19", features = ["critical-section", "rt"], optional = true } esp32s2 = { version = "0.31", features = ["critical-section", "rt"], optional = true } esp32s3 = { version = "0.35", features = ["critical-section", "rt"], optional = true } -# ESP32-P4 PAC: use git rev fc3e6d4 (matching firmware consumers) -- the -# crates.io release of esp32p4 0.2 doesn't match this revision's generated -# register layout, so we intentionally stick with the git dep here. -esp32p4 = { version = "0.2", features = ["critical-section", "rt"], optional = true, git = "https://github.com/esp-rs/esp-pacs", rev = "fc3e6d4" } +esp32p4 = { version = "0.2", features = ["critical-section", "rt"], optional = true, git = "https://github.com/esp-rs/esp-pacs", rev = "c4a5792c462c32116eb4a367a37c2d167ae94a40" } [target.'cfg(target_arch = "riscv32")'.dependencies] riscv = { version = "0.15.0" } @@ -236,10 +233,7 @@ esp32c6 = [ "esp-sync/esp32c6", "esp-metadata-generated/esp32c6", ] -## ESP32-P4 (chip revision v3.x / eco5 only, RISC-V dual-core HP + LP core) -## NOTE: This targets P4X (ESP32-P4NRW16X/32X) with chip revision >= v3.0. -## NRND variants (without X suffix) are NOT supported. -## Based on TRM v0.5 (Pre-release) and Chip Revision v3.x User Guide v1.0. +## ESP32-P4 (chip revision >= v3.x) esp32p4 = [ "dep:esp32p4", "esp-riscv-rt/rtc-ram", diff --git a/esp-hal/README.md b/esp-hal/README.md index 95a0427e617..02922dce471 100644 --- a/esp-hal/README.md +++ b/esp-hal/README.md @@ -70,7 +70,7 @@ For help getting started with this HAL, please refer to [The Rust on ESP Book] a | Camera interface | ❌ | | | | | | | ❌ | ❌ | ⚒️ | | DAC | ⚒️ | | | | | | | | ⚒️ | | | Dedicated GPIO | | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | | ⚒️ | ⚒️ | -| DMA | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | +| DMA | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ❌ | ⚒️ | ⚒️ | | DS | | | [❌][884] [^1] | [❌][884] [^1] | [❌][884] [^1] | | [❌][884] [^1] | ❌ | [❌][884] [^1] | [❌][884] [^1] | | ECDSA | | | | [❌][5444] [^1] | | [❌][5444] [^1] | [❌][5444] [^1] | ❌ | | | | ECC | | ⚒️ | | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ❌ | | | @@ -106,7 +106,7 @@ For help getting started with this HAL, please refer to [The Rust on ESP Book] a | SPI slave | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ❌ | ⚒️ | ⚒️ | | SYSTIMER | | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | | Temperature sensor | ⚒️ | ⚒️ | ⚒️ | [❌][5153] [^1] | ⚒️ | [❌][5421] [^1] | ⚒️ | ❌ | ⚒️ | ⚒️ | -| Timers | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | | ⚒️ | ⚒️ | +| Timers | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | ⚒️ | | Touch | ⚒️ | | | [❌][5164] [^1] | | | | ❌ | [❌][1905] [^1] | [❌][1905] [^1] | | TWAI / CAN / CANFD | ⚒️ | | ⚒️ | [❌][5163] [^1] | ⚒️ | | ⚒️ | ❌ | ⚒️ | ⚒️ | | UART | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ⚒️ | ✔️ | ✔️ | diff --git a/esp-hal/ld/esp32h2/esp32h2.x b/esp-hal/ld/esp32h2/esp32h2.x index 180d4a211b4..06b0dd3dee4 100644 --- a/esp-hal/ld/esp32h2/esp32h2.x +++ b/esp-hal/ld/esp32h2/esp32h2.x @@ -1,5 +1,5 @@ /* The ESP32-C2 and ESP32-C3 have interrupt IDs 1-31, while the ESP32-C6 and ESP32-H2 have - IDs 0-31, so we much define the handler for the one additional interrupt + IDs 0-31, so we must define the handler for the one additional interrupt ID: */ PROVIDE(interrupt0 = DefaultHandler); diff --git a/esp-hal/ld/esp32p4/esp32p4.x b/esp-hal/ld/esp32p4/esp32p4.x index 171eedf75fc..789a032e0d1 100644 --- a/esp-hal/ld/esp32p4/esp32p4.x +++ b/esp-hal/ld/esp32p4/esp32p4.x @@ -1,33 +1,10 @@ -ENTRY(_start) - -PROVIDE(_stext = ORIGIN(ROTEXT)); PROVIDE(_max_hart_id = 1); -PROVIDE(UserSoft = DefaultHandler); -PROVIDE(SupervisorSoft = DefaultHandler); -PROVIDE(MachineSoft = DefaultHandler); -PROVIDE(UserTimer = DefaultHandler); -PROVIDE(SupervisorTimer = DefaultHandler); -PROVIDE(MachineTimer = DefaultHandler); -PROVIDE(UserExternal = DefaultHandler); -PROVIDE(SupervisorExternal = DefaultHandler); -PROVIDE(MachineExternal = DefaultHandler); - -PROVIDE(ExceptionHandler = DefaultExceptionHandler); - /* The ESP32-C2 and ESP32-C3 have interrupt IDs 1-31, while the ESP32-C6, - ESP32-H2, and ESP32-P4 have IDs 0-31, so we much define the handler for the + ESP32-H2, and ESP32-P4 have IDs 0-31, so we must define the handler for the one additional interrupt ID: */ PROVIDE(interrupt0 = DefaultHandler); -/* Peripheral interrupt symbols are provided by the esp32p4 PAC's `device.x`, - which is included by `hal-defaults.x`. No need to list them here. */ - -PROVIDE(__post_init = default_post_init); - -/* A PAC/HAL defined routine that should initialize custom interrupt controller if needed. */ -PROVIDE(_setup_interrupts = default_setup_interrupts); - /* # Multi-processing hook function fn _mp_hook() -> bool; This function is called from all the harts and must return true only for one hart, @@ -36,38 +13,24 @@ PROVIDE(_setup_interrupts = default_setup_interrupts); */ PROVIDE(_mp_hook = default_mp_hook); -/* # Start trap function override - By default uses the riscv crates default trap handler - but by providing the `_start_trap` symbol external crates can override. -*/ -PROVIDE(_start_trap = _default_start_trap); - -/* Must be called __global_pointer$ for linker relaxations to work. */ -PROVIDE(__global_pointer$ = _data_start + 0x800); - -/* NOTE: .trap section is generated by build.rs in rwtext.x, not duplicated here. */ +SECTIONS { + /* Shared sections - ordering matters */ + INCLUDE "rwtext.x" + INCLUDE "rwdata.x" + /* End of Shared sections */ +} SECTIONS { /** * Bootloader really wants to have separate segments for ROTEXT and RODATA - * It also needs to be located in a separate 64k flash segment. + * Thus, we need to force a gap here. */ .text_gap (NOLOAD): { - . = ALIGN(0x10000) + 0x20; + . = . + 8; + . = ALIGN(4) + 0x20; } > ROM } -INSERT BEFORE .rodata; - -/* Shared sections - ordering matters. - rwtext.x and rwdata.x contain bare section directives that need a SECTIONS context. - We wrap them in SECTIONS {} blocks. */ -SECTIONS { - INCLUDE "rwtext.x" -} - -SECTIONS { - INCLUDE "rwdata.x" -} +INSERT BEFORE .text; INCLUDE "rodata.x" INCLUDE "text.x" @@ -77,4 +40,4 @@ INCLUDE "metadata.x" INCLUDE "eh_frame.x" /* End of Shared sections */ -_dram_data_start = ORIGIN(RAM) + SIZEOF(.trap) + SIZEOF(.rwtext); \ No newline at end of file +_dram_data_start = ORIGIN(RAM) + SIZEOF(.trap) + SIZEOF(.rwtext); diff --git a/esp-hal/ld/esp32p4/memory.x b/esp-hal/ld/esp32p4/memory.x index f128ed2b2e9..d4305627a9d 100644 --- a/esp-hal/ld/esp32p4/memory.x +++ b/esp-hal/ld/esp32p4/memory.x @@ -14,25 +14,26 @@ 3 "0KB" 0 KB 0x4FF00000 */ -MEMORY -{ - /* CONFIG 0 */ #IF ESP_HAL_CONFIG_L2_CACHE_SIZE_512KB - RAM : ORIGIN = 0x4FF80000, LENGTH = 0x4FFAE000 - 0x4FF80000 +RESERVED_L2_CACHE = 0x80000; #ENDIF - /* CONFIG 1 */ + #IF ESP_HAL_CONFIG_L2_CACHE_SIZE_256KB - RAM : ORIGIN = 0x4FF40000, LENGTH = 0x4FFAE000 - 0x4FF40000 +RESERVED_L2_CACHE = 0x40000; #ENDIF - /* CONFIG 2 */ + #IF ESP_HAL_CONFIG_L2_CACHE_SIZE_128KB - RAM : ORIGIN = 0x4FF20000, LENGTH = 0x4FFAE000 - 0x4FF20000 +RESERVED_L2_CACHE = 0x20000; #ENDIF - /* CONFIG 3 */ + #IF ESP_HAL_CONFIG_L2_CACHE_SIZE_0KB - RAM : ORIGIN = 0x4FF00000, LENGTH = 0x4FFAE000 - 0x4FF00000 +RESERVED_L2_CACHE = 0; #ENDIF +MEMORY +{ + RAM : ORIGIN = 0x4FF00000 + RESERVED_L2_CACHE, LENGTH = 0x4FFAE000 - RESERVED_L2_CACHE - 0x4FF00000 + /* External flash (XIP via cache); +0x20 skips the IDF app image header. */ ROM : ORIGIN = 0x40000000 + 0x20, LENGTH = 0x400000 - 0x20 diff --git a/esp-hal/src/clock/mod.rs b/esp-hal/src/clock/mod.rs index 1844b6ba573..33805e11722 100644 --- a/esp-hal/src/clock/mod.rs +++ b/esp-hal/src/clock/mod.rs @@ -104,8 +104,6 @@ impl CpuClock { } else if #[cfg(esp32h2)] { Self::_96MHz } else if #[cfg(esp32p4)] { - // ESP32-P4 v3.x (eco5): max 400 MHz via CPLL - // Ref: TRM v0.5 Ch 2 -- HP CPU max frequency 400 MHz for v3.x Self::_400MHz } else { Self::_240MHz @@ -462,9 +460,15 @@ fn calibrate_rtc_slow_clock() { } } - LP_AON::regs() - .store1() - .write(|w| unsafe { w.bits(cal_val) }); + cfg_if::cfg_if! { + if #[cfg(esp32p4)] { + let reg = LP_AON::regs().lp_store1(); + } else { + let reg = LP_AON::regs().store1(); + } + } + + reg.write(|w| unsafe { w.bits(cal_val) }); } /// The CPU clock frequency. @@ -498,11 +502,13 @@ fn rtc_slow_cal_period() -> u64 { // Once that lands this cfg branch can disappear. cfg_if::cfg_if! { if #[cfg(esp32p4)] { - LP_AON::regs().lp_store1().read().bits() as u64 + let reg = LP_AON::regs().lp_store1(); } else { - LP_AON::regs().store1().read().bits() as u64 + let reg = LP_AON::regs().store1(); } } + + reg.read().bits() as u64 } /// Convert RTC slow clock ticks to microseconds using the calibrated period. diff --git a/esp-hal/src/efuse/esp32p4/mod.rs b/esp-hal/src/efuse/esp32p4/mod.rs index e519d8c9504..7bc615607ce 100644 --- a/esp-hal/src/efuse/esp32p4/mod.rs +++ b/esp-hal/src/efuse/esp32p4/mod.rs @@ -53,15 +53,15 @@ impl EfuseBlock { let efuse = EFUSE::regs(); match self { Block0 => efuse.rd_wr_dis().as_ptr(), - Block1 => efuse.rd_mac_sys_0().as_ptr(), - Block2 => efuse.rd_sys_part1_data0().as_ptr(), - Block3 => efuse.rd_usr_data0().as_ptr(), - Block4 => efuse.rd_key0_data0().as_ptr(), - Block5 => efuse.rd_key1_data0().as_ptr(), - Block6 => efuse.rd_key2_data0().as_ptr(), - Block7 => efuse.rd_key3_data0().as_ptr(), - Block8 => efuse.rd_key4_data0().as_ptr(), - Block9 => efuse.rd_key5_data0().as_ptr(), + Block1 => efuse.rd_mac_sys0().as_ptr(), + Block2 => efuse.rd_sys_part1_data(0).as_ptr(), + Block3 => efuse.rd_usr_data(0).as_ptr(), + Block4 => efuse.rd_key0_data(0).as_ptr(), + Block5 => efuse.rd_key1_data(0).as_ptr(), + Block6 => efuse.rd_key2_data(0).as_ptr(), + Block7 => efuse.rd_key3_data(0).as_ptr(), + Block8 => efuse.rd_key4_data(0).as_ptr(), + Block9 => efuse.rd_key5_data(0).as_ptr(), Block10 => efuse.rd_sys_part2_data0().as_ptr(), } } diff --git a/esp-hal/src/efuse/mod.rs b/esp-hal/src/efuse/mod.rs index cb6b0c8b67c..92415c729c4 100644 --- a/esp-hal/src/efuse/mod.rs +++ b/esp-hal/src/efuse/mod.rs @@ -17,21 +17,25 @@ //! //! and more. It is useful for retrieving chip-specific configuration and //! identification data during runtime. -//! -//! ## Examples -//! -//! ### Reading interface MAC addresses -//! -//! ```rust, no_run -//! # {before_snippet} -//! use esp_hal::efuse::{self, InterfaceMacAddress}; -//! -//! # {interface_mac} -//! println!("MAC: {mac}"); -//! println!("MAC bytes: {:02x?}", mac.as_bytes()); -//! # {after_snippet} -//! ``` +#![cfg_attr( + any(soc_has_wifi, soc_has_bt), + doc = r#" +## Examples + +### Reading interface MAC addresses + +```rust, no_run +# {before_snippet} +use esp_hal::efuse::{self, InterfaceMacAddress}; + +# {interface_mac} +println!("MAC: {mac}"); +println!("MAC bytes: {:02x?}", mac.as_bytes()); +# {after_snippet} +``` +"# +)] use core::{cmp, mem, slice, sync::atomic::Ordering}; use bytemuck::AnyBitPattern; diff --git a/esp-hal/src/interrupt/mod.rs b/esp-hal/src/interrupt/mod.rs index d999cd860cc..f29e52a1d2c 100644 --- a/esp-hal/src/interrupt/mod.rs +++ b/esp-hal/src/interrupt/mod.rs @@ -69,8 +69,6 @@ mod xtensa; use crate::pac; unstable_driver! { - // TODO: Remove this workaround of P4 and resolve true reason. - #[cfg(not(esp32p4))] pub mod software; } diff --git a/esp-hal/src/interrupt/riscv.rs b/esp-hal/src/interrupt/riscv.rs index ac64f343d0c..0d07245176b 100644 --- a/esp-hal/src/interrupt/riscv.rs +++ b/esp-hal/src/interrupt/riscv.rs @@ -312,15 +312,6 @@ pub fn enable_direct( let clic = unsafe { crate::soc::pac::CLIC::steal() }; // Enable hardware vectoring - #[cfg(esp32p4)] - clic.int_ctrl(cpu_interrupt as usize).modify(|_, w| unsafe { - // P4: CLIC uses consolidated int_ctrl register (not separate int_attr). - // int_ctrl contains: int_ip[0], int_ie[8], int_attr_shv[16], - // int_attr_trig[17:18], int_attr_mode[22:23], int_ctl[24:31] - w.int_attr_shv().set_bit(); - w.int_attr_trig().bits(0) // positive level - }); - #[cfg(not(esp32p4))] clic.int_attr(cpu_interrupt as usize).modify(|_, w| { w.shv().hardware(); w.trig().positive_level() @@ -368,6 +359,14 @@ pub fn enable_direct( cpu_int::set_priority_raw(cpu_interrupt as u32, level); cpu_int::set_kind_raw(cpu_interrupt as u32, InterruptKind::Level); cpu_int::enable_cpu_interrupt_raw(cpu_interrupt as u32); + + #[cfg(esp32p4)] + unsafe { + // Write back the cache to make sure the new interrupt handler is visible to the CPU. + crate::soc::cache_writeback_addr(mtvt_table as u32, 48 * 4); + // Invalidate the cache to make sure the CPU does not read from a stale instruction cache. + crate::soc::cache_invalidate_addr(mtvt_table as u32, 48 * 4); + } } // helper: returns correctly encoded RISC-V `jal` instruction @@ -418,18 +417,8 @@ fn cpu_wait_mode_on() -> bool { cfg_if::cfg_if! { if #[cfg(soc_has_pcr)] { crate::peripherals::PCR::regs().cpu_waiti_conf().read().cpu_wait_mode_force_on().bit_is_set() - } else if #[cfg(all(multi_core, soc_has_hp_sys_clkrst))] { - // AMP-aware: read this core's CORE{N}_WAITI_ICG_EN bit in - // HP_SYS_CLKRST.CPU_WAITI_CTRL0 (hw_ver3). Each core answers - // locally, so AMP setups where cores run different firmware get - // the right per-core result. - // ICG_EN = 1 -> this core's WFI may gate clock -> NOT safe - // ICG_EN = 0 -> WFI will not gate -> safe - // TODO: add HP_SYS_CLKRST.CPU_WAITI_CTRL0 (offset 0xF4) to the - // esp32p4 PAC and replace this raw MMIO with the PAC accessor. - const HP_SYS_CLKRST_CPU_WAITI_CTRL0: *const u32 = 0x500E_60F4 as *const u32; - let reg = unsafe { core::ptr::read_volatile(HP_SYS_CLKRST_CPU_WAITI_CTRL0) }; - (reg & (1 << Cpu::current() as u32)) == 0 + } else if #[cfg(soc_has_hp_sys)] { + crate::peripherals::HP_SYS::regs().cpu_waiti_conf().read().cpu_wait_mode_force_on().bit_is_set() } else { crate::peripherals::SYSTEM::regs() .cpu_per_conf() diff --git a/esp-hal/src/interrupt/riscv/clic.rs b/esp-hal/src/interrupt/riscv/clic.rs index ae6b5f688d9..b45f26115a5 100644 --- a/esp-hal/src/interrupt/riscv/clic.rs +++ b/esp-hal/src/interrupt/riscv/clic.rs @@ -1,15 +1,3 @@ -// CLIC v1.x and v2.x currently coexist in this file. Depending on -// ESP32-P4 mass production results and future esp-rs/esp-pacs patches, -// this file may be split into clic_v1.rs / clic_v2.rs, or kept as is. -// -// TODO: keep tracking future P4 revision to check changes of CLIC. -// -// ESP32P4 follows pulp CLIC version 1.x -// ref : https://github.com/pulp-platform/clic/blob/v1.0.1/src/gen/clic.hjson.tpl -// -// ESP32C5, C61 follow pulp CLIC version 2.x -// ref : https://github.com/pulp-platform/clic/blob/v2.0.0/src/gen/mclic.hjson - use super::{InterruptKind, Priority, RunLevel}; use crate::{interrupt::ElevatedRunLevel, soc::pac::CLIC}; @@ -18,70 +6,33 @@ pub(super) fn init() { let clic = unsafe { CLIC::steal() }; // 3 level bits = 8 priority levels. - cfg_if::cfg_if! { - if #[cfg(esp32p4)] { - clic.int_config() - .modify(|_, w| unsafe { w.int_config_nlbits().bits(3) }); - } else { - clic.int_config() - .modify(|_, w| unsafe { w.mnlbits().bits(3) }); - } - } + clic.int_config() + .modify(|_, w| unsafe { w.mnlbits().bits(3) }); // Enable hardware vectoring on every interrupt line. - cfg_if::cfg_if! { - if #[cfg(esp32p4)] { - for int in clic.int_ctrl_iter() { - int.modify(|_, w| unsafe { - w.int_attr_shv().set_bit(); - w.int_attr_trig().bits(0) // positive level - }); - } - } else { - for int in clic.int_attr_iter() { - int.modify(|_, w| { - w.shv().hardware(); - w.trig().positive_level() - }); - } - } + for int in clic.int_attr_iter() { + int.modify(|_, w| { + w.shv().hardware(); + w.trig().positive_level() + }); } } pub(super) fn enable_cpu_interrupt_raw(cpu_interrupt: u32) { // Lower 16 interrupts are reserved for CLINT, which is currently not implemented. let clic = unsafe { CLIC::steal() }; - cfg_if::cfg_if! { - if #[cfg(esp32p4)] { - clic.int_ctrl(cpu_interrupt as usize) - .modify(|_, w| w.int_ie().set_bit()); - } else { - clic.int_ie(cpu_interrupt as usize) - .write(|w| w.int_ie().set_bit()); - } - } + clic.int_ie(cpu_interrupt as usize) + .write(|w| w.int_ie().set_bit()); } pub(super) fn set_kind_raw(cpu_interrupt: u32, kind: InterruptKind) { // Lower 16 interrupts are reserved for CLINT, which is currently not implemented. let clic = unsafe { CLIC::steal() }; - cfg_if::cfg_if! { - if #[cfg(esp32p4)] { - clic.int_ctrl(cpu_interrupt as usize) - .modify(|_, w| unsafe { - w.int_attr_trig().bits(match kind { - InterruptKind::Level => 0, // positive level - InterruptKind::Edge => 1, // positive edge - }) - }); - } else { - clic.int_attr(cpu_interrupt as usize) - .modify(|_, w| match kind { - InterruptKind::Level => w.trig().positive_level(), - InterruptKind::Edge => w.trig().positive_edge(), - }); - } - } + clic.int_attr(cpu_interrupt as usize) + .modify(|_, w| match kind { + InterruptKind::Level => w.trig().positive_level(), + InterruptKind::Edge => w.trig().positive_edge(), + }); } pub(super) fn set_priority_raw(cpu_interrupt: u32, priority: Priority) { @@ -92,41 +43,21 @@ pub(super) fn set_priority_raw(cpu_interrupt: u32, priority: Priority) { ))); // The `ctl` field would only write the 3 programmable bits, but we have the correct final // value anyway so let's write it directly. - cfg_if::cfg_if! { - if #[cfg(esp32p4)] { - clic.int_ctrl(cpu_interrupt as usize) - .modify(|_, w| unsafe { w.int_ctl().bits(prio_bits) }); - } else { - clic.int_ctl(cpu_interrupt as usize) - .write(|w| unsafe { w.bits(prio_bits) }); - } - } + clic.int_ctl(cpu_interrupt as usize) + .write(|w| unsafe { w.bits(prio_bits) }); } pub(super) fn clear_raw(cpu_interrupt: u32) { // Lower 16 interrupts are reserved for CLINT, which is currently not implemented. let clic = unsafe { CLIC::steal() }; - cfg_if::cfg_if! { - if #[cfg(esp32p4)] { - clic.int_ctrl(cpu_interrupt as usize) - .modify(|_, w| w.int_ip().clear_bit()); - } else { - clic.int_ip(cpu_interrupt as usize) - .write(|w| w.int_ip().clear_bit()); - } - } + clic.int_ip(cpu_interrupt as usize) + .write(|w| w.int_ip().clear_bit()); } pub(super) fn cpu_interrupt_priority_raw(cpu_interrupt: u32) -> u8 { // Lower 16 interrupts are reserved for CLINT, which is currently not implemented. let clic = unsafe { CLIC::steal() }; - cfg_if::cfg_if! { - if #[cfg(esp32p4)] { - let prio_level = clic.int_ctrl(cpu_interrupt as usize).read().int_ctl().bits() as usize; - } else { - let prio_level = clic.int_ctl(cpu_interrupt as usize).read().bits() as usize; - } - } + let prio_level = clic.int_ctl(cpu_interrupt as usize).read().bits() as usize; bits_to_prio(prio_level) } diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index 156792c16ff..f69ec509673 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -278,7 +278,6 @@ metadata!( #[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", feature = "rt"))))] #[cfg_attr(not(feature = "unstable"), doc(hidden))] pub use esp_riscv_rt::{self, riscv}; -use esp_sync::RawMutex; pub(crate) use peripherals::pac; #[cfg(xtensa)] #[cfg(all(xtensa, feature = "rt"))] @@ -423,6 +422,7 @@ mod soc; // Some PAC-related utility use crate::pac::generic::{Readable, Reg, Resettable, W, Writable}; +#[cfg_attr(esp32p4, expect(unused))] trait RegisterToggle { type Reg: Readable + Resettable + Writable; @@ -620,7 +620,8 @@ use crate::clock::{ClockConfig, CpuClock}; use crate::peripherals::Peripherals; /// A spinlock for seldom called stuff. Users assume that lock contention is not an issue. -pub(crate) static ESP_HAL_LOCK: RawMutex = RawMutex::new(); +#[cfg(feature = "rt")] +pub(crate) static ESP_HAL_LOCK: esp_sync::RawMutex = esp_sync::RawMutex::new(); #[procmacros::doc_replace] /// System configuration. diff --git a/esp-hal/src/psram/esp32p4.rs b/esp-hal/src/psram/esp32p4.rs index 5d04a7c202f..25ea7b02318 100644 --- a/esp-hal/src/psram/esp32p4.rs +++ b/esp-hal/src/psram/esp32p4.rs @@ -3,24 +3,19 @@ //! P4 has two PSRAM controllers wired to the same DQ pads //! The structure is looks same with DDR controller but not same. -// Several ROM cache helpers and MMIO wrappers are staged for follow-up -// PSRAM bring-up work (cache suspend/resume around config writes). -// They're intentionally retained so the follow-up PR can wire them in -// without re-deriving the constants. -#![allow(dead_code)] - -/// PSRAM virtual address range (cached) -pub const PSRAM_VADDR_START: usize = 0x4800_0000; +use super::{EXTMEM_ORIGIN, PsramSize}; +use crate::{ + peripherals::{HP_SYS_CLKRST, LP_AON_CLKRST, PMU}, + soc::regi2c, +}; /// MMU page size (64 KB) const MMU_PAGE_SIZE: usize = 0x10000; /// PSRAM_MSPI0 base, AXI cache controller. -/// CAUTION: Missing area of TRM. const MSPI0_BASE: u32 = 0x5008_E000; /// PSRAM_MSPI1 base, direct-command controller. -/// CAUTION: Missing area of TRM. const MSPI1_BASE: u32 = 0x5008_F000; /// Volatile 32-bit read. @@ -42,13 +37,6 @@ unsafe fn mmio_setbits_32(addr: u32, mask: u32) { unsafe { mmio_write_32(addr, mmio_read_32(addr) | mask) } } -/// Read-modify-write: clear every bit of `mask`. Equivalent to -/// `*addr &= !mask`. -#[inline(always)] -unsafe fn mmio_clrbits_32(addr: u32, mask: u32) { - unsafe { mmio_write_32(addr, mmio_read_32(addr) & !mask) } -} - /// Read-modify-write: clear `clear`-bits then set `set`-bits. /// Equivalent to `*addr = (*addr & !clear) | set`. #[inline(always)] @@ -56,13 +44,7 @@ unsafe fn mmio_clrsetbits_32(addr: u32, clear: u32, set: u32) { unsafe { mmio_write_32(addr, (mmio_read_32(addr) & !clear) | set) } } -/// PSRAM interface mode (line count of the data bus). Mirrors IDF's -/// `CONFIG_SPIRAM_MODE_*`. -/// -/// Only `Hex` is currently exercised by this driver; selecting `Oct` -/// requires the cache-side controller config (`mem_sdin_hex` / -/// `mem_sdout_hex` bits) and chip MR8.x16 to flip together. Wire that -/// path before exposing. +/// PSRAM interface mode (line count of the data bus). #[derive(Copy, Clone, Debug, Default, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[instability::unstable] @@ -70,37 +52,42 @@ pub enum PsramMode { /// 16-line DDR, AP HEX PSRAM with MR8.x16 = 1. Default. #[default] Hex, - /// 8-line DDR, MR8.x16 = 0. Not yet implemented in this driver. - Oct, + // TODO; selecting `Oct` + // requires the cache-side controller config (`mem_sdin_hex` / + // `mem_sdout_hex` bits) and chip MR8.x16 to flip together. Wire that + // path before exposing. + // Oct, } -/// PSRAM bus frequency. Choice ties together MPLL freq + bus divider -/// + chip-side read/write latency (each `SpiRamFreq` corresponds to a -/// `(MPLL, div, RL, WL, RD_dummy_bits, WR_dummy_bits)` tuple). +/// PSRAM bus frequency. /// -/// Variants referenced from `CONFIG_SPIRAM_SPEED_*`. +/// Choice ties together MPLL freq + bus divider + chip-side read/write latency. /// -/// | Variant | MPLL | div | MR0.RL | MR4.WL | RD dummy bits | Use case | -/// |-----------|------|-----|--------|--------|---------------|----------| -/// | `Mhz20` | 400 | 20 | 2 | 2 | 18 | Low-power / debug | +/// | Variant | MPLL | div | MR0.RL | MR4.WL | RD dummy bits | Use case | +/// |-----------|------|-----|--------|--------|---------------|------------------------| +/// | `Mhz20` | 400 | 20 | 2 | 2 | 18 | Low-power / debug | /// | `Mhz80` | 320 | 4 | 2 | 2 | 18 | Conservative SI margin | -/// | `Mhz200` | 400 | 2 | 4 | 1 | 26 | IDF default | -/// | `Mhz250` | 500 | 2 | 6 | 3 | 34 | Overclock, **silicon rev v3+ only** | +/// | `Mhz200` | 400 | 2 | 4 | 1 | 26 | IDF default | +/// | `Mhz250` | 500 | 2 | 6 | 3 | 34 | Overclock | #[derive(Copy, Clone, Debug, Default, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[instability::unstable] pub enum SpiRamFreq { - /// 20 MHz bus (MPLL 400 / div 20). Lowest-power option; - /// rarely used outside debug. + /// 20 MHz bus (MPLL 400 / div 20). Mhz20 = 20, - /// 80 MHz bus (MPLL 320 / div 4). Conservative; widest timing - /// margin. + + /// 80 MHz bus (MPLL 320 / div 4). + /// + /// Conservative; widest timing margin. Mhz80 = 80, - /// 200 MHz bus (MPLL 400 / div 2). IDF default for AP HEX PSRAM. - /// Validated on the EV board. + + /// 200 MHz bus (MPLL 400 / div 2). + /// + /// IDF default for AP HEX PSRAM. #[default] Mhz200 = 200, - /// 250 MHz bus (MPLL 500 / div 2). Top speed, silicon rev v3+ only. + + /// 250 MHz bus (MPLL 500 / div 2). Mhz250 = 250, } @@ -138,7 +125,7 @@ pub struct PsramConfig { /// PSRAM interface mode (Hex 16-line vs Oct 8-line). Default: Hex. pub mode: PsramMode, /// Size of PSRAM to map. Default: `AutoDetect` via MR2 density. - pub size: super::PsramSize, + pub size: PsramSize, /// MPLL override. `None` (default) derives the MPLL frequency /// from `ram_frequency` per the table on `SpiRamFreq`. pub core_clock: Option, @@ -156,8 +143,8 @@ pub(crate) fn init_psram(config: &mut PsramConfig) -> bool { } pub(crate) fn map_psram(config: PsramConfig) -> core::ops::Range { - let size = config.size.get(); - PSRAM_VADDR_START..PSRAM_VADDR_START + size + let start = EXTMEM_ORIGIN; + start..start + config.size.get() } /// Per-speed timing parameters. Mirrors IDF's `#if CONFIG_SPIRAM_SPEED_*` @@ -229,24 +216,6 @@ const AP_HEX_CS_SETUP_TIME: u32 = 4; const AP_HEX_CS_HOLD_TIME: u32 = 4; const AP_HEX_CS_HOLD_DELAY: u32 = 3; -/// Module-scope shadow of the speed parameters set by `init_psram_inner`. -/// Read by the helper functions (`init_mr_registers`, `psram_mr_read`, -/// `configure_psram_mspi`) that need the dummy / latency values without -/// having `config` threaded through every signature. -/// -/// Initialised to `Mhz200` (IDF default, matches default of -/// `SpiRamFreq`) so the value is well-defined before -/// `init_psram_inner` runs; overwritten there based on -/// `config.ram_frequency`. Single-init, single-thread at boot, so a -/// plain `static mut` is enough. -static mut PSRAM_SPEED: SpeedParams = SpeedParams::for_freq(SpiRamFreq::Mhz200); - -/// Read the active speed parameters. Safe wrapper since we only mutate -/// this once at init before any concurrent access. -fn psram_speed() -> SpeedParams { - unsafe { PSRAM_SPEED } -} - fn init_psram_inner(config: &mut PsramConfig) { // Resolve the speed parameter set from `ram_frequency`. The MPLL // override (`config.core_clock`) lets the caller bypass the default @@ -256,21 +225,21 @@ fn init_psram_inner(config: &mut PsramConfig) { if let Some(mpll) = config.core_clock { params.mpll_mhz = mpll as u32; } - unsafe { PSRAM_SPEED = params }; psram_phy_ldo_init(); // PMU EXT_LDO regulator setup for the MSPI PHY analog block. configure_mpll(params.mpll_mhz); // Module clock + clock source - let clkrst = crate::peripherals::HP_SYS_CLKRST::regs(); - clkrst + HP_SYS_CLKRST::regs() .soc_clk_ctrl0() .modify(|_, w| w.psram_sys_clk_en().set_bit()); - clkrst.peri_clk_ctrl00().modify(|_, w| unsafe { - w.psram_pll_clk_en().set_bit(); - w.psram_core_clk_en().set_bit(); - w.psram_clk_src_sel().bits(1) // 1 = MPLL - }); + HP_SYS_CLKRST::regs() + .peri_clk_ctrl00() + .modify(|_, w| unsafe { + w.psram_pll_clk_en().set_bit(); + w.psram_core_clk_en().set_bit(); + w.psram_clk_src_sel().bits(1) // 1 = MPLL + }); // Controller + PHY pad bring-up. set_bus_clock(params.bus_div); @@ -279,22 +248,14 @@ fn init_psram_inner(config: &mut PsramConfig) { set_cs_timing(); // SoC MR init (via MSPI3 SPI direct) - init_mr_registers(); - let psram_size = match config.size { - super::PsramSize::AutoDetect => psram_detect_size(), - super::PsramSize::Size(s) => s, - }; + init_mr_registers(params); - config.size = super::PsramSize::Size(psram_size); - - configure_psram_mspi(MSPI0_BASE); // basic AXI configuration here - mmu_map_psram(MSPI0_BASE, *config); // MMU mapping here - - if psram_size > 0 { - let start = PSRAM_VADDR_START; - let end = start + psram_size; - unsafe { super::set_psram_range(start..end) }; + if config.size.is_auto() { + config.size = PsramSize::Size(psram_detect_size(params)); } + + configure_psram_mspi(params, MSPI0_BASE); // basic AXI configuration here + mmu_map_psram(MSPI0_BASE, config); // MMU mapping here } /// Set bus-clock divider for both PSRAM_MSPI0 (SRAM_CLK at 0x50) and @@ -485,8 +446,8 @@ const MR_ADDR_MR8_MR9: u32 = 0x8; /// (MR_ADDR_MR4_MR5 / MR_ADDR_MR6 / MR_ADDR_MR8_MR9 — see the table at the /// `MR_ADDR_*` constants), the `high` value is don't-care and the /// caller should ignore it. -fn psram_mr_read(mr_addr: u32) -> (u8, u8) { - let pair = mspi1_reg_read16(mr_addr); +fn psram_mr_read(speed_params: SpeedParams, mr_addr: u32) -> (u8, u8) { + let pair = mspi1_reg_read16(speed_params, mr_addr); ((pair & 0xFF) as u8, ((pair >> 8) & 0xFF) as u8) } @@ -506,23 +467,23 @@ fn psram_mr_write(mr_addr: u32, low: u8, high: u8) { /// MR0: drive_str[1:0], read_latency[4:2], lt[5] /// MR4: wr_latency[7:5] /// MR8: bl[1:0], bt[2], rbx[3], x16[6] -fn init_mr_registers() { +fn init_mr_registers(speed_params: SpeedParams) { // Read+modify+write MR0 (preserve MR1 high byte). - let (mut mr0, mr1) = psram_mr_read(MR_ADDR_MR0_MR1); + let (mut mr0, mr1) = psram_mr_read(speed_params, MR_ADDR_MR0_MR1); mr0 &= !(0x3 | (0x7 << 2) | (1 << 5)); - mr0 |= ((psram_speed().mr0_rl & 0x7) << 2) | (1 << 5); + mr0 |= ((speed_params.mr0_rl & 0x7) << 2) | (1 << 5); psram_mr_write(MR_ADDR_MR0_MR1, mr0, mr1); // Read+modify+write MR4 (preserve MR5 reserved high byte). - let (mut mr4, mr5) = psram_mr_read(MR_ADDR_MR4_MR5); + let (mut mr4, mr5) = psram_mr_read(speed_params, MR_ADDR_MR4_MR5); mr4 &= !(0x7 << 5); - mr4 |= (psram_speed().mr4_wl & 0x7) << 5; + mr4 |= (speed_params.mr4_wl & 0x7) << 5; psram_mr_write(MR_ADDR_MR4_MR5, mr4, mr5); // do nothing for MR6 and MR7 // Read+modify+write MR8 (high byte is reserved/absent — pass 0). - let (mut mr8, mr9) = psram_mr_read(MR_ADDR_MR8_MR9); // MR9 is unused + let (mut mr8, mr9) = psram_mr_read(speed_params, MR_ADDR_MR8_MR9); // MR9 is unused mr8 &= !(0x3 | (1 << 2) | (1 << 3) | (1 << 6)); mr8 |= 3 // bt = 0 | (1 << 3) // rbx = 1 @@ -551,6 +512,7 @@ const ESP_ROM_SPIFLASH_OPI_DTR_MODE: u32 = 7; /// Maps to `PSRAM_CTRLR_LL_MSPI_ID_3` in IDF (`PSRAM_MSPI1` = 0x5008_F000). const ROM_SPI_PSRAM_CMD_NUM: i32 = 3; /// CS mask: PSRAM lives on CS1 (bit 1). Flash on CS0. +#[expect(dead_code)] const ROM_SPI_PSRAM_CS_MASK: u8 = 1 << 1; unsafe extern "C" { @@ -621,7 +583,7 @@ fn mspi1_kick_and_collect(rx: &mut [u8]) -> Result<(), ()> { /// 32-bit address, 16-bit MISO) through `PSRAM_MSPI1`. Setup via ROM /// helpers (`set_op_mode` + `cmd_config`); kick + poll done manually /// with a timeout (avoids ROM `cmd_start` poll-forever pitfall). -fn mspi1_reg_read16(addr: u32) -> u16 { +fn mspi1_reg_read16(speed_params: SpeedParams, addr: u32) -> u16 { const REG_READ_CMD: u16 = 0x4040; const CMD_BITLEN: u16 = 16; const ADDR_BITLEN: u32 = 32; @@ -638,12 +600,12 @@ fn mspi1_reg_read16(addr: u32) -> u16 { tx_data_bit_len: 0, rx_data: rx.as_mut_ptr() as *mut u32, rx_data_bit_len: DATA_BITLEN, - dummy_bit_len: psram_speed().reg_dummy_bits, + dummy_bit_len: speed_params.reg_dummy_bits, }; unsafe { esp_rom_spi_set_op_mode(ROM_SPI_PSRAM_CMD_NUM, ESP_ROM_SPIFLASH_OPI_DTR_MODE); - esp_rom_spi_cmd_config(ROM_SPI_PSRAM_CMD_NUM, &mut conf as *mut EspRomSpiCmd); + esp_rom_spi_cmd_config(ROM_SPI_PSRAM_CMD_NUM, &raw mut conf); } let _ = mspi1_kick_and_collect(&mut rx); u16::from_le_bytes(rx) @@ -681,8 +643,8 @@ fn mspi1_reg_write16(addr: u32, data: u16) { } /// Detect PSRAM size by reading mode register MR2 via MSPI1. -fn psram_detect_size() -> usize { - let (mr2, _mr3) = psram_mr_read(MR_ADDR_MR2_MR3); +fn psram_detect_size(speed_params: SpeedParams) -> usize { + let (mr2, _mr3) = psram_mr_read(speed_params, MR_ADDR_MR2_MR3); match mr2 & 0x7 { 0x1 => 4 * 1024 * 1024, // 32 Mbit 0x3 => 8 * 1024 * 1024, // 64 Mbit @@ -710,18 +672,14 @@ fn psram_detect_size() -> usize { /// is a separate table from the flash MMU, so PSRAM entries start at /// **entry index 0**, not at some offset relative to the flash range. /// `entry_id = (vaddr - 0x4800_0000) / 0x10000`. -fn mmu_map_psram(mspi_base: u32, config: PsramConfig) { +fn mmu_map_psram(mspi_base: u32, config: &PsramConfig) { const MMU_ITEM_CONTENT: u32 = 0x37C; const MMU_ITEM_INDEX: u32 = 0x380; const MMU_PSRAM_VALID: u32 = 1 << 11; const MMU_ACCESS_PSRAM: u32 = 1 << 10; const MMU_PADDR_MASK: u32 = 0x3FF; // 10 bits of physical page number - let psram_size = match config.size { - super::PsramSize::AutoDetect => 32 * 1024 * 1024, - super::PsramSize::Size(s) => s, - }; - let page_count = psram_size / MMU_PAGE_SIZE; + let page_count = config.size.get() / MMU_PAGE_SIZE; // Note: we do NOT call Cache_Suspend_*. The ROM helpers expect // interrupts/scheduler state we can't guarantee in init context, and @@ -743,7 +701,7 @@ fn mmu_map_psram(mspi_base: u32, config: PsramConfig) { #[allow(dead_code)] pub(crate) fn cache_invalidate(addr: u32, size: u32) { - let cache = unsafe { &*crate::pac::CACHE::PTR }; + let cache = unsafe { crate::pac::CACHE::steal() }; cache.sync_addr().write(|w| unsafe { w.bits(addr) }); cache.sync_size().write(|w| unsafe { w.bits(size) }); cache @@ -756,7 +714,7 @@ pub(crate) fn cache_invalidate(addr: u32, size: u32) { #[allow(dead_code)] pub(crate) fn cache_writeback(addr: u32, size: u32) { - let cache = unsafe { &*crate::pac::CACHE::PTR }; + let cache = unsafe { crate::pac::CACHE::steal() }; cache.sync_addr().write(|w| unsafe { w.bits(addr) }); cache.sync_size().write(|w| unsafe { w.bits(size) }); cache.sync_ctrl().modify(|_, w| w.writeback_ena().set_bit()); @@ -767,41 +725,59 @@ pub(crate) fn cache_writeback(addr: u32, size: u32) { /// Program the PMU external LDO regulators for the MSPI PHY fn psram_phy_ldo_init() { - const PMU_BASE: u32 = 0x5011_5000; - unsafe { - // P0 power-rail LDOs (general analog). - mmio_write_32(PMU_BASE + 0x1B8, 0x4020_0100); // EXT_LDO_P0_0P1A - mmio_write_32(PMU_BASE + 0x1BC, 0xB100_0000); // EXT_LDO_P0_0P1A_ANA - mmio_write_32(PMU_BASE + 0x1C0, 0x4020_0000); // EXT_LDO_P0_0P2A - mmio_write_32(PMU_BASE + 0x1C4, 0xA000_0000); // EXT_LDO_P0_0P2A_ANA - mmio_write_32(PMU_BASE + 0x1C8, 0x4020_0000); // EXT_LDO_P0_0P3A - mmio_write_32(PMU_BASE + 0x1CC, 0xA000_0000); // EXT_LDO_P0_0P3A_ANA - // P1 power-rail LDOs (MSPI PHY domain). - mmio_write_32(PMU_BASE + 0x1D0, 0x4020_0180); // EXT_LDO_P1_0P1A XPD + current limit - mmio_write_32(PMU_BASE + 0x1D4, 0x5700_0000); // EXT_LDO_P1_0P1A_ANA analog tune (THE one for PSRAM) - mmio_write_32(PMU_BASE + 0x1D8, 0x4020_0000); // EXT_LDO_P1_0P2A - mmio_write_32(PMU_BASE + 0x1DC, 0xA000_0000); // EXT_LDO_P1_0P2A_ANA - mmio_write_32(PMU_BASE + 0x1E0, 0x4020_0000); // EXT_LDO_P1_0P3A - mmio_write_32(PMU_BASE + 0x1E4, 0xA000_0000); // EXT_LDO_P1_0P3A_ANA - } + PMU::regs() + .ext_ldo_p0_0p1a() + .write(|w| unsafe { w.bits(0x4020_0100) }); + PMU::regs() + .ext_ldo_p0_0p1a_ana() + .write(|w| unsafe { w.bits(0xB100_0000) }); + + PMU::regs() + .ext_ldo_p0_0p2a() + .write(|w| unsafe { w.bits(0x4020_0000) }); + PMU::regs() + .ext_ldo_p0_0p2a_ana() + .write(|w| unsafe { w.bits(0xA000_0000) }); + + PMU::regs() + .ext_ldo_p0_0p3a() + .write(|w| unsafe { w.bits(0x4020_0000) }); + PMU::regs() + .ext_ldo_p0_0p3a_ana() + .write(|w| unsafe { w.bits(0xA000_0000) }); + + PMU::regs() + .ext_ldo_p1_0p1a() + .write(|w| unsafe { w.bits(0x4020_0180) }); + PMU::regs() + .ext_ldo_p1_0p1a_ana() + .write(|w| unsafe { w.bits(0x5700_0000) }); + + PMU::regs() + .ext_ldo_p1_0p2a() + .write(|w| unsafe { w.bits(0x4020_0000) }); + PMU::regs() + .ext_ldo_p1_0p2a_ana() + .write(|w| unsafe { w.bits(0xA000_0000) }); + + PMU::regs() + .ext_ldo_p1_0p3a() + .write(|w| unsafe { w.bits(0x4020_0000) }); + PMU::regs() + .ext_ldo_p1_0p3a_ana() + .write(|w| unsafe { w.bits(0xA000_0000) }); + // Allow LDO output to settle before the MSPI PHY is exercised. crate::rom::ets_delay_us(50); } /// Configure MPLL to target frequency for PSRAM clock. fn configure_mpll(freq_mhz: u32) { - use crate::soc::regi2c; - - const I2C_MPLL: u8 = 0x63; - const I2C_MPLL_DIV_REG_ADDR: u8 = 2; - const I2C_MPLL_DHREF: u8 = 3; - const I2C_MPLL_IR_CAL_RSTB: u8 = 5; - // Power up the MPLL analog block. - let pmu = crate::peripherals::PMU::regs(); - pmu.rf_pwc().modify(|_, w| w.mspi_phy_xpd().set_bit()); - let lp_clkrst = crate::peripherals::LP_AON_CLKRST::regs(); - lp_clkrst + PMU::regs() + .rf_pwc() + .modify(|_, w| w.mspi_phy_xpd().set_bit()); + LP_AON_CLKRST::regs() .lp_aonclkrst_hp_clk_ctrl() .modify(|_, w| w.lp_aonclkrst_hp_mpll_500m_clk_en().set_bit()); @@ -810,28 +786,31 @@ fn configure_mpll(freq_mhz: u32) { let div: u8 = (freq_mhz / 20).saturating_sub(1) as u8; let div_val: u8 = (div << 3) | ref_div; - let dhref = regi2c::regi2c_read(I2C_MPLL, 0, I2C_MPLL_DHREF); - regi2c::regi2c_write(I2C_MPLL, 0, I2C_MPLL_DHREF, dhref | (3 << 4)); - - let rstb = regi2c::regi2c_read(I2C_MPLL, 0, I2C_MPLL_IR_CAL_RSTB); - regi2c::regi2c_write(I2C_MPLL, 0, I2C_MPLL_IR_CAL_RSTB, rstb & 0xDF); - regi2c::regi2c_write(I2C_MPLL, 0, I2C_MPLL_IR_CAL_RSTB, rstb | (1 << 5)); + let dhref = regi2c::I2C_MPLL_DHREF.read(); + regi2c::I2C_MPLL_DHREF.write_reg(dhref | (3 << 4)); - regi2c::regi2c_write(I2C_MPLL, 0, I2C_MPLL_DIV_REG_ADDR, div_val); + let rstb = regi2c::I2C_MPLL_IR_CAL_RSTB.read(); + regi2c::I2C_MPLL_IR_CAL_RSTB.write_reg(rstb & 0xDF); + regi2c::I2C_MPLL_IR_CAL_RSTB.write_reg(rstb | (1 << 5)); + regi2c::I2C_MPLL_DIV_REG_ADDR.write_reg(div_val); - let clkrst = crate::peripherals::HP_SYS_CLKRST::regs(); - clkrst + HP_SYS_CLKRST::regs() .ana_pll_ctrl0() .modify(|_, w| w.mspi_cal_stop().clear_bit()); let mut t = 1_000_000_u32; - while !clkrst.ana_pll_ctrl0().read().mspi_cal_end().bit_is_set() { + while !HP_SYS_CLKRST::regs() + .ana_pll_ctrl0() + .read() + .mspi_cal_end() + .bit_is_set() + { t = t.saturating_sub(1); if t == 0 { break; } core::hint::spin_loop(); } - clkrst + HP_SYS_CLKRST::regs() .ana_pll_ctrl0() .modify(|_, w| w.mspi_cal_stop().set_bit()); // cal_end timeout (t == 0): surfaces later via `psram_detect_size` fallback. @@ -874,10 +853,10 @@ fn configure_mpll(freq_mhz: u32) { /// bit 2 `smem_ddr_rdat_swp`, bit 3 `smem_ddr_wdat_swp`. /// /// `CACHE_FCTRL` (0x3C): bit 0 `mem_axi_req_en`, bit 1 `close_axi_inf_en`. -fn configure_psram_mspi(base: u32) { +fn configure_psram_mspi(speed_params: SpeedParams, base: u32) { // Dummy bit-counts come from the active speed parameter table. - let rd_dummy_n = psram_speed().rd_dummy_bits; - let wr_dummy_n = psram_speed().wr_dummy_bits; + let rd_dummy_n = speed_params.rd_dummy_bits; + let wr_dummy_n = speed_params.wr_dummy_bits; unsafe { // CACHE_SCTRL. diff --git a/esp-hal/src/rtc_cntl/mod.rs b/esp-hal/src/rtc_cntl/mod.rs index 2d4ea32cb81..f116d31f7f5 100644 --- a/esp-hal/src/rtc_cntl/mod.rs +++ b/esp-hal/src/rtc_cntl/mod.rs @@ -415,23 +415,14 @@ impl<'d> Rtc<'d> { // ESP32-S3: TRM v1.5 chapter 8.3 // ESP32-H2: TRM v0.5 chapter 8.2.3 - // P4: LP_SYS (mapped as LP_AON) names its scratch registers - // `lp_store0..lp_store14`, while every other chip names them - // `store0..N`. esp-idf's `rtc_suppress_rom_log()` writes - // RTC_DISABLE_ROM_LOG = (1<<0) | (1<<16) to STORE4. - // TODO: file an esp-pacs issue/PR to rename the P4 fields to match; - // once that lands this cfg branch can collapse to a single line. cfg_if::cfg_if! { if #[cfg(esp32p4)] { - LP_AON::regs() - .lp_store4() - .modify(|r, w| unsafe { w.bits(r.bits() | Self::RTC_DISABLE_ROM_LOG) }); + let reg = LP_AON::regs().lp_store4(); } else { - LP_AON::regs() - .store4() - .modify(|r, w| unsafe { w.bits(r.bits() | Self::RTC_DISABLE_ROM_LOG) }); + let reg = LP_AON::regs().store4(); } } + reg.modify(|r, w| unsafe { w.bits(r.bits() | Self::RTC_DISABLE_ROM_LOG) }); } /// Register an interrupt handler for the RTC. diff --git a/esp-hal/src/rtc_cntl/rtc/esp32p4.rs b/esp-hal/src/rtc_cntl/rtc/esp32p4.rs index 5f0b0c1091d..f468d75ce0b 100644 --- a/esp-hal/src/rtc_cntl/rtc/esp32p4.rs +++ b/esp-hal/src/rtc_cntl/rtc/esp32p4.rs @@ -16,7 +16,10 @@ use strum::FromRepr; -use crate::peripherals::{LP_WDT, PMU, TIMG0, TIMG1}; +use crate::{ + peripherals::{HP_SYS_CLKRST, LP_AON_CLKRST, LP_WDT, PMU, TIMG0, TIMG1}, + soc::regi2c, +}; /// SOC Reset Reason. #[derive(Debug, Clone, Copy, PartialEq, Eq, FromRepr)] @@ -152,8 +155,7 @@ pub(crate) fn init() { lp_wdt.swd_wprotect().write(|w| unsafe { w.bits(0) }); // 6. Clear DCDC switch force flags PMU_POWER_DCDC_SWITCH_REG (offset 0x10c) - let pmu = PMU::regs(); - pmu.power_dcdc_switch().modify(|_, w| { + PMU::regs().power_dcdc_switch().modify(|_, w| { w.force_dcdc_switch_pu().bit(false); w.force_dcdc_switch_pd().bit(false) }); @@ -163,20 +165,20 @@ pub(crate) fn init() { spll_configure(480); // 8. Set CPU divider to 1 (400 MHz CPU), MEM divider 2, APB divider 2 - let clkrst = crate::peripherals::HP_SYS_CLKRST::regs(); - // Set CPU divider: cpu_clk_div_num = divider - 1 = 0 // Ref: HP_SYS_CLKRST.root_clk_ctrl0.reg_cpu_clk_div_num - clkrst.root_clk_ctrl0().modify(|_, w| unsafe { - w.cpu_clk_div_num().bits(0); // CPU: /1 = 400 MHz - w.cpu_clk_div_numerator().bits(0); - w.cpu_clk_div_denominator().bits(0) - }); + HP_SYS_CLKRST::regs() + .root_clk_ctrl0() + .modify(|_, w| unsafe { + w.cpu_clk_div_num().bits(0); // CPU: /1 = 400 MHz + w.cpu_clk_div_numerator().bits(0); + w.cpu_clk_div_denominator().bits(0) + }); // Trigger clock divider update - clkrst + HP_SYS_CLKRST::regs() .root_clk_ctrl0() .modify(|_, w| w.soc_clk_div_update().set_bit()); - while clkrst + while HP_SYS_CLKRST::regs() .root_clk_ctrl0() .read() .soc_clk_div_update() @@ -187,7 +189,7 @@ pub(crate) fn init() { // 9. Switch CPU clock source from XTAL to CPLL LP_AON_CLKRST.hp_clk_ctrl.hp_root_clk_src_sel: // 0=XTAL, 1=CPLL, 2=RC_FAST - crate::peripherals::LP_AON_CLKRST::regs() + LP_AON_CLKRST::regs() .lp_aonclkrst_hp_clk_ctrl() .modify(|_, w| unsafe { w.lp_aonclkrst_hp_root_clk_src_sel().bits(1) }); // 1 = CPLL } @@ -197,20 +199,11 @@ pub(crate) fn init() { /// eco5 (v3.x) uses different I2C register values than eco4 (v1.x). /// Ref: TRM v0.5 Ch 12 -- CPLL configuration fn cpll_configure(freq_mhz: u32) { - use crate::soc::regi2c; - - // I2C CPLL register addresses - const I2C_CPLL: u8 = 0x67; // CPLL slave address - const I2C_CPLL_OC_REF_DIV: u8 = 2; - const I2C_CPLL_OC_DIV_7_0: u8 = 3; - const I2C_CPLL_OC_DCUR: u8 = 6; - // 1. Enable CPLL power PMU.imm_hp_ck_power: tie_high_xpd_pll, tie_high_xpd_pll_i2c Note: PAC // uses "pll" not "cpll" (eco4 PAC, single PLL) - let pmu = PMU::regs(); // PAC: tie_high_xpd_pll is 4-bit field (one bit per PLL: CPLL/SPLL/MPLL/PLLA). // Set all bits to enable all PLLs. Same for pll_i2c. - pmu.imm_hp_ck_power().write(|w| unsafe { + PMU::regs().imm_hp_ck_power().write(|w| unsafe { w.tie_high_xpd_pll().bits(0xF); w.tie_high_xpd_pll_i2c().bits(0xF) }); @@ -233,25 +226,28 @@ fn cpll_configure(freq_mhz: u32) { // OC_DCUR: (dlref_sel << 6) | (dhref_sel << 4) | dcur = 0x73 let dcur: u8 = 0x73; // dlref_sel=1, dhref_sel=3, dcur=3 - regi2c::regi2c_write(I2C_CPLL, 0, I2C_CPLL_OC_REF_DIV, lref); - regi2c::regi2c_write(I2C_CPLL, 0, I2C_CPLL_OC_DIV_7_0, div7_0); - regi2c::regi2c_write(I2C_CPLL, 0, I2C_CPLL_OC_DCUR, dcur); + regi2c::I2C_CPLL_OC_REF_DIV.write_reg(lref); + regi2c::I2C_CPLL_OC_DIV_7_0.write_reg(div7_0); + regi2c::I2C_CPLL_OC_DCUR.write_reg(dcur); // 3. Run CPLL calibration HP_SYS_CLKRST.ana_pll_ctrl0.cpu_pll_cal_stop - let clkrst = crate::peripherals::HP_SYS_CLKRST::regs(); - // Start calibration: set cpu_pll_cal_stop = 0 - clkrst + HP_SYS_CLKRST::regs() .ana_pll_ctrl0() .modify(|_, w| w.cpu_pll_cal_stop().clear_bit()); // Wait for calibration to complete - while !clkrst.ana_pll_ctrl0().read().cpu_pll_cal_end().bit_is_set() { + while !HP_SYS_CLKRST::regs() + .ana_pll_ctrl0() + .read() + .cpu_pll_cal_end() + .bit_is_set() + { core::hint::spin_loop(); } // Stop calibration: set cpu_pll_cal_stop = 1 - clkrst + HP_SYS_CLKRST::regs() .ana_pll_ctrl0() .modify(|_, w| w.cpu_pll_cal_stop().set_bit()); @@ -264,14 +260,6 @@ fn cpll_configure(freq_mhz: u32) { /// SPLL provides peripheral clocks: PLL_F240M/160M/120M/80M/20M. /// Ref: TRM v0.5 Ch 12 -- SPLL configuration fn spll_configure(freq_mhz: u32) { - use crate::soc::regi2c; - - // I2C SPLL register addresses - const I2C_SPLL: u8 = regi2c::REGI2C_SYS_PLL; - const I2C_SPLL_OC_REF_DIV: u8 = 2; - const I2C_SPLL_OC_DIV_7_0: u8 = 3; - const I2C_SPLL_OC_DCUR: u8 = 6; - // PLL power already enabled in cpll_configure (PMU xpd_pll bits(0xF) enables all PLLs) // Configure SPLL via I2C analog registers @@ -286,23 +274,26 @@ fn spll_configure(freq_mhz: u32) { let lref: u8 = 0x50; // dchgp=5, div_ref=0, oc_enb_fcal=0 let dcur: u8 = 0x73; // dlref_sel=1, dhref_sel=3, dcur=3 - regi2c::regi2c_write(I2C_SPLL, 0, I2C_SPLL_OC_REF_DIV, lref); - regi2c::regi2c_write(I2C_SPLL, 0, I2C_SPLL_OC_DIV_7_0, div7_0); - regi2c::regi2c_write(I2C_SPLL, 0, I2C_SPLL_OC_DCUR, dcur); + regi2c::I2C_SPLL_OC_REF_DIV.write_reg(lref); + regi2c::I2C_SPLL_OC_DIV_7_0.write_reg(div7_0); + regi2c::I2C_SPLL_OC_DCUR.write_reg(dcur); // Run SPLL calibration // HP_SYS_CLKRST.ana_pll_ctrl0.sys_pll_cal_stop - let clkrst = crate::peripherals::HP_SYS_CLKRST::regs(); - - clkrst + HP_SYS_CLKRST::regs() .ana_pll_ctrl0() .modify(|_, w| w.sys_pll_cal_stop().clear_bit()); - while !clkrst.ana_pll_ctrl0().read().sys_pll_cal_end().bit_is_set() { + while !HP_SYS_CLKRST::regs() + .ana_pll_ctrl0() + .read() + .sys_pll_cal_end() + .bit_is_set() + { core::hint::spin_loop(); } - clkrst + HP_SYS_CLKRST::regs() .ana_pll_ctrl0() .modify(|_, w| w.sys_pll_cal_stop().set_bit()); diff --git a/esp-hal/src/soc/esp32p4/clocks.rs b/esp-hal/src/soc/esp32p4/clocks.rs index dc4297358e6..69a73dfc143 100644 --- a/esp-hal/src/soc/esp32p4/clocks.rs +++ b/esp-hal/src/soc/esp32p4/clocks.rs @@ -17,6 +17,8 @@ reason = "CPU frequency variant names follow the chip-spec MHz convention" )] +use crate::peripherals::{HP_SYS_CLKRST, LP_AON_CLKRST}; + define_clock_tree_types!(); /// CPU clock frequency presets for ESP32-P4X (eco5 / chip revision v3.x). @@ -26,7 +28,6 @@ define_clock_tree_types!(); pub enum CpuClock { /// 400 MHz CPU clock (eco5 / v3.x maximum) /// CPLL -> CPU_ROOT -> CPU/1, APB divider /4 = 100MHz - #[default] _400MHz = 400, /// 360 MHz CPU clock (conservative) @@ -38,6 +39,7 @@ pub enum CpuClock { /// 100 MHz CPU clock (ultra low power) /// CPLL -> CPU_ROOT -> CPU/4, APB /1 = 100MHz + #[default] _100MHz = 100, } @@ -49,6 +51,7 @@ impl CpuClock { apb_clk: Some(ApbClkConfig::new(3)), // /4 = 100 MHz lp_fast_clk: Some(LpFastClkConfig::RcFast), lp_slow_clk: Some(LpSlowClkConfig::RcSlow), + timg_calibration_clock: None, }; const PRESET_360: ClockConfig = ClockConfig { @@ -57,6 +60,7 @@ impl CpuClock { apb_clk: Some(ApbClkConfig::new(3)), // /4 = 90 MHz lp_fast_clk: Some(LpFastClkConfig::RcFast), lp_slow_clk: Some(LpSlowClkConfig::RcSlow), + timg_calibration_clock: None, }; const PRESET_200: ClockConfig = ClockConfig { @@ -65,6 +69,7 @@ impl CpuClock { apb_clk: Some(ApbClkConfig::new(1)), // /2 = 100 MHz lp_fast_clk: Some(LpFastClkConfig::RcFast), lp_slow_clk: Some(LpSlowClkConfig::RcSlow), + timg_calibration_clock: None, }; const PRESET_100: ClockConfig = ClockConfig { @@ -73,6 +78,7 @@ impl CpuClock { apb_clk: Some(ApbClkConfig::new(0)), // /1 = 100 MHz lp_fast_clk: Some(LpFastClkConfig::RcFast), lp_slow_clk: Some(LpSlowClkConfig::RcSlow), + timg_calibration_clock: None, }; } @@ -124,7 +130,7 @@ fn configure_cpu_root_clk_impl( CpuRootClkConfig::Cpll => 1, CpuRootClkConfig::RcFast => 2, }; - crate::peripherals::LP_AON_CLKRST::regs() + LP_AON_CLKRST::regs() .lp_aonclkrst_hp_clk_ctrl() .modify(|_, w| unsafe { w.lp_aonclkrst_hp_root_clk_src_sel().bits(sel) }); } @@ -174,7 +180,7 @@ fn configure_lp_fast_clk_impl( _old_selector: Option, new_selector: LpFastClkConfig, ) { - crate::peripherals::LP_AON_CLKRST::regs() + LP_AON_CLKRST::regs() .lp_aonclkrst_lp_clk_conf() .modify(|_, w| unsafe { w.lp_aonclkrst_fast_clk_sel().bits(match new_selector { @@ -190,13 +196,13 @@ fn configure_lp_slow_clk_impl( _old_selector: Option, new_selector: LpSlowClkConfig, ) { - crate::peripherals::LP_AON_CLKRST::regs() + LP_AON_CLKRST::regs() .lp_aonclkrst_lp_clk_conf() .modify(|_, w| unsafe { w.lp_aonclkrst_slow_clk_sel().bits(match new_selector { LpSlowClkConfig::RcSlow => 0, LpSlowClkConfig::Xtal32k => 1, - LpSlowClkConfig::Rc32k => 2, + // LpSlowClkConfig::Rc32k => 2, LpSlowClkConfig::OscSlow => 3, }) }); @@ -286,3 +292,28 @@ fn enable_pll_f240m_impl(_clocks: &mut ClockTree, _en: bool) {} fn enable_pll_f25m_impl(_clocks: &mut ClockTree, _en: bool) {} fn enable_pll_f50m_impl(_clocks: &mut ClockTree, _en: bool) {} fn enable_xtal_d2_clk_impl(_clocks: &mut ClockTree, _en: bool) {} + +// TIMG_CALIBRATION_CLOCK + +fn enable_timg_calibration_clock_impl(_clocks: &mut ClockTree, _en: bool) { + // Nothing to do here. +} + +fn configure_timg_calibration_clock_impl( + _clocks: &mut ClockTree, + _old_config: Option, + new_config: TimgCalibrationClockConfig, +) { + HP_SYS_CLKRST::regs() + .peri_clk_ctrl21() + .modify(|_, w| unsafe { + w.timergrp0_tgrt_clk_src_sel().bits(match new_config { + TimgCalibrationClockConfig::MpllClk => 0, + TimgCalibrationClockConfig::SpllClk => 1, + TimgCalibrationClockConfig::CpllClk => 2, + TimgCalibrationClockConfig::RcFastClk => 7, + TimgCalibrationClockConfig::RcSlowClk => 8, + TimgCalibrationClockConfig::Xtal32kClk => 10, + }) + }); +} diff --git a/esp-hal/src/soc/esp32p4/mod.rs b/esp-hal/src/soc/esp32p4/mod.rs index 439e719d6d8..9ea031af00f 100644 --- a/esp-hal/src/soc/esp32p4/mod.rs +++ b/esp-hal/src/soc/esp32p4/mod.rs @@ -10,26 +10,53 @@ pub(crate) mod regi2c; pub(crate) use esp32p4 as pac; -// P4 DMA module alias: the esp-hal GDMA driver expects the GDMA-AHB (`ahb_dma`) -// register layout. The PAC's `dma` module maps to a different block (see -// SOC_DW_GDMA_SUPPORTED), so alias `ahb_dma` to keep ahb_v2.rs type paths working. -#[allow(unused)] -pub(crate) mod dma_compat { - pub use super::pac::ahb_dma::*; -} - pub(crate) mod registers { pub const INTERRUPT_MAP_BASE: u32 = 0x500D_6000; + #[expect(dead_code)] pub const INTERRUPT_MAP_BASE_APP_CPU: u32 = 0x500D_6800; } -pub(crate) mod constants { - #[allow(dead_code)] // used by other chips; reserved for future P4 DRAM boundary checks - pub const SOC_DRAM_LOW: u32 = 0x4FF0_0000; - #[allow(dead_code)] - pub const SOC_DRAM_HIGH: u32 = 0x4FFC_0000; -} - pub(crate) fn pre_init() { // TODO: Check if anything needs to be done here } + +const CACHE_MAP_L1_ICACHE_0: u32 = 1 << 0; +const CACHE_MAP_L1_ICACHE_1: u32 = 1 << 1; +const CACHE_MAP_L1_DCACHE: u32 = 1 << 4; +const CACHE_MAP_L2_CACHE: u32 = 1 << 5; + +/// Write back a specific range of data in the cache. +pub(crate) unsafe fn cache_writeback_addr(addr: u32, size: u32) { + unsafe extern "C" { + fn Cache_WriteBack_Addr(bus: u32, addr: u32, size: u32); + } + + unsafe { + Cache_WriteBack_Addr( + CACHE_MAP_L1_ICACHE_0 + | CACHE_MAP_L1_ICACHE_1 + | CACHE_MAP_L1_DCACHE + | CACHE_MAP_L2_CACHE, + addr, + size, + ); + } +} + +/// Write back a specific range of data in the cache. +pub(crate) unsafe fn cache_invalidate_addr(addr: u32, size: u32) { + unsafe extern "C" { + fn Cache_Invalidate_Addr(bus: u32, addr: u32, size: u32); + } + + unsafe { + Cache_Invalidate_Addr( + CACHE_MAP_L1_ICACHE_0 + | CACHE_MAP_L1_ICACHE_1 + | CACHE_MAP_L1_DCACHE + | CACHE_MAP_L2_CACHE, + addr, + size, + ); + } +} diff --git a/esp-hal/src/soc/esp32p4/regi2c.rs b/esp-hal/src/soc/esp32p4/regi2c.rs index 63062f91779..9f78ef16e78 100644 --- a/esp-hal/src/soc/esp32p4/regi2c.rs +++ b/esp-hal/src/soc/esp32p4/regi2c.rs @@ -1,42 +1,36 @@ -//! I2C analog register access for ESP32-P4. -//! -//! Used for PLL configuration (CPLL, SPLL, MPLL) and other analog peripherals. -//! Accesses the LP_I2C_ANA_MST peripheral which bridges to internal analog I2C bus. -//! -//! Ref: TRM v0.5 Ch 49 (Analog I2C Controller) +use crate::rom::regi2c::{RegI2cMaster, RegI2cRegister, define_regi2c}; -// I2C slave addresses for analog blocks -#[allow(dead_code)] -pub(crate) const REGI2C_DIG_REG: u8 = 0x6d; -#[allow(dead_code)] -pub(crate) const REGI2C_CPU_PLL: u8 = 0x67; -#[allow(dead_code)] -pub(crate) const REGI2C_SDIO_PLL: u8 = 0x62; -#[allow(dead_code)] -pub(crate) const REGI2C_BIAS: u8 = 0x6a; -#[allow(dead_code)] -pub(crate) const REGI2C_MSPI: u8 = 0x63; -#[allow(dead_code)] -pub(crate) const REGI2C_SYS_PLL: u8 = 0x66; -#[allow(dead_code)] -pub(crate) const REGI2C_PLLA: u8 = 0x6f; -#[allow(dead_code)] -pub(crate) const REGI2C_SAR_I2C: u8 = 0x69; +define_regi2c! { + master: REGI2C_SDIO_PLL(0x62, 0) {} + master: REGI2C_MSPI(0x63, 0) { + reg: I2C_MPLL_DIV_REG_ADDR(2) {} + reg: I2C_MPLL_DHREF(3) {} + reg: I2C_MPLL_IR_CAL_RSTB(5) {} + } + master: REGI2C_SYS_PLL(0x66, 0) { + reg: I2C_SPLL_OC_REF_DIV(2) {} + reg: I2C_SPLL_OC_DIV_7_0(3) {} + reg: I2C_SPLL_OC_DCUR(6) {} + } + master: REGI2C_CPU_PLL(0x67, 0) { + reg: I2C_CPLL_OC_REF_DIV(2) {} + reg: I2C_CPLL_OC_DIV_7_0(3) {} + reg: I2C_CPLL_OC_DCUR(6) {} + } + master: REGI2C_SAR_I2C(0x69, 0) {} + master: REGI2C_BIAS(0x6a, 0) {} + master: REGI2C_DIG_REG(0x6d, 0) {} + master: REGI2C_PLLA(0x6f, 0) {} +} // Master select bits in ANA_CONF2 register const REGI2C_DIG_REG_MST_SEL: u16 = 1 << 10; const REGI2C_PLL_CPU_MST_SEL: u16 = 1 << 11; -#[allow(dead_code)] const REGI2C_PLL_SDIO_MST_SEL: u16 = 1 << 6; -#[allow(dead_code)] const REGI2C_BIAS_MST_SEL: u16 = 1 << 12; -#[allow(dead_code)] const REGI2C_MSPI_XTAL_MST_SEL: u16 = 1 << 9; -#[allow(dead_code)] const REGI2C_PLL_SYS_MST_SEL: u16 = 1 << 5; -#[allow(dead_code)] const REGI2C_PLLA_MST_SEL: u16 = 1 << 8; -#[allow(dead_code)] const REGI2C_SAR_I2C_MST_SEL: u16 = 1 << 7; /// I2C control register bit fields @@ -66,14 +60,14 @@ fn regi2c_enable_block(block: u8) { // Set the master select bit for this block let sel_bit: u32 = match block { - REGI2C_DIG_REG => REGI2C_DIG_REG_MST_SEL as u32, - REGI2C_CPU_PLL => REGI2C_PLL_CPU_MST_SEL as u32, - REGI2C_SDIO_PLL => REGI2C_PLL_SDIO_MST_SEL as u32, - REGI2C_BIAS => REGI2C_BIAS_MST_SEL as u32, - REGI2C_MSPI => REGI2C_MSPI_XTAL_MST_SEL as u32, - REGI2C_SYS_PLL => REGI2C_PLL_SYS_MST_SEL as u32, - REGI2C_PLLA => REGI2C_PLLA_MST_SEL as u32, - REGI2C_SAR_I2C => REGI2C_SAR_I2C_MST_SEL as u32, + v if v == REGI2C_DIG_REG.master => REGI2C_DIG_REG_MST_SEL as u32, + v if v == REGI2C_CPU_PLL.master => REGI2C_PLL_CPU_MST_SEL as u32, + v if v == REGI2C_SDIO_PLL.master => REGI2C_PLL_SDIO_MST_SEL as u32, + v if v == REGI2C_BIAS.master => REGI2C_BIAS_MST_SEL as u32, + v if v == REGI2C_MSPI.master => REGI2C_MSPI_XTAL_MST_SEL as u32, + v if v == REGI2C_SYS_PLL.master => REGI2C_PLL_SYS_MST_SEL as u32, + v if v == REGI2C_PLLA.master => REGI2C_PLLA_MST_SEL as u32, + v if v == REGI2C_SAR_I2C.master => REGI2C_SAR_I2C_MST_SEL as u32, _ => return, }; diff --git a/esp-hal/src/spi/master/mod.rs b/esp-hal/src/spi/master/mod.rs index 7e68365f074..bd767fa3364 100644 --- a/esp-hal/src/spi/master/mod.rs +++ b/esp-hal/src/spi/master/mod.rs @@ -57,11 +57,12 @@ use enumset::{EnumSet, EnumSetType, enum_set}; use procmacros::doc_replace; use super::{BitOrder, Error, Mode}; +#[cfg(spi_master_supports_dma)] +use crate::RegisterToggle; use crate::{ Async, Blocking, DriverMode, - RegisterToggle, asynch::AtomicWaker, gpio::{ InputConfig, diff --git a/esp-hal/src/system.rs b/esp-hal/src/system.rs index bc9cb3e5ee1..17f384800f6 100644 --- a/esp-hal/src/system.rs +++ b/esp-hal/src/system.rs @@ -103,6 +103,7 @@ impl GenericPeripheralGuard

{ Self {} } + #[cfg_attr(esp32p4, allow(unused))] #[cfg_attr(not(feature = "unstable"), allow(unused))] pub(crate) fn new() -> Self { Self::new_with(|| {}) diff --git a/esp-metadata-generated/src/_build_script_utils.rs b/esp-metadata-generated/src/_build_script_utils.rs index fa9b17d7c0b..b589cb60b91 100644 --- a/esp-metadata-generated/src/_build_script_utils.rs +++ b/esp-metadata-generated/src/_build_script_utils.rs @@ -4259,13 +4259,15 @@ impl Chip { symbols: &[ "esp32p4", "riscv", - "multi_core", + "single_core", "soc_has_efuse", "soc_has_gpio", + "soc_has_system", "soc_has_hp_sys", "soc_has_hp_sys_clkrst", "soc_has_interrupt_core0", "soc_has_interrupt_core1", + "soc_has_lp_i2c_ana_mst", "soc_has_clic", "soc_has_io_mux", "soc_has_lp_aon", @@ -4306,6 +4308,7 @@ impl Chip { "soc_has_sha", "soc_has_rsa", "soc_has_ecc", + "soc_has_sw_interrupt", "very_large_intr_status", "spi_octal", "rom_crc_le", @@ -4313,7 +4316,6 @@ impl Chip { "rom_md5_bsd", "pm_support_ext1_wakeup", "pm_support_touch_sensor_wakeup", - "dma_driver_supported", "gpio_driver_supported", "i2c_master_driver_supported", "interrupts_driver_supported", @@ -4321,12 +4323,15 @@ impl Chip { "soc_driver_supported", "spi_master_driver_supported", "systimer_driver_supported", + "timergroup_driver_supported", "uart_driver_supported", "usb_serial_jtag_driver_supported", "i2c_master_i2c0", "i2c_master_i2c1", "spi_master_spi2", "spi_master_spi3", + "timergroup_timg0", + "timergroup_timg1", "uart_uart0", "uart_uart1", "uart_uart2", @@ -4393,26 +4398,30 @@ impl Chip { "soc_has_clock_node_apb_clk", "soc_has_clock_node_lp_fast_clk", "soc_has_clock_node_lp_slow_clk", + "soc_has_clock_node_timg_calibration_clock", "soc_has_clock_node_uart_function_clock", "soc_has_clock_node_uart_baud_rate_generator", "soc_has_clock_node_timg_function_clock", "soc_has_clock_node_timg_wdt_clock", "has_dram_region", "has_dram2_uninit_region", - "spi_master_supports_dma", + "timergroup_timg_has_divcnt_rst", + "timergroup_rc_fast_calibration_is_set", "uart_ram_size=\"128\"", "uart_version=\"2\"", ], cfgs: &[ "cargo:rustc-cfg=esp32p4", "cargo:rustc-cfg=riscv", - "cargo:rustc-cfg=multi_core", + "cargo:rustc-cfg=single_core", "cargo:rustc-cfg=soc_has_efuse", "cargo:rustc-cfg=soc_has_gpio", + "cargo:rustc-cfg=soc_has_system", "cargo:rustc-cfg=soc_has_hp_sys", "cargo:rustc-cfg=soc_has_hp_sys_clkrst", "cargo:rustc-cfg=soc_has_interrupt_core0", "cargo:rustc-cfg=soc_has_interrupt_core1", + "cargo:rustc-cfg=soc_has_lp_i2c_ana_mst", "cargo:rustc-cfg=soc_has_clic", "cargo:rustc-cfg=soc_has_io_mux", "cargo:rustc-cfg=soc_has_lp_aon", @@ -4453,6 +4462,7 @@ impl Chip { "cargo:rustc-cfg=soc_has_sha", "cargo:rustc-cfg=soc_has_rsa", "cargo:rustc-cfg=soc_has_ecc", + "cargo:rustc-cfg=soc_has_sw_interrupt", "cargo:rustc-cfg=very_large_intr_status", "cargo:rustc-cfg=spi_octal", "cargo:rustc-cfg=rom_crc_le", @@ -4460,7 +4470,6 @@ impl Chip { "cargo:rustc-cfg=rom_md5_bsd", "cargo:rustc-cfg=pm_support_ext1_wakeup", "cargo:rustc-cfg=pm_support_touch_sensor_wakeup", - "cargo:rustc-cfg=dma_driver_supported", "cargo:rustc-cfg=gpio_driver_supported", "cargo:rustc-cfg=i2c_master_driver_supported", "cargo:rustc-cfg=interrupts_driver_supported", @@ -4468,12 +4477,15 @@ impl Chip { "cargo:rustc-cfg=soc_driver_supported", "cargo:rustc-cfg=spi_master_driver_supported", "cargo:rustc-cfg=systimer_driver_supported", + "cargo:rustc-cfg=timergroup_driver_supported", "cargo:rustc-cfg=uart_driver_supported", "cargo:rustc-cfg=usb_serial_jtag_driver_supported", "cargo:rustc-cfg=i2c_master_i2c0", "cargo:rustc-cfg=i2c_master_i2c1", "cargo:rustc-cfg=spi_master_spi2", "cargo:rustc-cfg=spi_master_spi3", + "cargo:rustc-cfg=timergroup_timg0", + "cargo:rustc-cfg=timergroup_timg1", "cargo:rustc-cfg=uart_uart0", "cargo:rustc-cfg=uart_uart1", "cargo:rustc-cfg=uart_uart2", @@ -4540,13 +4552,15 @@ impl Chip { "cargo:rustc-cfg=soc_has_clock_node_apb_clk", "cargo:rustc-cfg=soc_has_clock_node_lp_fast_clk", "cargo:rustc-cfg=soc_has_clock_node_lp_slow_clk", + "cargo:rustc-cfg=soc_has_clock_node_timg_calibration_clock", "cargo:rustc-cfg=soc_has_clock_node_uart_function_clock", "cargo:rustc-cfg=soc_has_clock_node_uart_baud_rate_generator", "cargo:rustc-cfg=soc_has_clock_node_timg_function_clock", "cargo:rustc-cfg=soc_has_clock_node_timg_wdt_clock", "cargo:rustc-cfg=has_dram_region", "cargo:rustc-cfg=has_dram2_uninit_region", - "cargo:rustc-cfg=spi_master_supports_dma", + "cargo:rustc-cfg=timergroup_timg_has_divcnt_rst", + "cargo:rustc-cfg=timergroup_rc_fast_calibration_is_set", "cargo:rustc-cfg=uart_ram_size=\"128\"", "cargo:rustc-cfg=uart_version=\"2\"", ], diff --git a/esp-metadata-generated/src/_generated_esp32p4.rs b/esp-metadata-generated/src/_generated_esp32p4.rs index 0b302397b04..19d30d95c2b 100644 --- a/esp-metadata-generated/src/_generated_esp32p4.rs +++ b/esp-metadata-generated/src/_generated_esp32p4.rs @@ -44,10 +44,10 @@ macro_rules! property { "riscv" }; ("cores") => { - 2 + 1 }; ("cores", str) => { - stringify!(2) + stringify!(1) }; ("trm") => { "https://www.espressif.com/sites/default/files/documentation/esp32-p4_technical_reference_manual_en.pdf" @@ -293,7 +293,7 @@ macro_rules! property { (0, 4095) }; ("spi_master.supports_dma") => { - true + false }; ("spi_master.has_octal") => { false @@ -310,6 +310,12 @@ macro_rules! property { ("spi_slave.supports_dma") => { false }; + ("timergroup.timg_has_timer1") => { + false + }; + ("timergroup.timg_has_divcnt_rst") => { + true + }; ("uart.ram_size") => { 128 }; @@ -939,6 +945,20 @@ macro_rules! for_each_sha_algorithm { /// todo!() /// } /// +/// // TIMG_CALIBRATION_CLOCK +/// +/// fn enable_timg_calibration_clock_impl(_clocks: &mut ClockTree, _en: bool) { +/// todo!() +/// } +/// +/// fn configure_timg_calibration_clock_impl( +/// _clocks: &mut ClockTree, +/// _old_config: Option, +/// _new_config: TimgCalibrationClockConfig, +/// ) { +/// todo!() +/// } +/// /// impl TimgInstance { /// // TIMG_FUNCTION_CLOCK /// @@ -1099,11 +1119,26 @@ macro_rules! define_clock_tree_types { RcSlow, /// Selects `XTAL32K_CLK`. Xtal32k, - /// Selects `RC32K_CLK`. - Rc32k, /// Selects `OSC_SLOW_CLK`. OscSlow, } + /// The list of clock signals that the `TIMG_CALIBRATION_CLOCK` multiplexer can output. + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub enum TimgCalibrationClockConfig { + /// Selects `MPLL_CLK`. + MpllClk, + /// Selects `SPLL_CLK`. + SpllClk, + /// Selects `CPLL_CLK`. + CpllClk, + /// Selects `RC_FAST_CLK`. + RcFastClk, + /// Selects `LP_SLOW_CLK`. + RcSlowClk, + /// Selects `XTAL32K_CLK`. + Xtal32kClk, + } /// The list of clock signals that the `TIMG0_FUNCTION_CLOCK` multiplexer can output. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -1217,13 +1252,17 @@ macro_rules! define_clock_tree_types { apb_clk: Option, lp_fast_clk: Option, lp_slow_clk: Option, + timg_calibration_clock: Option, timg_function_clock: [Option; 2], timg_wdt_clock: [Option; 2], uart_function_clock: [Option; 5], uart_baud_rate_generator: [Option; 5], + cpll_clk_refcount: u32, spll_clk_refcount: u32, mpll_clk_refcount: u32, rc_fast_clk_refcount: u32, + xtal32k_clk_refcount: u32, + rc32k_clk_refcount: u32, pll_f20m_refcount: u32, pll_f80m_refcount: u32, pll_f120m_refcount: u32, @@ -1233,7 +1272,7 @@ macro_rules! define_clock_tree_types { pll_f50m_refcount: u32, apb_clk_refcount: u32, lp_fast_clk_refcount: u32, - lp_slow_clk_refcount: u32, + timg_calibration_clock_refcount: u32, timg_function_clock_refcount: [u32; 2], timg_wdt_clock_refcount: [u32; 2], uart_function_clock_refcount: [u32; 5], @@ -1264,6 +1303,10 @@ macro_rules! define_clock_tree_types { pub fn lp_slow_clk(&self) -> Option { self.lp_slow_clk } + /// Returns the current configuration of the TIMG_CALIBRATION_CLOCK clock tree node + pub fn timg_calibration_clock(&self) -> Option { + self.timg_calibration_clock + } /// Returns the current configuration of the TIMG0_FUNCTION_CLOCK clock tree node pub fn timg0_function_clock(&self) -> Option { self.timg_function_clock[TimgInstance::Timg0 as usize] @@ -1328,13 +1371,17 @@ macro_rules! define_clock_tree_types { apb_clk: None, lp_fast_clk: None, lp_slow_clk: None, + timg_calibration_clock: None, timg_function_clock: [None; 2], timg_wdt_clock: [None; 2], uart_function_clock: [None; 5], uart_baud_rate_generator: [None; 5], + cpll_clk_refcount: 0, spll_clk_refcount: 0, mpll_clk_refcount: 0, rc_fast_clk_refcount: 0, + xtal32k_clk_refcount: 0, + rc32k_clk_refcount: 0, pll_f20m_refcount: 0, pll_f80m_refcount: 0, pll_f120m_refcount: 0, @@ -1344,7 +1391,7 @@ macro_rules! define_clock_tree_types { pll_f50m_refcount: 0, apb_clk_refcount: 0, lp_fast_clk_refcount: 0, - lp_slow_clk_refcount: 0, + timg_calibration_clock_refcount: 0, timg_function_clock_refcount: [0; 2], timg_wdt_clock_refcount: [0; 2], uart_function_clock_refcount: [0; 5], @@ -1360,6 +1407,8 @@ macro_rules! define_clock_tree_types { ::core::sync::atomic::AtomicU32::new(0); static LP_SLOW_CLK_FREQ_CACHE: ::core::sync::atomic::AtomicU32 = ::core::sync::atomic::AtomicU32::new(0); + static TIMG_CALIBRATION_CLOCK_FREQ_CACHE: ::core::sync::atomic::AtomicU32 = + ::core::sync::atomic::AtomicU32::new(0); static TIMG_FUNCTION_CLOCK_FREQ_CACHE: [::core::sync::atomic::AtomicU32; 2] = [const { ::core::sync::atomic::AtomicU32::new(0) }; 2]; static TIMG_WDT_CLOCK_FREQ_CACHE: [::core::sync::atomic::AtomicU32; 2] = @@ -1375,15 +1424,19 @@ macro_rules! define_clock_tree_types { } pub fn request_cpll_clk(clocks: &mut ClockTree) { trace!("Requesting CPLL_CLK"); - trace!("Enabling CPLL_CLK"); - request_xtal_clk(clocks); - enable_cpll_clk_impl(clocks, true); + if increment_reference_count(&mut clocks.cpll_clk_refcount) { + trace!("Enabling CPLL_CLK"); + request_xtal_clk(clocks); + enable_cpll_clk_impl(clocks, true); + } } pub fn release_cpll_clk(clocks: &mut ClockTree) { trace!("Releasing CPLL_CLK"); - trace!("Disabling CPLL_CLK"); - enable_cpll_clk_impl(clocks, false); - release_xtal_clk(clocks); + if decrement_reference_count(&mut clocks.cpll_clk_refcount) { + trace!("Disabling CPLL_CLK"); + enable_cpll_clk_impl(clocks, false); + release_xtal_clk(clocks); + } } pub fn cpll_clk_frequency() -> u32 { 400000000 @@ -1445,13 +1498,17 @@ macro_rules! define_clock_tree_types { } pub fn request_xtal32k_clk(clocks: &mut ClockTree) { trace!("Requesting XTAL32K_CLK"); - trace!("Enabling XTAL32K_CLK"); - enable_xtal32k_clk_impl(clocks, true); + if increment_reference_count(&mut clocks.xtal32k_clk_refcount) { + trace!("Enabling XTAL32K_CLK"); + enable_xtal32k_clk_impl(clocks, true); + } } pub fn release_xtal32k_clk(clocks: &mut ClockTree) { trace!("Releasing XTAL32K_CLK"); - trace!("Disabling XTAL32K_CLK"); - enable_xtal32k_clk_impl(clocks, false); + if decrement_reference_count(&mut clocks.xtal32k_clk_refcount) { + trace!("Disabling XTAL32K_CLK"); + enable_xtal32k_clk_impl(clocks, false); + } } pub fn xtal32k_clk_frequency() -> u32 { 32768 @@ -1484,13 +1541,17 @@ macro_rules! define_clock_tree_types { } pub fn request_rc32k_clk(clocks: &mut ClockTree) { trace!("Requesting RC32K_CLK"); - trace!("Enabling RC32K_CLK"); - enable_rc32k_clk_impl(clocks, true); + if increment_reference_count(&mut clocks.rc32k_clk_refcount) { + trace!("Enabling RC32K_CLK"); + enable_rc32k_clk_impl(clocks, true); + } } pub fn release_rc32k_clk(clocks: &mut ClockTree) { trace!("Releasing RC32K_CLK"); - trace!("Disabling RC32K_CLK"); - enable_rc32k_clk_impl(clocks, false); + if decrement_reference_count(&mut clocks.rc32k_clk_refcount) { + trace!("Disabling RC32K_CLK"); + enable_rc32k_clk_impl(clocks, false); + } } pub fn rc32k_clk_frequency() -> u32 { 32768 @@ -1815,24 +1876,18 @@ macro_rules! define_clock_tree_types { pub fn configure_lp_slow_clk(clocks: &mut ClockTree, new_selector: LpSlowClkConfig) { let old_selector = clocks.lp_slow_clk.replace(new_selector); refresh_lp_slow_clk_downstream(clocks); - if clocks.lp_slow_clk_refcount > 0 { - match new_selector { - LpSlowClkConfig::RcSlow => request_rc_slow_clk(clocks), - LpSlowClkConfig::Xtal32k => request_xtal32k_clk(clocks), - LpSlowClkConfig::Rc32k => request_rc32k_clk(clocks), - LpSlowClkConfig::OscSlow => request_osc_slow_clk(clocks), - } - configure_lp_slow_clk_impl(clocks, old_selector, new_selector); - if let Some(old_selector) = old_selector { - match old_selector { - LpSlowClkConfig::RcSlow => release_rc_slow_clk(clocks), - LpSlowClkConfig::Xtal32k => release_xtal32k_clk(clocks), - LpSlowClkConfig::Rc32k => release_rc32k_clk(clocks), - LpSlowClkConfig::OscSlow => release_osc_slow_clk(clocks), - } + match new_selector { + LpSlowClkConfig::RcSlow => request_rc_slow_clk(clocks), + LpSlowClkConfig::Xtal32k => request_xtal32k_clk(clocks), + LpSlowClkConfig::OscSlow => request_osc_slow_clk(clocks), + } + configure_lp_slow_clk_impl(clocks, old_selector, new_selector); + if let Some(old_selector) = old_selector { + match old_selector { + LpSlowClkConfig::RcSlow => release_rc_slow_clk(clocks), + LpSlowClkConfig::Xtal32k => release_xtal32k_clk(clocks), + LpSlowClkConfig::OscSlow => release_osc_slow_clk(clocks), } - } else { - configure_lp_slow_clk_impl(clocks, old_selector, new_selector); } } pub fn lp_slow_clk_config(clocks: &mut ClockTree) -> Option { @@ -1840,28 +1895,22 @@ macro_rules! define_clock_tree_types { } pub fn request_lp_slow_clk(clocks: &mut ClockTree) { trace!("Requesting LP_SLOW_CLK"); - if increment_reference_count(&mut clocks.lp_slow_clk_refcount) { - trace!("Enabling LP_SLOW_CLK"); - match unwrap!(clocks.lp_slow_clk) { - LpSlowClkConfig::RcSlow => request_rc_slow_clk(clocks), - LpSlowClkConfig::Xtal32k => request_xtal32k_clk(clocks), - LpSlowClkConfig::Rc32k => request_rc32k_clk(clocks), - LpSlowClkConfig::OscSlow => request_osc_slow_clk(clocks), - } - enable_lp_slow_clk_impl(clocks, true); + trace!("Enabling LP_SLOW_CLK"); + match unwrap!(clocks.lp_slow_clk) { + LpSlowClkConfig::RcSlow => request_rc_slow_clk(clocks), + LpSlowClkConfig::Xtal32k => request_xtal32k_clk(clocks), + LpSlowClkConfig::OscSlow => request_osc_slow_clk(clocks), } + enable_lp_slow_clk_impl(clocks, true); } pub fn release_lp_slow_clk(clocks: &mut ClockTree) { trace!("Releasing LP_SLOW_CLK"); - if decrement_reference_count(&mut clocks.lp_slow_clk_refcount) { - trace!("Disabling LP_SLOW_CLK"); - enable_lp_slow_clk_impl(clocks, false); - match unwrap!(clocks.lp_slow_clk) { - LpSlowClkConfig::RcSlow => release_rc_slow_clk(clocks), - LpSlowClkConfig::Xtal32k => release_xtal32k_clk(clocks), - LpSlowClkConfig::Rc32k => release_rc32k_clk(clocks), - LpSlowClkConfig::OscSlow => release_osc_slow_clk(clocks), - } + trace!("Disabling LP_SLOW_CLK"); + enable_lp_slow_clk_impl(clocks, false); + match unwrap!(clocks.lp_slow_clk) { + LpSlowClkConfig::RcSlow => release_rc_slow_clk(clocks), + LpSlowClkConfig::Xtal32k => release_xtal32k_clk(clocks), + LpSlowClkConfig::OscSlow => release_osc_slow_clk(clocks), } } #[allow(unused_variables)] @@ -1872,13 +1921,94 @@ macro_rules! define_clock_tree_types { match config { LpSlowClkConfig::RcSlow => rc_slow_clk_frequency(), LpSlowClkConfig::Xtal32k => xtal32k_clk_frequency(), - LpSlowClkConfig::Rc32k => rc32k_clk_frequency(), LpSlowClkConfig::OscSlow => osc_slow_clk_frequency(), } } pub fn lp_slow_clk_frequency() -> u32 { LP_SLOW_CLK_FREQ_CACHE.load(::core::sync::atomic::Ordering::Acquire) } + pub fn configure_timg_calibration_clock( + clocks: &mut ClockTree, + new_selector: TimgCalibrationClockConfig, + ) { + let old_selector = clocks.timg_calibration_clock.replace(new_selector); + refresh_timg_calibration_clock_downstream(clocks); + if clocks.timg_calibration_clock_refcount > 0 { + match new_selector { + TimgCalibrationClockConfig::MpllClk => request_mpll_clk(clocks), + TimgCalibrationClockConfig::SpllClk => request_spll_clk(clocks), + TimgCalibrationClockConfig::CpllClk => request_cpll_clk(clocks), + TimgCalibrationClockConfig::RcFastClk => request_rc_fast_clk(clocks), + TimgCalibrationClockConfig::RcSlowClk => request_lp_slow_clk(clocks), + TimgCalibrationClockConfig::Xtal32kClk => request_xtal32k_clk(clocks), + } + configure_timg_calibration_clock_impl(clocks, old_selector, new_selector); + if let Some(old_selector) = old_selector { + match old_selector { + TimgCalibrationClockConfig::MpllClk => release_mpll_clk(clocks), + TimgCalibrationClockConfig::SpllClk => release_spll_clk(clocks), + TimgCalibrationClockConfig::CpllClk => release_cpll_clk(clocks), + TimgCalibrationClockConfig::RcFastClk => release_rc_fast_clk(clocks), + TimgCalibrationClockConfig::RcSlowClk => release_lp_slow_clk(clocks), + TimgCalibrationClockConfig::Xtal32kClk => release_xtal32k_clk(clocks), + } + } + } else { + configure_timg_calibration_clock_impl(clocks, old_selector, new_selector); + } + } + pub fn timg_calibration_clock_config( + clocks: &mut ClockTree, + ) -> Option { + clocks.timg_calibration_clock + } + pub fn request_timg_calibration_clock(clocks: &mut ClockTree) { + trace!("Requesting TIMG_CALIBRATION_CLOCK"); + if increment_reference_count(&mut clocks.timg_calibration_clock_refcount) { + trace!("Enabling TIMG_CALIBRATION_CLOCK"); + match unwrap!(clocks.timg_calibration_clock) { + TimgCalibrationClockConfig::MpllClk => request_mpll_clk(clocks), + TimgCalibrationClockConfig::SpllClk => request_spll_clk(clocks), + TimgCalibrationClockConfig::CpllClk => request_cpll_clk(clocks), + TimgCalibrationClockConfig::RcFastClk => request_rc_fast_clk(clocks), + TimgCalibrationClockConfig::RcSlowClk => request_lp_slow_clk(clocks), + TimgCalibrationClockConfig::Xtal32kClk => request_xtal32k_clk(clocks), + } + enable_timg_calibration_clock_impl(clocks, true); + } + } + pub fn release_timg_calibration_clock(clocks: &mut ClockTree) { + trace!("Releasing TIMG_CALIBRATION_CLOCK"); + if decrement_reference_count(&mut clocks.timg_calibration_clock_refcount) { + trace!("Disabling TIMG_CALIBRATION_CLOCK"); + enable_timg_calibration_clock_impl(clocks, false); + match unwrap!(clocks.timg_calibration_clock) { + TimgCalibrationClockConfig::MpllClk => release_mpll_clk(clocks), + TimgCalibrationClockConfig::SpllClk => release_spll_clk(clocks), + TimgCalibrationClockConfig::CpllClk => release_cpll_clk(clocks), + TimgCalibrationClockConfig::RcFastClk => release_rc_fast_clk(clocks), + TimgCalibrationClockConfig::RcSlowClk => release_lp_slow_clk(clocks), + TimgCalibrationClockConfig::Xtal32kClk => release_xtal32k_clk(clocks), + } + } + } + #[allow(unused_variables)] + pub fn timg_calibration_clock_config_frequency( + clocks: &mut ClockTree, + config: TimgCalibrationClockConfig, + ) -> u32 { + match config { + TimgCalibrationClockConfig::MpllClk => mpll_clk_frequency(), + TimgCalibrationClockConfig::SpllClk => spll_clk_frequency(), + TimgCalibrationClockConfig::CpllClk => cpll_clk_frequency(), + TimgCalibrationClockConfig::RcFastClk => rc_fast_clk_frequency(), + TimgCalibrationClockConfig::RcSlowClk => lp_slow_clk_frequency(), + TimgCalibrationClockConfig::Xtal32kClk => xtal32k_clk_frequency(), + } + } + pub fn timg_calibration_clock_frequency() -> u32 { + TIMG_CALIBRATION_CLOCK_FREQ_CACHE.load(::core::sync::atomic::Ordering::Acquire) + } impl TimgInstance { pub fn configure_function_clock( self, @@ -2170,6 +2300,8 @@ macro_rules! define_clock_tree_types { pub lp_fast_clk: Option, /// `LP_SLOW_CLK` configuration. pub lp_slow_clk: Option, + /// `TIMG_CALIBRATION_CLOCK` configuration. + pub timg_calibration_clock: Option, } impl ClockConfig { fn apply(&self, clocks: &mut ClockTree) { @@ -2188,6 +2320,9 @@ macro_rules! define_clock_tree_types { if let Some(config) = self.lp_slow_clk { configure_lp_slow_clk(clocks, config); } + if let Some(config) = self.timg_calibration_clock { + configure_timg_calibration_clock(clocks, config); + } } } fn increment_reference_count(refcount: &mut u32) -> bool { @@ -2241,6 +2376,15 @@ macro_rules! define_clock_tree_types { ::core::sync::atomic::Ordering::Release, ); } + refresh_timg_calibration_clock_downstream(clocks); + } + fn refresh_timg_calibration_clock_downstream(clocks: &mut ClockTree) { + if let Some(config) = clocks.timg_calibration_clock { + TIMG_CALIBRATION_CLOCK_FREQ_CACHE.store( + timg_calibration_clock_config_frequency(clocks, config), + ::core::sync::atomic::Ordering::Release, + ); + } } fn refresh_timg_function_clock_downstream(clocks: &mut ClockTree, instance: TimgInstance) { if let Some(config) = clocks.timg_function_clock[instance as usize] { @@ -2382,8 +2526,13 @@ macro_rules! implement_peripheral_clocks { UsbOtg20, } impl Peripheral { - const KEEP_ENABLED: &[Peripheral] = - &[Self::Iomux, Self::Systimer, Self::Uart0, Self::UsbDevice]; + const KEEP_ENABLED: &[Peripheral] = &[ + Self::Iomux, + Self::Systimer, + Self::Timg0, + Self::Uart0, + Self::UsbDevice, + ]; const COUNT: usize = Self::ALL.len(); const ALL: &[Self] = &[ Self::Adc, @@ -3243,14 +3392,18 @@ macro_rules! for_each_peripheral { _for_each_inner_peripheral!((@ peri_type #[doc = "EFUSE peripheral singleton"] EFUSE <= EFUSE() (unstable))); _for_each_inner_peripheral!((@ peri_type #[doc = "GPIO peripheral singleton"] GPIO <= GPIO() (unstable))); - _for_each_inner_peripheral!((@ peri_type #[doc = "HP_SYS peripheral singleton"] - HP_SYS <= HP_SYS() (unstable))); _for_each_inner_peripheral!((@ peri_type #[doc = + _for_each_inner_peripheral!((@ peri_type #[doc = "SYSTEM peripheral singleton"] + SYSTEM <= HP_SYS() (unstable))); _for_each_inner_peripheral!((@ peri_type #[doc = + "HP_SYS peripheral singleton"] HP_SYS <= HP_SYS() (unstable))); + _for_each_inner_peripheral!((@ peri_type #[doc = "HP_SYS_CLKRST peripheral singleton"] HP_SYS_CLKRST <= HP_SYS_CLKRST() (unstable))); _for_each_inner_peripheral!((@ peri_type #[doc = "INTERRUPT_CORE0 peripheral singleton"] INTERRUPT_CORE0 <= INTERRUPT_CORE0() (unstable))); _for_each_inner_peripheral!((@ peri_type #[doc = "INTERRUPT_CORE1 peripheral singleton"] INTERRUPT_CORE1 <= INTERRUPT_CORE1() (unstable))); _for_each_inner_peripheral!((@ peri_type #[doc = + "LP_I2C_ANA_MST peripheral singleton"] LP_I2C_ANA_MST <= LP_I2C_ANA_MST() + (unstable))); _for_each_inner_peripheral!((@ peri_type #[doc = "CLIC peripheral singleton"] CLIC <= CLIC() (unstable))); _for_each_inner_peripheral!((@ peri_type #[doc = "IO_MUX peripheral singleton"] IO_MUX <= IO_MUX() (unstable))); _for_each_inner_peripheral!((@ peri_type #[doc = @@ -3336,39 +3489,43 @@ macro_rules! for_each_peripheral { enable_peri_interrupt, disable_peri_interrupt }) (unstable))); _for_each_inner_peripheral!((@ peri_type #[doc = "ECC peripheral singleton"] ECC <= ECC(ECC : { bind_peri_interrupt, enable_peri_interrupt, disable_peri_interrupt - }) (unstable))); _for_each_inner_peripheral!((GPIO0)); - _for_each_inner_peripheral!((GPIO1)); _for_each_inner_peripheral!((GPIO2)); - _for_each_inner_peripheral!((GPIO3)); _for_each_inner_peripheral!((GPIO4)); - _for_each_inner_peripheral!((GPIO5)); _for_each_inner_peripheral!((GPIO6)); - _for_each_inner_peripheral!((GPIO7)); _for_each_inner_peripheral!((GPIO8)); - _for_each_inner_peripheral!((GPIO9)); _for_each_inner_peripheral!((GPIO10)); - _for_each_inner_peripheral!((GPIO11)); _for_each_inner_peripheral!((GPIO12)); - _for_each_inner_peripheral!((GPIO13)); _for_each_inner_peripheral!((GPIO14)); - _for_each_inner_peripheral!((GPIO15)); _for_each_inner_peripheral!((GPIO16)); - _for_each_inner_peripheral!((GPIO17)); _for_each_inner_peripheral!((GPIO18)); - _for_each_inner_peripheral!((GPIO19)); _for_each_inner_peripheral!((GPIO20)); - _for_each_inner_peripheral!((GPIO21)); _for_each_inner_peripheral!((GPIO22)); - _for_each_inner_peripheral!((GPIO23)); _for_each_inner_peripheral!((GPIO24)); - _for_each_inner_peripheral!((GPIO25)); _for_each_inner_peripheral!((GPIO26)); - _for_each_inner_peripheral!((GPIO27)); _for_each_inner_peripheral!((GPIO28)); - _for_each_inner_peripheral!((GPIO29)); _for_each_inner_peripheral!((GPIO30)); - _for_each_inner_peripheral!((GPIO31)); _for_each_inner_peripheral!((GPIO32)); - _for_each_inner_peripheral!((GPIO33)); _for_each_inner_peripheral!((GPIO34)); - _for_each_inner_peripheral!((GPIO35)); _for_each_inner_peripheral!((GPIO36)); - _for_each_inner_peripheral!((GPIO37)); _for_each_inner_peripheral!((GPIO38)); - _for_each_inner_peripheral!((GPIO39)); _for_each_inner_peripheral!((GPIO40)); - _for_each_inner_peripheral!((GPIO41)); _for_each_inner_peripheral!((GPIO42)); - _for_each_inner_peripheral!((GPIO43)); _for_each_inner_peripheral!((GPIO44)); - _for_each_inner_peripheral!((GPIO45)); _for_each_inner_peripheral!((GPIO46)); - _for_each_inner_peripheral!((GPIO47)); _for_each_inner_peripheral!((GPIO48)); - _for_each_inner_peripheral!((GPIO49)); _for_each_inner_peripheral!((GPIO50)); - _for_each_inner_peripheral!((GPIO51)); _for_each_inner_peripheral!((GPIO52)); - _for_each_inner_peripheral!((GPIO53)); _for_each_inner_peripheral!((GPIO54)); + }) (unstable))); _for_each_inner_peripheral!((@ peri_type #[doc = + "SW_INTERRUPT peripheral singleton"] SW_INTERRUPT <= virtual() (unstable))); + _for_each_inner_peripheral!((GPIO0)); _for_each_inner_peripheral!((GPIO1)); + _for_each_inner_peripheral!((GPIO2)); _for_each_inner_peripheral!((GPIO3)); + _for_each_inner_peripheral!((GPIO4)); _for_each_inner_peripheral!((GPIO5)); + _for_each_inner_peripheral!((GPIO6)); _for_each_inner_peripheral!((GPIO7)); + _for_each_inner_peripheral!((GPIO8)); _for_each_inner_peripheral!((GPIO9)); + _for_each_inner_peripheral!((GPIO10)); _for_each_inner_peripheral!((GPIO11)); + _for_each_inner_peripheral!((GPIO12)); _for_each_inner_peripheral!((GPIO13)); + _for_each_inner_peripheral!((GPIO14)); _for_each_inner_peripheral!((GPIO15)); + _for_each_inner_peripheral!((GPIO16)); _for_each_inner_peripheral!((GPIO17)); + _for_each_inner_peripheral!((GPIO18)); _for_each_inner_peripheral!((GPIO19)); + _for_each_inner_peripheral!((GPIO20)); _for_each_inner_peripheral!((GPIO21)); + _for_each_inner_peripheral!((GPIO22)); _for_each_inner_peripheral!((GPIO23)); + _for_each_inner_peripheral!((GPIO24)); _for_each_inner_peripheral!((GPIO25)); + _for_each_inner_peripheral!((GPIO26)); _for_each_inner_peripheral!((GPIO27)); + _for_each_inner_peripheral!((GPIO28)); _for_each_inner_peripheral!((GPIO29)); + _for_each_inner_peripheral!((GPIO30)); _for_each_inner_peripheral!((GPIO31)); + _for_each_inner_peripheral!((GPIO32)); _for_each_inner_peripheral!((GPIO33)); + _for_each_inner_peripheral!((GPIO34)); _for_each_inner_peripheral!((GPIO35)); + _for_each_inner_peripheral!((GPIO36)); _for_each_inner_peripheral!((GPIO37)); + _for_each_inner_peripheral!((GPIO38)); _for_each_inner_peripheral!((GPIO39)); + _for_each_inner_peripheral!((GPIO40)); _for_each_inner_peripheral!((GPIO41)); + _for_each_inner_peripheral!((GPIO42)); _for_each_inner_peripheral!((GPIO43)); + _for_each_inner_peripheral!((GPIO44)); _for_each_inner_peripheral!((GPIO45)); + _for_each_inner_peripheral!((GPIO46)); _for_each_inner_peripheral!((GPIO47)); + _for_each_inner_peripheral!((GPIO48)); _for_each_inner_peripheral!((GPIO49)); + _for_each_inner_peripheral!((GPIO50)); _for_each_inner_peripheral!((GPIO51)); + _for_each_inner_peripheral!((GPIO52)); _for_each_inner_peripheral!((GPIO53)); + _for_each_inner_peripheral!((GPIO54)); _for_each_inner_peripheral!((GPIO(unstable))); + _for_each_inner_peripheral!((SYSTEM(unstable))); _for_each_inner_peripheral!((HP_SYS(unstable))); _for_each_inner_peripheral!((HP_SYS_CLKRST(unstable))); _for_each_inner_peripheral!((INTERRUPT_CORE0(unstable))); _for_each_inner_peripheral!((INTERRUPT_CORE1(unstable))); + _for_each_inner_peripheral!((LP_I2C_ANA_MST(unstable))); _for_each_inner_peripheral!((CLIC(unstable))); _for_each_inner_peripheral!((IO_MUX(unstable))); _for_each_inner_peripheral!((LP_AON(unstable))); @@ -3408,12 +3565,13 @@ macro_rules! for_each_peripheral { _for_each_inner_peripheral!((AES(unstable))); _for_each_inner_peripheral!((SHA(unstable))); _for_each_inner_peripheral!((RSA(unstable))); - _for_each_inner_peripheral!((ECC(unstable))); _for_each_inner_peripheral!((SPI2, - Spi2, 1)); _for_each_inner_peripheral!((SPI3, Spi3, 2)); - _for_each_inner_peripheral!((AES, Aes, 4)); _for_each_inner_peripheral!((SHA, - Sha, 5)); _for_each_inner_peripheral!((all(@ peri_type #[doc = - "GPIO0 peripheral singleton"] GPIO0 <= virtual()), (@ peri_type #[doc = - "GPIO1 peripheral singleton"] GPIO1 <= virtual()), (@ peri_type #[doc = + _for_each_inner_peripheral!((ECC(unstable))); + _for_each_inner_peripheral!((SW_INTERRUPT(unstable))); + _for_each_inner_peripheral!((SPI2, Spi2, 1)); _for_each_inner_peripheral!((SPI3, + Spi3, 2)); _for_each_inner_peripheral!((AES, Aes, 4)); + _for_each_inner_peripheral!((SHA, Sha, 5)); _for_each_inner_peripheral!((all(@ + peri_type #[doc = "GPIO0 peripheral singleton"] GPIO0 <= virtual()), (@ peri_type + #[doc = "GPIO1 peripheral singleton"] GPIO1 <= virtual()), (@ peri_type #[doc = "GPIO2 peripheral singleton (Limitations exist)"] #[doc = ""] #[doc = "

"] #[doc = "This pin may be available with certain limitations. Check your hardware to make sure whether you can use it."] @@ -3544,16 +3702,18 @@ macro_rules! for_each_peripheral { "GPIO54 peripheral singleton"] GPIO54 <= virtual()), (@ peri_type #[doc = "EFUSE peripheral singleton"] EFUSE <= EFUSE() (unstable)), (@ peri_type #[doc = "GPIO peripheral singleton"] GPIO <= GPIO() (unstable)), (@ peri_type #[doc = - "HP_SYS peripheral singleton"] HP_SYS <= HP_SYS() (unstable)), (@ peri_type #[doc - = "HP_SYS_CLKRST peripheral singleton"] HP_SYS_CLKRST <= HP_SYS_CLKRST() + "SYSTEM peripheral singleton"] SYSTEM <= HP_SYS() (unstable)), (@ peri_type #[doc + = "HP_SYS peripheral singleton"] HP_SYS <= HP_SYS() (unstable)), (@ peri_type + #[doc = "HP_SYS_CLKRST peripheral singleton"] HP_SYS_CLKRST <= HP_SYS_CLKRST() (unstable)), (@ peri_type #[doc = "INTERRUPT_CORE0 peripheral singleton"] INTERRUPT_CORE0 <= INTERRUPT_CORE0() (unstable)), (@ peri_type #[doc = "INTERRUPT_CORE1 peripheral singleton"] INTERRUPT_CORE1 <= INTERRUPT_CORE1() - (unstable)), (@ peri_type #[doc = "CLIC peripheral singleton"] CLIC <= CLIC() - (unstable)), (@ peri_type #[doc = "IO_MUX peripheral singleton"] IO_MUX <= - IO_MUX() (unstable)), (@ peri_type #[doc = "LP_AON peripheral singleton"] LP_AON - <= LP_SYS() (unstable)), (@ peri_type #[doc = - "LP_AON_CLKRST peripheral singleton"] LP_AON_CLKRST <= LP_AON_CLKRST() + (unstable)), (@ peri_type #[doc = "LP_I2C_ANA_MST peripheral singleton"] + LP_I2C_ANA_MST <= LP_I2C_ANA_MST() (unstable)), (@ peri_type #[doc = + "CLIC peripheral singleton"] CLIC <= CLIC() (unstable)), (@ peri_type #[doc = + "IO_MUX peripheral singleton"] IO_MUX <= IO_MUX() (unstable)), (@ peri_type #[doc + = "LP_AON peripheral singleton"] LP_AON <= LP_SYS() (unstable)), (@ peri_type + #[doc = "LP_AON_CLKRST peripheral singleton"] LP_AON_CLKRST <= LP_AON_CLKRST() (unstable)), (@ peri_type #[doc = "LP_SYS peripheral singleton"] LP_SYS <= LP_SYS() (unstable)), (@ peri_type #[doc = "LP_WDT peripheral singleton"] LP_WDT <= LP_WDT() (unstable)), (@ peri_type #[doc = "LPWR peripheral singleton"] LPWR @@ -3613,7 +3773,8 @@ macro_rules! for_each_peripheral { = "RSA peripheral singleton"] RSA <= RSA(RSA : { bind_peri_interrupt, enable_peri_interrupt, disable_peri_interrupt }) (unstable)), (@ peri_type #[doc = "ECC peripheral singleton"] ECC <= ECC(ECC : { bind_peri_interrupt, - enable_peri_interrupt, disable_peri_interrupt }) (unstable)))); + enable_peri_interrupt, disable_peri_interrupt }) (unstable)), (@ peri_type #[doc + = "SW_INTERRUPT peripheral singleton"] SW_INTERRUPT <= virtual() (unstable)))); _for_each_inner_peripheral!((singletons(GPIO0), (GPIO1), (GPIO2), (GPIO3), (GPIO4), (GPIO5), (GPIO6), (GPIO7), (GPIO8), (GPIO9), (GPIO10), (GPIO11), (GPIO12), (GPIO13), (GPIO14), (GPIO15), (GPIO16), (GPIO17), (GPIO18), (GPIO19), @@ -3621,21 +3782,21 @@ macro_rules! for_each_peripheral { (GPIO28), (GPIO29), (GPIO30), (GPIO31), (GPIO32), (GPIO33), (GPIO34), (GPIO35), (GPIO36), (GPIO37), (GPIO38), (GPIO39), (GPIO40), (GPIO41), (GPIO42), (GPIO43), (GPIO44), (GPIO45), (GPIO46), (GPIO47), (GPIO48), (GPIO49), (GPIO50), (GPIO51), - (GPIO52), (GPIO53), (GPIO54), (GPIO(unstable)), (HP_SYS(unstable)), - (HP_SYS_CLKRST(unstable)), (INTERRUPT_CORE0(unstable)), - (INTERRUPT_CORE1(unstable)), (CLIC(unstable)), (IO_MUX(unstable)), - (LP_AON(unstable)), (LP_AON_CLKRST(unstable)), (LP_SYS(unstable)), - (LP_WDT(unstable)), (LPWR(unstable)), (PMU(unstable)), (SYSTIMER(unstable)), - (TIMG0(unstable)), (TIMG1(unstable)), (UART0(unstable)), (UART1(unstable)), - (UART2(unstable)), (UART3(unstable)), (UART4(unstable)), (SPI2(unstable)), - (SPI3(unstable)), (I2C0(unstable)), (I2C1(unstable)), (TWAI0(unstable)), - (TWAI1(unstable)), (TWAI2(unstable)), (PSRAM(unstable)), (DMA(unstable)), - (DMA_CH0(unstable)), (DMA_CH1(unstable)), (DMA_CH2(unstable)), + (GPIO52), (GPIO53), (GPIO54), (GPIO(unstable)), (SYSTEM(unstable)), + (HP_SYS(unstable)), (HP_SYS_CLKRST(unstable)), (INTERRUPT_CORE0(unstable)), + (INTERRUPT_CORE1(unstable)), (LP_I2C_ANA_MST(unstable)), (CLIC(unstable)), + (IO_MUX(unstable)), (LP_AON(unstable)), (LP_AON_CLKRST(unstable)), + (LP_SYS(unstable)), (LP_WDT(unstable)), (LPWR(unstable)), (PMU(unstable)), + (SYSTIMER(unstable)), (TIMG0(unstable)), (TIMG1(unstable)), (UART0(unstable)), + (UART1(unstable)), (UART2(unstable)), (UART3(unstable)), (UART4(unstable)), + (SPI2(unstable)), (SPI3(unstable)), (I2C0(unstable)), (I2C1(unstable)), + (TWAI0(unstable)), (TWAI1(unstable)), (TWAI2(unstable)), (PSRAM(unstable)), + (DMA(unstable)), (DMA_CH0(unstable)), (DMA_CH1(unstable)), (DMA_CH2(unstable)), (USB_DEVICE(unstable)), (SDHOST(unstable)), (LEDC(unstable)), (MCPWM0(unstable)), (MCPWM1(unstable)), (PCNT(unstable)), (RMT(unstable)), (ADC(unstable)), - (AES(unstable)), (SHA(unstable)), (RSA(unstable)), (ECC(unstable)))); - _for_each_inner_peripheral!((dma_eligible(SPI2, Spi2, 1), (SPI3, Spi3, 2), (AES, - Aes, 4), (SHA, Sha, 5))); + (AES(unstable)), (SHA(unstable)), (RSA(unstable)), (ECC(unstable)), + (SW_INTERRUPT(unstable)))); _for_each_inner_peripheral!((dma_eligible(SPI2, Spi2, + 1), (SPI3, Spi3, 2), (AES, Aes, 4), (SHA, Sha, 5))); }; } /// This macro can be used to generate code for each `GPIOn` instance. diff --git a/esp-metadata/CHANGELOG.md b/esp-metadata/CHANGELOG.md index 06de5ce842c..62591eb757e 100644 --- a/esp-metadata/CHANGELOG.md +++ b/esp-metadata/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - ESP32-P4: emit `pm_support_ext1_wakeup` and `pm_support_touch_sensor_wakeup` (#5400) - C5 and C61: I2S support (#5483) - More I2S flags for HW unification (#5483) +- Initial ESP32-P4 support (#5400) ### Changed diff --git a/esp-metadata/devices/esp32p4.toml b/esp-metadata/devices/esp32p4.toml index 55b026ed1e2..090e3562230 100644 --- a/esp-metadata/devices/esp32p4.toml +++ b/esp-metadata/devices/esp32p4.toml @@ -9,7 +9,7 @@ name = "esp32p4" arch = "riscv" target = "riscv32imafc-unknown-none-elf" -cores = 2 +cores = 1 # FIXME: Temporarily set to 1, too many things want CPU_CTRL to be implemented trm = "https://www.espressif.com/sites/default/files/documentation/esp32-p4_technical_reference_manual_en.pdf" symbols = [ @@ -105,9 +105,24 @@ clocks = { system_clocks = { clock_tree = [ { name = "LP_SLOW_CLK", type = "mux", variants = [ { name = "RC_SLOW", outputs = "RC_SLOW_CLK" }, { name = "XTAL32K", outputs = "XTAL32K_CLK" }, - { name = "RC32K", outputs = "RC32K_CLK" }, + #{ name = "RC32K", outputs = "RC32K_CLK" }, { name = "OSC_SLOW", outputs = "OSC_SLOW_CLK" }, ] }, + + # TIMG0-only? + { name = "TIMG_CALIBRATION_CLOCK", type = "mux", variants = [ + { name = "MPLL_CLK", outputs = "MPLL_CLK" }, + { name = "SPLL_CLK", outputs = "SPLL_CLK" }, + { name = "CPLL_CLK", outputs = "CPLL_CLK" }, + #{ name = "APLL_CLK", outputs = "APLL_CLK" }, + #{ name = "SDIO_PLL0_CLK", outputs = "SDIO_PLL0_CLK" }, + #{ name = "SDIO_PLL1_CLK", outputs = "SDIO_PLL1_CLK" }, + #{ name = "SDIO_PLL2_CLK", outputs = "SDIO_PLL2_CLK" }, + { name = "RC_FAST_CLK", outputs = "RC_FAST_CLK" }, + { name = "RC_SLOW_CLK", outputs = "LP_SLOW_CLK" }, + { name = "XTAL32K_CLK", outputs = "XTAL32K_CLK" }, + #{ name = "PLL_LP_CLK", outputs = "PLL_LP_CLK" }, + ] }, ], template_groups = [ { group = "UART", clocks = [ { name = "FUNCTION_CLOCK", type = "generic", output = "sclk / (div_num + 1)", params = { sclk = [ @@ -169,7 +184,7 @@ clocks = { system_clocks = { clock_tree = [ { name = "I2s2", template_params = { default_clk_en_template = "{{apb_clk_template}}", apb_field = "i2s2_apb_clk_en", default_rst_template = "{{rst_en2_template}}", rst_field = "rst_en_i2s2_apb" } }, # Timers -- Systimer also needs PERI_CLK_CTRL21.systimer_clk_en gate. { name = "Systimer", template_params = { default_clk_en_template = "{{control}}::regs().soc_clk_ctrl2().modify(|_, w| w.systimer_apb_clk_en().bit(enable)); {{control}}::regs().peri_clk_ctrl21().modify(|_, w| w.systimer_clk_en().bit(enable));", default_rst_template = "{{rst_en1_template}}", rst_field = "rst_en_stimer" }, keep_enabled = true }, - { name = "Timg0", template_params = { default_clk_en_template = "{{apb_clk_template}}", apb_field = "timergrp0_apb_clk_en", default_rst_template = "{{rst_en1_template}}", rst_field = "rst_en_timergrp0" } }, + { name = "Timg0", template_params = { default_clk_en_template = "{{apb_clk_template}}", apb_field = "timergrp0_apb_clk_en", default_rst_template = "{{rst_en1_template}}", rst_field = "rst_en_timergrp0" }, keep_enabled = true }, { name = "Timg1", template_params = { default_clk_en_template = "{{apb_clk_template}}", apb_field = "timergrp1_apb_clk_en", default_rst_template = "{{rst_en1_template}}", rst_field = "rst_en_timergrp1" } }, # IO MUX -- gated via PERI_CLK_CTRL26; KEEP_ENABLED because GPIO depends on it. { name = "Iomux", template_params = { default_clk_en_template = "{{control}}::regs().peri_clk_ctrl26().modify(|_, w| w.iomux_clk_en().bit(enable));", default_rst_template = "{{rst_en1_template}}", rst_field = "rst_en_iomux" }, keep_enabled = true }, @@ -227,10 +242,12 @@ peripherals = [ # Minimal set for esp-hal compilation { name = "EFUSE", hidden = true }, { name = "GPIO" }, + { name = "SYSTEM", pac = "HP_SYS" }, { name = "HP_SYS" }, { name = "HP_SYS_CLKRST" }, { name = "INTERRUPT_CORE0" }, { name = "INTERRUPT_CORE1" }, + { name = "LP_I2C_ANA_MST" }, { name = "CLIC" }, { name = "IO_MUX" }, # LP_AON / LPWR: compatibility aliases -- other chips expose an `LP_AON` @@ -285,6 +302,8 @@ peripherals = [ { name = "SHA", interrupts = { peri = "SHA" }, dma_peripheral = 5 }, { name = "RSA", interrupts = { peri = "RSA" } }, { name = "ECC", interrupts = { peri = "ECC" } }, + + { name = "SW_INTERRUPT", virtual = true }, ] # UART: 5 instances (UART0-4), 128-byte FIFO @@ -306,18 +325,19 @@ version = 2 [device.systimer] # GP Timer (TIMG): 2 groups, each with 2 timers + WDT -[device.gp_timer] +[device.timergroup] support_status = "partial" instances = [ - { name = "timg0", sys_instance = "Timg0", interrupt = "TG0_T0_LEVEL" }, - { name = "timg1", sys_instance = "Timg1", interrupt = "TG1_T0_LEVEL" }, + { name = "timg0" }, + { name = "timg1" }, ] +timg_has_divcnt_rst = true # SPI Master: 2 instances (GPSPI2, GPSPI3) # SPI Master: SPI2 only (SPI2 and SPI3 have different PAC RegisterBlock types) [device.spi_master] support_status = "partial" -supports_dma = true +supports_dma = false # TODO instances = [ { name = "spi2", sys_instance = "Spi2", sclk = "SPI2_CK", sio = ["SPI2_D", "SPI2_Q", "SPI2_WP", "SPI2_HOLD"], cs = ["SPI2_CS"] }, { name = "spi3", sys_instance = "Spi3", sclk = "SPI3_CK", sio = ["SPI3_D", "SPI3_Q", "SPI3_WP", "SPI3_HOLD"], cs = ["SPI3_CS", "SPI3_CS1", "SPI3_CS2"] }, @@ -348,7 +368,7 @@ max_bus_timeout = 0x1F # esp-hal's `Dma` singleton must be GDMA v2 compatible, hence PAC alias AHB_DMA above. # Ref: IDF linker esp32p4.peripherals.ld (AHB_DMA, AXI_DMA, DW_GDMA symbols). [device.dma] -support_status = "partial" +support_status = "not_supported" # PAC needs more work kind = "gdma" gdma_version = 2 separate_in_out_interrupts = true @@ -446,7 +466,7 @@ dma = true algo = { sha1 = 0, sha224 = 1, sha256 = 2 } [device.psram] -extmem_origin = 0x48000000 +extmem_origin = 0x4800_0000 [device.rsa] support_status = "not_supported" diff --git a/esp-rom-sys/CHANGELOG.md b/esp-rom-sys/CHANGELOG.md index 2a787d81aa5..87ec92684fd 100644 --- a/esp-rom-sys/CHANGELOG.md +++ b/esp-rom-sys/CHANGELOG.md @@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- ESP32-P4: replace the pre-ECO5 ROM linker scripts with ECO5+ symbol addresses sourced from ESP-IDF v6.0.1 (#5400) +- Initial ESP32-P4 support (#5400) ### Fixed diff --git a/esp-rtos/CHANGELOG.md b/esp-rtos/CHANGELOG.md index b17b0a2798e..848aad2c6ee 100644 --- a/esp-rtos/CHANGELOG.md +++ b/esp-rtos/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Initial support for ESP32-P4 (#5523) ### Changed diff --git a/esp-rtos/Cargo.toml b/esp-rtos/Cargo.toml index 4a54ae29792..4781155edc6 100644 --- a/esp-rtos/Cargo.toml +++ b/esp-rtos/Cargo.toml @@ -118,6 +118,8 @@ esp32c61 = ["esp-hal/esp32c61", "esp-metadata-generated/esp32c61", "esp-rom-sys/ ## esp32h2 = ["esp-hal/esp32h2", "esp-metadata-generated/esp32h2", "esp-rom-sys/esp32h2"] ## +esp32p4 = ["esp-hal/esp32p4", "esp-metadata-generated/esp32p4", "esp-rom-sys/esp32p4"] +## esp32s2 = ["esp-hal/esp32s2", "esp-metadata-generated/esp32s2", "esp-rom-sys/esp32s2"] ## esp32s3 = ["esp-hal/esp32s3", "esp-metadata-generated/esp32s3", "esp-rom-sys/esp32s3"] diff --git a/esp-sync/CHANGELOG.md b/esp-sync/CHANGELOG.md index 959d52ecfe2..ead9091ee19 100644 --- a/esp-sync/CHANGELOG.md +++ b/esp-sync/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Initial ESP32-P4 (chip revision v3.0+) support (#5400) +- Initial ESP32-P4 (chip revision v3.0+) support (#5400, #5523) ### Changed diff --git a/esp-sync/src/raw.rs b/esp-sync/src/raw.rs index 44ee2612788..778caabd170 100644 --- a/esp-sync/src/raw.rs +++ b/esp-sync/src/raw.rs @@ -35,7 +35,7 @@ impl RawLock for SingleCoreInterruptLock { #[inline] unsafe fn enter(&self) -> RestoreState { cfg_if::cfg_if! { - if #[cfg(riscv)] { + if #[cfg(esp32p4)] { // TODO: any with zcmp // ESP32-P4 (v3.2/ECO7 etc.) Zcmp hardware bug workaround (IDF-14279 / DIG-661): // Clearing mstatus.mie alone does not fully mask CLIC interrupts -- an // interrupt can still fire mid-instruction on cm.push (and possibly on @@ -43,9 +43,7 @@ impl RawLock for SingleCoreInterruptLock { // while mie is cleared, then restore the previous mintthresh on exit. // Ref: esp-idf commit c27c33a83 "fix(riscv): implement a workaround for // Zcmp hardware bug". - #[cfg(esp32p4)] let old_mintthresh: u32; - #[cfg(esp32p4)] unsafe { core::arch::asm!( "li t0, 0xff", @@ -57,10 +55,11 @@ impl RawLock for SingleCoreInterruptLock { let mut mstatus = 0u32; unsafe { core::arch::asm!("csrrci {0}, mstatus, 8", inout(reg) mstatus); } let mie_bit = mstatus & 0b1000; - #[cfg(esp32p4)] let token = mie_bit | ((old_mintthresh & 0xff) << 8); - #[cfg(not(esp32p4))] - let token = mie_bit; + } else if #[cfg(riscv)] { + let mut mstatus = 0u32; + unsafe { core::arch::asm!("csrrci {0}, mstatus, 8", inout(reg) mstatus); } + let token = mstatus & 0b1000; } else if #[cfg(xtensa)] { let token: u32; unsafe { core::arch::asm!("rsil {0}, 5", out(reg) token); } @@ -87,21 +86,31 @@ impl RawLock for SingleCoreInterruptLock { let token = token.inner(); cfg_if::cfg_if! { - if #[cfg(riscv)] { + if #[cfg(esp32p4)] { if (token & 0b1000) != 0 { unsafe { riscv::interrupt::enable(); } } // Restore mintthresh AFTER re-enabling mie (P4 Zcmp workaround, see enter()). - #[cfg(esp32p4)] - { - let old_mintthresh = (token >> 8) & 0xff; + let old_mintthresh = (token >> 8) & 0xff; + unsafe { + core::arch::asm!( + "csrw 0x347, {0}", + in(reg) old_mintthresh, + ); + } + + // The delay between the moment we unmask the interrupt threshold register + // and the moment the potential requested interrupt is triggered is not + // null: up to three machine cycles/instructions can be executed. + riscv::asm::nop(); + riscv::asm::nop(); + riscv::asm::nop(); + } else if #[cfg(riscv)] { + if token != 0 { unsafe { - core::arch::asm!( - "csrw 0x347, {0}", - in(reg) old_mintthresh, - ); + riscv::interrupt::enable(); } } } else if #[cfg(xtensa)] { diff --git a/examples/async/embassy_hello_world/Cargo.toml b/examples/async/embassy_hello_world/Cargo.toml index cff8434e6ec..da282d40aa4 100644 --- a/examples/async/embassy_hello_world/Cargo.toml +++ b/examples/async/embassy_hello_world/Cargo.toml @@ -59,6 +59,12 @@ esp32h2 = [ "esp-rtos/esp32h2", "esp-hal/esp32h2", ] +esp32p4 = [ + "esp-backtrace/esp32p4", + "esp-bootloader-esp-idf/esp32p4", + "esp-rtos/esp32p4", + "esp-hal/esp32p4", +] esp32s2 = [ "esp-backtrace/esp32s2", "esp-bootloader-esp-idf/esp32s2", diff --git a/examples/async/embassy_hello_world_defmt/Cargo.toml b/examples/async/embassy_hello_world_defmt/Cargo.toml index 7e576e5562b..0b167de9aca 100644 --- a/examples/async/embassy_hello_world_defmt/Cargo.toml +++ b/examples/async/embassy_hello_world_defmt/Cargo.toml @@ -68,6 +68,13 @@ esp32h2 = [ "esp-rtos/esp32h2", "esp-hal/esp32h2", ] +esp32p4 = [ + "esp-backtrace/esp32p4", + "esp-println/esp32p4", + "esp-bootloader-esp-idf/esp32p4", + "esp-rtos/esp32p4", + "esp-hal/esp32p4", +] esp32s2 = [ "esp-backtrace/esp32s2", "esp-println/esp32s2", diff --git a/examples/async/embassy_multiprio/Cargo.toml b/examples/async/embassy_multiprio/Cargo.toml index cd39753b11d..8a41f10e391 100644 --- a/examples/async/embassy_multiprio/Cargo.toml +++ b/examples/async/embassy_multiprio/Cargo.toml @@ -48,6 +48,12 @@ esp32h2 = [ "esp-rtos/esp32h2", "esp-hal/esp32h2", ] +esp32p4 = [ + "esp-backtrace/esp32p4", + "esp-bootloader-esp-idf/esp32p4", + "esp-rtos/esp32p4", + "esp-hal/esp32p4", +] esp32s2 = [ "esp-backtrace/esp32s2", "esp-bootloader-esp-idf/esp32s2", diff --git a/examples/async/embassy_usb_serial_jtag/Cargo.toml b/examples/async/embassy_usb_serial_jtag/Cargo.toml index a4f654fe8a4..7c303ef6920 100644 --- a/examples/async/embassy_usb_serial_jtag/Cargo.toml +++ b/examples/async/embassy_usb_serial_jtag/Cargo.toml @@ -50,6 +50,12 @@ esp32h2 = [ "esp-rtos/esp32h2", "esp-hal/esp32h2", ] +esp32p4 = [ + "esp-backtrace/esp32p4", + "esp-bootloader-esp-idf/esp32p4", + "esp-rtos/esp32p4", + "esp-hal/esp32p4", +] esp32s3 = [ "esp-backtrace/esp32s3", "esp-bootloader-esp-idf/esp32s3", diff --git a/hil-test/Cargo.toml b/hil-test/Cargo.toml index 2f07a87e5c9..74e8119de0b 100644 --- a/hil-test/Cargo.toml +++ b/hil-test/Cargo.toml @@ -213,6 +213,13 @@ esp32h2 = [ "esp-metadata-generated/esp32h2", "esp-rtos?/esp32h2", ] +esp32p4 = [ + "esp-hal/esp32p4", + "esp-alloc?/esp32p4", + "esp-bootloader-esp-idf/esp32p4", + "esp-metadata-generated/esp32p4", + "esp-rtos?/esp32p4" +] esp32s2 = [ "embedded-test/xtensa-semihosting", "esp-hal/esp32s2", diff --git a/hil-test/src/bin/alloc_psram.rs b/hil-test/src/bin/alloc_psram.rs index 21b69091572..f9775c9c52b 100644 --- a/hil-test/src/bin/alloc_psram.rs +++ b/hil-test/src/bin/alloc_psram.rs @@ -1,10 +1,11 @@ //! Allocator and PSRAM-related tests //% CHIPS: -//% CHIPS(llff, tlsf): esp32 esp32s2 esp32c5 esp32c61 esp32s3 +//% CHIPS(llff, tlsf): esp32 esp32s2 esp32c5 esp32c61 esp32s3 esp32p4 //% ENV(llff): ESP_ALLOC_CONFIG_HEAP_ALGORITHM=LLFF //% ENV(tlsf): ESP_ALLOC_CONFIG_HEAP_ALGORITHM=TLSF -//% FEATURES: unstable esp-storage esp-alloc/nightly +//% FEATURES: unstable esp-alloc/nightly +//% FEATURES(esp32 esp32s2 esp32c5 esp32c61 esp32s3): esp-storage #![no_std] #![no_main] @@ -13,27 +14,17 @@ use hil_test as _; extern crate alloc; -#[embedded_test::tests] +#[embedded_test::tests(default_timeout = 30)] // P4 PSRAM can get large mod tests { use alloc::vec::Vec as AllocVec; use allocator_api2::vec::Vec; - use embedded_storage::*; use esp_alloc::{AnyMemory, ExternalMemory, InternalMemory}; - use esp_bootloader_esp_idf::partitions; - use esp_hal::peripherals::FLASH; - use esp_storage::FlashStorage; - - struct Context<'a> { - flash: FLASH<'a>, - } #[init] - fn init() -> Context<'static> { + fn init() { let p = esp_hal::init(esp_hal::Config::default()); esp_alloc::psram_allocator!(p.PSRAM, esp_hal::psram); - - Context { flash: p.FLASH } } // alloc::vec::Vec tests @@ -145,6 +136,35 @@ mod tests { } } } +} + +#[cfg(not(esp32p4))] +#[embedded_test::tests] +mod storage_tests { + use alloc::vec::Vec as AllocVec; + + use allocator_api2::vec::Vec; + use embedded_storage::*; + use esp_alloc::{AnyMemory, ExternalMemory, InternalMemory}; + use esp_bootloader_esp_idf::partitions; + use esp_hal::peripherals::FLASH; + use esp_storage::FlashStorage; + + struct Context<'a> { + #[cfg(not(esp32p4))] + flash: FLASH<'a>, + } + + #[init] + fn init() -> Context<'static> { + let p = esp_hal::init(esp_hal::Config::default()); + esp_alloc::psram_allocator!(p.PSRAM, esp_hal::psram); + + Context { + #[cfg(not(esp32p4))] + flash: p.FLASH, + } + } #[test] fn test_with_accessing_flash_storage(ctx: Context<'static>) { diff --git a/hil-test/src/bin/esp_radio.rs b/hil-test/src/bin/esp_radio.rs index c1c6bbc9157..c0bc7c173b0 100644 --- a/hil-test/src/bin/esp_radio.rs +++ b/hil-test/src/bin/esp_radio.rs @@ -1,10 +1,11 @@ //% CHIPS(no_wifi): esp32h2 //% CHIPS(no_ble): esp32s2 +//% CHIPS(no_radio): esp32p4 //% CHIPS(has_wifi_ble): esp32 esp32c2 esp32c3 esp32c6 esp32s3 esp32c5 //% CHIPS(stable_wifi): esp32 esp32c2 esp32c3 esp32c5 esp32c6 esp32s2 esp32s3 //% FEATURES: unstable esp-alloc embassy -// //% FEATURES(no_radio): rtos-radio-driver TODO: restore for P4 +//% FEATURES(no_radio): rtos-radio-driver //% FEATURES(no_ble): esp-radio/wifi esp-radio esp-radio-unstable //% FEATURES(no_wifi): esp-radio/ble esp-radio esp-radio-unstable trouble-host //% FEATURES(has_wifi_ble): esp-radio/wifi esp-radio/ble esp-radio/coex esp-radio-unstable @@ -26,7 +27,7 @@ extern crate alloc; fn init_heap() { cfg_if::cfg_if! { - if #[cfg(any(esp32, esp32s2, esp32s3, esp32c3, esp32c2, esp32c5, esp32c6, esp32c61))] { + if #[cfg(any(esp32, esp32s2, esp32s3, esp32c3, esp32c2, esp32c5, esp32c6, esp32c61, esp32p4))] { use esp_hal::ram; esp_alloc::heap_allocator!(#[ram(reclaimed)] size: 64 * 1024); esp_alloc::heap_allocator!(size: 48 * 1024); diff --git a/hil-test/src/bin/misc_non_drivers.rs b/hil-test/src/bin/misc_non_drivers.rs index e7ce49c374a..a27708bdd21 100644 --- a/hil-test/src/bin/misc_non_drivers.rs +++ b/hil-test/src/bin/misc_non_drivers.rs @@ -19,7 +19,7 @@ //! The goal of this test suite is to collect smaller, simpler test cases, to keep the overall //! number of test suites low(er). -//% CHIPS: esp32 esp32c2 esp32c3 esp32c5 esp32c6 esp32c61 esp32h2 esp32s2 esp32s3 +//% CHIPS: esp32 esp32c2 esp32c3 esp32c5 esp32c6 esp32c61 esp32h2 esp32p4 esp32s2 esp32s3 //% FEATURES: unstable #![no_std] diff --git a/hil-test/src/bin/misc_non_drivers/critical_section.rs b/hil-test/src/bin/misc_non_drivers/critical_section.rs index 65d4eb954d8..6d0c8b7674e 100644 --- a/hil-test/src/bin/misc_non_drivers/critical_section.rs +++ b/hil-test/src/bin/misc_non_drivers/critical_section.rs @@ -179,7 +179,7 @@ mod tests { } #[test] - #[cfg(multi_core)] + #[cfg(all(multi_core, soc_has_cpu_ctrl))] fn critical_section_on_multi_core(p: Peripherals) { // TODO: test other locks, too use core::{cell::Cell, sync::atomic::AtomicBool}; diff --git a/hil-test/src/bin/misc_non_drivers/efuse.rs b/hil-test/src/bin/misc_non_drivers/efuse.rs index 849adcca674..20645485104 100644 --- a/hil-test/src/bin/misc_non_drivers/efuse.rs +++ b/hil-test/src/bin/misc_non_drivers/efuse.rs @@ -2,6 +2,7 @@ #[embedded_test::tests(default_timeout = 2)] mod tests { + #[cfg(any(soc_has_wifi, soc_has_bt))] use esp_hal::efuse::{self, InterfaceMacAddress, MacAddress}; use hil_test as _; diff --git a/hil-test/src/lib.rs b/hil-test/src/lib.rs index 161a8782dee..4bf95f76f52 100644 --- a/hil-test/src/lib.rs +++ b/hil-test/src/lib.rs @@ -76,7 +76,7 @@ macro_rules! i2c_pins { ($peripherals.GPIO12, $peripherals.GPIO22) } else if #[cfg(esp32c2)] { ($peripherals.GPIO18, $peripherals.GPIO9) - } else if #[cfg(esp32c5)] { + } else if #[cfg(any(esp32c5, esp32p4))] { ($peripherals.GPIO2, $peripherals.GPIO3) } else { // esp32c3 ($peripherals.GPIO4, $peripherals.GPIO5) @@ -93,6 +93,8 @@ macro_rules! common_test_pins { ($peripherals.GPIO9, $peripherals.GPIO10) } else if #[cfg(esp32)] { ($peripherals.GPIO2, $peripherals.GPIO4) + } else if #[cfg(esp32p4)] { + ($peripherals.GPIO7, $peripherals.GPIO8) } else { // esp32c6, esp32c61, esp32h2, esp32c2, esp32c3 ($peripherals.GPIO2, $peripherals.GPIO3) } @@ -112,6 +114,8 @@ macro_rules! unconnected_pin { $peripherals.GPIO8 } else if #[cfg(esp32c5)] { $peripherals.GPIO28 + } else if #[cfg(esp32p4)] { + $peripherals.GPIO35 } else { // esp32c3, esp32c6, esp32c61, esp32h2 $peripherals.GPIO9 } diff --git a/qa-test/.cargo/config.toml b/qa-test/.cargo/config.toml index 0832070e117..bc229a80959 100644 --- a/qa-test/.cargo/config.toml +++ b/qa-test/.cargo/config.toml @@ -5,6 +5,7 @@ esp32c3 = "run --release --features=esp32c3 --target=riscv32imc-unknown-none-elf esp32c5 = "run --release --features=esp32c5 --target=riscv32imac-unknown-none-elf" esp32c6 = "run --release --features=esp32c6 --target=riscv32imac-unknown-none-elf" esp32h2 = "run --release --features=esp32h2 --target=riscv32imac-unknown-none-elf" +esp32p4 = "run --release --features=esp32p4 --target=riscv32imafc-unknown-none-elf" esp32s2 = "run --release --features=esp32s2 --target=xtensa-esp32s2-none-elf" esp32s3 = "run --release --features=esp32s3 --target=xtensa-esp32s3-none-elf" diff --git a/qa-test/Cargo.toml b/qa-test/Cargo.toml index 2cae2408115..48ed2a90fd7 100644 --- a/qa-test/Cargo.toml +++ b/qa-test/Cargo.toml @@ -42,6 +42,7 @@ trouble-host = { version = "0.6.0", features = [ "derive", "scan", ] } +log = "0.4" [features] unstable = [] @@ -108,6 +109,13 @@ esp32h2 = [ "esp-println/esp32h2", "esp-radio?/esp32h2", ] +esp32p4 = [ + "esp-backtrace/esp32p4", + "esp-bootloader-esp-idf/esp32p4", + "esp-hal/esp32p4", + "esp-rtos/esp32p4", + "esp-println/esp32p4", +] esp32s2 = [ "esp-backtrace/esp32s2", "esp-bootloader-esp-idf/esp32s2", diff --git a/qa-test/src/bin/embassy_executor_benchmark.rs b/qa-test/src/bin/embassy_executor_benchmark.rs index c01e8906bad..b11158c23c7 100644 --- a/qa-test/src/bin/embassy_executor_benchmark.rs +++ b/qa-test/src/bin/embassy_executor_benchmark.rs @@ -1,6 +1,6 @@ //! Embassy executor benchmark, used to try out optimization ideas. -//% CHIPS: esp32c2 esp32c3 esp32c5 esp32c6 esp32c61 esp32h2 esp32s2 esp32s3 +//% CHIPS: esp32c2 esp32c3 esp32c5 esp32c6 esp32c61 esp32h2 esp32p4 esp32s2 esp32s3 //% FEATURES: rtos-trace #![no_std] diff --git a/qa-test/src/bin/sw_int_timer.rs b/qa-test/src/bin/sw_int_timer.rs new file mode 100644 index 00000000000..84758427670 --- /dev/null +++ b/qa-test/src/bin/sw_int_timer.rs @@ -0,0 +1,39 @@ +//! Demonstrates software interrupts + +//% CHIPS: esp32 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 esp32c2 esp32p4 + +#![no_std] +#![no_main] + +use esp_backtrace as _; +use esp_hal::{ + delay::Delay, + interrupt::software::{SoftwareInterrupt, SoftwareInterruptControl}, + main, +}; + +esp_bootloader_esp_idf::esp_app_desc!(); + +#[main] +fn main() -> ! { + esp_println::logger::init_logger_from_env(); + let peripherals = esp_hal::init(esp_hal::Config::default()); + + let sw_ints = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); + let mut sw_int = sw_ints.software_interrupt0; + + sw_int.set_interrupt_handler(sw_int_handler); + + let delay = Delay::new(); + + loop { + delay.delay_millis(2500); + sw_int.raise(); + } +} + +#[esp_hal::handler] +fn sw_int_handler() { + unsafe { SoftwareInterrupt::<'static, 0>::steal() }.reset(); + log::info!("Triggered"); +}