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

📄 amdflash.c

📁 norflash的文件系统。 用于中低端手机开发的参考
💻 C
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************
 
  FILE NAME: AmdFlashDrv.c

  DESCRIPTION:

    For AMD Dual-bank flash.

 Copyright (c) 2002, VIA Technologies, Inc.
*****************************************************************************/


#include "fsmdefs.h"
#include "fsmflash.h"
#include "amdflash.h"
#include "ostype.h"


#define BLOCK_SIZE				0x10000
#define FSM_DATA_BLOCKS			7
#define FSM_DATA_START_ADDR		0x07010000


#define COPY_BUFFER_SIZE		32

#define GET_MIN(a, b)               (((a) < (b)) ? (a) : (b))

#define ALIGN_ADDRESS(addr)		((uint32) ((addr) & ((uint32) ~(sizeof(FLASH_DATA) - 1))))

#define UNALIGNED_BYTES(addr)	((uint32) ((addr) & ((uint32) (sizeof(FLASH_DATA) - 1))))


uint32		FsmAmdFlashInit(FsmDevObjHdrT * DevObjP);
uint32		FsmAmdFlashRead(FsmDevObjHdrT * DevObjP, uint8 * buf, uint32 Addr, uint32 length);
uint32		FsmAmdFlashWrite(FsmDevObjHdrT * DevObjP, uint8 * buf, uint32 Addr, uint32 length);
uint32		FsmAmdFlashErase(FsmDevObjHdrT * DevObjP, uint32 Addr);
uint32		FsmAmdFlashCopy(FsmDevObjHdrT * DevObjP, uint32 DstAddr, uint32 SrcAddr, uint32 length);
uint32		FsmAmdFlashCtrl(FsmDevObjHdrT * DevObjP, uint32 CtrlCode, void *arg);

/* =============== global variables ========================= */

const FsmDevDrvT	AmdFlashDrv = \
					{
						FsmAmdFlashRead,
						FsmAmdFlashWrite,
						FsmAmdFlashCopy,
						FsmAmdFlashErase,
						FsmAmdFlashCtrl,
						FsmAmdFlashInit
					};


FsmFlashDevT		FlashDev = /* Amd Flash Device */
					{
						{ (FsmDevDrvT *)&AmdFlashDrv, DEV_TYPE_FLASH, NULL },
						NULL,
						NULL,
						BLOCK_SIZE,
						FSM_DATA_BLOCKS,
						FSM_DATA_START_ADDR
					};


volatile uint8	FsmStarting = FALSE;



/*-------------------------------- Local Functions ------------------------------*/

/******************************************************************************
 * PollWait()
 *
 * descriptions:
 *   The data polling bit, DQ7, indicates whether a program or erase operation 
 *   is in progress or completed. While programming or erasure is in process 
 *   DQ7 indicates the complement of the programmed data at bit 7. When the 
 *   operation completes, DQ7 indicates the programmed data.
 *
 * parameters:
 *
 *   p - Flash address for which poll wait status will be returned.
 *   Data - Data that was programmed to the flash (0xff for erase operations).
 *   EraseFlag - Flag indicating if the poll is on an erase or program operation.
 *
 * return:
 *   Poll wait status results. OKAY if the program/erase operation completes
 *   without a timeout condition. FAIL is returned otherwise.
 *
 *****************************************************************************/

static uint8 PollWait(volatile FLASH_DATA *p, FLASH_DATA Data)
{
   FLASH_DATA	dq7;

   dq7 = Data & DQ7_MASK;
   /* 
      Read the status word. If bit 7 doesn't match bit 7 of
      the data that was programmed (or erased) then the operation
      is not complete 
   */
   while (((*p) & DQ7_MASK) != dq7)
   {
      /* 
         If bit 5 goes high then the program or erase time has
         exceeded a specified internal pulse count limit.
      */
      if (((*p) & DQ5_MASK) != 0)
      {
         if (((*p) & DQ7_MASK) != dq7)
         {
            /* Reset the flash to read mode */
            RESET_TO_READ(p);

            return FALSE;
         }
         else
            break;
      }
   }

   return TRUE;
}

static BANK_STATUS BankEraseStatus(volatile FLASH_DATA *p)
{
   FLASH_DATA	old_dq_2_6;
   FLASH_DATA	new_dq_2_6;
   FLASH_DATA	dq_2_6_mask;

   /* if(((*p) & DQ7_MASK) != 0)
   {
	   return BANK_STATUS_READY;
   } */

   dq_2_6_mask = (DQ2_MASK | DQ6_MASK);

   /*
		Read the status word twice to check if the
		bits (DQ2,DQ6) both toggles. If not both toggles, 
		then the earse operation is complete.
   */

   old_dq_2_6 = (*p) & dq_2_6_mask;
   new_dq_2_6 = (*p) & dq_2_6_mask;

   if ((old_dq_2_6 ^ new_dq_2_6) == dq_2_6_mask)
   {
	  /*
	      If toggles, then read status word again to check DQ5,
		  if it is low, then the erase operation is in progress.
		  if it is high, then it is timeout, we should check
		  toggle bits again.
	  */
      if (((*p) & DQ5_MASK) != 0)
      {
		 old_dq_2_6 = (*p) & dq_2_6_mask;
		 new_dq_2_6 = (*p) & dq_2_6_mask;

		 /*
		     If these two bits toggle still even if timeout,
			 then we must write reset command to return to 
			 reading array data.
		 */

	     if ((old_dq_2_6 ^ new_dq_2_6) == dq_2_6_mask)
		 {
			 /*RESET_TO_READ(p);*/ /* SHOULD let the initiator know the timeout */

			 return BANK_STATUS_TIMEOUT;
		 }
		 else
			 return BANK_STATUS_READY;
      }
	  else
		  return BANK_STATUS_BUSY;
   }

   return BANK_STATUS_READY;
}

static uint8 IsEraseSuspended(volatile FLASH_DATA *p)
{
   FLASH_DATA	old_dq_2_6;
   FLASH_DATA	new_dq_2_6;

   if(((*p) & DQ7_MASK) == 0)
   {
	   return FALSE;
   }

   /*
		Read the status word twice to check if the
		bits (DQ2,DQ6) both toggles. If not both toggles, 
		then the earse operation is complete.
   */

   old_dq_2_6 = (*p) & (DQ2_MASK | DQ6_MASK);
   new_dq_2_6 = (*p) & (DQ2_MASK | DQ6_MASK);

   if ((old_dq_2_6 ^ new_dq_2_6) == DQ2_MASK)
   {
	   return TRUE;
   }
   else
	   return FALSE;
}

static BANK_STATUS BankStatus(volatile FLASH_DATA *p)
{
   FLASH_DATA	old_dq_6;
   FLASH_DATA	new_dq_6;

   /*
		Read the status word twice to check if the
		bits (DQ2,DQ6) both toggles. If not both toggles, 
		then the earse operation is complete.
   */

   old_dq_6 = (*p) & DQ6_MASK;
   new_dq_6 = (*p) & DQ6_MASK;

   if ((old_dq_6 ^ new_dq_6) == DQ6_MASK)
   {
	  /*
	      If toggles, then read status word again to check DQ5,
		  if it is low, then the erase operation is in progress.
		  if it is high, then it is timeout, we should check
		  toggle bits again.
	  */
      if (((*p) & DQ5_MASK) != 0)
      {
		 old_dq_6 = (*p) & DQ6_MASK;
		 new_dq_6 = (*p) & DQ6_MASK;

		 /*
		     If these two bits toggle still even if timeout,
			 then we must write reset command to return to 
			 reading array data.
		 */

	     if ((old_dq_6 ^ new_dq_6) == DQ6_MASK)
		 {
			 /* RESET_TO_READ(p); */ /* SHOULD let the initiator know the timeout */

			 return BANK_STATUS_TIMEOUT;
		 }
		 else
			 return BANK_STATUS_READY;
      }
	  else
		  return BANK_STATUS_BUSY;
   }

   return BANK_STATUS_READY;
}


/******************************************************************************
 * WriteToFlash()
 *
 * descriptions:
 *   Writes data to flash.
 *
 * parameters:
 *   FLASH_DATA_PTR dst_ptr - A pointer to the data destination.
 *   FLASH_DATA_PTR src_ptr - A pointer to the data source.
 *   uint32  size  - The number of FLASH_DATA units to write.
 *
 * return:
 *   If any portion of the data is not written successfully, the function
 *   returns HW_ERR_WRITE; otherwise, the function returns HW_ERR_NONE.
 *
 *****************************************************************************/

static uint32 WriteToFlash(
	volatile FLASH_DATA *	flash_ptr,
	const    FLASH_DATA *	ram_ptr,
	uint32					size,
	uint32					start_addr
	)
{
	uint8		bRet;


	while (size > 0)
	{
		/* If try to program data bit from 0 to 1. */
		if(((*ram_ptr) & (~(*flash_ptr))) != 0)
		{
			return HW_ERR_WRITE;
		}

		/* If the result data is not equal to original. */
		else if((*ram_ptr) != (*flash_ptr))
		{
			/* write to flash */
			DISABLE_INTERRUPTS();

			WRITE_FLASH(flash_ptr, *ram_ptr, start_addr);

			ENABLE_INTERRUPTS();

			/* wait until flash is done */
			bRet = PollWait(flash_ptr, *ram_ptr);

			RESET_TO_READ(flash_ptr); /* perhaps it is superfluous for AMD flash. */

			/* check for errors */
			if (!bRet)
			{
				return HW_ERR_WRITE;
			}
		}

		/* If the result data is equal to original. */
		else
		{
		}

		/* update pointers */
		flash_ptr++;
		ram_ptr++;
		size--;
	}

	return HW_ERR_NONE;
}


/*-----------------------  Global Functions ---------------------*/

/******************************************************************************
 * FsmAmdFlashInit()
 *
 * descriptions:
 *   reset flash device to read-mode.
 *
 * parameters:
 *    FsmDevObjHdrT * DevObjP - device object
 *
 * return:
 *   HW_ERR_NONE.
 *
 *****************************************************************************/

uint32 FsmAmdFlashInit(FsmDevObjHdrT * DevObjP)
{
	volatile FLASH_DATA_PTR		dst_data_ptr;

	FsmFlashDevT *	pDev;

	pDev = (FsmFlashDevT *)DevObjP;

	dst_data_ptr = (volatile FLASH_DATA_PTR)(pDev->DevStartAddr);
	RESET_TO_READ(dst_data_ptr);

	return HW_ERR_NONE;
}

/******************************************************************************
 * FsmAmdFlashWrite()
 *
 * descriptions:
 *   write data to flash.
 *
 * parameters:
 *    FsmDevObjHdrT * DevObjP - device object
 *    uint8 * buf - buffer contains the data to be written.
 *    uint32 Addr - the destination address within flash device.
 *    uint32 length - The amount of data, in bytes, to be written.
 * 
 * return:
 *   HW_ERR_NONE, HW_ERR_SYSTEM, HW_ERR_PARAM, HW_ERR_WRITE.
 *
 *****************************************************************************/

uint32 FsmAmdFlashWrite(FsmDevObjHdrT * DevObjP, uint8 * buf, uint32 Addr, uint32 length)
{
	volatile FLASH_DATA_PTR		dst_data_ptr;

	FLASH_DATA		temp_buffer[COPY_BUFFER_SIZE / sizeof(FLASH_DATA)];

	uint8 *			dst_byte_ptr;
	uint8 *			src_byte_ptr;

	uint32			dst_offset;
	uint32			byte_size;
	uint32			data_size;
	uint32			status = HW_ERR_NONE;

	uint32			rem_byte_size;

	uint8			suspended = (uint8)FALSE;

	BANK_STATUS		bank_status;

	FsmFlashDevT *	pDev;


	pDev = (FsmFlashDevT *)DevObjP;

	/* validate address */
#ifdef VALIDATE_ADDRESS

	if((Addr + length) > (pDev->BlockSize * pDev->Blocks))
	{
		return HW_ERR_PARAM;
	}

#endif /* VALIDATE_ADDRESS */

	Addr += pDev->DevStartAddr;


	/* return if nothing to write */
	if (length == 0)
	{
		return HW_ERR_NONE;
	}


	dst_data_ptr = (volatile FLASH_DATA_PTR) ALIGN_ADDRESS(Addr);
	dst_offset   = UNALIGNED_BYTES(Addr);
	dst_byte_ptr = (uint8 *) temp_buffer + dst_offset;
	data_size    = COPY_BUFFER_SIZE - dst_offset;
	src_byte_ptr = buf;

	/* get flash write mutex. */
	if(FsmGetMtxSem(pDev->DevWriteLock) != ERR_NONE)
	{
		if(FsmStarting == FALSE)
			return HW_ERR_SYSTEM;
	}

	/* suspend if flash is busy erasing */
	bank_status = BankEraseStatus(dst_data_ptr);
	if (bank_status == BANK_STATUS_BUSY)
	{
		ERASE_SUSPEND(dst_data_ptr);

		PollWait(dst_data_ptr, FLASH_ERASE_DATA);

		if (IsEraseSuspended(dst_data_ptr))
		{
			suspended = (uint8) TRUE;
		}
	}
	else if (bank_status == BANK_STATUS_TIMEOUT)
	{
		/*
			we SHOULD delay some time to let the 
			erase initiator know what has happened.
		*/
		TASK_SLEEP(100);
		RESET_TO_READ(dst_data_ptr);
	}
	else
	{
		/* The bank is ready */
	}


	while ((length > 0) && (status == HW_ERR_NONE))
	{
		/* */
		byte_size = GET_MIN(data_size, length);

		/* calculate the number of FLASH_DATA to write */
		data_size = (byte_size + dst_offset + sizeof(FLASH_DATA) - 1) /
					  sizeof(FLASH_DATA);

		/* For AMD flash device, if you attempt to program a bit
		* from 0 to 1, device will timeout, so we can't initialize
		* the leader spare area to 0xFF, we must read data from 
		* flash to initialize these bytes, the same to the remainder
		* area for the buffer.
		*/

		RESET_TO_READ(dst_data_ptr);

		if(dst_offset != 0)
		{
			FsmMemoryMove((uint8 *)temp_buffer, (uint8 *)dst_data_ptr, dst_offset);
		}
		rem_byte_size = (byte_size + dst_offset) % (sizeof(FLASH_DATA));
		if(rem_byte_size != 0)
		{
			FsmMemoryMove(((uint8 *)temp_buffer) + byte_size + dst_offset, \
						  ((uint8 *)dst_data_ptr) + byte_size + dst_offset, \
						  sizeof(FLASH_DATA) - rem_byte_size
						  );
		}

		FsmMemoryMove(dst_byte_ptr, src_byte_ptr, (uint16)byte_size);

		/* write buffer */
		status = WriteToFlash(dst_data_ptr, temp_buffer, data_size, pDev->DevStartAddr);

		/* update pointers/variables */
		dst_data_ptr += data_size;
		dst_byte_ptr = (uint8 *) temp_buffer;
		src_byte_ptr += byte_size;
		length -= byte_size;

⌨️ 快捷键说明

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