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@790 cc03376c-175c-47c8-b038-4cd826a8556b
416 lines
8.2 KiB
C
416 lines
8.2 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "libsys.h"
|
|
#include "cfiflash.h"
|
|
|
|
UINT32 cfi_get_status(flash_t *pObj)
|
|
{
|
|
volatile UINT32 *pF;
|
|
UINT32 status;
|
|
|
|
pF = (UINT32*)pObj->pBase;
|
|
|
|
*pF = 0x00700070;
|
|
|
|
status = *pF;
|
|
|
|
*pF = 0x00FF00FF;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
void cfi_init(flash_t *pObj, UINT32 base_addr)
|
|
{
|
|
int i;
|
|
UINT8 *pInfo;
|
|
UINT32 endian;
|
|
UINT8 *pEndian;
|
|
|
|
pObj->pBase = (void*)base_addr;
|
|
|
|
pInfo = (UINT8*)&pObj->info;
|
|
for (i=0; i < sizeof(flash_info_t); i++)
|
|
{
|
|
pInfo[i] = 0;
|
|
}
|
|
pObj->eb = 0;
|
|
endian = 0x12345678;
|
|
pEndian = (UINT8*)&endian;
|
|
if (*pEndian == 0x12)
|
|
{
|
|
pObj->eb = 1;
|
|
}
|
|
|
|
}
|
|
|
|
UINT32 cfi_find(flash_t *pObj)
|
|
{
|
|
int i;
|
|
volatile UINT32 *pF;
|
|
volatile UINT16 *pF16;
|
|
// UINT8 qry_ref[12] = {0x51, 0x00, 0x51, 0x00, 0x52, 0x00, 0x52, 0x00, 0x59, 0x00, 0x59, 0x00};
|
|
UINT32 size;
|
|
|
|
pF = (UINT32*)pObj->pBase;
|
|
pF16 = (UINT16*)pObj->pBase;
|
|
|
|
// Look for flash
|
|
*pF = 0x00980098;
|
|
// for (i=0; i < sizeof(qry_ref); i++)
|
|
// if (((UINT8*)(&pF[0x10]))[i] != qry_ref[i])
|
|
// return (UINT32)-1;
|
|
|
|
*pF = 0x00FF00FF;
|
|
*pF = 0x00900090;
|
|
|
|
/*
|
|
printf("ManID : %8.8X\n", (UINT32)pF[0]);
|
|
printf("Device code : %8.8X\n", (UINT32)pF[1]);
|
|
printf("Block info : %8.8X\n", (UINT32)pF[2]);
|
|
|
|
printf("VCC(min) : %8.8X\n", (UINT32)pF[0x1B]);
|
|
printf("VCC(max) : %8.8X\n", (UINT32)pF[0x1C]);
|
|
printf("VPP(min) : %8.8X\n", (UINT32)pF[0x1D]);
|
|
printf("VPP(max) : %8.8X\n", (UINT32)pF[0x1E]);
|
|
printf("Device Layout : %8.8X\n", (UINT32)pF[0x27]);
|
|
printf("Interface type : %8.8X %8.8X\n", (UINT32)pF[0x28], (UINT32)pF[0x29]);
|
|
printf("Write buffer size : %8.8X %8.8X\n", (UINT32)pF[0x2A], (UINT32)pF[0x2B]);
|
|
printf("Num. erase blocks : %8.8X\n", (UINT32)pF[0x2C]);
|
|
printf("Erase block info : %8.8X %8.8X %8.8X %8.8X\n", (UINT32)pF[0x2D], (UINT32)pF[0x2E], (UINT32)pF[0x2F], (UINT32)pF[0x30]);
|
|
*/
|
|
pObj->info.num_flash = 2;
|
|
pObj->info.if_width = 32;
|
|
size = (UINT32)pF16[2*0x27];
|
|
pObj->info.flashsize = pObj->info.num_flash;
|
|
for (i=0; i < size; i++)
|
|
pObj->info.flashsize *= 2;
|
|
|
|
size = (UINT32)(pF16[2*0x2B] << 8 | pF16[2*0x2A]);
|
|
pObj->info.wbuf_size = pObj->info.num_flash;
|
|
for (i=0; i < size; i++)
|
|
pObj->info.wbuf_size *= 2;
|
|
|
|
pObj->info.nblocks = (UINT32)(pF16[2*0x2E] << 8 | pF16[2*0x2D]) + 1;
|
|
pObj->info.blocksize = pObj->info.num_flash * ((UINT32)(pF16[2*0x30] << 8 | pF16[2*0x2F]) * 256);
|
|
|
|
*pF = 0x00FF00FF;
|
|
|
|
return 0;
|
|
}
|
|
|
|
UINT32 cfi_block_is_locked(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 = 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_index = word_index & block_mask;
|
|
|
|
pF[block_index] = 0x00200020;
|
|
pF[block_index] = 0x00D000D0;
|
|
|
|
error = 0;
|
|
do
|
|
{
|
|
status = pF[block_index];
|
|
|
|
} 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;
|
|
|
|
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)
|
|
{
|
|
volatile UINT32 *pF;
|
|
UINT32 status, error;
|
|
|
|
pF = (UINT32*)pObj->pBase;
|
|
|
|
if (word_index >= (pObj->info.flashsize/4))
|
|
return CFI_ERR_INVPARAM;
|
|
|
|
pF[word_index] = 0x00400040;
|
|
pF[word_index] = word;
|
|
|
|
error = 0;
|
|
do
|
|
{
|
|
status = pF[word_index];
|
|
|
|
} 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;
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
UINT32 cfi_program_multi(flash_t *pObj, UINT32 word_index, UINT32 *pWords, UINT32 num_words)
|
|
{
|
|
int i, j, k;
|
|
volatile UINT32 *pF;
|
|
UINT32 status, bcurr, bnext, block_mask, nblock_write, nbuf_write;
|
|
UINT32 error;
|
|
|
|
pF = (UINT32*)pObj->pBase;
|
|
|
|
if (word_index >= (pObj->info.flashsize/4))
|
|
return CFI_ERR_INVPARAM;
|
|
|
|
block_mask = ((pObj->info.nblocks-1) << 16);
|
|
|
|
k = 0;
|
|
while(num_words)
|
|
{
|
|
|
|
bcurr = word_index & block_mask;
|
|
bnext = bcurr + (1 << 16);
|
|
nblock_write = bnext - word_index;
|
|
if (nblock_write > num_words)
|
|
nblock_write = num_words;
|
|
|
|
while(nblock_write)
|
|
{
|
|
error = 0;
|
|
pF[bcurr] = 0x00E800E8;
|
|
do
|
|
{
|
|
status = pF[bcurr];
|
|
|
|
} 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;
|
|
if (nblock_write > pObj->info.wbuf_size/4)
|
|
nbuf_write = pObj->info.wbuf_size/4;
|
|
|
|
pF[bcurr] = (nbuf_write-1) << 16 | (nbuf_write-1);
|
|
|
|
for (j=0; j < nbuf_write; j++)
|
|
pF[word_index+j] = pWords[k++];
|
|
|
|
word_index += j;
|
|
nblock_write -= j;
|
|
num_words -= j;
|
|
|
|
error = 0;
|
|
pF[bcurr] = 0x00D000D0;
|
|
do
|
|
{
|
|
status = pF[bcurr];
|
|
|
|
} 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;
|
|
}
|
|
|
|
if (IS_ERROR(error))
|
|
{
|
|
pF[bcurr] = 0x00FF00FF;
|
|
break;
|
|
}
|
|
bcurr = bnext;
|
|
}
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
UINT32 flash_find(flash_t *pObj, UINT32 base_addr)
|
|
{
|
|
cfi_init(pObj, base_addr);
|
|
return cfi_find(pObj);
|
|
}
|
|
|
|
UINT32 flash_erase(flash_t *pObj, UINT32 offset, UINT32 size)
|
|
{
|
|
int i;
|
|
UINT32 offset_end, error;
|
|
|
|
if (size % 4)
|
|
size = 4*(size/4 + 1);
|
|
|
|
offset_end = offset + size;
|
|
|
|
for (i=offset; i < offset_end; i += pObj->info.blocksize)
|
|
{
|
|
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 error;
|
|
|
|
}
|
|
|
|
UINT32 flash_program(flash_t *pObj, UINT32 offset, UINT8 *pData, UINT32 size)
|
|
{
|
|
if (size % 4)
|
|
size = 4*(size/4 + 1);
|
|
|
|
return cfi_program_multi(pObj, offset/4, (UINT32*)pData, size/4);
|
|
}
|
|
|
|
UINT32 flash_verify(flash_t *pObj, UINT32 offset, UINT8 *pData, UINT32 size)
|
|
{
|
|
int i;
|
|
UINT8 *pF;
|
|
|
|
pF = (UINT8*)(pObj->pBase + offset);
|
|
|
|
for (i=0; i < size; i++)
|
|
if (pF[i] != pData[i])
|
|
return CFI_ERR_VFY_FAIL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
UINT32 flash_get_blocknum_by_offset(flash_t *pObj, UINT32 offset)
|
|
{
|
|
UINT32 blocknum;
|
|
|
|
blocknum = offset/pObj->info.blocksize;
|
|
if (offset%pObj->info.blocksize)
|
|
blocknum++;
|
|
|
|
return blocknum;
|
|
}
|
|
|
|
UINT32 flash_get_offset_by_blocknum(flash_t *pObj, UINT32 blocknum)
|
|
{
|
|
if (blocknum >= pObj->info.nblocks)
|
|
blocknum = pObj->info.nblocks - 1;
|
|
|
|
return blocknum*pObj->info.blocksize;
|
|
}
|
|
|
|
UINT32 flash_get_offset_blockaligned(flash_t *pObj, UINT32 offset)
|
|
{
|
|
return flash_get_blocknum_by_offset(pObj, offset) * pObj->info.blocksize;
|
|
}
|
|
|