1 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only 2 /* 3 * calculate ecc code for nand flash 4 * 5 * Copyright (C) 2008 yajin <yajin@vm-kernel.org> 6 * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name> 7 */ 8 9 10 #include <sys/types.h> 11 #include <sys/stat.h> 12 #include <unistd.h> 13 #include <stdlib.h> 14 #include <stdint.h> 15 #include <fcntl.h> 16 #include <stdio.h> 17 18 #define DEF_NAND_PAGE_SIZE 2048 19 #define DEF_NAND_OOB_SIZE 64 20 #define DEF_NAND_ECC_OFFSET 0x28 21 22 static int page_size = DEF_NAND_PAGE_SIZE; 23 static int oob_size = DEF_NAND_OOB_SIZE; 24 static int ecc_offset = DEF_NAND_ECC_OFFSET; 25 26 /* 27 * Pre-calculated 256-way 1 byte column parity 28 */ 29 static const uint8_t nand_ecc_precalc_table[] = { 30 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, 31 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, 32 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, 33 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, 34 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, 35 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, 36 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, 37 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, 38 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, 39 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, 40 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, 41 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, 42 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, 43 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, 44 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, 45 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 46 }; 47 48 /** 49 * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block 50 * @dat: raw data 51 * @ecc_code: buffer for ECC 52 */ 53 int nand_calculate_ecc(const uint8_t *dat, 54 uint8_t *ecc_code) 55 { 56 uint8_t idx, reg1, reg2, reg3, tmp1, tmp2; 57 int i; 58 59 /* Initialize variables */ 60 reg1 = reg2 = reg3 = 0; 61 62 /* Build up column parity */ 63 for(i = 0; i < 256; i++) { 64 /* Get CP0 - CP5 from table */ 65 idx = nand_ecc_precalc_table[*dat++]; 66 reg1 ^= (idx & 0x3f); 67 68 /* All bit XOR = 1 ? */ 69 if (idx & 0x40) { 70 reg3 ^= (uint8_t) i; 71 reg2 ^= ~((uint8_t) i); 72 } 73 } 74 75 /* Create non-inverted ECC code from line parity */ 76 tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */ 77 tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */ 78 tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */ 79 tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */ 80 tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */ 81 tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */ 82 tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */ 83 tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */ 84 85 tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */ 86 tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */ 87 tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */ 88 tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */ 89 tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */ 90 tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */ 91 tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */ 92 tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */ 93 94 /* Calculate final ECC code */ 95 #ifdef CONFIG_MTD_NAND_ECC_SMC 96 ecc_code[0] = ~tmp2; 97 ecc_code[1] = ~tmp1; 98 #else 99 ecc_code[0] = ~tmp1; 100 ecc_code[1] = ~tmp2; 101 #endif 102 ecc_code[2] = ((~reg1) << 2) | 0x03; 103 104 return 0; 105 } 106 107 /* 108 * usage: bb-nandflash-ecc start_address size 109 */ 110 void usage(const char *prog) 111 { 112 fprintf(stderr, "Usage: %s [options] <input> <output>\n" 113 "Options:\n" 114 " -p <pagesize> NAND page size (default: %d)\n" 115 " -o <oobsize> NAND OOB size (default: %d)\n" 116 " -e <offset> NAND ECC offset (default: %d)\n" 117 "\n", prog, DEF_NAND_PAGE_SIZE, DEF_NAND_OOB_SIZE, 118 DEF_NAND_ECC_OFFSET); 119 exit(1); 120 } 121 122 /*start_address/size does not include oob 123 */ 124 int main(int argc, char **argv) 125 { 126 uint8_t *page_data = NULL; 127 uint8_t *ecc_data; 128 int infd = -1, outfd = -1; 129 int ret = 1; 130 ssize_t bytes; 131 int ch; 132 133 while ((ch = getopt(argc, argv, "e:o:p:")) != -1) { 134 switch(ch) { 135 case 'p': 136 page_size = strtoul(optarg, NULL, 0); 137 break; 138 case 'o': 139 oob_size = strtoul(optarg, NULL, 0); 140 break; 141 case 'e': 142 ecc_offset = strtoul(optarg, NULL, 0); 143 break; 144 default: 145 usage(argv[0]); 146 } 147 } 148 argc -= optind; 149 if (argc < 2) 150 usage(argv[0]); 151 152 argv += optind; 153 154 infd = open(argv[0], O_RDONLY, 0); 155 if (infd < 0) { 156 perror("open input file"); 157 goto out; 158 } 159 160 outfd = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC, 0644); 161 if (outfd < 0) { 162 perror("open output file"); 163 goto out; 164 } 165 166 page_data = malloc(page_size + oob_size); 167 168 while ((bytes = read(infd, page_data, page_size)) == page_size) { 169 int j; 170 171 ecc_data = page_data + page_size + ecc_offset; 172 for (j = 0; j < page_size / 256; j++) 173 { 174 nand_calculate_ecc(page_data + j * 256, ecc_data); 175 ecc_data += 3; 176 } 177 write(outfd, page_data, page_size + oob_size); 178 } 179 180 ret = 0; 181 out: 182 if (infd >= 0) 183 close(infd); 184 if (outfd >= 0) 185 close(outfd); 186 if (page_data) 187 free(page_data); 188 return ret; 189 } 190 191
This page was automatically generated by LXR 0.3.1. • OpenWrt