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