- reworked file i/o. every fileaccess (target, flash, nand, in future configuration...
authordrath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Thu, 15 Mar 2007 13:36:44 +0000 (13:36 +0000)
committerdrath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Thu, 15 Mar 2007 13:36:44 +0000 (13:36 +0000)
- added support for reading IHEX files (through fileio)
- load/dump_binary renamed to the more generic load/dump_image <file> <address> ['bin'|'ihex']
- added NAND framework (preliminary)
- added support for the LPC3180 SLC and MLC NAND controllers (preliminary)
- fix initialization for parport
- gw16012 fixes/cleanups
- added EmbeddedICE version 7 (preliminary, reported on two LPC23xx devices so far)
- added 'arm7_9 etm <target#>' configuration command to enable access to the ETM registers

git-svn-id: svn://svn.berlios.de/openocd/trunk@132 b42882b7-edfa-0310-969c-e2dbd0fdcd60

20 files changed:
src/flash/Makefile.am
src/flash/flash.c
src/flash/lpc3180_nand_controller.c [new file with mode: 0644]
src/flash/lpc3180_nand_controller.h [new file with mode: 0644]
src/flash/nand.c [new file with mode: 0644]
src/flash/nand.h [new file with mode: 0644]
src/helper/Makefile.am
src/helper/time_support.c
src/helper/time_support.h
src/helper/types.h
src/jtag/gw16012.c
src/jtag/jtag.c
src/jtag/jtag.h
src/jtag/parport.c
src/openocd.c
src/target/arm7_9_common.c
src/target/arm7tdmi.c
src/target/arm9tdmi.c
src/target/embeddedice.c
src/target/target.c

index 65692e3a2e620b51ec9baca7b3140ebae84cb7eb..6368f626ea2f91f5b0d79ed63698bbc5400f5d9f 100644 (file)
@@ -1,5 +1,5 @@
 INCLUDES = -I$(top_srcdir)/src/helper -I$(top_srcdir)/src/jtag -I$(top_srcdir)/src/target $(all_includes)
 METASOURCES = AUTO
 noinst_LIBRARIES = libflash.a
-libflash_a_SOURCES = flash.c lpc2000.c cfi.c at91sam7.c str7x.c str9x.c
-noinst_HEADERS = flash.h lpc2000.h cfi.h at91sam7.h str7x.h str9x.h
+libflash_a_SOURCES = flash.c lpc2000.c cfi.c at91sam7.c str7x.c str9x.c nand.c lpc3180_nand_controller.c
+noinst_HEADERS = flash.h lpc2000.h cfi.h at91sam7.h str7x.h str9x.h nand.h lpc3180_nand_controller.h
index 0a6796468fb5a741cd96a43af0c284e70e28a8e2..f5c83f80c43ffdc43cdd8e6cd60758f1af0a63ab 100644 (file)
@@ -34,6 +34,8 @@
 #include <sys/stat.h>
 #include <errno.h>
 
+#include <fileio.h>
+
 /* command handlers */
 int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 int handle_flash_banks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
@@ -486,24 +488,31 @@ int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, c
 
 int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
-       FILE *binary;
        u32 offset;
-       struct stat binary_stat;
        u32 binary_size;
        u8 *buffer;
        u32 buf_cnt;
+
+       fileio_t file;
+       fileio_image_t image_info;
+       enum fileio_sec_type sec_type;
+       
+       duration_t duration;
+       char *duration_text;
+       
        int retval;
        flash_bank_t *p;
-       struct timeval start, end, duration;
 
-       gettimeofday(&start, NULL);
-               
        if (argc < 3)
        {
-               command_print(cmd_ctx, "usage: flash write <bank> <file> <offset>");
+               command_print(cmd_ctx, "usage: flash write <bank> <file> <offset> [type]");
                return ERROR_OK;
        }
        
+       duration_start_measure(&duration);
+       
+       fileio_identify_image_type(&sec_type, (argc == 4) ? args[3] : NULL);
+       
        offset = strtoul(args[2], NULL, 0);
        p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
        if (!p)
@@ -512,36 +521,21 @@ int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, cha
                return ERROR_OK;
        }
        
-       if (stat(args[1], &binary_stat) == -1)
-       {
-               ERROR("couldn't stat() %s: %s", args[1], strerror(errno));
-               return ERROR_OK;
-       }
+       image_info.base_address = strtoul(args[2], NULL, 0);
+       image_info.has_start_address = 0;
 
-       if (S_ISDIR(binary_stat.st_mode))
+       if (fileio_open(&file, args[1], FILEIO_READ, 
+               FILEIO_IMAGE, &image_info, sec_type) != ERROR_OK)
        {
-               ERROR("%s is a directory", args[1]);
-               command_print(cmd_ctx,"%s is a directory", args[1]);
+               command_print(cmd_ctx, "flash write error: %s", file.error_str);
                return ERROR_OK;
        }
-               
-       if (binary_stat.st_size == 0){
-               ERROR("Empty file %s", args[1]);
-               command_print(cmd_ctx,"Empty file %s", args[1]);
-               return ERROR_OK;
-       }
-               
-       if (!(binary = fopen(args[1], "rb")))
-       {
-               ERROR("couldn't open %s: %s", args[1], strerror(errno));
-               command_print(cmd_ctx, "couldn't open %s", args[1]);
-               return ERROR_OK;
-       }
-
-       binary_size = binary_stat.st_size;
+       
+       binary_size = file.size;
        buffer = malloc(binary_size);
-       buf_cnt = fread(buffer, 1, binary_size, binary);
 
+       fileio_read(&file, binary_size, buffer, &buf_cnt);
+       
        if ((retval = p->driver->write(p, buffer, offset, buf_cnt)) != ERROR_OK)
        {
                command_print(cmd_ctx, "failed writing file %s to flash bank %i at offset 0x%8.8x",
@@ -575,14 +569,14 @@ int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, cha
        }
        else
        {
-               gettimeofday(&end, NULL);       
-               timeval_subtract(&duration, &end, &start);
-               
-               command_print(cmd_ctx, "wrote file %s to flash bank %i at offset 0x%8.8x in %is %ius", args[1], strtoul(args[0], NULL, 0), strtoul(args[2], NULL, 0), duration.tv_sec, duration.tv_usec);
+               duration_stop_measure(&duration, &duration_text);
+               command_print(cmd_ctx, "wrote file %s to flash bank %i at offset 0x%8.8x in %s",
+                       file.url, strtoul(args[0], NULL, 0), offset, duration_text);
+               free(duration_text);
        }
        
        free(buffer);
-       fclose(binary);
+       fileio_close(&file);
        
        return ERROR_OK;
 }
diff --git a/src/flash/lpc3180_nand_controller.c b/src/flash/lpc3180_nand_controller.c
new file mode 100644 (file)
index 0000000..aae5cbb
--- /dev/null
@@ -0,0 +1,916 @@
+/***************************************************************************
+ *   Copyright (C) 2007 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   This program 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 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program 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 this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "lpc3180_nand_controller.h"
+
+#include "replacements.h"
+#include "log.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "nand.h"
+#include "target.h"
+
+int lpc3180_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
+int lpc3180_register_commands(struct command_context_s *cmd_ctx);
+int lpc3180_init(struct nand_device_s *device);
+int lpc3180_reset(struct nand_device_s *device);
+int lpc3180_command(struct nand_device_s *device, u8 command);
+int lpc3180_address(struct nand_device_s *device, u8 address);
+int lpc3180_write_data(struct nand_device_s *device, u16 data);
+int lpc3180_read_data(struct nand_device_s *device, void *data);
+int lpc3180_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
+int lpc3180_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
+int lpc3180_controller_ready(struct nand_device_s *device, int timeout);
+int lpc3180_nand_ready(struct nand_device_s *device, int timeout);
+
+int handle_lpc3180_select_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+nand_flash_controller_t lpc3180_nand_controller =
+{
+       .name = "lpc3180",
+       .nand_device_command = lpc3180_nand_device_command,
+       .register_commands = lpc3180_register_commands,
+       .init = lpc3180_init,
+       .reset = lpc3180_reset,
+       .command = lpc3180_command,
+       .address = lpc3180_address,
+       .write_data = lpc3180_write_data,
+       .read_data = lpc3180_read_data,
+       .write_page = lpc3180_write_page,
+       .read_page = lpc3180_read_page,
+       .controller_ready = lpc3180_controller_ready,
+       .nand_ready = lpc3180_nand_ready,
+};
+
+/* nand device lpc3180 <target#> <oscillator_frequency>
+ */
+int lpc3180_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device)
+{
+       lpc3180_nand_controller_t *lpc3180_info;
+               
+       if (argc < 3)
+       {
+               WARNING("incomplete 'lpc3180' nand flash configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+       
+       lpc3180_info = malloc(sizeof(lpc3180_nand_controller_t));
+       device->controller_priv = lpc3180_info;
+
+       lpc3180_info->target = get_target_by_num(strtoul(args[1], NULL, 0));
+       if (!lpc3180_info->target)
+       {
+               ERROR("no target '%s' configured", args[1]);
+               return ERROR_NAND_DEVICE_INVALID;
+       }
+
+       lpc3180_info->osc_freq = strtoul(args[2], NULL, 0);
+       if ((lpc3180_info->osc_freq < 1000) || (lpc3180_info->osc_freq > 20000))
+       {
+               WARNING("LPC3180 oscillator frequency should be between 1000 and 20000 kHz, was %i", lpc3180_info->osc_freq); 
+       }
+       lpc3180_info->selected_controller = LPC3180_NO_CONTROLLER;
+       lpc3180_info->sw_write_protection = 0;
+       lpc3180_info->sw_wp_lower_bound = 0x0;
+       lpc3180_info->sw_wp_upper_bound = 0x0;
+               
+       return ERROR_OK;
+}
+
+int lpc3180_register_commands(struct command_context_s *cmd_ctx)
+{
+       command_t *lpc3180_cmd = register_command(cmd_ctx, NULL, "lpc3180", NULL, COMMAND_ANY, "commands specific to the LPC3180 NAND flash controllers");
+       
+       register_command(cmd_ctx, lpc3180_cmd, "select", handle_lpc3180_select_command, COMMAND_EXEC, "select <'mlc'|'slc'> controller (default is mlc)");
+       
+       return ERROR_OK;
+}
+
+int lpc3180_pll(int fclkin, u32 pll_ctrl)
+{
+       int bypass = (pll_ctrl & 0x8000) >> 15;
+       int direct = (pll_ctrl & 0x4000) >> 14;
+       int feedback = (pll_ctrl & 0x2000) >> 13;
+       int p = (1 << ((pll_ctrl & 0x1800) >> 11) * 2);
+       int n = ((pll_ctrl & 0x0600) >> 9) + 1;
+       int m = ((pll_ctrl & 0x01fe) >> 1) + 1;
+       int lock = (pll_ctrl & 0x1);
+
+       if (!lock)
+               WARNING("PLL is not locked");
+       
+       if (!bypass && direct)  /* direct mode */
+               return (m * fclkin) / n;
+       
+       if (bypass && !direct)  /* bypass mode */
+               return fclkin / (2 * p);
+               
+       if (bypass & direct)    /* direct bypass mode */
+               return fclkin;
+       
+       if (feedback)                   /* integer mode */
+               return m * (fclkin / n);
+       else                                    /* non-integer mode */
+               return (m / (2 * p)) * (fclkin / n); 
+}
+
+float lpc3180_cycle_time(lpc3180_nand_controller_t *lpc3180_info)
+{
+       target_t *target = lpc3180_info->target;
+       u32 sysclk_ctrl, pwr_ctrl, hclkdiv_ctrl, hclkpll_ctrl;
+       int sysclk;
+       int hclk;
+       int hclk_pll;
+       float cycle;
+       
+       /* calculate timings */
+       
+       /* determine current SYSCLK (13'MHz or main oscillator) */ 
+       target_read_u32(target, 0x40004050, &sysclk_ctrl);
+       
+       if (sysclk_ctrl & 1)
+               sysclk = lpc3180_info->osc_freq;
+       else
+               sysclk = 13000;
+       
+       /* determine selected HCLK source */
+       target_read_u32(target, 0x40004044, &pwr_ctrl);
+       
+       if ((pwr_ctrl & (1 << 2)) == 0) /* DIRECT RUN mode */
+       {
+               hclk = sysclk;
+       }
+       else
+       {
+               target_read_u32(target, 0x40004058, &hclkpll_ctrl);
+               hclk_pll = lpc3180_pll(sysclk, hclkpll_ctrl);
+
+               target_read_u32(target, 0x40004040, &hclkdiv_ctrl);
+               
+               if (pwr_ctrl & (1 << 10)) /* ARM_CLK and HCLK use PERIPH_CLK */
+               {
+                       hclk = hclk_pll / (((hclkdiv_ctrl & 0x7c) >> 2) + 1);
+               }
+               else /* HCLK uses HCLK_PLL */
+               {
+                       hclk = hclk_pll / (1 << (hclkdiv_ctrl & 0x3)); 
+               }
+       }
+       
+       DEBUG("LPC3180 HCLK currently clocked at %i kHz", hclk);
+       
+       cycle = (1.0 / hclk) * 1000000.0;
+       
+       return cycle;
+}
+
+int lpc3180_init(struct nand_device_s *device)
+{
+       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
+       target_t *target = lpc3180_info->target;
+       int bus_width = (device->bus_width) ? (device->bus_width) : 8;
+       int address_cycles = (device->address_cycles) ? (device->address_cycles) : 3;
+       int page_size = (device->page_size) ? (device->page_size) : 512;
+               
+       if (target->state != TARGET_HALTED)
+       {
+               ERROR("target must be halted to use LPC3180 NAND flash controller");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       
+       /* sanitize arguments */
+       if ((bus_width != 8) && (bus_width != 16))
+       {
+               ERROR("LPC3180 only supports 8 or 16 bit bus width, not %i", bus_width);
+               return ERROR_NAND_OPERATION_NOT_SUPPORTED;
+       }
+       
+       /* The LPC3180 only brings out 8 bit NAND data bus, but the controller
+        * would support 16 bit, too, so we just warn about this for now
+        */
+       if (bus_width == 16)
+       {
+               WARNING("LPC3180 only supports 8 bit bus width");
+       }
+       
+       /* inform calling code about selected bus width */
+       device->bus_width = bus_width;
+       
+       if ((address_cycles != 3) && (address_cycles != 4))
+       {
+               ERROR("LPC3180 only supports 3 or 4 address cycles, not %i", address_cycles);
+               return ERROR_NAND_OPERATION_NOT_SUPPORTED;
+       }
+       
+       if ((page_size != 512) && (page_size != 2048))
+       {
+               ERROR("LPC3180 only supports 512 or 2048 byte pages, not %i", page_size);
+               return ERROR_NAND_OPERATION_NOT_SUPPORTED;
+       }
+       
+       /* select MLC controller if none is currently selected */
+       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
+       {
+               DEBUG("no LPC3180 NAND flash controller selected, using default 'mlc'");
+               lpc3180_info->selected_controller = LPC3180_MLC_CONTROLLER;
+       }
+       
+       if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
+       {
+               u32 mlc_icr_value = 0x0;
+               float cycle;
+               int twp, twh, trp, treh, trhz, trbwb, tcea;
+               
+               /* FLASHCLK_CTRL = 0x22 (enable clock for MLC flash controller) */
+               target_write_u32(target, 0x400040c8, 0x22);
+               
+               /* MLC_CEH = 0x0 (Force nCE assert) */
+               target_write_u32(target, 0x200b804c, 0x0);
+               
+               /* MLC_LOCK = 0xa25e (unlock protected registers) */
+               target_write_u32(target, 0x200b8044, 0xa25e);
+               
+               /* MLC_ICR = configuration */
+               if (lpc3180_info->sw_write_protection)
+                       mlc_icr_value |= 0x8;
+               if (page_size == 2048)
+                       mlc_icr_value |= 0x4;
+               if (address_cycles == 4)
+                       mlc_icr_value |= 0x2;
+               if (bus_width == 16)
+                       mlc_icr_value |= 0x1;
+               target_write_u32(target, 0x200b8030, mlc_icr_value);
+               
+               /* calculate NAND controller timings */
+               cycle = lpc3180_cycle_time(lpc3180_info);
+               
+               twp = ((40 / cycle) + 1);
+               twh = ((20 / cycle) + 1);
+               trp = ((30 / cycle) + 1);
+               treh = ((15 / cycle) + 1);
+               trhz = ((30 / cycle) + 1);
+               trbwb = ((100 / cycle) + 1);
+               tcea = ((45 / cycle) + 1);
+                               
+               /* MLC_LOCK = 0xa25e (unlock protected registers) */
+               target_write_u32(target, 0x200b8044, 0xa25e);
+       
+               /* MLC_TIME_REG */
+               target_write_u32(target, 0x200b8034, (twp & 0xf) | ((twh & 0xf) << 4) | 
+                       ((trp & 0xf) << 8) | ((treh & 0xf) << 12) | ((trhz & 0x7) << 16) | 
+                       ((trbwb & 0x1f) << 19) | ((tcea & 0x3) << 24)); 
+
+               lpc3180_reset(device);
+       }
+       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
+       {
+               float cycle;
+               int r_setup, r_hold, r_width, r_rdy;
+               int w_setup, w_hold, w_width, w_rdy;
+               
+               /* FLASHCLK_CTRL = 0x05 (enable clock for SLC flash controller) */
+               target_write_u32(target, 0x400040c8, 0x05);
+               
+               /* SLC_CFG = 0x (Force nCE assert, ECC enabled, WIDTH = bus_width) */
+               target_write_u32(target, 0x20020014, 0x28 | (bus_width == 16) ? 1 : 0);
+               
+               /* calculate NAND controller timings */
+               cycle = lpc3180_cycle_time(lpc3180_info);
+               
+               r_setup = w_setup = 0;
+               r_hold = w_hold = 10 / cycle;
+               r_width = 30 / cycle;
+               w_width = 40 / cycle;
+               r_rdy = w_rdy = 100 / cycle;
+               
+               /* SLC_TAC: SLC timing arcs register */
+               target_write_u32(target, 0x2002002c, (r_setup & 0xf) | ((r_hold & 0xf) << 4) |
+                       ((r_width & 0xf) << 8) | ((r_rdy & 0xf) << 12) |  ((w_setup & 0xf) << 16) |
+                       ((w_hold & 0xf) << 20) | ((w_width & 0xf) << 24) | ((w_rdy & 0xf) << 28)); 
+               
+               lpc3180_reset(device);
+       }
+       
+       return ERROR_OK;
+}
+
+int lpc3180_reset(struct nand_device_s *device)
+{
+       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
+       target_t *target = lpc3180_info->target;
+       
+       if (target->state != TARGET_HALTED)
+       {
+               ERROR("target must be halted to use LPC3180 NAND flash controller");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       
+       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
+       {
+               ERROR("BUG: no LPC3180 NAND flash controller selected");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
+       {
+               /* MLC_CMD = 0xff (reset controller and NAND device) */
+               target_write_u32(target, 0x200b8000, 0xff);
+
+               if (!lpc3180_controller_ready(device, 100))
+               {
+                       ERROR("LPC3180 NAND controller timed out after reset");
+                       return ERROR_NAND_OPERATION_TIMEOUT;
+               }
+       }
+       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
+       {
+               /* SLC_CTRL = 0x6 (ECC_CLEAR, SW_RESET) */
+               target_write_u32(target, 0x20020010, 0x6);
+               
+               if (!lpc3180_controller_ready(device, 100))
+               {
+                       ERROR("LPC3180 NAND controller timed out after reset");
+                       return ERROR_NAND_OPERATION_TIMEOUT;
+               }
+       }
+       
+       return ERROR_OK;
+}
+
+int lpc3180_command(struct nand_device_s *device, u8 command)
+{
+       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
+       target_t *target = lpc3180_info->target;
+       
+       if (target->state != TARGET_HALTED)
+       {
+               ERROR("target must be halted to use LPC3180 NAND flash controller");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       
+       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
+       {
+               ERROR("BUG: no LPC3180 NAND flash controller selected");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
+       {
+               /* MLC_CMD = command */
+               target_write_u32(target, 0x200b8000, command);
+       }
+       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
+       {
+               /* SLC_CMD = command */
+               target_write_u32(target, 0x20020008, command);
+       }       
+       
+       return ERROR_OK;
+}
+
+int lpc3180_address(struct nand_device_s *device, u8 address)
+{
+       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
+       target_t *target = lpc3180_info->target;
+       
+       if (target->state != TARGET_HALTED)
+       {
+               ERROR("target must be halted to use LPC3180 NAND flash controller");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       
+       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
+       {
+               ERROR("BUG: no LPC3180 NAND flash controller selected");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
+       {
+               /* MLC_ADDR = address */
+               target_write_u32(target, 0x200b8004, address);
+       }
+       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
+       {
+               /* SLC_ADDR = address */
+               target_write_u32(target, 0x20020004, address);
+       }
+               
+       return ERROR_OK;
+}
+
+int lpc3180_write_data(struct nand_device_s *device, u16 data)
+{
+       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
+       target_t *target = lpc3180_info->target;
+       
+       if (target->state != TARGET_HALTED)
+       {
+               ERROR("target must be halted to use LPC3180 NAND flash controller");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       
+       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
+       {
+               ERROR("BUG: no LPC3180 NAND flash controller selected");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
+       {
+               /* MLC_DATA = data */
+               target_write_u32(target, 0x200b0000, data);
+       }
+       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
+       {
+               /* SLC_DATA = data */
+               target_write_u32(target, 0x20020000, data);
+       }
+       
+       return ERROR_OK;
+}
+
+int lpc3180_read_data(struct nand_device_s *device, void *data)
+{
+       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
+       target_t *target = lpc3180_info->target;
+       
+       if (target->state != TARGET_HALTED)
+       {
+               ERROR("target must be halted to use LPC3180 NAND flash controller");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       
+       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
+       {
+               ERROR("BUG: no LPC3180 NAND flash controller selected");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
+       {
+               /* data = MLC_DATA, use sized access */
+               if (device->bus_width == 8)
+               {
+                       u8 *data8 = data;
+                       target_read_u8(target, 0x200b0000, data8);
+               }
+               else if (device->bus_width == 16)
+               {
+                       u16 *data16 = data;
+                       target_read_u16(target, 0x200b0000, data16);
+               }
+               else
+               {
+                       ERROR("BUG: bus_width neither 8 nor 16 bit");
+                       return ERROR_NAND_OPERATION_FAILED;
+               }
+       }
+       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
+       {
+               u32 data32;
+
+               /* data = SLC_DATA, must use 32-bit access */
+               target_read_u32(target, 0x20020000, &data32);
+               
+               if (device->bus_width == 8)
+               {
+                       u8 *data8 = data;
+                       *data8 = data32 & 0xff;
+               }
+               else if (device->bus_width == 16)
+               {
+                       u16 *data16 = data;
+                       *data16 = data32 & 0xffff;
+               }
+               else
+               {
+                       ERROR("BUG: bus_width neither 8 nor 16 bit");
+                       return ERROR_NAND_OPERATION_FAILED;
+               }
+       }       
+       
+       return ERROR_OK;
+}
+
+int lpc3180_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)
+{
+       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
+       target_t *target = lpc3180_info->target;
+       int retval;
+       u8 status;
+       
+       if (target->state != TARGET_HALTED)
+       {
+               ERROR("target must be halted to use LPC3180 NAND flash controller");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       
+       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
+       {
+               ERROR("BUG: no LPC3180 NAND flash controller selected");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
+       {
+               u8 *page_buffer;
+               u8 *oob_buffer;
+               int quarter, num_quarters;
+               
+               if (!data && oob)
+               {
+                       ERROR("LPC3180 MLC controller can't write OOB data only");
+                       return ERROR_NAND_OPERATION_NOT_SUPPORTED;
+               }
+               
+               if (oob && (oob_size > 6))
+               {
+                       ERROR("LPC3180 MLC controller can't write more than 6 bytes of OOB data");
+                       return ERROR_NAND_OPERATION_NOT_SUPPORTED;
+               }
+               
+               if (data_size > device->page_size)
+               {
+                       ERROR("data size exceeds page size");
+                       return ERROR_NAND_OPERATION_NOT_SUPPORTED;
+               }
+               
+               /* MLC_CMD = sequential input */
+               target_write_u32(target, 0x200b8000, NAND_CMD_SEQIN);
+
+               page_buffer = malloc(512);
+               oob_buffer = malloc(6);         
+
+               if (device->page_size == 512)
+               {
+                       /* MLC_ADDR = 0x0 (one column cycle) */
+                       target_write_u32(target, 0x200b8004, 0x0);
+
+                       /* MLC_ADDR = row */
+                       target_write_u32(target, 0x200b8004, page & 0xff);
+                       target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);
+                       
+                       if (device->address_cycles == 4)
+                               target_write_u32(target, 0x200b8004, (page >> 16) & 0xff);
+               }
+               else
+               {
+                       /* MLC_ADDR = 0x0 (two column cycles) */
+                       target_write_u32(target, 0x200b8004, 0x0);
+                       target_write_u32(target, 0x200b8004, 0x0);
+
+                       /* MLC_ADDR = row */
+                       target_write_u32(target, 0x200b8004, page & 0xff);
+                       target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);
+               }
+               
+               /* when using the MLC controller, we have to treat a large page device
+                * as being made out of four quarters, each the size of a small page device
+                */
+               num_quarters = (device->page_size == 2048) ? 4 : 1;
+                
+               for (quarter = 0; quarter < num_quarters; quarter++)
+               {
+                       int thisrun_data_size = (data_size > 512) ? 512 : data_size;
+                       int thisrun_oob_size = (oob_size > 6) ? 6 : oob_size;
+                       
+                       memset(page_buffer, 0xff, 512);
+                       if (data)
+                       {
+                               memcpy(page_buffer, data, thisrun_data_size);
+                               data_size -= thisrun_data_size;
+                               data += thisrun_data_size;
+                       }
+                       
+                       memset(oob_buffer, 0xff, (device->page_size == 512) ? 6 : 24);
+                       if (oob)
+                       {
+                               memcpy(page_buffer, oob, thisrun_oob_size);
+                               oob_size -= thisrun_oob_size;
+                               oob += thisrun_oob_size;
+                       }
+                       
+                       /* write MLC_ECC_ENC_REG to start encode cycle */
+                       target_write_u32(target, 0x200b8008, 0x0);
+                       
+                       target->type->write_memory(target, 0x200a8000, 4, 128, page_buffer + (quarter * 512));
+                       target->type->write_memory(target, 0x200a8000, 1, 6, oob_buffer + (quarter * 6));
+                       
+                       /* write MLC_ECC_AUTO_ENC_REG to start auto encode */
+                       target_write_u32(target, 0x200b8010, 0x0);
+                       
+                       if (!lpc3180_controller_ready(device, 1000))
+                       {
+                               ERROR("timeout while waiting for completion of auto encode cycle");
+                               return ERROR_NAND_OPERATION_FAILED;
+                       }
+               }
+               
+               /* MLC_CMD = auto program command */
+               target_write_u32(target, 0x200b8000, NAND_CMD_PAGEPROG);
+               
+               if ((retval = nand_read_status(device, &status)) != ERROR_OK)
+               {
+                       ERROR("couldn't read status");
+                       return ERROR_NAND_OPERATION_FAILED;
+               }
+                       
+               if (status & NAND_STATUS_FAIL)
+               {
+                       ERROR("write operation didn't pass, status: 0x%2.2x", status);
+                       return ERROR_NAND_OPERATION_FAILED;
+               }
+       
+               free(page_buffer);
+               free(oob_buffer);
+       }
+       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
+       {
+               return nand_write_page_raw(device, page, data, data_size, oob, oob_size);
+       }
+       
+       return ERROR_OK;
+}
+
+int lpc3180_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)
+{
+       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
+       target_t *target = lpc3180_info->target;
+       
+       if (target->state != TARGET_HALTED)
+       {
+               ERROR("target must be halted to use LPC3180 NAND flash controller");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       
+       if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
+       {
+               ERROR("BUG: no LPC3180 NAND flash controller selected");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
+       {
+               u8 *page_buffer;
+               u8 *oob_buffer;
+               u32 page_bytes_done = 0;
+               u32 oob_bytes_done = 0;
+               u32 mlc_isr;
+
+#if 0
+               if (oob && (oob_size > 6))
+               {
+                       ERROR("LPC3180 MLC controller can't read more than 6 bytes of OOB data");
+                       return ERROR_NAND_OPERATION_NOT_SUPPORTED;
+               }
+#endif
+               
+               if (data_size > device->page_size)
+               {
+                       ERROR("data size exceeds page size");
+                       return ERROR_NAND_OPERATION_NOT_SUPPORTED;
+               }
+               
+               if (device->page_size == 2048)
+               {
+                       page_buffer = malloc(2048);
+                       oob_buffer = malloc(64);
+               }
+               else
+               {
+                       page_buffer = malloc(512);
+                       oob_buffer = malloc(16);
+               }
+               
+               if (!data && oob)
+               {
+                       /* MLC_CMD = Read OOB 
+                        * we can use the READOOB command on both small and large page devices,
+                        * as the controller translates the 0x50 command to a 0x0 with appropriate
+                        * positioning of the serial buffer read pointer
+                        */
+                       target_write_u32(target, 0x200b8000, NAND_CMD_READOOB);
+               }
+               else
+               {
+                       /* MLC_CMD = Read0 */
+                       target_write_u32(target, 0x200b8000, NAND_CMD_READ0);
+               }
+               
+               if (device->page_size == 512)
+               {
+                       /* small page device */
+                       /* MLC_ADDR = 0x0 (one column cycle) */
+                       target_write_u32(target, 0x200b8004, 0x0);
+
+                       /* MLC_ADDR = row */
+                       target_write_u32(target, 0x200b8004, page & 0xff);
+                       target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);
+                       
+                       if (device->address_cycles == 4)
+                               target_write_u32(target, 0x200b8004, (page >> 16) & 0xff);
+               }
+               else
+               {
+                       /* large page device */
+                       /* MLC_ADDR = 0x0 (two column cycles) */
+                       target_write_u32(target, 0x200b8004, 0x0);
+                       target_write_u32(target, 0x200b8004, 0x0);
+
+                       /* MLC_ADDR = row */
+                       target_write_u32(target, 0x200b8004, page & 0xff);
+                       target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);
+                       
+                       /* MLC_CMD = Read Start */
+                       target_write_u32(target, 0x200b8000, NAND_CMD_READSTART);
+               }
+               
+               while (page_bytes_done < device->page_size)
+               {
+                       /* MLC_ECC_AUTO_DEC_REG = dummy */
+                       target_write_u32(target, 0x200b8014, 0xaa55aa55);
+                       
+                       if (!lpc3180_controller_ready(device, 1000))
+                       {
+                               ERROR("timeout while waiting for completion of auto decode cycle");
+                               return ERROR_NAND_OPERATION_FAILED;
+                       }
+               
+                       target_read_u32(target, 0x200b8048, &mlc_isr);
+                       
+                       if (mlc_isr & 0x8)
+                       {
+                               if (mlc_isr & 0x40)
+                               {
+                                       ERROR("uncorrectable error detected: 0x%2.2x", mlc_isr);
+                                       return ERROR_NAND_OPERATION_FAILED;
+                               }
+                               
+                               WARNING("%i symbol error detected and corrected", ((mlc_isr & 0x30) >> 4) + 1);
+                       }
+                       
+                       if (data)
+                       {
+                               target->type->read_memory(target, 0x200a8000, 4, 128, page_buffer + page_bytes_done);
+                       }
+                       
+                       if (oob)
+                       {
+                               target->type->read_memory(target, 0x200a8000, 4, 4, oob_buffer + oob_bytes_done);
+                       }
+
+                       page_bytes_done += 512;
+                       oob_bytes_done += 16;
+               }
+               
+               if (data)
+                       memcpy(data, page_buffer, data_size);
+               
+               if (oob)
+                       memcpy(oob, oob_buffer, oob_size);
+               
+               free(page_buffer);
+               free(oob_buffer);
+       }
+       else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
+       {
+               return nand_read_page_raw(device, page, data, data_size, oob, oob_size);
+       }
+       
+       return ERROR_OK;
+}
+
+int lpc3180_controller_ready(struct nand_device_s *device, int timeout)
+{
+       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
+       target_t *target = lpc3180_info->target;
+       u8 status = 0x0;
+       
+       if (target->state != TARGET_HALTED)
+       {
+               ERROR("target must be halted to use LPC3180 NAND flash controller");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+                       
+       do
+       {
+               if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
+               {
+                       /* Read MLC_ISR, wait for controller to become ready */
+                       target_read_u8(target, 0x200b8048, &status);
+                       
+                       if (status & 2)
+                               return 1;
+               }
+               else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
+               {
+                       /* we pretend that the SLC controller is always ready */
+                       return 1;
+               }
+
+               usleep(1000);
+       } while (timeout-- > 0);
+       
+       return 0;
+}
+
+int lpc3180_nand_ready(struct nand_device_s *device, int timeout)
+{
+       lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
+       target_t *target = lpc3180_info->target;
+       
+       if (target->state != TARGET_HALTED)
+       {
+               ERROR("target must be halted to use LPC3180 NAND flash controller");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+                       
+       do
+       {
+               if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
+               {       
+                       u8 status = 0x0;
+                       
+                       /* Read MLC_ISR, wait for NAND flash device to become ready */
+                       target_read_u8(target, 0x200b8048, &status);
+                       
+                       if (status & 1)
+                               return 1;
+               }
+               else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
+               {
+                       u32 status = 0x0;
+                       
+                       /* Read SLC_STAT and check READY bit */
+                       target_read_u32(target, 0x20020018, &status);
+                       
+                       if (status & 1)
+                               return 1;
+               }
+               
+               usleep(1000);
+       } while (timeout-- > 0);
+       
+       return 0;       
+}
+
+int handle_lpc3180_select_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       nand_device_t *device = NULL;
+       lpc3180_nand_controller_t *lpc3180_info = NULL;
+       char *selected[] = 
+       {
+               "no", "mlc", "slc"
+       };
+       
+       if ((argc < 1) || (argc > 2))
+       {
+               command_print(cmd_ctx, "usage: lpc3180 select <num> <'mlc'|'slc'>");
+               return ERROR_OK;
+       }
+       
+       device = get_nand_device_by_num(strtoul(args[0], NULL, 0));
+       if (!device)
+       {
+               command_print(cmd_ctx, "nand device '#%s' is out of bounds", args[0]);
+               return ERROR_OK;
+       }
+       
+       lpc3180_info = device->controller_priv;
+       
+       if (argc == 2)
+       {
+               if (strcmp(args[1], "mlc") == 0)
+               {
+                       lpc3180_info->selected_controller = LPC3180_MLC_CONTROLLER;
+               }
+               else if (strcmp(args[1], "slc") == 0)
+               {
+                       lpc3180_info->selected_controller = LPC3180_SLC_CONTROLLER;
+               }
+               else
+               {
+                       command_print(cmd_ctx, "usage: lpc3180 select <'mlc'|'slc'>");
+               }
+       }
+       
+       command_print(cmd_ctx, "%s controller selected", selected[lpc3180_info->selected_controller]);
+       
+       return ERROR_OK;
+}
diff --git a/src/flash/lpc3180_nand_controller.h b/src/flash/lpc3180_nand_controller.h
new file mode 100644 (file)
index 0000000..d0f0113
--- /dev/null
@@ -0,0 +1,42 @@
+/***************************************************************************
+ *   Copyright (C) 2007 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   This program 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 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program 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 this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#ifndef LPC3180_NAND_CONTROLLER_H
+#define LPC3180_NAND_CONTROLLER_H
+
+#include "target.h"
+
+enum lpc3180_selected_controller
+{
+       LPC3180_NO_CONTROLLER,
+       LPC3180_MLC_CONTROLLER,
+       LPC3180_SLC_CONTROLLER,
+};
+
+typedef struct lpc3180_nand_controller_s
+{
+       struct target_s *target;
+       int osc_freq;
+       enum lpc3180_selected_controller selected_controller;
+       int sw_write_protection;
+       u32 sw_wp_lower_bound;
+       u32 sw_wp_upper_bound;
+} lpc3180_nand_controller_t;
+
+#endif /*LPC3180_NAND_CONTROLLER_H */
diff --git a/src/flash/nand.c b/src/flash/nand.c
new file mode 100644 (file)
index 0000000..221d2a4
--- /dev/null
@@ -0,0 +1,1482 @@
+/***************************************************************************
+ *   Copyright (C) 2007 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   partially based on                                                    *
+ *      drivers/mtd/nand_ids.c                                                *
+ *                                                                         *
+ *   Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)               *
+ *                                                                         *
+ *   This program 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 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program 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 this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "replacements.h"
+#include "log.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <errno.h>
+
+#include "nand.h"
+#include "flash.h"
+#include "time_support.h"
+#include "fileio.h"
+
+int nand_register_commands(struct command_context_s *cmd_ctx);
+int handle_nand_list_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_nand_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_nand_check_bad_blocks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_nand_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_nand_copy_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_nand_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+int handle_nand_raw_access_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+int nand_read_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
+int nand_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
+int nand_read_plain(struct nand_device_s *device, u32 address, u8 *data, u32 data_size);
+
+int nand_write_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
+int nand_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
+
+/* NAND flash controller
+ */
+extern nand_flash_controller_t lpc3180_nand_controller;
+/* extern nand_flash_controller_t s3c2410_nand_controller; */
+/* extern nand_flash_controller_t boundary_scan_nand_controller; */
+
+nand_flash_controller_t *nand_flash_controllers[] =
+{
+       &lpc3180_nand_controller,
+/*     &s3c2410_nand_controller, */
+/*     &boundary_scan_nand_controller, */
+       NULL
+};
+
+/* configured NAND devices and NAND Flash command handler */
+nand_device_t *nand_devices = NULL;
+static command_t *nand_cmd;
+
+/*     Chip ID list
+ *
+ *     Name, ID code, pagesize, chipsize in MegaByte, eraseblock size,
+ *     options
+ *
+ *     Pagesize; 0, 256, 512
+ *     0       get this information from the extended chip ID
+ *     256     256 Byte page size
+ *     512     512 Byte page size
+ */
+nand_info_t nand_flash_ids[] =
+{
+       {"NAND 1MiB 5V 8-bit",          0x6e, 256, 1, 0x1000, 0},
+       {"NAND 2MiB 5V 8-bit",          0x64, 256, 2, 0x1000, 0},
+       {"NAND 4MiB 5V 8-bit",          0x6b, 512, 4, 0x2000, 0},
+       {"NAND 1MiB 3,3V 8-bit",        0xe8, 256, 1, 0x1000, 0},
+       {"NAND 1MiB 3,3V 8-bit",        0xec, 256, 1, 0x1000, 0},
+       {"NAND 2MiB 3,3V 8-bit",        0xea, 256, 2, 0x1000, 0},
+       {"NAND 4MiB 3,3V 8-bit",        0xd5, 512, 4, 0x2000, 0},
+       {"NAND 4MiB 3,3V 8-bit",        0xe3, 512, 4, 0x2000, 0},
+       {"NAND 4MiB 3,3V 8-bit",        0xe5, 512, 4, 0x2000, 0},
+       {"NAND 8MiB 3,3V 8-bit",        0xd6, 512, 8, 0x2000, 0},
+
+       {"NAND 8MiB 1,8V 8-bit",        0x39, 512, 8, 0x2000, 0},
+       {"NAND 8MiB 3,3V 8-bit",        0xe6, 512, 8, 0x2000, 0},
+       {"NAND 8MiB 1,8V 16-bit",       0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
+       {"NAND 8MiB 3,3V 16-bit",       0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
+
+       {"NAND 16MiB 1,8V 8-bit",       0x33, 512, 16, 0x4000, 0},
+       {"NAND 16MiB 3,3V 8-bit",       0x73, 512, 16, 0x4000, 0},
+       {"NAND 16MiB 1,8V 16-bit",      0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},
+       {"NAND 16MiB 3,3V 16-bit",      0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},
+
+       {"NAND 32MiB 1,8V 8-bit",       0x35, 512, 32, 0x4000, 0},
+       {"NAND 32MiB 3,3V 8-bit",       0x75, 512, 32, 0x4000, 0},
+       {"NAND 32MiB 1,8V 16-bit",      0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},
+       {"NAND 32MiB 3,3V 16-bit",      0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},
+
+       {"NAND 64MiB 1,8V 8-bit",       0x36, 512, 64, 0x4000, 0},
+       {"NAND 64MiB 3,3V 8-bit",       0x76, 512, 64, 0x4000, 0},
+       {"NAND 64MiB 1,8V 16-bit",      0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},
+       {"NAND 64MiB 3,3V 16-bit",      0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
+
+       {"NAND 128MiB 1,8V 8-bit",      0x78, 512, 128, 0x4000, 0},
+       {"NAND 128MiB 1,8V 8-bit",      0x39, 512, 128, 0x4000, 0},
+       {"NAND 128MiB 3,3V 8-bit",      0x79, 512, 128, 0x4000, 0},
+       {"NAND 128MiB 1,8V 16-bit",     0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+       {"NAND 128MiB 1,8V 16-bit",     0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+       {"NAND 128MiB 3,3V 16-bit",     0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+       {"NAND 128MiB 3,3V 16-bit",     0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+
+       {"NAND 256MiB 3,3V 8-bit",      0x71, 512, 256, 0x4000, 0},
+
+       {"NAND 64MiB 1,8V 8-bit",       0xA2, 0,  64, 0, LP_OPTIONS},
+       {"NAND 64MiB 3,3V 8-bit",       0xF2, 0,  64, 0, LP_OPTIONS},
+       {"NAND 64MiB 1,8V 16-bit",      0xB2, 0,  64, 0, LP_OPTIONS16},
+       {"NAND 64MiB 3,3V 16-bit",      0xC2, 0,  64, 0, LP_OPTIONS16},
+
+       {"NAND 128MiB 1,8V 8-bit",      0xA1, 0, 128, 0, LP_OPTIONS},
+       {"NAND 128MiB 3,3V 8-bit",      0xF1, 0, 128, 0, LP_OPTIONS},
+       {"NAND 128MiB 1,8V 16-bit",     0xB1, 0, 128, 0, LP_OPTIONS16},
+       {"NAND 128MiB 3,3V 16-bit",     0xC1, 0, 128, 0, LP_OPTIONS16},
+
+       {"NAND 256MiB 1,8V 8-bit",      0xAA, 0, 256, 0, LP_OPTIONS},
+       {"NAND 256MiB 3,3V 8-bit",      0xDA, 0, 256, 0, LP_OPTIONS},
+       {"NAND 256MiB 1,8V 16-bit",     0xBA, 0, 256, 0, LP_OPTIONS16},
+       {"NAND 256MiB 3,3V 16-bit",     0xCA, 0, 256, 0, LP_OPTIONS16},
+
+       {"NAND 512MiB 1,8V 8-bit",      0xAC, 0, 512, 0, LP_OPTIONS},
+       {"NAND 512MiB 3,3V 8-bit",      0xDC, 0, 512, 0, LP_OPTIONS},
+       {"NAND 512MiB 1,8V 16-bit",     0xBC, 0, 512, 0, LP_OPTIONS16},
+       {"NAND 512MiB 3,3V 16-bit",     0xCC, 0, 512, 0, LP_OPTIONS16},
+
+       {"NAND 1GiB 1,8V 8-bit",        0xA3, 0, 1024, 0, LP_OPTIONS},
+       {"NAND 1GiB 3,3V 8-bit",        0xD3, 0, 1024, 0, LP_OPTIONS},
+       {"NAND 1GiB 1,8V 16-bit",       0xB3, 0, 1024, 0, LP_OPTIONS16},
+       {"NAND 1GiB 3,3V 16-bit",       0xC3, 0, 1024, 0, LP_OPTIONS16},
+
+       {"NAND 2GiB 1,8V 8-bit",        0xA5, 0, 2048, 0, LP_OPTIONS},
+       {"NAND 2GiB 3,3V 8-bit",        0xD5, 0, 2048, 0, LP_OPTIONS},
+       {"NAND 2GiB 1,8V 16-bit",       0xB5, 0, 2048, 0, LP_OPTIONS16},
+       {"NAND 2GiB 3,3V 16-bit",       0xC5, 0, 2048, 0, LP_OPTIONS16},
+
+       {NULL, 0,}
+};
+
+/* Manufacturer ID list
+ */
+nand_manufacturer_t nand_manuf_ids[] =
+{
+       {0x0, "unknown"},
+       {NAND_MFR_TOSHIBA, "Toshiba"},
+       {NAND_MFR_SAMSUNG, "Samsung"},
+       {NAND_MFR_FUJITSU, "Fujitsu"},
+       {NAND_MFR_NATIONAL, "National"},
+       {NAND_MFR_RENESAS, "Renesas"},
+       {NAND_MFR_STMICRO, "ST Micro"},
+       {NAND_MFR_HYNIX, "Hynix"},
+       {0x0, NULL},
+};
+
+/* nand device <nand_controller> [controller options]
+ */
+int handle_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       int i;
+       int retval;
+               
+       if (argc < 1)
+       {
+               WARNING("incomplete flash device nand configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+       
+       for (i = 0; nand_flash_controllers[i]; i++)
+       {
+               nand_device_t *p, *c;
+               
+               if (strcmp(args[0], nand_flash_controllers[i]->name) == 0)
+               {
+                       /* register flash specific commands */
+                       if (nand_flash_controllers[i]->register_commands(cmd_ctx) != ERROR_OK)
+                       {
+                               ERROR("couldn't register '%s' commands", args[0]);
+                               exit(-1);
+                       }
+       
+                       c = malloc(sizeof(nand_device_t));
+
+                       c->controller = nand_flash_controllers[i];
+                       c->controller_priv = NULL;
+                       c->manufacturer = NULL;
+                       c->device = NULL;
+                       c->bus_width = 0;
+                       c->address_cycles = 0;
+                       c->page_size = 0;
+                       c->use_raw = 0;
+                       c->next = NULL;
+
+                       if ((retval = nand_flash_controllers[i]->nand_device_command(cmd_ctx, cmd, args, argc, c)) != ERROR_OK)
+                       {
+                               ERROR("'%s' driver rejected nand flash", c->controller->name);
+                               free(c);
+                               return ERROR_OK;
+                       }
+                       
+                       /* put NAND device in linked list */
+                       if (nand_devices)
+                       {
+                               /* find last flash device */
+                               for (p = nand_devices; p && p->next; p = p->next);
+                               if (p)
+                                       p->next = c;
+                       }
+                       else
+                       {
+                               nand_devices = c;
+                       }
+                       
+                       return ERROR_OK;
+               }
+       }
+
+       /* no valid NAND controller was found (i.e. the configuration option,
+        * didn't match one of the compiled-in controllers)
+        */
+       ERROR("No valid NAND flash controller found (%s)", args[0]);
+       ERROR("compiled-in NAND flash controllers:");
+       for (i = 0; nand_flash_controllers[i]; i++)
+       {
+               ERROR("%i: %s", i, nand_flash_controllers[i]->name);
+       }
+       
+       return ERROR_OK;
+}
+
+int nand_register_commands(struct command_context_s *cmd_ctx)
+{
+       nand_cmd = register_command(cmd_ctx, NULL, "nand", NULL, COMMAND_ANY, NULL);
+       
+       register_command(cmd_ctx, nand_cmd, "device", handle_nand_device_command, COMMAND_CONFIG, NULL);
+       
+       return ERROR_OK;
+}
+
+int nand_init(struct command_context_s *cmd_ctx)
+{
+       if (nand_devices)
+       {
+               register_command(cmd_ctx, nand_cmd, "list", handle_nand_list_command, COMMAND_EXEC,
+                                                "list configured NAND flash devices");
+               register_command(cmd_ctx, nand_cmd, "info", handle_nand_info_command, COMMAND_EXEC,
+                                                "print info about NAND flash device <num>");
+               register_command(cmd_ctx, nand_cmd, "probe", handle_nand_probe_command, COMMAND_EXEC,
+                                                "identify NAND flash device <num>");
+               register_command(cmd_ctx, nand_cmd, "check_bad_blocks", handle_nand_check_bad_blocks_command, COMMAND_EXEC,
+                                                "check NAND flash device <num> for bad blocks [<first> <last>]");
+               register_command(cmd_ctx, nand_cmd, "erase", handle_nand_erase_command, COMMAND_EXEC,
+                                                "erase blocks on NAND flash device <num> <first> <last>");
+               register_command(cmd_ctx, nand_cmd, "copy", handle_nand_copy_command, COMMAND_EXEC,
+                                                "copy from NAND flash device <num> <offset> <length> <ram-address>");
+               register_command(cmd_ctx, nand_cmd, "dump", handle_nand_dump_command, COMMAND_EXEC,
+                                                "dump from NAND flash device <num> <filename> <offset> <size> [options]");
+               register_command(cmd_ctx, nand_cmd, "write", handle_nand_write_command, COMMAND_EXEC,
+                                                "write to NAND flash device <num> <filename> <offset> [options]");
+               register_command(cmd_ctx, nand_cmd, "raw_access", handle_nand_raw_access_command, COMMAND_EXEC,
+                                                "raw access to NAND flash device <num> ['enable'|'disable']");
+       }
+       
+       return ERROR_OK;
+}
+
+nand_device_t *get_nand_device_by_num(int num)
+{
+       nand_device_t *p;
+       int i = 0;
+
+       for (p = nand_devices; p; p = p->next)
+       {
+               if (i++ == num)
+               {
+                       return p;
+               }
+       }
+       
+       return NULL;
+}
+
+int nand_build_bbt(struct nand_device_s *device, int first, int last)
+{
+       u32 page = 0x0;
+       int i;
+       u8 *oob;
+       
+       oob = malloc(6);
+       
+       if ((first < 0) || (first >= device->num_blocks))
+               first = 0;
+       
+       if ((last >= device->num_blocks) || (last == -1))
+               last = device->num_blocks - 1;
+       
+       for (i = first; i < last; i++)
+       {
+               nand_read_page(device, page, NULL, 0, oob, 6);
+               
+               if (((device->device->options & NAND_BUSWIDTH_16) && ((oob[0] & oob[1]) != 0xff))
+                       || (((device->page_size == 512) && (oob[5] != 0xff)) ||
+                               ((device->page_size == 2048) && (oob[0] != 0xff))))
+               {
+                       WARNING("invalid block: %i", i);
+                       device->blocks[i].is_bad = 1;
+               }
+               else
+               {
+                       device->blocks[i].is_bad = 0;
+               }
+               
+               page += (device->erase_size / device->page_size);
+       }
+       
+       return ERROR_OK;
+}
+
+int nand_read_status(struct nand_device_s *device, u8 *status)
+{
+       if (!device->device)
+               return ERROR_NAND_DEVICE_NOT_PROBED;
+               
+       /* Send read status command */
+       device->controller->command(device, NAND_CMD_STATUS);
+       
+       usleep(1000);
+       
+       /* read status */
+       if (device->device->options & NAND_BUSWIDTH_16)
+       {
+               u16 data;
+               device->controller->read_data(device, &data);
+               *status = data & 0xff;
+       }
+       else
+       {
+               device->controller->read_data(device, status);
+       }
+                       
+       return ERROR_OK;
+}
+
+int nand_probe(struct nand_device_s *device)
+{
+       u8 manufacturer_id, device_id;
+       nand_manufacturer_t *manufacturer;
+       int retval;
+       int i;
+
+       /* clear device data */
+       device->device = NULL;
+       device->manufacturer = NULL;
+       
+       /* clear device parameters */
+       device->bus_width = 0;
+       device->address_cycles = 0;
+       device->page_size = 0;
+       device->erase_size = 0;
+       
+       /* initialize controller (device parameters are zero, use controller default) */
+       if ((retval = device->controller->init(device) != ERROR_OK))
+       {
+               switch (retval)
+               {
+                       case ERROR_NAND_OPERATION_FAILED:
+                               DEBUG("controller initialization failed");
+                               return ERROR_NAND_OPERATION_FAILED;
+                       case ERROR_NAND_OPERATION_NOT_SUPPORTED:
+                               ERROR("BUG: controller reported that it doesn't support default parameters");
+                               return ERROR_NAND_OPERATION_FAILED;
+                       default:
+                               ERROR("BUG: unknown controller initialization failure");
+                               return ERROR_NAND_OPERATION_FAILED;
+               }
+       }
+       
+       device->controller->command(device, NAND_CMD_RESET);
+       device->controller->reset(device);
+
+       device->controller->command(device, NAND_CMD_READID);
+       device->controller->address(device, 0x0);
+       
+       if (device->bus_width == 8)
+       {
+               device->controller->read_data(device, &manufacturer_id);
+               device->controller->read_data(device, &device_id);
+       }
+       else
+       {
+               u16 data_buf;
+               device->controller->read_data(device, &data_buf);
+               manufacturer_id = data_buf & 0xff;
+               device->controller->read_data(device, &data_buf);
+               device_id = data_buf & 0xff;
+       }
+               
+       device->manufacturer = manufacturer;
+       
+       for (i = 0; nand_flash_ids[i].name; i++)
+       {
+               if (nand_flash_ids[i].id == device_id)
+               {
+                       device->device = &nand_flash_ids[i];
+                       break;
+               }
+       }
+       
+       for (i = 0; nand_manuf_ids[i].name; i++)
+       {
+               if (nand_manuf_ids[i].id == manufacturer_id)
+               {
+                       device->manufacturer = &nand_manuf_ids[i];
+                       break;
+               }
+       }
+       
+       if (!device->manufacturer)
+       {
+               device->manufacturer = &nand_manuf_ids[0];
+               device->manufacturer->id = manufacturer_id;
+       }
+       
+       if (!device->device)
+       {
+               ERROR("unknown NAND flash device found, manufacturer id: 0x%2.2x device id: 0x%2.2x",
+                       manufacturer_id, device_id);
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       
+       DEBUG("found %s (%s)", device->device->name, device->manufacturer->name);
+       
+       /* initialize device parameters */
+       
+       /* bus width */ 
+       if (device->device->options & NAND_BUSWIDTH_16)
+               device->bus_width = 16;
+       else
+               device->bus_width = 8;
+               
+       /* page size */
+       if (device->device->page_size == 0)
+       {
+               /* TODO: support reading extended chip id to determine page size */
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       else if (device->device->page_size == 256)
+       {
+               ERROR("NAND flashes with 256 byte pagesize are not supported");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       else
+       {
+               device->page_size = device->device->page_size;
+       }
+       
+       /* number of address cycles */
+       if (device->page_size <= 512)
+       {
+               /* small page devices */
+               if (device->device->chip_size <= 32)
+                       device->address_cycles = 3;
+               else if (device->device->chip_size <= 8*1024)
+                       device->address_cycles = 4;
+               else
+               {
+                       ERROR("BUG: small page NAND device with more than 8 GiB encountered");
+                       device->address_cycles = 5;
+               }
+       }
+       else
+       {
+               /* large page devices */
+               if (device->device->chip_size <= 128)
+                       device->address_cycles = 4;
+               else if (device->device->chip_size <= 32*1024)
+                       device->address_cycles = 5;
+               else
+               {
+                       ERROR("BUG: small page NAND device with more than 32 GiB encountered");
+                       device->address_cycles = 6;
+               }
+       }
+       
+       /* erase size */
+       if (device->device->erase_size == 0)
+       {
+               /* TODO: support reading extended chip id to determine erase size */
+       }
+       else
+       {
+               device->erase_size = device->device->erase_size;
+       }
+       
+       /* initialize controller, but leave parameters at the controllers default */
+       if ((retval = device->controller->init(device) != ERROR_OK))
+       {
+               switch (retval)
+               {
+                       case ERROR_NAND_OPERATION_FAILED:
+                               DEBUG("controller initialization failed");
+                               return ERROR_NAND_OPERATION_FAILED;
+                       case ERROR_NAND_OPERATION_NOT_SUPPORTED:
+                               ERROR("controller doesn't support requested parameters (buswidth: %i, address cycles: %i, page size: %i)",
+                                       device->bus_width, device->address_cycles, device->page_size);
+                               return ERROR_NAND_OPERATION_FAILED;
+                       default:
+                               ERROR("BUG: unknown controller initialization failure");
+                               return ERROR_NAND_OPERATION_FAILED;
+               }
+       }
+       
+       device->num_blocks = (device->device->chip_size * 1024) / (device->erase_size / 1024);
+       device->blocks = malloc(sizeof(nand_block_t) * device->num_blocks);
+       
+       for (i = 0; i < device->num_blocks; i++)
+       {
+               device->blocks[i].size = device->erase_size;
+               device->blocks[i].offset = i * device->erase_size;
+               device->blocks[i].is_erased = -1;
+               device->blocks[i].is_bad = -1;
+       }
+       
+       return ERROR_OK;
+}
+
+int nand_erase(struct nand_device_s *device, int first_block, int last_block)
+{
+       int i;
+       u32 page;
+       u8 status;
+       int retval;
+       
+       if (!device->device)
+               return ERROR_NAND_DEVICE_NOT_PROBED;
+       
+       if ((first_block < 0) || (last_block > device->num_blocks))
+               return ERROR_INVALID_ARGUMENTS;
+       
+       /* make sure we know if a block is bad before erasing it */
+       for (i = first_block; i <= last_block; i++)
+       {
+               if (device->blocks[i].is_bad == -1)
+               {
+                       nand_build_bbt(device, i, last_block);
+                       break;
+               }
+       }
+       
+       for (i = first_block; i <= last_block; i++)
+       {
+               /* Send erase setup command */
+               device->controller->command(device, NAND_CMD_ERASE1);
+               
+               page = i * (device->erase_size / device->page_size);
+               
+               /* Send page address */
+               if (device->page_size <= 512)
+               {
+                       /* row */
+                       device->controller->address(device, page & 0xff);
+                       device->controller->address(device, (page >> 8) & 0xff);
+                       
+                       /* 3rd cycle only on devices with more than 32 MiB */
+                       if (device->address_cycles >= 4)
+                               device->controller->address(device, (page >> 16) & 0xff);
+       
+                       /* 4th cycle only on devices with more than 8 GiB */
+                       if (device->address_cycles >= 5)
+                               device->controller->address(device, (page >> 24) & 0xff);
+               }
+               else
+               {
+                       /* row */
+                       device->controller->address(device, page & 0xff);
+                       device->controller->address(device, (page >> 8) & 0xff);
+       
+                       /* 3rd cycle only on devices with more than 128 MiB */
+                       if (device->address_cycles >= 5)
+                               device->controller->address(device, (page >> 16) & 0xff);
+               }
+               
+               /* Send erase confirm command */
+               device->controller->command(device, NAND_CMD_ERASE2);
+               
+               if (!device->controller->nand_ready(device, 1000))
+               {
+                       ERROR("timeout waiting for NAND flash block erase to complete");
+                       return ERROR_NAND_OPERATION_TIMEOUT;
+               }
+               
+               if ((retval = nand_read_status(device, &status)) != ERROR_OK)
+               {
+                       ERROR("couldn't read status");
+                       return ERROR_NAND_OPERATION_FAILED;
+               }
+               
+               if (status & 0x1)
+               {
+                       ERROR("erase operation didn't pass, status: 0x%2.2x", status);
+                       return ERROR_NAND_OPERATION_FAILED;
+               }
+       }
+       
+       return ERROR_OK;
+}
+
+int nand_read_plain(struct nand_device_s *device, u32 address, u8 *data, u32 data_size)
+{
+       u8 *page;
+       
+       if (!device->device)
+               return ERROR_NAND_DEVICE_NOT_PROBED;
+               
+       if (address % device->page_size)
+       {
+               ERROR("reads need to be page aligned");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       
+       page = malloc(device->page_size);
+       
+       while (data_size > 0 )
+       {
+               u32 thisrun_size = (data_size > device->page_size) ? device->page_size : data_size;
+               u32 page_address;
+               
+               
+               page_address = address / device->page_size;
+               
+               nand_read_page(device, page_address, page, device->page_size, NULL, 0);
+
+               memcpy(data, page, thisrun_size);
+               
+               address += thisrun_size;
+               data += thisrun_size;
+               data_size -= thisrun_size;
+       }
+       
+       free(page);
+       
+       return ERROR_OK;
+}
+
+int nand_write_plain(struct nand_device_s *device, u32 address, u8 *data, u32 data_size)
+{
+       u8 *page;
+       
+       if (!device->device)
+               return ERROR_NAND_DEVICE_NOT_PROBED;
+               
+       if (address % device->page_size)
+       {
+               ERROR("writes need to be page aligned");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       
+       page = malloc(device->page_size);
+       
+       while (data_size > 0 )
+       {
+               u32 thisrun_size = (data_size > device->page_size) ? device->page_size : data_size;
+               u32 page_address;
+               
+               memset(page, 0xff, device->page_size);
+               memcpy(page, data, thisrun_size);
+               
+               page_address = address / device->page_size;
+               
+               nand_write_page(device, page_address, page, device->page_size, NULL, 0);
+               
+               address += thisrun_size;
+               data += thisrun_size;
+               data_size -= thisrun_size;
+       }
+       
+       free(page);
+       
+       return ERROR_OK;
+}
+
+int nand_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)
+{
+       if (!device->device)
+               return ERROR_NAND_DEVICE_NOT_PROBED;
+               
+       if (device->use_raw)
+               return nand_write_page_raw(device, page, data, data_size, oob, oob_size);
+       else
+               return device->controller->write_page(device, page, data, data_size, oob, oob_size);
+}
+
+int nand_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)
+{
+       if (!device->device)
+               return ERROR_NAND_DEVICE_NOT_PROBED;
+               
+       if (device->use_raw)
+               return nand_read_page_raw(device, page, data, data_size, oob, oob_size);
+       else
+               return device->controller->read_page(device, page, data, data_size, oob, oob_size);
+}
+
+int nand_read_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)
+{
+       int i;
+       
+       if (!device->device)
+               return ERROR_NAND_DEVICE_NOT_PROBED;
+
+       if (device->page_size <= 512)
+       {
+               /* small page device */
+               if (data)
+                       device->controller->command(device, NAND_CMD_READ0);
+               else
+                       device->controller->command(device, NAND_CMD_READOOB);
+               
+               /* column (always 0, we start at the beginning of a page/OOB area) */
+               device->controller->address(device, 0x0);
+               
+               /* row */
+               device->controller->address(device, page & 0xff);
+               device->controller->address(device, (page >> 8) & 0xff);
+               
+               /* 4th cycle only on devices with more than 32 MiB */
+               if (device->address_cycles >= 4)
+                       device->controller->address(device, (page >> 16) & 0xff);
+
+               /* 5th cycle only on devices with more than 8 GiB */
+               if (device->address_cycles >= 5)
+                       device->controller->address(device, (page >> 24) & 0xff);
+       }
+       else
+       {
+               /* large page device */
+               device->controller->command(device, NAND_CMD_READ0);
+               
+               /* column (0 when we start at the beginning of a page,
+                * or 2048 for the beginning of OOB area)
+                */
+               device->controller->address(device, 0x0);
+               device->controller->address(device, 0x8);
+               
+               /* row */
+               device->controller->address(device, page & 0xff);
+               device->controller->address(device, (page >> 8) & 0xff);
+
+               /* 5th cycle only on devices with more than 128 MiB */
+               if (device->address_cycles >= 5)
+                       device->controller->address(device, (page >> 16) & 0xff);
+
+               /* large page devices need a start command */
+               device->controller->command(device, NAND_CMD_READSTART);
+       }
+       
+       if (!device->controller->nand_ready(device, 100))
+               return ERROR_NAND_OPERATION_TIMEOUT;
+       
+       if (data)
+       {
+               for (i = 0; i < data_size;)
+               {
+                       if (device->device->options & NAND_BUSWIDTH_16)
+                       {
+                               device->controller->read_data(device, data);
+                               data += 2;
+                               i += 2;
+                       }
+                       else
+                       {
+                               device->controller->read_data(device, data);
+                               data += 1;
+                               i += 1;
+                       }
+               }
+       }
+       
+       if (oob)
+       {
+               for (i = 0; i < oob_size;)
+               {
+                       if (device->device->options & NAND_BUSWIDTH_16)
+                       {
+                               device->controller->read_data(device, oob);
+                               oob += 2;
+                               i += 2;
+                       }
+                       else
+                       {
+                               device->controller->read_data(device, oob);
+                               oob += 1;
+                               i += 1;
+                       }
+               }
+       }
+       
+       return ERROR_OK;        
+}
+
+int nand_write_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)
+{
+       int i;
+       int retval;
+       u8 status;
+       
+       if (!device->device)
+               return ERROR_NAND_DEVICE_NOT_PROBED;
+
+       device->controller->command(device, NAND_CMD_SEQIN);
+       
+       if (device->page_size <= 512)
+       {
+               /* column (always 0, we start at the beginning of a page/OOB area) */
+               device->controller->address(device, 0x0);
+               
+               /* row */
+               device->controller->address(device, page & 0xff);
+               device->controller->address(device, (page >> 8) & 0xff);
+               
+               /* 4th cycle only on devices with more than 32 MiB */
+               if (device->address_cycles >= 4)
+                       device->controller->address(device, (page >> 16) & 0xff);
+
+               /* 5th cycle only on devices with more than 8 GiB */
+               if (device->address_cycles >= 5)
+                       device->controller->address(device, (page >> 24) & 0xff);
+       }
+       else
+       {
+               /* column (0 when we start at the beginning of a page,
+                * or 2048 for the beginning of OOB area)
+                */
+               device->controller->address(device, 0x0);
+               device->controller->address(device, 0x8);
+               
+               /* row */
+               device->controller->address(device, page & 0xff);
+               device->controller->address(device, (page >> 8) & 0xff);
+
+               /* 5th cycle only on devices with more than 128 MiB */
+               if (device->address_cycles >= 5)
+                       device->controller->address(device, (page >> 16) & 0xff);
+       }
+       
+       if (data)
+       {
+               for (i = 0; i < data_size;)
+               {
+                       if (device->device->options & NAND_BUSWIDTH_16)
+                       {
+                               u16 data_buf = le_to_h_u16(data);
+                               device->controller->write_data(device, data_buf);
+                               data += 2;
+                               i += 2;
+                       }
+                       else
+                       {
+                               device->controller->write_data(device, *data);
+                               data += 1;
+                               i += 1;
+                       }
+               }
+       }
+       
+       if (oob)
+       {
+               for (i = 0; i < oob_size;)
+               {
+                       if (device->device->options & NAND_BUSWIDTH_16)
+                       {
+                               u16 oob_buf = le_to_h_u16(data);
+                               device->controller->write_data(device, oob_buf);
+                               oob += 2;
+                               i += 2;
+                       }
+                       else
+                       {
+                               device->controller->write_data(device, *oob);
+                               oob += 1;
+                               i += 1;
+                       }
+               }
+       }
+       
+       device->controller->command(device, NAND_CMD_PAGEPROG);
+       
+       if (!device->controller->nand_ready(device, 100))
+               return ERROR_NAND_OPERATION_TIMEOUT;
+       
+       if ((retval = nand_read_status(device, &status)) != ERROR_OK)
+       {
+               ERROR("couldn't read status");
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+               
+       if (status & NAND_STATUS_FAIL)
+       {
+               ERROR("write operation didn't pass, status: 0x%2.2x", status);
+               return ERROR_NAND_OPERATION_FAILED;
+       }
+       
+       return ERROR_OK;        
+}
+
+int handle_nand_list_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       nand_device_t *p;
+       int i = 0;
+       
+       if (!nand_devices)
+       {
+               command_print(cmd_ctx, "no NAND flash devices configured");
+               return ERROR_OK;
+       }
+       
+       for (p = nand_devices; p; p = p->next)
+       {
+               if (p->device)
+                       command_print(cmd_ctx, "#%i: %s (%s) pagesize: %i, buswidth: %i, erasesize: %i",
+                               i++, p->device->name, p->manufacturer->name, p->page_size, p->bus_width, p->erase_size);
+               else
+                       command_print(cmd_ctx, "#%i: not probed");
+       }
+       
+       return ERROR_OK;
+}
+
+int handle_nand_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       nand_device_t *p;
+       int i = 0;
+       int j = 0;
+       int first = -1;
+       int last = -1;
+               
+       if ((argc < 1) || (argc > 3))
+       {
+               command_print(cmd_ctx, "usage: nand info <num> [<first> <last>]");
+               return ERROR_OK;
+       }
+       
+       if (argc == 2)
+       {
+               first = last = strtoul(args[1], NULL, 0);
+       }
+       else if (argc == 3)
+       {
+               first = strtoul(args[1], NULL, 0);
+               last = strtoul(args[2], NULL, 0);
+       }
+               
+       p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
+       if (p)
+       {
+               if (p->device)
+               {
+                       if (first >= p->num_blocks)
+                               first = p->num_blocks - 1;
+                       
+                       if (last >= p->num_blocks)
+                               last = p->num_blocks - 1;
+                       
+                       command_print(cmd_ctx, "#%i: %s (%s) pagesize: %i, buswidth: %i, erasesize: %i",
+                               i++, p->device->name, p->manufacturer->name, p->page_size, p->bus_width, p->erase_size);
+                       
+                       for (j = first; j <= last; j++)
+                       {
+                               char *erase_state, *bad_state;
+                               
+                               if (p->blocks[j].is_erased == 0)
+                                       erase_state = "not erased";
+                               else if (p->blocks[j].is_erased == 1)
+                                       erase_state = "erased";
+                               else
+                                       erase_state = "erase state unknown";
+                               
+                               if (p->blocks[j].is_bad == 0)
+                                       bad_state = "";
+                               else if (p->blocks[j].is_bad == 1)
+                                       bad_state = " (marked bad)";
+                               else
+                                       bad_state = " (block condition unknown)";
+
+                               command_print(cmd_ctx, "\t#%i: 0x%8.8x (0x%xkB) %s%s",
+                                                       j, p->blocks[j].offset, p->blocks[j].size / 1024,
+                                                       erase_state, bad_state);
+                       }
+               }
+               else
+               {
+                       command_print(cmd_ctx, "#%i: not probed");
+               }
+       }
+       
+       return ERROR_OK;
+}
+
+int handle_nand_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       nand_device_t *p;
+       int retval;
+               
+       if (argc != 1)
+       {
+               command_print(cmd_ctx, "usage: nand probe <num>");
+               return ERROR_OK;
+       }
+       
+       p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
+       if (p)
+       {
+               if ((retval = nand_probe(p)) == ERROR_OK)
+               {
+                       command_print(cmd_ctx, "NAND flash device '%s' found", p->device->name);
+               }
+               else if (retval == ERROR_NAND_OPERATION_FAILED)
+               {
+                       command_print(cmd_ctx, "probing failed for NAND flash device");
+               }
+               else
+               {
+                       command_print(cmd_ctx, "unknown error when probing NAND flash device");
+               }
+       }
+       else
+       {
+               command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
+       }
+       
+       return ERROR_OK;
+}
+
+int handle_nand_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       nand_device_t *p;
+       int retval;
+               
+       if (argc != 3)
+       {
+               command_print(cmd_ctx, "usage: nand erase <num> <first> <last>");
+               return ERROR_OK;
+       }
+       
+       p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
+       if (p)
+       {
+               int first = strtoul(args[1], NULL, 0);
+               int last = strtoul(args[2], NULL, 0);
+               
+               if ((retval = nand_erase(p, first, last)) == ERROR_OK)
+               {
+                       command_print(cmd_ctx, "successfully erased blocks %i to %i on NAND flash device '%s'", first, last, p->device->name);
+               }
+               else if (retval == ERROR_NAND_OPERATION_FAILED)
+               {
+                       command_print(cmd_ctx, "erase failed");
+               }
+               else
+               {
+                       command_print(cmd_ctx, "unknown error when erasing NAND flash device");
+               }
+       }
+       else
+       {
+               command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
+       }
+       
+       return ERROR_OK;
+}
+
+int handle_nand_check_bad_blocks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       nand_device_t *p;
+       int retval;
+       int first = -1;
+       int last = -1;
+               
+       if ((argc < 1) || (argc > 3) || (argc == 2))
+       {
+               command_print(cmd_ctx, "usage: nand check_bad_blocks <num> [<first> <last>]");
+               return ERROR_OK;
+       }
+       
+       if (argc == 3)
+       {
+               first = strtoul(args[1], NULL, 0);
+               last = strtoul(args[2], NULL, 0);
+       }
+       
+       p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
+       if (p)
+       {
+               if ((retval = nand_build_bbt(p, first, last)) == ERROR_OK)
+               {
+                       command_print(cmd_ctx, "checked NAND flash device for bad blocks, use \"nand info\" command to list blocks", p->device->name);
+               }
+               else if (retval == ERROR_NAND_OPERATION_FAILED)
+               {
+                       command_print(cmd_ctx, "error when checking for bad blocks on NAND flash device");
+               }
+               else
+               {
+                       command_print(cmd_ctx, "unknown error when checking for bad blocks on NAND flash device");
+               }
+       }
+       else
+       {
+               command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
+       }
+       
+       return ERROR_OK;
+}
+
+int handle_nand_copy_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       nand_device_t *p;
+       int retval;
+               
+       if (argc != 4)
+       {
+               command_print(cmd_ctx, "usage: nand copy <num> <offset> <length> <ram-address>");
+               return ERROR_OK;
+       }
+       
+       p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
+       if (p)
+       {
+
+       }
+       else
+       {
+               command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
+       }
+       
+       return ERROR_OK;
+}
+
+int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       u32 offset;
+       u32 binary_size;
+       u32 buf_cnt;
+       enum oob_formats oob_format = NAND_OOB_NONE;
+       
+       fileio_t file;
+       fileio_image_t image_info;
+       int sec_type_identified = 0;
+       enum fileio_sec_type sec_type;
+       
+       duration_t duration;
+       char *duration_text;
+       
+       nand_device_t *p;
+               
+       if (argc < 3)
+       {
+               command_print(cmd_ctx, "usage: nand write <num> <file> <offset> [options]");
+               return ERROR_OK;
+       }
+       
+       p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
+       if (p)
+       {
+               u8 *page = NULL;
+               u32 page_size = 0;
+               u8 *oob = NULL;
+               u32 oob_size = 0;
+                       
+               duration_start_measure(&duration);
+               strtoul(args[2], NULL, 0);
+               
+               if (argc > 3)
+               {
+                       int i;
+                       for (i = 3; i < argc; i++)
+                       {
+                               if (!strcmp(args[i], "oob_raw"))
+                                       oob_format |= NAND_OOB_RAW;
+                               else if (!strcmp(args[i], "oob_only"))
+                                       oob_format |= NAND_OOB_RAW | NAND_OOB_ONLY;
+                               else
+                               {
+                                       if (fileio_identify_image_type(&sec_type, args[i]) == ERROR_OK)
+                                       {
+                                               sec_type_identified = 1;
+                                       }
+                                       else
+                                       {
+                                               command_print(cmd_ctx, "unknown option: %s", args[i]);
+                                       }
+                               }
+                       }
+               }
+               
+               /* if no image type option was encountered, set the default */
+               if (!sec_type_identified)
+               {
+                       
+                       fileio_identify_image_type(&sec_type, NULL);
+                       sec_type_identified = 1;
+               }
+
+               image_info.base_address = strtoul(args[2], NULL, 0);
+               image_info.has_start_address = 0;
+       
+               if (fileio_open(&file, args[1], FILEIO_READ, 
+                       FILEIO_IMAGE, &image_info, sec_type) != ERROR_OK)
+               {
+                       command_print(cmd_ctx, "flash write error: %s", file.error_str);
+                       return ERROR_OK;
+               }
+       
+               /* the offset might have been overwritten by the image base address */
+               offset = image_info.base_address;
+               
+               buf_cnt = binary_size = file.size;
+               
+               if (!(oob_format & NAND_OOB_ONLY))
+               {
+                       page_size = p->page_size;
+                       page = malloc(p->page_size);
+               }
+
+               if (oob_format & NAND_OOB_RAW)
+               {
+                       if (p->page_size == 512)
+                               oob_size = 16;
+                       else if (p->page_size == 2048)
+                               oob_size = 64;
+                       oob = malloc(oob_size);
+               }
+               
+               if (offset % p->page_size)
+               {
+                       command_print(cmd_ctx, "only page size aligned offsets and sizes are supported");
+                       return ERROR_OK;
+               }
+               
+               while (buf_cnt > 0)
+               {
+                       u32 size_read;
+                       
+                       if (page)
+                       {
+                               fileio_read(&file, page_size, page, &size_read);
+                               buf_cnt -= size_read;
+                               if (size_read < page_size)
+                               {
+                                       memset(page + size_read, 0xff, page_size - size_read);
+                               }
+                       }
+                               
+                       if (oob)
+                       {
+                               fileio_read(&file, oob_size, oob, &size_read);
+                               buf_cnt -= size_read;
+                               if (size_read < oob_size)
+                               {
+                                       memset(oob + size_read, 0xff, oob_size - size_read);
+                               }
+                       }
+                       
+                       if (nand_write_page(p, offset / p->page_size, page, page_size, oob, oob_size) != ERROR_OK)
+                       {
+                               command_print(cmd_ctx, "failed writing file %s to NAND flash %s at offset 0x%8.8x",
+                                       file.url, args[0], offset);
+                               return ERROR_OK;
+                       }
+                       offset += page_size;
+               }
+
+               duration_stop_measure(&duration, &duration_text);
+               command_print(cmd_ctx, "wrote file %s to NAND flash %s at offset 0x%8.8x in %s",
+                       file.url, args[0], image_info.base_address, duration_text);
+               free(duration_text);
+       }
+       else
+       {
+               command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
+       }
+       
+       return ERROR_OK;
+}
+
+int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       nand_device_t *p;
+                       
+       if (argc < 4)
+       {
+               command_print(cmd_ctx, "usage: nand dump <num> <filename> <address> <size> [options]");
+               return ERROR_OK;
+       }
+       
+       p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
+       if (p)
+       {
+               if (p->device)
+               {
+                       fileio_t file;
+                       fileio_image_t image_info;
+                       duration_t duration;
+                       char *duration_text;
+                       int retval;
+                       
+                       u8 *page = NULL;
+                       u32 page_size = 0;
+                       u8 *oob = NULL;
+                       u32 oob_size = 0;
+                       u32 address = strtoul(args[2], NULL, 0);
+                       u32 size = strtoul(args[3], NULL, 0);
+                       u32 bytes_done = 0;
+                       enum oob_formats oob_format = NAND_OOB_NONE;
+                       
+                       if (argc > 4)
+                       {
+                               int i;
+                               for (i = 4; i < argc; i++)
+                               {
+                                       if (!strcmp(args[i], "oob_raw"))
+                                               oob_format |= NAND_OOB_RAW;
+                                       else if (!strcmp(args[i], "oob_only"))
+                                               oob_format |= NAND_OOB_RAW | NAND_OOB_ONLY;
+                                       else
+                                               command_print(cmd_ctx, "unknown option: '%s'", args[i]); 
+                               }
+                       }
+                       
+                       if ((address % p->page_size) || (size % p->page_size))
+                       {
+                               command_print(cmd_ctx, "only page size aligned addresses and sizes are supported");
+                               return ERROR_OK;
+                       }
+               
+                       if (!(oob_format & NAND_OOB_ONLY))
+                       {
+                               page_size = p->page_size;
+                               page = malloc(p->page_size);
+                       }
+
+                       if (oob_format & NAND_OOB_RAW)
+                       {
+                               if (p->page_size == 512)
+                                       oob_size = 16;
+                               else if (p->page_size == 2048)
+                                       oob_size = 64;
+                               oob = malloc(oob_size);
+                       }
+
+                       image_info.base_address = address;
+                       image_info.has_start_address = 0;
+                       
+                       if (fileio_open(&file, args[1], FILEIO_WRITE, 
+                               FILEIO_IMAGE, &image_info, FILEIO_PLAIN) != ERROR_OK)
+                       {
+                               command_print(cmd_ctx, "dump_image error: %s", file.error_str);
+                               return ERROR_OK;
+                       }
+       
+                       duration_start_measure(&duration);
+                       
+                       while (size > 0)
+                       {
+                               u32 size_written;
+                               if ((retval = nand_read_page(p, address / p->page_size, page, page_size, oob, oob_size)) != ERROR_OK)
+                               {
+                                       command_print(cmd_ctx, "reading NAND flash page failed");
+                                       return ERROR_OK;
+                               }
+                               
+                               if (page)
+                               {
+                                       fileio_write(&file, page_size, page, &size_written);
+                                       bytes_done += page_size;
+                               }
+                                       
+                               if (oob)
+                               {
+                                       fileio_write(&file, oob_size, oob, &size_written);
+                                       bytes_done += oob_size;
+                               }
+                                       
+                               size -= p->page_size;
+                               address += p->page_size;
+                       }
+                       
+                       if (page)
+                               free(page);
+                               
+                       if (oob)
+                               free(oob);
+                       
+                       fileio_close(&file);
+
+                       duration_stop_measure(&duration, &duration_text);
+                       command_print(cmd_ctx, "dumped %lli byte in %s", file.size, duration_text);
+                       free(duration_text);
+               }
+               else
+               {
+                       command_print(cmd_ctx, "#%i: not probed");
+               }
+       }
+       else
+       {
+               command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
+       }
+       
+       return ERROR_OK;
+}
+
+int handle_nand_raw_access_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       nand_device_t *p;
+               
+       if ((argc < 1) || (argc > 2))
+       {
+               command_print(cmd_ctx, "usage: nand raw_access <num> ['enable'|'disable']");
+               return ERROR_OK;
+       }
+       
+       p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
+       if (p)
+       {
+               if (p->device)
+               {
+                       if (argc == 2)
+                       {
+                               if (strcmp("enable", args[1]) == 0)
+                               {
+                                       p->use_raw = 1;
+                               }
+                               else if (strcmp("disable", args[1]) == 0)
+                               {
+                                       p->use_raw = 0;
+                               }
+                               else
+                               {
+                                       command_print(cmd_ctx, "usage: nand raw_access ['enable'|disable']");
+                               }
+                       }
+       
+                       command_print(cmd_ctx, "raw access is %s", (p->use_raw) ? "enabled" : "disabled");
+               }
+               else
+               {
+                       command_print(cmd_ctx, "#%i: not probed");
+               }
+       }
+       else
+       {
+               command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
+       }
+       
+       return ERROR_OK;
+}
+
diff --git a/src/flash/nand.h b/src/flash/nand.h
new file mode 100644 (file)
index 0000000..65f1589
--- /dev/null
@@ -0,0 +1,207 @@
+/***************************************************************************
+ *   Copyright (C) 2007 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   partially based on                                                    *
+ *      linux/include/linux/mtd/nand.h                                        *
+ *                                                                         *
+ *   Copyright (c) 2000 David Woodhouse <dwmw2@mvhi.com>                   *
+ *                      Steven J. Hill <sjhill@realitydiluted.com>         *
+ *                      Thomas Gleixner <tglx@linutronix.de>               *
+ *                                                                         *
+ *   This program 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 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program 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 this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#ifndef NAND_H
+#define NAND_H
+
+#include "flash.h"
+
+struct nand_device_s;
+
+typedef struct nand_flash_controller_s
+{
+       char *name;
+       int (*nand_device_command)(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
+       int (*register_commands)(struct command_context_s *cmd_ctx);
+       int (*init)(struct nand_device_s *device);
+       int (*reset)(struct nand_device_s *device);
+       int (*command)(struct nand_device_s *device, u8 command);
+       int (*address)(struct nand_device_s *device, u8 address);
+       int (*write_data)(struct nand_device_s *device, u16 data);
+       int (*read_data)(struct nand_device_s *device, void *data);
+       int (*write_page)(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
+       int (*read_page)(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
+       int (*controller_ready)(struct nand_device_s *device, int timeout);
+       int (*nand_ready)(struct nand_device_s *device, int timeout);
+} nand_flash_controller_t;
+
+typedef struct nand_block_s
+{
+       u32 offset;
+       u32 size;
+       int is_erased;
+       int is_bad;
+} nand_block_t;
+
+typedef struct nand_device_s
+{
+       nand_flash_controller_t *controller;
+       void *controller_priv;
+       struct nand_manufacturer_s *manufacturer;
+       struct nand_info_s *device;
+       int bus_width;
+       int address_cycles;
+       int page_size;
+       int erase_size;
+       int use_raw;
+       int num_blocks;
+       nand_block_t *blocks;
+       struct nand_device_s *next;
+} nand_device_t;
+
+/* NAND Flash Manufacturer ID Codes
+ */
+enum
+{
+       NAND_MFR_TOSHIBA = 0x98,
+       NAND_MFR_SAMSUNG = 0xec,
+       NAND_MFR_FUJITSU = 0x04,
+       NAND_MFR_NATIONAL = 0x8f,
+       NAND_MFR_RENESAS = 0x07,
+       NAND_MFR_STMICRO = 0x20,
+       NAND_MFR_HYNIX = 0xad,
+};
+
+typedef struct nand_manufacturer_s
+{
+    int id;
+       char *name;
+} nand_manufacturer_t;
+
+typedef struct nand_info_s
+{
+       char *name;
+       int id;
+       int page_size;
+       int chip_size;
+       int erase_size;
+       int options;
+} nand_info_t;
+
+/* Option constants for bizarre disfunctionality and real features
+ */
+enum { 
+       /* Chip can not auto increment pages */
+       NAND_NO_AUTOINCR = 0x00000001,
+       
+       /* Buswitdh is 16 bit */
+       NAND_BUSWIDTH_16 = 0x00000002,
+       
+       /* Device supports partial programming without padding */
+       NAND_NO_PADDING = 0x00000004,
+       
+       /* Chip has cache program function */
+       NAND_CACHEPRG = 0x00000008,
+       
+       /* Chip has copy back function */
+       NAND_COPYBACK = 0x00000010,
+       
+       /* AND Chip which has 4 banks and a confusing page / block
+        * assignment. See Renesas datasheet for further information */
+       NAND_IS_AND = 0x00000020,
+       
+       /* Chip has a array of 4 pages which can be read without
+        * additional ready /busy waits */
+       NAND_4PAGE_ARRAY = 0x00000040,
+       
+       /* Chip requires that BBT is periodically rewritten to prevent
+        * bits from adjacent blocks from 'leaking' in altering data.
+        * This happens with the Renesas AG-AND chips, possibly others.  */
+       BBT_AUTO_REFRESH = 0x00000080,
+       
+       /* Chip does not require ready check on read. True
+        * for all large page devices, as they do not support
+        * autoincrement.*/
+       NAND_NO_READRDY = 0x00000100,
+       
+       /* Options valid for Samsung large page devices */
+       NAND_SAMSUNG_LP_OPTIONS = (NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK),
+       
+       /* Options for new chips with large page size. The pagesize and the
+        * erasesize is determined from the extended id bytes
+        */
+       LP_OPTIONS = (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR),
+       LP_OPTIONS16 = (LP_OPTIONS | NAND_BUSWIDTH_16),
+};
+
+enum
+{
+       /* Standard NAND flash commands */
+       NAND_CMD_READ0 = 0x0,
+       NAND_CMD_READ1 = 0x1,
+       NAND_CMD_RNDOUT = 0x5,
+       NAND_CMD_PAGEPROG = 0x10,
+       NAND_CMD_READOOB = 0x50,
+       NAND_CMD_ERASE1 = 0x60,
+       NAND_CMD_STATUS = 0x70,
+       NAND_CMD_STATUS_MULTI = 0x71,
+       NAND_CMD_SEQIN = 0x80,
+       NAND_CMD_RNDIN = 0x85,
+       NAND_CMD_READID = 0x90,
+       NAND_CMD_ERASE2 = 0xd0,
+       NAND_CMD_RESET = 0xff,
+       
+       /* Extended commands for large page devices */
+       NAND_CMD_READSTART = 0x30,
+       NAND_CMD_RNDOUTSTART = 0xE0,
+       NAND_CMD_CACHEDPROG = 0x15,
+};
+
+/* Status bits */
+enum
+{
+       NAND_STATUS_FAIL = 0x01,
+       NAND_STATUS_FAIL_N1 = 0x02,
+       NAND_STATUS_TRUE_READY = 0x20,
+       NAND_STATUS_READY = 0x40,
+       NAND_STATUS_WP = 0x80,
+};
+
+/* OOB (spare) data formats */
+enum oob_formats
+{
+       NAND_OOB_NONE = 0x0,    /* no OOB data at all */
+       NAND_OOB_RAW = 0x1,             /* raw OOB data (16 bytes for 512b page sizes, 64 bytes for 2048b page sizes) */
+       NAND_OOB_ONLY = 0x2,    /* only OOB data */
+       NAND_OOB_SW_ECC = 0x10, /* when writing, use SW ECC (as opposed to no ECC) */ 
+       NAND_OOB_HW_ECC = 0x20, /* when writing, use HW ECC (as opposed to no ECC) */
+       NAND_OOB_JFFS2 = 0x100, /* when writing, use JFFS2 OOB layout */
+       NAND_OOB_YAFFS2 = 0x100,/* when writing, use YAFFS2 OOB layout */
+};
+
+/* Function prototypes */
+extern nand_device_t *get_nand_device_by_num(int num);
+extern int nand_read_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
+extern int nand_write_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
+
+#define                ERROR_NAND_DEVICE_INVALID               (-1100)
+#define                ERROR_NAND_OPERATION_FAILED             (-1101)
+#define                ERROR_NAND_OPERATION_TIMEOUT    (-1102)
+#define                ERROR_NAND_OPERATION_NOT_SUPPORTED      (-1103)
+#define                ERROR_NAND_DEVICE_NOT_PROBED    (-1104)
+#define                ERROR_NAND_ERROR_CORRECTION_FAILED      (-1105)
+
+#endif /* NAND_H */
index 5720b9d79a896969b8d44377bc2871b8345e7bf2..2214146cd5847af99bf5b8211aba46b6897ce6f0 100644 (file)
@@ -1,6 +1,7 @@
 INCLUDES = $(all_includes)
 METASOURCES = AUTO
 noinst_LIBRARIES = libhelper.a
-libhelper_a_SOURCES = binarybuffer.c configuration.c log.c interpreter.c command.c time_support.c replacements.c
+libhelper_a_SOURCES = binarybuffer.c configuration.c log.c interpreter.c command.c time_support.c \
+       replacements.c fileio.c
 noinst_HEADERS = binarybuffer.h configuration.h types.h log.h command.h \
-       interpreter.h time_support.h replacements.h
+       interpreter.h time_support.h replacements.h fileio.h
index 620c9c488e675dfdf2f46a0d30539197f00475c6..fffc53797c4a1a2babbf7515c71d4fb0efc39d28 100644 (file)
@@ -22,6 +22,7 @@
 #endif
 
 #include "time_support.h"
+#include "log.h"
 
 #include <sys/time.h>
 #include <time.h>
@@ -82,3 +83,26 @@ int timeval_add_time(struct timeval *result, int sec, int usec)
        return 0;
 }
 
+int duration_start_measure(duration_t *duration)
+{
+       gettimeofday(&duration->start, NULL);
+       
+       return ERROR_OK;
+}
+
+int duration_stop_measure(duration_t *duration, char **text)
+{
+       struct timeval end;
+       
+       gettimeofday(&end, NULL);
+       
+       timeval_subtract(&duration->duration, &end, &duration->start);
+       
+       if (text)
+       {
+               *text = malloc(16);
+               snprintf(*text, 16, "%is %ius", duration->duration.tv_sec, duration->duration.tv_usec);
+       }
+       
+       return ERROR_OK;
+}
index d8b7fe5ca6e95aae357f8d704037d15067f5f494..4e79d0d0b1e3f8a5ea6745a05d0ce33092a52ae2 100644 (file)
@@ -27,4 +27,13 @@ extern int timeval_subtract(struct timeval *result, struct timeval *x, struct ti
 extern int timeval_add(struct timeval *result, struct timeval *x, struct timeval *y);
 extern int timeval_add_time(struct timeval *result, int sec, int usec);
 
+typedef struct duration_s
+{
+       struct timeval start;
+       struct timeval duration;
+} duration_t;
+
+extern int duration_start_measure(duration_t *duration);
+extern int duration_stop_measure(duration_t *duration, char **text);
+
 #endif /* TIME_SUPPORT_H */
index 90f493963eb3aacabfe8f8ffff160722960fac11..69cb16a28d704a648e074da0e6eaa077360df5a5 100644 (file)
@@ -34,6 +34,10 @@ typedef unsigned short u16;
 typedef unsigned int u32;
 #endif
 
+#ifndef u64
+typedef unsigned long long u64;
+#endif
+
 #ifdef WORDS_BIGENDIAN /* big endian host */
 
 #define le_to_h_u32(x) (u32)(x[0] | x[1] << 8 | x[2] << 16 | x[3] << 24)
@@ -61,8 +65,8 @@ typedef unsigned int u32;
 #else /* little endian host */
 #define le_to_h_u32(x) (*(u32*)(x))
 #define le_to_h_u16(x) (*(u16*)(x))
-#define be_to_h_u32(x) (u32)(x[3] | x[2] << 8 | x[1] << 16 | x[0] << 24)
-#define be_to_h_u16(x) (u16)(x[1] | x[0] << 8)
+#define be_to_h_u32(x) (u32)((x)[3] | (x)[2] << 8 | (x)[1] << 16 | (x)[0] << 24)
+#define be_to_h_u16(x) (u16)((x)[1] | (x)[0] << 8)
 
 #define h_u32_to_le(buf, val) do { *(u32*)(buf) = (val); } while (0)
 #define h_u16_to_le(buf, val) do { *(u16*)(buf) = (val); } while (0)
index 218ac4c61e3b049ce7452d4cf37357bd92db4057..8211fee3a75303b43e672242844ef660e6771824 100644 (file)
@@ -288,13 +288,17 @@ void gw16012_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
        enum tap_state saved_end_state = end_state;
        u8 scan_out, scan_in;
 
-       if (ir_scan)
-               gw16012_end_state(TAP_SI);
-       else
-               gw16012_end_state(TAP_SD);
+       /* only if we're not already in the correct Shift state */
+       if (!((!ir_scan && (cur_state == TAP_SD)) || (ir_scan && (cur_state == TAP_SI))))
+       {
+               if (ir_scan)
+                       gw16012_end_state(TAP_SI);
+               else
+                       gw16012_end_state(TAP_SD);
 
-       gw16012_state_move();
-       gw16012_end_state(saved_end_state);
+               gw16012_state_move();
+               gw16012_end_state(saved_end_state);
+       }
 
        while (type == SCAN_OUT && ((bits_left - 1) > 7))
        {
@@ -309,6 +313,9 @@ void gw16012_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
        while (bits_left-- > 0)
        {
                u8 tms = 0;
+               
+               scan_out = buf_get_u32(buffer, bit_count, 1);
+               
                if (bits_left == 0) /* last bit */
                {
                        if ((ir_scan && (end_state == TAP_SI))
@@ -321,14 +328,15 @@ void gw16012_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
                                tms = 2;
                        }
                }
-               
-               scan_out = buf_get_u32(buffer, bit_count, 1);
+
                gw16012_data(scan_out | tms);
+
                if (type != SCAN_OUT)
                {
                        gw16012_input(&scan_in);
                        buf_set_u32(buffer, bit_count, 1, ((scan_in & 0x08) >> 3));
-               }
+               }               
+
                bit_count++;
        }
 
@@ -530,6 +538,13 @@ int gw16012_init(void)
                return ERROR_JTAG_INIT_FAILED;
        }
        DEBUG("...privileges granted");
+
+       /* make sure parallel port is in right mode (clear tristate and interrupt */
+#ifdef __FreeBSD__
+       outb(gw16012_port + 2, 0x0);
+#else
+       outb(0x0, gw16012_port + 2);
+#endif
 #endif /* PARPORT_USE_PPDEV */
        
        gw16012_input(&status_port);
index a3e8cff8dba11eb9703b0995979e7d69935dfc15..b8d963b1c5a5fc03ec66df38e87983f44f6bf9dc 100644 (file)
@@ -1143,6 +1143,7 @@ void jtag_sleep(u32 us)
  */
 int jtag_examine_chain()
 {
+       jtag_device_t *device = jtag_devices;
        scan_field_t field;
        u8 idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
        int i;
@@ -1204,6 +1205,11 @@ int jtag_examine_chain()
                                break;
                        }
                        
+                       if (device)
+                       {
+                               device->idcode = idcode;
+                               device = device->next;
+                       }
                        device_count++;
                        
                        manufacturer = (idcode & 0xffe) >> 1;
index ad038ae5f03f98ee6a44a086632e87bc65172a67..29e3da6085176c513a3c79c1253b0187158493a2 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "command.h"
 
-#if 1
+#if 0
 #define _DEBUG_JTAG_IO_
 #endif
 
index 83006d866e9040e46018de8b699e3b7abfd035df..6386940e8c581d326f7f62c4af57b94d152655b5 100644 (file)
@@ -94,6 +94,7 @@ cable_t cables[] =
 {      
        /* name                                 tdo   trst  tms   tck   tdi   srst  o_inv i_inv init */
        { "wiggler",                    0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80 },
+       { "wiggler_ntrst_inverted",     0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x11, 0x80, 0x80 },
        { "old_amt_wiggler",    0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x11, 0x80, 0x80 },
        { "chameleon",                  0x80, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00 },
        { "dlc5",                               0x10, 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x10 },
@@ -390,7 +391,7 @@ int parport_init(void)
        #ifdef __FreeBSD__
                outb(parport_port + 2, 0x0);
        #else
-               outb(0x0, dataport);
+               outb(0x0, parport_port + 2);
        #endif
        
 #endif /* PARPORT_USE_PPDEV */
index f10c1a98c97bb7d488a74d975a682ed4097b32ef..123db3c8e44cafc62b3c673040f7669a6fa8a6cd 100644 (file)
@@ -18,7 +18,7 @@
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
-#define OPENOCD_VERSION "Open On-Chip Debugger (2007-01-31 12:00 CET)"
+#define OPENOCD_VERSION "Open On-Chip Debugger (2007-03-15 14:30 CET)"
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -75,6 +75,7 @@ int main(int argc, char *argv[])
        xsvf_register_commands(cmd_ctx);
        target_register_commands(cmd_ctx);
        flash_register_commands(cmd_ctx);
+       nand_register_commands(cmd_ctx);
        pld_register_commands(cmd_ctx);
        
        if (log_init(cmd_ctx) != ERROR_OK)
@@ -109,6 +110,10 @@ int main(int argc, char *argv[])
                return EXIT_FAILURE;
        DEBUG("flash init complete");
 
+       if (nand_init(cmd_ctx) != ERROR_OK)
+               return EXIT_FAILURE;
+       DEBUG("NAND init complete");
+
        if (pld_init(cmd_ctx) != ERROR_OK)
                return EXIT_FAILURE;
        DEBUG("pld init complete");
index 8e74dedab29711b40cdcea892d2f5891e73b7808..a3ef8dea8b85dea94f46410604bf6434261ac464 100644 (file)
@@ -54,6 +54,7 @@ int handle_arm7_9_force_hw_bkpts_command(struct command_context_s *cmd_ctx, char
 int handle_arm7_9_dbgrq_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 int handle_arm7_9_fast_memory_access_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 int handle_arm7_9_dcc_downloads_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_arm7_9_etm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 
 int arm7_9_reinit_embeddedice(target_t *target)
 {
@@ -2049,6 +2050,8 @@ int arm7_9_register_commands(struct command_context_s *cmd_ctx)
        command_t *arm7_9_cmd;
        
        arm7_9_cmd = register_command(cmd_ctx, NULL, "arm7_9", NULL, COMMAND_ANY, "arm7/9 specific commands");
+
+       register_command(cmd_ctx, arm7_9_cmd, "etm", handle_arm7_9_etm_command, COMMAND_CONFIG, NULL);
        
        register_command(cmd_ctx, arm7_9_cmd, "write_xpsr", handle_arm7_9_write_xpsr_command, COMMAND_EXEC, "write program status register <value> <not cpsr|spsr>");
        register_command(cmd_ctx, arm7_9_cmd, "write_xpsr_im8", handle_arm7_9_write_xpsr_im8_command, COMMAND_EXEC, "write program status register <8bit immediate> <rotate> <not cpsr|spsr>");
@@ -2376,6 +2379,37 @@ int handle_arm7_9_dcc_downloads_command(struct command_context_s *cmd_ctx, char
        return ERROR_OK;
 }
 
+int handle_arm7_9_etm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target;
+       armv4_5_common_t *armv4_5;
+       arm7_9_common_t *arm7_9;
+       
+       if (argc != 1)
+       {
+               ERROR("incomplete 'arm7_9 etm <target>' command");
+               exit(-1);
+       }
+       
+       target = get_target_by_num(strtoul(args[0], NULL, 0));
+       
+       if (!target)
+       {
+               ERROR("target number '%s' not defined", args[0]);
+               exit(-1);
+       }
+       
+       if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+               return ERROR_OK;
+       }
+       
+       arm7_9->has_etm = 1;
+       
+       return ERROR_OK;
+}
+
 int arm7_9_init_arch_info(target_t *target, arm7_9_common_t *arm7_9)
 {
        armv4_5_common_t *armv4_5 = &arm7_9->armv4_5_common;
index 5d925e219d5bc9fe36692020ef7cbac52b5fd8d5..a87b8a4a118c91f5f44894d1bf46262fcb06509a 100644 (file)
@@ -736,8 +736,6 @@ void arm7tdmi_build_reg_cache(target_t *target)
        armv4_5_common_t *armv4_5 = target->arch_info;
        arm7_9_common_t *arm7_9 = armv4_5->arch_info;
        arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-       arm7tdmi_common_t *arch_info = arm7_9->arch_info;
-
 
        (*cache_p) = armv4_5_build_reg_cache(target, armv4_5);
        armv4_5->core_cache = (*cache_p);
@@ -771,7 +769,6 @@ int arm7tdmi_init_arch_info(target_t *target, arm7tdmi_common_t *arm7tdmi, int c
 {
        armv4_5_common_t *armv4_5;
        arm7_9_common_t *arm7_9;
-       int has_etm = 0;
        
        arm7_9 = &arm7tdmi->arm7_9_common;
        armv4_5 = &arm7_9->armv4_5_common;
index ef978956de2b543f93e846da2b10888191f37b53..434b5c9931dae5d590a9e1d2d92a3e9d7596c2f4 100644 (file)
@@ -28,6 +28,7 @@
 #include "target.h"
 #include "armv4_5.h"
 #include "embeddedice.h"
+#include "etm.h"
 #include "log.h"
 #include "jtag.h"
 #include "arm_jtag.h"
@@ -824,9 +825,6 @@ void arm9tdmi_build_reg_cache(target_t *target)
        armv4_5_common_t *armv4_5 = target->arch_info;
        arm7_9_common_t *arm7_9 = armv4_5->arch_info;
        arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-       arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
-
-       embeddedice_reg_t *vec_catch_arch_info;
 
        (*cache_p) = armv4_5_build_reg_cache(target, armv4_5);
        armv4_5->core_cache = (*cache_p);
@@ -835,17 +833,11 @@ void arm9tdmi_build_reg_cache(target_t *target)
        (*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9);
        arm7_9->eice_cache = (*cache_p)->next;
 
-#if 0  
-       (*cache_p)->next->reg_list[EICE_VEC_CATCH].name = "vector catch";
-       (*cache_p)->next->reg_list[EICE_VEC_CATCH].dirty = 0;
-       (*cache_p)->next->reg_list[EICE_VEC_CATCH].valid = 0;
-       (*cache_p)->next->reg_list[EICE_VEC_CATCH].bitfield_desc = NULL;
-       (*cache_p)->next->reg_list[EICE_VEC_CATCH].num_bitfields = 0;
-       (*cache_p)->next->reg_list[EICE_VEC_CATCH].size = 8;
-       (*cache_p)->next->reg_list[EICE_VEC_CATCH].value = calloc(1, 4);
-       vec_catch_arch_info = (*cache_p)->next->reg_list[EICE_VEC_CATCH].arch_info;
-       vec_catch_arch_info->addr = 0x2;
-#endif
+       if (arm7_9->has_etm)
+       {
+               (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, 0);
+               arm7_9->etm_cache = (*cache_p)->next->next;
+       }
 }
 
 int arm9tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
index 200a5390a8eb766f81edc78371b3e00e04cb7cb4..b7e14b615f0f11a1c53859d1de2560dcdfb32053 100644 (file)
@@ -171,6 +171,12 @@ reg_cache_t* embeddedice_build_reg_cache(target_t *target, arm7_9_common_t *arm7
                        reg_list[EICE_DBG_STAT].size = 10;
                        arm7_9->has_monitor_mode = 1;
                        break;
+               case 7:
+                       WARNING("EmbeddedICE version 7 detected, EmbeddedICE handling might be broken");
+                       reg_list[EICE_DBG_CTRL].size = 6;
+                       reg_list[EICE_DBG_STAT].size = 5;
+                       arm7_9->has_monitor_mode = 1;
+                       break;
                default:
                        ERROR("unknown EmbeddedICE version (comms ctrl: 0x%4.4x)", buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 0, 32));
        }
index e2e0530f7e37aee4e6ad2e2d2db6ae54c2830107..4020564230f0b349c56616fa534377b66148c688 100644 (file)
@@ -42,6 +42,8 @@
 
 #include <time_support.h>
 
+#include <fileio.h>
+
 int cli_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv);
 
 int handle_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
@@ -62,8 +64,8 @@ int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, char **a
 int handle_step_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 int handle_md_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_load_binary_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_dump_binary_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 int handle_bp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 int handle_rbp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 int handle_wp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
@@ -732,6 +734,8 @@ void target_read_u32(struct target_s *target, u32 address, u32 *value)
        target->type->read_memory(target, address, 4, 1, value_buf);
        
        *value = target_buffer_get_u32(target, value_buf);
+
+       DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, *value);
 }
 
 void target_read_u16(struct target_s *target, u32 address, u16 *value)
@@ -741,17 +745,23 @@ void target_read_u16(struct target_s *target, u32 address, u16 *value)
        target->type->read_memory(target, address, 2, 1, value_buf);
        
        *value = target_buffer_get_u16(target, value_buf);
+
+       DEBUG("address: 0x%8.8x, value: 0x%4.4x", address, *value);
 }
 
 void target_read_u8(struct target_s *target, u32 address, u8 *value)
 {
        target->type->read_memory(target, address, 1, 1, value);
+
+       DEBUG("address: 0x%8.8x, value: 0x%2.2x", address, *value);
 }
 
 void target_write_u32(struct target_s *target, u32 address, u32 value)
 {
        u8 value_buf[4];
 
+       DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, value);
+
        target_buffer_set_u32(target, value_buf, value);        
        target->type->write_memory(target, address, 4, 1, value_buf);
 }
@@ -760,12 +770,16 @@ void target_write_u16(struct target_s *target, u32 address, u16 value)
 {
        u8 value_buf[2];
        
+       DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, value);
+
        target_buffer_set_u16(target, value_buf, value);        
        target->type->write_memory(target, address, 2, 1, value_buf);
 }
 
 void target_write_u8(struct target_s *target, u32 address, u8 value)
 {
+       DEBUG("address: 0x%8.8x, value: 0x%2.2x", address, value);
+
        target->type->read_memory(target, address, 1, 1, &value);
 }
 
@@ -773,7 +787,7 @@ int target_register_user_commands(struct command_context_s *cmd_ctx)
 {
        register_command(cmd_ctx,  NULL, "reg", handle_reg_command, COMMAND_EXEC, NULL);
        register_command(cmd_ctx,  NULL, "poll", handle_poll_command, COMMAND_EXEC, "poll target state");
-       register_command(cmd_ctx,  NULL, "wait_halt", handle_wait_halt_command, COMMAND_EXEC, "wait for target halt");
+       register_command(cmd_ctx,  NULL, "wait_halt", handle_wait_halt_command, COMMAND_EXEC, "wait for target halt [time (s)]");
        register_command(cmd_ctx,  NULL, "halt", handle_halt_command, COMMAND_EXEC, "halt target");
        register_command(cmd_ctx,  NULL, "resume", handle_resume_command, COMMAND_EXEC, "resume target [addr]");
        register_command(cmd_ctx,  NULL, "step", handle_step_command, COMMAND_EXEC, "step one instruction");
@@ -793,8 +807,10 @@ int target_register_user_commands(struct command_context_s *cmd_ctx)
        register_command(cmd_ctx,  NULL, "wp", handle_wp_command, COMMAND_EXEC, "set watchpoint <address> <length> <r/w/a> [value] [mask]");    
        register_command(cmd_ctx,  NULL, "rwp", handle_rwp_command, COMMAND_EXEC, "remove watchpoint <adress>");
        
-       register_command(cmd_ctx,  NULL, "load_binary", handle_load_binary_command, COMMAND_EXEC, "load binary <file> <address>");
-       register_command(cmd_ctx,  NULL, "dump_binary", handle_dump_binary_command, COMMAND_EXEC, "dump binary <file> <address> <size>");
+       register_command(cmd_ctx,  NULL, "load_image", handle_load_image_command, COMMAND_EXEC, "load_image <file> <address> ['bin'|'ihex']");
+       register_command(cmd_ctx,  NULL, "dump_image", handle_dump_image_command, COMMAND_EXEC, "dump_image <file> <address> <size>");
+       register_command(cmd_ctx,  NULL, "load_binary", handle_load_image_command, COMMAND_EXEC, "[DEPRECATED] load_binary <file> <address>");
+       register_command(cmd_ctx,  NULL, "dump_binary", handle_dump_image_command, COMMAND_EXEC, "[DEPRECATED] dump_binary <file> <address> <size>");
        
        return ERROR_OK;
 }
@@ -1223,7 +1239,17 @@ int handle_wait_halt_command(struct command_context_s *cmd_ctx, char *cmd, char
        struct timeval timeout, now;
        
        gettimeofday(&timeout, NULL);
-       timeval_add_time(&timeout, 5, 0);
+       if (!argc)
+               timeval_add_time(&timeout, 5, 0);
+       else {
+               char *end;
+
+               timeval_add_time(&timeout, strtoul(args[0], &end, 0), 0);
+               if (*end) {
+                       command_print(cmd_ctx, "usage: wait_halt [seconds]");
+                       return ERROR_OK;
+               }
+       }
 
        command_print(cmd_ctx, "waiting for target halted...");
 
@@ -1560,118 +1586,126 @@ int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char **args,
 
 }
 
-int handle_load_binary_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
-       FILE *binary;
        u32 address;
-       struct stat binary_stat;
-       u32 binary_size;
-
        u8 *buffer;
        u32 buf_cnt;
+       u32 binary_size;
+       
+       fileio_t file;
+       enum fileio_pri_type pri_type = FILEIO_IMAGE;
+       fileio_image_t image_info;
+       enum fileio_sec_type sec_type;
+       
+       duration_t duration;
+       char *duration_text;
        
-       struct timeval start, end, duration;
-               
        target_t *target = get_current_target(cmd_ctx);
 
-       if (argc != 2)
+       if (argc < 2)
        {
-               command_print(cmd_ctx, "usage: load_binary <filename> <address>");
+               command_print(cmd_ctx, "usage: load_image <filename> <address> [type]");
                return ERROR_OK;
        }
+       
+       memset(&file, 0, sizeof(fileio_t));
+       fileio_identify_image_type(&sec_type, (argc == 3) ? args[2] : NULL);
 
-       address = strtoul(args[1], NULL, 0);
-
-       if (stat(args[0], &binary_stat) == -1)
-       {
-               ERROR("couldn't stat() %s: %s", args[0], strerror(errno));
-               command_print(cmd_ctx, "error accessing file %s", args[0]);
-               return ERROR_OK;
-       }
+       image_info.base_address = strtoul(args[1], NULL, 0);
+       image_info.has_start_address = 0;
+       
+       buffer = malloc(128 * 1024);
 
-       if (!(binary = fopen(args[0], "rb")))
+       duration_start_measure(&duration);
+       
+       if (fileio_open(&file, args[0], FILEIO_READ, 
+               pri_type, &image_info, sec_type) != ERROR_OK)
        {
-               ERROR("couldn't open %s: %s", args[0], strerror(errno));
-               command_print(cmd_ctx, "error accessing file %s", args[0]);
+               command_print(cmd_ctx, "load_image error: %s", file.error_str);
                return ERROR_OK;
        }
        
-       buffer = malloc(128 * 1024);
-
-       gettimeofday(&start, NULL);     
-
-       binary_size = binary_stat.st_size;
-       while (binary_size > 0)
+       binary_size = file.size;
+       address = image_info.base_address;
+       while ((binary_size > 0) &&
+               (fileio_read(&file, 128 * 1024, buffer, &buf_cnt) == ERROR_OK))
        {
-               buf_cnt = fread(buffer, 1, 128*1024, binary);
                target_write_buffer(target, address, buf_cnt, buffer);
                address += buf_cnt;
                binary_size -= buf_cnt;
        }
 
-       gettimeofday(&end, NULL);       
-
        free(buffer);
        
-       timeval_subtract(&duration, &end, &start);
-       command_print(cmd_ctx, "downloaded %lli byte in %is %ius", (long long) binary_stat.st_size, duration.tv_sec, duration.tv_usec);
+       duration_stop_measure(&duration, &duration_text);
+       command_print(cmd_ctx, "downloaded %lli byte in %s", file.size, duration_text);
+       free(duration_text);
        
-       fclose(binary);
+       fileio_close(&file);
 
        return ERROR_OK;
 
 }
 
-int handle_dump_binary_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
-       FILE *binary;
+       fileio_t file;
+       fileio_image_t image_info;
+       
        u32 address;
        u32 size;
        u8 buffer[560];
        
-       struct timeval start, end, duration;
+       duration_t duration;
+       char *duration_text;
        
        target_t *target = get_current_target(cmd_ctx);
 
        if (argc != 3)
        {
-               command_print(cmd_ctx, "usage: dump_binary <filename> <address> <size>");
+               command_print(cmd_ctx, "usage: dump_image <filename> <address> <size>");
                return ERROR_OK;
        }
 
        address = strtoul(args[1], NULL, 0);
        size = strtoul(args[2], NULL, 0);
 
-       if (!(binary = fopen(args[0], "wb")))
+       if ((address & 3) || (size & 3))
        {
-               ERROR("couldn't open %s for writing: %s", args[0], strerror(errno));
-               command_print(cmd_ctx, "error accessing file %s", args[0]);
+               command_print(cmd_ctx, "only 32-bit aligned address and size are supported");
                return ERROR_OK;
        }
-
-       if ((address & 3) || (size & 3))
+       
+       image_info.base_address = address;
+       image_info.has_start_address = 0;
+       
+       if (fileio_open(&file, args[0], FILEIO_WRITE, 
+               FILEIO_IMAGE, &image_info, FILEIO_PLAIN) != ERROR_OK)
        {
-               command_print(cmd_ctx, "only 32-bit aligned address and size are supported");
+               command_print(cmd_ctx, "dump_image error: %s", file.error_str);
                return ERROR_OK;
        }
-
-       gettimeofday(&start, NULL);     
+       
+       duration_start_measure(&duration);
        
        while (size > 0)
        {
+               u32 size_written;
                u32 this_run_size = (size > 560) ? 560 : size;
+               
                target->type->read_memory(target, address, 4, this_run_size / 4, buffer);
-               fwrite(buffer, 1, this_run_size, binary);
+               fileio_write(&file, this_run_size, buffer, &size_written);
+               
                size -= this_run_size;
                address += this_run_size;
        }
 
-       fclose(binary);
-
-       gettimeofday(&end, NULL);       
+       fileio_close(&file);
 
-       timeval_subtract(&duration, &end, &start);
-       command_print(cmd_ctx, "dumped %i byte in %is %ius", strtoul(args[2], NULL, 0), duration.tv_sec, duration.tv_usec);
+       duration_stop_measure(&duration, &duration_text);
+       command_print(cmd_ctx, "dumped %lli byte in %s", file.size, duration_text);
+       free(duration_text);
        
        return ERROR_OK;
 

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)