static int wait_for_command_done(int bank, int timeout) { u32 toTest; u64 startTime = iphone_microtime(); if(NoMultibankCmdStatus) bank = 0; else bank &= 0xffff; toTest = 1 << (bank + 4); while((readl(NAND + FMCSTAT) & toTest) == 0) { yield(); if(iphone_has_elapsed(startTime, timeout * 1000)) { return -ETIMEDOUT; } } writel(toTest, NAND + FMCSTAT); #ifdef FTL_PROFILE if(InWrite) Time_wait_for_command_done += iphone_microtime() - startTime; #endif return 0; }
static int wait_for_nand_bank_ready(int bank) { u32 toTest; u64 startTime; writel(((WEHighHoldTime & FMCTRL_TWH_MASK) << FMCTRL_TWH_SHIFT) | ((WPPulseTime & FMCTRL_TWP_MASK) << FMCTRL_TWP_SHIFT) | (1 << (banksTable[bank] + 1)) | FMCTRL0_ON | FMCTRL0_WPB, NAND + FMCTRL0); toTest = 1 << (bank + 4); if((readl(NAND + FMCSTAT) & toTest) != 0) { writel(toTest, NAND + FMCSTAT); } writel(FMCTRL1_FLUSHFIFOS, NAND + FMCTRL1); writel(NAND_CMD_READSTATUS, NAND + NAND_CMD); wait_for_ready(500); startTime = iphone_microtime(); while(true) { u32 data; writel(0, NAND + FMDNUM); writel(FMCTRL1_DOREADDATA, NAND + FMCTRL1); if(wait_for_transfer_done(500) != 0) { LOG("nand: wait_for_nand_bank_ready: wait for transfer done timed out\n"); return -ETIMEDOUT; } data = readl(NAND + FMFIFO); writel(FMCTRL1_FLUSHRXFIFO, NAND + FMCTRL1); if((data & (1 << 6)) == 0) { if(iphone_has_elapsed(startTime, 500 * 1000)) { LOG("nand: wait_for_nand_bank_ready: wait for bit 6 of DMA timed out\n"); return -ETIMEDOUT; } } else { break; } } writel(0, NAND + NAND_CMD); wait_for_ready(500); #ifdef FTL_PROFILE if(InWrite) Time_wait_for_nand_bank_ready += iphone_microtime() - startTime; #endif return 0; }
static int transferToFlash(void* buffer, int size) { int controller = 0; int channel = 0; dma_addr_t dma; #ifdef FTL_PROFILE u64 startTime; #endif if((((u32)buffer) & 0x3) != 0) { // the buffer needs to be aligned for DMA, last two bits have to be clear return -EINVAL; } writel(readl(NAND + FMCTRL0) | (1 << FMCTRL0_DMASETTINGSHIFT), NAND + FMCTRL0); writel(size - 1, NAND + FMDNUM); writel(0x7F4, NAND + FMCTRL1); dma = dma_map_single(nand_dev, buffer, size, DMA_TO_DEVICE); iphone_dma_request(IPHONE_DMA_MEMORY, 4, 4, IPHONE_DMA_NAND, 4, 4, &controller, &channel); iphone_dma_perform((u32)dma, IPHONE_DMA_NAND, size, 0, &controller, &channel); #ifdef FTL_PROFILE startTime = iphone_microtime(); #endif if(iphone_dma_finish(controller, channel, 500) != 0) { LOG("nand: dma timed out\n"); return -ETIMEDOUT; } #ifdef FTL_PROFILE if(InWrite) Time_iphone_dma_finish += iphone_microtime() - startTime; #endif if(wait_for_transfer_done(500) != 0) { LOG("nand: waiting for transfer done timed out\n"); return -ETIMEDOUT; } writel(FMCTRL1_FLUSHFIFOS, NAND + FMCTRL1); dma_unmap_single(nand_dev, dma, size, DMA_TO_DEVICE); return 0; }
static int wait_for_ready(int timeout) { u64 startTime; if((readl(NAND + FMCSTAT) & FMCSTAT_READY) != 0) { return 0; } startTime = iphone_microtime(); while((readl(NAND + FMCSTAT) & FMCSTAT_READY) == 0) { yield(); if(iphone_has_elapsed(startTime, timeout * 1000)) { return -ETIMEDOUT; } } #ifdef FTL_PROFILE if(InWrite) Time_wait_for_ready += iphone_microtime() - startTime; #endif return 0; }
static int wait_for_transfer_done(int timeout) { u64 startTime; if((readl(NAND + FMCSTAT) & (1 << 3)) != 0) { writel(1 << 3, NAND + FMCSTAT); return 0; } startTime = iphone_microtime(); while((readl(NAND + FMCSTAT) & (1 << 3)) == 0) { yield(); if(iphone_has_elapsed(startTime, timeout * 1000)) { return -ETIMEDOUT; } } writel(1 << 3, NAND + FMCSTAT); #ifdef FTL_PROFILE if(InWrite) Time_wait_for_transfer_done += iphone_microtime() - startTime; #endif return 0; }
static int wait_for_ecc_interrupt(int timeout) { u64 startTime = iphone_microtime(); u32 mask = (1 << (NANDECC_INT - VIC_InterruptSeparator)); while((readl(VIC1 + VICRAWINTR) & mask) == 0) { yield(); if(iphone_has_elapsed(startTime, timeout * 1000)) { return -ETIMEDOUT; } } writel(1, NANDECC + NANDECC_CLEARINT); #ifdef FTL_PROFILE if(InWrite) Time_wait_for_ecc_interrupt += iphone_microtime() - startTime; #endif if((readl(VIC1 + VICRAWINTR) & mask) == 0) { return 0; } else { return -ETIMEDOUT; } }
int iphone_has_elapsed(u64 startTime, u64 elapsedTime) { if((iphone_microtime() - startTime) >= elapsedTime) return 1; else return 0; }