Example #1
0
static BOOL32 check_format_mark(void)
{
	// This function reads a flash page from (bank #0, block #0) in order to check whether the SSD is formatted or not.

#ifdef __GNUC__
	extern UINT32 size_of_firmware_image;
	UINT32 firmware_image_pages = (((UINT32) (&size_of_firmware_image)) + BYTES_PER_FW_PAGE - 1) / BYTES_PER_FW_PAGE;
#else
	extern UINT32 Image$$ER_CODE$$RO$$Length;
	extern UINT32 Image$$ER_RW$$RW$$Length;
	UINT32 firmware_image_bytes = ((UINT32) &Image$$ER_CODE$$RO$$Length) + ((UINT32) &Image$$ER_RW$$RW$$Length);
	UINT32 firmware_image_pages = (firmware_image_bytes + BYTES_PER_FW_PAGE - 1) / BYTES_PER_FW_PAGE;
#endif

	UINT32 format_mark_page_offset = FW_PAGE_OFFSET + firmware_image_pages;
	UINT32 temp;

	flash_clear_irq();	// clear any flash interrupt flags that might have been set

	SETREG(FCP_CMD, FC_COL_ROW_READ_OUT);
	SETREG(FCP_BANK, REAL_BANK(0));
	SETREG(FCP_OPTION, FO_E);
	SETREG(FCP_DMA_ADDR, FTL_BUF_ADDR); 	// flash -> DRAM
	SETREG(FCP_DMA_CNT, BYTES_PER_SECTOR);
	SETREG(FCP_COL, 0);
	SETREG(FCP_ROW_L(0), format_mark_page_offset);
	SETREG(FCP_ROW_H(0), format_mark_page_offset);

	// At this point, we do not have to check Waiting Room status before issuing a command,
	// because scan list loading has been completed just before this function is called.
	SETREG(FCP_ISSUE, NULL);

	// wait for the FC_COL_ROW_READ_OUT command to be accepted by bank #0
	while ((GETREG(WR_STAT) & 0x00000001) != 0);

	// wait until bank #0 finishes the read operation
	while (BSP_FSM(0) != BANK_IDLE);

	// Now that the read operation is complete, we can check interrupt flags.
	temp = BSP_INTR(0) & FIRQ_ALL_FF;

	// clear interrupt flags
	CLR_BSP_INTR(0, 0xFF);

	if (temp != 0)
	{
		return FALSE;	// the page contains all-0xFF (the format mark does not exist.)
	}
	else
	{
		return TRUE;	// the page contains something other than 0xFF (it must be the format mark)
	}
}
Example #2
0
void ftl_isr(void)
{
	// interrupt service routine for flash interrupts

	UINT32 bank;
	UINT32 bsp_intr_flag;

	for (bank = 0; bank < NUM_BANKS; bank++)
	{
		while (BSP_FSM(bank) != BANK_IDLE);

		bsp_intr_flag = BSP_INTR(bank);

		if (bsp_intr_flag == 0)
		{
			continue;
		}

		UINT32 fc = GETREG(BSP_CMD(bank));

		CLR_BSP_INTR(bank, bsp_intr_flag);

		if (bsp_intr_flag & FIRQ_DATA_CORRUPT)
		{
			g_read_fail_count++;
		}

		if (bsp_intr_flag & (FIRQ_BADBLK_H | FIRQ_BADBLK_L))
		{
			if (fc == FC_COL_ROW_IN_PROG || fc == FC_IN_PROG || fc == FC_PROG)
			{
				g_program_fail_count++;
			}
			else
			{
				ASSERT(fc == FC_ERASE);
				g_erase_fail_count++;
			}
		}
	}

	// clear the flash interrupt flag at the interrupt controller
	SETREG(APB_INT_STS, INTR_FLASH);
}
Example #3
0
// BSP interrupt service routine
void ftl_isr(void)
{
    UINT32 bank;
    UINT32 bsp_intr_flag;

    uart_print("BSP interrupt occured...");
    // interrupt pending clear (ICU)
    SETREG(APB_INT_STS, INTR_FLASH);

    for (bank = 0; bank < NUM_BANKS; bank++) {
        while (BSP_FSM(bank) != BANK_IDLE);
        // get interrupt flag from BSP
        bsp_intr_flag = BSP_INTR(bank);

        if (bsp_intr_flag == 0) {
            continue;
        }
        UINT32 fc = GETREG(BSP_CMD(bank));
        // BSP clear
        CLR_BSP_INTR(bank, bsp_intr_flag);

        // interrupt handling
		if (bsp_intr_flag & FIRQ_DATA_CORRUPT) {
            uart_printf("BSP interrupt at bank: 0x%x", bank);
            uart_print("FIRQ_DATA_CORRUPT occured...");
		}
		if (bsp_intr_flag & (FIRQ_BADBLK_H | FIRQ_BADBLK_L)) {
            uart_printf("BSP interrupt at bank: 0x%x", bank);
			if (fc == FC_COL_ROW_IN_PROG || fc == FC_IN_PROG || fc == FC_PROG) {
                uart_print("find runtime bad block when block program...");
			}
			else {
                uart_printf("find runtime bad block when block erase...vblock #: %d", GETREG(BSP_ROW_H(bank)) / PAGES_PER_BLK);
				ASSERT(fc == FC_ERASE);
			}
		}
    }
}
Example #4
0
void loading_misc_meta()
{
	/*int i;
	flash_finish();

	disable_irq();
	flash_clear_irq();

	for(i = 0 ;i < NUM_BANKS;i++){
		SETREG(FCP_CMD, FC_COL_ROW_READ_OUT);	
		SETREG(FCP_DMA_CNT, sizeof(misc_metadata));
		SETREG(FCP_COL, 0);
		SETREG(FCP_DMA_ADDR, FTL_BUF_ADDR);
		//SETREG(FCP_DMA_ADDR, &(g_misc_meta[i]));
		SETREG(FCP_OPTION, FO_P | FO_E );		
		SETREG(FCP_ROW_L(i), PAGES_PER_VBLK);
		SETREG(FCP_ROW_H(i), PAGES_PER_VBLK);
		flash_issue_cmd(i, RETURN_ON_ISSUE);
		flash_finish();
		CLR_BSP_INTR(i,0xff);
		mem_copy(&(g_misc_meta[i]),FTL_BUF_ADDR,sizeof(misc_metadata));
	}

	enable_irq();*/
	UINT32 load_flag = 0;
	UINT32 bank, page_num;
	UINT32 load_cnt = 0;

	flash_finish();

	disable_irq();
	flash_clear_irq();	// clear any flash interrupt flags that might have been set

	// scan valid metadata in descending order from last page offset
	for (page_num = PAGES_PER_VBLK - 1; page_num != ((UINT32) -1); page_num--)
	{
		for (bank = 0; bank < NUM_BANKS; bank++)
		{
			if (load_flag & (0x1 << bank))
			{
				continue;
			}
			// read valid metadata from misc. metadata area
			nand_page_ptread(bank,
					1,
					page_num,
					0,
					((sizeof(misc_metadata) + BYTES_PER_SECTOR -1 ) / BYTES_PER_SECTOR),	
					FTL_BUF_ADDR,
					RETURN_ON_ISSUE);
			flash_finish();
			mem_copy(&g_misc_meta[bank], FTL_BUF_ADDR, sizeof(misc_metadata));
		}

		for (bank = 0; bank < NUM_BANKS; bank++)
		{
			if (!(load_flag & (0x1 << bank)) && !(BSP_INTR(bank) & FIRQ_ALL_FF))
			{
				load_flag = load_flag | (0x1 << bank);
				load_cnt++;
			}
			CLR_BSP_INTR(bank, 0xFF);
		}
	}
	ASSERT(load_cnt == NUM_BANKS);

	enable_irq();
}
Example #5
0
// misc + VCOUNT
static void load_misc_metadata(void)
{
    UINT32 misc_meta_bytes = NUM_MISC_META_SECT * BYTES_PER_SECTOR;
    UINT32 vcount_bytes    = NUM_VCOUNT_SECT * BYTES_PER_SECTOR;
    UINT32 vcount_addr     = VCOUNT_ADDR;
    UINT32 vcount_boundary = VCOUNT_ADDR + VCOUNT_BYTES;

    UINT32 load_flag = 0;
    UINT32 bank, page_num;
    UINT32 load_cnt = 0;

    flash_finish();

	disable_irq();
	flash_clear_irq();	// clear any flash interrupt flags that might have been set

    // scan valid metadata in descending order from last page offset
    for (page_num = PAGES_PER_BLK - 1; page_num != ((UINT32) -1); page_num--)
    {
        for (bank = 0; bank < NUM_BANKS; bank++)
        {
            if (load_flag & (0x1 << bank))
            {
                continue;
            }
            // read valid metadata from misc. metadata area
            nand_page_ptread(bank,
                             MISCBLK_VBN,
                             page_num,
                             0,
                             NUM_MISC_META_SECT + NUM_VCOUNT_SECT,
                             FTL_BUF(bank),
                             RETURN_ON_ISSUE);
        }
        flash_finish();

        for (bank = 0; bank < NUM_BANKS; bank++)
        {
            if (!(load_flag & (0x1 << bank)) && !(BSP_INTR(bank) & FIRQ_ALL_FF))
            {
                load_flag = load_flag | (0x1 << bank);
                load_cnt++;
            }
            CLR_BSP_INTR(bank, 0xFF);
        }
    }
    ASSERT(load_cnt == NUM_BANKS);

    for (bank = 0; bank < NUM_BANKS; bank++)
    {
        // misc. metadata
        mem_copy(&g_misc_meta[bank], FTL_BUF(bank), sizeof(misc_metadata));

        // vcount metadata
        if (vcount_addr <= vcount_boundary)
        {
            mem_copy(vcount_addr, FTL_BUF(bank) + misc_meta_bytes, vcount_bytes);
            vcount_addr += vcount_bytes;

        }
    }
	enable_irq();
}
Example #6
0
void test_nand_blocks(void)
{
	// This function is a utility that writes random data to flash pages and verifies them.
	// This function takes a long time to complete.

	UINT32 bank, vblk_offset, page_offset, data, bad;

	#define write_buffer_base	DRAM_BASE
	#define read_buffer_base	(DRAM_BASE + BYTES_PER_VBLK)

	disable_irq();
	flash_clear_irq();

	mem_set_sram(g_test_result, 0, sizeof(g_test_result));

	// Configure the flash controller so that any FIRQ_* does not lead to pause state.
	SETREG(FCONF_PAUSE, 0);

	// STEP 1 - prepare random data

	srand(10);

	for (page_offset = 0; page_offset < PAGES_PER_VBLK; page_offset++)
	{
		data = (rand() & 0xFFFF) | (rand() << 16);
		mem_set_dram(write_buffer_base + page_offset * BYTES_PER_PAGE, data, BYTES_PER_PAGE);
	}

	for (vblk_offset = 1; vblk_offset < VBLKS_PER_BANK; vblk_offset++)
	{
		// STEP 2 - erase a block at each bank

		for (bank = 0; bank < NUM_BANKS; bank++)
		{
			UINT32 rbank = REAL_BANK(bank);

			SETREG(FCP_CMD, FC_ERASE);
			SETREG(FCP_BANK, rbank);
			SETREG(FCP_OPTION, FO_P);
			SETREG(FCP_ROW_L(bank), vblk_offset * PAGES_PER_VBLK);
			SETREG(FCP_ROW_H(bank), vblk_offset * PAGES_PER_VBLK);

			while ((GETREG(WR_STAT) & 0x00000001) != 0);
			SETREG(FCP_ISSUE, NULL);
		}

		// STEP 3 - write to every pages of the erased block

		for (page_offset = 0; page_offset < PAGES_PER_VBLK; page_offset++)
		{
			for (bank = 0; bank < NUM_BANKS; bank++)
			{
				UINT32 rbank = REAL_BANK(bank);

				SETREG(FCP_CMD, FC_COL_ROW_IN_PROG);
				SETREG(FCP_BANK, rbank);
				SETREG(FCP_OPTION, FO_P | FO_E | FO_B_W_DRDY);
				SETREG(FCP_DMA_ADDR, write_buffer_base + page_offset * BYTES_PER_PAGE);
				SETREG(FCP_DMA_CNT, BYTES_PER_PAGE);
				SETREG(FCP_COL, 0);
				SETREG(FCP_ROW_L(bank), vblk_offset * PAGES_PER_VBLK + page_offset);
				SETREG(FCP_ROW_H(bank), vblk_offset * PAGES_PER_VBLK + page_offset);

				while ((GETREG(WR_STAT) & 0x00000001) != 0);
				SETREG(FCP_ISSUE, NULL);
			}
		}

		// STEP 4 - check the FC_ERASE and FC_COL_ROW_IN_PROG results.

		bad = 0;

		while (GETREG(MON_CHABANKIDLE) != 0);

		for (bank = 0; bank < NUM_BANKS; bank++)
		{
			if (BSP_INTR(bank) & (FIRQ_BADBLK_H | FIRQ_BADBLK_L))
			{
				bad |= (1 << bank);
				CLR_BSP_INTR(bank, 0xFF);
				g_test_result[bank].erase_prog_fail++;
			}
		}

		// STEP 5 - read and verify
		// We check ECC/CRC results for verification.

		for (page_offset = 0; page_offset < PAGES_PER_VBLK; page_offset++)
		{
			for (bank = 0; bank < NUM_BANKS; bank++)
			{
				UINT32 rbank = REAL_BANK(bank);

				if (bad & (1 << bank))
					continue;

				SETREG(FCP_CMD, FC_COL_ROW_READ_OUT);
				SETREG(FCP_BANK, rbank);
				SETREG(FCP_OPTION, FO_P | FO_E);
				SETREG(FCP_DMA_ADDR, read_buffer_base + bank * BYTES_PER_PAGE);
				SETREG(FCP_DMA_CNT, BYTES_PER_PAGE);
				SETREG(FCP_COL, 0);
				SETREG(FCP_ROW_L(bank), vblk_offset * PAGES_PER_VBLK + page_offset);
				SETREG(FCP_ROW_H(bank), vblk_offset * PAGES_PER_VBLK + page_offset);

				while ((GETREG(WR_STAT) & 0x00000001) != 0);
				SETREG(FCP_ISSUE, NULL);
			}
		}

		// STEP 6 - check the FC_COL_ROW_READ_OUT results

		while (GETREG(MON_CHABANKIDLE) != 0);

		for (bank = 0; bank < NUM_BANKS; bank++)
		{
			if (BSP_INTR(bank) & FIRQ_DATA_CORRUPT)
			{
				bad |= (1 << bank);
				CLR_BSP_INTR(bank, 0xFF);
				g_test_result[bank].read_fail++;
			}
		}

		// STEP 7 - erase the blocks, but not the bad ones

		for (bank = 0; bank < NUM_BANKS; bank++)
		{
			UINT32 rbank = REAL_BANK(bank);

			if (bad & (1 << bank))
				continue;

			SETREG(FCP_CMD, FC_ERASE);
			SETREG(FCP_BANK, rbank);
			SETREG(FCP_OPTION, FO_P);
			SETREG(FCP_ROW_L(bank), vblk_offset * PAGES_PER_VBLK);
			SETREG(FCP_ROW_H(bank), vblk_offset * PAGES_PER_VBLK);

			while ((GETREG(WR_STAT) & 0x00000001) != 0);
			SETREG(FCP_ISSUE, NULL);
		}
	}

	// Now that bad blocks contain non-0xFF data, it is a good time to use install.exe to scan bad blocks.
}