00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 #define diag_printf printf
00049
00050
00051 #define D(x) x
00052
00053 #define D_D(x) x
00054
00055
00056 #include <linuxerr.h>
00057 #include <nandflash.h>
00058
00059 #include <axisrfl/types.h>
00060 #include <axisrfl/mtd.h>
00061 #include <axisrfl/mtd_nand.h>
00062 #include <axisrfl/rflflash.h>
00063
00064
00065
00066 #include <axisrfl/funcs.h>
00067
00068 #include <string.h>
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079 #define DATA_BUF_SIZE (2048 + 128)
00080
00081
00082 #define OOB_BUF_SIZE (4096)
00083
00084
00085 u_char data_buf[DATA_BUF_SIZE];
00086 u_char oob_buf[OOB_BUF_SIZE];
00087
00088
00089 static struct mtd_info mtd_info;
00090 static struct nand_chip nand_chip;
00091
00092
00093 static struct mtd_info *our_mtd = NULL;
00094
00095
00096 #define ROUND_DOWN(value, boundary) ((value) & (~((boundary)-1)))
00097 #define NAND_ECC_SIZE (512)
00098
00099 #define NAND_READ (0)
00100 #define NAND_WRITE (1)
00101 #define NAND_CSUM (2)
00102
00103
00104 #define NO_END_LIMIT (0xffffffff)
00105
00106
00107 #define CSUM_CHUNK_SIZE (NAND_ECC_SIZE)
00108
00109
00110
00111
00112
00113
00114 #define TEST_WRITE_FAILED (0)
00115 #define TEST_WRITE_BADADDR (0x48000)
00116 #define TEST_ERASE_FAILED (0)
00117 #define TEST_ERASE_FILL (0)
00118 #define TEST_ERASE_BADADDR (0x268000)
00119
00120
00121 unsigned long errno_flash;
00122
00123 static unsigned verbose_nand = 0;
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134 static int
00135 rflflash_nand_rw (struct mtd_info* mtd, int mode,
00136 size_t start, size_t end, size_t len,
00137 size_t *retlen, unsigned long *retcsum,
00138 u_char *buffer)
00139 {
00140 int ret = 0, n, total = 0;
00141 static u_char csumbuf[CSUM_CHUNK_SIZE];
00142 unsigned long int csum = 0;
00143 int i;
00144 size_t this_len;
00145 u_char *buf = buffer;
00146
00147
00148
00149
00150 size_t eblk = ~0;
00151 size_t erasesize = mtd->erasesize;
00152
00153 while (len && start < end)
00154 {
00155 if ((start & (-erasesize)) != eblk)
00156 {
00157
00158
00159
00160 eblk = start & (-erasesize);
00161 if (mtd->block_isbad (mtd, eblk)) {
00162
00163 if (mode == NAND_WRITE) {
00164 if (verbose_nand) {
00165 printf("Skipping bad block 0x%x, 0x%8.8x-0x%8.8x\n",
00166 eblk/erasesize,
00167 eblk,
00168 eblk+(1*erasesize)-1);
00169 }
00170 }
00171
00172 start += erasesize;
00173 continue;
00174 }
00175 if (mode == NAND_WRITE) {
00176 unsigned block = start/mtd->erasesize;
00177 if (verbose_nand) {
00178 printf("Writing block 0x%x, 0x%8.8x-0x%8.8x\n",
00179 block, block*mtd->erasesize, (block+1)*mtd->erasesize);
00180 }
00181 }
00182
00183 }
00184
00185
00186
00187 if((start != ROUND_DOWN(start, NAND_ECC_SIZE)) || (len < NAND_ECC_SIZE))
00188 {
00189 D(diag_printf("Warning nand accesses should be at least 512 bytes and start on a 512 byte boundary\n"));
00190
00191 }
00192
00193
00194 this_len = min_t(size_t,
00195 (mode == NAND_CSUM) ? CSUM_CHUNK_SIZE : len,
00196 eblk + erasesize - start);
00197
00198 if (mode == NAND_WRITE)
00199 {
00200
00201 ret = mtd->write_ecc(mtd, start, this_len,
00202 (size_t *)&n, (u_char*)buf, NULL, NULL);
00203 #if TEST_WRITE_FAILED
00204
00205 if (start == TEST_WRITE_BADADDR)
00206 {
00207 D(diag_printf("nand_write: forcing bad block at 0x%x\n", start));
00208 ret = -EIO;
00209 }
00210 #endif
00211 if (ret == -EIO)
00212 {
00213 printf("Block 0x%x failed during write, 0x%8.8x-0x%8.8x\n",
00214 start/erasesize,
00215 start,
00216 start+erasesize);
00217
00218 mtd->block_markbad(mtd, start);
00219
00220
00221
00222
00223
00224
00225 buf -= start - eblk;
00226 total -= start - eblk;
00227 len += start - eblk;
00228 start = eblk + erasesize;
00229
00230
00231 if (buf < buffer)
00232 {
00233 start += buffer - buf;
00234 total += buffer - buf;
00235 len -= buffer - buf;
00236 buf = buffer;
00237 }
00238
00239 continue;
00240 }
00241 }
00242 else if (mode == NAND_READ)
00243 ret = mtd->read_ecc(mtd, start, this_len,
00244 (size_t *)&n, (u_char*)buf, NULL, NULL);
00245 else if (mode == NAND_CSUM)
00246 ret = mtd->read_ecc(mtd, start, this_len,
00247 (size_t *)&n, csumbuf, NULL, NULL);
00248 else
00249 n = len;
00250
00251 if (ret)
00252 break;
00253
00254 if (mode == NAND_CSUM)
00255 for (i = 0; i < n; i++)
00256 csum += csumbuf[i];
00257
00258 start += n;
00259 buf += n;
00260 total += n;
00261 len -= n;
00262 }
00263
00264 if (len && (start >= end)) {
00265 printf("Error. Writing exceeded the max_dst address 0x%8.8x\n", end);
00266 exit(0);
00267 }
00268 if (retlen)
00269 *retlen = total;
00270 if (retcsum)
00271 *retcsum = csum;
00272
00273 return ret;
00274 }
00275
00276
00277
00278
00279 int
00280 rflflash_nand_do_erase(unsigned long start, unsigned long end)
00281 {
00282 rflflash_init();
00283
00284 if (start >= our_mtd->size) {
00285 printf("Cannot erase from 0x%8.8x, nand size is 0x%8.8x\n", end, our_mtd->size);
00286 exit(0);
00287 }
00288 if (end >= our_mtd->size) {
00289 printf("Cannot erase to 0x%8.8x, nand size is 0x%8.8x\n", end, our_mtd->size);
00290 exit(0);
00291 }
00292 return (rflflash_nand_erase(our_mtd, start, end));
00293 }
00294
00295
00296
00297
00298 int
00299 rflflash_nand_erase (struct mtd_info *mtd,
00300 unsigned long start, unsigned long end)
00301 {
00302 struct erase_info mtd_erase;
00303 int mtd_err;
00304
00305 D(diag_printf(">rflflash_nand_erase(%s) Erase from 0x%lx to 0x%lx\n",
00306 __FILE__, start, end));
00307
00308 memset(&mtd_erase, 0, sizeof(mtd_erase));
00309
00310 while (start < end)
00311 {
00312 if (!mtd->block_isbad(mtd, start))
00313 {
00314 mtd_erase.addr = start;
00315 mtd_erase.len = mtd->erasesize;
00316 mtd_erase.mtd = mtd;
00317 mtd_err = mtd->erase(mtd, &mtd_erase);
00318
00319 if (verbose_nand) {
00320 unsigned block = start/mtd->erasesize;
00321 printf("Erasing block 0x%x, 0x%8.8x-0x%8.8x\n",
00322 block, block*mtd->erasesize, (block+1)*mtd->erasesize);
00323 }
00324
00325 #if TEST_ERASE_FAILED
00326
00327 #if TEST_ERASE_FILL
00328 if (start >= TEST_ERASE_BADADDR)
00329 #else
00330 if (start == TEST_ERASE_BADADDR)
00331 #endif
00332 {
00333 D(diag_printf("nand_erase: forcing bad block at 0x%x\n", start));
00334 mtd_err = -EIO;
00335 }
00336 #endif
00337 if (mtd_err)
00338 {
00339 if (mtd_err == -EIO)
00340 {
00341 mtd->block_markbad(mtd, start);
00342 D_D(diag_printf("Block at 0x%lx has become bad, skipping\n", start));
00343 }
00344 else
00345 return mtd_err;
00346 }
00347 } else {
00348 unsigned block = start/mtd->erasesize;
00349
00350
00351 printf("Skipping bad block 0x%x, 0x%8.8x-0x%8.8x\n",
00352 block,
00353 block*mtd->erasesize,
00354 (block+1)*mtd->erasesize-1);
00355
00356
00357
00358 }
00359 start += mtd->erasesize;
00360 }
00361 return 0;
00362 }
00363
00364
00365
00366
00367
00368
00369
00370 unsigned long
00371 rflflash_write (unsigned char *source, unsigned long offset,
00372 unsigned long end_offset, unsigned long size)
00373 {
00374 int mtd_err;
00375 size_t written_size;
00376
00377
00378
00379
00380 if (our_mtd)
00381 {
00382 mtd_err = rflflash_nand_erase(our_mtd, offset, end_offset);
00383 if (mtd_err)
00384 errno_flash |= ERROR_ERASE_FAILED;
00385 else
00386 {
00387 mtd_err = rflflash_nand_rw (our_mtd, NAND_WRITE,
00388 offset, end_offset, size,
00389 &written_size, NULL, source);
00390 if (mtd_err || written_size != size)
00391 errno_flash |= ERROR_WRITE_FAILED;
00392 }
00393 }
00394 else
00395 errno_flash = ERROR_NO_CHIP_FOUND;
00396
00397 return errno_flash;
00398 }
00399
00400 void
00401 rflflash_mark_bad(unsigned long from, unsigned long to)
00402 {
00403 rflflash_init();
00404
00405 unsigned pagesize = rflflash_nand_pagesize();
00406 unsigned blocksize = our_mtd->erasesize;
00407 unsigned from_block = from/blocksize;
00408 unsigned to_block = to/blocksize;
00409 unsigned p;
00410 unsigned b;
00411
00412 if (!our_mtd->ignore_bad) {
00413 printf("Error, --nandignorebad must be set to allow --nandmarkbad.\n");
00414 exit(0);
00415 }
00416
00417 for (b=from_block; b<=to_block; b++) {
00418 printf("mark bad block 0x%x, 0x%8.8x-0x%8.8x\n", b, b*blocksize, ((b+1)*blocksize)-1);
00419 our_mtd->block_markbad(our_mtd, b*blocksize);
00420 our_mtd->block_markbad(our_mtd, b*blocksize+pagesize);
00421 }
00422
00423 }
00424
00425 void
00426 rflflash_ignore_bad()
00427 {
00428 rflflash_init();
00429
00430 printf(">rflflash_ignore_bad\n");
00431
00432 our_mtd->ignore_bad = 1;
00433 }
00434
00435
00436
00437 void
00438 rflflash_dump(unsigned long from, unsigned long to)
00439 {
00440 unsigned *i = from;
00441 int j;
00442
00443 rflflash_init();
00444
00445 {
00446 int pagesize = rflflash_nand_pagesize();
00447 unsigned blocksize = our_mtd->erasesize;
00448 unsigned ppb = blocksize/pagesize;
00449 int from_page = from/pagesize;
00450 int to_page = to/pagesize;
00451 int current_page = from_page;
00452
00453 while(current_page <= to_page) {
00454
00455
00456
00457 if ((current_page%ppb) == 0) {
00458 unsigned current_block = current_page/ppb;
00459
00460
00461
00462 if ((our_mtd->block_isbad(our_mtd, (current_block)*blocksize)) ||
00463 (our_mtd->block_isbad(our_mtd, (current_block)*blocksize+pagesize))) {
00464 printf("Skipping bad block 0x%x, 0x%8.8x-0x%8.8x\n",
00465 current_block,
00466 current_block*blocksize,
00467 (current_block+1)*blocksize-1);
00468 current_page+=ppb;
00469 i+=(blocksize/4);
00470 continue;
00471 }
00472 }
00473
00474 {
00475 unsigned long foo;
00476 rflflash_read(current_page*pagesize, data_buf, pagesize, &foo);
00477
00478 }
00479
00480 {
00481 unsigned l;
00482
00483 for(l=0;l<pagesize && i<to; l+=16, i+=4) {
00484
00485 printf("%8.8x :", i);
00486 for(j=0; j != 4 && (i+j < to); j++) {
00487 printf(" %8.8x", *(unsigned*)(data_buf+(((unsigned)i+j*4)-(current_page*pagesize))));
00488
00489 }
00490 printf("\r\n");
00491 }
00492 }
00493
00494 current_page++;
00495 }
00496 }
00497
00498 }
00499
00500
00501
00502 void
00503 rflflash_dump_oob(unsigned long from, unsigned long to, unsigned char only_bad)
00504 {
00505 rflflash_init();
00506
00507 unsigned pagesize = rflflash_nand_pagesize();
00508 unsigned from_page = from/pagesize;
00509 unsigned to_page = to/pagesize;
00510 unsigned blocksize = our_mtd->erasesize;
00511 unsigned p;
00512 struct nand_chip *this;
00513 unsigned badblockpos;
00514 unsigned char buf[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
00515
00516
00517 #if 0
00518 if (only_bad) {
00519 unsigned i;
00520
00521 for(i=0; i!=16; i++) {
00522 rflflash_nand_erase(our_mtd, 0, 500);
00523 our_mtd->write_oob(our_mtd, i, 1, &p, buf);
00524 rflflash_dump_oob(0, 1, 0);
00525 }
00526 }
00527 #endif
00528
00529 this = our_mtd->priv;
00530 badblockpos = this->badblockpos;
00531
00532 for (p=from_page; p<=to_page; p++) {
00533 size_t ret;
00534
00535 our_mtd->read_oob(our_mtd, p*pagesize, our_mtd->oobsize, &ret, oob_buf);
00536
00537 if(only_bad) {
00538 if(oob_buf[badblockpos-1] == 0xff) {
00539 continue;
00540 }
00541 }
00542
00543 {
00544 unsigned ppb = blocksize/pagesize;
00545 printf("block 0x%x, page 0x%x (0x%x in block), 0x%8.8x-0x%8.8x: ",
00546 (p*pagesize)/blocksize, p, p%ppb, p*pagesize, (p+1)*pagesize-1);
00547 }
00548
00549 {
00550 unsigned j;
00551
00552 for(j=0; j != our_mtd->oobsize; j++) {
00553 printf(" %2.2x", oob_buf[j]);
00554 }
00555 #if 0
00556 if (our_mtd->block_isbad(our_mtd, p*pagesize)) {
00557 printf(" BAD");
00558 }
00559 #endif
00560 printf("\r\n");
00561 }
00562 }
00563 }
00564
00565
00566
00567
00568
00569
00570 unsigned long
00571 rflflash_read (unsigned long offset, unsigned char *datum,
00572 unsigned long size, unsigned long *readlen)
00573 {
00574 int mtd_err;
00575 int read = 0;
00576
00577
00578 errno_flash = ERROR_RESET;
00579
00580 if (our_mtd)
00581 {
00582 mtd_err =
00583 rflflash_nand_rw(our_mtd, NAND_READ, offset, NO_END_LIMIT,
00584 size, &read, NULL, datum);
00585 if (mtd_err)
00586 errno_flash |= ERROR_READ_FAILED;
00587 }
00588 else
00589 errno_flash |= ERROR_NO_CHIP_FOUND;
00590
00591 if (readlen)
00592 *readlen = read;
00593 return errno_flash;
00594 }
00595
00596
00597
00598
00599
00600 unsigned long
00601 rflflash_checksum (unsigned long offset, unsigned long size,
00602 unsigned long *ret_csum)
00603 {
00604 int mtd_err;
00605 unsigned long csum;
00606 diag_printf("Csum from 0x%x, len 0x%x\n", offset, size);
00607
00608 errno_flash = ERROR_RESET;
00609
00610 if (our_mtd)
00611 {
00612 mtd_err =
00613 rflflash_nand_rw(our_mtd, NAND_CSUM, offset, NO_END_LIMIT,
00614 size, NULL, &csum, NULL);
00615 if (mtd_err)
00616 errno_flash |= ERROR_READ_FAILED;
00617 }
00618 else
00619 errno_flash |= ERROR_NO_CHIP_FOUND;
00620
00621 if (ret_csum)
00622 *ret_csum = csum;
00623 return errno_flash;
00624 }
00625
00626
00627
00628
00629
00630 static void
00631 nand_hwcontrol(struct mtd_info *mtd, int cmd)
00632 {
00633
00634 #if (NAND_CTL_SETCLE == NAND_SET_CLE) && \
00635 (NAND_CTL_CLRCLE == NAND_CLR_CLE) && \
00636 (NAND_CTL_SETALE == NAND_SET_ALE) && \
00637 (NAND_CTL_CLRALE == NAND_CLR_ALE) && \
00638 (NAND_CTL_SETNCE == NAND_SET_NCE) && \
00639 (NAND_CTL_CLRNCE == NAND_CLR_NCE)
00640 hal_nand_hwcontrol(cmd);
00641
00642 #else
00643 int halcmd;
00644
00645 switch (cmd) {
00646 case NAND_CTL_SETCLE:
00647 halcmd = NAND_SET_CLE;
00648 break;
00649 case NAND_CTL_CLRCLE:
00650 halcmd = NAND_CLR_CLE;
00651 break;
00652 case NAND_CTL_SETALE:
00653 halcmd = NAND_SET_ALE;
00654 break;
00655 case NAND_CTL_CLRALE:
00656 halcmd = NAND_CLR_ALE;
00657 break;
00658 case NAND_CTL_SETNCE:
00659 halcmd = NAND_SET_NCE;
00660 break;
00661 case NAND_CTL_CLRNCE:
00662 halcmd = NAND_CLR_NCE;
00663 break;
00664 }
00665
00666 hal_nand_hwcontrol(halcmd);
00667 #endif
00668 }
00669
00670
00671
00672
00673
00674 static int
00675 nand_device_ready(struct mtd_info *mtd)
00676 {
00677 return hal_nand_device_ready();
00678 }
00679
00680
00681
00682
00683
00684
00685 unsigned long
00686 rflflash_init (void)
00687 {
00688
00689
00690 if (!our_mtd)
00691 {
00692
00693 hal_nand_init();
00694
00695
00696 memset((char *) &mtd_info, 0, sizeof(struct mtd_info));
00697 memset((char *) &nand_chip, 0, sizeof(struct nand_chip));
00698
00699
00700 mtd_info.priv = &nand_chip;
00701
00702
00703 nand_chip.IO_ADDR_R = (void *) NAND_RD_ADDR;
00704 nand_chip.IO_ADDR_W = (void *) NAND_WR_ADDR;
00705 nand_chip.hwcontrol = nand_hwcontrol;
00706 nand_chip.dev_ready = nand_device_ready;
00707
00708 nand_chip.chip_delay = 20;
00709 nand_chip.eccmode = NAND_ECC_SOFT;
00710
00711 nand_chip.data_buf = data_buf;
00712 nand_chip.oob_buf = oob_buf;
00713
00714
00715
00716
00717
00718
00719 nand_chip.options = NAND_USE_FLASH_BBT;
00720
00721
00722
00723 if (nand_scan(&mtd_info, 1)) {
00724 D(diag_printf("rflflash_init(NAND): nand_scan failed\n"));
00725 }
00726 else
00727 {
00728 our_mtd = &mtd_info;
00729
00730
00731 printf("blocksize %d, pagesize %d, oobsize %d, total 0x%8.8x bytes\n",
00732 our_mtd->erasesize, our_mtd->oobblock,
00733 our_mtd->oobsize, our_mtd->size);
00734 }
00735 }
00736
00737 return errno_flash;
00738 }
00739
00740
00741
00742
00743 unsigned long
00744 rflflash_nand_pagesize(void)
00745 {
00746 if (our_mtd)
00747 return our_mtd->oobblock;
00748 else
00749 return 1;
00750 }
00751
00752
00753
00754
00755 unsigned long
00756 rflflash_nand_size(void)
00757 {
00758 if (our_mtd)
00759 return our_mtd->size;
00760 else
00761 return 0;
00762 }
00763
00764