/***************************************************************************
* Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> *
* Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> *
* Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
* *
* 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., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "imp.h"
#include <helper/time_support.h>
#include <target/image.h>
/**
* @file
* Implements Tcl commands used to access NOR flash facilities.
*/
COMMAND_HELPER(flash_command_get_bank, unsigned name_index,
struct flash_bank **bank)
{
const char *name = CMD_ARGV[name_index];
int retval = get_flash_bank_by_name(name, bank);
if (retval != ERROR_OK)
return retval;
if (*bank)
return ERROR_OK;
unsigned bank_num;
COMMAND_PARSE_NUMBER(uint, name, bank_num);
return get_flash_bank_by_num(bank_num, bank);
}
COMMAND_HANDLER(handle_flash_info_command)
{
struct flash_bank *p;
int j = 0;
int retval;
if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;
retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
if (retval != ERROR_OK)
return retval;
if (p != NULL) {
char buf[1024];
/* attempt auto probe */
retval = p->driver->auto_probe(p);
if (retval != ERROR_OK)
return retval;
/* We must query the hardware to avoid printing stale information! */
retval = p->driver->protect_check(p);
if (retval != ERROR_OK)
return retval;
command_print(CMD_CTX,
"#%d : %s at 0x%8.8" PRIx32 ", size 0x%8.8" PRIx32
", buswidth %i, chipwidth %i",
p->bank_number,
p->driver->name,
p->base,
p->size,
p->bus_width,
p->chip_width);
for (j = 0; j < p->num_sectors; j++) {
char *protect_state;
if (p->sectors[j].is_protected == 0)
protect_state = "not protected";
else if (p->sectors[j].is_protected == 1)
protect_state = "protected";
else
protect_state = "protection state unknown";
command_print(CMD_CTX,
"\t#%3i: 0x%8.8" PRIx32 " (0x%" PRIx32 " %" PRIi32 "kB) %s",
j,
p->sectors[j].offset,
p->sectors[j].size,
p->sectors[j].size >> 10,
protect_state);
}
if (p->driver->info != NULL) {
retval = p->driver->info(p, buf, sizeof(buf));
if (retval == ERROR_OK)
command_print(CMD_CTX, "%s", buf);
else
LOG_ERROR("error retrieving flash info");
}
}
return retval;
}
COMMAND_HANDLER(handle_flash_probe_command)
{
struct flash_bank *p;
int retval;
if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;
retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
if (retval != ERROR_OK)
return retval;
if (p) {
retval = p->driver->probe(p);
if (retval == ERROR_OK)
command_print(CMD_CTX,
"flash '%s' found at 0x%8.8" PRIx32,
p->driver->name,
p->base);
} else {
command_print(CMD_CTX, "flash bank '#%s' is out of bounds", CMD_ARGV[0]);
retval = ERROR_FAIL;
}
return retval;
}
COMMAND_HANDLER(handle_flash_erase_check_command)
{
if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;
struct flash_bank *p;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
if (ERROR_OK != retval)
return retval;
int j;
retval = p->driver->erase_check(p);
if (retval == ERROR_OK)
command_print(CMD_CTX, "successfully checked erase state");
else {
command_print(CMD_CTX,
"unknown error when checking erase state of flash bank #%s at 0x%8.8" PRIx32,
CMD_ARGV[0],
p->base);
}
for (j = 0; j < p->num_sectors; j++) {
char *erase_state;
if (p->sectors[j].is_erased == 0)
erase_state = "not erased";
else if (p->sectors[j].is_erased == 1)
erase_state = "erased";
else