X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fflash%2Fnor%2Fstm32f1x.c;h=d021bbfb3835a4a81f06ebc4de97d426197cdc70;hb=9e001244da2a2c472038ce1af0df32cfb2329569;hp=d06016a4d849ff3ae46fd88115616cacd642e591;hpb=9a8edbfa8bd83d58a1904dfd35a00f9793d99314;p=fw%2Fopenocd diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index d06016a4d..d021bbfb3 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -102,6 +102,11 @@ #define KEY1 0x45670123 #define KEY2 0xCDEF89AB +/* timeout values */ + +#define FLASH_WRITE_TIMEOUT 10 +#define FLASH_ERASE_TIMEOUT 100 + struct stm32x_options { uint16_t RDP; uint16_t user_options; @@ -110,7 +115,6 @@ struct stm32x_options { struct stm32x_flash_bank { struct stm32x_options option_bytes; - struct working_area *write_algorithm; int ppage_size; int probed; @@ -134,7 +138,6 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) stm32x_info = malloc(sizeof(struct stm32x_flash_bank)); bank->driver_priv = stm32x_info; - stm32x_info->write_algorithm = NULL; stm32x_info->probed = 0; stm32x_info->has_dual_banks = false; stm32x_info->register_base = FLASH_REG_BASE_B0; @@ -249,6 +252,14 @@ static int stm32x_erase_options(struct flash_bank *bank) stm32x_info = bank->driver_priv; + /* stlink is currently does not support 16bit + * read/writes. so we cannot write option bytes */ + struct armv7m_common *armv7m = target_to_armv7m(target); + if (armv7m && armv7m->stlink) { + LOG_ERROR("Option bytes currently unsupported for stlink"); + return ERROR_FAIL; + } + /* read current options */ stm32x_read_options(bank); @@ -277,7 +288,7 @@ static int stm32x_erase_options(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - retval = stm32x_wait_status_busy(bank, 10); + retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) return retval; @@ -321,7 +332,7 @@ static int stm32x_write_options(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - retval = stm32x_wait_status_busy(bank, 10); + retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); if (retval != ERROR_OK) return retval; @@ -330,7 +341,7 @@ static int stm32x_write_options(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - retval = stm32x_wait_status_busy(bank, 10); + retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); if (retval != ERROR_OK) return retval; @@ -339,7 +350,7 @@ static int stm32x_write_options(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - retval = stm32x_wait_status_busy(bank, 10); + retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); if (retval != ERROR_OK) return retval; @@ -348,7 +359,7 @@ static int stm32x_write_options(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - retval = stm32x_wait_status_busy(bank, 10); + retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); if (retval != ERROR_OK) return retval; @@ -357,7 +368,7 @@ static int stm32x_write_options(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - retval = stm32x_wait_status_busy(bank, 10); + retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); if (retval != ERROR_OK) return retval; @@ -366,7 +377,7 @@ static int stm32x_write_options(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - retval = stm32x_wait_status_busy(bank, 10); + retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); if (retval != ERROR_OK) return retval; @@ -481,7 +492,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last) if (retval != ERROR_OK) return retval; - retval = stm32x_wait_status_busy(bank, 100); + retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) return retval; @@ -595,6 +606,7 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, struct stm32x_flash_bank *stm32x_info = bank->driver_priv; 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]; @@ -644,12 +656,12 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, /* flash write code */ if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), - &stm32x_info->write_algorithm) != ERROR_OK) { + &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; - retval = target_write_buffer(target, stm32x_info->write_algorithm->address, + retval = target_write_buffer(target, write_algorithm->address, sizeof(stm32x_flash_write_code), (uint8_t *)stm32x_flash_write_code); if (retval != ERROR_OK) return retval; @@ -659,10 +671,9 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, 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 + /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ - if (stm32x_info->write_algorithm) - target_free_working_area(target, stm32x_info->write_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; @@ -688,7 +699,7 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, 0, NULL, 5, reg_params, source->address, source->size, - stm32x_info->write_algorithm->address, 0, + write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) { @@ -709,7 +720,7 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, } target_free_working_area(target, source); - target_free_working_area(target, stm32x_info->write_algorithm); + target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); @@ -724,11 +735,7 @@ static int stm32x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; - uint32_t words_remaining = (count / 2); - uint32_t bytes_remaining = (count & 0x00000001); - uint32_t address = bank->base + offset; - uint32_t bytes_written = 0; - int retval; + uint8_t *new_buffer = NULL; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -736,76 +743,75 @@ static int stm32x_write(struct flash_bank *bank, uint8_t *buffer, } if (offset & 0x1) { - LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); + LOG_ERROR("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } + /* If there's an odd number of bytes, the data has to be padded. Duplicate + * the buffer and use the normal code path with a single block write since + * it's probably cheaper than to special case the last odd write using + * discrete accesses. */ + if (count & 1) { + new_buffer = malloc(count + 1); + 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, padding with 0xff"); + buffer = memcpy(new_buffer, buffer, count); + buffer[count++] = 0xff; + } + + uint32_t words_remaining = count / 2; + int retval, retval2; + /* unlock flash registers */ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY1); if (retval != ERROR_OK) - return retval; + goto cleanup; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) - return retval; + goto cleanup; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG); if (retval != ERROR_OK) - return retval; + goto cleanup; - /* multiple half words (2-byte) to be programmed? */ - if (words_remaining > 0) { - /* try using a block write */ - retval = stm32x_write_block(bank, buffer, offset, words_remaining); - if (retval != ERROR_OK) { - if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { - /* if block write failed (no sufficient working area), - * we use normal (slow) single dword accesses */ - LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); - } - } else { - buffer += words_remaining * 2; - address += words_remaining * 2; - words_remaining = 0; - } - } + /* try using a block write */ + retval = stm32x_write_block(bank, buffer, offset, words_remaining); - if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)) - goto reset_pg_and_lock; + if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { + /* if block write failed (no sufficient working area), + * we use normal (slow) single halfword accesses */ + LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); - while (words_remaining > 0) { - uint16_t value; - memcpy(&value, buffer + bytes_written, sizeof(uint16_t)); + while (words_remaining > 0) { + uint16_t value; + memcpy(&value, buffer, sizeof(uint16_t)); - retval = target_write_u16(target, address, value); - if (retval != ERROR_OK) - goto reset_pg_and_lock; + retval = target_write_u16(target, bank->base + offset, value); + if (retval != ERROR_OK) + goto reset_pg_and_lock; - retval = stm32x_wait_status_busy(bank, 5); - if (retval != ERROR_OK) - goto reset_pg_and_lock; + retval = stm32x_wait_status_busy(bank, 5); + if (retval != ERROR_OK) + goto reset_pg_and_lock; - bytes_written += 2; - words_remaining--; - address += 2; + words_remaining--; + buffer += 2; + offset += 2; + } } - if (bytes_remaining) { - uint16_t value = 0xffff; - memcpy(&value, buffer + bytes_written, bytes_remaining); - - retval = target_write_u16(target, address, value); - if (retval != ERROR_OK) - goto reset_pg_and_lock; - - retval = stm32x_wait_status_busy(bank, 5); - if (retval != ERROR_OK) - goto reset_pg_and_lock; - } +reset_pg_and_lock: + retval2 = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); + if (retval == ERROR_OK) + retval = retval2; - return target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); +cleanup: + if (new_buffer) + free(new_buffer); -reset_pg_and_lock: - target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); return retval; } @@ -1139,6 +1145,10 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size) snprintf(buf, buf_size, "1.0"); break; + case 0x2000: + snprintf(buf, buf_size, "2.0"); + break; + default: snprintf(buf, buf_size, "unknown"); break; @@ -1185,6 +1195,10 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size) snprintf(buf, buf_size, "1.0"); break; + case 0x2000: + snprintf(buf, buf_size, "2.0"); + break; + default: snprintf(buf, buf_size, "unknown"); break; @@ -1466,7 +1480,7 @@ static int stm32x_mass_erase(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - retval = stm32x_wait_status_busy(bank, 100); + retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) return retval;