Chinaunix首页 | 论坛 | 博客
  • 博客访问: 226309
  • 博文数量: 88
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 555
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-03 13:08
个人简介

失意高调,得意低调

文章分类

全部博文(88)

文章存档

2021年(3)

2020年(2)

2018年(2)

2017年(3)

2016年(6)

2015年(19)

2014年(32)

2013年(21)

我的朋友

分类: LINUX

2014-05-28 17:47:53

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) |
给主人留下些什么吧!~~