www.pudn.com > SMSC USB2.0.zip > nand_media.c


/*============================================================================ 
  ____________________________________________________________________________ 
                                ______________________________________________ 
   SSSS  M   M          CCCC          Standard Microsystems Corporation 
  S      MM MM   SSSS  C                    Austin Design Center 
   SSS   M M M  S      C                 11000 N. Mopac Expressway 
      S  M   M   SSS   C                Stonelake Bldg. 6, Suite 500 
  SSSS   M   M      S   CCCC                Austin, Texas 78759 
                SSSS            ______________________________________________ 
  ____________________________________________________________________________ 
  Copyright(C) 1999, Standard Microsystems Corporation 
  All Rights Reserved. 
  This program code listing is proprietary to SMSC and may not be copied, 
  distributed, or used without a license to do so.  Such license may have 
  Limited or Restricted Rights. Please refer to the license for further 
  clarification. 
  ____________________________________________________________________________ 
  Notice: The program contained in this listing is a proprietary trade 
  secret of SMSC, Hauppauge, New York, and is copyrighted 
  under the United States Copyright Act of 1976 as an unpublished work, 
  pursuant to Section 104 and Section 408 of Title XVII of the United 
  States code. Unauthorized copying, adaption, distribution, use, or 
  display is prohibited by this law. 
  ____________________________________________________________________________ 
  Use, duplication, or disclosure by the Government is subject to 
  restrictions as set forth in subparagraph(c)(1)(ii) of the Rights 
  in Technical Data and Computer Software clause at DFARS 52.227-7013. 
  Contractor/Manufacturer is Standard Microsystems Corporation, 
  80 Arkay Drive, Hauppauge, New York, 1178-8847. 
  ____________________________________________________________________________ 
  ____________________________________________________________________________ 
  nand_media.c - nand flash media class implementation 
  ____________________________________________________________________________ 
  comments tbd 
  ____________________________________________________________________________ 
  Revision History 
  Date      Who  Comment 
  ________  ___  _____________________________________________________________ 
  06/21/02  cds  initial version - derives from the sm_media methods to ensure 
                 the correct chip is selected before performing any sort of  
                 access to the flash ram.  These methods are called by the  
                 media and mapper code, set up the media, then call the base 
                 sm_media functions to perform the work.  
  06/25/02  cds  incorporated boot block reading/writing for device usb config 
                 info                  
  06/26/02  cds  fixed multi-card reads/writes by adjusting when the card select 
                 is called in the fmc xfers, and fixed the chip select to  
                 multiply the # of chips by the max zone for the particular type 
                 of chip detected, instead of assuming that it was 8 zones per chip. 
  06/27/02  cds  - implemented nand-specific set_read/write/erase addr functions 
                 that can be called vcalled from the smart media base class.  these 
                 functions calculate the chip-based zone from the global g_addr_zone. 
                 - fixed select_chip equation to correctly select a chip from g_addr_zone 
                 - added new variables g_nand_num_chips and g_nand_max_zones_per_chip 
                   to allow future chip auto-detection.                   
  07/09/02  cds  _media_data(sectors_per_block) and g_addr_sector 8->16 bit conversion                                       
  07/09/02  cds  renamed WorkBuf to g_sector_buffer  
  07/16/02  cds  removed extra code that checks for 256 byte page sizes.  these 
                 aren't supported on nand arrays. 
  08/06/02  cds  added some debug code (commented out in real build) to dump 
                 all pages from a particular logical block.  
  08/09/02  cds  - used attribute flag to determine whether to force Smart Media  
                   compatible rw cycle timing for a data xfer. 
                 - separated setting the device address from code that calculates 
                   a the physical address from the mapper's virtual address. 
                 - converted physical address variable into 3 separate xdata bytes 
                   for quick-access when incrementing & writing to the device.                  
  08/13/02  cds  updated nand_va2pa functions to call the n2k versions for calculating 
                 addresses on 2k paged media. 
  08/20/02  cds  removed some debug code which dumped logical sectors 
  09/04/02  cds  address name & usage change-over 
                  g_addr_sector => g_addr_page, 
                  g_addr_page   => g_addr_segment, 
                  _media_data(sectors_per_block)  => _media_data(pages_per_block) 
                  _media_data(cis_phy_block)      => _media_data(boot_block) 
                  _media_data(cis_sector)         => _media_data(boot_sector) 
                  (new item)                      => _media_data(segments_per_page)                                                    
  10/16/02  cds  fixed nand_boot_seek and nand_boot_write_flush to work with  
                 2k paged chips by calling virtual _write_sector() function, and 
                 setting g_addr_segment to 0. 
  10/17/02  cds  - project-wide lun data & vtbl paging to reduce code space.            
                 - removed g_active_media from _lun_data, _lun_() virtual functions     
                 - added _lun_data_rd() and _lun_data_wr() macros to bypass lun paging  
                 - added lun_set_active(log_lun) function to switch luns                
  10/23/02  cds  set g_addr_rd_phy_blk to _media_data(boot_block) on nand_boot_write_flush 
                 for 2k paged media for copying existing data into to the buffer before overwriting 
                 with nvstore data.  (future robustization)                  
  11/21/02  ds   Modified nand_write_boot_flush to suit nand_int implementation.                  
============================================================================*/ 
#define __nand_media_dot_c__ 
#include "project.h" 
 
// provide vtable definition for 'nand_media' 
code _vtbl_defn(nand_media) ; 
 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
extern xdata uint8  g_sector_buffer[]  ; 
extern void fmc_dbg_dump_sector(uint8* sector) reentrant ; 
 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
t_result sm_media_check_format(void)reentrant; 
t_result sm_media_seek_cis(void) reentrant; 
t_result sm_read_cis_sect(uint8 *)reentrant; 
t_result sm_validate_cis(uint8 *) reentrant ; 
t_result sm_media_erase_block(void)reentrant; 
t_result sm_wait_rdy_with_timeout(uint16 ) reentrant; 
 
 
extern void util_trace_buffer(uint8* sector, uint16 size) reentrant; 
 
//------------------------------------------------------------------------------ 
//------------------------------------------------------------------------------ 
static xdata uint8 _nand_boot_cache[256] ; 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   nand_boot_read() 
// 
// Declaration: 
//   t_result nand_boot_read(void) reentrant 
// 
// Purpose: 
// 
// Arguments: 
// 
// Return: 
// 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
uint8  nand_boot_read(uint8 addr) reentrant 
{ 
  TRACE2(427, nand, 0, "nand_boot_read(%d): %02x", addr, (_nand_boot_cache[addr]) ) ;  
 
  return (_nand_boot_cache[addr]) ; 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   nand_boot_read() 
// 
// Declaration: 
//   t_result nand_boot_read(void) reentrant 
// 
// Purpose: 
// 
// Arguments: 
// 
// Return: 
// 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void  nand_boot_write(uint8 addr, uint8 datum) reentrant 
{ 
  TRACE2(428, nand, 0, "nand_boot_write( addr:%d, datum:%02x )", addr, datum) ; 
  _nand_boot_cache[addr] = datum ; 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   nand_boot_write_flush() 
// 
// Declaration: 
//   void nand_boot_write_flush(void) reentrant 
// 
// Purpose: 
//   flushes cached boot block data to the media 
// 
// Arguments: 
// 
// Return: 
// 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result nand_boot_write_flush() reentrant 
{ 
  TRACE0(429, nand, 0, "nand_boot_write_flush()") ; 
 
  lun_set_active(k_lun_nand); // g_active_lun=k_lun_nand ; 
  fmc_select_nand() ; 
 
  // erase boot block 
  g_addr_zone=0 ; 
  g_addr_wr_phy_blk=_media_data(boot_block); 
  g_addr_rd_phy_blk=_media_data(boot_block); 
  g_addr_page=_media_data(boot_page) ; 
  g_addr_segment=0; 
  _media_data(sector_buffer)=g_sector_buffer; 
 
  _media_erase_block(); 
 
  if(g_active_media == k_ix_media_nand_int) 
    nand_int_select_chip(g_addr_segment); 
  else 
    nand_select_card() ; 
   
  nand_rd_va2pa(); 
  nand_wr_va2pa(); 
   
  // start erasing 
  _sm_wr_cmd_begin(k_sm_erase1); 
  _media_set_erase_addr() ;  
  _sm_set_wr_cmd(k_sm_erase2); 
 
  // create a "nvstore" sector while erase is going on 
  memcpy(g_sector_buffer, _nand_boot_cache, 256) ; 
  memset(g_sector_buffer+256, 0, 256) ; 
  memset(x_sm_redt_data, 0, 16); 
 
  if (sm_wait_rdy_with_timeout(k_sm_busy_erase_timeout)) 
  { 
    TRACE0(430, nand, 0, "block erase failed.") ; 
    nand_cmd_reset_device(); 
    return k_error ; 
  } 
   
  // write the sector to the media and bail 
  return _media_write_sector(); 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   nand_boot_seek() 
// 
// Declaration: 
//   void nand_boot_seek(void) reentrant 
// 
// Purpose: 
// 
// Arguments: 
// 
// Return: 
// 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
extern void sm_dbg_dump_redt_data() reentrant; 
void nand_boot_seek() reentrant 
{  
  uint16 i ; 
  TRACE0(431, nand, 0, "nand_boot_seek()"); 
   
  // could try looping here, akin to the seek_cis in sm_media,  
  // but that will be a TBD which probably won't BD unless there 
  // are issues with certain chips having bad first blocks at  
  // some point. 
  g_addr_zone=0; 
  g_addr_rd_phy_blk=0; 
  g_addr_page=0; 
  g_addr_segment=0; 
  _media_data(sector_buffer) = g_sector_buffer; 
 
  //nand_select_card() ; 
  _media_read_sector() ; 
  for(i=0;i<0x100;i++) 
    _nand_boot_cache[i] = g_sector_buffer[i] ; 
 
  _media_data(boot_block) = 0; 
  _media_data(boot_page) = 0; 
 
} 
 
 
//------------------------------------------------------------------------------ 
//+----------------------------------------------------------------------------- 
// Name: 
//   nand_read_sector() 
// 
// Declaration: 
//   t_result nand_read_sector(void) reentrant 
// 
// Purpose: 
// 
// Arguments: 
// 
// Return: 
// 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result  nand_read_sector(void) reentrant 
{ 
  TRACE4(432, nand, 0, "nand_read_sector() - zone:%d RD_PHY:%d log:%d page:%d", g_addr_zone, g_addr_rd_phy_blk, g_addr_log_blk, g_addr_page) ; 
  nand_select_card() ; 
  return sm_media_read_sector() ; 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   nand_write_sector() 
// 
// Declaration: 
// t_result nand_write_sector(uint8 *buf) reentrant 
// 
// Purpose: 
// 
// Arguments: 
// 
// Return: 
// 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result nand_write_sector() reentrant 
{ 
  TRACE4(433, nand, 0, "nand_write_sector() zone:%d WR_PHY:%d log:%d page:%d", g_addr_zone, g_addr_wr_phy_blk, g_addr_log_blk, g_addr_page) ; 
  nand_select_card() ; 
  return sm_media_write_sector() ; 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   nand_copy_sector() 
// 
// Declaration: 
// t_result nand_copy_sector() reentrant 
// 
// Purpose: 
// 
// Arguments: 
// 
// Return: 
// 
// Notes: 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result nand_copy_sector() reentrant 
{ 
  TRACE4(434, nand, 0, "nand_copy_sector() zone:%d SRC_BLK:%d DEST_BLK:%d page:%d", g_addr_zone, g_addr_rd_phy_blk, g_addr_wr_phy_blk, g_addr_page) ; 
  nand_select_card() ; 
  return sm_media_copy_sector() ; 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   nand_read_extra_data() 
// 
// Declaration: 
//   TBD 
// 
// Purpose: 
//   TBD 
// 
// Arguments: 
//   TBD 
// 
// Return: 
//   TBD 
// 
// Notes: 
//   TBD 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result nand_read_extra_data(void) reentrant 
{ 
  TRACE3(435, nand, 0, "nand_read_extra_data() zone:%d phy_blk:%d page:%d", g_addr_zone, g_addr_rd_phy_blk, g_addr_page) ; 
  nand_select_card( ) ; 
  return sm_media_read_extra_data() ; 
} 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   nand_write_extra_data() 
// 
// Declaration: 
//   t_result nand_write_extra_data(void) reentrant 
// 
// Purpose: 
//   TBD 
// 
// Arguments: 
//   TBD 
// 
// Return: 
//   TBD 
// 
// Notes: 
//   TBD 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result nand_write_extra_data(void) reentrant 
{ 
  nand_select_card( ) ; 
  return sm_media_write_extra_data() ; 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   nand_set_read_addr() 
// 
// Declaration: 
//   t_result nand_set_read_addr() reentrant 
//                
// Purpose: 
//   set media-specific address from internal zone/rd_phy_blk/sector addres 
// 
// Arguments: 
//  TBD 
// 
// Return: 
//  k_success always 
// 
// Notes: 
//  TBD 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result nand_set_read_addr() reentrant  
{ 
  TRACE3(436, nand, 0, "nand_set_read_addr() page:%02x%02x%02x", g_nand_rd_addr_msb, g_nand_rd_addr_mid, g_nand_rd_addr_lsb) ;   
  _sm_hw_set_rd_addr(); 
  _sm_data_wr(0x00); 
  _sm_data_wr(g_nand_rd_addr_lsb) ;  
  _sm_data_wr(g_nand_rd_addr_mid) ;  
  if ( _lun_data(media)&kbm_sm_media_addr_4cyc) 
    _sm_data_wr(g_nand_rd_addr_msb); 
  _sm_hw_set_rd_data(g_nand_rw_speed); 
  return k_success ; 
} 
 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   nand_set_write_addr() 
// 
// Declaration: 
//   t_result nand_set_write_addr() reentrant 
// 
// Purpose: 
//   set media-specific address from internal zone/wr_phy_blk/sector addres 
// 
// Arguments: 
//  TBD 
// 
// Return: 
//  k_success always 
// 
// Notes: 
//  TBD 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result nand_set_write_addr() reentrant  
{ 
  TRACE3(437, nand, 0, "nand_set_write_addr() page:%02x%02x%02x", g_nand_wr_addr_msb, g_nand_wr_addr_mid, g_nand_wr_addr_lsb) ;   
  _sm_hw_set_wr_addr(); 
  _sm_data_wr(0x00); 
  _sm_data_wr(g_nand_wr_addr_lsb) ;  
  _sm_data_wr(g_nand_wr_addr_mid) ;  
  if ( _lun_data(media)&kbm_sm_media_addr_4cyc) 
    _sm_data_wr(g_nand_wr_addr_msb); 
  _sm_hw_set_wr_data(g_nand_rw_speed); 
  return k_success ; 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   nand_set_erase_addr() 
// 
// Declaration: 
//   t_result nand_set_erase_addr() reentrant 
// 
// Purpose: 
//   set media-specific address from internal zone/wr_phy_blk 
// 
// Arguments: 
//  TBD 
// 
// Return: 
//  k_success always 
// 
// Notes: 
//  The block to be erased should be in g_addr_wr_phy_blk before this  
//  function is called 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
t_result nand_set_erase_addr() reentrant  
{ 
  TRACE3(438, nand, 0, "nand_set_erase_addr() page:%02x%02x%02x", g_nand_wr_addr_msb, g_nand_wr_addr_mid, g_nand_wr_addr_lsb) ; 
  _sm_hw_set_wr_addr(); 
  _sm_data_wr(g_nand_wr_addr_lsb) ;  
  _sm_data_wr(g_nand_wr_addr_mid) ;  
  if ( _lun_data(media)&kbm_sm_media_addr_4cyc) 
    _sm_data_wr(g_nand_wr_addr_msb); 
  _sm_hw_set_wr_data(g_nand_rw_speed); 
  return k_success ; 
}