瀏覽代碼

Configurable SDIO Wait States

androda 1 年之前
父節點
當前提交
45019c2657

+ 1 - 0
lib/BlueSCSI_platform_RP2040/BlueSCSI_platform.h

@@ -93,6 +93,7 @@ bool is202309a();
 // This can be used to implement simultaneous transfer to SCSI bus.
 typedef void (*sd_callback_t)(uint32_t bytes_complete);
 void platform_set_sd_callback(sd_callback_t func, const uint8_t *buffer);
+void add_extra_sdio_delay(uint16_t additional_delay);
 
 // Reprogram firmware in main program area.
 #ifndef RP2040_DISABLE_BOOTLOADER

+ 41 - 0
lib/BlueSCSI_platform_RP2040/rp2040_sdio.cpp

@@ -24,6 +24,12 @@
 #define SDIO_DMA_CH 4
 #define SDIO_DMA_CHB 5
 
+#define PIO_INSTR_MASK_REMOVE_DELAY 0xF8FF
+#define PIO_INSTR_MASK_GET_DELAY 0x700
+
+#define PIO_INSTR_JMP_MASK 0xE000
+#define PIO_INSTR_JMP_ADDR 0x1F
+
 // Maximum number of 512 byte blocks to transfer in one request
 #define SDIO_MAX_BLOCKS 256
 
@@ -931,3 +937,38 @@ void rp2040_sdio_init(int clock_divider)
     irq_set_enabled(DMA_IRQ_1, true);
 #endif
 }
+
+void rp2040_sdio_update_delays(pio_program program, uint32_t offset, uint16_t additional_delay) {
+    //log("Offset:", offset);
+    uint16_t instr_to_rewrite;
+    uint16_t existing_delay;
+    for (int i = 0; i < program.length; i++) {
+        instr_to_rewrite = program.instructions[i];
+        //log("Old Instr:", i, ":", (uint32_t)instr_to_rewrite);
+        if (instr_to_rewrite & PIO_INSTR_MASK_GET_DELAY) {  // If there's a delay, increment it.  Otherwise, leave it alone.
+            existing_delay = (instr_to_rewrite & PIO_INSTR_MASK_GET_DELAY) >> 8;
+            existing_delay += additional_delay;
+            instr_to_rewrite = (instr_to_rewrite & PIO_INSTR_MASK_REMOVE_DELAY) | (existing_delay << 8);
+
+            // Canonicalize JMP addresses
+            if ((instr_to_rewrite & PIO_INSTR_JMP_MASK) == 0) {  // Highest three bits are zero on a JMP
+                uint32_t jmp_address = instr_to_rewrite & PIO_INSTR_JMP_ADDR;
+                jmp_address += offset;
+                instr_to_rewrite = (instr_to_rewrite & (~ PIO_INSTR_JMP_ADDR)) | jmp_address;
+            }
+
+            //log("New Instr:", i, ":", (uint32_t)instr_to_rewrite);
+            SDIO_PIO->instr_mem[offset + i] = instr_to_rewrite;
+        }
+    }
+}
+
+void rp2040_sdio_delay_increment(uint16_t additional_delay) {
+    /*
+    Rewrite in-place every SDIO instruction for all the SDIO programs.
+    These additional delay cycles effectively decrease the SDIO clock rate, which can be helpful in electrically noisy environments.
+    */
+    rp2040_sdio_update_delays(cmd_rsp_program, g_sdio.pio_cmd_rsp_clk_offset, additional_delay);
+    rp2040_sdio_update_delays(rd_data_w_clock_program, g_sdio.pio_data_rx_offset, additional_delay);
+    rp2040_sdio_update_delays(sdio_tx_w_clock_program, g_sdio.pio_data_tx_offset, additional_delay);
+}

+ 3 - 0
lib/BlueSCSI_platform_RP2040/rp2040_sdio.h

@@ -58,3 +58,6 @@ sdio_status_t receive_status_register(uint8_t* sds);
 
 // (Re)initialize the SDIO interface
 void rp2040_sdio_init(int clock_divider = 1);
+
+// Adds extra clock delay as specified in additional_delay
+void rp2040_sdio_delay_increment(uint16_t additional_delay);

+ 4 - 0
lib/BlueSCSI_platform_RP2040/sd_card_sdio.cpp

@@ -45,6 +45,10 @@ void platform_set_sd_callback(sd_callback_t func, const uint8_t *buffer)
     m_stream_count_start = 0;
 }
 
+void add_extra_sdio_delay(uint16_t additional_delay) {
+    rp2040_sdio_delay_increment(additional_delay);
+}
+
 static sd_callback_t get_stream_callback(const uint8_t *buf, uint32_t count, const char *accesstype, uint32_t sector)
 {
     m_stream_count_start = m_stream_count;

+ 14 - 0
src/BlueSCSI.cpp

@@ -600,6 +600,20 @@ extern "C" void bluescsi_setup(void)
       log("SD card without filesystem!");
     }
 
+    long add_sdio_delay = ini_getl("SDIO", "AddClockDelay", 0, CONFIGFILE);
+    if (add_sdio_delay) {
+      if (add_sdio_delay < 0) {
+        add_sdio_delay = 0;
+        log("---- WARNING: Negative numbers are not valid for AddClockDelay. Setting value to 0");
+      }
+      if (add_sdio_delay > 2) {
+        add_sdio_delay = 2;
+        log("---- WARNING: Max value 2 exceeded for AddClockDelay. Setting value to 2.");
+      }
+      log("INFO: Injecting ", (uint16_t)add_sdio_delay, " additional wait state(s) on SDIO");
+      add_extra_sdio_delay((uint16_t) add_sdio_delay);
+    }
+
     print_sd_info();
   
     reinitSCSI();