⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcl_gdi_flash_cfi.c

📁 完全支持CFI协议的Flash驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
#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 + -