Example #1
0
//! Returns the first free block seen, scanning downstream.
//!
//! It uses g_curr_block_addr (current block address of each device).
//!
//! @param i_dev              device number on which we look for a free block
//!
//! @return the physical block number
//!
static U16 nf_fetch_free_block(U8 i_dev)
{

   U16 block_addr= g_curr_block_addr[i_dev];

   while ( block_addr>=g_nf_first_block )
   {
      nfc_read_spare_byte( g_byte, 8, nf_block_2_page( block_addr ) );
      if(( 0xFF           ==g_byte[G_OFST_BLK_STATUS          ] ) // the block is valid
      && ( NFC_BLK_ID_DATA==g_byte[NFC_SPARE_OFST_1_BLK_ID    ] ) // the block is a data block
      && ( 0xFF           ==g_byte[NFC_SPARE_OFST_6_LBA       ] ) // and is not affected
      && ( 0xFF           ==g_byte[NFC_SPARE_OFST_6_LBA+1     ] ))
      {
         // Since we rebuild the flash, we should not see any of these blocks
         //
         Assert( NFC_BLK_ID_SUBLUT!=g_byte[NFC_SPARE_OFST_1_BLK_ID] );
         Assert( NFC_BLK_ID_FBB   !=g_byte[NFC_SPARE_OFST_1_BLK_ID] );

         // Find a free and valid block addr. Store the current position
         //
         g_curr_block_addr[i_dev] = block_addr-1;
         return block_addr;
      }
      block_addr-=1 ;
   }
   // This situation is dramatic: it should never happen !
   // Force Rebuild on next startup
   nfc_erase_block( nf_block_2_page( g_fbb_block_addr ), TRUE );
   while(1);
   Assert( FALSE ) ; // Not enough free blocks: fatal error!
}
Example #2
0
//! Cleanup the memory by erasing all the management blocks.
//!
//! The sub-LUT blocks, the recovery block and the free-blocks block
//! will be erased on any devices.
//!
//! @param none
//!
void nf_cleanup_memory(void)
{
   U8   i_dev  =0;
   U16  i_block=0;
   U8   block_valid;
   U8   block_id;

   // Scan all the devices and looks for:
   // - the sub-LUT
   // - the recovery block
   // - the free-blocks block
   //
   for( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
   {
      // Select the devices
      //
      Nfc_action(NFC_ACT_DEV_SELECT, i_dev);

      for( i_block=g_nf_first_block ; i_block<G_N_BLOCKS ; i_block++ )
      {

         nfc_open_page_read( nf_block_2_page(i_block), NF_SPARE_POS);
         block_valid = Nfc_rd_data_fetch_next();
         block_id    = Nfc_rd_data()           ;

         if ( block_valid!=0xFF )
         {
            continue; // The block is bad
         }

         if(( NFC_BLK_ID_SUBLUT==block_id )
         || ( NFC_BLK_ID_FBB   ==block_id ))
         {
            nfc_erase_block( nf_block_2_page(i_block), TRUE ) ;
            if ( FAIL==nfc_check_status() )
            {
               nfc_mark_bad_block( nf_block_2_page(i_block) );
            }
         }
      } // for( i_block...
   } // for( i_dev...
} // nf_cleanup_memory
Example #3
0
//! Refines the position of the 'block' index according to a particular
//! pattern. This allow to find exactely where are stored the last
//! sub-LUT, Free_blocks or Recovery entry.
//! The index is roughly initialized at the beginning of the block that holds
//! the 'pattern' at the location 1 of the spare zone. The function parses the
//! block until the pattern is no more found.
//!
//! @param block_addr  physical block address
//! @param inc         increment
//! @param pattern     pattern which is scanned
//!
//! @return the offset (in page) of the last valid entry in the block
//!
static U8 nf_refine_index(
   U16 block_addr
,  U8  inc
,  U8  pattern)
{
   _MEM_TYPE_SLOW_ U8 u8_tmp;
   _MEM_TYPE_SLOW_ U8 val=0;
   do
   {
      val+= inc; // Assume that the pattern has already be seen previously
      if( val>=SIZE_BLOCK_PAGE )
         { break; }
      nfc_open_page_read(
         nf_block_2_page(block_addr) + val
      ,  NF_SPARE_POS+NFC_SPARE_OFST_1_BLK_ID
      );
      u8_tmp = Nfc_rd_data();
   } while( pattern==u8_tmp );
   val-= inc; // come back to last valid entry
   Assert( val<(1<<G_SHIFT_BLOCK_PAGE) ); // The offset shall not be outside the block
   return val;
}
Example #4
0
//! @brief Rebuild the memory and create LUT, Recovery and Free-blocks blocks.
//!
//! TBD
//!
//! It uses s_n_invalid_blocks (number of invalid blocks) and
//! g_curr_block_addr (current block address of each device).
//!
//! @return a status:
//!           PASS if there are no error;
//!           FAIL a programmation error occured: the block is marked as bad. The
//!           function must be recall.
//!
static Status_bool nf_rebuild ( void )
{
   Status_bool status_bool=PASS;
   Bool        b_duplicate;
   U8   i_sub_lut;
   U8   i_dev  =0;
   _MEM_TYPE_SLOW_ U16  i_block=0;
   _MEM_TYPE_SLOW_ U16  u16_tmp;
   _MEM_TYPE_SLOW_ U16  sub_lut_log_sz;
   _MEM_TYPE_SLOW_ U16  log_block_addr;
   _MEM_TYPE_SLOW_ U16  log_block_addr_min;
   _MEM_TYPE_SLOW_ U16  log_block_addr_max;

   // Refine the computation
   //
   s_n_invalid_blocks[S_MNGT_DEV] +=
      1                                        // Need a block for the Free-blocks block
   +  (G_N_BLOCKS*NF_N_DEVICES)/NF_SUBLUT_SIZE // and one for each sub-LUT
   ;

   // Take the max number of invalid blocks of each devices
   //
   u16_tmp=s_n_invalid_blocks[0] ;
   for ( i_dev=1 ; i_dev<NF_N_DEVICES ; i_dev++ )
   {
      u16_tmp=Max( u16_tmp, s_n_invalid_blocks[i_dev] );
   }

   // Take the max number of quarantine blocks of each devices
   //
   i_sub_lut=s_n_quarantine_blocks[0] ;
   for ( i_dev=1 ; i_dev<NF_N_DEVICES ; i_dev++ )
   {
      i_sub_lut=Max( i_sub_lut, s_n_quarantine_blocks[i_dev] );
   }

   sub_lut_log_sz = (U16)NF_N_DEVICES*(G_N_BLOCKS -g_nf_first_block -u16_tmp);

   // Finally compute the number of exportable physical blocks and free blocks
   //
   Assert( u16_tmp<(G_N_BLOCKS -g_nf_first_block) );
   g_n_export_blocks= (U16)( ((U32)( (U32)sub_lut_log_sz ) * 1000) / 1024);
   g_n_export_blocks= Align_down( g_n_export_blocks, NF_N_DEVICES);

   g_n_free_blocks  = (U16)sub_lut_log_sz - g_n_export_blocks;
   g_n_free_blocks -= (U16)NF_N_DEVICES*i_sub_lut;

   if( g_n_free_blocks<=NF_LOW_N_FREE_THRESHOLD )
   {
      while(1); // TBD
   }

   Assert( g_n_free_blocks>0 );
   Assert( g_n_free_blocks<(1L<<NF_SHIFT_PAGE_BYTE) ); // limit the free blocks in order to fit in 1 page

   // Compute the number of needed sub-LUT
   // Affect to each management block a free block address
   //
   Nfc_action(NFC_ACT_DEV_SELECT, S_MNGT_DEV);
   g_fbb_block_addr = nf_fetch_free_block(S_MNGT_DEV);
   nfc_erase_block( nf_block_2_page( g_fbb_block_addr ), TRUE );
   g_n_sub_lut= 0;
   u16_tmp    = g_n_export_blocks;
//#error il faut positionner les index(LUT, FBB, RCV...)
   while(1)
   {
      Assert( g_n_sub_lut<N_SUBLUT );
      g_lut_block_addr [g_n_sub_lut]=nf_fetch_free_block(S_MNGT_DEV);
      g_lut_block_index[g_n_sub_lut]=0;
      nfc_erase_block( nf_block_2_page( g_lut_block_addr [g_n_sub_lut] ), TRUE );
      g_n_sub_lut++;
      if( u16_tmp>NF_SUBLUT_SIZE )  u16_tmp-=NF_SUBLUT_SIZE;
      else                          break;
   }
   g_last_sub_lut_log_sz=u16_tmp/NF_N_DEVICES;

   // Build the sub-LUTs
   //
   for ( i_sub_lut=0 ; i_sub_lut<g_n_sub_lut ;  )
   {
      U8  n_sublut_in_buf = g_n_sub_lut - i_sub_lut; // Count remaining sublut to build

      log_block_addr_max =
      log_block_addr_min = (U16)i_sub_lut<<(NF_SHIFT_SUBLUT_PHYS-NF_SHIFT_N_DEVICES); // first included

      if( n_sublut_in_buf>(NF_PAGE_BUFFER_SIZE/(2*NF_SUBLUT_SIZE)) )
      {
         n_sublut_in_buf = NF_PAGE_BUFFER_SIZE/(2*NF_SUBLUT_SIZE);
         log_block_addr_max += ((U16)n_sublut_in_buf)*g_sub_lut_log_sz; // last not included
      }
      else
      {
         log_block_addr_max += ((U16)n_sublut_in_buf-1)*g_sub_lut_log_sz +g_last_sub_lut_log_sz; // last not included
      }

      nf_init_buffer();

      // Report affected logical blocks
      //
      u16_tmp=g_n_export_blocks/NF_N_DEVICES; // Number of logical blocks used for the mass storage

      b_duplicate=FALSE;

      for ( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
      {
         Nfc_action(NFC_ACT_DEV_SELECT, i_dev);

         g_block_to_kill[i_dev]=0xFFFF;

         for ( i_block=g_nf_first_block ; i_block<G_N_BLOCKS ; i_block++ )
         {
            nfc_read_spare_byte( g_byte, 8, nf_block_2_page(i_block) );
            if(( 0xFF           !=g_byte[G_OFST_BLK_STATUS          ] ) // The block is bad
            || ( NFC_BLK_ID_DATA!=g_byte[NFC_SPARE_OFST_1_BLK_ID    ] ) // or is not a data block
            || (  ( 0xFF        ==g_byte[NFC_SPARE_OFST_6_LBA       ] ) // or is not affected
               && ( 0xFF        ==g_byte[NFC_SPARE_OFST_6_LBA+1     ] )
               )
            ) {
               continue;
            }

            MSB(log_block_addr) = g_byte[NFC_SPARE_OFST_6_LBA  ];
            LSB(log_block_addr) = g_byte[NFC_SPARE_OFST_6_LBA+1];

            if( log_block_addr>=u16_tmp )
            {  // The LBA seems bad: it does not fit in any LUT. This happens when unplugging the player.
               // Block is erased.
               // Anyway, stay in the loop to track similar problems.
               nfc_erase_block( nf_block_2_page(i_block), TRUE );
               status_bool=FAIL;
            }

            if(( log_block_addr>=log_block_addr_min )
            && ( log_block_addr< log_block_addr_max ))
            {
               U16 ofst=2*((U16)i_dev + (log_block_addr%((U16)NF_PAGE_BUFFER_SIZE/2/NF_N_DEVICES))*NF_N_DEVICES) ;
               if(
                  ( 0xFF==g_page_buffer[ ofst    ] )
               && ( 0xFF==g_page_buffer[ ofst +1 ] )
               )
               {  // no redundant phys blocks
                  Assert(      ( ofst +1 ) < NF_PAGE_BUFFER_SIZE );
                  g_page_buffer[ ofst    ] = MSB(i_block);
                  g_page_buffer[ ofst +1 ] = LSB(i_block);
               }
               else
               {  // A duplicated logical block is detected. This happens when unplugging the player.
                  // Anyway, stay in the loop to track any other redundant blocks, for that sub-LUT.
                  _MEM_TYPE_SLOW_ U16 tmp_addr;
                  MSB(tmp_addr)=g_page_buffer[ ofst    ];
                  LSB(tmp_addr)=g_page_buffer[ ofst +1 ];
                  //trace("Dupl "); trace_hex32(tmp_addr); trace("-"); trace_hex32(i_block);; trace("\n\r");

                  if(0xFFFF!=g_block_to_kill[i_dev])
                  {  // !!! There are more than 1 duplicated block on the device. This should never happen...
                     nfc_erase_block( nf_block_2_page(g_block_to_kill[i_dev]), TRUE );
                     return FAIL;
                  }

                  b_duplicate=TRUE;
                  g_log_block_id=log_block_addr;

                  nfc_open_page_read(
                     nf_block_2_page(i_block)
                  ,  NF_SPARE_POS+NFC_SPARE_OFST_3_BYTE_3
                  );
                  if( NFC_OFST_3_DATA_DST!=Nfc_rd_data_fetch_next() )
                  {
                     trace("1. Src block="); trace_hex16(i_block); trace_nl();
                     trace("1. Dst block="); trace_hex16(tmp_addr); trace_nl();
                     //nfc_print_block(i_block, 0);
                     //nfc_print_block(tmp_addr, 0);
                     //while(1);
                     g_block_to_kill[i_dev]=i_block;                        // source block
                     g_phys_page_addr[i_dev] = nf_block_2_page( tmp_addr ); // recipient block
                  }
                  else
                  {
                     trace("2. Src block="); trace_hex16(tmp_addr); trace_nl();
                     trace("2. Dst block="); trace_hex16(i_block); trace_nl();
                     //nfc_print_block(tmp_addr, 0);
                     //nfc_print_block(i_block, 0);
                     //while(1);
                     g_block_to_kill[i_dev]= tmp_addr ;                     // source block
                     g_page_buffer[ ofst    ]=MSB(i_block);
                     g_page_buffer[ ofst +1 ]=LSB(i_block);
                     g_phys_page_addr[i_dev] = nf_block_2_page( i_block );  // recipient block
                  }
               }
            }
         } // for ( i_block ../..
      } // for ( i_dev ../..

      if( b_duplicate )
      {
         U8 i_page;
         U8 i_sect;

         trace("recovery\n\r");
         // Test that recovery can be done
         for ( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
         {
            if( 0xFFFF==g_block_to_kill[i_dev] )
            {  // !Ooops... we can not recover from that case since there are duplication
               // only on on device
               for ( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
               {
                  if( 0xFFFF!=g_block_to_kill[i_dev] )
                  {
                     nfc_erase_block( nf_block_2_page(g_block_to_kill[i_dev]), TRUE );
                  }
               }
               return FAIL;
            }
         }

         // Initialize variable for nf_copy_tail
         g_curr_dev_id=0;
         g_last_log_sector= ((U32)g_log_block_id) << S_SHIFT_LOG_BLOCK_SECTOR;

         // Look for last written sector
         for( i_page=0 ; i_page<SIZE_BLOCK_PAGE ; i_page++ )
         {
            Nfc_action(NFC_ACT_DEV_SELECT, g_curr_dev_id);  // open the current device
            for( i_sect=0 ; i_sect<SIZE_PAGE_SECTOR ; i_sect++ )
            {
               nfc_open_page_read(
                  g_phys_page_addr[g_curr_dev_id]
               ,  NF_SPARE_POS + (((U16)i_sect)*16) + NFC_SPARE_OFST_6_LBA
               );
               if(( 0xFF==Nfc_rd_data_fetch_next() )
               && ( 0xFF==Nfc_rd_data_fetch_next() ))
                  goto recovery_exit;
               else
               {
                  g_last_log_sector++;
                  trace("g_last_log_sector="); trace_hex32(g_last_log_sector); trace_nl();
               }
            }
            g_phys_page_addr[g_curr_dev_id]++;                                                   // update the current physical page of the current device
            g_curr_dev_id++;                                                                     // update the current device
            if( g_curr_dev_id==NF_N_DEVICES ) { g_curr_dev_id=0; }
            trace("g_curr_dev_id="); trace_hex(g_curr_dev_id); trace_nl();
            trace("g_phys_page_addr="); trace_hex32(g_phys_page_addr[g_curr_dev_id]); trace_nl();
         }
recovery_exit:
         trace("recovery stop on g_last_log_sector="); trace_hex32(g_last_log_sector); trace_nl();
         trace("g_curr_dev_id="); trace_hex(g_curr_dev_id); trace_nl();
         trace("g_phys_page_addr="); trace_hex32(g_phys_page_addr[g_curr_dev_id]); trace_nl();
         //while(1);
         nf_copy_tail();
         return FAIL;
      }

      // At least one redundant have been found: the LUT must be rebuilt since the fetch of free block
      // may not have seen that affected block (redundant) are in fact free.
      if( PASS!=status_bool ) { return FAIL; }

      // Affect a free physical block to the logical block
      //
      for( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
      {
         Nfc_action(NFC_ACT_DEV_SELECT, i_dev);

         for(u16_tmp=0
         ;   u16_tmp<(log_block_addr_max-log_block_addr_min)
         ;   u16_tmp++ )
         {
            U16 ofst=2*((U16)i_dev + u16_tmp*NF_N_DEVICES);
            if(( 0xFF==g_page_buffer[ofst  ] )
            && ( 0xFF==g_page_buffer[ofst+1] ))
            {
               i_block=nf_fetch_free_block(i_dev);
               Assert(       ofst+1<NF_PAGE_BUFFER_SIZE);
               g_page_buffer[ofst  ] = MSB(i_block);
               g_page_buffer[ofst+1] = LSB(i_block);
            }
         }
      } // for ( i_dev ../..

      // Each sub-LUT will fit in a physical page and will be of the same size
      // except the last one which contains less
      //
      for( ; n_sublut_in_buf!=0 ; n_sublut_in_buf--, i_sub_lut++ )
      {
         sub_lut_log_sz= ( i_sub_lut==(g_n_sub_lut-1) ) ? g_last_sub_lut_log_sz : g_sub_lut_log_sz ;

         // Write the sub-LUT in the page
         //
         status_bool = nf_write_lut(i_sub_lut%(NF_PAGE_BUFFER_SIZE/(2*NF_SUBLUT_SIZE)), i_sub_lut, sub_lut_log_sz);
         if ( PASS!=status_bool )
         {
            nfc_mark_bad_block( nf_block_2_page( g_lut_block_addr[i_sub_lut] ) );
            return FAIL;
         }
      }
   }

//#error: si recovery, il faut effacer la lut en question. Il faut donc la reconstruire.
//        Pour cela, il faut trouver des blocs libres.
// 1ere methode: effacer aussi le free-blocks block et le reconstruire, ainsi que la sub-LUT
// 2eme methode: marquer les free block pour les reconnaitre et reconstruire la sub lut

   // Build the free-blocks block
   // First, fill the internal buffer with the free blocks
   //
   for ( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
   {
      Nfc_action(NFC_ACT_DEV_SELECT, i_dev);

      for ( u16_tmp=0 ; u16_tmp<(g_n_free_blocks/NF_N_DEVICES) ; u16_tmp++ )
      {
         // This define is better than using a variable that holds the expression...
         #define OFST   (2*(i_dev + u16_tmp*NF_N_DEVICES))
         i_block=nf_fetch_free_block(i_dev);
         nfc_erase_block( nf_block_2_page(i_block), TRUE );
         Assert(       OFST   <NF_PAGE_BUFFER_SIZE);
         Assert(       OFST +1<NF_PAGE_BUFFER_SIZE);
         Assert( i_block>=g_nf_first_block );
         Assert( i_block< G_N_BLOCKS       );
         g_page_buffer[OFST   ] = MSB(i_block);
         g_page_buffer[OFST +1] = LSB(i_block);
         #undef OFST
      }
   }

   // Then write the buffer in the free-blocks block
   // Note that the list of free-blocks holds on one page only; the
   // algo is thus made for both 512B and 2kB pages.
   //
   g_fbb_block_index=0;
   status_bool = nf_write_fbb();
   if ( PASS!=status_bool )
   {
      nfc_mark_bad_block( nf_block_2_page( g_fbb_block_addr ) );
      return FAIL;
   }

//#error Effacer les free blocks !!!!!!
//#error il faut determiner s_lut_index[all] pour les sub-lut existantes
//#error si il existe un bloc de recovery, alors la lut associƩe n'est plus valide
//#error rendre parametrable la taille du buffer (actuellement 2k). Si <512 et no partial prog: fatal error

   //nf_init_buffer(); // Cleanup the buffer
   return PASS;
}
Example #5
0
//! Scan the memory and looks for sub-LUT, free-blocks block and recovery blocks
//!
//! @param none
//!
//! @return a status:
//!           PASS if the scan has been succesfully executed;
//!           FAIL if the scan encountered any problem
//!
static Status_bool nf_scan( void )
{
   U8          i_dev  =0;
   U16         i_block=0;
   U8          n_quarantine_blocks=0;
   U16         n_invalid_blocks=0;

   g_last_sub_lut_log_sz =(U16)-1;
   g_sub_lut_log_sz      =(U16)NF_SUBLUT_SIZE/NF_N_DEVICES;


   // Initialize the recovery structure. This should be done by the startup !
   //
   g_is_found_lut  =FALSE;
   g_is_found_fbb  =FALSE;
   g_fatal         =FALSE;
   g_n_real_sub_lut=0;

   trace("nf_scan");    trace_nl();
   
   // Scan all the devices and looks for:
   // - the sub-LUT blocks
   // - the recovery block
   // - the free-blocks block
   //
   for( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
   {
      n_invalid_blocks   = 0;
      n_quarantine_blocks= 0;
      g_curr_block_addr[i_dev]= G_N_BLOCKS -1; // points on the last block

      trace("Device "); trace_hex(i_dev); trace("\n\r");
      Nfc_action(NFC_ACT_DEV_SELECT, i_dev);

      for( i_block=g_nf_first_block ; i_block<G_N_BLOCKS ; i_block++ )
      {
         nfc_read_spare_byte( g_byte, 16, nf_block_2_page(i_block) );
         if ( g_byte[G_OFST_BLK_STATUS]!=0xFF )
         {
            n_invalid_blocks +=1 ;
            trace_hex16(i_block); trace(" ("); trace_u32(i_block); trace("): bad Block\n\r");
            continue; // The block is bad
         }

         if(( g_byte[NFC_SPARE_OFST_1_BLK_ID]!=NFC_BLK_ID_SUBLUT     )
         && ( g_byte[NFC_SPARE_OFST_1_BLK_ID]!=NFC_BLK_ID_FBB        )
         && ( g_byte[NFC_SPARE_OFST_1_BLK_ID]!=NFC_BLK_ID_QUARANTINE )
         && ( g_byte[NFC_SPARE_OFST_1_BLK_ID]!=NFC_BLK_ID_DATA       ))
         {
            n_invalid_blocks +=1;
            trace_hex16(i_block); trace(" ("); trace_u32(i_block); trace("): Unknown\n\r");
            continue;
         }
         else if ( g_byte[NFC_SPARE_OFST_1_BLK_ID]==NFC_BLK_ID_QUARANTINE )
         {
            n_quarantine_blocks +=1;
            trace_hex16(i_block); trace(" ("); trace_u32(i_block); trace("): Quarantine\n\r");
            continue;
         }
         else if ( g_byte[NFC_SPARE_OFST_1_BLK_ID]==NFC_BLK_ID_SUBLUT )
         {
            n_invalid_blocks +=1;
            if ( i_dev==S_MNGT_DEV )
            {
               U8 sub_lut_id                   = g_byte[NFC_SPARE_OFST_2_BYTE_2];
               g_n_sub_lut                     = g_byte[NFC_SPARE_OFST_4_BYTE_4];
               g_is_found_lut = TRUE;
               g_n_real_sub_lut++;
               g_lut_block_addr[sub_lut_id] = i_block;
               if ( sub_lut_id==(g_n_sub_lut-1) )
               {
                  MSB(g_last_sub_lut_log_sz)= g_byte[NFC_SPARE_OFST_6_LBA  ];
                  LSB(g_last_sub_lut_log_sz)= g_byte[NFC_SPARE_OFST_6_LBA+1];
               }
               g_lut_block_index[sub_lut_id]= nf_refine_index(i_block, 1, NFC_BLK_ID_SUBLUT);
               trace_hex16(i_block); trace(" ("); trace_u32(i_block); trace("): SUB-LUT (id ");trace_hex(sub_lut_id);trace(" ofst "); trace_hex(g_lut_block_index[sub_lut_id]); trace(")\n\r");
               continue ;
            }
            else
            {  // LUT found on bad NF
               g_fatal=TRUE;
               break;
            }
         }

         else if ( g_byte[NFC_SPARE_OFST_1_BLK_ID]==NFC_BLK_ID_FBB )
         {
            n_invalid_blocks +=1;
            if ( i_dev==S_MNGT_DEV )
            {
               if ( TRUE==g_is_found_fbb )
               {
                  g_fatal=TRUE; // already found
                  break;
               }
               g_fbb_block_addr  = i_block;
               g_fbb_block_index = nf_refine_index(i_block, 1, NFC_BLK_ID_FBB);
               nfc_read_spare_byte( g_byte, 16, nf_block_2_page(i_block) + (U32)g_fbb_block_index );     // Reload
               if( NFC_OFST_6_FBB_VALID!=g_byte[NFC_SPARE_OFST_6_LBA] )
               {
                  g_fatal=TRUE; // FBB not valid. Force rebuild
                  break;
               }

               MSB(g_n_free_blocks)   = g_byte[NFC_SPARE_OFST_2_BYTE_2];
               LSB(g_n_free_blocks)   = g_byte[NFC_SPARE_OFST_3_BYTE_3];
               s_nfd_rev              = g_byte[NFC_SPARE_OFST_4_BYTE_4];
               MSB(g_n_export_blocks) = g_byte[NFC_SPARE_OFST_EXPORT];
               LSB(g_n_export_blocks) = g_byte[NFC_SPARE_OFST_EXPORT+1];
               trace("      g_n_free_blocks="); trace_hex16(g_n_free_blocks); trace_nl();
               trace("      g_n_export_blocks="); trace_hex16(g_n_export_blocks); trace_nl();
               g_is_found_fbb=TRUE;
               trace_hex16(i_block); trace(" ("); trace_u32(i_block); trace("): FBB (ofst "); trace_hex( g_fbb_block_index ); trace(")\n\r");
               continue ;
            }
            else
            {
               g_fatal=TRUE;
               break;
            }
         }
      } // for ( i_block

      // A fatal error on one device is enough to cleanup all the devices !
      //
      s_n_invalid_blocks[   i_dev]= n_invalid_blocks;
      s_n_quarantine_blocks[i_dev]= n_quarantine_blocks;

      if ( TRUE==g_fatal ) { break; }
   } // for ( i_dev

   return (g_fatal==TRUE) ? FAIL: PASS;
} // nf_scan
Example #6
0
// main function
int main(void)
{
  bool   valid_block_found[NF_N_DEVICES];
  U32    u32_nf_ids, i_dev, i_block;
  U8     maker_id, device_id;
  U32    i, j;
  // ECCHRS options.
  static const ecchrs_options_t ECCHRS_OPTIONS =
  {
    .typecorrect = ECCHRS_TYPECORRECT_4_BIT,
    .pagesize    = ECCHRS_PAGESIZE_4_BIT_2112_W
  };

  // switch to oscillator 0
  pcl_switch_to_osc(PCL_OSC0, FOSC0, OSC0_STARTUP);

   // init debug serial interface
  init_dbg_rs232(FOSC0);

  nf_init(FOSC0); // init the nand flash driver with the correct HSB frequency
  nf_unprotect();

  print_dbg("\r\nECCHRS example using Nand Flash.\r\n================================\r\n\r\n");

  // - Simple test of the NF communication through the SMC.
  // - Find all bad blocks.
  // - Find a valid block for the remaining tests.
  nf_reset_nands(NF_N_DEVICES);

  print_dbg("\tCPU, HSB is at 12000000Mhz.\r\n");
  print_dbg("\tPBA, PBB is at 12000000Mhz.\r\n");

  print_dbg("\tDetecting Nand Flash device(s).\r\n");
  for( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
  {
    // Performs some init here...
    valid_block_found[i_dev] = false;

    // Test Maker and Device ids
    u32_nf_ids = nf_read_id( NF_READ_ID_CMD, i_dev );
    maker_id  = MSB0(u32_nf_ids);
    device_id = MSB1(u32_nf_ids);
    print_dbg("\t\tNF");
    print_dbg_hex(i_dev);
    print_dbg(" [Maker=");
    print_dbg_hex(maker_id);
    print_dbg("] [Device=");
    print_dbg_hex(device_id);
    print_dbg("]\r\n");
    if( maker_id==M_ID_MICRON )
    {
      print_dbg("\t\t       Micron chip");
      if( device_id==0xDA ){
        print_dbg("- MT29F2G08AACWP device\r\n");
      }
      else
      {
       print_dbg("- *** Error: unexpected chip detected. Please check the board settings and hardware.\r\n");
        return -1;
      }
    }
    else
    {
      print_dbg("\t\t       *** Error: unexpected chip detected. Please check the board settings and hardware.\r\n");
      return -1;
    }
  }

  // Looking for valid blocks for the test.
  for( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
  {
    nf_select(i_dev);
    for( i_block=0 ; i_block<G_N_BLOCKS ; i_block++ )
    {
      nf_open_page_read( nf_block_2_page(i_block), NF_SPARE_POS + G_OFST_BLK_STATUS );
      if( (nf_rd_data()==0xFF) )
      { // The block is valid.
        print_dbg("\tValid block found (");
        print_dbg_ulong(i_block);
        print_dbg(") on NF ");
        print_dbg_hex(i_dev);
        print_dbg("\r\n");
        valid_block_found[i_dev]= true;
        valid_block_addr[i_dev] = i_block;
        break;
      }
    }
  }

  for( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
    if( !valid_block_found[i_dev] )
    {
      print_dbg("Error: no valid blocks found.\r\n");
      return 0;
    }

  print_dbg("\tECCHRS IP ver ");
  print_dbg_ulong(ecchrs->version);
  print_dbg("(");
  print_dbg_hex(ecchrs->version);
  print_dbg(")");
  print_dbg("\r\n");


  // Work with NF 0 from now...
  nf_select(0);

  // Setup the ECCHRS.
  ecchrs_init(&AVR32_ECCHRS, &ECCHRS_OPTIONS);

  // Ensures that the block is erased for the test.
  print_dbg("\tErasing a free block for the test.\r\n");
  nf_erase_block(nf_block_2_page(valid_block_addr[0]), false);

  // Reset the ECCHRS state machine.
  ecchrs_reset(&AVR32_ECCHRS);

  // Program a simple patterns in the first page.
  print_dbg("\tProgramming the first page with a simple pattern.\r\n");
  nf_open_page_write( nf_block_2_page(valid_block_addr[0]), 0);
  for ( i = 0; i < 2048/2; i++ )
  {
    U16 val = i;
    nf_wr_data(MSB(val));
    nf_wr_data(LSB(val));
  }

  // Extract the ECCs and store them at the end of the page.
  // [2054; 2063]: codeword  0:9
  // [2070; 2079]: codeword 10:19
  // [2086; 2095]: codeword 20:29
  // [2102; 2111]: codeword 30:39
  // Since we use the Random Data Output command, we need to freeze
  // the ECCHRS in order to keep our ECC codewords unchanged.
  print_dbg("\tExtracting the ECCHRS codewords and store them in the page.\r\n");
  ecchrs_freeze(&AVR32_ECCHRS);  // not needed if ECCHRS reaches the end of page.
  for ( i=0 ; i<4 ; i++ )
  {
    U16 offset = 2048+6+16*i;
    nf_wr_cmd(NF_RANDOM_DATA_INPUT_CMD);
    nf_wr_addr( LSB(offset) );
    nf_wr_addr( MSB(offset) );
    for ( j=0 ; j<10 ; j++ )
      nf_wr_data( ecchrs_get_cw(&AVR32_ECCHRS, i*10+j) );
  }
  ecchrs_unfreeze(&AVR32_ECCHRS);

  nf_wr_cmd(NF_PAGE_PROGRAM_CMD);


  // Now let's test the ECC verification.
  print_dbg("\tReading the first page.\r\n");
  nf_open_page_read( nf_block_2_page(valid_block_addr[0]), 0);
  for( i=0 ; i<2048 ; i++ )
    nf_rd_data();

  print_dbg("\tChecking if the data are valid thanks to the ECCHRS codewords.\r\n");
  for ( i=0 ; i<4 ; i++ )
  {
    U16 offset = 2048+6+16*i;
    ecchrs_freeze(&AVR32_ECCHRS);
    nf_wr_cmd(NF_RANDOM_READ_CMD_C1);
    nf_wr_addr( LSB(offset) );
    nf_wr_addr( MSB(offset) );
    nf_wr_cmd(NF_RANDOM_READ_CMD_C2);
    ecchrs_unfreeze(&AVR32_ECCHRS);
    for ( j=0 ; j<10 ; j++ )
      nf_rd_data();
  }

  // Check if there is any errors after the read of the page.
  i = ecchrs_4bit_check_error(&AVR32_ECCHRS);
  print_dbg("\tSR1 is  ");
  print_dbg_ulong(i);
  print_dbg("(");
  print_dbg_hex(i);
  print_dbg(")");
  print_dbg("\r\n");

  if(i&(15))
  {
   print_dbg("\tERROR: ECCHRS detects some errors in the sectors 1, 2, 3 or 4\r\n");
  }
  else
   print_dbg("\tNo error detected.\r\n");

  // Let the block free.
  nf_erase_block(nf_block_2_page(valid_block_addr[0]), false);
  return 0;
}
Example #7
0
/*! \brief Main function.
 */
int main(void)
{
  bool   valid_block_found[NF_N_DEVICES];
  U32    u32_nf_ids, i_dev, i_block;
  U8     maker_id, device_id, byte3;
  U32    i, time_s, time_e;
  U8     data;

  // start init
  sysclk_init();

  // Enable clock for require module
  sysclk_enable_hsb_module(SYSCLK_EBI);
  sysclk_enable_pbb_module(SYSCLK_SMC_REGS);
  sysclk_enable_pbb_module(SYSCLK_HMATRIX);

  // Initialize the board.
  // The board-specific conf_board.h file contains the configuration of the board
  // initialization.
  board_init();

  init_stdio();

#ifdef NF_ADDON // addon nandflash board for EVK1104 (not mounted by default)
  // Unselect NF on board
  gpio_set_gpio_pin(AVR32_PIN_PX53);
  gpio_set_gpio_pin(AVR32_PIN_PX52);
#endif

  nf_init(sysclk_get_cpu_hz());
  nf_unprotect();

  printf("\x0C");
  printf("Nand Flash example.\r\n===================\r\n\r\n");

  // - Simple test of the NF communication through the SMC.
  // - Find all bad blocks.
  // - Find a valid block for the remaining tests.
  nf_reset_nands(NF_N_DEVICES);

  printf("\tDetecting Nand Flash device(s).\r\n");
  for( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
  {
    // Performs some init here...
    valid_block_found[i_dev] = false;

    // Test Maker and Device ids
    u32_nf_ids = nf_read_id( NF_READ_ID_CMD, i_dev );
    maker_id  = MSB0(u32_nf_ids);
    device_id = MSB1(u32_nf_ids);
    byte3     = MSB3(u32_nf_ids);
    printf("\t\tNF %ld: [Maker=0x%02x] [Device=0x%02x] [byte3=0x%02x]\r\n", i_dev, maker_id, device_id, byte3);
    if( maker_id==M_ID_MICRON )
    {
      printf("\t\t       Micron chip");
      if( (device_id==0xDA) && (byte3==0x15) )
        printf("- MT29F2G08AACWP device\r\n");
      else if( (device_id==0xDA) && (byte3==0x95) )
        printf("- MT29F2G08AADWP device\r\n");
      else
      {
        printf("- *** Error: unexpected chip detected. Please check the board settings and hardware.\r\n");
        return -1;
      }
    }
    else
    {
      printf("\t\t       *** Error: unexpected chip detected. Please check the board settings and hardware.\r\n");
      return -1;
    }
  }

  printf("\r\n\tTesting bad blocks.\r\n");
  for( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
  {
    printf("\t\tNF %ld:\r\n", i_dev);
    nf_select(i_dev);
    for( i_block=0 ; i_block<G_N_BLOCKS ; i_block++ )
    {
      nf_open_page_read( nf_block_2_page(i_block), NF_SPARE_POS + G_OFST_BLK_STATUS );
      if( (nf_rd_data()!=0xFF) )
      { // The block is bad.
        printf("\t\t\tBlock %ld (0x%lx) is bad.\r\n", i_block, i_block);
      }
      else
      {
        if( !valid_block_found[i_dev] )
        {
          valid_block_found[i_dev]= true;
          valid_block_addr[i_dev] = i_block;
          printf("\t\t\tFirst valid block is at address %ld (0x%lx).\r\n", i_block, i_block);
        }
      }
    }
  }

  for( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
    if( !valid_block_found[i_dev] )
    {
      printf("Error %d\r\n", __LINE__);
      return 0;
    }



  // - Ensure good NF behaviour through simple commands.
  //   Erase, Program, Read
  // - Measures NF timings.
  printf("\r\n\tMeasuring NF timings.\r\n");
  for( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
  {
    printf("\t\tNF %ld:\r\n", i_dev);
    nf_select(i_dev);
    nf_erase_block( nf_block_2_page(valid_block_addr[0]), false);
    time_s = Get_sys_count();
    nf_wait_busy();
    time_e = Get_sys_count();

    // Verify that the block is erased.
    nf_open_page_read( nf_block_2_page(valid_block_addr[0]), 0);
    for( i= 0; i<2048 ; i++ )
    {
      data = nf_rd_data();
      if( data!=0xFF )
      {
        printf("\tError: offset %d is not erased (read %d).\r\n", (U8)i, data);
        return 0;
      }
    }
    printf("\t\t\tTime to erase a page:%ld cy (%ld us)\r\n", time_e-time_s, cpu_cy_2_us(time_e-time_s, sysclk_get_cpu_hz()));

    nf_open_page_write( nf_block_2_page(valid_block_addr[0]), 0);
    for( i=0 ; i<2048 ; i++ )
      nf_wr_data(i%256);
    nf_wr_cmd(NF_PAGE_PROGRAM_CMD);

    time_s = Get_sys_count();
    nf_wait_busy();
    time_e = Get_sys_count();
    printf("\t\t\tTime to program a page:%ld cy (%ld us)\r\n", time_e-time_s, cpu_cy_2_us(time_e-time_s, sysclk_get_cpu_hz()));

    time_s = Get_sys_count();
    nf_open_page_read( nf_block_2_page(valid_block_addr[0]), 0);
    time_e = Get_sys_count();
    printf("\t\t\tTime to access to a page:%ld cy (%ld us)\r\n", time_e-time_s, cpu_cy_2_us(time_e-time_s, sysclk_get_cpu_hz()));
    for( i= 0; i<2048 ; i++ )
    {
      data = nf_rd_data();
      if( data!= i%256)
      {
        printf("\tError: expect %d, read %d\r\n", (U8)i, data);
        return 0;
      }
    }
  }

  printf("Example DONE\r\n");

  return 0;
}