X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fflash%2Fnor%2Fstm32f1x.c;h=a0520c79278b3ee497bf42c36ca0d2302cc4fedb;hp=6bc4300144f6111a561c8349349bd925c40e7aa4;hb=92b14f8ca96e87715697be74a08907595a7d4dcb;hpb=b066a7db2498eadcdeb55ea763d805c75fbbd00b diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 6bc4300144..a0520c7927 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -5,6 +5,9 @@ * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * + * Copyright (C) 2011 by Andreas Fritiofson * + * andreas.fritiofson@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 * @@ -31,14 +34,29 @@ /* stm32x register locations */ -#define STM32_FLASH_ACR 0x40022000 -#define STM32_FLASH_KEYR 0x40022004 -#define STM32_FLASH_OPTKEYR 0x40022008 -#define STM32_FLASH_SR 0x4002200C -#define STM32_FLASH_CR 0x40022010 -#define STM32_FLASH_AR 0x40022014 -#define STM32_FLASH_OBR 0x4002201C -#define STM32_FLASH_WRPR 0x40022020 +#define FLASH_REG_BASE_B0 0x40022000 +#define FLASH_REG_BASE_B1 0x40022040 + +#define STM32_FLASH_ACR 0x00 +#define STM32_FLASH_KEYR 0x04 +#define STM32_FLASH_OPTKEYR 0x08 +#define STM32_FLASH_SR 0x0C +#define STM32_FLASH_CR 0x10 +#define STM32_FLASH_AR 0x14 +#define STM32_FLASH_OBR 0x1C +#define STM32_FLASH_WRPR 0x20 + +/* TODO: Check if code using these really should be hard coded to bank 0. + * There are valid cases, on dual flash devices the protection of the + * second bank is done on the bank0 reg's. */ +#define STM32_FLASH_ACR_B0 0x40022000 +#define STM32_FLASH_KEYR_B0 0x40022004 +#define STM32_FLASH_OPTKEYR_B0 0x40022008 +#define STM32_FLASH_SR_B0 0x4002200C +#define STM32_FLASH_CR_B0 0x40022010 +#define STM32_FLASH_AR_B0 0x40022014 +#define STM32_FLASH_OBR_B0 0x4002201C +#define STM32_FLASH_WRPR_B0 0x40022020 /* option byte location */ @@ -83,12 +101,6 @@ #define KEY1 0x45670123 #define KEY2 0xCDEF89AB -/* we use an offset to access the second bank on dual flash devices - * strangely the protection of the second bank is done on the bank0 reg's */ - -#define FLASH_OFFSET_B0 0x00 -#define FLASH_OFFSET_B1 0x40 - struct stm32x_options { uint16_t RDP; @@ -104,10 +116,8 @@ struct stm32x_flash_bank int probed; bool has_dual_banks; - /* used to access dual flash bank stm32xl - * 0x00 will address bank 0 flash - * 0x40 will address bank 1 flash */ - int register_offset; + /* used to access dual flash bank stm32xl */ + uint32_t register_base; }; static int stm32x_mass_erase(struct flash_bank *bank); @@ -130,7 +140,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) stm32x_info->write_algorithm = NULL; stm32x_info->probed = 0; stm32x_info->has_dual_banks = false; - stm32x_info->register_offset = FLASH_OFFSET_B0; + stm32x_info->register_base = FLASH_REG_BASE_B0; return ERROR_OK; } @@ -138,7 +148,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) static inline int stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; - return reg + stm32x_info->register_offset; + return reg + stm32x_info->register_base; } static inline int stm32x_get_flash_status(struct flash_bank *bank, uint32_t *status) @@ -200,7 +210,7 @@ int stm32x_check_operation_supported(struct flash_bank *bank) /* if we have a dual flash bank device then * we need to perform option byte stuff on bank0 only */ - if (stm32x_info->register_offset != FLASH_OFFSET_B0) + if (stm32x_info->register_base != FLASH_REG_BASE_B0) { LOG_ERROR("Option Byte Operation's must use bank0"); return ERROR_FLASH_OPERATION_FAILED; @@ -218,7 +228,7 @@ static int stm32x_read_options(struct flash_bank *bank) stm32x_info = bank->driver_priv; /* read current option bytes */ - int retval = target_read_u32(target, STM32_FLASH_OBR, &optiondata); + int retval = target_read_u32(target, STM32_FLASH_OBR_B0, &optiondata); if (retval != ERROR_OK) return retval; @@ -229,7 +239,7 @@ static int stm32x_read_options(struct flash_bank *bank) LOG_INFO("Device Security Bit Set"); /* each bit refers to a 4bank protection */ - retval = target_read_u32(target, STM32_FLASH_WRPR, &optiondata); + retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &optiondata); if (retval != ERROR_OK) return retval; @@ -252,27 +262,27 @@ static int stm32x_erase_options(struct flash_bank *bank) stm32x_read_options(bank); /* unlock flash registers */ - int retval = target_write_u32(target, STM32_FLASH_KEYR, KEY1); + int retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY1); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_KEYR, KEY2); + retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY2); if (retval != ERROR_OK) return retval; /* unlock option flash registers */ - retval = target_write_u32(target, STM32_FLASH_OPTKEYR, KEY1); + retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY1); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_OPTKEYR, KEY2); + retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY2); if (retval != ERROR_OK) return retval; /* erase option bytes */ - retval = target_write_u32(target, STM32_FLASH_CR, FLASH_OPTER | FLASH_OPTWRE); + retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_OPTER | FLASH_OPTWRE); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_CR, FLASH_OPTER | FLASH_STRT | FLASH_OPTWRE); + retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_OPTER | FLASH_STRT | FLASH_OPTWRE); if (retval != ERROR_OK) return retval; @@ -295,23 +305,23 @@ static int stm32x_write_options(struct flash_bank *bank) stm32x_info = bank->driver_priv; /* unlock flash registers */ - int retval = target_write_u32(target, STM32_FLASH_KEYR, KEY1); + int retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY1); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_KEYR, KEY2); + retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY2); if (retval != ERROR_OK) return retval; /* unlock option flash registers */ - retval = target_write_u32(target, STM32_FLASH_OPTKEYR, KEY1); + retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY1); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_OPTKEYR, KEY2); + retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY2); if (retval != ERROR_OK) return retval; /* program option bytes */ - retval = target_write_u32(target, STM32_FLASH_CR, FLASH_OPTPG | FLASH_OPTWRE); + retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_OPTPG | FLASH_OPTWRE); if (retval != ERROR_OK) return retval; @@ -369,7 +379,7 @@ static int stm32x_write_options(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK); + retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK); if (retval != ERROR_OK) return retval; @@ -398,7 +408,7 @@ static int stm32x_protect_check(struct flash_bank *bank) /* medium density - each bit refers to a 4bank protection * high density - each bit refers to a 2bank protection */ - retval = target_read_u32(target, STM32_FLASH_WRPR, &protection); + retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &protection); if (retval != ERROR_OK) return retval; @@ -544,7 +554,7 @@ static int stm32x_protect(struct flash_bank *bank, int set, int first, int last) /* medium density - each bit refers to a 4bank protection * high density - each bit refers to a 2bank protection */ - retval = target_read_u32(target, STM32_FLASH_WRPR, &protection); + retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &protection); if (retval != ERROR_OK) return retval; @@ -616,34 +626,45 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t buffer_size = 16384; struct working_area *source; uint32_t address = bank->base + offset; - struct reg_param reg_params[4]; + struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; - /* see contib/loaders/flash/stm32x.s for src */ + /* see contrib/loaders/flash/stm32f1x.S for src */ static const uint8_t stm32x_flash_write_code[] = { - /* #define STM32_FLASH_CR_OFFSET 0x10 */ - /* #define STM32_FLASH_SR_OFFSET 0x0C */ - /* write: */ - 0x08, 0x4c, /* ldr r4, STM32_FLASH_BASE */ - 0x1c, 0x44, /* add r4, r3 */ - /* write_half_word: */ - 0x01, 0x23, /* movs r3, #0x01 */ - 0x23, 0x61, /* str r3, [r4, #STM32_FLASH_CR_OFFSET] */ - 0x30, 0xf8, 0x02, 0x3b, /* ldrh r3, [r0], #0x02 */ - 0x21, 0xf8, 0x02, 0x3b, /* strh r3, [r1], #0x02 */ - /* busy: */ - 0xe3, 0x68, /* ldr r3, [r4, #STM32_FLASH_SR_OFFSET] */ - 0x13, 0xf0, 0x01, 0x0f, /* tst r3, #0x01 */ - 0xfb, 0xd0, /* beq busy */ - 0x13, 0xf0, 0x14, 0x0f, /* tst r3, #0x14 */ - 0x01, 0xd1, /* bne exit */ - 0x01, 0x3a, /* subs r2, r2, #0x01 */ - 0xf0, 0xd1, /* bne write_half_word */ - /* exit: */ - 0x00, 0xbe, /* bkpt #0x00 */ - 0x00, 0x20, 0x02, 0x40, /* STM32_FLASH_BASE: .word 0x40022000 */ + /* #define STM32_FLASH_CR_OFFSET 0x10 */ + /* #define STM32_FLASH_SR_OFFSET 0x0C */ + /* wait_fifo: */ + 0x16, 0x68, /* ldr r6, [r2, #0] */ + 0x00, 0x2e, /* cmp r6, #0 */ + 0x1a, 0xd0, /* beq exit */ + 0x55, 0x68, /* ldr r5, [r2, #4] */ + 0xb5, 0x42, /* cmp r5, r6 */ + 0xf9, 0xd0, /* beq wait_fifo */ + 0x01, 0x26, /* movs r6, #1 */ + 0x06, 0x61, /* str r6, [r0, #STM32_FLASH_CR_OFFSET] */ + 0x35, 0xf8, 0x02, 0x6b, /* ldrh r6, [r5], #2 */ + 0x24, 0xf8, 0x02, 0x6b, /* strh r6, [r4], #2 */ + /* busy: */ + 0xc6, 0x68, /* ldr r6, [r0, #STM32_FLASH_SR_OFFSET] */ + 0x16, 0xf0, 0x01, 0x0f, /* tst r6, #1 */ + 0xfb, 0xd1, /* bne busy */ + 0x16, 0xf0, 0x14, 0x0f, /* tst r6, #0x14 */ + 0x07, 0xd1, /* bne error */ + 0x9d, 0x42, /* cmp r5, r3 */ + 0x28, 0xbf, /* it cs */ + 0x02, 0xf1, 0x08, 0x05, /* addcs r5, r2, #8 */ + 0x55, 0x60, /* str r5, [r2, #4] */ + 0x01, 0x39, /* subs r1, r1, #1 */ + 0x19, 0xb1, /* cbz r1, exit */ + 0xe4, 0xe7, /* b wait_fifo */ + /* error: */ + 0x00, 0x20, /* movs r0, #0 */ + 0xc2, 0xf8, 0x02, 0x00, /* str r0, [r2, #2] */ + /* exit: */ + 0x30, 0x46, /* mov r0, r6 */ + 0x00, 0xbe, /* bkpt #0 */ }; /* flash write code */ @@ -663,6 +684,7 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; + buffer_size &= ~3UL; // Make sure it's 4 byte aligned if (buffer_size <= 256) { /* if we already allocated the writing code, but failed to get a @@ -675,60 +697,152 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, } }; + /* Set up working area. First word is write pointer, second word is read pointer, + * rest is fifo data area. */ + uint32_t wp_addr = source->address; + uint32_t rp_addr = source->address + 4; + uint32_t fifo_start_addr = source->address + 8; + uint32_t fifo_end_addr = source->address + source->size; + + uint32_t wp = fifo_start_addr; + uint32_t rp = fifo_start_addr; + + retval = target_write_u32(target, wp_addr, wp); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, rp_addr, rp); + if (retval != ERROR_OK) + return retval; + + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* count (halfword-16bit) */ + 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, stm32x_info->register_base); + 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 = ARMV7M_MODE_ANY; - 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_IN_OUT); + /* Start up algorithm on target and let it idle while writing the first chunk */ + if ((retval = target_start_algorithm(target, 0, NULL, 5, reg_params, + stm32x_info->write_algorithm->address, + 0, + &armv7m_info)) != ERROR_OK) + { + LOG_ERROR("error starting stm32x flash write algorithm"); + goto cleanup; + } while (count > 0) { - uint32_t thisrun_count = (count > (buffer_size / 2)) ? - (buffer_size / 2) : count; - - if ((retval = target_write_buffer(target, source->address, - thisrun_count * 2, buffer)) != ERROR_OK) + retval = target_read_u32(target, rp_addr, &rp); + if (retval != ERROR_OK) + { + LOG_ERROR("failed to get read pointer"); break; + } - buf_set_u32(reg_params[0].value, 0, 32, source->address); - buf_set_u32(reg_params[1].value, 0, 32, address); - buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); - buf_set_u32(reg_params[3].value, 0, 32, stm32x_info->register_offset); + LOG_DEBUG("count 0x%"PRIx32" wp 0x%"PRIx32" rp 0x%"PRIx32, count, wp, rp); - if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params, - stm32x_info->write_algorithm->address, - 0, - 10000, &armv7m_info)) != ERROR_OK) + if (rp == 0) { - LOG_ERROR("error executing stm32x flash write algorithm"); + LOG_ERROR("flash write algorithm aborted by target"); + retval = ERROR_FLASH_OPERATION_FAILED; break; } - if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_PGERR) + if ((rp & 1) || rp < fifo_start_addr || rp >= fifo_end_addr) + { + LOG_ERROR("corrupted fifo read pointer 0x%"PRIx32, rp); + break; + } + + /* Count the number of bytes available in the fifo without + * crossing the wrap around. Make sure to not fill it completely, + * because that would make wp == rp and that's the empty condition. */ + uint32_t thisrun_bytes; + if (rp > wp) + thisrun_bytes = rp - wp - 2; + else if (rp > fifo_start_addr) + thisrun_bytes = fifo_end_addr - wp; + else + thisrun_bytes = fifo_end_addr - wp - 2; + + if (thisrun_bytes == 0) + { + /* Throttle polling a bit if transfer is (much) faster than flash + * programming. The exact delay shouldn't matter as long as it's + * less than buffer size / flash speed. This is very unlikely to + * run when using high latency connections such as USB. */ + alive_sleep(10); + continue; + } + + /* Limit to the amount of data we actually want to write */ + if (thisrun_bytes > count * 2) + thisrun_bytes = count * 2; + + /* Write data to fifo */ + retval = target_write_buffer(target, wp, thisrun_bytes, buffer); + if (retval != ERROR_OK) + break; + + /* Update counters and wrap write pointer */ + buffer += thisrun_bytes; + count -= thisrun_bytes / 2; + wp += thisrun_bytes; + if (wp >= fifo_end_addr) + wp = fifo_start_addr; + + /* Store updated write pointer to target */ + retval = target_write_u32(target, wp_addr, wp); + if (retval != ERROR_OK) + break; + } + + if (retval != ERROR_OK) + { + /* abort flash write algorithm on target */ + target_write_u32(target, wp_addr, 0); + } + + int retval2; + if ((retval2 = target_wait_algorithm(target, 0, NULL, 5, reg_params, + 0, + 10000, + &armv7m_info)) != ERROR_OK) + { + LOG_ERROR("error waiting for stm32x flash write algorithm"); + retval = retval2; + } + + if (retval == ERROR_FLASH_OPERATION_FAILED) + { + LOG_ERROR("flash write failed at address 0x%"PRIx32, + buf_get_u32(reg_params[4].value, 0, 32)); + + if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_PGERR) { LOG_ERROR("flash memory not erased before writing"); /* Clear but report errors */ - target_write_u32(target, STM32_FLASH_SR, FLASH_PGERR); - retval = ERROR_FAIL; - break; + target_write_u32(target, STM32_FLASH_SR_B0, FLASH_PGERR); } - if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_WRPRTERR) + if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_WRPRTERR) { LOG_ERROR("flash memory write protected"); /* Clear but report errors */ - target_write_u32(target, STM32_FLASH_SR, FLASH_WRPRTERR); - retval = ERROR_FAIL; - break; + target_write_u32(target, STM32_FLASH_SR_B0, FLASH_WRPRTERR); } - - buffer += thisrun_count * 2; - address += thisrun_count * 2; - count -= thisrun_count; } +cleanup: target_free_working_area(target, source); target_free_working_area(target, stm32x_info->write_algorithm); @@ -736,6 +850,7 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); return retval; } @@ -832,7 +947,7 @@ static int stm32x_write(struct flash_bank *bank, uint8_t *buffer, return retval; } - return target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK); + return target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK); } static int stm32x_probe(struct flash_bank *bank) @@ -846,7 +961,7 @@ static int stm32x_probe(struct flash_bank *bank) uint32_t base_address = 0x08000000; stm32x_info->probed = 0; - stm32x_info->register_offset = FLASH_OFFSET_B0; + stm32x_info->register_base = FLASH_REG_BASE_B0; /* read stm32 device id register */ int retval = target_read_u32(target, 0xE0042000, &device_id); @@ -938,6 +1053,22 @@ static int stm32x_probe(struct flash_bank *bank) num_pages = 128; } } + else if ((device_id & 0x7ff) == 0x428) + { + /* value line density - we have 1k pages + * 4 pages for a protection area */ + page_size = 2048; + stm32x_info->ppage_size = 4; + + /* check for early silicon */ + if (num_pages == 0xffff) + { + /* number of sectors may be incorrrect on early silicon */ + LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming 128k flash"); + num_pages = 128; + } + } + else if ((device_id & 0x7ff) == 0x430) { /* xl line density - we have 2k pages @@ -964,7 +1095,7 @@ static int stm32x_probe(struct flash_bank *bank) { num_pages -= 512; /* bank1 also uses a register offset */ - stm32x_info->register_offset = FLASH_OFFSET_B1; + stm32x_info->register_base = FLASH_REG_BASE_B1; base_address = 0x08080000; } } @@ -1138,6 +1269,27 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size) break; } } + else if ((device_id & 0x7ff) == 0x428) + { + printed = snprintf(buf, buf_size, "stm32x (Value HD) - Rev: "); + buf += printed; + buf_size -= printed; + + switch (device_id >> 16) + { + case 0x1000: + snprintf(buf, buf_size, "A"); + break; + + case 0x1001: + snprintf(buf, buf_size, "Z"); + break; + + default: + snprintf(buf, buf_size, "unknown"); + break; + } + } else if ((device_id & 0x7ff) == 0x430) { printed = snprintf(buf, buf_size, "stm32x (XL) - Rev: "); @@ -1291,7 +1443,7 @@ COMMAND_HANDLER(stm32x_handle_options_read_command) if (ERROR_OK != retval) return retval; - retval = target_read_u32(target, STM32_FLASH_OBR, &optionbyte); + retval = target_read_u32(target, STM32_FLASH_OBR_B0, &optionbyte); if (retval != ERROR_OK) return retval; command_print(CMD_CTX, "Option Byte: 0x%" PRIx32 "", optionbyte);