#include #include #include #include #include #include #include "../lib/mc_bch.h" #define DIV_ROUND_UP(x,y) (((x) + ((y)-1)))/(y) static int check_image_info(struct image_info *info) { static int valid_ecc_strengths[] = {8,24}; int eccbytes, eccsteps; unsigned i; if (!info->page_size) { fprintf(stderr, "--page is missing\n"); return -EINVAL; } if (!info->oob_size) { fprintf(stderr, "--oob is missing\n"); return -EINVAL; } if (!info->eraseblock_size) { fprintf(stderr, "--eraseblock is missing\n"); return -EINVAL; } if (info->ecc_step_size != 512 && info->ecc_step_size != 1024) { fprintf(stderr, "Invalid ECC step argument: %d\n", info->ecc_step_size); return -EINVAL; } for (i = 0; i < 2; i++) { if (valid_ecc_strengths[i] == info->ecc_strength) break; } if (i == 2) { fprintf(stderr, "Invalid ECC strength argument: %d\n", info->ecc_strength); return -EINVAL; } eccbytes = DIV_ROUND_UP(info->ecc_strength * 14, 8); eccsteps = info->page_size / info->ecc_step_size; if (info->page_size + info->oob_size < info->page_size + (eccsteps * eccbytes)) { fprintf(stderr, "ECC bytes do not fit in the NAND page, choose a weaker ECC\n"); return -EINVAL; } return 0; } void spl_header_init(struct image_info *info,struct spl_nand_header *sheader) { int steps = info->page_size / info->ecc_step_size; int eccbytes = DIV_ROUND_UP(info->ecc_strength * 14, 8); int ctrlbyte = info->oob_size/steps -eccbytes; sheader->main_size = info->page_size; sheader->oob_size = info->oob_size; if(info->ecc_strength == 8){ sheader->ecc_mode = 0; } else if(info->ecc_strength == 24){ sheader->ecc_mode = 1; } sheader->ecc_pos = ctrlbyte; //printf("ec_pos = %d\r\n",ctrlbyte); sheader->sector_num = info->page_size/info->ecc_step_size; sheader->spare_size = sheader->ecc_pos; sheader->block_page = info->block_page; } static int spl_image_create(struct image_info *info,FILE *src,FILE *dst) { uint32_t cnt; uint32_t page_num = 0; uint8_t *buffer; uint32_t fill_page_num; uint32_t i; struct spl_nand_header *sheader; long pos = ftell(dst); buffer = malloc(512); sheader = (struct spl_nand_header *)buffer; memset(buffer, 0xff, 512); cnt = fread(buffer, 1, 512, src); page_num++; if (!cnt) { if (!feof(src)) { fprintf(stderr, "Failed to read data from the source\n"); return -1; } else { return 0; } } info->ctrl_num = 0; info->ecc_pos = (char *)sheader->ecc; encode_bch_24(info,buffer,512,info->ecc_pos); /*init spl header*/ spl_header_init(info,sheader); fwrite(buffer, 512 ,1, dst); fseek(dst, pos + 512 , SEEK_SET); while (!feof(src)) { memset(buffer, 0xff, 512); cnt = fread(buffer, 1, 512, src); pos = ftell(dst); fwrite(buffer, 512 ,1, dst); page_num++; /* Make dst pointer point to the next page. */ fseek(dst, pos + 512 , SEEK_SET); } fill_page_num = 32*1024/512 -page_num; memset(buffer, 0xff, 512); for(i = 0;ipage_size); // sheader = (struct spl_nand_header *)buffer; for(copy = 0;copyspl_copys;copy++){ fseek(src, 0 , SEEK_SET); pos = ftell(dst); page_num = 0; memset(buffer, 0xff, info->page_size); cnt = fread(buffer, 1, info->page_size, src); if (!cnt) { if (!feof(src)) { fprintf(stderr, "Failed to read data from the source\n"); return -1; } else { return 0; } } page_num++; // info->ctrl_num = 0; //info->ecc_pos = buffer + 0x30; // info->ecc_pos = (char *)sheader->ecc; // encode_bch_24(info,buffer,512,info->ecc_pos); /*init spl header*/ // spl_header_init(info,sheader); fwrite(buffer, info->page_size ,1, dst); fseek(dst, pos + info->page_size , SEEK_SET); while (!feof(src)) { memset(buffer, 0xff, info->page_size); cnt = fread(buffer, 1, info->page_size, src); pos = ftell(dst); fwrite(buffer, info->page_size ,1, dst); page_num++; /* Make dst pointer point to the next page. */ fseek(dst, pos + info->page_size , SEEK_SET); if(page_num*info->page_size == 32*1024) break; } fill_page_num = info->eraseblock_size/info->page_size -page_num; memset(buffer, 0xff, info->page_size); for(i = 0;ipage_size ,1, dst); fseek(dst, pos + info->page_size, SEEK_SET); } } while (!feof(src)) { memset(buffer, 0xff, info->page_size); cnt = fread(buffer, 1, info->page_size, src); pos = ftell(dst); fwrite(buffer, info->page_size ,1, dst); /* Make dst pointer point to the next page. */ fseek(dst, pos + info->page_size , SEEK_SET); } return 0; } static int write_page(struct image_info *info, uint8_t *buffer, FILE *src, FILE *dst, int page) { int steps = info->page_size / info->ecc_step_size; int eccbytes = DIV_ROUND_UP(info->ecc_strength * 14, 8); int ctrlbyte = info->oob_size/steps -eccbytes; long pos = ftell(dst); size_t cnt; int i; memset(buffer, 0xff, info->page_size + info->oob_size); cnt = fread(buffer, 1, info->page_size, src); if (!cnt) { if (!feof(src)) { fprintf(stderr, "Failed to read data from the source\n"); return -1; } else { return 0; } } info->ctrl_num = ctrlbyte; for(i=0;iecc_pos = (char *)(buffer + info->page_size + (info->oob_size/steps)*(i+1) - eccbytes); //calu ecc if(info->ecc_strength == 24) encode_bch_24(info,buffer + i*info->ecc_step_size,info->ecc_step_size ,info->ecc_pos); else if(info->ecc_strength == 8) encode_bch_8(info,buffer + i*info->ecc_step_size,info->ecc_step_size ,info->ecc_pos); } fwrite(buffer, info->page_size + info->oob_size, 1, dst); /* Make dst pointer point to the next page. */ fseek(dst, pos + info->page_size + info->oob_size, SEEK_SET); return 0; } static int create_image(struct image_info *info) { long page = 0, flen; FILE *src,*dst; uint8_t *buffer; buffer = malloc(info->page_size + info->oob_size); if (!buffer) { fprintf(stderr, "Failed to allocate the NAND page buffer\n"); return -1; } memset(buffer, 0xff, info->page_size + info->oob_size); src = fopen(info->source, "r"); if (!src) { fprintf(stderr, "Failed to open source file (%s)\n", info->source); return -1; } fseek(src, 0, SEEK_END); flen = ftell(src); if (flen > 0x10000) { printf("source image is bigger than 64KB(0x%lx)!!!\n\n", flen); return -1; } fseek(src, 0, SEEK_SET); dst = fopen(info->dest, "w"); if (!dst) { fprintf(stderr, "Failed to open dest file (%s)\n", info->dest); return -1; } if(info->spl_image_flag) { spl_image_create(info,src,dst); }else if(info->spl_with_uboot){ spl_with_uboot_image_create(info,src,dst); }else{ while (!feof(src)) { int ret; ret = write_page(info, buffer, src, dst, page++); if (ret) return ret; } } return 0; } static void display_help(int status) { printf( "Usage: mc-image-builder [OPTIONS] source-image output-image\n" "\n" "Creates a raw NAND image that can be read by the molchip NAND controller.\n" "\n" "-h --help Display this help and exit\n" "-c / --ecc=/ ECC config (strength/step-size)\n" "-p --page= Page size\n" "-o --oob= OOB size\n" "-e --erase= erase size\n" "-n --pages= pages per block\n" "-d -duplication-= duplication spl\n" "-w --spl with uboot spl with uboot \n" "-s --spl generate spl header ecc\n"); exit(status); } int main(int argc, char **argv) { struct image_info info; memset(&info, 0, sizeof(info)); for(;;){ int option_index = 0; char *endptr = NULL; static const struct option long_options[] = { {"ecc", required_argument, 0, 'c'}, {"page", required_argument, 0, 'p'}, {"oob", required_argument, 0, 'o'}, {"eraseblock", required_argument, 0, 'e'}, {0, 0, 0, 0}, }; int c = getopt_long(argc, argv, "c:p:o:e:n:d:shw", long_options, &option_index); if (c == EOF) break; switch (c) { case 'c': info.ecc_strength = strtol(optarg, &endptr, 0); if (*endptr == '/') info.ecc_step_size = strtol(endptr + 1, NULL, 0); break; case 'p': info.page_size = strtol(optarg, NULL, 0); break; case 'o': info.oob_size = strtol(optarg, NULL, 0); break; case 'e': info.eraseblock_size = strtol(optarg, NULL, 0); break; case 's': info.spl_image_flag = 1; break; case 'w': info.spl_with_uboot = 1; break; case 'd': info.spl_copys = strtol(optarg, NULL, 0); break; case 'h': display_help(-1); break; case 'n': info.block_page = strtol(optarg,NULL,0); break; default: break; } } if ((argc - optind) != 2) display_help(-1); info.source = argv[optind]; info.dest = argv[optind + 1]; printf("ecc_strength = %d,ecc_step_size = %d,eraseblokc_size = %x,page_size = %d,oob_size=%d\r\n",info.ecc_strength,info.ecc_step_size,info.eraseblock_size,info.page_size,info.oob_size); check_image_info(&info); return create_image(&info); }