Logo Search packages:      
Sourcecode: xbox-raincoat version File versions  Download package

BootFlash.c

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

 /*
  2003-04-14  andy@warmcat.com  Fixed W49F020 erase, confirmed working
  2003-01-27  andy@warmcat.com  Fixed and verified ST29F080A programming
                                Different block erase command from SST part
                                Also seemed to require explicit chip reset action
  2003-01-06  andy@warmcat.com  Created
 */

#include "boot.h"
#include "BootFlash.h"
#include <stdio.h>
#include <string.h>

      // gets device ID, sets pof up accordingly
      // returns true if device okay or false for unrecognized device

bool BootFlashGetDescriptor( OBJECT_FLASH *pof, KNOWN_FLASH_TYPE * pkft )
{
      bool fSeen=false;
      BYTE baNormalModeFirstTwoBytes[2];
      int nTries=0;
      int nPos=0;

      pof->m_fIsBelievedCapableOfWriteAndErase=true;
      pof->m_szAdditionalErrorInfo[0]='\0';

      baNormalModeFirstTwoBytes[0]=pof->m_pbMemoryMappedStartAddress[0];
      baNormalModeFirstTwoBytes[1]=pof->m_pbMemoryMappedStartAddress[1];

      while(nTries++ <2) { // first we try 29xxx method, then 28xxx if that failed

                  // no ISRs should touch flash while we do the stuff
            __asm__ __volatile__ ( "pushf ; cli ");


            if(nTries!=1) { // 29xxx protocol

                  // make sure the flash state machine is reset

                  pof->m_pbMemoryMappedStartAddress[0x5555]=0xf0;
                  pof->m_pbMemoryMappedStartAddress[0x5555]=0xaa;
                  pof->m_pbMemoryMappedStartAddress[0x2aaa]=0x55;
                  pof->m_pbMemoryMappedStartAddress[0x5555]=0xf0;

                        // read flash ID

                  pof->m_pbMemoryMappedStartAddress[0x5555]=0xaa;
                  pof->m_pbMemoryMappedStartAddress[0x2aaa]=0x55;
                  pof->m_pbMemoryMappedStartAddress[0x5555]=0x90;

                  pof->m_bManufacturerId=pof->m_pbMemoryMappedStartAddress[0];
                  pof->m_bDeviceId=pof->m_pbMemoryMappedStartAddress[1];

                  pof->m_pbMemoryMappedStartAddress[0x5555]=0xf0;

                  pof->m_fDetectedUsing28xxxConventions=false; // mark the flash object as representing a 28xxx job


            } else { // 28xxx protocol, seen on Sharp

                        // make sure the flash state machine is reset

                  pof->m_pbMemoryMappedStartAddress[0x5555]=0xff;

                        // read flash ID

                  pof->m_pbMemoryMappedStartAddress[0x5555]=0x90;
                  pof->m_bManufacturerId=pof->m_pbMemoryMappedStartAddress[0];

                  pof->m_pbMemoryMappedStartAddress[0x5555]=0x90;
                  pof->m_bDeviceId=pof->m_pbMemoryMappedStartAddress[1];

                  pof->m_pbMemoryMappedStartAddress[0x5555]=0xff;

                  pof->m_fDetectedUsing28xxxConventions=true; // mark the flash object as representing a 28xxx job

            }

            __asm__ __volatile__ ( "popf ");


            if(
                  (baNormalModeFirstTwoBytes[0]!=pof->m_bManufacturerId) ||
                  (baNormalModeFirstTwoBytes[1]!=pof->m_pbMemoryMappedStartAddress[1])
            ) nTries=2;  // don't try any more if we got some result the first time

      } // while


            // interpret device ID info

      {
            bool fMore=true;
            while(fMore) {
                  if(!pkft->m_bManufacturerId) {
                        fMore=false; continue;
                  }
                  if((pkft->m_bManufacturerId == pof->m_bManufacturerId) &&
                        (pkft->m_bDeviceId == pof->m_bDeviceId)
                  ) {
                        fSeen=true;
                        fMore=false;
                        nPos+=sprintf(&pof->m_szFlashDescription[nPos], "%s (%ldK)", pkft->m_szFlashDescription, pkft->m_dwLengthInBytes/1024);
                        pof->m_dwLengthInBytes = pkft->m_dwLengthInBytes;

                        if(pof->m_fDetectedUsing28xxxConventions) {
                              int n=0;
                                    // detect master lock situation

                              pof->m_pbMemoryMappedStartAddress[0x5555]=0x90;
                              if(pof->m_pbMemoryMappedStartAddress[3]!=0) { // master lock bit is set, no erases or writes are going to happen
                                    pof->m_fIsBelievedCapableOfWriteAndErase=false;
                                    nPos+=sprintf(&pof->m_szFlashDescription[nPos], "Master Lock SET  ");
                              }

                                    // detect block lock situation

                              nPos+=sprintf(&pof->m_szFlashDescription[nPos], "Block Locks: ");
                              while(n<pof->m_dwLengthInBytes) {
                                    pof->m_pbMemoryMappedStartAddress[0x5555]=0x90;
                                    nPos+=sprintf(&pof->m_szFlashDescription[nPos], "%u", pof->m_pbMemoryMappedStartAddress[n|0x0002]&1);
                                    n+=0x10000;
                              }
                              nPos+=sprintf(&pof->m_szFlashDescription[nPos], "  ");
                              pof->m_pbMemoryMappedStartAddress[0x5555]=0x50;
                              pof->m_pbMemoryMappedStartAddress[0x5555]=0xff;

                        }
                  }
                  pkft++;
            }
      }


      if(!fSeen) {
            if(
                  (baNormalModeFirstTwoBytes[0]==pof->m_bManufacturerId) &&
                  (baNormalModeFirstTwoBytes[1]==pof->m_pbMemoryMappedStartAddress[1])
            ) { // we didn't get anything worth reporting
                  sprintf(pof->m_szFlashDescription, "Read Only??? manf=0x%02X, dev=0x%02X", pof->m_bManufacturerId, pof->m_bDeviceId);
            } else { // we got what is probably an unknown flash type
                  sprintf(pof->m_szFlashDescription, "manf=0x%02X, dev=0x%02X", pof->m_bManufacturerId, pof->m_bDeviceId);
            }
      }

      return fSeen;
}

 // uses the block erase function on the flash to erase the minimal footprint
 // needed to cover pof->m_dwStartOffset .. (pof->m_dwStartOffset+pof->m_dwLengthUsedArea)

 #define MAX_ERASE_RETRIES_IN_4KBLOCK_BEFORE_FAILING 4
 
bool BootFlashEraseMinimalRegion( OBJECT_FLASH *pof )
{
      DWORD dw=pof->m_dwStartOffset;
      DWORD dwLen=pof->m_dwLengthUsedArea;
      DWORD dwLastEraseAddress=0xffffffff;
      int nCountEraseRetryIn4KBlock=MAX_ERASE_RETRIES_IN_4KBLOCK_BEFORE_FAILING;

      pof->m_szAdditionalErrorInfo[0]='\0';

      if(pof->m_pcallbackFlash!=NULL)
            if(!(pof->m_pcallbackFlash)(pof, EE_ERASE_START, 0, 0)) {
                  strcpy(pof->m_szAdditionalErrorInfo, "Erase Aborted");
                  return false;
            }

      while(dwLen) {

            if(pof->m_pbMemoryMappedStartAddress[dw]!=0xff) { // something needs erasing

                  BYTE b;

                  if((dwLastEraseAddress & 0xfffff000)==(dw & 0xfffff000)) { // same 4K block?
                        nCountEraseRetryIn4KBlock--;
                        if(nCountEraseRetryIn4KBlock==0) { // run out of tries in this 4K block
                              if(pof->m_pcallbackFlash!=NULL) {
                                    (pof->m_pcallbackFlash)(pof, EE_ERASE_ERROR, dw-pof->m_dwStartOffset, pof->m_pbMemoryMappedStartAddress[dw]);
                                    (pof->m_pcallbackFlash)(pof, EE_ERASE_END, 0, 0);
                              }
                              sprintf(pof->m_szAdditionalErrorInfo, "Erase failed for block at +0x%lx, reads as 0x%02X", dw, pof->m_pbMemoryMappedStartAddress[dw]);
                              return false; // failure
                        }
                  } else {
                        nCountEraseRetryIn4KBlock=MAX_ERASE_RETRIES_IN_4KBLOCK_BEFORE_FAILING;  // different block, reset retry counter
                        dwLastEraseAddress=dw;
                  }


                        // no ISRs should touch flash while we do the stuff

                  __asm__ __volatile__ ( "pushf ; cli ");


                  if(pof->m_fDetectedUsing28xxxConventions) {
                        int nCountMinSpin=0x100;
                        b=0x00;
                        pof->m_pbMemoryMappedStartAddress[0x5555]=0x50; // clear status register
                              // erase the block containing the non 0xff guy
                        pof->m_pbMemoryMappedStartAddress[dw]=0x20;
                        pof->m_pbMemoryMappedStartAddress[dw]=0xd0;

                        while((!(b&0x80)) || (nCountMinSpin)) { // busy - Sharp has a problem, does not go busy for ~500nS
                              b=pof->m_pbMemoryMappedStartAddress[dw];
                              if(nCountMinSpin) nCountMinSpin--;
                        }
                        pof->m_pbMemoryMappedStartAddress[0x5555]=0x50;
                        pof->m_pbMemoryMappedStartAddress[0x5555]=0xff;
                        if(b&0x7e) { // uh-oh something wrong
                              if(pof->m_pcallbackFlash!=NULL) {
                                    (pof->m_pcallbackFlash)(pof, EE_ERASE_ERROR, dw-pof->m_dwStartOffset, pof->m_pbMemoryMappedStartAddress[dw]);
                                    (pof->m_pcallbackFlash)(pof, EE_ERASE_END, 0, 0);
                              }
                              if(b&8) {
                                    sprintf(pof->m_szAdditionalErrorInfo, "This chip requires +5V on pin 11 (Vpp).  See the README.");
                              } else {
                                    sprintf(pof->m_szAdditionalErrorInfo, "Chip Status after Erase: 0x%02X", b);
                              }
                              return false;
                        }
                  } else { // more common 29xxx style
                        DWORD dwCountTries=0;

                        pof->m_pbMemoryMappedStartAddress[0x5555]=0xaa;
                        pof->m_pbMemoryMappedStartAddress[0x2aaa]=0x55;
                        pof->m_pbMemoryMappedStartAddress[0x5555]=0x80;

                        pof->m_pbMemoryMappedStartAddress[0x5555]=0xaa;
                        pof->m_pbMemoryMappedStartAddress[0x2aaa]=0x55;
                        pof->m_pbMemoryMappedStartAddress[dw]=0x50; // erase the block containing the non 0xff guy

                        b=pof->m_pbMemoryMappedStartAddress[dw];  // waits until b6 is no longer toggling on each read
                        while((pof->m_pbMemoryMappedStartAddress[dw]&0x40)!=(b&0x40)) {
                              dwCountTries++; b^=0x40;
                        }

                        if(dwCountTries<3) { // <3 means never entered busy mode - block erase code 0x50 not supported, try alternate
                              pof->m_pbMemoryMappedStartAddress[0x5555]=0xaa;
                              pof->m_pbMemoryMappedStartAddress[0x2aaa]=0x55;
                              pof->m_pbMemoryMappedStartAddress[0x5555]=0xf0;

                              pof->m_pbMemoryMappedStartAddress[0x5555]=0xaa;
                              pof->m_pbMemoryMappedStartAddress[0x2aaa]=0x55;
                              pof->m_pbMemoryMappedStartAddress[0x5555]=0x80;

                              pof->m_pbMemoryMappedStartAddress[0x5555]=0xaa;
                              pof->m_pbMemoryMappedStartAddress[0x2aaa]=0x55;
                              pof->m_pbMemoryMappedStartAddress[dw]=0x30; // erase the block containing the non 0xff guy

                              b=pof->m_pbMemoryMappedStartAddress[dw];
                              dwCountTries=0;
                              while((pof->m_pbMemoryMappedStartAddress[dw]&0x40)!=(b&0x40)) {
                                    dwCountTries++; b^=0x40;
                              }
                        }

                              // if we had a couple of unsuccessful tries at block erase already, try chip erase                    
                              // safety features...
                        if(
                              (dwCountTries<3) &&  // other commands did not work at all
                              (nCountEraseRetryIn4KBlock<2) &&  // had multiple attempts at them already
                              (pof->m_dwStartOffset==0) && // reprogramming whole chip .. starting from start
                              (pof->m_dwLengthUsedArea == pof->m_dwLengthInBytes)  // and doing the whole length of the chip
                        ) { // <3 means never entered busy mode - block erase code 0x30 not supported
                              #if 1
                              printf("Trying to erase whole chip\n");
                              #endif
                              pof->m_pbMemoryMappedStartAddress[0x5555]=0xaa;
                              pof->m_pbMemoryMappedStartAddress[0x2aaa]=0x55;
                              pof->m_pbMemoryMappedStartAddress[0x5555]=0xf0;

                              pof->m_pbMemoryMappedStartAddress[0x5555]=0xaa;
                              pof->m_pbMemoryMappedStartAddress[0x2aaa]=0x55;
                              pof->m_pbMemoryMappedStartAddress[0x5555]=0x80;

                              pof->m_pbMemoryMappedStartAddress[0x5555]=0xaa;
                              pof->m_pbMemoryMappedStartAddress[0x2aaa]=0x55;
                              pof->m_pbMemoryMappedStartAddress[0x5555]=0x10; // chip erase ONLY available on W49F020

                              b=pof->m_pbMemoryMappedStartAddress[dw];
                              dwCountTries=0;
                              while((pof->m_pbMemoryMappedStartAddress[dw]&0x40)!=(b&0x40)) {
                                    dwCountTries++; b^=0x40;
                              }
                        }

                  }


                  __asm__ __volatile__ ( "popf ");

                  continue; // retry reading this address without moving on
            }

                  // update callback every 1K addresses
            if((dw&0x3ff)==0) {
                  if(pof->m_pcallbackFlash!=NULL) {
                        if(!(pof->m_pcallbackFlash)(pof, EE_ERASE_UPDATE, dw-pof->m_dwStartOffset, pof->m_dwLengthUsedArea)) {
                              strcpy(pof->m_szAdditionalErrorInfo, "Erase Aborted");
                              return false;
                        }
                  }
            }

            dwLen--; dw++;
      }

      if(pof->m_pcallbackFlash!=NULL) if(!(pof->m_pcallbackFlash)(pof, EE_ERASE_END, 0, 0)) return false;

      return true;
}

      // program the flash from the data in pba
      // length of valid data in pba held in pof->m_dwLengthUsedArea

bool BootFlashProgram( OBJECT_FLASH *pof, BYTE *pba )
{
      DWORD dw=pof->m_dwStartOffset;
      DWORD dwLen=pof->m_dwLengthUsedArea;
      DWORD dwSrc=0;
      DWORD dwLastProgramAddress=0xffffffff;
      int nCountProgramRetries=4;

      pof->m_szAdditionalErrorInfo[0]='\0';
      if(pof->m_pcallbackFlash!=NULL)
            if(!(pof->m_pcallbackFlash)(pof, EE_PROGRAM_START, 0, 0)) {
                  strcpy(pof->m_szAdditionalErrorInfo, "Program Aborted");
                  return false;
            }

            // program

      while(dwLen) {

            if(pof->m_pbMemoryMappedStartAddress[dw]!=pba[dwSrc]) { // needs programming

                  if(dwLastProgramAddress==dw) {
                        nCountProgramRetries--;
                        if(nCountProgramRetries==0) {
                              if(pof->m_pcallbackFlash!=NULL) {
                                    (pof->m_pcallbackFlash)(pof, EE_PROGRAM_ERROR, dw, (((DWORD)pba[dwSrc])<<8) |pof->m_pbMemoryMappedStartAddress[dw] );
                                    (pof->m_pcallbackFlash)(pof, EE_PROGRAM_END, 0, 0);
                              }
                              sprintf(pof->m_szAdditionalErrorInfo, "Program failed for byte at +0x%lx; wrote 0x%02X, read 0x%02X", dw, pba[dwSrc], pof->m_pbMemoryMappedStartAddress[dw]);
                              return false;
                        }
                  } else {
                        nCountProgramRetries=4;
                        dwLastProgramAddress=dw;
                  }

                        // no ISRs should touch flash while we do the stuff
                  __asm__ __volatile__ ( "pushf ; cli ");

                  if(pof->m_fDetectedUsing28xxxConventions) {
                        BYTE b=0x0;
                        DWORD dwTimeToLive=0xfffff;  // 1M times around, a few mS
                        int nCountMinSpin=2; // force wait for this long, suspect busy is not coming up immediately
                        pof->m_pbMemoryMappedStartAddress[dw]=0x40;
                        pof->m_pbMemoryMappedStartAddress[dw]=pba[dwSrc]; // perform programming action
                        while(((!(b&0x80)) && (--dwTimeToLive)) || (nCountMinSpin)) { // busy - Sharp has a problem, does not go busy for ~500nS
                              b=pof->m_pbMemoryMappedStartAddress[dw];
                              if(nCountMinSpin) nCountMinSpin--;
                        }
                        pof->m_pbMemoryMappedStartAddress[dw]=0x50;
                        pof->m_pbMemoryMappedStartAddress[dw]=0xff;
                        if((b&0x7e)||(!dwTimeToLive)) { // uh-oh something wrong
                              if(pof->m_pcallbackFlash!=NULL) {
                                    (pof->m_pcallbackFlash)(pof, EE_PROGRAM_ERROR, dw-pof->m_dwStartOffset, (((DWORD)pba[dwSrc])<<8) | pof->m_pbMemoryMappedStartAddress[dw]);
                                    (pof->m_pcallbackFlash)(pof, EE_PROGRAM_END, 0, 0);
                              }
                              if(dwTimeToLive) {
                                    sprintf(pof->m_szAdditionalErrorInfo, "Chip Status after Program: 0x%02X", b);
                              } else {
                                    sprintf(pof->m_szAdditionalErrorInfo, "Chip Status after TIMED-OUT Program: 0x%02X", b);
                              }
                              if(b&8) {
                                    sprintf(pof->m_szAdditionalErrorInfo, "This chip requires +5V on pin 11 (Vpp).  See the README.");
                              }
                              return false;
                        }
                  } else {
                        BYTE b;
                        pof->m_pbMemoryMappedStartAddress[0x5555]=0xaa;
                        pof->m_pbMemoryMappedStartAddress[0x2aaa]=0x55;
                        pof->m_pbMemoryMappedStartAddress[0x5555]=0xa0;
                        pof->m_pbMemoryMappedStartAddress[dw]=pba[dwSrc]; // perform programming action
                        b=pof->m_pbMemoryMappedStartAddress[dw];  // waits until b6 is no longer toggling on each read
                        while((pof->m_pbMemoryMappedStartAddress[dw]&0x40)!=(b&0x40)) b^=0x40;
                  }

                  __asm__ __volatile__ ( "popf ");

                  continue;  // does NOT advance yet
            }

            if((dw&0x3ff)==0)
                  if(pof->m_pcallbackFlash!=NULL)
                        if(!(pof->m_pcallbackFlash)(pof, EE_PROGRAM_UPDATE, dwSrc, pof->m_dwLengthUsedArea)) {
                              strcpy(pof->m_szAdditionalErrorInfo, "Program Aborted");
                              return false;
                        }

            dwLen--; dw++; dwSrc++;
      }

      if(pof->m_pcallbackFlash!=NULL) if(!(pof->m_pcallbackFlash)(pof, EE_PROGRAM_END, 0, 0)) return false;

            // verify

      if(pof->m_pcallbackFlash!=NULL) if(!(pof->m_pcallbackFlash)(pof, EE_VERIFY_START, 0, 0)) return false;

      dw=pof->m_dwStartOffset;
      dwLen=pof->m_dwLengthUsedArea;
      dwSrc=0;

      while(dwLen) {

            if(pof->m_pbMemoryMappedStartAddress[dw]!=pba[dwSrc]) { // verify error
                  if(pof->m_pcallbackFlash!=NULL) if(!(pof->m_pcallbackFlash)(pof, EE_VERIFY_ERROR, dw, (((DWORD)pba[dwSrc])<<8) |pof->m_pbMemoryMappedStartAddress[dw])) return false;
                  if(pof->m_pcallbackFlash!=NULL) if(!(pof->m_pcallbackFlash)(pof, EE_VERIFY_END, 0, 0)) return false;
                  return false;
            }

            dwLen--; dw++; dwSrc++;
      }

      if(pof->m_pcallbackFlash!=NULL) if(!(pof->m_pcallbackFlash)(pof, EE_VERIFY_END, 0, 0)) return false;
      return true;
}

Generated by  Doxygen 1.6.0   Back to index