⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nand.c

📁 U盘控制器USB97C223的固件代码,对2kPAGE NAND FLASH 有很好的支持.
💻 C
📖 第 1 页 / 共 4 页
字号:
// 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 + -