📄 am29lv160db.c
字号:
/************************************************************************/
/* */
/* AMD CFI Enabled Flash Memory Drivers */
/* File name: CFIFLASH.C */
/* Revision: 1.0 5/07/98 */
/* */
/* Copyright (c) 1998 ADVANCED MICRO DEVICES, INC. All Rights Reserved. */
/* This software is unpublished and contains the trade secrets and */
/* confidential proprietary information of AMD. Unless otherwise */
/* provided in the Software Agreement associated herewith, it is */
/* licensed in confidence "AS IS" and is not to be reproduced in whole */
/* or part by any means except for backup. Use, duplication, or */
/* disclosure by the Government is subject to the restrictions in */
/* paragraph (b) (3) (B) of the Rights in Technical Data and Computer */
/* Software clause in DFAR 52.227-7013 (a) (Oct 1988). */
/* Software owned by */
/* Advanced Micro Devices, Inc., */
/* One AMD Place, */
/* P.O. Box 3453 */
/* Sunnyvale, CA 94088-3453. */
/************************************************************************/
/* This software constitutes a basic shell of source code for */
/* programming all AMD Flash components. AMD */
/* will not be responsible for misuse or illegal use of this */
/* software for devices not supported herein. AMD is providing */
/* this source code "AS IS" and will not be responsible for */
/* issues arising from incorrect user implementation of the */
/* source code herein. It is the user's responsibility to */
/* properly design-in this source code. */
/* */
/************************************************************************/
#include "vxWorks.h"
#include "ioLib.h"
#include "errno.h"
#include "stdio.h"
#include "string.h"
#include "time.h"
/*#include "dosFsLib.h"*/
#include "am29lv160db.h"
/*********************************************************************/
/* The purpose of get_flash_memptr() is to return a memory pointer */
/* which points to the beginning of memory space allocated for the */
/* flash. All function pointers are then referenced from this */
/* pointer. */
/* */
/* Different systems will implement this in different ways: */
/* possibilities include: */
/* - A direct memory pointer */
/* - A pointer to a memory map */
/* - A pointer to a hardware port from which the linear */
/* address is translated */
/* - Output of an MMU function / service */
/* */
/* Also note that this function expects the pointer to a specific */
/* sector of the device. This can be provided by dereferencing */
/* the pointer from a translated offset of the sector from a */
/* global base pointer (e.g. flashptr = base_pointer + sector_offset)*/
/* */
/* Important: Many AMD flash devices need both bank and or sector */
/* address bits to be correctly set (bank address bits are A18-A16, */
/* and sector address bits are A18-A12, or A12-A15). Flash parts */
/* which do not need these bits will ignore them, so it is safe to */
/* assume that every part will require these bits to be set. */
/*********************************************************************/
/*extern unsigned char FAR *get_flash_memptr(int sector);*/
/*extern unsigned char *get_flash_memptr(int sector);*/
/*********************************************************************/
/* 'meminfo' should be a pointer, but most C compilers will not */
/* allocate static storage for a pointer without calling */
/* non-portable functions such as 'new'. We also want to avoid */
/* the overhead of passing this pointer for every driver call. */
/* Systems with limited heap space will need to do this. */
/*********************************************************************/
struct flashinfo meminfo; /* Flash information structure */
/*********************************************************************/
/* Init_flash is used to build a sector table from the information */
/* provided through the CFI query. This information is translated */
/* from erase_block information to base:offset information for each */
/* individual sector. This information is then stored in the meminfo */
/* structure, and used throughout the driver to access sector */
/* information. */
/* */
/* This is more efficient than deriving the sector base:offset */
/* information every time the memory map switches (since on the */
/* development platform can only map 64k at a time). If the entire */
/* flash memory array can be mapped in, then the addition static */
/* allocation for the meminfo structure can be eliminated, but the */
/* drivers will have to be re-written. */
/* */
/* The meminfo struct occupies 653 bytes of heap space, depending */
/* on the value of the define MAXSECTORS. Adjust to suit */
/* application */
/*********************************************************************/
/*********************************************************************/
/* config BR2 and OR2 */
/*********************************************************************/
void init_flash_memory()
{
*(unsigned long*)(IMMR_CONFIG+IMMR_OR2) = (unsigned long)OR2_CONFIG;
*(unsigned long*)(IMMR_CONFIG+IMMR_BR2) = (unsigned long)BR2_CONFIG;
}
byte init_flash(struct cfi_query *q)
{
unsigned int i=0, j=0, count=0;
long basecount=0L;
/* If q == NULL, then we havent performed a CFI query
* to retrieve the sector organization. First, assume
* a single 8k sector for sector 0. This is to allow
* the system to perform memory mapping to the device,
* even though the actual physical layout is unknown.
* Once mapped in, the CFI query will produce all
* relevant information.
*/
if(q == NULL) {
meminfo.addr = 0L;
meminfo.areg = 0;
meminfo.nsect = 1;
meminfo.bank1start = 0;
meminfo.bank2start = 0;
meminfo.sec[0].size = 8192;
meminfo.sec[0].base = 0x00000;
meminfo.sec[0].bank = 1;
return(1);
} else {
count=0;basecount=0L;
for (i=0; i<q->num_erase_blocks; i++) {
count += q->erase_block[i].num_sectors;
}
meminfo.nsect = count;
count=0;
for (i=0; i<q->num_erase_blocks; i++) {
for(j=0; j<q->erase_block[i].num_sectors; j++) {
meminfo.sec[count].size = (long) q->erase_block[i].sector_size;
meminfo.sec[count].base = (long) basecount;
basecount += (long) q->erase_block[i].sector_size;
count++;
}
}
}
}
/*********************************************************************/
/* Flash_command() is the main driver function. It performs */
/* every possible command available to AMD B revision */
/* flash parts. Note that this command is not used directly, but */
/* rather called through the API wrapper functions provided below. */
/*********************************************************************/
void flash_command(int command, int sector, int offset,
unsigned int data)
{
static dword base; /* base offset for our sector */
static word *selp;
static dword sechigh;
/* static word far *flashptr; */ /* flash window (64K bytes) */
static word *flashptr;
static int oldsector = -1;
int retry;
/**************************************************************/
/* IMPORTANT: Note that flashptr is defined as a WORD pointer */
/* If BYTE pointers are used, the command tables will have to */
/* be remapped */
/* Note 1: flashptr is declared far - if system does not */
/* support far pointers, this will have to be changed */
/* Note 2: flashptr is declared static to avoid calling */
/* get_flash_memptr() on successive sector accesses */
/**************************************************************/
/* Some commands may not work the first time, but will work */
/* on successive attempts. Vary the number of retries to suit*/
/* requirements. */
static int retrycount[] = {0,0,0,0,15,15,0,15,0,0};
retry = retrycount[command];
if(sector != oldsector) {
/* flashptr = (word far *) get_flash_memptr(sector);*/
flashptr = (word *) get_flash_memptr(sector);
}
again1:
if (command == FLASH_SELECT) {
return;
} else if (command == FLASH_RESET || command > FLASH_LASTCMD) {
flashptr[0] = 0xF0; /* assume reset device to read mode */
} else if (command == FLASH_ESUSPEND) {
flashptr[0] = 0xB0; /* suspend sector erase */
} else if (command == FLASH_ERESUME) {
flashptr[0] = 0x30; /* resume suspended sector erase */
} else if (command == FLASH_UBPROG) {
flashptr[0] = 0xA0;
/* flashptr[((meminfo->sec[sector].base)+offset)/2] = data;*/
flashptr[((meminfo.sec[sector].base)+offset)/2] = data;
} else if (command == FLASH_UBRESET) {
flashptr[0] = 0x90;
flashptr[0] = 0x00;
}
else {
flashptr[0x555] = 0xAA; /* unlock 1 */
flashptr[0x2AA] = 0x55; /* unlock 2 */
switch (command) {
case FLASH_AUTOSEL:
flashptr[0x555] = 0x90;
break;
case FLASH_PROG:
flashptr[0x555] = 0xA0;
/* flashptr[((meminfo->sec[sector].base)+offset)/2] = data;*/
flashptr[((meminfo.sec[sector].base)+offset)/2] = data;
break;
case FLASH_CERASE:
flashptr[0x555] = 0x80;
flashptr[0x555] = 0xAA;
flashptr[0x2AA] = 0x55;
flashptr[0x555] = 0x10;
break;
case FLASH_SERASE:
flashptr[0x555] = 0x80;
flashptr[0x555] = 0xAA;
flashptr[0x2AA] = 0x55;
/* flashptr[(meminfo->sec[sector].base)/2] = 0x30;*/
/*flashptr[(meminfo.sec[sector].base)/2] = 0x30;*/
flashptr[0x0] = 0x30;
break;
case FLASH_UB:
flashptr[0x555] = 0x20;
break;
case FLASH_CFIQUERY:
flashptr[0x55] = 0x98;
break;
}
}
if (retry-- > 0 && flash_status(flashptr) == STATUS_READY) {
goto again1;
}
}
/*********************************************************************/
/* Flash_write extends the functionality of flash_program() by */
/* providing an faster way to program multiple data words, without */
/* needing the function overhead of looping algorithms which */
/* program word by word. This function utilizes fast pointers */
/* to quickly loop through bulk data. */
/*********************************************************************/
int flash_write(int sector, unsigned offset, byte *buf,
int nbytes, int ub)
{
/* word far *flashptr; *//* flash window */
/* word far *src, *dst;*/
word *flashptr; /* flash window */
word *src, *dst;
int stat;
int retry = 0, retried = 0;
flashptr = (word *)get_flash_memptr(sector);
dst = flashptr + offset/2; /* (byte offset) */
src = (word *)buf;
if ((nbytes | offset) & 1) {
return -1;
}
again2:
/* Check to see if we're in unlock bypass mode */
if (ub == FALSE)
flashptr[0] = 0xF0; /* reset device to read mode */
while ((stat = flash_status(flashptr)) == STATUS_BUSY) {}
if (stat != STATUS_READY) {
return (byte *)src - buf;
}
while (nbytes > 0) {
if (ub == FALSE){
flashptr[0x555] = 0xAA; /* unlock 1 */
flashptr[0x2AA] = 0x55; /* unlock 2 */
}
flashptr[0x555] = 0xA0;
*dst++ = *src++;
while ((stat = flash_status(flashptr)) == STATUS_BUSY) {}
if (stat != STATUS_READY) break;
nbytes -= 2;
}
if (stat != STATUS_READY || nbytes != 0) {
if (retry-- > 0) {
++retried;
--dst, --src; /* back up */
goto again2; /* and retry the last word */
}
if (ub == FALSE)
flash_command(FLASH_RESET,sector,0,0);
}
return (byte *)src - buf;
}
/*********************************************************************/
/* Flash_status utilizes the DQ6, DQ5, and DQ3 polling algorithms */
/* described in the flash data book. It can quickly ascertain the */
/* operational status of the flash device, and return an */
/* appropriate status code (defined in flash.h) */
/*********************************************************************/
/*int flash_status(word far *fp)*/
int flash_status(word *fp)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -