1 | /* |
2 | * Copyright (C) 2007 Ingenic Semiconductor Inc. |
3 | * Author: Regen Huang <lhhuang@ingenic.cn> |
4 | * |
5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License as |
7 | * published by the Free Software Foundation; either version 2 of |
8 | * the License, or (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
18 | * MA 02111-1307 USA |
19 | */ |
20 | |
21 | #include "target/jz4760.h" |
22 | #include "target/nandflash.h" |
23 | #include "target/usb_boot.h" |
24 | #include "target/xburst_types.h" |
25 | #include "usb_boot_defines.h" |
26 | |
27 | #define USE_BCH 1 |
28 | #define USE_PN 1 |
29 | #define NEMC_PNCR (NEMC_BASE + 0x100) |
30 | #define NEMC_PNDR (NEMC_BASE + 0x104) |
31 | #define REG_NEMC_PNCR REG32(NEMC_PNCR) |
32 | #define REG_NEMC_PNDR REG32(NEMC_PNDR) |
33 | |
34 | #define pn_enable() \ |
35 | do {\ |
36 | REG_NEMC_PNCR = 0x3;\ |
37 | }while(0) |
38 | #define pn_disable() \ |
39 | do {\ |
40 | REG_NEMC_PNCR = 0x0;\ |
41 | }while(0) |
42 | |
43 | #ifdef DEBUG |
44 | #define dprintf(n...) printf(n) |
45 | #else |
46 | #define dprintf(n...) |
47 | #endif |
48 | |
49 | /* for spl */ |
50 | #define ECC_BLOCK0 256 |
51 | #define PAR_SIZE_SPL 78 |
52 | #define PAR_SIZE_SPL1 ((PAR_SIZE_SPL+1)/2) |
53 | |
54 | /* |
55 | * NAND flash definitions |
56 | */ |
57 | #define NAND_DATAPORT 0xBA000000 |
58 | #define NAND_ADDRPORT 0xBA800000 |
59 | #define NAND_COMMPORT 0xBA400000 |
60 | |
61 | #define ECC_BLOCK 512 |
62 | static int par_size, par_size1; |
63 | |
64 | #define CMD_READA 0x00 |
65 | #define CMD_READB 0x01 |
66 | #define CMD_READC 0x50 |
67 | #define CMD_ERASE_SETUP 0x60 |
68 | #define CMD_ERASE 0xD0 |
69 | #define CMD_READ_STATUS 0x70 |
70 | #define CMD_CONFIRM 0x30 |
71 | #define CMD_SEQIN 0x80 |
72 | #define CMD_PGPROG 0x10 |
73 | #define CMD_READID 0x90 |
74 | |
75 | #define __nand_cmd(n) (REG8(NAND_COMMPORT) = (n)) |
76 | #define __nand_addr(n) (REG8(NAND_ADDRPORT) = (n)) |
77 | #define __nand_data8() REG8(NAND_DATAPORT) |
78 | #define __nand_data16() REG16(NAND_DATAPORT) |
79 | |
80 | #define __nand_enable() (REG_NEMC_NFCSR |= NEMC_NFCSR_NFE1 | NEMC_NFCSR_NFCE1) |
81 | #define __nand_disable() (REG_NEMC_NFCSR &= ~(NEMC_NFCSR_NFCE1)) |
82 | |
83 | static int bus = 8, row = 2, pagesize = 512, oobsize = 16, ppb = 32; |
84 | static int eccpos = 3, bchbit = 8, par_size = 26, par_size1 = 13, forceerase = 1, wp_pin = 0; |
85 | static int oobfs = 0; /* 1:store file system information in oob, 0:don't store */ |
86 | static int oobecc = 0; /* Whether the oob data of the binary contains ECC data? */ |
87 | static int bad_block_page = 127; /* Specify the page number of badblock flag inside a block */ |
88 | static u32 bad_block_pos = 0; /* Specify the badblock flag offset inside the oob */ |
89 | static u8 oob_buf[256] = {0}; |
90 | extern struct hand Hand; |
91 | extern u16 handshake_PKT[4]; |
92 | |
93 | static inline void __nand_sync(void) |
94 | { |
95 | unsigned int timeout = 1000; |
96 | while ((REG_GPIO_PXPIN(0) & 0x00100000) && timeout--); |
97 | while (!(REG_GPIO_PXPIN(0) & 0x00100000)); |
98 | } |
99 | |
100 | /* |
101 | * External routines |
102 | */ |
103 | extern void flush_cache_all(void); |
104 | extern int serial_init(void); |
105 | extern void serial_puts(const char *s); |
106 | extern void sdram_init(void); |
107 | extern void pll_init(void); |
108 | |
109 | static int read_oob(void *buf, u32 size, u32 pg); |
110 | static int nand_data_write8(char *buf, int count); |
111 | static int nand_data_write16(char *buf, int count); |
112 | static int nand_data_read8(char *buf, int count); |
113 | static int nand_data_read16(char *buf, int count); |
114 | |
115 | static int (*write_proc)(char *, int) = NULL; |
116 | static int (*read_proc)(char *, int) = NULL; |
117 | |
118 | int read_nand_spl_page(unsigned char *databuf, unsigned int pageaddr); |
119 | int program_nand_spl_page(unsigned char *databuf, unsigned int pageaddr); |
120 | |
121 | /* |
122 | * NAND flash routines |
123 | */ |
124 | |
125 | static inline void nand_read_buf16(void *buf, int count) |
126 | { |
127 | int i; |
128 | u16 *p = (u16 *)buf; |
129 | |
130 | for (i = 0; i < count; i += 2) |
131 | *p++ = __nand_data16(); |
132 | } |
133 | |
134 | static inline void nand_read_buf8(void *buf, int count) |
135 | { |
136 | int i; |
137 | u8 *p = (u8 *)buf; |
138 | |
139 | for (i = 0; i < count; i++) |
140 | *p++ = __nand_data8(); |
141 | } |
142 | |
143 | static inline void nand_read_buf(void *buf, int count, int bw) |
144 | { |
145 | if (bw == 8) |
146 | nand_read_buf8(buf, count); |
147 | else |
148 | nand_read_buf16(buf, count); |
149 | } |
150 | |
151 | inline void nand_enable_4760(unsigned int csn) |
152 | { |
153 | //modify this fun to a specifical borad |
154 | //this fun to enable the chip select pin csn |
155 | //the choosn chip can work after this fun |
156 | //dprintf("\n Enable chip select :%d",csn); |
157 | __gpio_as_nand_8bit(1); |
158 | __nand_enable(); |
159 | } |
160 | |
161 | inline void nand_disable_4760(unsigned int csn) |
162 | { |
163 | //modify this fun to a specifical borad |
164 | //this fun to enable the chip select pin csn |
165 | //the choosn chip can not work after this fun |
166 | //dprintf("\n Disable chip select :%d",csn); |
167 | __nand_disable(); |
168 | } |
169 | |
170 | void udelay(unsigned long usec) |
171 | { |
172 | volatile int i, j; |
173 | |
174 | for (i = 0; i < usec; i++) { |
175 | for (j = 0; j < 100; j++) { |
176 | ; |
177 | } |
178 | } |
179 | } |
180 | |
181 | unsigned int nand_query_4760(u8 *id) |
182 | { |
183 | __nand_disable(); |
184 | __nand_enable(); |
185 | #if 1 |
186 | __nand_cmd(0xff); |
187 | __nand_sync(); |
188 | #endif |
189 | __nand_cmd(CMD_READID); |
190 | __nand_addr(0); |
191 | udelay(1000); |
192 | #if 1 |
193 | id[0] = __nand_data8(); //VID |
194 | id[1] = __nand_data8(); //PID |
195 | id[2] = __nand_data8(); //CHIP ID |
196 | id[3] = __nand_data8(); //PAGE ID |
197 | id[4] = __nand_data8(); //PLANE ID |
198 | |
199 | serial_put_hex(id[0]); |
200 | serial_put_hex(id[1]); |
201 | serial_put_hex(id[2]); |
202 | serial_put_hex(id[3]); |
203 | serial_put_hex(id[4]); |
204 | |
205 | #endif |
206 | |
207 | __nand_disable(); |
208 | return 0; |
209 | } |
210 | |
211 | int nand_init_4760(int bus_width, int row_cycle, int page_size, int page_per_block, |
212 | int bch_bit, int ecc_pos, int bad_pos, int bad_page, int force) |
213 | { |
214 | bus = bus_width; |
215 | row = row_cycle; |
216 | pagesize = page_size; |
217 | oobsize = pagesize / 32; |
218 | ppb = page_per_block; |
219 | bchbit = bch_bit; |
220 | forceerase = force; |
221 | eccpos = ecc_pos; |
222 | bad_block_pos = bad_pos; |
223 | bad_block_page = bad_page; |
224 | wp_pin = Hand.nand_wppin; |
225 | |
226 | if(bchbit == 4) |
227 | par_size = 13; |
228 | else if(bchbit == 8) |
229 | par_size = 26; |
230 | else if(bchbit == 12) |
231 | par_size =39; |
232 | else if(bchbit == 16) |
233 | par_size =52; |
234 | else if(bchbit == 20) |
235 | par_size = 65; |
236 | else |
237 | par_size ==78; |
238 | |
239 | par_size1 = (par_size + 1)/2; |
240 | |
241 | /* Initialize NAND Flash Pins */ |
242 | if (bus == 8) { |
243 | REG_NEMC_SMCR1 = 0x0d444400; |
244 | __gpio_as_nand_8bit(1); |
245 | write_proc = nand_data_write8; |
246 | read_proc = nand_data_read8; |
247 | } else { |
248 | REG_NEMC_SMCR1 = 0x0d444400 | 0x40; |
249 | __gpio_as_nand_16bit(1); |
250 | write_proc = nand_data_write16; |
251 | read_proc = nand_data_read16; |
252 | } |
253 | |
254 | if (wp_pin) |
255 | { |
256 | __gpio_as_output(wp_pin); |
257 | __gpio_disable_pull(wp_pin); |
258 | } |
259 | __nand_enable(); |
260 | |
261 | /* If ECCPOS isn't configured in config file, the initial value is 0 */ |
262 | if (eccpos == 0) { |
263 | eccpos = 3; |
264 | } |
265 | |
266 | #ifdef USE_BCH |
267 | serial_puts("Use bch.\n"); |
268 | #else |
269 | serial_puts("Not use bch.\n"); |
270 | #endif |
271 | #ifdef USE_PN |
272 | serial_puts("Use PN.\n"); |
273 | #else |
274 | serial_puts("Not use PN.\n"); |
275 | #endif |
276 | return 0; |
277 | } |
278 | |
279 | /* |
280 | * Correct the error bit in ECC_BLOCK bytes data |
281 | */ |
282 | static void bch_correct(unsigned char *dat, int idx) |
283 | { |
284 | int i, bit; // the 'bit' of i byte is error |
285 | i = (idx - 1) >> 3; |
286 | bit = (idx - 1) & 0x7; |
287 | if (i < ECC_BLOCK) |
288 | dat[i] ^= (1 << bit); |
289 | } |
290 | |
291 | u32 nand_read_oob_4760(void *buf, u32 startpage, u32 pagenum) |
292 | { |
293 | u32 cnt, cur_page; |
294 | u8 *tmpbuf; |
295 | |
296 | tmpbuf = (u8 *)buf; |
297 | |
298 | cur_page = startpage; |
299 | cnt = 0; |
300 | |
301 | while (cnt < pagenum) { |
302 | read_oob((void *)tmpbuf, oobsize, cur_page); |
303 | tmpbuf += oobsize; |
304 | cur_page++; |
305 | cnt++; |
306 | } |
307 | |
308 | return cur_page; |
309 | } |
310 | |
311 | static int nand_check_block(u32 block) |
312 | { |
313 | u32 pg,i; |
314 | |
315 | if ( bad_block_page >= ppb ) //do absolute bad block detect! |
316 | { |
317 | pg = block * ppb + 0; |
318 | read_oob(oob_buf, oobsize, pg); |
319 | if ( oob_buf[0] != 0xff || oob_buf[1] != 0xff ) |
320 | { |
321 | serial_puts("Absolute skip a bad block\n"); |
322 | serial_put_hex(block); |
323 | return 1; |
324 | } |
325 | |
326 | pg = block * ppb + 1; |
327 | read_oob(oob_buf, oobsize, pg); |
328 | if ( oob_buf[0] != 0xff || oob_buf[1] != 0xff ) |
329 | { |
330 | serial_puts("Absolute skip a bad block\n"); |
331 | serial_put_hex(block); |
332 | return 1; |
333 | } |
334 | |
335 | pg = block * ppb + ppb - 2 ; |
336 | read_oob(oob_buf, oobsize, pg); |
337 | if ( oob_buf[0] != 0xff || oob_buf[1] != 0xff ) |
338 | { |
339 | serial_puts("Absolute skip a bad block\n"); |
340 | serial_put_hex(block); |
341 | return 1; |
342 | } |
343 | |
344 | pg = block * ppb + ppb - 1 ; |
345 | read_oob(oob_buf, oobsize, pg); |
346 | if ( oob_buf[0] != 0xff || oob_buf[1] != 0xff ) |
347 | { |
348 | serial_puts("Absolute skip a bad block\n"); |
349 | serial_put_hex(block); |
350 | return 1; |
351 | } |
352 | |
353 | } |
354 | else |
355 | { |
356 | pg = block * ppb + bad_block_page; |
357 | read_oob(oob_buf, oobsize, pg); |
358 | if (oob_buf[bad_block_pos] != 0xff) |
359 | { |
360 | serial_put_hex(oob_buf[bad_block_pos]); |
361 | serial_puts("Skip a bad block at:\n"); |
362 | serial_put_hex(block); |
363 | |
364 | return 1; |
365 | } |
366 | |
367 | } |
368 | return 0; |
369 | } |
370 | |
371 | u32 nand_erase_4760(int blk_num, int sblk, int force) |
372 | { |
373 | int i, j; |
374 | u32 cur, rowaddr; |
375 | |
376 | __nand_enable(); |
377 | |
378 | if (wp_pin) |
379 | __gpio_set_pin(wp_pin); |
380 | cur = sblk * ppb; |
381 | for (i = 0; i < blk_num; i++) { |
382 | rowaddr = cur; |
383 | |
384 | if (!force) /* if set, erase anything */ |
385 | if (nand_check_block(cur/ppb)) |
386 | { |
387 | cur += ppb; |
388 | blk_num += Hand.nand_plane; |
389 | continue; |
390 | } |
391 | |
392 | __nand_cmd(CMD_ERASE_SETUP); |
393 | |
394 | for (j = 0; j < row; j++) { |
395 | __nand_addr(rowaddr & 0xff); |
396 | rowaddr >>= 8; |
397 | } |
398 | __nand_cmd(CMD_ERASE); |
399 | __nand_sync(); |
400 | __nand_cmd(CMD_READ_STATUS); |
401 | |
402 | if (__nand_data8() & 0x01) |
403 | { |
404 | serial_puts("Erase fail at "); |
405 | serial_put_hex(cur / ppb); |
406 | nand_mark_bad_4760(cur / ppb); |
407 | cur += ppb; |
408 | blk_num += Hand.nand_plane; |
409 | continue; |
410 | } |
411 | cur += ppb; |
412 | } |
413 | |
414 | if (wp_pin) |
415 | __gpio_clear_pin(wp_pin); |
416 | |
417 | __nand_disable(); |
418 | return cur; |
419 | } |
420 | |
421 | /* |
422 | * Read oob |
423 | */ |
424 | static int read_oob(void *buf, unsigned int size, unsigned int pg) |
425 | { |
426 | unsigned int i, coladdr, rowaddr; |
427 | |
428 | __nand_enable(); |
429 | |
430 | if (pagesize == 512) |
431 | coladdr = 0; |
432 | else { |
433 | if (bus == 8) |
434 | coladdr = pagesize; |
435 | else |
436 | coladdr = pagesize / 2; |
437 | } |
438 | |
439 | if (pagesize == 512) |
440 | /* Send READOOB command */ |
441 | __nand_cmd(CMD_READC); |
442 | else |
443 | /* Send READ0 command */ |
444 | __nand_cmd(CMD_READA); |
445 | |
446 | /* Send column address */ |
447 | __nand_addr(coladdr & 0xff); |
448 | if (pagesize != 512) |
449 | __nand_addr(coladdr >> 8); |
450 | |
451 | /* Send page address */ |
452 | rowaddr = pg; |
453 | for (i = 0; i < row; i++) { |
454 | __nand_addr(rowaddr & 0xff); |
455 | rowaddr >>= 8; |
456 | } |
457 | |
458 | /* Send READSTART command for 2048 ps NAND */ |
459 | if (pagesize != 512) |
460 | __nand_cmd(CMD_CONFIRM); |
461 | |
462 | /* Wait for device ready */ |
463 | __nand_sync(); |
464 | |
465 | /* Read oob data */ |
466 | read_proc(buf, size); |
467 | |
468 | if (pagesize == 512) |
469 | __nand_sync(); |
470 | |
471 | __nand_disable(); |
472 | return 0; |
473 | } |
474 | |
475 | /* |
476 | * Read data <pagenum> pages from <startpage> page. |
477 | * Don't skip bad block. |
478 | * Don't use HW ECC. |
479 | */ |
480 | u32 nand_read_raw_4760(void *buf, u32 startpage, u32 pagenum, int option) |
481 | { |
482 | u32 cnt, j; |
483 | u32 cur_page, rowaddr; |
484 | u8 *tmpbuf; |
485 | |
486 | tmpbuf = (u8 *)buf; |
487 | |
488 | cur_page = startpage; |
489 | cnt = 0; |
490 | while (cnt < pagenum) { |
491 | if ((cur_page % ppb) == 0) { |
492 | if (nand_check_block(cur_page / ppb)) { |
493 | cur_page += ppb; // Bad block, set to next block |
494 | continue; |
495 | } |
496 | } |
497 | |
498 | __nand_cmd(CMD_READA); |
499 | __nand_addr(0); |
500 | if (pagesize != 512) |
501 | __nand_addr(0); |
502 | |
503 | rowaddr = cur_page; |
504 | for (j = 0; j < row; j++) { |
505 | __nand_addr(rowaddr & 0xff); |
506 | rowaddr >>= 8; |
507 | } |
508 | |
509 | if (pagesize != 512) |
510 | __nand_cmd(CMD_CONFIRM); |
511 | |
512 | __nand_sync(); |
513 | #ifdef USE_PN |
514 | pn_enable(); |
515 | #endif |
516 | |
517 | read_proc(tmpbuf, pagesize); |
518 | |
519 | tmpbuf += pagesize; |
520 | if (option != NO_OOB) |
521 | { |
522 | read_oob(tmpbuf, oobsize, cur_page); |
523 | tmpbuf += oobsize; |
524 | } |
525 | #ifdef USE_PN |
526 | pn_disable(); |
527 | #endif |
528 | cur_page++; |
529 | cnt++; |
530 | } |
531 | |
532 | return cur_page; |
533 | } |
534 | |
535 | #ifndef CFG_NAND_BADBLOCK_PAGE |
536 | #define CFG_NAND_BADBLOCK_PAGE 0 /* NAND bad block was marked at this page in a block, starting from 0 */ |
537 | #endif |
538 | |
539 | /* |
540 | * Read data <pagenum> pages from <startpage> page. |
541 | * Skip bad block if detected. |
542 | * HW ECC is used. |
543 | */ |
544 | u32 nand_read_4760(void *buf, u32 startpage, u32 pagenum, int option) |
545 | { |
546 | u32 j, k; |
547 | u32 cur_page, cur_blk, cnt, rowaddr, ecccnt; |
548 | u8 *tmpbuf, *p, flag = 0; |
549 | u32 oob_per_eccsize; |
550 | u32 spl_size = 8 * 1024 / pagesize; |
551 | ecccnt = pagesize / ECC_BLOCK; |
552 | oob_per_eccsize = eccpos / ecccnt; |
553 | |
554 | cur_page = startpage; |
555 | cnt = 0; |
556 | |
557 | if(startpage >= 0 && startpage < spl_size * 2) |
558 | tmpbuf = buf + 8 * 1024; |
559 | else |
560 | tmpbuf = buf; |
561 | |
562 | __nand_enable(); |
563 | while (cnt < pagenum) { |
564 | if (cur_page < spl_size * 2) { |
565 | u32 m; |
566 | for (m=0; (m < pagenum) && (m < spl_size); m++) |
567 | read_nand_spl_page(buf + pagesize * m, m * 2); |
568 | |
569 | cur_page = ppb * 2; |
570 | cnt = spl_size; |
571 | continue; |
572 | } |
573 | |
574 | /* If this is the first page of the block, check for bad. */ |
575 | if ((cur_page % ppb) == 0) { |
576 | cur_blk = cur_page / ppb; |
577 | if (nand_check_block(cur_blk)) { |
578 | cur_page += ppb; // Bad block, set to next block |
579 | continue; |
580 | } |
581 | } |
582 | __nand_cmd(CMD_READA); |
583 | |
584 | __nand_addr(0); |
585 | if (pagesize != 512) |
586 | __nand_addr(0); |
587 | |
588 | rowaddr = cur_page; |
589 | for (j = 0; j < row; j++) { |
590 | __nand_addr(rowaddr & 0xff); |
591 | rowaddr >>= 8; |
592 | } |
593 | |
594 | if (pagesize != 512) |
595 | __nand_cmd(CMD_CONFIRM); |
596 | |
597 | __nand_sync(); |
598 | |
599 | #ifdef USE_PN |
600 | // pn_enable(); |
601 | #endif |
602 | /* Read data */ |
603 | read_proc((char *)tmpbuf, pagesize); |
604 | |
605 | /* read oob first */ |
606 | read_proc((char *)oob_buf, oobsize); |
607 | #ifdef USE_PN |
608 | // pn_disable(); |
609 | #endif |
610 | |
611 | for (j = 0; j < ecccnt; j++) { |
612 | u32 stat; |
613 | flag = 0; |
614 | REG_BCH_INTS = 0xffffffff; |
615 | |
616 | if (cur_page >= 16384 / pagesize) |
617 | { |
618 | if(bchbit == 4) |
619 | __ecc_decoding_4bit(); |
620 | else if(bchbit == 8) |
621 | __ecc_decoding_8bit(); |
622 | else if(bchbit == 12) |
623 | __ecc_decoding_12bit(); |
624 | else if(bchbit == 16) |
625 | __ecc_decoding_16bit(); |
626 | else if(bchbit == 20) |
627 | __ecc_decoding_20bit(); |
628 | else |
629 | __ecc_decoding_24bit(); |
630 | } |
631 | else |
632 | { |
633 | __ecc_decoding_24bit(); |
634 | } |
635 | |
636 | if (option != NO_OOB) |
637 | __ecc_cnt_dec(ECC_BLOCK*2 + oob_per_eccsize*2 + par_size); |
638 | else |
639 | __ecc_cnt_dec(ECC_BLOCK*2 + par_size); |
640 | |
641 | for (k = 0; k < ECC_BLOCK; k++) { |
642 | REG_BCH_DR = tmpbuf[k]; |
643 | } |
644 | |
645 | if (option != NO_OOB) { |
646 | for (k = 0; k < oob_per_eccsize; k++) { |
647 | REG_BCH_DR = oob_buf[oob_per_eccsize * j + k]; |
648 | } |
649 | } |
650 | |
651 | for (k = 0; k < par_size1; k++) { |
652 | REG_BCH_DR = oob_buf[eccpos + j * par_size1 + k]; |
653 | if (oob_buf[eccpos + j * par_size1 + k] != 0xff) //why? |
654 | flag = 1; |
655 | } |
656 | |
657 | /* Wait for completion */ |
658 | __ecc_decode_sync(); |
659 | __ecc_disable(); |
660 | /* Check decoding */ |
661 | stat = REG_BCH_INTS; |
662 | |
663 | if (stat & BCH_INTS_ERR) { |
664 | if (stat & BCH_INTS_UNCOR) { |
665 | if (flag) |
666 | { |
667 | dprintf("Uncorrectable ECC error occurred\n"); |
668 | handshake_PKT[3] = 1; |
669 | } |
670 | } |
671 | else { |
672 | handshake_PKT[3] = 0; |
673 | unsigned int errcnt = (stat & BCH_INTS_ERRC_MASK) >> BCH_INTS_ERRC_BIT; |
674 | switch (errcnt) { |
675 | case 24: |
676 | dprintf("correct 24th error\n"); |
677 | bch_correct(tmpbuf, (REG_BCH_ERR11 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
678 | case 23: |
679 | bch_correct(tmpbuf, (REG_BCH_ERR11 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
680 | case 22: |
681 | bch_correct(tmpbuf, (REG_BCH_ERR10 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
682 | case 21: |
683 | bch_correct(tmpbuf, (REG_BCH_ERR10 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
684 | case 20: |
685 | bch_correct(tmpbuf, (REG_BCH_ERR9 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
686 | case 19: |
687 | bch_correct(tmpbuf, (REG_BCH_ERR9 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
688 | case 18: |
689 | bch_correct(tmpbuf, (REG_BCH_ERR8 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
690 | case 17: |
691 | bch_correct(tmpbuf, (REG_BCH_ERR8 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
692 | case 16: |
693 | bch_correct(tmpbuf, (REG_BCH_ERR7 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
694 | case 15: |
695 | bch_correct(tmpbuf, (REG_BCH_ERR7 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
696 | case 14: |
697 | bch_correct(tmpbuf, (REG_BCH_ERR6 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
698 | case 13: |
699 | bch_correct(tmpbuf, (REG_BCH_ERR6 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
700 | case 12: |
701 | bch_correct(tmpbuf, (REG_BCH_ERR5 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
702 | case 11: |
703 | bch_correct(tmpbuf, (REG_BCH_ERR5 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
704 | case 10: |
705 | bch_correct(tmpbuf, (REG_BCH_ERR4 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
706 | case 9: |
707 | bch_correct(tmpbuf, (REG_BCH_ERR4 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
708 | case 8: |
709 | dprintf("correct 8th error\n"); |
710 | bch_correct(tmpbuf, (REG_BCH_ERR3 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
711 | case 7: |
712 | dprintf("correct 7th error\n"); |
713 | bch_correct(tmpbuf, (REG_BCH_ERR3 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
714 | case 6: |
715 | dprintf("correct 6th error\n"); |
716 | bch_correct(tmpbuf, (REG_BCH_ERR2 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
717 | case 5: |
718 | dprintf("correct 5th error\n"); |
719 | bch_correct(tmpbuf, (REG_BCH_ERR2 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
720 | case 4: |
721 | dprintf("correct 4th error\n"); |
722 | bch_correct(tmpbuf, (REG_BCH_ERR1 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
723 | case 3: |
724 | dprintf("correct 3th error\n"); |
725 | bch_correct(tmpbuf, (REG_BCH_ERR1 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
726 | case 2: |
727 | dprintf("correct 2th error\n"); |
728 | bch_correct(tmpbuf, (REG_BCH_ERR0 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
729 | case 1: |
730 | dprintf("correct 1th error\n"); |
731 | bch_correct(tmpbuf, (REG_BCH_ERR0 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
732 | break; |
733 | default: |
734 | dprintf("no error\n"); |
735 | break; |
736 | } |
737 | } |
738 | } |
739 | /* increment pointer */ |
740 | tmpbuf += ECC_BLOCK; |
741 | } |
742 | |
743 | switch (option) |
744 | { |
745 | case OOB_ECC: |
746 | for (j = 0; j < oobsize; j++) |
747 | tmpbuf[j] = oob_buf[j]; |
748 | tmpbuf += oobsize; |
749 | break; |
750 | case OOB_NO_ECC: |
751 | for (j = 0; j < par_size1 * ecccnt; j++) |
752 | oob_buf[eccpos + j] = 0xff; |
753 | for (j = 0; j < oobsize; j++) |
754 | tmpbuf[j] = oob_buf[j]; |
755 | tmpbuf += oobsize; |
756 | break; |
757 | case NO_OOB: |
758 | break; |
759 | } |
760 | |
761 | cur_page++; |
762 | cnt++; |
763 | } |
764 | |
765 | __nand_disable(); |
766 | |
767 | return cur_page; |
768 | } |
769 | |
770 | int read_nand_spl_page(unsigned char *databuf, unsigned int pageaddr) |
771 | { |
772 | unsigned int i, j; |
773 | unsigned int rowaddr, ecccnt; |
774 | u8 *tmpbuf; |
775 | char eccbuf[1024]; |
776 | |
777 | for(i=0; i<1024; i++) |
778 | eccbuf[i] = 0xff; |
779 | |
780 | /* read oob first */ |
781 | __nand_enable(); |
782 | |
783 | ecccnt = pagesize / ECC_BLOCK0; |
784 | __nand_cmd(CMD_READA); |
785 | |
786 | __nand_addr(0); |
787 | if (pagesize != 512) |
788 | __nand_addr(0); |
789 | |
790 | rowaddr = pageaddr+1; //?? |
791 | |
792 | for (i = 0; i < row; i++) { |
793 | __nand_addr(rowaddr & 0xff); |
794 | rowaddr >>= 8; |
795 | } |
796 | |
797 | if (pagesize != 512) |
798 | __nand_cmd(CMD_CONFIRM); |
799 | |
800 | __nand_sync(); |
801 | |
802 | #ifdef USE_PN |
803 | pn_enable(); |
804 | #endif |
805 | /* Read ecc */ |
806 | read_proc(eccbuf, pagesize/ECC_BLOCK0*PAR_SIZE_SPL1); |
807 | |
808 | #ifdef USE_PN |
809 | pn_disable(); |
810 | #endif |
811 | |
812 | __nand_disable(); |
813 | |
814 | /* read data */ |
815 | __nand_enable(); |
816 | |
817 | ecccnt = pagesize / ECC_BLOCK0; |
818 | |
819 | __nand_cmd(CMD_READA); |
820 | |
821 | __nand_addr(0); |
822 | if (pagesize != 512) |
823 | __nand_addr(0); |
824 | |
825 | rowaddr = pageaddr; |
826 | |
827 | for (i = 0; i < row; i++) { |
828 | __nand_addr(rowaddr & 0xff); |
829 | rowaddr >>= 8; |
830 | } |
831 | |
832 | if (pagesize != 512) |
833 | __nand_cmd(CMD_CONFIRM); |
834 | |
835 | __nand_sync(); |
836 | |
837 | #ifdef USE_EFNAND |
838 | __nand_cmd(CMD_READ_STATUS); |
839 | |
840 | if (__nand_data8() & 0x01) { /* page program error */ |
841 | __nand_disable(); |
842 | |
843 | return 1; |
844 | } |
845 | __nand_cmd(CMD_READA); |
846 | #endif |
847 | |
848 | tmpbuf = (u8 *)databuf; |
849 | for(i=0; i<pagesize; i++) |
850 | tmpbuf[i] = 0xff; |
851 | |
852 | for (i = 0; i < ecccnt; i++) { |
853 | unsigned int stat; |
854 | |
855 | #ifdef USE_PN |
856 | if (!(((pageaddr % 64) == 0) && (i == 0))) |
857 | pn_enable(); |
858 | else |
859 | dprintf("don't use pn. pageaddr=%d ecccnt=%d\n", pageaddr,i); |
860 | #endif |
861 | /* Read data */ |
862 | read_proc((char *)tmpbuf, ECC_BLOCK0); |
863 | #ifdef USE_PN |
864 | pn_disable(); |
865 | #endif |
866 | |
867 | #ifdef USE_BCH |
868 | REG_BCH_INTS = 0xffffffff; |
869 | |
870 | __ecc_decoding_24bit(); |
871 | |
872 | __ecc_cnt_dec(2 * ECC_BLOCK0 + PAR_SIZE_SPL); |
873 | |
874 | for (j = 0; j < ECC_BLOCK0; j++) {//if(i==1)serial_put_hex(tmpbuf[j]); |
875 | REG_BCH_DR = tmpbuf[j]; |
876 | } |
877 | |
878 | /* assume parities be wrote to data register not parity register */ |
879 | for (j = 0; j < PAR_SIZE_SPL1; j++) { |
880 | REG_BCH_DR = eccbuf[i*PAR_SIZE_SPL1 + j]; |
881 | } |
882 | |
883 | /* Wait for completion */ |
884 | __ecc_decode_sync(); |
885 | |
886 | __ecc_disable(); |
887 | |
888 | /* Check decoding */ |
889 | stat = REG_BCH_INTS; |
890 | |
891 | if (stat & BCH_INTS_ERR) { |
892 | if (stat & BCH_INTS_UNCOR) { |
893 | serial_puts("ecc Uncorrectable ECC error occurred __spl__\n"); |
894 | serial_put_hex(i); |
895 | } |
896 | else { |
897 | unsigned int errcnt = (stat & BCH_INTS_ERRC_MASK) >> BCH_INTS_ERRC_BIT; |
898 | switch (errcnt) { |
899 | case 24: |
900 | dprintf("correct 24th error\n"); |
901 | bch_correct(tmpbuf, (REG_BCH_ERR11 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
902 | case 23: |
903 | bch_correct(tmpbuf, (REG_BCH_ERR11 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
904 | case 22: |
905 | bch_correct(tmpbuf, (REG_BCH_ERR10 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
906 | case 21: |
907 | bch_correct(tmpbuf, (REG_BCH_ERR10 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
908 | case 20: |
909 | bch_correct(tmpbuf, (REG_BCH_ERR9 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
910 | case 19: |
911 | bch_correct(tmpbuf, (REG_BCH_ERR9 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
912 | case 18: |
913 | bch_correct(tmpbuf, (REG_BCH_ERR8 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
914 | case 17: |
915 | bch_correct(tmpbuf, (REG_BCH_ERR8 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
916 | case 16: |
917 | bch_correct(tmpbuf, (REG_BCH_ERR7 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
918 | case 15: |
919 | bch_correct(tmpbuf, (REG_BCH_ERR7 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
920 | case 14: |
921 | bch_correct(tmpbuf, (REG_BCH_ERR6 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
922 | case 13: |
923 | bch_correct(tmpbuf, (REG_BCH_ERR6 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
924 | case 12: |
925 | bch_correct(tmpbuf, (REG_BCH_ERR5 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
926 | case 11: |
927 | bch_correct(tmpbuf, (REG_BCH_ERR5 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
928 | case 10: |
929 | bch_correct(tmpbuf, (REG_BCH_ERR4 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
930 | case 9: |
931 | bch_correct(tmpbuf, (REG_BCH_ERR4 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
932 | case 8: |
933 | dprintf("correct 8th error\n"); |
934 | bch_correct(tmpbuf, (REG_BCH_ERR3 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
935 | case 7: |
936 | dprintf("correct 7th error\n"); |
937 | bch_correct(tmpbuf, (REG_BCH_ERR3 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
938 | case 6: |
939 | dprintf("correct 6th error\n"); |
940 | bch_correct(tmpbuf, (REG_BCH_ERR2 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
941 | case 5: |
942 | dprintf("correct 5th error\n"); |
943 | bch_correct(tmpbuf, (REG_BCH_ERR2 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
944 | case 4: |
945 | dprintf("correct 4th error\n"); |
946 | bch_correct(tmpbuf, (REG_BCH_ERR1 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
947 | case 3: |
948 | dprintf("correct 3th error\n"); |
949 | bch_correct(tmpbuf, (REG_BCH_ERR1 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
950 | case 2: |
951 | dprintf("correct 2th error\n"); |
952 | bch_correct(tmpbuf, (REG_BCH_ERR0 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
953 | case 1: |
954 | dprintf("correct 1th error\n"); |
955 | bch_correct(tmpbuf, (REG_BCH_ERR0 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
956 | break; |
957 | default: |
958 | dprintf("no error\n"); |
959 | break; |
960 | } |
961 | } |
962 | } |
963 | #endif |
964 | /* increment pointer */ |
965 | tmpbuf += ECC_BLOCK0; |
966 | } |
967 | |
968 | __nand_disable(); |
969 | |
970 | return 0; |
971 | } |
972 | |
973 | u32 nand_program_4760(void *context, int spage, int pages, int option) |
974 | { |
975 | u32 i, j, cur_page, cur_blk, rowaddr; |
976 | u8 *tmpbuf; |
977 | u32 ecccnt; |
978 | u8 ecc_buf[1024], oob_buf[512]; |
979 | u32 oob_per_eccsize; |
980 | int spl_size = 8 * 1024 / pagesize; |
981 | |
982 | if (wp_pin) |
983 | __gpio_set_pin(wp_pin); |
984 | restart: |
985 | tmpbuf = (u8 *)context; |
986 | ecccnt = pagesize / ECC_BLOCK; |
987 | oob_per_eccsize = eccpos / ecccnt; |
988 | |
989 | i = 0; |
990 | cur_page = spage; |
991 | |
992 | while (i < pages) { |
993 | if (cur_page == 0) { |
994 | int k; |
995 | for(k = 0; k < spl_size; k++) { |
996 | program_nand_spl_page(context + pagesize * k, k * 2); |
997 | } |
998 | #if 0 |
999 | for(k = 0; k < spl_size; k++) { |
1000 | program_nand_spl_page(context + pagesize * k, k * 2 + ppb ); |
1001 | } |
1002 | #endif |
1003 | tmpbuf += pagesize * spl_size; |
1004 | cur_page = 2 * ppb; |
1005 | i += spl_size; |
1006 | continue; |
1007 | } |
1008 | |
1009 | if ((cur_page % ppb) == 0) { /* First page of block, test BAD. */ |
1010 | if (nand_check_block(cur_page / ppb)) { |
1011 | cur_page += ppb; /* Bad block, set to next block */ |
1012 | continue; |
1013 | } |
1014 | } |
1015 | |
1016 | if ( option != NO_OOB ) //if NO_OOB do not perform vaild check! |
1017 | { |
1018 | for ( j = 0 ; j < pagesize + oobsize; j++) |
1019 | { |
1020 | if (tmpbuf[j] != 0xff) |
1021 | break; |
1022 | } |
1023 | if ( j == oobsize + pagesize ) |
1024 | { |
1025 | tmpbuf += (pagesize + oobsize) ; |
1026 | i ++; |
1027 | cur_page ++; |
1028 | continue; |
1029 | } |
1030 | } |
1031 | |
1032 | __nand_enable(); |
1033 | __nand_sync(); |
1034 | |
1035 | if (pagesize == 512) |
1036 | __nand_cmd(CMD_READA); |
1037 | |
1038 | __nand_cmd(CMD_SEQIN); |
1039 | __nand_addr(0); |
1040 | |
1041 | if (pagesize != 512) |
1042 | __nand_addr(0); |
1043 | |
1044 | rowaddr = cur_page; |
1045 | for (j = 0; j < row; j++) { |
1046 | __nand_addr(rowaddr & 0xff); |
1047 | rowaddr >>= 8; |
1048 | } |
1049 | |
1050 | /* write out data */ |
1051 | for (j = 0; j < ecccnt; j++) { |
1052 | volatile u8 *paraddr; |
1053 | int k; |
1054 | |
1055 | paraddr = (volatile u8 *)BCH_PAR0; |
1056 | |
1057 | REG_BCH_INTS = 0xffffffff; |
1058 | if(bchbit == 4) |
1059 | __ecc_encoding_4bit(); |
1060 | else if(bchbit == 8) |
1061 | __ecc_encoding_8bit(); |
1062 | else if(bchbit == 12) |
1063 | __ecc_encoding_12bit(); |
1064 | else if(bchbit == 16) |
1065 | __ecc_encoding_16bit(); |
1066 | else if(bchbit == 20) |
1067 | __ecc_encoding_20bit(); |
1068 | else |
1069 | __ecc_encoding_24bit(); |
1070 | |
1071 | /* Set BCHCNT.DEC_COUNT to data block size in bytes */ |
1072 | if (option != NO_OOB) |
1073 | __ecc_cnt_enc((ECC_BLOCK + oob_per_eccsize) * 2); |
1074 | else |
1075 | __ecc_cnt_enc(ECC_BLOCK * 2); |
1076 | |
1077 | /* Write data in data area to BCH */ |
1078 | for (k = 0; k < ECC_BLOCK; k++) { |
1079 | REG_BCH_DR = tmpbuf[ECC_BLOCK * j + k]; |
1080 | } |
1081 | |
1082 | /* Write file system information in oob area to BCH */ |
1083 | if (option != NO_OOB) |
1084 | { |
1085 | if(j == 0){ |
1086 | REG_BCH_DR = 0xff; |
1087 | REG_BCH_DR = 0xff; |
1088 | for(k = 2; k < oob_per_eccsize; k++) |
1089 | REG_BCH_DR = tmpbuf[pagesize + k]; |
1090 | } else { |
1091 | for (k = 0; k < oob_per_eccsize; k++) { |
1092 | REG_BCH_DR = tmpbuf[pagesize + oob_per_eccsize * j + k]; |
1093 | } |
1094 | } |
1095 | } |
1096 | |
1097 | __ecc_encode_sync(); |
1098 | __ecc_disable(); |
1099 | |
1100 | /* Read PAR values */ |
1101 | for (k = 0; k < par_size1; k++) { |
1102 | ecc_buf[j * par_size1 + k] = *paraddr++; |
1103 | } |
1104 | #ifdef USE_PN |
1105 | // pn_enable(); |
1106 | #endif |
1107 | write_proc((char *)&tmpbuf[ECC_BLOCK * j], ECC_BLOCK); |
1108 | #ifdef USE_PN |
1109 | // pn_disable(); |
1110 | #endif |
1111 | } |
1112 | |
1113 | for(j=0; j<oobsize; j++) |
1114 | oob_buf[j] = 0xff; |
1115 | switch (option) |
1116 | { |
1117 | case OOB_ECC: |
1118 | case OOB_NO_ECC: |
1119 | for (j = 2; j < eccpos; j++) { |
1120 | oob_buf[j] = tmpbuf[pagesize + j]; |
1121 | } |
1122 | for (j = 0; j < ecccnt * par_size1; j++) { |
1123 | oob_buf[eccpos + j] = ecc_buf[j]; |
1124 | } |
1125 | tmpbuf += pagesize + oobsize; |
1126 | break; |
1127 | case NO_OOB: //bin image |
1128 | for (j = 0; j < ecccnt * par_size1; j++) { |
1129 | oob_buf[eccpos + j] = ecc_buf[j]; |
1130 | } |
1131 | tmpbuf += pagesize; |
1132 | break; |
1133 | } |
1134 | |
1135 | #ifdef USE_PN |
1136 | // pn_enable(); |
1137 | #endif |
1138 | /* write out oob buffer */ |
1139 | write_proc((u8 *)oob_buf, oobsize); |
1140 | |
1141 | #ifdef USE_PN |
1142 | #ifndef USE_STATUS_PORT |
1143 | // pn_disable(); |
1144 | #endif |
1145 | #endif |
1146 | /* send program confirm command */ |
1147 | __nand_cmd(CMD_PGPROG); |
1148 | __nand_sync(); |
1149 | |
1150 | __nand_cmd(CMD_READ_STATUS); |
1151 | __nand_sync(); |
1152 | |
1153 | if (__nand_data8() & 0x01) /* page program error */ |
1154 | { |
1155 | serial_puts("Skip a write fail block\n"); |
1156 | nand_erase_4760( 1, cur_page/ppb, 1); //force erase before |
1157 | nand_mark_bad_4760(cur_page/ppb); |
1158 | spage += ppb; |
1159 | goto restart; |
1160 | } |
1161 | __nand_disable(); |
1162 | |
1163 | i++; |
1164 | cur_page++; |
1165 | } |
1166 | |
1167 | if (wp_pin) |
1168 | __gpio_clear_pin(wp_pin); |
1169 | |
1170 | return cur_page; |
1171 | } |
1172 | |
1173 | int program_nand_spl_page(unsigned char *databuf, unsigned int pageaddr) |
1174 | { |
1175 | int i, j, ecccnt; |
1176 | char *tmpbuf; |
1177 | char ecc_buf[1024]; // need 39*16 bytes at least for 24bit BCH |
1178 | unsigned int rowaddr; |
1179 | |
1180 | for(i=0; i<1024; i++) |
1181 | ecc_buf[i] = 0xff; |
1182 | |
1183 | __nand_enable(); |
1184 | |
1185 | tmpbuf = (char *)databuf; |
1186 | |
1187 | ecccnt = pagesize / ECC_BLOCK0; |
1188 | |
1189 | if (pagesize == 512) |
1190 | __nand_cmd(CMD_READA); |
1191 | |
1192 | __nand_cmd(CMD_SEQIN); |
1193 | |
1194 | /* write out col addr */ |
1195 | __nand_addr(0); |
1196 | if (pagesize != 512) |
1197 | __nand_addr(0); |
1198 | |
1199 | rowaddr = pageaddr; |
1200 | /* write out row addr */ |
1201 | for (i = 0; i < row; i++) { |
1202 | __nand_addr(rowaddr & 0xff); |
1203 | rowaddr >>= 8; |
1204 | } |
1205 | |
1206 | /* write out data */ |
1207 | |
1208 | for (i = 0; i < ecccnt; i++) { |
1209 | #ifdef USE_BCH |
1210 | volatile char *paraddr = (volatile char *)BCH_PAR0; |
1211 | |
1212 | REG_BCH_INTS = 0xffffffff; |
1213 | |
1214 | __ecc_encoding_24bit(); |
1215 | |
1216 | /* Set BCHCNT.DEC_COUNT to data block size in bytes */ |
1217 | __ecc_cnt_enc(2 * ECC_BLOCK0); |
1218 | |
1219 | for (j = 0; j < ECC_BLOCK0; j++) { |
1220 | REG_BCH_DR = tmpbuf[j]; |
1221 | } |
1222 | |
1223 | __ecc_encode_sync(); |
1224 | __ecc_disable(); |
1225 | |
1226 | /* Read PAR values for 256 bytes from BCH_PARn to ecc_buf */ |
1227 | for (j=0;j<PAR_SIZE_SPL1;j++) { |
1228 | ecc_buf[j + PAR_SIZE_SPL1 * i] = *paraddr++; |
1229 | } |
1230 | #endif |
1231 | #ifdef MAKE_ERROR |
1232 | char tmpbuf0[ECC_BLOCK0]; |
1233 | u8 k, n_err; |
1234 | u16 err_bit; |
1235 | |
1236 | memcpy(tmpbuf0, tmpbuf, ECC_BLOCK0); |
1237 | n_err = 1 + random() % 24; // 1 ~ 24 |
1238 | dprintf("generate %d error bits.\n",n_err); |
1239 | /* generate n_err error bits */ |
1240 | for(k = 0; k < n_err; k++) { |
1241 | err_bit = random() % (256*8); |
1242 | dprintf("err_bit=%04x in databuf[%03d]=0x%x \n",err_bit,err_bit / 8,tmpbuf0[(err_bit / 8)]); |
1243 | tmpbuf0[(err_bit / 8)] ^= 1 << (err_bit % 8); |
1244 | dprintf(" error databuf[%03d]= 0x%x \n",err_bit / 8,databuf[(err_bit / 8)]); |
1245 | } |
1246 | #endif |
1247 | |
1248 | #ifdef USE_PN |
1249 | if (!(((pageaddr % 64) == 0) && (i == 0))) |
1250 | pn_enable(); |
1251 | else |
1252 | dprintf("don't use pn. pageaddr=%d ecccnt=%d\n", pageaddr,i); |
1253 | #endif |
1254 | |
1255 | /* write ECC_BLOCK0 bytes to nand */ |
1256 | #ifdef MAKE_ERROR |
1257 | write_proc((char *)tmpbuf0, ECC_BLOCK0); |
1258 | #else |
1259 | write_proc((char *)tmpbuf, ECC_BLOCK0); |
1260 | #endif |
1261 | |
1262 | #ifdef USE_PN |
1263 | #ifndef USE_STATUS_PORT |
1264 | pn_disable(); |
1265 | #endif |
1266 | #endif |
1267 | tmpbuf += ECC_BLOCK0; |
1268 | } |
1269 | |
1270 | /* send program confirm command */ |
1271 | __nand_cmd(CMD_PGPROG); |
1272 | dprintf("%s %d \n", __FUNCTION__, __LINE__); |
1273 | __nand_sync(); |
1274 | dprintf("%s %d \n", __FUNCTION__, __LINE__); |
1275 | |
1276 | #if 1 |
1277 | __nand_cmd(CMD_READ_STATUS); |
1278 | dprintf("%s %d \n", __FUNCTION__, __LINE__); |
1279 | u8 status; |
1280 | #ifdef USE_STATUS_PORT |
1281 | status = __nand_status(); |
1282 | #else |
1283 | status = __nand_data8(); |
1284 | #endif |
1285 | if (status & 0x01) { |
1286 | __nand_disable(); |
1287 | return 1; |
1288 | } |
1289 | else { |
1290 | __nand_disable(); |
1291 | } |
1292 | dprintf("%s %d \n", __FUNCTION__, __LINE__); |
1293 | /* -----program ecc----- */ |
1294 | __nand_enable(); |
1295 | #endif |
1296 | if (pagesize == 512) |
1297 | __nand_cmd(CMD_READA); |
1298 | |
1299 | __nand_cmd(CMD_SEQIN); |
1300 | |
1301 | /* write out col addr */ |
1302 | __nand_addr(0); |
1303 | if (pagesize != 512) |
1304 | __nand_addr(0); |
1305 | |
1306 | rowaddr = pageaddr + 1; |
1307 | /* write out row addr */ |
1308 | for (i = 0; i < row; i++) { |
1309 | __nand_addr(rowaddr & 0xff); |
1310 | rowaddr >>= 8; |
1311 | } |
1312 | |
1313 | #ifdef USE_PN |
1314 | #ifdef PN_ADD_DELAY |
1315 | udelay(1000); |
1316 | dprintf("delay should be add for pn.\n"); |
1317 | #endif |
1318 | #endif |
1319 | |
1320 | #ifdef USE_PN |
1321 | pn_enable(); |
1322 | #endif |
1323 | dprintf("%s %d \n", __FUNCTION__, __LINE__); |
1324 | write_proc(ecc_buf, pagesize/ECC_BLOCK0*PAR_SIZE_SPL1); |
1325 | |
1326 | #ifdef USE_PN |
1327 | pn_disable(); |
1328 | #endif |
1329 | |
1330 | /* send program confirm command */ |
1331 | __nand_cmd(CMD_PGPROG); |
1332 | dprintf("%s %d \n", __FUNCTION__, __LINE__); |
1333 | __nand_sync(); |
1334 | dprintf("%s %d \n", __FUNCTION__, __LINE__); |
1335 | __nand_cmd(CMD_READ_STATUS); |
1336 | |
1337 | if (__nand_data8() & 0x01) { /* page program error */ |
1338 | __nand_disable(); |
1339 | return 1; |
1340 | } |
1341 | else { |
1342 | __nand_disable(); |
1343 | return 0; |
1344 | } |
1345 | } |
1346 | |
1347 | // be careful |
1348 | static u32 nand_mark_bad_page(u32 page) |
1349 | { |
1350 | #if 1 |
1351 | u8 badbuf[4096 + 128]; |
1352 | u32 i; |
1353 | |
1354 | if (wp_pin) |
1355 | __gpio_set_pin(wp_pin); |
1356 | for (i = 0; i < pagesize + oobsize; i++) |
1357 | badbuf[i] = 0x00; |
1358 | //all set to 0x00 |
1359 | |
1360 | __nand_cmd(CMD_READA); |
1361 | __nand_cmd(CMD_SEQIN); |
1362 | |
1363 | __nand_addr(0); |
1364 | if (pagesize != 512) |
1365 | __nand_addr(0); |
1366 | for (i = 0; i < row; i++) { |
1367 | __nand_addr(page & 0xff); |
1368 | page >>= 8; |
1369 | } |
1370 | |
1371 | write_proc((char *)badbuf, pagesize + oobsize); |
1372 | __nand_cmd(CMD_PGPROG); |
1373 | __nand_sync(); |
1374 | |
1375 | if (wp_pin) |
1376 | __gpio_clear_pin(wp_pin); |
1377 | return page; |
1378 | #endif |
1379 | } |
1380 | |
1381 | u32 nand_mark_bad_4760(int block) |
1382 | { |
1383 | u32 rowaddr; |
1384 | |
1385 | if ( bad_block_page >= ppb ) //absolute bad block mark! |
1386 | { //mark four page! |
1387 | rowaddr = block * ppb + 0; |
1388 | nand_mark_bad_page(rowaddr); |
1389 | |
1390 | rowaddr = block * ppb + 1; |
1391 | nand_mark_bad_page(rowaddr); |
1392 | |
1393 | rowaddr = block * ppb + ppb - 2; |
1394 | nand_mark_bad_page(rowaddr); |
1395 | |
1396 | rowaddr = block * ppb + ppb - 1; |
1397 | nand_mark_bad_page(rowaddr); |
1398 | } |
1399 | else //mark one page only |
1400 | { |
1401 | rowaddr = block * ppb + bad_block_page; |
1402 | nand_mark_bad_page(rowaddr); |
1403 | } |
1404 | |
1405 | return rowaddr; |
1406 | } |
1407 | |
1408 | static int nand_data_write8(char *buf, int count) |
1409 | { |
1410 | int i; |
1411 | u8 *p = (u8 *)buf; |
1412 | for (i=0;i<count;i++) |
1413 | __nand_data8() = *p++; |
1414 | return 0; |
1415 | } |
1416 | |
1417 | static int nand_data_write16(char *buf, int count) |
1418 | { |
1419 | int i; |
1420 | u16 *p = (u16 *)buf; |
1421 | for (i=0;i<count/2;i++) |
1422 | __nand_data16() = *p++; |
1423 | return 0; |
1424 | } |
1425 | |
1426 | static int nand_data_read8(char *buf, int count) |
1427 | { |
1428 | int i; |
1429 | u8 *p = (u8 *)buf; |
1430 | for (i=0;i<count;i++) |
1431 | *p++ = __nand_data8(); |
1432 | return 0; |
1433 | } |
1434 | |
1435 | static int nand_data_read16(char *buf, int count) |
1436 | { |
1437 | int i; |
1438 | u16 *p = (u16 *)buf; |
1439 | for (i=0;i<count/2;i++) |
1440 | *p++ = __nand_data16(); |
1441 | return 0; |
1442 | } |
1443 | |