tools/build-R2_19_3/fsboot/cbl/nand/rflnandflash.c

Go to the documentation of this file.
00001 /* vi: set sw=2 ts=2: */
00002 //==========================================================================
00003 //
00004 //      rflnandflash.c
00005 //
00006 //      NAND Flash support used in Axis RFL
00007 //
00008 //==========================================================================
00009 //####COPYRIGHTBEGIN####
00010 //                                                                          
00011 // -------------------------------------------                              
00012 // The contents of this file are subject to the Red Hat eCos Public License 
00013 // Version 1.1 (the "License"); you may not use this file except in         
00014 // compliance with the License.  You may obtain a copy of the License at    
00015 // http://www.redhat.com/                                                   
00016 //                                                                          
00017 // Software distributed under the License is distributed on an "AS IS"      
00018 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the 
00019 // License for the specific language governing rights and limitations under 
00020 // the License.                                                             
00021 //                                                                          
00022 // The Original Code is eCos - Embedded Configurable Operating System,      
00023 // released September 30, 1998.                                             
00024 //                                                                          
00025 // The Initial Developer of the Original Code is Red Hat.                   
00026 // Portions created by Red Hat are                                          
00027 // Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.                             
00028 // All Rights Reserved.                                                     
00029 // -------------------------------------------                              
00030 //                                                                          
00031 //####COPYRIGHTEND####
00032 //==========================================================================
00033 //#####DESCRIPTIONBEGIN####
00034 //
00035 // Author(s):    starvik@axis.com
00036 // Contributors: starvik@axis.com
00037 // Date:         2006-03-11
00038 // Purpose:      
00039 // Description:  
00040 //              
00041 // This code is part of RedBoot (tm).
00042 //
00043 //
00044 //####DESCRIPTIONEND####
00045 //
00046 //==========================================================================
00047 
00048 #define diag_printf printf
00049 
00050 /* Debug messages. */
00051 #define D(x) x
00052 /* Detailed debug messages, verbose. */
00053 #define D_D(x) x 
00054 
00055 //#include <redboot.h>
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 //#include <cyg/hal/hardware.h>
00064 //#include <cyg/hal/nandflash.h>
00065 
00066 #include <axisrfl/funcs.h>
00067 
00068 #include <string.h>
00069 
00070 
00071 /* Buffer sizes, for mtd */
00072 //#define DATA_BUF_SIZE (1024 * (128 + 2)) /* (512 + 16) ok for small chips */
00073 //#define OOB_BUF_SIZE (32768)             /* (512) ok for small chips      */
00074 // Elphel !!!!
00075 //#define DATA_BUF_SIZE (2048)
00076 //#define OOB_BUF_SIZE (1024) 
00077 //#define DATA_BUF_SIZE (4096 * 2)
00078 //#define DATA_BUF_SIZE (4096)
00079 #define DATA_BUF_SIZE (2048 + 128)
00080 
00081 //#define DATA_BUF_SIZE (2048)
00082 #define OOB_BUF_SIZE (4096) 
00083 
00084 /* Buffers for mtd */
00085 u_char data_buf[DATA_BUF_SIZE];
00086 u_char oob_buf[OOB_BUF_SIZE];
00087 
00088 /* Mtd structures */
00089 static struct mtd_info mtd_info;
00090 static struct nand_chip nand_chip;
00091 
00092 /* main mtd structure referring to our NAND flash */
00093 static struct mtd_info *our_mtd = NULL;
00094 
00095 /* Stuff for rflflash_nand_rw */
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 /* Value to use for end when don't have anything better */
00104 #define NO_END_LIMIT    (0xffffffff)
00105 
00106 /* Minimum size to checksum over, necessary to get ECC operating correctly. */
00107 #define CSUM_CHUNK_SIZE (NAND_ECC_SIZE)
00108 
00109 /* testing */
00110 /* WARNING: enabling any of these will force (artificial) bad blocks into the
00111  * flash. These _cannot_ be erased unless the mtd layer is patched!  */
00112 /* Note: When testing, the addresess below must be chosen to correspond
00113  * to the image being downloaded. */
00114 #define TEST_WRITE_FAILED (0)
00115 #define TEST_WRITE_BADADDR (0x48000)
00116 #define TEST_ERASE_FAILED (0)
00117 #define TEST_ERASE_FILL (0) /* fill to end of flash when set, else one block */
00118 #define TEST_ERASE_BADADDR (0x268000)
00119 
00120 /* Contains integer larger than zero on error defined in rflflash.h.  */
00121 unsigned long errno_flash;
00122 
00123 static unsigned verbose_nand = 0;
00124 /*
00125  * Read/write nand flash, with badblock skip 
00126  * From U-Boot 1.4.4, modified
00127  * Modified to skip bad blocks developing during write
00128  * Operates on an mtd, mode may be read, write or checksum.
00129  * Partition operated on is start .. end-1, with len bytes of (valid) data
00130  * retlen will be set to # bytes operated on (if != NULL)
00131  * retcsum will be set to checksum if != NULL and mode is checksum
00132  * buffer is read/write buffer, may be NULL when checksumming.
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         /* eblk (once set) is the start of the erase block containing the
00148          * data being processed.
00149          */
00150         size_t eblk = ~0;       /* force mismatch on first pass */
00151         size_t erasesize = mtd->erasesize;
00152 
00153         while (len && start < end) 
00154         {
00155                 if ((start & (-erasesize)) != eblk) 
00156                 {
00157                         /* have crossed into new erase block, deal with
00158                          * it if it is marked bad.
00159                          */
00160                         eblk = start & (-erasesize); /* start of block */
00161                         if (mtd->block_isbad (mtd, eblk)) {
00162                           //D_D(diag_printf("nand_rw: bad block, skipping\n"));
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                 /* The ECC will not be calculated correctly if
00185                    less than 512 is written or read */
00186                 /* Is request at least 512 bytes AND it starts on a proper boundary */
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                 /* how much to read/write until the end of this eraseblock */
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                   //              printf("HERE\n");
00201                         ret = mtd->write_ecc(mtd, start, this_len,
00202                                              (size_t *)&n, (u_char*)buf, NULL, NULL);
00203 #if TEST_WRITE_FAILED
00204                         /* Test code - force bad block */
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) /* write failed: mark block as bad, skip and continue */
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                                 /* Now we need to restart writing the data so far written to this
00221                                  * block to the next one. Thus, we must back up the input buf pointer
00222                                  * as far as we have gotten into this block.
00223                                  * This assumes that we started writing buf at the start of a block.
00224                                  * A reasonable assumption given that partitions are block aligned. */
00225                                 buf -= start - eblk; /* how far into the block we are */
00226                                 total -= start - eblk;
00227                                 len += start - eblk;
00228                                 start = eblk + erasesize; /* start of next block */
00229 
00230                                 /* And in case the assumption is false: */
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; /* bad mode, just get out of here */
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 /* with initial rflflash_init */
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  * erase flash between addresses indicated, skipping bad blocks
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                         //                      D_D(diag_printf("Erasing block at 0x%lx, status %d\n", start, mtd_err));
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                         /* Test code - force bad block */
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) /* write failed, so we mark block as bad */
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 //                if (verbose_nand) {
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                   //D_D(diag_printf("Block at 0x%lx is bad, skipping.\n", start));
00358                 }
00359                 start += mtd->erasesize;
00360         }
00361         return 0;
00362 }
00363 
00364 
00365 /* 
00366  * Write size octets from buffer source to memory starting at offset.
00367  * Prior to write, erase whole area from offset to end_offset-1.
00368  * Limitation: Must be complete eraseblocks, and start at start of a block.
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         /*      printf(">rflflash_write(%s) %x, %x, %x, %x\n", 
00378                 __FILE__, source, offset, end_offset, size); */
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 /* dump nand memory region, addresses are offsets from 0 in nand */
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; /* pages per block */
00449     int from_page      = from/pagesize;
00450     int to_page        = to/pagesize;
00451     int current_page   = from_page; /* -1 so we get new page immediately */
00452 
00453     while(current_page <= to_page) {
00454       //printf("new page %d, a=0x%x i=0x%x\n", current_page, current_page*pagesize, i);
00455 
00456       /* New block? Check if it's bad. */
00457       if ((current_page%ppb) == 0) { 
00458         unsigned current_block = current_page/ppb;
00459         //printf("new block %d\n", current_block);
00460 
00461         /* check bad block in first two pages */
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       { /* read page */
00475         unsigned long foo;
00476         rflflash_read(current_page*pagesize, data_buf, pagesize, &foo);
00477         //printf("read 0x%x 0x%x\n", current_page*pagesize, *(int*)data_buf[4]);
00478       }
00479       
00480       {
00481         unsigned l;
00482         /* print page */
00483         for(l=0;l<pagesize && i<to; l+=16, i+=4) {
00484           /* print one line */
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 /* dump oob in memory region, addresses are offsets from 0 in nand */
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  * Read data from flash to datum (copy size bytes). Returns errno_flash .
00568  * Limitation: Must read at least 512 bytes, and from start of a page.
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         //      diag_printf("Read from 0x%x, len 0x%x, to 0x%x\n", offset, size, datum);
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  * Checksum data from flash (size bytes). Returns error code.
00598  * Limitation: Size must be at least 512 bytes, and from start of a page.
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  *      hardware specific access to control-lines, via hal nand layer
00629  */
00630 static void
00631 nand_hwcontrol(struct mtd_info *mtd, int cmd)
00632 {
00633 /* If we're "lucky" and the control values match 1 to 1 ... */
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); /* call hal function directly */
00641 
00642 #else /* map them */
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  * Read busy line on flash chip
00673  */
00674 static int
00675 nand_device_ready(struct mtd_info *mtd)
00676 {
00677         return hal_nand_device_ready();
00678 }
00679 
00680 
00681 /*
00682  * Deduce the number of flash units and the type of each unit.
00683  * Returns 0 on success, and the bit mask errno_flash on error.
00684  */
00685 unsigned long
00686 rflflash_init (void)
00687 {
00688   //printf(">rflflash_init\n");
00689 
00690         if (!our_mtd)
00691         {
00692                 /* Initialize the hardware */
00693                 hal_nand_init();
00694 
00695                 /* Clear structures */
00696                 memset((char *) &mtd_info, 0, sizeof(struct mtd_info));
00697                 memset((char *) &nand_chip, 0, sizeof(struct nand_chip));
00698 
00699                 /* Link the private data with the MTD structure */
00700                 mtd_info.priv = &nand_chip;
00701 
00702                 /* Set address of NAND IO lines */
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                 /* 20 us command delay time */
00708                 nand_chip.chip_delay = 20;              
00709                 nand_chip.eccmode = NAND_ECC_SOFT;
00710                 /* buffers */
00711                 nand_chip.data_buf = data_buf;
00712                 nand_chip.oob_buf = oob_buf;
00713 
00714                 /* Enable the following for a flash based bad block table */
00715 //              nand_chip.options = NAND_USE_FLASH_BBT;
00716 
00717                 /* don't scan for BBT - we read them on-the-fly */
00718 //              nand_chip.options = NAND_SKIP_BBTSCAN;
00719                 nand_chip.options = NAND_USE_FLASH_BBT;
00720 //              nand_chip.options = 0;
00721 
00722                 /* Scan to find existance of the device */
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                   //D(diag_printf("rflflash_init(NAND): NAND flash detected:\n"));
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  * Return page size for nand flash in use
00742  */
00743 unsigned long
00744 rflflash_nand_pagesize(void)
00745 {
00746         if (our_mtd)
00747                 return our_mtd->oobblock;
00748         else
00749                 return 1; /* 0 might lead to an infinite loop somewhere */
00750 }
00751 
00752 /*
00753  * Return total size of nand flash in use
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 /*************************** END OF FILE *******************************/

Generated on Fri Nov 28 00:06:25 2008 for elphel by  doxygen 1.5.1