Root/usbboot/xburst_stage2/nandflash_4740.c

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

Archive Download this file



interactive