From 5319ccd7eb4761f1481dcbb041b256848efc005e Mon Sep 17 00:00:00 2001 From: Spencer Oliver Date: Mon, 24 May 2010 11:41:50 +0100 Subject: 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 --- src/flash/nor/virtual.c | 244 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 src/flash/nor/virtual.c (limited to 'src/flash/nor/virtual.c') diff --git a/src/flash/nor/virtual.c b/src/flash/nor/virtual.c new file mode 100644 index 00000000..4908c0c8 --- /dev/null +++ b/src/flash/nor/virtual.c @@ -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, +}; -- cgit v1.2.3