nandflash 生成镜像制作步骤:
芯片:MT29F2G08ABAEAWP-ITX
1,按照分区生成分区信息表
按照实际img的大小,生产每个分区内的有用数据块
2,制作镜像文件:有两种方法
(1):按照ECC算法制作
(2):nanddump读出带oob的镜像文件,如果有坏块则需要补齐
nanddump -f /tmp/u-bootb.bin -s 0 -b -l 0x700000 /dev/mtd0
nanddump -f /tmp/kernelb.bin -s 0 -b -l 0x800000 /dev/mtd03
cat u-bootb.bin kernelb.bin > nand_data.bin
3,校验,读出相应分区头和镜像文件比较
hexdump -n 64 -s 0x1080000 nand_data.bin
code:
// nand_merge.c
// Tool to create 7019 NAND programming image for System General programmers.
// Baustem Jan24,2011.
// Note: Add link option:
// /link setargv.obj
// to project option (in the link page of project settings)
// to enable argument expansion which is very useful for this
// tool.
// This allows the user to use the same batch script on
// different image sets, providing the image set shares
// the same naming convention.
// Usage:
//
// nand_merge offset file_name offset file_name ...
//
// Offset and file_name must appear as a pair.
// The data contained in "file_name" will be put into "offset"
// in the NAND chip.
// Offset must be aligned to block boundary.
// Offsets must be sorted from low to high.
// Data files MUST NOT overlap, i.e. space between offsets
// must be big engouh for the data file.
//
// Output files are:
// nand_data.bin
// partition_table.bin
// Output files will be over-written when nand_merge is called repeatedly.
//
// Output files conform to System General's requirements.
// This tool will calculate ECC in 7019 style and create OOB with the ECC,
// then insert the OOB into nand_data.bin.
// This tool is only for (2048+64)*2048 NAND.
//
// FixMe: This tool is designed for simple use, we'd better to provide
// partition start/end point instead of guess from start points only,
// so un-used partition can be defined.
// Current design takes the next offset as the end of current partition,
// no un-used partition can be defined, so chips with too much bad blocks
// may overflow to reserved space for un-used partition.
// Jan29,2013 Change to support Sinaen programmer.
#include
#include
#include "nand_ecc.h"
#define SWAP // Swap data area and change the output name.
#define NAND_TOTAL_BLK (2048)
#define NAND_AVAILABLE_BLK (2048 - 4) // We reserve 4 blocks for bbt.
#define NAND_PAGE_PER_BLK (64)
#define NAND_PAGE_SIZE (2048)
#define NAND_OOB_SIZE (64)
#define NAND_ECCINPUT_SIZE (512)
#define NAND_OOB_PER_ECC (16)
#define NAND_BLK_SIZE (NAND_PAGE_SIZE * NAND_PAGE_PER_BLK)
#define NAND_AVAILABLE_SIZE (NAND_BLK_SIZE * NAND_AVAILABLE_BLK)
#ifdef SWAP
#define NAND_IMG_FILE ("nand_data_swapped.bin")
#else
#define NAND_IMG_FILE ("nand_data.bin")
#endif
#define NAND_PARTITION_FILE ("partition_table.bin")
static unsigned char data_buf[NAND_PAGE_SIZE];
static unsigned char oob_buf[NAND_OOB_SIZE];
// Input MUST be 4 bytes aligned.
static void endian_swap_4bytes(unsigned char *buf, unsigned int len) {
unsigned int i;
unsigned char temp;
// Work on 4 byte set, ignoring possible tail.
for(i = 0; i < len - (len % 4); i += 4) {
temp = buf[i];
buf[i] = buf[i + 3];
buf[i + 3] = temp;
temp = buf[i + 1];
buf[i + 1] = buf[i + 2];
buf[i + 2] = temp;
}
}
// Open and read input_file_name file, add OOB containing ECC,
// pad to block boundary with 0xFF, append the result to output file.
// This function takes empty input file as error.
// Return: >0 the number of blocks, <=0 error.
int process_input_file(char *input_file_name, FILE *output) {
int ret, w_ret;
FILE *input;
unsigned int i;
unsigned int page_count;
if(NULL == output) {
printf("Parm err.\r\n");
return -1;
}
input = fopen(input_file_name, "rb");
if(NULL == input) {
printf("Can not open input file %s.\r\n", input_file_name);
return -2; // Can not open input.
}
// FixMe: We just read to the point we can not read, don't know Error or EOF.
page_count = 0;
do {
// Padding or not used bytes are all 0xFF.
memset(data_buf, 0xFF, NAND_PAGE_SIZE);
memset(oob_buf, 0xFF, NAND_OOB_SIZE);
ret = fread(data_buf, 1, NAND_PAGE_SIZE, input);
if(0 == ret) break; // No input, don't output.
// ToDo: We don't want to calc ECC on all FF sub-pages.
// So compare with all FF buffer and count sub-pages
// until non-FF value or end of binary file is encountered.
// If there is non-FF value then take the FF as written value
// and calc ECC and output them, else thake the FF as file
// trailer, don't calc ECC and throw it away.
for(i = 0; i < (NAND_PAGE_SIZE / NAND_ECCINPUT_SIZE); i++) {
if(ret > NAND_ECCINPUT_SIZE * i) {
// Only do ECC on written area.
calc_ecc(data_buf + NAND_ECCINPUT_SIZE * i,
oob_buf + 6 + NAND_OOB_PER_ECC * i);
}
}
// Note on Nanjing Xeltek programmers:
// Data is 4 bytes swapped when programming to chip while OOB is not.
// So we swap our data to get correct content on chip.
// This is also needed for SG.
// But Changhong's Sinaen programmer don't swap data bytes.
#ifdef SWAP
endian_swap_4bytes(data_buf, NAND_PAGE_SIZE);
#endif
w_ret = fwrite(data_buf, 1, NAND_PAGE_SIZE, output);
if(NAND_PAGE_SIZE != w_ret) {
fclose(input);
return -3; // Failed to write output.
}
w_ret = fwrite(oob_buf, 1, NAND_OOB_SIZE, output);
if(NAND_OOB_SIZE != w_ret) {
fclose(input);
return -4; // Failed to write output.
}
page_count++;
} while(NAND_PAGE_SIZE == ret);
fclose(input);
memset(data_buf, 0xFF, NAND_PAGE_SIZE);
memset(oob_buf, 0xFF, NAND_OOB_SIZE);
// Pad to block boundary.
// ToFix: This will add one more block of pad when data is already aligned.
// for(i = 0; i < NAND_PAGE_PER_BLK - (page_count & (NAND_PAGE_PER_BLK - 1)); i++) {
// The fix shall be the standard 2^n alignment calc.
for(i = 0; i < ((page_count + (NAND_PAGE_PER_BLK - 1)) & (~(unsigned int)(NAND_PAGE_PER_BLK - 1))) - page_count; i++) {
w_ret = fwrite(data_buf, 1, NAND_PAGE_SIZE, output);
if(NAND_PAGE_SIZE != w_ret) {
return -3; // Failed to write output.
}
w_ret = fwrite(oob_buf, 1, NAND_OOB_SIZE, output);
if(NAND_OOB_SIZE != w_ret) {
return -4; // Failed to write output.
}
}
// ToDo: Return block count.
return (page_count + (NAND_PAGE_PER_BLK - 1)) / NAND_PAGE_PER_BLK;
}
// Write blk_to_pad blocks of 0xFF Data with 0xFF OOB.
// Return:
// 0 if all padding blocks are written ok.
// <0 error.
// FixMe: Create a generic pad function, used here and above...
int pad_output_file(FILE *output, int blk_to_pad) {
int i, j;
int ret;
memset(data_buf, 0xFF, NAND_PAGE_SIZE);
memset(oob_buf, 0xFF, NAND_OOB_SIZE);
for(i = 0; i < blk_to_pad; i++) {
for(j = 0; j < NAND_PAGE_PER_BLK; j++) {
ret = fwrite(data_buf, 1, NAND_PAGE_SIZE, output);
if(NAND_PAGE_SIZE != ret) {
return -1; // Failed to write output.
}
ret = fwrite(oob_buf, 1, NAND_OOB_SIZE, output);
if(NAND_OOB_SIZE != ret) {
return -1; // Failed to write output.
}
}
}
return 0;
}
typedef struct partition_table_entry_s {
unsigned int start_block;
unsigned int end_block; // Index of the last block INSIDE the current partition.
unsigned int data_block_count;
unsigned int padding;
} partition_table_entry_t;
int main(int argc, char **argv) {
FILE *nand_data_file;
FILE *partition_table_file;
partition_table_entry_t partition;
unsigned int offset;
unsigned int last_offset;
unsigned int last_blk_count;
int i;
int ret;
int blk_to_pad;
printf("\r\nArgument list (please check):\r\n");
for(i = 1; i < argc; i++) {
printf("%s\r\n", argv[i]);
}
if(argc < 3 || !(argc & 0x01)) {
printf("Usage: nand_merge offset file offset file ...\r\n");
printf("\toffset is in hex without the \"0x\".\r\n");
printf("\toffset and input file name must appear in pair.\r\n");
printf("\tInput files must be placed in order\r\n\tfrom low address to high.\r\n");
return 1; // Parm error.
}
nand_data_file = fopen(NAND_IMG_FILE, "wb");
if(NULL == nand_data_file) {
printf("Can not open output file.\r\n");
return 2;
}
partition_table_file = fopen(NAND_PARTITION_FILE, "wb");
if(NULL == partition_table_file) {
printf("Can not open output partition table.\r\n");
return 3;
}
partition.padding = 0xFFFFFFFF;
last_offset = 0;
last_blk_count = 0;
// One loop one input.
for(i = 1; i < argc; i += 2) {
// Offset: Get and check.
ret = sscanf(argv[i], "%x", &offset);
if(1 != ret) {
printf("Error, hex number expected: %s.\r\n", argv[i]);
ret = 4;
goto fail;
}
if(offset >= NAND_AVAILABLE_SIZE) {
printf("Error, offset must be smaller than chip size: %x.\r\n", offset);
ret = 5;
goto fail;
}
if(offset & (NAND_BLK_SIZE - 1)) {
printf("Error, offset must be block aligned: %x.\r\n", offset);
ret = 6;
goto fail;
}
if(offset < last_offset) {
// Seems not necessary... but more friendly.
printf("Error, offset must increase: %x.\r\n", offset);
ret = 7;
goto fail;
}
if(offset < last_offset + NAND_BLK_SIZE * last_blk_count) {
printf("Error, offset too small or previous file too big: %x.\r\n", offset);
ret = 8;
goto fail;
}
if(i > 1) {
// Add partition info. Here we got all needed for the previous partition.
partition.start_block = last_offset / NAND_BLK_SIZE;
partition.end_block = offset / NAND_BLK_SIZE - 1;
partition.data_block_count = last_blk_count;
// Write to partition table.
ret = fwrite(&partition, sizeof(partition), 1, partition_table_file);
if(1 != ret) {
printf("Failed to write partition table.\r\n");
ret = 9;
goto fail;
}
// Then pad output with 0xFF to the start address of the next partition.
// This is required on most programmers, Xeltek,Sinaen.
blk_to_pad = (partition.end_block + 1 - partition.start_block) - partition.data_block_count;
ret = pad_output_file(nand_data_file, blk_to_pad);
if(ret < 0) {
printf("Failed to write padding into data output file.\r\n");
ret = 11;
goto fail;
}
}
// Process input file.
ret = process_input_file(argv[i + 1], nand_data_file);
if(ret <= 0) {
goto fail;
}
if(offset + NAND_BLK_SIZE * ret > NAND_AVAILABLE_SIZE) {
printf("Error, input file %s used up available chip space.\r\n", argv[i + 1]);
ret = 10;
goto fail;
}
last_blk_count = ret;
last_offset = offset;
}
// For the last partition, we use all available blocks.
partition.start_block = last_offset / NAND_BLK_SIZE;
partition.end_block = NAND_AVAILABLE_BLK - 1;
partition.data_block_count = last_blk_count;
// Write to partition table.
ret = fwrite(&partition, sizeof(partition), 1, partition_table_file);
if(1 != ret) {
printf("Failed to write partition table.\r\n");
ret = 9;
goto fail;
}
// Write an end-record to partition table.
memset(&partition, 0xff, sizeof(partition));
ret = fwrite(&partition, sizeof(partition), 1, partition_table_file);
if(1 != ret) {
printf("Failed to write partition table.\r\n");
ret = 9;
goto fail;
}
fclose(partition_table_file);
fclose(nand_data_file);
return 0;
fail:
fclose(nand_data_file);
remove(NAND_IMG_FILE);
fclose(partition_table_file);
remove(NAND_PARTITION_FILE);
return ret;
}
// Sample code for generating ECC.
// From kernel source of mtd/bcmnand.
#include
#include "nand_ecc.h"
void calc_ecc(const uint8_t *data, uint8_t *ecc_code) {
int i,j;
static uint8_t o_ecc[24], temp[10];
static uint32_t b_din[128];
uint32_t* i_din = &b_din[0];
unsigned long pre_ecc;
i_din = (uint32_t*) data;
memset(o_ecc, 0, sizeof(o_ecc));
for(i=0;i<128;i++){
memset(temp, 0, sizeof(temp));
for(j=0;j<32;j++){
temp[0]^=((i_din[i]& 0x55555555)>>j)&0x1;
temp[1]^=((i_din[i]& 0xAAAAAAAA)>>j)&0x1;
temp[2]^=((i_din[i]& 0x33333333)>>j)&0x1;
temp[3]^=((i_din[i]& 0xCCCCCCCC)>>j)&0x1;
temp[4]^=((i_din[i]& 0x0F0F0F0F)>>j)&0x1;
temp[5]^=((i_din[i]& 0xF0F0F0F0)>>j)&0x1;
temp[6]^=((i_din[i]& 0x00FF00FF)>>j)&0x1;
temp[7]^=((i_din[i]& 0xFF00FF00)>>j)&0x1;
temp[8]^=((i_din[i]& 0x0000FFFF)>>j)&0x1;
temp[9]^=((i_din[i]& 0xFFFF0000)>>j)&0x1;
}
for(j=0;j<10;j++)
o_ecc[j]^=temp[j];
if(i%2){
for(j=0;j<32;j++)
o_ecc[11]^=(i_din[i]>>j)&0x1;//P32
}
else{
for(j=0;j<32;j++)
o_ecc[10]^=(i_din[i]>>j)&0x1;//P32'
}
if((i&0x3)<2){
for(j=0;j<32;j++)
o_ecc[12]^=(i_din[i]>>j)&0x1;//P64'
}
else{
for(j=0;j<32;j++)
o_ecc[13]^=(i_din[i]>>j)&0x1;//P64
}
if((i&0x7)<4){
for(j=0;j<32;j++)
o_ecc[14]^=(i_din[i]>>j)&0x1;//P128'
}
else{
for(j=0;j<32;j++)
o_ecc[15]^=(i_din[i]>>j)&0x1;//P128
}
if((i&0xF)<8){
for(j=0;j<32;j++)
o_ecc[16]^=(i_din[i]>>j)&0x1;//P256'
}
else{
for(j=0;j<32;j++)
o_ecc[17]^=(i_din[i]>>j)&0x1;//P256
}
if((i&0x1F)<16){
for(j=0;j<32;j++)
o_ecc[18]^=(i_din[i]>>j)&0x1;//P512'
}
else{
for(j=0;j<32;j++)
o_ecc[19]^=(i_din[i]>>j)&0x1;//P512
}
if((i&0x3F)<32){
for(j=0;j<32;j++)
o_ecc[20]^=(i_din[i]>>j)&0x1;//P1024'
}
else{
for(j=0;j<32;j++)
o_ecc[21]^=(i_din[i]>>j)&0x1;//P1024
}
if((i&0x7F)<64){
for(j=0;j<32;j++)
o_ecc[22]^=(i_din[i]>>j)&0x1;//P2048'
}
else{
for(j=0;j<32;j++)
o_ecc[23]^=(i_din[i]>>j)&0x1;//P2048
}
pre_ecc = 0;
for(j=23;j>=0;j--) {
pre_ecc = (pre_ecc << 1) | (o_ecc[j] ? 1 : 0 );
}
}
ecc_code[0] = (o_ecc[ 7]<<7 | o_ecc[ 6]<<6 | o_ecc[ 5]<<5 | o_ecc[ 4]<<4 | o_ecc[ 3]<<3 | o_ecc[ 2]<<2 | o_ecc[ 1]<<1 | o_ecc[ 0]);
ecc_code[1] = (o_ecc[15]<<7 | o_ecc[14]<<6 | o_ecc[13]<<5 | o_ecc[12]<<4 | o_ecc[11]<<3 | o_ecc[10]<<2 | o_ecc[ 9]<<1 | o_ecc[ 8]);
ecc_code[2] = (o_ecc[23]<<7 | o_ecc[22]<<6 | o_ecc[21]<<5 | o_ecc[20]<<4 | o_ecc[19]<<3 | o_ecc[18]<<2 | o_ecc[17]<<1 | o_ecc[16]);
}
// nand_ecc.h
#ifndef NAND_ECC_H
#define NAND_ECC_H
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
void calc_ecc(const uint8_t *data, uint8_t *ecc_code);
#endif // #ifndef NAND_ECC_H
阅读(3964) | 评论(0) | 转发(0) |