1use super::{EXTMEM_ORIGIN, PsramSize};
4use crate::{
5 clock::ll::{ClockTree, PsramFunctionClockConfig, PsramInstance},
6 efuse,
7 peripherals::{HP_SYS, HP_SYS_CLKRST, MEMSPI2, PMU},
8};
9
10mod oct_hex;
11
12#[derive(Copy, Clone, Debug, Default, PartialEq)]
14#[cfg_attr(feature = "defmt", derive(defmt::Format))]
15#[instability::unstable]
16pub enum PsramMode {
17 #[default]
19 Hex,
20 }
26
27#[derive(Copy, Clone, Debug, Default, PartialEq)]
29#[cfg_attr(feature = "defmt", derive(defmt::Format))]
30#[instability::unstable]
31pub struct PsramConfig {
32 pub mode: PsramMode,
34
35 pub size: PsramSize,
37
38 pub timing: PsramTimingParams,
40 }
44
45#[derive(Copy, Clone, Debug, PartialEq)]
50#[cfg_attr(feature = "defmt", derive(defmt::Format))]
51pub struct PsramTimingParams {
52 pub clock_source: PsramFunctionClockConfig,
54
55 pub clock: u32,
57
58 pub mr0_rl: u8,
60
61 pub mr4_wl: u8,
63
64 pub rd_dummy_bits: u8,
68
69 pub wr_dummy_bits: u8,
73
74 pub reg_dummy_bits: u32,
76}
77
78impl Default for PsramTimingParams {
79 fn default() -> Self {
80 Self::MHZ_250
81 }
82}
83
84impl PsramTimingParams {
85 pub const MHZ_20: Self = Self {
87 clock_source: PsramFunctionClockConfig::Mpll,
88 clock: 20,
89 mr0_rl: 2,
90 mr4_wl: 2,
91 rd_dummy_bits: 17,
92 wr_dummy_bits: 7,
93 reg_dummy_bits: 8,
94 };
95
96 pub const MHZ_80: Self = Self {
98 clock_source: PsramFunctionClockConfig::Mpll,
99 clock: 80,
100 mr0_rl: 2,
101 mr4_wl: 2,
102 rd_dummy_bits: 17,
103 wr_dummy_bits: 7,
104 reg_dummy_bits: 8,
105 };
106
107 pub const MHZ_125: Self = Self {
109 clock_source: PsramFunctionClockConfig::Mpll,
110 clock: 125,
111 mr0_rl: 2,
112 mr4_wl: 2,
113 rd_dummy_bits: 17,
114 wr_dummy_bits: 7,
115 reg_dummy_bits: 8,
116 };
117
118 pub const MHZ_200: Self = Self {
120 clock_source: PsramFunctionClockConfig::Mpll,
121 clock: 200,
122 mr0_rl: 4,
123 mr4_wl: 1,
124 rd_dummy_bits: 25,
125 wr_dummy_bits: 11,
126 reg_dummy_bits: 12,
127 };
128
129 pub const MHZ_250: Self = Self {
131 clock_source: PsramFunctionClockConfig::Mpll,
132 clock: 250,
133 mr0_rl: 6,
134 mr4_wl: 3,
135 rd_dummy_bits: 33,
136 wr_dummy_bits: 15,
137 reg_dummy_bits: 16,
138 };
139}
140
141#[crate::ram]
143pub(crate) fn init_psram(config: &mut PsramConfig) -> bool {
144 psram_phy_ldo_init();
145
146 enable_psram_mspi();
148 reset_psram_mspi();
149
150 ClockTree::with(|clocks| {
151 PsramInstance::Psram.configure_function_clock(clocks, config.timing.clock_source);
152 PsramInstance::Psram.request_function_clock(clocks);
153 });
154
155 if !oct_hex::set_bus_clock(config.timing.clock) {
157 return false;
158 }
159 let is_hex = matches!(config.mode, PsramMode::Hex);
160 oct_hex::enable_dll();
161 oct_hex::psram_pad_init(is_hex); oct_hex::set_cs_timing();
163
164 oct_hex::init_mr_registers(&config.timing, is_hex);
166
167 if config.size.is_auto() {
168 config.size = PsramSize::Size(oct_hex::psram_detect_size(&config.timing));
169 }
170
171 oct_hex::configure_psram_mspi(&config.timing, is_hex);
173
174 if efuse::chip_revision() == efuse::ChipRevision::from_combined(300) {
178 debug!("Applying P4 v3.0 PSRAM workaround");
179 p4_rev3_psram_workaround();
180 }
181
182 oct_hex::mmu_map_psram(config.size.get());
183
184 true
185}
186
187pub(crate) fn map_psram(config: PsramConfig) -> core::ops::Range<usize> {
188 let start = EXTMEM_ORIGIN;
189 start..start + config.size.get()
190}
191
192fn psram_phy_ldo_init() {
194 PMU::regs()
195 .ext_ldo_p0_0p1a()
196 .write(|w| unsafe { w.bits(0x4020_0100) });
197 PMU::regs()
198 .ext_ldo_p0_0p1a_ana()
199 .write(|w| unsafe { w.bits(0xB100_0000) });
200
201 PMU::regs()
202 .ext_ldo_p0_0p2a()
203 .write(|w| unsafe { w.bits(0x4020_0000) });
204 PMU::regs()
205 .ext_ldo_p0_0p2a_ana()
206 .write(|w| unsafe { w.bits(0xA000_0000) });
207
208 PMU::regs()
209 .ext_ldo_p0_0p3a()
210 .write(|w| unsafe { w.bits(0x4020_0000) });
211 PMU::regs()
212 .ext_ldo_p0_0p3a_ana()
213 .write(|w| unsafe { w.bits(0xA000_0000) });
214
215 PMU::regs()
216 .ext_ldo_p1_0p1a()
217 .write(|w| unsafe { w.bits(0x4020_0180) });
218 PMU::regs()
219 .ext_ldo_p1_0p1a_ana()
220 .write(|w| unsafe { w.bits(0x5700_0000) });
221
222 PMU::regs()
223 .ext_ldo_p1_0p2a()
224 .write(|w| unsafe { w.bits(0x4020_0000) });
225 PMU::regs()
226 .ext_ldo_p1_0p2a_ana()
227 .write(|w| unsafe { w.bits(0xA000_0000) });
228
229 PMU::regs()
230 .ext_ldo_p1_0p3a()
231 .write(|w| unsafe { w.bits(0x4020_0000) });
232 PMU::regs()
233 .ext_ldo_p1_0p3a_ana()
234 .write(|w| unsafe { w.bits(0xA000_0000) });
235
236 crate::rom::ets_delay_us(50);
238}
239
240fn enable_psram_mspi() {
241 HP_SYS_CLKRST::regs()
242 .soc_clk_ctrl0()
243 .modify(|_, w| w.psram_sys_clk_en().set_bit());
244}
245
246fn reset_psram_mspi() {
247 HP_SYS_CLKRST::regs().hp_rst_en0().modify(|_, w| {
248 w.rst_en_dual_mspi_axi().set_bit();
249 w.rst_en_dual_mspi_apb().set_bit()
250 });
251 HP_SYS_CLKRST::regs().hp_rst_en0().modify(|_, w| {
252 w.rst_en_dual_mspi_axi().clear_bit();
253 w.rst_en_dual_mspi_apb().clear_bit()
254 });
255}
256
257fn p4_rev3_psram_workaround() {
262 let cache_fctrl = MEMSPI2::regs().cache_fctrl().read().bits();
264 let cache_sctrl = MEMSPI2::regs().cache_sctrl().read().bits();
265 let sram_cmd = MEMSPI2::regs().sram_cmd().read().bits();
266 let sram_drd_cmd = MEMSPI2::regs().sram_drd_cmd().read().bits();
267 let sram_dwr_cmd = MEMSPI2::regs().sram_dwr_cmd().read().bits();
268 let sram_clk = MEMSPI2::regs().sram_clk().read().bits();
269 let ctrl1 = MEMSPI2::regs().ctrl1().read().bits();
270 let smem_ddr = MEMSPI2::regs().smem_ddr().read().bits();
271 let timing_cali = MEMSPI2::regs().timing_cali().read().bits();
272 let smem_timing_cali = MEMSPI2::regs().smem_timing_cali().read().bits();
273 let smem_ac = MEMSPI2::regs().smem_ac().read().bits();
274
275 HP_SYS::regs()
277 .core_err_resp_dis()
278 .write(|w| unsafe { w.bits(0x7) });
279
280 unsafe {
281 oct_hex::write_psram_mmu_entry(0, 0);
284
285 let _ = core::ptr::read_volatile(0x8800_0000u32 as *const u32);
288 let _ = core::ptr::read_volatile(0x8800_0080u32 as *const u32);
289
290 crate::rom::ets_delay_us(1);
291 }
292
293 reset_psram_mspi();
296
297 HP_SYS::regs()
299 .core_err_resp_dis()
300 .write(|w| unsafe { w.bits(0) });
301
302 unsafe {
304 MEMSPI2::regs().cache_fctrl().write(|w| w.bits(cache_fctrl));
305 MEMSPI2::regs().cache_sctrl().write(|w| w.bits(cache_sctrl));
306 MEMSPI2::regs().sram_cmd().write(|w| w.bits(sram_cmd));
307 MEMSPI2::regs()
308 .sram_drd_cmd()
309 .write(|w| w.bits(sram_drd_cmd));
310 MEMSPI2::regs()
311 .sram_dwr_cmd()
312 .write(|w| w.bits(sram_dwr_cmd));
313 MEMSPI2::regs().sram_clk().write(|w| w.bits(sram_clk));
314 MEMSPI2::regs().ctrl1().write(|w| w.bits(ctrl1));
315 MEMSPI2::regs().smem_ddr().write(|w| w.bits(smem_ddr));
316 MEMSPI2::regs().timing_cali().write(|w| w.bits(timing_cali));
317 MEMSPI2::regs()
318 .smem_timing_cali()
319 .write(|w| w.bits(smem_timing_cali));
320 MEMSPI2::regs().smem_ac().write(|w| w.bits(smem_ac));
321 }
322}