ramips: fix USW-Flex reversed switch-port order
[openwrt/staging/jow.git] / tools / firmware-utils / src / nand_ecc.c
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