mirror of
https://github.com/LNH-team/pico-loader.git
synced 2026-06-02 09:16:49 +02:00
Initial commit
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
#include "common.h"
|
||||
#include <libtwl/mem/memExtern.h>
|
||||
#include "../SdioDefinitions.h"
|
||||
#include "thumbInstructions.h"
|
||||
#include "SuperCardDefinitions.h"
|
||||
#include "SuperCardLoaderPlatform.h"
|
||||
#include "SuperCardSDCommands.h"
|
||||
|
||||
enum SupercardType
|
||||
{
|
||||
SUPERCARD_TYPE_SC_SD = 0x00,
|
||||
SUPERCARD_TYPE_SC_LITE = 0x01,
|
||||
SUPERCARD_TYPE_SC_CF = 0x02,
|
||||
SUPERCARD_TYPE_SC_RUMBLE = (0x10 | SUPERCARD_TYPE_SC_LITE),
|
||||
SUPERCARD_TYPE_UNK = ~SUPERCARD_TYPE_SC_RUMBLE,
|
||||
};
|
||||
|
||||
static void changeSupercardMode(u16 mode)
|
||||
{
|
||||
SC_MODE_REG = SC_MODE_MAGIC;
|
||||
SC_MODE_REG = SC_MODE_MAGIC;
|
||||
SC_MODE_REG = mode;
|
||||
SC_MODE_REG = mode;
|
||||
}
|
||||
|
||||
static SupercardType detectSupercardType()
|
||||
{
|
||||
changeSupercardMode(SC_MODE_SDCARD);
|
||||
u32 val = *(vu16*)0x09800000;
|
||||
switch (val & 0xE300)
|
||||
{
|
||||
case 0xA000:
|
||||
{
|
||||
return SUPERCARD_TYPE_SC_LITE;
|
||||
}
|
||||
case 0xC000:
|
||||
{
|
||||
return SUPERCARD_TYPE_SC_RUMBLE;
|
||||
}
|
||||
case 0xE000:
|
||||
{
|
||||
return SUPERCARD_TYPE_SC_SD;
|
||||
}
|
||||
default:
|
||||
{
|
||||
auto* cfstatns = (vu16*)0x99C0000;
|
||||
*cfstatns = 0x50;
|
||||
__asm__ volatile(
|
||||
"nop\n"
|
||||
"nop\n"
|
||||
"nop\n"
|
||||
"nop\n"
|
||||
"nop\n"
|
||||
"nop\n"
|
||||
"nop\n"
|
||||
"nop\n"
|
||||
);
|
||||
return *cfstatns == 0x50
|
||||
? SUPERCARD_TYPE_SC_CF
|
||||
: SUPERCARD_TYPE_UNK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SuperCardLoaderPlatform::InitializeSdCard()
|
||||
{
|
||||
u32 oldMemCnt = REG_EXMEMCNT;
|
||||
mem_setGbaCartridgeRomWaits(EXMEMCNT_SLOT2_ROM_WAIT1_10, EXMEMCNT_SLOT2_ROM_WAIT2_6);
|
||||
bool result = InitializeSdCardIntern();
|
||||
REG_EXMEMCNT = oldMemCnt;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SuperCardLoaderPlatform::InitializeSdCardIntern()
|
||||
{
|
||||
changeSupercardMode(SC_MODE_SDRAM | SC_MODE_SDCARD);
|
||||
sc_resetSdCard();
|
||||
sc_sendSdClock(NUM_STARTUP_CLOCKS);
|
||||
sc_sdCommand(SD_CMD0_GO_IDLE_STATE, 0);
|
||||
sc_sendSdClock(NUM_STARTUP_CLOCKS);
|
||||
|
||||
u8 responseBuffer[17]; // purposely uninitialized
|
||||
bool isSdhc = false;
|
||||
if (sc_sdCommandAndReadResponse(SD_CMD8_SEND_IF_COND, SD_IF_COND_PATTERN, responseBuffer, SD_R1_RESPONSE_LENGTH_BYTES) &&
|
||||
responseBuffer[0] == SD_CMD8_SEND_IF_COND &&
|
||||
responseBuffer[1] == 0 &&
|
||||
responseBuffer[2] == 0 &&
|
||||
responseBuffer[3] == (SD_IF_COND_PATTERN >> 8) &&
|
||||
responseBuffer[4] == (SD_IF_COND_PATTERN & 0xFF))
|
||||
{
|
||||
isSdhc = true; //might be
|
||||
}
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MAX_STARTUP_TRIES; ++i)
|
||||
{
|
||||
u32 arg = 0;
|
||||
arg |= (1 << 28); //Max performance
|
||||
arg |= (1 << 20); //3.3v
|
||||
if (isSdhc)
|
||||
{
|
||||
arg |= (1 << 30); // Set HCS bit,Supports SDHC
|
||||
}
|
||||
auto res = sc_sdAppCommandAndReadResponse(
|
||||
SD_ACMD41_SD_SEND_OP_COND, 0, arg, responseBuffer, SD_R1_RESPONSE_LENGTH_BYTES);
|
||||
if (res == ScAppCommandResult::FailedToSend)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (res == ScAppCommandResult::Ok &&//ACMD41
|
||||
((responseBuffer[1] & (1 << 7)) != 0)/*Busy:0b:initing 1b:init completed*/)
|
||||
{
|
||||
u16 ccs = responseBuffer[1] & (1 << 6);//0b:SDSC 1b:SDHC/SDXC
|
||||
if (!ccs && isSdhc)
|
||||
{
|
||||
isSdhc = false;
|
||||
}
|
||||
break; // Card is ready
|
||||
}
|
||||
sc_sendSdClock(NUM_STARTUP_CLOCKS);
|
||||
}
|
||||
|
||||
if (i >= MAX_STARTUP_TRIES)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The card's name, as assigned by the manufacturer
|
||||
sc_sdCommandAndDropResponse(SD_CMD2_ALL_SEND_CID, 0, SD_R2_RESPONSE_LENGTH_BYTES);
|
||||
// Get a new address
|
||||
u32 relativeCardAddress = 0;
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MAX_STARTUP_TRIES; i++)
|
||||
{
|
||||
sc_sdCommandAndReadResponse(SD_CMD3_SEND_RELATIVE_ADDR, 0, responseBuffer, SD_R1_RESPONSE_LENGTH_BYTES);
|
||||
relativeCardAddress = (responseBuffer[1] << 24) | (responseBuffer[2] << 16);
|
||||
if ((responseBuffer[3] & 0x1E) != (SD_STATE_STBY << 1))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= MAX_STARTUP_TRIES)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Some cards won't go to higher speeds unless they think you checked their capabilities
|
||||
sc_sdCommandAndDropResponse(SD_CMD9_SEND_CSD, relativeCardAddress, SD_R2_RESPONSE_LENGTH_BYTES);
|
||||
|
||||
// Only this card should respond to all future commands
|
||||
sc_sdCommandAndDropResponse(SD_CMD7_SELECT_CARD, relativeCardAddress, SD_R1_RESPONSE_LENGTH_BYTES);
|
||||
|
||||
// Set a 4 bit data bus
|
||||
sc_sdAppCommandAndDropResponse(SD_ACMD6_SET_BUS_WIDTH, relativeCardAddress, 2, SD_R1_RESPONSE_LENGTH_BYTES);
|
||||
|
||||
|
||||
const u16 nonSdhcOpcode = THUMB_LSLS_IMM(THUMB_R1, THUMB_R0, 9);
|
||||
const u16 sdhcOpcode = THUMB_MOVS_REG(THUMB_R1, THUMB_R0);
|
||||
const u16 opcode = isSdhc ? sdhcOpcode : nonSdhcOpcode;
|
||||
scsd_writeSectorSdhcLabel = opcode;
|
||||
sclite_writeSectorSdhcLabel = opcode;
|
||||
scsd_readSectorSdhcLabel = opcode;
|
||||
sclite_readSectorSdhcLabel = opcode;
|
||||
|
||||
auto type = detectSupercardType();
|
||||
switch (type)
|
||||
{
|
||||
case SUPERCARD_TYPE_SC_SD:
|
||||
case SUPERCARD_TYPE_SC_LITE:
|
||||
case SUPERCARD_TYPE_SC_RUMBLE:
|
||||
{
|
||||
isScLite = (type & SUPERCARD_TYPE_SC_LITE) != 0;
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user