AMI EFI Flash emodule

我可爱的多多还没满三个月时,公司就把我招回来干活了。为了能准时下班陪多多,我在上班的前两天拼命的debug呀,终于把M2MTC那个串口的问题解决了。接下来就很闲,闲的发慌的时候就胡思乱想,有一分钟想到了以前phoenix EFI下读写SPI flash的问题,于是决定也来研究一下AMI的flash模块。

 

第一只程序—FlashInit

BOOLEAN found = FALSE;

   for(i=0; !found && FlashList[i]; i++)

    {

       found=FlashList[i](pBlockAddress, &FlashAPI);

}

FlashList的定义为:IDENTIFY*FlashList[] = {FLASH_LIST NULL};

FlashList是一个指针数组,它在flash.mak里有定义/D\"FLASH_LIST=$(FlashList)\"\,这个数组的每一个指针都指向一个函数。由于不同厂家的flash part都可能有不同的opcode,所以每一家的flash part都有一个identify函数,在我们这个案子里,一共支持了4种flash part,我们可以在build生成的token.mak里找到FlashList的实际值。

FlashList = IdentifySst_25VF,\

                  IdentifyStm_25PExx,\

                  IdentifyAtmel_26DF,\

                  IdentifySst_25LF,

所以FlashList[0]= IdentifySst_25VF

       FlashList[1]= IdentifyStm_25Pexx

       FlashList[2]= IdentifyAtmel_26DF

       FlashList[3]= IdentifySst_25LF

       FlashList[4]=NULL

如果FlashList[0]返回值为true,就表明flash part型号已经找到,否则继续调用FlashList[1],依此类推,直到FlashList[i]全部执行完都没有找到flash part,就可以向全世界公告本机台不支持你这颗flash芯片了。

 

第二只程序—CommonSpiReadId

其实所有的Identify函数都差不多,只是opcode不同而已,这里我们以IdentifySst_25VF为例来研究。这只程序调用到的第一个函数为

CommonSpiReadId( &Sst_25VF, &MfgDevId );

注意Sst_25VF的定义为:

// Flash Part Data Structures

FLASH_INFOSst_25VF =

{  // Write Byte

  {SPI_SST25LF_COMMAND_WRITE,    SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS},

  // Read Data

  {SPI_SST25LF_COMMAND_READ,     SPI_OPCODE_TYPE_READ_WITH_ADDRESS},

  // Erase 4k Sector

  {SPI_SST25LF_COMMAND_ERASE,    SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS},

  // Read Device Status Reg

  {SPI_SST25LF_COMMAND_READ_STATUS,SPI_OPCODE_TYPE_READ_NO_ADDRESS},

  // Read device ID

  {SPI_SST25VF_COMMAND_READ_ID,  SPI_OPCODE_TYPE_READ_WITH_ADDRESS},

  // Write Status Register

  {SPI_SST25LF_COMMAND_WRITE_S,   SPI_OPCODE_TYPE_WRITE_NO_ADDRESS},

  // Write Status Enable

  {SPI_SST25LF_COMMAND_WRITE_S_EN, SPI_OPCODE_TYPE_READ_NO_ADDRESS},

  // Write Enable

{SPI_SST25LF_COMMAND_WRITE_ENABLE,SPI_OPCODE_TYPE_WRITE_NO_ADDRESS},

  1,                                  // Page Size

  SECTOR_SIZE_4KB

};

CommonSpiReadId这只程序所做的事情如下:

(1)      InitializeSpiEnvironment(FlashInfo);  

               //FlashInfo就是Sst_25VF, SPI BAR=RCBA+0x3020

              把Sst_25VF里相应的值填到SPI BAR 那边的opcode menu和opcode type里去。

              注意:write status enable和write enable这两个opcode是填到opcode prefix那边,和其他的read,read ID等命令区别开,以防止flash芯片被恶意擦写。

(2)      SPI Address填0,然后往SPIcontrol寄存器下命令,opcode index要按照(1)里面SPI_SST25VF_COMMAND_READ_ID所在位置来设置。

(3)      ID读回来后,根据ID就能判断flash芯片的容量了。使用一个结构体mExFlashPart来记录下容量,ID,还有opcode等信息,

 

 

第三个重点—FLASH_PART FlashAPI

(1)第一只程序FlashInit跑完后,会返回一个类型为FLASH_PART的FlashAPI。

typedef struct _FLASH_PART {

   FLASH_READ_COMMAND             FlashReadCommand;

   FLASH_ERASE_COMMAND            FlashEraseCommand;

   FLASH_PROGRAM_COMMAND          FlashProgramCommand;

   FLASH_IS_ERASE_COMPLETED       FlashIsEraseCompleted;

   FLASH_IS_PROGRAM_COMPLETED     FlashIsProgramCompleted;

   FLASH_BLOCK_WRITE_ENABLE       FlashBlockWriteEnable;

   FLASH_BLOCK_WRITE_DISABLE      FlashBlockWriteDisable;

   FLASH_DEVICE_WRITE_ENABLE      FlashDeviceWriteEnable;

   FLASH_DEVICE_WRITE_DISABLE      FlashDeviceWriteDisable;

   FLASH_VIRTUAL_FIXUP            FlashVirtualFixup;

   UINT32                         FlashProgramSize;

   UINT32                         FlashSectorSize;

   UINT8                          *FlashPartNumber;   

} FLASH_PART;

 

(2)上面那个FlashAPI是啥时候被初始化的呢,原来第二只程序IdentifySst_25VF读完ID后,会给FlashAPI赋值,

*FlashStruct = &mCommonSpiFlash;

FLASH_PART mCommonSpiFlash ={

   CommonSpiReadCommand,

   CommonSpiEraseCommand,

   CommonSpiProgramCommand,

   CommonSpiIsEraseCompleted,

    CommonSpiIsProgramCompleted,

   CommonSpiBlockWriteEnable,

   CommonSpiBlockWriteDisable,

   CommonSpiDeviceWriteEnable,

   CommonSpiDeviceWriteDisable,

   CommonSpiDeviceVirtualFixup,

   1,                      // defaultvalue, should be changed in Init function

   SECTOR_SIZE_4KB

};

所以实际上FlashAPI -> FlashReadCommand = CommonSpiReadCommand; 等等。。

各位,请注意这里的Common,所谓Common就是通用了,我之所以能通用,是因为CommonSpiReadId里的InitializeSpiEnvironment已经把opcode填好了。不同的flash芯片最大的差异就在于opcode的不同,真希望有一天,这个世界可以和谐到所有的opcode都统一。

 

所以以后的读写擦除程序,你想单干的都必须先做FlashInit。

(1)      CommonSpiReadCommand

              很简单,使用SPI_SST25LF_COMMAND_READ命令,一次读一个byte回来,想要多长的数据就读多少次了。

(2)      CommonSpiEraseCommand

              FlashPart擦除是以一个sector为单位的,大多数sector都是4KB的,也有些是8KB或者64KB。

             说到sector,我一直在想,它和block到底谁是老大,他们的实际关系如下:

                           1 Flash = n x FV (Flash Volume)

                           1 FV = n x Block

                           1 Block = n x Sector

                           1 page = n x Sector

                擦之前先读一下,如果值已经是全FF,就不必再擦了。

(3)      CommonSpiProgramCommand

               有些flash芯片只支持一次写一个byte,有些可以一次写256个byte。

              下一次命令写一点,写完为止。

你可能感兴趣的:(list,struct,command,Flash,null,byte)