📄 pflash.c
字号:
/***************************************** Copyright (c) 2003-2004 Sigma Designs, Inc. All Rights Reserved Proprietary and Confidential *****************************************//* * pflash.c */#include <string.h>#ifdef YAMON#include <stdarg.h>#include <util.h>#else#define ALLOW_OS_CODE 1#include "../llad/include/gbus.h"#include "../emhwlib_hal/include/emhwlib_registers.h"#endif#include <pflash.h>/************************************************************************ * Definitions ************************************************************************///for dqx_wait#define FLASH_WAIT_DIV 2 /* 1 for the board without IORDY lifted, it'll try the full cycle; or more than 1 for others*/// to enable or disable the debug messages of this source file, put 1 or 0 below#if 1#define LOCALDBG ENABLE#else#define LOCALDBG DISABLE#endif/* * based on CFI (Common Flash Memory Interface) Specification 2.0 * supports multiple flashes, supports command set 2 (AMD standard) * * Parallel flash memory base should be remapped address base, * no cpu remap register be used inside this program. */#define CFIDEV_INTERLEAVE 1 // paired device. unused (no pair)#define CFIDEV_DEVTYPE 2 // type : x8 = 1, x16 = 2, x32 = 4 //==2 (16 bits capable device)#define CFIDEV_UNLOCK_BYPASS // Using unlock bypass #define PB_cs_config_CS2_8bit 4//PB_cs_config CS2 8/16bit/************************************************************************ * Macro Definitions*************************************************************************/// for matching endian between CPU and CFI interface// CFI and HOST use same endian#define cpu_to_cfi8(x) (x)#define cfi8_to_cpu(x) (x)#define cpu_to_cfi16(x) (x)#define cfi16_to_cpu(x) (x)#define cpu_to_cfi32(x) (x)#define cfi32_to_cpu(x) (x)/************************************************************************ * Public variables ************************************************************************/#define MAXREGIONSIZE 0x20000 //AMD:0x10000, STRARA:0x20000/************************************************************************ * Static variables ************************************************************************//* Use DQx toggling bit to detect programming status *//* flash_use_DQX defined when R12 is not on the board, so IORDY disconnected*/static RMuint8 flash_use_DQX; static RMuint32 flash_wait_div = FLASH_WAIT_DIV;/************************************************************************ * Static function prototypes ************************************************************************/#ifdef YAMON#define gbus_read_remapped_uint8(h,x) gbus_read_uint8(h,sigmaremap(x))#define gbus_read_remapped_uint16(h,x) gbus_read_uint16(h,sigmaremap(x))#define gbus_read_remapped_uint32(h,x) gbus_read_uint32(h,sigmaremap(x))#define gbus_write_remapped_uint8(h,x,y) gbus_write_uint8(h,sigmaremap(x),y)#define gbus_write_remapped_uint16(h,x,y) gbus_write_uint16(h,sigmaremap(x),y)#define gbus_write_remapped_uint32(h,x,y) gbus_write_uint32(h,sigmaremap(x),y)#else#define gbus_read_remapped_uint8(h,x) gbus_read_uint8(h,x)#define gbus_read_remapped_uint16(h,x) gbus_read_uint16(h,x)#define gbus_read_remapped_uint32(h,x) gbus_read_uint32(h,x)#define gbus_write_remapped_uint8(h,x,y) gbus_write_uint8(h,x,y)#define gbus_write_remapped_uint16(h,x,y) gbus_write_uint16(h,x,y)#define gbus_write_remapped_uint32(h,x,y) gbus_write_uint32(h,x,y)#endifstatic void dqx_wait(struct gbus *h, RMuint32 addr, RMuint32 buswidth, RMuint32 datum, RMuint32 wait, void(*cb_usleep)(struct gbus *,RMuint32));// CFI basic I/O -- base on CFIDEV_BUSWIDTH, read/write datastatic RMuint32 cfi_read(struct gbus *h, RMuint32 addr, RMuint32 bwidth);static void cfi_write(struct gbus *h, RMuint32 bwidth, RMuint32 val, RMuint32 addr);// CFI advanced I/O//base on CFIDEV_DEVTYPE,CFIDEV_INTERLEAVEstatic RMuint32 cfi_build_cmd_addr(RMuint32 addr);//base on CFIDEV_BUSWIDTH,CFIDEV_INTERLEAVEstatic RMuint32 cfi_build_cmd(RMuint32 cmd, RMuint32 bwidth);static void cfi_send_cmd(struct gbus *h, RMuint32 bwidth, RMuint32 cmd, RMuint32 cmd_addr, RMuint32 base);// probing & setupstatic RMstatus cfi_probe_chip(struct gbus *h, cfi_info *pcfi);static RMstatus cfi_query_present(struct gbus *h, RMuint32 base, RMuint32 bwidth);static RMstatus cfi_chip_setup(struct gbus *h, cfi_info *pcfi);static void cfi_cmdset_0002(cfi_info *pcfi);// others#if (defined _DEBUG) || (defined YAMON)static char *cfi_get_idname(RMuint32 vendor);#endifstatic RMint32 flash_erase_oneblock(struct gbus *h, cfi_info *pcfi, RMuint32 addr,void(*cb_usleep)(struct gbus *,RMuint32));static RMstatus flash_writable(struct gbus *h, RMuint32 addr, RMint32 len);static RMstatus flash_write_onebyte(struct gbus *h, cfi_info *pcfi, RMuint32 addr, RMuint32 data, void(*cb_usleep)(struct gbus *,RMuint32));static RMstatus flash_write_data_internal(struct gbus *h, RMuint32 addr, RMuint16 *data, RMint32 nwords, cfi_info *pcfi, void(*cb_usleep)(struct gbus*,RMuint32));static void flash_list(cfi_info *pcfi);/************************************************************************ * Implementation : Public functions ************************************************************************//******************************************* RMstatus flash_init(struct gbus *h, cfi_info *pcfi, RMuint32 gbus_addr, RMuint32 buswidth, RMuint8 dq56mark, RMbool disp)** Description :* Initialization parallel flash * This function will modify CPU_remap4 register.* Only one parallel flash can be use at same time.** Input parameters:* pcfi: Pointer to parallel flash structure;* gbus_addr: Parallel flash address;* buswidth: Parallel flash bus width, 8 or 16;** Return values:* RMstatus ******************************************/RMstatus flash_init(struct gbus *h, cfi_info *pcfi, RMuint32 gbus_addr, RMuint32 buswidth, RMuint8 dq56mark, RMbool disp){ RMint32 ret; RMint32 data; if ( (buswidth == CFIDEV_BUSWIDTH_8) || (buswidth == CFIDEV_BUSWIDTH_16) ) { pcfi->buswidth = buswidth; data = gbus_read_uint32(h,REG_BASE_host_interface + PB_CS_config); if( (buswidth == CFIDEV_BUSWIDTH_8) && ((data & PB_cs_config_CS2_8bit)==0) ) { data |= PB_cs_config_CS2_8bit; gbus_write_uint32(h,REG_BASE_host_interface + PB_CS_config, data); } else if( (buswidth == CFIDEV_BUSWIDTH_16) && ((data & PB_cs_config_CS2_8bit)!=0) ){ data &= (~PB_cs_config_CS2_8bit); gbus_write_uint32(h,REG_BASE_host_interface + PB_CS_config, data); } } else return RM_ERROR; flash_use_DQX = dq56mark;#if (RMARCHID==RMARCHID_MIPS) if(disp) RMDBGLOG((ENABLE,"CPU_remap4 map to 0x%08lx\n",gbus_addr)); gbus_write_uint32(h, REG_BASE_cpu_block + CPU_remap4, gbus_addr);#endif pcfi->gbus_address = gbus_addr; if ((ret = cfi_probe_chip(h, pcfi)) != RM_OK) { RMDBGLOG((LOCALDBG,"flash does not exist at address 0x%08x, bus width 0x%x\n", pcfi->gbus_address, pcfi->buswidth)); return RM_ERROR; } if(disp) flash_list(pcfi); pcfi->exist = 1; return RM_OK;}/******************************************* RMstatus flash_erase_chip(struct gbus *h, cfi_info *pcfi, void(*cb_usleep)(struct gbus*, RMuint32))** Description :* Erase specified parallel flash chip** Input parameters:* pcfi: Pointer to parallel flash structure** Return values:* OK: operation successful; * fail: error message******************************************/RMstatus flash_erase_chip(struct gbus *h, cfi_info *pcfi, void(*cb_usleep)(struct gbus*, RMuint32)){ if (!pcfi->exist) return RM_NOT_FOUND; cfi_send_cmd(h, pcfi->buswidth, 0xaa, pcfi->addr_unlock1, pcfi->gbus_address); cfi_send_cmd(h, pcfi->buswidth, 0x55, pcfi->addr_unlock2, pcfi->gbus_address); cfi_send_cmd(h, pcfi->buswidth, 0x80, pcfi->addr_unlock1, pcfi->gbus_address); cfi_send_cmd(h, pcfi->buswidth, 0xaa, pcfi->addr_unlock1, pcfi->gbus_address); cfi_send_cmd(h, pcfi->buswidth, 0x55, pcfi->addr_unlock2, pcfi->gbus_address); cfi_send_cmd(h, pcfi->buswidth, 0x10, pcfi->addr_unlock1, pcfi->gbus_address); if ( flash_use_DQX ) { if (pcfi->ident.timeout_chip_erase != 0) dqx_wait(h, pcfi->gbus_address, pcfi->buswidth, 0xff, 1000*(1<<pcfi->ident.timeout_chip_erase), cb_usleep); else dqx_wait(h, pcfi->gbus_address, pcfi->buswidth, 0xff, 1000*40, cb_usleep); //40ms } else { if (pcfi->ident.timeout_chip_erase != 0) (*cb_usleep)(h, 1000*(1<<pcfi->ident.max_timeout_chip_erase)*(1<<pcfi->ident.timeout_chip_erase)); else { RMint32 j, delay = 0; for (j = 0; j < pcfi->ident.num_erase_regions; ++j) delay += pcfi->erase_regions[j].blocks; RMDBGPRINT((LOCALDBG,"Please wait %d ms...\n",delay*(1<<pcfi->ident.timeout_block_erase))); (*cb_usleep)(h, 1000*delay*(1<<pcfi->ident.timeout_block_erase)); } } if ((cfi_read(h, pcfi->gbus_address, pcfi->buswidth) & 0xff) != 0xff) { RMDBGPRINT((LOCALDBG," erase chip fail.\n")); return RM_ERROR; } return RM_OK;}/******************************************* RMstatus flash_erase_region(struct gbus *h, cfi_info *pcfi, RMuint32 addroffs, RMuint32 length, void(*cb_usleep)(struct gbus*, RMuint32))** Description :* Erase a region of specified parallel flash chip ** Input parameters:* pcfi: Pointer to parallel flash structure* addroffs: start offset address of parallel flash erase region (0 - pflash size)* length: erase length** Return values:* OK: operation successful; * fail: error message******************************************/RMstatus flash_erase_region(struct gbus *h, cfi_info *pcfi, RMuint32 addroffs, RMuint32 length, void(*cb_usleep)(struct gbus*, RMuint32)){ RMuint32 start, blocksize; if (length == 0) return RM_OK; if (!pcfi->exist) return RM_NOT_FOUND; if (flash_calcblock(h, pcfi, addroffs, &start, &blocksize) < 0) return RM_NOT_FOUND; do { //RMDBGLOG((LOCALDBG,"erasing offset 0x%08lx (%dbytes)\n",start,blocksize)); flash_erase_oneblock(h, pcfi, start + pcfi->gbus_address, cb_usleep); start += blocksize; if (flash_calcblock(h, pcfi, start, &start, &blocksize) < 0) break; } while (start < addroffs + length); return RM_OK;}static RMuint8 savebuf[MAXREGIONSIZE];RMstatus flash_save_erase_region(struct gbus *h,cfi_info *pcfi,RMuint32 addroffs, RMuint32 length,void(*cb_usleep)(struct gbus*,RMuint32)){ RMuint32 start, blocksize; RMuint32 wraddr,wrlen; if (length == 0) return RM_OK; if (!pcfi->exist) return RM_NOT_FOUND; if (flash_calcblock(h, pcfi, addroffs, &start, &blocksize) < 0) return RM_NOT_FOUND; do { wraddr = addroffs - start; wrlen = (length <= blocksize - wraddr ? length : blocksize - wraddr ); if(addroffs > start || length < blocksize) { //read & save first if (blocksize > MAXREGIONSIZE) { RMDBGPRINT((LOCALDBG,"Please increase save buffer size!!\n")); return !RM_OK; } flash_read_data(h, pcfi, start, savebuf, blocksize); memset( &savebuf[wraddr], 0xff, wrlen); if( flash_erase_oneblock(h, pcfi, start + pcfi->gbus_address, cb_usleep) != RM_OK) return RM_ERROR; if( flash_write_data(h, pcfi, start, savebuf, blocksize, cb_usleep) != RM_OK) return RM_ERROR; } else { //just erase if( flash_erase_oneblock(h, pcfi, start + pcfi->gbus_address, cb_usleep) != RM_OK) return RM_ERROR; } start += blocksize; if (flash_calcblock(h, pcfi, start, &start, &blocksize) < 0) break; addroffs += wrlen; length -= wrlen; } while (start < addroffs + length); return RM_OK;}// read / writing (suppose 16 bits writing)/******************************************* RMint32 flash_read_data(struct gbus *h, cfi_info *pcfi, RMuint32 addroffs, void *data, RMuint32 length)** Description :* Read a region of specified parallel flash chip ** Input parameters:* pcfi: Pointer to parallel flash structure* addroffs: start offset address of parallel flash read region (0 - pflash size)* *data: destination address of read data* length: read length** Return values:* OK: operation successful; * fail: error message******************************************/RMstatus flash_read_data(struct gbus *h, cfi_info *pcfi, RMuint32 addroffs, void *data, RMuint32 length){ RMuint32 ii; if (!pcfi->exist) return RM_NOT_FOUND; if( (addroffs & 0x3) != ((RMuint32)data & 0x3) ) { for (ii = 0; ii < length; ii++) { *(RMuint8 *)(data + ii) = gbus_read_remapped_uint8(h, pcfi->gbus_address + addroffs + ii ); } } else { while (addroffs & 0x3) { *(RMuint8 *)(data++) = gbus_read_remapped_uint8(h, pcfi->gbus_address + addroffs); addroffs++; length--;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -