Beispiel #1
0
/***************************************************************************
* cfiscsIdentify - Identification routine for devices conforming to CFI/SC
*
* Identifies media based on CFI and the AMD/Fujitsu command set and registers
* as an MTD for such. This routine should be placed on the MTD list in 
* flcustom.h. It must be an extern routine. On successful identification, the
* Flash structure is filled out and the write and erase routines registered. 
*
* RETURNS:
*      FLStatus        : 0 on positive identification, failed otherwise 
*
* ERRNO
*
* http://www.amd.com/us-en/FlashMemory/ProductInformation/0,,37_1447_1451_1780%5E1834%5E1955,00.html
*
* \NOMANUAL
*/
FLStatus cfiAmdIdentify
    (
    FLFlash vol              /* Pointer identifying drive */
    )
    {
    FlashPTR flashPtr = (FlashPTR) flMap(vol.socket, 0);
    FlashWPTR flashWPtr = (FlashWPTR) flashPtr;

    unsigned primaryTable, secondaryTable;
    FLBoolean eightBitMode = FALSE;
    int thisSector = 0;     /* running count of sectors for this CFI */
    CardAddress sectorBaseAdrs = 0; /* base address of this sector */
    int ix = 0;

#ifdef DEBUG_PRINT
    DEBUG_PRINT("Debug: entering CFIAMD identification routine.\n");
    DEBUG_PRINT("Debug: flash base addr = 0x%x\n", (UINT32)flashPtr);
#endif

    flSetWindowBusWidth(vol.socket, 16);/* use 16-bits */
    flSetWindowSpeed(vol.socket, 120);  /* 120 nsec. */
    flSetWindowSize(vol.socket, 2);       /* 8 KBytes */

    vol.mtdVars = &mtdVars[flSocketNoOf(vol.socket)];
    thisCFI->bootBlockSectors = 0;

    /* Is this an 8 bit device */
    flashPtr[0x55] = AMD_READ_ARRAY;
    flashPtr[0x55] = QUERY;

    if (flashPtr[0x10] == 0x51 && /* 'Q' */
        flashPtr[0x11] == 0x52 && /* 'R' */
        flashPtr[0x12] == 0x59)   /* 'Y' */
        {
#ifdef DEBUG_PRINT
        DEBUG_PRINT ("Debug: detected single 8 bit device\n");
#endif
        thisCFI->multiplier = 1;
        thisCFI->interleaveWidth = 1;
        vol.interleaving = 1;
        eightBitMode = TRUE;

        goto getCFI;
        }

    /* Reset to READ_ARRAY and retry. Maybe 16 bit addressing 
     */
    flashPtr[0x55] = AMD_READ_ARRAY;
    flashWPtr[0x55] = (USHORT) ((QUERY << 8) | QUERY); 

    /* Check for two interleaved 8 bit parts */
    if (flashPtr[0x20] == 0x51 && /* 'Q' */
        flashPtr[0x21] == 0x51 && /* 'Q' */
        flashPtr[0x22] == 0x52 && /* 'R' */
        flashPtr[0x23] == 0x52 && /* 'R' */
        flashPtr[0x24] == 0x59 && /* 'Y' */
        flashPtr[0x25] == 0x59)   /* 'Y' */
        {
        /* Let's try turning one off */
        CFI_WORD_WRITE((FlashWPTR)(&flashPtr[0x55]), AMD_READ_ARRAY);
        if (flashPtr[0x20] != 0x51) /* Turned off successfully */
            {
            thisCFI->multiplier = 2;
            thisCFI->interleaveWidth = 1;
            vol.interleaving =2;
#ifdef DEBUG_PRINT
            DEBUG_PRINT ("Debug: detected two 8 bit devices\n");
#endif
            eightBitMode = TRUE;
            goto getCFI;
            }
        }

    /* a 16 bit device in 16 bit mode */
    if (flashWPtr[0x10] == 'Q' && 
        flashWPtr[0x11] == 'R' &&
        flashWPtr[0x12] == 'Y')
        {
        thisCFI->multiplier = 2;
        thisCFI->interleaveWidth = 1;
        vol.interleaving = 1;
#ifdef DEBUG_PRINT
        DEBUG_PRINT ("Debug: detected one 16 bit device\n");
#endif
        goto getCFI;
        }

#ifdef DEBUG_PRINT
    DEBUG_PRINT ("Debug: No flash media detected!\n");
#endif

    return flUnknownMedia;

    getCFI:

    if (!eightBitMode)
        {
        thisCFI->wordMode = TRUE; /* limiting ourselves to 8 an 16 bit devs */
        thisCFI->unlockAddr1 = AMD_WW_UNLOCK_ADDR1;
        thisCFI->unlockAddr2 = AMD_WW_UNLOCK_ADDR2;
#ifdef DEBUG_PRINT
        DEBUG_PRINT("WORD MODE !!\n");
#endif
        }
    else
        {
        thisCFI->wordMode = FALSE;
        thisCFI->unlockAddr1 = AMD_BW_UNLOCK_ADDR1;
        thisCFI->unlockAddr2 = AMD_BW_UNLOCK_ADDR2;
#ifdef DEBUG_PRINT
        DEBUG_PRINT("WORD MODE !!\n");
#endif
        }

    /* check the command set ID */
    /* NOTE: Not swapped */
    thisCFI->commandSetId = *(USHORT *)(&flashPtr[0x13 * thisCFI->multiplier]);
#ifdef DEBUG_PRINT
    DEBUG_PRINT ("Debug: Commandset ID is 0x%x\n", thisCFI->commandSetId);
#endif

    /* Only support the AMD/Fujitsu Command set */
    if ( thisCFI->commandSetId != AMDFUJ_COMMAND_SET)
        {
#ifdef DEBUG_PRINT
        DEBUG_PRINT("Debug: did not recognize command set.\n");
#endif
        return flUnknownMedia;
        }

    /* get address for primary algorithm extended table. */
    primaryTable = CFI_WORD_READ(&flashPtr[0x15 * thisCFI->multiplier]);

    /* check alternate command set ID. */
    /* NOTE: not swapped */
    thisCFI->altCommandSetId = *(USHORT *)
                               (&flashPtr[0x17 * thisCFI->multiplier]);
    if (thisCFI->altCommandSetId != AMDFUJ_ALT_COMMAND_SET &&
        thisCFI->altCommandSetId != ALT_NOT_SUPPORTED)
        return flUnknownMedia;

    /* get address for secondary algorithm extended table. */
    secondaryTable = CFI_WORD_READ(&flashPtr[0x19 * thisCFI->multiplier]);

    thisCFI->vpp = flashPtr[0x1d * thisCFI->multiplier];

    /*Get the number of erase block descriptions for the CFI*/
    if (eightBitMode)
        thisCFI->sectorDefs = (int) (*(UCHAR *) 
                                     (&flashPtr[0x2c * thisCFI->multiplier]));
    else
        thisCFI->sectorDefs = (int) (*(USHORT *)
                                     (&flashPtr[0x2c * thisCFI->multiplier]));

    /* We should bail out if this is greater than 8 */
#ifdef DEBUG_PRINT
    DEBUG_PRINT ("Debug: Number of erase block descriptions is 0x%x\n", 
                 thisCFI->sectorDefs);
#endif

    vol.erasableBlockSize = 0;
    thisCFI->sectorsInCFI = 0;

    for ( ix = 0; ix < thisCFI->sectorDefs; ix++)
        {
        thisCFI->secDesc[ix].numSecs = (int) (*(USHORT *)
                                              (&flashPtr[(0x2d + (ix * 4)) * thisCFI->multiplier]));
        thisCFI->secDesc[ix].numSecs++;

#ifdef DEBUG_PRINT
        DEBUG_PRINT ("Debug: Num sectors in %d - %d\n", ix, thisCFI->secDesc[ix].numSecs);
#endif

        thisCFI->secDesc[ix].secSize = (long) ((*(USHORT *)
                                                (&flashPtr[(0x2f + (ix * 4)) * thisCFI->multiplier])) +
                                               (*(USHORT *)(&flashPtr[(0x30 + (ix * 4)) * 
                                                                      thisCFI->multiplier])) * 0x100L);
#ifdef DEBUG_PRINT
        DEBUG_PRINT ("Debug: Sector size is 0x%x\n",
                     (UINT32) thisCFI->secDesc[ix].secSize);
#endif

        /* TrueFFS does not support the flexible sector architecture so we 
         * take the largest sector size to be the erase block size.
         */ 
        if (vol.erasableBlockSize < thisCFI->secDesc[ix].secSize)
            vol.erasableBlockSize = thisCFI->secDesc[ix].secSize;

        /* Also track the number of sector on this device */
        thisCFI->sectorsInCFI += thisCFI->secDesc[ix].numSecs;
        }

    if (vol.erasableBlockSize == 0x00)
        vol.erasableBlockSize = 0x80L;
    else
        vol.erasableBlockSize *= 256;

    /* Get Device Size */   
    if (eightBitMode)
        vol.chipSize = (1L << flashPtr[0x27 * thisCFI->multiplier]);
    else
        vol.chipSize = (1L << *(USHORT*)(&flashPtr[0x27 * thisCFI->multiplier]));

    vol.erasableBlockSize *= vol.interleaving;

    vol.chipSize -= CDS85XX_FLASH_RESERVED_SIZE;

#ifdef SAVE_NVRAM_REGION

    /* Top boot block devices will loose their entire boot block to NVRAM. Since 
     * TrueFFS cares not about the subdivisions we reserve an entire erase block
     * on each of the interleaved devices. 
     */
    vol.chipSize -= vol.erasableBlockSize;
#endif

#ifdef DEBUG_PRINT
    DEBUG_PRINT("Debug: %d sectors on device\n", thisCFI->sectorsInCFI);
    DEBUG_PRINT("Debug: Erasable block size is 0x%lx\n", vol.erasableBlockSize);
    DEBUG_PRINT("Debug: Chip size is 0x%lx\n", vol.chipSize);
#endif

    thisCFI->bootBlockType = BOOTBLOCK_NONE;

    /* Simplest case is the uniform sector device. Has only one 
     * sector desc. 
     */
    for (; thisSector < thisCFI->secDesc[0].numSecs; thisSector++)
        {
        thisCFI->secInfo[thisSector].sectorSize = vol.erasableBlockSize;
        thisCFI->secInfo[thisSector].sectorBaseAdrs = sectorBaseAdrs;
        sectorBaseAdrs += (CardAddress) vol.erasableBlockSize;
        }

#ifdef DEBUG_PRINT
    DEBUG_PRINT("Debug: Number of boot block sectors is %d\n", thisCFI->bootBlockSectors);
#endif

    /* Make sure this comes at the end since the device is set to READ_ARRAY
     * mode prior to the return
     */
    if (cfiAmdChipCountGet(&vol) != flOK)
        return flUnknownMedia;

#ifdef DEBUG_PRINT
    DEBUG_PRINT ("Debug: No of chips detected is %d\n", vol.noOfChips);
#if 0
    for (ix = 0; ix < thisCFI->sectorsInCFI; ix++)
        DEBUG_PRINT ("%2d:0x%x	---  0x%lx\n", ix,
                     thisCFI->secInfo[ix].sectorBaseAdrs, 
                     thisCFI->secInfo[ix].sectorSize);
#endif
#endif

    vol.erase = cfiAmdErase;
    vol.write = cfiAmdWrite;

    /* Might have to do this on a bus width basis but for now it seems to
     * work with Intel devices.
     */
    flashPtr[0] = AMD_READ_ARRAY;
    flashPtr[1] = AMD_READ_ARRAY;
    flashPtr[2] = AMD_READ_ARRAY;
    flashPtr[3] = AMD_READ_ARRAY;

    return flOK;
    }
Beispiel #2
0
FLStatus check43Format(FLFlash *flash)
{
   FLStatus status;
   byte FAR1* buf;

   /* If this is an alon */
   if (flash->mediaType != DOC2000TSOP_TYPE)
      return flOK;
   buf = (flBufferOf(flSocketNoOf(flash->socket))->flData);
   if(flash->readBBT == NULL)
   {
      DFORMAT_PRINT(("ERROR : MTD read BBT routine was not initialized\r\n"));
      return flFeatureNotSupported;
   }
   status = flash->readBBT(flash,0,1,0,buf,FALSE);

   if (status == flBadBBT)
   {
      dword mediaSize = ((dword)flash->noOfChips*flash->chipSize);
      dword blockSize = 1<<flash->erasableBlockSizeBits;
      dword addr      = 0;
      dword offset;
      word  mediaHeaderBlock; /* ANAND unit number                */
      byte  blocksPerUnit;    /* Blocks per virtual unit          */
      byte  blockShift;       /* Bits to shift from block to unit */

CHECK_UNIT_WITH_ANAND:

      /* Either virgin or formated wih TrueFFS 4.3 */

      for( ; addr < mediaSize ; addr += blockSize)
      {
         checkStatus(flash->read(flash,addr,buf,5,0));
         if(tffscmp(buf,"ANAND",5) == 0)
            break;
      }

      if (addr == mediaSize) /* virgin card */
         return flOK;

      DFORMAT_PRINT(("This DiskOnChip was formated with an NFTL format.\r\n"));

      /* Calculate block multiplier bits */

      for (offset = addr + SECTOR_SIZE , status = flOK;
           (offset < addr + blockSize) && (status == flOK) ;
           offset += SECTOR_SIZE)
      {
         status = flash->read(flash,addr+offset,buf,512,EDC);
      }

      if(offset == addr + (SECTOR_SIZE<<1)) /* Bad EDC for NFTL unit header */
      {
         DFORMAT_PRINT(("ERROR - Unit with ANAND was found, but the BBT has bad EDC.\r\n"));
         addr += blockSize;
         goto CHECK_UNIT_WITH_ANAND; /* Keep searching */
      }

      offset = (offset - addr - (SECTOR_SIZE<<1)) << flash->erasableBlockSizeBits;

      for(blockShift = 0 ; offset < mediaSize ; blockShift++)
      {
         offset <<= 1;
      }
      blocksPerUnit = 1 << blockShift;

      mediaHeaderBlock = (word)(addr >> (flash->erasableBlockSizeBits + blockShift));

      DFORMAT_PRINT(("Please wait while unformating is in progress...\r\n"));

      /* Read and write 512 blocks of the BBT (start from the end) */

      for (offset = 0;
           offset < mediaSize>>(flash->erasableBlockSizeBits + blockShift);
           offset += SECTOR_SIZE)
      {
         word i;

         checkStatus(flash->read(flash,addr+offset+SECTOR_SIZE,buf,SECTOR_SIZE,EDC));
         for(i=0;i<SECTOR_SIZE;i++)
         {
            if (i+offset == mediaHeaderBlock)
               continue;

            if (buf[i]==BBT_BAD_UNIT) /* A bad block */
            {
               markUnitBad(flash , i+offset);
            }
            else                      /* A good block */
            {
               status = flash->erase(flash,(word)(i+offset),blocksPerUnit);
               if (status != flOK)
                  markUnitBad(flash , i+offset);
            }
         }
      }
      status = flash->erase(flash,mediaHeaderBlock,blocksPerUnit);
      if (status != flOK)
         markUnitBad(flash , mediaHeaderBlock);

      DFORMAT_PRINT(("Unformating of DiskOnChip 2000 tsop complete.\r\n"));
   }
Beispiel #3
0
FLStatus flIdentifyFlash(FLSocket *socket, FLFlash vol)
{
  FLStatus status = flUnknownMedia;
  int iMTD;
  dword blockSize;

  vol.socket = socket;

#ifndef FIXED_MEDIA
  /* Check that we have a media */
  flResetCardChanged(vol.socket);        /* we're mounting anyway */
  checkStatus(flMediaCheck(vol.socket));
#endif

#ifdef ENVIRONMENT_VARS
   if(flUseisRAM==1)
   {
#endif
#if !defined(FL_IDE_DOC) && !defined(FL_IDE_MDOCP)
     if ( isRAM(&vol))
       return flUnknownMedia;    /* if it looks like RAM, leave immediately */
#endif /* !FL_IDE_DOC && !FL_IDE_MDOCP */
#ifdef ENVIRONMENT_VARS
   }
#endif

  /* Install default methods */
  vol.type                   = NOT_FLASH;
  vol.mediaType              = NOT_DOC_TYPE;
  vol.pageSize               = 0;
  vol.flags                  = 0;
  vol.map                    = flashMap;
  vol.read                   = flashRead;
  vol.setPowerOnCallback     = setNoCallback;
  vol.erase                  = flashNoErase;
  vol.write                  = flashNoWrite;
  vol.readBBT                = NULL;
  vol.writeIPL               = NULL;
  vol.readIPL                = NULL;
#ifdef HW_OTP
  vol.otpSize                = NULL;
  vol.readOTP                = NULL;
  vol.writeOTP               = NULL;
  vol.getUniqueId            = NULL;
#endif /* HW_OTP */
#ifdef  HW_PROTECTION
  vol.protectionBoundries    = NULL;
  vol.protectionKeyInsert    = NULL;
  vol.protectionKeyRemove    = NULL;
  vol.protectionType         = NULL;
  vol.protectionSet          = NULL;
#endif /* HW_PROTECTION */
  vol.download               = NULL;
  vol.enterDeepPowerDownMode = NULL;
#ifndef FL_NO_USE_FUNC
  if(flBusConfig[flSocketNoOf(socket)] != FL_ACCESS_USER_DEFINED)
  {
     vol.memRead                = NULL;
     vol.memWrite               = NULL;
     vol.memSet                 = NULL;
     vol.memRead8bit            = NULL;
     vol.memWrite8bit           = NULL;
     vol.memRead16bit           = NULL;
     vol.memWrite16bit          = NULL;
     vol.memWindowSize          = NULL;
     vol.memSetGetMode          = NULL;
  }
#endif /* FL_NO_USE_FUNC */
  /* Setup arbitrary parameters for read-only mount */
  vol.chipSize                 = 0x100000L;
  vol.erasableBlockSize        = 0x1000L;
  vol.noOfChips                = 1;
  vol.interleaving             = 1;
  vol.noOfFloors               = 1;
  vol.totalProtectedAreas      = 0;
  vol.changeableProtectedAreas = 0;
  vol.ppp                      = 5;
  vol.firstUsableBlock         = 0;
  vol.maxEraseCycles           = 100000L; /* Defaul for NOR */

  /* Attempt all MTD's */
  for (iMTD = 0; (iMTD < noOfMTDs) && (status != flOK) &&
       (status != flBadDownload); iMTD++)
    status = mtdTable[iMTD](&vol);

  if (status == flBadDownload)
  {
    DEBUG_PRINT(("Debug: Flash media reported bad download error.\r\n"));
    return flBadDownload;
  }

  if (status != flOK) /* No MTD recognition */
  {
    DEBUG_PRINT(("Debug: did not identify flash media.\r\n"));
    return flUnknownMedia;
  }

  /* Calculate erasable Block Size Bits */
  for(blockSize = vol.erasableBlockSize>>1,vol.erasableBlockSizeBits = 0;
      blockSize>0; vol.erasableBlockSizeBits++,blockSize = blockSize >> 1);

  return flOK;


}