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