diff options
| author | Magnus Nordlander <[email protected]> | 2025-08-05 12:52:20 +0200 |
|---|---|---|
| committer | Magnus Nordlander <[email protected]> | 2025-08-05 12:52:20 +0200 |
| commit | 88934c42d3b70d1da21808436daaeb7210580ab4 (patch) | |
| tree | 3d425654c8920e477b99c3d0ba8af1cc76708e18 /embassy-rp/src | |
| parent | 0e913319f240a96cef43fd0662f1759fbca8ac07 (diff) | |
Gate ARM-specific assembly using cfg
Diffstat (limited to 'embassy-rp/src')
| -rw-r--r-- | embassy-rp/src/psram.rs | 386 |
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 | } |
