📄 nand.c
字号:
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result nand_check_format(void) reentrant
{
trace0(0, nand, 0, "nand_check_format()") ;
#if 0
trace0(0, nand, 0, "ERASING ALL FLASH CARDS") ;
util_safe_erase_media() ;
#endif
if ( _lun_is_media_known(g_active_lun) )
return(k_success);
// media already identified, but sector map not built yet
g_addr_rd_phy_blk=0;
g_addr_page=0;
_media_data(boot_block)=0;
_media_data(boot_page)=0;
_media_data(assign_zone)=0;
g_addr_zone=0;
// note: building a sector map could take 100s of ms
if ( k_success != map_build_sector_map())
{
trace0(0, nand, 0, "failed to build sector map") ;
return k_error ;
}
// induce an error bit here under cbw protection, after a sector map has been built
// util_test_copy_double_bit_ecc(33) ;
sm_reset_device() ;
trace0(0, nand, 0, "media identified") ;
_lun_data(media) &= ~kbm_lun_media_unknown ;
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// nand_erase_block()
//
// Declaration:
// t_result nand_erase_block(void) reentrant
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
xdata t_result _temp;
t_result nand_erase_block(void) reentrant
{
trace4(0, nand, 0, "nand_erase_block() - zone:%d wr_phy:%d log:%d page:%d", g_addr_zone, g_addr_wr_phy_blk, g_addr_log_blk, g_addr_page) ;
_mcu_begin_critical_section() ;
nand_select_card() ;
_temp = sm_media_erase_block();
_mcu_end_critical_section();
return _temp;
}
//------------------------------------------------------------------------------
// read for serial-input.
//------------------------------------------------------------------------------
t_result nand_page_read_for_data(void) reentrant
{
trace4(0, nand, 0, "nand_page_read_for_data() - zone:%d blk:%d log_blk:%d page:%d", g_addr_zone, g_addr_rd_phy_blk, g_addr_log_blk, g_addr_page) ;
_mcu_register_wr(x_smc_stat, kbm_smc_stat_rdy) ;
_sm_set_rd_cmd(k_sm_read) ;
nand_2k_set_read_addr() ;
_sm_set_rd_cmd(k_nand_cmd_read_for_data) ;
if (k_success != sm_wait_rdy_with_timeout(k_sm_busy_read_timeout))
{
trace0(0, nand, 0, "error waiting for data") ;
sm_reset_device();
return k_error ;
}
return k_success ;
}
//------------------------------------------------------------------------------
// read for copyback
//------------------------------------------------------------------------------
t_result n2k_page_read_for_copy() reentrant
{
trace4(0, n2k, 0, "n2k_page_read_for_copy() - zone:%d blk:%d log_blk:%d page:%d", g_addr_zone, g_addr_rd_phy_blk, g_addr_log_blk, g_addr_page) ;
_mcu_register_wr(x_smc_stat, kbm_smc_stat_rdy) ;
_sm_set_rd_cmd(k_sm_read) ;
nand_2k_set_read_addr() ;
_sm_set_rd_cmd(k_nand_cmd_read_for_copy) ;
if (k_success != sm_wait_rdy_with_timeout(k_sm_busy_read_timeout))
{
trace0(0, n2k, 0, "error waiting for data") ;
sm_reset_device();
return k_error ;
}
// g_addr_rd_phy_blk is now in the chip's page cache register
return k_success ;
}
//------------------------------------------------------------------------------
// jump to offset within page in chip cache for data source... page_rd_for_data
// must have previously been called.
//------------------------------------------------------------------------------
t_result n2k_page_set_rd_offset( uint16 offset ) reentrant
{
trace1(0, n2k, 0, "n2k_page_set_rd_offset() - column:%04X", offset) ;
_sm_set_rd_cmd(k_nand_cmd_read_offset_addr) ;
_sm_hw_set_rd_addr();
_sm_data_wr( _l(offset) ) ;
_sm_data_wr( _h(offset) ) ;
_sm_set_rd_cmd(k_nand_cmd_read_offset_data) ;
_sm_hw_set_rd_data(g_nand_rw_speed);
return k_success ;
}
//------------------------------------------------------------------------------
// jump to offset within page in chip cache for data dest
//------------------------------------------------------------------------------
t_result n2k_page_set_wr_offset( uint16 offset ) reentrant
{
trace1(0, n2k, 0, "n2k_page_set_wr_offset() - column:%02X", offset) ;
sm_set_wr_cmd(k_nand_cmd_write_cache_data) ;
_sm_hw_set_wr_addr() ;
_sm_data_wr( _l(offset) ) ;
_sm_data_wr( _h(offset) ) ;
_sm_hw_set_wr_data(g_nand_rw_speed);
return k_success ;
}
//------------------------------------------------------------------------------
// program page with serial data input
//------------------------------------------------------------------------------
t_result n2k_page_write_cache_data() reentrant
{
sm_set_wr_cmd(k_nand_cmd_write_cache_data) ;
nand_2k_set_write_addr() ;
return k_success ;
}
//------------------------------------------------------------------------------
// program page with serial data input
//------------------------------------------------------------------------------
t_result n2k_page_program() reentrant
{
trace0(0, n2k, 0, "n2k_page_program()") ;
_mcu_register_wr(x_smc_stat, kbm_smc_stat_rdy) ;
sm_set_wr_cmd(k_nand_cmd_write_page) ;
if (k_success != sm_wait_rdy_with_timeout(k_nand_write_page_timeout))
{
trace0(0, n2k, 0, "error writing data") ;
sm_reset_device();
return k_error ;
}
if (k_success != sm_check_status())
{
trace0(0, n2k, 0, "error failed status check") ;
sm_reset_device() ;
return k_error ;
}
trace0(0, n2k, 0, "success") ;
return k_success ;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result n2k_cache_program() reentrant
{
trace0(0, n2k, 0, "n2k_cache_program()") ;
_mcu_register_wr(x_smc_stat, kbm_smc_stat_rdy) ;
sm_set_wr_cmd(k_nand_cmd_write_cache) ;
if (k_success != sm_wait_rdy_with_timeout(k_nand_write_page_timeout))
{
trace0(0, n2k, 0, "error waiting for device busy") ;
sm_reset_device();
return k_error ;
}
trace0(0, n2k, 0, "success") ;
return k_success ;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result n2k_read_cache_next() reentrant
{
trace0(0, n2k, 0, "n2k_read_cache_next()") ;
_mcu_register_wr(x_smc_stat, kbm_smc_stat_rdy) ;
_sm_set_rd_cmd(k_nand_cmd_read_cache_next) ;
if(k_success!=sm_wait_rdy_with_timeout(k_sm_busy_read_timeout))
{
trace0(0, n2k, 0, "error waiting for data") ;
sm_reset_device();
return k_error ;
}
return k_success ;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result n2k_read_cache_final() reentrant
{
trace0(0, n2k, 0, "n2k_read_cache_final()") ;
_mcu_register_wr(x_smc_stat, kbm_smc_stat_rdy) ;
_sm_set_rd_cmd(k_nand_cmd_read_cache_final) ;
if(k_success!=sm_wait_rdy_with_timeout(k_sm_busy_read_timeout))
{
trace0(0, n2k, 0, "error waiting for data") ;
sm_reset_device();
return k_error ;
}
return k_success ;
}
//-----------------------------------------------------------------------------
// read fmc xfer callbacks
//-----------------------------------------------------------------------------
extern t_result nand_read_begin_split(void) reentrant;
extern t_result nand_read_end_first_split(void) reentrant ;
//+-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_result nand_read_begin_xfer() reentrant
{
trace4(0, nand, 10, "nand_read_begin_xfer() - start:0x%04X%04X count:0x%04X%04X" , _hw(_fmc_get_start_lb_32()), _lw(_fmc_get_start_lb_32()), _hw(_fmc_get_lb_count_32()), _lw(_fmc_get_lb_count_32()));
_lun_data(sensep) = &sense_read_error;
if (g_ix_media_nand == k_ix_media_nand)
{
return sm_read_begin_xfer() ;
}
if (k_success != map_lba2addr_rd( _fmc_get_start_lb_32() ) )
{
_lun_data(sensep)=&sense_illegal_address ;
TRACE0(268, sm, 0, "error in lba2addr") ;
return k_error ;
}
_lun_data(max_lb_per_split) = 4-g_addr_segment ;
_lun_data(max_lb_per_burst) = 4-g_addr_segment ;
return k_success ;
}
//+-----------------------------------------------------------------------------
// Name:
// sm_read_begin_next_split
//
// Declaration:
// t_result sm_read_begin_next_split(void);
//
// Purpose:
// Issue the read command to subsequent splits after the first.
//
// Arguments:
// None.
//
// Return:
// A t_result indicating:
// k_success - command completed.
//
// Notes:
// This is a FUNCTION, not a DFA.
// Do not yeild, or run a DFA, from within this callback.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result nand_read_begin_split(void) reentrant
{
t_result result ;
trace0(0, nand, 1, "nand_read_begin_split()") ;
if (k_success != map_lba2addr_rd( _fmc_get_start_lb_32() ) )
{
_lun_data(sensep)=&sense_illegal_address ;
return k_error ;
}
// start the read
nand_select_card() ;
if(map_log_blk_has_bad_data())
{
if(sm_check_data_status(g_addr_page, (uint8) _fmc_get_lb_count_32()))
{
TRACE0(269, sm, 0, "read error detected in lba range") ;
sm_reset_device();
return k_error;
}
sm_reset_device();
TRACE0(270, sm, 0, "read in log blk that has bad data is OK");
}
trace5(0, nand, 0, "beginning split - zone:%d phy:%d log:%d page:%d segment:%d", g_addr_zone, g_addr_rd_phy_blk, g_addr_log_blk, g_addr_page, g_addr_segment) ;
nand_rd_va2pa() ;
if(g_ix_media_nand == k_ix_media_nand_2k)
{
trace0(0, nand, 0, "using large nand flash chips") ;
// g_fmc_begin_burst_callback=(t_fmc_callback) nand_read_begin_burst ;
result = nand_page_read_for_data() ;
if (g_addr_segment)
n2k_page_set_rd_offset( _n2k_data_offset(g_addr_segment)) ;
// return k_success;
}
else
{
sm_rd_cmd_begin(k_sm_read) ;
_media_set_read_addr() ;
result = sm_wait_rdy_with_timeout(k_sm_busy_read_timeout);
}
if (k_success != result)
{
trace1(0, nand, 0, "timeout waiting for busy - smc_stat:%02x", x_smc_stat) ;
sm_reset_device();
return k_error ;
}
// setup hardware
_mcu_register_wr(x_smc_stat, kbm_smc_stat_ecc_err_d_a|kbm_smc_stat_ecc_err_d_b|kbm_smc_stat_ecc_err_c_a|kbm_smc_stat_ecc_err_c_b) ;
_mcu_register_clr_bits(x_smc_stat_msk, kbm_smc_stat_ecc_err_d_a | kbm_smc_stat_ecc_err_d_b | kbm_smc_stat_ecc_err_c_a | kbm_smc_stat_ecc_err_c_b) ;
_mcu_register_wr(x_isr0, kbm_isr0_fmc_irq) ;
_mcu_register_clr_bits(x_imr0, kbm_isr0_fmc_irq) ;
_mcu_register_set_bits(sm_mode_ctl,kbm_sm_mode_ecc_blk_xfer_en);
return k_success;
}
#if 0
//------------------------------------------------------------------------------
// only for n2k media, that doesn't have read-sequential capabilities.
//------------------------------------------------------------------------------
t_result nand_read_begin_burst() reentrant
{
if ( g_addr_page <= (_media_data(pages_per_block)-2))
{
trace0(0, nand, 0, "issue read next cached page here") ;
n2k_read_cache_next() ;
}
else if ( g_addr_page == (_media_data(pages_per_block)-2))
{
trace0(0, nand, 0, "issue read final cached page here") ;
n2k_read_cache_final() ;
}
_lun_data(max_lb_per_burst) = 4 ;
// setup hardware
_mcu_register_wr(x_smc_stat, kbm_smc_stat_ecc_err_d_a | kbm_smc_stat_ecc_err_d_b | kbm_smc_stat_ecc_err_c_a | kbm_smc_stat_ecc_err_c_b) ;
_mcu_register_clr_bits(x_smc_stat_msk, kbm_smc_stat_ecc_err_d_a | kbm_smc_stat_ecc_err_d_b | kbm_smc_stat_ecc_err_c_a | kbm_smc_stat_ecc_err_c_b) ;
_mcu_register_wr(x_isr0, kbm_isr0_fmc_irq) ;
_mcu_register_clr_bits(x_imr0, kbm_isr0_fmc_irq) ;
_mcu_register_set_bits(sm_mode_ctl,kbm_sm_mode_ecc_blk_xfer_en);
return k_success ;
}
#endif
//+-----------------------------------------------------------------------------
// Name:
// nand_read_end_first_split
//
// Declaration:
// t_result nand_read_end_first_split(void);
//
// Purpose:
//
//
// Arguments:
// None.
//
// Return:
// A t_result indicating:
// k_success - command completed.
//
// Notes:
// This is a FUNCTION, not a DFA.
// Do not yeild, or run a DFA, from within this callback.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result nand_read_end_first_split(void) reentrant
{
trace0(0, nand, 0, "nand_read_end_first_split()") ;
// go into overdrive
trace2(0, nand, 0, "adjusting split/burst size. before: max_lb_per_split:%d max_lb_per_burst: %d", _lun_data(max_lb_per_split), _lun_data(max_lb_per_burst)) ;
if(g_active_media==k_ix_media_nand)
{
_lun_data(max_lb_per_split) = _min( (_media_data(pages_per_block)*_media_data(segments_per_page)), g_n_lb_this_xfer.u32);
_lun_data(max_lb_per_burst) = _lun_data(max_lb_per_split) ;
}
else
{
_lun_data(max_lb_per_split) = _min( 4, g_n_lb_this_xfer.u32);
_lun_data(max_lb_per_burst) = _min( 4, g_n_lb_this_xfer.u32);
}
trace2(0, nand, 0, "adjusting split/burst size. after: max_lb_per_split:%d max_lb_per_burst: %d", _lun_data(max_lb_per_split), _lun_data(max_lb_per_burst)) ;
// no need to callback here any more
g_fmc_end_split_callback = (t_fmc_callback) sm_read_end_split ;
_sm_hw_set_rd_standby() ;
return k_success ;
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_sm_read
//
// Declaration:
// void dfa_sm_read(void) reentrant
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -