//--------------------------------------------------------------------------------- void sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, void *in) { //--------------------------------------------------------------------------------- u16 *in16 = (u16*)in; if(numsectors==1) { return sdmmc_sdcard_writesector(sector_no, in); } if(!sdmmc_sdhc) sector_no *= 512; sdmmc_mask16(0x100, 2, 0); sdmmc_write16(0xd8, 0); sdmmc_write16(REG_SDSTOP, 0x100); sdmmc_write16(REG_SDBLKCOUNT, numsectors); sdmmc_mask16(REG_SDCLKCTL, 0, 0x100); sdmmc_write16(REG_SDBLKLEN, 0x200); set_irqhandler(2, in16, numsectors); // CMD25 - write multiple blocks sdmmc_send_command(25, sector_no & 0xffff, (sector_no >> 16)); if(sdmmc_timeout) { sdmmc_mask16(REG_SDCLKCTL, 0x100, 0); fifoSendValue32(FIFO_SDMMC, 1); } }
//--------------------------------------------------------------------------------- void sdmmc_controller_init() { //--------------------------------------------------------------------------------- int oldIME = enterCriticalSection(); // Reset sdmmc_write16(0x100, 0x0402); sdmmc_write16(0x100, 0x0000); sdmmc_write16(0x104, 0x0000); sdmmc_write16(0x108, 0x0001); // InitIP sdmmc_mask16(REG_SDRESET, 0x0001, 0x0000); sdmmc_mask16(REG_SDRESET, 0x0000, 0x0001); sdmmc_mask16(REG_SDSTOP, 0x0001, 0x0000); // Reset sdmmc_mask16(REG_SDOPT, 0x0005, 0x0000); // EnableInfo sdmmc_mask16(REG_SDSTATUS0, 0x0018, 0x0000); sdmmc_mask16(0x20, 0x0018, 0x0000); // ?? sdmmc_mask16(0x20, 0x0000, 0x0018); sdmmc_init_irq(); leaveCriticalSection(oldIME); }
//--------------------------------------------------------------------------------- void sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, void *out) { //--------------------------------------------------------------------------------- u16 *out16 = (u16*)out; // int ret; if(numsectors==1) { return sdmmc_sdcard_readsector(sector_no, out); } if(!sdmmc_sdhc) sector_no *= 512; sdmmc_mask16(0x100, 2, 0); sdmmc_write16(0xd8, 0); sdmmc_write16(REG_SDSTOP, 0x100); sdmmc_write16(REG_SDBLKCOUNT, numsectors); sdmmc_mask16(REG_SDCLKCTL, 0, 0x100); sdmmc_write16(REG_SDBLKLEN, 0x200); set_irqhandler(1, out16, numsectors); // CMD18 - read multiple blocks sdmmc_send_command(18, sector_no & 0xffff, (sector_no >> 16)); if(sdmmc_timeout) { sdmmc_mask16(REG_SDCLKCTL, 0x100, 0); fifoSendValue32(FIFO_SDMMC, 1); } }
//--------------------------------------------------------------------------------- int sdmmc_send_command(u16 cmd, u16 arg0, u16 arg1) { //--------------------------------------------------------------------------------- u16 is_stat0, was_stat0; u16 is_stat1, was_stat1; sdmmc_write16(REG_SDCMDARG0, arg0); sdmmc_write16(REG_SDCMDARG1, arg1); was_stat1 = sdmmc_read16(REG_SDSTATUS1); while(sdmmc_read16(REG_SDSTATUS1) & 0x4000); is_stat1 = sdmmc_read16(REG_SDSTATUS1); sdmmc_mask16(REG_SDSTATUS1, 0x807F, 0); sdmmc_mask16(REG_SDSTATUS0, 0x0001, 0); sdmmc_mask16(REG_SDSTATUS0, 0x0004, 0); sdmmc_mask16(REG_SDSTATUS1, 0x100, 0); sdmmc_mask16(REG_SDSTATUS1, 0x200, 0); sdmmc_mask16(REG_SDSTOP, 1, 0); sdmmc_mask16(0x22, 0x807F, 0); sdmmc_mask16(0x20, 0x4, 0); sdmmc_timeout = 0; if(cmd==17 || cmd==18) { if((sdmmc_read16(0x100) & 2)==0)sdmmc_mask16(0x22, 0x100, 0); } if(cmd==24 || cmd==25) { if((sdmmc_read16(0x100) & 2)==0)sdmmc_mask16(0x22, 0x200, 0); } sdmmc_write16(REG_SDCMD, cmd); if (cmd != 0) { was_stat0 = sdmmc_read16(REG_SDSTATUS0); if (cmd != 0x5016) { while((sdmmc_read16(REG_SDSTATUS0) & 5) == 0) { if(sdmmc_read16(REG_SDSTATUS1) & 0x40) { sdmmc_mask16(REG_SDSTATUS1, 0x40, 0); sdmmc_timeout = 1; break; } } } is_stat0 = sdmmc_read16(REG_SDSTATUS0); sdmmc_mask16(REG_SDSTATUS0, 5, 0); } if(cmd!=17 && cmd!=18 && cmd!=24 && cmd!=25)sdmmc_mask16(0x22, 0, 0x807F); return 0; }
int NO_INLINE sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in) { if(handelSD.isSDHC == 0) sector_no <<= 9; inittarget(&handelSD); sdmmc_write16(REG_SDSTOP,0x100); #ifdef DATA32_SUPPORT sdmmc_write16(REG_SDBLKCOUNT32,numsectors); #endif sdmmc_write16(REG_SDBLKCOUNT,numsectors); handelSD.data = in; handelSD.size = numsectors << 9; sdmmc_send_command(&handelSD,0x52C19,sector_no); return geterror(&handelSD); }
int NO_INLINE sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out) { if(handelNAND.isSDHC == 0) sector_no <<= 9; inittarget(&handelNAND); sdmmc_write16(REG_SDSTOP,0x100); #ifdef DATA32_SUPPORT sdmmc_write32(REG_SDBLKCOUNT32,numsectors); #else sdmmc_write16(REG_SDBLKCOUNT,numsectors); #endif handelNAND.data = out; handelNAND.size = numsectors << 9; sdmmc_send_command(&handelNAND,0x33C12,sector_no); inittarget(&handelSD); return geterror(&handelNAND); }
//--------------------------------------------------------------------------------- void sdmmc_sdcard_readsector(u32 sector_no, void *out) { //--------------------------------------------------------------------------------- u16 *out16 = (u16*)out; // int ret; if(!sdmmc_sdhc) sector_no *= 512; sdmmc_mask16(0x100, 2, 0); sdmmc_write16(0xd8, 0); sdmmc_mask16(REG_SDCLKCTL, 0, 0x100); sdmmc_write16(REG_SDBLKLEN, 0x200); set_irqhandler(1, out16, 1); // CMD17 - read single block sdmmc_send_command(17, sector_no & 0xffff, (sector_no >> 16)); if(sdmmc_timeout) { sdmmc_mask16(REG_SDCLKCTL, 0x100, 0); fifoSendValue32(FIFO_SDMMC, 1); } }
static void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx, u32 cmd, u32 args) { bool getSDRESP = (cmd << 15) >> 31; u16 flags = (cmd << 15) >> 31; const bool readdata = cmd & 0x20000; const bool writedata = cmd & 0x40000; if (readdata || writedata) flags |= TMIO_STAT0_DATAEND; ctx->error = 0; while (sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY); //mmc working? sdmmc_write16(REG_SDIRMASK0,0); sdmmc_write16(REG_SDIRMASK1,0); sdmmc_write16(REG_SDSTATUS0,0); sdmmc_write16(REG_SDSTATUS1,0); sdmmc_mask16(REG_SDDATACTL32,0x1800,0); sdmmc_write16(REG_SDCMDARG0,args &0xFFFF); sdmmc_write16(REG_SDCMDARG1,args >> 16); sdmmc_write16(REG_SDCMD,cmd &0xFFFF); u32 size = ctx->size; vu8 *dataPtr = ctx->data; bool useBuf = ( NULL != dataPtr ); u16 status0 = 0; while(true) { u16 status1 = sdmmc_read16(REG_SDSTATUS1); if (status1 & TMIO_STAT1_RXRDY) { if (readdata && useBuf) { sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0); //sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_RXRDY); if (size > 0x1FF) { for(int i = 0; i<0x200; i+=2) { u16 data = sdmmc_read16(REG_SDFIFO); *dataPtr++ = data & 0xFF; *dataPtr++ = data >> 8; } size -= 0x200; } } } if (status1 & TMIO_STAT1_TXRQ) { if (writedata && useBuf) { sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0); //sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_TXRQ); if (size > 0x1FF) { for (int i = 0; i<0x200; i+=2) { u16 data = *dataPtr++; data |= *dataPtr++ << 8; sdmmc_write16(REG_SDFIFO, data); } size -= 0x200; } } } if (status1 & TMIO_MASK_GW) { ctx->error |= 4; break; } if (!(status1 & TMIO_STAT1_CMD_BUSY)) { status0 = sdmmc_read16(REG_SDSTATUS0); if (sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND) ctx->error |= 0x1; if (status0 & TMIO_STAT0_DATAEND) ctx->error |= 0x2; if ((status0 & flags) == flags) break; } }
static inline void sdmmc_mask16(u16 reg, const u16 clear, const u16 set) { u16 val = sdmmc_read16(reg); val &= ~clear; val |= set; sdmmc_write16(reg, val); }
void NO_INLINE sdmmc_send_command(struct mmcdevice *ctx, uint32_t cmd, uint32_t args) { bool getSDRESP = (cmd << 15) >> 31; uint16_t flags = (cmd << 15) >> 31; const bool readdata = cmd & 0x20000; const bool writedata = cmd & 0x40000; if(readdata || writedata) { flags |= TMIO_STAT0_DATAEND; } ctx->error = 0; while(sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY); //mmc working? sdmmc_write16(REG_SDIRMASK0,0); sdmmc_write16(REG_SDIRMASK1,0); sdmmc_write16(REG_SDSTATUS0,0); sdmmc_write16(REG_SDSTATUS1,0); #ifdef DATA32_SUPPORT if(readdata)sdmmc_mask16(REG_DATACTL32, 0x1000, 0x800); if(writedata)sdmmc_mask16(REG_DATACTL32, 0x800, 0x1000); #else sdmmc_mask16(REG_DATACTL32,0x1800,0); #endif sdmmc_write16(REG_SDCMDARG0,args &0xFFFF); sdmmc_write16(REG_SDCMDARG1,args >> 16); sdmmc_write16(REG_SDCMD,cmd &0xFFFF); uint32_t size = ctx->size; uint16_t *dataPtr = (uint16_t*)ctx->data; #ifdef DATA32_SUPPORT uint32_t *dataPtr32 = (uint32_t*)ctx->data; #endif bool useBuf = ( NULL != dataPtr ); #ifdef DATA32_SUPPORT bool useBuf32 = (useBuf && (0 == (3 & ((uint32_t)dataPtr)))); #endif uint16_t status0 = 0; while(1) { uint16_t status1 = sdmmc_read16(REG_SDSTATUS1); if(status1 & TMIO_STAT1_RXRDY) { if(readdata) { if(useBuf) { sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0); //sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_RXRDY); if(size > 0x1FF) { #ifdef DATA32_SUPPORT if(useBuf32) { for(int i = 0; i<0x200; i+=4) { *dataPtr32++ = sdmmc_read32(REG_SDFIFO32); } } else { #endif for(int i = 0; i<0x200; i+=2) { *dataPtr++ = sdmmc_read16(REG_SDFIFO); } #ifdef DATA32_SUPPORT } #endif size -= 0x200; } } } } if(status1 & TMIO_STAT1_TXRQ) { if(writedata) { if(useBuf) { sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0); //sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_TXRQ); if(size > 0x1FF) { #ifdef DATA32_SUPPORT for(int i = 0; i<0x200; i+=4) { sdmmc_write32(REG_SDFIFO32,*dataPtr32++); } #else for(int i = 0; i<0x200; i+=2) { sdmmc_write16(REG_SDFIFO,*dataPtr++); } #endif size -= 0x200; } } } } if(status1 & TMIO_MASK_GW) { ctx->error |= 4; break; } if(!(status1 & TMIO_STAT1_CMD_BUSY)) { status0 = sdmmc_read16(REG_SDSTATUS0); if(sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND) { ctx->error |= 0x1; } if(status0 & TMIO_STAT0_DATAEND) { ctx->error |= 0x2; } if((status0 & flags) == flags) break; } } ctx->stat0 = sdmmc_read16(REG_SDSTATUS0); ctx->stat1 = sdmmc_read16(REG_SDSTATUS1); sdmmc_write16(REG_SDSTATUS0,0); sdmmc_write16(REG_SDSTATUS1,0); if(getSDRESP != 0) { ctx->ret[0] = sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1) << 16); ctx->ret[1] = sdmmc_read16(REG_SDRESP2) | (sdmmc_read16(REG_SDRESP3) << 16); ctx->ret[2] = sdmmc_read16(REG_SDRESP4) | (sdmmc_read16(REG_SDRESP5) << 16); ctx->ret[3] = sdmmc_read16(REG_SDRESP6) | (sdmmc_read16(REG_SDRESP7) << 16); } }
//--------------------------------------------------------------------------------- int sdmmc_sdcard_init() { //--------------------------------------------------------------------------------- u16 sdaddr; u32 resp0; u32 resp1; u32 resp2; u32 resp3; u32 resp4; u32 resp5; u32 resp6; u32 resp7; u32 ocr, ccs, hcs, response; sdmmc_cardready = 0; int oldIME = enterCriticalSection(); sdmmc_write16(REG_SDCLKCTL, 0x20); sdmmc_write16(REG_SDOPT, 0x40EA); // XXX: document me! sdmmc_write16(0x02, 0x400); sdmmc_mask16(REG_SDCLKCTL, 0, 0x100); sdmmc_write16(REG_SDCLKCTL, sdmmc_read16(REG_SDCLKCTL)); sdmmc_mask16(REG_SDCLKCTL, 0x100, 0); sdmmc_mask16(REG_SDCLKCTL, 0, 0x200); sdmmc_mask16(REG_SDCLKCTL, 0, 0x100); // CMD0 sdmmc_send_command(0x0000, 0x0000, 0x0000); sdmmc_send_command(0x0408, 0x01aa, 0x0000); sdmmc_gotcmd8reply = 1; if(sdmmc_timeout) sdmmc_gotcmd8reply = 0; if(sdmmc_gotcmd8reply) hcs = (1<<30); else hcs = 0; ocr = 0x00ff8000; while (1) { sdmmc_send_acmd41(ocr | hcs, &response); if (response & 0x80000000) break; } ccs = response & (1<<30); if(ccs && hcs) sdmmc_sdhc = 1; else sdmmc_sdhc = 0; // CMD2 - get CID sdmmc_send_command(2, 0, 0); resp0 = sdmmc_read16(REG_SDRESP0); resp1 = sdmmc_read16(REG_SDRESP1); resp2 = sdmmc_read16(REG_SDRESP2); resp3 = sdmmc_read16(REG_SDRESP3); resp4 = sdmmc_read16(REG_SDRESP4); resp5 = sdmmc_read16(REG_SDRESP5); resp6 = sdmmc_read16(REG_SDRESP6); resp7 = sdmmc_read16(REG_SDRESP7); sdmmc_cid[0] = resp0 | (u32)(resp1<<16); sdmmc_cid[1] = resp2 | (u32)(resp3<<16); sdmmc_cid[2] = resp4 | (u32)(resp5<<16); sdmmc_cid[3] = resp6 | (u32)(resp7<<16); // CMD3 sdmmc_send_command(3, 0, 0); resp0 = sdmmc_read16(REG_SDRESP0); resp1 = sdmmc_read16(REG_SDRESP1); sdaddr = resp1; // CMD9 - get CSD sdmmc_send_command(9, 0, sdaddr); resp0 = sdmmc_read16(REG_SDRESP0); resp1 = sdmmc_read16(REG_SDRESP1); resp2 = sdmmc_read16(REG_SDRESP2); resp3 = sdmmc_read16(REG_SDRESP3); resp4 = sdmmc_read16(REG_SDRESP4); resp5 = sdmmc_read16(REG_SDRESP5); resp6 = sdmmc_read16(REG_SDRESP6); resp7 = sdmmc_read16(REG_SDRESP7); sdmmc_write16(REG_SDCLKCTL, 0x100); // CMD7 sdmmc_send_command(7, 0, sdaddr); resp0 = sdmmc_read16(REG_SDRESP0); resp1 = sdmmc_read16(REG_SDRESP1); // CMD55 sdmmc_send_command(55, 0, sdaddr); // ACMD6 sdmmc_send_command(6, 2, 0); resp0 = sdmmc_read16(REG_SDRESP0); resp1 = sdmmc_read16(REG_SDRESP1); sdmmc_send_command(13, 0, sdaddr); resp0 = sdmmc_read16(REG_SDRESP0); resp1 = sdmmc_read16(REG_SDRESP1); sdmmc_send_command(16, 0x200, 0x0); resp0 = sdmmc_read16(REG_SDRESP0); resp1 = sdmmc_read16(REG_SDRESP1); sdmmc_write16(REG_SDCLKCTL, sdmmc_read16(REG_SDCLKCTL)); sdmmc_write16(REG_SDBLKLEN, 0x200); sdmmc_mask16(REG_SDCLKCTL, 0x100, 0); sdmmc_cardready = 1; leaveCriticalSection(oldIME); return 0; }
//--------------------------------------------------------------------------------- static void sdmmc_irqhandler() { //--------------------------------------------------------------------------------- int i; //u32 irqs; u32 status; u32 errstat; if(sdmmcirq_transfer==0)return; //irqs = sdmmc_read16(0x100); status = sdmmc_read16(REG_SDSTATUS0); errstat = sdmmc_read16(REG_SDSTATUS1) & 0x807f;//STATUS errors mask if(errstat) { sdmmc_mask16(REG_SDSTATUS1, errstat, 0); //sdmmc_mask16(0x22, 0x0, errstat); sdmmcirq_transfer = 0; sdmmcirq_bufpos = 0; sdmmcirq_abort = 1; sdmmc_mask16(REG_SDCLKCTL, 0x100, 0); fifoSendValue32(FIFO_SDMMC, 1); return; } if(sdmmcirq_blocks==0) { if(status & 0x4) { sdmmcirq_transfer = 0; sdmmcirq_bufpos = 0; sdmmc_mask16(REG_SDSTATUS0, 0x4, 0); sdmmc_mask16(0x22, 0, 0x807F | 0x4000); sdmmc_mask16(0x20, 0, 0x4); if((sdmmc_read16(0x22) & 0x100)==0)sdmmc_mask16(0x22, 0, 0x100); if((sdmmc_read16(0x22) & 0x200)==0)sdmmc_mask16(0x22, 0, 0x200); } sdmmc_mask16(REG_SDCLKCTL, 0x100, 0); fifoSendValue32(FIFO_SDMMC, 0); return; } if(sdmmcirq_transfer==1) { sdmmc_mask16(REG_SDSTATUS1, 0x100, 0); //if((sdmmc_read16(0x22) & 0x100))sdmmc_mask16(0x22, 0x100, 0x0); } if(sdmmcirq_transfer==2) { sdmmc_mask16(REG_SDSTATUS1, 0x200, 0); //if((sdmmc_read16(0x22) & 0x200))sdmmc_mask16(0x22, 0x200, 0x0); if(sdmmcirq_blocks==1) { sdmmc_mask16(0x100, 0x1800, 0x0); sdmmc_mask16(0x22, 0x0, 0x100); sdmmc_mask16(0x22, 0x0, 0x200); } } for(i=0; i<0x100; i++) { if(sdmmcirq_transfer==1)sdmmcirq_buffer[sdmmcirq_bufpos] = sdmmc_read16(REG_SDFIFO); if(sdmmcirq_transfer==2)sdmmc_write16(REG_SDFIFO, sdmmcirq_buffer[sdmmcirq_bufpos]); sdmmcirq_bufpos++; } sdmmcirq_blocks--; }