changeset 2933:28851b95600b

import RedBoot NAND support patch as of 20090826
author Ross Younger <wry@ecoscentric.com>
date Mon, 02 Nov 2009 16:35:28 +0000
parents d3f316d0a705
children b190dd0f03b1
files packages/redboot/current/ChangeLog packages/redboot/current/cdl/redboot.cdl packages/redboot/current/src/fs/fileio.c packages/redboot/current/src/main.c packages/redboot/current/src/nand.c
diffstat 5 files changed, 367 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/packages/redboot/current/ChangeLog
+++ b/packages/redboot/current/ChangeLog
@@ -1,3 +1,11 @@
+2009-06-26  Ross Younger  <wry@ecoscentric.com>
+
+	* src/nand.c: Created for NAND utilities
+	* cdl/redboot.cdl: Build nand.c if it's appropriate.
+	CYGMEM_REDBOOT_WORKSPACE_HEAP defaults on where active.
+	* fs/fileio.c: Try to be more helpful if mount failed.
+	* main.c: If mallinfo exists, report on it.
+
 2009-06-24  Nick Garnett  <nickg@ecoscentric.com>
 
 	* cdl/redboot.cdl:
--- a/packages/redboot/current/cdl/redboot.cdl
+++ b/packages/redboot/current/cdl/redboot.cdl
@@ -1290,7 +1290,7 @@ cdl_package CYGPKG_REDBOOT {
             flavor	    	bool
             active_if   	CYGPKG_MEMALLOC
             active_if   	CYGPKG_MEMALLOC_MALLOC_ALLOCATORS
-            default_value	0
+            default_value	1
             description 	"
                     If the MEMALLOC package is present, it usually allocates
                     the whole of memory not used by the program to the heap.
@@ -1320,6 +1320,35 @@ cdl_package CYGPKG_REDBOOT {
                 The size of this buffer can have a big impart on load speed."
         }
 
+        cdl_component CYGPKG_REDBOOT_NAND {
+            display       "Include NAND utilities in RedBoot"
+            flavor        bool
+            default_value 1
+            active_if     CYGPKG_IO_NAND
+            requires      CYGPKG_IO_NAND
+            description   "
+              If this option is enabled then RedBoot will provide commands
+              to interrogate and manage NAND storage chips at a low level.
+              (Note that files are normally stored on a NAND chip
+               via a filesystem. To enable that, you need to add the
+               relevant package to the configuration and check that
+               CYGPKG_REDBOOT_FILEIO is enabled.)"
+            compile -library=libextras.a nand.c
+
+            cdl_option CYGSEM_REDBOOT_NAND_ERASE_CMD {
+                display     "Include support for nand erase command"
+                flavor      bool
+                default_value   1
+                active_if   CYGPKG_REDBOOT_NAND
+                description "
+                    This option provides a helper command to erase 
+                    a partition of a NAND device. It may be useful to 
+                    turn off if (for example) you don't want to provide 
+                    your users with this ability.
+                "
+            }
+        }
+
     }
 }
 
--- a/packages/redboot/current/src/fs/fileio.c
+++ b/packages/redboot/current/src/fs/fileio.c
@@ -233,7 +233,12 @@ do_mount(int argc, char *argv[])
 
     if (err)
     {
-        err_printf("fs mount: mount(%s,%s,%s) failed %d\n", dev_str, mp_str, type_str, errno);
+        const char *msg = "";
+        switch(errno) {
+            case ENOENT: msg="(No such entity)"; break;
+            case ENODEV: msg="(No such device)"; break;
+        }
+        err_printf("fs mount: mount(%s,%s,%s) failed %d %s\n", dev_str, mp_str, type_str, errno, msg);
         mounts[m].mp_str[0] = '\0'; // mount failed so don't let it appear mounted
     }
     else
--- a/packages/redboot/current/src/main.c
+++ b/packages/redboot/current/src/main.c
@@ -53,6 +53,7 @@
 
 #define  DEFINE_VARS
 #include <redboot.h>
+#include <stdlib.h>
 #include <cyg/hal/hal_arch.h>
 #include <cyg/hal/hal_intr.h>
 #include <cyg/hal/hal_if.h>
@@ -76,6 +77,11 @@
 extern void breakpoint(void);
 #endif
 
+#if defined(CYGMEM_REDBOOT_WORKSPACE_HEAP)
+# include <stdlib.h>
+static unsigned char* heap_base;
+#endif
+
 // Builtin Self Test (BIST)
 externC void bist(void);
 
@@ -170,6 +176,9 @@ do_version(int argc, char *argv[])
 #ifdef CYGPKG_REDBOOT_FLASH
     externC void _flash_info(void);
 #endif
+#ifdef CYGPKG_REDBOOT_NAND
+    externC void _nand_info(void);
+#endif
     char *version = CYGACC_CALL_IF_MONITOR_VERSION();
 
     diag_printf(version);
@@ -196,9 +205,16 @@ do_version(int argc, char *argv[])
         }
     }
 #endif
+#ifdef CYGMEM_REDBOOT_WORKSPACE_HEAP
+    struct mallinfo mi = mallinfo();
+    diag_printf("  Arena: base 0x%x, size 0x%x, %u%% free, maxfree 0x%x\n", heap_base, mi.arena, (unsigned)(100 * ((double)mi.fordblks / mi.arena)), mi.maxfree);
+#endif
 #ifdef CYGPKG_REDBOOT_FLASH
     _flash_info();
 #endif
+#ifdef CYGPKG_REDBOOT_NAND
+    _nand_info();
+#endif
 }
 
 //
@@ -306,6 +322,7 @@ cyg_start(void)
         extern cyg_bool cyg_memalloc_heap_reinit( cyg_uint8 *base, cyg_uint32 size );
 
         workspace_end -= CYGMEM_REDBOOT_WORKSPACE_HEAP_SIZE;
+        heap_base = workspace_end;
 
         if( !cyg_memalloc_heap_reinit( (cyg_uint8 *)workspace_end, CYGMEM_REDBOOT_WORKSPACE_HEAP_SIZE ) )
             diag_printf("Heap reinitialization failed\n");
new file mode 100644
--- /dev/null
+++ b/packages/redboot/current/src/nand.c
@@ -0,0 +1,306 @@
+//==========================================================================
+//
+//      nand.c
+//
+//      RedBoot - NAND library support
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 2009 eCosCentric Limited.
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    wry
+// Date:         2009-05-29
+// Purpose:      
+// Description:  
+//              
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <pkgconf/system.h>
+#ifdef CYGPKG_IO_FILEIO
+# include <cyg/fileio/fileio.h>
+#endif
+#include <cyg/nand/nand.h>
+#include <cyg/nand/nand_device.h>
+#include <cyg/nand/util.h>
+
+CYG_HAL_TABLE_BEGIN( __NAND_cmds_TAB__, NAND_cmds);
+CYG_HAL_TABLE_END( __NAND_cmds_TAB_END__, NAND_cmds);
+
+extern struct cmd __NAND_cmds_TAB__[], __NAND_cmds_TAB_END__;
+
+//==========================================================================
+
+static void
+nand_usage(char *why)
+{
+    diag_printf("*** invalid 'nand' command: %s\n", why);
+    cmd_usage(__NAND_cmds_TAB__, &__NAND_cmds_TAB_END__, "nand ");
+}
+
+static void
+do_nand(int argc, char *argv[])
+{
+    struct cmd *cmd;
+
+    if (argc < 2) {
+        nand_usage("too few arguments");
+        return;
+    }
+    if ((cmd = cmd_search(__NAND_cmds_TAB__, &__NAND_cmds_TAB_END__, 
+                          argv[1])) != (struct cmd *)0) {
+        (cmd->fun)(argc-1, argv+1);
+        return;
+    }
+    nand_usage("unrecognized command");
+}
+
+RedBoot_nested_cmd("nand", "Manage NAND arrays", "{cmds}", do_nand, 
+        __NAND_cmds_TAB__, &__NAND_cmds_TAB_END__);
+
+//==========================================================================
+// nand list - enumerates the available devices
+
+static void nand_list_guts(const char *banner, const char *eachdev,
+        const char *donefound, const char *donenone)
+{
+    cyg_bool found=false;
+    cyg_nand_device *nand;
+    for (nand = &cyg_nanddevtab[0]; nand != &cyg_nanddevtab_end; nand++) {
+        if (!found) {
+            diag_printf(banner);
+            found=true;
+        }
+        diag_printf(eachdev, nand->devname);
+    }
+    if (found) {
+        if (donefound)
+            diag_printf(donefound);
+    } else {
+        if (donenone)
+            diag_printf(donenone);
+    }
+}
+
+static void nand_list(int argc, char*argv[])
+{
+    nand_list_guts("NAND devices available:\n", "\t%s\n", 
+            0, "No NAND devices available.\n");
+}
+
+// Startup banner is suspiciously similar..
+void _nand_info(void)
+{
+    nand_list_guts("NAND:", " %s", "\n", 0);
+    // We could do more here, maybe interrogate each device like nand_info,
+    // but we'd have to be certain that calling each device's devinit
+    // wouldn't risk an unrecoverable crash in case of trouble.
+}
+
+local_cmd_entry("list", "Lists available NAND devices", "", nand_list, NAND_cmds);
+
+//==========================================================================
+// nand info DEVICE - list chip info, partitions & sizes
+
+static void pretty_print(unsigned log) {
+    char si = ' ';
+    if (log>30) {
+        si='G'; log -= 30;
+    } else if (log>20) {
+        si='M'; log -= 20;
+    } else if (log>10) {
+        si='k'; log -= 10;
+    }
+    diag_printf("%u %cB", 1<<log, si);
+}
+
+static void do_info(cyg_nand_device *nand)
+{
+    // Dev must be initialised.
+    diag_printf("NAND device `%s':\n"
+                "  %u bytes/page, %u pages/block, "
+                "capacity %u blocks x ",
+                nand->devname,
+                1 << nand->page_bits,
+                1 << nand->block_page_bits,
+                1 << nand->blockcount_bits);
+    pretty_print(nand->page_bits + nand->block_page_bits);
+    diag_printf(" = ");
+    pretty_print(nand->chipsize_log);
+    diag_printf("\n");
+
+    cyg_bool found = false;
+    int p;
+    for (p=0; p < CYGNUM_NAND_MAX_PARTITIONS; p++) {
+        if (nand->partition[p].dev) {
+            if (!found) {
+                found=true;
+                diag_printf("  Partition Start Blocks\n");
+            }
+            diag_printf("  %6u    %4u  %5u\n",
+                    p,
+                    nand->partition[p].first,
+                    1 + nand->partition[p].last - nand->partition[p].first);
+        }
+    }
+    if (!found)
+        diag_printf("  (No partitions defined.)\n");
+}
+
+static void nand_info(int argc, char*argv[])
+{
+    cyg_nand_device *nand;
+
+    int arg = 1;
+    while (arg < argc) {
+        const char *dev = argv[arg];
+        if (0==cyg_nand_lookup(dev, &nand))
+            do_info(nand);
+        else
+            diag_printf("No such NAND device `%s'\n", dev);
+        ++arg;
+    }
+
+    // However, if they've not provided an arg ...
+    if (argc == 1) {
+        for (nand = &cyg_nanddevtab[0]; nand != &cyg_nanddevtab_end; nand++) {
+            cyg_nand_lookup(nand->devname,0);
+            do_info(nand);
+        }
+    }
+}
+
+local_cmd_entry("info", "Displays information about one or more NAND devices", "[<device>] [<device>...]", nand_info, NAND_cmds);
+
+//==========================================================================
+// nand erase - erases a nand partition. (Who'd have thunk?)
+
+#ifdef CYGSEM_REDBOOT_NAND_ERASE_CMD
+
+#ifdef CYGPKG_IO_FILEIO
+__externC cyg_mtab_entry cyg_mtab[];
+__externC cyg_mtab_entry cyg_mtab_end;
+
+static cyg_mtab_entry * find_mounted_nand(const char *dev)
+{
+    cyg_mtab_entry *m;
+    for( m = &cyg_mtab[0]; m != &cyg_mtab_end; m++ ) {
+        if( m->name == NULL || !m->valid ) continue;
+        if (0==strcmp(m->devname, dev)) {
+            return m;
+        }
+    }
+    return NULL;
+}
+#endif
+
+static void nand_erase(int argc, char*argv[])
+{
+    char *part_str=0;
+    int rv;
+
+    if (!scan_opts(argc, argv, 1, NULL, 0, &part_str, OPTION_ARG_TYPE_STR, "NAND partition, e.g. mynand/0"))
+        return;
+
+    if (!part_str) {
+        err_printf("nand erase: partition required\n");
+        return;
+    }
+
+    cyg_nand_device *nand=0;
+    cyg_nand_partition *part=0;
+    cyg_nand_resolve_device(part_str, &nand, &part);
+    if (!nand) {
+        err_printf("nand erase: device not found\n");
+        return;
+    }
+    if (!part) {
+        err_printf("nand erase: partition not found\n");
+        return;
+    }
+
+#ifdef CYGPKG_IO_FILEIO
+    cyg_mtab_entry *mte = find_mounted_nand(part_str);
+    if (mte) {
+        err_printf("nand erase: device %s is mounted on %s, must unmount first\n", part_str, mte->name);
+        return;
+    }
+#endif
+
+    diag_printf("Erasing device %s blocks %u to %u...\n", nand->devname, part->first, part->last);
+    cyg_nand_block_addr blk;
+    // Compute a modulus to print out about 72 x `.' as we go by
+    int progmod = (part->last - part->first + 1) / 73 + 1;
+
+    for (blk = part->first; blk <= part->last; blk++) {
+        int st = cyg_nand_bbt_query(part, blk);
+        if (st<0) {
+            diag_printf("Block %d BBTI error %d\n", blk, -st);
+        }
+        const char *msg = 0;
+        switch(st) {
+            case CYG_NAND_BBT_OK:
+                rv = cyg_nand_erase_block(part, blk);
+                if (rv != 0)
+                    diag_printf("Block %d: error %d\n", blk, -rv);
+                break;
+            case CYG_NAND_BBT_WORNBAD:
+                msg="worn bad"; break;
+            case CYG_NAND_BBT_FACTORY_BAD:
+                msg="factory bad"; break;
+
+            case CYG_NAND_BBT_RESERVED:
+                // Skip quietly
+                break;
+        }
+        if (msg)
+            diag_printf("Skipping block %d (%s)\n", blk, msg);
+
+        if (0==(blk % progmod))
+            diag_printf(".");
+    }
+    diag_printf("\nErase complete.\n");
+}
+
+local_cmd_entry("erase", "Erases a NAND partition", "<partition> (e.g. mynand/0)", nand_erase, NAND_cmds);
+
+#endif // CYGSEM_REDBOOT_NAND_ERASE_CMD
+
+//==========================================================================
+
+// end nand.c