aboutsummaryrefslogtreecommitdiff
path: root/embassy-rp/src
diff options
context:
space:
mode:
authorMagnus Nordlander <[email protected]>2025-08-05 12:52:20 +0200
committerMagnus Nordlander <[email protected]>2025-08-05 12:52:20 +0200
commit88934c42d3b70d1da21808436daaeb7210580ab4 (patch)
tree3d425654c8920e477b99c3d0ba8af1cc76708e18 /embassy-rp/src
parent0e913319f240a96cef43fd0662f1759fbca8ac07 (diff)
Gate ARM-specific assembly using cfg
Diffstat (limited to 'embassy-rp/src')
-rw-r--r--embassy-rp/src/psram.rs386
1 files changed, 200 insertions, 186 deletions
diff --git a/embassy-rp/src/psram.rs b/embassy-rp/src/psram.rs
index 0823b4be6..ae43dd5aa 100644
--- a/embassy-rp/src/psram.rs
+++ b/embassy-rp/src/psram.rs
@@ -255,8 +255,6 @@ impl<'d> Psram<'d> {
255 #[inline(never)] 255 #[inline(never)]
256 fn verify_aps6404l(qmi: &pac::qmi::Qmi, expected_size: usize) -> Result<(), Error> { 256 fn verify_aps6404l(qmi: &pac::qmi::Qmi, expected_size: usize) -> Result<(), Error> {
257 // APS6404L-specific constants 257 // APS6404L-specific constants
258 const RESET_ENABLE_CMD: u8 = 0xf5;
259 const READ_ID_CMD: u8 = 0x9f;
260 const EXPECTED_KGD: u8 = 0x5D; 258 const EXPECTED_KGD: u8 = 0x5D;
261 crate::multicore::pause_core1(); 259 crate::multicore::pause_core1();
262 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst); 260 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
@@ -279,126 +277,7 @@ impl<'d> Psram<'d> {
279 277
280 let _cs = unsafe { CriticalSection::new() }; 278 let _cs = unsafe { CriticalSection::new() };
281 279
282 let qmi_base = qmi.as_ptr() as usize; 280 let (kgd, eid) = unsafe { Self::read_aps6404l_kgd_eid(qmi) };
283
284 #[allow(unused_assignments)]
285 let mut kgd: u32 = 0;
286 #[allow(unused_assignments)]
287 let mut eid: u32 = 0;
288
289 unsafe {
290 core::arch::asm!(
291 // Configure DIRECT_CSR: shift clkdiv (30) to bits 29:22 and set EN (bit 0)
292 "movs {temp}, #30",
293 "lsls {temp}, {temp}, #22",
294 "orr {temp}, {temp}, #1", // Set EN bit
295 "str {temp}, [{qmi_base}]",
296
297 // Poll for BUSY to clear before first operation
298 "1:",
299 "ldr {temp}, [{qmi_base}]",
300 "lsls {temp}, {temp}, #30", // Shift BUSY bit to sign position
301 "bmi 1b", // Branch if negative (BUSY = 1)
302
303 // Assert CS1N (bit 3)
304 "ldr {temp}, [{qmi_base}]",
305 "orr {temp}, {temp}, #8", // Set ASSERT_CS1N bit (bit 3)
306 "str {temp}, [{qmi_base}]",
307
308 // Transmit RESET_ENABLE_CMD as quad
309 // DIRECT_TX: OE=1 (bit 19), IWIDTH=2 (bits 17:16), DATA=RESET_ENABLE_CMD
310 "movs {temp}, {reset_enable_cmd}",
311 "orr {temp}, {temp}, #0x80000", // Set OE (bit 19)
312 "orr {temp}, {temp}, #0x20000", // Set IWIDTH=2 (quad, bits 17:16)
313 "str {temp}, [{qmi_base}, #4]", // Store to DIRECT_TX
314
315 // Wait for BUSY to clear
316 "2:",
317 "ldr {temp}, [{qmi_base}]",
318 "lsls {temp}, {temp}, #30",
319 "bmi 2b",
320
321 // Read and discard RX data
322 "ldr {temp}, [{qmi_base}, #8]",
323
324 // Deassert CS1N
325 "ldr {temp}, [{qmi_base}]",
326 "bic {temp}, {temp}, #8", // Clear ASSERT_CS1N bit
327 "str {temp}, [{qmi_base}]",
328
329 // Assert CS1N again
330 "ldr {temp}, [{qmi_base}]",
331 "orr {temp}, {temp}, #8", // Set ASSERT_CS1N bit
332 "str {temp}, [{qmi_base}]",
333
334 // Read ID loop (7 iterations)
335 "movs {counter}, #0", // Initialize counter
336
337 "3:", // Loop start
338 "cmp {counter}, #0",
339 "bne 4f", // If not first iteration, send 0xFF
340
341 // First iteration: send READ_ID_CMD
342 "movs {temp}, {read_id_cmd}",
343 "b 5f",
344
345 "4:", // Other iterations: send 0xFF
346 "movs {temp}, #0xFF",
347
348 "5:",
349 "str {temp}, [{qmi_base}, #4]", // Store to DIRECT_TX
350
351 // Wait for TXEMPTY
352 "6:",
353 "ldr {temp}, [{qmi_base}]",
354 "lsls {temp}, {temp}, #20", // Shift TXEMPTY (bit 11) to bit 31
355 "bpl 6b", // Branch if positive (TXEMPTY = 0)
356
357 // Wait for BUSY to clear
358 "7:",
359 "ldr {temp}, [{qmi_base}]",
360 "lsls {temp}, {temp}, #30", // Shift BUSY bit to sign position
361 "bmi 7b", // Branch if negative (BUSY = 1)
362
363 // Read RX data
364 "ldr {temp}, [{qmi_base}, #8]",
365 "uxth {temp}, {temp}", // Extract lower 16 bits
366
367 // Store KGD or EID based on iteration
368 "cmp {counter}, #5",
369 "bne 8f",
370 "mov {kgd}, {temp}", // Store KGD
371 "b 9f",
372
373 "8:",
374 "cmp {counter}, #6",
375 "bne 9f",
376 "mov {eid}, {temp}", // Store EID
377
378 "9:",
379 "adds {counter}, #1",
380 "cmp {counter}, #7",
381 "blt 3b", // Continue loop if counter < 7
382
383 // Disable direct mode: clear EN and ASSERT_CS1N
384 "movs {temp}, #0",
385 "str {temp}, [{qmi_base}]",
386
387 // Memory barriers
388 "dmb",
389 "dsb",
390 "isb",
391
392 qmi_base = in(reg) qmi_base,
393 temp = out(reg) _,
394 counter = out(reg) _,
395 kgd = out(reg) kgd,
396 eid = out(reg) eid,
397 reset_enable_cmd = const RESET_ENABLE_CMD as u32,
398 read_id_cmd = const READ_ID_CMD as u32,
399 options(nostack),
400 );
401 }
402 281
403 let mut detected_size: u32 = 0; 282 let mut detected_size: u32 = 0;
404 if kgd == EXPECTED_KGD as u32 { 283 if kgd == EXPECTED_KGD as u32 {
@@ -427,6 +306,134 @@ impl<'d> Psram<'d> {
427 Ok(()) 306 Ok(())
428 } 307 }
429 308
309 #[link_section = ".data.ram_func"]
310 #[inline(never)]
311 unsafe fn read_aps6404l_kgd_eid(qmi: &pac::qmi::Qmi) -> (u32, u32) {
312 const RESET_ENABLE_CMD: u8 = 0xf5;
313 const READ_ID_CMD: u8 = 0x9f;
314
315 #[allow(unused_assignments)]
316 let mut kgd: u32 = 0;
317 #[allow(unused_assignments)]
318 let mut eid: u32 = 0;
319
320 let qmi_base = qmi.as_ptr() as usize;
321
322 #[cfg(target_arch = "arm")]
323 core::arch::asm!(
324 // Configure DIRECT_CSR: shift clkdiv (30) to bits 29:22 and set EN (bit 0)
325 "movs {temp}, #30",
326 "lsls {temp}, {temp}, #22",
327 "orr {temp}, {temp}, #1", // Set EN bit
328 "str {temp}, [{qmi_base}]",
329
330 // Poll for BUSY to clear before first operation
331 "1:",
332 "ldr {temp}, [{qmi_base}]",
333 "lsls {temp}, {temp}, #30", // Shift BUSY bit to sign position
334 "bmi 1b", // Branch if negative (BUSY = 1)
335
336 // Assert CS1N (bit 3)
337 "ldr {temp}, [{qmi_base}]",
338 "orr {temp}, {temp}, #8", // Set ASSERT_CS1N bit (bit 3)
339 "str {temp}, [{qmi_base}]",
340
341 // Transmit RESET_ENABLE_CMD as quad
342 // DIRECT_TX: OE=1 (bit 19), IWIDTH=2 (bits 17:16), DATA=RESET_ENABLE_CMD
343 "movs {temp}, {reset_enable_cmd}",
344 "orr {temp}, {temp}, #0x80000", // Set OE (bit 19)
345 "orr {temp}, {temp}, #0x20000", // Set IWIDTH=2 (quad, bits 17:16)
346 "str {temp}, [{qmi_base}, #4]", // Store to DIRECT_TX
347
348 // Wait for BUSY to clear
349 "2:",
350 "ldr {temp}, [{qmi_base}]",
351 "lsls {temp}, {temp}, #30",
352 "bmi 2b",
353
354 // Read and discard RX data
355 "ldr {temp}, [{qmi_base}, #8]",
356
357 // Deassert CS1N
358 "ldr {temp}, [{qmi_base}]",
359 "bic {temp}, {temp}, #8", // Clear ASSERT_CS1N bit
360 "str {temp}, [{qmi_base}]",
361
362 // Assert CS1N again
363 "ldr {temp}, [{qmi_base}]",
364 "orr {temp}, {temp}, #8", // Set ASSERT_CS1N bit
365 "str {temp}, [{qmi_base}]",
366
367 // Read ID loop (7 iterations)
368 "movs {counter}, #0", // Initialize counter
369
370 "3:", // Loop start
371 "cmp {counter}, #0",
372 "bne 4f", // If not first iteration, send 0xFF
373
374 // First iteration: send READ_ID_CMD
375 "movs {temp}, {read_id_cmd}",
376 "b 5f",
377 "4:", // Other iterations: send 0xFF
378 "movs {temp}, #0xFF",
379 "5:",
380 "str {temp}, [{qmi_base}, #4]", // Store to DIRECT_TX
381
382 // Wait for TXEMPTY
383 "6:",
384 "ldr {temp}, [{qmi_base}]",
385 "lsls {temp}, {temp}, #20", // Shift TXEMPTY (bit 11) to bit 31
386 "bpl 6b", // Branch if positive (TXEMPTY = 0)
387
388 // Wait for BUSY to clear
389 "7:",
390 "ldr {temp}, [{qmi_base}]",
391 "lsls {temp}, {temp}, #30", // Shift BUSY bit to sign position
392 "bmi 7b", // Branch if negative (BUSY = 1)
393
394 // Read RX data
395 "ldr {temp}, [{qmi_base}, #8]",
396 "uxth {temp}, {temp}", // Extract lower 16 bits
397
398 // Store KGD or EID based on iteration
399 "cmp {counter}, #5",
400 "bne 8f",
401 "mov {kgd}, {temp}", // Store KGD
402 "b 9f",
403 "8:",
404 "cmp {counter}, #6",
405 "bne 9f",
406 "mov {eid}, {temp}", // Store EID
407
408 "9:",
409 "adds {counter}, #1",
410 "cmp {counter}, #7",
411 "blt 3b", // Continue loop if counter < 7
412
413 // Disable direct mode: clear EN and ASSERT_CS1N
414 "movs {temp}, #0",
415 "str {temp}, [{qmi_base}]",
416
417 // Memory barriers
418 "dmb",
419 "dsb",
420 "isb",
421 qmi_base = in(reg) qmi_base,
422 temp = out(reg) _,
423 counter = out(reg) _,
424 kgd = out(reg) kgd,
425 eid = out(reg) eid,
426 reset_enable_cmd = const RESET_ENABLE_CMD as u32,
427 read_id_cmd = const READ_ID_CMD as u32,
428 options(nostack),
429 );
430
431 #[cfg(target_arch = "riscv32")]
432 unimplemented!("APS6404L PSRAM verification not implemented for RISC-V");
433
434 (kgd, eid)
435 }
436
430 /// Initialize PSRAM with proper timing. 437 /// Initialize PSRAM with proper timing.
431 #[link_section = ".data.ram_func"] 438 #[link_section = ".data.ram_func"]
432 #[inline(never)] 439 #[inline(never)]
@@ -476,70 +483,7 @@ impl<'d> Psram<'d> {
476 483
477 let _cs = unsafe { CriticalSection::new() }; 484 let _cs = unsafe { CriticalSection::new() };
478 485
479 unsafe { 486 unsafe { Self::direct_csr_send_init_command(config, enter_quad_cmd) };
480 core::arch::asm!(
481 // Full memory barrier
482 "dmb",
483 "dsb",
484 "isb",
485
486 // Configure QMI Direct CSR register
487 // Load base address of QMI (0x400D0000)
488 "movw {base}, #0x0000",
489 "movt {base}, #0x400D",
490
491 // Load init_clkdiv and shift to bits 29:22
492 "lsl {temp}, {clkdiv}, #22",
493
494 // OR with EN (bit 0) and AUTO_CS1N (bit 7)
495 "orr {temp}, {temp}, #0x81",
496
497 // Store to DIRECT_CSR register
498 "str {temp}, [{base}, #0]",
499
500 // Memory barrier
501 "dmb",
502
503 // First busy wait loop
504 "1:",
505 "ldr {temp}, [{base}, #0]", // Load DIRECT_CSR
506 "tst {temp}, #0x2", // Test BUSY bit (bit 1)
507 "bne 1b", // Branch if busy
508
509 // Write to Direct TX register
510 "mov {temp}, {enter_quad_cmd}",
511
512 // OR with NOPUSH (bit 20)
513 "orr {temp}, {temp}, #0x100000",
514
515 // Store to DIRECT_TX register (offset 0x4)
516 "str {temp}, [{base}, #4]",
517
518 // Memory barrier
519 "dmb",
520
521 // Second busy wait loop
522 "2:",
523 "ldr {temp}, [{base}, #0]", // Load DIRECT_CSR
524 "tst {temp}, #0x2", // Test BUSY bit (bit 1)
525 "bne 2b", // Branch if busy
526
527 // Disable Direct CSR
528 "mov {temp}, #0",
529 "str {temp}, [{base}, #0]", // Clear DIRECT_CSR register
530
531 // Full memory barrier to ensure no prefetching
532 "dmb",
533 "dsb",
534 "isb",
535
536 base = out(reg) _,
537 temp = out(reg) _,
538 clkdiv = in(reg) config.init_clkdiv as u32,
539 enter_quad_cmd = in(reg) u32::from(enter_quad_cmd),
540 options(nostack),
541 );
542 }
543 487
544 qmi.mem(1).timing().write(|w| { 488 qmi.mem(1).timing().write(|w| {
545 w.set_cooldown(config.cooldown); 489 w.set_cooldown(config.cooldown);
@@ -665,4 +609,74 @@ impl<'d> Psram<'d> {
665 609
666 Ok(()) 610 Ok(())
667 } 611 }
612
613 #[link_section = ".data.ram_func"]
614 #[inline(never)]
615 unsafe fn direct_csr_send_init_command(config: &Config, init_cmd: u8) {
616 #[cfg(target_arch = "arm")]
617 core::arch::asm!(
618 // Full memory barrier
619 "dmb",
620 "dsb",
621 "isb",
622
623 // Configure QMI Direct CSR register
624 // Load base address of QMI (0x400D0000)
625 "movw {base}, #0x0000",
626 "movt {base}, #0x400D",
627
628 // Load init_clkdiv and shift to bits 29:22
629 "lsl {temp}, {clkdiv}, #22",
630
631 // OR with EN (bit 0) and AUTO_CS1N (bit 7)
632 "orr {temp}, {temp}, #0x81",
633
634 // Store to DIRECT_CSR register
635 "str {temp}, [{base}, #0]",
636
637 // Memory barrier
638 "dmb",
639
640 // First busy wait loop
641 "1:",
642 "ldr {temp}, [{base}, #0]", // Load DIRECT_CSR
643 "tst {temp}, #0x2", // Test BUSY bit (bit 1)
644 "bne 1b", // Branch if busy
645
646 // Write to Direct TX register
647 "mov {temp}, {enter_quad_cmd}",
648
649 // OR with NOPUSH (bit 20)
650 "orr {temp}, {temp}, #0x100000",
651
652 // Store to DIRECT_TX register (offset 0x4)
653 "str {temp}, [{base}, #4]",
654
655 // Memory barrier
656 "dmb",
657
658 // Second busy wait loop
659 "2:",
660 "ldr {temp}, [{base}, #0]", // Load DIRECT_CSR
661 "tst {temp}, #0x2", // Test BUSY bit (bit 1)
662 "bne 2b", // Branch if busy
663
664 // Disable Direct CSR
665 "mov {temp}, #0",
666 "str {temp}, [{base}, #0]", // Clear DIRECT_CSR register
667
668 // Full memory barrier to ensure no prefetching
669 "dmb",
670 "dsb",
671 "isb",
672 base = out(reg) _,
673 temp = out(reg) _,
674 clkdiv = in(reg) config.init_clkdiv as u32,
675 enter_quad_cmd = in(reg) u32::from(init_cmd),
676 options(nostack),
677 );
678
679 #[cfg(target_arch = "riscv32")]
680 unimplemented!("Direct CSR command sending is not implemented for RISC-V yet");
681 }
668} 682}