- improved erase/program failure detection

- added block_lock/unlock functions
- locked blocks are unlocked automatically during erase
Committed on the Free edition of March Hare Software CVSNT Server.
Upgrade to CVS Suite for more features and support:
http://march-hare.com/cvsnt/


git-svn-id: http://moon:8086/svn/vhdl/trunk@461 cc03376c-175c-47c8-b038-4cd826a8556b
This commit is contained in:
2009-05-02 16:18:20 +00:00
parent 66984e5b25
commit a2a17fd24a
2 changed files with 169 additions and 32 deletions
+151 -25
View File
@@ -99,15 +99,38 @@ UINT32 cfi_find(flash_t *pObj)
return 0; return 0;
} }
UINT32 cfi_block_erase(flash_t *pObj, UINT32 word_index) UINT32 cfi_block_is_locked(flash_t *pObj, UINT32 word_index)
{ {
volatile UINT32 *pF; volatile UINT32 *pF;
UINT32 status, block_index, block_mask; UINT32 status, block_index, block_mask;
UINT32 error;
pF = (UINT32*)pObj->pBase; pF = (UINT32*)pObj->pBase;
if (word_index >= (pObj->info.flashsize/4)) if (word_index >= (pObj->info.flashsize/4))
return -1; return CFI_ERR_INVPARAM;
block_mask = ((pObj->info.nblocks-1) << 16);
block_index = word_index & block_mask;
*pF = 0x00900090;
error = ((UINT32)pF[block_index+2] & 0x00010001) != 0;
*pF = 0x00FF00FF;
return error;
}
UINT32 cfi_block_erase(flash_t *pObj, UINT32 word_index)
{
volatile UINT32 *pF;
UINT32 status, block_index, block_mask;
UINT32 error;
pF = (UINT32*)pObj->pBase;
if (word_index >= (pObj->info.flashsize/4))
return CFI_ERR_INVPARAM;
block_mask = ((pObj->info.nblocks-1) << 16); block_mask = ((pObj->info.nblocks-1) << 16);
block_index = word_index & block_mask; block_index = word_index & block_mask;
@@ -115,39 +138,119 @@ UINT32 cfi_block_erase(flash_t *pObj, UINT32 word_index)
pF[block_index] = 0x00200020; pF[block_index] = 0x00200020;
pF[block_index] = 0x00D000D0; pF[block_index] = 0x00D000D0;
error = 0;
do do
{ {
status = pF[block_index]; status = pF[block_index];
} while((status & SR_BIT_ISMS) != SR_BIT_ISMS); } while((status & SR_BIT_ISMS) != SR_BIT_ISMS);
if (status & (SR_BIT_ECLBS | SR_BIT_VPENS | SR_BIT_DPS))
{
error = CFI_ERR_DEV_FAIL | status;
}
pF[block_index] = 0x00FF00FF; pF[block_index] = 0x00FF00FF;
return 0; return error;
}
UINT32 cfi_block_lock(flash_t *pObj, UINT32 word_index)
{
volatile UINT32 *pF;
UINT32 status, block_index, block_mask;
UINT32 error;
pF = (UINT32*)pObj->pBase;
if (word_index >= (pObj->info.flashsize/4))
return CFI_ERR_INVPARAM;
block_mask = ((pObj->info.nblocks-1) << 16);
block_index = word_index & block_mask;
pF[block_index] = 0x00600060;
pF[block_index] = 0x00010001;
error = 0;
do
{
status = pF[block_index];
} while((status & SR_BIT_ISMS) != SR_BIT_ISMS);
if (status & (SR_BIT_PSLBS | SR_BIT_VPENS | SR_BIT_ECLBS))
{
error = CFI_ERR_DEV_FAIL | status;
}
pF[block_index] = 0x00FF00FF;
return error;
}
UINT32 cfi_block_unlock(flash_t *pObj, UINT32 word_index)
{
volatile UINT32 *pF;
UINT32 status, block_index, block_mask;
UINT32 error;
pF = (UINT32*)pObj->pBase;
if (word_index >= (pObj->info.flashsize/4))
return CFI_ERR_INVPARAM;
block_mask = ((pObj->info.nblocks-1) << 16);
block_index = word_index & block_mask;
pF[block_index] = 0x00600060;
pF[block_index] = 0x00D000D0;
error = 0;
do
{
status = pF[block_index];
} while((status & SR_BIT_ISMS) != SR_BIT_ISMS);
if (status & (SR_BIT_PSLBS | SR_BIT_VPENS | SR_BIT_ECLBS))
{
error = CFI_ERR_DEV_FAIL | status;
}
pF[block_index] = 0x00FF00FF;
return error;
} }
UINT32 cfi_program_single(flash_t *pObj, UINT32 word_index, UINT32 word) UINT32 cfi_program_single(flash_t *pObj, UINT32 word_index, UINT32 word)
{ {
volatile UINT32 *pF; volatile UINT32 *pF;
UINT32 status; UINT32 status, error;
pF = (UINT32*)pObj->pBase; pF = (UINT32*)pObj->pBase;
if (word_index >= (pObj->info.flashsize/4)) if (word_index >= (pObj->info.flashsize/4))
return -1; return CFI_ERR_INVPARAM;
pF[word_index] = 0x00400040; pF[word_index] = 0x00400040;
pF[word_index] = word; pF[word_index] = word;
error = 0;
do do
{ {
status = pF[word_index]; status = pF[word_index];
} while((status & SR_BIT_ISMS) != SR_BIT_ISMS); } while((status & SR_BIT_ISMS) != SR_BIT_ISMS);
if (status & (SR_BIT_PSLBS | SR_BIT_VPENS | SR_BIT_DPS))
{
error = CFI_ERR_DEV_FAIL | status;
}
pF[word_index] = 0x00FF00FF; pF[word_index] = 0x00FF00FF;
return 0; return error;
} }
@@ -156,11 +259,12 @@ UINT32 cfi_program_multi(flash_t *pObj, UINT32 word_index, UINT32 *pWords, UINT3
int i, j, k; int i, j, k;
volatile UINT32 *pF; volatile UINT32 *pF;
UINT32 status, bcurr, bnext, block_mask, nblock_write, nbuf_write; UINT32 status, bcurr, bnext, block_mask, nblock_write, nbuf_write;
UINT32 error;
pF = (UINT32*)pObj->pBase; pF = (UINT32*)pObj->pBase;
if (word_index >= (pObj->info.flashsize/4)) if (word_index >= (pObj->info.flashsize/4))
return -1; return CFI_ERR_INVPARAM;
block_mask = ((pObj->info.nblocks-1) << 16); block_mask = ((pObj->info.nblocks-1) << 16);
@@ -174,28 +278,25 @@ UINT32 cfi_program_multi(flash_t *pObj, UINT32 word_index, UINT32 *pWords, UINT3
if (nblock_write > num_words) if (nblock_write > num_words)
nblock_write = num_words; nblock_write = num_words;
// printf("bcurr : %8.8X\n", bcurr);
// printf("bnext : %8.8X\n", bnext);
// printf("windex : %8.8X\n", word_index);
// printf("num_words : %d\n", num_words);
// printf("nblock_write : %d\n", nblock_write);
while(nblock_write) while(nblock_write)
{ {
error = 0;
pF[bcurr] = 0x00E800E8; pF[bcurr] = 0x00E800E8;
do do
{ {
status = pF[bcurr]; status = pF[bcurr];
// printf("status : %8.8X\n", status);
} while((status & SR_BIT_ISMS) != SR_BIT_ISMS); } while((status & SR_BIT_ISMS) != SR_BIT_ISMS);
if (status & (SR_BIT_PSLBS | SR_BIT_VPENS | SR_BIT_DPS))
{
error = CFI_ERR_DEV_FAIL | status;
break;
}
nbuf_write = nblock_write; nbuf_write = nblock_write;
if (nblock_write > pObj->info.wbuf_size/4) if (nblock_write > pObj->info.wbuf_size/4)
nbuf_write = pObj->info.wbuf_size/4; nbuf_write = pObj->info.wbuf_size/4;
// printf("nbuf_write : %d\n", nbuf_write);
pF[bcurr] = (nbuf_write-1) << 16 | (nbuf_write-1); pF[bcurr] = (nbuf_write-1) << 16 | (nbuf_write-1);
for (j=0; j < nbuf_write; j++) for (j=0; j < nbuf_write; j++)
@@ -205,20 +306,31 @@ UINT32 cfi_program_multi(flash_t *pObj, UINT32 word_index, UINT32 *pWords, UINT3
nblock_write -= j; nblock_write -= j;
num_words -= j; num_words -= j;
error = 0;
pF[bcurr] = 0x00D000D0; pF[bcurr] = 0x00D000D0;
do do
{ {
status = pF[bcurr]; status = pF[bcurr];
// printf("status : %8.8X\n", status);
} while((status & SR_BIT_ISMS) != SR_BIT_ISMS); } while((status & SR_BIT_ISMS) != SR_BIT_ISMS);
if (status & (SR_BIT_PSLBS | SR_BIT_VPENS | SR_BIT_DPS))
{
error = CFI_ERR_DEV_FAIL | status;
break;
}
pF[bcurr] = 0x00FF00FF; pF[bcurr] = 0x00FF00FF;
} }
if (IS_ERROR(error))
{
pF[bcurr] = 0x00FF00FF;
break;
}
bcurr = bnext; bcurr = bnext;
} }
return 0; return error;
} }
@@ -231,15 +343,24 @@ UINT32 flash_find(flash_t *pObj, UINT32 base_addr)
UINT32 flash_erase(flash_t *pObj, UINT32 offset, UINT32 size) UINT32 flash_erase(flash_t *pObj, UINT32 offset, UINT32 size)
{ {
int i; int i;
UINT32 offset_end; UINT32 offset_end, error;
offset_end = offset + size; offset_end = offset + size;
for (i=offset; i < offset_end; i += pObj->info.blocksize) for (i=offset; i < offset_end; i += pObj->info.blocksize)
if (cfi_block_erase(pObj, i/4) < 0) {
return -1; if (cfi_block_is_locked(pObj, i/4))
{
error = cfi_block_unlock(pObj, i/4);
if (IS_ERROR(error))
break;
}
error = cfi_block_erase(pObj, i/4);
if (IS_ERROR(error))
break;
}
return 0; return error;
} }
@@ -257,12 +378,12 @@ UINT32 flash_verify(flash_t *pObj, UINT32 offset, UINT8 *pData, UINT32 size)
for (i=0; i < size; i++) for (i=0; i < size; i++)
if (pF[i] != pData[i]) if (pF[i] != pData[i])
return -1; return CFI_ERR_VFY_FAIL;
return 0; return 0;
} }
UINT32 flash_aligned_addr_by_offset(flash_t *pObj, UINT32 offset) UINT32 flash_get_blocknum_by_offset(flash_t *pObj, UINT32 offset)
{ {
UINT32 blocknum; UINT32 blocknum;
@@ -270,7 +391,12 @@ UINT32 flash_aligned_addr_by_offset(flash_t *pObj, UINT32 offset)
if (offset%pObj->info.blocksize) if (offset%pObj->info.blocksize)
blocknum++; blocknum++;
return blocknum*pObj->info.blocksize; return blocknum;
}
UINT32 flash_aligned_addr_by_offset(flash_t *pObj, UINT32 offset)
{
return flash_get_blocknum_by_offset(pObj, offset) * pObj->info.blocksize;
} }
UINT32 flash_aligned_addr_by_blocknum(flash_t *pObj, UINT32 blocknum) UINT32 flash_aligned_addr_by_blocknum(flash_t *pObj, UINT32 blocknum)
+11
View File
@@ -12,6 +12,13 @@
#define SR_BIT_ESS 0x00400040 #define SR_BIT_ESS 0x00400040
#define SR_BIT_ISMS 0x00800080 #define SR_BIT_ISMS 0x00800080
#define CFI_ERR_BASE (LSYS_ERR_BASE + 0x00100000)
#define CFI_ERR_GENERAL (CFI_ERR_BASE + 0)
#define CFI_ERR_NOTFOUND (CFI_ERR_BASE + 1)
#define CFI_ERR_INVPARAM (CFI_ERR_BASE + 2)
#define CFI_ERR_VFY_FAIL (CFI_ERR_BASE + 3)
#define CFI_ERR_DEV_FAIL (CFI_ERR_BASE + 0x10000000)
typedef struct _sflash_info_t typedef struct _sflash_info_t
{ {
UINT32 flashsize; UINT32 flashsize;
@@ -33,12 +40,16 @@ typedef struct _sflash_t
void cfi_init(flash_t *pObj, UINT32 base_addr); void cfi_init(flash_t *pObj, UINT32 base_addr);
UINT32 cfi_find(flash_t *pObj); UINT32 cfi_find(flash_t *pObj);
UINT32 cfi_block_is_locked(flash_t *pObj, UINT32 word_index);
UINT32 cfi_block_erase(flash_t *pObj, UINT32 word_index); UINT32 cfi_block_erase(flash_t *pObj, UINT32 word_index);
UINT32 cfi_block_lock(flash_t *pObj, UINT32 word_index);
UINT32 cfi_block_unlock(flash_t *pObj, UINT32 word_index);
UINT32 cfi_program_single(flash_t *pObj, UINT32 word_index, UINT32 word); UINT32 cfi_program_single(flash_t *pObj, UINT32 word_index, UINT32 word);
UINT32 cfi_program_multi(flash_t *pObj, UINT32 word_index, UINT32 *pWords, UINT32 num_words); UINT32 cfi_program_multi(flash_t *pObj, UINT32 word_index, UINT32 *pWords, UINT32 num_words);
UINT32 flash_aligned_addr_by_offset(flash_t *pObj, UINT32 offset); UINT32 flash_aligned_addr_by_offset(flash_t *pObj, UINT32 offset);
UINT32 flash_aligned_addr_by_blocknum(flash_t *pObj, UINT32 blocknum); UINT32 flash_aligned_addr_by_blocknum(flash_t *pObj, UINT32 blocknum);
UINT32 flash_get_blocknum_by_offset(flash_t *pObj, UINT32 offset);
UINT32 flash_find(flash_t *pObj, UINT32 base_addr); UINT32 flash_find(flash_t *pObj, UINT32 base_addr);
UINT32 flash_erase(flash_t *pObj, UINT32 offset, UINT32 size); UINT32 flash_erase(flash_t *pObj, UINT32 offset, UINT32 size);
UINT32 flash_program(flash_t *pObj, UINT32 offset, UINT8 *pData, UINT32 size); UINT32 flash_program(flash_t *pObj, UINT32 offset, UINT8 *pData, UINT32 size);