AMI EFI Flash emodule
我可爱的多多还没满三个月时,公司就把我招回来干活了。为了能准时下班陪多多,我在上班的前两天拼命的debug呀,终于把M2MTC那个串口的问题解决了。接下来就很闲,闲的发慌的时候就胡思乱想,有一分钟想到了以前phoenix EFI下读写SPI flash的问题,于是决定也来研究一下AMI的flash模块。 ? u? 第一只程序—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芯片了。 ? u? 第二只程序—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, ? // 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等信息, ? ? u? 第三个重点—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。 ??????????????下一次命令写一点,写完为止。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |