📄 amd29lv800.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 + -