take all the SDMMC shit further. now it's completing MMC init and trying to read shit.

This commit is contained in:
Arisotura 2019-06-18 14:12:37 +02:00
parent 6c75275593
commit dc3c9f5bf8
4 changed files with 218 additions and 11 deletions

View File

@ -20,12 +20,17 @@
#define DSI_H #define DSI_H
#include "NDS.h" #include "NDS.h"
#include "DSi_SD.h"
namespace DSi namespace DSi
{ {
extern u8 eMMC_CID[16]; extern u8 eMMC_CID[16];
extern DSi_SDHost* SDMMC;
extern DSi_SDHost* SDIO;
bool Init(); bool Init();
void DeInit(); void DeInit();
void Reset(); void Reset();

View File

@ -30,12 +30,18 @@ DSi_SDHost::DSi_SDHost(u32 num)
{ {
Num = num; Num = num;
DataFIFO[0] = new FIFO<u16>(0x100);
DataFIFO[1] = new FIFO<u16>(0x100);
Ports[0] = NULL; Ports[0] = NULL;
Ports[1] = NULL; Ports[1] = NULL;
} }
DSi_SDHost::~DSi_SDHost() DSi_SDHost::~DSi_SDHost()
{ {
delete DataFIFO[0];
delete DataFIFO[1];
if (Ports[0]) delete Ports[0]; if (Ports[0]) delete Ports[0];
if (Ports[1]) delete Ports[1]; if (Ports[1]) delete Ports[1];
} }
@ -53,14 +59,26 @@ void DSi_SDHost::Reset()
SoftReset = 0x0007; // CHECKME SoftReset = 0x0007; // CHECKME
SDClock = 0; SDClock = 0;
SDOption = 0;
Command = 0; Command = 0;
Param = 0; Param = 0;
memset(ResponseBuffer, 0, sizeof(ResponseBuffer)); memset(ResponseBuffer, 0, sizeof(ResponseBuffer));
DataFIFO[0]->Clear();
DataFIFO[1]->Clear();
CurFIFO = 0;
IRQStatus = 0; IRQStatus = 0;
IRQMask = 0x8B7F031D; IRQMask = 0x8B7F031D;
DataCtl = 0;
Data32IRQ = 0;
DataMode = 0;
BlockCount16 = 0; BlockCount32 = 0; BlockCountInternal = 0;
BlockLen16 = 0; BlockLen32 = 0;
StopAction = 0;
if (Ports[0]) delete Ports[0]; if (Ports[0]) delete Ports[0];
if (Ports[1]) delete Ports[1]; if (Ports[1]) delete Ports[1];
Ports[0] = NULL; Ports[0] = NULL;
@ -86,6 +104,11 @@ void DSi_SDHost::DoSavestate(Savestate* file)
} }
void DSi_SDHost::ClearIRQ(u32 irq)
{
IRQStatus &= ~(1<<irq);
}
void DSi_SDHost::SetIRQ(u32 irq) void DSi_SDHost::SetIRQ(u32 irq)
{ {
u32 oldflags = IRQStatus & ~IRQMask; u32 oldflags = IRQStatus & ~IRQMask;
@ -107,6 +130,37 @@ void DSi_SDHost::SendResponse(u32 val, bool last)
if (last) SetIRQ(0); if (last) SetIRQ(0);
} }
void DSi_SDHost::FinishSend(u32 param)
{
DSi_SDHost* host = (param & 0x1) ? DSi::SDIO : DSi::SDMMC;
host->CurFIFO ^= 1;
host->ClearIRQ(25);
host->SetIRQ(24);
if (param & 0x2) host->SetIRQ(2);
}
void DSi_SDHost::SendData(u8* data, u32 len, bool last)
{
printf("%s: data RX, len=%d, blkcnt=%d blklen=%d, irq=%08X\n", SD_DESC, len, BlockCount16, BlockLen16, IRQMask);
if (len != BlockLen16) printf("!! BAD BLOCKLEN\n");
u32 f = CurFIFO ^ 1;
for (u32 i = 0; i < len; i += 2)
DataFIFO[f]->Write(*(u16*)&data[i]);
//CurFIFO = f;
//SetIRQ(24);
// TODO: determine what the delay should be!
// for now, this is a placeholder
// we need a delay because DSi boot2 will send a command and then wait for IRQ0
// but if IRQ24 is thrown instantly, the handler clears IRQ0 before the
// send-command function starts polling IRQ status
u32 param = Num | (last << 1);
NDS::ScheduleEvent(NDS::Event_DSi_SDTransfer, false, 512, FinishSend, param);
}
u16 DSi_SDHost::Read(u32 addr) u16 DSi_SDHost::Read(u32 addr)
{ {
@ -119,6 +173,9 @@ u16 DSi_SDHost::Read(u32 addr)
case 0x004: return Param & 0xFFFF; case 0x004: return Param & 0xFFFF;
case 0x006: return Param >> 16; case 0x006: return Param >> 16;
case 0x008: return StopAction;
case 0x00A: return BlockCount16;
case 0x00C: return ResponseBuffer[0]; case 0x00C: return ResponseBuffer[0];
case 0x00E: return ResponseBuffer[1]; case 0x00E: return ResponseBuffer[1];
case 0x010: return ResponseBuffer[2]; case 0x010: return ResponseBuffer[2];
@ -128,14 +185,70 @@ u16 DSi_SDHost::Read(u32 addr)
case 0x018: return ResponseBuffer[6]; case 0x018: return ResponseBuffer[6];
case 0x01A: return ResponseBuffer[7]; case 0x01A: return ResponseBuffer[7];
case 0x01C: return IRQStatus & 0x031D; case 0x01C: return (IRQStatus & 0x031D) | 0x0030; // TODO: adjust insert flags for SD card
case 0x01E: return (IRQStatus >> 16) & 0x8B7F; case 0x01E: return ((IRQStatus >> 16) & 0x8B7F);
case 0x020: return IRQMask & 0x031D; case 0x020: return IRQMask & 0x031D;
case 0x022: return (IRQMask >> 16) & 0x8B7F; case 0x022: return (IRQMask >> 16) & 0x8B7F;
case 0x024: return SDClock; case 0x024: return SDClock;
case 0x026: return BlockLen16;
case 0x028: return SDOption;
case 0x030: // FIFO16
{
// TODO: decrement BlockLen????
u32 f = CurFIFO;
if (DataFIFO[f]->IsEmpty())
{
// TODO
return 0;
}
DSi_SDDevice* dev = Ports[PortSelect & 0x1];
u16 ret = DataFIFO[f]->Read();
if (DataFIFO[f]->IsEmpty())
{
ClearIRQ(24);
if (BlockCountInternal == 0)
{
printf("%s: data RX complete", SD_DESC);
if (StopAction & (1<<8))
{
printf(", sending CMD12");
if (dev) dev->SendCMD(12, 0);
}
printf("\n");
// CHECKME: presumably IRQ2 should not trigger here, but rather
// when the data transfer is done
//SetIRQ(0);
//SetIRQ(2);
}
else
{
BlockCountInternal--;
if (dev) dev->ContinueTransfer();
}
SetIRQ(25);
}
return ret;
}
case 0x0D8: return DataCtl;
case 0x0E0: return SoftReset; case 0x0E0: return SoftReset;
case 0x100: return Data32IRQ;
case 0x104: return BlockLen32;
case 0x108: return BlockCount32;
} }
printf("unknown %s read %08X\n", SD_DESC, addr); printf("unknown %s read %08X\n", SD_DESC, addr);
@ -171,32 +284,55 @@ void DSi_SDHost::Write(u32 addr, u16 val)
} }
return; return;
case 0x002: PortSelect = val; return; case 0x002: PortSelect = val; printf("%s: PORT SELECT %04X\n", SD_DESC, val); return;
case 0x004: Param = (Param & 0xFFFF0000) | val; return; case 0x004: Param = (Param & 0xFFFF0000) | val; return;
case 0x006: Param = (Param & 0x0000FFFF) | (val << 16); return; case 0x006: Param = (Param & 0x0000FFFF) | (val << 16); return;
case 0x01C: IRQStatus &= ~(u32)val; return; case 0x008: StopAction = val & 0x0101; return;
case 0x01E: IRQStatus &= ~((u32)val << 16); return; case 0x00A: BlockCount16 = val; BlockCountInternal = val; return;
case 0x01C: IRQStatus &= (val | 0xFFFF0000); return;
case 0x01E: IRQStatus &= ((val << 16) | 0xFFFF); return;
case 0x020: IRQMask = (IRQMask & 0x8B7F0000) | (val & 0x031D); return; case 0x020: IRQMask = (IRQMask & 0x8B7F0000) | (val & 0x031D); return;
case 0x022: IRQMask = (IRQMask & 0x0000031D) | ((val & 0x8B7F) << 16); return; case 0x022: IRQMask = (IRQMask & 0x0000031D) | ((val & 0x8B7F) << 16); return;
case 0x024: SDClock = val & 0x03FF; return; case 0x024: SDClock = val & 0x03FF; return;
case 0x026:
BlockLen16 = val & 0x03FF;
if (BlockLen16 > 0x200) BlockLen16 = 0x200;
return;
case 0x028: SDOption = val & 0xC1FF; return;
case 0x0D8:
DataCtl = (val & 0x0022);
DataMode = ((DataCtl >> 1) & 0x1) & ((Data32IRQ >> 1) & 0x1);
printf("%s: data mode %d-bit\n", SD_DESC, DataMode?32:16);
return;
case 0x0E0: case 0x0E0:
if ((SoftReset & 0x0001) && !(val & 0x0001)) if ((SoftReset & 0x0001) && !(val & 0x0001))
{ {
printf("%s: RESET\n", SD_DESC); printf("%s: RESET\n", SD_DESC);
// TODO: STOP_INTERNAL_ACTION StopAction = 0;
// TODO: SD_RESPONSE memset(ResponseBuffer, 0, sizeof(ResponseBuffer));
IRQStatus = 0; IRQStatus = 0;
// TODO: ERROR_DETAIL_STATUS // TODO: ERROR_DETAIL_STATUS
// TODO: CARD_CLK_CTL SDClock &= ~0x0500;
// TODO: CARD_OPTION SDOption = 0x40EE;
// TODO: CARD_IRQ_STAT // TODO: CARD_IRQ_STAT
// TODO: FIFO16 shit // TODO: FIFO16 shit
} }
SoftReset = 0x0006 | (val & 0x0001); SoftReset = 0x0006 | (val & 0x0001);
return; return;
case 0x100:
Data32IRQ = (val & 0x1802) | (Data32IRQ & 0x0300);
if (val & (1<<10)) printf("TODO: SD/MMC: CLEAR FIFO32\n");
DataMode = ((DataCtl >> 1) & 0x1) & ((Data32IRQ >> 1) & 0x1);
printf("%s: data mode %d-bit\n", SD_DESC, DataMode?32:16);
return;
case 0x104: BlockLen32 = val & 0x03FF; return;
case 0x108: BlockCount32 = val; return;
} }
printf("unknown %s write %08X %04X\n", SD_DESC, addr, val); printf("unknown %s write %08X %04X\n", SD_DESC, addr, val);
@ -210,7 +346,7 @@ DSi_MMCStorage::DSi_MMCStorage(DSi_SDHost* host, bool internal, const char* path
File = Platform::OpenLocalFile(path, "r+b"); File = Platform::OpenLocalFile(path, "r+b");
CSR = 0x00; // checkme CSR = 0x00000100; // checkme
// TODO: busy bit // TODO: busy bit
// TODO: SDHC/SDXC bit // TODO: SDHC/SDXC bit
@ -219,6 +355,12 @@ DSi_MMCStorage::DSi_MMCStorage(DSi_SDHost* host, bool internal, const char* path
// TODO: customize based on card size etc // TODO: customize based on card size etc
u8 csd_template[16] = {0x40, 0x40, 0x96, 0xE9, 0x7F, 0xDB, 0xF6, 0xDF, 0x01, 0x59, 0x0F, 0x2A, 0x01, 0x26, 0x90, 0x00}; u8 csd_template[16] = {0x40, 0x40, 0x96, 0xE9, 0x7F, 0xDB, 0xF6, 0xDF, 0x01, 0x59, 0x0F, 0x2A, 0x01, 0x26, 0x90, 0x00};
memcpy(CSD, csd_template, 16); memcpy(CSD, csd_template, 16);
// checkme
memset(SCR, 0, 8);
*(u32*)&SCR[0] = 0x012A0000;
memset(SSR, 0, 64);
} }
DSi_MMCStorage::~DSi_MMCStorage() DSi_MMCStorage::~DSi_MMCStorage()
@ -277,8 +419,16 @@ void DSi_MMCStorage::SendCMD(u8 cmd, u32 param)
Host->SendResponse(*(u32*)&CSD[3], true); Host->SendResponse(*(u32*)&CSD[3], true);
return; return;
case 12: // stop operation
Host->SendResponse(CSR, true);
return;
case 16: // set block size
BlockSize = param;
Host->SendResponse(CSR, true);
return;
case 55: // ?? case 55: // ??
printf("CMD55 %08X\n", param);
CSR |= (1<<5); CSR |= (1<<5);
Host->SendResponse(CSR, true); Host->SendResponse(CSR, true);
return; return;
@ -291,13 +441,37 @@ void DSi_MMCStorage::SendACMD(u8 cmd, u32 param)
{ {
switch (cmd) switch (cmd)
{ {
case 6: // set bus width (TODO?)
printf("SET BUS WIDTH %08X\n", param);
Host->SendResponse(CSR, true);
return;
case 13: // get SSR
Host->SendResponse(CSR, true);
Host->SendData(SSR, 64, true);
return;
case 41: // set operating conditions case 41: // set operating conditions
OCR &= 0xBF000000; OCR &= 0xBF000000;
OCR |= (param & 0x40FFFFFF); OCR |= (param & 0x40FFFFFF);
Host->SendResponse(OCR, true); Host->SendResponse(OCR, true);
SetState(0x01); SetState(0x01);
return; return;
case 42: // ???
Host->SendResponse(CSR, true);
return;
case 51: // get SCR
Host->SendResponse(CSR, true);
Host->SendData(SCR, 8, true);
return;
} }
printf("MMC: unknown ACMD %d %08X\n", cmd, param); printf("MMC: unknown ACMD %d %08X\n", cmd, param);
} }
void DSi_MMCStorage::ContinueTransfer()
{
//
}

View File

@ -19,6 +19,10 @@
#ifndef DSI_SD_H #ifndef DSI_SD_H
#define DSI_SD_H #define DSI_SD_H
#include <string.h>
#include "FIFO.h"
class DSi_SDDevice; class DSi_SDDevice;
@ -32,7 +36,9 @@ public:
void DoSavestate(Savestate* file); void DoSavestate(Savestate* file);
static void FinishSend(u32 param);
void SendResponse(u32 val, bool last); void SendResponse(u32 val, bool last);
void SendData(u8* data, u32 len, bool last);
u16 Read(u32 addr); u16 Read(u32 addr);
void Write(u32 addr, u16 val); void Write(u32 addr, u16 val);
@ -43,16 +49,28 @@ private:
u16 PortSelect; u16 PortSelect;
u16 SoftReset; u16 SoftReset;
u16 SDClock; u16 SDClock;
u16 SDOption;
u32 IRQStatus; // IF u32 IRQStatus; // IF
u32 IRQMask; // ~IE u32 IRQMask; // ~IE
u16 DataCtl;
u16 Data32IRQ;
u32 DataMode; // 0=16bit 1=32bit
u16 BlockCount16, BlockCount32, BlockCountInternal;
u16 BlockLen16, BlockLen32;
u16 StopAction;
u16 Command; u16 Command;
u32 Param; u32 Param;
u16 ResponseBuffer[8]; u16 ResponseBuffer[8];
FIFO<u16>* DataFIFO[2];
u32 CurFIFO; // FIFO accessible for read/write
DSi_SDDevice* Ports[2]; DSi_SDDevice* Ports[2];
void ClearIRQ(u32 irq);
void SetIRQ(u32 irq); void SetIRQ(u32 irq);
}; };
@ -64,6 +82,7 @@ public:
~DSi_SDDevice() {} ~DSi_SDDevice() {}
virtual void SendCMD(u8 cmd, u32 param) = 0; virtual void SendCMD(u8 cmd, u32 param) = 0;
virtual void ContinueTransfer() = 0;
protected: protected:
DSi_SDHost* Host; DSi_SDHost* Host;
@ -81,6 +100,8 @@ public:
void SendCMD(u8 cmd, u32 param); void SendCMD(u8 cmd, u32 param);
void SendACMD(u8 cmd, u32 param); void SendACMD(u8 cmd, u32 param);
void ContinueTransfer();
private: private:
bool Internal; bool Internal;
char FilePath[1024]; char FilePath[1024];
@ -92,6 +113,10 @@ private:
u32 CSR; u32 CSR;
u32 OCR; u32 OCR;
u32 RCA; u32 RCA;
u8 SCR[8];
u8 SSR[64];
u32 BlockSize;
void SetState(u32 state) { CSR &= ~(0xF << 9); CSR |= (state << 9); } void SetState(u32 state) { CSR &= ~(0xF << 9); CSR |= (state << 9); }
}; };

View File

@ -42,6 +42,9 @@ enum
Event_Div, Event_Div,
Event_Sqrt, Event_Sqrt,
// DSi
Event_DSi_SDTransfer,
Event_MAX Event_MAX
}; };