|
| 1 | +//go:build esp32s3 && numa_psram_octal |
| 2 | + |
| 3 | +// Shared PSRAM support for ESP32-S3: linker symbols, MMU/ROM-call helpers, |
| 4 | +// and address-map documentation common to both the Quad SPI driver |
| 5 | +// (runtime_esp32_psram_qspi.go, build tag numa_psram_qspi) and the Octal |
| 6 | +// SPI driver (runtime_esp32_psram_octal.go, build tag numa_psram_octal). |
| 7 | +// Everything protocol-specific (SPI1 command sequencing, chip ID/mode |
| 8 | +// register parsing, SPI0 cache-phase configuration) lives in those files. |
| 9 | +// |
| 10 | +// Address map (esp-idf soc/ext_mem_defs.h; verified on hardware while |
| 11 | +// bringing up the Octal driver): |
| 12 | +// |
| 13 | +// 0x600C5000 MMU table, 512 x 32-bit entries, one per 64KB page. |
| 14 | +// A SINGLE table shared by IBUS (0x42000000 window) and DBUS |
| 15 | +// (0x3C000000 window), indexed by linear address: |
| 16 | +// entry = (vaddr & SOC_MMU_LINEAR_ADDR_MASK 0x1FFFFFF) >> 16. |
| 17 | +// There is no ICache/DCache half-split: 0x3C800000 and |
| 18 | +// 0x42800000 both decode to entry 128. |
| 19 | +// Entry format: bits[13:0] physical page number, bit 14 = |
| 20 | +// invalid (SOC_MMU_INVALID), bit 15 = target type, 0 = flash, |
| 21 | +// 1 = PSRAM (SOC_MMU_ACCESS_SPIRAM). |
| 22 | +// |
| 23 | +// Flash XIP identity-maps linear page N -> flash page N for both IROM |
| 24 | +// and DROM (esp32s3.S), so the flash image occupies entries |
| 25 | +// 0..(image pages - 1), up to 16M. PSRAM lives in the upper half of the |
| 26 | +// DBUS window (0x3D000000, entries 256-511; targets/esp32s3.ld), |
| 27 | +// disjoint from all flash entries. |
| 28 | +// |
| 29 | +// DCache (data cache) is the L1/L2 cache in front of the DBUS window. |
| 30 | +// It is disabled (ROM Cache_Disable_DCache, which also invalidates all |
| 31 | +// tag memory) while MMU entries are modified and re-enabled after, so |
| 32 | +// that no stale cache lines survive the remap. |
| 33 | +package runtime |
| 34 | + |
| 35 | +import "unsafe" |
| 36 | + |
| 37 | +//go:extern _spsram |
| 38 | +var _spsram [0]byte |
| 39 | + |
| 40 | +//go:extern _epsram |
| 41 | +var _epsram [0]byte |
| 42 | + |
| 43 | +//go:extern _psram_start |
| 44 | +var _psram_start [0]byte |
| 45 | + |
| 46 | +//go:extern _psram_end |
| 47 | +var _psram_end [0]byte |
| 48 | + |
| 49 | +// ROM functions baked into every ESP32-S3 chip (fixed addresses provided |
| 50 | +// via PROVIDE() in targets/esp32s3.ld); see esp32s3/rom/cache.h. |
| 51 | + |
| 52 | +//export Cache_Dbus_MMU_Set |
| 53 | +func romCacheDbusMMUSet(extRam uint32, vaddr uint32, paddr uint32, psize uint32, num uint32, fixed uint32) int32 |
| 54 | + |
| 55 | +// Cache_Disable_DCache / Cache_Enable_DCache: the documented-safe pairing |
| 56 | +// around an MMU change (Cache_Disable_DCache also invalidates all DCache |
| 57 | +// tag memory). Cache_Suspend_DCache/Resume, the alternative pairing, is |
| 58 | +// explicitly documented as unsafe to use while changing the MMU. |
| 59 | + |
| 60 | +//export Cache_Disable_DCache |
| 61 | +func romCacheDisableDCache() uint32 |
| 62 | + |
| 63 | +//export Cache_Enable_DCache |
| 64 | +func romCacheEnableDCache(autoload uint32) |
| 65 | + |
| 66 | +const mmuAccessSpiram = 0x8000 // SOC_MMU_TYPE / SOC_MMU_ACCESS_SPIRAM: routes entry to PSRAM instead of flash. |
| 67 | + |
| 68 | +// psramWindow returns the linker-provided PSRAM vaddr window |
| 69 | +// (targets/esp32s3.ld) and its capacity in 64KB MMU pages. |
| 70 | +func psramWindow() (start, end uintptr, pageCap int) { |
| 71 | + start = uintptr(unsafe.Pointer(&_psram_start)) |
| 72 | + end = uintptr(unsafe.Pointer(&_psram_end)) |
| 73 | + pageCap = int((end - start) / 65536) |
| 74 | + return |
| 75 | +} |
| 76 | + |
| 77 | +// zeroInitPSRAM zero-initializes .psram BSS after PSRAM has been mapped |
| 78 | +// into the MMU, verifying with a known pattern first that writes actually |
| 79 | +// reach the chip (a hardware or timing issue could otherwise silently |
| 80 | +// drop them). |
| 81 | +func zeroInitPSRAM() { |
| 82 | + spsram := uintptr(unsafe.Pointer(&_spsram)) |
| 83 | + epsram := uintptr(unsafe.Pointer(&_epsram)) |
| 84 | + if epsram <= spsram { |
| 85 | + return |
| 86 | + } |
| 87 | + |
| 88 | + *(*uint32)(unsafe.Pointer(spsram)) = 0x5A5A5A5A |
| 89 | + if *(*uint32)(unsafe.Pointer(spsram)) != 0x5A5A5A5A { |
| 90 | + panic("PSRAM readback test failed") |
| 91 | + } |
| 92 | + *(*uint32)(unsafe.Pointer(spsram)) = 0 |
| 93 | + if *(*uint32)(unsafe.Pointer(spsram)) != 0 { |
| 94 | + panic("PSRAM readback test failed") |
| 95 | + } |
| 96 | + |
| 97 | + for addr := spsram + 4; addr < epsram; addr += 4 { |
| 98 | + *(*uint32)(unsafe.Pointer(addr)) = 0 |
| 99 | + } |
| 100 | +} |
0 commit comments