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:
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;
}