📄 flash.c
字号:
/* flash.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.
*
* Note1: the majority of this code was edited with 4-space tabs.
* Note2: as more and more contributions are accepted, the term "author"
* is becoming a mis-representation of credit.
*
* Original author: Ed Sutter
* Email: esutter@lucent.com
* Phone: 908-582-2351
*/
#include "config.h"
#if INCLUDE_FLASH
#include "cpu.h"
#include "flash.h"
#include "genlib.h"
#include "ctype.h"
#include "stddefs.h"
#include "tfs.h"
#include "tfsprivate.h"
#include "cli.h"
extern struct flashdesc FlashNamId[];
int FlashTrace = 1;
int FlashCurrentBank;
char *boot_device_name;
int sectortoaddr(int,int *,uchar **);
#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.
*/
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
/* showlockop():
* Return a string that verbosely represents the flash lock
* operation...
*/
char *
showlockop(int operation)
{
switch(operation) {
case FLASH_LOCK:
return("lock");
case FLASH_UNLOCK:
return("unlock");
case FLASH_LOCKDWN:
return("lock_down");
case FLASH_LOCKQRY:
return("lock_qry");
case FLASH_LOCKABLE:
return("lockable");
default:
return("???");
}
}
/* 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, int showid)
{
struct flashdesc *fdp;
if (showid)
printf("Flash ID: 0x%lx\n",id);
fdp = FlashNamId;
while(fdp->desc) {
if (id == fdp->id) {
printf("Device = %s\n",fdp->desc);
return(0);
}
fdp++;
}
if (id == FLASHRAM) {
printf("Device = FLASH-RAM\n");
return(0);
}
printf("Flash id 0x%lx not recognized\n",id);
return(-1);
}
void
showflashtotal(void)
{
#if FLASHBANKS > 1
printf("Total of %d banks (0-%d), current default bank: %d\n",
FLASHBANKS,FLASHBANKS-1,FlashCurrentBank);
#else
printf("Current flash bank: 0\n");
#endif
}
/* showflashinfo():
* Dump information about specified flash device.
*/
int
showflashinfo(char *range)
{
uchar *base;
struct sectorinfo *sp;
struct flashinfo *fdev;
int first_sector_of_device;
int rc, locksupported, sector, lastsector, hdrprinted;
rc = 0;
hdrprinted = 0;
lastsector = lastflashsector();
/* An incoming NULL range implies "any" sector...
*/
if (range == 0) {
showflashtotal();
range = "any";
}
/* Loop through all sectors on all devices, picking only those
* sectors that fall in the specified range.
*/
for(sector = 0; sector <= lastsector; sector++) {
if (!inRange(range,sector))
continue;
//if (!(fdev = snumtofdev(sector)))
if (!(fdev = nametofdev(boot_device_name)))
return(-1);
first_sector_of_device = fdev->sectors[0].snum;
if (flashlock(first_sector_of_device,FLASH_LOCKABLE) > 0)
locksupported = 1;
else
locksupported = 0;
/* If sector is first sector of a device, then print
* device info also...
*/
if ((sector == first_sector_of_device) && (!strcmp(range,"any"))) {
if (showflashtype(fdev->id,0) < 0)
return(-1);
printf(" Bank width : %d\n",fdev->width);
printf(" Sectors : %d\n",fdev->sectorcnt);
printf(" Base addr : 0x%08lx\n",(ulong)(fdev->base));
hdrprinted = 0;
}
if (!hdrprinted) {
printf(" Sctno Begin End Size %s %s",
"SWProt?",locksupported ? " Locked?\n" : "\n");
hdrprinted = 1;
}
sp = &fdev->sectors[sector - first_sector_of_device];
sectortoaddr(sp->snum,0,base);
if ((range == 0) || inRange(range,sp->snum)) {
printf(" %3d 0x%08lx 0x%08lx 0x%06lx %s",
sp->snum,
(ulong)(sp->begin), (ulong)(sp->end), sp->size,
sp->protected ? "yes" : " no");
if (locksupported) {
switch(flashlock(sp->snum,FLASH_LOCKQRY)) {
case -1:
printf("???");
break;
case 1:
printf("yes");
break;
case 0:
printf(" no");
break;
}
}
printf("\n");
}
}
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);
}
/* Initially fill the copy space with 0xff so that the space
* remaining is viewable...
*/
memset((char *)copy,0xff,size);
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(struct flashinfo *fdev)
{
return(fdev->fltype(fdev));
}
/* flasherased():
* Return 1 if range of memory is all 0xff; else 0.
* Scan through the range of memory specified by begin-end (inclusive)
* looking for anything that is not 0xff. Do this in three sections so
* that the pointers can be 4-byte aligned for the bulk of the comparison
* range...
* The beginning steps through as a char pointer until aligned on a 4-byte
* boundary. Then do ulong * comparisons until the just before the end
* where we once again use char pointers to align on the last few
* non-aligned bytes (if any).
*/
int
flasherased(uchar *begin, uchar *end)
{
ulong *lp, *lp1, ltmp;
uchar *data;
/* If begin is greater than end, the range is illegal. The only
* exception to this is the case where end may be zero. This is
* considered an exception because in cases where we are dealing
* with the last sector of a device that sits at the end of memory
* space, the end point will wrap.
*/
if ((begin > end) && (end != 0)) {
printf("flasherased(): bad range\n");
return(0);
}
WATCHDOG_MACRO;
/* Get pointers aligned so that we can do the bulk of the comparison
* with long pointers...
*/
while(((long)(begin) & 3) && (begin <= end)) {
//NorFlashRdData(begin,data,1);
if (*data != 0xff)
return(0);
begin++;
}
if (begin > end)
return(1);
lp = (ulong *)begin;
ltmp = (ulong)end;
ltmp &= ~3;
lp1 = (ulong *)ltmp;
while(lp != lp1) {
if (*lp != 0xffffffff)
return(0);
lp++;
}
if (lp > (ulong *)end)
return(1);
begin = (uchar *)lp;
do {
if (*begin != 0xff)
return(0);
} while(begin++ != end);
return(*end == 0xff);
}
/* 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.
* Return...
* 1 if successful
* -1 if failure
* 0 if sector is protected or locked
*/
int
flasherase(int snum)
{
uchar *tmp;
ulong *base, *end;
int size, rc, dev_snum;
struct flashinfo *fdev;
struct sectorinfo *sinfo;
if (FlashTrace)
printf("flasherase(%d)\n",snum);
//printf("deveice name : %s\n",);
if (!(fdev = nametofdev(boot_device_name)))
return(-1);
/* If the sector is soft-protected or locked, return negative
* and print failure. If the sector is already erased, then
* there is no need to issue the device-specific erase algorithm.
*/
if(snum > fdev->sectorcnt)
{
printf("sector number out of range!\n");
return -1;
}
//dev_snum = snum - fdev->sectors[0].snum;
sinfo = &fdev->sectors[snum];
//if (!flasherased(sinfo->begin,sinfo->end)) {
if ((!FlashProtectWindow) && (sinfo->protected)) {
printf("Sector %d protected\n",snum);
return(0);
}
if (flashlocked(snum,1))
return(0);
rc = fdev->flerase(fdev,snum);
if (rc < 0)
return(rc);
//}
return(1);
}
/* 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, rc, first_sector_of_device;
register uchar *dp, *sp, *edp;
if (FlashTrace)
printf("flashwrite(0x%lx,0x%lx,%ld)\n",(long)dest,(long)src,bytecnt);
dp = dest;
sp = src;
edp = (dest + bytecnt) - 1;
first_sector_of_device = fdev->sectors[0].snum;
// 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 or locked...
//
for(j=lowsector;j<=highsector;j++) {
if (fdev->sectors[j].protected) {
printf("flashwrite() failed: sector protected\n");
return(-1);
}
if (flashlocked(j+first_sector_of_device,1))
return(-1);
}
}
rc = fdev->flwrite(fdev,dest,src,bytecnt);
if (rc < 0)
return(rc);
// Assuming everything else appears to have passed, make sure the
// source and destination addresses match...
return(0);
}
/* flashread():
* 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
flashread(struct flashinfo *fdev,uchar *dest,uchar *src,long bytecnt)
{
int j, lowsector, highsector, rc, first_sector_of_device;
register uchar *dp, *sp, *edp;
if (FlashTrace)
printf("flashread(0x%lx,0x%lx,%ld)\n",(long)dest,(long)src,bytecnt);
dp = src;
sp = dest;
edp = (src + bytecnt) - 1;
first_sector_of_device = fdev->sectors[0].snum;
// If outside the devices space, return failed..
if ((edp < fdev->sectors[0].begin) ||
(dp > fdev->sectors[fdev->sectorcnt-1].end)) {
printf("flashread() failed: srcout of flash range\n");
return(-1);
}
// Make sure the destination is not within a protected sector
printf("flashread :%s\n",fdev->device_name);
rc = fdev->flread(fdev,dest,src,bytecnt);
if (rc < 0)
return(rc);
// Assuming everything else appears to have passed, make sure the
// source and destination addresses match...
return(0);
}
/* flashewrite():
* Use the device-specific function pointer to call the routine
* relocated to RAM space.
*/
int
flashewrite(uchar *dest,uchar *src,long bytecnt)
{
int i;
struct flashinfo *fdev;
if (FlashTrace)
printf("flashwrite(0x%lx,0x%lx,%ld)\n",(long)dest,(long)src,bytecnt);
if ((fdev = addrtobank(dest)) == 0)
return(-1);
/* 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));
}
/* flashlock():
Use a function pointer to call the routine relocated to RAM space.
*/
int
flashlock(int snum,int operation)
{
int dev_snum;
struct flashinfo *fdev;
if (FlashTrace)
printf("flashlock(%d,%s)\n",snum,showlockop(operation));
fdev = snumtofdev(snum);
dev_snum = snum - fdev->sectors[0].snum;
return(fdev->fllock(fdev,dev_snum,operation));
}
int
flashlocked(int snum, int verbose)
{
if ((flashlock(snum,FLASH_LOCKABLE) > 0) &&
(flashlock(snum,FLASH_LOCKQRY) == 1)) {
if (verbose)
printf("Sector %d locked\n",snum);
return(1);
}
return(0);
}
/* snumtofdev():
* Return the flash device pointer that corresponds to the incoming
* sector number.
*/
struct flashinfo *
snumtofdev(int snum)
{
int dev;
struct flashinfo *fbnk;
fbnk = FlashBank;
for(dev=0;dev<FLASHBANKS;dev++,fbnk++) {
if ((snum >= fbnk->sectors[0].snum) &&
(snum <= fbnk->sectors[fbnk->sectorcnt-1].snum))
return(fbnk);
}
printf("snumtfdev(%d) failed\n",snum);
return(0);
}
/* snumtofdev():
* Return the flash device pointer that corresponds to the incoming
* sector number.
*/
struct flashinfo *
nametofdev(char *device_name)
{
int dev;
struct flashinfo *fbnk;
fbnk = FlashBank;
for(dev=0;dev<FLASHBANKS;dev++,fbnk++) {
if(strcmp(fbnk->device_name,device_name) == 0)
{
//printf("namettodev(%s) get bank,%s\n",device_name,fbnk->device_name);
return(fbnk);
}
}
printf("namettodev(%s) failed,no this device\n",device_name);
return(0);
}
/* 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;
fbnk = FlashBank;
sec = 0;
for(dev=0;dev<FLASHBANKS;dev++,fbnk++) {
for(i=0;i<fbnk->sectorcnt;i++,sec++) {
sinfo = &fbnk->sectors[i];
if ((addr >= sinfo->begin) && (addr <= sinfo->end)) {
if (sector) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -