/* read a page with ECC */ static int nand_read_page(u_char *buf, ulong page_addr) { u_char ecc_code[6]; u_char ecc_calc[3]; u_char oob_buf[16]; u_char *p; u16 val; int cntr; NAND_ENABLE_CE(); NanD_Command(NAND_CMD_READ0); NanD_Address(ADDR_COLUMN_PAGE, page_addr>>1); NAND_WAIT_READY(); p = buf; for (cntr = 0; cntr < 256; cntr++){ val = READ_NAND(NAND_ADDR); *p++ = val & 0xff; *p++ = val >> 8; } p = oob_buf; for (cntr = 0; cntr < 8; cntr++){ val = READ_NAND(NAND_ADDR); *p++ = val & 0xff; *p++ = val >> 8; } NAND_DISABLE_CE(); /* set pin high */ /* Pick the ECC bytes out of the oob data */ for (cntr = 0; cntr < 6; cntr++) ecc_code[cntr] = oob_buf[ecc_pos[cntr]]; if ((oob_buf[eccvalid_pos] & 0x0f) != 0x0f) { nand_calculate_ecc (buf, &ecc_calc[0]); if (nand_correct_data (buf, &ecc_code[0], &ecc_calc[0]) == -1) { printf ("ECC Failed, page 0x%08x\n", page_addr); return 1; } } if ((oob_buf[eccvalid_pos] & 0xf0) != 0xf0) { nand_calculate_ecc (buf + 256, &ecc_calc[0]); if (nand_correct_data (buf + 256, &ecc_code[3], &ecc_calc[0]) == -1) { printf ("ECC Failed, page 0x%08x\n", page_addr+0x100); return 1; } } return 0; }
void cmd_nand_ecc(int argc, char** argv) { if(argc < 3) { bufferPrintf("Usage: %s <data> <ecc>\r\n", argv[0]); return; } uint32_t address = parseNumber(argv[1]); uint32_t ecc = parseNumber(argv[2]); bufferPrintf("nand_calculate_ecc(%x, %x) = %d\r\n", address, ecc, nand_calculate_ecc((uint8_t*) address, (uint8_t*) ecc)); }
void ecc_sector(unsigned char *sector, unsigned char *code) { unsigned char *p; int ecc = 0; ecc = nand_calculate_ecc(sector); p = (unsigned char *)&ecc; code[0] = p[0]; code[1] = p[2]; code[2] = p[1] | (p[3] << 4); }
/** * @returns If no error occurred, returns number of bytes consumed; * otherwise, returns a negative error code.) */ int nand_fileio_read(struct nand_device *nand, struct nand_fileio_state *s) { size_t total_read = 0; size_t one_read; if (NULL != s->page) { fileio_read(&s->fileio, s->page_size, s->page, &one_read); if (one_read < s->page_size) memset(s->page + one_read, 0xff, s->page_size - one_read); total_read += one_read; } if (s->oob_format & NAND_OOB_SW_ECC) { uint8_t ecc[3]; memset(s->oob, 0xff, s->oob_size); for (uint32_t i = 0, j = 0; i < s->page_size; i += 256) { nand_calculate_ecc(nand, s->page + i, ecc); s->oob[s->eccpos[j++]] = ecc[0]; s->oob[s->eccpos[j++]] = ecc[1]; s->oob[s->eccpos[j++]] = ecc[2]; } } else if (s->oob_format & NAND_OOB_SW_ECC_KW) { /* * In this case eccpos is not used as * the ECC data is always stored contigously * at the end of the OOB area. It consists * of 10 bytes per 512-byte data block. */ uint8_t *ecc = s->oob + s->oob_size - s->page_size / 512 * 10; memset(s->oob, 0xff, s->oob_size); for (uint32_t i = 0; i < s->page_size; i += 512) { nand_calculate_ecc_kw(nand, s->page + i, ecc); ecc += 10; } } else if (NULL != s->oob) { fileio_read(&s->fileio, s->oob_size, s->oob, &one_read); if (one_read < s->oob_size) memset(s->oob + one_read, 0xff, s->oob_size - one_read); total_read += one_read; } return total_read; }
/*start_address/size does not include oob */ int main(int argc, char **argv) { uint8_t *page_data = NULL; uint8_t *ecc_data; int infd = -1, outfd = -1; int ret = 1; ssize_t bytes; int ch; while ((ch = getopt(argc, argv, "e:o:p:")) != -1) { switch(ch) { case 'p': page_size = strtoul(optarg, NULL, 0); break; case 'o': oob_size = strtoul(optarg, NULL, 0); break; case 'e': ecc_offset = strtoul(optarg, NULL, 0); break; default: usage(argv[0]); } } argc -= optind; if (argc < 2) usage(argv[0]); argv += optind; infd = open(argv[0], O_RDONLY, 0); if (infd < 0) { perror("open input file"); goto out; } outfd = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC, 0644); if (outfd < 0) { perror("open output file"); goto out; } page_data = malloc(page_size + oob_size); while ((bytes = read(infd, page_data, page_size)) == page_size) { int j; ecc_data = page_data + page_size + ecc_offset; for (j = 0; j < page_size / 256; j++) { nand_calculate_ecc(page_data + j * 256, ecc_data); ecc_data += 3; } write(outfd, page_data, page_size + oob_size); } ret = 0; out: if (infd >= 0) close(infd); if (outfd >= 0) close(outfd); if (page_data) free(page_data); return ret; }
/*start_address/size does not include oob */ int main(int argc, char **argv) { uint32_t start_address,size; char *nand_image; uint32_t pagenumber,pages; int nand_fd; uint32_t i,j; uint8_t page_data[BB_NAND_PAGE_SIZE+BB_NAND_OOB_SIZE]; uint8_t ecc_data[3]; if (argc!=4) { useage(); exit(1); } nand_image = argv[1]; start_address = strtol(argv[2],NULL,0); size = strtol(argv[3],NULL,0); nand_fd = open(nand_image,O_RDWR); if (nand_fd<0) { printf("Can not open nand image %s \n",nand_image); exit(1); } if (start_address>=BB_NAND_SIZE) { printf("start_address can no be more than 0x%x \n",BB_NAND_SIZE); exit(1); } if ((start_address%BB_NAND_PAGE_SIZE)!=0) { printf("start_address should be aligned to page boundary \n"); exit(1); } if (size==0) { printf("size can no be zero \n"); exit(1); } if ((size%BB_NAND_PAGE_SIZE)!=0) { printf("size should be aligned to page boundary \n"); exit(1); } pagenumber = start_address/BB_NAND_PAGE_SIZE; pages = size/BB_NAND_PAGE_SIZE; for (i=0;i<pages;i++) { lseek(nand_fd,pagenumber*(BB_NAND_PAGE_SIZE+BB_NAND_OOB_SIZE),SEEK_SET); read(nand_fd,page_data,BB_NAND_PAGE_SIZE+BB_NAND_OOB_SIZE); for (j=0;j<BB_NAND_PAGE_SIZE/256;j++) { nand_calculate_ecc(page_data+j*256,ecc_data); memcpy(page_data+BB_NAND_PAGE_SIZE+BB_NAND_ECC_OFFSET+j*3,ecc_data,3); } lseek(nand_fd,pagenumber*(BB_NAND_PAGE_SIZE+BB_NAND_OOB_SIZE),SEEK_SET); write(nand_fd,page_data,BB_NAND_PAGE_SIZE+BB_NAND_OOB_SIZE); pagenumber++; } close(nand_fd); return (1); }