mdebug

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 449406f1147fbe37b1b2f109d4b9e63f9ea84101
parent bbc9bd4d6fd8eb07a946a12cd7233d11ca155101
Author: Brian Swetland <swetland@frotz.net>
Date:   Wed, 13 Apr 2022 22:49:03 -0700

agent: efr32bg2x: initial commit

- initial support for flash/erase on silabs efr32bg2x family

Diffstat:
MMakefile | 1+
Aagents/efr32bg2x.c | 167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtools/debugger-commands.c | 49++++++++++++++++++++++++++++++++++++++++++++++---
Mtools/rswdp.c | 13++++++++++---
4 files changed, 224 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile @@ -46,6 +46,7 @@ $(call agent, lpc13xx, 0x10000400, M3) $(call agent, lpc15xx, 0x02000400, M3) $(call agent, cc13xx, 0x20000400, M3) $(call agent, nrf528xx, 0x20000400, M3) +$(call agent, efr32bg2x, 0x20000400, M3) $(call agent, pico, 0x20000400, M0) $(call program,picoboot,tools/picoboot.c) diff --git a/agents/efr32bg2x.c b/agents/efr32bg2x.c @@ -0,0 +1,167 @@ +// agents/efr32bg2x.c +// +// Copyright 2022 Brian Swetland <swetland@frotz.net> +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#define LOADADDR 0x20000400 + +#define FLASH_BASE 0x00000000 + +#include <agent/flash.h> +#include <fw/io.h> + +#define CMU_CLKEN1_SET 0x40009068 +#define CMU_CLKEN1_MSC (1U<<17) + +#define MSC_WRITECTRL 0x4003000C +#define MSC_WRITECTRL_SET 0x4003100C +#define MSC_WRITECTRL_CLR 0x4003200C +#define MSC_WRITECMD 0x40030010 +#define MSC_WRITECMD_SET 0x40031010 +#define MSC_WRITECMD_CLR 0x40032010 +#define MSC_ADDRB 0x40030014 +#define MSC_WDATA 0x40030018 +#define MSC_STATUS 0x4003001C + +#define MSC_WRITECTRL_WREN 1 + +#define MSC_WRITECMD_WRITEND (1U<<2) +#define MSC_WRITECMD_ERASEPAGE (1U<<1) + +#define MSC_STATUS_WREADY (1U<<27) +#define MSC_STATUS_PWRON (1U<<24) +#define MSC_STATUS_REGLOCK (1U<<16) +#define MSC_STATUS_TIMEOUT (1U<<6) +#define MSC_STATUS_PENDING (1U<<5) +#define MSC_STATUS_ERASEABORTYED (1U<<4) +#define MSC_STATUS_WDATAREADY (1U<<3) +#define MSC_STATUS_INVADDR (1U<<2) +#define MSC_STATUS_LOCKED (1U<<1) +#define MSC_STATUS_BUSY (1U<<0) + +static unsigned FLASH_PAGE_SIZE = 8192; +static unsigned FLASH_SIZE = 352 * 1024; + +int flash_agent_setup(flash_agent *agent) { + // TODO - validate part ID + if (0) { + // unknown part + return ERR_INVALID; + } + + // TODO: read from userdata + agent->flash_size = FLASH_SIZE; + + return ERR_NONE; +} + +int flash_agent_erase(u32 flash_addr, u32 length) { + unsigned v; + int status = ERR_NONE; + if (flash_addr > FLASH_SIZE) { + return ERR_INVALID; + } + if (flash_addr & (FLASH_PAGE_SIZE - 1)) { + return ERR_ALIGNMENT; + } + + writel(CMU_CLKEN1_MSC, CMU_CLKEN1_SET); + writel(MSC_WRITECTRL_WREN, MSC_WRITECTRL_SET); + while (length > 0) { + writel(flash_addr, MSC_ADDRB); + v = readl(MSC_STATUS); + if (v & (MSC_STATUS_INVADDR | MSC_STATUS_LOCKED)) { + status = ERR_INVALID; + break; + } + if (!(v & MSC_STATUS_WREADY)) { + status = ERR_FAIL; + break; + } + if (length > FLASH_PAGE_SIZE) { + length -= FLASH_PAGE_SIZE; + } else { + length = 0; + } + writel(MSC_WRITECMD_ERASEPAGE, MSC_WRITECMD_SET); + while (readl(MSC_STATUS) & MSC_STATUS_BUSY) ; + for (unsigned n = 0; n < FLASH_PAGE_SIZE; n += 4) { + if (readl(flash_addr + n) != 0xFFFFFFFF) { + status = ERR_FAIL; + goto done; + } + } + flash_addr += FLASH_PAGE_SIZE; + } +done: + writel(MSC_WRITECTRL_WREN, MSC_WRITECTRL_CLR); + return status; +} + +int flash_agent_write(u32 flash_addr, const void *_data, u32 length) { + int status = ERR_NONE; + const unsigned *data = _data; + unsigned v; + if (flash_addr > FLASH_SIZE) { + return ERR_INVALID; + } + if ((flash_addr & 3) || (length & 3)) { + return ERR_ALIGNMENT; + } + writel(CMU_CLKEN1_MSC, CMU_CLKEN1_SET); + writel(MSC_WRITECTRL_WREN, MSC_WRITECTRL_SET); + while (length > 0) { + writel(flash_addr, MSC_ADDRB); + v = readl(MSC_STATUS); + if (v & (MSC_STATUS_INVADDR | MSC_STATUS_LOCKED)) { + status = ERR_INVALID; + break; + } + if (!(v & MSC_STATUS_WREADY)) { + status = ERR_FAIL; + break; + } + writel(*data, MSC_WDATA); + while (readl(MSC_STATUS) & MSC_STATUS_BUSY) ; + if (readl(flash_addr) != *data) { + status = ERR_FAIL; + goto done; + } + data++; + length -= 4; + flash_addr += 4; + } +done: + writel(MSC_WRITECTRL_WREN, MSC_WRITECTRL_CLR); + return status; +} + +int flash_agent_ioctl(u32 op, void *ptr, u32 arg0, u32 arg1) { + return ERR_INVALID; +} + +const flash_agent __attribute((section(".vectors"))) FlashAgent = { + .magic = AGENT_MAGIC, + .version = AGENT_VERSION, + .flags = 0, + .load_addr = LOADADDR, + .data_addr = LOADADDR + 0x400, + .data_size = 0x4000, + .flash_addr = FLASH_BASE, + .flash_size = 0, + .setup = flash_agent_setup, + .erase = flash_agent_erase, + .write = flash_agent_write, + .ioctl = flash_agent_ioctl, +}; diff --git a/tools/debugger-commands.c b/tools/debugger-commands.c @@ -387,15 +387,58 @@ int do_reset_hw(int argc, param *argv) { return 0; } +extern int swd_verbose; + +int wait_for_stop() { + u32 x; + unsigned m = 0; + unsigned xr = -1; + for (unsigned n = 0; n < 100; n++) { + if (swdp_ahb_read(DHCSR, &x) == 0) { + if (x & DHCSR_S_HALT) { + xprintf(XSWD,"CPU HALTED (%u,%u)\n", n,m); + unsigned y = -1, z = -1; + swdp_ahb_read(DFSR, &y); + swdp_ahb_read(DEMCR, &z); + xprintf(XSWD,"DHCSR %08x (%08x)\nDFSR %08x\nDEMCR %08x\n", x, xr, y, z); + return 0; + } + if (x & DHCSR_S_RESET_ST) { + xr = x; + m++; + continue; + } + //xprintf(XSWD,"??? %08x\n", x); + swdp_ahb_write(DHCSR, DHCSR_DBGKEY | DHCSR_C_HALT | DHCSR_C_DEBUGEN); + } else { + swdp_reset(); + } + } + xprintf(XSWD,"CPU DID NOT HALT\n"); + return -1; +} + int do_reset_stop(int argc, param *argv) { swdp_core_halt(); + wait_for_stop(); + // enable vector-trap on reset, enable DWT/FPB swdp_ahb_write(DEMCR, DEMCR_VC_CORERESET | DEMCR_TRCENA | vcflags); + + swdp_ahb_write(0xe00ee08, 0x00010002); // core reset and sys reset - swdp_ahb_write(0xe000ed0c, 0x05fa0005); + //swdp_ahb_write(0xe000ed0c, 0x05fa0005); + // sys reset + // TRM says requesting both at once is unpredictable... + swdp_ahb_write(0xe000ed0c, 0x05fa0004); + + swd_verbose = 0; + wait_for_stop(); + swd_verbose = 1; + //swdp_core_wait_for_halt(); - do_stop(0,0); - swdp_ahb_write(DEMCR, DEMCR_TRCENA | vcflags); + //do_stop(0,0); + //swdp_ahb_write(DEMCR, DEMCR_TRCENA | vcflags); return 0; } diff --git a/tools/rswdp.c b/tools/rswdp.c @@ -482,6 +482,7 @@ static void q_ap_read(struct txn *t, u32 addr, u32 *value) { } static void q_ahb_write(struct txn *t, u32 addr, u32 value) { +// xprintf(XSWD, "WR %08x -> %08x\n", value, addr); if (t->cache_ahbtar != addr) { q_ap_write(t, AHB_TAR, addr); t->cache_ahbtar = addr; @@ -846,9 +847,13 @@ static int _swdp_reset(void) { t.tx[t.txc++] = SWD_RD(DP_IDCODE, 1); t.rx[t.rxc++] = &idcode; if (q_exec(&t)) { - xprintf(XSWD, "attach: IDCODE: ????????\n"); + if (swd_verbose) { + xprintf(XSWD, "attach: IDCODE: ????????\n"); + } } else { - xprintf(XSWD, "attach: IDCODE: %08x\n", idcode); + if (swd_verbose) { + xprintf(XSWD, "attach: IDCODE: %08x\n", idcode); + } } swd_error = 0; @@ -883,7 +888,9 @@ static int _swdp_reset(void) { if (q_exec(&t)) return -1; - xprintf(XSWD, "attach: DPCTRL: %08x\n", n); + if (swd_verbose) { + xprintf(XSWD, "attach: DPCTRL: %08x\n", n); + } //xprintf(XSWD, "attach: BASE: %08x\n", base); return 0; }