//--------------------------------------------------------------------------------- void sdmmcValueHandler(u32 value, void* user_data) { //--------------------------------------------------------------------------------- int result; switch(value) { case SDMMC_HAVE_SD: result = sdmmc_read16(REG_SDSTATUS0); fifoSendValue32(FIFO_SDMMC, result); break; case SDMMC_SD_START: if (sdmmc_read16(REG_SDSTATUS0) == 0) { result = 1; } else { sdmmc_controller_init(); result = sdmmc_sdcard_init(); } fifoSendValue32(FIFO_SDMMC, result); break; case SDMMC_SD_IS_INSERTED: result = sdmmc_cardinserted(); fifoSendValue32(FIFO_SDMMC, result); break; case SDMMC_SD_STOP: break; } }
//--------------------------------------------------------------------------------- void sdmmc_send_acmd41(u32 arg, u32 *resp) { //--------------------------------------------------------------------------------- sdmmc_send_command(55, 0x0000, 0x000); *resp = sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1)<<16); sdmmc_send_command(41, (u16)arg, (arg>>16)); *resp = sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1)<<16); }
//--------------------------------------------------------------------------------- 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; }
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); }
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] = (u32)sdmmc_read16(REG_SDRESP0) | (u32)(sdmmc_read16(REG_SDRESP1) << 16); ctx->ret[1] = (u32)sdmmc_read16(REG_SDRESP2) | (u32)(sdmmc_read16(REG_SDRESP3) << 16); ctx->ret[2] = (u32)sdmmc_read16(REG_SDRESP4) | (u32)(sdmmc_read16(REG_SDRESP5) << 16); ctx->ret[3] = (u32)sdmmc_read16(REG_SDRESP6) | (u32)(sdmmc_read16(REG_SDRESP7) << 16); } } u32 __attribute__((noinline)) sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out) { if (handleSD.isSDHC == 0)
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--; }