Root/nandprog/jz4730/nandflash_4730.c

1/*
2 * Common NAND Flash operations for JZ4730.
3 *
4 * This software is free.
5 */
6
7#include "jz4730.h"
8#include "include.h"
9
10unsigned int EMC_BASE;
11extern struct nand_oobinfo oob_64[];
12
13/*
14 * Standard NAND commands.
15 */
16#define CMD_READA 0x00
17#define CMD_READB 0x01
18#define CMD_READC 0x50
19#define CMD_ERASE_SETUP 0x60
20#define CMD_ERASE 0xD0
21#define CMD_READ_STATUS 0x70
22#define CMD_CONFIRM 0x30
23#define CMD_SEQIN 0x80
24#define CMD_PGPROG 0x10
25#define CMD_READID 0x90
26#define CMD_RESET 0xff
27
28#define ECC_BLOCK 256 /* 3-bytes HW ECC per 256-bytes data */
29#define ECC_OFFSET 4 /* ECC store location offset to the spare area */
30
31/*
32 * NAND routines.
33 */
34#define nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE | EMC_NFCSR_FCE)
35#define nand_disable() (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFE | EMC_NFCSR_FCE))
36#define nand_ecc_enable() (REG_EMC_NFCSR |= EMC_NFCSR_ECCE | EMC_NFCSR_ERST)
37#define nand_ecc_disable() (REG_EMC_NFCSR &= ~EMC_NFCSR_ECCE)
38#define nand_ready() (REG_EMC_NFCSR & EMC_NFCSR_RB)
39#define nand_ecc() (REG_EMC_NFECC & 0x00ffffff)
40#define nand_cmd(n) (REG8(cmdport+csn) = (n))
41#define nand_addr(n) (REG8(addrport+csn) = (n))
42#define nand_data8() REG8(dataport+csn)
43#define nand_data16() REG16(dataport+csn)
44
45static inline void nand_wait_ready(void)
46{
47    u32 to = 1000;
48    while (nand_ready() && to--);
49    while (!nand_ready());
50}
51
52static volatile unsigned char *emcbase = 0;
53static volatile unsigned char *addrport = 0;
54static volatile unsigned char *dataport = 0;
55static volatile unsigned char *cmdport = 0;
56
57static u32 bus = 8, row = 2, pagesize = 512, oobsize = 16, ppb = 32;
58static u32 bad_block_pos = 0 , bad_block_page =0, csn =0;
59static struct nand_oobinfo *oob_pos;
60static np_data *np;
61
62/*
63 * notify(int param)
64 *
65 * param value:
66 * 0 : Ok
67 * -1: page op fail
68 * -2: hit bad block, skip it.
69 */
70
71static int (*write_proc)(unsigned char *, int) = 0;
72static int (*read_proc)(unsigned char *, int) = 0;
73
74static u8 badbuf[2048 + 64] = {0};
75static u8 oobbuf[64] = {0};
76
77
78/*
79 * I/O read/write interface.
80 */
81static inline int nand_data_write8(unsigned char *buf, int count)
82{
83    int i;
84    u8 *p = (u8 *)buf;
85
86    for (i = 0; i < count; i++)
87        nand_data8() = *p++;
88    return 0;
89}
90
91static inline int nand_data_write16(unsigned char *buf, int count)
92{
93    int i;
94    u16 *p = (u16 *)buf;
95
96    for (i = 0; i < count/2; i++)
97        nand_data16() = *p++;
98    return 0;
99}
100
101static inline int nand_data_read8(unsigned char *buf, int count)
102{
103    int i;
104    u8 *p = (u8 *)buf;
105
106    for (i = 0; i < count; i++)
107        *p++ = nand_data8();
108    return 0;
109}
110
111static inline int nand_data_read16(unsigned char *buf, int count)
112{
113    int i;
114    u16 *p = (u16 *)buf;
115
116    for (i = 0; i < count/2; i++)
117        *p++ = nand_data16();
118    return 0;
119}
120
121int chip_select_4730(u8 cs)
122{
123    csn = (u32)cs << 15; //modify this number for your board
124    return 0;
125}
126
127/*
128 * Init nand parameters and enable nand controller.
129 */
130int nand_init_4730(np_data *npp)
131{
132    bus = npp->bw;
133    row = npp->rc;
134    pagesize = npp->ps;
135    oobsize = npp->os;
136    ppb = npp->ppb;
137    bad_block_pos = npp->bbp;
138    bad_block_page = npp->bba;
139
140    if (bus == 8) {
141        write_proc = nand_data_write8;
142        read_proc = nand_data_read8;
143    } else {
144        write_proc = nand_data_write16;
145        read_proc = nand_data_read16;
146    }
147    emcbase = (u8 *)npp->base_map;
148    dataport = (u8 *)npp->port_map;
149    addrport = (u8 *)((u32)dataport + npp->ap_offset);
150    cmdport = (u8 *)((u32)dataport + npp->cp_offset);
151
152    EMC_BASE = (u32)emcbase;
153    oob_pos = &oob_64[npp->ep];
154    np = npp;
155    nand_enable();
156    chip_select_4730(npp->cs);
157    return 0;
158}
159
160/*
161 * Disable nand operation.
162 */
163int nand_fini_4730(void)
164{
165    nand_disable();
166    return 0;
167}
168
169/*
170 * Read ID.
171 */
172unsigned int nand_query_4730(void)
173{
174    u16 vid, did;
175
176    nand_cmd(CMD_READID);
177    nand_addr(0);
178
179    vid = nand_data8();
180    did = nand_data8();
181
182    return (vid << 16) | did;
183}
184
185/*
186 * Read oob data for 512B pagesize.
187 */
188static void read_oob_512(void *buf, u32 oobsize, u32 pg)
189{
190    int i;
191    u32 rowaddr;
192
193    rowaddr = pg;
194
195    nand_cmd(0x50);
196    nand_addr(0);
197    for (i = 0; i < row; i++) {
198        nand_addr(rowaddr & 0xff);
199        rowaddr >>= 8;
200    }
201    nand_wait_ready();
202
203    read_proc(buf, oobsize);
204}
205
206/*
207 * Read oob data for 2KB pagesize.
208 */
209static void read_oob_2048(u8 *buf, u32 oobsize, u32 pg)
210{
211    u32 i, coladdr, rowaddr;
212
213
214    coladdr = 2048;
215    rowaddr = pg;
216
217    nand_cmd(CMD_READA);
218    nand_addr(coladdr & 0xff);
219    nand_addr(coladdr >> 8);
220    for (i = 0; i < row; i++) {
221        nand_addr(rowaddr & 0xff);
222        rowaddr >>= 8;
223    }
224    nand_cmd(CMD_CONFIRM);
225    nand_wait_ready();
226    read_proc(buf, oobsize);
227}
228
229/*
230 * Read oob data.
231 */
232static void read_oob(u8 *buf, int oobsize, int pg)
233{
234    if (pagesize == 2048)
235        read_oob_2048(buf, oobsize, pg);
236    else
237        read_oob_512(buf, oobsize, pg);
238}
239
240/*
241 * Return 1 if the block is bad block, else return 0.
242 */
243int nand_check_block(u32 block)
244{
245    u32 pg;
246
247// pg = block * ppb;
248    pg = block * ppb + bad_block_page;
249    //bad block ID locate No.bad_block_page
250    read_oob(oobbuf, oobsize, pg);
251    if (oobbuf[bad_block_pos] != 0xff)
252        return -1;
253    read_oob(oobbuf, oobsize, pg + 1);
254    if (oobbuf[bad_block_pos] != 0xff)
255        return -1;
256
257    return 0;
258}
259
260/*
261 * Mark a block bad.
262 */
263void nand_block_markbad(u32 block)
264{
265    u32 i, rowaddr;
266
267    for (i = 0; i < pagesize + oobsize; i++)
268        badbuf[i] = 0xff;
269    badbuf[pagesize + bad_block_pos] = 0; /* bad block flag */
270
271    rowaddr = block * ppb + bad_block_page;
272    //bad block ID locate No.bad_block_page
273
274    nand_cmd(CMD_READA);
275    nand_cmd(CMD_SEQIN);
276
277    nand_addr(0);
278    if (pagesize == 2048)
279        nand_addr(0);
280    for (i = 0; i < row; i++) {
281        nand_addr(rowaddr & 0xff);
282        rowaddr >>= 8;
283    }
284
285    write_proc((unsigned char *)badbuf, pagesize + oobsize);
286    nand_cmd(CMD_PGPROG);
287    nand_wait_ready();
288}
289
290/*
291 * Erase <blk_num> blocks from block <sblk>.
292 */
293int nand_erase_4730(int blk_num, int sblk, int force)
294{
295    int i, cnt;
296    u32 cur_blk, rowaddr;
297
298    force = 0;
299    /* Send reset command to nand */
300    nand_cmd(CMD_RESET);
301    nand_wait_ready();
302
303    cur_blk = sblk;
304    cnt = 0;
305    while (cnt < blk_num) {
306        /*
307         * if force flag was not set, check for bad block.
308         * if force flag was set, erase anything.
309         */
310#if 1
311        //we do force erase for ever??
312        if (!force) {
313            if (nand_check_block(cur_blk)) {
314                cur_blk ++; /* Bad block, set to next block */
315                continue;
316            }
317        }
318#endif
319        nand_cmd(CMD_ERASE_SETUP);
320
321        rowaddr = cur_blk * ppb;
322        for (i = 0; i < row; i++) {
323            nand_addr(rowaddr & 0xff);
324            rowaddr >>= 8;
325        }
326
327        nand_cmd(CMD_ERASE);
328        nand_wait_ready();
329
330        nand_cmd(CMD_READ_STATUS);
331        nand_wait_ready();
332
333        if (nand_data8() & 0x01) {
334            /* Erase Error, mark it as bad block */
335            nand_block_markbad(cur_blk);
336
337        } else {
338            /* Erase OK */
339            cnt++;
340        }
341        cur_blk++;
342    }
343
344    return 0;
345}
346
347
348/*
349 * Do nand hw ecc correction.
350 */
351int nand_hw_ecc_correct(u8 *buf, u8 *stored_ecc, u8 *calc_ecc, int eccblock)
352{
353    u32 i, j, ecc_bit,a,b,c,tmp;
354    int res = 0;
355
356    for (i = 0; i < eccblock; i++) {
357        a=stored_ecc[oob_pos->eccpos[i*3+0]] ^ calc_ecc[i*4+0];
358        b=stored_ecc[oob_pos->eccpos[i*3+1]] ^ calc_ecc[i*4+1];
359        c=stored_ecc[oob_pos->eccpos[i*3+2]] ^ calc_ecc[i*4+2];
360        tmp = (c<<16) + (b<<8) +a;
361#if 0
362        printf("AAAAAAAA %x %x %x : %x %x %x %x\n",
363               stored_ecc[oob_pos->eccpos[i*3+0]],
364               stored_ecc[oob_pos->eccpos[i*3+1]],
365               stored_ecc[oob_pos->eccpos[i*3+2]],
366               calc_ecc[i*4+0],
367               calc_ecc[i*4+1],
368               calc_ecc[i*4+2],
369               tmp);
370#endif
371        if (tmp) { /* ECC error */
372            ecc_bit = 0;
373            for (j = 0; j < 24; j++)
374                if ((tmp >> j) & 0x01)
375                    ecc_bit ++;
376            if (ecc_bit == 11) { /* Correctable error */
377                u8 idx;
378
379                ecc_bit = 0;
380                for (j = 12; j >= 1; j--) {
381                    ecc_bit <<= 1;
382                    ecc_bit |= ((tmp >> (j*2-1)) & 0x01);
383                }
384                idx = ecc_bit & 0x07;
385
386                buf[i * ECC_BLOCK + (ecc_bit >> 3)] ^= (1 << idx);
387            }
388            else { /* Fatal error */
389                //if ecc all ff means this page no data!
390                if (stored_ecc[oob_pos->eccpos[i*3+0]]==0xff
391                    &&stored_ecc[oob_pos->eccpos[i*3+1]]==0xff
392                    &&stored_ecc[oob_pos->eccpos[i*3+2]]==0xff )
393                    return res;
394// printf("Uncorrectable ecc error!\n");
395                res = -1;
396            }
397        }
398    }
399    return res;
400}
401
402/*
403 * Read data <pagenum> pages from <startpage> page.
404 * Skip bad block if detected.
405 * HW ECC is used.
406 */
407int nand_read_4730(u8 *buf, u32 startpage, u32 pagenum)
408{
409    u32 cnt, i;
410    u32 cur_page, rowaddr, eccblock;
411    u32 calc_ecc[8];
412    u8 *tmpbuf,*stored_ecc;
413
414    eccblock = pagesize / ECC_BLOCK;
415    cur_page = startpage;
416    cnt = 0;
417    while (cnt < pagenum) {
418        
419        //we do not check bad block here!
420#if 0
421        if ((cur_page % ppb) == 0) {
422            cur_blk = cur_page / ppb;
423            if (nand_check_block(cur_blk)) {
424                cur_page += ppb; /* Bad block, set to next block */
425                continue;
426            }
427        }
428#endif
429        nand_cmd(CMD_READA);
430        nand_addr(0);
431        if (pagesize == 2048)
432            nand_addr(0);
433
434        rowaddr = cur_page;
435        for (i = 0; i < row; i++) {
436            nand_addr(rowaddr & 0xff);
437            rowaddr >>= 8;
438        }
439        if (pagesize == 2048)
440            nand_cmd(CMD_CONFIRM);
441
442        nand_wait_ready();
443        tmpbuf = (u8 *)((u32)buf + cnt * (pagesize + oobsize));
444        for (i = 0; i < eccblock; i++) {
445            nand_ecc_enable();
446            read_proc(tmpbuf, ECC_BLOCK);
447            nand_ecc_disable();
448            calc_ecc[i] = nand_ecc();
449            if (oob_pos->eccname == LINUXHM)
450                calc_ecc[i] = ~(calc_ecc[i]) | 0x00030000;
451            tmpbuf += ECC_BLOCK;
452        }
453        read_proc((u8 *)tmpbuf, oobsize);
454        tmpbuf = (u8 *)((u32)buf + cnt * (pagesize + oobsize));
455        //read ecc from oob
456        stored_ecc = (u8 *)(((u32)tmpbuf) + pagesize );
457
458        /* Check ECC */
459        nand_hw_ecc_correct(tmpbuf, stored_ecc, (u8 *)calc_ecc, eccblock);
460        cur_page++;
461        cnt++;
462    }
463    return 0;
464}
465
466/*
467 * Read data <pagenum> pages from <startpage> page.
468 * Don't skip bad block.
469 * Don't use HW ECC.
470 */
471int nand_read_raw_4730(u8 *buf, u32 startpage, u32 pagenum)
472{
473    u32 cnt, i;
474    u32 cur_page, rowaddr;
475    u8 *tmpbuf;
476
477    tmpbuf = (u8 *)buf;
478
479    cur_page = startpage;
480    cnt = 0;
481    while (cnt < pagenum) {
482        nand_cmd(CMD_READA);
483        nand_addr(0);
484        if (pagesize == 2048)
485            nand_addr(0);
486
487        rowaddr = cur_page;
488        for (i = 0; i < row; i++) {
489            nand_addr(rowaddr & 0xff);
490            rowaddr >>= 8;
491        }
492
493        if (pagesize == 2048)
494            nand_cmd(CMD_CONFIRM);
495
496        nand_wait_ready();
497
498        read_proc(tmpbuf, pagesize);
499
500        tmpbuf += pagesize;
501        cur_page++;
502        cnt++;
503    }
504
505    return 0;
506}
507
508/*
509 * Read oob <pagenum> pages from <startpage> page.
510 * Don't skip bad block.
511 * Don't use HW ECC.
512 */
513int nand_read_oob_4730(u8 *buf, u32 startpage, u32 pagenum)
514{
515    u32 cnt, cur_page;
516    u8 *tmpbuf;
517
518    tmpbuf = (u8 *)buf;
519
520    cur_page = startpage;
521    cnt = 0;
522    while (cnt < pagenum) {
523        read_oob((void *)tmpbuf, oobsize, cur_page);
524
525        tmpbuf += oobsize;
526        cur_page++;
527        cnt++;
528    }
529
530    return 0;
531}
532
533/*
534 * Write <pagenum> pages from <startpage> page.
535 * Skip bad block if detected.
536 */
537int nand_program_4730(u8 *buf, int startpage, int pagenum)
538{
539    u32 cnt, i,j;
540    u32 cur_page, rowaddr, eccblock;
541    u8 *tmpbuf;
542
543    tmpbuf = (u8 *)buf;
544
545    eccblock = pagesize / ECC_BLOCK;
546
547    cur_page = startpage;
548    cnt = 0;
549    while (cnt < pagenum) {
550        //do not check bad block here! check uplayer!
551
552        for (j=0;j<np->os;j++)
553        {
554            if (tmpbuf[j+np->ps]!=0xff)
555                break;
556        }
557
558        if (j==np->os)
559        {
560            tmpbuf += np->ps+np->os;
561            cur_page ++;
562            cnt ++;
563            continue;
564        }
565
566// nand_wait_ready();
567        nand_cmd(CMD_READA);
568        nand_cmd(CMD_SEQIN);
569
570        nand_addr(0);
571        if (pagesize == 2048)
572            nand_addr(0);
573
574        rowaddr = cur_page;
575        for (i = 0; i < row; i++) {
576            nand_addr(rowaddr & 0xff);
577            rowaddr >>= 8;
578        }
579
580        /* Write out data and oob*/
581        // we don't need work out ecc
582        //because it already exist in image file
583
584        write_proc(tmpbuf, np->ps+np->os);
585        tmpbuf += np->ps+np->os;
586        nand_cmd(CMD_PGPROG);
587        nand_wait_ready();
588
589        nand_cmd(CMD_READ_STATUS);
590// nand_wait_ready();
591
592        if (nand_data8() & 0x01) {
593            /* Page program error.
594             * Note: we should mark this block bad, and copy data of this
595             * block to a new block.
596             */
597            ;
598        } else {
599            ;
600        }
601
602        cur_page ++;
603        cnt ++;
604    }
605    return cnt;
606}
607

Archive Download this file



interactive