1use core::ops::Range;
2
3use super::{EXTMEM_ORIGIN, PsramSize};
4use crate::{
5 peripherals::{CACHE, SPI0, SPI1},
6 psram::implem::quad::MspiTimingSpeedMode,
7};
8
9mod quad;
10
11use procmacros::ram;
12use quad::CommandMode;
13
14const FUNC_SPICS1_SPICS1: u8 = 0;
15const PIN_FUNC_GPIO: u8 = 1;
16
17cfg_select! {
18 esp32c61 => {
19 const PSRAM_CS_IO: u8 = 14;
20 const SPI_CS1_GPIO_NUM: u8 = 14;
21 const SPICS1_OUT_IDX: u8 = 102;
22 const PSRAM_SPIWP_SD3_IO: u8 = 17;
23 }
24 esp32c5 => {
25 const PSRAM_CS_IO: u8 = 15;
26 const SPI_CS1_GPIO_NUM: u8 = 15;
27 const SPICS1_OUT_IDX: u8 = 101;
28 const PSRAM_SPIWP_SD3_IO: u8 = 18;
29 }
30 _ => {}
31}
32
33#[derive(Copy, Clone, Debug, PartialEq, Eq)]
34pub(crate) enum PsramLlCsIdT {
35 PsramLlCsId0,
36 PsramLlCsId1,
37}
38
39#[derive(Copy, Clone, Debug, Default, PartialEq)]
41#[cfg_attr(feature = "defmt", derive(defmt::Format))]
42pub enum FlashFreq {
43 FlashFreq40m = 40,
45 #[default]
47 FlashFreq80m = 80,
48}
49
50impl FlashFreq {
51 fn mhz(&self) -> u32 {
52 match self {
53 FlashFreq::FlashFreq40m => 40,
54 FlashFreq::FlashFreq80m => 80,
55 }
56 }
57}
58
59#[derive(Copy, Clone, Debug, Default, PartialEq)]
61#[cfg_attr(feature = "defmt", derive(defmt::Format))]
62pub enum SpiRamFreq {
63 Freq40m = 40,
65 #[default]
67 Freq80m = 80,
68}
69
70impl SpiRamFreq {
71 pub(crate) fn need_timing_tuning(&self) -> bool {
72 *self != SpiRamFreq::Freq40m
73 }
74
75 fn mhz(&self) -> u32 {
76 match self {
77 SpiRamFreq::Freq40m => 40,
78 SpiRamFreq::Freq80m => 80,
79 }
80 }
81}
82
83#[derive(Copy, Clone, Debug, Default, PartialEq)]
85#[cfg_attr(feature = "defmt", derive(defmt::Format))]
86pub struct MspiTimingTuningParam {
87 pub spi_din_mode: u8,
89 pub spi_din_num: u8,
91 pub extra_dummy_len: u8,
93}
94
95#[derive(Copy, Clone, Debug, PartialEq)]
97#[cfg_attr(feature = "defmt", derive(defmt::Format))]
98pub struct PsramConfig {
99 pub size: PsramSize,
101 pub flash_frequency: FlashFreq,
103 pub flash_tuning: MspiTimingTuningParam,
106 pub ram_frequency: SpiRamFreq,
108 pub ram_tuning: MspiTimingTuningParam,
111}
112
113impl Default for PsramConfig {
114 fn default() -> Self {
115 Self {
116 size: Default::default(),
117 flash_frequency: Default::default(),
118 flash_tuning: MspiTimingTuningParam {
119 spi_din_mode: 3,
120 spi_din_num: 1,
121 extra_dummy_len: 2,
122 },
123 ram_frequency: Default::default(),
124 ram_tuning: MspiTimingTuningParam {
126 spi_din_mode: 3,
127 spi_din_num: 1,
128 extra_dummy_len: 2,
129 },
130 }
131 }
132}
133
134#[procmacros::ram]
136pub(crate) fn init_psram(config: &mut PsramConfig) -> bool {
137 quad::psram_init(config);
138 true
139}
140
141#[procmacros::ram]
142pub(crate) fn map_psram(config: PsramConfig) -> Range<usize> {
143 const MMU_PAGE_SIZE: u32 = property!("mmu.page_size");
144 const FLASH_MMU_TABLE_SIZE: u32 = property!("mmu.entry_num");
145
146 fn select_mmu_entry(entry_id: u32) {
147 SPI0::regs()
148 .mmu_item_index()
149 .write(|w| unsafe { w.mmu_item_index().bits(entry_id) });
150 }
151
152 fn mmu_entry_is_valid(entry_id: u32) -> bool {
153 select_mmu_entry(entry_id);
154 SPI0::regs().mmu_item_content().read().valid().bit()
155 }
156
157 fn write_psram_mmu_entry(entry_id: u32, page: u16) {
158 select_mmu_entry(entry_id);
159 SPI0::regs().mmu_item_content().write(|w| {
160 unsafe { w.paddr().bits(page) };
161 w.access_spiram().set_bit();
162 w.valid().set_bit()
163 });
164 }
165
166 let mut mapped_pages = 0;
171
172 for i in (0..(FLASH_MMU_TABLE_SIZE - 1)).rev() {
175 if mmu_entry_is_valid(i) {
176 mapped_pages = i + 1;
177 break;
178 }
179 }
180 let start = EXTMEM_ORIGIN as u32 + (MMU_PAGE_SIZE * mapped_pages);
181 debug!("PSRAM start address = {:x}", start);
182
183 for i in 0..config.size.get() as u32 / MMU_PAGE_SIZE {
184 write_psram_mmu_entry(i + mapped_pages, i as u16);
185 }
186
187 CACHE::regs().cache_ctrl().modify(|_, w| {
189 w.cache_shut_bus0().clear_bit();
190 w.cache_shut_bus1().clear_bit()
191 });
192
193 start as usize..start as usize + config.size.get()
194}
195
196fn core_clock_for_mode(_speed_mode: MspiTimingSpeedMode) -> u32 {
197 80
199}
200
201mod ctrlr_ll {
202 use super::*;
203
204 pub(crate) const PSRAM_CTRLR_LL_MSPI_ID_0: u32 = 0;
205
206 #[inline(always)]
207 pub(crate) fn psram_ctrlr_ll_set_cs_hold(_mspi_id: u32, hold_n: u32) {
208 assert!(hold_n > 0);
209
210 SPI0::regs().smem_ac().modify(|_, w| {
211 w.smem_cs_hold().set_bit();
212 unsafe {
213 w.smem_cs_hold_time().bits(hold_n as u8 - 1);
214 }
215 w
216 });
217 }
218
219 #[inline(always)]
220 pub(crate) fn psram_ctrlr_ll_set_cs_setup(_mspi_id: u32, setup_n: u32) {
221 assert!(setup_n > 0);
222
223 SPI0::regs().smem_ac().modify(|_, w| {
224 w.smem_cs_setup().set_bit();
225 unsafe {
226 w.smem_cs_setup_time().bits(setup_n as u8 - 1);
227 }
228 w
229 });
230 }
231
232 #[inline(always)]
233 pub(crate) fn psram_ctrlr_ll_set_read_mode(mspi_id: u32, read_mode: CommandMode) {
234 assert!(mspi_id == 0);
235
236 SPI0::regs().cache_sctrl().modify(|_, w| {
237 w.usr_sram_dio().bit(read_mode == CommandMode::PsramCmdSpi);
238 w.usr_sram_qio().bit(read_mode == CommandMode::PsramCmdQpi);
239 w
240 });
241 }
242
243 #[inline(always)]
245 pub(crate) fn psram_ctrlr_ll_set_wr_cmd(_mspi_id: u32, cmd_bitlen: u32, cmd_val: u32) {
246 assert!(cmd_bitlen > 0);
247 SPI0::regs()
248 .cache_sctrl()
249 .modify(|_, w| w.cache_sram_usr_wcmd().set_bit());
250
251 SPI0::regs().sram_dwr_cmd().modify(|_, w| {
252 unsafe { w.cache_sram_usr_wr_cmd_bitlen().bits(cmd_bitlen as u8 - 1) };
253 unsafe { w.cache_sram_usr_wr_cmd_value().bits(cmd_val as u16) };
254 w
255 });
256 }
257
258 #[inline(always)]
260 pub(crate) fn psram_ctrlr_ll_set_rd_cmd(_mspi_id: u32, cmd_bitlen: u32, cmd_val: u32) {
261 assert!(cmd_bitlen > 0);
262
263 SPI0::regs()
264 .cache_sctrl()
265 .modify(|_, w| w.cache_sram_usr_rcmd().set_bit());
266
267 SPI0::regs().sram_drd_cmd().modify(|_, w| {
268 unsafe { w.cache_sram_usr_rd_cmd_bitlen().bits(cmd_bitlen as u8 - 1) };
269 unsafe { w.cache_sram_usr_rd_cmd_value().bits(cmd_val as u16) };
270 w
271 });
272 }
273
274 #[inline(always)]
276 pub(crate) fn psram_ctrlr_ll_set_addr_bitlen(_mspi_id: u32, addr_bitlen: u32) {
277 assert!(addr_bitlen > 0);
278
279 SPI0::regs()
280 .cache_sctrl()
281 .modify(|_, w| unsafe { w.sram_addr_bitlen().bits(addr_bitlen as u8 - 1) });
282 }
283
284 #[inline(always)]
286 pub(crate) fn psram_ctrlr_ll_set_rd_dummy(_mspi_id: u32, dummy_n: u32) {
287 assert!(dummy_n > 0);
288
289 SPI0::regs().cache_sctrl().modify(|_, w| {
290 w.usr_rd_sram_dummy().set_bit();
291 unsafe { w.sram_rdummy_cyclelen().bits(dummy_n as u8 - 1) };
292 w
293 });
294 }
295
296 #[inline(always)]
298 pub(crate) fn psram_ctrlr_ll_set_cs_pin(_mspi_id: u32, cs_id: PsramLlCsIdT) {
299 SPI1::regs().misc().modify(|_, w| {
300 w.cs0_dis().bit(cs_id == PsramLlCsIdT::PsramLlCsId0);
301 w.cs1_dis().bit(cs_id == PsramLlCsIdT::PsramLlCsId1);
302 w
303 });
304 }
305}
306
307#[ram]
308fn mspi_timing_config_set_flash_clock(flash_freq_mhz: u32, speed_mode: quad::MspiTimingSpeedMode) {
309 let core_clock_mhz = core_clock_for_mode(speed_mode);
310 mspi_timing_ll_set_core_clock(core_clock_mhz);
312
313 let freqdiv: u32 = core_clock_mhz / flash_freq_mhz;
314 debug!("flash freqdiv: {}", freqdiv);
315 assert!(freqdiv > 0);
316 let reg_val: u32 = mspi_timing_ll_calculate_clock_reg(freqdiv);
317 mspi_timing_ll_set_flash_clock(0, reg_val);
318 mspi_timing_ll_set_flash_clock(1, reg_val);
319}
320
321#[inline(always)]
323pub(crate) fn mspi_timing_ll_set_core_clock(core_clk_mhz: u32) {
324 let divider = match core_clk_mhz {
325 80 => 6,
326 _ => panic!("Invalid core clock"),
327 };
328
329 crate::peripherals::PCR::regs()
330 .mspi_clk_conf()
331 .modify(|_, w| unsafe { w.mspi_fast_div_num().bits(divider - 1) });
332}
333
334#[inline(always)]
336fn mspi_timing_ll_calculate_clock_reg(clkdiv: u32) -> u32 {
337 if clkdiv == 1 {
338 1 << 31
339 } else {
340 (clkdiv - 1) | ((((clkdiv - 1) / 2) & 0xff) << 8) | (((clkdiv - 1) & 0xff) << 16)
341 }
342}
343
344#[inline(always)]
346fn mspi_timing_ll_set_flash_clock(mspi_id: u32, clock_conf: u32) {
347 if mspi_id == 0 {
348 SPI0::regs()
349 .clock()
350 .write(|w| unsafe { w.bits(clock_conf) });
351 } else {
352 SPI1::regs()
353 .clock()
354 .write(|w| unsafe { w.bits(clock_conf) });
355 }
356}
357
358#[ram]
359fn mspi_timing_config_set_psram_clock(psram_freq_mhz: u32, speed_mode: quad::MspiTimingSpeedMode) {
360 let core_clock_mhz = core_clock_for_mode(speed_mode);
362
363 mspi_timing_ll_set_core_clock(core_clock_mhz);
365
366 let freqdiv: u32 = core_clock_mhz / psram_freq_mhz;
367 debug!("psram freqdiv: {}", freqdiv);
368 assert!(freqdiv > 0);
369 let reg_val: u32 = mspi_timing_ll_calculate_clock_reg(freqdiv);
370 mspi_timing_ll_set_psram_clock(reg_val);
371}
372
373#[inline(always)]
375fn mspi_timing_ll_set_psram_clock(clock_conf: u32) {
376 SPI0::regs()
377 .sram_clk()
378 .write(|w| unsafe { w.bits(clock_conf) });
379}
380
381#[inline(always)]
383pub(crate) fn mspi_timing_ll_set_flash_din_mode(mspi_id: u8, din_mode: u8) {
384 assert!(mspi_id == 0);
385 assert!(din_mode <= 7);
386
387 SPI0::regs().din_mode().modify(|_, w| {
388 unsafe {
389 w.din0_mode().bits(din_mode);
390 w.din1_mode().bits(din_mode);
391 w.din2_mode().bits(din_mode);
392 w.din3_mode().bits(din_mode);
393 w.din4_mode().bits(din_mode);
394 w.din5_mode().bits(din_mode);
395 w.din6_mode().bits(din_mode);
396 w.din7_mode().bits(din_mode);
397 w.dins_mode().bits(din_mode);
398 }
399
400 w
401 });
402
403 SPI0::regs()
404 .timing_cali()
405 .modify(|_, w| w.update().set_bit());
406}
407
408#[inline(always)]
410pub(crate) fn mspi_timing_ll_set_flash_din_num(mspi_id: u8, din_num: u8) {
411 assert!(mspi_id == 0);
412 assert!(din_num <= 3);
413
414 SPI0::regs().din_num().modify(|_, w| {
415 unsafe {
416 w.din0_num().bits(din_num);
417 w.din1_num().bits(din_num);
418 w.din2_num().bits(din_num);
419 w.din3_num().bits(din_num);
420 w.din4_num().bits(din_num);
421 w.din5_num().bits(din_num);
422 w.din6_num().bits(din_num);
423 w.din7_num().bits(din_num);
424 w.dins_num().bits(din_num);
425 }
426
427 w
428 });
429
430 SPI0::regs()
431 .timing_cali()
432 .modify(|_, w| w.update().set_bit());
433}
434
435#[inline(always)]
437pub(crate) fn mspi_timing_ll_set_flash_extra_dummy(mspi_id: u8, extra_dummy: u8) {
438 if mspi_id == 0 {
439 SPI0::regs().timing_cali().modify(|_, w| {
440 w.timing_cali().bit(extra_dummy > 0);
441 unsafe { w.extra_dummy_cyclelen().bits(extra_dummy) };
442 w
443 });
444 } else {
445 SPI1::regs().timing_cali().modify(|_, w| {
446 w.timing_cali().bit(extra_dummy > 0);
447 unsafe { w.extra_dummy_cyclelen().bits(extra_dummy) };
448 w
449 });
450 }
451
452 SPI0::regs()
453 .timing_cali()
454 .modify(|_, w| w.update().set_bit());
455}
456
457#[inline(always)]
459pub(crate) fn mspi_timing_ll_set_psram_din_mode(mspi_id: u8, din_mode: u8) {
460 assert!(mspi_id == 0);
461 assert!(din_mode <= 7);
462
463 SPI0::regs().smem_din_mode().modify(|_, w| {
464 unsafe {
465 w.smem_din0_mode().bits(din_mode);
466 w.smem_din1_mode().bits(din_mode);
467 w.smem_din2_mode().bits(din_mode);
468 w.smem_din3_mode().bits(din_mode);
469 w.smem_din4_mode().bits(din_mode);
470 w.smem_din5_mode().bits(din_mode);
471 w.smem_din6_mode().bits(din_mode);
472 w.smem_din7_mode().bits(din_mode);
473 w.smem_dins_mode().bits(din_mode);
474 }
475
476 w
477 });
478
479 SPI0::regs()
480 .timing_cali()
481 .modify(|_, w| w.update().set_bit());
482}
483
484#[inline(always)]
486pub(crate) fn mspi_timing_ll_set_psram_din_num(mspi_id: u8, din_num: u8) {
487 assert!(mspi_id == 0);
488 assert!(din_num <= 3);
489
490 SPI0::regs().smem_din_num().modify(|_, w| {
491 unsafe {
492 w.smem_din0_num().bits(din_num);
493 w.smem_din1_num().bits(din_num);
494 w.smem_din2_num().bits(din_num);
495 w.smem_din3_num().bits(din_num);
496 w.smem_din4_num().bits(din_num);
497 w.smem_din5_num().bits(din_num);
498 w.smem_din6_num().bits(din_num);
499 w.smem_din7_num().bits(din_num);
500 w.smem_dins_num().bits(din_num);
501 }
502
503 w
504 });
505
506 SPI0::regs()
507 .timing_cali()
508 .modify(|_, w| w.update().set_bit());
509}
510
511#[inline(always)]
513pub(crate) fn mspi_timing_ll_set_psram_extra_dummy(mspi_id: u8, extra_dummy: u8) {
514 assert!(mspi_id == 0);
515
516 SPI0::regs().smem_timing_cali().modify(|_, w| {
517 w.smem_timing_cali().bit(extra_dummy > 0);
518 unsafe { w.smem_extra_dummy_cyclelen().bits(extra_dummy) };
519 w
520 });
521
522 SPI0::regs()
523 .timing_cali()
524 .modify(|_, w| w.update().set_bit());
525}
526
527#[inline(always)]
529pub(crate) fn mspi_timing_ll_get_flash_dummy(mspi_id: u8) -> (u8, u8) {
530 assert!(mspi_id <= 1);
531
532 if mspi_id == 0 {
533 let usr_dummy = SPI0::regs().user1().read().usr_dummy_cyclelen().bits();
534 let extra_dummy = SPI0::regs()
535 .timing_cali()
536 .read()
537 .extra_dummy_cyclelen()
538 .bits();
539 (usr_dummy, extra_dummy)
540 } else {
541 let usr_dummy = SPI1::regs().user1().read().usr_dummy_cyclelen().bits();
542 let extra_dummy = SPI1::regs()
543 .timing_cali()
544 .read()
545 .extra_dummy_cyclelen()
546 .bits();
547 (usr_dummy, extra_dummy)
548 }
549}
550
551#[inline(always)]
553pub(crate) fn mspi_timing_ll_get_psram_dummy(mspi_id: u8) -> (u8, u8) {
554 assert!(mspi_id == 0);
555
556 let usr_dummy = SPI0::regs()
557 .cache_sctrl()
558 .read()
559 .sram_rdummy_cyclelen()
560 .bits();
561 let extra_dummy = SPI0::regs()
562 .smem_timing_cali()
563 .read()
564 .smem_extra_dummy_cyclelen()
565 .bits();
566 (usr_dummy, extra_dummy)
567}