?? flash.c
字號:
/* flashcom.c:
* This file contains the portions of the flash code that are device
* independent. Refer to the appropriate device sub-directory for the
* code that is specific to the flash device on the target.
*
* General notice:
* This code is part of a boot-monitor package developed as a generic base
* platform for embedded system designs. As such, it is likely to be
* distributed to various projects beyond the control of the original
* author. Please notify the author of any enhancements made or bugs found
* so that all may benefit from the changes. In addition, notification back
* to the author will allow the new user to pick up changes that may have
* been made by other users after this version of the code was distributed.
*
* Author: Ed Sutter
* email: esutter@lucent.com (home: lesutter@worldnet.att.net)
* phone: 908-582-2351 (home: 908-889-5161)
*/
#include "config.h"
#if INCLUDE_FLASH
#include "cpu.h"
#include "flashdev.h"
#include "flash.h"
#include "genlib.h"
#include "ctype.h"
#define printf mprintf //m
typedef unsigned char uchar;
typedef unsigned long ulong;
extern struct flashdesc FlashNamId[];
int FlashCurrentBank;
int sectortoaddr(int,int *,uchar **);
extern int FlashInit(void);
#define SRANGE_ERROR -1
#define SRANGE_SINGLE 1
#define SRANGE_RANGE 2
#define SRANGE_ALL 3
/* FlashProtectWindow:
* Must be set to allow any flash operation to be done on space assumed
* to be software protected.
*/
int FlashProtectWindow;
/* FlashBank[]:
* This table contains all of the information that is needed to keep the
* flash code somewhat generic across multiple flash devices.
*/
extern struct flashinfo FlashBank[FLASHBANKS];
#ifdef DISABLE_INTERRUPTS_DURING_FLASHOPS
#define FLASH_INTSOFF() intsoff()
#define FLASH_INTSRESTORE(ival) intsrestore(ival)
#else
#define FLASH_INTSOFF() 0
#define FLASH_INTSRESTORE(ival)
#endif
/* showflashtype():
* Find a match between the incoming id and an entry in the FlashNamId[]
* table. The FlashNamId[] table is part of the device-specific code.
*/
int
showflashtype(ulong id)
{
struct flashdesc *fdp;
fdp = FlashNamId;
while(fdp->desc) {
if (id == fdp->id) {
printf("Device = %s\n",fdp->desc);
return(0);
}
fdp++;
}
printf("Flash id 0x%lx not recognized\n",id);
return(-1);
}
int
showflashinfo(struct flashinfo *fdev)
{
int i;
if (showflashtype(fdev->id) < 0)
return(-1);
printf(" Base addr : 0x%08lx\n",(ulong)(fdev->base));
printf(" Sectors : %d\n",fdev->sectorcnt);
printf(" Bank width : %d\n",fdev->width);
printf(" Sector Begin End Size SW-Protected?\n");
for(i=0;i<fdev->sectorcnt;i++) {
printf(" %2d 0x%08lx 0x%08lx 0x%06lx %s\n",
fdev->sectors[i].snum,
(ulong)(fdev->sectors[i].begin),
(ulong)(fdev->sectors[i].end),
fdev->sectors[i].size,
fdev->sectors[i].protected ? "yes" : " no");
}
return(0);
}
/* flashopload():
* Copy flash operation to ram space.
* Note that this function assumes that cache is disabled at this point.
* This is important because we are copying text into bss space and if
* cache was on, there could be a coherency problem.
*/
int
flashopload(ulong *begin,ulong *end,ulong *copy,int size)
{
volatile ulong *bp;
int ret;
/* Verify space availability: */
if (((int)end - (int)begin) >= size) {
printf("flashopload overflow ((0x%lx-0x%lx) > 0x%x)\n",
(ulong)end,(ulong)begin,size);
return(-1);
}
ret = 0;
/* Copy function() to RAM, then verify: */
bp = begin;
while(bp <= end) {
*copy = *bp;
if (*copy++ != *bp++) {
printf("flashopload failed\n");
ret = -1;
break;
}
}
return(ret);
}
/* flashtype():
* Use the device-specific function pointer to call the routine
* relocated to RAM space.
*/
int
flashtype(fdev)
struct flashinfo *fdev;
{
return(fdev->fltype(fdev));
}
/* flasherase():
* Use the device-specific function pointer to call the routine
* relocated to RAM space.
* Note that flasherase() is called with a sector number. The sector
* number is relative to the entire system, not just the particular device.
* This means that if there is more than one flash device in the system that
* the actual sector number (relative to the device) may not be the same
* value. This adjustment is made here so that the underlying code that is
* pumped into ram for execution does not have to be aware of this.
*/
int
flasherase(fdev,snum)
struct flashinfo *fdev;
int snum;
{
int size;
unsigned char *base, *end;
if (fdev->id == FLASHRAM) {
if (snum == ALL_SECTORS) {
size = fdev->end - fdev->base;
base = fdev->base;
}
else {
sectortoaddr(snum,&size,&base);
}
end = base+size;
while(base < end) {
*base = 0xff;
if (*base++ != 0xff)
return(-1);
}
return(0);
}
if ((snum != ALL_SECTORS) && (fdev->sectors[0].snum != 0)) {
/* printf("Adjusting snum from %d to",snum); */
snum -= fdev->sectors[0].snum;
/* printf(" %d.\n",snum); */
}
return(fdev->flerase(fdev,snum));
}
/* flashwrite():
* Use the device-specific function pointer to call the routine
* relocated to RAM space.
* First make a few checks on the request, then write to flash if all
* checks succeed.
*/
int
flashwrite(struct flashinfo *fdev,uchar *dest,uchar *src,long bytecnt)
{
int j, lowsector, highsector;
register uchar *dp, *sp, *edp;
if (fdev->id == FLASHRAM) {
uchar *sp, *dp, *end;
sp = src;
dp = dest;
end = dp+bytecnt;
while(dp < end) {
*dp = *sp;
if (*dp != *sp)
return(-1);
dp++; sp++;
}
return(0);
}
dp = dest;
sp = src;
edp = (dest + bytecnt) - 1;
/* If outside the devices space, return failed.. */
if ((edp < fdev->sectors[0].begin) ||
(dp > fdev->sectors[fdev->sectorcnt-1].end)) {
printf("flashwrite() failed: dest out of flash range\n");
return(-1);
}
/* Make sure the destination is not within a protected sector */
if (FlashProtectWindow == FLASH_PROTECT_WINDOW_CLOSED) {
/* First determine the sectors that overlap with the
* flash space to be written...
*/
lowsector = highsector = -1;
for(j=0;j<fdev->sectorcnt;j++) {
if ((dp >= fdev->sectors[j].begin) &&
(dp <= fdev->sectors[j].end))
lowsector = j;
}
for(j=0;j<fdev->sectorcnt;j++) {
if ((edp >= fdev->sectors[j].begin) &&
(edp <= fdev->sectors[j].end))
highsector = j;
}
if ((lowsector == -1) || (highsector == -1)) {
printf("flashwrite() failed: can't find sector\n");
return(-1);
}
/* Now that the range of affected sectors is known,
* verify that those sectors are not protected...
*/
for(j=lowsector;j<=highsector;j++) {
if (fdev->sectors[j].protected) {
printf("flashwrite() failed: sector protected\n");
return(-1);
}
}
}
/* Now make sure that there is no attempt to transition a bit
* in the affected range from 0 to 1... A flash write can only
* bring bits low (erase brings them high).
*/
while(dp < edp) {
if ((*dp & *sp) != *sp) {
printf("flashwrite() failed: bit 0->1 rqst denied.\n");
return(-1);
}
dp++;
sp++;
}
return(fdev->flwrite(fdev,dest,src,bytecnt));
}
/* flashewrite():
* Use the device-specific function pointer to call the routine
* relocated to RAM space.
*/
int
flashewrite(struct flashinfo *fdev,uchar *dest,uchar *src,long bytecnt)
{
int i;
/* Source and destination addresses must be long-aligned. */
if (((int)src & 3) || ((int)dest & 3))
return(-1);
/* If the protection window is closed, then verify that no protected
* sectors will be written over...
*/
if (FlashProtectWindow == FLASH_PROTECT_WINDOW_CLOSED) {
for (i=0;i<fdev->sectorcnt;i++) {
if((((uchar *)dest) > (fdev->sectors[i].end)) ||
(((uchar *)dest+bytecnt) < (fdev->sectors[i].begin)))
continue;
else
if (fdev->sectors[i].protected)
return(-1);
}
}
return(fdev->flewrite(fdev,dest,src,bytecnt));
}
/* addrtosector():
* Incoming address is translated to sector number, size of sector
* and base of sector.
* Return 0 if successful; else -1.
*/
int
addrtosector(uchar *addr,int *sector,int *size,uchar **base)
{
struct flashinfo *fbnk;
struct sectorinfo *sinfo;
int dev, sec, i;
sec = 0;
for(dev=0;dev<FLASHBANKS;dev++) {
fbnk = &FlashBank[dev];
for(i=0;i<fbnk->sectorcnt;i++,sec++) {
sinfo = &fbnk->sectors[i];
if ((addr >= sinfo->begin) && (addr <= sinfo->end)) {
if (sector) {
*sector = sec;
}
if (base) {
*base = sinfo->begin;
}
if (size) {
*size = sinfo->size;
}
return(0);
}
}
}
printf("addrtosector(0x%lx) failed\n",(ulong)addr);
return(-1);
}
/* addrtobank():
* From the incoming address, return a pointer to the flash bank that
* this address is within.
*/
struct flashinfo *
addrtobank(uchar *addr)
{
struct flashinfo *fbnk;
int dev;
for(dev=0;dev<FLASHBANKS;dev++) {
fbnk = &FlashBank[dev];
if ((addr >= fbnk->base) && (addr <= fbnk->end))
return(fbnk);
}
printf("addrtobank(0x%lx) failed\n",(ulong)addr);
return(0);
}
int
sectortoaddr(int sector,int *size,uchar **base)
{
struct flashinfo *fbnk;
struct sectorinfo *sinfo;
int dev, sec, i;
sec = 0;
for(dev=0;dev<FLASHBANKS;dev++) {
fbnk = &FlashBank[dev];
for(i=0;i<fbnk->sectorcnt;i++,sec++) {
if (sec == sector) {
sinfo = &fbnk->sectors[i];
if (base) *base = sinfo->begin;
if (size) *size = sinfo->size;
return(0);
}
}
}
printf("sectortoaddr(%d) failed\n",sector);
return(-1);
}
/* flashbankinfo():
* Based on the incoming bank number, return the beginning, end and
* number of sectors within that bank.
*/
int
flashbankinfo(int bank,uchar **begin,uchar **end,int *sectorcnt)
{
struct flashinfo *fbnk;
if (bank >= FLASHBANKS)
return(-1);
fbnk = &FlashBank[bank];
if (begin)
*begin = fbnk->base;
if (end)
*end = fbnk->end;
if (sectorcnt)
*sectorcnt = fbnk->sectorcnt;
return(0);
}
/* lastlargesector():
* Incoming bank number is used to populate the sector information
* (sector number, sector size and address) of the last large sector
* in the specified bank.
* Return 0 if successful; else -1.
*/
int
lastlargesector(int bank,int *sector,int *size,uchar **base)
{
struct flashinfo *fbnk;
struct sectorinfo *sinfo;
uchar *largest_sbase;
int i, largest_ssize, largest_snum;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -