Comprehensive STM32G03/4/5/6/7/8/B/C driver
This commit is contained in:
parent
fb8492a7e5
commit
6d6cfd6c98
|
@ -57,6 +57,7 @@ SRC = \
|
||||||
stm32h7.c \
|
stm32h7.c \
|
||||||
stm32l0.c \
|
stm32l0.c \
|
||||||
stm32l4.c \
|
stm32l4.c \
|
||||||
|
stm32g0.c \
|
||||||
target.c \
|
target.c \
|
||||||
|
|
||||||
include $(PLATFORM_DIR)/Makefile.inc
|
include $(PLATFORM_DIR)/Makefile.inc
|
||||||
|
|
|
@ -399,6 +399,7 @@ bool cortexm_probe(ADIv5_AP_t *ap)
|
||||||
PROBE(stm32h7_probe);
|
PROBE(stm32h7_probe);
|
||||||
PROBE(stm32l0_probe);
|
PROBE(stm32l0_probe);
|
||||||
PROBE(stm32l4_probe);
|
PROBE(stm32l4_probe);
|
||||||
|
PROBE(stm32g0_probe);
|
||||||
if (ap->ap_partno == 0x472) {
|
if (ap->ap_partno == 0x472) {
|
||||||
t->driver = "STM32L552(no flash)";
|
t->driver = "STM32L552(no flash)";
|
||||||
target_halt_resume(t, 0);
|
target_halt_resume(t, 0);
|
||||||
|
|
|
@ -0,0 +1,710 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the Black Magic Debug project.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Fabrice Prost-Boucle <fabalthazar@falbalab.fr>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file implements STM32G0 target specific functions for detecting
|
||||||
|
* the device, providing the XML memory map and Flash memory programming.
|
||||||
|
*
|
||||||
|
* References:
|
||||||
|
* RM0454 - Rev 5 (Value line)
|
||||||
|
* Reference manual - STM32G0x0 advanced ARM(R)-based 32-bit MCUs
|
||||||
|
* (STM32G030/STM32G050/STM32G070/STM32G0B0)
|
||||||
|
* RM0444 - Rev 5 (Access line)
|
||||||
|
* Reference manual - STM32G0x1 advanced ARM(R)-based 32-bit MCUs
|
||||||
|
* (STM32G031/STM32G041/STM32G051/STM32G061/
|
||||||
|
* STM32G071/STM32G081/STM32G0B1/STM32G0C1)
|
||||||
|
* PM0223 - Rev 5
|
||||||
|
* Programming manual - Cortex(R)-M0+ programming manual for STM32L0, STM32G0,
|
||||||
|
* STM32WL and STM32WB Series
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "general.h"
|
||||||
|
#include "target.h"
|
||||||
|
#include "target_internal.h"
|
||||||
|
#include "cortexm.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
/* FLASH */
|
||||||
|
#define FLASH_START 0x08000000
|
||||||
|
#define FLASH_MEMORY_SIZE 0x1FFF75E0
|
||||||
|
#define FLASH_PAGE_SIZE 0x800
|
||||||
|
#define FLASH_BANK2_START_PAGE_NB 256U
|
||||||
|
#define FLASH_SIZE_MAX_G03_4 (64U * 1024U) // 64 kiB
|
||||||
|
#define FLASH_SIZE_MAX_G05_6 (64U * 1024U) // 64 kiB
|
||||||
|
#define FLASH_SIZE_MAX_G07_8 (128U * 1024U) // 128 kiB
|
||||||
|
#define FLASH_SIZE_MAX_G0B_C (512U * 1024U) // 512 kiB
|
||||||
|
|
||||||
|
#define G0_FLASH_BASE 0x40022000
|
||||||
|
#define FLASH_ACR (G0_FLASH_BASE + 0x000)
|
||||||
|
#define FLASH_ACR_EMPTY (1U << 16U)
|
||||||
|
|
||||||
|
#define FLASH_KEYR (G0_FLASH_BASE + 0x008)
|
||||||
|
#define FLASH_KEYR_KEY1 0x45670123
|
||||||
|
#define FLASH_KEYR_KEY2 0xCDEF89AB
|
||||||
|
#define FLASH_CR (G0_FLASH_BASE + 0x014)
|
||||||
|
#define FLASH_CR_LOCK (1U << 31U)
|
||||||
|
#define FLASH_CR_OBL_LAUNCH (1U << 27U)
|
||||||
|
#define FLASH_CR_OPTSTRT (1U << 17U)
|
||||||
|
#define FLASH_CR_STRT (1U << 16U)
|
||||||
|
#define FLASH_CR_MER2 (1U << 15U)
|
||||||
|
#define FLASH_CR_MER1 (1U << 2U)
|
||||||
|
#define FLASH_CR_BKER (1U << 13U)
|
||||||
|
#define FLASH_CR_PNB_SHIFT 3U
|
||||||
|
#define FLASH_CR_PER (1U << 1U)
|
||||||
|
#define FLASH_CR_PG (1U << 0U)
|
||||||
|
|
||||||
|
#define FLASH_SR (G0_FLASH_BASE + 0x010)
|
||||||
|
#define FLASH_SR_BSY2 (1U << 17U)
|
||||||
|
#define FLASH_SR_BSY1 (1U << 16U)
|
||||||
|
#define FLASH_SR_OPTVERR (1U << 15U)
|
||||||
|
#define FLASH_SR_RDERR (1U << 14U)
|
||||||
|
#define FLASH_SR_FASTERR (1U << 9U)
|
||||||
|
#define FLASH_SR_MISSERR (1U << 8U)
|
||||||
|
#define FLASH_SR_PGSERR (1U << 7U)
|
||||||
|
#define FLASH_SR_SIZERR (1U << 6U)
|
||||||
|
#define FLASH_SR_PGAERR (1U << 5U)
|
||||||
|
#define FLASH_SR_WRPERR (1U << 4U)
|
||||||
|
#define FLASH_SR_PROGERR (1U << 3U)
|
||||||
|
#define FLASH_SR_OPERR (1U << 1U)
|
||||||
|
#define FLASH_SR_EOP (1U << 0U)
|
||||||
|
#define FLASH_SR_ERROR_MASK \
|
||||||
|
(FLASH_SR_OPTVERR | FLASH_SR_RDERR | FLASH_SR_FASTERR | \
|
||||||
|
FLASH_SR_MISSERR | FLASH_SR_PGSERR | FLASH_SR_SIZERR | \
|
||||||
|
FLASH_SR_PGAERR | FLASH_SR_WRPERR | FLASH_SR_PROGERR | \
|
||||||
|
FLASH_SR_OPERR)
|
||||||
|
#define FLASH_SR_BSY_MASK (FLASH_SR_BSY2 | FLASH_SR_BSY1)
|
||||||
|
|
||||||
|
#define FLASH_OPTKEYR (G0_FLASH_BASE + 0x00C)
|
||||||
|
#define FLASH_OPTKEYR_KEY1 0x08192A3B
|
||||||
|
#define FLASH_OPTKEYR_KEY2 0x4C5D6E7F
|
||||||
|
#define FLASH_OPTR (G0_FLASH_BASE + 0x020)
|
||||||
|
#define FLASH_OPTR_RDP_MASK 0xFF
|
||||||
|
#define FLASH_PCROP1ASR (G0_FLASH_BASE + 0x024)
|
||||||
|
#define FLASH_PCROP1AER (G0_FLASH_BASE + 0x028)
|
||||||
|
#define FLASH_WRP1AR (G0_FLASH_BASE + 0x02C)
|
||||||
|
#define FLASH_WRP1BR (G0_FLASH_BASE + 0x030)
|
||||||
|
#define FLASH_PCROP1BSR (G0_FLASH_BASE + 0x034)
|
||||||
|
#define FLASH_PCROP1BER (G0_FLASH_BASE + 0x038)
|
||||||
|
#define FLASH_PCROP2ASR (G0_FLASH_BASE + 0x044)
|
||||||
|
#define FLASH_PCROP2AER (G0_FLASH_BASE + 0x048)
|
||||||
|
#define FLASH_WRP2AR (G0_FLASH_BASE + 0x04C)
|
||||||
|
#define FLASH_WRP2BR (G0_FLASH_BASE + 0x050)
|
||||||
|
#define FLASH_PCROP2BSR (G0_FLASH_BASE + 0x054)
|
||||||
|
#define FLASH_PCROP2BER (G0_FLASH_BASE + 0x058)
|
||||||
|
#define FLASH_SECR (G0_FLASH_BASE + 0x080)
|
||||||
|
|
||||||
|
/* RAM */
|
||||||
|
#define RAM_START 0x20000000
|
||||||
|
#define RAM_SIZE_G03_4 (8U * 1024U) // 8 kiB
|
||||||
|
#define RAM_SIZE_G05_6 (18U * 1024U) // 18 kiB
|
||||||
|
#define RAM_SIZE_G07_8 (36U * 1024U) // 36 kiB
|
||||||
|
#define RAM_SIZE_G0B_C (144U * 1024U) // 144 kiB
|
||||||
|
|
||||||
|
/* RCC */
|
||||||
|
#define G0_RCC_BASE 0x40021000
|
||||||
|
#define RCC_APBENR1 (G0_RCC_BASE + 0x3C)
|
||||||
|
#define RCC_APBENR1_DBGEN (1U << 27U)
|
||||||
|
|
||||||
|
/* DBG */
|
||||||
|
#define DBG_BASE 0x40015800
|
||||||
|
#define DBG_CR (DBG_BASE + 0x04)
|
||||||
|
#define DBG_CR_DBG_STANDBY (1U << 2U)
|
||||||
|
#define DBG_CR_DBG_STOP (1U << 1U)
|
||||||
|
#define DBG_APB_FZ1 (DBG_BASE + 0x08)
|
||||||
|
#define DBG_APB_FZ1_DBG_IWDG_STOP (1U << 12U)
|
||||||
|
#define DBG_APB_FZ1_DBG_WWDG_STOP (1U << 11U)
|
||||||
|
|
||||||
|
enum STM32G0_DEV_ID {
|
||||||
|
STM32G03_4 = 0x466,
|
||||||
|
STM32G05_6 = 0x456,
|
||||||
|
STM32G07_8 = 0x460,
|
||||||
|
STM32G0B_C = 0x467
|
||||||
|
};
|
||||||
|
struct stm32g0_saved_regs_s {
|
||||||
|
uint32_t rcc_apbenr1;
|
||||||
|
uint32_t dbg_cr;
|
||||||
|
uint32_t dbg_apb_fz1;
|
||||||
|
};
|
||||||
|
struct stm32g0_priv_s {
|
||||||
|
struct stm32g0_saved_regs_s saved_regs;
|
||||||
|
bool irreversible_enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool stm32g0_attach(target *t);
|
||||||
|
static void stm32g0_detach(target *t);
|
||||||
|
static int stm32g0_flash_erase(struct target_flash *f, target_addr addr,
|
||||||
|
size_t len);
|
||||||
|
static int stm32g0_flash_write(struct target_flash *f, target_addr dest,
|
||||||
|
const void *src, size_t len);
|
||||||
|
|
||||||
|
/* Custom commands */
|
||||||
|
static bool stm32g0_cmd_erase_mass(target *t, int argc, const char **argv);
|
||||||
|
static bool stm32g0_cmd_option(target *t, int argc, const char **argv);
|
||||||
|
static bool stm32g0_cmd_irreversible(target *t, int argc, const char **argv);
|
||||||
|
|
||||||
|
const struct command_s stm32g0_cmd_list[] = {
|
||||||
|
{ "erase_mass [1|2]", (cmd_handler)stm32g0_cmd_erase_mass,
|
||||||
|
"Erase entire flash memory or specified bank" },
|
||||||
|
{ "option", (cmd_handler)stm32g0_cmd_option,
|
||||||
|
"Manipulate option bytes" },
|
||||||
|
{ "irreversible", (cmd_handler)stm32g0_cmd_irreversible,
|
||||||
|
"Allow irreversible operations: (enable|disable)" },
|
||||||
|
{ NULL, NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void stm32g0_add_flash(target *t, uint32_t addr, size_t length,
|
||||||
|
size_t blocksize)
|
||||||
|
{
|
||||||
|
struct target_flash *f = calloc(1, sizeof(*f));
|
||||||
|
if (!f) { /* calloc failed: heap exhaustion */
|
||||||
|
DEBUG_WARN("calloc: failed in %s\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
f->start = addr;
|
||||||
|
f->length = length;
|
||||||
|
f->blocksize = blocksize;
|
||||||
|
f->erase = stm32g0_flash_erase;
|
||||||
|
f->write = stm32g0_flash_write;
|
||||||
|
f->buf_size = FLASH_PAGE_SIZE;
|
||||||
|
f->erased = 0xFF;
|
||||||
|
target_add_flash(t, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Probe for a known STM32G0 MCU.
|
||||||
|
* Populate the memory map and add custom commands.
|
||||||
|
* Single bank devices are populated with their maximal flash capacity to allow
|
||||||
|
* users to program devices with more flash than announced.
|
||||||
|
*/
|
||||||
|
bool stm32g0_probe(target *t)
|
||||||
|
{
|
||||||
|
uint32_t ram_size = 0U;
|
||||||
|
size_t flash_size = 0U;
|
||||||
|
|
||||||
|
target_mem_map_free(t);
|
||||||
|
|
||||||
|
switch (t->idcode) {
|
||||||
|
case STM32G03_4:
|
||||||
|
/* SRAM 8 kiB, Flash up to 64 kiB */
|
||||||
|
ram_size = (uint32_t)RAM_SIZE_G03_4;
|
||||||
|
flash_size = (uint32_t)FLASH_SIZE_MAX_G03_4;
|
||||||
|
t->driver = "STM32G03/4";
|
||||||
|
break;
|
||||||
|
case STM32G05_6:
|
||||||
|
/* SRAM 18 kiB, Flash up to 64 kiB */
|
||||||
|
ram_size = (uint32_t)RAM_SIZE_G05_6;
|
||||||
|
flash_size = (uint32_t)FLASH_SIZE_MAX_G05_6;
|
||||||
|
t->driver = "STM32G05/6";
|
||||||
|
break;
|
||||||
|
case STM32G07_8:
|
||||||
|
/* SRAM 36 kiB, Flash up to 128 kiB */
|
||||||
|
ram_size = (uint32_t)RAM_SIZE_G07_8;
|
||||||
|
flash_size = (uint32_t)FLASH_SIZE_MAX_G07_8;
|
||||||
|
t->driver = "STM32G07/8";
|
||||||
|
break;
|
||||||
|
case STM32G0B_C:
|
||||||
|
/* SRAM 144 kiB, Flash up to 512 kiB */
|
||||||
|
ram_size = (uint32_t)RAM_SIZE_G0B_C;
|
||||||
|
flash_size = (size_t)target_mem_read16(t, FLASH_MEMORY_SIZE);
|
||||||
|
flash_size *= 1024U;
|
||||||
|
t->driver = "STM32G0B/C";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
target_add_ram(t, RAM_START, ram_size);
|
||||||
|
/* Dual banks: contiguous in memory */
|
||||||
|
stm32g0_add_flash(t, FLASH_START, flash_size, FLASH_PAGE_SIZE);
|
||||||
|
|
||||||
|
t->attach = stm32g0_attach;
|
||||||
|
t->detach = stm32g0_detach;
|
||||||
|
target_add_commands(t, stm32g0_cmd_list, t->driver);
|
||||||
|
|
||||||
|
/* Save private storage */
|
||||||
|
struct stm32g0_priv_s *priv_storage = calloc(1, sizeof(*priv_storage));
|
||||||
|
priv_storage->irreversible_enabled = false;
|
||||||
|
t->target_storage = (void*)priv_storage;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In addition to attaching the debug core with cortexm_attach(), this function
|
||||||
|
* keeps the FCLK and HCLK clocks running in Standby and Stop modes while
|
||||||
|
* debugging.
|
||||||
|
* The watchdogs (IWDG and WWDG) are stopped when the core is halted. This
|
||||||
|
* allows basic Flash operations (erase/write) if the watchdog is started by
|
||||||
|
* hardware or by a previous program without prior power cycle.
|
||||||
|
*/
|
||||||
|
static bool stm32g0_attach(target *t)
|
||||||
|
{
|
||||||
|
struct stm32g0_priv_s *ps = (struct stm32g0_priv_s*)t->target_storage;
|
||||||
|
|
||||||
|
if (!cortexm_attach(t))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ps->saved_regs.rcc_apbenr1 = target_mem_read32(t, RCC_APBENR1);
|
||||||
|
target_mem_write32(t, RCC_APBENR1, ps->saved_regs.rcc_apbenr1 |
|
||||||
|
RCC_APBENR1_DBGEN);
|
||||||
|
ps->saved_regs.dbg_cr = target_mem_read32(t, DBG_CR);
|
||||||
|
target_mem_write32(t, DBG_CR, ps->saved_regs.dbg_cr |
|
||||||
|
(DBG_CR_DBG_STANDBY | DBG_CR_DBG_STOP));
|
||||||
|
ps->saved_regs.dbg_apb_fz1 = target_mem_read32(t, DBG_APB_FZ1);
|
||||||
|
target_mem_write32(t, DBG_APB_FZ1, ps->saved_regs.dbg_apb_fz1 |
|
||||||
|
(DBG_APB_FZ1_DBG_IWDG_STOP | DBG_APB_FZ1_DBG_WWDG_STOP));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Restore the modified registers and detach the debug core.
|
||||||
|
* The registers are restored as is to leave the target in the same state as
|
||||||
|
* before attachment.
|
||||||
|
*/
|
||||||
|
static void stm32g0_detach(target *t)
|
||||||
|
{
|
||||||
|
struct stm32g0_priv_s *ps = (struct stm32g0_priv_s*)t->target_storage;
|
||||||
|
|
||||||
|
target_mem_write32(t, DBG_APB_FZ1, ps->saved_regs.dbg_apb_fz1);
|
||||||
|
target_mem_write32(t, DBG_CR, ps->saved_regs.dbg_cr);
|
||||||
|
target_mem_write32(t, RCC_APBENR1, ps->saved_regs.rcc_apbenr1);
|
||||||
|
|
||||||
|
cortexm_detach(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stm32g0_flash_unlock(target *t)
|
||||||
|
{
|
||||||
|
target_mem_write32(t, FLASH_KEYR, FLASH_KEYR_KEY1);
|
||||||
|
target_mem_write32(t, FLASH_KEYR, FLASH_KEYR_KEY2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stm32g0_flash_lock(target *t)
|
||||||
|
{
|
||||||
|
uint32_t flash_cr = target_mem_read32(t, FLASH_CR);
|
||||||
|
flash_cr |= (uint32_t)FLASH_CR_LOCK;
|
||||||
|
target_mem_write32(t, FLASH_CR, flash_cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flash erasure function.
|
||||||
|
*/
|
||||||
|
static int stm32g0_flash_erase(struct target_flash *f, target_addr addr,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
target *t = f->t;
|
||||||
|
target_addr end = addr + len - 1U;
|
||||||
|
uint16_t page_nb = 0U;
|
||||||
|
uint16_t nb_pages_to_erase = 0U;
|
||||||
|
uint16_t bank1_end_page_nb = FLASH_BANK2_START_PAGE_NB - 1U; // Max
|
||||||
|
bool on_bank2 = false;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (end > (f->start + f->length - 1U))
|
||||||
|
goto exit_error;
|
||||||
|
if (len == (size_t)0U)
|
||||||
|
goto exit_cleanup;
|
||||||
|
|
||||||
|
nb_pages_to_erase = (uint16_t)((len - 1U) / f->blocksize) + 1U;
|
||||||
|
if (t->idcode == STM32G0B_C) // Dual-bank devices
|
||||||
|
bank1_end_page_nb = ((f->length / 2U) - 1U) / f->blocksize;
|
||||||
|
page_nb = (uint16_t)((addr - f->start) / f->blocksize);
|
||||||
|
|
||||||
|
/* Wait for Flash ready */
|
||||||
|
while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY_MASK) {
|
||||||
|
if (target_check_error(t))
|
||||||
|
goto exit_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear any previous programming error */
|
||||||
|
target_mem_write32(t, FLASH_SR, target_mem_read32(t, FLASH_SR));
|
||||||
|
|
||||||
|
stm32g0_flash_unlock(t);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (!on_bank2 && (page_nb > bank1_end_page_nb)) {
|
||||||
|
/* Jump on bank 2 */
|
||||||
|
on_bank2 = true;
|
||||||
|
page_nb = FLASH_BANK2_START_PAGE_NB;
|
||||||
|
}
|
||||||
|
/* Erase */
|
||||||
|
uint32_t flash_cr = (uint32_t)((page_nb << FLASH_CR_PNB_SHIFT) |
|
||||||
|
FLASH_CR_PER);
|
||||||
|
if (on_bank2)
|
||||||
|
flash_cr |= (uint32_t)(FLASH_CR_BKER);
|
||||||
|
|
||||||
|
target_mem_write32(t, FLASH_CR, flash_cr);
|
||||||
|
|
||||||
|
flash_cr |= (uint32_t)FLASH_CR_STRT;
|
||||||
|
target_mem_write32(t, FLASH_CR, flash_cr);
|
||||||
|
|
||||||
|
while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY_MASK) {
|
||||||
|
if (target_check_error(t))
|
||||||
|
goto exit_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
page_nb++;
|
||||||
|
nb_pages_to_erase--;
|
||||||
|
} while (nb_pages_to_erase > 0U);
|
||||||
|
|
||||||
|
/* Check for error */
|
||||||
|
uint32_t flash_sr = target_mem_read32(t, FLASH_SR);
|
||||||
|
if (flash_sr & FLASH_SR_ERROR_MASK) {
|
||||||
|
DEBUG_WARN("stm32g0 flash erase error: sr 0x%" PRIx32 "\n",
|
||||||
|
flash_sr);
|
||||||
|
goto exit_error;
|
||||||
|
}
|
||||||
|
goto exit_cleanup;
|
||||||
|
|
||||||
|
exit_error:
|
||||||
|
ret = -1;
|
||||||
|
exit_cleanup:
|
||||||
|
target_mem_write32(t, FLASH_SR, (uint32_t)FLASH_SR_EOP); // Clear EOP
|
||||||
|
stm32g0_flash_lock(t);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flash programming function.
|
||||||
|
* The SR is supposed to be ready and free of any error.
|
||||||
|
* After a successful programming, the EMPTY bit is cleared to allow rebooting
|
||||||
|
* in Main Flash memory without power cycle.
|
||||||
|
*/
|
||||||
|
static int stm32g0_flash_write(struct target_flash *f, target_addr dest,
|
||||||
|
const void *src, size_t len)
|
||||||
|
{
|
||||||
|
target *t = f->t;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
stm32g0_flash_unlock(t);
|
||||||
|
|
||||||
|
target_mem_write32(t, FLASH_CR, FLASH_CR_PG);
|
||||||
|
target_mem_write(t, dest, src, len);
|
||||||
|
/* Wait for completion or an error */
|
||||||
|
uint32_t flash_sr;
|
||||||
|
do {
|
||||||
|
flash_sr = target_mem_read32(t, FLASH_SR);
|
||||||
|
if (target_check_error(t)) {
|
||||||
|
DEBUG_WARN("stm32g0 flash write: comm error\n");
|
||||||
|
goto exit_error;
|
||||||
|
}
|
||||||
|
} while (flash_sr & FLASH_SR_BSY_MASK);
|
||||||
|
|
||||||
|
if (flash_sr & FLASH_SR_ERROR_MASK) {
|
||||||
|
DEBUG_WARN("stm32g0 flash write error: sr 0x%" PRIx32 "\n",
|
||||||
|
flash_sr);
|
||||||
|
goto exit_error;
|
||||||
|
}
|
||||||
|
if ((dest == (target_addr)FLASH_START) &&
|
||||||
|
target_mem_read32(t, FLASH_START) != 0xFFFFFFFF) {
|
||||||
|
uint32_t flash_acr = target_mem_read32(t, FLASH_ACR);
|
||||||
|
flash_acr &= ~(uint32_t)FLASH_ACR_EMPTY;
|
||||||
|
target_mem_write32(t, FLASH_ACR, flash_acr);
|
||||||
|
}
|
||||||
|
goto exit_cleanup;
|
||||||
|
|
||||||
|
exit_error:
|
||||||
|
ret = -1;
|
||||||
|
exit_cleanup:
|
||||||
|
target_mem_write32(t, FLASH_SR, (uint32_t)FLASH_SR_EOP); // Clear EOP
|
||||||
|
/* Clear PG: half-word access not to clear unwanted bits */
|
||||||
|
target_mem_write16(t, FLASH_CR, (uint16_t)0x0);
|
||||||
|
stm32g0_flash_lock(t);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************
|
||||||
|
* Custom commands
|
||||||
|
*******************/
|
||||||
|
|
||||||
|
static bool stm32g0_cmd_erase_mass(target *t, int argc, const char **argv)
|
||||||
|
{
|
||||||
|
uint32_t flash_cr = 0U;
|
||||||
|
bool ret = true;
|
||||||
|
|
||||||
|
if (argc == 2) {
|
||||||
|
switch (argv[1][0]) {
|
||||||
|
case '1':
|
||||||
|
flash_cr = (uint32_t)FLASH_CR_MER1 | FLASH_CR_STRT;
|
||||||
|
break;
|
||||||
|
case '2':
|
||||||
|
flash_cr = (uint32_t)FLASH_CR_MER2 | FLASH_CR_STRT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto exit_error;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
flash_cr = (uint32_t)(FLASH_CR_MER1 | FLASH_CR_MER2 |
|
||||||
|
FLASH_CR_STRT);
|
||||||
|
}
|
||||||
|
|
||||||
|
stm32g0_flash_unlock(t);
|
||||||
|
|
||||||
|
target_mem_write32(t, FLASH_CR, flash_cr);
|
||||||
|
|
||||||
|
/* Read FLASH_SR to poll for BSY bits */
|
||||||
|
while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY_MASK) {
|
||||||
|
if (target_check_error(t))
|
||||||
|
goto exit_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for error */
|
||||||
|
uint16_t flash_sr = target_mem_read32(t, FLASH_SR);
|
||||||
|
if (flash_sr & FLASH_SR_ERROR_MASK)
|
||||||
|
goto exit_error;
|
||||||
|
goto exit_cleanup;
|
||||||
|
|
||||||
|
exit_error:
|
||||||
|
ret = false;
|
||||||
|
exit_cleanup:
|
||||||
|
stm32g0_flash_lock(t);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stm32g0_flash_option_unlock(target *t)
|
||||||
|
{
|
||||||
|
target_mem_write32(t, FLASH_OPTKEYR, FLASH_OPTKEYR_KEY1);
|
||||||
|
target_mem_write32(t, FLASH_OPTKEYR, FLASH_OPTKEYR_KEY2);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum option_bytes_registers {
|
||||||
|
OPTR_ENUM = 0,
|
||||||
|
PCROP1ASR_ENUM,
|
||||||
|
PCROP1AER_ENUM,
|
||||||
|
WRP1AR_ENUM,
|
||||||
|
WRP1BR_ENUM,
|
||||||
|
PCROP1BSR_ENUM,
|
||||||
|
PCROP1BER_ENUM,
|
||||||
|
PCROP2ASR_ENUM,
|
||||||
|
PCROP2AER_ENUM,
|
||||||
|
WRP2AR_ENUM,
|
||||||
|
WRP2BR_ENUM,
|
||||||
|
PCROP2BSR_ENUM,
|
||||||
|
PCROP2BER_ENUM,
|
||||||
|
SECR_ENUM,
|
||||||
|
|
||||||
|
NB_REG_OPT
|
||||||
|
};
|
||||||
|
|
||||||
|
struct registers_s {
|
||||||
|
uint32_t addr;
|
||||||
|
uint32_t val;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* G0x1: OPTR = FFFFFEAA
|
||||||
|
* 1111 1111 1111 1111 1111 1110 1010 1010
|
||||||
|
* G0x0: OPTR = DFFFE1AA
|
||||||
|
* 1101 1111 1111 1111 1110 0001 1010 1010
|
||||||
|
* *IRHEN * ****BOREN
|
||||||
|
* IRH and BOR are reserved on G0x0, it is safe to apply G0x1 options.
|
||||||
|
* The same for PCROP and SECR.
|
||||||
|
*/
|
||||||
|
static const struct registers_s options_def[NB_REG_OPT] = {
|
||||||
|
[OPTR_ENUM] = { FLASH_OPTR, 0xFFFFFEAA },
|
||||||
|
[PCROP1ASR_ENUM] = { FLASH_PCROP1ASR, 0xFFFFFFFF },
|
||||||
|
[PCROP1AER_ENUM] = { FLASH_PCROP1AER, 0x00000000 },
|
||||||
|
[WRP1AR_ENUM] = { FLASH_WRP1AR, 0x000000FF },
|
||||||
|
[WRP1BR_ENUM] = { FLASH_WRP1BR, 0x000000FF },
|
||||||
|
[PCROP1BSR_ENUM] = { FLASH_PCROP1BSR, 0xFFFFFFFF },
|
||||||
|
[PCROP1BER_ENUM] = { FLASH_PCROP1BER, 0x00000000 },
|
||||||
|
[PCROP2ASR_ENUM] = { FLASH_PCROP2ASR, 0xFFFFFFFF },
|
||||||
|
[PCROP2AER_ENUM] = { FLASH_PCROP2AER, 0x00000000 },
|
||||||
|
[WRP2AR_ENUM] = { FLASH_WRP2AR, 0x000000FF },
|
||||||
|
[WRP2BR_ENUM] = { FLASH_WRP2BR, 0x000000FF },
|
||||||
|
[PCROP2BSR_ENUM] = { FLASH_PCROP2BSR, 0xFFFFFFFF },
|
||||||
|
[PCROP2BER_ENUM] = { FLASH_PCROP2BER, 0x00000000 },
|
||||||
|
[SECR_ENUM] = { FLASH_SECR, 0x00000000 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void write_registers(target *t, const struct registers_s *regs,
|
||||||
|
uint8_t nb_regs)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0U; i < nb_regs; i++) {
|
||||||
|
if (regs[i].addr > 0U)
|
||||||
|
target_mem_write32(t, regs[i].addr, regs[i].val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Option bytes programming.
|
||||||
|
*/
|
||||||
|
static bool stm32g0_option_write(target *t,
|
||||||
|
const struct registers_s *options_req)
|
||||||
|
{
|
||||||
|
stm32g0_flash_unlock(t);
|
||||||
|
stm32g0_flash_option_unlock(t);
|
||||||
|
|
||||||
|
/* Wait for Flash ready */
|
||||||
|
while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY_MASK) {
|
||||||
|
if (target_check_error(t))
|
||||||
|
goto exit_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_registers(t, options_req, NB_REG_OPT);
|
||||||
|
|
||||||
|
target_mem_write32(t, FLASH_CR, FLASH_CR_OPTSTRT);
|
||||||
|
while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY_MASK) {
|
||||||
|
if (target_check_error(t))
|
||||||
|
goto exit_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Option bytes loading generates a system reset */
|
||||||
|
target_mem_write32(t, FLASH_CR, FLASH_CR_OBL_LAUNCH);
|
||||||
|
tc_printf(t, "Scan and attach again\n");
|
||||||
|
return true;
|
||||||
|
|
||||||
|
exit_error:
|
||||||
|
stm32g0_flash_lock(t); // Also locks option bytes
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This fonction adds a register given on the command line to a table.
|
||||||
|
* This table is further written to the target.
|
||||||
|
* The register is added only if its address is valid.
|
||||||
|
*/
|
||||||
|
static bool add_reg_value(struct registers_s *reg_req,
|
||||||
|
const struct registers_s *reg_def,
|
||||||
|
uint8_t reg_def_len, uint32_t addr, uint32_t val)
|
||||||
|
{
|
||||||
|
for (uint8_t j = 0U; j < reg_def_len; j++) {
|
||||||
|
if (addr == reg_def[j].addr) {
|
||||||
|
reg_req[j].addr = addr;
|
||||||
|
reg_req[j].val = val;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse (address, value) register pairs given on the command line.
|
||||||
|
*/
|
||||||
|
static bool parse_cmdline_registers(int args_nb, const char **reg_str,
|
||||||
|
struct registers_s *reg_req,
|
||||||
|
const struct registers_s *reg_def,
|
||||||
|
uint8_t reg_def_len)
|
||||||
|
{
|
||||||
|
uint32_t addr = 0U;
|
||||||
|
uint32_t val = 0U;
|
||||||
|
uint8_t valid_regs_nb = 0U;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < args_nb; i += 2U) {
|
||||||
|
addr = strtoul(reg_str[i], NULL, 0);
|
||||||
|
val = strtoul(reg_str[i + 1], NULL, 0);
|
||||||
|
if (add_reg_value(reg_req, reg_def, reg_def_len, addr, val))
|
||||||
|
valid_regs_nb++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valid_regs_nb > 0U)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Validates option bytes.
|
||||||
|
* Prevents RDP level 2 request if not explicitly allowed.
|
||||||
|
*/
|
||||||
|
static bool validate_options(target *t, const struct registers_s *options_req)
|
||||||
|
{
|
||||||
|
struct stm32g0_priv_s *ps = (struct stm32g0_priv_s*)t->target_storage;
|
||||||
|
|
||||||
|
if (((options_req[OPTR_ENUM].val & FLASH_OPTR_RDP_MASK) ==
|
||||||
|
(uint32_t)0xCC) &&
|
||||||
|
!ps->irreversible_enabled) {
|
||||||
|
tc_printf(t, "Irreversible operations disabled\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void display_registers(target *t, const struct registers_s *reg_def,
|
||||||
|
uint8_t len)
|
||||||
|
{
|
||||||
|
uint32_t val = 0U;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < len; i++) {
|
||||||
|
val = target_mem_read32(t, reg_def[i].addr);
|
||||||
|
tc_printf(t, "0x%08X: 0x%08X\n", reg_def[i].addr, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Option bytes manipulating.
|
||||||
|
* Erasure has to be done in two steps if Proprietary Code Read Out Protection
|
||||||
|
* is active:
|
||||||
|
* Step 1: increase RDP level to 1 and set PCROP_RDP if not already the case;
|
||||||
|
* Step 2: reset to defaults.
|
||||||
|
*/
|
||||||
|
static bool stm32g0_cmd_option(target *t, int argc, const char **argv)
|
||||||
|
{
|
||||||
|
struct registers_s options_req[NB_REG_OPT] = { { 0U, 0U } };
|
||||||
|
|
||||||
|
if ((argc == 2) && !strcmp(argv[1], "erase")) {
|
||||||
|
if (!stm32g0_option_write(t, options_def))
|
||||||
|
goto exit_error;
|
||||||
|
} else if ((argc > 2) && (argc % 2U == 0U) &&
|
||||||
|
!strcmp(argv[1], "write")) {
|
||||||
|
if (!parse_cmdline_registers(argc - 2, argv + 2, options_req,
|
||||||
|
options_def, NB_REG_OPT))
|
||||||
|
goto exit_error;
|
||||||
|
if (!validate_options(t, options_req))
|
||||||
|
goto exit_error;
|
||||||
|
if (!stm32g0_option_write(t, options_req))
|
||||||
|
goto exit_error;
|
||||||
|
} else {
|
||||||
|
tc_printf(t, "usage: monitor option erase\n");
|
||||||
|
tc_printf(t, "usage: monitor option write <addr> <val> [<addr> <val>]...\n");
|
||||||
|
display_registers(t, options_def, NB_REG_OPT);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
exit_error:
|
||||||
|
tc_printf(t, "Writing options failed!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enables irreversible operations:
|
||||||
|
* RDP level 2 read protection.
|
||||||
|
*/
|
||||||
|
static bool stm32g0_cmd_irreversible(target *t, int argc, const char **argv)
|
||||||
|
{
|
||||||
|
struct stm32g0_priv_s *ps = (struct stm32g0_priv_s*)t->target_storage;
|
||||||
|
bool ret = true;
|
||||||
|
|
||||||
|
if (argc == 2) {
|
||||||
|
if (!parse_enable_or_disable(argv[1],
|
||||||
|
&(ps->irreversible_enabled)))
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
tc_printf(t, "Irreversible operations: %s\n",
|
||||||
|
ps->irreversible_enabled ? "enabled" : "disabled");
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -165,6 +165,10 @@ struct stm32h7_flash {
|
||||||
uint32_t regbase;
|
uint32_t regbase;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct stm32h7_priv_s {
|
||||||
|
uint32_t dbg_cr;
|
||||||
|
};
|
||||||
|
|
||||||
static void stm32h7_add_flash(target *t,
|
static void stm32h7_add_flash(target *t,
|
||||||
uint32_t addr, size_t length, size_t blocksize)
|
uint32_t addr, size_t length, size_t blocksize)
|
||||||
{
|
{
|
||||||
|
@ -223,7 +227,9 @@ static bool stm32h7_attach(target *t)
|
||||||
|
|
||||||
static void stm32h7_detach(target *t)
|
static void stm32h7_detach(target *t)
|
||||||
{
|
{
|
||||||
target_mem_write32(t, DBGMCU_CR, t->target_storage);
|
struct stm32h7_priv_s *ps = (struct stm32h7_priv_s*)t->target_storage;
|
||||||
|
|
||||||
|
target_mem_write32(t, DBGMCU_CR, ps->dbg_cr);
|
||||||
cortexm_detach(t);
|
cortexm_detach(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,7 +241,10 @@ bool stm32h7_probe(target *t)
|
||||||
t->attach = stm32h7_attach;
|
t->attach = stm32h7_attach;
|
||||||
t->detach = stm32h7_detach;
|
t->detach = stm32h7_detach;
|
||||||
target_add_commands(t, stm32h7_cmd_list, stm32h7_driver_str);
|
target_add_commands(t, stm32h7_cmd_list, stm32h7_driver_str);
|
||||||
t->target_storage = target_mem_read32(t, DBGMCU_CR);
|
/* Save private storage */
|
||||||
|
struct stm32h7_priv_s *priv_storage = calloc(1, sizeof(*priv_storage));
|
||||||
|
priv_storage->dbg_cr = target_mem_read32(t, DBGMCU_CR);
|
||||||
|
t->target_storage = (void*)priv_storage;
|
||||||
/* RM0433 Rev 4 is not really clear, what bits are needed in DBGMCU_CR.
|
/* RM0433 Rev 4 is not really clear, what bits are needed in DBGMCU_CR.
|
||||||
* Maybe more flags needed?
|
* Maybe more flags needed?
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -116,7 +116,6 @@ static int stm32l4_flash_write(struct target_flash *f,
|
||||||
#define DBGMCU_CR_DBG_STANDBY (0x1U << 2U)
|
#define DBGMCU_CR_DBG_STANDBY (0x1U << 2U)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
STM32G0_DBGMCU_IDCODE_PHYS = 0x40015800,
|
|
||||||
STM32L4_DBGMCU_IDCODE_PHYS = 0xe0042000,
|
STM32L4_DBGMCU_IDCODE_PHYS = 0xe0042000,
|
||||||
};
|
};
|
||||||
#define FLASH_SIZE_REG 0x1FFF75E0
|
#define FLASH_SIZE_REG 0x1FFF75E0
|
||||||
|
@ -126,6 +125,10 @@ struct stm32l4_flash {
|
||||||
uint32_t bank1_start;
|
uint32_t bank1_start;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct stm32l4_priv_s {
|
||||||
|
uint32_t dbgmcu_cr;
|
||||||
|
};
|
||||||
|
|
||||||
enum ID_STM32L4 {
|
enum ID_STM32L4 {
|
||||||
ID_STM32L41 = 0x464u, /* RM0394, Rev.4 */
|
ID_STM32L41 = 0x464u, /* RM0394, Rev.4 */
|
||||||
ID_STM32L43 = 0x435u, /* RM0394, Rev.4 */
|
ID_STM32L43 = 0x435u, /* RM0394, Rev.4 */
|
||||||
|
@ -133,8 +136,6 @@ enum ID_STM32L4 {
|
||||||
ID_STM32L47 = 0x415u, /* RM0351, Rev.5 */
|
ID_STM32L47 = 0x415u, /* RM0351, Rev.5 */
|
||||||
ID_STM32L49 = 0x461u, /* RM0351, Rev.5 */
|
ID_STM32L49 = 0x461u, /* RM0351, Rev.5 */
|
||||||
ID_STM32L4R = 0x470u, /* RM0432, Rev.5 */
|
ID_STM32L4R = 0x470u, /* RM0432, Rev.5 */
|
||||||
ID_STM32G03 = 0x466u, /* RM0444/454, Rev.2 */
|
|
||||||
ID_STM32G07 = 0x460u, /* RM0444/454, Rev.2 */
|
|
||||||
ID_STM32G43 = 0x468u, /* RM0440, Rev.1 */
|
ID_STM32G43 = 0x468u, /* RM0440, Rev.1 */
|
||||||
ID_STM32G47 = 0x469u, /* RM0440, Rev.1 */
|
ID_STM32G47 = 0x469u, /* RM0440, Rev.1 */
|
||||||
};
|
};
|
||||||
|
@ -142,7 +143,6 @@ enum ID_STM32L4 {
|
||||||
enum FAM_STM32L4 {
|
enum FAM_STM32L4 {
|
||||||
FAM_STM32L4xx = 1,
|
FAM_STM32L4xx = 1,
|
||||||
FAM_STM32L4Rx = 2,
|
FAM_STM32L4Rx = 2,
|
||||||
FAM_STM32G0x = 3,
|
|
||||||
FAM_STM32WBxx = 4,
|
FAM_STM32WBxx = 4,
|
||||||
FAM_STM32G4xx = 5,
|
FAM_STM32G4xx = 5,
|
||||||
};
|
};
|
||||||
|
@ -210,20 +210,6 @@ struct stm32l4_info const L4info[] = {
|
||||||
.sram3 = 384,
|
.sram3 = 384,
|
||||||
.flags = 3 | DUAL_BANK,
|
.flags = 3 | DUAL_BANK,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
.idcode = ID_STM32G07,
|
|
||||||
.family = FAM_STM32G0x,
|
|
||||||
.designator = "STM32G07",
|
|
||||||
.sram1 = 36,
|
|
||||||
.flags = 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.idcode = ID_STM32G03,
|
|
||||||
.family = FAM_STM32G0x,
|
|
||||||
.designator = "STM32G03",
|
|
||||||
.sram1 = 8,
|
|
||||||
.flags = 1,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
.idcode = ID_STM32G43,
|
.idcode = ID_STM32G43,
|
||||||
.family = FAM_STM32G4xx,
|
.family = FAM_STM32G4xx,
|
||||||
|
@ -287,14 +273,13 @@ static bool stm32l4_attach(target *t)
|
||||||
struct stm32l4_info const *chip = stm32l4_get_chip_info(t->idcode);
|
struct stm32l4_info const *chip = stm32l4_get_chip_info(t->idcode);
|
||||||
|
|
||||||
|
|
||||||
uint32_t idcodereg = (chip->family == FAM_STM32G0x)
|
uint32_t idcodereg = STM32L4_DBGMCU_IDCODE_PHYS;
|
||||||
? STM32G0_DBGMCU_IDCODE_PHYS
|
|
||||||
: STM32L4_DBGMCU_IDCODE_PHYS;
|
|
||||||
|
|
||||||
|
|
||||||
/* Save DBGMCU_CR to restore it when detaching*/
|
/* Save DBGMCU_CR to restore it when detaching*/
|
||||||
uint32_t dbgmcu_cr = target_mem_read32(t, DBGMCU_CR(idcodereg));
|
struct stm32l4_priv_s *priv_storage = calloc(1, sizeof(*priv_storage));
|
||||||
t->target_storage = dbgmcu_cr;
|
priv_storage->dbgmcu_cr = target_mem_read32(t, DBGMCU_CR(idcodereg));
|
||||||
|
t->target_storage = (void*)priv_storage;
|
||||||
|
|
||||||
/* Enable debugging during all low power modes*/
|
/* Enable debugging during all low power modes*/
|
||||||
target_mem_write32(t, DBGMCU_CR(idcodereg), DBGMCU_CR_DBG_SLEEP | DBGMCU_CR_DBG_STANDBY | DBGMCU_CR_DBG_STOP);
|
target_mem_write32(t, DBGMCU_CR(idcodereg), DBGMCU_CR_DBG_SLEEP | DBGMCU_CR_DBG_STANDBY | DBGMCU_CR_DBG_STOP);
|
||||||
|
@ -304,15 +289,11 @@ static bool stm32l4_attach(target *t)
|
||||||
target_mem_map_free(t);
|
target_mem_map_free(t);
|
||||||
|
|
||||||
/* Add RAM to memory map */
|
/* Add RAM to memory map */
|
||||||
if (chip->family == FAM_STM32G0x) {
|
target_add_ram(t, 0x10000000, chip->sram2 << 10);
|
||||||
target_add_ram(t, 0x20000000, chip->sram1 << 10);
|
/* All L4 beside L47 alias SRAM2 after SRAM1.*/
|
||||||
} else {
|
uint32_t ramsize = (t->idcode == ID_STM32L47)?
|
||||||
target_add_ram(t, 0x10000000, chip->sram2 << 10);
|
chip->sram1 : (chip->sram1 + chip->sram2 + chip->sram3);
|
||||||
/* All L4 beside L47 alias SRAM2 after SRAM1.*/
|
target_add_ram(t, 0x20000000, ramsize << 10);
|
||||||
uint32_t ramsize = (t->idcode == ID_STM32L47)?
|
|
||||||
chip->sram1 : (chip->sram1 + chip->sram2 + chip->sram3);
|
|
||||||
target_add_ram(t, 0x20000000, ramsize << 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add the flash to memory map. */
|
/* Add the flash to memory map. */
|
||||||
uint32_t size = target_mem_read16(t, FLASH_SIZE_REG);
|
uint32_t size = target_mem_read16(t, FLASH_SIZE_REG);
|
||||||
|
@ -363,11 +344,11 @@ static bool stm32l4_attach(target *t)
|
||||||
|
|
||||||
static void stm32l4_detach(target *t)
|
static void stm32l4_detach(target *t)
|
||||||
{
|
{
|
||||||
|
struct stm32l4_priv_s *ps = (struct stm32l4_priv_s*)t->target_storage;
|
||||||
|
|
||||||
/*reverse all changes to DBGMCU_CR*/
|
/*reverse all changes to DBGMCU_CR*/
|
||||||
uint32_t idcodereg = STM32L4_DBGMCU_IDCODE_PHYS;
|
uint32_t idcodereg = STM32L4_DBGMCU_IDCODE_PHYS;
|
||||||
if (t->idcode == ID_STM32G07)
|
target_mem_write32(t, DBGMCU_CR(idcodereg), ps->dbgmcu_cr);
|
||||||
idcodereg = STM32G0_DBGMCU_IDCODE_PHYS;
|
|
||||||
target_mem_write32(t, DBGMCU_CR(idcodereg), t->target_storage);
|
|
||||||
cortexm_detach(t);
|
cortexm_detach(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,10 +494,6 @@ static const uint8_t l4_i2offset[9] = {
|
||||||
0x20, 0x24, 0x28, 0x2c, 0x30, 0x44, 0x48, 0x4c, 0x50
|
0x20, 0x24, 0x28, 0x2c, 0x30, 0x44, 0x48, 0x4c, 0x50
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint8_t g0_i2offset[7] = {
|
|
||||||
0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t g4_i2offset[11] = {
|
static const uint8_t g4_i2offset[11] = {
|
||||||
0x20, 0x24, 0x28, 0x2c, 0x30, 0x70, 0x44, 0x48, 0x4c, 0x50, 0x74
|
0x20, 0x24, 0x28, 0x2c, 0x30, 0x70, 0x44, 0x48, 0x4c, 0x50, 0x74
|
||||||
};
|
};
|
||||||
|
@ -577,9 +554,6 @@ static bool stm32l4_cmd_option(target *t, int argc, char *argv[])
|
||||||
const uint8_t *i2offset = l4_i2offset;
|
const uint8_t *i2offset = l4_i2offset;
|
||||||
if (t->idcode == ID_STM32L43) {/* L43x */
|
if (t->idcode == ID_STM32L43) {/* L43x */
|
||||||
len = 5;
|
len = 5;
|
||||||
} else if (t->idcode == ID_STM32G07) {/* G07x */
|
|
||||||
i2offset = g0_i2offset;
|
|
||||||
len = 7;
|
|
||||||
} else if (t->idcode == ID_STM32G47) {/* G47 */
|
} else if (t->idcode == ID_STM32G47) {/* G47 */
|
||||||
i2offset = g4_i2offset;
|
i2offset = g4_i2offset;
|
||||||
len = 11;
|
len = 11;
|
||||||
|
|
|
@ -66,6 +66,8 @@ target *target_new(void)
|
||||||
t->halt_poll = (void*)nop_function;
|
t->halt_poll = (void*)nop_function;
|
||||||
t->halt_resume = (void*)nop_function;
|
t->halt_resume = (void*)nop_function;
|
||||||
|
|
||||||
|
t->target_storage = NULL;
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +111,7 @@ void target_list_free(void)
|
||||||
free(target_list->commands);
|
free(target_list->commands);
|
||||||
target_list->commands = tc;
|
target_list->commands = tc;
|
||||||
}
|
}
|
||||||
|
free(target_list->target_storage);
|
||||||
target_mem_map_free(target_list);
|
target_mem_map_free(target_list);
|
||||||
while (target_list->bw_list) {
|
while (target_list->bw_list) {
|
||||||
void * next = target_list->bw_list->next;
|
void * next = target_list->bw_list->next;
|
||||||
|
|
|
@ -113,7 +113,7 @@ struct target_s {
|
||||||
unsigned target_options;
|
unsigned target_options;
|
||||||
uint16_t t_designer;
|
uint16_t t_designer;
|
||||||
uint16_t idcode;
|
uint16_t idcode;
|
||||||
uint32_t target_storage;
|
void *target_storage;
|
||||||
|
|
||||||
struct target_ram *ram;
|
struct target_ram *ram;
|
||||||
struct target_flash *flash;
|
struct target_flash *flash;
|
||||||
|
@ -176,6 +176,7 @@ bool stm32h7_probe(target *t);
|
||||||
bool stm32l0_probe(target *t);
|
bool stm32l0_probe(target *t);
|
||||||
bool stm32l1_probe(target *t);
|
bool stm32l1_probe(target *t);
|
||||||
bool stm32l4_probe(target *t);
|
bool stm32l4_probe(target *t);
|
||||||
|
bool stm32g0_probe(target *t);
|
||||||
bool lmi_probe(target *t);
|
bool lmi_probe(target *t);
|
||||||
bool lpc11xx_probe(target *t);
|
bool lpc11xx_probe(target *t);
|
||||||
bool lpc15xx_probe(target *t);
|
bool lpc15xx_probe(target *t);
|
||||||
|
|
Loading…
Reference in New Issue