http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/69f466b5/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/sim3x.c ---------------------------------------------------------------------- diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/sim3x.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/sim3x.c deleted file mode 100755 index df4e19c..0000000 --- a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/sim3x.c +++ /dev/null @@ -1,1123 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2014 by Ladislav Bábel * - * ladaba...@seznam.cz * - * * - * Copyright (C) 2015 by Andreas Bomholtz * - * andr...@seluxit.com * - * * - * 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. * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "imp.h" -#include <helper/binarybuffer.h> -#include <helper/time_support.h> -#include <target/algorithm.h> -#include <target/cortex_m.h> - -/* SI32_DEVICEID0 */ -#define DEVICEID0_DEVICEID0 (0x400490C0) -#define DEVICEID0_DEVICEID1 (0x400490D0) -#define DEVICEID0_DEVICEID2 (0x400490E0) -#define DEVICEID0_DEVICEID3 (0x400490F0) - -/* cortex_m CPUID */ -#define CPUID_CHECK_VALUE (0x410FC230) -#define CPUID_CHECK_VALUE_MASK (0xFF0FFFF0) - -/* Flash */ -#define FLASH_BASE_ADDRESS (0x00000000) -#define LOCK_WORD_ADDRESS (0x0003FFFC) - -#define LOCK_WORD_MCU_UNLOCKED (0xFFFFFFFF) -/* Can't by locked again without erase, because LOCK_WORD is in FLASH */ -#define LOCK_WORD_MCU_UNLOCKED_BY_FIRMWARE (0x00000000) - -/* SI32_FLASHCTRL_0 */ -#define FLASHCTRL0_CONFIG_ALL (0x4002E000) -#define FLASHCTRL0_CONFIG_SET (0x4002E004) -#define FLASHCTRL0_CONFIG_CLR (0x4002E008) -#define FLASHCTRL0_CONFIG_ERASEEN_MASK (0x00040000) -#define FLASHCTRL0_CONFIG_BUSYF_MASK (0x00100000) - -#define FLASHCTRL0_WRADDR (0x4002E0A0) -#define FLASHCTRL0_WRDATA (0x4002E0B0) - -#define FLASHCTRL0_KEY (0x4002E0C0) -#define FLASHCTRL0_KEY_INITIAL_UNLOCK (0x000000A5) -#define FLASHCTRL0_KEY_SINGLE_UNLOCK (0x000000F1) -#define FLASHCTRL0_KEY_MULTIPLE_UNLOCK (0x000000F2) -#define FLASHCTRL0_KEY_MULTIPLE_LOCK (0x0000005A) - -#define FLASH_BUSY_TIMEOUT (100) - -/* SI32_RSTSRC_0 */ -#define RSTSRC0_RESETEN_ALL (0x4002D060) -#define RSTSRC0_RESETEN_SET (0x4002D064) -#define RSTSRC0_RESETEN_CLR (0x4002D068) -#define RSTSRC0_RESETEN_VMONREN_MASK (0x00000004) -#define RSTSRC0_RESETEN_SWREN_MASK (0x00000040) - -/* SI32_VMON_0 */ -#define VMON0_CONTROL_ALL (0x4002F000) -#define VMON0_CONTROL_SET (0x4002F004) -#define VMON0_CONTROL_CLR (0x4002F008) -#define VMON0_CONTROL_VMONEN_MASK (0x80000000) - -/* SI32_CLKCTRL_0 */ -#define CLKCTRL0_APBCLKG0_ALL (0x4002D020) -#define CLKCTRL0_APBCLKG0_SET (0x4002D024) -#define CLKCTRL0_APBCLKG0_CLR (0x4002D028) -#define CLKCTRL0_APBCLKG0_FLCTRLCEN_MASK (0x40000000) - -/* SI32_WDTIMER_0 */ -#define WDTIMER0_CONTROL_ALL (0x40030000) -#define WDTIMER0_CONTROL_SET (0x40030004) -#define WDTIMER0_CONTROL_CLR (0x40030008) -#define WDTIMER0_CONTROL_DBGMD_MASK (0x00000002) - -#define WDTIMER0_STATUS_ALL (0x40030010) -#define WDTIMER0_STATUS_SET (0x40030014) -#define WDTIMER0_STATUS_CLR (0x40030018) -#define WDTIMER0_STATUS_KEYSTS_MASK (0x00000001) -#define WDTIMER0_STATUS_PRIVSTS_MASK (0x00000002) - -#define WDTIMER0_THRESHOLD (0x40030020) - -#define WDTIMER0_WDTKEY (0x40030030) -#define WDTIMER0_KEY_ATTN (0x000000A5) -#define WDTIMER0_KEY_WRITE (0x000000F1) -#define WDTIMER0_KEY_RESET (0x000000CC) -#define WDTIMER0_KEY_DISABLE (0x000000DD) -#define WDTIMER0_KEY_START (0x000000EE) -#define WDTIMER0_KEY_LOCK (0x000000FF) - -/* DAP */ -#define SIM3X_AP (0x0A) - -#define SIM3X_AP_CTRL1 (0x00) -#define SIM3X_AP_CTRL2 (0x04) -#define SIM3X_AP_LOCK (0x08) -#define SIM3X_AP_CRC (0x0C) - -#define SIM3X_AP_INIT_STAT (0x10) -#define SIM3X_AP_DAP_IN (0x14) -#define SIM3X_AP_DAP_OUT (0x18) - -#define SIM3X_AP_ID (0xFC) - -/* DAP register values */ -#define SIM3X_AP_CTRL1_MASS_ERASE_REQ (0x00000001) -#define SIM3X_AP_CTRL1_RESET_REQ (0x00000008) -/* this bit is set if MCU is locked */ -#define SIM3X_AP_INIT_STAT_LOCK (0x00000004) -/* expected value inside SIM3X_AP_ID */ -#define SIM3X_AP_ID_VALUE (0x2430002) - -#define SIM3X_FLASH_PAGE_SIZE 1024 - -struct sim3x_info { - uint16_t flash_size_kb; - uint16_t part_number; - char part_family; - uint8_t device_revision; - char device_package[4]; - bool probed; - bool need_init; - bool flash_locked; -}; - -/* flash bank sim3x 0 0 0 0 <target#> */ -FLASH_BANK_COMMAND_HANDLER(sim3x_flash_bank_command) -{ - struct sim3x_info *sim3x_info; - - if (CMD_ARGC < 6) - return ERROR_COMMAND_SYNTAX_ERROR; - - /* Init sim3x_info struct */ - sim3x_info = malloc(sizeof(struct sim3x_info)); - sim3x_info->probed = false; - sim3x_info->need_init = true; - sim3x_info->device_revision = 0; - memset(sim3x_info->device_package, 0, 4); - bank->driver_priv = sim3x_info; - - return ERROR_OK; -} - -static int sim3x_init(struct flash_bank *bank) -{ - int ret; - struct target *target; - struct sim3x_info *sim3x_info; - - target = bank->target; - - /* Disable watchdog timer */ - ret = target_write_u32(target, WDTIMER0_WDTKEY, WDTIMER0_KEY_ATTN); - if (ret != ERROR_OK) - return ret; - - ret = target_write_u32(target, WDTIMER0_WDTKEY, WDTIMER0_KEY_DISABLE); - if (ret != ERROR_OK) - return ret; - - /* Enable one write command */ - ret = target_write_u32(target, WDTIMER0_WDTKEY, WDTIMER0_KEY_ATTN); - if (ret != ERROR_OK) - return ret; - - ret = target_write_u32(target, WDTIMER0_WDTKEY, WDTIMER0_KEY_WRITE); - if (ret != ERROR_OK) - return ret; - - /* Watchdog Timer Debug Mode */ - ret = target_write_u32(target, WDTIMER0_CONTROL_SET, - WDTIMER0_CONTROL_DBGMD_MASK); - if (ret != ERROR_OK) - return ret; - - /* Enable VDD Supply Monitor */ - ret = target_write_u32(target, VMON0_CONTROL_SET, - VMON0_CONTROL_VMONEN_MASK); - if (ret != ERROR_OK) - return ret; - - /* Set VDD Supply Monitor as a reset source */ - ret = target_write_u32(target, RSTSRC0_RESETEN_SET, - RSTSRC0_RESETEN_VMONREN_MASK); - if (ret != ERROR_OK) - return ret; - - /* Flash Controller Clock Enable */ - ret = target_write_u32(target, CLKCTRL0_APBCLKG0_SET, - CLKCTRL0_APBCLKG0_FLCTRLCEN_MASK); - if (ret != ERROR_OK) - return ret; - - /* Disable Flash Erase Mode */ - ret = target_write_u32(target, FLASHCTRL0_CONFIG_CLR, - FLASHCTRL0_CONFIG_ERASEEN_MASK); - if (ret != ERROR_OK) - return ret; - - sim3x_info = bank->driver_priv; - sim3x_info->need_init = 0; - return ERROR_OK; -} - -static int sim3x_erase_page(struct flash_bank *bank, uint32_t addr) -{ - int ret, i; - uint32_t temp; - struct target *target; - - target = bank->target; - - for (i = 0; i < FLASH_BUSY_TIMEOUT; i++) { - ret = target_read_u32(target, FLASHCTRL0_CONFIG_ALL, &temp); - if (ret != ERROR_OK) - return ret; - - /* If is not busy */ - if ((temp & FLASHCTRL0_CONFIG_BUSYF_MASK) == 0) { - /* If erase is not enabled */ - if ((temp & FLASHCTRL0_CONFIG_ERASEEN_MASK) == 0) { - /* Enter Flash Erase Mode */ - ret = target_write_u32(target, FLASHCTRL0_CONFIG_SET, - FLASHCTRL0_CONFIG_ERASEEN_MASK); - if (ret != ERROR_OK) - return ret; - } - - /* Write the address of the Flash page to WRADDR */ - ret = target_write_u32(target, FLASHCTRL0_WRADDR, addr); - if (ret != ERROR_OK) - return ret; - - /* Write the inital unlock value to KEY */ - ret = target_write_u32(target, FLASHCTRL0_KEY, - FLASHCTRL0_KEY_INITIAL_UNLOCK); - if (ret != ERROR_OK) - return ret; - - /* Write the single unlock value to KEY */ - ret = target_write_u32(target, FLASHCTRL0_KEY, - FLASHCTRL0_KEY_SINGLE_UNLOCK); - if (ret != ERROR_OK) - return ret; - - /* Write any value to WRDATA to initiate the page erase */ - ret = target_write_u32(target, FLASHCTRL0_WRDATA, 0); - if (ret != ERROR_OK) - return ret; - - return ERROR_OK; - } - - alive_sleep(1); - } - - LOG_ERROR("timed out waiting for FLASHCTRL0_CONFIG_BUSYF"); - return ERROR_FAIL; -} - -static int sim3x_flash_erase(struct flash_bank *bank, int first, int last) -{ - int ret, i; - uint32_t temp; - struct sim3x_info *sim3x_info; - struct target *target; - - /* Check if target is halted */ - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - sim3x_info = bank->driver_priv; - - /* Init MCU after reset */ - if (sim3x_info->need_init) { - ret = sim3x_init(bank); - if (ret != ERROR_OK) { - LOG_ERROR("Failed to init MCU"); - return ret; - } - } - - /* erase pages */ - for (i = first; i <= last; i++) { - ret = sim3x_erase_page(bank, bank->sectors[i].offset); - if (ret != ERROR_OK) - return ret; - } - - target = bank->target; - - /* Wait until busy */ - for (i = 0; i < FLASH_BUSY_TIMEOUT; i++) { - ret = target_read_u32(target, FLASHCTRL0_CONFIG_ALL, &temp); - if (ret != ERROR_OK) - return ret; - - if ((temp & FLASHCTRL0_CONFIG_BUSYF_MASK) == 0) { /* If is not busy */ - if ((temp & FLASHCTRL0_CONFIG_ERASEEN_MASK) != 0) { /* If erase is enabled */ - /* Disable Flash Erase Mode */ - ret = target_write_u32(target, FLASHCTRL0_CONFIG_CLR, - FLASHCTRL0_CONFIG_ERASEEN_MASK); - if (ret != ERROR_OK) - return ret; - } - - return ERROR_OK; - } - - alive_sleep(1); - } - - LOG_ERROR("timed out waiting for FLASHCTRL0_CONFIG_BUSYF"); - return ERROR_FAIL; -} - -static int sim3x_write_block(struct flash_bank *bank, const uint8_t *buf, - uint32_t offset, uint32_t count) /* count is count of half words (2 bytes)! */ -{ - struct target *target = bank->target; - uint32_t buffer_size = 16384; - struct working_area *write_algorithm; - struct working_area *source; - uint32_t address = bank->base + offset; - struct reg_param reg_params[5]; - struct armv7m_algorithm armv7m_info; - int ret = ERROR_OK; - - /* see contrib/loaders/flash/sim3x.s for src */ - - static const uint8_t sim3x_flash_write_code[] = { - /* Write the initial unlock value to KEY (0xA5) */ - 0xA5, 0x26, /* movs r6, #INITIAL_UNLOCK */ - 0xC0, 0xF8, 0xC0, 0x60, /* str r6, [r0, #FLASHCTRL_KEY] */ - - /* Write the multiple unlock value to KEY (0xF2) */ - 0xF2, 0x26, /* movs r6, #MULTIPLE_UNLOCK */ - 0xC0, 0xF8, 0xC0, 0x60, /* str r6, [r0, #FLASHCTRL_KEY] */ - - /* wait_fifo: */ - 0x16, 0x68, /* ldr r6, [r2, #0] */ - 0x00, 0x2E, /* cmp r6, #0 */ - 0x16, 0xD0, /* beq exit */ - 0x55, 0x68, /* ldr r5, [r2, #4] */ - 0xB5, 0x42, /* cmp r5, r6 */ - 0xF9, 0xD0, /* beq wait_fifo */ - - /* wait for BUSYF flag */ - /* wait_busy1: */ - 0x06, 0x68, /* ldr r6, [r0, #FLASHCTRL_CONFIG] */ - 0x16, 0xF4, 0x80, 0x1F, /* tst r6, #BUSYF */ - 0xFB, 0xD1, /* bne wait_busy1 */ - - /* Write the destination address to WRADDR */ - 0xC0, 0xF8, 0xA0, 0x40, /* str r4, [r0, #FLASHCTRL_WRADDR] */ - - /* Write the data half-word to WRDATA in right-justified format */ - 0x2E, 0x88, /* ldrh r6, [r5] */ - 0xC0, 0xF8, 0xB0, 0x60, /* str r6, [r0, #FLASHCTRL_WRDATA] */ - - 0x02, 0x35, /* adds r5, #2 */ - 0x02, 0x34, /* adds r4, #2 */ - - /* wrap rp at end of buffer */ - 0x9D, 0x42, /* cmp r5, r3 */ - 0x01, 0xD3, /* bcc no_wrap */ - 0x15, 0x46, /* mov r5, r2 */ - 0x08, 0x35, /* adds r5, #8 */ - - /* no_wrap: */ - 0x55, 0x60, /* str r5, [r2, #4] */ - 0x49, 0x1E, /* subs r1, r1, #1 */ - 0x00, 0x29, /* cmp r1, #0 */ - 0x00, 0xD0, /* beq exit */ - 0xE5, 0xE7, /* b wait_fifo */ - - /* exit: */ - 0x5A, 0x26, /* movs r6, #MULTIPLE_LOCK */ - 0xC0, 0xF8, 0xC0, 0x60, /* str r6, [r0, #FLASHCTRL_KEY] */ - - /* wait for BUSYF flag */ - /* wait_busy2: */ - 0x06, 0x68, /* ldr r6, [r0, #FLASHCTRL_CONFIG] */ - 0x16, 0xF4, 0x80, 0x1F, /* tst r6, #BUSYF */ - 0xFB, 0xD1, /* bne wait_busy2 */ - - 0x00, 0xBE /* bkpt #0 */ - }; - - /* flash write code */ - if (target_alloc_working_area(target, sizeof(sim3x_flash_write_code), - &write_algorithm) != ERROR_OK) { - LOG_WARNING("no working area available, can't do block memory writes"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - ret = target_write_buffer(target, write_algorithm->address, - sizeof(sim3x_flash_write_code), sim3x_flash_write_code); - if (ret != ERROR_OK) - return ret; - - /* memory buffer */ - while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { - buffer_size /= 2; - buffer_size &= ~1UL; /* Make sure it's 2 byte aligned */ - if (buffer_size <= 256) { - /* we already allocated the writing code, but failed to get a - * buffer, free the algorithm - */ - target_free_working_area(target, write_algorithm); - - LOG_WARNING("no large enough working area available, can't do block memory writes"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - } - - init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* flash base */ - init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* count */ - init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer start */ - init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* buffer end */ - init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */ - - buf_set_u32(reg_params[0].value, 0, 32, FLASHCTRL0_CONFIG_ALL); - buf_set_u32(reg_params[1].value, 0, 32, count); - buf_set_u32(reg_params[2].value, 0, 32, source->address); - buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); - buf_set_u32(reg_params[4].value, 0, 32, address); - - armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; - armv7m_info.core_mode = ARM_MODE_THREAD; - - ret = target_run_flash_async_algorithm(target, buf, count, 2, 0, NULL, 5, - reg_params, source->address, source->size, write_algorithm->address, - 0, &armv7m_info); - - if (ret == ERROR_FLASH_OPERATION_FAILED) { - LOG_ERROR("flash write failed at address 0x%"PRIx32, - buf_get_u32(reg_params[4].value, 0, 32)); - } - - target_free_working_area(target, source); - target_free_working_area(target, write_algorithm); - - destroy_reg_param(®_params[0]); - destroy_reg_param(®_params[1]); - destroy_reg_param(®_params[2]); - destroy_reg_param(®_params[3]); - destroy_reg_param(®_params[4]); - - return ret; -} - -static int sim3x_flash_write(struct flash_bank *bank, const uint8_t * buffer, uint32_t offset, uint32_t count) -{ - int ret; - struct target *target; - struct sim3x_info *sim3x_info; - uint8_t *new_buffer = NULL; - - target = bank->target; - - /* Check if target is halted */ - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - sim3x_info = bank->driver_priv; - - if (sim3x_info->flash_locked) { - LOG_ERROR("Falsh is locked"); - return ERROR_FAIL; - } - - /* Init MCU after reset */ - if (sim3x_info->need_init) { - ret = sim3x_init(bank); - if (ret != ERROR_OK) - return ret; - } - - if (offset & 0x1) { - LOG_ERROR("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); - return ERROR_FLASH_DST_BREAKS_ALIGNMENT; - } - - if (count & 0x1) { - uint32_t old_count = count; - count++; - new_buffer = malloc(count); - - if (new_buffer == NULL) { - LOG_ERROR("odd number of bytes to write and no memory " - "for padding buffer"); - return ERROR_FAIL; - } - LOG_INFO("odd number of bytes to write (%" PRIu32 "), extending to %" PRIu32 - " and padding with 0xff", old_count, count); - - new_buffer[count - 1] = 0xff; - buffer = memcpy(new_buffer, buffer, old_count); - } - - ret = sim3x_write_block(bank, buffer, offset, count / 2); - free(new_buffer); - return ret; -} - -static int sim3x_flash_lock_check(struct flash_bank *bank) -{ - int ret; - uint32_t lock_word; - struct sim3x_info *sim3x_info; - - ret = target_read_u32(bank->target, LOCK_WORD_ADDRESS, &lock_word); - if (ret != ERROR_OK) { - LOG_ERROR("Can not read Lock Word"); - return ret; - } - - sim3x_info = bank->driver_priv; - sim3x_info->flash_locked = (lock_word != 0xFFFFFFFF); - - return ERROR_OK; -} - -static int sim3x_flash_protect_check(struct flash_bank *bank) -{ - int ret, i; - struct sim3x_info *sim3x_info; - - /* Check if target is halted */ - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - ret = sim3x_flash_lock_check(bank); - if (ret != ERROR_OK) - return ret; - - sim3x_info = bank->driver_priv; - - for (i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_protected = sim3x_info->flash_locked; - - return ERROR_OK; -} - -static int sim3x_flash_protect(struct flash_bank *bank, int set, int first, int last) -{ - int ret; - uint8_t lock_word[4]; - struct sim3x_info *sim3x_info; - struct target *target; - - target = bank->target; - - /* Check if target is halted */ - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (first != 0 || last != bank->num_sectors - 1) { - LOG_ERROR("Flash does not support finer granularity"); - return ERROR_FAIL; - } - - sim3x_info = bank->driver_priv; - - if (set) { - if (sim3x_info->flash_locked) { - LOG_INFO("Flash is already locked"); - return ERROR_OK; - } - - /* Lock Flash */ - target_buffer_set_u32(target, lock_word, 0xFFFFFFFE); - ret = sim3x_flash_write(bank, lock_word, LOCK_WORD_ADDRESS, 4); - if (ret != ERROR_OK) - return ret; - - } else { - /* Flash is unlocked by an erase operation */ - ret = sim3x_flash_erase(bank, 0, 0); - if (ret != ERROR_OK) - return ret; - } - - ret = sim3x_flash_protect_check(bank); - if (ret != ERROR_OK) - return ret; - - if (set) { - if (sim3x_info->flash_locked) { - LOG_INFO("Flash locked"); - return ERROR_OK; - } else { - LOG_ERROR("Flash lock error"); - return ERROR_FAIL; - } - } else { - if (sim3x_info->flash_locked) { - LOG_ERROR("Flash unlock error"); - return ERROR_FAIL; - } else { - LOG_INFO("Flash unlocked"); - return ERROR_OK; - } - } -} - -static int sim3x_read_deviceid(struct flash_bank *bank) -{ - int ret; - struct sim3x_info *sim3x_info; - - uint32_t device_id; - int part_number; - char part_num_string[4]; - - sim3x_info = bank->driver_priv; - - /* MCU check */ - ret = target_read_u32(bank->target, DEVICEID0_DEVICEID2, &device_id); - if (ret != ERROR_OK) - return ret; - - /* Device ID should be 'M3' */ - if (device_id != 0x00004D33) - return ERROR_FAIL; - - /* Family and Part number */ - ret = target_read_u32(bank->target, DEVICEID0_DEVICEID1, &device_id); - if (ret != ERROR_OK) - return ret; - - part_num_string[0] = device_id >> 16; - part_num_string[1] = device_id >> 8; - part_num_string[2] = device_id; - part_num_string[3] = 0; - - part_number = atoi(part_num_string); - - /* Part Number should be between 100 and 999 */ - if (!isalpha(device_id >> 24) || part_number < 100 || part_number > 999) - return ERROR_FAIL; - - sim3x_info->part_family = device_id >> 24; - sim3x_info->part_number = part_number; - - /* Package and Revision */ - ret = target_read_u32(bank->target, DEVICEID0_DEVICEID0, &device_id); - if (ret != ERROR_OK) - return ret; - - sim3x_info->device_package[0] = device_id >> 24; - sim3x_info->device_package[1] = device_id >> 16; - sim3x_info->device_package[2] = device_id >> 8; - sim3x_info->device_package[3] = 0; - - sim3x_info->device_revision = device_id; - - return ERROR_OK; -} - -static int sim3x_parse_part_info(struct sim3x_info *sim3x_info) -{ - switch (sim3x_info->part_number) { - case 134: - case 136: - sim3x_info->flash_size_kb = 32; - break; - case 144: - case 146: - sim3x_info->flash_size_kb = 64; - break; - case 154: - case 156: - case 157: - sim3x_info->flash_size_kb = 128; - break; - case 164: - case 166: - case 167: - sim3x_info->flash_size_kb = 256; - break; - default: - LOG_ERROR("Unknown Part number %d", sim3x_info->part_number); - sim3x_info->part_number = 0; - return ERROR_FAIL; - } - - switch (sim3x_info->part_family) { - case 'c': - case 'C': - LOG_INFO("SiM3C%d detected", sim3x_info->part_number); - break; - case 'u': - case 'U': - LOG_INFO("SiM3U%d detected", sim3x_info->part_number); - break; - case 'l': - case 'L': - LOG_INFO("SiM3L%d detected", sim3x_info->part_number); - break; - default: - LOG_ERROR("Unsupported MCU family %c", sim3x_info->part_family); - sim3x_info->part_family = 0; - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int sim3x_read_info(struct flash_bank *bank) -{ - int ret; - struct sim3x_info *sim3x_info; - uint32_t cpuid; - - sim3x_info = bank->driver_priv; - - /* Core check */ - ret = target_read_u32(bank->target, CPUID, &cpuid); - if (ret != ERROR_OK) { - LOG_ERROR("Failed to read CPU ID"); - return ret; - } - - if (((cpuid >> 4) & 0xfff) != 0xc23) { - LOG_ERROR("Target is not CortexM3"); - return ERROR_FAIL; - } - - /* Read info from chip */ - ret = sim3x_read_deviceid(bank); - if (ret == ERROR_OK) { - ret = sim3x_parse_part_info(sim3x_info); - if (ret != ERROR_OK) { - LOG_ERROR("Failed to parse info from MCU"); - return ERROR_FAIL; - } - } else { - LOG_WARNING("Failed to read info from MCU, using info from flash bank parameters"); - - /* Check if flash size is given in flash bank command */ - if (!bank->size) { - LOG_ERROR("Flash size not set in the flash bank command"); - return ERROR_FAIL; - } - - /* Convert bank size to kb */ - sim3x_info->flash_size_kb = bank->size / 1024; - } - - LOG_INFO("Flash size = %dKB", sim3x_info->flash_size_kb); - - return ERROR_OK; -} - -static int sim3x_probe(struct flash_bank *bank) -{ - int ret, i; - struct sim3x_info *sim3x_info; - - sim3x_info = bank->driver_priv; - sim3x_info->probed = false; - sim3x_info->need_init = true; - - /* Read info from chip */ - ret = sim3x_read_info(bank); - if (ret != ERROR_OK) - return ret; - - ret = sim3x_flash_lock_check(bank); - if (ret != ERROR_OK) - return ret; - - if (bank->sectors) { - free(bank->sectors); - bank->sectors = NULL; - } - - bank->base = FLASH_BASE_ADDRESS; - bank->size = sim3x_info->flash_size_kb * SIM3X_FLASH_PAGE_SIZE; - bank->num_sectors = SIM3X_FLASH_PAGE_SIZE; - bank->sectors = malloc(sizeof(struct flash_sector) * sim3x_info->flash_size_kb); - - for (i = 0; i < sim3x_info->flash_size_kb; i++) { - bank->sectors[i].offset = i * SIM3X_FLASH_PAGE_SIZE; - bank->sectors[i].size = SIM3X_FLASH_PAGE_SIZE; - bank->sectors[i].is_erased = -1; - bank->sectors[i].is_protected = sim3x_info->flash_locked; - } - - sim3x_info->probed = true; - - return ERROR_OK; -} - -static int sim3x_auto_probe(struct flash_bank *bank) -{ - struct sim3x_info *sim3x_info; - - sim3x_info = bank->driver_priv; - - if (sim3x_info->probed) { - sim3x_info->need_init = true; - return ERROR_OK; - } else { - return sim3x_probe(bank); - } -} - -static int sim3x_flash_info(struct flash_bank *bank, char *buf, int buf_size) -{ - int ret; - int printed = 0; - struct sim3x_info *sim3x_info; - - sim3x_info = bank->driver_priv; - - /* Read info about chip */ - ret = sim3x_read_info(bank); - if (ret != ERROR_OK) - return ret; - - /* Part */ - if (sim3x_info->part_family && sim3x_info->part_number) { - printed = snprintf(buf, buf_size, "SiM3%c%d", sim3x_info->part_family, sim3x_info->part_number); - buf += printed; - buf_size -= printed; - - if (buf_size <= 0) - return ERROR_BUF_TOO_SMALL; - - /* Revision */ - if (sim3x_info->device_revision && sim3x_info->device_revision <= 'Z' - 'A') { - printed = snprintf(buf, buf_size, "-%c", sim3x_info->device_revision + 'A'); - buf += printed; - buf_size -= printed; - - if (buf_size <= 0) - return ERROR_BUF_TOO_SMALL; - - /* Package */ - printed = snprintf(buf, buf_size, "-G%s", sim3x_info->device_package); - buf += printed; - buf_size -= printed; - - if (buf_size <= 0) - return ERROR_BUF_TOO_SMALL; - } - } - - /* Print flash size */ - printed = snprintf(buf, buf_size, " flash_size = %dKB", sim3x_info->flash_size_kb); - buf_size -= printed; - - if (buf_size <= 0) - return ERROR_BUF_TOO_SMALL; - - return ERROR_OK; -} -/** - * reg 31:8 - no effect - * reg 7:4 - bank - * reg 3:2 - register - * reg 1:0 - no effect - */ -static int ap_write_register(struct adiv5_dap *dap, unsigned reg, uint32_t value) -{ - int retval; - LOG_DEBUG("DAP_REG[0x%02x] <- %08" PRIX32, reg, value); - - retval = dap_queue_ap_write(dap_ap(dap, SIM3X_AP), reg, value); - if (retval != ERROR_OK) { - LOG_DEBUG("DAP: failed to queue a write request"); - return retval; - } - - retval = dap_run(dap); - if (retval != ERROR_OK) { - LOG_DEBUG("DAP: dap_run failed"); - return retval; - } - - return ERROR_OK; -} - -static int ap_read_register(struct adiv5_dap *dap, unsigned reg, uint32_t *result) -{ - int retval; - - retval = dap_queue_ap_read(dap_ap(dap, SIM3X_AP), reg, result); - if (retval != ERROR_OK) { - LOG_DEBUG("DAP: failed to queue a read request"); - return retval; - } - - retval = dap_run(dap); - if (retval != ERROR_OK) { - LOG_DEBUG("DAP: dap_run failed"); - return retval; - } - - LOG_DEBUG("DAP_REG[0x%02x]: %08" PRIX32, reg, *result); - return ERROR_OK; -} - -static int ap_poll_register(struct adiv5_dap *dap, unsigned reg, uint32_t mask, uint32_t value, int timeout) -{ - uint32_t val; - int retval; - - do { - retval = ap_read_register(dap, reg, &val); - if (retval != ERROR_OK || (val & mask) == value) - return retval; - - alive_sleep(1); - } while (timeout--); - - LOG_DEBUG("DAP: polling timed out"); - return ERROR_FAIL; -} - -COMMAND_HANDLER(sim3x_mass_erase) -{ - uint32_t val; - int ret; - - struct target *target = get_current_target(CMD_CTX); - struct cortex_m_common *cortex_m = target_to_cm(target); - struct adiv5_dap *dap = cortex_m->armv7m.arm.dap; - - if (dap == NULL) { - /* Used debug interface doesn't support direct DAP access */ - LOG_ERROR("mass_erase can't be used by this debug interface"); - return ERROR_FAIL; - } - - ret = ap_read_register(dap, SIM3X_AP_ID, &val); - if (ret != ERROR_OK) - return ret; - - if (val != SIM3X_AP_ID_VALUE) { - LOG_ERROR("Wrong SIM3X_AP_ID"); - return ERROR_FAIL; - } - - /* Mass erase sequence */ - ret = ap_write_register(dap, SIM3X_AP_CTRL1, SIM3X_AP_CTRL1_RESET_REQ); - if (ret != ERROR_OK) - return ret; - - ret = ap_write_register(dap, SIM3X_AP_CTRL1, SIM3X_AP_CTRL1_RESET_REQ | SIM3X_AP_CTRL1_MASS_ERASE_REQ); - if (ret != ERROR_OK) - return ret; - - ret = ap_poll_register(dap, SIM3X_AP_CTRL1, SIM3X_AP_CTRL1_MASS_ERASE_REQ, 0x00000000, FLASH_BUSY_TIMEOUT); - if (ret != ERROR_OK) - return ret; - - ret = ap_write_register(dap, SIM3X_AP_CTRL1, 0x00000000); /* clear SIM3X_AP_CTRL1_RESET_REQ */ - if (ret != ERROR_OK) - return ret; - - LOG_INFO("Mass erase success"); - return ERROR_OK; -} - -COMMAND_HANDLER(sim3x_lock) -{ - uint32_t val; - int ret; - - struct target *target = get_current_target(CMD_CTX); - struct cortex_m_common *cortex_m = target_to_cm(target); - struct adiv5_dap *dap = cortex_m->armv7m.arm.dap; - - if (dap == NULL) { - /* Used debug interface doesn't support direct DAP access */ - LOG_INFO("Target can't by unlocked by this debug interface"); - - /* Core check */ - ret = target_read_u32(target, CPUID, &val); - if (ret != ERROR_OK) - return ret; - - if ((val & CPUID_CHECK_VALUE_MASK) != CPUID_CHECK_VALUE) { - LOG_ERROR("Target is not ARM CortexM3 or is already locked"); - return ERROR_FAIL; - } - } else { - /* check SIM3X_AP_ID */ - ret = ap_read_register(dap, SIM3X_AP_ID, &val); - if (ret != ERROR_OK) - return ret; - - if (val != SIM3X_AP_ID_VALUE) { - LOG_ERROR("Wrong SIM3X_AP_ID"); - return ERROR_FAIL; - } - - /* check if locked */ - ret = target_read_u32(target, CPUID, &val); - /* if correct value is read, then it will continue */ - if (ret != ERROR_OK || (val & CPUID_CHECK_VALUE_MASK) != CPUID_CHECK_VALUE) { - /* if correct value is'n read, then it will check SIM3X_AP_INIT_STAT register */ - ret = ap_read_register(dap, SIM3X_AP_INIT_STAT, &val); - if (ret != ERROR_OK) - return ret; - - if (val & SIM3X_AP_INIT_STAT_LOCK) { - LOG_INFO("Target is already locked"); - return ERROR_OK; - } else { - LOG_ERROR("Target doesn't seem to be locked but memory was not read correct"); - return ERROR_FAIL; - } - } - } - - ret = target_read_u32(target, LOCK_WORD_ADDRESS, &val); - if (ret != ERROR_OK) - return ret; - - if (val == LOCK_WORD_MCU_UNLOCKED) { - /* Lock Flash */ - uint8_t lock_word[4]; - target_buffer_set_u32(target, lock_word, 0xFFFFFFFE); - - /* Get Flash Bank */ - struct flash_bank *bank; - int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (retval != ERROR_OK) - return retval; - - ret = sim3x_flash_write(bank, lock_word, LOCK_WORD_ADDRESS, 4); - if (ERROR_OK != ret) - return ret; - - LOG_INFO("Target is successfully locked"); - return ERROR_OK; - } else if (val == LOCK_WORD_MCU_UNLOCKED_BY_FIRMWARE) { - /* Can't by locked again without erase, because LOCK_WORD is in FLASH */ - LOG_ERROR("Target is unlocked by firmware and can't by locked again without the lock page erase or mass erase"); - return ERROR_FAIL; - } else { - LOG_ERROR("Unexpected lock word value"); - - /* SIM3X_AP_ID_VALUE is not checked */ - if (dap == NULL) - LOG_INFO("Maybe this isn't a SiM3x MCU"); - - return ERROR_FAIL; - } -} - -static const struct command_registration sim3x_exec_command_handlers[] = { - { - .name = "mass_erase", - .mode = COMMAND_EXEC, - .help = "Erase the complete flash", - .usage = "", - .handler = sim3x_mass_erase, - }, - { - .name = "lock", - .mode = COMMAND_EXEC, - .help = "Locks the flash. Unlock by mass erase", - .usage = "", - .handler = sim3x_lock, - }, - COMMAND_REGISTRATION_DONE -}; - -static const struct command_registration sim3x_command_handlers[] = { - { - .name = "sim3x", - .mode = COMMAND_ANY, - .help = "sim3x flash command group", - .usage = "", - .chain = sim3x_exec_command_handlers, - }, - COMMAND_REGISTRATION_DONE -}; - -struct flash_driver sim3x_flash = { - .name = "sim3x", - .commands = sim3x_command_handlers, - .flash_bank_command = sim3x_flash_bank_command, - .erase = sim3x_flash_erase, - .protect = sim3x_flash_protect, - .write = sim3x_flash_write, - .read = default_flash_read, - .probe = sim3x_probe, - .auto_probe = sim3x_auto_probe, - .erase_check = default_flash_blank_check, - .protect_check = sim3x_flash_protect_check, - .info = sim3x_flash_info -};
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/69f466b5/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/spi.c ---------------------------------------------------------------------- diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/spi.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/spi.c deleted file mode 100755 index c8f51b9..0000000 --- a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/spi.c +++ /dev/null @@ -1,84 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2012 by George Harris * - * geo...@luminairecoffee.com * - * * - * Copyright (C) 2010 by Antonio Borneo * - * borneo.anto...@gmail.com * - * * - * 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 "spi.h" -#include <jtag/jtag.h> - - /* Shared table of known SPI flash devices for SPI-based flash drivers. Taken - * from device datasheets and Linux SPI flash drivers. */ -const struct flash_device flash_devices[] = { - /* name, erase_cmd, chip_erase_cmd, device_id, pagesize, sectorsize, size_in_bytes */ - FLASH_ID("st m25p05", 0xd8, 0xc7, 0x00102020, 0x80, 0x8000, 0x10000), - FLASH_ID("st m25p10", 0xd8, 0xc7, 0x00112020, 0x80, 0x8000, 0x20000), - FLASH_ID("st m25p20", 0xd8, 0xc7, 0x00122020, 0x100, 0x10000, 0x40000), - FLASH_ID("st m25p40", 0xd8, 0xc7, 0x00132020, 0x100, 0x10000, 0x80000), - FLASH_ID("st m25p80", 0xd8, 0xc7, 0x00142020, 0x100, 0x10000, 0x100000), - FLASH_ID("st m25p16", 0xd8, 0xc7, 0x00152020, 0x100, 0x10000, 0x200000), - FLASH_ID("st m25p32", 0xd8, 0xc7, 0x00162020, 0x100, 0x10000, 0x400000), - FLASH_ID("st m25p64", 0xd8, 0xc7, 0x00172020, 0x100, 0x10000, 0x800000), - FLASH_ID("st m25p128", 0xd8, 0xc7, 0x00182020, 0x100, 0x40000, 0x1000000), - FLASH_ID("st m45pe10", 0xd8, 0xd8, 0x00114020, 0x100, 0x10000, 0x20000), - FLASH_ID("st m45pe20", 0xd8, 0xd8, 0x00124020, 0x100, 0x10000, 0x40000), - FLASH_ID("st m45pe40", 0xd8, 0xd8, 0x00134020, 0x100, 0x10000, 0x80000), - FLASH_ID("st m45pe80", 0xd8, 0xd8, 0x00144020, 0x100, 0x10000, 0x100000), - FLASH_ID("sp s25fl004", 0xd8, 0xc7, 0x00120201, 0x100, 0x10000, 0x80000), - FLASH_ID("sp s25fl008", 0xd8, 0xc7, 0x00130201, 0x100, 0x10000, 0x100000), - FLASH_ID("sp s25fl016", 0xd8, 0xc7, 0x00140201, 0x100, 0x10000, 0x200000), - FLASH_ID("sp s25fl116k", 0xd8, 0xc7, 0x00154001, 0x100, 0x10000, 0x200000), - FLASH_ID("sp s25fl032", 0xd8, 0xc7, 0x00150201, 0x100, 0x10000, 0x400000), - FLASH_ID("sp s25fl132k", 0xd8, 0xc7, 0x00164001, 0x100, 0x10000, 0x400000), - FLASH_ID("sp s25fl064", 0xd8, 0xc7, 0x00160201, 0x100, 0x10000, 0x800000), - FLASH_ID("sp s25fl164k", 0xd8, 0xc7, 0x00174001, 0x100, 0x10000, 0x800000), - FLASH_ID("sp s25fl128", 0xd8, 0xc7, 0x00182001, 0x100, 0x10000, 0x1000000), - FLASH_ID("sp s25fl256", 0xd8, 0xc7, 0x00190201, 0x100, 0x10000, 0x2000000), - FLASH_ID("atmel 25f512", 0x52, 0xc7, 0x0065001f, 0x80, 0x8000, 0x10000), - FLASH_ID("atmel 25f1024", 0x52, 0x62, 0x0060001f, 0x100, 0x8000, 0x20000), - FLASH_ID("atmel 25f2048", 0x52, 0x62, 0x0063001f, 0x100, 0x10000, 0x40000), - FLASH_ID("atmel 25f4096", 0x52, 0x62, 0x0064001f, 0x100, 0x10000, 0x80000), - FLASH_ID("atmel 25fs040", 0xd7, 0xc7, 0x0004661f, 0x100, 0x10000, 0x80000), - FLASH_ID("mac 25l512", 0xd8, 0xc7, 0x001020c2, 0x010, 0x10000, 0x10000), - FLASH_ID("mac 25l1005", 0xd8, 0xc7, 0x001120c2, 0x010, 0x10000, 0x20000), - FLASH_ID("mac 25l2005", 0xd8, 0xc7, 0x001220c2, 0x010, 0x10000, 0x40000), - FLASH_ID("mac 25l4005", 0xd8, 0xc7, 0x001320c2, 0x010, 0x10000, 0x80000), - FLASH_ID("mac 25l8005", 0xd8, 0xc7, 0x001420c2, 0x010, 0x10000, 0x100000), - FLASH_ID("mac 25l1605", 0xd8, 0xc7, 0x001520c2, 0x100, 0x10000, 0x200000), - FLASH_ID("mac 25l3205", 0xd8, 0xc7, 0x001620c2, 0x100, 0x10000, 0x400000), - FLASH_ID("mac 25l6405", 0xd8, 0xc7, 0x001720c2, 0x100, 0x10000, 0x800000), - FLASH_ID("micron n25q064", 0xd8, 0xc7, 0x0017ba20, 0x100, 0x10000, 0x800000), - FLASH_ID("micron n25q128", 0xd8, 0xc7, 0x0018ba20, 0x100, 0x10000, 0x1000000), - FLASH_ID("win w25q80bv", 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000), - FLASH_ID("win w25q32fv", 0xd8, 0xc7, 0x001640ef, 0x100, 0x10000, 0x400000), - FLASH_ID("win w25q32dw", 0xd8, 0xc7, 0x001660ef, 0x100, 0x10000, 0x400000), - FLASH_ID("win w25q64cv", 0xd8, 0xc7, 0x001740ef, 0x100, 0x10000, 0x800000), - FLASH_ID("win w25q128fv", 0xd8, 0xc7, 0x001840ef, 0x100, 0x10000, 0x1000000), - FLASH_ID("gd gd25q20", 0x20, 0xc7, 0x00c84012, 0x100, 0x1000, 0x80000), - FLASH_ID("gd gd25q16c", 0xd8, 0xc7, 0x001540c8, 0x100, 0x10000, 0x200000), - FLASH_ID("gd gd25q32c", 0xd8, 0xc7, 0x001640c8, 0x100, 0x10000, 0x400000), - FLASH_ID("gd gd25q128c", 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000), - FLASH_ID(NULL, 0, 0, 0, 0, 0, 0) -}; http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/69f466b5/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/spi.h ---------------------------------------------------------------------- diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/spi.h b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/spi.h deleted file mode 100755 index 6e939b7..0000000 --- a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/spi.h +++ /dev/null @@ -1,58 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2012 by George Harris * - * geo...@luminairecoffee.com * - * * - * Copyright (C) 2010 by Antonio Borneo * - * borneo.anto...@gmail.com * - * * - * 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. * - ***************************************************************************/ - -/* data structure to maintain flash ids from different vendors */ -struct flash_device { - char *name; - uint8_t erase_cmd; - uint8_t chip_erase_cmd; - uint32_t device_id; - uint32_t pagesize; - unsigned long sectorsize; - unsigned long size_in_bytes; -}; - -#define FLASH_ID(n, es, ces, id, psize, ssize, size) \ -{ \ - .name = n, \ - .erase_cmd = es, \ - .chip_erase_cmd = ces, \ - .device_id = id, \ - .pagesize = psize, \ - .sectorsize = ssize, \ - .size_in_bytes = size \ -} - -extern const struct flash_device flash_devices[]; - -/* fields in SPI flash status register */ -#define SPIFLASH_BSY_BIT 0x00000001 /* WIP Bit of SPI SR on SMI SR */ -#define SPIFLASH_WE_BIT 0x00000002 /* WEL Bit of SPI SR on SMI SR */ - -/* SPI Flash Commands */ -#define SPIFLASH_READ_ID 0x9F /* Read Flash Identification */ -#define SPIFLASH_READ_STATUS 0x05 /* Read Status Register */ -#define SPIFLASH_WRITE_ENABLE 0x06 /* Write Enable */ -#define SPIFLASH_PAGE_PROGRAM 0x02 /* Page Program */ -#define SPIFLASH_FAST_READ 0x0B /* Fast Read */ -#define SPIFLASH_READ 0x03 /* Normal Read */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/69f466b5/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/stellaris.c ---------------------------------------------------------------------- diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/stellaris.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/stellaris.c deleted file mode 100755 index 0f50b41..0000000 --- a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/stellaris.c +++ /dev/null @@ -1,1457 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2006 by Magnus Lundin * - * lun...@mlu.mine.nu * - * * - * Copyright (C) 2008 by Spencer Oliver * - * s...@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., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - ***************************************************************************/ - -/*************************************************************************** -* STELLARIS flash is tested on LM3S811, LM3S6965, LM3s3748, more. -***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "jtag/interface.h" -#include "imp.h" -#include <target/algorithm.h> -#include <target/armv7m.h> - -#define DID0_VER(did0) ((did0 >> 28)&0x07) - -/* STELLARIS control registers */ -#define SCB_BASE 0x400FE000 -#define DID0 0x000 -#define DID1 0x004 -#define DC0 0x008 -#define DC1 0x010 -#define DC2 0x014 -#define DC3 0x018 -#define DC4 0x01C - -#define RIS 0x050 -#define RCC 0x060 -#define PLLCFG 0x064 -#define RCC2 0x070 -#define NVMSTAT 0x1a0 - -/* "legacy" flash memory protection registers (64KB max) */ -#define FMPRE 0x130 -#define FMPPE 0x134 - -/* new flash memory protection registers (for more than 64KB) */ -#define FMPRE0 0x200 /* PRE1 = PRE0 + 4, etc */ -#define FMPPE0 0x400 /* PPE1 = PPE0 + 4, etc */ - -#define USECRL 0x140 - -#define FLASH_CONTROL_BASE 0x400FD000 -#define FLASH_FMA (FLASH_CONTROL_BASE | 0x000) -#define FLASH_FMD (FLASH_CONTROL_BASE | 0x004) -#define FLASH_FMC (FLASH_CONTROL_BASE | 0x008) -#define FLASH_CRIS (FLASH_CONTROL_BASE | 0x00C) -#define FLASH_CIM (FLASH_CONTROL_BASE | 0x010) -#define FLASH_MISC (FLASH_CONTROL_BASE | 0x014) -#define FLASH_FSIZE (FLASH_CONTROL_BASE | 0xFC0) -#define FLASH_SSIZE (FLASH_CONTROL_BASE | 0xFC4) - -#define AMISC 1 -#define PMISC 2 - -#define AMASK 1 -#define PMASK 2 - -/* Flash Controller Command bits */ -#define FMC_WRKEY (0xA442 << 16) -#define FMC_COMT (1 << 3) -#define FMC_MERASE (1 << 2) -#define FMC_ERASE (1 << 1) -#define FMC_WRITE (1 << 0) - -/* STELLARIS constants */ - -/* values to write in FMA to commit write-"once" values */ -#define FLASH_FMA_PRE(x) (2 * (x)) /* for FMPPREx */ -#define FLASH_FMA_PPE(x) (2 * (x) + 1) /* for FMPPPEx */ - -static void stellaris_read_clock_info(struct flash_bank *bank); -static int stellaris_mass_erase(struct flash_bank *bank); - -struct stellaris_flash_bank { - /* chip id register */ - uint32_t did0; - uint32_t did1; - uint32_t dc0; - uint32_t dc1; - uint32_t fsize; - uint32_t ssize; - - const char *target_name; - uint8_t target_class; - - uint32_t sramsiz; - /* flash geometry */ - uint32_t num_pages; - uint32_t pagesize; - - /* main clock status */ - uint32_t rcc; - uint32_t rcc2; - uint8_t mck_valid; - uint8_t xtal_mask; - uint32_t iosc_freq; - uint32_t mck_freq; - const char *iosc_desc; - const char *mck_desc; -}; - -/* Autogenerated by contrib/gen-stellaris-part-header.pl */ -/* From Stellaris Firmware Development Package revision 9453 */ -static const struct { - uint8_t class; - uint8_t partno; - const char *partname; -} StellarisParts[] = { - {0x00, 0x01, "LM3S101"}, - {0x00, 0x02, "LM3S102"}, - {0x01, 0xBF, "LM3S1110"}, - {0x01, 0xC3, "LM3S1133"}, - {0x01, 0xC5, "LM3S1138"}, - {0x01, 0xC1, "LM3S1150"}, - {0x01, 0xC4, "LM3S1162"}, - {0x01, 0xC2, "LM3S1165"}, - {0x01, 0xEC, "LM3S1166"}, - {0x01, 0xC6, "LM3S1332"}, - {0x01, 0xBC, "LM3S1435"}, - {0x01, 0xBA, "LM3S1439"}, - {0x01, 0xBB, "LM3S1512"}, - {0x01, 0xC7, "LM3S1538"}, - {0x01, 0xDB, "LM3S1601"}, - {0x03, 0x06, "LM3S1607"}, - {0x01, 0xDA, "LM3S1608"}, - {0x01, 0xC0, "LM3S1620"}, - {0x04, 0xCD, "LM3S1621"}, - {0x03, 0x03, "LM3S1625"}, - {0x03, 0x04, "LM3S1626"}, - {0x03, 0x05, "LM3S1627"}, - {0x01, 0xB3, "LM3S1635"}, - {0x01, 0xEB, "LM3S1636"}, - {0x01, 0xBD, "LM3S1637"}, - {0x04, 0xB1, "LM3S1651"}, - {0x01, 0xB9, "LM3S1751"}, - {0x03, 0x10, "LM3S1776"}, - {0x04, 0x16, "LM3S1811"}, - {0x04, 0x3D, "LM3S1816"}, - {0x01, 0xB4, "LM3S1850"}, - {0x01, 0xDD, "LM3S1911"}, - {0x01, 0xDC, "LM3S1918"}, - {0x01, 0xB7, "LM3S1937"}, - {0x01, 0xBE, "LM3S1958"}, - {0x01, 0xB5, "LM3S1960"}, - {0x01, 0xB8, "LM3S1968"}, - {0x01, 0xEA, "LM3S1969"}, - {0x04, 0xCE, "LM3S1B21"}, - {0x06, 0xCA, "LM3S1C21"}, - {0x06, 0xCB, "LM3S1C26"}, - {0x06, 0x98, "LM3S1C58"}, - {0x06, 0xB0, "LM3S1D21"}, - {0x06, 0xCC, "LM3S1D26"}, - {0x06, 0x1D, "LM3S1F11"}, - {0x06, 0x1B, "LM3S1F16"}, - {0x06, 0xAF, "LM3S1G21"}, - {0x06, 0x95, "LM3S1G58"}, - {0x06, 0x1E, "LM3S1H11"}, - {0x06, 0x1C, "LM3S1H16"}, - {0x04, 0x0F, "LM3S1J11"}, - {0x04, 0x3C, "LM3S1J16"}, - {0x04, 0x0E, "LM3S1N11"}, - {0x04, 0x3B, "LM3S1N16"}, - {0x04, 0xB2, "LM3S1P51"}, - {0x04, 0x9E, "LM3S1R21"}, - {0x04, 0xC9, "LM3S1R26"}, - {0x04, 0x30, "LM3S1W16"}, - {0x04, 0x2F, "LM3S1Z16"}, - {0x01, 0x51, "LM3S2110"}, - {0x01, 0x84, "LM3S2139"}, - {0x03, 0x39, "LM3S2276"}, - {0x01, 0xA2, "LM3S2410"}, - {0x01, 0x59, "LM3S2412"}, - {0x01, 0x56, "LM3S2432"}, - {0x01, 0x5A, "LM3S2533"}, - {0x01, 0xE1, "LM3S2601"}, - {0x01, 0xE0, "LM3S2608"}, - {0x03, 0x33, "LM3S2616"}, - {0x01, 0x57, "LM3S2620"}, - {0x01, 0x85, "LM3S2637"}, - {0x01, 0x53, "LM3S2651"}, - {0x03, 0x80, "LM3S2671"}, - {0x03, 0x50, "LM3S2678"}, - {0x01, 0xA4, "LM3S2730"}, - {0x01, 0x52, "LM3S2739"}, - {0x03, 0x3A, "LM3S2776"}, - {0x04, 0x6D, "LM3S2793"}, - {0x01, 0xE3, "LM3S2911"}, - {0x01, 0xE2, "LM3S2918"}, - {0x01, 0xED, "LM3S2919"}, - {0x01, 0x54, "LM3S2939"}, - {0x01, 0x8F, "LM3S2948"}, - {0x01, 0x58, "LM3S2950"}, - {0x01, 0x55, "LM3S2965"}, - {0x04, 0x6C, "LM3S2B93"}, - {0x06, 0x94, "LM3S2D93"}, - {0x06, 0x93, "LM3S2U93"}, - {0x00, 0x19, "LM3S300"}, - {0x00, 0x11, "LM3S301"}, - {0x00, 0x1A, "LM3S308"}, - {0x00, 0x12, "LM3S310"}, - {0x00, 0x13, "LM3S315"}, - {0x00, 0x14, "LM3S316"}, - {0x00, 0x17, "LM3S317"}, - {0x00, 0x15, "LM3S328"}, - {0x03, 0x08, "LM3S3634"}, - {0x03, 0x43, "LM3S3651"}, - {0x04, 0xC8, "LM3S3654"}, - {0x03, 0x44, "LM3S3739"}, - {0x03, 0x49, "LM3S3748"}, - {0x03, 0x45, "LM3S3749"}, - {0x04, 0x42, "LM3S3826"}, - {0x04, 0x41, "LM3S3J26"}, - {0x04, 0x40, "LM3S3N26"}, - {0x04, 0x3F, "LM3S3W26"}, - {0x04, 0x3E, "LM3S3Z26"}, - {0x03, 0x81, "LM3S5632"}, - {0x04, 0x0C, "LM3S5651"}, - {0x03, 0x8A, "LM3S5652"}, - {0x04, 0x4D, "LM3S5656"}, - {0x03, 0x91, "LM3S5662"}, - {0x03, 0x96, "LM3S5732"}, - {0x03, 0x97, "LM3S5737"}, - {0x03, 0xA0, "LM3S5739"}, - {0x03, 0x99, "LM3S5747"}, - {0x03, 0xA7, "LM3S5749"}, - {0x03, 0x9A, "LM3S5752"}, - {0x03, 0x9C, "LM3S5762"}, - {0x04, 0x69, "LM3S5791"}, - {0x04, 0x0B, "LM3S5951"}, - {0x04, 0x4E, "LM3S5956"}, - {0x04, 0x68, "LM3S5B91"}, - {0x06, 0x2E, "LM3S5C31"}, - {0x06, 0x2C, "LM3S5C36"}, - {0x06, 0x5E, "LM3S5C51"}, - {0x06, 0x5B, "LM3S5C56"}, - {0x06, 0x5F, "LM3S5D51"}, - {0x06, 0x5C, "LM3S5D56"}, - {0x06, 0x87, "LM3S5D91"}, - {0x06, 0x2D, "LM3S5G31"}, - {0x06, 0x1F, "LM3S5G36"}, - {0x06, 0x5D, "LM3S5G51"}, - {0x06, 0x4F, "LM3S5G56"}, - {0x04, 0x09, "LM3S5K31"}, - {0x04, 0x4A, "LM3S5K36"}, - {0x04, 0x0A, "LM3S5P31"}, - {0x04, 0x48, "LM3S5P36"}, - {0x04, 0xB6, "LM3S5P3B"}, - {0x04, 0x0D, "LM3S5P51"}, - {0x04, 0x4C, "LM3S5P56"}, - {0x04, 0x07, "LM3S5R31"}, - {0x04, 0x4B, "LM3S5R36"}, - {0x04, 0x47, "LM3S5T36"}, - {0x06, 0x7F, "LM3S5U91"}, - {0x04, 0x46, "LM3S5Y36"}, - {0x00, 0x2A, "LM3S600"}, - {0x00, 0x21, "LM3S601"}, - {0x00, 0x2B, "LM3S608"}, - {0x00, 0x22, "LM3S610"}, - {0x01, 0xA1, "LM3S6100"}, - {0x00, 0x23, "LM3S611"}, - {0x01, 0x74, "LM3S6110"}, - {0x00, 0x24, "LM3S612"}, - {0x00, 0x25, "LM3S613"}, - {0x00, 0x26, "LM3S615"}, - {0x00, 0x28, "LM3S617"}, - {0x00, 0x29, "LM3S618"}, - {0x00, 0x27, "LM3S628"}, - {0x01, 0xA5, "LM3S6420"}, - {0x01, 0x82, "LM3S6422"}, - {0x01, 0x75, "LM3S6432"}, - {0x01, 0x76, "LM3S6537"}, - {0x01, 0x71, "LM3S6610"}, - {0x01, 0xE7, "LM3S6611"}, - {0x01, 0xE6, "LM3S6618"}, - {0x01, 0x83, "LM3S6633"}, - {0x01, 0x8B, "LM3S6637"}, - {0x01, 0xA3, "LM3S6730"}, - {0x01, 0x77, "LM3S6753"}, - {0x01, 0xE9, "LM3S6911"}, - {0x01, 0xE8, "LM3S6918"}, - {0x01, 0x89, "LM3S6938"}, - {0x01, 0x72, "LM3S6950"}, - {0x01, 0x78, "LM3S6952"}, - {0x01, 0x73, "LM3S6965"}, - {0x06, 0xAA, "LM3S6C11"}, - {0x06, 0xAC, "LM3S6C65"}, - {0x06, 0x9F, "LM3S6G11"}, - {0x06, 0xAB, "LM3S6G65"}, - {0x00, 0x38, "LM3S800"}, - {0x00, 0x31, "LM3S801"}, - {0x00, 0x39, "LM3S808"}, - {0x00, 0x32, "LM3S811"}, - {0x00, 0x33, "LM3S812"}, - {0x00, 0x34, "LM3S815"}, - {0x00, 0x36, "LM3S817"}, - {0x00, 0x37, "LM3S818"}, - {0x00, 0x35, "LM3S828"}, - {0x01, 0x64, "LM3S8530"}, - {0x01, 0x8E, "LM3S8538"}, - {0x01, 0x61, "LM3S8630"}, - {0x01, 0x63, "LM3S8730"}, - {0x01, 0x8D, "LM3S8733"}, - {0x01, 0x86, "LM3S8738"}, - {0x01, 0x65, "LM3S8930"}, - {0x01, 0x8C, "LM3S8933"}, - {0x01, 0x88, "LM3S8938"}, - {0x01, 0xA6, "LM3S8962"}, - {0x01, 0x62, "LM3S8970"}, - {0x01, 0xD7, "LM3S8971"}, - {0x06, 0xAE, "LM3S8C62"}, - {0x06, 0xAD, "LM3S8G62"}, - {0x04, 0xCF, "LM3S9781"}, - {0x04, 0x67, "LM3S9790"}, - {0x04, 0x6B, "LM3S9792"}, - {0x04, 0x2D, "LM3S9971"}, - {0x04, 0x20, "LM3S9997"}, - {0x04, 0xD0, "LM3S9B81"}, - {0x04, 0x66, "LM3S9B90"}, - {0x04, 0x6A, "LM3S9B92"}, - {0x04, 0x6E, "LM3S9B95"}, - {0x04, 0x6F, "LM3S9B96"}, - {0x04, 0x1D, "LM3S9BN2"}, - {0x04, 0x1E, "LM3S9BN5"}, - {0x04, 0x1F, "LM3S9BN6"}, - {0x06, 0x70, "LM3S9C97"}, - {0x06, 0xA9, "LM3S9D81"}, - {0x06, 0x7E, "LM3S9D90"}, - {0x06, 0x92, "LM3S9D92"}, - {0x06, 0x9D, "LM3S9D96"}, - {0x06, 0x7B, "LM3S9DN5"}, - {0x06, 0x7C, "LM3S9DN6"}, - {0x06, 0x60, "LM3S9G97"}, - {0x06, 0x79, "LM3S9GN5"}, - {0x04, 0x1B, "LM3S9L71"}, - {0x04, 0x18, "LM3S9L97"}, - {0x06, 0xA8, "LM3S9U81"}, - {0x06, 0x7D, "LM3S9U90"}, - {0x06, 0x90, "LM3S9U92"}, - {0x06, 0x9B, "LM3S9U96"}, - {0x05, 0x01, "LM4F120B2QR/TM4C1233C3PM"}, - {0x05, 0x02, "LM4F120C4QR/TM4C1233D5PM"}, - {0x05, 0x03, "LM4F120E5QR/TM4C1233E6PM"}, - {0x05, 0x04, "LM4F120H5QR/TM4C1233H6PM"}, - {0x05, 0x08, "LM4F121B2QR/TM4C1232C3PM"}, - {0x05, 0x09, "LM4F121C4QR/TM4C1232D5PM"}, - {0x05, 0x0A, "LM4F121E5QR/TM4C1232E6PM"}, - {0x05, 0x0B, "LM4F121H5QR/TM4C1232H6PM"}, - {0x05, 0x10, "LM4F110E5QR/TM4C1231E6PM"}, - {0x05, 0x11, "LM4F110H5QR/TM4C1231H6PM"}, - {0x05, 0x18, "LM4F110B2QR/TM4C1231C3PM"}, - {0x05, 0x19, "LM4F110C4QR/TM4C1231D5PM"}, - {0x05, 0x20, "LM4F111E5QR/TM4C1230E6PM"}, - {0x05, 0x21, "LM4F111H5QR/TM4C1230H6PM"}, - {0x05, 0x22, "LM4F111B2QR/TM4C1230C3PM"}, - {0x05, 0x23, "LM4F111C4QR/TM4C1230D5PM"}, - {0x05, 0x30, "LM4F112E5QC/TM4C1231E6PZ"}, - {0x05, 0x31, "LM4F112H5QC/TM4C1231H6PZ"}, - {0x05, 0x35, "LM4F112H5QD/TM4C1231H6PGE"}, - {0x05, 0x36, "LM4F112C4QC/TM4C1231D5PZ"}, - {0x05, 0x40, "LM4F130E5QR/TM4C1237E6PM"}, - {0x05, 0x41, "LM4F130H5QR/TM4C1237H6PM"}, - {0x05, 0x48, "LM4F130C4QR/TM4C1237D5PM"}, - {0x05, 0x50, "LM4F131E5QR/TM4C1236E6PM"}, - {0x05, 0x51, "LM4F131H5QR/TM4C1236H6PM"}, - {0x05, 0x52, "LM4F131C4QR/TM4C1236D5PM"}, - {0x05, 0x60, "LM4F132E5QC/TM4C1237E6PZ"}, - {0x05, 0x61, "LM4F132H5QC/TM4C1237H6PZ"}, - {0x05, 0x65, "LM4F132H5QD/TM4C1237H6PGE"}, - {0x05, 0x66, "LM4F132C4QC/TM4C1237D5PZ"}, - {0x05, 0x70, "LM4F210E5QR/TM4C123BE6PM"}, - {0x05, 0x73, "LM4F210H5QR/TM4C123BH6PM"}, - {0x05, 0x80, "LM4F211E5QR/TM4C123AE6PM"}, - {0x05, 0x83, "LM4F211H5QR/TM4C123AH6PM"}, - {0x05, 0xA0, "LM4F230E5QR/TM4C123GE6PM"}, - {0x05, 0xA1, "LM4F230H5QR/TM4C123GH6PM"}, - {0x05, 0xB0, "LM4F231E5QR/TM4C123FE6PM"}, - {0x05, 0xB1, "LM4F231H5QR/TM4C123FH6PM"}, - {0x05, 0xC0, "LM4F232E5QC/TM4C123GE6PZ"}, - {0x05, 0xC1, "LM4F232H5QC/TM4C123GH6PZ"}, - {0x05, 0xC3, "LM4F212E5QC/TM4C123BE6PZ"}, - {0x05, 0xC4, "LM4F212H5QC/TM4C123BH6PZ"}, - {0x05, 0xC5, "LM4F232H5QD/TM4C123GH6PGE"}, - {0x05, 0xC6, "LM4F212H5QD/TM4C123BH6PGE"}, - {0x05, 0xD0, "LM4F122C4QC/TM4C1233D5PZ"}, - {0x05, 0xD1, "LM4F122E5QC/TM4C1233E6PZ"}, - {0x05, 0xD2, "LM4F122H5QC/TM4C1233H6PZ"}, - {0x05, 0xD6, "LM4F122H5QD/TM4C1233H6PGE"}, - {0x05, 0xE1, "LM4FSXLH5BB"}, - {0x05, 0xE3, "LM4F232H5BB/TM4C123GH6ZRB"}, - {0x05, 0xE4, "LM4FS99H5BB"}, - {0x05, 0xE5, "LM4FS1AH5BB"}, - {0x05, 0xE9, "LM4F212H5BB/TM4C123BH6ZRB"}, - {0x05, 0xEA, "LM4FS1GH5BB"}, - {0x05, 0xF0, "TM4C123GH6ZXR"}, - {0x0A, 0x19, "TM4C1290NCPDT"}, - {0x0A, 0x1B, "TM4C1290NCZAD"}, - {0x0A, 0x1C, "TM4C1292NCPDT"}, - {0x0A, 0x1E, "TM4C1292NCZAD"}, - {0x0A, 0x1F, "TM4C1294NCPDT"}, - {0x0A, 0x21, "TM4C1294NCZAD"}, - {0x0A, 0x22, "TM4C1297NCZAD"}, - {0x0A, 0x23, "TM4C1299NCZAD"}, - {0x0A, 0x24, "TM4C129CNCPDT"}, - {0x0A, 0x26, "TM4C129CNCZAD"}, - {0x0A, 0x27, "TM4C129DNCPDT"}, - {0x0A, 0x29, "TM4C129DNCZAD"}, - {0x0A, 0x2D, "TM4C129ENCPDT"}, - {0x0A, 0x2F, "TM4C129ENCZAD"}, - {0x0A, 0x30, "TM4C129LNCZAD"}, - {0x0A, 0x32, "TM4C129XNCZAD"}, - {0x0A, 0x34, "TM4C1294KCPDT"}, - {0x0A, 0x35, "TM4C129EKCPDT"}, - {0x0A, 0x36, "TM4C1299KCZAD"}, - {0x0A, 0x37, "TM4C129XKCZAD"}, - {0xFF, 0x00, "Unknown Part"} -}; - -static const char * const StellarisClassname[] = { - "Sandstorm", - "Fury", - "Unknown", - "DustDevil", - "Tempest", - "Blizzard/TM4C123x", - "Firestorm", - "", - "", - "", - "Snowflake", -}; - -/*************************************************************************** -* openocd command interface * -***************************************************************************/ - -/* flash_bank stellaris <base> <size> 0 0 <target#> - */ -FLASH_BANK_COMMAND_HANDLER(stellaris_flash_bank_command) -{ - struct stellaris_flash_bank *stellaris_info; - - if (CMD_ARGC < 6) - return ERROR_COMMAND_SYNTAX_ERROR; - - stellaris_info = calloc(sizeof(struct stellaris_flash_bank), 1); - bank->base = 0x0; - bank->driver_priv = stellaris_info; - - stellaris_info->target_name = "Unknown target"; - - /* part wasn't probed for info yet */ - stellaris_info->did1 = 0; - - /* TODO Specify the main crystal speed in kHz using an optional - * argument; ditto, the speed of an external oscillator used - * instead of a crystal. Avoid programming flash using IOSC. - */ - return ERROR_OK; -} - -static int get_stellaris_info(struct flash_bank *bank, char *buf, int buf_size) -{ - int printed; - struct stellaris_flash_bank *stellaris_info = bank->driver_priv; - - if (stellaris_info->did1 == 0) - return ERROR_FLASH_BANK_NOT_PROBED; - - /* Read main and master clock freqency register */ - stellaris_read_clock_info(bank); - - printed = snprintf(buf, - buf_size, - "\nTI/LMI Stellaris information: Chip is " - "class %i (%s) %s rev %c%i\n", - stellaris_info->target_class, - StellarisClassname[stellaris_info->target_class], - stellaris_info->target_name, - (int)('A' + ((stellaris_info->did0 >> 8) & 0xFF)), - (int)((stellaris_info->did0) & 0xFF)); - buf += printed; - buf_size -= printed; - - printed = snprintf(buf, - buf_size, - "did1: 0x%8.8" PRIx32 ", arch: 0x%4.4" PRIx32 - ", eproc: %s, ramsize: %" PRIu32 "k, flashsize: %" PRIu32 "k\n", - stellaris_info->did1, - stellaris_info->did1, - "ARMv7M", - stellaris_info->sramsiz, - (uint32_t)(stellaris_info->num_pages * stellaris_info->pagesize / 1024)); - buf += printed; - buf_size -= printed; - - snprintf(buf, - buf_size, - "master clock: %ikHz%s, " - "rcc is 0x%" PRIx32 ", rcc2 is 0x%" PRIx32 ", " - "pagesize: %" PRIu32 ", pages: %" PRIu32, - (int)(stellaris_info->mck_freq / 1000), - stellaris_info->mck_desc, - stellaris_info->rcc, - stellaris_info->rcc2, - stellaris_info->pagesize, - stellaris_info->num_pages); - - return ERROR_OK; -} - -/*************************************************************************** -* chip identification and status * -***************************************************************************/ - -/* Set the flash timimg register to match current clocking */ -static void stellaris_set_flash_timing(struct flash_bank *bank) -{ - struct stellaris_flash_bank *stellaris_info = bank->driver_priv; - struct target *target = bank->target; - uint32_t usecrl = (stellaris_info->mck_freq/1000000ul-1); - - /* only valid for Sandstorm and Fury class devices */ - if (stellaris_info->target_class > 1) - return; - - LOG_DEBUG("usecrl = %i", (int)(usecrl)); - target_write_u32(target, SCB_BASE | USECRL, usecrl); -} - -static const unsigned rcc_xtal[32] = { - [0x00] = 1000000, /* no pll */ - [0x01] = 1843200, /* no pll */ - [0x02] = 2000000, /* no pll */ - [0x03] = 2457600, /* no pll */ - - [0x04] = 3579545, - [0x05] = 3686400, - [0x06] = 4000000, /* usb */ - [0x07] = 4096000, - - [0x08] = 4915200, - [0x09] = 5000000, /* usb */ - [0x0a] = 5120000, - [0x0b] = 6000000, /* (reset) usb */ - - [0x0c] = 6144000, - [0x0d] = 7372800, - [0x0e] = 8000000, /* usb */ - [0x0f] = 8192000, - - /* parts before DustDevil use just 4 bits for xtal spec */ - - [0x10] = 10000000, /* usb */ - [0x11] = 12000000, /* usb */ - [0x12] = 12288000, - [0x13] = 13560000, - - [0x14] = 14318180, - [0x15] = 16000000, /* usb */ - [0x16] = 16384000, -}; - -/** Read clock configuration and set stellaris_info->usec_clocks. */ -static void stellaris_read_clock_info(struct flash_bank *bank) -{ - struct stellaris_flash_bank *stellaris_info = bank->driver_priv; - struct target *target = bank->target; - uint32_t rcc, rcc2, pllcfg, sysdiv, usesysdiv, bypass, oscsrc; - unsigned xtal; - unsigned long mainfreq; - - target_read_u32(target, SCB_BASE | RCC, &rcc); - LOG_DEBUG("Stellaris RCC %" PRIx32 "", rcc); - - target_read_u32(target, SCB_BASE | RCC2, &rcc2); - LOG_DEBUG("Stellaris RCC2 %" PRIx32 "", rcc); - - target_read_u32(target, SCB_BASE | PLLCFG, &pllcfg); - LOG_DEBUG("Stellaris PLLCFG %" PRIx32 "", pllcfg); - - stellaris_info->rcc = rcc; - stellaris_info->rcc2 = rcc2; - - sysdiv = (rcc >> 23) & 0xF; - usesysdiv = (rcc >> 22) & 0x1; - bypass = (rcc >> 11) & 0x1; - oscsrc = (rcc >> 4) & 0x3; - xtal = (rcc >> 6) & stellaris_info->xtal_mask; - - /* NOTE: post-Sandstorm parts have RCC2 which may override - * parts of RCC ... with more sysdiv options, option for - * 32768 Hz mainfreq, PLL controls. On Sandstorm it reads - * as zero, so the "use RCC2" flag is always clear. - */ - if (rcc2 & (1 << 31)) { - sysdiv = (rcc2 >> 23) & 0x3F; - bypass = (rcc2 >> 11) & 0x1; - oscsrc = (rcc2 >> 4) & 0x7; - - /* FIXME Tempest parts have an additional lsb for - * fractional sysdiv (200 MHz / 2.5 == 80 MHz) - */ - } - - stellaris_info->mck_desc = ""; - - switch (oscsrc) { - case 0: /* MOSC */ - mainfreq = rcc_xtal[xtal]; - break; - case 1: /* IOSC */ - mainfreq = stellaris_info->iosc_freq; - stellaris_info->mck_desc = stellaris_info->iosc_desc; - break; - case 2: /* IOSC/4 */ - mainfreq = stellaris_info->iosc_freq / 4; - stellaris_info->mck_desc = stellaris_info->iosc_desc; - break; - case 3: /* lowspeed */ - /* Sandstorm doesn't have this 30K +/- 30% osc */ - mainfreq = 30000; - stellaris_info->mck_desc = " (±30%)"; - break; - case 8: /* hibernation osc */ - /* not all parts support hibernation */ - mainfreq = 32768; - break; - - default: /* NOTREACHED */ - mainfreq = 0; - break; - } - - /* PLL is used if it's not bypassed; its output is 200 MHz - * even when it runs at 400 MHz (adds divide-by-two stage). - */ - if (!bypass) - mainfreq = 200000000; - - if (usesysdiv) - stellaris_info->mck_freq = mainfreq/(1 + sysdiv); - else - stellaris_info->mck_freq = mainfreq; -} - -/* Read device id register, main clock frequency register and fill in driver info structure */ -static int stellaris_read_part_info(struct flash_bank *bank) -{ - struct stellaris_flash_bank *stellaris_info = bank->driver_priv; - struct target *target = bank->target; - uint32_t did0, did1, ver, fam; - int i; - - /* Read and parse chip identification register */ - target_read_u32(target, SCB_BASE | DID0, &did0); - target_read_u32(target, SCB_BASE | DID1, &did1); - target_read_u32(target, SCB_BASE | DC0, &stellaris_info->dc0); - target_read_u32(target, SCB_BASE | DC1, &stellaris_info->dc1); - LOG_DEBUG("did0 0x%" PRIx32 ", did1 0x%" PRIx32 ", dc0 0x%" PRIx32 ", dc1 0x%" PRIx32 "", - did0, did1, stellaris_info->dc0, stellaris_info->dc1); - - ver = DID0_VER(did0); - if ((ver != 0) && (ver != 1)) { - LOG_WARNING("Unknown did0 version, cannot identify target"); - return ERROR_FLASH_OPERATION_FAILED; - } - - if (did1 == 0) { - LOG_WARNING("Cannot identify target as a Stellaris"); - return ERROR_FLASH_OPERATION_FAILED; - } - - ver = did1 >> 28; - fam = (did1 >> 24) & 0xF; - if (((ver != 0) && (ver != 1)) || (fam != 0)) { - LOG_WARNING("Unknown did1 version/family."); - return ERROR_FLASH_OPERATION_FAILED; - } - - /* For Sandstorm, Fury, DustDevil: current data sheets say IOSC - * is 12 MHz, but some older parts have 15 MHz. A few data sheets - * even give _both_ numbers! We'll use current numbers; IOSC is - * always approximate. - * - * For Tempest: IOSC is calibrated, 16 MHz - * For Blizzard: IOSC is calibrated, 16 MHz - * For Firestorm: IOSC is calibrated, 16 MHz - */ - stellaris_info->iosc_freq = 12000000; - stellaris_info->iosc_desc = " (±30%)"; - stellaris_info->xtal_mask = 0x0f; - - /* get device class */ - if (DID0_VER(did0) > 0) { - stellaris_info->target_class = (did0 >> 16) & 0xFF; - } else { - /* Sandstorm class */ - stellaris_info->target_class = 0; - } - - switch (stellaris_info->target_class) { - case 0: /* Sandstorm */ - /* - * Current (2009-August) parts seem to be rev C2 and use 12 MHz. - * Parts before rev C0 used 15 MHz; some C0 parts use 15 MHz - * (LM3S618), but some other C0 parts are 12 MHz (LM3S811). - */ - if (((did0 >> 8) & 0xff) < 2) { - stellaris_info->iosc_freq = 15000000; - stellaris_info->iosc_desc = " (±50%)"; - } - break; - - case 1: /* Fury */ - break; - - case 4: /* Tempest */ - case 5: /* Blizzard */ - case 6: /* Firestorm */ - case 0xa: /* Snowflake */ - stellaris_info->iosc_freq = 16000000; /* +/- 1% */ - stellaris_info->iosc_desc = " (±1%)"; - /* FALL THROUGH */ - - case 3: /* DustDevil */ - stellaris_info->xtal_mask = 0x1f; - break; - - default: - LOG_WARNING("Unknown did0 class"); - } - - for (i = 0; StellarisParts[i].partno; i++) { - if ((StellarisParts[i].partno == ((did1 >> 16) & 0xFF)) && - (StellarisParts[i].class == stellaris_info->target_class)) - break; - } - - stellaris_info->target_name = StellarisParts[i].partname; - - stellaris_info->did0 = did0; - stellaris_info->did1 = did1; - - if (stellaris_info->target_class == 5) { /* Blizzard */ - target_read_u32(target, FLASH_FSIZE, &stellaris_info->fsize); - target_read_u32(target, FLASH_SSIZE, &stellaris_info->ssize); - - stellaris_info->num_pages = 2 * (1 + (stellaris_info->fsize & 0xFFFF)); - stellaris_info->sramsiz = (1 + (stellaris_info->ssize & 0xFFFF)) / 4; - stellaris_info->pagesize = 1024; - } else if (stellaris_info->target_class == 0xa) { /* Snowflake */ - target_read_u32(target, FLASH_FSIZE, &stellaris_info->fsize); - target_read_u32(target, FLASH_SSIZE, &stellaris_info->ssize); - - stellaris_info->pagesize = (1 << ((stellaris_info->fsize >> 16) & 7)) * 1024; - stellaris_info->num_pages = 2048 * (1 + (stellaris_info->fsize & 0xFFFF)) / - stellaris_info->pagesize; - stellaris_info->sramsiz = (1 + (stellaris_info->ssize & 0xFFFF)) / 4; - } else { - stellaris_info->num_pages = 2 * (1 + (stellaris_info->dc0 & 0xFFFF)); - stellaris_info->sramsiz = (1 + ((stellaris_info->dc0 >> 16) & 0xFFFF)) / 4; - stellaris_info->pagesize = 1024; - } - - /* REVISIT for at least Tempest parts, read NVMSTAT.FWB too. - * That exposes a 32-word Flash Write Buffer ... enabling - * writes of more than one word at a time. - */ - - return ERROR_OK; -} - -/*************************************************************************** -* flash operations * -***************************************************************************/ - -static int stellaris_protect_check(struct flash_bank *bank) -{ - struct stellaris_flash_bank *stellaris = bank->driver_priv; - struct target *target = bank->target; - uint32_t flash_sizek = stellaris->pagesize / 1024 * - stellaris->num_pages; - uint32_t fmppe_addr; - int status = ERROR_OK; - unsigned i; - - if (stellaris->did1 == 0) - return ERROR_FLASH_BANK_NOT_PROBED; - - for (i = 0; i < (unsigned) bank->num_sectors; i++) - bank->sectors[i].is_protected = -1; - - /* Read each Flash Memory Protection Program Enable (FMPPE) register - * to report any pages that we can't write. Ignore the Read Enable - * register (FMPRE). - */ - - if (stellaris->target_class >= 0x0a || flash_sizek > 64) - fmppe_addr = SCB_BASE | FMPPE0; - else - fmppe_addr = SCB_BASE | FMPPE; - - unsigned int page = 0, lockbitnum, lockbitcnt = flash_sizek / 2; - unsigned int bits_per_page = stellaris->pagesize / 2048; - /* Every lock bit always corresponds to a 2k region */ - for (lockbitnum = 0; lockbitnum < lockbitcnt; lockbitnum += 32) { - uint32_t fmppe; - - target_read_u32(target, fmppe_addr, &fmppe); - for (i = 0; i < 32 && lockbitnum + i < lockbitcnt; i++) { - bool protect = !(fmppe & (1 << i)); - if (bits_per_page) { - bank->sectors[page++].is_protected = protect; - i += bits_per_page - 1; - } else { /* 1024k pages, every lockbit covers 2 pages */ - bank->sectors[page++].is_protected = protect; - bank->sectors[page++].is_protected = protect; - } - } - fmppe_addr += 4; - } - - return status; -} - -static int stellaris_erase(struct flash_bank *bank, int first, int last) -{ - int banknr; - uint32_t flash_fmc, flash_cris; - struct stellaris_flash_bank *stellaris_info = bank->driver_priv; - struct target *target = bank->target; - - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (stellaris_info->did1 == 0) - return ERROR_FLASH_BANK_NOT_PROBED; - - if ((first < 0) || (last < first) || (last >= (int)stellaris_info->num_pages)) - return ERROR_FLASH_SECTOR_INVALID; - - if ((first == 0) && (last == ((int)stellaris_info->num_pages-1))) - return stellaris_mass_erase(bank); - - /* Refresh flash controller timing */ - stellaris_read_clock_info(bank); - stellaris_set_flash_timing(bank); - - /* Clear and disable flash programming interrupts */ - target_write_u32(target, FLASH_CIM, 0); - target_write_u32(target, FLASH_MISC, PMISC | AMISC); - - /* REVISIT this clobbers state set by any halted firmware ... - * it might want to process those IRQs. - */ - - for (banknr = first; banknr <= last; banknr++) { - /* Address is first word in page */ - target_write_u32(target, FLASH_FMA, banknr * stellaris_info->pagesize); - /* Write erase command */ - target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_ERASE); - /* Wait until erase complete */ - do { - target_read_u32(target, FLASH_FMC, &flash_fmc); - } while (flash_fmc & FMC_ERASE); - - /* Check acess violations */ - target_read_u32(target, FLASH_CRIS, &flash_cris); - if (flash_cris & (AMASK)) { - LOG_WARNING("Error erasing flash page %i, flash_cris 0x%" PRIx32 "", - banknr, flash_cris); - target_write_u32(target, FLASH_CRIS, 0); - return ERROR_FLASH_OPERATION_FAILED; - } - - bank->sectors[banknr].is_erased = 1; - } - - return ERROR_OK; -} - -static int stellaris_protect(struct flash_bank *bank, int set, int first, int last) -{ - struct stellaris_flash_bank *stellaris = bank->driver_priv; - struct target *target = bank->target; - uint32_t flash_fmc, flash_cris; - unsigned int bits_per_page = stellaris->pagesize / 2048; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (!set) { - LOG_ERROR("Hardware doesn't support page-level unprotect. " - "Try the 'recover' command."); - return ERROR_COMMAND_SYNTAX_ERROR; - } - - if (stellaris->did1 == 0) - return ERROR_FLASH_BANK_NOT_PROBED; - - if (stellaris->target_class == 0x03 && - !((stellaris->did0 >> 8) & 0xFF) && - !((stellaris->did0) & 0xFF)) { - LOG_ERROR("DustDevil A0 parts can't be unprotected, see errata; refusing to proceed"); - return ERROR_FLASH_OPERATION_FAILED; - } - - if (!bits_per_page && (first % 2 || !(last % 2))) { - LOG_ERROR("Can't protect unaligned pages"); - return ERROR_FLASH_SECTOR_INVALID; - } - - /* Refresh flash controller timing */ - stellaris_read_clock_info(bank); - stellaris_set_flash_timing(bank); - - /* Clear and disable flash programming interrupts */ - target_write_u32(target, FLASH_CIM, 0); - target_write_u32(target, FLASH_MISC, PMISC | AMISC); - - uint32_t flash_sizek = stellaris->pagesize / 1024 * - stellaris->num_pages; - uint32_t fmppe_addr; - - if (stellaris->target_class >= 0x0a || flash_sizek > 64) - fmppe_addr = SCB_BASE | FMPPE0; - else - fmppe_addr = SCB_BASE | FMPPE; - - int page = 0; - unsigned int lockbitnum, lockbitcnt = flash_sizek / 2; - /* Every lock bit always corresponds to a 2k region */ - for (lockbitnum = 0; lockbitnum < lockbitcnt; lockbitnum += 32) { - uint32_t fmppe; - - target_read_u32(target, fmppe_addr, &fmppe); - for (unsigned int i = 0; - i < 32 && lockbitnum + i < lockbitcnt; - i++) { - if (page >= first && page <= last) - fmppe &= ~(1 << i); - - if (bits_per_page) { - if (!((i + 1) % bits_per_page)) - page++; - } else { /* 1024k pages, every lockbit covers 2 pages */ - page += 2; - } - } - target_write_u32(target, fmppe_addr, fmppe); - - /* Commit FMPPE* */ - target_write_u32(target, FLASH_FMA, 1 + lockbitnum / 16); - /* Write commit command */ - target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_COMT); - - /* Wait until commit complete */ - do { - target_read_u32(target, FLASH_FMC, &flash_fmc); - } while (flash_fmc & FMC_COMT); - - /* Check access violations */ - target_read_u32(target, FLASH_CRIS, &flash_cris); - if (flash_cris & (AMASK)) { - LOG_WARNING("Error setting flash page protection, flash_cris 0x%" PRIx32 "", flash_cris); - target_write_u32(target, FLASH_CRIS, 0); - return ERROR_FLASH_OPERATION_FAILED; - } - - fmppe_addr += 4; - } - - return ERROR_OK; -} - -/* see contib/loaders/flash/stellaris.s for src */ - -static const uint8_t stellaris_write_code[] = { - /* write: */ - 0xDF, 0xF8, 0x40, 0x40, /* ldr r4, pFLASH_CTRL_BASE */ - 0xDF, 0xF8, 0x40, 0x50, /* ldr r5, FLASHWRITECMD */ - /* wait_fifo: */ - 0xD0, 0xF8, 0x00, 0x80, /* ldr r8, [r0, #0] */ - 0xB8, 0xF1, 0x00, 0x0F, /* cmp r8, #0 */ - 0x17, 0xD0, /* beq exit */ - 0x47, 0x68, /* ldr r7, [r0, #4] */ - 0x47, 0x45, /* cmp r7, r8 */ - 0xF7, 0xD0, /* beq wait_fifo */ - /* mainloop: */ - 0x22, 0x60, /* str r2, [r4, #0] */ - 0x02, 0xF1, 0x04, 0x02, /* add r2, r2, #4 */ - 0x57, 0xF8, 0x04, 0x8B, /* ldr r8, [r7], #4 */ - 0xC4, 0xF8, 0x04, 0x80, /* str r8, [r4, #4] */ - 0xA5, 0x60, /* str r5, [r4, #8] */ - /* busy: */ - 0xD4, 0xF8, 0x08, 0x80, /* ldr r8, [r4, #8] */ - 0x18, 0xF0, 0x01, 0x0F, /* tst r8, #1 */ - 0xFA, 0xD1, /* bne busy */ - 0x8F, 0x42, /* cmp r7, r1 */ - 0x28, 0xBF, /* it cs */ - 0x00, 0xF1, 0x08, 0x07, /* addcs r7, r0, #8 */ - 0x47, 0x60, /* str r7, [r0, #4] */ - 0x01, 0x3B, /* subs r3, r3, #1 */ - 0x03, 0xB1, /* cbz r3, exit */ - 0xE2, 0xE7, /* b wait_fifo */ - /* exit: */ - 0x00, 0xBE, /* bkpt #0 */ - - /* pFLASH_CTRL_BASE: */ - 0x00, 0xD0, 0x0F, 0x40, /* .word 0x400FD000 */ - /* FLASHWRITECMD: */ - 0x01, 0x00, 0x42, 0xA4 /* .word 0xA4420001 */ -}; -static int stellaris_write_block(struct flash_bank *bank, - const uint8_t *buffer, uint32_t offset, uint32_t wcount) -{ - struct target *target = bank->target; - uint32_t buffer_size = 16384; - struct working_area *source; - struct working_area *write_algorithm; - uint32_t address = bank->base + offset; - struct reg_param reg_params[4]; - struct armv7m_algorithm armv7m_info; - int retval = ERROR_OK; - - /* power of two, and multiple of word size */ - static const unsigned buf_min = 128; - - /* for small buffers it's faster not to download an algorithm */ - if (wcount * 4 < buf_min) - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - - LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32 "", - bank, buffer, offset, wcount); - - /* flash write code */ - if (target_alloc_working_area(target, sizeof(stellaris_write_code), - &write_algorithm) != ERROR_OK) { - LOG_DEBUG("no working area for block memory writes"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - /* plus a buffer big enough for this data */ - if (wcount * 4 < buffer_size) - buffer_size = wcount * 4; - - /* memory buffer */ - while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { - buffer_size /= 2; - if (buffer_size <= buf_min) { - target_free_working_area(target, write_algorithm); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - LOG_DEBUG("retry target_alloc_working_area(%s, size=%u)", - target_name(target), (unsigned) buffer_size); - } - - target_write_buffer(target, write_algorithm->address, - sizeof(stellaris_write_code), - stellaris_write_code); - - armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; - armv7m_info.core_mode = ARM_MODE_THREAD; - - init_reg_param(®_params[0], "r0", 32, PARAM_OUT); - init_reg_param(®_params[1], "r1", 32, PARAM_OUT); - init_reg_param(®_params[2], "r2", 32, PARAM_OUT); - init_reg_param(®_params[3], "r3", 32, PARAM_OUT); - - buf_set_u32(reg_params[0].value, 0, 32, source->address); - buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); - buf_set_u32(reg_params[2].value, 0, 32, address); - buf_set_u32(reg_params[3].value, 0, 32, wcount); - - retval = target_run_flash_async_algorithm(target, buffer, wcount, 4, - 0, NULL, - 4, reg_params, - source->address, source->size, - write_algorithm->address, 0, - &armv7m_info); - - if (retval == ERROR_FLASH_OPERATION_FAILED) - LOG_ERROR("error %d executing stellaris flash write algorithm", retval); - - target_free_working_area(target, write_algorithm); - target_free_working_area(target, source); - - destroy_reg_param(®_params[0]); - destroy_reg_param(®_params[1]); - destroy_reg_param(®_params[2]); - destroy_reg_param(®_params[3]); - - return retval; -} - -static int stellaris_write(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count) -{ - struct stellaris_flash_bank *stellaris_info = bank->driver_priv; - struct target *target = bank->target; - uint32_t address = offset; - uint32_t flash_cris, flash_fmc; - uint32_t words_remaining = (count / 4); - uint32_t bytes_remaining = (count & 0x00000003); - uint32_t bytes_written = 0; - int retval; - - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " count=%08" PRIx32 "", - bank, buffer, offset, count); - - if (stellaris_info->did1 == 0) - return ERROR_FLASH_BANK_NOT_PROBED; - - if (offset & 0x3) { - LOG_WARNING("offset size must be word aligned"); - return ERROR_FLASH_DST_BREAKS_ALIGNMENT; - } - - if (offset + count > bank->size) - return ERROR_FLASH_DST_OUT_OF_BANK; - - /* Refresh flash controller timing */ - stellaris_read_clock_info(bank); - stellaris_set_flash_timing(bank); - - /* Clear and disable flash programming interrupts */ - target_write_u32(target, FLASH_CIM, 0); - target_write_u32(target, FLASH_MISC, PMISC | AMISC); - - /* REVISIT this clobbers state set by any halted firmware ... - * it might want to process those IRQs. - */ - - /* multiple words to be programmed? */ - if (words_remaining > 0) { - /* try using a block write */ - retval = stellaris_write_block(bank, buffer, offset, - words_remaining); - if (retval != ERROR_OK) { - if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { - LOG_DEBUG("writing flash word-at-a-time"); - } else if (retval == ERROR_FLASH_OPERATION_FAILED) { - /* if an error occured, we examine the reason, and quit */ - target_read_u32(target, FLASH_CRIS, &flash_cris); - - LOG_ERROR("flash writing failed with CRIS: 0x%" PRIx32 "", flash_cris); - return ERROR_FLASH_OPERATION_FAILED; - } - } else { - buffer += words_remaining * 4; - address += words_remaining * 4; - words_remaining = 0; - } - } - - while (words_remaining > 0) { - if (!(address & 0xff)) - LOG_DEBUG("0x%" PRIx32 "", address); - - /* Program one word */ - target_write_u32(target, FLASH_FMA, address); - target_write_buffer(target, FLASH_FMD, 4, buffer); - target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_WRITE); - /* LOG_DEBUG("0x%x 0x%x 0x%x",address,buf_get_u32(buffer, 0, 32),FMC_WRKEY | FMC_WRITE); */ - /* Wait until write complete */ - do { - target_read_u32(target, FLASH_FMC, &flash_fmc); - } while (flash_fmc & FMC_WRITE); - - buffer += 4; - address += 4; - words_remaining--; - } - - if (bytes_remaining) { - uint8_t last_word[4] = {0xff, 0xff, 0xff, 0xff}; - - /* copy the last remaining bytes into the write buffer */ - memcpy(last_word, buffer+bytes_written, bytes_remaining); - - if (!(address & 0xff)) - LOG_DEBUG("0x%" PRIx32 "", address); - - /* Program one word */ - target_write_u32(target, FLASH_FMA, address); - target_write_buffer(target, FLASH_FMD, 4, last_word); - target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_WRITE); - /* LOG_DEBUG("0x%x 0x%x 0x%x",address,buf_get_u32(buffer, 0, 32),FMC_WRKEY | FMC_WRITE); */ - /* Wait until write complete */ - do { - target_read_u32(target, FLASH_FMC, &flash_fmc); - } while (flash_fmc & FMC_WRITE); - } - - /* Check access violations */ - target_read_u32(target, FLASH_CRIS, &flash_cris); - if (flash_cris & (AMASK)) { - LOG_DEBUG("flash_cris 0x%" PRIx32 "", flash_cris); - return ERROR_FLASH_OPERATION_FAILED; - } - return ERROR_OK; -} - -static int stellaris_probe(struct flash_bank *bank) -{ - struct stellaris_flash_bank *stellaris_info = bank->driver_priv; - int retval; - - /* If this is a stellaris chip, it has flash; probe() is just - * to figure out how much is present. Only do it once. - */ - if (stellaris_info->did1 != 0) - return ERROR_OK; - - /* stellaris_read_part_info() already handled error checking and - * reporting. Note that it doesn't write, so we don't care about - * whether the target is halted or not. - */ - retval = stellaris_read_part_info(bank); - if (retval != ERROR_OK) - return retval; - - if (bank->sectors) { - free(bank->sectors); - bank->sectors = NULL; - } - - /* provide this for the benefit of the NOR flash framework */ - bank->size = stellaris_info->num_pages * stellaris_info->pagesize; - bank->num_sectors = stellaris_info->num_pages; - bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector)); - for (int i = 0; i < bank->num_sectors; i++) { - bank->sectors[i].offset = i * stellaris_info->pagesize; - bank->sectors[i].size = stellaris_info->pagesize; - bank->sectors[i].is_erased = -1; - bank->sectors[i].is_protected = -1; - } - - return retval; -} - -static int stellaris_mass_erase(struct flash_bank *bank) -{ - struct target *target = NULL; - struct stellaris_flash_bank *stellaris_info = NULL; - uint32_t flash_fmc; - - stellaris_info = bank->driver_priv; - target = bank->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (stellaris_info->did1 == 0) - return ERROR_FLASH_BANK_NOT_PROBED; - - /* Refresh flash controller timing */ - stellaris_read_clock_info(bank); - stellaris_set_flash_timing(bank); - - /* Clear and disable flash programming interrupts */ - target_write_u32(target, FLASH_CIM, 0); - target_write_u32(target, FLASH_MISC, PMISC | AMISC); - - /* REVISIT this clobbers state set by any halted firmware ... - * it might want to process those IRQs. - */ - - target_write_u32(target, FLASH_FMA, 0); - target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE); - /* Wait until erase complete */ - do { - target_read_u32(target, FLASH_FMC, &flash_fmc); - } while (flash_fmc & FMC_MERASE); - - /* if device has > 128k, then second erase cycle is needed - * this is only valid for older devices, but will not hurt */ - if (stellaris_info->num_pages * stellaris_info->pagesize > 0x20000) { - target_write_u32(target, FLASH_FMA, 0x20000); - target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE); - /* Wait until erase complete */ - do { - target_read_u32(target, FLASH_FMC, &flash_fmc); - } while (flash_fmc & FMC_MERASE); - } - - return ERROR_OK; -} - -COMMAND_HANDLER(stellaris_handle_mass_erase_command) -{ - int i; - - if (CMD_ARGC < 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - struct flash_bank *bank; - int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) - return retval; - - if (stellaris_mass_erase(bank) == ERROR_OK) { - /* set all sectors as erased */ - for (i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_erased = 1; - - command_print(CMD_CTX, "stellaris mass erase complete"); - } else - command_print(CMD_CTX, "stellaris mass erase failed"); - - return ERROR_OK; -} - -/** - * Perform the Stellaris "Recovering a 'Locked' Device procedure. - * This performs a mass erase and then restores all nonvolatile registers - * (including USER_* registers and flash lock bits) to their defaults. - * Accordingly, flash can be reprogrammed, and JTAG can be used. - * - * NOTE that DustDevil parts (at least rev A0 silicon) have errata which - * can affect this operation if flash protection has been enabled. - */ -COMMAND_HANDLER(stellaris_handle_recover_command) -{ - struct flash_bank *bank; - int retval; - - if (CMD_ARGC != 0) - return ERROR_COMMAND_SYNTAX_ERROR; - - bank = get_flash_bank_by_num_noprobe(0); - if (!bank) - return ERROR_FAIL; - - /* REVISIT ... it may be worth sanity checking that the AP is - * inactive before we start. ARM documents that switching a DP's - * mode while it's active can cause fault modes that need a power - * cycle to recover. - */ - - Jim_Eval_Named(CMD_CTX->interp, "catch { hla_command \"debug unlock\" }", 0, 0); - if (!strcmp(Jim_GetString(Jim_GetResult(CMD_CTX->interp), NULL), "0")) { - retval = ERROR_OK; - goto user_action; - } - - /* assert SRST */ - if (!(jtag_get_reset_config() & RESET_HAS_SRST)) { - LOG_ERROR("Can't recover Stellaris flash without SRST"); - return ERROR_FAIL; - } - adapter_assert_reset(); - - for (int i = 0; i < 5; i++) { - retval = dap_to_swd(bank->target); - if (retval != ERROR_OK) - goto done; - - retval = dap_to_jtag(bank->target); - if (retval != ERROR_OK) - goto done; - } - - /* de-assert SRST */ - adapter_deassert_reset(); - retval = jtag_execute_queue(); - - /* wait 400+ msec ... OK, "1+ second" is simpler */ - usleep(1000); - -user_action: - /* USER INTERVENTION required for the power cycle - * Restarting OpenOCD is likely needed because of mode switching. - */ - LOG_INFO("USER ACTION: " - "power cycle Stellaris chip, then restart OpenOCD."); - -done: - return retval; -} - -static const struct command_registration stellaris_exec_command_handlers[] = { - { - .name = "mass_erase", - .usage = "<bank>", - .handler = stellaris_handle_mass_erase_command, - .mode = COMMAND_EXEC, - .help = "erase entire device", - }, - { - .name = "recover", - .handler = stellaris_handle_recover_command, - .mode = COMMAND_EXEC, - .usage = "", - .help = "recover (and erase) locked device", - }, - COMMAND_REGISTRATION_DONE -}; -static const struct command_registration stellaris_command_handlers[] = { - { - .name = "stellaris", - .mode = COMMAND_EXEC, - .help = "Stellaris flash command group", - .usage = "", - .chain = stellaris_exec_command_handlers, - }, - COMMAND_REGISTRATION_DONE -}; - -struct flash_driver stellaris_flash = { - .name = "stellaris", - .commands = stellaris_command_handlers, - .flash_bank_command = stellaris_flash_bank_command, - .erase = stellaris_erase, - .protect = stellaris_protect, - .write = stellaris_write, - .read = default_flash_read, - .probe = stellaris_probe, - .auto_probe = stellaris_probe, - .erase_check = default_flash_blank_check, - .protect_check = stellaris_protect_check, - .info = get_stellaris_info, -};