From 5c632b58f54a7df6f100971918716d3a74f367c4 Mon Sep 17 00:00:00 2001 From: lifehackerhansol Date: Mon, 4 Nov 2024 11:06:41 -0800 Subject: [PATCH] ttio: update from DLDI source Fixes issues on R4iTT DSTT-based carts which have a weird quirk --- arm9/source/launcher/ttio/scdssdhc.c | 230 ++++++++++++++++----------- arm9/source/launcher/ttio/scdssdhc.h | 96 ++++------- 2 files changed, 164 insertions(+), 162 deletions(-) diff --git a/arm9/source/launcher/ttio/scdssdhc.c b/arm9/source/launcher/ttio/scdssdhc.c index 160c888..a3e451e 100644 --- a/arm9/source/launcher/ttio/scdssdhc.c +++ b/arm9/source/launcher/ttio/scdssdhc.c @@ -1,5 +1,3 @@ -// clang-format off - /* SuperCard DSONE Card IO routines @@ -15,85 +13,105 @@ u32 SCDS_isSDHC = 0; -static void SCDS_ReadCardData(u64 command, u32 flags, void *buffer, u32 length) +static u32 SCDS_SDHostSetMode(u8 sdio, u32 parameter, u8 response_type, u32 latency) { + u64 command = ((u64)SCDS_CMD_SD_HOST_PARAM << 56) | ((u64)parameter << 24) | ((u64)sdio << 16) | ((u64)response_type << 8); card_romSetCmd(command); - card_romStartXfer(flags, false); + card_romStartXfer(SCDS_CTRL_READ_4B | MCCNT1_LATENCY1(latency), false); + card_romWaitDataReady(); + return card_romGetData(); +} + +static u32 SCDS_IsSDHostBusy(void) +{ + REG_SCDS_MCCMD[0] = SCDS_CMD_SD_HOST_BUSY; + card_romStartXfer(SCDS_CTRL_READ_4B, false); + card_romWaitDataReady(); + return card_romGetData(); +} + +static u32 SCDS_SDHostGetResponse(void) +{ + REG_SCDS_MCCMD[0] = SCDS_CMD_SD_HOST_RESPONSE; + card_romStartXfer(SCDS_CTRL_READ_4B, false); + card_romWaitDataReady(); + return __builtin_bswap32(card_romGetData()); +} + +static void SCDS_SDSendR0Command(u8 sdio, u32 parameter, u32 latency) +{ + SCDS_SDHostSetMode(sdio, parameter, SCDS_SD_HOST_NORESPONSE, latency); + while(SCDS_IsSDHostBusy()); +} + +static u32 SCDS_SDSendR1Command(u8 sdio, u32 parameter, u32 latency) +{ + SCDS_SDHostSetMode(sdio, parameter, SCDS_SD_HOST_READ_4B, latency); + while(SCDS_IsSDHostBusy()); + return SCDS_SDHostGetResponse(); +} + +// TODO: save the response to a buffer (also figure out in which order they're sent) +static void SCDS_SDSendR2Command(u8 sdio, u32 parameter, u32 latency) +{ + SCDS_SDHostSetMode(sdio, parameter, SCDS_SD_HOST_READ_4B_MULTI, latency); + while(SCDS_IsSDHostBusy()); + + // TODO: parse this response + SCDS_SDHostGetResponse(); + + for(int i=0; i < 4; i++) + { + SCDS_SDHostSetMode(sdio, parameter, SCDS_SD_HOST_NEXT_4B, latency); + while(SCDS_IsSDHostBusy()); + // TODO: parse this response + SCDS_SDHostGetResponse(); + } + SCDS_SDHostSetMode(sdio, parameter, SCDS_SD_HOST_SEND_STOP_CLK, 0); + while(SCDS_IsSDHostBusy()); +} + +void waitByLoop(u32 count); + +static void SCDS_SDHostSetRegister(u8 bits) +{ + u64 command = ((u64)SCDS_CMD_SD_HOST_SET_REGISTER << 56) | ((u64)(0x30 | bits) << 48); + card_romSetCmd(command); + card_romStartXfer(SCDS_CTRL_READ_4B, false); + card_romWaitDataReady(); + card_romGetData(); + waitByLoop(0x300); +} + +static u32 SCDS_IsSDFIFOBusy(void) { + REG_SCDS_MCCMD[0] = SCDS_CMD_FIFO_BUSY; + card_romStartXfer(SCDS_CTRL_READ_4B, false); + card_romWaitDataReady(); + return card_romGetData(); +} + +// Reads max 512 bytes +static void SCDS_SDFIFOReadData(void *buffer, u32 length) +{ + REG_SCDS_MCCMD[0] = SCDS_CMD_FIFO_READ_DATA; + card_romStartXfer(SCDS_CTRL_READ_512B, false); if ((u32)buffer & 3) card_romCpuReadUnaligned((u8 *)buffer, length); else card_romCpuRead(buffer, length); } -static void SCDS_WriteCardData(u64 command, u32 flags, const void *buffer, u32 length) +// Writes max 512 bytes +static void SCDS_SDFIFOWriteData(const void *buffer, u32 length) { - card_romSetCmd(command); - card_romStartXfer(flags, false); + REG_SCDS_MCCMD[0] = SCDS_CMD_FIFO_WRITE_DATA; + card_romStartXfer(SCDS_CTRL_WRITE_512B, false); if ((u32)buffer & 3) card_romCpuWriteUnaligned((u8 *)buffer, length); else card_romCpuWrite(buffer, length); } -static u32 SCDS_IsSDHostBusy(void) -{ - return SCDS_SendCommand(SCDS_CMD_SD_HOST_BUSY, 0); -} - -static void SCDS_SDSendR0Command(u8 sdio, u32 parameter, u32 latency) -{ - SCDS_SendCommand(SCDS_CMD_SD_HOST_PARAM(sdio, parameter, SCDS_SD_HOST_NORESPONSE), latency); - while(SCDS_IsSDHostBusy()); -} - -static u32 SCDS_SDSendR1Command(u8 sdio, u32 parameter, u32 latency) -{ - SCDS_SendCommand(SCDS_CMD_SD_HOST_PARAM(sdio, parameter, SCDS_SD_HOST_READ_4B), latency); - while(SCDS_IsSDHostBusy()); - return __builtin_bswap32(SCDS_SendCommand(SCDS_CMD_SD_HOST_RESPONSE, 0)); -} - -// TODO: save the response to a buffer (also figure out in which order they're sent) -static void SCDS_SDSendR2Command(u8 sdio, u32 parameter, u32 latency) -{ - SCDS_SendCommand(SCDS_CMD_SD_HOST_PARAM(sdio, parameter, SCDS_SD_HOST_READ_4B_MULTI), latency); - while(SCDS_IsSDHostBusy()); - - // TODO: parse this response - SCDS_SendCommand(SCDS_CMD_SD_HOST_RESPONSE, 0); - - for(int i=0; i < 4; i++) - { - SCDS_SendCommand(SCDS_CMD_SD_HOST_PARAM(sdio, parameter, SCDS_SD_HOST_NEXT_4B), latency); - while(SCDS_IsSDHostBusy()); - // TODO: parse this response - SCDS_SendCommand(SCDS_CMD_SD_HOST_RESPONSE, 0); - } - SCDS_SendCommand(SCDS_CMD_SD_HOST_PARAM(sdio, parameter, SCDS_SD_HOST_SEND_STOP_CLK), 0); - while(SCDS_IsSDHostBusy()); -} - -void waitByLoop(u32 count); - -static void SCDS_SDSetHostRegister(u8 bits) -{ - SCDS_SendCommand(SCDS_CMD_SD_HOST_SET_REGISTER(bits), 0); - waitByLoop(0x300); -} - -void SCDS_SDGetSDHCStatusFromSRAM(void) -{ - SCDS_isSDHC = SCDS_SendCommand(SCDS_CMD_SRAM_READ_DATA(0x7F9E0), 0) != 0 ? 1 : 0; -} - -u32 SCDS_SendCommand(const u64 command, u32 latency) -{ - card_romSetCmd(command); - card_romStartXfer(SCDS_CTRL_READ_4B | MCCNT1_LATENCY1(latency), false); - card_romWaitDataReady(); - return card_romGetData(); -} - bool SCDS_SDInitialize(void) { u32 isSD20 = 0; @@ -102,35 +120,38 @@ bool SCDS_SDInitialize(void) SCDS_isSDHC = 0; // TODO: What is this command doing? - SCDS_ReadCardData(0x6600000000000000ull, 0xA7586000, &response, 1); + card_romSetCmd(0x6600000000000000ull); + card_romStartXfer(0xA7586000, false); + card_romWaitDataReady(); + card_romGetData(); // Reset SD host - SCDS_SDSetHostRegister(0); + SCDS_SDHostSetRegister(0); // Init - SCDS_SDSetHostRegister(SCDS_SD_HOST_REG_RESET | SCDS_SD_HOST_REG_400KHZ_CLK | SCDS_SD_HOST_REG_CLEAN_ROM_MODE); - SCDS_SendCommand(SCDS_CMD_SD_HOST_PARAM(0, 0, SCDS_SD_HOST_SEND_CLK), SCDS_CTRL_SD_LOW_CLK_LATENCY); + SCDS_SDHostSetRegister(SCDS_SD_HOST_REG_RESET | SCDS_SD_HOST_REG_400KHZ_CLK | SCDS_SD_HOST_REG_CLEAN_ROM_MODE); + SCDS_SDHostSetMode(0, 0, SCDS_SD_HOST_SEND_CLK, SCDS_CTRL_SD_LOW_CLK_LATENCY); waitByLoop(0x1000); // CMD0 SCDS_SDSendR0Command(0, 0, SCDS_CTRL_SD_LOW_CLK_LATENCY); - SCDS_SendCommand(SCDS_CMD_SD_HOST_PARAM(0, 0, SCDS_SD_HOST_SEND_STOP_CLK), SCDS_CTRL_SD_LOW_CLK_LATENCY); + SCDS_SDHostSetMode(0, 0, SCDS_SD_HOST_SEND_STOP_CLK, SCDS_CTRL_SD_LOW_CLK_LATENCY); // CMD8 - SCDS_SendCommand(SCDS_CMD_SD_HOST_PARAM(8, 0x1AA, SCDS_SD_HOST_READ_4B), SCDS_CTRL_SD_LOW_CLK_LATENCY); + SCDS_SDHostSetMode(8, 0x1AA, SCDS_SD_HOST_READ_4B, SCDS_CTRL_SD_LOW_CLK_LATENCY); u32 retryCount = 9999; while(1) { if(!SCDS_IsSDHostBusy()) { - response = __builtin_bswap32(SCDS_SendCommand(SCDS_CMD_SD_HOST_RESPONSE, 0)); + response = SCDS_SDHostGetResponse(); break; } if (--retryCount == 0) { - SCDS_SDSetHostRegister(0); - SCDS_SDSetHostRegister(SCDS_SD_HOST_REG_RESET | SCDS_SD_HOST_REG_400KHZ_CLK | SCDS_SD_HOST_REG_CLEAN_ROM_MODE); + SCDS_SDHostSetRegister(0); + SCDS_SDHostSetRegister(SCDS_SD_HOST_REG_RESET | SCDS_SD_HOST_REG_400KHZ_CLK | SCDS_SD_HOST_REG_CLEAN_ROM_MODE); response = 0; break; } @@ -142,18 +163,18 @@ bool SCDS_SDInitialize(void) do { // CMD55 - SCDS_SendCommand(SCDS_CMD_SD_HOST_PARAM(55, 0, SCDS_SD_HOST_READ_4B), SCDS_CTRL_SD_LOW_CLK_LATENCY); + SCDS_SDHostSetMode(55, 0, SCDS_SD_HOST_READ_4B, SCDS_CTRL_SD_LOW_CLK_LATENCY); retryCount = 9999; while(SCDS_IsSDHostBusy()) { if (--retryCount == 0) { - SCDS_SDSetHostRegister(0); - SCDS_SDSetHostRegister(SCDS_SD_HOST_REG_RESET | SCDS_SD_HOST_REG_400KHZ_CLK | SCDS_SD_HOST_REG_CLEAN_ROM_MODE); + SCDS_SDHostSetRegister(0); + SCDS_SDHostSetRegister(SCDS_SD_HOST_REG_RESET | SCDS_SD_HOST_REG_400KHZ_CLK | SCDS_SD_HOST_REG_CLEAN_ROM_MODE); return false; } } - SCDS_SendCommand(SCDS_CMD_SD_HOST_RESPONSE, 0); + SCDS_SDHostGetResponse(); // ACMD41 u32 parameter = 0x00FC0000; @@ -181,43 +202,49 @@ bool SCDS_SDInitialize(void) // CMD16 SCDS_SDSendR1Command(16, 512, SCDS_CTRL_SD_LOW_CLK_LATENCY); - SCDS_SDSetHostRegister(0); - SCDS_SDSetHostRegister(SCDS_SD_HOST_REG_RESET | SCDS_SD_HOST_REG_CLEAN_ROM_MODE); - if(SCDS_isSDHC ) - SCDS_SDSetHostRegister(SCDS_SD_HOST_REG_RESET | SCDS_SD_HOST_REG_CLEAN_ROM_MODE | SCDS_SD_HOST_REG_SDHC); + SCDS_SDHostSetRegister(0); + SCDS_SDHostSetRegister(SCDS_SD_HOST_REG_RESET | SCDS_SD_HOST_REG_CLEAN_ROM_MODE); + if(SCDS_isSDHC) + SCDS_SDHostSetRegister(SCDS_SD_HOST_REG_RESET | SCDS_SD_HOST_REG_CLEAN_ROM_MODE | SCDS_SD_HOST_REG_SDHC); return true; } void SCDS_SDReadSingleSector(u32 sector, void *buffer) { - // instruct cart what to read - SCDS_SendCommand(SCDS_CMD_SD_READ_SINGLE_BLOCK(SCDS_isSDHC ? sector : sector << 9), 0); + u64 command = ((u64)SCDS_CMD_SD_READ_SINGLE_BLOCK << 56) | ((u64)(SCDS_isSDHC ? sector : sector << 9) << 24); + card_romSetCmd(command); + card_romStartXfer(SCDS_CTRL_READ_4B, false); + card_romWaitDataReady(); + card_romGetData(); // wait until data ready - while(SCDS_SendCommand(SCDS_CMD_FIFO_BUSY, 0)); + while(SCDS_IsSDFIFOBusy()); // retrieve data - SCDS_ReadCardData(SCDS_CMD_FIFO_READ_DATA, SCDS_CTRL_READ_512B, buffer, 128); + SCDS_SDFIFOReadData(buffer, 128); } void SCDS_SDReadMultiSector(u32 sector, void *buffer, u32 num_sectors) { - // instruct cart what to read - SCDS_SendCommand(SCDS_CMD_SD_READ_MULTI_BLOCK(SCDS_isSDHC ? sector : sector << 9), 0); + u64 command = ((u64)SCDS_CMD_SD_READ_MULTI_BLOCK << 56) | ((u64)(SCDS_isSDHC ? sector : sector << 9) << 24); + card_romSetCmd(command); + card_romStartXfer(SCDS_CTRL_READ_4B, false); + card_romWaitDataReady(); + card_romGetData(); while(1) { // wait until data ready - while(SCDS_SendCommand(SCDS_CMD_FIFO_BUSY, 0)); + while(SCDS_IsSDFIFOBusy()); // retrieve data - SCDS_ReadCardData(SCDS_CMD_FIFO_READ_DATA, SCDS_CTRL_READ_512B, buffer, 128); + SCDS_SDFIFOReadData(buffer, 128); buffer = (u8 *)buffer + 0x200; num_sectors--; if(num_sectors == 0) break; - SCDS_SendCommand(SCDS_CMD_SD_HOST_PARAM(0, 0, SCDS_SD_HOST_NEXT_DATABLOCK), 0); + SCDS_SDHostSetMode(0, 0, SCDS_SD_HOST_NEXT_DATABLOCK, 0); }; // end read @@ -230,11 +257,14 @@ void SCDS_SDWriteSingleSector(u32 sector, const void *buffer) SCDS_SDSendR1Command(24, SCDS_isSDHC ? sector : sector << 9, 0); // write - SCDS_WriteCardData(SCDS_CMD_FIFO_WRITE_DATA, SCDS_CTRL_WRITE_512B, buffer, 128); + SCDS_SDFIFOWriteData(buffer, 128); while(SCDS_IsSDHostBusy()); // end write - SCDS_SendCommand(SCDS_CMD_SD_WRITE_END, 0); + REG_SCDS_MCCMD[0] = SCDS_CMD_SD_WRITE_END; + card_romStartXfer(SCDS_CTRL_READ_4B, false); + card_romWaitDataReady(); + card_romGetData(); while(SCDS_IsSDHostBusy()); } @@ -247,16 +277,22 @@ void SCDS_SDWriteMultiSector(u32 sector, const void *buffer, u32 num_sectors) // end write // well, it's supposed to be end write. But doing it first is a no-op, and it's also // a little simpler to write this way - SCDS_SendCommand(SCDS_CMD_SD_WRITE_END, 0); + REG_SCDS_MCCMD[0] = SCDS_CMD_SD_WRITE_END; + card_romStartXfer(SCDS_CTRL_READ_4B, false); + card_romWaitDataReady(); + card_romGetData(); while(SCDS_IsSDHostBusy()); // write - SCDS_WriteCardData(SCDS_CMD_FIFO_WRITE_DATA, SCDS_CTRL_WRITE_512B, buffer, 128); + SCDS_SDFIFOWriteData(buffer, 128); while(SCDS_IsSDHostBusy()); buffer = (u8 *)buffer + 0x200; } // *really* end write SCDS_SDSendR1Command(12, 0, 0); - SCDS_SendCommand(SCDS_CMD_SD_WRITE_END, 0); + REG_SCDS_MCCMD[0] = SCDS_CMD_SD_WRITE_END; + card_romStartXfer(SCDS_CTRL_READ_4B, false); + card_romWaitDataReady(); + card_romGetData(); while(SCDS_IsSDHostBusy()); } diff --git a/arm9/source/launcher/ttio/scdssdhc.h b/arm9/source/launcher/ttio/scdssdhc.h index 9fad624..41ed5f1 100644 --- a/arm9/source/launcher/ttio/scdssdhc.h +++ b/arm9/source/launcher/ttio/scdssdhc.h @@ -1,5 +1,3 @@ -// clang-format off - /* SuperCard DSONE Card IO routines @@ -17,11 +15,16 @@ extern "C" { #endif #include +#include "libtwl_card.h" #ifndef NULL #define NULL 0 #endif +// libtwl workaround +// Certain DSTT clones need bytewise access to MCCMD +#define REG_SCDS_MCCMD ((vu8*)®_MCCMD0) + // SCDS defines // SCDS ROMCTRL flags #define SCDS_CTRL_BASE (MCCNT1_ENABLE | MCCNT1_RESET_OFF | MCCNT1_LATENCY2(24) | MCCNT1_LATENCY1(0)) @@ -42,52 +45,32 @@ extern "C" { AA = command BBBBBBBB = address */ - -static inline u64 SCDS_CMD_SRAM_READ_DATA(u32 address) -{ - return (0x70ull << 56) | ((u64)address << 24); -} - -static inline u64 SCDS_CMD_SRAM_WRITE_DATA(u32 address) -{ - return (0x71ull << 56) | ((u64)address << 24); -} - -/* - This address in SRAM *usually* contains a bool for SD or SDHC - While not exactly reliable, the original driver did it, so here goes - - return 0 == SD - return non-0 == SDHC -*/ -static inline u64 SCDS_CMD_SD_IS_SDHC(void) -{ - return SCDS_CMD_SRAM_READ_DATA(0x7F9E0); -} +#define SCDS_CMD_SRAM_READ_DATA (0x70) +#define SCDS_CMD_SRAM_WRITE_DATA (0x71) // FIFO commands -#define SCDS_CMD_FIFO_BUSY (0x80ull << 56) -#define SCDS_CMD_FIFO_READ_DATA (0x81ull << 56) -#define SCDS_CMD_FIFO_WRITE_DATA (0x82ull << 56) +#define SCDS_CMD_FIFO_BUSY (0x80) +#define SCDS_CMD_FIFO_READ_DATA (0x81) +#define SCDS_CMD_FIFO_WRITE_DATA (0x82) /* SD host modes Used with 0x51 command, see below */ enum SCDS_SD_HOST_MODES { - SCDS_SD_HOST_NORESPONSE = 0ull, - SCDS_SD_HOST_READ_4B = 1ull, - SCDS_SD_HOST_READ_4B_MULTI = 2ull, // use mode 3 to continue this read - SCDS_SD_HOST_NEXT_4B = 3ull, - SCDS_SD_HOST_SEND_CLK = 4ull, - SCDS_SD_HOST_SEND_STOP_CLK = 5ull, - SCDS_SD_HOST_READ_DATABLOCK = 6ull, - SCDS_SD_HOST_NEXT_DATABLOCK = 7ull, - SCDS_SD_HOST_CMD17_READ_DATA = 8ull, // Send SDIO CMD17 & read data - SCDS_SD_HOST_CMD18_READ_DATA = 9ull, // Send SDIO CMD18 & read data until stop - SCDS_SD_HOST_COMMIT_FIFO_DATA = 0xAull, // commit data in FIFO to SD card - SCDS_SD_HOST_CMD24_WRITE_DATA = 0xBull, // Send SDIO CMD24 & send data in SRAM buffer - SCDS_SD_HOST_WAIT_BUSY = 0xCull // wait until data transfer ends + SCDS_SD_HOST_NORESPONSE = 0, + SCDS_SD_HOST_READ_4B = 1, + SCDS_SD_HOST_READ_4B_MULTI = 2, // use mode 3 to continue this read + SCDS_SD_HOST_NEXT_4B = 3, + SCDS_SD_HOST_SEND_CLK = 4, + SCDS_SD_HOST_SEND_STOP_CLK = 5, + SCDS_SD_HOST_READ_DATABLOCK = 6, + SCDS_SD_HOST_NEXT_DATABLOCK = 7, + SCDS_SD_HOST_CMD17_READ_DATA = 8, // Send SDIO CMD17 & read data + SCDS_SD_HOST_CMD18_READ_DATA = 9, // Send SDIO CMD18 & read data until stop + SCDS_SD_HOST_COMMIT_FIFO_DATA = 0xA, // commit data in FIFO to SD card + SCDS_SD_HOST_CMD24_WRITE_DATA = 0xB, // Send SDIO CMD24 & send data in SRAM buffer + SCDS_SD_HOST_WAIT_BUSY = 0xC // wait until data transfer ends }; /* @@ -103,34 +86,22 @@ enum SCDS_SD_HOST_MODES { BB = SDIO command CC = SD host mode, see SCDS_SD_HOST_MODES enum */ -static inline u64 SCDS_CMD_SD_HOST_PARAM(u8 sdio, u32 parameter, u8 mode) -{ - return (0x51ull << 56) | ((u64)parameter << 24) | ((u64)sdio << 16) | ((u64)mode << 8); -} +#define SCDS_CMD_SD_HOST_PARAM (0x51) // SD host misc commands // return 0 == idle // return non-0 == not idle -#define SCDS_CMD_SD_HOST_BUSY (0x50ull << 56) +#define SCDS_CMD_SD_HOST_BUSY (0x50) // Gets response of SD_HOST commands, if the sent mode is 1 or 2 -#define SCDS_CMD_SD_HOST_RESPONSE (0x52ull << 56) +#define SCDS_CMD_SD_HOST_RESPONSE (0x52) // Stops SD host data transfer -#define SCDS_CMD_SD_WRITE_END (0x56ull << 56) +#define SCDS_CMD_SD_WRITE_END (0x56) // Sends CMD17 -// This is effectively 0x51/0x50/0x52 rolled into one command -static inline u64 SCDS_CMD_SD_READ_SINGLE_BLOCK(u32 sector) -{ - return (0x53ull << 56) | ((u64)sector << 24); -} - +#define SCDS_CMD_SD_READ_SINGLE_BLOCK (0x53) // Sends CMD18 -// This is effectively 0x51/0x50/0x52 rolled into one command -static inline u64 SCDS_CMD_SD_READ_MULTI_BLOCK(u32 sector) -{ - return (0x54ull << 56) | ((u64)sector << 24); -} +#define SCDS_CMD_SD_READ_MULTI_BLOCK (0x54) /* SD host control registers @@ -148,15 +119,10 @@ static inline u64 SCDS_CMD_SD_READ_MULTI_BLOCK(u32 sector) #define SCDS_SD_HOST_REG_CLEAN_ROM_MODE BIT(2) #define SCDS_SD_HOST_REG_SDHC BIT(3) -// This function will always set bits 4-5 to 1 and bits 6-7 to 0 for convenience -static inline u64 SCDS_CMD_SD_HOST_SET_REGISTER(u8 bits) -{ - return (0x5F30ull << 48) | ((u64)bits << 48); -} +// Command to write to host register +#define SCDS_CMD_SD_HOST_SET_REGISTER (0x5F) // user API -u32 SCDS_SendCommand(const u64 command, u32 latency); -void SCDS_SDGetSDHCStatusFromSRAM(void); bool SCDS_SDInitialize(void); void SCDS_SDReadSingleSector(u32 sector, void *buffer); void SCDS_SDReadMultiSector(u32 sector, void *buffer, u32 num_sectors);