/******************************************************************************* | |
* Copyright (C) 2016, ZIXC Corporation. | |
* | |
* File Name: | |
* File Mark: | |
* Description: | |
* Others: | |
* Version: 1.0 | |
* Author: geanfeng | |
* Date: 2013-3-4 | |
* History 1: | |
* Date: | |
* Version: | |
* Author: | |
* Modification: | |
* History 2: | |
********************************************************************************/ | |
/**************************************************************************** | |
* Include files | |
****************************************************************************/ | |
#include "downloader_nand.h" | |
#include <asm/errno.h> | |
#include "partition_table.h" | |
#include <linux/mtd/nor_spifc.h> | |
/**************************************************************************** | |
* Local Macros | |
****************************************************************************/ | |
#define DATA_WITH_OOB (1 << 0) /* whether write with oob data*/ | |
/**************************************************************************** | |
* Local Types | |
****************************************************************************/ | |
/**************************************************************************** | |
* Global Variables | |
****************************************************************************/ | |
extern partition_table_t * g_partition_table; | |
extern partition_table_t * g_partition_table_dl; | |
extern partition_entry_t * get_partitions(const char *partname, partition_table_t *table); | |
/**************************************************************************** | |
* Global Function Prototypes | |
****************************************************************************/ | |
/**************************************************************************** | |
* Function Definitions | |
****************************************************************************/ | |
/******************************************************************************* | |
* Function:get_part_offset_skipbase | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
*phyBase | |
* | |
* Others: | |
********************************************************************************/ | |
static int get_part_offset_skipbase(partition_entry_t * part, uint offset, uint * skipBase) | |
{ | |
nand_info_t * pNandInfo = NULL; | |
uint offsetSkipBase = 0; | |
uint blockNum = 0; | |
int ret = 0; | |
pNandInfo = &nand_info[nand_curr_device]; | |
offsetSkipBase = part->part_offset; | |
assert((offset & (pNandInfo->erasesize - 1)) == 0); | |
assert((offsetSkipBase & (pNandInfo->erasesize - 1)) == 0); | |
if(offset != 0) | |
{ | |
blockNum = offset /pNandInfo->erasesize; | |
while(blockNum > 0) | |
{ | |
ret = nand_block_isbad (pNandInfo, offsetSkipBase); | |
offsetSkipBase += pNandInfo->erasesize; | |
if (ret) | |
{ | |
continue; | |
} | |
else | |
{ | |
blockNum--; | |
} | |
} | |
} | |
*skipBase = offsetSkipBase; | |
return 0; | |
} | |
/******************************************************************************* | |
* Function:nand_read_skip_bad_compt | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* NULL:error else: success | |
* | |
* Others: | |
********************************************************************************/ | |
int nand_read_skip_bad_compat(nand_info_t *nand, loff_t offset, size_t *length, | |
u_char *buffer, int flags) | |
{ | |
int rval = 0, blocksize; | |
size_t left_to_read = *length; | |
u_char *p_buffer = buffer; | |
if (flags & DATA_WITH_OOB) { | |
int pages; | |
pages = nand->erasesize / nand->writesize; | |
blocksize = (pages * nand->oobsize) + nand->erasesize; | |
if (*length % (nand->writesize + nand->oobsize)) { | |
printf ("Attempt to write incomplete page" | |
" in yaffs mode\n"); | |
return -EINVAL; | |
} | |
} else | |
{ | |
blocksize = nand->erasesize; | |
} | |
if ((offset & (nand->writesize - 1)) != 0) { | |
printf ("Attempt to write non page aligned data\n"); | |
*length = 0; | |
return -EINVAL; | |
} | |
while (left_to_read > 0) { | |
size_t block_offset = offset & (nand->erasesize - 1); | |
size_t read_size, truncated_read_size; | |
if (nand_block_isbad (nand, offset & ~(nand->erasesize - 1))) { | |
printf ("Skip bad block 0x%08llx\n", | |
(u64)(offset & ~(nand->erasesize - 1))); | |
offset += nand->erasesize - block_offset; | |
continue; | |
} | |
if (left_to_read < (blocksize - block_offset)) | |
read_size = left_to_read; | |
else | |
read_size = blocksize - block_offset; | |
if (flags & DATA_WITH_OOB) { | |
int page, pages; | |
size_t pagesize = nand->writesize; | |
size_t pagesize_oob = pagesize + nand->oobsize; | |
struct mtd_oob_ops ops; | |
memset(&ops, 0x0, sizeof(ops)); | |
ops.len = pagesize; | |
ops.ooblen = nand->oobsize; | |
ops.mode = MTD_OOB_RAW; | |
ops.ooboffs = 0; | |
pages = read_size / pagesize_oob; | |
for (page = 0; page < pages; page++) { | |
ops.datbuf = p_buffer; | |
ops.oobbuf = ops.datbuf + pagesize; | |
rval = nand->read_oob(nand, offset, &ops); | |
if (rval) | |
break; | |
offset += pagesize; | |
p_buffer += pagesize_oob; | |
} | |
} | |
else | |
{ | |
truncated_read_size = read_size; | |
rval = nand_read(nand, offset, &truncated_read_size, | |
p_buffer); | |
offset += read_size; | |
p_buffer += read_size; | |
} | |
if (rval != 0) { | |
printf ("NAND read from offset %llx failed %d\n", | |
(u64)offset, rval); | |
*length -= left_to_read; | |
return rval; | |
} | |
left_to_read -= read_size; | |
} | |
return 0; | |
} | |
/******************************************************************************* | |
* Function:nand_read_skip_bad_compt | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* NULL:error else: success | |
* | |
* Others: | |
********************************************************************************/ | |
int nand_write_skip_bad_compat(nand_info_t *nand, loff_t offset, size_t *length, | |
u_char *buffer, int flags) | |
{ | |
int rval = 0, blocksize; | |
size_t left_to_write = *length; | |
u_char *p_buffer = buffer; | |
if (flags & DATA_WITH_OOB) { | |
int pages; | |
pages = nand->erasesize / nand->writesize; | |
blocksize = (pages * nand->oobsize) + nand->erasesize; | |
if (*length % (nand->writesize + nand->oobsize)) { | |
printf ("Attempt to write incomplete page" | |
" in yaffs mode\n"); | |
return -EINVAL; | |
} | |
} else | |
{ | |
blocksize = nand->erasesize; | |
} | |
/* | |
* nand_write() handles unaligned, partial page writes. | |
* | |
* We allow length to be unaligned, for convenience in | |
* using the $filesize variable. | |
* | |
* However, starting at an unaligned offset makes the | |
* semantics of bad block skipping ambiguous (really, | |
* you should only start a block skipping access at a | |
* partition boundary). So don't try to handle that. | |
*/ | |
if ((offset & (nand->writesize - 1)) != 0) { | |
printf ("Attempt to write non page aligned data\n"); | |
*length = 0; | |
return -EINVAL; | |
} | |
while (left_to_write > 0) { | |
size_t block_offset = offset & (nand->erasesize - 1); | |
size_t write_size, truncated_write_size; | |
if (nand_block_isbad (nand, offset & ~(nand->erasesize - 1))) { | |
printf ("Skip bad block 0x%08llx\n", | |
(u64)(offset & ~(nand->erasesize - 1))); | |
offset += nand->erasesize - block_offset; | |
continue; | |
} | |
if (left_to_write < (blocksize - block_offset)) | |
write_size = left_to_write; | |
else | |
write_size = blocksize - block_offset; | |
if (flags & DATA_WITH_OOB) { | |
int page, pages; | |
size_t pagesize = nand->writesize; | |
size_t pagesize_oob = pagesize + nand->oobsize; | |
struct mtd_oob_ops ops; | |
ops.len = pagesize; | |
ops.ooblen = nand->oobsize; | |
ops.mode = MTD_OOB_RAW; | |
ops.ooboffs = 0; | |
pages = write_size / pagesize_oob; | |
for (page = 0; page < pages; page++) { | |
ops.datbuf = p_buffer; | |
ops.oobbuf = ops.datbuf + pagesize; | |
//ops.oobbuf = NULL; | |
if(*(ops.datbuf + pagesize) != 0xFF || *(ops.datbuf + pagesize+1) != 0xFF) { | |
printf ("Fs image format error\n"); | |
return -EINVAL; | |
} | |
rval = nand->write_oob(nand, offset, &ops); | |
if (rval) | |
break; | |
offset += pagesize; | |
p_buffer += pagesize_oob; | |
} | |
} | |
else | |
{ | |
truncated_write_size = write_size; | |
rval = nand_write(nand, offset, &truncated_write_size, | |
p_buffer); | |
offset += write_size; | |
p_buffer += write_size; | |
} | |
if (rval != 0) { | |
printf ("NAND write to offset %llx failed %d\n", | |
(u64)offset, rval); | |
*length -= left_to_write; | |
return rval; | |
} | |
left_to_write -= write_size; | |
} | |
return 0; | |
} | |
/******************************************************************************* | |
* Function:downloader_get_part | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* NULL:error else: success | |
* | |
* Others: | |
********************************************************************************/ | |
partition_entry_t * downloader_get_part(const char *partname) | |
{ | |
partition_entry_t *part; | |
part = find_partition_para((uchar *)partname); | |
if(part == NULL) | |
return NULL; | |
return part; | |
} | |
/******************************************************************************* | |
* Function:downloader_get_part_dl | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* NULL:error else: success | |
* | |
* Others: | |
********************************************************************************/ | |
partition_entry_t * downloader_get_part_dl(const char *partname) | |
{ | |
partition_entry_t *part; | |
part = get_partitions((const char *)partname,g_partition_table_dl); | |
if(part == NULL) | |
{ | |
return NULL; | |
} | |
printf("name=%s,part-name=%s,typt=%s\n",partname,part->part_name,part->part_type); | |
return part; | |
} | |
/******************************************************************************* | |
* Function:downloader_get_part_actual_size | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* NULL:error else: success | |
* | |
* Others: | |
********************************************************************************/ | |
u32 downloader_get_part_actual_size(partition_entry_t *part) | |
{ | |
nand_info_t * pNandInfo = NULL; | |
pNandInfo = &nand_info[nand_curr_device]; | |
u32 bad_blk_cnt = 0; | |
u32 offset = part->part_offset; | |
while(offset < part->part_offset + part->part_size ) | |
{ | |
if (nand_block_isbad (pNandInfo, offset) ){ | |
bad_blk_cnt = bad_blk_cnt +1 ; | |
offset += pNandInfo->erasesize; | |
continue; | |
} | |
offset += pNandInfo->erasesize; | |
} | |
printf("downloader_get_part_actual_size:[%s] bad_blk_cnt = %d\n",part->part_name, bad_blk_cnt); | |
u32 part_actual_size = part->part_size -(bad_blk_cnt * pNandInfo->erasesize); | |
return part_actual_size; | |
} | |
/******************************************************************************* | |
* Function:downloader_nand_read | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* 0: success else:error | |
* | |
* Others: | |
********************************************************************************/ | |
int downloader_nand_read(partition_entry_t * part, uint offset, uint size, unchar * buffer) | |
{ | |
nand_info_t * pNandInfo = NULL; | |
uint nandPhyBase = 0; | |
int ret = 0; | |
char ack[64] = {0}; | |
if(part == NULL || \ | |
offset>part->part_size || (size>downloader_get_part_actual_size(part)) || (offset+size) > part->part_size) | |
{ | |
printf(" [downloader_nand_read:][%s]bin_size > actual part_size \n", part->part_name); | |
sprintf(ack, " READ FAIL UNLEGAL SIZE "); | |
downloader_serial_write(ack, strlen(ack)+1); | |
return -1; | |
} | |
pNandInfo = &nand_info[nand_curr_device]; | |
get_part_offset_skipbase(part,offset,&nandPhyBase); | |
if( strcmp((const char *)part->part_name , "zloader") == 0 ) | |
{ | |
/* ÕâÀﲻʹÓÃECC¶Áȡʱ£¬Òª¶ÁÈ¡OOB£¬¶øOOBµÃÊý¾Ý»á·ÅÈëdata->buf; | |
ËùÒÔ´æ·ÅÊý¾ÝµÄbuf±ØÐëΪ (1 page + oob),²»ÄÜʹÓÃÉÏÃæ´«ÏÂÀ´µÄ | |
buffer,ÒòΪbufferµÄ´óСΪ²»°üº¬ oob µÄ´óС | |
*/ | |
u_char *buf = kzalloc(pNandInfo->writesize + pNandInfo->oobsize, GFP_KERNEL); | |
if( buf == NULL ) | |
{ | |
printf("downloader_nand_read kzalloc error\n"); | |
return -1; | |
} | |
int times = size/pNandInfo->writesize; | |
int i = 0; | |
for(; i<times; i++) | |
{ | |
ret += nand_read_page_with_ecc(pNandInfo, | |
((loff_t)i*pNandInfo->writesize), | |
&size, | |
(u_char*)buf ); | |
memcpy((u_char*)buffer, buf ,pNandInfo->writesize); | |
buffer += pNandInfo->writesize; | |
} | |
kfree(buf); | |
} | |
else | |
ret = nand_read_skip_bad(pNandInfo,\ | |
nandPhyBase+offset%(pNandInfo->erasesize),&size,(u_char*)buffer); | |
if(ret) | |
{ | |
printf("downloader_nand_read error\n"); | |
return -1; | |
} | |
return 0; | |
} | |
/******************************************************************************* | |
* Function:downloader_nand_write | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* 0: success else:error | |
* | |
* Others: | |
********************************************************************************/ | |
int downloader_nand_write(partition_entry_t * part, uint offset, uint size, unchar * buffer) | |
{ | |
nand_info_t * pNandInfo = NULL; | |
uint nandPhyBase = 0; | |
int ret = 0; | |
uchar * buf = buffer; | |
char ack[64] = {0}; | |
if(part == NULL || \ | |
offset>part->part_size || (size > downloader_get_part_actual_size(part)) || (offset+size) > part->part_size) | |
{ | |
printf("[downloader_nand_write:][%s] bin_size > actual part_size \n", part->part_name); | |
sprintf(ack, "WRITE FAIL UNLEGAL SIZE "); | |
downloader_serial_write(ack, strlen(ack)+1); | |
return -1; | |
} | |
/*if(zftl_get_ZFTLrecord(part->part_offset)) | |
{ | |
printf("Function not allowed write zftl\n"); | |
return -1; | |
}*/ | |
pNandInfo = &nand_info[nand_curr_device]; | |
get_part_offset_skipbase(part,offset,&nandPhyBase); | |
printf("entry nand_write\n"); | |
/* רÃÅдZ-LOADʱʹÓ㬲»Ê¹ÓÃECC*/ | |
if( strcmp((const char *)part->part_name , "zloader") == 0 ) | |
{ | |
if(g_nor_flag == 1) | |
{ | |
int times = 0x9000/pNandInfo->writesize; | |
int i = 0; | |
for(; i<times; i++) | |
{ | |
ret += nand_write_page_with_ecc(pNandInfo, | |
((loff_t)i*(pNandInfo->writesize)), | |
buf ); | |
buf += pNandInfo->writesize; | |
} | |
} | |
else | |
{ | |
if( size != 12*1024 ) | |
{ | |
printf("downloader_nand_write z-load size != 12k...\n"); | |
return -1; | |
} | |
int times = 12*1024/pNandInfo->writesize; | |
int i = 0; | |
for(; i<times; i++) | |
{ | |
ret += nand_write_page_with_ecc(pNandInfo, | |
((loff_t)i*(pNandInfo->writesize)), | |
buf ); | |
buf += pNandInfo->writesize; | |
} | |
} | |
} | |
else | |
ret = nand_write_skip_bad(pNandInfo,\ | |
nandPhyBase+offset%(pNandInfo->erasesize),&size,(u_char*)buffer, 0); | |
printf("write skipbad finish, addr = %d,size = %d\n",nandPhyBase+offset%(pNandInfo->erasesize),size); | |
if(ret) | |
{ | |
printf("downloader_nand_write error\n"); | |
return -1; | |
} | |
return 0; | |
} | |
/******************************************************************************* | |
* Function:downloader_nand_fs_read | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* 0: success else:error | |
* | |
* Others: | |
********************************************************************************/ | |
int downloader_nand_fs_read(partition_entry_t * part, uint offset, uint size, unchar * buffer) | |
{ | |
nand_info_t * pNandInfo = NULL; | |
uint nandPhyBase = 0; | |
int ret = 0; | |
char ack[64] = {0}; | |
if(part == NULL || \ | |
offset>part->part_size || (size>downloader_get_part_actual_size(part)) || (offset+size) > part->part_size) | |
{ | |
printf("[downloader_nand_fs_read:][%s] bin_size > actual part_size \n", part->part_name); | |
sprintf(ack, " FS_READ FAIL UNLEGAL SIZE "); | |
downloader_serial_write(ack, strlen(ack)+1); | |
return -1; | |
} | |
pNandInfo = &nand_info[nand_curr_device]; | |
assert(pNandInfo!=NULL); | |
get_part_offset_skipbase(part,offset,&nandPhyBase); | |
ret = nand_read_skip_bad_compat(pNandInfo,nandPhyBase+offset%(pNandInfo->erasesize),&size,(u_char*)buffer,DATA_WITH_OOB); | |
if(ret) | |
{ | |
printf("downloader_nand_fs_read error\n"); | |
return -1; | |
} | |
return 0; | |
} | |
/******************************************************************************* | |
* Function:downloader_nand_fs_write | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* 0: success else:error | |
* | |
* Others: | |
********************************************************************************/ | |
int downloader_nand_fs_write(partition_entry_t * part, uint offset, uint size, unchar * buffer) | |
{ | |
nand_info_t * pNandInfo = NULL; | |
uint nandPhyBase = 0; | |
int ret = 0; | |
char ack[64] = {0}; | |
if(part == NULL || \ | |
offset>part->part_size || (size>downloader_get_part_actual_size(part)) || (offset+size) > part->part_size) | |
{ | |
printf("[downloader_nand_fs_write:][%s] bin_size > actual part_size \n", part->part_name); | |
sprintf(ack, " FS_WRITE FAIL UNLEGAL SIZE "); | |
downloader_serial_write(ack, strlen(ack)+1); | |
return -1; | |
} | |
pNandInfo = &nand_info[nand_curr_device]; | |
assert(pNandInfo!=NULL); | |
get_part_offset_skipbase(part,offset,&nandPhyBase); | |
ret = nand_write_skip_bad_compat(pNandInfo,nandPhyBase+offset%(pNandInfo->erasesize),&size,(u_char*)buffer, DATA_WITH_OOB); | |
if(ret) | |
{ | |
printf("downloader_nand_fs_write error\n"); | |
return -1; | |
} | |
return 0; | |
} | |
/******************************************************************************* | |
* Function:downloader_nand_erase | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* 0: success else:error | |
* | |
* Others: | |
********************************************************************************/ | |
int downloader_nand_erase(partition_entry_t * part, uint partEraseSize) | |
{ | |
nand_info_t * pNandInfo = NULL; | |
int ret = 0; | |
struct erase_info instr; | |
uint size = 0; | |
if(part == NULL ) | |
{ | |
return -1; | |
} | |
pNandInfo = &nand_info[nand_curr_device]; | |
instr.mtd = pNandInfo; | |
instr.addr = part->part_offset; | |
assert( (instr.addr & (pNandInfo->erasesize - 1)) == 0); | |
instr.callback = 0; | |
//ret=nand_erase(pNandInfo, part->part_offset, part->part_size); | |
while(size < partEraseSize && (instr.addr < (part->part_offset+part->part_size))) | |
{ | |
if(nand_block_isbad (pNandInfo, instr.addr)) | |
{ | |
instr.addr += pNandInfo->erasesize; | |
continue ; | |
} | |
instr.len = pNandInfo->erasesize; | |
instr.state = 0; | |
ret = pNandInfo->erase(pNandInfo, &instr); | |
if(ret && instr.state == MTD_ERASE_FAILED) | |
{ | |
pNandInfo->block_markbad(pNandInfo,instr.addr); | |
} | |
else if (ret == 0) | |
{ | |
size += pNandInfo->erasesize; | |
} | |
else | |
{ | |
printf( "downloader nand: erase error\n"); | |
return 1; | |
} | |
instr.addr += pNandInfo->erasesize; | |
} | |
return ret; | |
} | |
/******************************************************************************* | |
* Function:downloader_nand_eraseall | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* 0: success else:error | |
* | |
* Others: | |
********************************************************************************/ | |
int downloader_nand_eraseall(void) | |
{ | |
nand_info_t * pNandInfo = NULL; | |
struct erase_info instr; | |
int i = 0; | |
int ret = 0; | |
for(i=0; i<CONFIG_SYS_MAX_NAND_DEVICE; i++) | |
{ | |
pNandInfo = &nand_info[i]; | |
instr.mtd = pNandInfo; | |
instr.addr = 0x00; | |
assert( (instr.addr & (pNandInfo->erasesize - 1)) == 0); | |
instr.callback = 0; | |
while(instr.addr < pNandInfo->size) | |
{ | |
if(nand_block_isbad (pNandInfo, instr.addr)) | |
{ | |
instr.addr += pNandInfo->erasesize; | |
continue ; | |
} | |
instr.len = pNandInfo->erasesize; | |
instr.state = 0; | |
ret = pNandInfo->erase(pNandInfo, &instr); | |
if(ret && instr.state == MTD_ERASE_FAILED) | |
{ | |
pNandInfo->block_markbad(pNandInfo,instr.addr); | |
} | |
instr.addr += pNandInfo->erasesize; | |
} | |
} | |
return ret; | |
} | |
/******************************************************************************* | |
* Function:downloader_nand_erase_auto | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* 0: success else:error | |
* | |
* Others: | |
********************************************************************************/ | |
int downloader_nand_erase_auto(void) | |
{ | |
int ret = 0; | |
partition_entry_t *entry = &g_partition_table->table[0]; | |
uint32_t entry_nums = g_partition_table->entrys; | |
while( entry_nums-- ) | |
{ | |
if ( strcmp((const char *)entry->part_name, "nvrofs") == 0 \ | |
||strcmp((const char *)entry->part_name, "ddr") == 0 \ | |
||strcmp((const char *)entry->part_name, "raw") == 0) | |
{ | |
entry++; | |
continue; | |
} | |
ret = downloader_nand_erase(entry,entry->part_size); | |
entry++; | |
} | |
return ret; | |
} | |
extern struct fsl_qspi spi_nor_flash; | |
/******************************************************************************* | |
* Function:downloader_nor_read | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* 0: success else:error | |
* | |
* Others: | |
********************************************************************************/ | |
int downloader_nor_read(partition_entry_t * part, uint offset, uint size, unchar * buffer) | |
{ | |
int ret = 0; | |
char ack[64] = {0}; | |
size_t read_size = size; | |
struct fsl_qspi *nor = NULL; | |
if(part == NULL | |
||offset>part->part_size | |
|| (offset+size) > part->part_size) | |
{ | |
printf(" [downloader_nor_read:][%s]bin_size > actual part_size \n", part->part_name); | |
sprintf(ack, " READ FAIL UNLEGAL SIZE "); | |
downloader_serial_write(ack, strlen(ack)+1); | |
return -1; | |
} | |
nor = &spi_nor_flash; | |
ret = nand_read(&(nor->nor[0].mtd), part->part_offset + offset, &read_size, buffer); | |
if(ret) | |
{ | |
printf("downloader_nor_read error\n"); | |
return -1; | |
} | |
return 0; | |
} | |
/******************************************************************************* | |
* Function:downloader_nor_write | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* 0: success else:error | |
* | |
* Others: | |
********************************************************************************/ | |
int downloader_nor_write(partition_entry_t * part, uint offset, uint size, unchar * buffer) | |
{ | |
int ret = 0; | |
size_t write_size=0; | |
char ack[64] = {0}; | |
struct fsl_qspi *nor = NULL; | |
write_size = size; | |
if(part == NULL | |
|| offset>part->part_size | |
|| (offset+size) > part->part_size) | |
{ | |
printf("[downloader_nor_write:][%s] bin_size > actual part_size \n", part->part_name); | |
sprintf(ack, "WRITE FAIL UNLEGAL SIZE "); | |
downloader_serial_write(ack, strlen(ack)+1); | |
return -1; | |
} | |
nor = &spi_nor_flash; | |
ret = nand_write(&(nor->nor[0].mtd), part->part_offset + offset, &write_size, buffer); | |
if(ret) | |
{ | |
printf("downloader_nor_write error\n"); | |
return ret; | |
} | |
return 0; | |
} | |
/******************************************************************************* | |
* Function:downloader_nand_erase | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* 0: success else:error | |
* | |
* Others: | |
********************************************************************************/ | |
int downloader_nor_erase(partition_entry_t * part, uint partEraseSize) | |
{ | |
int ret = 0; | |
struct fsl_qspi *nor = NULL; | |
if(part == NULL) | |
{ | |
return -1; | |
} | |
nor = &spi_nor_flash; | |
ret = nand_erase(&(nor->nor[0].mtd), part->part_offset, partEraseSize); | |
if(ret) | |
{ | |
printf("downloader_nor_erase error\n"); | |
return ret; | |
} | |
printf("downloader_nor_erase ok\n"); | |
return 0; | |
} | |
/******************************************************************************* | |
* Function:downloader_nor_eraseall | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* 0: success else:error | |
* | |
* Others: | |
********************************************************************************/ | |
int downloader_nor_eraseall(void) | |
{ | |
int ret = 0; | |
struct fsl_qspi *nor = NULL; | |
nor = &spi_nor_flash; | |
ret = nand_erase(&(nor->nor[0].mtd), 0x0, nor->nor[0].mtd.size); | |
if(ret) | |
{ | |
printf("downloader_nor_eraseall error\n"); | |
return ret; | |
} | |
printf("downloader_nor_eraseall ok\n"); | |
return 0; | |
} | |
/******************************************************************************* | |
* Function:downloader_nor_erase_auto | |
* Description: | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* 0: success else:error | |
* | |
* Others: | |
********************************************************************************/ | |
int downloader_nor_erase_auto(void) | |
{ | |
int ret = 0; | |
partition_entry_t *entry = &g_partition_table->table[0]; | |
uint32_t entry_nums = g_partition_table->entrys; | |
while(entry_nums--) | |
{ | |
if ( strcmp((const char *)entry->part_name, "nvrofs") == 0 \ | |
||strcmp((const char *)entry->part_name, "ddr") == 0 \ | |
||strcmp((const char *)entry->part_name, "raw") == 0) | |
{ | |
entry++; | |
continue; | |
} | |
ret = downloader_nor_erase(entry,entry->part_size); | |
if(ret) | |
{ | |
printf("downloader_nor_erase_auto error\n"); | |
return ret; | |
} | |
entry++; | |
} | |
printf("downloader_nor_erase_auto ok\n"); | |
return 0; | |
} | |
int get_nor_null_slice_flag(unsigned int *flag) | |
{ | |
int ret = 0; | |
size_t read_size = 0x100; | |
unchar buffer[256]; | |
struct fsl_qspi *nor = NULL; | |
memset(buffer, 0xFF, 0x100); | |
nor = &spi_nor_flash; | |
ret = nand_read(&(nor->nor[0].mtd), 0x0, &read_size, buffer); | |
if(ret) | |
{ | |
printf("downloader_nor_read error\n"); | |
return -1; | |
} | |
if(strncmp((const char *)(buffer+4), "ZX7521V1", 8) == 0) | |
{ | |
*flag = 1; | |
printf("nor flash not null\n"); | |
} | |
return 0; | |
} | |