From f2340740991cd7457a0df2d5fcef6db7a38948ee Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Wed, 25 Jul 2018 10:58:52 +0200 Subject: [PATCH 1/6] stm32h7: Start of support. Implement probe, memory map, erase, write, uid, crc, parallelism. --- src/Makefile | 1 + src/target/cortexm.c | 1 + src/target/stm32h7.c | 486 +++++++++++++++++++++++++++++++++++ src/target/target_internal.h | 1 + 4 files changed, 489 insertions(+) create mode 100644 src/target/stm32h7.c diff --git a/src/Makefile b/src/Makefile index 797fd15b..d416ddb5 100644 --- a/src/Makefile +++ b/src/Makefile @@ -54,6 +54,7 @@ SRC = \ samd.c \ stm32f1.c \ stm32f4.c \ + stm32h7.c \ stm32l0.c \ stm32l4.c \ swdptap.c \ diff --git a/src/target/cortexm.c b/src/target/cortexm.c index cbd769be..4f6de808 100644 --- a/src/target/cortexm.c +++ b/src/target/cortexm.c @@ -330,6 +330,7 @@ bool cortexm_probe(ADIv5_AP_t *ap) PROBE(stm32f1_probe); PROBE(stm32f4_probe); + PROBE(stm32h7_probe); PROBE(stm32l0_probe); /* STM32L0xx & STM32L1xx */ PROBE(stm32l4_probe); PROBE(lpc11xx_probe); diff --git a/src/target/stm32h7.c b/src/target/stm32h7.c new file mode 100644 index 00000000..5e843767 --- /dev/null +++ b/src/target/stm32h7.c @@ -0,0 +1,486 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2017-2018 Uwe Bonnes bon@elektron.ikp.physik.tu-darmstadt.de + * + * 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* This file implements STM32H7 target specific functions for detecting + * the device, providing the XML memory map and Flash memory programming. + * + * Refereces: + * ST doc - RM0433 + * Reference manual - STM32H7x3 advanced ARMĀ®-based 32-bit MCUs Rev.3 + */ + +#include "general.h" +#include "target.h" +#include "target_internal.h" +#include "cortexm.h" + +static bool stm32h7_cmd_erase_mass(target *t); +/* static bool stm32h7_cmd_option(target *t, int argc, char *argv[]); */ +static bool stm32h7_uid(target *t); +static bool stm32h7_crc(target *t); +static bool stm32h7_cmd_psize(target *t, int argc, char *argv[]); + +const struct command_s stm32h7_cmd_list[] = { + {"erase_mass", (cmd_handler)stm32h7_cmd_erase_mass, + "Erase entire flash memory"}, +/* {"option", (cmd_handler)stm32h7_cmd_option, + "Manipulate option bytes"},*/ + {"psize", (cmd_handler)stm32h7_cmd_psize, + "Configure flash write parallelism: (x8|x16|x32|x64(default))"}, + {"uid", (cmd_handler)stm32h7_uid, "Print unique device ID"}, + {"crc", (cmd_handler)stm32h7_crc, "Print CRC of both banks"}, + {NULL, NULL, NULL} +}; + + +static int stm32h7_flash_erase(struct target_flash *f, target_addr addr, + size_t len); +static int stm32h7_flash_write(struct target_flash *f, + target_addr dest, const void *src, size_t len); + +static const char stm32h74_driver_str[] = "STM32H74x"; + +enum stm32h7_regs +{ + FLASH_ACR = 0x00, + FLASH_KEYR = 0x04, + FLASH_OPTKEYR = 0x08, + FLASH_CR = 0x0c, + FLASH_SR = 0x10, + FLASH_CCR = 0x14, + FLASH_OPTCR = 0x18, + FLASH_OPTSR_CUR = 0x1C, + FLASH_OPTSR = 0x20, + FLASH_CRCCR = 0x50, + FLASH_CRCDATA = 0x5C, +}; + +/* Flash Program and Erase Controller Register Map */ +#define H7_IWDG_BASE 0x58004c00 +#define FPEC1_BASE 0x52002000 +#define FPEC2_BASE 0x52002100 +#define FLASH_SR_BSY (1 << 0) +#define FLASH_SR_WBNE (1 << 1) +#define FLASH_SR_QW (1 << 2) +#define FLASH_SR_CRC_BUSY (1 << 3) +#define FLASH_SR_EOP (1 << 16) +#define FLASH_SR_WRPERR (1 << 17) +#define FLASH_SR_PGSERR (1 << 18) +#define FLASH_SR_STRBERR (1 << 19) +#define FLASH_SR_INCERR (1 << 21) +#define FLASH_SR_OPERR (1 << 22) +#define FLASH_SR_OPERR (1 << 22) +#define FLASH_SR_RDPERR (1 << 23) +#define FLASH_SR_RDSERR (1 << 24) +#define FLASH_SR_SNECCERR (1 << 25) +#define FLASH_SR_DBERRERR (1 << 26) +#define FLASH_SR_ERROR_READ (FLASH_SR_RDPERR | FLASH_SR_RDSERR | \ + FLASH_SR_SNECCERR |FLASH_SR_DBERRERR) +#define FLASH_SR_ERROR_MASK ( \ + FLASH_SR_WRPERR | FLASH_SR_PGSERR | FLASH_SR_STRBERR | \ + FLASH_SR_INCERR | FLASH_SR_OPERR | FLASH_SR_ERROR_READ) +#define FLASH_CR_LOCK (1 << 0) +#define FLASH_CR_PG (1 << 1) +#define FLASH_CR_SER (1 << 2) +#define FLASH_CR_BER (1 << 3) +#define FLASH_CR_PSIZE8 (0 << 4) +#define FLASH_CR_PSIZE16 (1 << 4) +#define FLASH_CR_PSIZE32 (2 << 4) +#define FLASH_CR_PSIZE64 (3 << 4) +#define FLASH_CR_FW (1 << 6) +#define FLASH_CR_START (1 << 7) +#define FLASH_CR_SNB_1 (1 << 8) +#define FLASH_CR_SNB (3 << 8) +#define FLASH_CR_CRC_EN (1 << 15) + +#define FLASH_OPTCR_OPTLOCK (1 << 0) +#define FLASH_OPTCR_OPTSTRT (1 << 1) + +#define FLASH_OPTSR_IWDG1_SW (1 << 4) + +#define FLASH_CRCCR_ALL_BANK (1 << 7) +#define FLASH_CRCCR_START_CRC (1 << 16) +#define FLASH_CRCCR_CLEAN_CRC (1 << 17) +#define FLASH_CRCCR_CRC_BURST_3 (3 << 20) + +#define KEY1 0x45670123 +#define KEY2 0xCDEF89AB + +#define OPTKEY1 0x08192A3B +#define OPTKEY2 0x4C5D6E7F + +#define DBGMCU_IDCODE 0x5c001000 +/* Access via 0xe00e1000 does not show device! */ +#define DBGMCU_CR (DBGMCU_IDCODE + 4) +#define DBGSLEEP_D1 (1 << 0) +#define DBGSTOP_D1 (1 << 1) +#define DBGSTBY_D1 (1 << 2) +#define DBGSTOP_D3 (1 << 7) +#define DBGSTBY_D3 (1 << 8) +#define D1DBGCKEN (1 << 21) +#define D3DBGCKEN (1 << 22) + + +#define FLASH_SIZE_REG 0x1ff1e880 + +#define BANK1_START 0x08000000 +#define NUM_SECTOR_PER_BANK 8 +#define FLASH_SECTOR_SIZE 0x20000 +#define BANK2_START 0x08100000 +enum ID_STM32H7 { + ID_STM32H74x = 0x450, +}; + +struct stm32h7_flash { + struct target_flash f; + enum align psize; + uint32_t regbase; +}; + +static void stm32h7_add_flash(target *t, + uint32_t addr, size_t length, size_t blocksize) +{ + struct stm32h7_flash *sf = calloc(1, sizeof(*sf)); + struct target_flash *f = &sf->f; + f->start = addr; + f->length = length; + f->blocksize = blocksize; + f->erase = stm32h7_flash_erase; + f->write = stm32h7_flash_write; + f->buf_size = 2048; + f->erased = 0xff; + sf->regbase = FPEC1_BASE; + if (addr >= BANK2_START) + sf->regbase = FPEC2_BASE; + sf->psize = ALIGN_DWORD; + target_add_flash(t, f); +} + +bool stm32h7_probe(target *t) +{ + uint32_t idcode = target_mem_read32(t, DBGMCU_IDCODE) & 0xFFF; + if (idcode == ID_STM32H74x) { + /* RM0433 Rev 4 is not really clear, what bits are needed. + * Set all possible relevant bits for now. */ + target_mem_write32(t, DBGMCU_CR, DBGSLEEP_D1 | D1DBGCKEN); + t->idcode = idcode; + t->driver = stm32h74_driver_str; + target_add_commands(t, stm32h7_cmd_list, stm32h74_driver_str); + target_add_ram(t, 0x00000000, 0x10000); /* ITCM Ram, 64 k */ + target_add_ram(t, 0x20000000, 0x20000); /* DTCM Ram, 128 k */ + target_add_ram(t, 0x24000000, 0x80000); /* AXI Ram, 512 k */ + target_add_ram(t, 0x30000000, 0x20000); /* AHB SRAM1, 128 k */ + target_add_ram(t, 0x32000000, 0x20000); /* AHB SRAM2, 128 k */ + target_add_ram(t, 0x34000000, 0x08000); /* AHB SRAM3, 32 k */ + target_add_ram(t, 0x38000000, 0x01000); /* AHB SRAM4, 32 k */ + stm32h7_add_flash(t, 0x8000000, 0x100000, FLASH_SECTOR_SIZE); + stm32h7_add_flash(t, 0x8100000, 0x100000, FLASH_SECTOR_SIZE); + /* If IWDG runs as HARDWARE watchdog (44.3.4) erase + * will be aborted by the Watchdog and erase fails! + * Setting IWDG_KR to 0xaaaa does not seem to help!*/ + uint32_t optsr = target_mem_read32(t, FPEC1_BASE + FLASH_OPTSR); + if (!(optsr & FLASH_OPTSR_IWDG1_SW)) + tc_printf(t, "Hardware IWDG running. Expect failure. Set IWDG1_SW!"); + return true; + } + return false; +} + +static bool stm32h7_flash_unlock(target *t, uint32_t addr) +{ + uint32_t regbase = FPEC1_BASE; + if (addr >= BANK2_START) { + regbase = FPEC2_BASE; + } + + while(target_mem_read32(t, regbase + FLASH_SR) & FLASH_SR_BSY) { + if(target_check_error(t)) + return false; + } + uint32_t sr = target_mem_read32(t, regbase + FLASH_SR); + if (sr & FLASH_SR_ERROR_MASK) { + tc_printf(t, "Error 0x%08lx", sr & FLASH_SR_ERROR_MASK); + target_mem_write32(t, regbase + FLASH_CCR, sr & FLASH_SR_ERROR_MASK); + return false; + } + if (target_mem_read32(t, regbase + FLASH_CR) & FLASH_CR_LOCK) { + /* Enable FLASH controller access */ + target_mem_write32(t, regbase + FLASH_KEYR, KEY1); + target_mem_write32(t, regbase + FLASH_KEYR, KEY2); + } + if (target_mem_read32(t, regbase + FLASH_CR) & FLASH_CR_LOCK) + return false; + else + return true; +} + +static int stm32h7_flash_erase(struct target_flash *f, target_addr addr, + size_t len) +{ + target *t = f->t; + struct stm32h7_flash *sf = (struct stm32h7_flash *)f; + if (stm32h7_flash_unlock(t, addr) == false) + return -1; + /* We come out of reset with HSI 64 MHz. Adapt FLASH_ACR.*/ + target_mem_write32(t, sf->regbase + FLASH_ACR, 0); + addr &= (NUM_SECTOR_PER_BANK * FLASH_SECTOR_SIZE) - 1; + int start_sector = addr / FLASH_SECTOR_SIZE; + int end_sector = (addr + len - 1) / FLASH_SECTOR_SIZE; + + enum align psize = ((struct stm32h7_flash *)f)->psize; + uint32_t sr; + while (start_sector <= end_sector) { + uint32_t cr = (psize * FLASH_CR_PSIZE16) | FLASH_CR_SER | + (start_sector * FLASH_CR_SNB_1); + target_mem_write32(t, sf->regbase + FLASH_CR, cr); + cr |= FLASH_CR_START; + target_mem_write32(t, sf->regbase + FLASH_CR, cr); + DEBUG(" started cr %08" PRIx32 " sr %08" PRIx32 "\n", + target_mem_read32(t, sf->regbase + FLASH_CR), + target_mem_read32(t, sf->regbase + FLASH_SR)); + do { + sr = target_mem_read32(t, sf->regbase + FLASH_SR); + if (target_check_error(t)) { + DEBUG("stm32h7_flash_erase: comm failed\n"); + return -1; + } +// target_mem_write32(t, H7_IWDG_BASE, 0x0000aaaa); + }while (sr & (FLASH_SR_QW | FLASH_SR_BSY)); + if (sr & FLASH_SR_ERROR_MASK) { + DEBUG("stm32h7_flash_erase: error, sr: %08" PRIx32 "\n", sr); + return -1; + } + start_sector++; + } + return 0; +} + +static int stm32h7_flash_write(struct target_flash *f, target_addr dest, + const void *src, size_t len) +{ + target *t = f->t; + struct stm32h7_flash *sf = (struct stm32h7_flash *)f; + enum align psize = sf->psize; + if (stm32h7_flash_unlock(t, dest) == false) + return -1; + uint32_t cr = psize * FLASH_CR_PSIZE16; + target_mem_write32(t, sf->regbase + FLASH_CR, cr); + cr |= FLASH_CR_PG; + target_mem_write32(t, sf->regbase + FLASH_CR, cr); + /* does H7 stall?*/ + uint32_t sr_reg = sf->regbase + FLASH_SR; + uint32_t sr; + target_mem_write(t, dest, src, len); + while ((sr = target_mem_read32(t, sr_reg)) & FLASH_SR_BSY) { + if(target_check_error(t)) { + DEBUG("stm32h7_flash_write: BSY comm failed\n"); + return -1; + } + } + if (sr & FLASH_SR_ERROR_MASK) { + DEBUG("stm32h7_flash_write: error sr %08" PRIx32 "\n", sr); + return -1; + } + /* Close write windows.*/ + target_mem_write32(t, sf->regbase + FLASH_CR, 0); + return 0; +} + +/* Both banks are erased in parallel.*/ +static bool stm32h7_cmd_erase(target *t, int bank_mask) +{ + const char spinner[] = "|/-\\"; + int spinindex = 0; + bool do_bank1 = bank_mask & 1, do_bank2 = bank_mask & 2; + uint32_t cr; + bool result = false; + enum align psize = ALIGN_DWORD; + for (struct target_flash *f = t->flash; f; f = f->next) { + if (f->write == stm32h7_flash_write) { + psize = ((struct stm32h7_flash *)f)->psize; + } + } + cr = (psize * FLASH_CR_PSIZE16) | FLASH_CR_BER | FLASH_CR_START; + /* Flash mass erase start instruction */ + if (do_bank1) { + if (stm32h7_flash_unlock(t, BANK1_START) == false) { + DEBUG("ME: Unlock bank1 failed\n"); + goto done; + } + uint32_t regbase = FPEC1_BASE; + /* BER and start can be merged (3.3.10).*/ + target_mem_write32(t, regbase + FLASH_CR, cr); + DEBUG("ME bank1 started\n"); + } + if (do_bank2) { + if (stm32h7_flash_unlock(t, BANK2_START) == false) { + DEBUG("ME: Unlock bank2 failed\n"); + goto done; + } + uint32_t regbase = FPEC2_BASE; + /* BER and start can be merged (3.3.10).*/ + target_mem_write32(t, regbase + FLASH_CR, cr); + DEBUG("ME bank2 started\n"); + } + + /* Read FLASH_SR to poll for QW bit */ + if (do_bank1) { + uint32_t regbase = FPEC1_BASE; + while (target_mem_read32(t, regbase + FLASH_SR) & FLASH_SR_QW) { +// target_mem_write32(t, H7_IWDG_BASE, 0x0000aaaa); + tc_printf(t, "\b%c", spinner[spinindex++ % 4]); + if(target_check_error(t)) { + DEBUG("ME bank1: comm failed\n"); + goto done; + } + } + } + if (do_bank2) { + uint32_t regbase = FPEC2_BASE; + while (target_mem_read32(t, regbase + FLASH_SR) & FLASH_SR_QW) { +// target_mem_write32(t, H7_IWDG_BASE 0x0000aaaa); + tc_printf(t, "\b%c", spinner[spinindex++ % 4]); + if(target_check_error(t)) { + DEBUG("ME bank2: comm failed\n"); + goto done; + } + } + } + + if (do_bank1) { + /* Check for error */ + uint32_t regbase = FPEC1_BASE; + uint32_t sr = target_mem_read32(t, regbase + FLASH_SR); + if (sr & FLASH_SR_ERROR_MASK) { + DEBUG("ME bank1: sr %" PRIx32 "\n", sr); + goto done; + } + } + if (do_bank2) { + /* Check for error */ + uint32_t regbase = FPEC2_BASE; + uint32_t sr = target_mem_read32(t, regbase + FLASH_SR); + if (sr & FLASH_SR_ERROR_MASK) { + DEBUG("ME bank2: sr %" PRIx32 "\n", sr); + goto done; + } + } + result = true; + done: + tc_printf(t, "\n"); + return result; +} + +static bool stm32h7_cmd_erase_mass(target *t) +{ + tc_printf(t, "Erasing flash... This may take a few seconds. "); + return stm32h7_cmd_erase(t, 3); +} + +/* Print the Unique device ID. + * Can be reused for other STM32 devices With uid as parameter. + */ +static bool stm32h7_uid(target *t) +{ + uint32_t uid = 0x1ff1e800; + int i; + tc_printf(t, "0x"); + for (i = 0; i < 12; i = i + 4) { + uint32_t val = target_mem_read32(t, uid + i); + tc_printf(t, "%02X", (val >> 24) & 0xff); + tc_printf(t, "%02X", (val >> 16) & 0xff); + tc_printf(t, "%02X", (val >> 8) & 0xff); + tc_printf(t, "%02X", (val >> 0) & 0xff); + } + tc_printf(t, "\n"); + return true; +} +static int stm32h7_crc_bank(target *t, uint32_t bank) +{ + uint32_t regbase = FPEC1_BASE; + if (bank >= BANK2_START) + regbase = FPEC2_BASE; + + if (stm32h7_flash_unlock(t, bank) == false) + return -1; + uint32_t cr = FLASH_CR_CRC_EN; + target_mem_write32(t, regbase + FLASH_CR, cr); + uint32_t crccr= FLASH_CRCCR_CRC_BURST_3 | + FLASH_CRCCR_CLEAN_CRC | FLASH_CRCCR_ALL_BANK; + target_mem_write32(t, regbase + FLASH_CRCCR, crccr); + target_mem_write32(t, regbase + FLASH_CRCCR, crccr | FLASH_CRCCR_START_CRC); + uint32_t sr; + while ((sr = target_mem_read32(t, regbase + FLASH_SR)) & FLASH_SR_CRC_BUSY) { + if(target_check_error(t)) { + DEBUG("CRC bank %d: comm failed\n", (bank < BANK2_START) ? 1 : 2); + return -1; + } + if (sr & FLASH_SR_ERROR_READ) { + DEBUG("CRC bank %d: error sr %08" PRIx32 "\n", + (bank < BANK2_START) ? 1 : 2, sr); + return -1; + } + } + return 0; +} + +static bool stm32h7_crc(target *t) +{ + if (stm32h7_crc_bank(t, BANK1_START) ) return false; + uint32_t crc1 = target_mem_read32(t, FPEC1_BASE + FLASH_CRCDATA); + if (stm32h7_crc_bank(t, BANK2_START) ) return false; + uint32_t crc2 = target_mem_read32(t, FPEC1_BASE + FLASH_CRCDATA); + tc_printf(t, "CRC: bank1 0x%08lx, bank2 0x%08lx\n", crc1, crc2); + return true; +} +static bool stm32h7_cmd_psize(target *t, int argc, char *argv[]) +{ + if (argc == 1) { + enum align psize = ALIGN_DWORD; + for (struct target_flash *f = t->flash; f; f = f->next) { + if (f->write == stm32h7_flash_write) { + psize = ((struct stm32h7_flash *)f)->psize; + } + } + tc_printf(t, "Flash write parallelism: %s\n", + psize == ALIGN_DWORD ? "x64" : + psize == ALIGN_WORD ? "x32" : + psize == ALIGN_HALFWORD ? "x16" : "x8"); + } else { + enum align psize; + if (!strcmp(argv[1], "x8")) { + psize = ALIGN_BYTE; + } else if (!strcmp(argv[1], "x16")) { + psize = ALIGN_HALFWORD; + } else if (!strcmp(argv[1], "x32")) { + psize = ALIGN_WORD; + } else if (!strcmp(argv[1], "x64")) { + psize = ALIGN_DWORD; + } else { + tc_printf(t, "usage: monitor psize (x8|x16|x32|x64)\n"); + return false; + } + for (struct target_flash *f = t->flash; f; f = f->next) { + if (f->write == stm32h7_flash_write) { + ((struct stm32h7_flash *)f)->psize = psize; + } + } + } + return true; +} diff --git a/src/target/target_internal.h b/src/target/target_internal.h index d78ed537..62664a8b 100644 --- a/src/target/target_internal.h +++ b/src/target/target_internal.h @@ -161,6 +161,7 @@ int tc_system(target *t, target_addr cmd, size_t cmdlen); */ bool stm32f1_probe(target *t); bool stm32f4_probe(target *t); +bool stm32h7_probe(target *t); bool stm32l0_probe(target *t); bool stm32l1_probe(target *t); bool stm32l4_probe(target *t); From 2c1c91321304ce1cdfa5b5bdb957a66db3fd7b28 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Fri, 20 Jul 2018 16:40:42 +0200 Subject: [PATCH 2/6] adiv5.c: Add units found on M7. --- src/target/adiv5.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/target/adiv5.c b/src/target/adiv5.c index 109cab30..1bea9f6d 100644 --- a/src/target/adiv5.c +++ b/src/target/adiv5.c @@ -171,6 +171,7 @@ static const struct { {0x00b, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M0 BPU", "(Breakpoint Unit)")}, {0x00c, aa_cortexm, cidc_gipc, PIDR_PN_BIT_STRINGS("Cortex-M4 SCS", "(System Control Space)")}, {0x00d, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETM11", "(Embedded Trace)")}, + {0x00e, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 FBP", "(Flash Patch and Breakpoint)")}, {0x490, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 GIC", "(Generic Interrupt Controller)")}, {0x4c7, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 PPB", "(Private Peripheral Bus ROM Table)")}, {0x906, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight CTI", "(Cross Trigger)")}, @@ -194,8 +195,10 @@ static const struct { {0x95f, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 PTM", "(Program Trace Macrocell)")}, {0x961, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight TMC", "(Trace Memory Controller)")}, {0x962, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight STM", "(System Trace Macrocell)")}, + {0x975, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 ETM", "(Embedded Trace)")}, {0x9a0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight PMU", "(Performance Monitoring Unit)")}, {0x9a1, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M4 TPIU", "(Trace Port Interface Unit)")}, + {0x9a9, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 TPIU", "(Trace Port Interface Unit)")}, {0x9a5, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A5 ETM", "(Embedded Trace)")}, {0x9a7, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A7 PMU", "(Performance Monitor Unit)")}, {0x9af, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 PMU", "(Performance Monitor Unit)")}, From 5918608156098db4b4f42f386b59e75bef79b79a Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Fri, 20 Jul 2018 17:42:33 +0200 Subject: [PATCH 3/6] STM32F7: Debug does not work with WFI without DBG_SLEEP --- src/target/stm32f4.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/target/stm32f4.c b/src/target/stm32f4.c index 1ecdcbbe..a7848fca 100644 --- a/src/target/stm32f4.c +++ b/src/target/stm32f4.c @@ -99,6 +99,8 @@ static int stm32f4_flash_write(struct target_flash *f, #define F7_FLASHSIZE 0x1FF0F442 #define F72X_FLASHSIZE 0x1FF07A22 #define DBGMCU_IDCODE 0xE0042000 +#define DBGMCU_CR 0xE0042004 +#define DBG_SLEEP (1 << 0) #define ARM_CPUID 0xE000ED00 #define AXIM_BASE 0x8000000 @@ -194,6 +196,11 @@ bool stm32f4_probe(target *t) idcode = ID_STM32F40X; } switch(idcode) { + case ID_STM32F74X: /* F74x RM0385 Rev.4 */ + case ID_STM32F76X: /* F76x F77x RM0410 */ + case ID_STM32F72X: /* F72x F73x RM0431 */ + target_mem_write32(t, DBGMCU_CR, DBG_SLEEP); + /* fallthrough */ case ID_STM32F40X: case ID_STM32F42X: /* 427/437 */ case ID_STM32F46X: /* 469/479 */ @@ -204,9 +211,6 @@ bool stm32f4_probe(target *t) case ID_STM32F412: /* F412 RM0402 Rev.4, 256 kB Ram */ case ID_STM32F401E: /* F401 D/E RM0368 Rev.3 */ case ID_STM32F413: /* F413 RM0430 Rev.2, 320 kB Ram, 1.5 MB flash. */ - case ID_STM32F74X: /* F74x RM0385 Rev.4 */ - case ID_STM32F76X: /* F76x F77x RM0410 */ - case ID_STM32F72X: /* F72x F73x RM0431 */ t->idcode = idcode; t->driver = stm32f4_get_chip_name(idcode); t->attach = stm32f4_attach; From cb8596b0b2f7505b9634c4f34628ab3402e2e892 Mon Sep 17 00:00:00 2001 From: Mark Rages Date: Fri, 27 Jul 2018 14:43:29 -0600 Subject: [PATCH 4/6] Another chip ID for Nordic nRF52832. --- src/target/nrf51.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/target/nrf51.c b/src/target/nrf51.c index f85d182d..7ea546c4 100644 --- a/src/target/nrf51.c +++ b/src/target/nrf51.c @@ -164,8 +164,9 @@ bool nrf51_probe(target *t) target_add_commands(t, nrf51_cmd_list, "nRF51"); return true; case 0x00AC: /* nRF52832 Preview QFAA BA0 */ - case 0x00C7: /* nRF52832 Revision 1 QFAA B00 */ - case 0x00E3: /* nRF52832-CIAA CSP */ + case 0x00C7: /* nRF52832 (rev 1) QFAA B00 */ + case 0x00E3: /* nRF52832 (rev 1) CIAA B?? */ + case 0x0139: /* nRF82832 (rev 2) ??AA B?0 */ t->driver = "Nordic nRF52"; target_add_ram(t, 0x20000000, 64*1024); nrf51_add_flash(t, 0x00000000, 512*1024, NRF52_PAGE_SIZE); From d0a8ce08199b40e29a7c7b3642c56e7158b1ca09 Mon Sep 17 00:00:00 2001 From: Mark Rages Date: Fri, 27 Jul 2018 16:07:19 -0600 Subject: [PATCH 5/6] Add extra port for mass erasing / unprotecting nRF52 with APPROTECT set. Mostly copied from the equivalent in kinetis.c and https://devzone.nordicsemi.com/f/nordic-q-a/12484/approtect-and-dap/47301 --- src/target/adiv5.c | 3 ++ src/target/kinetis.c | 2 +- src/target/nrf51.c | 78 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/src/target/adiv5.c b/src/target/adiv5.c index 109cab30..08baf303 100644 --- a/src/target/adiv5.c +++ b/src/target/adiv5.c @@ -445,6 +445,9 @@ void adiv5_dp_init(ADIv5_DP_t *dp) extern void kinetis_mdm_probe(ADIv5_AP_t *); kinetis_mdm_probe(ap); + extern void nrf51_mdm_probe(ADIv5_AP_t *); + nrf51_mdm_probe(ap); + if (ap->base == 0xffffffff) { /* No debug entries... useless AP */ adiv5_ap_unref(ap); diff --git a/src/target/kinetis.c b/src/target/kinetis.c index 4770773c..d9f4d0a1 100644 --- a/src/target/kinetis.c +++ b/src/target/kinetis.c @@ -341,7 +341,7 @@ const struct command_s kinetis_mdm_cmd_list[] = { {NULL, NULL, NULL} }; -bool nop_function(void) +static bool nop_function(void) { return true; } diff --git a/src/target/nrf51.c b/src/target/nrf51.c index f85d182d..9948bb19 100644 --- a/src/target/nrf51.c +++ b/src/target/nrf51.c @@ -335,3 +335,81 @@ static bool nrf51_cmd_read(target *t, int argc, const char *argv[]) return nrf51_cmd_read_help(t); } + +#include "adiv5.h" +#define NRF52_MDM_IDR 0x02880000 + +static bool nrf51_mdm_cmd_erase_mass(target *t); + +const struct command_s nrf51_mdm_cmd_list[] = { + {"erase_mass", (cmd_handler)nrf51_mdm_cmd_erase_mass, "Erase entire flash memory"}, + {NULL, NULL, NULL} +}; + +static bool nop_function(void) +{ + return true; +} + +void nrf51_mdm_probe(ADIv5_AP_t *ap) +{ + switch(ap->idr) { + case NRF52_MDM_IDR: + break; + default: + return; + } + + target *t = target_new(); + adiv5_ap_ref(ap); + t->priv = ap; + t->priv_free = (void*)adiv5_ap_unref; + + t->driver = "Nordic nRF52 Access Port"; + t->attach = (void*)nop_function; + t->detach = (void*)nop_function; + t->check_error = (void*)nop_function; + t->mem_read = (void*)nop_function; + t->mem_write = (void*)nop_function; + t->regs_size = 4; + t->regs_read = (void*)nop_function; + t->regs_write = (void*)nop_function; + t->reset = (void*)nop_function; + t->halt_request = (void*)nop_function; + //t->halt_poll = mdm_halt_poll; + t->halt_resume = (void*)nop_function; + + target_add_commands(t, nrf51_mdm_cmd_list, t->driver); +} + +#define MDM_POWER_EN ADIV5_DP_REG(0x01) +#define MDM_SELECT_AP ADIV5_DP_REG(0x02) +#define MDM_STATUS ADIV5_AP_REG(0x08) +#define MDM_CONTROL ADIV5_AP_REG(0x04) +#define MDM_PROT_EN ADIV5_AP_REG(0x0C) + + +static bool nrf51_mdm_cmd_erase_mass(target *t) +{ + ADIv5_AP_t *ap = t->priv; + + uint32_t status = adiv5_ap_read(ap, MDM_STATUS); + + adiv5_dp_write(ap->dp, MDM_POWER_EN, 0x50000000); + + adiv5_dp_write(ap->dp, MDM_SELECT_AP, 0x01000000); + + adiv5_ap_write(ap, MDM_CONTROL, 0x00000001); + + // Read until 0, probably should have a timeout here... + do { + status = adiv5_ap_read(ap, MDM_STATUS); + } while (status); + + // The second read will provide true prot status + status = adiv5_ap_read(ap, MDM_PROT_EN); + status = adiv5_ap_read(ap, MDM_PROT_EN); + + // should we return the prot status here? + return true; +} From f39701c4c8977dfcaa1548573fa8aae7777d2891 Mon Sep 17 00:00:00 2001 From: Rik van der Heijden Date: Wed, 5 Sep 2018 17:40:02 +0200 Subject: [PATCH 6/6] Move the LPC17xx probe function down since it performs an IAP call which can hang when performed on other devices than a LPC17xx --- src/target/cortexm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/cortexm.c b/src/target/cortexm.c index 4f6de808..8de881cd 100644 --- a/src/target/cortexm.c +++ b/src/target/cortexm.c @@ -335,7 +335,6 @@ bool cortexm_probe(ADIv5_AP_t *ap) PROBE(stm32l4_probe); PROBE(lpc11xx_probe); PROBE(lpc15xx_probe); - PROBE(lpc17xx_probe); PROBE(lpc43xx_probe); PROBE(sam3x_probe); PROBE(sam4l_probe); @@ -345,6 +344,7 @@ bool cortexm_probe(ADIv5_AP_t *ap) PROBE(kinetis_probe); PROBE(efm32_probe); PROBE(msp432_probe); + PROBE(lpc17xx_probe); #undef PROBE return true;