📄 amd29lv004.c
字号:
/*****************************************************************************
*
* File: amd29lv004.c
* Date: 19 December 1997
* Purpose: Device driver for the AMD 29LV004 Flash.
*
* Notes: This driver supports a single width of the 512K x 8 AMD29LV004
* FLASH: 8-bit, 16-bit, or 32-bit. The width support is declared
* during compilation, and is implemented with either 1, 2, or 4
* AMD29LV004s, respectively.
*****************************************************************************/
/*****************************************************************************
*
* 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 mustbe executed out of RAM.
*****************************************************************************/
/*****************************************************************************
*
* WARNING: The two routines/symbols amd29lv004_start and amd29lv004_end are
* used to determine the start and end of the FLASH PIC driver in ROM/FLASH so
* that it can becopied 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/amd29lv004.h"
/*****************************************************************************/
void
amd29lv004_start (void) {}
/*****************************************************************************/
void
amd29lv004_read (AMD29LV004 *amd29lv004)
{
/************************************************************************/
/* This routine places the FLASH in the read/reset mode. */
/************************************************************************/
amd29lv004->device.cmdreg1 = AMD29LV004_READ_CMD;
}
/*****************************************************************************/
int
amd29lv004_sector_erase (AMD29LV004 *amd29lv004, AMD29LV004_SECTOR sector)
{
/************************************************************************/
/* This routine erases one sector in the Flash. */
/************************************************************************/
/* Setup pointer to the sector to be erased */
AMD29LV004_CELL *s;
s = (AMD29LV004_CELL *)&(amd29lv004->sector[sector]);
/* Perform the Sector Erase command sequence */
amd29lv004->device.cmdreg1 = AMD29LV004_UNLOCK_CMD1;
amd29lv004->device.cmdreg2 = AMD29LV004_UNLOCK_CMD2;
amd29lv004->device.cmdreg1 = AMD29LV004_ERASE_CMD;
amd29lv004->device.cmdreg1 = AMD29LV004_UNLOCK_CMD1;
amd29lv004->device.cmdreg2 = AMD29LV004_UNLOCK_CMD2;
*s = AMD29LV004_SECTORERASE_CMD;
/* Wait for the device to finish erasing the chip */
while (1)
{
/* Flash has been erased */
if ((*s & AMD29LV004_ERASE_DONE) == AMD29LV004_ERASE_DONE)
{
return 1;
}
}
}
/*****************************************************************************/
int
amd29lv004_chip_erase (AMD29LV004 *amd29lv004)
{
/************************************************************************/
/* This function will erase all of the sectors in the Flash. */
/************************************************************************/
/* Setup pointer to any sector to read status information */
AMD29LV004_CELL *s;
s = (AMD29LV004_CELL *)&(amd29lv004->sector[AMD29LV004_SECTOR_0]);
/* Perform the Chip Erase command sequence */
amd29lv004->device.cmdreg1 = AMD29LV004_UNLOCK_CMD1;
amd29lv004->device.cmdreg2 = AMD29LV004_UNLOCK_CMD2;
amd29lv004->device.cmdreg1 = AMD29LV004_ERASE_CMD;
amd29lv004->device.cmdreg1 = AMD29LV004_UNLOCK_CMD1;
amd29lv004->device.cmdreg2 = AMD29LV004_UNLOCK_CMD2;
amd29lv004->device.cmdreg1 = AMD29LV004_CHIPERASE_CMD;
/* Wait for the device to finish erasing the chip */
while (1)
{
int timeouts;
timeouts = 0;
/* Flash has been erased */
if ((*s & AMD29LV004_ERASE_DONE) == AMD29LV004_ERASE_DONE)
{
return 1;
}
/* Error has been noticed by the chip */
if (*s & AMD29LV004_TIME_EXCEEDED)
{
amd29lv004_read (amd29lv004);
return -1;
}
/* Timeout has been called by the program */
if (++timeouts > 1024)
{
amd29lv004_read (amd29lv004);
return -2;
}
}
}
/*****************************************************************************/
int
amd29lv004_id (AMD29LV004 *amd29lv004)
{
/************************************************************************/
/* This routine extracts from the FLASH the manufacturer and device */
/* code. If the codes match those for the AMD29LV004, then 1 is */
/* returned, else 0. */
/************************************************************************/
unsigned int manuf, device;
/* Perform the Autoselect command sequence. */
amd29lv004->device.cmdreg1 = AMD29LV004_UNLOCK_CMD1;
amd29lv004->device.cmdreg2 = AMD29LV004_UNLOCK_CMD2;
amd29lv004->device.cmdreg1 = AMD29LV004_AUTOSELECT_CMD;
/* Read the manufacturer and device id codes. */
manuf = amd29lv004->device.manuf;
device = amd29lv004->device.id;
/* Place the device back in the Read/Reset mode. */
amd29lv004_read (amd29lv004);
/* Determine if an AMD29LV004 or not. */
if ((manuf == AMD29LV004_AMD_CODE) & (device == AMD29LV004_DEVICE_CODE))
return 1;
else
return -1;
}
/*****************************************************************************/
int
amd29lv004_write (AMD29LV004 *amd29lv004,
void *data, unsigned length, AMD29LV004_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 written = 0, done = 0, hash1 = 0, hash2 = 0;
int i, sector_size, timeouts;
AMD29LV004_CELL *source, *target, rdata;
/* Step 1) ID the flash as a AMD29LV004. */
if (!amd29lv004_id(amd29lv004))
return -1;
/* Step 2) Point to the beginning sector. */
target = (AMD29LV004_CELL *)&(amd29lv004->sector[sector]);
source = (AMD29LV004_CELL *)data;
/* Loop if writing across different sectors. */
while (!done)
{
/* Step 3) Determine the size of the sector and divide by (8 * 1024) */
/* This will depend on the type of Flash */
switch(sector)
{
case AMD29LV004_SECTOR_0: sector_size = (8); break;
case AMD29LV004_SECTOR_1: sector_size = (8); break;
case AMD29LV004_SECTOR_2: sector_size = (8); break;
case AMD29LV004_SECTOR_3: sector_size = (8); break;
case AMD29LV004_SECTOR_4: sector_size = (8); break;
case AMD29LV004_SECTOR_5: sector_size = (8); break;
case AMD29LV004_SECTOR_6: sector_size = (8); break;
case AMD29LV004_SECTOR_7: sector_size = (4); break;
case AMD29LV004_SECTOR_8: sector_size = (1); break;
case AMD29LV004_SECTOR_9: sector_size = (1); break;
case AMD29LV004_SECTOR_10: sector_size = (2); break;
default: sector_size = (8); break;
}
/* Step 4) Erase the sector. */
if (!amd29lv004_sector_erase (amd29lv004, sector))
return -2;
/* Step 5) Program the FLASH with the sector(s) contained in RAM. */
for (i = 0; (i < (sector_size * 8 * 1024)) && (written < length); ++i)
{
if (!updbug)
{
/* Hash marks to indicate progress */
if (hash1 == 2000)
{
printf(".");
hash1 = -1;
if (hash2++ == 52) /* 52 characters */
{
printf("\n");
hash2 = 0;
}
}
hash1++;
}
/* Perform the Byte Program command sequence */
amd29lv004->device.cmdreg1 = AMD29LV004_UNLOCK_CMD1;
amd29lv004->device.cmdreg2 = AMD29LV004_UNLOCK_CMD2;
amd29lv004->device.cmdreg1 = AMD29LV004_BYTEPROG_CMD;
*target = *source;
/* Poll to make sure it is done before continuing... */
timeouts = 0;
while (1)
{
/* Read the data from the Flash. */
rdata = *(volatile AMD29LV004_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 & AMD29LV004_DATA_POLL_MASK) ==
(*source & AMD29LV004_DATA_POLL_MASK))
break;
/*
* If the status bits have not changed for too long, timeout.
*/
if (++timeouts > 1024)
{
amd29lv004_read (amd29lv004);
break;
}
}
/* Verify write and increment bytes written counter. */
amd29lv004_read (amd29lv004);
if (*target == *source)
{
written += sizeof(AMD29LV004_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 += (sector_size);
if ((sector > AMD29LV004_BLOCKS) || (written >= length))
done = 1;
}
/* Step 6) Place the device back in the read mode. */
amd29lv004_read (amd29lv004);
/* 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
amd29lv004_end(void)
{ }
/*****************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -