From 04fb21b28d7f79557dce4d52f3ea22dd654af836 Mon Sep 17 00:00:00 2001 From: ntfreak Date: Thu, 16 Oct 2008 21:02:44 +0000 Subject: - update docs deprecated section to include links to new commands (if any) - added missing svn props git-svn-id: svn://svn.berlios.de/openocd/trunk@1077 b42882b7-edfa-0310-969c-e2dbd0fdcd60 --- doc/openocd.texi | 27 +- src/flash/mflash.c | 1752 ++++++++++++++++++++++++++-------------------------- src/flash/mflash.h | 490 +++++++-------- 3 files changed, 1138 insertions(+), 1131 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 8c8be259..35a8ca16 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -275,6 +275,7 @@ and get the output from the TCL engine. first target will be gdb_port, the second target will listen on gdb_port + 1, and so on. @item @b{gdb_breakpoint_override} <@var{hard|soft|disabled}> @cindex gdb_breakpoint_override +@anchor{gdb_breakpoint_override} @*Force breakpoint type for gdb 'break' commands. The raison d'etre for this option is to support GDB GUI's without a hard/soft breakpoint concept where the default OpenOCD and @@ -724,7 +725,7 @@ Use the standard str9 driver for programming. @item @b{mflash bank} <@var{soc}> <@var{base}> <@var{chip_width}> <@var{bus_width}> <@var{RST pin}> <@var{WP pin}> <@var{DPD pin}> <@var{target #}> @cindex mflash bank -Configures a mflash for <@var{soc}> host bank at <@var{base}>. <@var{chip_width}> and +@*Configures a mflash for <@var{soc}> host bank at <@var{base}>. <@var{chip_width}> and <@var{bus_width}> are bytes order. Pin number format is dependent on host GPIO calling convention. If WP or DPD pin was not used, write -1. Currently, mflash bank support s3c2440 and pxa270. @end itemize @@ -904,9 +905,11 @@ These commands allow accesses of a specific size to the memory system: @item @b{load_image} <@var{file}> <@var{address}> [@option{bin}|@option{ihex}|@option{elf}] @cindex load_image +@anchor{load_image} @*Load image <@var{file}> to target memory at <@var{address}> @item @b{dump_image} <@var{file}> <@var{address}> <@var{size}> @cindex dump_image +@anchor{dump_image} @*Dump <@var{size}> bytes of target memory starting at <@var{address}> to a (binary) <@var{file}>. @item @b{verify_image} <@var{file}> <@var{address}> [@option{bin}|@option{ihex}|@option{elf}] @@ -940,6 +943,7 @@ updated information. @option{flash erase_sector} using the same syntax. @item @b{flash erase_sector} <@var{num}> <@var{first}> <@var{last}> @cindex flash erase_sector +@anchor{flash erase_sector} @*Erase sectors at bank <@var{num}>, starting at sector <@var{first}> up to and including <@var{last}>. Sector numbering starts at 0. Depending on the flash type, erasing may require the protection to be disabled first (e.g. Intel Advanced Bootblock flash using @@ -949,10 +953,12 @@ the CFI driver). @*Erase sectors starting at <@var{address}> for <@var{length}> bytes @item @b{flash write_bank} <@var{num}> <@var{file}> <@var{offset}> @cindex flash write_bank +@anchor{flash write_bank} @*Write the binary <@var{file}> to flash bank <@var{num}>, starting at <@option{offset}> bytes from the beginning of the bank. @item @b{flash write_image} [@var{erase}] <@var{file}> [@var{offset}] [@var{type}] @cindex flash write_image +@anchor{flash write_image} @*Write the image <@var{file}> to the current target's flash bank(s). A relocation [@var{offset}] can be specified and the file [@var{type}] can be specified explicitly as @option{bin} (binary), @option{ihex} (Intel hex), @option{elf} @@ -1569,6 +1575,7 @@ ARM920t or ARM926EJ-S. safe for all but ARM7TDMI--S cores (like Philips LPC). @item @b{arm7_9 fast_memory_access} <@var{enable}|@var{disable}> @cindex arm7_9 fast_memory_access +@anchor{arm7_9 fast_memory_access} @*Allow OpenOCD to read and write memory without checking completion of the operation. This provides a huge speed increase, especially with USB JTAG cables (FT2232), but might be unsafe if used with targets running at a very low @@ -1820,7 +1827,7 @@ working area. Informing gdb of the memory map of the target will enable gdb to protect any flash area of the target and use hardware breakpoints by default. This means that the OpenOCD option @option{gdb_breakpoint_override} is not required when -using a memory map. +using a memory map. @xref{gdb_breakpoint_override} To view the configured memory map in gdb, use the gdb command @option{info mem} All other unasigned addresses within gdb are treated as RAM. @@ -1936,29 +1943,29 @@ Certain OpenOCD commands have been deprecated/removed during the various revisio @itemize @bullet @item @b{load_binary} @cindex load_binary -@*use @option{load_image} command with same args +@*use @option{load_image} command with same args. @xref{load_image} @item @b{target} @cindex target @*@option{target} no longer take the reset_init, reset_run, run_and_halt, run_and_init. The @option{reset} command always does a @option{reset run} when passed no arguments. @item @b{dump_binary} @cindex dump_binary -@*use @option{dump_image} command with same args +@*use @option{dump_image} command with same args. @xref{dump_image} @item @b{flash erase} @cindex flash erase -@*use @option{flash erase_sector} command with same args +@*use @option{flash erase_sector} command with same args. @xref{flash erase_sector} @item @b{flash write} @cindex flash write -@*use @option{flash write_bank} command with same args +@*use @option{flash write_bank} command with same args. @xref{flash write_bank} @item @b{flash write_binary} @cindex flash write_binary @*use @option{flash write_bank} command with same args @item @b{arm7_9 fast_writes} @cindex arm7_9 fast_writes -@*use @option{arm7_9 fast_memory_access} command with same args +@*use @option{arm7_9 fast_memory_access} command with same args. @xref{arm7_9 fast_memory_access} @item @b{flash auto_erase} @cindex flash auto_erase -@*use @option{flash write_image} command passing @option{erase} as the first parameter. +@*use @option{flash write_image} command passing @option{erase} as the first parameter. @xref{flash write_image} @item @b{daemon_startup} @cindex daemon_startup @*this config option has been removed, simply adding @option{init} and @option{reset halt} to @@ -1966,12 +1973,12 @@ the end of your config script will give the same behaviour as using @option{daem and @option{target cortex_m3 little reset_halt 0}. @item @b{arm7_9 sw_bkpts} @cindex arm7_9 sw_bkpts -@*On by default. See also @option{gdb_breakpoint_override}. +@*On by default. See also @option{gdb_breakpoint_override}. @xref{gdb_breakpoint_override} @item @b{arm7_9 force_hw_bkpts} @cindex arm7_9 force_hw_bkpts @*Use @option{gdb_breakpoint_override} instead. Note that GDB will use hardware breakpoints for flash if the gdb memory map has been set up(default when flash is declared in -target configuration). +target configuration). @xref{gdb_breakpoint_override} @item @b{run_and_halt_time} @cindex run_and_halt_time @*This command has been removed for simpler reset behaviour, it can be simulated with the diff --git a/src/flash/mflash.c b/src/flash/mflash.c index 52c6a9fe..9bc94adf 100644 --- a/src/flash/mflash.c +++ b/src/flash/mflash.c @@ -1,876 +1,876 @@ -/*************************************************************************** - * Copyright (C) 2007-2008 by unsik Kim * - * * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include "command.h" -#include "log.h" -#include "target.h" -#include "time_support.h" -#include "fileio.h" -#include "mflash.h" - -static int s3c2440_set_gpio_to_output (mflash_gpio_num_t gpio); -static int s3c2440_set_gpio_output_val (mflash_gpio_num_t gpio, u8 val); -static int pxa270_set_gpio_to_output (mflash_gpio_num_t gpio); -static int pxa270_set_gpio_output_val (mflash_gpio_num_t gpio, u8 val); - -static command_t *mflash_cmd; - -static mflash_bank_t *mflash_bank; - -static mflash_gpio_drv_t pxa270_gpio = { - .name = "pxa270", - .set_gpio_to_output = pxa270_set_gpio_to_output, - .set_gpio_output_val = pxa270_set_gpio_output_val -}; - -static mflash_gpio_drv_t s3c2440_gpio = { - .name = "s3c2440", - .set_gpio_to_output = s3c2440_set_gpio_to_output, - .set_gpio_output_val = s3c2440_set_gpio_output_val -}; - -static mflash_gpio_drv_t *mflash_gpio[] = -{ - &pxa270_gpio, - &s3c2440_gpio, - NULL -}; - -#define PXA270_GAFR0_L 0x40E00054 -#define PXA270_GAFR3_U 0x40E00070 -#define PXA270_GAFR3_U_RESERVED_BITS 0xfffc0000u -#define PXA270_GPDR0 0x40E0000C -#define PXA270_GPDR3 0x40E0010C -#define PXA270_GPDR3_RESERVED_BITS 0xfe000000u -#define PXA270_GPSR0 0x40E00018 -#define PXA270_GPCR0 0x40E00024 - -static int pxa270_set_gpio_to_output (mflash_gpio_num_t gpio) -{ - u32 addr, value, mask; - target_t *target = mflash_bank->target; - int ret; - - // remove alternate function. - mask = 0x3u << (gpio.num & 0xF)*2; - - addr = PXA270_GAFR0_L + (gpio.num >> 4) * 4; - - if ((ret = target_read_u32(target, addr, &value)) != ERROR_OK) - return ret; - - value &= ~mask; - if (addr == PXA270_GAFR3_U) - value &= ~PXA270_GAFR3_U_RESERVED_BITS; - - if ((ret = target_write_u32(target, addr, value)) != ERROR_OK) - return ret; - - // set direction to output - mask = 0x1u << (gpio.num & 0x1F); - - addr = PXA270_GPDR0 + (gpio.num >> 5) * 4; - - if ((ret = target_read_u32(target, addr, &value)) != ERROR_OK) - return ret; - - value |= mask; - if (addr == PXA270_GPDR3) - value &= ~PXA270_GPDR3_RESERVED_BITS; - - ret = target_write_u32(target, addr, value); - return ret; -} - -static int pxa270_set_gpio_output_val (mflash_gpio_num_t gpio, u8 val) -{ - u32 addr, value, mask; - target_t *target = mflash_bank->target; - int ret; - - mask = 0x1u << (gpio.num & 0x1F); - - if (val) { - addr = PXA270_GPSR0 + (gpio.num >> 5) * 4; - } else { - addr = PXA270_GPCR0 + (gpio.num >> 5) * 4; - } - - if ((ret = target_read_u32(target, addr, &value)) != ERROR_OK) - return ret; - - value |= mask; - - ret = target_write_u32(target, addr, value); - - return ret; -} - -#define S3C2440_GPACON 0x56000000 -#define S3C2440_GPADAT 0x56000004 -#define S3C2440_GPJCON 0x560000d0 -#define S3C2440_GPJDAT 0x560000d4 - -static int s3c2440_set_gpio_to_output (mflash_gpio_num_t gpio) -{ - u32 data, mask, gpio_con; - target_t *target = mflash_bank->target; - int ret; - - if (gpio.port[0] >= 'a' && gpio.port[0] <= 'h') { - gpio_con = S3C2440_GPACON + (gpio.port[0] - 'a') * 0x10; - } else if (gpio.port[0] == 'j') { - gpio_con = S3C2440_GPJCON; - } else { - LOG_ERROR("invalid port %d%s", gpio.num, gpio.port); - return ERROR_INVALID_ARGUMENTS; - } - - ret = target_read_u32(target, gpio_con, &data); - - if (ret == ERROR_OK) { - if (gpio.port[0] == 'a') { - mask = 1 << gpio.num; - data &= ~mask; - } else { - mask = 3 << gpio.num * 2; - data &= ~mask; - data |= (1 << gpio.num * 2); - } - - ret = target_write_u32(target, gpio_con, data); - } - return ret; -} - -static int s3c2440_set_gpio_output_val (mflash_gpio_num_t gpio, u8 val) -{ - u32 data, mask, gpio_dat; - target_t *target = mflash_bank->target; - int ret; - - if (gpio.port[0] >= 'a' && gpio.port[0] <= 'h') { - gpio_dat = S3C2440_GPADAT + (gpio.port[0] - 'a') * 0x10; - } else if (gpio.port[0] == 'j') { - gpio_dat = S3C2440_GPJDAT; - } else { - LOG_ERROR("invalid port %d%s", gpio.num, gpio.port); - return ERROR_INVALID_ARGUMENTS; - } - - ret = target_read_u32(target, gpio_dat, &data); - - if (ret == ERROR_OK) { - mask = 1 << gpio.num; - if (val) - data |= mask; - else - data &= ~mask; - - ret = target_write_u32(target, gpio_dat, data); - } - return ret; -} - -static int mflash_rst(u8 level) -{ - return mflash_bank->gpio_drv->set_gpio_output_val(mflash_bank->rst_pin, level); -} - -static int mg_dump_task_reg (void) -{ - target_t *target = mflash_bank->target; - u32 address = mflash_bank->base + MG_REG_OFFSET + MG_REG_ERROR; - u8 value, i; - char *reg_name[9] = { - "error ", - "sector count ", - "sector num (LBA 7- 0) ", - "cyl. low (LBA 15- 8) ", - "cyl. high (LBA 23-16) ", - "drv/head ", - "status ", - "dev control ", - "burst control " - }; - - for (i = 0; i < 9; i++) { - target_read_u8(target, address + i * 2, &value); - LOG_INFO("%s : 0x%2.2x", reg_name[i], value); - } - - return ERROR_OK; - -} -static int mflash_init_gpio (void) -{ - mflash_gpio_drv_t *gpio_drv = mflash_bank->gpio_drv; - - gpio_drv->set_gpio_to_output(mflash_bank->rst_pin); - gpio_drv->set_gpio_output_val(mflash_bank->rst_pin, 1); - - if (mflash_bank->wp_pin.num != -1) { - gpio_drv->set_gpio_to_output(mflash_bank->wp_pin); - gpio_drv->set_gpio_output_val(mflash_bank->wp_pin, 1); - } - - if (mflash_bank->dpd_pin.num != -1) { - gpio_drv->set_gpio_to_output(mflash_bank->dpd_pin); - gpio_drv->set_gpio_output_val(mflash_bank->dpd_pin, 1); - } - - return ERROR_OK; -} - -static int mg_dsk_wait(mg_io_type_wait wait, u32 time) -{ - u8 status, error; - target_t *target = mflash_bank->target; - u32 mg_task_reg = mflash_bank->base + MG_REG_OFFSET; - duration_t duration; - long long t=0; - - duration_start_measure(&duration); - - while (time) { - - target_read_u8(target, mg_task_reg + MG_REG_STATUS, &status); - - if (status & mg_io_rbit_status_busy) - { - if (wait == mg_io_wait_bsy) - return ERROR_OK; - } else { - switch(wait) - { - case mg_io_wait_not_bsy: - return ERROR_OK; - case mg_io_wait_rdy_noerr: - if (status & mg_io_rbit_status_ready) - return ERROR_OK; - break; - case mg_io_wait_drq_noerr: - if (status & mg_io_rbit_status_data_req) - return ERROR_OK; - break; - default: - break; - } - - // Now we check the error condition! - if (status & mg_io_rbit_status_error) - { - target_read_u8(target, mg_task_reg + MG_REG_ERROR, &error); - - if (error & mg_io_rbit_err_bad_sect_num) { - LOG_ERROR("sector not found"); - return ERROR_FAIL; - } - else if (error & (mg_io_rbit_err_bad_block | mg_io_rbit_err_uncorrectable)) { - LOG_ERROR("bad block"); - return ERROR_FAIL; - } else { - LOG_ERROR("disk operation fail"); - return ERROR_FAIL; - } - } - - switch (wait) - { - case mg_io_wait_rdy: - if (status & mg_io_rbit_status_ready) - return ERROR_OK; - - case mg_io_wait_drq: - if (status & mg_io_rbit_status_data_req) - return ERROR_OK; - - default: - break; - } - } - - duration_stop_measure(&duration, NULL); - - t=duration.duration.tv_usec/1000; - t+=duration.duration.tv_sec*1000; - - if (t > time) - break; - } - - LOG_ERROR("timeout occured"); - return ERROR_FAIL; -} - -static int mg_dsk_srst(u8 on) -{ - target_t *target = mflash_bank->target; - u32 mg_task_reg = mflash_bank->base + MG_REG_OFFSET; - u8 value; - int ret; - - if ((ret = target_read_u8(target, mg_task_reg + MG_REG_DRV_CTRL, &value)) != ERROR_OK) - return ret; - - if(on) { - value |= (mg_io_rbit_devc_srst); - } else { - value &= ~mg_io_rbit_devc_srst; - } - - ret = target_write_u8(target, mg_task_reg + MG_REG_DRV_CTRL, value); - return ret; -} - -static int mg_dsk_io_cmd(u32 sect_num, u32 cnt, u8 cmd) -{ - target_t *target = mflash_bank->target; - u32 mg_task_reg = mflash_bank->base + MG_REG_OFFSET; - u8 value; - - if (mg_dsk_wait(mg_io_wait_rdy_noerr, MG_OEM_DISK_WAIT_TIME_NORMAL) != ERROR_OK) - return ERROR_FAIL; - - value = mg_io_rval_dev_drv_master | mg_io_rval_dev_lba_mode |((sect_num >> 24) & 0xf); - - target_write_u8(target, mg_task_reg + MG_REG_DRV_HEAD, value); - target_write_u8(target, mg_task_reg + MG_REG_SECT_CNT, (u8)cnt); - target_write_u8(target, mg_task_reg + MG_REG_SECT_NUM, (u8)sect_num); - target_write_u8(target, mg_task_reg + MG_REG_CYL_LOW, (u8)(sect_num >> 8)); - target_write_u8(target, mg_task_reg + MG_REG_CYL_HIGH, (u8)(sect_num >> 16)); - - target_write_u8(target, mg_task_reg + MG_REG_COMMAND, cmd); - - return ERROR_OK; -} - -static int mg_dsk_drv_info(void) -{ - target_t *target = mflash_bank->target; - u32 mg_buff = mflash_bank->base + MG_BUFFER_OFFSET; - - if ( mg_dsk_io_cmd(0, 1, mg_io_cmd_identify) != ERROR_OK) - return ERROR_FAIL; - - if ( mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL) != ERROR_OK) - return ERROR_FAIL; - - LOG_INFO("read drive info."); - - if (! mflash_bank->drv_info) - mflash_bank->drv_info = malloc(sizeof(mg_drv_info_t)); - - target->type->read_memory(target, mg_buff, 2, sizeof(mg_io_type_drv_info) >> 1, - (u8 *)&mflash_bank->drv_info->drv_id); - - mflash_bank->drv_info->tot_sects = (u32)(mflash_bank->drv_info->drv_id.total_user_addressable_sectors_hi << 16) - + mflash_bank->drv_info->drv_id.total_user_addressable_sectors_lo; - - target_write_u8(target, mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND, mg_io_cmd_confirm_read); - - return ERROR_OK; -} - -static int mg_mflash_probe(void) -{ - mflash_bank->proved = 0; - - mflash_init_gpio(); - - LOG_INFO("reset mflash"); - - mflash_rst(0); - - if (mg_dsk_wait(mg_io_wait_bsy, MG_OEM_DISK_WAIT_TIME_LONG) != ERROR_OK) - return ERROR_FAIL; - - mflash_rst(1); - - if (mg_dsk_wait(mg_io_wait_not_bsy, MG_OEM_DISK_WAIT_TIME_LONG) != ERROR_OK) - return ERROR_FAIL; - - mg_dsk_srst(1); - - if (mg_dsk_wait(mg_io_wait_bsy, MG_OEM_DISK_WAIT_TIME_LONG) != ERROR_OK) - return ERROR_FAIL; - - mg_dsk_srst(0); - - if (mg_dsk_wait(mg_io_wait_not_bsy, MG_OEM_DISK_WAIT_TIME_LONG) != ERROR_OK) - return ERROR_FAIL; - - if (mg_dsk_drv_info() != ERROR_OK) - return ERROR_FAIL; - - mflash_bank->proved = 1; - - return ERROR_OK; -} - -static int mflash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int ret; - - ret = mg_mflash_probe(); - - if (ret == ERROR_OK) { - command_print(cmd_ctx, "mflash (total %u sectors) found at 0x%8.8x", - mflash_bank->drv_info->tot_sects, mflash_bank->base ); - } - - return ret; -} - -static int mg_mflash_do_read_sects(void *buff, u32 sect_num, u32 sect_cnt) -{ - u32 i, address; - int ret; - target_t *target = mflash_bank->target; - u8 *buff_ptr = buff; - duration_t duration; - - if ( mg_dsk_io_cmd(sect_num, sect_cnt, mg_io_cmd_read) != ERROR_OK ) - return ERROR_FAIL; - - address = mflash_bank->base + MG_BUFFER_OFFSET; - - duration_start_measure(&duration); - - for (i = 0; i < sect_cnt; i++) { - mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL); - - target->type->read_memory(target, address, 2, MG_MFLASH_SECTOR_SIZE / 2, buff_ptr); - buff_ptr += MG_MFLASH_SECTOR_SIZE; - - target_write_u8(target, mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND, mg_io_cmd_confirm_read); - - LOG_DEBUG("%u (0x%8.8x) sector read", sect_num + i, (sect_num + i) * MG_MFLASH_SECTOR_SIZE); - - duration_stop_measure(&duration, NULL); - - if ((duration.duration.tv_sec * 1000 + duration.duration.tv_usec / 1000) > 3000) { - LOG_INFO("read %u'th sectors", sect_num + i); - duration_start_measure(&duration); - } - } - - ret = mg_dsk_wait(mg_io_wait_rdy, MG_OEM_DISK_WAIT_TIME_NORMAL); - - return ret; -} - -static int mg_mflash_read_sects(void *buff, u32 sect_num, u32 sect_cnt) -{ - u32 quotient, residue, i; - u8 *buff_ptr = buff; - - quotient = sect_cnt >> 8; - residue = sect_cnt % 256; - - for (i = 0; i < quotient; i++) { - LOG_DEBUG("sect num : %u buff : 0x%8.8x", sect_num, (u32)buff_ptr); - mg_mflash_do_read_sects(buff_ptr, sect_num, 256); - sect_num += 256; - buff_ptr += 256 * MG_MFLASH_SECTOR_SIZE; - } - - if (residue) { - LOG_DEBUG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr); - mg_mflash_do_read_sects(buff_ptr, sect_num, residue); - } - - return ERROR_OK; -} - -static int mg_mflash_do_write_sects(void *buff, u32 sect_num, u32 sect_cnt) -{ - u32 i, address; - int ret; - target_t *target = mflash_bank->target; - u8 *buff_ptr = buff; - duration_t duration; - - if ( mg_dsk_io_cmd(sect_num, sect_cnt, mg_io_cmd_write) != ERROR_OK ) { - LOG_ERROR("mg_io_cmd_write fail"); - return ERROR_FAIL; - } - - address = mflash_bank->base + MG_BUFFER_OFFSET; - - duration_start_measure(&duration); - - for (i = 0; i < sect_cnt; i++) { - ret = mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL); - if (ret != ERROR_OK) - LOG_ERROR("mg_io_wait_drq time out"); - - ret = target->type->write_memory(target, address, 2, MG_MFLASH_SECTOR_SIZE / 2, buff_ptr); - if (ret != ERROR_OK) - LOG_ERROR("mem write error"); - buff_ptr += MG_MFLASH_SECTOR_SIZE; - - ret = target_write_u8(target, mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND, mg_io_cmd_confirm_write); - if (ret != ERROR_OK) - LOG_ERROR("mg_io_cmd_confirm_write error"); - - LOG_DEBUG("%u (0x%8.8x) sector write", sect_num + i, (sect_num + i) * MG_MFLASH_SECTOR_SIZE); - - duration_stop_measure(&duration, NULL); - - if ((duration.duration.tv_sec * 1000 + duration.duration.tv_usec / 1000) > 3000) { - LOG_INFO("wrote %u'th sectors", sect_num + i); - duration_start_measure(&duration); - } - } - - ret = mg_dsk_wait(mg_io_wait_rdy, MG_OEM_DISK_WAIT_TIME_NORMAL); - - return ret; -} - -static int mg_mflash_write_sects(void *buff, u32 sect_num, u32 sect_cnt) -{ - u32 quotient, residue, i; - u8 *buff_ptr = buff; - - quotient = sect_cnt >> 8; - residue = sect_cnt % 256; - - for (i = 0; i < quotient; i++) { - LOG_DEBUG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr); - mg_mflash_do_write_sects(buff_ptr, sect_num, 256); - sect_num += 256; - buff_ptr += 256 * MG_MFLASH_SECTOR_SIZE; - } - - if (residue) { - LOG_DEBUG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr); - mg_mflash_do_write_sects(buff_ptr, sect_num, residue); - } - - return ERROR_OK; -} - -static int mg_mflash_read (u32 addr, u8 *buff, u32 len) -{ - u8 *sect_buff, *buff_ptr = buff; - u32 cur_addr, next_sec_addr, end_addr, cnt, sect_num; - - cnt = 0; - cur_addr = addr; - end_addr = addr + len; - - sect_buff = malloc(MG_MFLASH_SECTOR_SIZE); - - if (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK) { - - next_sec_addr = (cur_addr + MG_MFLASH_SECTOR_SIZE) & ~MG_MFLASH_SECTOR_SIZE_MASK; - sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT; - mg_mflash_read_sects(sect_buff, sect_num, 1); - - if (end_addr < next_sec_addr) { - memcpy(buff_ptr, sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), end_addr - cur_addr); - LOG_DEBUG("copies %u byte from sector offset 0x%8.8x", end_addr - cur_addr, cur_addr); - cur_addr = end_addr; - } else { - memcpy(buff_ptr, sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), next_sec_addr - cur_addr); - LOG_DEBUG("copies %u byte from sector offset 0x%8.8x", next_sec_addr - cur_addr, cur_addr); - buff_ptr += (next_sec_addr - cur_addr); - cur_addr = next_sec_addr; - } - } - - if (cur_addr < end_addr) { - - sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT; - next_sec_addr = cur_addr + MG_MFLASH_SECTOR_SIZE; - - while (next_sec_addr <= end_addr) { - cnt++; - next_sec_addr += MG_MFLASH_SECTOR_SIZE; - } - - if (cnt) - mg_mflash_read_sects(buff_ptr, sect_num, cnt); - - buff_ptr += cnt * MG_MFLASH_SECTOR_SIZE; - cur_addr += cnt * MG_MFLASH_SECTOR_SIZE; - - if (cur_addr < end_addr) { - - sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT; - mg_mflash_read_sects(sect_buff, sect_num, 1); - memcpy(buff_ptr, sect_buff, end_addr - cur_addr); - LOG_DEBUG("copies %u byte", end_addr - cur_addr); - - } - - } - - free(sect_buff); - - return ERROR_OK; -} - -static int mg_mflash_write(u32 addr, u8 *buff, u32 len) -{ - u8 *sect_buff, *buff_ptr = buff; - u32 cur_addr, next_sec_addr, end_addr, cnt, sect_num; - - cnt = 0; - cur_addr = addr; - end_addr = addr + len; - - sect_buff = malloc(MG_MFLASH_SECTOR_SIZE); - - if (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK) { - - next_sec_addr = (cur_addr + MG_MFLASH_SECTOR_SIZE) & ~MG_MFLASH_SECTOR_SIZE_MASK; - sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT; - mg_mflash_read_sects(sect_buff, sect_num, 1); - - if (end_addr < next_sec_addr) { - memcpy(sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), buff_ptr, end_addr - cur_addr); - LOG_DEBUG("copies %u byte to sector offset 0x%8.8x", end_addr - cur_addr, cur_addr); - cur_addr = end_addr; - } else { - memcpy(sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), buff_ptr, next_sec_addr - cur_addr); - LOG_DEBUG("copies %u byte to sector offset 0x%8.8x", next_sec_addr - cur_addr, cur_addr); - buff_ptr += (next_sec_addr - cur_addr); - cur_addr = next_sec_addr; - } - - mg_mflash_write_sects(sect_buff, sect_num, 1); - - } - - if (cur_addr < end_addr) { - - sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT; - next_sec_addr = cur_addr + MG_MFLASH_SECTOR_SIZE; - - while (next_sec_addr <= end_addr) { - cnt++; - next_sec_addr += MG_MFLASH_SECTOR_SIZE; - } - - if (cnt) - mg_mflash_write_sects(buff_ptr, sect_num, cnt); - - buff_ptr += cnt * MG_MFLASH_SECTOR_SIZE; - cur_addr += cnt * MG_MFLASH_SECTOR_SIZE; - - if (cur_addr < end_addr) { - - sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT; - mg_mflash_read_sects(sect_buff, sect_num, 1); - memcpy(sect_buff, buff_ptr, end_addr - cur_addr); - LOG_DEBUG("copies %u byte", end_addr - cur_addr); - mg_mflash_write_sects(sect_buff, sect_num, 1); - - } - - } - - free(sect_buff); - - return ERROR_OK; -} - -static int mflash_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - u32 address, buf_cnt; - u8 *buffer; - // TODO : multi-bank support, large file support - fileio_t fileio; - duration_t duration; - char *duration_text; - int ret; - - if (argc != 3) { - return ERROR_COMMAND_SYNTAX_ERROR; - } - - address = strtoul(args[2], NULL, 0); - - if (! mflash_bank->proved ) { - mg_mflash_probe(); - } - - - if (fileio_open(&fileio, args[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK) { - return ERROR_FAIL; - } - - buffer = malloc(fileio.size); - - if (fileio_read(&fileio, fileio.size, buffer, &buf_cnt) != ERROR_OK) - { - free(buffer); - fileio_close(&fileio); - return ERROR_FAIL; - } - - duration_start_measure(&duration); - - ret = mg_mflash_write(address, buffer, (u32)fileio.size); - - duration_stop_measure(&duration, &duration_text); - - command_print(cmd_ctx, "wrote %lli byte from file %s in %s (%f kB/s)", - fileio.size, args[1], duration_text, - (float)fileio.size / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0))); - - free(duration_text); - - fileio_close(&fileio); - - free(buffer); - - return ERROR_OK; -} - -static int mflash_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - u32 address, size_written, size; - u8 *buffer; - // TODO : multi-bank support - fileio_t fileio; - duration_t duration; - char *duration_text; - - if (argc != 4) { - return ERROR_COMMAND_SYNTAX_ERROR; - } - - address = strtoul(args[2], NULL, 0); - size = strtoul(args[3], NULL, 0); - - if (! mflash_bank->proved ) { - mg_mflash_probe(); - } - - if (fileio_open(&fileio, args[1], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) { - return ERROR_FAIL; - } - - buffer = malloc(size); - - duration_start_measure(&duration); - - mg_mflash_read(address, buffer, size); - - duration_stop_measure(&duration, &duration_text); - - fileio_write(&fileio, size, buffer, &size_written); - - command_print(cmd_ctx, "dump image (address 0x%8.8x size %u) to file %s in %s (%f kB/s)", - address, size, args[1], duration_text, - (float)size / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0))); - - free(duration_text); - - fileio_close(&fileio); - - free(buffer); - - return ERROR_OK; -} - -int mflash_init_drivers(struct command_context_s *cmd_ctx) -{ - if (mflash_bank) { - register_command(cmd_ctx, mflash_cmd, "probe", mflash_probe_command, COMMAND_EXEC, NULL); - register_command(cmd_ctx, mflash_cmd, "write", mflash_write_command, COMMAND_EXEC, - "mflash write
"); - register_command(cmd_ctx, mflash_cmd, "dump", mflash_dump_command, COMMAND_EXEC, - "mflash dump
"); - } - - return ERROR_OK; -} - -static int mflash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - char *str; - int i; - - if (argc < 8) - { - return ERROR_COMMAND_SYNTAX_ERROR; - } - - if ((target = get_target_by_num(strtoul(args[7], NULL, 0))) == NULL) - { - LOG_ERROR("target %lu not defined", strtoul(args[7], NULL, 0)); - return ERROR_FAIL; - } - - mflash_bank = calloc(sizeof(mflash_bank_t), 1); - mflash_bank->base = strtoul(args[1], NULL, 0); - mflash_bank->chip_width = strtoul(args[2], NULL, 0); - mflash_bank->bus_width = strtoul(args[3], NULL, 0); - mflash_bank->rst_pin.num = strtoul(args[4], &str, 0); - if (*str) - mflash_bank->rst_pin.port[0] = (u16)tolower(str[0]); - mflash_bank->wp_pin.num = strtol(args[5], &str, 0); - if (*str) - mflash_bank->wp_pin.port[0] = (u16)tolower(str[0]); - mflash_bank->dpd_pin.num = strtol(args[6], &str, 0); - if (*str) - mflash_bank->dpd_pin.port[0] = (u16)tolower(str[0]); - - mflash_bank->target = target; - - for (i = 0; mflash_gpio[i] ; i++) { - if (! strcmp(mflash_gpio[i]->name, args[0])) { - mflash_bank->gpio_drv = mflash_gpio[i]; - } - } - - if (! mflash_bank->gpio_drv) { - LOG_ERROR("%s is unsupported soc", args[0]); - return ERROR_INVALID_ARGUMENTS; - } - - return ERROR_OK; -} - -int mflash_register_commands(struct command_context_s *cmd_ctx) -{ - mflash_cmd = register_command(cmd_ctx, NULL, "mflash", NULL, COMMAND_ANY, NULL); - register_command(cmd_ctx, mflash_cmd, "bank", mflash_bank_command, COMMAND_CONFIG, - "mflash bank "); - return ERROR_OK; -} +/*************************************************************************** + * Copyright (C) 2007-2008 by unsik Kim * + * * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "command.h" +#include "log.h" +#include "target.h" +#include "time_support.h" +#include "fileio.h" +#include "mflash.h" + +static int s3c2440_set_gpio_to_output (mflash_gpio_num_t gpio); +static int s3c2440_set_gpio_output_val (mflash_gpio_num_t gpio, u8 val); +static int pxa270_set_gpio_to_output (mflash_gpio_num_t gpio); +static int pxa270_set_gpio_output_val (mflash_gpio_num_t gpio, u8 val); + +static command_t *mflash_cmd; + +static mflash_bank_t *mflash_bank; + +static mflash_gpio_drv_t pxa270_gpio = { + .name = "pxa270", + .set_gpio_to_output = pxa270_set_gpio_to_output, + .set_gpio_output_val = pxa270_set_gpio_output_val +}; + +static mflash_gpio_drv_t s3c2440_gpio = { + .name = "s3c2440", + .set_gpio_to_output = s3c2440_set_gpio_to_output, + .set_gpio_output_val = s3c2440_set_gpio_output_val +}; + +static mflash_gpio_drv_t *mflash_gpio[] = +{ + &pxa270_gpio, + &s3c2440_gpio, + NULL +}; + +#define PXA270_GAFR0_L 0x40E00054 +#define PXA270_GAFR3_U 0x40E00070 +#define PXA270_GAFR3_U_RESERVED_BITS 0xfffc0000u +#define PXA270_GPDR0 0x40E0000C +#define PXA270_GPDR3 0x40E0010C +#define PXA270_GPDR3_RESERVED_BITS 0xfe000000u +#define PXA270_GPSR0 0x40E00018 +#define PXA270_GPCR0 0x40E00024 + +static int pxa270_set_gpio_to_output (mflash_gpio_num_t gpio) +{ + u32 addr, value, mask; + target_t *target = mflash_bank->target; + int ret; + + // remove alternate function. + mask = 0x3u << (gpio.num & 0xF)*2; + + addr = PXA270_GAFR0_L + (gpio.num >> 4) * 4; + + if ((ret = target_read_u32(target, addr, &value)) != ERROR_OK) + return ret; + + value &= ~mask; + if (addr == PXA270_GAFR3_U) + value &= ~PXA270_GAFR3_U_RESERVED_BITS; + + if ((ret = target_write_u32(target, addr, value)) != ERROR_OK) + return ret; + + // set direction to output + mask = 0x1u << (gpio.num & 0x1F); + + addr = PXA270_GPDR0 + (gpio.num >> 5) * 4; + + if ((ret = target_read_u32(target, addr, &value)) != ERROR_OK) + return ret; + + value |= mask; + if (addr == PXA270_GPDR3) + value &= ~PXA270_GPDR3_RESERVED_BITS; + + ret = target_write_u32(target, addr, value); + return ret; +} + +static int pxa270_set_gpio_output_val (mflash_gpio_num_t gpio, u8 val) +{ + u32 addr, value, mask; + target_t *target = mflash_bank->target; + int ret; + + mask = 0x1u << (gpio.num & 0x1F); + + if (val) { + addr = PXA270_GPSR0 + (gpio.num >> 5) * 4; + } else { + addr = PXA270_GPCR0 + (gpio.num >> 5) * 4; + } + + if ((ret = target_read_u32(target, addr, &value)) != ERROR_OK) + return ret; + + value |= mask; + + ret = target_write_u32(target, addr, value); + + return ret; +} + +#define S3C2440_GPACON 0x56000000 +#define S3C2440_GPADAT 0x56000004 +#define S3C2440_GPJCON 0x560000d0 +#define S3C2440_GPJDAT 0x560000d4 + +static int s3c2440_set_gpio_to_output (mflash_gpio_num_t gpio) +{ + u32 data, mask, gpio_con; + target_t *target = mflash_bank->target; + int ret; + + if (gpio.port[0] >= 'a' && gpio.port[0] <= 'h') { + gpio_con = S3C2440_GPACON + (gpio.port[0] - 'a') * 0x10; + } else if (gpio.port[0] == 'j') { + gpio_con = S3C2440_GPJCON; + } else { + LOG_ERROR("invalid port %d%s", gpio.num, gpio.port); + return ERROR_INVALID_ARGUMENTS; + } + + ret = target_read_u32(target, gpio_con, &data); + + if (ret == ERROR_OK) { + if (gpio.port[0] == 'a') { + mask = 1 << gpio.num; + data &= ~mask; + } else { + mask = 3 << gpio.num * 2; + data &= ~mask; + data |= (1 << gpio.num * 2); + } + + ret = target_write_u32(target, gpio_con, data); + } + return ret; +} + +static int s3c2440_set_gpio_output_val (mflash_gpio_num_t gpio, u8 val) +{ + u32 data, mask, gpio_dat; + target_t *target = mflash_bank->target; + int ret; + + if (gpio.port[0] >= 'a' && gpio.port[0] <= 'h') { + gpio_dat = S3C2440_GPADAT + (gpio.port[0] - 'a') * 0x10; + } else if (gpio.port[0] == 'j') { + gpio_dat = S3C2440_GPJDAT; + } else { + LOG_ERROR("invalid port %d%s", gpio.num, gpio.port); + return ERROR_INVALID_ARGUMENTS; + } + + ret = target_read_u32(target, gpio_dat, &data); + + if (ret == ERROR_OK) { + mask = 1 << gpio.num; + if (val) + data |= mask; + else + data &= ~mask; + + ret = target_write_u32(target, gpio_dat, data); + } + return ret; +} + +static int mflash_rst(u8 level) +{ + return mflash_bank->gpio_drv->set_gpio_output_val(mflash_bank->rst_pin, level); +} + +static int mg_dump_task_reg (void) +{ + target_t *target = mflash_bank->target; + u32 address = mflash_bank->base + MG_REG_OFFSET + MG_REG_ERROR; + u8 value, i; + char *reg_name[9] = { + "error ", + "sector count ", + "sector num (LBA 7- 0) ", + "cyl. low (LBA 15- 8) ", + "cyl. high (LBA 23-16) ", + "drv/head ", + "status ", + "dev control ", + "burst control " + }; + + for (i = 0; i < 9; i++) { + target_read_u8(target, address + i * 2, &value); + LOG_INFO("%s : 0x%2.2x", reg_name[i], value); + } + + return ERROR_OK; + +} +static int mflash_init_gpio (void) +{ + mflash_gpio_drv_t *gpio_drv = mflash_bank->gpio_drv; + + gpio_drv->set_gpio_to_output(mflash_bank->rst_pin); + gpio_drv->set_gpio_output_val(mflash_bank->rst_pin, 1); + + if (mflash_bank->wp_pin.num != -1) { + gpio_drv->set_gpio_to_output(mflash_bank->wp_pin); + gpio_drv->set_gpio_output_val(mflash_bank->wp_pin, 1); + } + + if (mflash_bank->dpd_pin.num != -1) { + gpio_drv->set_gpio_to_output(mflash_bank->dpd_pin); + gpio_drv->set_gpio_output_val(mflash_bank->dpd_pin, 1); + } + + return ERROR_OK; +} + +static int mg_dsk_wait(mg_io_type_wait wait, u32 time) +{ + u8 status, error; + target_t *target = mflash_bank->target; + u32 mg_task_reg = mflash_bank->base + MG_REG_OFFSET; + duration_t duration; + long long t=0; + + duration_start_measure(&duration); + + while (time) { + + target_read_u8(target, mg_task_reg + MG_REG_STATUS, &status); + + if (status & mg_io_rbit_status_busy) + { + if (wait == mg_io_wait_bsy) + return ERROR_OK; + } else { + switch(wait) + { + case mg_io_wait_not_bsy: + return ERROR_OK; + case mg_io_wait_rdy_noerr: + if (status & mg_io_rbit_status_ready) + return ERROR_OK; + break; + case mg_io_wait_drq_noerr: + if (status & mg_io_rbit_status_data_req) + return ERROR_OK; + break; + default: + break; + } + + // Now we check the error condition! + if (status & mg_io_rbit_status_error) + { + target_read_u8(target, mg_task_reg + MG_REG_ERROR, &error); + + if (error & mg_io_rbit_err_bad_sect_num) { + LOG_ERROR("sector not found"); + return ERROR_FAIL; + } + else if (error & (mg_io_rbit_err_bad_block | mg_io_rbit_err_uncorrectable)) { + LOG_ERROR("bad block"); + return ERROR_FAIL; + } else { + LOG_ERROR("disk operation fail"); + return ERROR_FAIL; + } + } + + switch (wait) + { + case mg_io_wait_rdy: + if (status & mg_io_rbit_status_ready) + return ERROR_OK; + + case mg_io_wait_drq: + if (status & mg_io_rbit_status_data_req) + return ERROR_OK; + + default: + break; + } + } + + duration_stop_measure(&duration, NULL); + + t=duration.duration.tv_usec/1000; + t+=duration.duration.tv_sec*1000; + + if (t > time) + break; + } + + LOG_ERROR("timeout occured"); + return ERROR_FAIL; +} + +static int mg_dsk_srst(u8 on) +{ + target_t *target = mflash_bank->target; + u32 mg_task_reg = mflash_bank->base + MG_REG_OFFSET; + u8 value; + int ret; + + if ((ret = target_read_u8(target, mg_task_reg + MG_REG_DRV_CTRL, &value)) != ERROR_OK) + return ret; + + if(on) { + value |= (mg_io_rbit_devc_srst); + } else { + value &= ~mg_io_rbit_devc_srst; + } + + ret = target_write_u8(target, mg_task_reg + MG_REG_DRV_CTRL, value); + return ret; +} + +static int mg_dsk_io_cmd(u32 sect_num, u32 cnt, u8 cmd) +{ + target_t *target = mflash_bank->target; + u32 mg_task_reg = mflash_bank->base + MG_REG_OFFSET; + u8 value; + + if (mg_dsk_wait(mg_io_wait_rdy_noerr, MG_OEM_DISK_WAIT_TIME_NORMAL) != ERROR_OK) + return ERROR_FAIL; + + value = mg_io_rval_dev_drv_master | mg_io_rval_dev_lba_mode |((sect_num >> 24) & 0xf); + + target_write_u8(target, mg_task_reg + MG_REG_DRV_HEAD, value); + target_write_u8(target, mg_task_reg + MG_REG_SECT_CNT, (u8)cnt); + target_write_u8(target, mg_task_reg + MG_REG_SECT_NUM, (u8)sect_num); + target_write_u8(target, mg_task_reg + MG_REG_CYL_LOW, (u8)(sect_num >> 8)); + target_write_u8(target, mg_task_reg + MG_REG_CYL_HIGH, (u8)(sect_num >> 16)); + + target_write_u8(target, mg_task_reg + MG_REG_COMMAND, cmd); + + return ERROR_OK; +} + +static int mg_dsk_drv_info(void) +{ + target_t *target = mflash_bank->target; + u32 mg_buff = mflash_bank->base + MG_BUFFER_OFFSET; + + if ( mg_dsk_io_cmd(0, 1, mg_io_cmd_identify) != ERROR_OK) + return ERROR_FAIL; + + if ( mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL) != ERROR_OK) + return ERROR_FAIL; + + LOG_INFO("read drive info."); + + if (! mflash_bank->drv_info) + mflash_bank->drv_info = malloc(sizeof(mg_drv_info_t)); + + target->type->read_memory(target, mg_buff, 2, sizeof(mg_io_type_drv_info) >> 1, + (u8 *)&mflash_bank->drv_info->drv_id); + + mflash_bank->drv_info->tot_sects = (u32)(mflash_bank->drv_info->drv_id.total_user_addressable_sectors_hi << 16) + + mflash_bank->drv_info->drv_id.total_user_addressable_sectors_lo; + + target_write_u8(target, mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND, mg_io_cmd_confirm_read); + + return ERROR_OK; +} + +static int mg_mflash_probe(void) +{ + mflash_bank->proved = 0; + + mflash_init_gpio(); + + LOG_INFO("reset mflash"); + + mflash_rst(0); + + if (mg_dsk_wait(mg_io_wait_bsy, MG_OEM_DISK_WAIT_TIME_LONG) != ERROR_OK) + return ERROR_FAIL; + + mflash_rst(1); + + if (mg_dsk_wait(mg_io_wait_not_bsy, MG_OEM_DISK_WAIT_TIME_LONG) != ERROR_OK) + return ERROR_FAIL; + + mg_dsk_srst(1); + + if (mg_dsk_wait(mg_io_wait_bsy, MG_OEM_DISK_WAIT_TIME_LONG) != ERROR_OK) + return ERROR_FAIL; + + mg_dsk_srst(0); + + if (mg_dsk_wait(mg_io_wait_not_bsy, MG_OEM_DISK_WAIT_TIME_LONG) != ERROR_OK) + return ERROR_FAIL; + + if (mg_dsk_drv_info() != ERROR_OK) + return ERROR_FAIL; + + mflash_bank->proved = 1; + + return ERROR_OK; +} + +static int mflash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int ret; + + ret = mg_mflash_probe(); + + if (ret == ERROR_OK) { + command_print(cmd_ctx, "mflash (total %u sectors) found at 0x%8.8x", + mflash_bank->drv_info->tot_sects, mflash_bank->base ); + } + + return ret; +} + +static int mg_mflash_do_read_sects(void *buff, u32 sect_num, u32 sect_cnt) +{ + u32 i, address; + int ret; + target_t *target = mflash_bank->target; + u8 *buff_ptr = buff; + duration_t duration; + + if ( mg_dsk_io_cmd(sect_num, sect_cnt, mg_io_cmd_read) != ERROR_OK ) + return ERROR_FAIL; + + address = mflash_bank->base + MG_BUFFER_OFFSET; + + duration_start_measure(&duration); + + for (i = 0; i < sect_cnt; i++) { + mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL); + + target->type->read_memory(target, address, 2, MG_MFLASH_SECTOR_SIZE / 2, buff_ptr); + buff_ptr += MG_MFLASH_SECTOR_SIZE; + + target_write_u8(target, mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND, mg_io_cmd_confirm_read); + + LOG_DEBUG("%u (0x%8.8x) sector read", sect_num + i, (sect_num + i) * MG_MFLASH_SECTOR_SIZE); + + duration_stop_measure(&duration, NULL); + + if ((duration.duration.tv_sec * 1000 + duration.duration.tv_usec / 1000) > 3000) { + LOG_INFO("read %u'th sectors", sect_num + i); + duration_start_measure(&duration); + } + } + + ret = mg_dsk_wait(mg_io_wait_rdy, MG_OEM_DISK_WAIT_TIME_NORMAL); + + return ret; +} + +static int mg_mflash_read_sects(void *buff, u32 sect_num, u32 sect_cnt) +{ + u32 quotient, residue, i; + u8 *buff_ptr = buff; + + quotient = sect_cnt >> 8; + residue = sect_cnt % 256; + + for (i = 0; i < quotient; i++) { + LOG_DEBUG("sect num : %u buff : 0x%8.8x", sect_num, (u32)buff_ptr); + mg_mflash_do_read_sects(buff_ptr, sect_num, 256); + sect_num += 256; + buff_ptr += 256 * MG_MFLASH_SECTOR_SIZE; + } + + if (residue) { + LOG_DEBUG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr); + mg_mflash_do_read_sects(buff_ptr, sect_num, residue); + } + + return ERROR_OK; +} + +static int mg_mflash_do_write_sects(void *buff, u32 sect_num, u32 sect_cnt) +{ + u32 i, address; + int ret; + target_t *target = mflash_bank->target; + u8 *buff_ptr = buff; + duration_t duration; + + if ( mg_dsk_io_cmd(sect_num, sect_cnt, mg_io_cmd_write) != ERROR_OK ) { + LOG_ERROR("mg_io_cmd_write fail"); + return ERROR_FAIL; + } + + address = mflash_bank->base + MG_BUFFER_OFFSET; + + duration_start_measure(&duration); + + for (i = 0; i < sect_cnt; i++) { + ret = mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL); + if (ret != ERROR_OK) + LOG_ERROR("mg_io_wait_drq time out"); + + ret = target->type->write_memory(target, address, 2, MG_MFLASH_SECTOR_SIZE / 2, buff_ptr); + if (ret != ERROR_OK) + LOG_ERROR("mem write error"); + buff_ptr += MG_MFLASH_SECTOR_SIZE; + + ret = target_write_u8(target, mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND, mg_io_cmd_confirm_write); + if (ret != ERROR_OK) + LOG_ERROR("mg_io_cmd_confirm_write error"); + + LOG_DEBUG("%u (0x%8.8x) sector write", sect_num + i, (sect_num + i) * MG_MFLASH_SECTOR_SIZE); + + duration_stop_measure(&duration, NULL); + + if ((duration.duration.tv_sec * 1000 + duration.duration.tv_usec / 1000) > 3000) { + LOG_INFO("wrote %u'th sectors", sect_num + i); + duration_start_measure(&duration); + } + } + + ret = mg_dsk_wait(mg_io_wait_rdy, MG_OEM_DISK_WAIT_TIME_NORMAL); + + return ret; +} + +static int mg_mflash_write_sects(void *buff, u32 sect_num, u32 sect_cnt) +{ + u32 quotient, residue, i; + u8 *buff_ptr = buff; + + quotient = sect_cnt >> 8; + residue = sect_cnt % 256; + + for (i = 0; i < quotient; i++) { + LOG_DEBUG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr); + mg_mflash_do_write_sects(buff_ptr, sect_num, 256); + sect_num += 256; + buff_ptr += 256 * MG_MFLASH_SECTOR_SIZE; + } + + if (residue) { + LOG_DEBUG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr); + mg_mflash_do_write_sects(buff_ptr, sect_num, residue); + } + + return ERROR_OK; +} + +static int mg_mflash_read (u32 addr, u8 *buff, u32 len) +{ + u8 *sect_buff, *buff_ptr = buff; + u32 cur_addr, next_sec_addr, end_addr, cnt, sect_num; + + cnt = 0; + cur_addr = addr; + end_addr = addr + len; + + sect_buff = malloc(MG_MFLASH_SECTOR_SIZE); + + if (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK) { + + next_sec_addr = (cur_addr + MG_MFLASH_SECTOR_SIZE) & ~MG_MFLASH_SECTOR_SIZE_MASK; + sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT; + mg_mflash_read_sects(sect_buff, sect_num, 1); + + if (end_addr < next_sec_addr) { + memcpy(buff_ptr, sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), end_addr - cur_addr); + LOG_DEBUG("copies %u byte from sector offset 0x%8.8x", end_addr - cur_addr, cur_addr); + cur_addr = end_addr; + } else { + memcpy(buff_ptr, sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), next_sec_addr - cur_addr); + LOG_DEBUG("copies %u byte from sector offset 0x%8.8x", next_sec_addr - cur_addr, cur_addr); + buff_ptr += (next_sec_addr - cur_addr); + cur_addr = next_sec_addr; + } + } + + if (cur_addr < end_addr) { + + sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT; + next_sec_addr = cur_addr + MG_MFLASH_SECTOR_SIZE; + + while (next_sec_addr <= end_addr) { + cnt++; + next_sec_addr += MG_MFLASH_SECTOR_SIZE; + } + + if (cnt) + mg_mflash_read_sects(buff_ptr, sect_num, cnt); + + buff_ptr += cnt * MG_MFLASH_SECTOR_SIZE; + cur_addr += cnt * MG_MFLASH_SECTOR_SIZE; + + if (cur_addr < end_addr) { + + sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT; + mg_mflash_read_sects(sect_buff, sect_num, 1); + memcpy(buff_ptr, sect_buff, end_addr - cur_addr); + LOG_DEBUG("copies %u byte", end_addr - cur_addr); + + } + + } + + free(sect_buff); + + return ERROR_OK; +} + +static int mg_mflash_write(u32 addr, u8 *buff, u32 len) +{ + u8 *sect_buff, *buff_ptr = buff; + u32 cur_addr, next_sec_addr, end_addr, cnt, sect_num; + + cnt = 0; + cur_addr = addr; + end_addr = addr + len; + + sect_buff = malloc(MG_MFLASH_SECTOR_SIZE); + + if (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK) { + + next_sec_addr = (cur_addr + MG_MFLASH_SECTOR_SIZE) & ~MG_MFLASH_SECTOR_SIZE_MASK; + sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT; + mg_mflash_read_sects(sect_buff, sect_num, 1); + + if (end_addr < next_sec_addr) { + memcpy(sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), buff_ptr, end_addr - cur_addr); + LOG_DEBUG("copies %u byte to sector offset 0x%8.8x", end_addr - cur_addr, cur_addr); + cur_addr = end_addr; + } else { + memcpy(sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), buff_ptr, next_sec_addr - cur_addr); + LOG_DEBUG("copies %u byte to sector offset 0x%8.8x", next_sec_addr - cur_addr, cur_addr); + buff_ptr += (next_sec_addr - cur_addr); + cur_addr = next_sec_addr; + } + + mg_mflash_write_sects(sect_buff, sect_num, 1); + + } + + if (cur_addr < end_addr) { + + sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT; + next_sec_addr = cur_addr + MG_MFLASH_SECTOR_SIZE; + + while (next_sec_addr <= end_addr) { + cnt++; + next_sec_addr += MG_MFLASH_SECTOR_SIZE; + } + + if (cnt) + mg_mflash_write_sects(buff_ptr, sect_num, cnt); + + buff_ptr += cnt * MG_MFLASH_SECTOR_SIZE; + cur_addr += cnt * MG_MFLASH_SECTOR_SIZE; + + if (cur_addr < end_addr) { + + sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT; + mg_mflash_read_sects(sect_buff, sect_num, 1); + memcpy(sect_buff, buff_ptr, end_addr - cur_addr); + LOG_DEBUG("copies %u byte", end_addr - cur_addr); + mg_mflash_write_sects(sect_buff, sect_num, 1); + + } + + } + + free(sect_buff); + + return ERROR_OK; +} + +static int mflash_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + u32 address, buf_cnt; + u8 *buffer; + // TODO : multi-bank support, large file support + fileio_t fileio; + duration_t duration; + char *duration_text; + int ret; + + if (argc != 3) { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + address = strtoul(args[2], NULL, 0); + + if (! mflash_bank->proved ) { + mg_mflash_probe(); + } + + + if (fileio_open(&fileio, args[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK) { + return ERROR_FAIL; + } + + buffer = malloc(fileio.size); + + if (fileio_read(&fileio, fileio.size, buffer, &buf_cnt) != ERROR_OK) + { + free(buffer); + fileio_close(&fileio); + return ERROR_FAIL; + } + + duration_start_measure(&duration); + + ret = mg_mflash_write(address, buffer, (u32)fileio.size); + + duration_stop_measure(&duration, &duration_text); + + command_print(cmd_ctx, "wrote %lli byte from file %s in %s (%f kB/s)", + fileio.size, args[1], duration_text, + (float)fileio.size / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0))); + + free(duration_text); + + fileio_close(&fileio); + + free(buffer); + + return ERROR_OK; +} + +static int mflash_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + u32 address, size_written, size; + u8 *buffer; + // TODO : multi-bank support + fileio_t fileio; + duration_t duration; + char *duration_text; + + if (argc != 4) { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + address = strtoul(args[2], NULL, 0); + size = strtoul(args[3], NULL, 0); + + if (! mflash_bank->proved ) { + mg_mflash_probe(); + } + + if (fileio_open(&fileio, args[1], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) { + return ERROR_FAIL; + } + + buffer = malloc(size); + + duration_start_measure(&duration); + + mg_mflash_read(address, buffer, size); + + duration_stop_measure(&duration, &duration_text); + + fileio_write(&fileio, size, buffer, &size_written); + + command_print(cmd_ctx, "dump image (address 0x%8.8x size %u) to file %s in %s (%f kB/s)", + address, size, args[1], duration_text, + (float)size / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0))); + + free(duration_text); + + fileio_close(&fileio); + + free(buffer); + + return ERROR_OK; +} + +int mflash_init_drivers(struct command_context_s *cmd_ctx) +{ + if (mflash_bank) { + register_command(cmd_ctx, mflash_cmd, "probe", mflash_probe_command, COMMAND_EXEC, NULL); + register_command(cmd_ctx, mflash_cmd, "write", mflash_write_command, COMMAND_EXEC, + "mflash write
"); + register_command(cmd_ctx, mflash_cmd, "dump", mflash_dump_command, COMMAND_EXEC, + "mflash dump
"); + } + + return ERROR_OK; +} + +static int mflash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + char *str; + int i; + + if (argc < 8) + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if ((target = get_target_by_num(strtoul(args[7], NULL, 0))) == NULL) + { + LOG_ERROR("target %lu not defined", strtoul(args[7], NULL, 0)); + return ERROR_FAIL; + } + + mflash_bank = calloc(sizeof(mflash_bank_t), 1); + mflash_bank->base = strtoul(args[1], NULL, 0); + mflash_bank->chip_width = strtoul(args[2], NULL, 0); + mflash_bank->bus_width = strtoul(args[3], NULL, 0); + mflash_bank->rst_pin.num = strtoul(args[4], &str, 0); + if (*str) + mflash_bank->rst_pin.port[0] = (u16)tolower(str[0]); + mflash_bank->wp_pin.num = strtol(args[5], &str, 0); + if (*str) + mflash_bank->wp_pin.port[0] = (u16)tolower(str[0]); + mflash_bank->dpd_pin.num = strtol(args[6], &str, 0); + if (*str) + mflash_bank->dpd_pin.port[0] = (u16)tolower(str[0]); + + mflash_bank->target = target; + + for (i = 0; mflash_gpio[i] ; i++) { + if (! strcmp(mflash_gpio[i]->name, args[0])) { + mflash_bank->gpio_drv = mflash_gpio[i]; + } + } + + if (! mflash_bank->gpio_drv) { + LOG_ERROR("%s is unsupported soc", args[0]); + return ERROR_INVALID_ARGUMENTS; + } + + return ERROR_OK; +} + +int mflash_register_commands(struct command_context_s *cmd_ctx) +{ + mflash_cmd = register_command(cmd_ctx, NULL, "mflash", NULL, COMMAND_ANY, NULL); + register_command(cmd_ctx, mflash_cmd, "bank", mflash_bank_command, COMMAND_CONFIG, + "mflash bank "); + return ERROR_OK; +} diff --git a/src/flash/mflash.h b/src/flash/mflash.h index 3fc935a2..7e7e7c64 100644 --- a/src/flash/mflash.h +++ b/src/flash/mflash.h @@ -1,245 +1,245 @@ -/*************************************************************************** - * Copyright (C) 2007-2008 by unsik Kim * - * * - * 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 _MFLASH_H -#define _MFLASH_H - -typedef unsigned long mg_io_uint32; -typedef unsigned short mg_io_uint16; -typedef unsigned char mg_io_uint8; - -typedef struct mflash_gpio_num_s -{ - char port[2]; - signed short num; -} mflash_gpio_num_t; - -typedef struct mflash_gpio_drv_s -{ - char *name; - int (*set_gpio_to_output) (mflash_gpio_num_t gpio); - int (*set_gpio_output_val) (mflash_gpio_num_t gpio, u8 val); -} mflash_gpio_drv_t; - -typedef struct _mg_io_type_drv_info { - - mg_io_uint16 general_configuration; // 00 - mg_io_uint16 number_of_cylinders; // 01 - mg_io_uint16 reserved1; // 02 - mg_io_uint16 number_of_heads; // 03 - mg_io_uint16 unformatted_bytes_per_track; // 04 - mg_io_uint16 unformatted_bytes_per_sector; // 05 - mg_io_uint16 sectors_per_track; // 06 - mg_io_uint8 vendor_unique1[6]; // 07/08/09 - - mg_io_uint8 serial_number[20]; // 10~19 - - mg_io_uint16 buffer_type; // 20 - mg_io_uint16 buffer_sector_size; // 21 - mg_io_uint16 number_of_ecc_bytes; // 22 - - mg_io_uint8 firmware_revision[8]; // 23~26 - mg_io_uint8 model_number[40]; // 27 - - mg_io_uint8 maximum_block_transfer; // 47 low byte - mg_io_uint8 vendor_unique2; // 47 high byte - mg_io_uint16 dword_io; // 48 - - mg_io_uint16 capabilities; // 49 - mg_io_uint16 reserved2; // 50 - - mg_io_uint8 vendor_unique3; // 51 low byte - mg_io_uint8 pio_cycle_timing_mode; // 51 high byte - mg_io_uint8 vendor_unique4; // 52 low byte - mg_io_uint8 dma_cycle_timing_mode; // 52 high byte - mg_io_uint16 translation_fields_valid; // 53 (low bit) - mg_io_uint16 number_of_current_cylinders; // 54 - mg_io_uint16 number_of_current_heads; // 55 - mg_io_uint16 current_sectors_per_track; // 56 - mg_io_uint16 current_sector_capacity_lo; // 57 & 58 - mg_io_uint16 current_sector_capacity_hi; // 57 & 58 - mg_io_uint8 multi_sector_count; // 59 low - mg_io_uint8 multi_sector_setting_valid; // 59 high (low bit) - - mg_io_uint16 total_user_addressable_sectors_lo; // 60 & 61 - mg_io_uint16 total_user_addressable_sectors_hi; // 60 & 61 - - mg_io_uint8 single_dma_modes_supported; // 62 low byte - mg_io_uint8 single_dma_transfer_active; // 62 high byte - mg_io_uint8 multi_dma_modes_supported; // 63 low byte - mg_io_uint8 multi_dma_transfer_active; // 63 high byte - mg_io_uint16 adv_pio_mode; - mg_io_uint16 min_dma_cyc; - mg_io_uint16 recommend_dma_cyc; - mg_io_uint16 min_pio_cyc_no_iordy; - mg_io_uint16 min_pio_cyc_with_iordy; - mg_io_uint8 reserved3[22]; - mg_io_uint16 major_ver_num; - mg_io_uint16 minor_ver_num; - mg_io_uint16 feature_cmd_set_suprt0; - mg_io_uint16 feature_cmd_set_suprt1; - mg_io_uint16 feature_cmd_set_suprt2; - mg_io_uint16 feature_cmd_set_en0; - mg_io_uint16 feature_cmd_set_en1; - mg_io_uint16 feature_cmd_set_en2; - mg_io_uint16 reserved4; - mg_io_uint16 req_time_for_security_er_done; - mg_io_uint16 req_time_for_enhan_security_er_done; - mg_io_uint16 adv_pwr_mgm_lvl_val; - mg_io_uint16 reserved5; - mg_io_uint16 re_of_hw_rst; - mg_io_uint8 reserved6[68]; - mg_io_uint16 security_stas; - mg_io_uint8 vendor_uniq_bytes[62]; - mg_io_uint16 cfa_pwr_mode; - mg_io_uint8 reserved7[186]; - - mg_io_uint16 scts_per_secure_data_unit; - mg_io_uint16 integrity_word; - -} mg_io_type_drv_info; - -typedef struct mg_drv_info_s { - mg_io_type_drv_info drv_id; - u32 tot_sects; -} mg_drv_info_t; - -typedef struct mflash_bank_s -{ - u32 base; - u32 chip_width; - u32 bus_width; - - mflash_gpio_num_t rst_pin; - mflash_gpio_num_t wp_pin; - mflash_gpio_num_t dpd_pin; - - mflash_gpio_drv_t *gpio_drv; - target_t *target; - mg_drv_info_t *drv_info; - - u8 proved; -} mflash_bank_t; - -extern int mflash_register_commands(struct command_context_s *cmd_ctx); -extern int mflash_init_drivers(struct command_context_s *cmd_ctx); - -#define MG_MFLASH_SECTOR_SIZE (0x200) //512Bytes = 2^9 -#define MG_MFLASH_SECTOR_SIZE_MASK (0x200-1) -#define MG_MFLASH_SECTOR_SIZE_SHIFT (9) - -#define MG_BUFFER_OFFSET 0x8000 -#define MG_REG_OFFSET 0xC000 -#define MG_REG_FEATURE 0x2 // write case -#define MG_REG_ERROR 0x2 // read case -#define MG_REG_SECT_CNT 0x4 -#define MG_REG_SECT_NUM 0x6 -#define MG_REG_CYL_LOW 0x8 -#define MG_REG_CYL_HIGH 0xA -#define MG_REG_DRV_HEAD 0xC -#define MG_REG_COMMAND 0xE // write case -#define MG_REG_STATUS 0xE // read case -#define MG_REG_DRV_CTRL 0x10 -#define MG_REG_BURST_CTRL 0x12 - -#define MG_OEM_DISK_WAIT_TIME_LONG 15000 // msec -#define MG_OEM_DISK_WAIT_TIME_NORMAL 3000 // msec -#define MG_OEM_DISK_WAIT_TIME_SHORT 1000 // msec - -typedef enum _mg_io_type_wait{ - - mg_io_wait_bsy = 1, - mg_io_wait_not_bsy = 2, - mg_io_wait_rdy = 3, - mg_io_wait_drq = 4, // wait for data request - mg_io_wait_drq_noerr = 5, // wait for DRQ but ignore the error status bit - mg_io_wait_rdy_noerr = 6 // wait for ready, but ignore error status bit - -} mg_io_type_wait; - -//= "Status Register" bit masks. -typedef enum _mg_io_type_rbit_status{ - - mg_io_rbit_status_error = 0x01, // error bit in status register - mg_io_rbit_status_corrected_error = 0x04, // corrected error in status register - mg_io_rbit_status_data_req = 0x08, // data request bit in status register - mg_io_rbit_status_seek_done = 0x10, // DSC - Drive Seek Complete - mg_io_rbit_status_write_fault = 0x20, // DWF - Drive Write Fault - mg_io_rbit_status_ready = 0x40, - mg_io_rbit_status_busy = 0x80 - -} mg_io_type_rbit_status; - -//= "Error Register" bit masks. -typedef enum _mg_io_type_rbit_error{ - - mg_io_rbit_err_general = 0x01, - mg_io_rbit_err_aborted = 0x04, - mg_io_rbit_err_bad_sect_num = 0x10, - mg_io_rbit_err_uncorrectable = 0x40, - mg_io_rbit_err_bad_block = 0x80 - -} mg_io_type_rbit_error; - -//= "Device Control Register" bit. -typedef enum _mg_io_type_rbit_devc{ - - mg_io_rbit_devc_intr = 0x02,// interrupt enable bit (1:disable, 0:enable) - mg_io_rbit_devc_srst = 0x04 // softwrae reset bit (1:assert, 0:de-assert) - -} mg_io_type_rbit_devc; - -// "Drive Select/Head Register" values. -typedef enum _mg_io_type_rval_dev{ - - mg_io_rval_dev_must_be_on = 0x80, // These 1 bits are always on - mg_io_rval_dev_drv_master = (0x00 | mg_io_rval_dev_must_be_on),// Master - mg_io_rval_dev_drv_slave0 = (0x10 | mg_io_rval_dev_must_be_on),// Slave0 - mg_io_rval_dev_drv_slave1 = (0x20 | mg_io_rval_dev_must_be_on),// Slave1 - mg_io_rval_dev_drv_slave2 = (0x30 | mg_io_rval_dev_must_be_on),// Slave2 - mg_io_rval_dev_lba_mode = (0x40 | mg_io_rval_dev_must_be_on) - -} mg_io_type_rval_dev; - -typedef enum _mg_io_type_cmd -{ - mg_io_cmd_read =0x20, - mg_io_cmd_write =0x30, - - mg_io_cmd_setmul =0xC6, - mg_io_cmd_readmul =0xC4, - mg_io_cmd_writemul =0xC5, - - mg_io_cmd_idle =0x97,//0xE3 - mg_io_cmd_idle_immediate =0x95,//0xE1 - - mg_io_cmd_setsleep =0x99,//0xE6 - mg_io_cmd_stdby =0x96,//0xE2 - mg_io_cmd_stdby_immediate =0x94,//0xE0 - - mg_io_cmd_identify =0xEC, - mg_io_cmd_set_feature =0xEF, - - mg_io_cmd_confirm_write =0x3C, - mg_io_cmd_confirm_read =0x40, - mg_io_cmd_wakeup =0xC3 - -} mg_io_type_cmd; - -#endif +/*************************************************************************** + * Copyright (C) 2007-2008 by unsik Kim * + * * + * 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 _MFLASH_H +#define _MFLASH_H + +typedef unsigned long mg_io_uint32; +typedef unsigned short mg_io_uint16; +typedef unsigned char mg_io_uint8; + +typedef struct mflash_gpio_num_s +{ + char port[2]; + signed short num; +} mflash_gpio_num_t; + +typedef struct mflash_gpio_drv_s +{ + char *name; + int (*set_gpio_to_output) (mflash_gpio_num_t gpio); + int (*set_gpio_output_val) (mflash_gpio_num_t gpio, u8 val); +} mflash_gpio_drv_t; + +typedef struct _mg_io_type_drv_info { + + mg_io_uint16 general_configuration; // 00 + mg_io_uint16 number_of_cylinders; // 01 + mg_io_uint16 reserved1; // 02 + mg_io_uint16 number_of_heads; // 03 + mg_io_uint16 unformatted_bytes_per_track; // 04 + mg_io_uint16 unformatted_bytes_per_sector; // 05 + mg_io_uint16 sectors_per_track; // 06 + mg_io_uint8 vendor_unique1[6]; // 07/08/09 + + mg_io_uint8 serial_number[20]; // 10~19 + + mg_io_uint16 buffer_type; // 20 + mg_io_uint16 buffer_sector_size; // 21 + mg_io_uint16 number_of_ecc_bytes; // 22 + + mg_io_uint8 firmware_revision[8]; // 23~26 + mg_io_uint8 model_number[40]; // 27 + + mg_io_uint8 maximum_block_transfer; // 47 low byte + mg_io_uint8 vendor_unique2; // 47 high byte + mg_io_uint16 dword_io; // 48 + + mg_io_uint16 capabilities; // 49 + mg_io_uint16 reserved2; // 50 + + mg_io_uint8 vendor_unique3; // 51 low byte + mg_io_uint8 pio_cycle_timing_mode; // 51 high byte + mg_io_uint8 vendor_unique4; // 52 low byte + mg_io_uint8 dma_cycle_timing_mode; // 52 high byte + mg_io_uint16 translation_fields_valid; // 53 (low bit) + mg_io_uint16 number_of_current_cylinders; // 54 + mg_io_uint16 number_of_current_heads; // 55 + mg_io_uint16 current_sectors_per_track; // 56 + mg_io_uint16 current_sector_capacity_lo; // 57 & 58 + mg_io_uint16 current_sector_capacity_hi; // 57 & 58 + mg_io_uint8 multi_sector_count; // 59 low + mg_io_uint8 multi_sector_setting_valid; // 59 high (low bit) + + mg_io_uint16 total_user_addressable_sectors_lo; // 60 & 61 + mg_io_uint16 total_user_addressable_sectors_hi; // 60 & 61 + + mg_io_uint8 single_dma_modes_supported; // 62 low byte + mg_io_uint8 single_dma_transfer_active; // 62 high byte + mg_io_uint8 multi_dma_modes_supported; // 63 low byte + mg_io_uint8 multi_dma_transfer_active; // 63 high byte + mg_io_uint16 adv_pio_mode; + mg_io_uint16 min_dma_cyc; + mg_io_uint16 recommend_dma_cyc; + mg_io_uint16 min_pio_cyc_no_iordy; + mg_io_uint16 min_pio_cyc_with_iordy; + mg_io_uint8 reserved3[22]; + mg_io_uint16 major_ver_num; + mg_io_uint16 minor_ver_num; + mg_io_uint16 feature_cmd_set_suprt0; + mg_io_uint16 feature_cmd_set_suprt1; + mg_io_uint16 feature_cmd_set_suprt2; + mg_io_uint16 feature_cmd_set_en0; + mg_io_uint16 feature_cmd_set_en1; + mg_io_uint16 feature_cmd_set_en2; + mg_io_uint16 reserved4; + mg_io_uint16 req_time_for_security_er_done; + mg_io_uint16 req_time_for_enhan_security_er_done; + mg_io_uint16 adv_pwr_mgm_lvl_val; + mg_io_uint16 reserved5; + mg_io_uint16 re_of_hw_rst; + mg_io_uint8 reserved6[68]; + mg_io_uint16 security_stas; + mg_io_uint8 vendor_uniq_bytes[62]; + mg_io_uint16 cfa_pwr_mode; + mg_io_uint8 reserved7[186]; + + mg_io_uint16 scts_per_secure_data_unit; + mg_io_uint16 integrity_word; + +} mg_io_type_drv_info; + +typedef struct mg_drv_info_s { + mg_io_type_drv_info drv_id; + u32 tot_sects; +} mg_drv_info_t; + +typedef struct mflash_bank_s +{ + u32 base; + u32 chip_width; + u32 bus_width; + + mflash_gpio_num_t rst_pin; + mflash_gpio_num_t wp_pin; + mflash_gpio_num_t dpd_pin; + + mflash_gpio_drv_t *gpio_drv; + target_t *target; + mg_drv_info_t *drv_info; + + u8 proved; +} mflash_bank_t; + +extern int mflash_register_commands(struct command_context_s *cmd_ctx); +extern int mflash_init_drivers(struct command_context_s *cmd_ctx); + +#define MG_MFLASH_SECTOR_SIZE (0x200) //512Bytes = 2^9 +#define MG_MFLASH_SECTOR_SIZE_MASK (0x200-1) +#define MG_MFLASH_SECTOR_SIZE_SHIFT (9) + +#define MG_BUFFER_OFFSET 0x8000 +#define MG_REG_OFFSET 0xC000 +#define MG_REG_FEATURE 0x2 // write case +#define MG_REG_ERROR 0x2 // read case +#define MG_REG_SECT_CNT 0x4 +#define MG_REG_SECT_NUM 0x6 +#define MG_REG_CYL_LOW 0x8 +#define MG_REG_CYL_HIGH 0xA +#define MG_REG_DRV_HEAD 0xC +#define MG_REG_COMMAND 0xE // write case +#define MG_REG_STATUS 0xE // read case +#define MG_REG_DRV_CTRL 0x10 +#define MG_REG_BURST_CTRL 0x12 + +#define MG_OEM_DISK_WAIT_TIME_LONG 15000 // msec +#define MG_OEM_DISK_WAIT_TIME_NORMAL 3000 // msec +#define MG_OEM_DISK_WAIT_TIME_SHORT 1000 // msec + +typedef enum _mg_io_type_wait{ + + mg_io_wait_bsy = 1, + mg_io_wait_not_bsy = 2, + mg_io_wait_rdy = 3, + mg_io_wait_drq = 4, // wait for data request + mg_io_wait_drq_noerr = 5, // wait for DRQ but ignore the error status bit + mg_io_wait_rdy_noerr = 6 // wait for ready, but ignore error status bit + +} mg_io_type_wait; + +//= "Status Register" bit masks. +typedef enum _mg_io_type_rbit_status{ + + mg_io_rbit_status_error = 0x01, // error bit in status register + mg_io_rbit_status_corrected_error = 0x04, // corrected error in status register + mg_io_rbit_status_data_req = 0x08, // data request bit in status register + mg_io_rbit_status_seek_done = 0x10, // DSC - Drive Seek Complete + mg_io_rbit_status_write_fault = 0x20, // DWF - Drive Write Fault + mg_io_rbit_status_ready = 0x40, + mg_io_rbit_status_busy = 0x80 + +} mg_io_type_rbit_status; + +//= "Error Register" bit masks. +typedef enum _mg_io_type_rbit_error{ + + mg_io_rbit_err_general = 0x01, + mg_io_rbit_err_aborted = 0x04, + mg_io_rbit_err_bad_sect_num = 0x10, + mg_io_rbit_err_uncorrectable = 0x40, + mg_io_rbit_err_bad_block = 0x80 + +} mg_io_type_rbit_error; + +//= "Device Control Register" bit. +typedef enum _mg_io_type_rbit_devc{ + + mg_io_rbit_devc_intr = 0x02,// interrupt enable bit (1:disable, 0:enable) + mg_io_rbit_devc_srst = 0x04 // softwrae reset bit (1:assert, 0:de-assert) + +} mg_io_type_rbit_devc; + +// "Drive Select/Head Register" values. +typedef enum _mg_io_type_rval_dev{ + + mg_io_rval_dev_must_be_on = 0x80, // These 1 bits are always on + mg_io_rval_dev_drv_master = (0x00 | mg_io_rval_dev_must_be_on),// Master + mg_io_rval_dev_drv_slave0 = (0x10 | mg_io_rval_dev_must_be_on),// Slave0 + mg_io_rval_dev_drv_slave1 = (0x20 | mg_io_rval_dev_must_be_on),// Slave1 + mg_io_rval_dev_drv_slave2 = (0x30 | mg_io_rval_dev_must_be_on),// Slave2 + mg_io_rval_dev_lba_mode = (0x40 | mg_io_rval_dev_must_be_on) + +} mg_io_type_rval_dev; + +typedef enum _mg_io_type_cmd +{ + mg_io_cmd_read =0x20, + mg_io_cmd_write =0x30, + + mg_io_cmd_setmul =0xC6, + mg_io_cmd_readmul =0xC4, + mg_io_cmd_writemul =0xC5, + + mg_io_cmd_idle =0x97,//0xE3 + mg_io_cmd_idle_immediate =0x95,//0xE1 + + mg_io_cmd_setsleep =0x99,//0xE6 + mg_io_cmd_stdby =0x96,//0xE2 + mg_io_cmd_stdby_immediate =0x94,//0xE0 + + mg_io_cmd_identify =0xEC, + mg_io_cmd_set_feature =0xEF, + + mg_io_cmd_confirm_write =0x3C, + mg_io_cmd_confirm_read =0x40, + mg_io_cmd_wakeup =0xC3 + +} mg_io_type_cmd; + +#endif -- cgit v1.2.3