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 #[default]
65 Freq40m = 40,
66 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 {
125 spi_din_mode: 3,
126 spi_din_num: 1,
127 extra_dummy_len: 2,
128 },
129 }
130 }
131}
132
133#[procmacros::ram]
135pub(crate) fn init_psram(config: &mut PsramConfig) -> bool {
136 quad::psram_init(config);
137 true
138}
139
140#[procmacros::ram]
141pub(crate) fn map_psram(config: PsramConfig) -> Range<usize> {
142 const MMU_PAGE_SIZE: u32 = property!("mmu.page_size");
143 const FLASH_MMU_TABLE_SIZE: u32 = property!("mmu.entry_num");
144
145 fn select_mmu_entry(entry_id: u32) {
146 SPI0::regs()
147 .mmu_item_index()
148 .write(|w| unsafe { w.mmu_item_index().bits(entry_id) });
149 }
150
151 fn mmu_entry_is_valid(entry_id: u32) -> bool {
152 select_mmu_entry(entry_id);
153 SPI0::regs().mmu_item_content().read().valid().bit()
154 }
155
156 fn write_psram_mmu_entry(entry_id: u32, page: u16) {
157 select_mmu_entry(entry_id);
158 SPI0::regs().mmu_item_content().write(|w| {
159 unsafe { w.paddr().bits(page) };
160 w.access_spiram().set_bit();
161 w.valid().set_bit()
162 });
163 }
164
165 let mut mapped_pages = 0;
170
171 for i in (0..(FLASH_MMU_TABLE_SIZE - 1)).rev() {
174 if mmu_entry_is_valid(i) {
175 mapped_pages = i + 1;
176 break;
177 }
178 }
179 let start = EXTMEM_ORIGIN as u32 + (MMU_PAGE_SIZE * mapped_pages);
180 debug!("PSRAM start address = {:x}", start);
181
182 for i in 0..config.size.get() as u32 / MMU_PAGE_SIZE {
183 write_psram_mmu_entry(i + mapped_pages, i as u16);
184 }
185
186 CACHE::regs().cache_ctrl().modify(|_, w| {
188 w.cache_shut_bus0().clear_bit();
189 w.cache_shut_bus1().clear_bit()
190 });
191
192 start as usize..start as usize + config.size.get()
193}
194
195fn core_clock_for_mode(_speed_mode: MspiTimingSpeedMode) -> u32 {
196 80
198}
199
200mod ctrlr_ll {
201 use super::*;
202
203 pub(crate) const PSRAM_CTRLR_LL_MSPI_ID_0: u32 = 0;
204
205 #[inline(always)]
206 pub(crate) fn psram_ctrlr_ll_set_cs_hold(_mspi_id: u32, hold_n: u32) {
207 assert!(hold_n > 0);
208
209 SPI0::regs().smem_ac().modify(|_, w| {
210 w.smem_cs_hold().set_bit();
211 unsafe {
212 w.smem_cs_hold_time().bits(hold_n as u8 - 1);
213 }
214 w
215 });
216 }
217
218 #[inline(always)]
219 pub(crate) fn psram_ctrlr_ll_set_cs_setup(_mspi_id: u32, setup_n: u32) {
220 assert!(setup_n > 0);
221
222 SPI0::regs().smem_ac().modify(|_, w| {
223 w.smem_cs_setup().set_bit();
224 unsafe {
225 w.smem_cs_setup_time().bits(setup_n as u8 - 1);
226 }
227 w
228 });
229 }
230
231 #[inline(always)]
232 pub(crate) fn psram_ctrlr_ll_set_read_mode(mspi_id: u32, read_mode: CommandMode) {
233 assert!(mspi_id == 0);
234
235 SPI0::regs().cache_sctrl().modify(|_, w| {
236 w.usr_sram_dio().bit(read_mode == CommandMode::PsramCmdSpi);
237 w.usr_sram_qio().bit(read_mode == CommandMode::PsramCmdQpi);
238 w
239 });
240 }
241
242 #[inline(always)]
244 pub(crate) fn psram_ctrlr_ll_set_wr_cmd(_mspi_id: u32, cmd_bitlen: u32, cmd_val: u32) {
245 assert!(cmd_bitlen > 0);
246 SPI0::regs()
247 .cache_sctrl()
248 .modify(|_, w| w.cache_sram_usr_wcmd().set_bit());
249
250 SPI0::regs().sram_dwr_cmd().modify(|_, w| {
251 unsafe { w.cache_sram_usr_wr_cmd_bitlen().bits(cmd_bitlen as u8 - 1) };
252 unsafe { w.cache_sram_usr_wr_cmd_value().bits(cmd_val as u16) };
253 w
254 });
255 }
256
257 #[inline(always)]
259 pub(crate) fn psram_ctrlr_ll_set_rd_cmd(_mspi_id: u32, cmd_bitlen: u32, cmd_val: u32) {
260 assert!(cmd_bitlen > 0);
261
262 SPI0::regs()
263 .cache_sctrl()
264 .modify(|_, w| w.cache_sram_usr_rcmd().set_bit());
265
266 SPI0::regs().sram_drd_cmd().modify(|_, w| {
267 unsafe { w.cache_sram_usr_rd_cmd_bitlen().bits(cmd_bitlen as u8 - 1) };
268 unsafe { w.cache_sram_usr_rd_cmd_value().bits(cmd_val as u16) };
269 w
270 });
271 }
272
273 #[inline(always)]
275 pub(crate) fn psram_ctrlr_ll_set_addr_bitlen(_mspi_id: u32, addr_bitlen: u32) {
276 assert!(addr_bitlen > 0);
277
278 SPI0::regs()
279 .cache_sctrl()
280 .modify(|_, w| unsafe { w.sram_addr_bitlen().bits(addr_bitlen as u8 - 1) });
281 }
282
283 #[inline(always)]
285 pub(crate) fn psram_ctrlr_ll_set_rd_dummy(_mspi_id: u32, dummy_n: u32) {
286 assert!(dummy_n > 0);
287
288 SPI0::regs().cache_sctrl().modify(|_, w| {
289 w.usr_rd_sram_dummy().set_bit();
290 unsafe { w.sram_rdummy_cyclelen().bits(dummy_n as u8 - 1) };
291 w
292 });
293 }
294
295 #[inline(always)]
297 pub(crate) fn psram_ctrlr_ll_set_cs_pin(_mspi_id: u32, cs_id: PsramLlCsIdT) {
298 SPI1::regs().misc().modify(|_, w| {
299 w.cs0_dis().bit(cs_id == PsramLlCsIdT::PsramLlCsId0);
300 w.cs1_dis().bit(cs_id == PsramLlCsIdT::PsramLlCsId1);
301 w
302 });
303 }
304}
305
306#[ram]
307fn mspi_timing_config_set_flash_clock(flash_freq_mhz: u32, speed_mode: quad::MspiTimingSpeedMode) {
308 let core_clock_mhz = core_clock_for_mode(speed_mode);
309 mspi_timing_ll_set_core_clock(core_clock_mhz);
311
312 let freqdiv: u32 = core_clock_mhz / flash_freq_mhz;
313 debug!("flash freqdiv: {}", freqdiv);
314 assert!(freqdiv > 0);
315 let reg_val: u32 = mspi_timing_ll_calculate_clock_reg(freqdiv);
316 mspi_timing_ll_set_flash_clock(0, reg_val);
317 mspi_timing_ll_set_flash_clock(1, reg_val);
318}
319
320#[inline(always)]
322pub(crate) fn mspi_timing_ll_set_core_clock(core_clk_mhz: u32) {
323 let divider = match core_clk_mhz {
324 80 => 6,
325 _ => panic!("Invalid core clock"),
326 };
327
328 crate::peripherals::PCR::regs()
329 .mspi_clk_conf()
330 .modify(|_, w| unsafe { w.mspi_fast_div_num().bits(divider - 1) });
331}
332
333#[inline(always)]
335fn mspi_timing_ll_calculate_clock_reg(clkdiv: u32) -> u32 {
336 if clkdiv == 1 {
337 1 << 31
338 } else {
339 (clkdiv - 1) | ((((clkdiv - 1) / 2) & 0xff) << 8) | (((clkdiv - 1) & 0xff) << 16)
340 }
341}
342
343#[inline(always)]
345fn mspi_timing_ll_set_flash_clock(mspi_id: u32, clock_conf: u32) {
346 if mspi_id == 0 {
347 SPI0::regs()
348 .clock()
349 .write(|w| unsafe { w.bits(clock_conf) });
350 } else {
351 SPI1::regs()
352 .clock()
353 .write(|w| unsafe { w.bits(clock_conf) });
354 }
355}
356
357#[ram]
358fn mspi_timing_config_set_psram_clock(psram_freq_mhz: u32, speed_mode: quad::MspiTimingSpeedMode) {
359 let core_clock_mhz = core_clock_for_mode(speed_mode);
361
362 mspi_timing_ll_set_core_clock(core_clock_mhz);
364
365 let freqdiv: u32 = core_clock_mhz / psram_freq_mhz;
366 debug!("psram freqdiv: {}", freqdiv);
367 assert!(freqdiv > 0);
368 let reg_val: u32 = mspi_timing_ll_calculate_clock_reg(freqdiv);
369 mspi_timing_ll_set_psram_clock(reg_val);
370}
371
372#[inline(always)]
374fn mspi_timing_ll_set_psram_clock(clock_conf: u32) {
375 SPI0::regs()
376 .sram_clk()
377 .write(|w| unsafe { w.bits(clock_conf) });
378}
379
380#[inline(always)]
382pub(crate) fn mspi_timing_ll_set_flash_din_mode(mspi_id: u8, din_mode: u8) {
383 assert!(mspi_id == 0);
384 assert!(din_mode <= 7);
385
386 SPI0::regs().din_mode().modify(|_, w| {
387 unsafe {
388 w.din0_mode().bits(din_mode);
389 w.din1_mode().bits(din_mode);
390 w.din2_mode().bits(din_mode);
391 w.din3_mode().bits(din_mode);
392 w.din4_mode().bits(din_mode);
393 w.din5_mode().bits(din_mode);
394 w.din6_mode().bits(din_mode);
395 w.din7_mode().bits(din_mode);
396 w.dins_mode().bits(din_mode);
397 }
398
399 w
400 });
401
402 SPI0::regs()
403 .timing_cali()
404 .modify(|_, w| w.update().set_bit());
405}
406
407#[inline(always)]
409pub(crate) fn mspi_timing_ll_set_flash_din_num(mspi_id: u8, din_num: u8) {
410 assert!(mspi_id == 0);
411 assert!(din_num <= 3);
412
413 SPI0::regs().din_num().modify(|_, w| {
414 unsafe {
415 w.din0_num().bits(din_num);
416 w.din1_num().bits(din_num);
417 w.din2_num().bits(din_num);
418 w.din3_num().bits(din_num);
419 w.din4_num().bits(din_num);
420 w.din5_num().bits(din_num);
421 w.din6_num().bits(din_num);
422 w.din7_num().bits(din_num);
423 w.dins_num().bits(din_num);
424 }
425
426 w
427 });
428
429 SPI0::regs()
430 .timing_cali()
431 .modify(|_, w| w.update().set_bit());
432}
433
434#[inline(always)]
436pub(crate) fn mspi_timing_ll_set_flash_extra_dummy(mspi_id: u8, extra_dummy: u8) {
437 if mspi_id == 0 {
438 SPI0::regs().timing_cali().modify(|_, w| {
439 w.timing_cali().bit(extra_dummy > 0);
440 unsafe { w.extra_dummy_cyclelen().bits(extra_dummy) };
441 w
442 });
443 } else {
444 SPI1::regs().timing_cali().modify(|_, w| {
445 w.timing_cali().bit(extra_dummy > 0);
446 unsafe { w.extra_dummy_cyclelen().bits(extra_dummy) };
447 w
448 });
449 }
450
451 SPI0::regs()
452 .timing_cali()
453 .modify(|_, w| w.update().set_bit());
454}
455
456#[inline(always)]
458pub(crate) fn mspi_timing_ll_set_psram_din_mode(mspi_id: u8, din_mode: u8) {
459 assert!(mspi_id == 0);
460 assert!(din_mode <= 7);
461
462 SPI0::regs().smem_din_mode().modify(|_, w| {
463 unsafe {
464 w.smem_din0_mode().bits(din_mode);
465 w.smem_din1_mode().bits(din_mode);
466 w.smem_din2_mode().bits(din_mode);
467 w.smem_din3_mode().bits(din_mode);
468 w.smem_din4_mode().bits(din_mode);
469 w.smem_din5_mode().bits(din_mode);
470 w.smem_din6_mode().bits(din_mode);
471 w.smem_din7_mode().bits(din_mode);
472 w.smem_dins_mode().bits(din_mode);
473 }
474
475 w
476 });
477
478 SPI0::regs()
479 .timing_cali()
480 .modify(|_, w| w.update().set_bit());
481}
482
483#[inline(always)]
485pub(crate) fn mspi_timing_ll_set_psram_din_num(mspi_id: u8, din_num: u8) {
486 assert!(mspi_id == 0);
487 assert!(din_num <= 3);
488
489 SPI0::regs().smem_din_num().modify(|_, w| {
490 unsafe {
491 w.smem_din0_num().bits(din_num);
492 w.smem_din1_num().bits(din_num);
493 w.smem_din2_num().bits(din_num);
494 w.smem_din3_num().bits(din_num);
495 w.smem_din4_num().bits(din_num);
496 w.smem_din5_num().bits(din_num);
497 w.smem_din6_num().bits(din_num);
498 w.smem_din7_num().bits(din_num);
499 w.smem_dins_num().bits(din_num);
500 }
501
502 w
503 });
504
505 SPI0::regs()
506 .timing_cali()
507 .modify(|_, w| w.update().set_bit());
508}
509
510#[inline(always)]
512pub(crate) fn mspi_timing_ll_set_psram_extra_dummy(mspi_id: u8, extra_dummy: u8) {
513 assert!(mspi_id == 0);
514
515 SPI0::regs().smem_timing_cali().modify(|_, w| {
516 w.smem_timing_cali().bit(extra_dummy > 0);
517 unsafe { w.smem_extra_dummy_cyclelen().bits(extra_dummy) };
518 w
519 });
520
521 SPI0::regs()
522 .timing_cali()
523 .modify(|_, w| w.update().set_bit());
524}
525
526#[inline(always)]
528pub(crate) fn mspi_timing_ll_get_flash_dummy(mspi_id: u8) -> (u8, u8) {
529 assert!(mspi_id <= 1);
530
531 if mspi_id == 0 {
532 let usr_dummy = SPI0::regs().user1().read().usr_dummy_cyclelen().bits();
533 let extra_dummy = SPI0::regs()
534 .timing_cali()
535 .read()
536 .extra_dummy_cyclelen()
537 .bits();
538 (usr_dummy, extra_dummy)
539 } else {
540 let usr_dummy = SPI1::regs().user1().read().usr_dummy_cyclelen().bits();
541 let extra_dummy = SPI1::regs()
542 .timing_cali()
543 .read()
544 .extra_dummy_cyclelen()
545 .bits();
546 (usr_dummy, extra_dummy)
547 }
548}
549
550#[inline(always)]
552pub(crate) fn mspi_timing_ll_get_psram_dummy(mspi_id: u8) -> (u8, u8) {
553 assert!(mspi_id == 0);
554
555 let usr_dummy = SPI0::regs()
556 .cache_sctrl()
557 .read()
558 .sram_rdummy_cyclelen()
559 .bits();
560 let extra_dummy = SPI0::regs()
561 .smem_timing_cali()
562 .read()
563 .smem_extra_dummy_cyclelen()
564 .bits();
565 (usr_dummy, extra_dummy)
566}