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_if::cfg_if! {
18 if #[cfg(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 } else if #[cfg(esp32c5)] {
24 const PSRAM_CS_IO: u8 = 15;
25 const SPI_CS1_GPIO_NUM: u8 = 15;
26 const SPICS1_OUT_IDX: u8 = 101;
27 const PSRAM_SPIWP_SD3_IO: u8 = 18;
28 }
29}
30
31#[derive(Copy, Clone, Debug, PartialEq, Eq)]
32pub(crate) enum PsramLlCsIdT {
33 PsramLlCsId0,
34 PsramLlCsId1,
35}
36
37#[derive(Copy, Clone, Debug, Default, PartialEq)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40pub enum FlashFreq {
41 FlashFreq40m = 40,
43 #[default]
45 FlashFreq80m = 80,
46}
47
48impl FlashFreq {
49 fn mhz(&self) -> u32 {
50 match self {
51 FlashFreq::FlashFreq40m => 40,
52 FlashFreq::FlashFreq80m => 80,
53 }
54 }
55}
56
57#[derive(Copy, Clone, Debug, Default, PartialEq)]
59#[cfg_attr(feature = "defmt", derive(defmt::Format))]
60pub enum SpiRamFreq {
61 #[default]
63 Freq40m = 40,
64 Freq80m = 80,
66}
67
68impl SpiRamFreq {
69 pub(crate) fn need_timing_tuning(&self) -> bool {
70 *self != SpiRamFreq::Freq40m
71 }
72
73 fn mhz(&self) -> u32 {
74 match self {
75 SpiRamFreq::Freq40m => 40,
76 SpiRamFreq::Freq80m => 80,
77 }
78 }
79}
80
81#[derive(Copy, Clone, Debug, Default, PartialEq)]
83#[cfg_attr(feature = "defmt", derive(defmt::Format))]
84pub struct MspiTimingTuningParam {
85 pub spi_din_mode: u8,
87 pub spi_din_num: u8,
89 pub extra_dummy_len: u8,
91}
92
93#[derive(Copy, Clone, Debug, PartialEq)]
95#[cfg_attr(feature = "defmt", derive(defmt::Format))]
96pub struct PsramConfig {
97 pub size: PsramSize,
99 pub flash_frequency: FlashFreq,
101 pub flash_tuning: MspiTimingTuningParam,
104 pub ram_frequency: SpiRamFreq,
106 pub ram_tuning: MspiTimingTuningParam,
109}
110
111impl Default for PsramConfig {
112 fn default() -> Self {
113 Self {
114 size: Default::default(),
115 flash_frequency: Default::default(),
116 flash_tuning: MspiTimingTuningParam {
117 spi_din_mode: 3,
118 spi_din_num: 1,
119 extra_dummy_len: 2,
120 },
121 ram_frequency: Default::default(),
122 ram_tuning: MspiTimingTuningParam {
123 spi_din_mode: 3,
124 spi_din_num: 1,
125 extra_dummy_len: 2,
126 },
127 }
128 }
129}
130
131#[procmacros::ram]
133pub(crate) fn init_psram(config: &mut PsramConfig) -> bool {
134 quad::psram_init(config);
135 true
136}
137
138#[procmacros::ram]
139pub(crate) fn map_psram(config: PsramConfig) -> Range<usize> {
140 const MMU_ACCESS_SPIRAM: u32 = 1 << 9;
141
142 const MMU_PAGE_SIZE: u32 = 0x10000;
143 const FLASH_MMU_TABLE_SIZE: u32 = 512;
144 const MMU_VALID: u32 = 1 << 10;
145
146 fn read_mmu_entry(i: u32) -> u32 {
147 SPI0::regs()
148 .mmu_item_index()
149 .write(|w| unsafe { w.mmu_item_index().bits(i) });
150 SPI0::regs()
151 .mmu_item_content()
152 .read()
153 .mmu_item_content()
154 .bits()
155 }
156
157 fn write_mmu_entry(i: u32, entry: u32) {
158 SPI0::regs()
159 .mmu_item_index()
160 .write(|w| unsafe { w.mmu_item_index().bits(i) });
161 SPI0::regs()
162 .mmu_item_content()
163 .write(|w| unsafe { w.mmu_item_content().bits(entry) });
164 }
165
166 let mut mapped_pages = 0;
171
172 for i in (0..(FLASH_MMU_TABLE_SIZE - 1)).rev() {
175 if (read_mmu_entry(i) & MMU_VALID) != 0 {
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_mmu_entry(i + mapped_pages, MMU_VALID + MMU_ACCESS_SPIRAM + i)
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}