diff --git a/libn3ds/include/drivers/mmc/mmc_spec.h b/libn3ds/include/drivers/mmc/mmc_spec.h index d33e0d3..d4f1ed8 100644 --- a/libn3ds/include/drivers/mmc/mmc_spec.h +++ b/libn3ds/include/drivers/mmc/mmc_spec.h @@ -26,7 +26,7 @@ // Controller specific macros. Add controller specific bits here. // MMC_CMD_[response type]_[transfer type] -// Transfer type: R = read, MR = multi-block read, W = write, MW = multi-block write. +// Transfer type: R = read, W = write. #define MMC_CMD_NONE(id) (CMD_RESP_NONE | (id)) #define MMC_CMD_R1(id) (CMD_RESP_R1 | (id)) #define MMC_CMD_R1b(id) (CMD_RESP_R1b | (id)) @@ -36,69 +36,67 @@ #define MMC_CMD_R5(id) (CMD_RESP_R5 | (id)) #define MMC_CMD_R1_R(id) (CMD_DIR_R | CMD_DT_EN | CMD_RESP_R1 | (id)) #define MMC_CMD_R1_W(id) (CMD_DIR_W | CMD_DT_EN | CMD_RESP_R1 | (id)) -#define MMC_CMD_R1_MR(id) (CMD_MBT | CMD_DIR_R | CMD_DT_EN | CMD_RESP_R1 | (id)) -#define MMC_CMD_R1_MW(id) (CMD_MBT | CMD_DIR_W | CMD_DT_EN | CMD_RESP_R1 | (id)) // Basic commands and read-stream command (class 0 and class 1). -#define MMC_GO_IDLE_STATE MMC_CMD_NONE(0u) // -, [31:0] 0x00000000 GO_IDLE_STATE, 0xF0F0F0F0 GO_PRE_IDLE_STATE, 0xFFFFFFFA BOOT_INITIATION. -#define MMC_SEND_OP_COND MMC_CMD_R3(1u) // R3, [31:0] OCR with-out busy. -#define MMC_ALL_SEND_CID MMC_CMD_R2(2u) // R2, [31:0] stuff bits. -#define MMC_SET_RELATIVE_ADDR MMC_CMD_R1(3u) // R1, [31:16] RCA [15:0] stuff bits. -#define MMC_SET_DSR MMC_CMD_NONE(4u) // -, [31:16] DSR [15:0] stuff bits. -#define MMC_SLEEP_AWAKE MMC_CMD_R1b(5u) // R1b, [31:16] RCA [15] Sleep/Awake [14:0] stuff bits. -#define MMC_SWITCH MMC_CMD_R1b(6u) // R1b, [31:26] Set to 0 [25:24] Access [23:16] Index [15:8] Value [7:3] Set to 0 [2:0] Cmd Set. -#define MMC_SELECT_CARD MMC_CMD_R1(7u) // R1, [31:16] RCA [15:0] stuff bits. -#define MMC_DESELECT_CARD MMC_CMD_NONE(7u) // -, [31:16] RCA [15:0] stuff bits. -#define MMC_SELECT_CARD_R1b MMC_CMD_R1b(7u) // R1b, [31:16] RCA [15:0] stuff bits. -#define MMC_SEND_EXT_CSD MMC_CMD_R1_R(8u) // R1, [31:0] stuff bits. -#define MMC_SEND_CSD MMC_CMD_R2(9u) // R2, [31:16] RCA [15:0] stuff bits. -#define MMC_SEND_CID MMC_CMD_R2(10u) // R2, [31:16] RCA [15:0] stuff bits. -#define MMC_READ_DAT_UNTIL_STOP MMC_CMD_R1_MR(11u) // R1, [31:0] data address. -#define MMC_STOP_TRANSMISSION_R MMC_CMD_R1(12u) // R1, [31:16] RCA [15:1] stuff bits [0] HPI. -#define MMC_STOP_TRANSMISSION_W MMC_CMD_R1b(12u) // R1b, [31:16] RCA [15:1] stuff bits [0] HPI. -#define MMC_SEND_STATUS MMC_CMD_R1(13u) // R1, [31:16] RCA [15:1] stuff bits [0] HPI. -#define MMC_BUSTEST_R MMC_CMD_R1_R(14u) // R1, [31:0] stuff bits. -#define MMC_GO_INACTIVE_STATE MMC_CMD_NONE(15u) // -, [31:16] RCA [15:0] stuff bits. -#define MMC_BUSTEST_W MMC_CMD_R1_W(19u) // R1, [31:0] stuff bits. +#define MMC_GO_IDLE_STATE MMC_CMD_NONE(0u) // -, [31:0] 0x00000000 GO_IDLE_STATE, 0xF0F0F0F0 GO_PRE_IDLE_STATE, 0xFFFFFFFA BOOT_INITIATION. +#define MMC_SEND_OP_COND MMC_CMD_R3(1u) // R3, [31:0] OCR with-out busy. +#define MMC_ALL_SEND_CID MMC_CMD_R2(2u) // R2, [31:0] stuff bits. +#define MMC_SET_RELATIVE_ADDR MMC_CMD_R1(3u) // R1, [31:16] RCA [15:0] stuff bits. +#define MMC_SET_DSR MMC_CMD_NONE(4u) // -, [31:16] DSR [15:0] stuff bits. +#define MMC_SLEEP_AWAKE MMC_CMD_R1b(5u) // R1b, [31:16] RCA [15] Sleep/Awake [14:0] stuff bits. +#define MMC_SWITCH MMC_CMD_R1b(6u) // R1b, [31:26] Set to 0 [25:24] Access [23:16] Index [15:8] Value [7:3] Set to 0 [2:0] Cmd Set. +#define MMC_SELECT_CARD MMC_CMD_R1(7u) // R1, [31:16] RCA [15:0] stuff bits. +#define MMC_DESELECT_CARD MMC_CMD_NONE(7u) // -, [31:16] RCA [15:0] stuff bits. +#define MMC_SELECT_CARD_R1b MMC_CMD_R1b(7u) // R1b, [31:16] RCA [15:0] stuff bits. +#define MMC_SEND_EXT_CSD MMC_CMD_R1_R(8u) // R1, [31:0] stuff bits. +#define MMC_SEND_CSD MMC_CMD_R2(9u) // R2, [31:16] RCA [15:0] stuff bits. +#define MMC_SEND_CID MMC_CMD_R2(10u) // R2, [31:16] RCA [15:0] stuff bits. +#define MMC_READ_DAT_UNTIL_STOP MMC_CMD_R1_R(11u) // R1, [31:0] data address. +#define MMC_STOP_TRANSMISSION_R MMC_CMD_R1(12u) // R1, [31:16] RCA [15:1] stuff bits [0] HPI. +#define MMC_STOP_TRANSMISSION_W MMC_CMD_R1b(12u) // R1b, [31:16] RCA [15:1] stuff bits [0] HPI. +#define MMC_SEND_STATUS MMC_CMD_R1(13u) // R1, [31:16] RCA [15:1] stuff bits [0] HPI. +#define MMC_BUSTEST_R MMC_CMD_R1_R(14u) // R1, [31:0] stuff bits. +#define MMC_GO_INACTIVE_STATE MMC_CMD_NONE(15u) // -, [31:16] RCA [15:0] stuff bits. +#define MMC_BUSTEST_W MMC_CMD_R1_W(19u) // R1, [31:0] stuff bits. // Block-oriented read commands (class 2). -#define MMC_SET_BLOCKLEN MMC_CMD_R1(16u) // R1, [31:0] block length. -#define MMC_READ_SINGLE_BLOCK MMC_CMD_R1_R(17u) // R1, [31:0] data address. -#define MMC_READ_MULTIPLE_BLOCK MMC_CMD_R1_MR(18u) // R1, [31:0] data address. +#define MMC_SET_BLOCKLEN MMC_CMD_R1(16u) // R1, [31:0] block length. +#define MMC_READ_SINGLE_BLOCK MMC_CMD_R1_R(17u) // R1, [31:0] data address. +#define MMC_READ_MULTIPLE_BLOCK MMC_CMD_R1_R(18u) // R1, [31:0] data address. // Stream write commands (class 3). -#define MMC_WRITE_DAT_UNTIL_STOP MMC_CMD_R1_MW(20u) // R1, [31:0] data address. +#define MMC_WRITE_DAT_UNTIL_STOP MMC_CMD_R1_W(20u) // R1, [31:0] data address. // Block-oriented write commands (class 4). -#define MMC_SET_BLOCK_COUNT MMC_CMD_R1(23u) // R1, [31] Reliable Write Request [30:16] set to 0 [15:0] number of blocks. -#define MMC_WRITE_BLOCK MMC_CMD_R1_W(24u) // R1, [31:0] data address. -#define MMC_WRITE_MULTIPLE_BLOCK MMC_CMD_R1_MW(25u) // R1, [31:0] data address. -#define MMC_PROGRAM_CID MMC_CMD_R1_W(26u) // R1, [31:0] stuff bits. -#define MMC_PROGRAM_CSD MMC_CMD_R1_W(27u) // R1, [31:0] stuff bits. +#define MMC_SET_BLOCK_COUNT MMC_CMD_R1(23u) // R1, [31] Reliable Write Request [30:16] set to 0 [15:0] number of blocks. +#define MMC_WRITE_BLOCK MMC_CMD_R1_W(24u) // R1, [31:0] data address. +#define MMC_WRITE_MULTIPLE_BLOCK MMC_CMD_R1_W(25u) // R1, [31:0] data address. +#define MMC_PROGRAM_CID MMC_CMD_R1_W(26u) // R1, [31:0] stuff bits. +#define MMC_PROGRAM_CSD MMC_CMD_R1_W(27u) // R1, [31:0] stuff bits. // Block-oriented write protection commands (class 6). -#define MMC_SET_WRITE_PROT MMC_CMD_R1b(28u) // R1b, [31:0] data address. -#define MMC_CLR_WRITE_PROT MMC_CMD_R1b(29u) // R1b, [31:0] data address. -#define MMC_SEND_WRITE_PROT MMC_CMD_R1_R(30u) // R1, [31:0] write protect data address. -#define MMC_SEND_WRITE_PROT_TYPE MMC_CMD_R1_R(31u) // R1, [31:0] write protect data address. +#define MMC_SET_WRITE_PROT MMC_CMD_R1b(28u) // R1b, [31:0] data address. +#define MMC_CLR_WRITE_PROT MMC_CMD_R1b(29u) // R1b, [31:0] data address. +#define MMC_SEND_WRITE_PROT MMC_CMD_R1_R(30u) // R1, [31:0] write protect data address. +#define MMC_SEND_WRITE_PROT_TYPE MMC_CMD_R1_R(31u) // R1, [31:0] write protect data address. // Erase commands (class 5). -#define MMC_ERASE_GROUP_START MMC_CMD_R1(35u) // R1, [31:0] data address. -#define MMC_ERASE_GROUP_END MMC_CMD_R1(36u) // R1, [31:0] data address. -#define MMC_ERASE MMC_CMD_R1b(38u) // R1b, [31] Secure request [30:16] set to 0 [15] Force Garbage Collect request [14:1] set to 0 [0] Identify Write block for Erase. +#define MMC_ERASE_GROUP_START MMC_CMD_R1(35u) // R1, [31:0] data address. +#define MMC_ERASE_GROUP_END MMC_CMD_R1(36u) // R1, [31:0] data address. +#define MMC_ERASE MMC_CMD_R1b(38u) // R1b, [31] Secure request [30:16] set to 0 [15] Force Garbage Collect request [14:1] set to 0 [0] Identify Write block for Erase. // I/O mode commands (class 9). -#define MMC_FAST_IO MMC_CMD_R4(39u) // R4, [31:16] RCA [15:15] register write flag [14:8] register address [7:0] register data. -#define MMC_GO_IRQ_STATE MMC_CMD_R5(40u) // R5, [31:0] stuff bits. +#define MMC_FAST_IO MMC_CMD_R4(39u) // R4, [31:16] RCA [15:15] register write flag [14:8] register address [7:0] register data. +#define MMC_GO_IRQ_STATE MMC_CMD_R5(40u) // R5, [31:0] stuff bits. // Lock card commands (class 7). -#define MMC_LOCK_UNLOCK MMC_CMD_R1_W(42u) // R1, [31:0] stuff bits. +#define MMC_LOCK_UNLOCK MMC_CMD_R1_W(42u) // R1, [31:0] stuff bits. // Application-specific commands (class 8). -#define MMC_APP_CMD MMC_CMD_R1(55u) // R1, [31:16] RCA [15:0] stuff bits. -#define MMC_GEN_CMD_R MMC_CMD_R1_R(56u) // R1, [31:1] stuff bits [0] RD/WR = 1. -#define MMC_GEN_CMD_W MMC_CMD_R1_W(56u) // R1, [31:1] stuff bits [0] RD/WR = 0. +#define MMC_APP_CMD MMC_CMD_R1(55u) // R1, [31:16] RCA [15:0] stuff bits. +#define MMC_GEN_CMD_R MMC_CMD_R1_R(56u) // R1, [31:1] stuff bits [0] RD/WR = 1. +#define MMC_GEN_CMD_W MMC_CMD_R1_W(56u) // R1, [31:1] stuff bits [0] RD/WR = 0. // 7.13 Card status. diff --git a/libn3ds/include/drivers/mmc/sd_spec.h b/libn3ds/include/drivers/mmc/sd_spec.h index 5854897..ca2d694 100644 --- a/libn3ds/include/drivers/mmc/sd_spec.h +++ b/libn3ds/include/drivers/mmc/sd_spec.h @@ -26,7 +26,7 @@ // Controller specific macros. Add controller specific bits here. // SD_[command type]_[response type]_[transfer type] // Command type: CMD = regular command, ACMD = Application-Specific Command. -// Transfer type: R = read, MR = multi-block read, W = write, MW = multi-block write. +// Transfer type: R = read, W = write. #define SD_CMD_NONE(id) (CMD_RESP_NONE | (id)) #define SD_CMD_R1(id) (CMD_RESP_R1 | (id)) #define SD_CMD_R1b(id) (CMD_RESP_R1b | (id)) @@ -35,8 +35,6 @@ #define SD_CMD_R7(id) (CMD_RESP_R7 | (id)) #define SD_CMD_R1_R(id) (CMD_DIR_R | CMD_DT_EN | CMD_RESP_R1 | (id)) #define SD_CMD_R1_W(id) (CMD_DIR_W | CMD_DT_EN | CMD_RESP_R1 | (id)) -#define SD_CMD_R1_MR(id) (CMD_MBT | CMD_DIR_R | CMD_DT_EN | CMD_RESP_R1 | (id)) -#define SD_CMD_R1_MW(id) (CMD_MBT | CMD_DIR_W | CMD_DT_EN | CMD_RESP_R1 | (id)) #define SD_ACMD_R1(id) (CMD_RESP_R1 | CMD_ACMD | (id)) #define SD_ACMD_R3(id) (CMD_RESP_R3 | CMD_ACMD | (id)) #define SD_ACMD_R1_R(id) (CMD_DIR_R | CMD_DT_EN | CMD_RESP_R1 | CMD_ACMD | (id)) @@ -61,7 +59,7 @@ // Block-Oriented Read Commands (class 2). #define SD_SET_BLOCKLEN SD_CMD_R1(16u) // R1, [31:0] block length. #define SD_READ_SINGLE_BLOCK SD_CMD_R1_R(17u) // R1, [31:0] data address. -#define SD_READ_MULTIPLE_BLOCK SD_CMD_R1_MR(18u) // R1, [31:0] data address. +#define SD_READ_MULTIPLE_BLOCK SD_CMD_R1_R(18u) // R1, [31:0] data address. #define SD_SEND_TUNING_BLOCK SD_CMD_R1_R(19u) // R1, [31:0] reserved bits (all 0). #define SD_SPEED_CLASS_CONTROL SD_CMD_R1b(20u) // R1b, [31:28] Speed Class Control [27:0] See command description. #define SD_ADDRESS_EXTENSION SD_CMD_R1(22u) // R1, [31:6] reserved bits (all 0) [5:0] extended address. @@ -73,7 +71,7 @@ // ADDRESS_EXTENSION // SET_BLOCK_COUNT #define SD_WRITE_BLOCK SD_CMD_R1_W(24u) // R1, [31:0] data address. -#define SD_WRITE_MULTIPLE_BLOCK SD_CMD_R1_MW(25u) // R1, [31:0] data address. +#define SD_WRITE_MULTIPLE_BLOCK SD_CMD_R1_W(25u) // R1, [31:0] data address. #define SD_PROGRAM_CSD SD_CMD_R1_W(27u) // R1, [31:0] stuff bits. // Block Oriented Write Protection Commands (class 6). @@ -111,8 +109,8 @@ // Function Extension Commands (class 11). #define SD_READ_EXTR_SINGLE SD_CMD_R1_R(48u) // R1, [31] MIO0: Memory, 1: I/O [30:27] FNO[26] Reserved (=0) [25:9] ADDR [8:0] LEN. #define SD_WRITE_EXTR_SINGLE SD_CMD_R1_W(49u) // R1, [31] MIO0: Memory, 1: I/O [30:27] FNO [26] MW [25:9] ADDR [8:0] LEN/MASK. -#define SD_READ_EXTR_MULTI SD_CMD_R1_MR(58u) // R1, [31] MIO0: Memory, 1: I/O [30:27] FNO [26] BUS0: 512B, 1: 32KB [25:9] ADDR [8:0] BUC. -#define SD_WRITE_EXTR_MULTI SD_CMD_R1_MW(59u) // R1, [31] MIO0: Memory, 1: I/O [30:27] FNO [26] BUS0: 512B, 1: 32KB [25:9] ADDR [8:0] BUC. +#define SD_READ_EXTR_MULTI SD_CMD_R1_R(58u) // R1, [31] MIO0: Memory, 1: I/O [30:27] FNO [26] BUS0: 512B, 1: 32KB [25:9] ADDR [8:0] BUC. +#define SD_WRITE_EXTR_MULTI SD_CMD_R1_W(59u) // R1, [31] MIO0: Memory, 1: I/O [30:27] FNO [26] BUS0: 512B, 1: 32KB [25:9] ADDR [8:0] BUC. // Command Queue Function Commands (class 1). #define SD_Q_MANAGEMENT SD_CMD_R1b(43u) // R1b, [31:21] Reserved [20:16]: Task ID [3:0]: Operation Code (Abort tasks etc.). diff --git a/libn3ds/include/drivers/toshsd.h b/libn3ds/include/drivers/toshsd.h index 8bf6ed5..3ef520e 100644 --- a/libn3ds/include/drivers/toshsd.h +++ b/libn3ds/include/drivers/toshsd.h @@ -120,8 +120,8 @@ ALWAYS_INLINE vu32* getToshsdFifo(Toshsd *const regs) #define PORTSEL_UNK10 (1u<<10) // Unknown writable bit 10? // REG_SD_STOP -#define STOP_STOP (1u) // Stop/abort a transfer. -#define STOP_AUTO_STOP (1u<<8) // Automatically send CMD12 on block transfer end. +#define STOP_STOP (1u) // Abort data transfer and send STOP_TRANSMISSION CMD. +#define STOP_AUTO_STOP (1u<<8) // Automatically send STOP_TRANSMISSION on multi-block transfer end. // REG_SD_STATUS1/2 Write 0 to acknowledge a bit. // REG_SD_STATUS1/2_MASK (M) = Maskable bit. 1 = disabled. diff --git a/libn3ds/source/drivers/mmc/sdmmc.c b/libn3ds/source/drivers/mmc/sdmmc.c index 49774ae..9051d61 100644 --- a/libn3ds/source/drivers/mmc/sdmmc.c +++ b/libn3ds/source/drivers/mmc/sdmmc.c @@ -60,11 +60,11 @@ #endif // #ifdef _3DS -#define SD_IF_COND_ARG (SD_CMD8_VHS_2_7_3_6V | SD_CMD8_CHK_PATT) -#define SD_OP_COND_ARG (SD_ACMD41_XPC | SD_OCR_3_2_3_3V) // We support 150 mA and 3.3V. Without HCS bit. -#define MMC_OP_COND_ARG (MMC_OCR_SECT_MODE | MMC_OCR_3_2_3_3V) // We support sector addressing and 3.3V. #define MMC_OCR_VOLT_MASK (MMC_OCR_3_2_3_3V) // We support 3.3V only. #define SD_OCR_VOLT_MASK (SD_OCR_3_2_3_3V) // We support 3.3V only. +#define SD_IF_COND_ARG (SD_CMD8_VHS_2_7_3_6V | SD_CMD8_CHK_PATT) +#define SD_OP_COND_ARG (SD_ACMD41_XPC | SD_OCR_VOLT_MASK) // We support 150 mA and 3.3V. Without HCS bit. +#define MMC_OP_COND_ARG (MMC_OCR_SECT_MODE | MMC_OCR_VOLT_MASK) // We support sector addressing and 3.3V. // Note: DEV_TYPE_NONE must be zero. enum @@ -384,7 +384,7 @@ static u32 initTranState(SdmmcDev *const dev, const u8 devType, const u32 rca, c // Get sector count from EXT_CSD only if sector addressing is used because // byte addressed (e)MMC may set sector count to 0. dev->sectors = ext_csd[EXT_CSD_SEC_COUNT + 3]<<24 | ext_csd[EXT_CSD_SEC_COUNT + 2]<<16 | - ext_csd[EXT_CSD_SEC_COUNT + 1]<<8 | ext_csd[EXT_CSD_SEC_COUNT + 0]; + ext_csd[EXT_CSD_SEC_COUNT + 1]<<8 | ext_csd[EXT_CSD_SEC_COUNT + 0]; } } } diff --git a/libn3ds/source/drivers/toshsd.c b/libn3ds/source/drivers/toshsd.c index 13191f7..e0fc350 100644 --- a/libn3ds/source/drivers/toshsd.c +++ b/libn3ds/source/drivers/toshsd.c @@ -22,6 +22,12 @@ #include "drivers/toshsd_config.h" +// Using atomic load/store produces better code than volatile +// but still ensures that the status is always read from memory. +#define GET_STATUS(ptr) atomic_load_explicit((ptr), memory_order_relaxed) +#define SET_STATUS(ptr, val) atomic_store_explicit((ptr), (val), memory_order_relaxed) + + static u32 g_status[2] = {0}; @@ -31,14 +37,9 @@ ALWAYS_INLINE u8 port2Controller(const u8 portNum) return portNum / 2; } -ALWAYS_INLINE u8 irq2controller(const u32 id) -{ - return (id == TOSHSD_IRQ_ID_CONTROLLER1 ? 0 : 1); -} - static void toshsdIsr(const u32 id) { - const u8 controller = irq2controller(id); + const u8 controller = (id == TOSHSD_IRQ_ID_CONTROLLER1 ? 0 : 1); Toshsd *const regs = getToshsdRegs(controller); g_status[controller] |= regs->sd_status; @@ -67,6 +68,9 @@ void TOSHSD_init(void) regs->dma_ext_mode = DMA_EXT_DMA_MODE; // Reset. Unlike similar controllers no delay is needed. + // Resets the following regs: + // REG_SD_STOP, REG_SD_RESP0-7, REG_SD_STATUS1-2, REG_SD_ERR_STATUS1-2, + // REG_SD_CLK_CTRL, REG_SD_OPTION, REG_SDIO_STATUS. regs->soft_rst = SOFT_RST_RST; regs->soft_rst = SOFT_RST_NORST; @@ -175,8 +179,8 @@ static void getResponse(const Toshsd *const regs, ToshsdPort *const port, const // single block read transfer. static void doCpuTransfer(Toshsd *const regs, const u16 cmd, u32 *buf, const u32 *const statusPtr) { - const u32 blockLen = regs->sd_blocklen; - u32 blockCount = regs->sd_blockcount; + const u32 wordBlockLen = regs->sd_blocklen / 4; + u32 blockCount = regs->sd_blockcount; vu32 *const fifo = getToshsdFifo(regs); if(cmd & CMD_DIR_R) { @@ -185,20 +189,18 @@ static void doCpuTransfer(Toshsd *const regs, const u16 cmd, u32 *buf, const u32 __wfi(); if(regs->sd_fifo32_cnt & FIFO32_FULL) // RX ready. { - const u32 *const blockEnd = buf + (blockLen / 4); + const u32 *const blockEnd = buf + wordBlockLen; do { - buf[0] = *fifo; - buf[1] = *fifo; - buf[2] = *fifo; - buf[3] = *fifo; - - buf += 4; + *buf++ = *fifo; + *buf++ = *fifo; + *buf++ = *fifo; + *buf++ = *fifo; } while(buf < blockEnd); blockCount--; } - } while((atomic_load_explicit(statusPtr, memory_order_relaxed) & STATUS_MASK_ERR) == 0 && blockCount); + } while((GET_STATUS(statusPtr) & STATUS_MASK_ERR) == 0 && blockCount > 0); } else { @@ -209,20 +211,18 @@ static void doCpuTransfer(Toshsd *const regs, const u16 cmd, u32 *buf, const u32 __wfi(); if(!(regs->sd_fifo32_cnt & FIFO32_NOT_EMPTY)) // TX request. { - const u32 *const blockEnd = buf + (blockLen / 4); + const u32 *const blockEnd = buf + wordBlockLen; do { - *fifo = buf[0]; - *fifo = buf[1]; - *fifo = buf[2]; - *fifo = buf[3]; - - buf += 4; + *fifo = *buf++; + *fifo = *buf++; + *fifo = *buf++; + *fifo = *buf++; } while(buf < blockEnd); blockCount--; } - } while((atomic_load_explicit(statusPtr, memory_order_relaxed) & STATUS_MASK_ERR) == 0 && blockCount); + } while((GET_STATUS(statusPtr) & STATUS_MASK_ERR) == 0 && blockCount > 0); } } @@ -233,18 +233,20 @@ u32 TOSHSD_sendCommand(ToshsdPort *const port, const u16 cmd, const u32 arg) // Clear status before sending another command. u32 *const statusPtr = &g_status[controller]; - atomic_store_explicit(statusPtr, 0, memory_order_relaxed); + SET_STATUS(statusPtr, 0); setPort(regs, port); - regs->sd_blockcount = port->blocks; // sd_blockcount32 doesn't need to be set. - regs->sd_stop = ((cmd & CMD_MBT) ? STOP_AUTO_STOP : 0); // Auto CMD12 on multi-block transfer. + const u16 blocks = port->blocks; + regs->sd_blockcount = blocks; // sd_blockcount32 doesn't need to be set. + regs->sd_stop = STOP_AUTO_STOP; // Auto STOP_TRANSMISSION (CMD12) on multi-block transfer. regs->sd_arg = arg; // We don't need FIFO IRQs when using DMA. buf = NULL means DMA. u32 *buf = port->buf; - const u16 fifoIrqs = (buf != NULL ? (cmd & CMD_DIR_R ? FIFO32_FULL_IE : FIFO32_NOT_EMPTY_IE) : 0u); - regs->sd_fifo32_cnt = fifoIrqs | FIFO32_CLEAR | FIFO32_EN; - regs->sd_cmd = cmd; // Start. + u16 f32Cnt = FIFO32_CLEAR | FIFO32_EN; + if(buf != NULL) f32Cnt |= (cmd & CMD_DIR_R ? FIFO32_FULL_IE : FIFO32_NOT_EMPTY_IE); + regs->sd_fifo32_cnt = f32Cnt; + regs->sd_cmd = (blocks > 1 ? CMD_MBT | cmd : cmd); // Start. // If we have to transfer data do so now. if((cmd & CMD_DT_EN) && (buf != NULL)) @@ -253,15 +255,15 @@ u32 TOSHSD_sendCommand(ToshsdPort *const port, const u16 cmd, const u32 arg) // Response end usually comes immediately after the command // has been sent so we need to check before __wfi(). // On error response end still fires. - while(!(atomic_load_explicit(statusPtr, memory_order_relaxed) & STATUS_RESP_END)) __wfi(); + while((GET_STATUS(statusPtr) & STATUS_RESP_END) == 0) __wfi(); getResponse(regs, port, cmd); // Wait for data end if needed. // On error data end still fires. if(cmd & CMD_DT_EN) - while(!(atomic_load_explicit(statusPtr, memory_order_relaxed) & STATUS_DATA_END)) __wfi(); + while((GET_STATUS(statusPtr) & STATUS_DATA_END) == 0) __wfi(); // STATUS_CMD_BUSY is no longer set at this point. - return atomic_load_explicit(statusPtr, memory_order_relaxed) & STATUS_MASK_ERR; + return GET_STATUS(statusPtr) & STATUS_MASK_ERR; }