os/nandboot-R2_0_4/bootload.c

Go to the documentation of this file.
00001 /*****************************************************************************
00002 *!
00003 *! FILE NAME  : bootload.c
00004 *!
00005 *! DESCRIPTION: Boot loader for NAND chips on ETRAX FS.
00006 *!
00007 *! ---------------------------------------------------------------------------
00008 *! Portions (nand_rw) derived from U-Boot 1.4.4 (common/cmd_nand.c):
00009 *! Driver for NAND support, Rick Bronson
00010 *! borrowed heavily from:
00011 *! (c) 1999 Machine Vision Holdings, Inc.
00012 *! (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
00013 *!
00014 *! Added 16-bit nand support
00015 *! (C) 2004 Texas Instruments
00016 *!
00017 *! Boot loader function
00018 *! (C) Copyright 2006-2007, Axis Communications AB, LUND, SWEDEN
00019 *!
00020 *! This program is free software; you can redistribute it and/or modify
00021 *! it under the terms of the GNU General Public License as published by
00022 *! the Free Software Foundation; either version 2 of the License, or
00023 *! (at your option) any later version.
00024 *!
00025 *! This program is distributed in the hope that it will be useful,
00026 *! but WITHOUT ANY WARRANTY; without even the implied warranty of
00027 *! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00028 *! GNU General Public License for more details.
00029 *!
00030 *! You should have received a copy of the GNU General Public License
00031 *! along with this program; if not, write to the Free Software
00032 *! Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00033 *!
00034 *!***************************************************************************/
00035 
00036 #include <linux/types.h>
00037 #include <linux/autoconf.h>
00038 
00039 #include "mtd.h"
00040 #include "nand.h"
00041 #include "delay.h"
00042 
00043 #include <asm/arch/hwregs/reg_rdwr.h>
00044 #include <asm/arch/hwregs/reg_map.h>
00045 #include <asm/arch/hwregs/pinmux_defs.h>
00046 
00047 #include <asm/arch/hwregs/reg_map.h>
00048 #include <asm/arch/hwregs/bif_core_defs.h>
00049 #include <asm/arch/hwregs/gio_defs.h>
00050 #include <asm/arch/hwregs/pinmux_defs.h>
00051 
00052 #include "lib.h"
00053 
00054 #include "bootconfig.h"
00055 
00056 #define BOOTDEBUG 1
00057 #define MORE_BOOTDEBUG 1
00058 
00059 /* Control macros for NAND read/write function from U-Boot 1.4.4 */
00060 /* bits for nand_rw() `cmd'; or together as needed */
00061 
00062 #define NANDRW_READ             0x01
00063 #define NANDRW_WRITE            0x00
00064 #define NANDRW_JFFS2            0x02
00065 #define NANDRW_JFFS2_SKIP       0x04
00066 
00067 #define ROUND_DOWN(value, boundary)      ((value) & (~((boundary)-1)))
00068 
00069 /* set $r8 to RAM_INIT_MAGIC, $r12 to NAND_BOOT_MAGIC then jump */
00070 /* multiple macros needed to get the constants into the asm string properly */
00071 #define SET_MAGIC_AND_BOOT(ADDR, MAGIC_R8, MAGIC_R12) \
00072         __asm__ volatile (" \
00073         move.d " #MAGIC_R8 ", $r8\n\
00074         move.d " #MAGIC_R12 ", $r12\n\
00075         jump %0\n\
00076         nop\n\
00077         " : : "r" (ADDR))
00078 #define BOOT1(ADDR, MAGIC_R8, MAGIC_R12) \
00079         SET_MAGIC_AND_BOOT(ADDR, MAGIC_R8, MAGIC_R12);
00080 #define BOOT(ADDR) \
00081         BOOT1(ADDR, RAM_INIT_MAGIC, NAND_BOOT_MAGIC);
00082 
00083 extern struct mtd_info *crisv32_nand_flash_probe(void);
00084 
00085 extern int _end, _bss, _edata;
00086 
00087 /*
00088  * NAND read/write from U-Boot 1.4.4
00089  * Modified for newer mtd and use of mtd interface instead of nand directly.
00090  * Note: bad block skipping assumes read starts on a block boundary.
00091  *
00092  * cmd: 0: NANDRW_WRITE                 write, fail on bad block
00093  *      1: NANDRW_READ                  read, fail on bad block
00094  *      2: NANDRW_WRITE | NANDRW_JFFS2  write, skip bad blocks
00095  *      3: NANDRW_READ | NANDRW_JFFS2   read, data all 0xff for bad blocks
00096  *      7: NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP read, skip bad blocks
00097  */
00098 static int
00099 nand_rw (struct mtd_info* mtd, int cmd,
00100          size_t start, size_t len,
00101          size_t *retlen, u_char * buf)
00102 {
00103         int total = 0;
00104         int ret = 0;
00105         int n;
00106 
00107         /* eblk (once set) is the start of the erase block containing the
00108          * data being processed.
00109          */
00110         size_t eblk = ~0;       /* force mismatch on first pass */
00111         size_t erasesize = mtd->erasesize;
00112 
00113         putnl();
00114         while (len) {
00115                 if ((start & (-erasesize)) != eblk) {
00116                         /* have crossed into new erase block, deal with
00117                          * it if it is marked bad.
00118                          */
00119                         eblk = start & (-erasesize); /* start of block */
00120 #if BOOTDEBUG
00121                         puts("New block ");
00122                         putx(eblk);
00123                         puts(";len: ");
00124                         putx(len);
00125                         puts(";start: ");
00126                         putx(start);
00127                         putnl();
00128 #endif
00129                         /* if block is bad, just skip it, and read next block */
00130                         if (mtd->block_isbad(mtd, eblk)) {
00131                                 if (cmd == (NANDRW_READ | NANDRW_JFFS2)) {
00132 //                                      len -= erasesize;
00133                                         start += erasesize;
00134                                         puts("bad block - skip it ...1");
00135                                         putnl();
00136 /*
00137                                         while (len > 0 && start - eblk < erasesize) {
00138                                                 *(buf++) = 0xff;
00139                                                 ++start;
00140                                                 ++total;
00141                                                 --len;
00142                                         }
00143 */
00144                                         continue;
00145                                 } else if (cmd == (NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP)) {
00146                                         puts("bad block - skip it ...2");
00147                                         putnl();
00148                                         start += erasesize;
00149                                         continue;
00150                                 } else if (cmd == (NANDRW_WRITE | NANDRW_JFFS2)) {
00151                                         puts("bad block - skip it ...3");
00152                                         putnl();
00153                                         /* skip bad block */
00154                                         start += erasesize;
00155                                         continue;
00156                                 } else {
00157                                         puts("bad block - skip it ...4");
00158                                         putnl();
00159                                         ret = 1;
00160                                         break;
00161                                 }
00162                         }
00163                 }
00164 
00165 #if 0
00166                 buf = (void *) 0x38008000; /* to fixed address, for testing */
00167 #endif
00168 
00169                 if (cmd & NANDRW_READ) {
00170                         ret = mtd->read_ecc(mtd, start,
00171                                             min(len, eblk + erasesize - start),
00172                                             (size_t *)&n, (u_char*)buf,
00173                                             NULL, NULL);
00174                 } else {
00175                         ret = mtd->write_ecc(mtd, start,
00176                                              min(len, eblk + erasesize - start),
00177                                              (size_t *)&n, (u_char*)buf,
00178                                              NULL, NULL);
00179                 }
00180 
00181                 if (ret) {
00182                         break;
00183                 }
00184 
00185                 start  += n;
00186                 buf   += n;
00187                 total += n;
00188                 len   -= n;
00189         }
00190         if (retlen)
00191                 *retlen = total;
00192 
00193         return ret;
00194 }
00195 
00196 
00197 void
00198 bootload(void)
00199 {
00200         char revision;
00201         struct mtd_info *mtd;
00202         int res;
00203         int copied;
00204 #if BOOTDEBUG
00205         int i;
00206 #endif
00207 
00208         serial_init();
00209 
00210 //      *(unsigned long *)REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg) = CONFIG_ETRAX_MEM_GRP1_CONFIG;
00211 //      *(unsigned long *)REG_ADDR(bif_core, regi_bif_core, rw_grp2_cfg) = CONFIG_ETRAX_MEM_GRP2_CONFIG;
00212         *(unsigned long *)REG_ADDR(bif_core, regi_bif_core, rw_grp3_cfg) = CONFIG_ETRAX_MEM_GRP3_CONFIG;
00213 //      *(unsigned long *)REG_ADDR(bif_core, regi_bif_core, rw_grp4_cfg) = CONFIG_ETRAX_MEM_GRP4_CONFIG;
00214 
00215         __asm__ volatile ("move $vr,%0" : "=rm" (revision));
00216         if (revision < 32) {
00217                 error("You need an ETRAX FS to run Linux 2.6/crisv32.\r\n");
00218                 while(1);
00219         }
00220         puts("Clear cmdline from memory") ;
00221         putnl();
00222         unsigned long *ul_cmdline_ram = (unsigned long *)0xC0004000;
00223         ul_cmdline_ram[0] = 0x00000000;
00224 
00225 #if BOOTDEBUG
00226         puts("\r\n\nETRAX FS NAND boot loader\r\n");
00227         puts("=========================\r\n");
00228         puts("Rev 1, " __DATE__ " " __TIME__ "\r\n");
00229 
00230         puts("Boot config: ");
00231         putx(FETCH_ADDR);
00232         puts("->");
00233         putx(STORE_ADDR);
00234         puts(", len ");
00235         putx(LOAD_SIZE);
00236         puts(", boot @ ");
00237         putx(BOOT_ADDR);
00238         putnl();
00239 
00240         puts("CPU revision: ");
00241         putx(revision);
00242         putnl();
00243 
00244 #if MORE_BOOTDEBUG
00245         puts("Bootloader main at ") ;
00246         putx((int) bootload);
00247         putnl();
00248 
00249         puts("Data end: ");
00250         putx((long) &_edata);
00251         putnl();
00252 
00253         puts("Bss: ");
00254         putx((long) &_bss);
00255         putnl();
00256 
00257         puts("Heap: ");
00258         putx((long) &_end);
00259         putnl();
00260 #endif
00261 
00262         puts("Identifying nand chip...\r\n");
00263 #endif
00264 
00265         mtd = crisv32_nand_flash_probe();
00266 
00267 #if BOOTDEBUG
00268         puts("Done.\r\n");
00269 #endif
00270 
00271         if (!mtd)
00272                 error("No NAND flash chip found to boot from.");
00273 
00274 #if BOOTDEBUG
00275         puts("Chip identified... 3; ");
00276 
00277 #if MORE_BOOTDEBUG
00278         if (mtd->name)
00279                 puts(mtd->name);
00280 
00281         puts("\r\ntype: ");
00282         putx(mtd->type);
00283         puts("\r\nflags: ");
00284         putx(mtd->flags);
00285         puts("\r\nsize: ");
00286         putx(mtd->size);
00287         puts("\r\nerasesize: ");
00288         putx(mtd->erasesize);
00289         puts("\r\noobblock: ");
00290         putx(mtd->oobblock);
00291         puts("\r\noobsize: ");
00292         putx(mtd->oobsize);
00293         puts("\r\necctype: ");
00294         putx(mtd->ecctype);
00295         puts("\r\neccsize: ");
00296         putx(mtd->eccsize);
00297 #endif /* MORE BOOTDEBUG */
00298         putnl();
00299 
00300 /*
00301         puts("Bad blocks:\r\n");
00302 
00303         for (i = 0; i < mtd->size; i += mtd->erasesize) {
00304                 if (mtd->block_isbad(mtd, i)) {
00305                         putx(i);
00306                         putnl();
00307                 }
00308         }
00309 */
00310 #endif /* BOOTDEBUG */
00311 
00312 #if MORE_BOOTDEBUG /* print oob parameters */
00313         puts("Oob info:\r\n");
00314         puts("useecc: ");
00315         putx(mtd->oobinfo.useecc);
00316         puts("\r\neccbytes: ");
00317         putx(mtd->oobinfo.eccbytes);
00318         puts("\r\neccpos: ");
00319         for (i = 0; i < mtd->oobinfo.eccbytes; i++) {
00320                 putx(mtd->oobinfo.eccpos[i]);
00321                 putc(' ');
00322         }
00323         putnl();
00324 #endif
00325 
00326 #if BOOTDEBUG
00327         puts("Bootload in progress...");
00328 #endif
00329 //      res = 1;
00330 //      while(res) {
00331 //              puts("---> try to read from flash from address: ");
00332 //              putx(FETCH_ADDR);
00333 //              putnl();
00334         res = nand_rw(mtd,
00335                       NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP,
00336                       FETCH_ADDR, LOAD_SIZE, &copied,
00337                       (void *) STORE_ADDR);
00338 //      }
00339 
00340 #if BOOTDEBUG
00341         puts("complete, status ");
00342         putx(res);
00343         puts(", loaded ");
00344         putx(copied);
00345         puts(" bytes\r\n");
00346 
00347         puts("Data in DRAM:\r\n");
00348         putx(* (int *) STORE_ADDR);
00349         putc(' ');
00350         putx(* (int *) (STORE_ADDR+4));
00351         putc(' ');
00352         putx(* (int *) (STORE_ADDR+8));
00353         putnl();
00354 #endif
00355 
00356         if (res)
00357                 error("Corrupt data in NAND flash.");
00358 
00359 #if BOOTDEBUG
00360         puts("Booting...\r\n");
00361 #endif
00362 
00363         BOOT(BOOT_ADDR);
00364 
00365         while (1)
00366                 ; /* hang around for a while ... */
00367 }

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