int VFL_Read(uint32_t virtualPageNumber, uint8_t* buffer, uint8_t* spare, int empty_ok, int* refresh_page) { if(refresh_page) { *refresh_page = FALSE; } VFLData1.field_8++; VFLData1.field_20++; uint32_t dwVpn = virtualPageNumber + (Data->pagesPerSubBlk * Data2->field_4); if(dwVpn >= Data->pagesTotal) { bufferPrintf("ftl: dwVpn overflow: %d\r\n", dwVpn); return ERROR_ARG; } if(dwVpn < Data->pagesPerSubBlk) { bufferPrintf("ftl: dwVpn underflow: %d\r\n", dwVpn); } uint16_t virtualBank; uint16_t virtualBlock; uint16_t virtualPage; uint16_t physicalBlock; virtual_page_number_to_virtual_address(dwVpn, &virtualBank, &virtualBlock, &virtualPage); physicalBlock = virtual_block_to_physical_block(virtualBank, virtualBlock); int page = physicalBlock * Data->pagesPerBlock + virtualPage; int ret = nand_read(virtualBank, page, buffer, spare, TRUE, TRUE); if(!empty_ok && ret == ERROR_EMPTYBLOCK) { ret = ERROR_NAND; } if(refresh_page) { if((Data->field_2F <= 0 && ret == 0) || ret == ERROR_NAND) { bufferPrintf("ftl: setting refresh_page to TRUE due to the following factors: Data->field_2F = %x, ret = %d\r\n", Data->field_2F, ret); *refresh_page = TRUE; } } if(ret == ERROR_ARG || ret == ERROR_NAND) { nand_bank_reset(virtualBank, 100); ret = nand_read(virtualBank, page, buffer, spare, TRUE, TRUE); if(!empty_ok && ret == ERROR_EMPTYBLOCK) { return ERROR_NAND; } if(ret == ERROR_ARG || ret == ERROR_NAND) return ret; } if(ret == ERROR_EMPTYBLOCK) { if(spare) { memset(spare, 0xFF, sizeof(SpareData)); } } return ret; }
int VFL_Read(u32 virtualPageNumber, u8* buffer, u8* spare, bool empty_ok) { u16 virtualBank; u16 virtualBlock; u16 virtualPage; u16 physicalBlock; u32 dwVpn; int page; int ret; VFLData1.field_8++; VFLData1.field_20++; dwVpn = virtualPageNumber + (NANDGeometry->pagesPerSuBlk * FTLData->field_4); if(dwVpn >= NANDGeometry->pagesTotal) { LOG("ftl: dwVpn overflow: %d\n", dwVpn); return -EINVAL; } if(dwVpn < NANDGeometry->pagesPerSuBlk) { LOG("ftl: dwVpn underflow: %d\n", dwVpn); } virtual_page_number_to_virtual_address(dwVpn, &virtualBank, &virtualBlock, &virtualPage); physicalBlock = virtual_block_to_physical_block(virtualBank, virtualBlock); page = physicalBlock * NANDGeometry->pagesPerBlock + virtualPage; #ifdef IPHONE_DEBUG LOG("ftl: vfl_read: vpn: %u, bank %d, page %u\n", virtualPageNumber, virtualBank, page); #endif ret = nand_read(virtualBank, page, buffer, spare, true, true); if(!empty_ok && ret == ERROR_EMPTYBLOCK) { ret = -EIO; } if(ret == -EINVAL || ret == -EIO) { nand_bank_reset(virtualBank, 100); ret = nand_read(virtualBank, page, buffer, spare, true, true); if(!empty_ok && ret == ERROR_EMPTYBLOCK) { return -EIO; } if(ret == -EINVAL || ret == -EIO) return ret; } if(ret == ERROR_EMPTYBLOCK) { if(spare) { memset(spare, 0xFF, sizeof(SpareData)); } } return ret; }
int nand_setup() { if(HasNANDInit) return 0; NANDSetting1 = 7; NANDSetting2 = 7; NANDSetting3 = 7; NANDSetting4 = 7; bufferPrintf("nand: Probing flash controller...\r\n"); clock_gate_switch(NAND_CLOCK_GATE1, ON); clock_gate_switch(NAND_CLOCK_GATE2, ON); int bank; for(bank = 0; bank < NAND_NUM_BANKS; bank++) { banksTable[bank] = bank; } NumValidBanks = 0; const NANDDeviceType* nandType = NULL; SET_REG(NAND + NAND_SETUP, 0); SET_REG(NAND + NAND_SETUP, GET_REG(NAND + NAND_SETUP) | (ECCType << 4)); for(bank = 0; bank < NAND_NUM_BANKS; bank++) { nand_bank_reset(bank, 100); SET_REG(NAND + NAND_CON, NAND_CON_SETTING1); SET_REG(NAND + NAND_CONFIG, ((NANDSetting1 & NAND_CONFIG_SETTING1MASK) << NAND_CONFIG_SETTING1SHIFT) | ((NANDSetting2 & NAND_CONFIG_SETTING2MASK) << NAND_CONFIG_SETTING2SHIFT) | (1 << (banksTable[bank] + 1)) | NAND_CONFIG_DEFAULTS); SET_REG(NAND + NAND_CMD, NAND_CMD_ID); wait_for_ready(500); SET_REG(NAND + NAND_CONFIG4, 0); SET_REG(NAND + NAND_CONFIG3, 0); SET_REG(NAND + NAND_CON, NAND_CON_ADDRESSDONE); wait_for_address_complete(500); nand_bank_reset_helper(bank, 100); SET_REG(NAND + NAND_TRANSFERSIZE, 8); SET_REG(NAND + NAND_CON, NAND_CON_BEGINTRANSFER); wait_for_status_bit_3(500); uint32_t id = GET_REG(NAND + NAND_DMA_SOURCE); const NANDDeviceType* candidate = SupportedDevices; while(candidate->id != 0) { if(candidate->id == id) { if(nandType == NULL) { nandType = candidate; } else if(nandType != candidate) { bufferPrintf("nand: Mismatched device IDs (0x%08x after 0x%08x)\r\n", id, nandType->id); return ERROR_ARG; } banksTable[NumValidBanks++] = bank; } candidate++; } SET_REG(NAND + NAND_CON, NAND_CON_SETTING1); } if(nandType == NULL) { bufferPrintf("nand: No supported NAND found\r\n"); return ERROR_ARG; } Data.DeviceID = nandType->id; Data.banksTable = banksTable; NANDSetting2 = (((clock_get_frequency(FrequencyBaseBus) * (nandType->NANDSetting2 + 1)) + 99999999)/100000000) - 1; NANDSetting1 = (((clock_get_frequency(FrequencyBaseBus) * (nandType->NANDSetting1 + 1)) + 99999999)/100000000) - 1; NANDSetting3 = (((clock_get_frequency(FrequencyBaseBus) * (nandType->NANDSetting3 + 1)) + 99999999)/100000000) - 1; NANDSetting4 = (((clock_get_frequency(FrequencyBaseBus) * (nandType->NANDSetting4 + 1)) + 99999999)/100000000) - 1; if(NANDSetting2 > 7) NANDSetting2 = 7; if(NANDSetting1 > 7) NANDSetting1 = 7; if(NANDSetting3 > 7) NANDSetting3 = 7; if(NANDSetting4 > 7) NANDSetting4 = 7; Data.blocksPerBank = nandType->blocksPerBank; Data.banksTotal = NumValidBanks; Data.sectorsPerPage = nandType->sectorsPerPage; Data.userSubBlksTotal = nandType->userSubBlksTotal; Data.bytesPerSpare = nandType->bytesPerSpare; Data.field_2E = 4; Data.field_2F = 3; Data.pagesPerBlock = nandType->pagesPerBlock; if(Data.sectorsPerPage > 4) { LargePages = TRUE; } else { LargePages = FALSE; } if(nandType->ecc1 == 6) { ECCType = 4; TotalECCDataSize = Data.sectorsPerPage * 15; } else if(nandType->ecc1 == 8) { ECCType = 8; TotalECCDataSize = Data.sectorsPerPage * 20; } else if(nandType->ecc1 == 4) { ECCType = 0; TotalECCDataSize = Data.sectorsPerPage * 10; } if(nandType->ecc2 == 6) { ECCType2 = 4; } else if(nandType->ecc2 == 8) { ECCType2 = 8; } else if(nandType->ecc2 == 4) { ECCType2 = 0; } Data.field_4 = 5; Data.bytesPerPage = SECTOR_SIZE * Data.sectorsPerPage; Data.pagesPerBank = Data.pagesPerBlock * Data.blocksPerBank; Data.pagesTotal = Data.pagesPerBank * Data.banksTotal; Data.pagesPerSubBlk = Data.pagesPerBlock * Data.banksTotal; Data.userPagesTotal = Data.userSubBlksTotal * Data.pagesPerSubBlk; Data.subBlksTotal = (Data.banksTotal * Data.blocksPerBank) / Data.banksTotal; Data2.field_2 = Data.subBlksTotal - Data.userSubBlksTotal - 28; Data2.field_0 = Data2.field_2 + 4; Data2.field_4 = Data2.field_2 + 5; Data2.field_6 = 3; Data2.field_8 = 23; if(Data2.field_8 == 0) Data.field_22 = 0; int bits = 0; int i = Data2.field_8; while((i <<= 1) != 0) { bits++; } Data.field_22 = bits; bufferPrintf("nand: DEVICE: %08x\r\n", Data.DeviceID); bufferPrintf("nand: BANKS_TOTAL: %d\r\n", Data.banksTotal); bufferPrintf("nand: BLOCKS_PER_BANK: %d\r\n", Data.blocksPerBank); bufferPrintf("nand: SUBLKS_TOTAL: %d\r\n", Data.subBlksTotal); bufferPrintf("nand: USER_SUBLKS_TOTAL: %d\r\n", Data.userSubBlksTotal); bufferPrintf("nand: PAGES_PER_SUBLK: %d\r\n", Data.pagesPerSubBlk); bufferPrintf("nand: PAGES_PER_BANK: %d\r\n", Data.pagesPerBank); bufferPrintf("nand: SECTORS_PER_PAGE: %d\r\n", Data.sectorsPerPage); bufferPrintf("nand: BYTES_PER_SPARE: %d\r\n", Data.bytesPerSpare); bufferPrintf("nand: BYTES_PER_PAGE: %d\r\n", Data.bytesPerPage); bufferPrintf("nand: PAGES_PER_BLOCK: %d\r\n", Data.pagesPerBlock); aTemporaryReadEccBuf = (uint8_t*) malloc(Data.bytesPerPage); memset(aTemporaryReadEccBuf, 0xFF, SECTOR_SIZE); aTemporarySBuf = (uint8_t*) malloc(Data.bytesPerSpare); HasNANDInit = TRUE; return 0; }
int nand_setup() { if(HasNANDInit) return 0; WEHighHoldTime = 7; WPPulseTime = 7; NANDSetting3 = 7; NANDSetting4 = 7; bufferPrintf("nand: Probing flash controller...\r\n"); clock_gate_switch(NAND_CLOCK_GATE1, ON); clock_gate_switch(NAND_CLOCK_GATE2, ON); int bank; for(bank = 0; bank < NAND_NUM_BANKS; bank++) { banksTable[bank] = bank; } NumValidBanks = 0; const NANDDeviceType* nandType = NULL; SET_REG(NAND + RSCTRL, 0); SET_REG(NAND + RSCTRL, GET_REG(NAND + RSCTRL) | (ECCType << 4)); for(bank = 0; bank < NAND_NUM_BANKS; bank++) { nand_bank_reset(bank, 100); SET_REG(NAND + FMCTRL1, FMCTRL1_FLUSHFIFOS); SET_REG(NAND + FMCTRL0, ((WEHighHoldTime & FMCTRL_TWH_MASK) << FMCTRL_TWH_SHIFT) | ((WPPulseTime & FMCTRL_TWP_MASK) << FMCTRL_TWP_SHIFT) | (1 << (banksTable[bank] + 1)) | FMCTRL0_ON | FMCTRL0_WPB); SET_REG(NAND + NAND_CMD, NAND_CMD_ID); wait_for_ready(500); SET_REG(NAND + FMANUM, 0); SET_REG(NAND + FMADDR0, 0); SET_REG(NAND + FMCTRL1, FMCTRL1_DOTRANSADDR); wait_for_address_done(500); wait_for_command_done(bank, 100); SET_REG(NAND + FMDNUM, 8); SET_REG(NAND + FMCTRL1, FMCTRL1_DOREADDATA); wait_for_transfer_done(500); uint32_t id = GET_REG(NAND + FMFIFO); const NANDDeviceType* candidate = SupportedDevices; while(candidate->id != 0) { if(candidate->id == id) { if(nandType == NULL) { nandType = candidate; } else if(nandType != candidate) { bufferPrintf("nand: Mismatched device IDs (0x%08x after 0x%08x)\r\n", id, nandType->id); return ERROR_ARG; } banksTable[NumValidBanks++] = bank; } candidate++; } SET_REG(NAND + FMCTRL1, FMCTRL1_FLUSHFIFOS); } if(nandType == NULL) { bufferPrintf("nand: No supported NAND found\r\n"); return ERROR_ARG; } Geometry.DeviceID = nandType->id; Geometry.banksTable = banksTable; WPPulseTime = (((clock_get_frequency(FrequencyBaseBus) * (nandType->WPPulseTime + 1)) + 99999999)/100000000) - 1; WEHighHoldTime = (((clock_get_frequency(FrequencyBaseBus) * (nandType->WEHighHoldTime + 1)) + 99999999)/100000000) - 1; NANDSetting3 = (((clock_get_frequency(FrequencyBaseBus) * (nandType->NANDSetting3 + 1)) + 99999999)/100000000) - 1; NANDSetting4 = (((clock_get_frequency(FrequencyBaseBus) * (nandType->NANDSetting4 + 1)) + 99999999)/100000000) - 1; if(WPPulseTime > 7) WPPulseTime = 7; if(WEHighHoldTime > 7) WEHighHoldTime = 7; if(NANDSetting3 > 7) NANDSetting3 = 7; if(NANDSetting4 > 7) NANDSetting4 = 7; Geometry.blocksPerBank = nandType->blocksPerBank; Geometry.banksTotal = NumValidBanks; Geometry.sectorsPerPage = nandType->sectorsPerPage; Geometry.userSuBlksTotal = nandType->userSuBlksTotal; Geometry.bytesPerSpare = nandType->bytesPerSpare; Geometry.field_2E = 4; Geometry.field_2F = 3; Geometry.pagesPerBlock = nandType->pagesPerBlock; if(Geometry.sectorsPerPage > 4) { LargePages = TRUE; } else { LargePages = FALSE; } if(nandType->ecc1 == 6) { ECCType = 4; TotalECCDataSize = Geometry.sectorsPerPage * 15; } else if(nandType->ecc1 == 8) { ECCType = 8; TotalECCDataSize = Geometry.sectorsPerPage * 20; } else if(nandType->ecc1 == 4) { ECCType = 0; TotalECCDataSize = Geometry.sectorsPerPage * 10; } if(nandType->ecc2 == 6) { ECCType2 = 4; } else if(nandType->ecc2 == 8) { ECCType2 = 8; } else if(nandType->ecc2 == 4) { ECCType2 = 0; } Geometry.field_4 = 5; Geometry.bytesPerPage = SECTOR_SIZE * Geometry.sectorsPerPage; Geometry.pagesPerBank = Geometry.pagesPerBlock * Geometry.blocksPerBank; Geometry.pagesTotal = Geometry.pagesPerBank * Geometry.banksTotal; Geometry.pagesPerSuBlk = Geometry.pagesPerBlock * Geometry.banksTotal; Geometry.userPagesTotal = Geometry.userSuBlksTotal * Geometry.pagesPerSuBlk; Geometry.suBlksTotal = (Geometry.banksTotal * Geometry.blocksPerBank) / Geometry.banksTotal; FTLData.field_2 = Geometry.suBlksTotal - Geometry.userSuBlksTotal - 28; FTLData.sysSuBlks = FTLData.field_2 + 4; FTLData.field_4 = FTLData.field_2 + 5; FTLData.field_6 = 3; FTLData.field_8 = 23; if(FTLData.field_8 == 0) Geometry.field_22 = 0; int bits = 0; int i = FTLData.field_8; while((i <<= 1) != 0) { bits++; } Geometry.field_22 = bits; bufferPrintf("nand: DEVICE: %08x\r\n", Geometry.DeviceID); bufferPrintf("nand: BANKS_TOTAL: %d\r\n", Geometry.banksTotal); bufferPrintf("nand: BLOCKS_PER_BANK: %d\r\n", Geometry.blocksPerBank); bufferPrintf("nand: SUBLKS_TOTAL: %d\r\n", Geometry.suBlksTotal); bufferPrintf("nand: USER_SUBLKS_TOTAL: %d\r\n", Geometry.userSuBlksTotal); bufferPrintf("nand: PAGES_PER_SUBLK: %d\r\n", Geometry.pagesPerSuBlk); bufferPrintf("nand: PAGES_PER_BANK: %d\r\n", Geometry.pagesPerBank); bufferPrintf("nand: SECTORS_PER_PAGE: %d\r\n", Geometry.sectorsPerPage); bufferPrintf("nand: BYTES_PER_SPARE: %d\r\n", Geometry.bytesPerSpare); bufferPrintf("nand: BYTES_PER_PAGE: %d\r\n", Geometry.bytesPerPage); bufferPrintf("nand: PAGES_PER_BLOCK: %d\r\n", Geometry.pagesPerBlock); aTemporaryReadEccBuf = (uint8_t*) malloc(Geometry.bytesPerPage); memset(aTemporaryReadEccBuf, 0xFF, SECTOR_SIZE); aTemporarySBuf = (uint8_t*) malloc(Geometry.bytesPerSpare); HasNANDInit = TRUE; return 0; }