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:
197
arm9/source/patches/platform/dstt/DSTTLoaderPlatform.cpp
Normal file
197
arm9/source/patches/platform/dstt/DSTTLoaderPlatform.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
#include "common.h"
|
||||
#include <libtwl/card/card.h>
|
||||
#include "dsttDefinitions.h"
|
||||
#include "../SdioDefinitions.h"
|
||||
#include "waitByLoop.h"
|
||||
#include "DSTTLoaderPlatform.h"
|
||||
|
||||
/// @brief Sets the mode of the SD host. Mostly used for SDIO commands.
|
||||
/// @param sdio An SDIO command to send, if any. Set 0 otherwise.
|
||||
/// @param parameter Parameter to send alongside the SDIO command, if any. Set 0 otherwise.
|
||||
/// @param response_type A response type defined in DSTTSdHostModes.
|
||||
/// @param latency Additional MCCNT1 latency to apply when applying the command.
|
||||
static u32 sdHostSetMode(u8 sdio, u32 parameter, u8 response_type, u32 latency)
|
||||
{
|
||||
u64 command = ((u64)DSTT_CMD_SD_HOST_PARAM << 56) | ((u64)parameter << 24) | ((u64)sdio << 16) | ((u64)response_type << 8);
|
||||
card_romSetCmd(command);
|
||||
card_romStartXfer(DSTT_CTRL_READ_4B | MCCNT1_LATENCY1(latency), false);
|
||||
card_romWaitDataReady();
|
||||
return card_romGetData();
|
||||
}
|
||||
|
||||
/// @brief Checks if the SD host is busy.
|
||||
/// @return 0 if not busy, 1 otherwise.
|
||||
static u32 isSdHostBusy(void)
|
||||
{
|
||||
REG_MCCMD0_U8[0] = DSTT_CMD_SD_HOST_BUSY;
|
||||
card_romStartXfer(DSTT_CTRL_READ_4B, false);
|
||||
card_romWaitDataReady();
|
||||
return card_romGetData();
|
||||
}
|
||||
|
||||
/// @brief Retrieves the response from the SD host.
|
||||
/// @return A u32 response. If the SD host was in SDIO mode, only bits 8-40 are returned.
|
||||
static u32 sdHostGetResponse(void)
|
||||
{
|
||||
REG_MCCMD0_U8[0] = DSTT_CMD_SD_HOST_RESPONSE;
|
||||
card_romStartXfer(DSTT_CTRL_READ_4B, false);
|
||||
card_romWaitDataReady();
|
||||
return __builtin_bswap32(card_romGetData());
|
||||
}
|
||||
|
||||
/// @brief Sends an SDIO R0-type command to the cartridge.
|
||||
static void sdSendR0Command(u8 sdio, u32 parameter, u32 latency)
|
||||
{
|
||||
sdHostSetMode(sdio, parameter, DSTT_SD_HOST_NORESPONSE, latency);
|
||||
while (isSdHostBusy())
|
||||
;
|
||||
}
|
||||
|
||||
/// @brief Sends an SDIO R1-type command to the cartridge.
|
||||
/// @return Bits 8-40 of the R1 response.
|
||||
static u32 sdSendR1Command(u8 sdio, u32 parameter, u32 latency)
|
||||
{
|
||||
sdHostSetMode(sdio, parameter, DSTT_SD_HOST_READ_4B, latency);
|
||||
while (isSdHostBusy())
|
||||
;
|
||||
return sdHostGetResponse();
|
||||
}
|
||||
|
||||
/// @brief Sends an SDIO R2-type command to the cartridge.
|
||||
/// TODO: save the response to a buffer (also figure out in which order they're sent)
|
||||
static void sdSendR2Command(u8 sdio, u32 parameter, u32 latency)
|
||||
{
|
||||
sdHostSetMode(sdio, parameter, DSTT_SD_HOST_READ_4B_MULTI, latency);
|
||||
while (isSdHostBusy())
|
||||
;
|
||||
|
||||
// TODO: parse this response
|
||||
sdHostGetResponse();
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
sdHostSetMode(sdio, parameter, DSTT_SD_HOST_NEXT_4B, latency);
|
||||
while (isSdHostBusy())
|
||||
;
|
||||
// TODO: parse this response
|
||||
sdHostGetResponse();
|
||||
}
|
||||
sdHostSetMode(sdio, parameter, DSTT_SD_HOST_SEND_STOP_CLK, 0);
|
||||
while (isSdHostBusy())
|
||||
;
|
||||
}
|
||||
|
||||
/// @brief Manipulates the cartridge's SD host register.
|
||||
static void sdHostSetRegister(u8 bits)
|
||||
{
|
||||
u64 command = ((u64)DSTT_CMD_SD_HOST_SET_REGISTER << 56) | ((u64)(0x30 | bits) << 48);
|
||||
card_romSetCmd(command);
|
||||
card_romStartXfer(DSTT_CTRL_READ_4B, false);
|
||||
card_romWaitDataReady();
|
||||
card_romGetData();
|
||||
waitByLoop(0x600);
|
||||
}
|
||||
|
||||
bool DSTTLoaderPlatform::InitializeSdCard(void)
|
||||
{
|
||||
bool isSdVersion2 = false;
|
||||
bool isSdhc = false;
|
||||
u32 response = 0;
|
||||
|
||||
// TODO: What is this command doing?
|
||||
card_romSetCmd(0x6600000000000000ull);
|
||||
card_romStartXfer(DSTT_CTRL_SET_CARD_MODE, false);
|
||||
card_romWaitDataReady();
|
||||
card_romGetData();
|
||||
|
||||
// Reset SD host
|
||||
sdHostSetRegister(DSTT_SD_HOST_REG_CLEAR_ALL);
|
||||
|
||||
// Init
|
||||
sdHostSetRegister(DSTT_SD_HOST_REG_RESET | DSTT_SD_HOST_REG_400KHZ_CLK | DSTT_SD_HOST_REG_CLEAN_ROM_MODE);
|
||||
sdHostSetMode(0, 0, DSTT_SD_HOST_SEND_CLK, DSTT_CTRL_SD_LOW_CLK_LATENCY);
|
||||
waitByLoop(0x2000);
|
||||
|
||||
// CMD0
|
||||
sdSendR0Command(0, 0, DSTT_CTRL_SD_LOW_CLK_LATENCY);
|
||||
sdHostSetMode(SD_CMD0_GO_IDLE_STATE, 0, DSTT_SD_HOST_SEND_STOP_CLK, DSTT_CTRL_SD_LOW_CLK_LATENCY);
|
||||
|
||||
// CMD8
|
||||
sdHostSetMode(SD_CMD8_SEND_IF_COND, SD_IF_COND_PATTERN, DSTT_SD_HOST_READ_4B, DSTT_CTRL_SD_LOW_CLK_LATENCY);
|
||||
|
||||
u32 retryCount = 9999;
|
||||
while (true)
|
||||
{
|
||||
if (!isSdHostBusy())
|
||||
{
|
||||
response = sdHostGetResponse();
|
||||
break;
|
||||
}
|
||||
if (--retryCount == 0)
|
||||
{
|
||||
sdHostSetRegister(DSTT_SD_HOST_REG_CLEAR_ALL);
|
||||
sdHostSetRegister(DSTT_SD_HOST_REG_RESET | DSTT_SD_HOST_REG_400KHZ_CLK | DSTT_SD_HOST_REG_CLEAN_ROM_MODE);
|
||||
response = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (response == SD_IF_COND_PATTERN)
|
||||
{
|
||||
isSdVersion2 = true;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
// CMD55
|
||||
sdHostSetMode(SD_CMD55_APP_CMD, 0, DSTT_SD_HOST_READ_4B, DSTT_CTRL_SD_LOW_CLK_LATENCY);
|
||||
retryCount = 9999;
|
||||
while (isSdHostBusy())
|
||||
{
|
||||
if (--retryCount == 0)
|
||||
{
|
||||
sdHostSetRegister(DSTT_SD_HOST_REG_CLEAR_ALL);
|
||||
sdHostSetRegister(DSTT_SD_HOST_REG_RESET | DSTT_SD_HOST_REG_400KHZ_CLK | DSTT_SD_HOST_REG_CLEAN_ROM_MODE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
sdHostGetResponse();
|
||||
|
||||
// ACMD41
|
||||
u32 parameter = 0x00FC0000;
|
||||
if (isSdVersion2)
|
||||
{
|
||||
parameter |= BIT(30);
|
||||
}
|
||||
response = sdSendR1Command(SD_ACMD41_SD_SEND_OP_COND, parameter, DSTT_CTRL_SD_LOW_CLK_LATENCY);
|
||||
} while (!(response & BIT(31)));
|
||||
|
||||
isSdhc = (response & BIT(30)) != 0;
|
||||
|
||||
// CMD2
|
||||
sdSendR2Command(SD_CMD2_ALL_SEND_CID, 0, DSTT_CTRL_SD_LOW_CLK_LATENCY);
|
||||
|
||||
// CMD3
|
||||
response = sdSendR1Command(SD_CMD3_SEND_RELATIVE_ADDR, 0, DSTT_CTRL_SD_LOW_CLK_LATENCY);
|
||||
u32 sdioRca = response & 0xFFFF0000;
|
||||
|
||||
// CMD7
|
||||
sdSendR1Command(SD_CMD7_SELECT_CARD, sdioRca, DSTT_CTRL_SD_LOW_CLK_LATENCY);
|
||||
|
||||
// ACMD6
|
||||
sdSendR1Command(SD_CMD55_APP_CMD, sdioRca, DSTT_CTRL_SD_LOW_CLK_LATENCY);
|
||||
sdSendR1Command(SD_ACMD6_SET_BUS_WIDTH, 2, DSTT_CTRL_SD_LOW_CLK_LATENCY);
|
||||
|
||||
// CMD16
|
||||
sdSendR1Command(SD_CMD16_SET_BLOCKLEN, 512, DSTT_CTRL_SD_LOW_CLK_LATENCY);
|
||||
|
||||
sdHostSetRegister(DSTT_SD_HOST_REG_CLEAR_ALL);
|
||||
sdHostSetRegister(DSTT_SD_HOST_REG_RESET | DSTT_SD_HOST_REG_CLEAN_ROM_MODE);
|
||||
if (isSdhc)
|
||||
{
|
||||
sdHostSetRegister(DSTT_SD_HOST_REG_RESET | DSTT_SD_HOST_REG_CLEAN_ROM_MODE | DSTT_SD_HOST_REG_SDHC);
|
||||
dstt_readSd_sdsc_shift = THUMB_MOVS_REG(THUMB_R7, THUMB_R0);
|
||||
dstt_writeSd_sdsc_shift = THUMB_NOP;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
38
arm9/source/patches/platform/dstt/DSTTLoaderPlatform.h
Normal file
38
arm9/source/patches/platform/dstt/DSTTLoaderPlatform.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
#include "common.h"
|
||||
#include "../LoaderPlatform.h"
|
||||
#include "dsttReadSdAsm.h"
|
||||
#include "dsttWriteSdAsm.h"
|
||||
|
||||
/// @brief Implementation of LoaderPlatform for the DSTT flashcard
|
||||
class DSTTLoaderPlatform : public LoaderPlatform
|
||||
{
|
||||
public:
|
||||
const SdReadPatchCode* CreateSdReadPatchCode(
|
||||
PatchCodeCollection& patchCodeCollection, PatchHeap& patchHeap) const override
|
||||
{
|
||||
return patchCodeCollection.GetOrAddSharedPatchCode([&]
|
||||
{
|
||||
return new DSTTReadSdPatchCode(patchHeap,
|
||||
patchCodeCollection.GetOrAddSharedPatchCode([&]
|
||||
{
|
||||
return new DSTTReadSdStopTransmissionPatchCode(patchHeap);
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
const SdWritePatchCode* CreateSdWritePatchCode(
|
||||
PatchCodeCollection& patchCodeCollection, PatchHeap& patchHeap) const override
|
||||
{
|
||||
return patchCodeCollection.GetOrAddSharedPatchCode([&]
|
||||
{
|
||||
return new DSTTWriteSdPatchCode(patchHeap,
|
||||
patchCodeCollection.GetOrAddSharedPatchCode([&]
|
||||
{
|
||||
return new DSTTWriteSdContinuePatchCode(patchHeap);
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
bool InitializeSdCard() override;
|
||||
};
|
||||
75
arm9/source/patches/platform/dstt/dsttDefinitions.h
Normal file
75
arm9/source/patches/platform/dstt/dsttDefinitions.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include <libtwl/card/card.h>
|
||||
|
||||
/// libtwl workaround. Certain DSTT clones need bytewise access to MCCMD
|
||||
#define REG_MCCMD0_U8 ((vu8*)®_MCCMD0)
|
||||
|
||||
/// Common DSTT MCCNT1 flags.
|
||||
#define DSTT_CTRL_BASE (MCCNT1_ENABLE | MCCNT1_RESET_OFF | MCCNT1_LATENCY2(24) | MCCNT1_LATENCY1(0))
|
||||
#define DSTT_CTRL_READ_4B (DSTT_CTRL_BASE | MCCNT1_LEN_4)
|
||||
#define DSTT_CTRL_SET_CARD_MODE (DSTT_CTRL_READ_4B | MCCNT1_CMD_SCRAMBLE | MCCNT1_CLOCK_SCRAMBLER | MCCNT1_READ_DATA_DESCRAMBLE)
|
||||
|
||||
/// Common MCCNT1 LATENCY1.
|
||||
/// During SDIO init SD host commands have a higher latency; in all other cases this is 0.
|
||||
#define DSTT_CTRL_SD_LOW_CLK_LATENCY 0x1000
|
||||
|
||||
/// SD host related commands.
|
||||
///
|
||||
/// Note:
|
||||
/// While this is where the SDIO happens, it isn't always SDIO.
|
||||
/// Thus, it can sometimes be 0.
|
||||
///
|
||||
/// Command structure:
|
||||
/// 51 AA AA AA AA BB CC 00
|
||||
/// AAAAAAAA = SDIO parameter
|
||||
/// BB = SDIO command
|
||||
/// CC = SD host mode, see DSTTSdHostModes enum.
|
||||
#define DSTT_CMD_SD_HOST_PARAM 0x51
|
||||
|
||||
/// SD host miscellaneous commands.
|
||||
/// return 0 == idle
|
||||
/// return non-0 == not idle
|
||||
#define DSTT_CMD_SD_HOST_BUSY 0x50
|
||||
|
||||
/// Retrieves the response from previous SD host param.
|
||||
/// Returns a value if the sent mode is 1 or 2.
|
||||
#define DSTT_CMD_SD_HOST_RESPONSE 0x52
|
||||
|
||||
/// Command to write to host register. The register bits can be found below.
|
||||
#define DSTT_CMD_SD_HOST_SET_REGISTER 0x5F
|
||||
|
||||
/// SD host modes.
|
||||
/// Used with DSTT_CMD_SD_HOST_PARAM command.
|
||||
enum DSTTSdHostModes
|
||||
{
|
||||
DSTT_SD_HOST_NORESPONSE = 0,
|
||||
DSTT_SD_HOST_READ_4B = 1,
|
||||
DSTT_SD_HOST_READ_4B_MULTI = 2, // use mode 3 to continue this read
|
||||
DSTT_SD_HOST_NEXT_4B = 3,
|
||||
DSTT_SD_HOST_SEND_CLK = 4,
|
||||
DSTT_SD_HOST_SEND_STOP_CLK = 5,
|
||||
DSTT_SD_HOST_READ_DATABLOCK = 6,
|
||||
DSTT_SD_HOST_NEXT_DATABLOCK = 7,
|
||||
DSTT_SD_HOST_CMD17_READ_DATA = 8, // Send SDIO CMD17 & read data
|
||||
DSTT_SD_HOST_CMD18_READ_DATA = 9, // Send SDIO CMD18 & read data until stop
|
||||
DSTT_SD_HOST_COMMIT_FIFO_DATA = 0xA, // commit data in FIFO to SD card
|
||||
DSTT_SD_HOST_CMD24_WRITE_DATA = 0xB, // Send SDIO CMD24 & send data in SRAM buffer
|
||||
DSTT_SD_HOST_WAIT_BUSY = 0xC // wait until data transfer ends
|
||||
};
|
||||
|
||||
/// SD host control registers.
|
||||
/// The 0x5F sets raw registers related to the SD host, which is a single u8.
|
||||
/// Bits:
|
||||
/// 0: Reset
|
||||
/// 1: Set 400k low clk
|
||||
/// 2: Use 0xB7 as alternative of 0x5B for ROM reads
|
||||
/// 3: Set SDHC mode
|
||||
/// 4-5: 1
|
||||
/// 6-7: 0
|
||||
#define DSTT_SD_HOST_REG_CLEAR_ALL 0
|
||||
#define DSTT_SD_HOST_REG_RESET BIT(0)
|
||||
#define DSTT_SD_HOST_REG_400KHZ_CLK BIT(1)
|
||||
#define DSTT_SD_HOST_REG_CLEAN_ROM_MODE BIT(2)
|
||||
#define DSTT_SD_HOST_REG_SDHC BIT(3)
|
||||
41
arm9/source/patches/platform/dstt/dsttReadSdAsm.h
Normal file
41
arm9/source/patches/platform/dstt/dsttReadSdAsm.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
#include "sections.h"
|
||||
#include "thumbInstructions.h"
|
||||
#include "../SdReadPatchCode.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(dstt_readsd);
|
||||
DEFINE_SECTION_SYMBOLS(dstt_readsd_stopTransmission);
|
||||
|
||||
extern "C" void dstt_readSd(u32 srcSector, void* dst, u32 sectorCount);
|
||||
extern "C" void dstt_stopTransmission();
|
||||
|
||||
extern u32 dstt_stopTransmission_address;
|
||||
extern u16 dstt_readSd_sdsc_shift;
|
||||
|
||||
class DSTTReadSdStopTransmissionPatchCode : public PatchCode
|
||||
{
|
||||
public:
|
||||
explicit DSTTReadSdStopTransmissionPatchCode(PatchHeap& patchHeap)
|
||||
: PatchCode(SECTION_START(dstt_readsd_stopTransmission), SECTION_SIZE(dstt_readsd_stopTransmission), patchHeap) { }
|
||||
|
||||
const void* GetStopTransmissionFunction() const
|
||||
{
|
||||
return GetAddressAtTarget((void*)dstt_stopTransmission);
|
||||
}
|
||||
};
|
||||
|
||||
class DSTTReadSdPatchCode : public SdReadPatchCode
|
||||
{
|
||||
public:
|
||||
explicit DSTTReadSdPatchCode(PatchHeap& patchHeap,
|
||||
const DSTTReadSdStopTransmissionPatchCode* dsttReadSdStopTransmissionPatchCode)
|
||||
: SdReadPatchCode(SECTION_START(dstt_readsd), SECTION_SIZE(dstt_readsd), patchHeap)
|
||||
{
|
||||
dstt_stopTransmission_address = (u32)dsttReadSdStopTransmissionPatchCode->GetStopTransmissionFunction();
|
||||
}
|
||||
|
||||
const SdReadFunc GetSdReadFunction() const override
|
||||
{
|
||||
return (const SdReadFunc)GetAddressAtTarget((void*)dstt_readSd);
|
||||
}
|
||||
};
|
||||
175
arm9/source/patches/platform/dstt/dsttReadSdAsm.s
Normal file
175
arm9/source/patches/platform/dstt/dsttReadSdAsm.s
Normal file
@@ -0,0 +1,175 @@
|
||||
.cpu arm7tdmi
|
||||
.section "dstt_readsd", "ax"
|
||||
.syntax unified
|
||||
.thumb
|
||||
|
||||
// r0 = src sector
|
||||
// r1 = dst
|
||||
// r2 = sector count
|
||||
.global dstt_readSd
|
||||
.type dstt_readSd, %function
|
||||
dstt_readSd:
|
||||
push {r4-r7,lr}
|
||||
|
||||
.global dstt_readSd_sdsc_shift
|
||||
dstt_readSd_sdsc_shift:
|
||||
lsls r7, r0, #9
|
||||
|
||||
adr r0, dstt_stopTransmission_address
|
||||
ldmia r0, {r0, r3, r4}
|
||||
|
||||
// request sd read for sector 0xaabbccdd
|
||||
// 54 aa bb cc dd 00 00 00
|
||||
movs r5, #0x54
|
||||
strb r5, [r4,#0x8]
|
||||
lsrs r5, r7, #24
|
||||
strb r5, [r4,#0x9]
|
||||
lsrs r5, r7, #16
|
||||
strb r5, [r4,#0xA]
|
||||
lsrs r5, r7, #8
|
||||
strb r5, [r4,#0xB]
|
||||
// make sure the last 3 bytes are zero
|
||||
movs r5, #0xFF
|
||||
ands r7, r5
|
||||
str r7, [r4,#0xC] // storing as little-endian puts the bottom 8 bits as first byte
|
||||
|
||||
movs r7, #0x80
|
||||
strb r7, [r4,#1]
|
||||
|
||||
movs r6, #0x41
|
||||
lsls r6, r6, #20
|
||||
|
||||
sector_loop:
|
||||
str r3, [r4,#4]
|
||||
|
||||
cmd54_wait_loop:
|
||||
ldrb r5, [r4,#6]
|
||||
lsrs r5, r5, #8
|
||||
bcc cmd54_wait_loop
|
||||
|
||||
ldr r5, [r6, #0x10]
|
||||
// sd fifo full poll
|
||||
// 80 xx xx xx xx xx xx xx
|
||||
// xx bytes are leftover from previous command
|
||||
strb r7, [r4,#0x8]
|
||||
|
||||
cmd80_poll_loop:
|
||||
str r3, [r4,#4]
|
||||
|
||||
cmd80_wait_loop:
|
||||
ldrb r5, [r4,#6]
|
||||
lsrs r5, r5, #8
|
||||
bcc cmd80_wait_loop
|
||||
ldr r5, [r6, #0x10]
|
||||
cmp r5, #0
|
||||
bne cmd80_poll_loop
|
||||
|
||||
// read sd fifo
|
||||
// 81 xx xx xx xx xx xx xx
|
||||
// xx bytes are leftover from previous command
|
||||
movs r5, #0x81
|
||||
strb r5, [r4,#0x8]
|
||||
movs r5, #0xA1
|
||||
strb r5, [r4,#7]
|
||||
|
||||
cmd81_data_loop:
|
||||
ldrb r5, [r4,#6]
|
||||
lsrs r5, r5, #8 // check if data is ready
|
||||
bcc cmd81_data_loop_check_transfer_end // if not skip reading
|
||||
|
||||
ldr r5, [r6, #0x10]
|
||||
stmia r1!, {r5}
|
||||
|
||||
cmd81_data_loop_check_transfer_end:
|
||||
ldrb r5, [r4,#7]
|
||||
lsrs r5, r5, #8 // check if transfer is done
|
||||
bcs cmd81_data_loop
|
||||
|
||||
subs r2, #1
|
||||
beq stop_transmission
|
||||
|
||||
// set sd host mode DSTT_MODE_RECEIVE_DATA_BLOCK_STOP_CLOCK
|
||||
// 51 00 00 00 00 00 07 00
|
||||
movs r5, #0x51
|
||||
str r5, [r4,#0x8]
|
||||
movs r5, #7
|
||||
lsls r5, r5, #16
|
||||
str r5, [r4,#0xC]
|
||||
|
||||
b sector_loop
|
||||
|
||||
stop_transmission:
|
||||
bx r0
|
||||
|
||||
.balign 4
|
||||
|
||||
.global dstt_stopTransmission_address
|
||||
dstt_stopTransmission_address:
|
||||
.word 0
|
||||
|
||||
settings:
|
||||
.word 0xA7180000
|
||||
|
||||
regbase:
|
||||
.word 0x040001A0
|
||||
|
||||
.pool
|
||||
|
||||
.section "dstt_readsd_stopTransmission", "ax"
|
||||
.thumb
|
||||
.global dstt_stopTransmission
|
||||
.type dstt_stopTransmission, %function
|
||||
dstt_stopTransmission:
|
||||
// send SD_CMD12_STOP_TRANSMISSION
|
||||
|
||||
// set sd host mode DSTT_MODE_SDCMD_RESPONSE_32BIT, SD_CMD12_STOP_TRANSMISSION
|
||||
// 51 00 00 00 00 0C 01 00
|
||||
movs r5, #0x51
|
||||
str r5, [r4,#0x8]
|
||||
ldr r5,= 0x00010C00
|
||||
str r5, [r4,#0xC]
|
||||
str r3, [r4,#4]
|
||||
|
||||
cmd51_1_wait_loop:
|
||||
ldrb r5, [r4,#6]
|
||||
lsrs r5, r5, #8
|
||||
bcc cmd51_1_wait_loop
|
||||
ldr r5, [r6, #0x10]
|
||||
|
||||
// sd busy poll
|
||||
// 50 xx xx xx xx xx xx xx
|
||||
// xx bytes are leftover from previous command
|
||||
movs r5, #0x50
|
||||
strb r5, [r4,#0x8]
|
||||
|
||||
cmd50_poll_loop:
|
||||
str r3, [r4,#4]
|
||||
|
||||
cmd50_wait_loop:
|
||||
ldrb r5, [r4,#6]
|
||||
lsrs r5, r5, #8
|
||||
bcc cmd50_wait_loop
|
||||
ldr r5, [r6, #0x10]
|
||||
cmp r5, #0
|
||||
bne cmd50_poll_loop
|
||||
|
||||
// read sd response
|
||||
// 52 xx xx xx xx xx xx xx
|
||||
// xx bytes are leftover from previous command
|
||||
movs r5, #0x52
|
||||
strb r5, [r4,#0x8]
|
||||
str r3, [r4,#4]
|
||||
|
||||
cmd52_wait_loop:
|
||||
ldrb r5, [r4,#6]
|
||||
lsrs r5, r5, #8
|
||||
bcc cmd52_wait_loop
|
||||
ldr r5, [r6, #0x10]
|
||||
|
||||
pop {r4-r7,pc}
|
||||
|
||||
.balign 4
|
||||
|
||||
.pool
|
||||
|
||||
.end
|
||||
40
arm9/source/patches/platform/dstt/dsttWriteSdAsm.h
Normal file
40
arm9/source/patches/platform/dstt/dsttWriteSdAsm.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
#include "sections.h"
|
||||
#include "../SdWritePatchCode.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(dstt_writesd);
|
||||
DEFINE_SECTION_SYMBOLS(dstt_writesd_continue);
|
||||
|
||||
extern "C" void dstt_writeSd(u32 dstSector, const void* src, u32 sectorCount);
|
||||
extern "C" void dstt_writeSdContinue();
|
||||
|
||||
extern u32 dstt_writeSdContinue_address;
|
||||
extern u16 dstt_writeSd_sdsc_shift;
|
||||
|
||||
class DSTTWriteSdContinuePatchCode : public PatchCode
|
||||
{
|
||||
public:
|
||||
explicit DSTTWriteSdContinuePatchCode(PatchHeap& patchHeap)
|
||||
: PatchCode(SECTION_START(dstt_writesd_continue), SECTION_SIZE(dstt_writesd_continue), patchHeap) { }
|
||||
|
||||
const void* GetWriteSdContinueFunction() const
|
||||
{
|
||||
return GetAddressAtTarget((void*)dstt_writeSdContinue);
|
||||
}
|
||||
};
|
||||
|
||||
class DSTTWriteSdPatchCode : public SdWritePatchCode
|
||||
{
|
||||
public:
|
||||
explicit DSTTWriteSdPatchCode(PatchHeap& patchHeap,
|
||||
const DSTTWriteSdContinuePatchCode* dsttWriteSdContinuePatchCode)
|
||||
: SdWritePatchCode(SECTION_START(dstt_writesd), SECTION_SIZE(dstt_writesd), patchHeap)
|
||||
{
|
||||
dstt_writeSdContinue_address = (u32)dsttWriteSdContinuePatchCode->GetWriteSdContinueFunction();
|
||||
}
|
||||
|
||||
const SdWriteFunc GetSdWriteFunction() const override
|
||||
{
|
||||
return (const SdWriteFunc)GetAddressAtTarget((void*)dstt_writeSd);
|
||||
}
|
||||
};
|
||||
157
arm9/source/patches/platform/dstt/dsttWriteSdAsm.s
Normal file
157
arm9/source/patches/platform/dstt/dsttWriteSdAsm.s
Normal file
@@ -0,0 +1,157 @@
|
||||
.cpu arm7tdmi
|
||||
.section "dstt_writesd", "ax"
|
||||
.syntax unified
|
||||
.thumb
|
||||
|
||||
// r0 = dst sector
|
||||
// r1 = src
|
||||
// r2 = sector count
|
||||
.global dstt_writeSd
|
||||
.type dstt_writeSd, %function
|
||||
dstt_writeSd:
|
||||
push {r4-r7,lr}
|
||||
|
||||
.global dstt_writeSd_sdsc_shift
|
||||
dstt_writeSd_sdsc_shift:
|
||||
lsls r0, r0, #9
|
||||
|
||||
adr r7, settings
|
||||
ldmia r7, {r3, r4, r5, r6, r7}
|
||||
|
||||
mov lr, r7
|
||||
movs r7, #0x80
|
||||
strb r7, [r4,#1]
|
||||
mov r7, lr
|
||||
|
||||
// send SD_CMD25_WRITE_MULTIPLE_BLOCK for sector 0xaabbccdd
|
||||
|
||||
// set sd host mode DSTT_MODE_SDCMD_RESPONSE_32BIT, SD_CMD25_WRITE_MULTIPLE_BLOCK
|
||||
// 51 aa bb cc dd 19 01 00
|
||||
str r5, [r4,#0xC]
|
||||
movs r5, #0x51
|
||||
strb r5, [r4,#0x8]
|
||||
lsrs r5, r0, #24
|
||||
strb r5, [r4,#0x9]
|
||||
lsrs r5, r0, #16
|
||||
strb r5, [r4,#0xA]
|
||||
lsrs r5, r0, #8
|
||||
strb r5, [r4,#0xB]
|
||||
strb r0, [r4,#0xC]
|
||||
|
||||
ldr r0, dstt_writeSdContinue_address
|
||||
bx r0
|
||||
|
||||
.balign 4
|
||||
|
||||
.global dstt_writeSdContinue_address
|
||||
dstt_writeSdContinue_address:
|
||||
.word 0
|
||||
|
||||
settings:
|
||||
.word 0xA7180000
|
||||
|
||||
regbase:
|
||||
.word 0x040001A0
|
||||
|
||||
writeStartCommandLo:
|
||||
.word 0x00011900
|
||||
|
||||
regbase2:
|
||||
.word 0x04100000
|
||||
|
||||
terminateCommandLo:
|
||||
.word 0x00010C00
|
||||
|
||||
.pool
|
||||
|
||||
.section "dstt_writesd_continue", "ax"
|
||||
.thumb
|
||||
.global dstt_writeSdContinue
|
||||
.type dstt_writeSdContinue, %function
|
||||
dstt_writeSdContinue:
|
||||
bl do32BitTransfer
|
||||
bl waitSdHostBusy
|
||||
bl readSdResponse
|
||||
|
||||
sector_loop:
|
||||
// write to fifo
|
||||
// 82 xx xx xx xx xx xx xx
|
||||
// xx bytes are leftover from previous command
|
||||
movs r5, #0x82
|
||||
strb r5, [r4,#0x8]
|
||||
movs r5, #0xE1
|
||||
strb r5, [r4,#7]
|
||||
|
||||
cmd82_data_loop:
|
||||
ldrb r5, [r4,#6]
|
||||
lsrs r5, r5, #8 // check if ready to write
|
||||
bcc cmd82_data_loop_check_transfer_end // if not skip writing
|
||||
|
||||
ldmia r1!, {r5}
|
||||
str r5, [r6, #0x10]
|
||||
|
||||
cmd82_data_loop_check_transfer_end:
|
||||
ldrb r5, [r4,#7]
|
||||
lsrs r5, r5, #8 // check if transfer is done
|
||||
bcs cmd82_data_loop
|
||||
|
||||
bl waitSdHostBusy
|
||||
|
||||
subs r2, #1
|
||||
bne skip_terminate
|
||||
|
||||
terminate:
|
||||
// send SD_CMD12_STOP_TRANSMISSION
|
||||
|
||||
// set sd host mode DSTT_MODE_SDCMD_RESPONSE_32BIT, SD_CMD12_STOP_TRANSMISSION
|
||||
// 51 00 00 00 00 0C 01 00
|
||||
str r7, [r4,#0xC]
|
||||
movs r5, #0x51
|
||||
bl do32BitTransferWriteCmdHi
|
||||
bl waitSdHostBusy
|
||||
bl readSdResponse
|
||||
|
||||
skip_terminate:
|
||||
// wait sddat[0] == 1
|
||||
// 56 00 00 00 00 00 00 00
|
||||
movs r5, #0x56
|
||||
bl do32BitTransferWriteCmdHi
|
||||
bl waitSdHostBusy
|
||||
cmp r2, #0
|
||||
bne sector_loop
|
||||
|
||||
pop {r4-r7,pc}
|
||||
|
||||
waitSdHostBusy:
|
||||
mov r12, lr
|
||||
cmd50_poll_loop:
|
||||
// sd busy poll
|
||||
// 50 xx xx xx xx xx xx xx
|
||||
// xx bytes are leftover from previous command
|
||||
movs r5, #0x50
|
||||
bl do32BitTransferWriteCmdHi
|
||||
cmp r5, #0
|
||||
bne cmd50_poll_loop
|
||||
bx r12
|
||||
|
||||
readSdResponse:
|
||||
// read sd response
|
||||
// 52 xx xx xx xx xx xx xx
|
||||
// xx bytes are leftover from previous command
|
||||
movs r5, #0x52
|
||||
do32BitTransferWriteCmdHi:
|
||||
strb r5, [r4,#0x8]
|
||||
do32BitTransfer:
|
||||
str r3, [r4,#4]
|
||||
1:
|
||||
ldrb r5, [r4,#6]
|
||||
lsrs r5, r5, #8
|
||||
bcc 1b
|
||||
ldr r5, [r6, #0x10]
|
||||
bx lr
|
||||
|
||||
.balign 4
|
||||
|
||||
.pool
|
||||
|
||||
.end
|
||||
Reference in New Issue
Block a user