Root/usbboot/xburst_stage2/nandflash_4740.c

1/*
2 * Copyright (C) 2009 Qi Hardware Inc.,
3 * Author: Xiangfu Liu <xiangfu@qi-hardware.com>
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
7 * version 3 as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA
18 */
19
20#include "nandflash.h"
21#include "jz4740.h"
22#include "usb_boot.h"
23#include "usb_boot_defines.h"
24
25#define __nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1)
26#define __nand_disable() (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFCE1))
27#define __nand_ecc_rs_encoding() (REG_EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_ERST | EMC_NFECR_RS | EMC_NFECR_RS_ENCODING)
28#define __nand_ecc_rs_decoding() (REG_EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_ERST | EMC_NFECR_RS | EMC_NFECR_RS_DECODING)
29#define __nand_ecc_disable() (REG_EMC_NFECR &= ~EMC_NFECR_ECCE)
30#define __nand_ecc_encode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_ENCF))
31#define __nand_ecc_decode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_DECF))
32
33#define __nand_ready() ((REG_GPIO_PXPIN(2) & 0x40000000) ? 1 : 0)
34#define __nand_ecc() (REG_EMC_NFECC & 0x00ffffff)
35#define __nand_cmd(n) (REG8(cmdport) = (n))
36#define __nand_addr(n) (REG8(addrport) = (n))
37#define __nand_data8() REG8(dataport)
38#define __nand_data16() REG16(dataport)
39
40#define CMD_READA 0x00
41#define CMD_READB 0x01
42#define CMD_READC 0x50
43#define CMD_ERASE_SETUP 0x60
44#define CMD_ERASE 0xD0
45#define CMD_READ_STATUS 0x70
46#define CMD_CONFIRM 0x30
47#define CMD_SEQIN 0x80
48#define CMD_PGPROG 0x10
49#define CMD_READID 0x90
50
51#define OOB_BAD_OFF 0x00
52#define OOB_ECC_OFF 0x04
53
54#define OP_ERASE 0
55#define OP_WRITE 1
56#define OP_READ 2
57
58#define ECC_BLOCK 512
59#define ECC_POS 6
60#define PAR_SIZE 9
61#define ECC_SIZE 36
62
63static volatile unsigned char *gpio_base = (volatile unsigned char *)0xb0010000;
64static volatile unsigned char *emc_base = (volatile unsigned char *)0xb3010000;
65static volatile unsigned char *addrport = (volatile unsigned char *)0xb8010000;
66static volatile unsigned char *dataport = (volatile unsigned char *)0xb8000000;
67static volatile unsigned char *cmdport = (volatile unsigned char *)0xb8008000;
68
69static int bus = 8, row = 2, pagesize = 2048, oobsize = 64, ppb = 128;
70static int bad_block_pos,bad_block_page,force_erase,ecc_pos,wp_pin;
71extern struct hand Hand;
72static u8 oob_buf[256] = {0};
73extern u16 handshake_PKT[4];
74
75#define dprintf(x) serial_puts(x)
76
77static unsigned int EMC_CSN[4]=
78{
79    0xb8000000,
80    0xb4000000,
81    0xa8000000,
82    0xa4000000
83};
84
85static inline void __nand_sync(void)
86{
87    unsigned int timeout = 100000;
88    while ((REG_GPIO_PXPIN(2) & 0x40000000) && timeout--);
89    while (!(REG_GPIO_PXPIN(2) & 0x40000000));
90}
91
92static void select_chip(int block)
93{
94    int t;
95    if (!Hand.nand_bpc)
96        return;
97    t = (block / Hand.nand_bpc) % 4;
98    addrport = (volatile unsigned char *)(EMC_CSN[t] + 0x10000);
99    dataport = (volatile unsigned char *)EMC_CSN[t];
100    cmdport = (volatile unsigned char *)(EMC_CSN[t] + 0x8000);
101}
102
103static int read_oob(void *buf, u32 size, u32 pg);
104static int nand_data_write8(char *buf, int count);
105static int nand_data_write16(char *buf, int count);
106static int nand_data_read8(char *buf, int count);
107static int nand_data_read16(char *buf, int count);
108static int (*write_proc)(char *, int) = NULL;
109static int (*read_proc)(char *, int) = NULL;
110
111static nand_init_gpio(void)
112{
113    /* modify this fun to a specifical borad
114     * this fun init those gpio use by all flash chip
115     * select the gpio function related to flash chip
116     */
117    __gpio_as_nand();
118}
119
120inline void nand_enable_4740(unsigned int csn)
121{
122    /* modify this fun to a specifical borad
123     * this fun to enable the chip select pin csn
124     * the choosn chip can work after this fun
125     */
126    __nand_enable();
127}
128
129inline void nand_disable_4740(unsigned int csn)
130{
131    /* modify this fun to a specifical borad
132     * this fun to enable the chip select pin csn
133     * the choosn chip can not work after this fun
134     */
135    __nand_disable();
136}
137
138unsigned int nand_query_4740(u8 *id)
139{
140    __nand_sync();
141    __nand_cmd(CMD_READID);
142    __nand_addr(0);
143
144    id[0] = __nand_data8(); //VID
145    id[1] = __nand_data8(); //PID
146    id[2] = __nand_data8(); //CHIP ID
147    id[3] = __nand_data8(); //PAGE ID
148    id[4] = __nand_data8(); //PLANE ID
149
150    return 0;
151}
152
153int nand_init_4740(int bus_width, int row_cycle, int page_size, int page_per_block,
154           int bbpage,int bbpos,int force,int ep)
155{
156    bus = bus_width;
157    row = row_cycle;
158    pagesize = page_size;
159    oobsize = pagesize / 32;
160    ppb = page_per_block;
161    bad_block_pos = bbpos;
162    bad_block_page = bbpage;
163    force_erase = force;
164    ecc_pos = ep;
165    wp_pin = Hand.nand_wppin;
166
167    /* Initialize NAND Flash Pins */
168    if (wp_pin)
169    {
170        __gpio_as_output(wp_pin);
171        __gpio_disable_pull(wp_pin);
172    }
173    nand_init_gpio();
174    select_chip(0);
175    REG_EMC_SMCR1 = 0x0fff7700; //slow speed
176// REG_EMC_SMCR1 = 0x04444400; //normal speed
177// REG_EMC_SMCR1 = 0x0d221200; //fast speed
178
179    if (bus == 8) {
180        write_proc = nand_data_write8;
181        read_proc = nand_data_read8;
182    } else {
183        write_proc = nand_data_write16;
184        read_proc = nand_data_read16;
185    }
186    return 0;
187}
188
189int nand_fini_4740(void)
190{
191    __nand_disable();
192    return 0;
193}
194
195/*
196 * Read oob <pagenum> pages from <startpage> page.
197 * Don't skip bad block.
198 * Don't use HW ECC.
199 */
200u32 nand_read_oob_4740(void *buf, u32 startpage, u32 pagenum)
201{
202    u32 cnt, cur_page;
203    u8 *tmpbuf;
204
205    tmpbuf = (u8 *)buf;
206
207    cur_page = startpage;
208    cnt = 0;
209    while (cnt < pagenum) {
210        read_oob((void *)tmpbuf, oobsize, cur_page);
211        tmpbuf += oobsize;
212        cur_page++;
213        cnt++;
214    }
215
216    return cur_page;
217}
218
219static int nand_check_block(u32 block)
220{
221    u32 pg,i;
222
223    if ( bad_block_page >= ppb ) {
224        /* do absolute bad block detect! */
225        pg = block * ppb + 0;
226        read_oob(oob_buf, oobsize, pg);
227        if ( oob_buf[0] != 0xff || oob_buf[1] != 0xff )
228            goto bad;
229
230        pg = block * ppb + 1;
231        read_oob(oob_buf, oobsize, pg);
232        if ( oob_buf[0] != 0xff || oob_buf[1] != 0xff )
233            goto bad;
234
235        pg = block * ppb + ppb - 2 ;
236        read_oob(oob_buf, oobsize, pg);
237        if ( oob_buf[0] != 0xff || oob_buf[1] != 0xff )
238            goto bad;
239
240        pg = block * ppb + ppb - 1 ;
241        read_oob(oob_buf, oobsize, pg);
242        if ( oob_buf[0] != 0xff || oob_buf[1] != 0xff )
243            goto bad;
244
245    } else {
246        pg = block * ppb + bad_block_page;
247        read_oob(oob_buf, oobsize, pg);
248        if (oob_buf[bad_block_pos] != 0xff)
249            goto bad;
250
251    }
252
253    return 0;
254
255bad:
256    serial_puts("Absolute skip a bad block\n");
257    return 1;
258    
259}
260
261/*
262 * Read data <pagecount> pages from <startpage> page.
263 * Don't skip bad block.
264 * Don't use HW ECC.
265 */
266u32 nand_read_raw_4740(void *buf, u32 startpage, u32 pagecount, int option)
267{
268    u32 cnt, j;
269    u32 cur_page, rowaddr;
270    u8 *tmpbuf;
271
272    tmpbuf = (u8 *)buf;
273
274    cur_page = startpage;
275    cnt = 0;
276    while (cnt < pagecount) {
277        select_chip(cnt / ppb);
278        if ((cur_page % ppb) == 0) {
279            if (nand_check_block(cur_page / ppb)) {
280                cur_page += ppb; //Bad block, set to next block
281                continue;
282            }
283        }
284
285        __nand_cmd(CMD_READA);
286        __nand_addr(0);
287        if (pagesize != 512)
288            __nand_addr(0);
289
290        rowaddr = cur_page;
291        for (j = 0; j < row; j++) {
292            __nand_addr(rowaddr & 0xff);
293            rowaddr >>= 8;
294        }
295
296        if (pagesize != 512)
297            __nand_cmd(CMD_CONFIRM);
298
299        __nand_sync();
300        read_proc(tmpbuf, pagesize);
301
302        tmpbuf += pagesize;
303        if (option != NO_OOB)
304        {
305            read_oob(tmpbuf, oobsize, cur_page);
306            tmpbuf += oobsize;
307        }
308
309        cur_page++;
310        cnt++;
311    }
312
313    return cur_page;
314}
315
316u32 nand_erase_4740(int blk_num, int sblk, int force)
317{
318    int i, j;
319    u32 cur, rowaddr;
320
321    if (wp_pin)
322        __gpio_set_pin(wp_pin);
323    cur = sblk * ppb;
324    for (i = 0; i < blk_num; ) {
325        rowaddr = cur;
326        select_chip(cur / ppb);
327        if ( !force ) {
328            if (nand_check_block(cur/ppb)) {
329                cur += ppb;
330                blk_num += Hand.nand_plane;
331                continue;
332            }
333        }
334
335        __nand_cmd(CMD_ERASE_SETUP);
336
337        for (j = 0; j < row; j++) {
338            __nand_addr(rowaddr & 0xff);
339            rowaddr >>= 8;
340        }
341        __nand_cmd(CMD_ERASE);
342        __nand_sync();
343        __nand_cmd(CMD_READ_STATUS);
344
345        if (__nand_data8() & 0x01) {
346            serial_puts("Erase fail at ");
347            serial_put_hex(cur / ppb);
348            nand_mark_bad_4740(cur/ppb);
349            cur += ppb;
350            blk_num += Hand.nand_plane;
351            continue;
352        }
353        cur += ppb;
354        i++;
355    }
356
357    if (wp_pin)
358        __gpio_clear_pin(wp_pin);
359    return cur;
360}
361
362static int read_oob(void *buf, u32 size, u32 pg)
363{
364    u32 i, coladdr, rowaddr;
365
366    select_chip(pg / ppb);
367    if (pagesize == 512)
368        coladdr = 0;
369    else
370        coladdr = pagesize;
371
372    if (pagesize == 512)
373        __nand_cmd(CMD_READC); /* Send READOOB command */
374    else
375        __nand_cmd(CMD_READA); /* Send READ0 command */
376
377    __nand_addr(coladdr & 0xff); /* Send column address */
378
379    if (pagesize != 512)
380        __nand_addr(coladdr >> 8);
381
382    /* Send page address */
383    rowaddr = pg;
384    for (i = 0; i < row; i++) {
385        __nand_addr(rowaddr & 0xff);
386        rowaddr >>= 8;
387    }
388
389    /* Send READSTART command for 2048 ps NAND */
390    if (pagesize != 512)
391        __nand_cmd(CMD_CONFIRM);
392
393    /* Wait for device ready */
394    __nand_sync();
395
396    /* Read oob data */
397    read_proc(buf, size);
398
399    if (pagesize == 512)
400        __nand_sync();
401    return 0;
402}
403
404void rs_correct(unsigned char *buf, int idx, int mask)
405{
406    int i, j;
407    unsigned short d, d1, dm;
408
409    i = (idx * 9) >> 3;
410    j = (idx * 9) & 0x7;
411
412    i = (j == 0) ? (i - 1) : i;
413    j = (j == 0) ? 7 : (j - 1);
414
415    d = (buf[i] << 8) | buf[i - 1];
416
417    d1 = (d >> j) & 0x1ff;
418    d1 ^= mask;
419
420    dm = ~(0x1ff << j);
421    d = (d & dm) | (d1 << j);
422
423    buf[i - 1] = d & 0xff;
424    buf[i] = (d >> 8) & 0xff;
425}
426
427 /*
428 * Read data <pagecount> pages from <startpage> page.
429 * Skip bad block if detected.
430 * HW ECC is used.
431 */
432u32 nand_read_4740(void *buf, u32 startpage, u32 pagecount, int option)
433{
434    u32 j, k;
435    u32 cur_page, cur_blk, cnt, rowaddr, ecccnt;
436    u8 *tmpbuf,flag = 0;
437    ecccnt = pagesize / ECC_BLOCK;
438    cur_page = startpage;
439    cnt = 0;
440    tmpbuf = buf;
441    handshake_PKT[3] = 0;
442
443    return cur_page + pagecount;
444
445    while (cnt < pagecount) {
446        select_chip(cnt / ppb);
447        /* If this is the first page of the block, check for bad. */
448        if ((cur_page % ppb) == 0) {
449            cur_blk = cur_page / ppb;
450            if (nand_check_block(cur_blk)) {
451                cur_page += ppb; //Bad block, set to next block
452                continue;
453            }
454        }
455        /* read oob first */
456        read_oob(oob_buf, oobsize, cur_page);
457        __nand_cmd(CMD_READA);
458
459        __nand_addr(0);
460        if (pagesize != 512)
461            __nand_addr(0);
462
463        rowaddr = cur_page;
464        for (j = 0; j < row; j++) {
465            __nand_addr(rowaddr & 0xff);
466            rowaddr >>= 8;
467        }
468
469        if (pagesize != 512)
470            __nand_cmd(CMD_CONFIRM);
471
472        __nand_sync();
473
474        for (j = 0; j < ecccnt; j++) {
475            volatile u8 *paraddr = (volatile u8 *)EMC_NFPAR0;
476            u32 stat;
477            flag = 0;
478
479            REG_EMC_NFINTS = 0x0;
480            __nand_ecc_rs_decoding();
481            read_proc(tmpbuf, ECC_BLOCK);
482            for (k = 0; k < PAR_SIZE; k++) {
483                *paraddr++ = oob_buf[ecc_pos + j*PAR_SIZE + k];
484                if (oob_buf[ecc_pos + j*PAR_SIZE + k] != 0xff)
485                    flag = 1;
486            }
487            REG_EMC_NFECR |= EMC_NFECR_PRDY;
488            __nand_ecc_decode_sync();
489            __nand_ecc_disable();
490            /* Check decoding */
491            stat = REG_EMC_NFINTS;
492            if (stat & EMC_NFINTS_ERR) {
493                if (stat & EMC_NFINTS_UNCOR) {
494                    if (flag) {
495                        serial_puts("\nUncorrectable error occurred, Page:");
496                        serial_put_hex(cur_page);
497                        handshake_PKT[3] = 1;
498                    }
499                } else {
500                    handshake_PKT[3] = 0;
501                    u32 errcnt = (stat & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT;
502                    switch (errcnt) {
503                    case 4:
504                        rs_correct(tmpbuf, (REG_EMC_NFERR3 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR3 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT);
505                    case 3:
506                        rs_correct(tmpbuf, (REG_EMC_NFERR2 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR2 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT);
507                    case 2:
508                        rs_correct(tmpbuf, (REG_EMC_NFERR1 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR1 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT);
509                    case 1:
510                        rs_correct(tmpbuf, (REG_EMC_NFERR0 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR0 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT);
511                        break;
512                    default:
513                        break;
514                    }
515                
516                }
517            }
518            /* increment pointer */
519            tmpbuf += ECC_BLOCK;
520        }
521
522        switch (option) {
523        case OOB_ECC:
524            for (j = 0; j < oobsize; j++)
525                tmpbuf[j] = oob_buf[j];
526            tmpbuf += oobsize;
527            break;
528        case OOB_NO_ECC:
529            for (j = 0; j < ecccnt * PAR_SIZE; j++)
530                oob_buf[ecc_pos + j] = 0xff;
531            for (j = 0; j < oobsize; j++)
532                tmpbuf[j] = oob_buf[j];
533            tmpbuf += oobsize;
534            break;
535        case NO_OOB:
536            break;
537        }
538
539        cur_page++;
540        cnt++;
541    }
542    return cur_page;
543}
544
545u32 nand_program_4740(void *context, int spage, int pages, int option)
546{
547    size_t datasize;
548    u32 i, j, cur, rowaddr;
549    u8 *tmpbuf;
550    u32 ecccnt,oobsize_sav,ecccnt_sav,eccpos_sav;
551    u8 ecc_buf[256];
552
553    datasize = pagesize;
554    if (option != NO_OOB)
555        datasize += oobsize;
556
557
558    if (wp_pin)
559        __gpio_set_pin(wp_pin);
560restart:
561    tmpbuf = (u8 *)context;
562    ecccnt_sav = ecccnt = pagesize / ECC_BLOCK;
563    oobsize_sav = oobsize;
564    eccpos_sav = ecc_pos;
565    i = 0;
566    cur = spage;
567
568    while (i < pages) {
569        select_chip(cur / ppb);
570#if 1
571        if ((pagesize == 4096) && (cur < 8)) {
572            ecccnt = 4;
573            oobsize = 64;
574            ecc_pos = 6;
575        } else {
576            ecccnt = ecccnt_sav;
577            oobsize = oobsize_sav;
578            ecc_pos = eccpos_sav;
579        }
580
581                /* Skip 16KB after nand_spl if pagesize=4096 */
582        if ((pagesize == 4096) && (cur == 8))
583            tmpbuf += 16 * 1024;
584#endif
585
586        if ((cur % ppb) == 0) {
587            if (nand_check_block(cur / ppb)) {
588                cur += ppb; // Bad block, set to next block
589                continue;
590            }
591        }
592
593        for (j = 0; j < datasize; ++j) {
594            if (tmpbuf[j] != 0xff)
595                break;
596        }
597
598        if (j == datasize) {
599            tmpbuf += datasize;
600            ++i;
601            ++cur;
602            continue;
603        }
604
605        if (pagesize == 512)
606            __nand_cmd(CMD_READA);
607
608        __nand_cmd(CMD_SEQIN);
609        __nand_addr(0);
610
611        if (pagesize != 512)
612            __nand_addr(0);
613
614        rowaddr = cur;
615        for (j = 0; j < row; j++) {
616            __nand_addr(rowaddr & 0xff);
617            rowaddr >>= 8;
618        }
619
620        switch (option) {
621        case OOB_ECC:
622            write_proc(tmpbuf, pagesize); //write data
623            tmpbuf += pagesize;
624            write_proc((u8 *)tmpbuf, oobsize); //write oob
625            tmpbuf += oobsize;
626
627            break;
628        case OOB_NO_ECC:
629            for (j = 0; j < ecccnt; j++) {
630                volatile u8 *paraddr = (volatile u8 *)EMC_NFPAR0;
631                int k;
632
633                REG_EMC_NFINTS = 0x0;
634                __nand_ecc_rs_encoding();
635                write_proc(tmpbuf, ECC_BLOCK);
636                __nand_ecc_encode_sync();
637                __nand_ecc_disable();
638
639                /* Read PAR values */
640                for (k = 0; k < PAR_SIZE; k++) {
641                    ecc_buf[j*PAR_SIZE+k] = *paraddr++;
642                }
643                
644                tmpbuf += ECC_BLOCK;
645            }
646            for (j = 0; j < oobsize; j++) {
647                oob_buf[j] = tmpbuf[j];
648            }
649            
650            for (j = 0; j < ecccnt*PAR_SIZE; j++)
651                oob_buf[ecc_pos + j] = ecc_buf[j];
652            write_proc((u8 *)oob_buf, oobsize);
653            tmpbuf += oobsize;
654
655            break;
656        case NO_OOB: /* bin image */
657            /* write out data */
658            for (j = 0; j < ecccnt; j++) {
659                volatile u8 *paraddr = (volatile u8 *)EMC_NFPAR0;
660                int k;
661
662                REG_EMC_NFINTS = 0x0;
663                __nand_ecc_rs_encoding();
664                write_proc(tmpbuf, ECC_BLOCK);
665                __nand_ecc_encode_sync();
666                __nand_ecc_disable();
667
668                /* Read PAR values */
669                for (k = 0; k < PAR_SIZE; k++) {
670                    ecc_buf[j*PAR_SIZE+k] = *paraddr++;
671                }
672                
673                tmpbuf += ECC_BLOCK;
674            }
675            
676            for (j = 0; j < oobsize; j++) {
677                oob_buf[j] = 0xff;
678            }
679
680            oob_buf[2] = 0;
681            oob_buf[3] = 0;
682            oob_buf[4] = 0;
683
684            for (j = 0; j < ecccnt*PAR_SIZE; j++) {
685                oob_buf[ecc_pos + j] = ecc_buf[j];
686            }
687
688            write_proc((u8 *)oob_buf, oobsize);
689            break;
690        }
691
692        /* send program confirm command */
693        __nand_cmd(CMD_PGPROG);
694        __nand_sync();
695
696        __nand_cmd(CMD_READ_STATUS);
697
698        /* page program error */
699        if (__nand_data8() & 0x01) {
700            serial_puts("Skip a write fail block\n");
701            nand_erase_4740(1, cur/ppb, 1); //force erase before
702            nand_mark_bad_4740(cur / ppb);
703            spage += ppb;
704            goto restart;
705        }
706            
707        i ++;
708        cur ++;
709    }
710
711    if (wp_pin)
712        __gpio_clear_pin(wp_pin);
713
714    ecccnt = ecccnt_sav;
715    oobsize = oobsize_sav;
716    ecc_pos = eccpos_sav;
717
718    return cur;
719}
720
721static u32 nand_mark_bad_page(u32 page)
722{
723    u8 badbuf[4096 + 128];
724    u32 i;
725
726    if (wp_pin)
727        __gpio_set_pin(wp_pin);
728    //all set to 0x00
729    for (i = 0; i < pagesize + oobsize; i++)
730        badbuf[i] = 0x00;
731
732    __nand_cmd(CMD_READA);
733    __nand_cmd(CMD_SEQIN);
734
735    __nand_addr(0);
736    if (pagesize != 512)
737        __nand_addr(0);
738    for (i = 0; i < row; i++) {
739        __nand_addr(page & 0xff);
740        page >>= 8;
741    }
742
743    write_proc((char *)badbuf, pagesize + oobsize);
744    __nand_cmd(CMD_PGPROG);
745    __nand_sync();
746
747    if (wp_pin)
748        __gpio_clear_pin(wp_pin);
749    return page;
750}
751
752
753u32 nand_mark_bad_4740(int block)
754{
755    u32 rowaddr;
756
757    //nand_erase_4740( 1, block, 1); //force erase before
758    if ( bad_block_page >= ppb ) { //mark four page!
759        rowaddr = block * ppb + 0;
760        nand_mark_bad_page(rowaddr);
761
762        rowaddr = block * ppb + 1;
763        nand_mark_bad_page(rowaddr);
764
765        rowaddr = block * ppb + ppb - 2;
766        nand_mark_bad_page(rowaddr);
767
768        rowaddr = block * ppb + ppb - 1;
769        nand_mark_bad_page(rowaddr);
770    } else { //mark one page only
771        rowaddr = block * ppb + bad_block_page;
772        nand_mark_bad_page(rowaddr);
773    }
774
775    return rowaddr;
776}
777
778static int nand_data_write8(char *buf, int count)
779{
780    int i;
781    u8 *p = (u8 *)buf;
782    for (i=0;i<count;i++)
783        __nand_data8() = *p++;
784    return 0;
785}
786
787static int nand_data_write16(char *buf, int count)
788{
789    int i;
790    u16 *p = (u16 *)buf;
791    for (i=0;i<count/2;i++)
792        __nand_data16() = *p++;
793    return 0;
794}
795
796static int nand_data_read8(char *buf, int count)
797{
798    int i;
799    u8 *p = (u8 *)buf;
800    for (i=0;i<count;i++)
801        *p++ = __nand_data8();
802    return 0;
803}
804
805static int nand_data_read16(char *buf, int count)
806{
807    int i;
808    u16 *p = (u16 *)buf;
809    for (i=0; i < count / 2; i++)
810        *p++ = __nand_data16();
811    return 0;
812}
813

Archive Download this file



interactive