| /******************************************************************************* | |
| * 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; | |
| } | |