stm32f0x: Remove duplicate code for revision string.
[openocd.git] / src / flash / nor / stm32f1x.c
index d06016a4d849ff3ae46fd88115616cacd642e591..e4fcca07fb1e0a5332bbea88a2e5050d10f97d75 100644 (file)
@@ -21,7 +21,7 @@
  *   You should have received a copy of the GNU General Public License     *
  *   along with this program; if not, write to the                         *
  *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
 #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;
+       uint16_t user_data;
        uint16_t protection[4];
 };
 
 struct stm32x_flash_bank {
        struct stm32x_options option_bytes;
-       struct working_area *write_algorithm;
        int ppage_size;
        int probed;
 
        bool has_dual_banks;
        /* used to access dual flash bank stm32xl */
        uint32_t register_base;
+       uint16_t default_rdp;
+       int user_data_offset;
+       int option_offset;
+       uint32_t user_bank_size;
 };
 
 static int stm32x_mass_erase(struct flash_bank *bank);
 static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id);
+static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
+               uint32_t offset, uint32_t count);
 
 /* flash bank stm32x <base> <size> 0 0 <target#>
  */
@@ -134,10 +145,10 @@ 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;
+       stm32x_info->user_bank_size = bank->size;
 
        return ERROR_OK;
 }
@@ -196,7 +207,7 @@ static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout)
        return retval;
 }
 
-int stm32x_check_operation_supported(struct flash_bank *bank)
+static int stm32x_check_operation_supported(struct flash_bank *bank)
 {
        struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
 
@@ -223,7 +234,8 @@ static int stm32x_read_options(struct flash_bank *bank)
        if (retval != ERROR_OK)
                return retval;
 
-       stm32x_info->option_bytes.user_options = (uint16_t)0xFFF8 | ((optiondata >> 2) & 0x07);
+       stm32x_info->option_bytes.user_options = (optiondata >> stm32x_info->option_offset >> 2) & 0xffff;
+       stm32x_info->option_bytes.user_data = (optiondata >> stm32x_info->user_data_offset) & 0xffff;
        stm32x_info->option_bytes.RDP = (optiondata & (1 << OPT_READOUT)) ? 0xFFFF : 0x5AA5;
 
        if (optiondata & (1 << OPT_READOUT))
@@ -277,13 +289,13 @@ 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;
 
        /* clear readout protection and complementary option bytes
         * this will also force a device unlock if set */
-       stm32x_info->option_bytes.RDP = 0x5AA5;
+       stm32x_info->option_bytes.RDP = stm32x_info->default_rdp;
 
        return ERROR_OK;
 }
@@ -316,59 +328,24 @@ static int stm32x_write_options(struct flash_bank *bank)
        if (retval != ERROR_OK)
                return retval;
 
-       /* write user option byte */
-       retval = target_write_u16(target, STM32_OB_USER, stm32x_info->option_bytes.user_options);
-       if (retval != ERROR_OK)
-               return retval;
-
-       retval = stm32x_wait_status_busy(bank, 10);
-       if (retval != ERROR_OK)
-               return retval;
-
-       /* write protection byte 1 */
-       retval = target_write_u16(target, STM32_OB_WRP0, stm32x_info->option_bytes.protection[0]);
-       if (retval != ERROR_OK)
-               return retval;
-
-       retval = stm32x_wait_status_busy(bank, 10);
-       if (retval != ERROR_OK)
-               return retval;
-
-       /* write protection byte 2 */
-       retval = target_write_u16(target, STM32_OB_WRP1, stm32x_info->option_bytes.protection[1]);
-       if (retval != ERROR_OK)
-               return retval;
-
-       retval = stm32x_wait_status_busy(bank, 10);
-       if (retval != ERROR_OK)
-               return retval;
-
-       /* write protection byte 3 */
-       retval = target_write_u16(target, STM32_OB_WRP2, stm32x_info->option_bytes.protection[2]);
-       if (retval != ERROR_OK)
-               return retval;
-
-       retval = stm32x_wait_status_busy(bank, 10);
-       if (retval != ERROR_OK)
-               return retval;
-
-       /* write protection byte 4 */
-       retval = target_write_u16(target, STM32_OB_WRP3, stm32x_info->option_bytes.protection[3]);
-       if (retval != ERROR_OK)
-               return retval;
-
-       retval = stm32x_wait_status_busy(bank, 10);
-       if (retval != ERROR_OK)
-               return retval;
-
-       /* write readout protection bit */
-       retval = target_write_u16(target, STM32_OB_RDP, stm32x_info->option_bytes.RDP);
-       if (retval != ERROR_OK)
-               return retval;
-
-       retval = stm32x_wait_status_busy(bank, 10);
-       if (retval != ERROR_OK)
+       uint8_t opt_bytes[16];
+
+       target_buffer_set_u16(target, opt_bytes, stm32x_info->option_bytes.RDP);
+       target_buffer_set_u16(target, opt_bytes + 2, stm32x_info->option_bytes.user_options);
+       target_buffer_set_u16(target, opt_bytes + 4, stm32x_info->option_bytes.user_data & 0xff);
+       target_buffer_set_u16(target, opt_bytes + 6, (stm32x_info->option_bytes.user_data >> 8) & 0xff);
+       target_buffer_set_u16(target, opt_bytes + 8, stm32x_info->option_bytes.protection[0]);
+       target_buffer_set_u16(target, opt_bytes + 10, stm32x_info->option_bytes.protection[1]);
+       target_buffer_set_u16(target, opt_bytes + 12, stm32x_info->option_bytes.protection[2]);
+       target_buffer_set_u16(target, opt_bytes + 14, stm32x_info->option_bytes.protection[3]);
+
+       uint32_t offset = STM32_OB_RDP - bank->base;
+       retval = stm32x_write_block(bank, opt_bytes, offset, sizeof(opt_bytes) / 2);
+       if (retval != ERROR_OK) {
+               if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
+                       LOG_ERROR("working area required to erase options bytes");
                return retval;
+       }
 
        retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK);
        if (retval != ERROR_OK)
@@ -387,11 +364,6 @@ static int stm32x_protect_check(struct flash_bank *bank)
        int num_bits;
        int set;
 
-       if (target->state != TARGET_HALTED) {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
        int retval = stm32x_check_operation_supported(bank);
        if (ERROR_OK != retval)
                return retval;
@@ -481,7 +453,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;
 
@@ -589,12 +561,13 @@ static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
        return stm32x_write_options(bank);
 }
 
-static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer,
+static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
                uint32_t offset, uint32_t count)
 {
        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,13 +617,13 @@ 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,
-                       sizeof(stm32x_flash_write_code), (uint8_t *)stm32x_flash_write_code);
+       retval = target_write_buffer(target, write_algorithm->address,
+                       sizeof(stm32x_flash_write_code), stm32x_flash_write_code);
        if (retval != ERROR_OK)
                return retval;
 
@@ -659,10 +632,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;
@@ -682,13 +654,13 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer,
        buf_set_u32(reg_params[4].value, 0, 32, address);
 
        armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
-       armv7m_info.core_mode = ARMV7M_MODE_ANY;
+       armv7m_info.core_mode = ARM_MODE_THREAD;
 
        retval = target_run_flash_async_algorithm(target, buffer, count, 2,
                        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 +681,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(&reg_params[0]);
        destroy_reg_param(&reg_params[1]);
@@ -720,15 +692,11 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer,
        return retval;
 }
 
-static int stm32x_write(struct flash_bank *bank, uint8_t *buffer,
+static int stm32x_write(struct flash_bank *bank, const 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 +704,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);
+               new_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;
 }
 
@@ -887,6 +854,11 @@ static int stm32x_probe(struct flash_bank *bank)
 
        stm32x_info->probed = 0;
        stm32x_info->register_base = FLASH_REG_BASE_B0;
+       stm32x_info->user_data_offset = 10;
+       stm32x_info->option_offset = 0;
+
+       /* default factory protection level */
+       stm32x_info->default_rdp = 0x5AA5;
 
        /* read stm32 device id register */
        int retval = stm32x_get_device_id(bank, &device_id);
@@ -922,10 +894,13 @@ static int stm32x_probe(struct flash_bank *bank)
                stm32x_info->ppage_size = 4;
                max_flash_size_in_kb = 128;
                break;
-       case 0x422: /* stm32f30x */
+       case 0x422: /* stm32f302xb/c */
                page_size = 2048;
                stm32x_info->ppage_size = 2;
                max_flash_size_in_kb = 256;
+               stm32x_info->user_data_offset = 16;
+               stm32x_info->option_offset = 6;
+               stm32x_info->default_rdp = 0x55AA;
                break;
        case 0x428: /* value line High density */
                page_size = 2048;
@@ -942,11 +917,44 @@ static int stm32x_probe(struct flash_bank *bank)
                page_size = 2048;
                stm32x_info->ppage_size = 2;
                max_flash_size_in_kb = 256;
+               stm32x_info->user_data_offset = 16;
+               stm32x_info->option_offset = 6;
+               stm32x_info->default_rdp = 0x55AA;
                break;
-       case 0x440: /* stm32f0x */
+       case 0x438: /* stm32f33x */
+       case 0x439: /* stm32f302x6/8 */
+               page_size = 2048;
+               stm32x_info->ppage_size = 2;
+               max_flash_size_in_kb = 64;
+               stm32x_info->user_data_offset = 16;
+               stm32x_info->option_offset = 6;
+               stm32x_info->default_rdp = 0x55AA;
+               break;
+       case 0x440: /* stm32f05x */
+       case 0x444: /* stm32f03x */
+       case 0x445: /* stm32f04x */
                page_size = 1024;
                stm32x_info->ppage_size = 4;
                max_flash_size_in_kb = 64;
+               stm32x_info->user_data_offset = 16;
+               stm32x_info->option_offset = 6;
+               stm32x_info->default_rdp = 0x55AA;
+               break;
+       case 0x448: /* stm32f07x */
+               page_size = 2048;
+               stm32x_info->ppage_size = 4;
+               max_flash_size_in_kb = 128;
+               stm32x_info->user_data_offset = 16;
+               stm32x_info->option_offset = 6;
+               stm32x_info->default_rdp = 0x55AA;
+               break;
+       case 0x442: /* stm32f09x */
+               page_size = 2048;
+               stm32x_info->ppage_size = 4;
+               max_flash_size_in_kb = 256;
+               stm32x_info->user_data_offset = 16;
+               stm32x_info->option_offset = 6;
+               stm32x_info->default_rdp = 0x55AA;
                break;
        default:
                LOG_WARNING("Cannot identify target as a STM32 family.");
@@ -977,6 +985,13 @@ static int stm32x_probe(struct flash_bank *bank)
                }
        }
 
+       /* if the user sets the size manually then ignore the probed value
+        * this allows us to work around devices that have a invalid flash size register value */
+       if (stm32x_info->user_bank_size) {
+               LOG_INFO("ignoring flash probed value, using configured bank size");
+               flash_size_in_kb = stm32x_info->user_bank_size / 1024;
+       }
+
        LOG_INFO("flash size = %dkbytes", flash_size_in_kb);
 
        /* did we assign flash size? */
@@ -1025,193 +1040,233 @@ COMMAND_HANDLER(stm32x_handle_part_id_command)
 }
 #endif
 
+static const char *get_stm32f0_revision(uint16_t rev_id)
+{
+       const char *rev_str = NULL;
+
+       switch (rev_id) {
+       case 0x1000:
+               rev_str = "1.0";
+               break;
+       case 0x2000:
+               rev_str = "2.0";
+               break;
+       }
+       return rev_str;
+}
+
 static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
 {
-       uint32_t device_id;
-       int printed;
+       uint32_t dbgmcu_idcode;
 
                /* read stm32 device id register */
-       int retval = stm32x_get_device_id(bank, &device_id);
+       int retval = stm32x_get_device_id(bank, &dbgmcu_idcode);
        if (retval != ERROR_OK)
                return retval;
 
-       if ((device_id & 0xfff) == 0x410) {
-               printed = snprintf(buf, buf_size, "stm32x (Medium Density) - Rev: ");
-               buf += printed;
-               buf_size -= printed;
+       uint16_t device_id = dbgmcu_idcode & 0xfff;
+       uint16_t rev_id = dbgmcu_idcode >> 16;
+       const char *device_str;
+       const char *rev_str = NULL;
 
-               switch (device_id >> 16) {
-                       case 0x0000:
-                               snprintf(buf, buf_size, "A");
-                               break;
+       switch (device_id) {
+       case 0x410:
+               device_str = "STM32F10x (Medium Density)";
 
-                       case 0x2000:
-                               snprintf(buf, buf_size, "B");
-                               break;
+               switch (rev_id) {
+               case 0x0000:
+                       rev_str = "A";
+                       break;
 
-                       case 0x2001:
-                               snprintf(buf, buf_size, "Z");
-                               break;
+               case 0x2000:
+                       rev_str = "B";
+                       break;
 
-                       case 0x2003:
-                               snprintf(buf, buf_size, "Y");
-                               break;
+               case 0x2001:
+                       rev_str = "Z";
+                       break;
 
-                       default:
-                               snprintf(buf, buf_size, "unknown");
-                               break;
+               case 0x2003:
+                       rev_str = "Y";
+                       break;
                }
-       } else if ((device_id & 0xfff) == 0x412) {
-               printed = snprintf(buf, buf_size, "stm32x (Low Density) - Rev: ");
-               buf += printed;
-               buf_size -= printed;
-
-               switch (device_id >> 16) {
-                       case 0x1000:
-                               snprintf(buf, buf_size, "A");
-                               break;
-
-                       default:
-                               snprintf(buf, buf_size, "unknown");
-                               break;
+               break;
+
+       case 0x412:
+               device_str = "STM32F10x (Low Density)";
+
+               switch (rev_id) {
+               case 0x1000:
+                       rev_str = "A";
+                       break;
                }
-       } else if ((device_id & 0xfff) == 0x414) {
-               printed = snprintf(buf, buf_size, "stm32x (High Density) - 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;
+               break;
+
+       case 0x414:
+               device_str = "STM32F10x (High Density)";
+
+               switch (rev_id) {
+               case 0x1000:
+                       rev_str = "A";
+                       break;
+
+               case 0x1001:
+                       rev_str = "Z";
+                       break;
+
+               case 0x1003:
+                       rev_str = "Y";
+                       break;
                }
-       } else if ((device_id & 0xfff) == 0x418) {
-               printed = snprintf(buf, buf_size, "stm32x (Connectivity) - 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;
+               break;
+
+       case 0x418:
+               device_str = "STM32F10x (Connectivity)";
+
+               switch (rev_id) {
+               case 0x1000:
+                       rev_str = "A";
+                       break;
+
+               case 0x1001:
+                       rev_str = "Z";
+                       break;
                }
-       } else if ((device_id & 0xfff) == 0x420) {
-               printed = snprintf(buf, buf_size, "stm32x (Value) - 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;
+               break;
+
+       case 0x420:
+               device_str = "STM32F100 (Low/Medium Density)";
+
+               switch (rev_id) {
+               case 0x1000:
+                       rev_str = "A";
+                       break;
+
+               case 0x1001:
+                       rev_str = "Z";
+                       break;
                }
-       } else if ((device_id & 0xfff) == 0x422) {
-               printed = snprintf(buf, buf_size, "stm32f30x - Rev: ");
-               buf += printed;
-               buf_size -= printed;
-
-               switch (device_id >> 16) {
-                       case 0x1000:
-                               snprintf(buf, buf_size, "1.0");
-                               break;
-
-                       default:
-                               snprintf(buf, buf_size, "unknown");
-                               break;
+               break;
+
+       case 0x422:
+               device_str = "STM32F302xB/C";
+
+               switch (rev_id) {
+               case 0x1000:
+                       rev_str = "A";
+                       break;
+
+               case 0x1001:
+                       rev_str = "Z";
+                       break;
+
+               case 0x1003:
+                       rev_str = "Y";
+                       break;
+
+               case 0x2000:
+                       rev_str = "B";
+                       break;
                }
-       } else if ((device_id & 0xfff) == 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;
+               break;
+
+       case 0x428:
+               device_str = "STM32F100 (High Density)";
+
+               switch (rev_id) {
+               case 0x1000:
+                       rev_str = "A";
+                       break;
+
+               case 0x1001:
+                       rev_str = "Z";
+                       break;
                }
-       } else if ((device_id & 0xfff) == 0x430) {
-               printed = snprintf(buf, buf_size, "stm32x (XL) - Rev: ");
-               buf += printed;
-               buf_size -= printed;
-
-               switch (device_id >> 16) {
-                       case 0x1000:
-                               snprintf(buf, buf_size, "A");
-                               break;
-
-                       default:
-                               snprintf(buf, buf_size, "unknown");
-                               break;
+               break;
+
+       case 0x430:
+               device_str = "STM32F10x (XL Density)";
+
+               switch (rev_id) {
+               case 0x1000:
+                       rev_str = "A";
+                       break;
                }
-       } else if ((device_id & 0xfff) == 0x432) {
-               printed = snprintf(buf, buf_size, "stm32f37x - Rev: ");
-               buf += printed;
-               buf_size -= printed;
-
-               switch (device_id >> 16) {
-                       case 0x1000:
-                               snprintf(buf, buf_size, "1.0");
-                               break;
-
-                       default:
-                               snprintf(buf, buf_size, "unknown");
-                               break;
+               break;
+
+       case 0x432:
+               device_str = "STM32F37x";
+
+               switch (rev_id) {
+               case 0x1000:
+                       rev_str = "A";
+                       break;
+
+               case 0x2000:
+                       rev_str = "B";
+                       break;
+               }
+               break;
+
+       case 0x438:
+               device_str = "STM32F33x";
+
+               switch (rev_id) {
+               case 0x1000:
+                       rev_str = "A";
+                       break;
                }
-       } else if ((device_id & 0xfff) == 0x440) {
-               printed = snprintf(buf, buf_size, "stm32f0x - Rev: ");
-               buf += printed;
-               buf_size -= printed;
-
-               switch (device_id >> 16) {
-                       case 0x1000:
-                               snprintf(buf, buf_size, "1.0");
-                               break;
-
-                       case 0x2000:
-                               snprintf(buf, buf_size, "2.0");
-                               break;
-
-                       default:
-                               snprintf(buf, buf_size, "unknown");
-                               break;
+               break;
+
+       case 0x439:
+               device_str = "STM32F302x6/8";
+
+               switch (rev_id) {
+               case 0x1000:
+                       rev_str = "A";
+                       break;
+
+               case 0x1001:
+                       rev_str = "Z";
+                       break;
                }
-       } else {
-               snprintf(buf, buf_size, "Cannot identify target as a stm32x\n");
+               break;
+
+       case 0x444:
+               device_str = "STM32F03x";
+               rev_str = get_stm32f0_revision(rev_id);
+               break;
+
+       case 0x440:
+               device_str = "STM32F05x";
+               rev_str = get_stm32f0_revision(rev_id);
+               break;
+
+       case 0x445:
+               device_str = "STM32F04x";
+               rev_str = get_stm32f0_revision(rev_id);
+               break;
+
+       case 0x448:
+               device_str = "STM32F07x";
+               rev_str = get_stm32f0_revision(rev_id);
+               break;
+
+       case 0x442:
+               device_str = "STM32F09x";
+               rev_str = get_stm32f0_revision(rev_id);
+               break;
+
+       default:
+               snprintf(buf, buf_size, "Cannot identify target as a STM32F0/1/3\n");
                return ERROR_FAIL;
        }
 
+       if (rev_str != NULL)
+               snprintf(buf, buf_size, "%s - Rev: %s", device_str, rev_str);
+       else
+               snprintf(buf, buf_size, "%s - Rev: unknown (0x%04x)", device_str, rev_id);
+
        return ERROR_OK;
 }
 
@@ -1331,36 +1386,46 @@ COMMAND_HANDLER(stm32x_handle_options_read_command)
                return retval;
        command_print(CMD_CTX, "Option Byte: 0x%" PRIx32 "", optionbyte);
 
-       if (buf_get_u32((uint8_t *)&optionbyte, OPT_ERROR, 1))
+       int user_data = optionbyte;
+
+       if (optionbyte >> OPT_ERROR & 1)
                command_print(CMD_CTX, "Option Byte Complement Error");
 
-       if (buf_get_u32((uint8_t *)&optionbyte, OPT_READOUT, 1))
+       if (optionbyte >> OPT_READOUT & 1)
                command_print(CMD_CTX, "Readout Protection On");
        else
                command_print(CMD_CTX, "Readout Protection Off");
 
-       if (buf_get_u32((uint8_t *)&optionbyte, OPT_RDWDGSW, 1))
+       /* user option bytes are offset depending on variant */
+       optionbyte >>= stm32x_info->option_offset;
+
+       if (optionbyte >> OPT_RDWDGSW & 1)
                command_print(CMD_CTX, "Software Watchdog");
        else
                command_print(CMD_CTX, "Hardware Watchdog");
 
-       if (buf_get_u32((uint8_t *)&optionbyte, OPT_RDRSTSTOP, 1))
+       if (optionbyte >> OPT_RDRSTSTOP & 1)
                command_print(CMD_CTX, "Stop: No reset generated");
        else
                command_print(CMD_CTX, "Stop: Reset generated");
 
-       if (buf_get_u32((uint8_t *)&optionbyte, OPT_RDRSTSTDBY, 1))
+       if (optionbyte >> OPT_RDRSTSTDBY & 1)
                command_print(CMD_CTX, "Standby: No reset generated");
        else
                command_print(CMD_CTX, "Standby: Reset generated");
 
        if (stm32x_info->has_dual_banks) {
-               if (buf_get_u32((uint8_t *)&optionbyte, OPT_BFB2, 1))
+               if (optionbyte >> OPT_BFB2 & 1)
                        command_print(CMD_CTX, "Boot: Bank 0");
                else
                        command_print(CMD_CTX, "Boot: Bank 1");
        }
 
+       command_print(CMD_CTX, "User Option0: 0x%02" PRIx8,
+                       (uint8_t)((user_data >> stm32x_info->user_data_offset) & 0xff));
+       command_print(CMD_CTX, "User Option1: 0x%02" PRIx8,
+                       (uint8_t)((user_data >> (stm32x_info->user_data_offset + 8)) & 0xff));
+
        return ERROR_OK;
 }
 
@@ -1368,9 +1433,9 @@ COMMAND_HANDLER(stm32x_handle_options_write_command)
 {
        struct target *target = NULL;
        struct stm32x_flash_bank *stm32x_info = NULL;
-       uint16_t optionbyte = 0xF8;
+       uint16_t optionbyte;
 
-       if (CMD_ARGC < 4)
+       if (CMD_ARGC < 2)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        struct flash_bank *bank;
@@ -1391,34 +1456,41 @@ COMMAND_HANDLER(stm32x_handle_options_write_command)
        if (ERROR_OK != retval)
                return retval;
 
-       /* REVISIT: ignores some options which we will display...
-        * and doesn't insist on the specified syntax.
-        */
-
-       /* OPT_RDWDGSW */
-       if (strcmp(CMD_ARGV[1], "SWWDG") == 0)
-               optionbyte |= (1 << 0);
-       else    /* REVISIT must be "HWWDG" then ... */
-               optionbyte &= ~(1 << 0);
-
-       /* OPT_RDRSTSTOP */
-       if (strcmp(CMD_ARGV[2], "NORSTSTOP") == 0)
-               optionbyte |= (1 << 1);
-       else    /* REVISIT must be "RSTSTNDBY" then ... */
-               optionbyte &= ~(1 << 1);
-
-       /* OPT_RDRSTSTDBY */
-       if (strcmp(CMD_ARGV[3], "NORSTSTNDBY") == 0)
-               optionbyte |= (1 << 2);
-       else    /* REVISIT must be "RSTSTOP" then ... */
-               optionbyte &= ~(1 << 2);
-
-       if (CMD_ARGC > 4 && stm32x_info->has_dual_banks) {
-               /* OPT_BFB2 */
-               if (strcmp(CMD_ARGV[4], "BOOT0") == 0)
-                       optionbyte |= (1 << 3);
-               else
-                       optionbyte &= ~(1 << 3);
+       retval = stm32x_read_options(bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       /* start with current options */
+       optionbyte = stm32x_info->option_bytes.user_options;
+
+       /* skip over flash bank */
+       CMD_ARGC--;
+       CMD_ARGV++;
+
+       while (CMD_ARGC) {
+               if (strcmp("SWWDG", CMD_ARGV[0]) == 0)
+                       optionbyte |= (1 << 0);
+               else if (strcmp("HWWDG", CMD_ARGV[0]) == 0)
+                       optionbyte &= ~(1 << 0);
+               else if (strcmp("NORSTSTOP", CMD_ARGV[0]) == 0)
+                       optionbyte |= (1 << 1);
+               else if (strcmp("RSTSTOP", CMD_ARGV[0]) == 0)
+                       optionbyte &= ~(1 << 1);
+               else if (strcmp("NORSTSTNDBY", CMD_ARGV[0]) == 0)
+                       optionbyte |= (1 << 2);
+               else if (strcmp("RSTSTNDBY", CMD_ARGV[0]) == 0)
+                       optionbyte &= ~(1 << 2);
+               else if (stm32x_info->has_dual_banks) {
+                       if (strcmp("BOOT0", CMD_ARGV[0]) == 0)
+                               optionbyte |= (1 << 3);
+                       else if (strcmp("BOOT1", CMD_ARGV[0]) == 0)
+                               optionbyte &= ~(1 << 3);
+                       else
+                               return ERROR_COMMAND_SYNTAX_ERROR;
+               } else
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               CMD_ARGC--;
+               CMD_ARGV++;
        }
 
        if (stm32x_erase_options(bank) != ERROR_OK) {
@@ -1466,7 +1538,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;
 

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)