#define io_M3SD_c #include "io_m3sd.h" #ifdef SUPPORT_M3SD //M3-SD interface SD card. #define DMA3SAD *(volatile u32*)0x040000D4 #define DMA3DAD *(volatile u32*)0x040000D8 #define DMA3CNT *(volatile u32*)0x040000DC #define DMA3CR *(volatile u16*)0x040000DE //SD dir control bit cmddir=bit0 clken=bit1 //output #define SDDIR (*(volatile u16*)0x8800000) //SD send get control bit send=bit0 get=bit1 //output #define SDCON (*(volatile u16*)0x9800000) //SD output data obyte[7:0]=AD[7:0] //output #define SDODA (*(volatile u16*)0x9000000) //SD input data AD[7:0]=ibyte[7:0] //input #define SDIDA (*(volatile u16*)0x9000000) //readsector data1 #define SDIDA1 (*(volatile u16*)0x9200000) //readsector data2 #define SDIDA2 (*(volatile u16*)0x9400000) //readsector data3 #define SDIDA3 (*(volatile u16*)0x9600000) //SD stutas cmdneg=bit0 cmdpos=bit1 issend=bit2 isget=bit3 //input #define SDSTA (*(volatile u16*)0x9800000) #define M3_REG_STS *(vu16*)(0x09800000) // Status of the CF Card / Device control #define M3_DATA (vu16*)(0x08800000) // Pointer to buffer of CF data transered from card // CF Card status #define CF_STS_INSERTED1 0x20 #define CF_STS_INSERTED2 0x30 #define CF_STS_INSERTED3 0x22 #define CF_STS_INSERTED4 0x32 #define isM3ins(sta) ((sta==CF_STS_INSERTED1) || (sta==CF_STS_INSERTED2) || (sta==CF_STS_INSERTED3) || (sta==CF_STS_INSERTED4)) #define CARD_TIMEOUT 400000 // Updated due to suggestion from SaTa, otherwise card will timeout sometimes on a write //#define CARD_TIMEOUT (500*100) // M3SD timeout nomal:500 void SendCommand(u16 command, u32 sectorn); void PassRespond(u32 num); void SD_crc16(u16* buff,u16 num,u16* crc16buff); void SD_data_write(u16 *buff,u16* crc16buff); u16 M3_SetChipReg(u32 Data); //========================================================= u16 M3_SetChipReg(u32 Data) { u16 i,j; i = *(volatile u16*)(0x700001*2+0x8000000); i = *(volatile u16*)(0x000007*2+0x8000000); i = *(volatile u16*)(0x400ffe*2+0x8000000); i = *(volatile u16*)(0x000825*2+0x8000000); i = *(volatile u16*)(0x400309*2+0x8000000); i = *(volatile u16*)(0x000000*2+0x8000000); i = *(volatile u16*)(0x400db3*2+0x8000000); i = *(volatile u16*)((Data*2)+0x8000000); j = *(volatile u16*)(0x000407*2+0x8000000); i = *(volatile u16*)(0x000000*2+0x8000000); return j; } void M3_SelectSaver(u8 Bank) { u16 i; i = *(volatile u16*)(0x700001*2+0x8000000); i = *(volatile u16*)(0x000007*2+0x8000000); i = *(volatile u16*)(0x400FFE*2+0x8000000); i = *(volatile u16*)(0x000825*2+0x8000000); i = *(volatile u16*)(0x400309*2+0x8000000); i = *(volatile u16*)(0x000000*2+0x8000000); i = *(volatile u16*)(0x400db3*2+0x8000000); i = *(volatile u16*)((Bank<<4)*2+0x8000000); i = *(volatile u16*)(0x000407*2+0x8000000); i = *(volatile u16*)(0x000000*2+0x8000000); } void DMA3(u32 src, u32 dst, u32 cnt) { u16 i,j,cnttmp; cnttmp = (cnt&0xffff); if( ((dst&0x03) == 0) &&((cnttmp&0x0f) == 0) &&(cnttmp>0)) { DC_FlushRange(dst,cnttmp*2); DMA3CR &= (~0x3a00); DMA3CR &= (~0x8000); i = DMA3CR; j = DMA3CR; DMA3SAD=src; DMA3DAD=dst; DMA3CNT=cnt; } else { for(j=0;j<cnttmp;j++) { *(u16*)(dst+j*2) = *(u16*)(src+j*2); } } } void SendCommand(u16 command, u32 sectorn) { SDCON=0x8; SDIDA1=0x40+command; SDIDA2=(sectorn>>7); SDIDA3=(sectorn<<9); SDDIR=0x29; while ((SDSTA&0x01) != 0x01); SDDIR=0x09; } void PassRespond(u32 num) { u32 i,j,dmanum; dmanum=(64+(num<<3))>>2; SDDIR=0x8; SDCON=0x4; for(j=0;j<dmanum;j++) { i = SDDIR; } } //read multi sectors function void readsectors(u16 * p,u32 sectorn,u16 number) { u32 i,j; SendCommand(18,sectorn); for(i=0;i<number;i++,p+=0x100) { SDDIR=0x49; while ( (SDSTA&0x40) !=0x40); SDDIR=0x09; SDDIR=0x8; SDCON=0x4; j = *(volatile u16*)0x8800000; DMA3(0x8800000,(u32)p,0x80000100); j = *(volatile u16*)0x8800000; j = *(volatile u16*)0x8800000; j = *(volatile u16*)0x8800000; j = *(volatile u16*)0x8800000; SDCON=0x8; } SendCommand(12,sectorn); PassRespond(6); } //write one sector function void M3SD_writesector(u16 * p,u32 sectorn) { u16 crc[4]; u16* check = (u16 *) malloc(512); u16* data = (u16 *) malloc(512); memcpy(data, p, 512); int verify = 0; int tries = 0; do { SendCommand(24,sectorn); PassRespond(6); SDDIR=0x4; SDCON=0x0; SD_crc16(data,512,crc); SD_data_write(data,crc); readsectors(check, sectorn, 1); int r; verify = 0; for (r = 0; r < 256; r++) { if (check[r] != data[r]) { verify++; } } if (verify > 0) { tries++; } } while ((verify > 0) && (tries < 16)); free(data); free(check); } // */ /*----------------------------------------------------------------- M3SD_IsInserted Is a compact flash card inserted? bool return OUT: true if a CF card is inserted -----------------------------------------------------------------*/ bool M3SD_IsInserted (void) { u16 sta; bool i; M3_SetChipReg(0x400003); M3_REG_STS = CF_STS_INSERTED1; sta=M3_REG_STS; i = ( isM3ins(sta) ); M3_SetChipReg(0x400002); return i; } /*----------------------------------------------------------------- M3SD_ClearStatus Tries to make the CF card go back to idle mode bool return OUT: true if a CF card is idle -----------------------------------------------------------------*/ bool M3SD_ClearStatus (void) { int i; u16 sta; M3_SetChipReg(0x400003); i = 0; M3_REG_STS = CF_STS_INSERTED1; while (i < CARD_TIMEOUT) { sta=M3_REG_STS; if( isM3ins(sta) )break; i++; } M3_SetChipReg(0x400002); if (i >= CARD_TIMEOUT) return false; return true; } /*----------------------------------------------------------------- M3SD_ReadSectors Read 512 byte sector numbered "sector" into "buffer" u32 sector IN: address of first 512 byte sector on CF card to read u8 numSecs IN: number of 512 byte sectors to read, 1 to 256 sectors can be read, 0 = 256 void* buffer OUT: pointer to 512 byte buffer to store data in bool return OUT: true if successful -----------------------------------------------------------------*/ bool M3SD_ReadSectors(u32 sector, u8 numSecs, void* buffer) { //read multi sectors function M3_SetChipReg(0x400003); readsectors((u16*)buffer,sector,numSecs); M3_SetChipReg(0x400002); return true; // */ } /*----------------------------------------------------------------- M3SD_WriteSectors Write 512 byte sector numbered "sector" from "buffer" u32 sector IN: address of 512 byte sector on CF card to read u8 numSecs IN: number of 512 byte sectors to read, 1 to 256 sectors can be read, 0 = 256 void* buffer IN: pointer to 512 byte buffer to read data from bool return OUT: true if successful -----------------------------------------------------------------*/ bool M3SD_WriteSectors (u32 sector, u8 numSecs, void* buffer) { bool r=true; int i; M3_SetChipReg(0x400003); for(i=0;i<numSecs;i++) { M3SD_writesector((u16*)((u32)buffer+512*i),sector+i); } M3_SetChipReg(0x400002); return r; } /*----------------------------------------------------------------- M3_Unlock Returns true if M3 was unlocked, false if failed Added by MightyMax -----------------------------------------------------------------*/ bool M3SD_Unlock(void) { vu16 sta; bool i; // run unlock sequence volatile unsigned short tmp; M3_SetChipReg(0x400003); tmp = *(volatile unsigned short *)0x08000000 ; tmp = *(volatile unsigned short *)0x08E00002 ; tmp = *(volatile unsigned short *)0x0800000E ; tmp = *(volatile unsigned short *)0x08801FFC ; tmp = *(volatile unsigned short *)0x0800104A ; tmp = *(volatile unsigned short *)0x08800612 ; tmp = *(volatile unsigned short *)0x08000000 ; tmp = *(volatile unsigned short *)0x08801B66 ; tmp = *(volatile unsigned short *)0x08800006 ; tmp = *(volatile unsigned short *)0x08000000 ; // test that we have register access sta=M3_REG_STS; sta=M3_REG_STS; if( isM3ins(sta) ) { i = true; } else { i = false; } M3_SetChipReg(0x400002); return i; } bool M3SD_Shutdown(void) { return M3SD_ClearStatus() ; } bool M3SD_StartUp(void) { vu16* waitCr = (vu16*)0x4000204; *waitCr |= 0x6000; // *(vu16*)0x4000204=0x6000; // Try unlocking 3 times, because occationally it fails to detect the reader. return M3SD_Unlock() | M3SD_Unlock() | M3SD_Unlock(); } IO_INTERFACE io_m3sd = { 0x4453334D, // 'M3SD' FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE, (FN_MEDIUM_STARTUP)&M3SD_StartUp, (FN_MEDIUM_ISINSERTED)&M3SD_IsInserted, (FN_MEDIUM_READSECTORS)&M3SD_ReadSectors, (FN_MEDIUM_WRITESECTORS)&M3SD_WriteSectors, (FN_MEDIUM_CLEARSTATUS)&M3SD_ClearStatus, (FN_MEDIUM_SHUTDOWN)&M3SD_Shutdown }; LPIO_INTERFACE M3SD_GetInterface(void) { return &io_m3sd ; } #endif