Initial ESP32-P4 support#5400
Conversation
Cherry-picked new files only (no conflicting modifications) from florianL21's esp32p4-support branch (commit 606f006). Includes: - Linker scripts (esp32p4.x, memory.x, linkall.x) - eFuse field definitions - RTC control and sleep mode support - SoC clock definitions and regi2c - Generated metadata for esp32p4 - ROM linker scripts (including eco5/P4X variants) - Radio clocks low-level (relocated to esp-radio/) These files need verification against ESP32-P4X (chip rev v3.1+) datasheet and TRM. P4X has significant silicon differences from earlier P4 revisions (eco4/NRND). Based on work by FlorianL21 <6053565+florianL21@users.noreply.github.com>
- Add esp32p4 PAC dependency (v0.2, from esp-pacs at fc3e6d4) - Add esp32p4 feature with CLIC-48, LP core, RTC RAM support (matching esp32c5/c61 pattern for RISC-V CLIC chips) - Update memory.x linker script: - Conservative RAM origin at 0x4FF40000 (avoids ROM reserved 256 KB) - Verified against esp-idf SOC_IRAM_LOW/HIGH, SOC_DIRAM_ROM_RESERVE_HIGH - Note L2MEM cached region change in v3.x (bottom-up vs top-down) - Add rt feature forwarding for esp32p4 PAC Target: ESP32-P4NRW16X / ESP32-P4NRW32X (chip revision v3.0/v3.1) NOT for NRND variants (ESP32-P4NRW32 without X suffix). References: - TRM v0.5 (Pre-release), Table 1.4-1 CPU Address Map - Datasheet v0.5, Table 1-1 Series Comparison - Chip Revision v3.x User Guide v1.0 (2026.03) - esp-idf components/soc/esp32p4/include/soc/soc.h
- Linker scripts (ld/esp32p4/*): RAM ends at 0x4FFAE000 per v3.x ROM reserve. - Regen esp-metadata(-generated) for esp32p4: SoC capability flags consistent. - CLIC / interrupt layer: consolidated int_ctrl regs; mintthresh run-level. - Clock tree (src/soc/esp32p4 + rtc_cntl): CPLL/SPLL/MPLL aligned to esp-idf. - New: src/psram/esp32p4.rs (AP HEX mode) and src/soc/esp32p4/gpio.rs (LP GPIO). - esp-sync/raw.rs: RV32 Zcmp hardware-bug workaround (mintthresh=0xff bracket around critical sections), mirrors esp-idf commit c27c33a83. #[cfg(esp32p4)]. - Misc PAC-name compat + xtask clippy auto-fix. Validated on P4X EV Board V1.7, silicon v3.2/ECO7: esp_hal::init -> embassy-net Runner -> IP101GRI MDIO alive.
Pulls in esp-hal 1.1.0-rc.0 release + 29 upstream commits.
Conflict resolutions (P4 branch stance preserved):
- esp-hal/Cargo.toml, esp-rom-sys/Cargo.toml: take upstream's bumped
published PAC versions for all chips, keep esp32p4 = 0.2 pinned to
git rev fc3e6d4 (required for our regenerated PAC layout).
- esp-hal/README.md: keep HEAD (has ESP32-P4 column); machine-gen table
will be refreshed by xtask on next regen.
- xtask/src/commands/release/bump_version.rs: take upstream's rename
`bump_version_number` -> `bump_base`.
- esp-metadata + _generated_esp32p4.rs: add [device.psram] extmem_origin
= 0x48000000 (required by upstream's new `property!("psram.extmem_origin")`
use in esp-hal/src/psram/mod.rs).
- esp-hal/src/psram/esp32p4.rs: adapt init_psram signature to upstream's
post-merge API `(&mut PsramConfig) -> bool` + add map_psram stub
returning the vaddr range; underlying HEX-mode impl unchanged.
Validated: firmware builds, boots, EMAC/PHY init still reaches
`PHY diag: scan addr=1 IDR1=0x0243 IDR2=0x0C54 (alive)`.
|
Please don't change the release tooling in a PR that's not meant to do that |
@bugadani Oops I touched it while just run "cargo clippy --fix" I will revert them. |
| Each maps to DefaultHandler unless overridden by the application. | ||
| Ref: esp32p4 PAC lib.rs __EXTERNAL_INTERRUPTS vector table | ||
| TRM v0.5 Ch 14 (Interrupt Matrix) */ | ||
| PROVIDE(LP_WDT = DefaultHandler); |
There was a problem hiding this comment.
Peripheral interrupt symbols are provided by the PAC (https://github.com/esp-rs/esp-pacs/blob/main/esp32p4/device.x), and the PAC's device.x is included by hal-defaults.x. These shouldn't be listed in esp-hal.
There was a problem hiding this comment.
Removed and confirmed it still builds.
I originally added these because I wasn't sure the PAC exposed the full interrupts, and I was worried different v3.x silicon revisions might expose different tables. (because very few information about 3.2 that I have)
Neither turned out to be true, PAC's device.x covers all 99 entries and they are the same across v3.x.
Thanks!
| // P4 PAC: intr_0() (Core0 GPIO interrupt status) | ||
| // Ref: esp-idf gpio_ll.h -- gpio_ll_get_intr_status() | ||
| // TRM v0.5 Ch 11 -- GPIO_STATUS_INT_REG |
There was a problem hiding this comment.
This is some LLM output, right? There's absolutely no need to cross-reference either esp-idf source code, or the TRM for these sorts of simple, obvious pieces of code.
There was a problem hiding this comment.
@bugadani Yes, assisted while TRM indexing.
But ESP-IDF and TRM citations were my decision.
v3.2 silicon info it not clear when I've got and it's unclear which tracks late-revision adopt faster.
So I cited both defensively.
But you're right that for trivial register reads it's noise. It's still draft PR and need to be remove that when I think it's enough to reference esp-idf side.
There was a problem hiding this comment.
Some of memory offset and address is not shown in TRM.
In this case, I keep left some idf based header/source name on comment.
| // P4 uses dedicated pins (GPIO49/50) for USB, so USB_DM/USB_DP are | ||
| // not in the analog function table -> this inner fn is unused on P4. |
There was a problem hiding this comment.
This should clearly say "pins 49 and 50", not GPIO49 and GPIO50. These are not GPIOs, but dedicated pins. But this is only true for USB HS, and not to USB Serial/JTAG or USB FS, which have their own DM and DP signals in the analog function table.
There was a problem hiding this comment.
// TODO: considering USB1P1_N0/1 USB1P1_P0/1 on P4
// On P4 the analog table uses USB_PHY{0,1}_DM/DP instead of
// USB_DM/DP, so neither arm below matches and this fn is unused.fixed like this
| } else if #[cfg(esp32p4)] { | ||
| // P4: CPU_WAITI_CTRL0_REG in HP_SYS_CLKRST (offset 0xf4) controls | ||
| // whether WFI gates the clock. Default: core0_waiti_icg_en=1 (enabled). | ||
| // This register is only in hw_ver3 (eco5+), not in current PAC. | ||
| // Ref: esp-idf hp_sys_clkrst_reg.h -- HP_SYS_CLKRST_CPU_WAITI_CTRL0_REG | ||
| // TRM v0.5 Ch 22 (v3.x addition) | ||
| // Return true (WFI clock gating active) -- matches default hardware state. | ||
| true |
There was a problem hiding this comment.
We only intend to support hw_ver3. If this register is not in the current PAC, it should be added. At least mark this place with a TODO label, please.
There was a problem hiding this comment.
4381c33
improved this. But need review again.
I am not sure what's right aporach between reading per bit or just judge 0th bit .
|
New commits in main has made this PR unmergable. Please resolve the conflicts. |
|
New commits in main has made this PR unmergable. Please resolve the conflicts. |
|
What can we do to help you get this into a mergeable state? This PR is huge, so it will just accumulate merge conflicts in its current state. It's not necessary to enable everything all at once, we've added support for other chips incrementally recently. |
|
This work will be belong to future PR or others' turn |
| @@ -1,38 +1,82 @@ | |||
| // ESP32P4 follows pulp CLIC version 1.x | |||
There was a problem hiding this comment.
This file will either need to be split into two, or the naming should be updated in the PAC to be consistent.
There was a problem hiding this comment.
But I dont sure about splitting, because there's some possibility ESP32P4 upgrade their CLIC or future pac takes compatibility with 2.x stuff.
There was a problem hiding this comment.
This is more a note to ourselves, I think you've done quite enough here already :) Also I hope the hardware won't change drastically once more.
There was a problem hiding this comment.
me either, I don't wanna espressif change it.
I will make issues on esp-pacs about this and left more comment on the code
- reason of keep v1.x and v2.x
- what to do on future , split or keep by future action
There was a problem hiding this comment.
// 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| - ESP32-C Series: _ESP32-C2, ESP32-C3, ESP32-C6_ | ||
| - ESP32-C Series: _ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61_ | ||
| - ESP32-H Series: _ESP32-H2_ | ||
| - ESP32-P Series: _ESP32-P4_ |
There was a problem hiding this comment.
Maybe this is out of scope. But touched.
Because when I look on the code and add P4 here, looks like C5/C61 is already supported in esp-hal
| MEMORY | ||
| { | ||
| /* CONFIG 0 */ | ||
| #IF ESP_HAL_CONFIG_L2_CACHE_SIZE_512KB | ||
| RAM : ORIGIN = 0x4FF80000, LENGTH = 0x4FFAE000 - 0x4FF80000 | ||
| #ENDIF | ||
| /* CONFIG 1 */ | ||
| #IF ESP_HAL_CONFIG_L2_CACHE_SIZE_256KB | ||
| RAM : ORIGIN = 0x4FF40000, LENGTH = 0x4FFAE000 - 0x4FF40000 | ||
| #ENDIF | ||
| /* CONFIG 2 */ | ||
| #IF ESP_HAL_CONFIG_L2_CACHE_SIZE_128KB | ||
| RAM : ORIGIN = 0x4FF20000, LENGTH = 0x4FFAE000 - 0x4FF20000 | ||
| #ENDIF | ||
| /* CONFIG 3 */ | ||
| #IF ESP_HAL_CONFIG_L2_CACHE_SIZE_0KB |
|
Synced with main (which brought in #5519) |
bugadani
left a comment
There was a problem hiding this comment.
Thank you very much for getting the chip this far! There is quite a bit still missing - basics like esp-alloc or esp-rtos don't work, probe-rs has difficulties flashing the chip, so tests don't boot, and the code is not really consistent with the repository, but this is still a very good first step!

ESP32-P4X support on top of esp-hal 1.1.0-rc.0
Submission Checklist
Current the
esp32p4-hal-testingrepo is link local path pmnxis/esp-hal, but this will be fixed after mergecargo xtask fmt-packagesrun.CHANGELOG.mdupdated.#[cfg(esp32p4)].Description
This branch adds early ESP32-P4X support to esp-hal.
ESP32-P4X is Espressif's product name for ESP32-P4 with chip revision v3.1 or later. My board is v3.2 / ECO7, which is an ESP32-P4X.
The branch started from the P4 import in
florianL21/esp-haland was re-applied on top of upstream 1.1.0-rc.0.Most important change: Zcmp workaround in
esp-syncOn esp32p4,
SingleCoreInterruptLocknow matches the ESP-IDF (latest master) workaround for the Zcmp hardware bug (ESP-IDF c27c33a83,IDF-14279 / DIG-661):
enter: setmintthresh(CSR0x347) to0xffbefore clearingmstatus.mie. Save the old value.exit: re-enablemstatus.miefirst, then restoremintthresh.Without this, some multi-cycle RV32 instruction sequences (for example
cm.push) can still be interrupted withmie = 0and corrupt state.The change is behind
#[cfg(esp32p4)].Note: on
riscv32imafc-unknown-none-elf(our only P4 target) rustc emits zero Zcmp instructions today, so the workaround is defensive -- protecting code paths that current rustc + target combination cannot actually emit, but matching ESP-IDF semantics if a future toolchain enables Zcmp.Other changes (all esp32p4-only)
ld/esp32p4/memory.x: RAM ends at0x4FFAE000. The top 72 KB of L2MEM is reserved by the ROM on v3.x silicon.esp-metadata-generated+esp-metadata/devices/esp32p4.toml: regenerated, added[device.psram] extmem_origin = 0x48000000.interrupt/riscv/clic.rs: P4 uses a mergedint_ctrlregister (int_attr_shv+int_attr_trigin one word). Run-level mappinggoes through
mintthresh.soc/esp32p4/clocks.rs,rtc_cntl/rtc/esp32p4.rs,rtc_cntl/sleep/esp32p4.rs: CPLL / SPLL / MPLL bring-up to matchESP-IDF's
clk_tree_ll.c.psram/esp32p4.rs(~475 lines): AP HEX-mode PSRAM driver, ported fromesp_psram_impl_ap_hex.c. Not yet tested on real PSRAM.init_psramreturnstrueoptimistically.soc/esp32p4/gpio.rs(~138 lines): LP GPIORtcPinfor GPIO0-5 + GPIO12-23. P4'sLP_IO_MUXuses namedpinN/padNinstead of indexedpin(n)/pad(n).Related crates (
esp-backtrace,esp-bootloader-esp-idf,esp-println,esp-rom-sys,esp-sync) getesp32p4feature entries.Testing
Board: ESP32-P4X Function EV Board V1.6, silicon v3.2 / ECO7.
Setup:
button nets (UART + DTR/RTS → EN/IO0 auto-reset).
I keep 28 test firmwares in a separate public repo: https://github.com/pmnxis/esp32p4-hal-testing.
A shell harness builds and flashes each one via
esptoolwith USB-native CDC auto-reset. Expected output is recorded inTEST_OUTPUTS.md. Pass/fail shown in the console log and GPIO with logic analyzer.Peripheral status on ESP32-P4X
Legend:
esp_hal::initesp-hal/src/lib.rstest_initesp-hal/src/efuse/esp32p4/test_chip_id,test_efuseesp-hal/src/soc/esp32p4/clocks.rs+rtc_cntl/rtc/esp32p4.rstest_clock,test_clock_switchtest_systimer_cornertest_wdttest_gpio,test_gpio_all_pinsRtcPin)esp-hal/src/soc/esp32p4/gpio.rstest_gpio_all_pinsesp-hal/src/uart/mod.rs(P4 PAC-name fixes)test_uart1_wire_w_logicpro(Logic Pro -verified bit-bang reference). Note: legacytest_uart_loopbackuses hand-rolled register access with a known GPIO matrix output-enable bug (pre-existing, not driver-related).esp-hal/src/i2c/master/mod.rs(P4txfifo_start_addrMMIO fix)test_i2c_wire_w_logicpro(LA-verified),test_i2c_scan(driver-instantiation smoke test)esp-hal/src/spi/master/mod.rs(P4cmd.update()fix)esp-hal/src/dma/gdma/*test_dma_mem2mem,test_sram_psram_crossovertest_crypto,test_crypto_rng_dmaesp-hal/src/interrupt/riscv/clic.rstest_interruptpmp_init.rsin firmware, not esp-hal)test_memory_boundaryesp-hal/src/psram/esp32p4.rsstubtest_psramfailed in current testing code. Need more studying with proffer PMP configurationtest_emac_phy— MDIO OK (IDR1=0x0243). EMAC MAC driver itself is out of scope for this PR.test_usb_dwc2,test_usb_rawtest_errata*(passes where documented)esp-sync/src/raw.rsriscv32imafc); verified the surrounding lock semantics still passtest_init,test_i2c_scan, embassy-net Runner spawn, MDIO readKnown open items (NOT fixed by this PR)
TODO -- to be addressed in follow-up PRs:
rtc_cntl/sleep/esp32p4.rs-- sleep mode + PMU wakeup state machine (stub).rtc_cntl/rtc/esp32p4.rs-- wakeup-source enumeration, several PMU paths.soc/esp32p4/clocks.rs-- APB divider write, UART/TIMG clock source mux, mux/source enable stubs.psram/esp32p4.rs-- ECC enable;init_psramcurrently optimistic.#[cfg(not(esp32p4))]gating.HP_SYS_CLKRST.CPU_WAITI_CTRL0-- raw MMIO, TODO for PAC accessor.pac::ahb_dma as gdma_pacalias).regi2c_read/regi2c_write+regi2c_enable_blockare in place (matches PR Enable regi2c-related clocks in regi2c enable_block impls #5405, fixes C6 (v0.0) deep sleep stuck on RtcClock::calibrate #5366).define_regi2c!macros for P4 analog registers (CPLL/SPLL/MPLL/BBPLL/LDO) are not yet ported -- needed before any driver wants typed access to PLL/bias trims. Tracking under the umbrella of issue QOL: Do something aboutregi2c_*functions. #1740.skip-semver-checkslabel requested, auto-seeds post-merge.