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

📄 amd29lv800.c

📁 Coldfire MCF5282 DBug bootloader
💻 C
字号:
/****************************************************************************************/
/*											*/
/*  File:		AMD29LV800.c							*/
/*  Date:		19 December 1997						*/
/*  Purpose:		Device driver for the AMD 29LV800 Flash.			*/
/*											*/
/*  Notes:		This driver supports a single width of the 512K x 16 AMD29LV800	*/
/*			FLASH: 8-bit, 16-bit, or 32-bit.  */
/*												*/
/*												*/
/*													*/
/*													*/
/****************************************************************************************/

/****************************************************************************************/
/*											*/
/*  IMPORTANT:  It is not possible to execute any of these routines if the code for	*/
/*  these routines is in the FLASH itself.  This is because these routines change the	*/
/*  mode of the device so that reads from it are not always possible.  The code must	*/
/*  be executed out of DRAM.								*/
/*											*/
/****************************************************************************************/

/****************************************************************************************/
/*											*/
/*  WARNING:  The two routines/symbols AMD29LV800_start and AMD29LV800_end are used to	*/
/*  determine the start and end of the FLASH PIC driver in ROM/FLASH so that it can be	*/
/*  copied out to DRAM and then executed.  In other words, any modifications/additions	*/
/*  must be between these two functions!						*/
/*											*/
/****************************************************************************************/

#include "src/include/dbug.h"
#include "src/dev/flash/amd29lv800.h"

void
amd29lv800_start (void) {}

/****************************************************************************************/

void
amd29lv800_read (AMD29LV800 *amd29lv800)
{
	/************************************************************************/
	/*  This routine places the FLASH in the read/reset mode.		*/
	/************************************************************************/

	amd29lv800->device.cmdreg1 = AMD29LV800_READ_CMD;
}

/****************************************************************************************/

int
amd29lv800_sector_erase (AMD29LV800 *amd29lv800, AMD29LV800_SECTOR sector)
{
	/************************************************************************/
	/*  This routine erases one sector in the Flash.			*/
	/************************************************************************/

	/*  Setup pointer to the sector to be erased  */
	AMD29LV800_CELL	*s;
	s = (AMD29LV800_CELL *)&(amd29lv800->sector[sector]);

	/*  Perform the Sector Erase command sequence  */
	amd29lv800->device.cmdreg1 = AMD29LV800_UNLOCK_CMD1;
	amd29lv800->device.cmdreg2 = AMD29LV800_UNLOCK_CMD2;
	amd29lv800->device.cmdreg1 = AMD29LV800_ERASE_CMD;
	amd29lv800->device.cmdreg1 = AMD29LV800_UNLOCK_CMD1;
	amd29lv800->device.cmdreg2 = AMD29LV800_UNLOCK_CMD2;
	*s = AMD29LV800_SECTORERASE_CMD;

	/*  Wait for the device to finish erasing the chip  */
	while (1)
	{
		/*  Flash has been erased  */
		if ((*s & AMD29LV800_ERASE_DONE) == AMD29LV800_ERASE_DONE)
		{
			return 1;
		}
	}
}


/****************************************************************************************/

int
amd29lv800_chip_erase (AMD29LV800 *amd29lv800)
{
	/************************************************************************/
	/*  This function will erase all of the sectors in the Flash.		*/
	/************************************************************************/

	/*  Setup pointer to any sector to read status information  */
	AMD29LV800_CELL *s;
	s = (AMD29LV800_CELL *)&(amd29lv800->sector[AMD29LV800_SECTOR_0]);

	/*  Perform the Chip Erase command sequence  */
	amd29lv800->device.cmdreg1 = AMD29LV800_UNLOCK_CMD1;
	amd29lv800->device.cmdreg2 = AMD29LV800_UNLOCK_CMD2;
	amd29lv800->device.cmdreg1 = AMD29LV800_ERASE_CMD;
	amd29lv800->device.cmdreg1 = AMD29LV800_UNLOCK_CMD1;
	amd29lv800->device.cmdreg2 = AMD29LV800_UNLOCK_CMD2;
	amd29lv800->device.cmdreg1 = AMD29LV800_CHIPERASE_CMD;

	/*  Wait for the device to finish erasing the chip  */
	while (1)
	{
		int timeouts;
		timeouts = 0;

		/*  Flash has been erased  */
		if ((*s & AMD29LV800_ERASE_DONE) == AMD29LV800_ERASE_DONE)
		{
			return 1;
		}

		/*  Error has been noticed by the chip  */
		if (*s & AMD29LV800_TIME_EXCEEDED)
		{
			amd29lv800_read (amd29lv800);
			return -1;
		}

		/*  Timeout has been called by the program  */
		if (++timeouts > 1024)
		{
			amd29lv800_read (amd29lv800);
			return -2;
		}
	}
}

/****************************************************************************************/

int
amd29lv800_id (AMD29LV800 *amd29lv800)
{
	/************************************************************************/
	/*  This routine extracts from the FLASH the manufacturer and device	*/
	/*  code.  If the codes match those for the AMD29LV800, then 1 is	*/
	/*  returned, else 0.							*/
	/************************************************************************/

	unsigned int manuf, device;

	/*  Perform the Autoselect command sequence.  */
	amd29lv800->device.cmdreg1 = AMD29LV800_UNLOCK_CMD1;
	amd29lv800->device.cmdreg2 = AMD29LV800_UNLOCK_CMD2;
	amd29lv800->device.cmdreg1 = AMD29LV800_AUTOSELECT_CMD;

	/*  Read the manufacturer and device id codes.  */
	manuf = amd29lv800->device.manuf;
	device = amd29lv800->device.id;

	/*  Place the device back in the Read/Reset mode.  */
	amd29lv800_read (amd29lv800);

	/*  Determine if an AMD29LV800 or not.  */
	if ((manuf == AMD29LV800_AMD_CODE) &
	    (device == AMD29LV800_DEVICE_CODE))
	{
		return 1;
	}
	else
	{
		return -1;
	}
}


/****************************************************************************************/

int
amd29lv800_write (AMD29LV800 *amd29lv800,
	void *data, unsigned length, AMD29LV800_SECTOR sector, void (*func)(void),int updbug)
{
	/************************************************************************/
	/* This routine programs the device beginning at 'sector' with		*/
	/* 'data' for 'length' bytes.  This routine is capable of		*/
	/* programming multiple consecutive sectors.				*/
	/************************************************************************/

	int index, written, done, delay, num_hash1 = 0, num_hash2 = 0;
	int AMD29LV800_SECTOR_SIZE;
	AMD29LV800_CELL *source;
	AMD29LV800_CELL *target;
	AMD29LV800_CELL rdata;

	/*  Step 1)  ID the flash as a AMD29LV800.  */
	if (!amd29lv800_id(amd29lv800))
		return -1;

	/*  Step 2)  Point to the beginning sector.  */
	target = (AMD29LV800_CELL *)&(amd29lv800->sector[sector]);
	source = (AMD29LV800_CELL *)data;

	done = 0;
	written = 0;

	/*  Loop if writing across different sectors.  */
	while (!done)
	{
	   /*  Step 3)  Determine the size of the sector and divide by (4 * 1024).    */
	   /*	     This will depend on the type of Flash.  */
	   switch(sector)
	   {
	      case AMD29LV800_SECTOR_0:	 AMD29LV800_SECTOR_SIZE = (2); break;
	      case AMD29LV800_SECTOR_1:	 AMD29LV800_SECTOR_SIZE = (1); break;
	      case AMD29LV800_SECTOR_2:	 AMD29LV800_SECTOR_SIZE = (1); break;
	      case AMD29LV800_SECTOR_3:	 AMD29LV800_SECTOR_SIZE = (4); break;
	      case AMD29LV800_SECTOR_4:	 AMD29LV800_SECTOR_SIZE = (8); break;
	      case AMD29LV800_SECTOR_5:	 AMD29LV800_SECTOR_SIZE = (8); break;
	      case AMD29LV800_SECTOR_6:	 AMD29LV800_SECTOR_SIZE = (8); break;
	      case AMD29LV800_SECTOR_7:	 AMD29LV800_SECTOR_SIZE = (8); break;
	      case AMD29LV800_SECTOR_8:	 AMD29LV800_SECTOR_SIZE = (8); break;
	      case AMD29LV800_SECTOR_9:	 AMD29LV800_SECTOR_SIZE = (8); break;
	      case AMD29LV800_SECTOR_10: 	 AMD29LV800_SECTOR_SIZE = (8); break;
	      case AMD29LV800_SECTOR_11: 	 AMD29LV800_SECTOR_SIZE = (8); break;
	      case AMD29LV800_SECTOR_12: 	 AMD29LV800_SECTOR_SIZE = (8); break;
	      case AMD29LV800_SECTOR_13: 	 AMD29LV800_SECTOR_SIZE = (8); break;
	      case AMD29LV800_SECTOR_14: 	 AMD29LV800_SECTOR_SIZE = (8); break;
	      case AMD29LV800_SECTOR_15: 	 AMD29LV800_SECTOR_SIZE = (8); break;
	      case AMD29LV800_SECTOR_16: 	 AMD29LV800_SECTOR_SIZE = (8); break;
	      case AMD29LV800_SECTOR_17: 	 AMD29LV800_SECTOR_SIZE = (8); break;
	      case AMD29LV800_SECTOR_18: 	 AMD29LV800_SECTOR_SIZE = (8); break;
	   }


			
	   /*  Step 4)  Erase the sector.  */
	   if (!amd29lv800_sector_erase (amd29lv800, sector))
	      return -2;

	   /*  Step 5)  Program the FLASH with the sector(s) contained in RAM.  */
	   for (index = 0; (index < (AMD29LV800_SECTOR_SIZE * 4 * 1024)) && (written < length);
	      ++index)

	   {

	/* ************************************************************************************** */ 
	/*	COMMENTED THIS BIT OUT AS IT CAUSED MAJOR PROBLEMS WITH UPUSER COMMAND ON LITE BOARD */
	/* 															*/
	/*	     if (!updbug)												*/
	/*	     {													*/
	/*		 Hash marks to indicate progress 								*/
	/*               if (num_hash1 == 2000)									*/
	/*               {												*/
	/*                       printf(".");									*/
	/*			num_hash2++;										*/
	/*			num_hash1 = -1;										*/
	/*                       if (num_hash2 == 53)   // 52 characters					*/
	/*                       {											*/
	/*                               printf("\n");								*/
	/*                               num_hash2 = 0;								*/
	/*                       }											*/	
	/*               }												*/
	/*		num_hash1++;											*/
	/*	     }													*/
	/* ************************************************************************************** */ 

	      /*  Perform the Byte Program command sequence.  */
	      amd29lv800->device.cmdreg1 = AMD29LV800_UNLOCK_CMD1;
	      amd29lv800->device.cmdreg2 = AMD29LV800_UNLOCK_CMD2;
	      amd29lv800->device.cmdreg1 = AMD29LV800_BYTEPROG_CMD;
	      *target = *source;

	      /*  Poll to make sure it is done before continuing...  */
	      while (1)
	      {
		 int timeouts;
		 timeouts = 0;

		 /*  Read the data from the Flash.  */
		 rdata = *(volatile AMD29LV800_CELL *)target;

		 /*  If the Polling bit of the Flash is the same as the polling  */
		 /*  bit of the last data written, then the write is complete.  */

		 /* PASS */
		 if ((rdata & AMD29LV800_DATA_POLL_MASK) ==
		     (*source & AMD29LV800_DATA_POLL_MASK))
		 {
		 break;
		 }

		 /*  If the status bits have not changed for too long, then timeout.  */
		 /*  FAIL */
		 if (++timeouts > 1024)
		 {
		    amd29lv800_read (amd29lv800);
		    break;
		 }
	      }

	      /*  Verify write and increment bytes written counter.  */
	      amd29lv800_read (amd29lv800);
	      if (*target == *source)
	      {
		 written += sizeof(AMD29LV800_CELL);
		 ++target;
		 ++source;
	      }
	      else
	      {
		 done = 1;
		 break;
	      }
	   }

	   /*  Point to the next sector.  If there are bytes left to write, and	the  */
	   /*  current sector was not the last, then continue in the next sector.    */
	   sector += (AMD29LV800_SECTOR_SIZE);
	   if ((sector > AMD29LV800_BLOCKS) || (written >= length))
	      done = 1;
	}

	/*  Step 6)  Place the device back in the read mode.  */
	amd29lv800_read (amd29lv800);

	/*  Step 7)  Run any function passed in by the caller before returning.  */
	/* In the case that updbug is the caller, the address of the new ROM     */
	/* Monitor's entrance point is passed in and execution of the new Monitor*/
	/* begins								 */
	if ((func != NULL))
	{
		func();
	}
	return written;
}

void
amd29lv800_end(void)
{ }

⌨️ 快捷键说明

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