📄 flashpic.c
字号:
/* flashpic_strata.c: * This file contains the portion of the flash driver code that can be * relocated (pic = position independent code) to RAM space so that it * is not executing out of the same flash device that it is operating on. * * This code is written for 2 Strata devices in 16-bit mode in parallel. * This forms one 32-bit wide flash bank. */#include "config.h"#if INCLUDE_FLASH#include "genlib.h"#include "stddefs.h"#include "flashdev.h"#include "flash.h"#include "cpu.h"#define USE_WRITE_BUFFER 1/* When this is used in an environment where it is NOT relocated, * then it is safe to turn on trace and call printf for debugging. * This can be changed to a #define initialized to zero to save * space if printf is not going to be used. */int STRATA_TRACE;/* Flasherase(): * Based on the 'snum' value, erase the appropriate sector(s). * Write the "Erase Setup" and "Erase Confirm" commands... * Return 0 if success, else -1. */intFlasheraseStrata_8x32(struct flashinfo *fdev,int snum){ ftype stat; volatile ulong add, *lp, *lp1; volatile int ret, sector, outofrange; ret = 0; outofrange = 1; add = (ulong)(fdev->base); if (STRATA_TRACE) printf("erase(%d)\n",snum); /* Start operation off by clearing the status register. */ Write_50_to_base(); /* Erase the request sector(s): */ for (sector=0;sector<fdev->sectorcnt;sector++) { if ((snum == ALL_SECTORS) || (snum == sector)) { /* Skip sector if it is protected. */ if ((!FlashProtectWindow) && (fdev->sectors[sector].protected)) { add += fdev->sectors[sector].size; continue; } /* As long as we enter this block of code once, we know * that the sector number requested was within the range * of the specified bank. */ outofrange = 0; /* If the space within the sector is all FF, then it * doesn't need to be erased, so don't... */ lp = (ulong *)fdev->sectors[sector].begin; lp1 = (ulong *)((char *)lp + fdev->sectors[sector].size); while(lp < lp1) { if (*lp++ != 0xffffffff) { /* Erased? */ Write_20_to_base(); /* setup */ Write_d0_to_(add); /* confirm */ WAIT_FOR_WSMS_READY(); /* Wait for WSMS ready */ stat = Read_0000(); if (stat & ECLBS) { /* Check for error */ Write_50_to_base(); /* Clear status register */ printf("Eerr 0x%lx\n",(ulong)stat); Write_ff_to_base(); /* Go to read-array mode */ return(-1); } Write_ff_to_base(); /* Go to read-array mode */ WAIT_FOR_FF(add); /* Wait for read == 0xff */ break; } } if (ret == -1) break; } add += fdev->sectors[sector].size; } if (outofrange) ret = -1; return(ret);}/* EndFlasherase(): * Function place holder to determine the "end" of the * sectorerase() function. */voidEndFlasheraseStrata_8x32(){}/* Flashwrite(): * This device has a 32-byte write buffer. The only gotcha for this is * that the destination address into the flash must be on a 32-byte boundary, * so we an only use the buffer when the destination address has the lower 5 * bits clear. To do this, we do however many "individual" writes are * necessary to get the destination address 32-byte aligned; then, if there * are at least 32 bytes left, we use the write-buffer mechanism for each * remaining block of 32 bytes. */intFlashwriteStrata_8x32(struct flashinfo *fdev,uchar *dest,uchar *src, long bytecnt){ ftype stat; volatile long cnt, buf4[1]; volatile int i, tot, ret, delta; volatile uchar *bp4;#if USE_WRITE_BUFFER volatile uchar *block, *bp64; volatile long buf64[16];#endif /* Start operation off by clearing the status register. */ Write_50_to_base(); /* If the destination address is not properly aligned, then build a * fake source buffer using bytes below dest. Then call this function * recursively to do that operation. */ if (Not32BitAligned(dest)) { uchar *tmpdest; delta = (long)dest & 3; tmpdest = dest - delta; bp4 = (uchar *)buf4; for(i=0;delta>0;i++,delta--) { *bp4++ = *(dest-delta); } for(;i<4;i++) { *bp4++ = *src++; bytecnt--; dest++; } if (STRATA_TRACE) printf("pre-align: 0x%lx = %08lx\n",(ulong)tmpdest,buf4[0]); if (FlashwriteStrata_8x32(fdev,tmpdest,(uchar *)buf4,4) == -1) return(-1); } /* This device supports a write-buffer mode. The buffer is 32 bytes * (16 words) and greatly speeds up the programming process. This * This function starts up with the word-at-a-time mode and uses it * until the destination address is mod32. Then for each successive * 32-byte block, the write buffer is used. When there is less than 32 * bytes left, the algorithm falls back to the one-word-at-a-time mode * to finish up. */ ret = 0; cnt = bytecnt & ~3; for (tot=0;tot<cnt;tot+=4) {#if USE_WRITE_BUFFER if (((ulong)dest & 0x3f) == 0) /* Break out when 6 LSBs are zero */ break;#endif bp4 = (uchar *)buf4; *bp4++ = *src++; /* Just in case src is not aligned... */ *bp4++ = *src++; *bp4++ = *src++; *bp4++ = *src++; if (STRATA_TRACE) printf("fwrite1: 0x%lx = %08lx\n",(ulong)dest,buf4[0]); Write_40_to_(dest); /* Flash program setup command */ Fwrite(dest,buf4); /* Write the value */ WAIT_FOR_WSMS_READY(); /* Wait for WSMS ready */ stat = Read_0000(); if (stat & PSLBS) { /* Check for error */ Write_50_to_base(); /* Clear status register */ Write_ff_to_base(); /* Go to read-array mode */ printf("Werr1 0x%lx\n",(ulong)stat); return(-1); } do { Write_ff_to_base(); /* Go to read-array mode */ } WAIT_FOR_WRITE(dest,buf4); dest += 4; }#if USE_WRITE_BUFFER /* If tot is less than cnt, then the upper loop reached a point where * the destination address had the 5 LSBs low. This means that we can * use the write-buffer for all remaining 32-byte blocks... Note that * each 32-byte block is actually 64 because we have two devices in * parallel. */ if ((cnt-tot) >= 64) { while((cnt-tot) >= 64) { Write_ff_to_base(); /* Go to read-array mode */ bp64 = (uchar *)buf64; /* Copy next buffer's worth of data */ for(i=0;i<64;i++) /* into local buffer just in case */ *bp64++ = *src++; /* the source is this flash device. */ bp64 = (uchar *)buf64; do { Write_e8_to_(dest); } while (WBUF_NOT_AVAIL(dest)); block = dest; Write_0f_to_(dest); for(i=0;i<16;i++) { bp4 = (uchar *)buf4; *bp4++ = *bp64++; /* Just in case src is not aligned... */ *bp4++ = *bp64++; *bp4++ = *bp64++; *bp4++ = *bp64++; if (STRATA_TRACE) printf("fwrite2: 0x%lx = %08lx\n",(ulong)dest,buf4[0]); Fwrite(dest,buf4); /* Write the value */ dest += 4; } Write_d0_to_(block); /* Write-confirm command */ tot += 64; Write_70_to_base(); /* Read Status Register */ WAIT_FOR_WSMS_READY(); /* Wait for idle state machine */ } stat = Read_0000(); /* Check for error */ if (stat & PSLBS) { Write_50_to_base(); /* Clear status register */ Write_ff_to_base(); /* Go to read-array mode */ printf("Werr2 0x%lx\n",stat); return(-1); } Write_ff_to_base(); /* Go to read-array mode */ }#endifonemore: for (;tot<cnt;tot+=4) { bp4 = (uchar *)buf4; *bp4++ = *src++; /* Just in case src is not aligned... */ *bp4++ = *src++; *bp4++ = *src++; *bp4++ = *src++; if (STRATA_TRACE) printf("fwrite3: 0x%lx = %08lx\n", (ulong)dest,buf4[0]); Write_40_to_(dest); /* Flash program setup command */ Fwrite(dest,buf4); /* Write the value */ WAIT_FOR_WSMS_READY(); /* Wait for WSMS ready */ stat = Read_0000(); if (stat & PSLBS) { /* Check for error */ Write_50_to_base(); /* Clear status register */ Write_ff_to_base(); /* Go to read-array mode */ printf("Werr3 0x%lx\n",stat); return(-1); } do { Write_ff_to_base(); /* Go to read-array mode */ } WAIT_FOR_WRITE(dest,buf4); dest += 4; } /* If cnt != bytecnt then bytecnt is not mod4, so one more write must be * be done. To do this, we must combine the source data with data that * is already in the flash above the intended final address... */ if (cnt != bytecnt) { bp4 = (uchar *)buf4; for(delta=0;cnt != bytecnt;delta++,cnt++) *bp4++ = *src++; for(;delta != 4;delta++) *bp4++ = *(dest+delta); src = (uchar *)buf4; if (STRATA_TRACE) printf("post-align: 0x%lx = %08lx\n",(ulong)dest,buf4[0]); tot = cnt-1; goto onemore; } return(ret);}/* EndFlashwrite(): * Function place holder to determine the "end" of the * Flashwrite() function. */voidEndFlashwriteStrata_8x32(){}/* Ewrite(): * Erase all sectors that are part of the address space to be written, * then write the data to that address space. This is basically a * concatenation of flasherase and flashwrite done in one step. This is * necessary primarily for re-writing the bootcode; because after the boot * code is erased, there is nowhere to return so the re-write must be done * while executing out of ram also. */intFlashewriteStrata_8x32(struct flashinfo *fdev,ftype *dest,ftype *src, int bytecnt){ int i; ulong add, stat; void (*reset)(); add = (ulong)(fdev->base); /* For each sector, if it overlaps any of the destination space */ /* then erase that sector. */ for (i=0;i<fdev->sectorcnt;i++) { if ((((uchar *)dest) > (fdev->sectors[i].end)) || (((uchar *)dest+bytecnt-1) < (fdev->sectors[i].begin))) { add += fdev->sectors[i].size; continue; } /* Sector erase sequence: */ Write_20_to_base(); /* setup */ Write_d0_to_(add); /* confirm */ WAIT_FOR_WSMS_READY(); /* Wait for WSMS ready */ stat = Read_0000(); if (stat & ECLBS) { /* Check for error */ Write_50_to_base(); /* Clear status register */ printf("Eerr 0x%lx\n",(ulong)stat); Write_ff_to_base(); /* Go to read-array mode */ return(-1); } Write_ff_to_base(); /* Go to read-array mode */ WAIT_FOR_FF(add); /* Wait for read == 0xff */ add += fdev->sectors[i].size; } for(i=0;i<bytecnt;i+=fdev->width) { Write_40_to_(dest); /* Flash program setup command */ Fwrite(dest,src); /* Write the value */ WAIT_FOR_WSMS_READY(); /* Wait for WSMS ready */ stat = Read_0000(); if (stat & PSLBS) { /* Check for error */ Write_50_to_base(); /* Clear status register */ Write_ff_to_base(); /* Go to read-array mode */ printf("Werr1 0x%lx\n",(ulong)stat); return(-1); } do { Write_ff_to_base(); /* Go to read-array mode */ } WAIT_FOR_WRITE(dest,src); dest++; src++; } /* Now that the re-programming of flash is complete, reset: */ reset = RESETFUNC(); reset(); return(0); /* won't get here */}/* EndFlashewrite(): * Function place holder to determine the "end" of the * FlashEraseAndWrite() function. */voidEndFlashewriteStrata_8x32(){}/* Flashtype(): * Use the ReadConfiguration command (90H) to read manufacturer code (0000) * and device id code (0001). */intFlashtypeStrata_8x32(struct flashinfo *fdev){ ulong man, dev; /* Start operation off by clearing the status register. */ Write_50_to_base(); /* Issue the read array command: */ Write_ff_to_base(); /* Issue the read configuration command: */ Write_90_to_base(); man = Read_0000(); /* manufacturer ID */ if (man == MANUFACTURER_INTEL) { dev = Read_0001(); /* device ID */ if (STRATA_TRACE) printf("Strata man-id/dev-id: 0x%lx 0x%lx\n",man,dev); } else { dev = 0xDEADBEEF; } if (fdev) fdev->id = dev; /* Issue the read array command: */ Write_ff_to_base(); return((int)dev);}/* EndFlashtype(): * Function place holder to determine the "end" of the * Flashtype() function. */voidEndFlashtypeStrata_8x32(){}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -