示例#1
0
static int transferToFlash(void* buffer, int size) {
	int controller = 0;
	int channel = 0;

	if((((uint32_t)buffer) & 0x3) != 0) {
		// the buffer needs to be aligned for DMA, last two bits have to be clear
		return ERROR_ALIGN;
	}

	SET_REG(NAND + FMCTRL0, GET_REG(NAND + FMCTRL0) | (1 << FMCTRL0_DMASETTINGSHIFT));
	SET_REG(NAND + FMDNUM, size - 1);
	SET_REG(NAND + FMCTRL1, 0x7F4);

	CleanCPUDataCache();

	dma_request(DMA_MEMORY, 4, 4, DMA_NAND, 4, 4, &controller, &channel, NULL);
	dma_perform((uint32_t)buffer, DMA_NAND, size, 0, &controller, &channel);

	if(dma_finish(controller, channel, 500) != 0) {
		bufferPrintf("nand: dma timed out\r\n");
		return ERROR_TIMEOUT;
	}

	if(wait_for_transfer_done(500) != 0) {
		bufferPrintf("nand: waiting for transfer done timed out\r\n");
		return ERROR_TIMEOUT;
	}

	SET_REG(NAND + FMCTRL1, FMCTRL1_FLUSHFIFOS);

	CleanAndInvalidateCPUDataCache();

	return 0;
}
示例#2
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;
}
示例#3
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;
}
示例#4
0
int nand_read_status()
{
	int status;

	SET_REG(NAND + NAND_REG_44, GET_REG(NAND + NAND_REG_44) & ~(1 << 4));
	SET_REG(NAND + FMCTRL1, FMCTRL1_CLEARALL);
	SET_REG(NAND + NAND_CMD, NAND_CMD_READSTATUS);
	SET_REG(NAND + FMDNUM, 0);
	SET_REG(NAND + FMCTRL1, FMCTRL1_CLEARALL | FMCTRL1_DOREADDATA);

	wait_for_transfer_done(500);

	status = GET_REG(NAND + FMFIFO);
	SET_REG(NAND + FMCTRL1, FMCTRL1_CLEARALL);
	SET_REG(NAND + FMCSTAT, 1 << 3);
	SET_REG(NAND + NAND_REG_44, GET_REG(NAND + NAND_REG_44) | (1 << 2));

	return status;
}
示例#5
0
int nand_read_status(void)
{
    int status;

    writel(readl(NAND + NAND_REG_44) & ~(1 << 4), NAND + NAND_REG_44);
    writel(FMCTRL1_CLEARALL, NAND + FMCTRL1);
    writel(NAND_CMD_READSTATUS, NAND + NAND_CMD);
    writel(0, NAND + FMDNUM);
    writel(FMCTRL1_CLEARALL | FMCTRL1_DOREADDATA, NAND + FMCTRL1);

    wait_for_transfer_done(500);

    status = readl(NAND + FMFIFO);
    writel(FMCTRL1_CLEARALL, NAND + FMCTRL1);
    writel(1 << 3, NAND + FMCSTAT);
    writel(readl(NAND + NAND_REG_44) | (1 << 2), NAND + NAND_REG_44);

    return status;
}
示例#6
0
static int wait_for_nand_bank_ready(int bank) {
	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);

	uint32_t toTest = 1 << (bank + 4);
	if((GET_REG(NAND + FMCSTAT) & toTest) != 0) {
		SET_REG(NAND + FMCSTAT, toTest);
	}

	SET_REG(NAND + FMCTRL1, FMCTRL1_FLUSHFIFOS); 
	SET_REG(NAND + NAND_CMD, NAND_CMD_READSTATUS);
	wait_for_ready(500);

	uint64_t startTime = timer_get_system_microtime();
	while(TRUE) {
		SET_REG(NAND + FMDNUM, 0);
		SET_REG(NAND + FMCTRL1, FMCTRL1_DOREADDATA);

		if(wait_for_transfer_done(500) != 0) {
			bufferPrintf("nand: wait_for_nand_bank_ready: wait for transfer done timed out\r\n");
			return ERROR_TIMEOUT;
		}


		uint32_t data = GET_REG(NAND + FMFIFO);
		SET_REG(NAND + FMCTRL1, FMCTRL1_FLUSHRXFIFO);
		if((data & (1 << 6)) == 0) {
			if(has_elapsed(startTime, 500 * 1000)) {
				bufferPrintf("nand: wait_for_nand_bank_ready: wait for bit 6 of DMA timed out\r\n");
				return ERROR_TIMEOUT;
			}
		} else {
			break;
		}
	}

	SET_REG(NAND + NAND_CMD, 0);
	wait_for_ready(500);
	return 0;
}
示例#7
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;
}