flash: add virtual flash bank driver

This adds a virtual flash bank driver that allows virtual banks to
be defined that refer to an existing flash bank.

For example the real address for bank0 on the pic32 is 0x1fc00000
but the user program will either be in kseg0 (0xbfc00000) or
kseg1 (0x9fc00000).
This also means that gdb will be aware of all the read only flash
addresses.

Signed-off-by: Spencer Oliver <ntfreak@users.sourceforge.net>
This commit is contained in:
Spencer Oliver 2010-05-24 11:41:50 +01:00
parent ef72484b78
commit 5319ccd7eb
4 changed files with 268 additions and 1 deletions

View File

@ -4672,6 +4672,26 @@ the flash clock.
@end deffn
@end deffn
@deffn {Flash Driver} virtual
This is a special driver that maps a previously defined bank to another
address. All bank settings will be copied from the master physical bank.
The @var{virtual} driver defines one mandatory parameters,
@itemize
@item @var{master_bank} The bank that this virtual address refers to.
@end itemize
So in the following example addresses 0xbfc00000 and 0x9fc00000 refer to
the flash bank defined at address 0x1fc00000. Any cmds executed on
the virtual banks are actually performed on the physical banks.
@example
flash bank $_FLASHNAME pic32mx 0x1fc00000 0 0 0 $_TARGETNAME
flash bank vbank0 virtual 0xbfc00000 0 0 0 $_TARGETNAME $_FLASHNAME
flash bank vbank1 virtual 0x9fc00000 0 0 0 $_TARGETNAME $_FLASHNAME
@end example
@end deffn
@subsection str9xpec driver
@cindex str9xpec

View File

@ -28,7 +28,8 @@ NOR_DRIVERS = \
str7x.c \
str9x.c \
str9xpec.c \
tms470.c
tms470.c \
virtual.c
noinst_HEADERS = \
at91sam7.h \

View File

@ -39,6 +39,7 @@ extern struct flash_driver ocl_flash;
extern struct flash_driver pic32mx_flash;
extern struct flash_driver avr_flash;
extern struct flash_driver faux_flash;
extern struct flash_driver virtual_flash;
/**
* The list of built-in flash drivers.
@ -63,6 +64,7 @@ static struct flash_driver *flash_drivers[] = {
&pic32mx_flash,
&avr_flash,
&faux_flash,
&virtual_flash,
NULL,
};

244
src/flash/nor/virtual.c Normal file
View File

@ -0,0 +1,244 @@
/***************************************************************************
* Copyright (C) 2010 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* 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 "imp.h"
static struct flash_bank* virtual_get_master_bank(struct flash_bank *bank)
{
struct flash_bank* master_bank;
master_bank = get_flash_bank_by_name(bank->driver_priv);
if (master_bank == NULL) {
LOG_ERROR("master flash bank '%s' does not exist", (char*)bank->driver_priv);
}
return master_bank;
}
static void virtual_update_bank_info(struct flash_bank *bank)
{
struct flash_bank *master_bank = virtual_get_master_bank(bank);
if (master_bank == NULL) {
return;
}
/* update the info we do not have */
bank->size = master_bank->size;
bank->chip_width = master_bank->chip_width;
bank->bus_width = master_bank->bus_width;
bank->num_sectors = master_bank->num_sectors;
bank->sectors = master_bank->sectors;
}
FLASH_BANK_COMMAND_HANDLER(virtual_flash_bank_command)
{
if (CMD_ARGC < 7)
{
LOG_WARNING("incomplete flash_bank virtual configuration");
return ERROR_FLASH_OPERATION_FAILED;
}
/* get the master flash bank */
const char *bank_name = CMD_ARGV[6];
struct flash_bank *master_bank = get_flash_bank_by_name(bank_name);
if (master_bank == NULL)
{
LOG_ERROR("master flash bank '%s' does not exist", bank_name);
return ERROR_FLASH_OPERATION_FAILED;
}
/* save master bank name - use this to get settings later */
bank->driver_priv = strdup(bank_name);
return ERROR_OK;
}
static int virtual_protect(struct flash_bank *bank, int set, int first, int last)
{
struct flash_bank *master_bank = virtual_get_master_bank(bank);
int retval;
if (master_bank == NULL) {
return ERROR_FLASH_OPERATION_FAILED;
}
/* call master handler */
if ((retval = master_bank->driver->protect(master_bank, set,
first, last)) != ERROR_OK)
return retval;
return ERROR_OK;
}
static int virtual_protect_check(struct flash_bank *bank)
{
struct flash_bank *master_bank = virtual_get_master_bank(bank);
int retval;
if (master_bank == NULL) {
return ERROR_FLASH_OPERATION_FAILED;
}
/* call master handler */
if ((retval = master_bank->driver->protect_check(master_bank)) != ERROR_OK)
return retval;
return ERROR_OK;
}
static int virtual_erase(struct flash_bank *bank, int first, int last)
{
struct flash_bank *master_bank = virtual_get_master_bank(bank);
int retval;
if (master_bank == NULL) {
return ERROR_FLASH_OPERATION_FAILED;
}
/* call master handler */
if ((retval = master_bank->driver->erase(master_bank,
first, last)) != ERROR_OK)
return retval;
return ERROR_OK;
}
static int virtual_write(struct flash_bank *bank, uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct flash_bank *master_bank = virtual_get_master_bank(bank);
int retval;
if (master_bank == NULL) {
return ERROR_FLASH_OPERATION_FAILED;
}
/* call master handler */
if ((retval = master_bank->driver->write(master_bank, buffer,
offset, count)) != ERROR_OK)
return retval;
return ERROR_OK;
}
static int virtual_probe(struct flash_bank *bank)
{
struct flash_bank *master_bank = virtual_get_master_bank(bank);
int retval;
if (master_bank == NULL) {
return ERROR_FLASH_OPERATION_FAILED;
}
/* call master handler */
if ((retval = master_bank->driver->probe(master_bank)) != ERROR_OK)
return retval;
/* update the info we do not have */
virtual_update_bank_info(bank);
return ERROR_OK;
}
static int virtual_auto_probe(struct flash_bank *bank)
{
struct flash_bank *master_bank = virtual_get_master_bank(bank);
int retval;
if (master_bank == NULL) {
return ERROR_FLASH_OPERATION_FAILED;
}
/* call master handler */
if ((retval = master_bank->driver->auto_probe(master_bank)) != ERROR_OK)
return retval;
/* update the info we do not have */
virtual_update_bank_info(bank);
return ERROR_OK;
}
static int virtual_info(struct flash_bank *bank, char *buf, int buf_size)
{
struct flash_bank *master_bank = virtual_get_master_bank(bank);
if (master_bank == NULL) {
return ERROR_FLASH_OPERATION_FAILED;
}
snprintf(buf, buf_size, "%s driver for flash bank %s at 0x%8.8" PRIx32 "",
bank->driver->name, master_bank->name, master_bank->base);
return ERROR_OK;
}
int virtual_blank_check(struct flash_bank *bank)
{
struct flash_bank *master_bank = virtual_get_master_bank(bank);
int retval;
if (master_bank == NULL) {
return ERROR_FLASH_OPERATION_FAILED;
}
/* call master handler */
if ((retval = master_bank->driver->erase_check(master_bank)) != ERROR_OK)
return retval;
return ERROR_OK;
}
int virtual_flash_read(struct flash_bank *bank,
uint8_t *buffer, uint32_t offset, uint32_t count)
{
struct flash_bank *master_bank = virtual_get_master_bank(bank);
int retval;
if (master_bank == NULL) {
return ERROR_FLASH_OPERATION_FAILED;
}
/* call master handler */
if ((retval = master_bank->driver->read(master_bank, buffer,
offset, count)) != ERROR_OK)
return retval;
return ERROR_OK;
}
struct flash_driver virtual_flash = {
.name = "virtual",
.flash_bank_command = virtual_flash_bank_command,
.erase = virtual_erase,
.protect = virtual_protect,
.write = virtual_write,
.read = virtual_flash_read,
.probe = virtual_probe,
.auto_probe = virtual_auto_probe,
.erase_check = virtual_blank_check,
.protect_check = virtual_protect_check,
.info = virtual_info,
};