summaryrefslogtreecommitdiff
path: root/src/flash/str7x.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/flash/str7x.c')
-rw-r--r--src/flash/str7x.c469
1 files changed, 469 insertions, 0 deletions
diff --git a/src/flash/str7x.c b/src/flash/str7x.c
new file mode 100644
index 00000000..2e3a6c8c
--- /dev/null
+++ b/src/flash/str7x.c
@@ -0,0 +1,469 @@
+/***************************************************************************
+ * Copyright (C) 2005 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. *
+ ***************************************************************************/
+
+#include "str7x.h"
+#include "flash.h"
+#include "target.h"
+#include "log.h"
+#include "armv4_5.h"
+#include "algorithm.h"
+#include "binarybuffer.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+str7x_mem_layout_t mem_layout[] = {
+ {0x00000000, 0x02000, 0x01},
+ {0x00002000, 0x02000, 0x01},
+ {0x00004000, 0x02000, 0x01},
+ {0x00006000, 0x02000, 0x01},
+ {0x00008000, 0x08000, 0x01},
+ {0x00010000, 0x10000, 0x01},
+ {0x00020000, 0x10000, 0x01},
+ {0x00030000, 0x10000, 0x01},
+ {0x000C0000, 0x02000, 0x10},
+ {0x000C2000, 0x02000, 0x10},
+ {0,0},
+};
+
+int str7x_register_commands(struct command_context_s *cmd_ctx);
+int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
+int str7x_erase(struct flash_bank_s *bank, int first, int last);
+int str7x_protect(struct flash_bank_s *bank, int set, int first, int last);
+int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
+int str7x_probe(struct flash_bank_s *bank);
+int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int str7x_protect_check(struct flash_bank_s *bank);
+int str7x_erase_check(struct flash_bank_s *bank);
+int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size);
+
+flash_driver_t str7x_flash =
+{
+ .name = "str7x",
+ .register_commands = str7x_register_commands,
+ .flash_bank_command = str7x_flash_bank_command,
+ .erase = str7x_erase,
+ .protect = str7x_protect,
+ .write = str7x_write,
+ .probe = str7x_probe,
+ .erase_check = str7x_erase_check,
+ .protect_check = str7x_protect_check,
+ .info = str7x_info
+};
+
+int str7x_register_commands(struct command_context_s *cmd_ctx)
+{
+
+ return ERROR_OK;
+}
+
+int str7x_get_flash_adr(struct flash_bank_s *bank, u32 reg)
+{
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;
+ return (str7x_info->flash_base|reg);
+}
+
+int str7x_build_block_list(struct flash_bank_s *bank)
+{
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;
+
+ int i;
+ int num_sectors;
+
+ switch (bank->size)
+ {
+ case 16 * 1024:
+ num_sectors = 2;
+ break;
+ case 64 * 1024:
+ num_sectors = 5;
+ break;
+ case 128 * 1024:
+ num_sectors = 6;
+ break;
+ case 256 * 1024:
+ num_sectors = 8;
+ break;
+ default:
+ ERROR("BUG: unknown bank->size encountered");
+ exit(-1);
+ }
+
+ if( str7x_info->bank1 == 1 )
+ {
+ num_sectors += 2;
+ }
+
+ bank->num_sectors = num_sectors;
+ bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
+
+ for (i = 0; i < num_sectors; i++)
+ {
+ bank->sectors[i].offset = mem_layout[i].sector_start;
+ bank->sectors[i].size = mem_layout[i].sector_size;
+ bank->sectors[i].is_erased = -1;
+ bank->sectors[i].is_protected = 1;
+ }
+
+ return ERROR_OK;
+}
+
+/* flash bank str7x <base> <size> 0 0 <str71_variant> <target#>
+ */
+int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
+{
+ str7x_flash_bank_t *str7x_info;
+
+ if (argc < 7)
+ {
+ WARNING("incomplete flash_bank str7x configuration");
+ return ERROR_FLASH_BANK_INVALID;
+ }
+
+ str7x_info = malloc(sizeof(str7x_flash_bank_t));
+ bank->driver_priv = str7x_info;
+
+ if (strcmp(args[5], "STR71x") == 0)
+ {
+ str7x_info->bank1 = 1;
+ str7x_info->flash_base = 0x40000000;
+ }
+ else if (strcmp(args[5], "STR73x") == 0)
+ {
+ str7x_info->bank1 = 0;
+ str7x_info->flash_base = 0x80000000;
+ }
+ else
+ {
+ ERROR("unknown STR7x variant");
+ free(str7x_info);
+ return ERROR_FLASH_BANK_INVALID;
+ }
+
+ str7x_info->target = get_target_by_num(strtoul(args[6], NULL, 0));
+ if (!str7x_info->target)
+ {
+ ERROR("no target '%i' configured", args[6]);
+ exit(-1);
+ }
+
+ str7x_build_block_list(bank);
+
+ return ERROR_OK;
+}
+
+u32 str7x_status(struct flash_bank_s *bank)
+{
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;
+ target_t *target = str7x_info->target;
+ u32 retval;
+
+ target->type->read_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&retval);
+
+ return retval;
+}
+
+u32 str7x_result(struct flash_bank_s *bank)
+{
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;
+ target_t *target = str7x_info->target;
+ u32 retval;
+
+ target->type->read_memory(target, str7x_get_flash_adr(bank, FLASH_ER), 4, 1, (u8*)&retval);
+
+ return retval;
+}
+
+int str7x_blank_check(struct flash_bank_s *bank, int first, int last)
+{
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;
+ target_t *target = str7x_info->target;
+ u8 *buffer;
+ int i;
+ int nBytes;
+
+ if ((first < 0) || (last > bank->num_sectors))
+ return ERROR_FLASH_SECTOR_INVALID;
+
+ if (str7x_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ buffer = malloc(256);
+
+ for (i = first; i <= last; i++)
+ {
+ bank->sectors[i].is_erased = 1;
+
+ target->type->read_memory(target, bank->base + bank->sectors[i].offset, 4, 256/4, buffer);
+
+ for (nBytes = 0; nBytes < 256; nBytes++)
+ {
+ if (buffer[nBytes] != 0xFF)
+ {
+ bank->sectors[i].is_erased = 0;
+ break;
+ }
+ }
+ }
+
+ free(buffer);
+
+ return ERROR_OK;
+}
+
+int str7x_protect_check(struct flash_bank_s *bank)
+{
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;
+ target_t *target = str7x_info->target;
+
+ int i;
+ int retval;
+
+ if (str7x_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ target->type->read_memory(target, str7x_get_flash_adr(bank, FLASH_NVWPAR), 4, 1, (u8*)&retval);
+
+ for (i = 0; i < bank->num_sectors; i++)
+ {
+ if (retval & (mem_layout[i].reg_offset << i))
+ bank->sectors[i].is_protected = 0;
+ else
+ bank->sectors[i].is_protected = 1;
+ }
+
+ return ERROR_OK;
+}
+
+int str7x_erase(struct flash_bank_s *bank, int first, int last)
+{
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;
+ target_t *target = str7x_info->target;
+
+ int i;
+ u32 cmd;
+ u32 retval;
+ u32 erase_blocks;
+
+ if (str7x_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ erase_blocks = 0;
+
+ for (i = first; i <= last; i++)
+ erase_blocks |= (mem_layout[i].reg_offset << i);
+
+ cmd = FLASH_SER;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
+
+ cmd = erase_blocks;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR1), 4, 1, (u8*)&cmd);
+
+ cmd = FLASH_SER|FLASH_WMS;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
+
+ while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
+ usleep(1000);
+ }
+
+ retval = str7x_result(bank);
+
+ if (retval & FLASH_ERER)
+ return ERROR_FLASH_SECTOR_NOT_ERASED;
+ else if (retval & FLASH_WPF)
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ for (i = first; i <= last; i++)
+ bank->sectors[i].is_erased = 1;
+
+ return ERROR_OK;
+}
+
+int str7x_protect(struct flash_bank_s *bank, int set, int first, int last)
+{
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;
+ target_t *target = str7x_info->target;
+ int i;
+ u32 cmd;
+ u32 retval;
+ u32 protect_blocks;
+
+ if (str7x_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ protect_blocks = 0xFFFFFFFF;
+
+ if( set )
+ {
+ for (i = first; i <= last; i++)
+ protect_blocks &= ~(mem_layout[i].reg_offset << i);
+ }
+
+ cmd = FLASH_SPR;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
+
+ cmd = str7x_get_flash_adr(bank, FLASH_NVWPAR);
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_AR), 4, 1, (u8*)&cmd);
+
+ cmd = protect_blocks;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, (u8*)&cmd);
+
+ cmd = FLASH_SPR|FLASH_WMS;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
+
+ while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
+ usleep(1000);
+ }
+
+ retval = str7x_result(bank);
+
+ if (retval & FLASH_ERER)
+ return ERROR_FLASH_SECTOR_NOT_ERASED;
+ else if (retval & FLASH_WPF)
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ return ERROR_OK;
+}
+
+int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
+{
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;
+ target_t *target = str7x_info->target;
+ u32 dwords_remaining = (count / 8);
+ u32 bytes_remaining = (count & 0x00000007);
+ u32 address = bank->base + offset;
+ u32 *wordbuffer = (u32*)buffer;
+ u32 bytes_written = 0;
+ u32 cmd;
+ u32 retval;
+
+ if (str7x_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (offset + count > bank->size)
+ return ERROR_FLASH_DST_OUT_OF_BANK;
+
+ while (dwords_remaining > 0)
+ {
+ // command
+ cmd = FLASH_DWPG;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
+
+ // address
+ cmd = address;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_AR), 4, 1, (u8*)&cmd);
+
+ // data byte 1
+ cmd = wordbuffer[bytes_written/4];
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, (u8*)&cmd);
+ bytes_written += 4;
+
+ // data byte 2
+ cmd = wordbuffer[bytes_written/4];
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, (u8*)&cmd);
+ bytes_written += 4;
+
+ /* start programming cycle */
+ cmd = FLASH_DWPG|FLASH_WMS;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
+
+ while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
+ usleep(1000);
+ }
+
+ retval = str7x_result(bank);
+
+ if (retval & FLASH_PGER)
+ return ERROR_FLASH_OPERATION_FAILED;
+ else if (retval & FLASH_WPF)
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ dwords_remaining--;
+ address += 8;
+ }
+
+ while( bytes_remaining > 0 )
+ {
+ // command
+ cmd = FLASH_WPG;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
+
+ // address
+ cmd = address;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_AR), 4, 1, (u8*)&cmd);
+
+ // data byte
+ cmd = buffer[bytes_written];
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, (u8*)&cmd);
+
+ /* start programming cycle */
+ cmd = FLASH_WPG|FLASH_WMS;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
+
+ while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
+ usleep(1000);
+ }
+
+ retval = str7x_result(bank);
+
+ if (retval & FLASH_PGER)
+ return ERROR_FLASH_OPERATION_FAILED;
+ else if (retval & FLASH_WPF)
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ address++;
+ bytes_remaining--;
+ bytes_written++;
+ }
+
+ return ERROR_OK;
+}
+
+int str7x_probe(struct flash_bank_s *bank)
+{
+ return ERROR_OK;
+}
+
+int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ return ERROR_OK;
+}
+
+int str7x_erase_check(struct flash_bank_s *bank)
+{
+ return str7x_blank_check(bank, 0, bank->num_sectors - 1);
+}
+
+int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size)
+{
+ snprintf(buf, buf_size, "str7x flash driver info" );
+ return ERROR_OK;
+}