MC3302_SDK_V1.1.9_202507281.../bsp/ramboot/tools/mc-image-builder.c
2025-11-11 12:08:31 +08:00

381 lines
9.4 KiB
C
Executable File

#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#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;i<fill_page_num;i++){
pos = ftell(dst);
fwrite(buffer, 512 ,1, dst);
page_num++;
fseek(dst, pos + 512 , SEEK_SET);
}
return 0;
}
static int spl_with_uboot_image_create(struct image_info *info,FILE *src,FILE *dst){
uint32_t cnt;
uint8_t *buffer;
uint32_t fill_page_num;
uint32_t page_num = 0;
uint32_t i;
uint32_t copy;
// struct spl_nand_header *sheader;
long pos = ftell(dst);
buffer = malloc(info->page_size);
// sheader = (struct spl_nand_header *)buffer;
for(copy = 0;copy<info->spl_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;i<fill_page_num;i++){
pos = ftell(dst);
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);
/* 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;i<steps;i++)
{
// calu ecc_pos
info->ecc_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 <str>/<step> --ecc=<str>/<step> ECC config (strength/step-size)\n"
"-p <size> --page=<size> Page size\n"
"-o <size> --oob=<size> OOB size\n"
"-e <size> --erase=<size> erase size\n"
"-n <number> --pages=<number> pages per block\n"
"-d <number> -duplication-=<number> 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);
}