/************************************************************************** * * Copyright (c) 2013 Alcatel-Lucent * * Alcatel Lucent licenses this file to You under the Apache License, * Version 2.0 (the "License"); you may not use this file except in * compliance with the License. A copy of the License is contained the * file LICENSE at the top level of this repository. * You may also obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ************************************************************************** * * 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. * * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) * */ #include "config.h" #include "genlib.h" #if INCLUDE_FLASH #include "cpu.h" #include "flash.h" #include #include "stddefs.h" #include "tfs.h" #include "tfsprivate.h" #include "cli.h" extern struct flashdesc FlashNamId[]; int FlashTrace; int FlashCurrentBank; 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_INTSDECL unsigned long oints #define FLASH_INTSOFF() oints = intsoff() #define FLASH_INTSRESTORE(ival) intsrestore(oints) #else #define FLASH_INTSDECL #define FLASH_INTSOFF() #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 *devrange) { uchar *base; struct sectorinfo *sp; struct flashinfo *fdev; char *range, varname[32]; int first_sector_of_device, devtot; int locksupported, sector, lastsector, hdrprinted; devtot = 0; hdrprinted = 0; lastsector = lastflashsector(); /* An incoming NULL range implies "any" sector... */ if (devrange == 0) { showflashtotal(); range = "any"; } else { range = devrange; } /* Loop through all sectors on all devices, picking only those * sectors that fall in the specified range. */ for(sector = 0; sector <= lastsector; sector++) { if (gotachar()) { getchar(); printf("\n"); break; } if (!inRange(range,sector)) continue; if (!(fdev = snumtofdev(sector))) 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 (devrange == 0) { sprintf(varname,"FLASH_BASE_%d",devtot); shell_sprintf(varname,"0x%lx",(ulong)(fdev->base)); sprintf(varname,"FLASH_SCNT_%d",devtot); shell_sprintf(varname,"%d",fdev->sectorcnt); sprintf(varname,"FLASH_END_%d",devtot); shell_sprintf(varname,"0x%lx",(ulong)(fdev->end)); } devtot++; } if (!hdrprinted) { printf(" Sctr TFS? Begin End Size %s %s%s", "SWProt?", "Erased?", 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 %c 0x%08lx 0x%08lx 0x%06lx %s %s ", sp->snum, tfsspace((char *)base) ? '*' : ' ', (ulong)(sp->begin), (ulong)(sp->end), sp->size, sp->protected ? "yes" : " no", flasherased(sp->begin,sp->end) ? "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"); } } if (devrange == 0) shell_sprintf("FLASH_DEVTOT","%d",devtot); return(0); } #ifdef FLASH_COPY_TO_RAM /* 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) { /* Some CPUs have 16bit opcodes and can only do aligned accesses. */ unsigned short *sBegin = (unsigned short *)begin; unsigned short *sEnd = (unsigned short *)end; unsigned short *sCopy = (unsigned short *)copy; /* 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); /* Copy function() to RAM, then verify: */ while(sBegin < sEnd) { *sCopy = *sBegin; if (*sCopy++ != *sBegin++) { printf("flashopload failed\n"); return(-1); } } return(0); } #endif /* flashtype(): * Use the device-specific function pointer to call the routine * relocated to RAM space. */ int flashtype(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. * 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); if (!(fdev = snumtofdev(snum))) return(-1); /* If the device type is RAM, the erase is a bit different... */ if (fdev->id == FLASHRAM) { // Use 'tmp' here to eliminate a 3.4 toolset warning. sectortoaddr(snum,&size,&tmp); base = (ulong *)tmp; end = base + (size/sizeof(long)); while(base < end) { *base = 0xffffffff; if (*base != 0xffffffff) return(-1); base++; } 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. */ dev_snum = snum - fdev->sectors[0].snum; sinfo = &fdev->sectors[dev_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,dev_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); 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; 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;jsectorcnt;j++) { if ((dp >= fdev->sectors[j].begin) && (dp <= fdev->sectors[j].end)) lowsector = j; } for(j=0;jsectorcnt;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); } } /* 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(0x%lx) failed: bit 0->1 rqst denied.\n", (long)dp); return(-1); } dp++; sp++; WATCHDOG_MACRO; } 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... */ if (memcmp((char *)dest,(char *)src,(int)bytecnt) != 0) { printf("flashwrite() post-verify failed.\n"); return(-1); } 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;isectorcnt;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= fbnk->sectors[0].snum) && (snum <= fbnk->sectors[fbnk->sectorcnt-1].snum)) return(fbnk); } printf("snumtofdev(%d) failed\n",snum); 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; sec = 0; fbnk = FlashBank; for(dev=0;devsectorcnt;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; fbnk = FlashBank; for(dev=0;dev= 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; fbnk = FlashBank; for(dev=0;devsectorcnt;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); } /* InFlashSpace(): * Return 1 if the block of memory is within flash space; * else return 0. */ int InFlashSpace(uchar *begin, int size) { int dev; uchar *end; struct flashinfo *fbnk; end = begin+size; fbnk = FlashBank; for(dev=0;dev= fbnk->base) && (begin <= fbnk->end)) || ((end >= fbnk->base) && (end <= fbnk->end))) return(1); } return(0); } /* 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. * * from_addr defines the search start address: * * from_addr = 0 means start from the first sector; * * from_addr MUST be sector aligned. * * sectorcnt defines the numbers of contiguous sectors to search across; * * sectorcnt = 0 means search to the last sector. * Return 0 if successful; else -1. */ int lastlargesector(int bank, uchar *from_addr, int sectorcnt, int *sector, int *size, uchar **base) { struct flashinfo *fbnk; struct sectorinfo *sinfo; uchar *largest_sbase; int i, from_sector, to_sector, largest_ssize, largest_snum; if (bank >= FLASHBANKS) { printf("lastlargesector(%d) failed\n",bank); return(-1); } fbnk = &FlashBank[bank]; largest_ssize = 0; largest_snum = 0; largest_sbase = (uchar *)0; if (from_addr) { if (addrtosector(from_addr, &from_sector, 0, 0) == -1) return(-1); if (fbnk->sectors[from_sector].begin != from_addr) { printf("lastlargesector failed:\n" " parameter from_addr (%0x08X) must be sector aligned\n", from_addr); return(-1); } } else { from_sector = 0; } to_sector = from_sector + sectorcnt - 1; if (to_sector > fbnk->sectorcnt - 1) { to_sector = fbnk->sectorcnt - 1; } //printf("from_addr = 0x%08X\n", from_addr); //printf("from_sector = %d\n", from_sector); //printf("to_sector = %d\n", to_sector); sinfo = &fbnk->sectors[from_sector]; for(i=from_sector; i<=to_sector; i++, sinfo++) { if (sinfo->size >= largest_ssize) { largest_ssize = sinfo->size; largest_snum = sinfo->snum; largest_sbase = sinfo->begin; } } //printf("largest_sbase = 0x%08X\n", largest_sbase); //printf("largest_snum = %d\n", largest_snum); //printf("largest_ssize = 0x%08X\n", largest_ssize); if (sector) *sector = largest_snum; if (size) *size = largest_ssize; if (base) *base = largest_sbase; return(0); } void LowerFlashProtectWindow() { if (FlashProtectWindow) FlashProtectWindow--; } /* AppFlashWrite(): * Takes in a source, destination and byte count and converts that to * the appropriate flashwrite() call. This function supports the possibility * of having one write request span across multiple devices in contiguous * memory space. */ int AppFlashWrite(uchar *dest,uchar *src,long bytecnt) { int ret; FLASH_INTSDECL; long tmpcnt; struct flashinfo *fbnk; ret = 0; while(bytecnt > 0) { fbnk = addrtobank((uchar *)dest); if (!fbnk) return(-1); if ((dest + bytecnt) <= fbnk->end) tmpcnt = bytecnt; else tmpcnt = (fbnk->end - dest) + 1; FLASH_INTSOFF(); ret = flashwrite(fbnk,dest,src,tmpcnt); FLASH_INTSRESTORE(); if (ret < 0) { printf("AppFlashWrite(0x%lx,0x%lx,%ld) failed (%d)\n", (ulong)dest,(ulong)src,bytecnt,ret); break; } src += tmpcnt; dest += tmpcnt; bytecnt -= tmpcnt; } return(ret); } #if INCLUDE_FLASHREAD /* flashread(): * Use the device-specific function pointer to call the routine * relocated to RAM space. * First make a few checks on the request, then read from flash * if the checks succeed. */ int flashread(struct flashinfo *fdev,uchar *dest,uchar *src,long bytecnt) { int 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); 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; 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: dest out of flash range\n"); return(-1); } 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... */ if (memcmp((char *)dest,(char *)src,(int)bytecnt) != 0) { printf("flashread() post-verify failed.\n"); return(-1); } return(0); } /* AppFlashRead(): * Takes in a source, destination and byte count and converts that to * the appropriate flashwrite() call. This function supports the possibility * of having one write request span across multiple devices in contiguous * memory space. */ int AppFlashRead(uchar *dest,uchar *src,long bytecnt) { int ret; FLASH_INTSDECL; long tmpcnt; struct flashinfo *fbnk; ret = 0; while(bytecnt > 0) { fbnk = addrtobank((uchar *)dest); if (!fbnk) return(-1); if ((dest + bytecnt) <= fbnk->end) tmpcnt = bytecnt; else tmpcnt = (fbnk->end - dest) + 1; FLASH_INTSOFF(); ret = flashread(fbnk,dest,src,tmpcnt); FLASH_INTSRESTORE(); if (ret < 0) { printf("AppFlashRead(0x%lx,0x%lx,%ld) failed (%d)\n", (ulong)dest,(ulong)src,bytecnt,ret); break; } src += tmpcnt; dest += tmpcnt; bytecnt -= tmpcnt; } return(ret); } #endif int lastflashsector(void) { int lastsnum; struct flashinfo *lastfbnk; lastfbnk = &FlashBank[FLASHBANKS-1]; lastsnum = lastfbnk->sectors[lastfbnk->sectorcnt-1].snum; return(lastsnum); } int AppFlashEraseAll() { FLASH_INTSDECL; int ret, snum, lastsnum; ret = 0; FLASH_INTSOFF(); /* Loop through all sectors of all banks... */ lastsnum = lastflashsector(); for(snum=0;snum<=lastsnum;snum++) { WATCHDOG_MACRO; ret = flasherase(snum); if (ret <= 0) break; } FLASH_INTSRESTORE(); return(ret); } /* Erase the flash sector specified. */ int AppFlashErase(int snum) /* erase specified sector */ { int ret; FLASH_INTSDECL; FLASH_INTSOFF(); ret = flasherase(snum); FLASH_INTSRESTORE(); return(ret); } /* sectorProtect(): * Set or clear (based on value of protect) the protected flag for the * specified range of sectors... * This supports incoming ranges that can be dash and/or comma delimited. * For example a range can be "0", "0-3", or "0,2-4", etc... */ int sectorProtect(char *range, int protect) { struct flashinfo *fbnk; int i, dev, snum; snum = 0; for(dev = 0;dev < FLASHBANKS;dev++) { fbnk = &FlashBank[dev]; for(i = 0;i < fbnk->sectorcnt;i++,snum++) { if ((range == 0) || (*range == 0) || inRange(range,snum)) fbnk->sectors[i].protected = protect; } } return(0); } #ifdef FLASHRAM_BASE struct sectorinfo sinfoRAM[FLASHRAM_SECTORCOUNT]; /* FlashRamInit(): * This monitor supports TFS space allocated across multiple flash devices * that may not be in contiguous memory space. To allow RAM to be seen * as a "flash-like" device to TFS, we set it up in sectors similar to * those in a real flash device. * Input... * snum: All the "flash" space is broken up into individual sectors. * This is the starting sector number that is to be used for * the block of sectors within this RAM space. * fbnk: Pointer to the structure that must be populated with the * flash bank information. Usually this contains pointers to the * functions that operate on the flash; but for RAM they aren't * necessary. * sinfo: Table populated with the characteristics (size, start, etc...) * of each sector. * ssizes: A table containing the size of each of the sectors. This is * copied to the sinfo space. If this pointer is NULL, then * this function sets all sector sizes to FLASHRAM_SECTORSIZE. */ int FlashRamInit(int snum, int scnt, struct flashinfo *fbnk, struct sectorinfo *sinfo, int *ssizes) { int i; uchar *begin; /* FLASHRAM_SECTORCOUNT (in config.h) must match the number of sectors * allocated to the flash ram device in flashdev.c... */ if (scnt != FLASHRAM_SECTORCOUNT) printf("Warning: flashram sector count inconsistency\n"); fbnk->id = FLASHRAM; /* Device id. */ fbnk->base = (uchar *)FLASHRAM_BASE; /* Base address of bank. */ fbnk->end = (uchar *)FLASHRAM_END; /* End address of bank. */ fbnk->sectorcnt = scnt; /* Number of sectors. */ fbnk->width = 1; /* Width (in bytes). */ fbnk->fltype = FlashOpNotSupported; /* Flashtype() function. */ fbnk->flerase = FlashOpNotSupported; /* Flasherase() function. */ fbnk->flwrite = FlashOpNotSupported; /* Flashwrite() function. */ fbnk->flewrite = FlashOpNotSupported; /* Flashewrite() function. */ fbnk->fllock = FlashOpNotSupported; /* Flashlock() function. */ fbnk->sectors = sinfo; /* Ptr to sector size table. */ begin = fbnk->base; for(i=0;isectorcnt;i++,snum++) { sinfo[i].snum = snum; if (ssizes == 0) sinfo[i].size = FLASHRAM_SECTORSIZE; else sinfo[i].size = ssizes[i]; sinfo[i].begin = begin; sinfo[i].end = sinfo[i].begin + sinfo[i].size - 1; sinfo[i].protected = 0; begin += sinfo[i].size; } return(snum); } #endif char *FlashHelp[] = { "Flash memory operations", "{op} [args]", #if INCLUDE_VERBOSEHELP "Ops...", " opw", " init", " type", " bank [#]", " prot {rnge}", " info [rnge]", " unprot {rnge}", " lock {rnge}", " unlock [rnge]", " lockdwn {rnge}", " erase {rnge}", " trace {lvl}", " write {dest} {src} {byte_cnt}", " ewrite {dest} {src} {byte_cnt}", "", " rnge = range of affected sectors", " Range syntax examples: <1> <1-5> <1,3,7> ", #endif 0, }; /* FlashCmd(): * Code that handles the user interface. See FlashHelp[] below for usage. */ int FlashCmd(int argc,char *argv[]) { int ret; FLASH_INTSDECL; ulong dest, src; long bytecnt, rslt; struct flashinfo *fbnk; FLASH_INTSOFF(); fbnk = &FlashBank[FlashCurrentBank]; ret = CMD_SUCCESS; if (strcmp(argv[1],"init") == 0) FlashInit(); else if (strcmp(argv[1],"info") == 0) { showflashinfo(argv[2]); } else if (strcmp(argv[1],"type") == 0) { showflashtype((ulong)flashtype(fbnk),1); } else if (strcmp(argv[1],"trace") == 0) { if (argc == 3) FlashTrace = atoi(argv[2]); else if (argc == 2) printf("Flash trace lvl: %d\n",FlashTrace); else return(CMD_PARAM_ERROR); } else if (strcmp(argv[1],"bank") == 0) { int tmpbank; if (argc == 3) { tmpbank = atoi(argv[2]); if (tmpbank < FLASHBANKS) { FlashCurrentBank = tmpbank; } else { printf("Bank %d out of range\n",tmpbank); return(CMD_PARAM_ERROR); } printf("Subsequent flash ops apply to bank %d\n", FlashCurrentBank); } else { showflashtotal(); } } else if (strcmp(argv[1],"ewrite") == 0) { if (argc == 5) { dest = strtoul(argv[2],(char **)0,0); src = strtoul(argv[3],(char **)0,0); bytecnt = (long)strtoul(argv[4],(char **)0,0); rslt = flashewrite((uchar *)dest,(uchar *)src,bytecnt); if (rslt < 0) { printf("ewrite failed (%ld)\n",rslt); ret = CMD_FAILURE; } } else ret = CMD_PARAM_ERROR; } else if (!strcmp(argv[1],"write")) { if (argc == 5) { dest = strtoul(argv[2],(char **)0,0); src = strtoul(argv[3],(char **)0,0); bytecnt = (long)strtoul(argv[4],(char **)0,0); rslt = AppFlashWrite((uchar *)dest,(uchar *)src,bytecnt); if (rslt < 0) { printf("Write failed (%ld)\n",rslt); ret = CMD_FAILURE; } } else ret = CMD_PARAM_ERROR; } #if INCLUDE_FLASHREAD else if (!strcmp(argv[1],"read")) { if (argc == 5) { dest = strtoul(argv[2],(char **)0,0); src = strtoul(argv[3],(char **)0,0); bytecnt = (long)strtoul(argv[4],(char **)0,0); rslt = AppFlashRead((uchar *)dest,(uchar *)src,bytecnt); if (rslt < 0) { printf("Read failed (%ld)\n",rslt); ret = CMD_FAILURE; } } else ret = CMD_PARAM_ERROR; } #endif else if (!strcmp(argv[1],"opw")) { if (getUsrLvl() != MAXUSRLEVEL) printf("Must be user level %d\n",MAXUSRLEVEL); else FlashProtectWindow = 2; } else if (!strcmp(argv[1],"unprot")) { if (argc != 3) ret = CMD_PARAM_ERROR; else sectorProtect(argv[2],0); } else if (!strcmp(argv[1],"prot")) { if (argc != 3) ret = CMD_PARAM_ERROR; else sectorProtect(argv[2],1); } else if (!strcmp(argv[1],"erase")) { if (argc != 3) { ret = CMD_PARAM_ERROR; } else { uchar *base; int rc, snum, size, stot = 0; if (strncmp(argv[2],"0x",2) == 0) { ulong begin, end; char *dash = strchr(argv[2],'-'); begin = end = strtoul(argv[2],0,0); if (dash) end = strtoul(dash+1,0,0); while(begin <= end) { if (addrtosector((uchar *)begin,&snum,&size,&base) < 0) break; begin = (ulong)base; rc = flasherase(snum); if (rc != 1) { printf("Erase failed (%d)\n",rc); ret = CMD_FAILURE; break; } stot++; begin += size; } } else { int last; last = lastflashsector(); for(snum=0;snum<=last;snum++) { int rc; if ((argv[2] == 0) || inRange(argv[2],snum)) { ticktock(); rc = flasherase(snum); if (rc != 1) { printf("Erase failed (%d)\n",rc); ret = CMD_FAILURE; break; } stot++; } } } printf("%d sectors erased\n",stot); } } else if ((!strcmp(argv[1],"lock")) || (!strcmp(argv[1],"unlock")) || (!strcmp(argv[1],"lockdwn"))) { int operation, snum; if (!strcmp(argv[1],"lock")) operation = FLASH_LOCK; else if (!strcmp(argv[1],"unlock")) operation = FLASH_UNLOCK; else operation = FLASH_LOCKDWN; if (argc == 2) { #ifdef FLASH_PROTECT_RANGE argv[2] = FLASH_PROTECT_RANGE; argc = 3; printf("Applying %s to sector(s) %s...\n",argv[1],argv[2]); #else printf("Monitor not built with specified protection range\n"); ret = CMD_FAILURE; #endif } if (argc != 3) { ret = CMD_PARAM_ERROR; } else { int last; struct flashinfo *fdev; last = lastflashsector(); for(snum=0;snum<=last;snum++) { if (inRange(argv[2],snum)) { ticktock(); if ((fdev = snumtofdev(snum)) == 0) { ret = CMD_FAILURE; break; } if (flashlock(fdev->sectors[0].snum,FLASH_LOCKABLE) <= 0) { printf("Sector %d does not support %s\n",snum,argv[1]); ret = CMD_FAILURE; break; } rslt = flashlock(snum,operation); if (rslt < 0) { printf("%s failed (%ld) at sector %d\n", argv[1],rslt,snum); ret = CMD_FAILURE; break; } } } } } else { ret = CMD_PARAM_ERROR; } FLASH_INTSRESTORE(); return(ret); } /* FlashOpOverride(): * This function is used by monlib to provide the application with the * ability to override the underlying flash operations with functions * provided by the application. * The finfo parameter is actually a flashinfo pointer; set void here * to eliminate confusion when used with monlib.h and the application . */ int FlashOpOverride(void *finfo, int get, int bank) { char *src, *dst; struct flashinfo *fdev; if ((!finfo) || (bank >= FLASHBANKS)) return(-1); fdev = &FlashBank[bank]; if (get) { src = (char *)fdev; dst = (char *)finfo; } else { src = (char *)finfo; dst = (char *)fdev; } memcpy(dst,src,sizeof(struct flashinfo)); return(0); } int FlashOpNotSupported(void) { if (FlashTrace) printf("flash operation not supported\n"); return(-1); } /* Used as a placeholder for the flash drivers that don't * support flash lock... */ int FlashLockNotSupported(struct flashinfo *fdev,int snum,int operation) { if (operation == FLASH_LOCKABLE) return(0); else return(-1); } #endif /* 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(unsigned char *begin, unsigned char *end) { unsigned long *lp, *lp1, ltmp; /* 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); } /* Get pointers aligned so that we can do the bulk of the comparison * with long pointers... */ while(((long)begin & 3) && (begin <= end)) { if (*begin != 0xff) return(0); begin++; } if (begin > end) return(1); lp = (unsigned long *)begin; ltmp = (unsigned long)end; ltmp &= ~3; lp1 = (unsigned long *)ltmp; while(lp != lp1) { if (*lp != 0xffffffff) return(0); lp++; #ifdef WATCHDOG_ENABLED /* For each 64K through this loop, tickle the watchdog. */ if ((0xffff & (unsigned long)lp) == 0) { WATCHDOG_MACRO; } #endif } if (lp > (unsigned long *)end) return(1); begin = (unsigned char *)lp; do { if (*begin != 0xff) return(0); } while(begin++ != end); return(*end == 0xff); }