mirror of
https://github.com/LNH-team/pico-loader.git
synced 2026-06-02 17:26:48 +02:00
156 lines
4.1 KiB
C++
156 lines
4.1 KiB
C++
#include "common.h"
|
|
#include <libtwl/card/card.h>
|
|
#include "ioRPGDefinitions.h"
|
|
#include "../SdioDefinitions.h"
|
|
#include "waitByLoop.h"
|
|
#include "IoRPGLoaderPlatform.h"
|
|
|
|
bool IoRPGLoaderPlatform::InitializeSdCard()
|
|
{
|
|
bool isSdhc = false;
|
|
bool isSdVersion2 = false;
|
|
u32 responseR1 = 0;
|
|
|
|
// CMD0
|
|
SdSendSdioCommand(IoRpgCmdSdio(SD_CMD0_GO_IDLE_STATE, IORPG_SDIO_NORESPONSE, 0), nullptr, 0);
|
|
|
|
// CMD8
|
|
responseR1 = SdSendR1Command(SD_CMD8_SEND_IF_COND, SD_IF_COND_PATTERN);
|
|
isSdVersion2 = responseR1 == SD_IF_COND_PATTERN;
|
|
|
|
for (u32 i = 0; i < 10000; i++)
|
|
{
|
|
// CMD55
|
|
SdSendR1Command(SD_CMD55_APP_CMD, 0);
|
|
|
|
// ACMD41
|
|
u32 argument = 0x00FF8000;
|
|
if (isSdVersion2)
|
|
{
|
|
argument |= BIT(30);
|
|
}
|
|
responseR1 = SdSendR1Command(SD_ACMD41_SD_SEND_OP_COND, argument);
|
|
if (responseR1 & BIT(31))
|
|
{
|
|
isSdhc = responseR1 & BIT(30);
|
|
break;
|
|
}
|
|
waitByLoop(1666);
|
|
}
|
|
|
|
// CMD2
|
|
SdSendR2Command(SD_CMD2_ALL_SEND_CID, 0);
|
|
|
|
// CMD3
|
|
responseR1 = SdSendR1Command(SD_CMD3_SEND_RELATIVE_ADDR, 0);
|
|
u32 sdioRca = responseR1 >> 16;
|
|
|
|
// CMD9
|
|
SdSendR2Command(SD_CMD9_SEND_CSD, (sdioRca << 16));
|
|
|
|
// CMD7
|
|
SdSendR1Command(SD_CMD7_SELECT_CARD, (sdioRca << 16));
|
|
|
|
// ACMD6
|
|
SdSendR1Command(SD_CMD55_APP_CMD, (sdioRca << 16));
|
|
SdSendR1Command(SD_ACMD6_SET_BUS_WIDTH, 2);
|
|
|
|
// CMD13
|
|
responseR1 = SdSendR1Command(SD_CMD13_SEND_STATUS, (sdioRca << 16));
|
|
bool isSuccess = (responseR1 >> 9) == 4;
|
|
|
|
if (isSuccess && isSdhc)
|
|
{
|
|
card_romSetCmd(IORPG_CMD_SET_SD_MODE_SDHC);
|
|
card_romStartXfer(IORPG_CTRL_POLL, false);
|
|
card_romWaitBusy();
|
|
PatchSdscShift();
|
|
}
|
|
|
|
return isSuccess;
|
|
}
|
|
|
|
void IoRPGLoaderPlatform::SdSendSdioCommand(u64 command, u8* buffer, u32 length) const
|
|
{
|
|
u32 flags;
|
|
if (length == 0)
|
|
{
|
|
flags = IORPG_CTRL_POLL | MCCNT1_LATENCY1(80);
|
|
}
|
|
else
|
|
{
|
|
// Actually the original driver used 4KB reads.
|
|
// But with SDIO, it only really reads up to 136 bytes,
|
|
// so 4KB is unnecessary.
|
|
flags = IORPG_CTRL_READ_512B | MCCNT1_LATENCY1(40);
|
|
}
|
|
|
|
// param SDIO, get response
|
|
card_romSetCmd(command);
|
|
card_romStartXfer(flags, false);
|
|
|
|
// don't poll if we aren't reading
|
|
if (length == 0)
|
|
{
|
|
card_romWaitBusy();
|
|
return;
|
|
}
|
|
|
|
u32 i = 0;
|
|
u32 data[2];
|
|
u8* target = buffer + (length >> 3);
|
|
do
|
|
{
|
|
// Read data if available
|
|
if (card_romIsDataReady())
|
|
{
|
|
data[i & 1] = card_romGetData();
|
|
if (i & 1)
|
|
{
|
|
target--;
|
|
// Since every byte is a bit, read two words,
|
|
// then pack it into a single byte to represent the
|
|
// true value
|
|
// BIT(7) is the needed bit from the return values
|
|
for (int j = 0; j < 8; ++j)
|
|
{
|
|
u8 bit = (((u8*)data)[7 - j] & BIT(7)) >> 7;
|
|
*target |= bit << j;
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
// Exit loop when we reach the number of words needed
|
|
if (i >= (length >> 2))
|
|
{
|
|
break;
|
|
}
|
|
} while (card_romIsBusy());
|
|
|
|
// Here we cut the transfer short. We don't actually read all 512 bytes as seen
|
|
// in MCCNT1.
|
|
// Cutting the transfer length in the middle of transfer causes undefined
|
|
// behaviour, so wait until then
|
|
card_romWaitDataReady();
|
|
// add a delay just in case
|
|
waitByLoop(33);
|
|
// Cut transmission
|
|
REG_MCCNT1 = 0;
|
|
card_romStartXfer(IORPG_CTRL_POLL, false);
|
|
card_romWaitBusy();
|
|
}
|
|
|
|
u32 IoRPGLoaderPlatform::SdSendR1Command(u8 cmd, u32 argument) const
|
|
{
|
|
u64 buffer = 0;
|
|
SdSendSdioCommand(IoRpgCmdSdio(cmd, IORPG_SDIO_READ_RESPONSE, argument), (u8*)&buffer, SD_R1_RESPONSE_LENGTH_BITS);
|
|
|
|
return (u32)(buffer >> 9);
|
|
}
|
|
|
|
void IoRPGLoaderPlatform::SdSendR2Command(u8 cmd, u32 argument) const
|
|
{
|
|
ALIGN(4) u8 ret[136 >> 3] = {};
|
|
SdSendSdioCommand(IoRpgCmdSdio(cmd, IORPG_SDIO_READ_RESPONSE, argument), ret, SD_R2_RESPONSE_LENGTH_BITS);
|
|
}
|