static UINT32 assign_new_write_vpn(UINT32 const bank) { UINT32 write_vpn; UINT32 vblock; write_vpn = get_cur_write_vpn(bank); vblock = write_vpn / PAGES_PER_BLK; // NOTE: if next new write page's offset is // the last page offset of vblock (i.e. PAGES_PER_BLK - 1), if ((write_vpn % PAGES_PER_BLK) == (PAGES_PER_BLK - 2)) { // then, because of the flash controller limitation // (prohibit accessing a spare area (i.e. OOB)), // thus, we persistenly write a lpn list into last page of vblock. mem_copy(TEMP_BUF(bank), g_misc_meta[bank].lpn_list_of_cur_vblock, sizeof(UINT32) * PAGES_PER_BLK); // fix minor bug misc_w++; nand_page_ptprogram(bank, vblock, PAGES_PER_BLK - 1, 0, ((sizeof(UINT32) * PAGES_PER_BLK + BYTES_PER_SECTOR - 1 ) / BYTES_PER_SECTOR), TEMP_BUF(bank)); mem_set_sram(g_misc_meta[bank].lpn_list_of_cur_vblock, 0x00000000, sizeof(UINT32) * PAGES_PER_BLK); inc_full_blk_cnt(bank); // do garbage collection if necessary if (is_full_all_blks(bank)) { GC: garbage_collection(bank); return get_cur_write_vpn(bank); } do { vblock++; if(vblock == VBLKS_PER_BANK) { uart_printf(" vblock == VBLKS_PER_BANK"); goto GC; } }while (get_vcount(bank, vblock) == VC_MAX); } // write page -> next block if (vblock != (write_vpn / PAGES_PER_BLK)) { write_vpn = vblock * PAGES_PER_BLK; } else { write_vpn++; } set_new_write_vpn(bank, write_vpn); return write_vpn; }
void sata_reset(void) { disable_interrupt(); mem_set_sram(&g_sata_context, 0, sizeof(g_sata_context)); g_sata_context.write_cache_enabled = TRUE; g_sata_context.read_look_ahead_enabled = TRUE; SETREG(PMU_ResetCon, RESET_SATA | RESET_SATADWCLK | RESET_SATAHCLK | RESET_PMCLK | RESET_PHYDOMAIN); delay(100); SETREG(PHY_DEBUG, 0x400A040E); int count=0; while ((GETREG(PHY_DEBUG) & BIT30) == 1) { count++; if (count > 100000) { uart_print_level_1("Warning1 in sata_reset::eventq_get\r\n"); count=0; } } SETREG(SATA_BUF_PAGE_SIZE, BYTES_PER_PAGE); SETREG(SATA_WBUF_BASE, (WR_BUF_ADDR - DRAM_BASE)); SETREG(SATA_RBUF_BASE, (RD_BUF_ADDR - DRAM_BASE)); SETREG(SATA_WBUF_SIZE, NUM_WR_BUFFERS); SETREG(SATA_RBUF_SIZE, NUM_RD_BUFFERS); SETREG(SATA_WBUF_MARGIN, 16); SETREG(SATA_RESET_WBUF_PTR, BIT0); SETREG(SATA_RESET_RBUF_PTR, BIT0); SETREG(SATA_NCQ_BASE, g_sata_ncq.queue); SETREG(SATA_EQ_CFG_1, BIT0 | BIT14 | BIT9 | BIT16 | ((NUM_BANKS / 2) << 24)); SETREG(SATA_EQ_CFG_2, (EQ_MARGIN & 0xF) << 16); SETREG(SATA_CFG_10, BIT0); SETREG(SATA_NCQ_CTRL, AUTOINC | FLUSH_NCQ); SETREG(SATA_NCQ_CTRL, AUTOINC); SETREG(SATA_CFG_5, BIT12 | BIT11*BSO_RX_SSC | (BIT9|BIT10)*BSO_TX_SSC | BIT4*0x05); SETREG(SATA_CFG_8, 0); SETREG(SATA_CFG_9, BIT20); SETREG(SATA_MAX_LBA, MAX_LBA); SETREG(APB_INT_STS, INTR_SATA); #if OPTION_SLOW_SATA SETREG(SATA_PHY_CTRL, 0x00000310); #else SETREG(SATA_PHY_CTRL, 0x00000300); #endif SETREG(SATA_ERROR, 0xFFFFFFFF); SETREG(SATA_INT_STAT, 0xFFFFFFFF); SETREG(SATA_CTRL_1, BIT31); count=0; while ((GETREG(SATA_INT_STAT) & PHY_ONLINE) == 0) { count++; if (count > 100000) { uart_print_level_1("Warning2 in sata_reset::eventq_get\r\n"); count=0; } } SETREG(SATA_CTRL_1, BIT31 | BIT25 | BIT24); SETREG(SATA_INT_ENABLE, PHY_ONLINE); enable_interrupt(); }
void init_jasmine(void) { UINT32 i, bank; extern UINT32 Image$$ER_ZI$$ZI$$Base; extern UINT32 Image$$ER_ZI$$ZI$$Length; // PLL initialization SETREG(CLKSelCon, USE_BYPASS_CLK); SETREG(PllCon, PLL_PD); // power down delay(600); // at least 500ns SETREG(PllCon, PLL_CLK_CONFIG | PLL_PD); // change settings delay(600); // at least 1us SETREG(PllCon, PLL_CLK_CONFIG); // power up while ((GETREG(PllCon) & PLL_LD) == 0); // wait lock SETREG(CLKSelCon, USE_PLL_CLK); // reset hardware modules SETREG(PMU_ResetCon, RESET_SDRAM | RESET_BM | RESET_SATA | RESET_FLASH); // GPIO bits // There are 7 GPIO bits from 0 to 6. // 0: This bit is connected to J2 (Factory Mode jumper). The ROM firmware configures it as input mode. // While main firmware is running, it can be freely used for arbitrary purpose. Beware that a "1" output while // the Factory Mode jumper is set to Normal position (tied to ground) can lead to circuit damage. // A "0" output while the jumper is tied to Vcc will also lead to circuit damage. // 1: This bit is connected to J3 (Boot ROM). The controller hardware checks its status upon reset. // After the reset is done, you can remove the jumper and use the pin as output. // 2 through 5: The IO pins for these bits are shared between MAX3232C (UART chip) and J4. // In order to use J4, you have to turn on the switches of SW4 and turn off the switches 1 through 4 in SW2. // In order to use UART, you have to turn off the switches of SW4 and turn on the switches 1 through 4 in SW2. // 6: This bit is connected to D4 (LED) via SW2. #if OPTION_UART_DEBUG SETREG(GPIO_MOD, 0); SETREG(GPIO_DIR, BIT3 | BIT4 | BIT6); // output pins: 3(UART_TXD), 4(UART_RTS), 6(LED) #else SETREG(GPIO_MOD, 7); SETREG(GPIO_DIR, BIT2 | BIT3 | BIT4 | BIT5 | BIT6); #endif SETREG(GPIO_REG, 0); // initial state of LED is "off" // ZI region is zero-filled by hardware. mem_set_sram((UINT32) &Image$$ER_ZI$$ZI$$Base, 0x00000000, (UINT32) &Image$$ER_ZI$$ZI$$Length); SETREG(PHY_DEBUG, 0x40000139); while((GETREG(PHY_DEBUG) & BIT30) == 1); SETREG(SDRAM_INIT, SDRAM_PARAM_MAIN_FW_INIT); SETREG(SDRAM_REFRESH, SDRAM_PARAM_MAIN_FW_REFRESH); SETREG(SDRAM_TIMING, SDRAM_PARAM_MAIN_FW_TIMING); SETREG(SDRAM_MRS, SDRAM_PARAM_MAIN_FW_MRS); SETREG(SDRAM_CTRL, SDRAM_INITIALIZE); // initialization of SDRAM begins now while (GETREG(SDRAM_STATUS) & 0x00000010); // wait until the initialization completes (200us) for (i = 0; i < DRAM_SIZE / MU_MAX_BYTES; i++) { mem_set_dram(DRAM_BASE + i * MU_MAX_BYTES, 0x00000000, MU_MAX_BYTES); } #if OPTION_UART_DEBUG uart_init(); uart_print("Welcome to OpenSSD"); #endif SETREG(SDRAM_ECC_MON, 0xFFFFFFFF); // configure SDRAM interrupt SETREG(SDRAM_INTCTRL, SDRAM_INT_ENABLE); // clear interrupt flags in DRAM controller SETREG(SDRAM_INTSTATUS, 0xFFFFFFFF); // configure ICU SETREG(APB_ICU_CON, INTR_SATA); // SATA = FIQ, other = IRQ SETREG(APB_INT_MSK, INTR_SATA | INTR_FLASH | INTR_SDRAM | INTR_TIMER_1 | INTR_TIMER_2 | INTR_TIMER_3); // clear interrupt flags in ICU SETREG(APB_INT_STS, 0xFFFFFFFF); flash_reset(); SETREG(FCONF_PAUSE, 0); SETREG(INTR_MASK, 0); for (bank = 0; bank < NUM_BANKS; bank++) { flash_clear_irq(); SETREG(FCP_CMD, FC_COL_ROW_READ_OUT); SETREG(FCP_OPTION, 0x06); // FO_E SETREG(FCP_DMA_ADDR, g_temp_mem); SETREG(FCP_DMA_CNT, BYTES_PER_SECTOR); SETREG(FCP_COL, 0); SETREG(FCP_ROW_L(bank), STAMP_PAGE_OFFSET); SETREG(FCP_ROW_H(bank), STAMP_PAGE_OFFSET); flash_issue_cmd(bank, RETURN_WHEN_DONE); if ( (BSP_INTR(bank) & 0xFE)== 0 ) break; } #if OPTION_FTL_TEST == FALSE sata_reset(); #endif ftl_open(); #if OPTION_FTL_TEST == TRUE extern void ftl_test(); ftl_test(); led(1); while (1); #endif }
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. }