mirror of
https://github.com/ApacheThunder/akmenu-next.git
synced 2025-06-19 03:35:36 -04:00
TopToyLauncher: Add support for dual SD/SDHC support for DSTT
Works by reinitializing the SD card to retrieve the HCS bit
This commit is contained in:
parent
7ebc6abf53
commit
2199c147ae
@ -32,7 +32,7 @@ CFLAGS := -g -Wall -O3\
|
||||
CFLAGS += -D_NO_BOOTSTUB_
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||
ASFLAGS := -g $(ARCH)
|
||||
ASFLAGS := -g $(ARCH) $(INCLUDE)
|
||||
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
|
@ -22,6 +22,11 @@
|
||||
#include "TopToyLauncher.h"
|
||||
#include "libfat_ext/fat_ext.h"
|
||||
|
||||
#ifdef __TTLAUNCHER_DSTT__
|
||||
#include "ttio/scdssdhc.h"
|
||||
extern u32 SCDS_isSDHC;
|
||||
#endif
|
||||
|
||||
static void resetAndLoop() {
|
||||
DC_FlushAll();
|
||||
DC_InvalidateAll();
|
||||
@ -213,8 +218,13 @@ bool TopToyLauncher::launchRom(std::string romPath, std::string savePath, u32 fl
|
||||
// ttpatch checks this for some reason
|
||||
*((vu32*)0x02FFFC20) = 0x5555AAAA;
|
||||
|
||||
// set SD/SDHC flag to SDHC, right now our DLDI only does SDHC
|
||||
*((vu32*)0x02FFFC24) = ~0;
|
||||
#ifdef __TTLAUNCHER_DSTT__
|
||||
// set SD/SDHC flag
|
||||
// Needs a SDIO reinitialization to retrieve HCS bit
|
||||
if (!SCDS_SDInitialize()) return false;
|
||||
|
||||
*((vu32*)0x02FFFC24) = SCDS_isSDHC ? ~0 : 0;
|
||||
#endif
|
||||
|
||||
// this int seems to be a flag to reinitialize the SD card in ttpatch
|
||||
// if this is *not* -1, ttpatch sends an SDIO CMD12 (STOP_TRANSMISSION)
|
||||
|
82
arm9/source/launcher/ttio/libtwl_card.c
Normal file
82
arm9/source/launcher/ttio/libtwl_card.c
Normal file
@ -0,0 +1,82 @@
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
This file is a part of libtwl (card.c)
|
||||
|
||||
Copyright (C) 2023 Gericom
|
||||
|
||||
SPDX-License-Identifier: Zlib
|
||||
*/
|
||||
|
||||
#include <nds/ndstypes.h>
|
||||
#include "libtwl_card.h"
|
||||
|
||||
void card_romCpuRead(u32* dst, u32 words)
|
||||
{
|
||||
u32* target = dst + words;
|
||||
do
|
||||
{
|
||||
// Read data if available
|
||||
if (card_romIsDataReady())
|
||||
{
|
||||
u32 data = card_romGetData();
|
||||
if (dst < target)
|
||||
*dst++ = data;
|
||||
}
|
||||
} while (card_romIsBusy());
|
||||
}
|
||||
|
||||
void card_romCpuReadUnaligned(u8* dst, u32 words)
|
||||
{
|
||||
u8* target = dst + (words << 2);
|
||||
do
|
||||
{
|
||||
// Read data if available
|
||||
if (card_romIsDataReady())
|
||||
{
|
||||
u32 data = card_romGetData();
|
||||
if (dst < target)
|
||||
{
|
||||
*dst++ = data & 0xFF;
|
||||
*dst++ = (data >> 8) & 0xFF;
|
||||
*dst++ = (data >> 16) & 0xFF;
|
||||
*dst++ = (data >> 24) & 0xFF;
|
||||
}
|
||||
}
|
||||
} while (card_romIsBusy());
|
||||
}
|
||||
|
||||
void card_romCpuWrite(const u32* src, u32 words)
|
||||
{
|
||||
u32 data = 0;
|
||||
const u32* target = src + words;
|
||||
do
|
||||
{
|
||||
// Write data if ready
|
||||
if (card_romIsDataReady())
|
||||
{
|
||||
if (src < target)
|
||||
data = *src++;
|
||||
card_romSetData(data);
|
||||
}
|
||||
} while (card_romIsBusy());
|
||||
}
|
||||
|
||||
void card_romCpuWriteUnaligned(const u8* src, u32 words)
|
||||
{
|
||||
u32 data = 0;
|
||||
const u8* target = src + (words << 2);
|
||||
do
|
||||
{
|
||||
// Write data if ready
|
||||
if (card_romIsDataReady())
|
||||
{
|
||||
if (src < target)
|
||||
{
|
||||
data = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
|
||||
src += 4;
|
||||
}
|
||||
card_romSetData(data);
|
||||
}
|
||||
} while (card_romIsBusy());
|
||||
}
|
134
arm9/source/launcher/ttio/libtwl_card.h
Normal file
134
arm9/source/launcher/ttio/libtwl_card.h
Normal file
@ -0,0 +1,134 @@
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
This file is a part of libtwl (card.h)
|
||||
|
||||
Copyright (C) 2023 Gericom
|
||||
|
||||
SPDX-License-Identifier: Zlib
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define REG_MCCNT0 (*(vu16*)0x040001A0)
|
||||
#define REG_MCD0 (*(vu16*)0x040001A2)
|
||||
#define REG_MCCNT1 (*(vu32*)0x040001A4)
|
||||
#define REG_MCCMD0 (*(vu32*)0x040001A8)
|
||||
#define REG_MCCMD1 (*(vu32*)0x040001AC)
|
||||
#define REG_MCSCR0 (*(vu32*)0x040001B0)
|
||||
#define REG_MCSCR1 (*(vu32*)0x040001B4)
|
||||
#define REG_MCSCR2 (*(vu32*)0x040001B8)
|
||||
#define REG_MCD1 (*(vu32*)0x04100010)
|
||||
|
||||
// REG_MCCNT0
|
||||
|
||||
#define MCCNT0_SPI_RATE_4_19_MHZ 0
|
||||
#define MCCNT0_SPI_RATE_2_09_MHZ 1
|
||||
#define MCCNT0_SPI_RATE_1_05_MHZ 2
|
||||
#define MCCNT0_SPI_RATE_524_KHZ 3
|
||||
|
||||
#define MCCNT0_SPI_HOLD_CS (1 << 6)
|
||||
#define MCCNT0_SPI_BUSY (1 << 7)
|
||||
|
||||
#define MCCNT0_MODE_MASK (1 << 13)
|
||||
#define MCCNT0_MODE_ROM (0 << 13)
|
||||
#define MCCNT0_MODE_SPI (1 << 13)
|
||||
|
||||
#define MCCNT0_ROM_XFER_IRQ (1 << 14)
|
||||
#define MCCNT0_ENABLE (1 << 15)
|
||||
|
||||
// REG_MCCNT1
|
||||
|
||||
#define MCCNT1_LATENCY1_SHIFT 0
|
||||
#define MCCNT1_LATENCY1_MASK 0x1FFF
|
||||
#define MCCNT1_LATENCY1(x) (x)
|
||||
|
||||
#define MCCNT1_READ_DATA_DESCRAMBLE (1 << 13)
|
||||
#define MCCNT1_CLOCK_SCRAMBLER (1 << 14)
|
||||
#define MCCNT1_APPLY_SCRAMBLE_SEED (1 << 15)
|
||||
|
||||
#define MCCNT1_LATENCY2_SHIFT 16
|
||||
#define MCCNT1_LATENCY2_MASK 0x3F0000
|
||||
#define MCCNT1_LATENCY2(x) (((x) << MCCNT1_LATENCY2_SHIFT) & MCCNT1_LATENCY2_MASK)
|
||||
|
||||
#define MCCNT1_CMD_SCRAMBLE (1 << 22)
|
||||
|
||||
#define MCCNT1_DATA_READY (1 << 23)
|
||||
|
||||
#define MCCNT1_LEN_0 (0 << 24)
|
||||
#define MCCNT1_LEN_512 (1 << 24)
|
||||
#define MCCNT1_LEN_1024 (2 << 24)
|
||||
#define MCCNT1_LEN_2048 (3 << 24)
|
||||
#define MCCNT1_LEN_4096 (4 << 24)
|
||||
#define MCCNT1_LEN_8192 (5 << 24)
|
||||
#define MCCNT1_LEN_16384 (6 << 24)
|
||||
#define MCCNT1_LEN_4 (7 << 24)
|
||||
|
||||
#define MCCNT1_CLK_6_7_MHZ (0 << 27)
|
||||
#define MCCNT1_CLK_4_2_MHZ (1 << 27)
|
||||
|
||||
#define MCCNT1_LATENCY_CLK (1 << 28)
|
||||
|
||||
#define MCCNT1_RESET_ON (0 << 29)
|
||||
#define MCCNT1_RESET_OFF (1 << 29)
|
||||
|
||||
#define MCCNT1_DIR_READ (0 << 30)
|
||||
#define MCCNT1_DIR_WRITE (1 << 30)
|
||||
|
||||
#define MCCNT1_ENABLE (1 << 31)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
static inline void card_romSetCmd(u64 cmd)
|
||||
{
|
||||
*(vu64*)®_MCCMD0 = __builtin_bswap64(cmd);
|
||||
}
|
||||
|
||||
static inline bool card_romIsDataReady(void)
|
||||
{
|
||||
return REG_MCCNT1 & MCCNT1_DATA_READY;
|
||||
}
|
||||
|
||||
static inline void card_romWaitDataReady(void)
|
||||
{
|
||||
while(!card_romIsDataReady());
|
||||
}
|
||||
|
||||
static inline u32 card_romGetData(void)
|
||||
{
|
||||
return REG_MCD1;
|
||||
}
|
||||
|
||||
static inline void card_romSetData(u32 data)
|
||||
{
|
||||
REG_MCD1 = data;
|
||||
}
|
||||
|
||||
static inline bool card_romIsBusy(void)
|
||||
{
|
||||
return REG_MCCNT1 & MCCNT1_ENABLE;
|
||||
}
|
||||
|
||||
static inline void card_romWaitBusy(void)
|
||||
{
|
||||
while(card_romIsBusy());
|
||||
}
|
||||
|
||||
static inline void card_romStartXfer(u32 settings, bool irq)
|
||||
{
|
||||
REG_MCCNT0 = (REG_MCCNT0 & ~(MCCNT0_MODE_MASK | MCCNT0_ROM_XFER_IRQ)) | MCCNT0_MODE_ROM | (irq ? MCCNT0_ROM_XFER_IRQ : 0) | MCCNT0_ENABLE;
|
||||
REG_MCCNT1 = MCCNT1_ENABLE | settings;
|
||||
}
|
||||
|
||||
void card_romCpuRead(u32* dst, u32 len);
|
||||
void card_romCpuReadUnaligned(u8* dst, u32 words);
|
||||
|
||||
void card_romCpuWrite(const u32* src, u32 words);
|
||||
void card_romCpuWriteUnaligned(const u8* src, u32 words);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
262
arm9/source/launcher/ttio/scdssdhc.c
Normal file
262
arm9/source/launcher/ttio/scdssdhc.c
Normal file
@ -0,0 +1,262 @@
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
SuperCard DSONE
|
||||
Card IO routines
|
||||
|
||||
Copyright (C) 2023 lifehackerhansol
|
||||
|
||||
SPDX-License-Identifier: Zlib
|
||||
*/
|
||||
|
||||
#include <nds/ndstypes.h>
|
||||
#include "scdssdhc.h"
|
||||
#include "libtwl_card.h"
|
||||
|
||||
u32 SCDS_isSDHC = 0;
|
||||
|
||||
static void SCDS_ReadCardData(u64 command, u32 flags, void *buffer, u32 length)
|
||||
{
|
||||
card_romSetCmd(command);
|
||||
card_romStartXfer(flags, 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)
|
||||
{
|
||||
card_romSetCmd(command);
|
||||
card_romStartXfer(flags, 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;
|
||||
u32 response = 0;
|
||||
|
||||
SCDS_isSDHC = 0;
|
||||
|
||||
// TODO: What is this command doing?
|
||||
SCDS_ReadCardData(0x6600000000000000ull, 0xA7586000, &response, 1);
|
||||
|
||||
// Reset SD host
|
||||
SCDS_SDSetHostRegister(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);
|
||||
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);
|
||||
|
||||
// CMD8
|
||||
SCDS_SendCommand(SCDS_CMD_SD_HOST_PARAM(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));
|
||||
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);
|
||||
response = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(response == 0x1AA)
|
||||
isSD20 = 1;
|
||||
|
||||
do
|
||||
{
|
||||
// CMD55
|
||||
SCDS_SendCommand(SCDS_CMD_SD_HOST_PARAM(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);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
SCDS_SendCommand(SCDS_CMD_SD_HOST_RESPONSE, 0);
|
||||
|
||||
// ACMD41
|
||||
u32 parameter = 0x00FC0000;
|
||||
if(isSD20)
|
||||
parameter |= BIT(30);
|
||||
response = SCDS_SDSendR1Command(41, parameter, SCDS_CTRL_SD_LOW_CLK_LATENCY);
|
||||
} while(!(response & BIT(31)));
|
||||
|
||||
SCDS_isSDHC = response & BIT(30) ? 1 : 0;
|
||||
|
||||
// CMD2
|
||||
SCDS_SDSendR2Command(2, 0, SCDS_CTRL_SD_LOW_CLK_LATENCY);
|
||||
|
||||
// CMD3
|
||||
response = SCDS_SDSendR1Command(3, 0, SCDS_CTRL_SD_LOW_CLK_LATENCY);
|
||||
u32 sdio_rca = response & 0xFFFF0000;
|
||||
|
||||
// CMD7
|
||||
SCDS_SDSendR1Command(7, sdio_rca, SCDS_CTRL_SD_LOW_CLK_LATENCY);
|
||||
|
||||
// ACMD6
|
||||
SCDS_SDSendR1Command(55, sdio_rca, SCDS_CTRL_SD_LOW_CLK_LATENCY);
|
||||
SCDS_SDSendR1Command(6, 2, SCDS_CTRL_SD_LOW_CLK_LATENCY);
|
||||
|
||||
// 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);
|
||||
|
||||
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);
|
||||
|
||||
// wait until data ready
|
||||
while(SCDS_SendCommand(SCDS_CMD_FIFO_BUSY, 0));
|
||||
|
||||
// retrieve data
|
||||
SCDS_ReadCardData(SCDS_CMD_FIFO_READ_DATA, SCDS_CTRL_READ_512B, 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);
|
||||
|
||||
while(1)
|
||||
{
|
||||
// wait until data ready
|
||||
while(SCDS_SendCommand(SCDS_CMD_FIFO_BUSY, 0));
|
||||
|
||||
// retrieve data
|
||||
SCDS_ReadCardData(SCDS_CMD_FIFO_READ_DATA, SCDS_CTRL_READ_512B, 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);
|
||||
};
|
||||
|
||||
// end read
|
||||
SCDS_SDSendR1Command(12, 0, 0);
|
||||
}
|
||||
|
||||
void SCDS_SDWriteSingleSector(u32 sector, const void *buffer)
|
||||
{
|
||||
// instruct cart where to write
|
||||
SCDS_SDSendR1Command(24, SCDS_isSDHC ? sector : sector << 9, 0);
|
||||
|
||||
// write
|
||||
SCDS_WriteCardData(SCDS_CMD_FIFO_WRITE_DATA, SCDS_CTRL_WRITE_512B, buffer, 128);
|
||||
while(SCDS_IsSDHostBusy());
|
||||
|
||||
// end write
|
||||
SCDS_SendCommand(SCDS_CMD_SD_WRITE_END, 0);
|
||||
while(SCDS_IsSDHostBusy());
|
||||
}
|
||||
|
||||
void SCDS_SDWriteMultiSector(u32 sector, const void *buffer, u32 num_sectors)
|
||||
{
|
||||
// instruct cart where to write
|
||||
SCDS_SDSendR1Command(25, SCDS_isSDHC ? sector : sector << 9, 0);
|
||||
|
||||
while (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);
|
||||
while(SCDS_IsSDHostBusy());
|
||||
// write
|
||||
SCDS_WriteCardData(SCDS_CMD_FIFO_WRITE_DATA, SCDS_CTRL_WRITE_512B, 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);
|
||||
while(SCDS_IsSDHostBusy());
|
||||
}
|
168
arm9/source/launcher/ttio/scdssdhc.h
Normal file
168
arm9/source/launcher/ttio/scdssdhc.h
Normal file
@ -0,0 +1,168 @@
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
SuperCard DSONE
|
||||
Card IO routines
|
||||
|
||||
Copyright (C) 2006 SuperCard
|
||||
Copyright (C) 2023 lifehackerhansol
|
||||
|
||||
SPDX-License-Identifier: Zlib
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <nds/ndstypes.h>
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
// SCDS defines
|
||||
// SCDS ROMCTRL flags
|
||||
#define SCDS_CTRL_BASE (MCCNT1_ENABLE | MCCNT1_RESET_OFF | MCCNT1_LATENCY2(24) | MCCNT1_LATENCY1(0))
|
||||
#define SCDS_CTRL_READ_4B (SCDS_CTRL_BASE | MCCNT1_LEN_4)
|
||||
#define SCDS_CTRL_READ_512B (SCDS_CTRL_BASE | MCCNT1_LEN_512)
|
||||
#define SCDS_CTRL_WRITE_4B (SCDS_CTRL_BASE | MCCNT1_DIR_WRITE | MCCNT1_LEN_4)
|
||||
#define SCDS_CTRL_WRITE_512B (SCDS_CTRL_BASE | MCCNT1_DIR_WRITE | MCCNT1_LEN_512)
|
||||
|
||||
#define SCDS_CTRL_SD_LOW_CLK_LATENCY 0x1000
|
||||
|
||||
// SCDS CARD_COMMANDs
|
||||
|
||||
/*
|
||||
SRAM commands
|
||||
|
||||
Command structure:
|
||||
AA BB BB BB BB 00 00 00
|
||||
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);
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
/*
|
||||
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
|
||||
};
|
||||
|
||||
/*
|
||||
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 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);
|
||||
}
|
||||
|
||||
// SD host misc commands
|
||||
// return 0 == idle
|
||||
// return non-0 == not idle
|
||||
#define SCDS_CMD_SD_HOST_BUSY (0x50ull << 56)
|
||||
|
||||
// Gets response of SD_HOST commands, if the sent mode is 1 or 2
|
||||
#define SCDS_CMD_SD_HOST_RESPONSE (0x52ull << 56)
|
||||
// Stops SD host data transfer
|
||||
#define SCDS_CMD_SD_WRITE_END (0x56ull << 56)
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
/*
|
||||
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 SCDS_SD_HOST_REG_RESET BIT(0)
|
||||
#define SCDS_SD_HOST_REG_400KHZ_CLK BIT(1)
|
||||
#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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
void SCDS_SDWriteSingleSector(u32 sector, const void *buffer);
|
||||
void SCDS_SDWriteMultiSector(u32 sector, const void *buffer, u32 num_sectors);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
18
arm9/source/launcher/ttio/waitByLoop.s
Normal file
18
arm9/source/launcher/ttio/waitByLoop.s
Normal file
@ -0,0 +1,18 @@
|
||||
@
|
||||
@ Copyright (C) 2024 lifehackerhansol
|
||||
@
|
||||
@ SPDX-License-Identifier: zlib
|
||||
@
|
||||
|
||||
#include <nds/asminc.h>
|
||||
|
||||
.syntax unified
|
||||
.arm
|
||||
|
||||
@ void waitByLoop(u32 count)
|
||||
@ because we can't use swi 0x3 in DLDI
|
||||
|
||||
BEGIN_ASM_FUNC waitByLoop
|
||||
subs r0, r0, #1
|
||||
bgt waitByLoop
|
||||
bx lr
|
@ -33,7 +33,7 @@ CFLAGS := -g -Wall -O3\
|
||||
CFLAGS += -D_NO_BOOTSTUB_ -D__KERNEL_LAUNCHER_SUPPORT__ -D__AKLOADER_AK2__
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||
ASFLAGS := -g $(ARCH)
|
||||
ASFLAGS := -g $(ARCH) $(INCLUDE)
|
||||
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
|
@ -33,7 +33,7 @@ CFLAGS := -g -Wall -O3\
|
||||
CFLAGS += -D_NO_BOOTSTUB_ -D__DSIMODE__
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||
ASFLAGS := -g $(ARCH)
|
||||
ASFLAGS := -g $(ARCH) $(INCLUDE)
|
||||
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
|
@ -17,7 +17,7 @@ SOURCE_PATH := ../arm9
|
||||
# all directories are relative to this makefile
|
||||
#---------------------------------------------------------------------------------
|
||||
BUILD := build
|
||||
SOURCES := $(SOURCE_PATH)/source $(SOURCE_PATH)/source/ui $(SOURCE_PATH)/source/font $(SOURCE_PATH)/source/launcher $(SOURCE_PATH)/source/launcher/libfat_ext $(SOURCE_PATH)/source/saves
|
||||
SOURCES := $(SOURCE_PATH)/source $(SOURCE_PATH)/source/ui $(SOURCE_PATH)/source/font $(SOURCE_PATH)/source/launcher $(SOURCE_PATH)/source/launcher/libfat_ext $(SOURCE_PATH)/source/launcher/ttio $(SOURCE_PATH)/source/saves
|
||||
INCLUDES := $(SOURCE_PATH)/include ../share $(SOURCES)
|
||||
DATA := $(SOURCE_PATH)/data ../data
|
||||
GRAPHICS :=
|
||||
@ -30,10 +30,10 @@ ARCH := -marm -mthumb-interwork -march=armv5te -mtune=arm946e-s
|
||||
CFLAGS := -g -Wall -O3\
|
||||
$(ARCH) $(INCLUDE) -DARM9
|
||||
|
||||
CFLAGS += -D_NO_BOOTSTUB_ -D__KERNEL_LAUNCHER_SUPPORT__ -D__TTLAUNCHER__
|
||||
CFLAGS += -D_NO_BOOTSTUB_ -D__KERNEL_LAUNCHER_SUPPORT__ -D__TTLAUNCHER__ -D__TTLAUNCHER_DSTT__
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||
ASFLAGS := -g $(ARCH)
|
||||
ASFLAGS := -g $(ARCH) $(INCLUDE)
|
||||
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user