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

📄 tcl_gdi_flash_cfi.c

📁 完全支持CFI协议的Flash驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
			/* Write the last unaligned byte */
			// TODO:need to think about endian
			iData = ((*(pData+uStartOdd+i*2))<<8)|uEndOddData;
			if ( !FL_WriteFlashWord( uWriteOfs+i, iData ) )
			{
				FLASH_ERROR(("3 - Flash write failed at offset %x\n",(uWriteOfs+i)));
				/* Disable writes to the flash */
				DisableFlash( );
				return TCL_GDI_FLASH_WRITE_FAILURE;
			}
		}
	}
	else
	{
		for( i=0; i<uDataLen; i++ )
		{
			/* Write the word to the flash */
			iData = pData[i];
			if ( !FL_WriteFlashWord( uOffset+i, iData ) )
			{
				FLASH_ERROR(("1 - Flash write failed at offset %x\n",(uOffset+i)));

				/* Disable writes to the flash */
				DisableFlash( );
				return TCL_GDI_FLASH_WRITE_FAILURE;
			}
		}
	}

	/* Disable writes to the flash */
	DisableFlash( );

	*pAlreadyWriteLen = i;
	return TCL_NO_ERROR;
}


/******************************************************************************
* Function:            FL_WriteFlashBuffer
* Description:        This function burns at least one 16bit word and 32 at most.
* Calls:            	omit
* Called By: 		omit
* Table Accessed:	none
* Table Updated:	none
* Input:   		 iOffset - where in the flash to burn the data, must be multiple of 32
				usDataWord - the start address of data to be burn
				DataCounter - total byte to written to flash.
* Output:              	none
* Return:              TCL_TRUE - 成功
				TCL_FALSE - 出错
*Arithmetic
* Others: 			
* Note:			
*		Author			Date								Purpose	
*----------------------------------------------------------------------------
*		JokQu			20080229						create
******************************************************************************/
TCL_BOOL FL_WriteFlashBuffer(TCL_INT32 iOffset, TCL_UCHAR *pucBuff, TCL_UINT8 DataCounter)
{
	TCL_UINT8 iLoop = 0;
	TCL_UINT32 SectorAdd = iOffset & 0xFFFF00;

	if(0 != (iOffset & 0x1F))
	{
		return TCL_FALSE;
	}

	/* write first two unlock command */
	FLASH_UnlockCmd(); 

	/* write buffer load command */
	WRITE_FLASH(SectorAdd,0x25);

	/* write the number of location.*/
	WRITE_FLASH(SectorAdd,DataCounter-1);

	/* write the first address and data pair */
	WRITE_FLASH(iOffset,pucBuff[0]);

	for(iLoop = 1; iLoop < DataCounter; iLoop++)
	{
		/* write the left address and data pairs */
		WRITE_FLASH(iOffset+iLoop,pucBuff[iLoop]);
	}

	/* write the program buffer to flash command */
	WRITE_FLASH(SectorAdd,0x29);

	return FLASH_CompletionPolling(iOffset+DataCounter-1, pucBuff[DataCounter-1]);
}


/******************************************************************************
* Function:            CFI_FastWrite
* 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_FastWrite(TCL_UINT32 uOffset, TCL_UINT8 *pData, TCL_UINT32 uDataLen,TCL_UINT32 *pAlreadyWriteLen)
{ 
	TCL_INT32 i, iData;
	TCL_UINT8 uMirrorBit;
	TCL_UINT8 uFlashSize;

	/* Enable writes to the flash */
	EnableFlash( );
	uFlashSize = READ_FLASH(CFI_DEV_SIZE_ADDR);
	WRITE_FLASH(CMD_CFI_QUERY_ADDR[gIsSst16Bit], CMD_CFI_QUERY_DATA);
	uMirrorBit = 0x08 & READ_FLASH(CMD_CFI_PROTECH_ADDR);
	WRITE_FLASH(CMD_RESET_ADDR[gIsSst16Bit], CMD_RESET_DATA[gIsSst16Bit]);

	/* For each word in the image */
	if(uMirrorBit & (uFlashSize > 0x15))
	{
		for( i=0; i<(TCL_INT32)uDataLen;  )
		{
			if(0 == ((uOffset+i) & 0x1F))
			{
				if(TCL_FALSE == FL_WriteFlashBuffer(uOffset+i,pData+i,((uDataLen-i)>32)?32:(uDataLen-i)))
				{
					FLASH_ERROR(("Flash write buffer failed at offset %x\n",(uOffset+i)));
					DisableFlash();
					return TCL_GDI_FLASH_WRITE_FAILURE;
				}

				i+=32;
			}
			else
			{
				iData = pData[i];
				if ( !FL_WriteFlashWord( uOffset+i, iData ) )
				{
					FLASH_ERROR(("Flash write failed at offset %x\n",(uOffset+i)));
					DisableFlash( );
					return TCL_GDI_FLASH_WRITE_FAILURE;
				}
				
				i+=1;
			}
		}
	}
	else
	{
		for( i=0; i<(TCL_INT32)uDataLen;  )
		{
			iData = pData[i];
			if ( !FL_WriteFlashWord( uOffset+i, iData ) )
			{
				FLASH_ERROR(("Flash write failed at offset %x\n",(uOffset+i)));
				DisableFlash( );
				return TCL_GDI_FLASH_WRITE_FAILURE;
			}

			i+=1;
		}
	}

	/* Disable writes to the flash */
	DisableFlash( );
	
	*pAlreadyWriteLen = i;
	return TCL_NO_ERROR;
}


/******************************************************************************
* Function:            CFI_ReadFlash
* 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_ReadFlash(TCL_UINT32 uOffset, TCL_UINT8 *pData, TCL_UINT32 uDataLen,TCL_UINT32 *pAlreadyReadLen)
{
	TCL_UINT32 i;
	TCL_UINT8 OddOffset;
	TCL_UINT8 OddCnt;
	TCL_UINT16 word;
	TCL_UINT32 Index;

	if (WorkMode == WORK_MODE_16BIT)
	{
		Index = 0;
		OddOffset = uOffset % 2;
		uOffset = uOffset / 2;
		OddCnt = (uDataLen - OddOffset) % 2;

		/* Check if the offset is odd. */
		if (OddOffset)
		{
			word = *((TCL_UINT16*)FLASH_ADDRESS(uOffset));
			pData[Index++] = (TCL_UINT8)word;
		}
		
		for( i=0; i < (uDataLen - OddOffset) / 2; i++ )
		{
			word = *((TCL_UINT16*)FLASH_ADDRESS(uOffset + i + OddOffset));
			pData[Index++] = (TCL_UINT8)(word >> 8);
			pData[Index++] = (TCL_UINT8)word;
		} 
		
		if (OddCnt)
		{
			word = *((TCL_UINT16*)FLASH_ADDRESS((uOffset + i + OddOffset)));
			pData[Index++] = (TCL_UINT8)(word >> 8);
		}
	}
	else
	{
		for( i=0; i < uDataLen; i++ )
		{
			pData[i] = *((TCL_UINT8*)(FLASH_BASE_ADDR + uOffset + i));
		} 
	}

	*pAlreadyReadLen = uDataLen;
	return TCL_NO_ERROR;
}


/******************************************************************************
* Function:            CFI_EraseSectors
* Description:       擦除扇区
* Calls:            	omit
* Called By: 		omit
* Table Accessed:	none
* Table Updated:	none
* Input:   		TCL_UINT32 uStartSectorNum 	- 起始扇区
				TCL_UINT32 uNumOfSecs		- 要擦除的扇区数目
* Output:              	none
* Return:               TCL_NO_ERROR - 操作成功
				 其它- 出错
* Others: 			
* Note:			
*		Author			Date								Purpose	
*----------------------------------------------------------------------------
*		JokQu			20080229						create
******************************************************************************/
TCL_UINT32 CFI_EraseSectors(TCL_UINT32 uStartSectorNum, TCL_UINT32 uNumOfSecs)
{
	TCL_UINT32      i;
	TCL_UINT32      addr;
	TCL_BOOL    bStatus = TCL_FALSE;

	/* erase the whole flash */
	if(uNumOfSecs == 0xFFFFFFFF)
	{
		FLASH_DEBUG(("....................................\n"));
		FLASH_DEBUG(("Warning: erase whole flash!\n"));
		FLASH_DEBUG(("....................................\n"));
	}

	/* Enable writes to the flash */
	EnableFlash();

	/*--------------------------------------------------
	We now load the sector erase buffer of the flash IC.
	It will collect all the sectors addresess to be erased.
	Erasure will start 50usec after the last address was added.
	--------------------------------------------------*/
	for( i=uStartSectorNum; i<uStartSectorNum + uNumOfSecs; i++ )
	{
		/* Issue unlock command */
		FLASH_UnlockCmd();

		/* Issue setup command */
		WRITE_FLASH( CMD_SETUP_ADDR[gIsSst16Bit] / WorkMode, CMD_SETUP_DATA[gIsSst16Bit]);

		/* Issue 2 additional unlock cycles */
		FLASH_UnlockCmd();

		/* Issue setup command */
		addr = CFI_FlashSecStartAddr( i ) / WorkMode;

		WRITE_FLASH( addr, mEraseCmd );		

		FLASH_DEBUG(("CFI_EraseFlash: sector = %d, address = %x\n", 
			i,FLASH_BASE_ADDR+CFI_FlashSecStartAddr( i ) / WorkMode));

		/* Wait until programming completes */
		bStatus = FLASH_CompletionPolling( addr, FLASH_DQ7 );
	}

	/* Disable writes to the flash */
	DisableFlash();

	if ( TCL_TRUE ==  bStatus )
	{
		return TCL_NO_ERROR;
	}
	else
	{
		return TCL_GDI_FLASH_ERASE_FAILURE;
	}
}


/******************************************************************************
* Function:            FlashProbeCFI
* Description:        获取CFI 信息
* Calls:            	omit
* Called By: 		omit
* Table Accessed:	none
* Table Updated:	none
* Input:   		TCL_GDI_FLASH_INFO *pFlashInfo - Flash 信息指针
* Output:              	TCL_GDI_FLASH_INFO *pFlashInfo - Flash 信息
* Return:              TCL_NO_ERROR
* Others: 			
* Note:			
*		Author			Date								Purpose	
*----------------------------------------------------------------------------
*		JokQu			20080229						create
******************************************************************************/
static TCL_BOOL FlashProbeCFI(TCL_GDI_FLASH_INFO *pFlashInfo)
{
	TCL_UINT8                   gNumEraseRegions;
	TCL_UINT8                   i;
	TCL_UINT8                   j;
	TCL_UINT32                  gFlashTotalSize;
	TCL_UINT32                  size;
	FL_ERASE_REGION_INFO    gEraseRegionInfo;
	TCL_UINT16 				puSectorNum = 0;

	FLASH_DEBUG(("FlashProbeCFI: enter\n"));
	
	/* Enable writes to the flash */
	EnableFlash( );

	if (gIsSst16Bit)
	{
		FLASH_UnlockCmd();
	}

	/* Issue CFI Query command */
	WRITE_FLASH(CMD_CFI_QUERY_ADDR[gIsSst16Bit] / WorkMode, CMD_CFI_QUERY_DATA);

	/* test if CFI supported */
	if( ('Q'!=READ_FLASH(CFI_DEV_QRY_ADDR / WorkMode)) ||
		('R'!=READ_FLASH((CFI_DEV_QRY_ADDR+2) / WorkMode)) ||
		('Y'!=READ_FLASH((CFI_DEV_QRY_ADDR+4) / WorkMode)) )
	{
		pFlashInfo->uCFI = 0;
		FLASH_DEBUG(("Not Support CFI\n"));
		return TCL_FALSE;
	}

	pFlashInfo->uCFI = 1;
	FLASH_DEBUG(("Support CFI\n"));

	/*-------------------------------------------------------	
	Get device boot type. 
		For some special type, we can not get boot type from CFI
		In this case, we should have got boot type from Device ID.
	-------------------------------------------------------	*/
	if( 0xFF == pFlashInfo->eBootMode)
	{
		TCL_UINT8   bootType;
		TCL_UINT16  pri_adr;

		pri_adr = (READ_FLASH(CFI_PRIMARY_ADDR1 / WorkMode)|(READ_FLASH(CFI_PRIMARY_ADDR2 / WorkMode)<<8)) << 1;
		bootType = READ_FLASH((pri_adr + 0x1E) / WorkMode);
		FLASH_DEBUG(("CFI pri_adr: 0x%x. bootType %d\n", pri_adr, bootType));

		if ((bootType != 2) && (bootType != 3)) 
		{
			FLASH_DEBUG(("CFI does not contain boot  bank location. Assuming Bottom boot.\n"));
			bootType = 2;
		}

		if(bootType == 3)
		{
			pFlashInfo->eBootMode= TCL_GDI_FLBOOT_TOP;
		}
		else
		{
			pFlashInfo->eBootMode = TCL_GDI_FLBOOT_BOTTOM;
		}
	}
    
	/* Read device size */
	gFlashTotalSize = (1<<READ_FLASH(CFI_DEV_SIZE_ADDR / WorkMode));

	/* Read ERASE REGIONS information */
	gNumEraseRegions = READ_FLASH( CFI_NUM_ERASE_REGIONS_ADDR / WorkMode );
	FLASH_DEBUG(("Flash Size: %dMB  <%d erase regions>\n", gFlashTotalSize>>20, gNumEraseRegions)); 

	/* init total sector number */
	pFlashInfo->uFlashSize = gFlashTotalSize;
	puSectorNum	= 0; 
	size = 0;
	j = 0;
    
	for(i=0; i<gNumEraseRegions; i++)
	{
		TCL_UINT32 uCurPos;

		if((pFlashInfo->eBootMode) == TCL_GDI_FLBOOT_TOP)
		{
			/* top boot mode flash */
			uCurPos = gNumEraseRegions - i - 1;
		}
		else
		{
			/* bottom boot mode flash */
			uCurPos = i;
		}
		
		gEraseRegionInfo.numSectors = 
			READ_FLASH((CFI_ERASE_REGION_START_ADDR+8*uCurPos) / WorkMode)
			+ (READ_FLASH((CFI_ERASE_REGION_START_ADDR+8*uCurPos+2) / WorkMode)<<8) + 1;
		gEraseRegionInfo.sectorSize = 
			(READ_FLASH((CFI_ERASE_REGION_START_ADDR+8*uCurPos+4) / WorkMode)<<8)
			+ (READ_FLASH((CFI_ERASE_REGION_START_ADDR+8*uCurPos+6) / WorkMode)<<16);
	        
		for(j=0;j<gEraseRegionInfo.numSectors;j++)
		{            
			pFlashInfo->eSectorInfo[puSectorNum].uSectorNo = puSectorNum;
			pFlashInfo->eSectorInfo[puSectorNum].uStartAdress = size;
			pFlashInfo->eSectorInfo[puSectorNum].uSecLength = gEraseRegionInfo.sectorSize;

			/*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -