📄 amd29f010.c
字号:
/*
* File: amd29f010.c
* Purpose: Device driver for the AMD 29F010 Flash.
*
* Notes: This driver supports a single type (AMD29F010) and
* width of FLASH. The width support is done during
* compilation. It can support multiple banks of
* same-width ADM29F010 FLASH.
*
* If different types and width of FLASH are required,
* see driver amd29f0x0.c.
*
* Author: Eric DeVolder
* Date: 7-8-96
*
* Modifications:
*
*/
#include "src/include/dbug.h"
#include "src/dev/flash/amd29f010.h"
/*
* The AMD29F010 FLASH devices. These devices are 128K x 8 devices.
*
* Note: This driver supports one of the following configurations
* for these devices. Possible configurations are:
*
* 1 AMD29F010 as a single 8-bit memory device
* 2 AMD29F010s as a single 16-bit memory device
* 4 AMD29F010s as a single 32-bit memory device
*
* One of the following C pre-processor define statements must
* exist prior to compilation:
*
* #define FLASH_8BIT_WIDE
* #define FLASH_16BIT_WIDE
* #define FLASH_32BIT_WIDE
*
* 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: To eliminate playing alot of games with the linker
* to properly treat this PIC driver, the two routines/symbols
* amd29f010_start and amd29f010_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!
*/
/*****************************************************************/
void
amd29f010_start (void)
{
}
/*****************************************************************/
void
amd29f010_read (AMD29F010 *amd29f010)
{
/*
* This routine places the FLASH in the read/reset mode.
*/
amd29f010->device.cmdreg1 = AMD29F010_READ_CMD1;
amd29f010->device.cmdreg2 = AMD29F010_READ_CMD2;
amd29f010->device.cmdreg1 = AMD29F010_READ_CMD3;
}
/*****************************************************************/
int
amd29f010_sector_erase (AMD29F010 *amd29f010, AMD29F010_SECTOR sector)
{
/*
* This routine erases one sector in the FLASH.
*/
AMD29F010_CELL *s;
s = (AMD29F010_CELL *)&(amd29f010->sector[sector]);
/*
* Perform the Sector Erase command sequence.
*/
amd29f010->device.cmdreg1 = AMD29F010_SECTORERASE_CMD1;
amd29f010->device.cmdreg2 = AMD29F010_SECTORERASE_CMD2;
amd29f010->device.cmdreg1 = AMD29F010_SECTORERASE_CMD3;
amd29f010->device.cmdreg1 = AMD29F010_SECTORERASE_CMD4;
amd29f010->device.cmdreg2 = AMD29F010_SECTORERASE_CMD5;
*s = AMD29F010_SECTORERASE_CMD6;
/*
* Wait for the device to erase the sector
*/
while ((*s & AMD29F010_SECTORERASE_DONE) != AMD29F010_SECTORERASE_DONE)
;
/*
* Place the device back in the Read/Reset mode.
*/
amd29f010_read (amd29f010);
return 1;
}
/*****************************************************************/
int
amd29f010_id (AMD29F010 *amd29f010)
{
/*
* This routine extracts from the FLASH the manufacturer and
* and device code. If the codes match those for the AMD29F010,
* then 1 is returned, else 0.
*/
volatile unsigned int manuf, device;
/*
* Perform the Autoselect command sequence.
*/
amd29f010->device.cmdreg1 = AMD29F010_AUTOSELECT_CMD1;
amd29f010->device.cmdreg2 = AMD29F010_AUTOSELECT_CMD2;
amd29f010->device.cmdreg1 = AMD29F010_AUTOSELECT_CMD3;
/*
* Read the manufacturer and device id codes.
*/
manuf = amd29f010->device.manuf;
device = amd29f010->device.id;
/*
* Place the device back in the Read/Reset mode.
*/
amd29f010_read (amd29f010);
/*
* Determine if an AMD29F010 or not.
*/
if (device == AMD29F010_DEVICE_CODE)
{
return 1;
}
else
{
return 0;
}
}
/*****************************************************************/
int
amd29f010_write (AMD29F010 *amd29f010,
void *data, unsigned length, AMD29F010_SECTOR sector, void (*func)(void))
{
/*
* 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;
AMD29F010_CELL *source;
AMD29F010_CELL *target;
AMD29F010_CELL rdata;
/*
* Step 1) ID the flash as a AMD29F010.
*/
if (!amd29f010_id(amd29f010))
return 0;
/*
* Step 2) Point to the beginning sector.
*/
target = (AMD29F010_CELL *)&(amd29f010->sector[sector]);
source = (AMD29F010_CELL *)data;
done = 0;
written = 0;
while (!done)
{
/*
* Step 3) Erase the sector.
*/
if (!amd29f010_sector_erase (amd29f010, sector))
return -1;
/*
* Step 5) Program the FLASH with the sector(s) contained in RAM.
*/
for (index = 0; (index < AMD29F010_SECTOR_SIZE) && (written < length);
++index)
{
/*
* Perform the Byte Program command sequence.
*/
amd29f010->device.cmdreg1 = AMD29F010_BYTEPROG_CMD1;
amd29f010->device.cmdreg2 = AMD29F010_BYTEPROG_CMD2;
amd29f010->device.cmdreg1 = AMD29F010_BYTEPROG_CMD3;
*target = *source;
/*
* Poll to make sure it is done before continuing...
*/
while (1)
{
int timeouts;
timeouts = 0;
rdata = *(volatile AMD29F010_CELL *)target;
if ((rdata & AMD29F010_DATA_POLL_MASK) ==
(*source & AMD29F010_DATA_POLL_MASK))
{
break;
}
else
{
rdata = *(volatile AMD29F010_CELL *)target;
if (rdata & AMD29F010_TIME_EXCEEDED)
{
rdata = *(volatile AMD29F010_CELL *)target;
if ((rdata & AMD29F010_DATA_POLL_MASK) ==
(*source & AMD29F010_DATA_POLL_MASK))
{
break;
}
if (++timeouts > 1024)
{
amd29f010_read (amd29f010);
break;
}
}
}
}
/*
* Verify write and increment bytes written counter.
*/
amd29f010_read (amd29f010);
if (*target == *source)
{
written += sizeof(AMD29F010_CELL);
++target;
++source;
}
else
{
done = 1;
break;
}
}
if (++sector >= AMD29F010_SECTORS)
done = 1;
if (written >= length)
done = 1;
}
/*
* Step 6) Place the device back in the read mode.
*/
amd29f010_read (amd29f010);
if (func != NULL)
{
func();
}
return written;
}
void
amd29f010_end(void)
{
/*
* This function is empty and at the END of all code so that it
* can be used to compute the size of the code contained in this
* driver.
*/
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -