📄 tcl_gdi_flash_cfi.c
字号:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "stddefs.h"
#include "testtool.h"
#include "sttbx.h"
#include "TCL_Common.h"
#include "TCL_Osp.h"
#include "TCL_Error.h"
#include "TCL_GDI_Flash_CFI.h"
#include "TCL_GDI_Flash.h"
#define CBUS_FLASH_WE 0x8ac
/*Support both CFI and SST 16bit flash*/
TCL_INT32 CMD_UNLOCK1_ADDR[2]={0xAAA,0xAAAA};
TCL_INT32 CMD_UNLOCK1_DATA[2]={0xAA,0xAA};
TCL_INT32 CMD_UNLOCK2_ADDR[2]={0x555,0x5555};
TCL_INT32 CMD_UNLOCK2_DATA[2]={0x55,0x55};
TCL_INT32 CMD_SETUP_ADDR[2]={0xAAA,0xAAAA};
TCL_INT32 CMD_SETUP_DATA[2]={0x80,0x80};
#define CMD_SECTOR_ERASE 0x30
#define CMD_BLOCK_ERASE 0x50
TCL_INT32 CMD_PROGRAM_ADDR[2]={0xAAA,0xAAAA};
TCL_INT32 CMD_PROGRAM_DATA[2]={0xA0,0xA0};
TCL_INT32 CMD_BYPASS_ADDR[2]={0xAAA,0xAAAA};
TCL_INT32 CMD_BYPASS_DATA[2]={0x20,0x20};
TCL_INT32 CMD_RESET_ADDR[2] ={0xAAA,0xAAAA};
TCL_INT32 CMD_RESET_DATA[2]={0xF0,0xF0};
TCL_INT32 CMD_AUTOSELECT_ADDR[2]={0xAAA,0xAAAA};
TCL_INT32 CMD_AUTOSELECT_DATA[2]={0x90,0x90};
TCL_INT32 CMD_CFI_QUERY_ADDR[2]={0xAA,0xAAAA};
#define CMD_CFI_PROTECH_ADDR 0x8A
#define CMD_CFI_QUERY_DATA 0x98
#define MANUFACTURER_ID_ADDR 0x00
#define DEVICE_ID_ADDR 0x02
#define CFI_DEV_QRY_ADDR 0x20
#define CFI_DEV_SIZE_ADDR 0x4E
#define CFI_NUM_ERASE_REGIONS_ADDR 0x58
#define CFI_ERASE_REGION_START_ADDR 0x5A
#define CFI_PRIMARY_ADDR1 0x2A
#define CFI_PRIMARY_ADDR2 0x2C
#define FLASH_DQ7 0x0080
#define FLASH_DQ5 0x0020
#define WORK_MODE_8BIT 1
#define WORK_MODE_16BIT 2
static unsigned char mEraseCmd=CMD_SECTOR_ERASE;
static TCL_BOOL gUseDQ5ForTimeout = TCL_TRUE;
static TCL_BOOL gIsSst16Bit = TCL_TRUE;
/* 1: 8 bits. */
/* 2: 16 bits. */
static TCL_UINT8 WorkMode;
/*----------------------------------------------------
The flash base address when using flash instead of eeprom
will be used through the guest bus
----------------------------------------------------*/
#define FLASH_BASE_ADDR 0x40000000
#define FLASH_ADDRESS(offset) (FLASH_BASE_ADDR | (offset<<1))
/* #define READ_FLASH(offset) (*((TCL_UINT16*)FLASH_BASE_ADDR+offset)) */
typedef struct mtd_erase_region_info
{
TCL_UINT32 offset;
TCL_UINT32 sectorSize;
TCL_UINT32 numSectors;
} FL_ERASE_REGION_INFO;
static TCL_VOID EnableFlash(TCL_VOID);
static TCL_VOID DisableFlash(TCL_VOID);
static TCL_UINT16 READ_FLASH(TCL_UINT32 offset);
static void WRITE_FLASH(TCL_UINT32 offset, TCL_UINT16 word);
static void FLASH_UnlockCmd(TCL_VOID);
static TCL_BOOL FLASH_CompletionPolling( TCL_UINT32 uOffset, TCL_UINT16 usDataWord );
static TCL_BOOL FL_WriteFlashWord(TCL_UINT32 iOffset,TCL_UINT16 usDataWord);
static TCL_BOOL FlashProbeCFI(TCL_GDI_FLASH_INFO *pFlashInfo);
static TCL_BOOL DTV_BoardIs8BitsFlash(TCL_VOID);
static TCL_BOOL FlashAutoSelect(TCL_GDI_FLASH_INFO *pFlashInfo);
static TCL_UINT32 CFI_FlashSecNum(TCL_UINT32 uAddr);
static TCL_UINT32 CFI_FlashSecStartAddr(TCL_UINT32 uSector);
/******************************************************************************
* Function: EnableFlash
* Description: enable flash
* Calls: omit
* Called By: omit
* Table Accessed: none
* Table Updated: none
* Input: none
* Output: none
* Return: TCL_VOID
* Others:
* Note:
* Author Date Purpose
*----------------------------------------------------------------------------
* JokQu 20080229 create
******************************************************************************/
static TCL_VOID EnableFlash(TCL_VOID)
{
/* Enable writes to the flash */
}
/******************************************************************************
* Function: EnableFlash
* Description: disable flash
* Calls: omit
* Called By: omit
* Table Accessed: none
* Table Updated: none
* Input: none
* Output: none
* Return: TCL_VOID
* Others:
* Note:
* Author Date Purpose
*----------------------------------------------------------------------------
* JokQu 20080229 create
******************************************************************************/
static TCL_VOID DisableFlash(TCL_VOID)
{
/* disable writes to the flash */
}
/******************************************************************************
* Function: WRITE_FLASH
* Description: 读flash
* Calls: omit
* Called By: omit
* Table Accessed: none
* Table Updated: none
* Input: none
* Output: none
* Return: void
*Arithmetic
* Others:
* Note:
* Author Date Purpose
*----------------------------------------------------------------------------
* JokQu 20080229 create
******************************************************************************/
static TCL_UINT16 READ_FLASH(TCL_UINT32 offset)
{
volatile TCL_UINT16 *Address;
volatile TCL_UINT8 *AddressB;
TCL_UINT8 val;
if (WorkMode == WORK_MODE_16BIT)
{
Address=(TCL_UINT16 *)FLASH_BASE_ADDR+offset;
return (TCL_UINT16)*Address;
}
else
{
AddressB=(TCL_UINT8 *)FLASH_BASE_ADDR+offset;
val = (TCL_UINT8)*AddressB;
return val;
}
}
/******************************************************************************
* Function: WRITE_FLASH
* Description: 写一个16 bits
* Calls: omit
* Called By: omit
* Table Accessed: none
* Table Updated: none
* Input: none
* Output: none
* Return: void
*Arithmetic
* Others:
* Note:
* Author Date Purpose
*----------------------------------------------------------------------------
* JokQu 20080229 create
******************************************************************************/
static void WRITE_FLASH(TCL_UINT32 offset, TCL_UINT16 word)
{
volatile TCL_UINT16 *Address;
volatile TCL_UINT8 *AddressB;
if (WorkMode == WORK_MODE_16BIT)
{
Address=(TCL_UINT16 *)FLASH_BASE_ADDR+offset;
*Address = word;
}
else
{
AddressB=(TCL_UINT8 *)FLASH_BASE_ADDR+offset;
*AddressB = (TCL_UINT8) word;
}
}
/******************************************************************************
* Function: FLASH_UnlockCmd
* Description: Writes 2 clock cycle unlock commands to the flash
* Calls: omit
* Called By: omit
* Table Accessed: none
* Table Updated: none
* Input: none
* Output: none
* Return: TCL_TRUE - 成功
TCL_FALSE - 出错
*Arithmetic
* Others:
* Note:
* Author Date Purpose
*----------------------------------------------------------------------------
* JokQu 20080229 create
******************************************************************************/
static void FLASH_UnlockCmd(TCL_VOID
)
{
WRITE_FLASH(CMD_UNLOCK1_ADDR[gIsSst16Bit] / WorkMode,CMD_UNLOCK1_DATA[gIsSst16Bit]);
WRITE_FLASH(CMD_UNLOCK2_ADDR[gIsSst16Bit] / WorkMode,CMD_UNLOCK2_DATA[gIsSst16Bit]);
}
/******************************************************************************
* Function: FLASH_CompletionPolling
* Description: 判断一个操作是否完成
* Calls: omit
* Called By: omit
* Table Accessed: none
* Table Updated: none
* Input: iOffset - offset in the flash to read the status word
usDataWord - when called after programming, should be the written word.
when called after erasing, should be 0.
* Output: none
* Return: TCL_TRUE - 成功
TCL_FALSE - 出错
*Arithmetic
* Others:
* Note:
* Author Date Purpose
*----------------------------------------------------------------------------
* JokQu 20080229 create
******************************************************************************/
static TCL_BOOL FLASH_CompletionPolling( TCL_UINT32 uOffset, TCL_UINT16 usDataWord )
{
#if 1
#define FLASH_POLL_TIMEOUT 3000000 /* 20ms for SST flash */
TCL_UINT32 iCount = 0;
#endif
TCL_UINT16 usStatusWord;
/* Clear all bits except DQ7 */
usDataWord &= FLASH_DQ7;
/* While flash command wasn't completed */
usStatusWord = READ_FLASH( uOffset );
while ((usStatusWord & FLASH_DQ7) != usDataWord)
{
/* Check if timeout occured */
if(gUseDQ5ForTimeout)
{
if ( (usStatusWord & FLASH_DQ5) == FLASH_DQ5 )
{
/* Read status word again */
usStatusWord = READ_FLASH( uOffset );
if ((usStatusWord & FLASH_DQ7) != usDataWord)
{
FLASH_ERROR(("error 1: FLASH_CompletionPolling\n "));
return TCL_FALSE;
}
}
}
/*------------------------------------------------
we expect SST39VF1681/SST39VF1682 never cause error.
can also add following timeout counter
------------------------------------------------*/
#if 1
else
{
/* If not use DQ5 to indicate write timeout,use timeout counter */
if(iCount < FLASH_POLL_TIMEOUT)
{
iCount += 1;
}
else
{
FLASH_ERROR(("error 2: FLASH_CompletionPolling\n "));
return TCL_FALSE;
}
}
#endif
TCL_OSP_TaskWait(0);
usStatusWord = READ_FLASH( uOffset );
}
return TCL_TRUE;
}
/******************************************************************************
* Function: FL_WriteFlashWord
* Description: 写一个16bit word.
* Calls: omit
* Called By: omit
* Table Accessed: none
* Table Updated: none
* Input: iOffset - where in the flash to burn the data
usDataWord - the data to burn
* Output: none
* Return: TCL_TRUE - 成功
TCL_FALSE - 出错
*Arithmetic
* Others:
* Note:
* Author Date Purpose
*----------------------------------------------------------------------------
* JokQu 20080229 create
******************************************************************************/
static TCL_BOOL FL_WriteFlashWord(TCL_UINT32 iOffset,TCL_UINT16 usDataWord)
{
/* Issue unlock command */
FLASH_UnlockCmd();
/* Issue program command */
WRITE_FLASH(CMD_PROGRAM_ADDR[gIsSst16Bit] / WorkMode,CMD_PROGRAM_DATA[gIsSst16Bit]);
/* Write data */
WRITE_FLASH( iOffset, usDataWord );
/* Wait until programming completes */
return FLASH_CompletionPolling( iOffset, usDataWord );
}
/******************************************************************************
* Function: CFI_WriteFlash
* Description: 写flash
* Calls: omit
* Called By: omit
* Table Accessed: none
* Table Updated: none
* Input: TCL_UINT32 uOffset - 地址
TCL_UINT8 *pData - 数据buffer
TCL_UINT32 uDataLen - 要写的数据长度
* Output: TCL_UINT32 *pAlreadyReadLen - 实际写成功的数据长度
* Return: ReturnType ( reference define of ReturnType)
*Arithmetic
* Others:
* Note:
* Author Date Purpose
*----------------------------------------------------------------------------
* JokQu 20080229 create
******************************************************************************/
TCL_UINT32 CFI_WriteFlash(TCL_UINT32 uOffset, TCL_UINT8 *pData, TCL_UINT32 uDataLen,TCL_UINT32 *pAlreadyWriteLen)
{
TCL_UINT32 i, iData;
TCL_UINT16 word;
TCL_UINT8 uStartOdd = 0;
TCL_UINT8 uEndOdd = 0;
TCL_UINT32 uWriteOfs;
TCL_UINT8 uStartOddData = 0;
TCL_UINT8 uEndOddData = 0;
// TODO:need to think about endian
/* If it's not bus-aligned, read the byte before this one*/
if (WorkMode == WORK_MODE_16BIT)
{
/* check if there is a odd byte in the start */
uStartOdd = uOffset%2;
/* check if there is a odd byte in the end */
uEndOdd = (uDataLen - uStartOdd) % 2;
/* if there is a odd byte in the end, read the byte after the last for combination */
if (uEndOdd)
{
word = *((TCL_UINT16*)FLASH_ADDRESS((uOffset+uDataLen-1)/2));
uEndOddData = (TCL_UINT8)word;
}
/* addr in 16bit mode */
uWriteOfs = (uOffset-uStartOdd)/2;
/* get the whole word */
word = *((TCL_UINT16*)FLASH_ADDRESS(uWriteOfs));
/* get the byte before the start odd data */
uStartOddData = (TCL_UINT8)(word>>8);
}
/* Enable writes to the flash */
EnableFlash( );
if (WorkMode == WORK_MODE_16BIT)
{
/* If it's not bus-aligned, do the first byte write */
if (uOffset%2)
{
// TODO:need to think about endian
iData = (uStartOddData<<8)|pData[0];
if ( !FL_WriteFlashWord( uWriteOfs, iData ) )
{
FLASH_ERROR(( "1 - Flash write failed at offset %x\n",uWriteOfs));
/* Disable writes to the flash */
DisableFlash( );
return TCL_GDI_FLASH_WRITE_FAILURE;
}
/* align to the next word */
uOffset = uOffset+uStartOdd;
uDataLen = uDataLen-uStartOdd;
}
/* offset is aligned, get addr in 16bit mode */
uWriteOfs = uOffset/2;
for( i=0; i<uDataLen/2; i++ )
{
/* Write the aligned words to the flash */
// TODO:need to think about endian
iData = ((*(pData+uStartOdd+i*2))<<8)|(*(pData+uStartOdd+i*2+1));
if ( !FL_WriteFlashWord( uWriteOfs+i, iData ) )
{
FLASH_ERROR(("2 - Flash write failed at offset %x\n",(uWriteOfs+i)));
/* Disable writes to the flash */
DisableFlash( );
return TCL_GDI_FLASH_WRITE_FAILURE;
}
}
if (uEndOdd)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -