take all the SDMMC shit further. now it's completing MMC init and trying to read shit.
This commit is contained in:
parent
6c75275593
commit
dc3c9f5bf8
|
@ -20,12 +20,17 @@
|
|||
#define DSI_H
|
||||
|
||||
#include "NDS.h"
|
||||
#include "DSi_SD.h"
|
||||
|
||||
namespace DSi
|
||||
{
|
||||
|
||||
extern u8 eMMC_CID[16];
|
||||
|
||||
extern DSi_SDHost* SDMMC;
|
||||
extern DSi_SDHost* SDIO;
|
||||
|
||||
|
||||
bool Init();
|
||||
void DeInit();
|
||||
void Reset();
|
||||
|
|
196
src/DSi_SD.cpp
196
src/DSi_SD.cpp
|
@ -30,12 +30,18 @@ DSi_SDHost::DSi_SDHost(u32 num)
|
|||
{
|
||||
Num = num;
|
||||
|
||||
DataFIFO[0] = new FIFO<u16>(0x100);
|
||||
DataFIFO[1] = new FIFO<u16>(0x100);
|
||||
|
||||
Ports[0] = NULL;
|
||||
Ports[1] = NULL;
|
||||
}
|
||||
|
||||
DSi_SDHost::~DSi_SDHost()
|
||||
{
|
||||
delete DataFIFO[0];
|
||||
delete DataFIFO[1];
|
||||
|
||||
if (Ports[0]) delete Ports[0];
|
||||
if (Ports[1]) delete Ports[1];
|
||||
}
|
||||
|
@ -53,14 +59,26 @@ void DSi_SDHost::Reset()
|
|||
|
||||
SoftReset = 0x0007; // CHECKME
|
||||
SDClock = 0;
|
||||
SDOption = 0;
|
||||
|
||||
Command = 0;
|
||||
Param = 0;
|
||||
memset(ResponseBuffer, 0, sizeof(ResponseBuffer));
|
||||
|
||||
DataFIFO[0]->Clear();
|
||||
DataFIFO[1]->Clear();
|
||||
CurFIFO = 0;
|
||||
|
||||
IRQStatus = 0;
|
||||
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[1]) delete Ports[1];
|
||||
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)
|
||||
{
|
||||
u32 oldflags = IRQStatus & ~IRQMask;
|
||||
|
@ -107,6 +130,37 @@ void DSi_SDHost::SendResponse(u32 val, bool last)
|
|||
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)
|
||||
{
|
||||
|
@ -119,6 +173,9 @@ u16 DSi_SDHost::Read(u32 addr)
|
|||
case 0x004: return Param & 0xFFFF;
|
||||
case 0x006: return Param >> 16;
|
||||
|
||||
case 0x008: return StopAction;
|
||||
case 0x00A: return BlockCount16;
|
||||
|
||||
case 0x00C: return ResponseBuffer[0];
|
||||
case 0x00E: return ResponseBuffer[1];
|
||||
case 0x010: return ResponseBuffer[2];
|
||||
|
@ -128,14 +185,70 @@ u16 DSi_SDHost::Read(u32 addr)
|
|||
case 0x018: return ResponseBuffer[6];
|
||||
case 0x01A: return ResponseBuffer[7];
|
||||
|
||||
case 0x01C: return IRQStatus & 0x031D;
|
||||
case 0x01E: return (IRQStatus >> 16) & 0x8B7F;
|
||||
case 0x01C: return (IRQStatus & 0x031D) | 0x0030; // TODO: adjust insert flags for SD card
|
||||
case 0x01E: return ((IRQStatus >> 16) & 0x8B7F);
|
||||
case 0x020: return IRQMask & 0x031D;
|
||||
case 0x022: return (IRQMask >> 16) & 0x8B7F;
|
||||
|
||||
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 0x100: return Data32IRQ;
|
||||
case 0x104: return BlockLen32;
|
||||
case 0x108: return BlockCount32;
|
||||
}
|
||||
|
||||
printf("unknown %s read %08X\n", SD_DESC, addr);
|
||||
|
@ -171,32 +284,55 @@ void DSi_SDHost::Write(u32 addr, u16 val)
|
|||
}
|
||||
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 0x006: Param = (Param & 0x0000FFFF) | (val << 16); return;
|
||||
|
||||
case 0x01C: IRQStatus &= ~(u32)val; return;
|
||||
case 0x01E: IRQStatus &= ~((u32)val << 16); return;
|
||||
case 0x008: StopAction = val & 0x0101; 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 0x022: IRQMask = (IRQMask & 0x0000031D) | ((val & 0x8B7F) << 16); 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:
|
||||
if ((SoftReset & 0x0001) && !(val & 0x0001))
|
||||
{
|
||||
printf("%s: RESET\n", SD_DESC);
|
||||
// TODO: STOP_INTERNAL_ACTION
|
||||
// TODO: SD_RESPONSE
|
||||
StopAction = 0;
|
||||
memset(ResponseBuffer, 0, sizeof(ResponseBuffer));
|
||||
IRQStatus = 0;
|
||||
// TODO: ERROR_DETAIL_STATUS
|
||||
// TODO: CARD_CLK_CTL
|
||||
// TODO: CARD_OPTION
|
||||
SDClock &= ~0x0500;
|
||||
SDOption = 0x40EE;
|
||||
// TODO: CARD_IRQ_STAT
|
||||
// TODO: FIFO16 shit
|
||||
}
|
||||
SoftReset = 0x0006 | (val & 0x0001);
|
||||
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);
|
||||
|
@ -210,7 +346,7 @@ DSi_MMCStorage::DSi_MMCStorage(DSi_SDHost* host, bool internal, const char* path
|
|||
|
||||
File = Platform::OpenLocalFile(path, "r+b");
|
||||
|
||||
CSR = 0x00; // checkme
|
||||
CSR = 0x00000100; // checkme
|
||||
|
||||
// TODO: busy 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
|
||||
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);
|
||||
|
||||
// checkme
|
||||
memset(SCR, 0, 8);
|
||||
*(u32*)&SCR[0] = 0x012A0000;
|
||||
|
||||
memset(SSR, 0, 64);
|
||||
}
|
||||
|
||||
DSi_MMCStorage::~DSi_MMCStorage()
|
||||
|
@ -277,8 +419,16 @@ void DSi_MMCStorage::SendCMD(u8 cmd, u32 param)
|
|||
Host->SendResponse(*(u32*)&CSD[3], true);
|
||||
return;
|
||||
|
||||
case 12: // stop operation
|
||||
Host->SendResponse(CSR, true);
|
||||
return;
|
||||
|
||||
case 16: // set block size
|
||||
BlockSize = param;
|
||||
Host->SendResponse(CSR, true);
|
||||
return;
|
||||
|
||||
case 55: // ??
|
||||
printf("CMD55 %08X\n", param);
|
||||
CSR |= (1<<5);
|
||||
Host->SendResponse(CSR, true);
|
||||
return;
|
||||
|
@ -291,13 +441,37 @@ void DSi_MMCStorage::SendACMD(u8 cmd, u32 param)
|
|||
{
|
||||
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
|
||||
OCR &= 0xBF000000;
|
||||
OCR |= (param & 0x40FFFFFF);
|
||||
Host->SendResponse(OCR, true);
|
||||
SetState(0x01);
|
||||
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);
|
||||
}
|
||||
|
||||
void DSi_MMCStorage::ContinueTransfer()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
|
25
src/DSi_SD.h
25
src/DSi_SD.h
|
@ -19,6 +19,10 @@
|
|||
#ifndef DSI_SD_H
|
||||
#define DSI_SD_H
|
||||
|
||||
#include <string.h>
|
||||
#include "FIFO.h"
|
||||
|
||||
|
||||
class DSi_SDDevice;
|
||||
|
||||
|
||||
|
@ -32,7 +36,9 @@ public:
|
|||
|
||||
void DoSavestate(Savestate* file);
|
||||
|
||||
static void FinishSend(u32 param);
|
||||
void SendResponse(u32 val, bool last);
|
||||
void SendData(u8* data, u32 len, bool last);
|
||||
|
||||
u16 Read(u32 addr);
|
||||
void Write(u32 addr, u16 val);
|
||||
|
@ -43,16 +49,28 @@ private:
|
|||
u16 PortSelect;
|
||||
u16 SoftReset;
|
||||
u16 SDClock;
|
||||
u16 SDOption;
|
||||
|
||||
u32 IRQStatus; // IF
|
||||
u32 IRQMask; // ~IE
|
||||
|
||||
u16 DataCtl;
|
||||
u16 Data32IRQ;
|
||||
u32 DataMode; // 0=16bit 1=32bit
|
||||
u16 BlockCount16, BlockCount32, BlockCountInternal;
|
||||
u16 BlockLen16, BlockLen32;
|
||||
u16 StopAction;
|
||||
|
||||
u16 Command;
|
||||
u32 Param;
|
||||
u16 ResponseBuffer[8];
|
||||
|
||||
FIFO<u16>* DataFIFO[2];
|
||||
u32 CurFIFO; // FIFO accessible for read/write
|
||||
|
||||
DSi_SDDevice* Ports[2];
|
||||
|
||||
void ClearIRQ(u32 irq);
|
||||
void SetIRQ(u32 irq);
|
||||
};
|
||||
|
||||
|
@ -64,6 +82,7 @@ public:
|
|||
~DSi_SDDevice() {}
|
||||
|
||||
virtual void SendCMD(u8 cmd, u32 param) = 0;
|
||||
virtual void ContinueTransfer() = 0;
|
||||
|
||||
protected:
|
||||
DSi_SDHost* Host;
|
||||
|
@ -81,6 +100,8 @@ public:
|
|||
void SendCMD(u8 cmd, u32 param);
|
||||
void SendACMD(u8 cmd, u32 param);
|
||||
|
||||
void ContinueTransfer();
|
||||
|
||||
private:
|
||||
bool Internal;
|
||||
char FilePath[1024];
|
||||
|
@ -92,6 +113,10 @@ private:
|
|||
u32 CSR;
|
||||
u32 OCR;
|
||||
u32 RCA;
|
||||
u8 SCR[8];
|
||||
u8 SSR[64];
|
||||
|
||||
u32 BlockSize;
|
||||
|
||||
void SetState(u32 state) { CSR &= ~(0xF << 9); CSR |= (state << 9); }
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue