Mercurial > nand-ecoscentric
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
