| ||
At this point, the portions of the flash device driver that directly touch the flash are copied to RAM so that the system can still execute out of the 29F040 while performing flash operations. However, the lowest level functions, FlashWrite040() and FlashErase040() , are device-dependent. I need to add another layer before I start allowing the rest of the system to use this functionality. I need a front end that allows me to write to any flash device using an interface similar to memcpy () (i.e., source and destination plus a size ). For erasure, I need the ability to call a function and specify the sector I wish to erase. This function eliminates the need for the higher-level code to know about the specific flash device.
At the command line, flash memory is manipulated with the flash command. This section explains how this command can manipulate the flash memory without knowing any device specifics.
int FlashCmd(int argc,char *argv[]) { int ret; ulong dest, src, oints; long bytecnt, rslt; struct flashinfo *fbnk; fbnk = &FlashBank[FlashCurrentBank]; ret = CMD_SUCCESS; if (strcmp(argv[1],"bank") == 0) { int tmpbank; if (argc == 3) { tmpbank = atoi(argv[2]); if (tmpbank < FLASHBANKS) FlashCurrentBank = tmpbank; printf("Subsequent flash ops apply to bank %d\n", FlashCurrentBank); } else printf("Current flash bank: %d\n",FlashCurrentBank); } 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((ulong *)dest,(ulong *)src,bytecnt); if (rslt == -1) printf("Write failed\n"); } else ret = CMD_PARAM_ERROR; } else if (!strcmp(argv[1],"opw")) { FlashProtectWindow = 2; } else { ret = CMD_PARAM_ERROR; } return(ret); }
The format for the flash command i flash {command} [args based on command]
For example flash write 0x1000 0xfff80000 128
copies 128 bytes from 0xfff80000 to the flash destination of 0x1000 . Theres nothing fancy here. This command doesnt take any options (see Listing 6.8), so getopt() is not used. The content of FlashCurrentBank points to the appropriate bank. Based on the earlier discussion, we know the 29F040-based target has only one bank, but multiples can be supported by increasing the size of the FlashBank[] array to the number of banks in the system. Listing 6.8 also shows how the FlashProtectWindow variable gets set so that the other flash operations that might be software protected can run. The most important thing to notice in FlashCMD() is the call to AppFlashWrite() .
The AppFlashWrite() function (in Listing 6.9) is used to abstract the characteristics of the flash memory. Notice that no device-specific information is passed to this function; hence, the caller is unaware of the underlying flash device characteristics.
int AppFlashWrite(uchar *dest,uchar *src, long bytecnt) { struct flashinfo *fbnk; int ret; long tmpcnt; ret = 0; while(bytecnt > 0) { fbnk = addrtobank(dest); if (!fbnk) return(-1); if (((int)dest + bytecnt) <= (int)(fbnk->end)) tmpcnt = bytecnt; else tmpcnt = ((int)(fbnk->end) - (int)dest) + 1; ret = fdev->flwrite(fbnk,dest,src,tmpcnt); if (ret < 0) { printf("AppFlashWrite(0x%lx,0x%lx,%ld) failed\n", (ulong)dest,(ulong)src,bytecnt); break; } dest += tmpcnt; src += tmpcnt; bytecnt -= tmpcnt; } return(ret); } 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); }
A few neat things occur in AppFlashWrite() . Notice that addrtobank() converts the destination address into a corresponding flashinfo structure pointer. Then the destination address is compared to the end address of the bank. If the destination + bytecount passes the end of the bank, the byte count shrinks to a value that ends at the last address in the bank. Then on the next pass through the loop, addrtobank() is called again, and the new flashinfo pointer is returned for the next block write. Finally, notice that the flashinfo structure is once again used to call the flash write function (through the function pointer fdev->flwrite that corresponds to the bank of flash memory that overlaps the destination address). This is only applicable to systems that have more than one flash bank.
| ||