diff --git a/flashstub/efm32.c b/flashstub/efm32.c
new file mode 100644
index 0000000..26f19a3
--- /dev/null
+++ b/flashstub/efm32.c
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the Black Magic Debug project.
+ *
+ * Copyright (C) 2015 Richard Meadows
+ *
+ * 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 .
+ */
+#include
+#include "stub.h"
+
+#define EFM32_MSC ((volatile uint32_t *)0x400c0000)
+#define EFM32_MSC_WRITECTRL EFM32_MSC[2]
+#define EFM32_MSC_WRITECMD EFM32_MSC[3]
+#define EFM32_MSC_ADDRB EFM32_MSC[4]
+#define EFM32_MSC_WDATA EFM32_MSC[6]
+#define EFM32_MSC_STATUS EFM32_MSC[7]
+#define EFM32_MSC_LOCK EFM32_MSC[15]
+
+#define EFM32_MSC_LOCK_LOCKKEY 0x1b71
+
+#define EFM32_MSC_WRITECMD_LADDRIM (1<<0)
+#define EFM32_MSC_WRITECMD_ERASEPAGE (1<<1)
+#define EFM32_MSC_WRITECMD_WRITEEND (1<<2)
+#define EFM32_MSC_WRITECMD_WRITEONCE (1<<3)
+#define EFM32_MSC_WRITECMD_WRITETRIG (1<<4)
+#define EFM32_MSC_WRITECMD_ERASEABORT (1<<5)
+
+#define EFM32_MSC_STATUS_BUSY (1<<0)
+#define EFM32_MSC_STATUS_LOCKED (1<<1)
+#define EFM32_MSC_STATUS_INVADDR (1<<2)
+#define EFM32_MSC_STATUS_WDATAREADY (1<<3)
+#define EFM32_MSC_STATUS_WORDTIMEOUT (1<<4)
+
+void __attribute__((naked))
+efm32_flash_write_stub(uint32_t *dest, uint32_t *src, uint32_t size)
+{
+ uint32_t i;
+
+ EFM32_MSC_LOCK = EFM32_MSC_LOCK_LOCKKEY;
+ EFM32_MSC_WRITECTRL = 1;
+
+ for (i = 0; i < size/4; i++) {
+ EFM32_MSC_ADDRB = (uint32_t)&dest[i];;
+ EFM32_MSC_WRITECMD = EFM32_MSC_WRITECMD_LADDRIM;
+
+ /* Wait for WDATAREADY */
+ while ((EFM32_MSC_STATUS & EFM32_MSC_STATUS_WDATAREADY) == 0);
+
+ EFM32_MSC_WDATA = src[i];
+ EFM32_MSC_WRITECMD = EFM32_MSC_WRITECMD_WRITEONCE;
+
+ /* Wait for BUSY */
+ while ((EFM32_MSC_STATUS & EFM32_MSC_STATUS_BUSY));
+ }
+
+ stub_exit(0);
+}
diff --git a/flashstub/efm32.stub b/flashstub/efm32.stub
new file mode 100644
index 0000000..01fe5db
--- /dev/null
+++ b/flashstub/efm32.stub
@@ -0,0 +1,41 @@
+ [0x0/2] = 0x4c10,
+ [0x2/2] = 0x4b11,
+ [0x4/2] = 0x0892,
+ [0x6/2] = 0x601c,
+ [0x8/2] = 0x2401,
+ [0xa/2] = 0x4b10,
+ [0xc/2] = 0x0092,
+ [0xe/2] = 0x601c,
+ [0x10/2] = 0x2400,
+ [0x12/2] = 0x4294,
+ [0x14/2] = 0xd015,
+ [0x16/2] = 0x4d0e,
+ [0x18/2] = 0x1903,
+ [0x1a/2] = 0x602b,
+ [0x1c/2] = 0x2501,
+ [0x1e/2] = 0x4b0d,
+ [0x20/2] = 0x601d,
+ [0x22/2] = 0x2608,
+ [0x24/2] = 0x4d0c,
+ [0x26/2] = 0x682f,
+ [0x28/2] = 0x46ac,
+ [0x2a/2] = 0x4237,
+ [0x2c/2] = 0xd0f9,
+ [0x2e/2] = 0x590d,
+ [0x30/2] = 0x4f0a,
+ [0x32/2] = 0x603d,
+ [0x34/2] = 0x601e,
+ [0x36/2] = 0x4663,
+ [0x38/2] = 0x681b,
+ [0x3a/2] = 0x07db,
+ [0x3c/2] = 0xd4fb,
+ [0x3e/2] = 0x3404,
+ [0x40/2] = 0xe7e7,
+ [0x42/2] = 0xbe00,
+ [0x44/2] = 0x1b71, 0x0000,
+ [0x48/2] = 0x003c, 0x400c,
+ [0x4c/2] = 0x0008, 0x400c,
+ [0x50/2] = 0x0010, 0x400c,
+ [0x54/2] = 0x000c, 0x400c,
+ [0x58/2] = 0x001c, 0x400c,
+ [0x5c/2] = 0x0018, 0x400c,
diff --git a/src/Makefile b/src/Makefile
index 1ef3486..b39326c 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -20,6 +20,7 @@ SRC = \
command.c \
cortexm.c \
crc32.c \
+ efm32.c \
exception.c \
gdb_if.c \
gdb_main.c \
@@ -91,4 +92,3 @@ include/version.h: FORCE
$(Q)echo "#define FIRMWARE_VERSION \"`git describe --dirty`\"" > $@
-include *.d
-
diff --git a/src/cortexm.c b/src/cortexm.c
index d459cce..93cf2e8 100644
--- a/src/cortexm.c
+++ b/src/cortexm.c
@@ -251,6 +251,7 @@ bool cortexm_probe(target *t)
PROBE(samd_probe);
PROBE(lmi_probe);
PROBE(kinetis_probe);
+ PROBE(efm32_probe);
#undef PROBE
return true;
@@ -974,4 +975,3 @@ static void cortexm_hostio_reply(target *t, int32_t retcode, uint32_t errcode)
target_regs_write(t, arm_regs);
priv->errno = errcode;
}
-
diff --git a/src/efm32.c b/src/efm32.c
new file mode 100644
index 0000000..ea5cd64
--- /dev/null
+++ b/src/efm32.c
@@ -0,0 +1,426 @@
+/*
+ * This file is part of the Black Magic Debug project.
+ *
+ * Copyright (C) 2015 Richard Meadows
+ *
+ * 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 EFM32 target specific functions for
+ * detecting the device, providing the XML memory map and Flash memory
+ * programming.
+ *
+ * Both EFM32 (microcontroller only) and EZR32 (microcontroller+radio)
+ * devices should be supported through this driver.
+ *
+ * Tested with:
+ * * EZR32LG230 (EZR Leopard Gecko M3)
+ * *
+ */
+
+/* Refer to the family reference manuals:
+ *
+ *
+ * Also refer to AN0062 "Programming Internal Flash Over the Serial Wire Debug Interface"
+ * http://www.silabs.com/Support%20Documents/TechnicalDocs/an0062.pdf
+ */
+
+#include "general.h"
+#include "jtagtap.h"
+#include "adiv5.h"
+#include "target.h"
+#include "command.h"
+#include "gdb_packet.h"
+#include "cortexm.h"
+
+#define SRAM_BASE 0x20000000
+#define STUB_BUFFER_BASE ALIGN(SRAM_BASE + sizeof(efm32_flash_write_stub), 4)
+
+static int efm32_flash_erase(struct target_flash *t, uint32_t addr, size_t len);
+static int efm32_flash_write(struct target_flash *f,
+ uint32_t dest, const void *src, size_t len);
+
+static const uint16_t efm32_flash_write_stub[] = {
+#include "../flashstub/efm32.stub"
+};
+
+static bool efm32_cmd_erase_all(target *t);
+static bool efm32_cmd_serial(target *t);
+
+const struct command_s efm32_cmd_list[] = {
+ {"erase_mass", (cmd_handler)efm32_cmd_erase_all, "Erase entire flash memory"},
+ {"serial", (cmd_handler)efm32_cmd_serial, "Prints unique number"},
+ {NULL, NULL, NULL}
+};
+
+
+
+/* -------------------------------------------------------------------------- */
+/* Memory System Controller (MSC) Registers */
+/* -------------------------------------------------------------------------- */
+
+#define EFM32_MSC 0x400c0000
+#define EFM32_MSC_WRITECTRL (EFM32_MSC+0x008)
+#define EFM32_MSC_WRITECMD (EFM32_MSC+0x00c)
+#define EFM32_MSC_ADDRB (EFM32_MSC+0x010)
+#define EFM32_MSC_WDATA (EFM32_MSC+0x018)
+#define EFM32_MSC_STATUS (EFM32_MSC+0x01c)
+#define EFM32_MSC_LOCK (EFM32_MSC+0x03c)
+#define EFM32_MSC_CMD (EFM32_MSC+0x040)
+#define EFM32_MSC_TIMEBASE (EFM32_MSC+0x050)
+#define EFM32_MSC_MASSLOCK (EFM32_MSC+0x054)
+
+#define EFM32_MSC_LOCK_LOCKKEY 0x1b71
+#define EFM32_MSC_MASSLOCK_LOCKKEY 0x631a
+
+#define EFM32_MSC_WRITECMD_LADDRIM (1<<0)
+#define EFM32_MSC_WRITECMD_ERASEPAGE (1<<1)
+#define EFM32_MSC_WRITECMD_WRITEEND (1<<2)
+#define EFM32_MSC_WRITECMD_WRITEONCE (1<<3)
+#define EFM32_MSC_WRITECMD_WRITETRIG (1<<4)
+#define EFM32_MSC_WRITECMD_ERASEABORT (1<<5)
+#define EFM32_MSC_WRITECMD_ERASEMAIN0 (1<<8)
+
+#define EFM32_MSC_STATUS_BUSY (1<<0)
+#define EFM32_MSC_STATUS_LOCKED (1<<1)
+#define EFM32_MSC_STATUS_INVADDR (1<<2)
+#define EFM32_MSC_STATUS_WDATAREADY (1<<3)
+
+
+/* -------------------------------------------------------------------------- */
+/* Flash Infomation Area */
+/* -------------------------------------------------------------------------- */
+
+#define EFM32_INFO 0x0fe00000
+#define EFM32_USER_DATA (EFM32_INFO+0x0000)
+#define EFM32_LOCK_BITS (EFM32_INFO+0x4000)
+#define EFM32_DI (EFM32_INFO+0x8000)
+
+
+/* -------------------------------------------------------------------------- */
+/* Device Information (DI) Area */
+/* -------------------------------------------------------------------------- */
+
+#define EFM32_DI_CMU_LFRCOCTRL (EFM32_DI+0x020)
+#define EFM32_DI_CMU_HFRCOCTRL (EFM32_DI+0x028)
+#define EFM32_DI_CMU_AUXHFRCOCTRL (EFM32_DI+0x030)
+#define EFM32_DI_ADC0_CAL (EFM32_DI+0x040)
+#define EFM32_DI_ADC0_BIASPROG (EFM32_DI+0x048)
+#define EFM32_DI_DAC0_CAL (EFM32_DI+0x050)
+#define EFM32_DI_DAC0_BIASPROG (EFM32_DI+0x058)
+#define EFM32_DI_ACMP0_CTRL (EFM32_DI+0x060)
+#define EFM32_DI_ACMP1_CTRL (EFM32_DI+0x068)
+#define EFM32_DI_CMU_LCDCTRL (EFM32_DI+0x078)
+#define EFM32_DI_DAC0_OPACTRL (EFM32_DI+0x0A0)
+#define EFM32_DI_DAC0_OPAOFFSET (EFM32_DI+0x0A8)
+#define EFM32_DI_EMU_BUINACT (EFM32_DI+0x0B0)
+#define EFM32_DI_EMU_BUACT (EFM32_DI+0x0B8)
+#define EFM32_DI_EMU_BUBODBUVINCAL (EFM32_DI+0x0C0)
+#define EFM32_DI_EMU_BUBODUNREGCAL (EFM32_DI+0x0C8)
+#define EFM32_DI_MCM_REV_MIN (EFM32_DI+0x1AA)
+#define EFM32_DI_MCM_REV_MAJ (EFM32_DI+0x1AB)
+#define EFM32_DI_RADIO_REV_MIN (EFM32_DI+0x1AC)
+#define EFM32_DI_RADIO_REV_MAJ (EFM32_DI+0x1AD)
+#define EFM32_DI_RADIO_OPN (EFM32_DI+0x1AE)
+#define EFM32_DI_DI_CRC (EFM32_DI+0x1B0)
+#define EFM32_DI_CAL_TEMP_0 (EFM32_DI+0x1B2)
+#define EFM32_DI_ADC0_CAL_1V25 (EFM32_DI+0x1B4)
+#define EFM32_DI_ADC0_CAL_2V5 (EFM32_DI+0x1B6)
+#define EFM32_DI_ADC0_CAL_VDD (EFM32_DI+0x1B8)
+#define EFM32_DI_ADC0_CAL_5VDIFF (EFM32_DI+0x1BA)
+#define EFM32_DI_ADC0_CAL_2XVDD (EFM32_DI+0x1BC)
+#define EFM32_DI_ADC0_TEMP_0_READ_1V25 (EFM32_DI+0x1BE)
+#define EFM32_DI_DAC0_CAL_1V25 (EFM32_DI+0x1C8)
+#define EFM32_DI_DAC0_CAL_2V5 (EFM32_DI+0x1CC)
+#define EFM32_DI_DAC0_CAL_VDD (EFM32_DI+0x1D0)
+#define EFM32_DI_AUXHFRCO_CALIB_BAND_1 (EFM32_DI+0x1D4)
+#define EFM32_DI_AUXHFRCO_CALIB_BAND_7 (EFM32_DI+0x1D5)
+#define EFM32_DI_AUXHFRCO_CALIB_BAND_11 (EFM32_DI+0x1D6)
+#define EFM32_DI_AUXHFRCO_CALIB_BAND_14 (EFM32_DI+0x1D7)
+#define EFM32_DI_AUXHFRCO_CALIB_BAND_21 (EFM32_DI+0x1D8)
+#define EFM32_DI_AUXHFRCO_CALIB_BAND_28 (EFM32_DI+0x1D9)
+#define EFM32_DI_HFRCO_CALIB_BAND_1 (EFM32_DI+0x1DC)
+#define EFM32_DI_HFRCO_CALIB_BAND_7 (EFM32_DI+0x1DD)
+#define EFM32_DI_HFRCO_CALIB_BAND_11 (EFM32_DI+0x1DE)
+#define EFM32_DI_HFRCO_CALIB_BAND_14 (EFM32_DI+0x1DF)
+#define EFM32_DI_HFRCO_CALIB_BAND_21 (EFM32_DI+0x1E0)
+#define EFM32_DI_HFRCO_CALIB_BAND_28 (EFM32_DI+0x1E1)
+#define EFM32_DI_MEM_INFO_PAGE_SIZE (EFM32_DI+0x1E7)
+#define EFM32_DI_RADIO_ID (EFM32_DI+0x1EE)
+#define EFM32_DI_EUI64_0 (EFM32_DI+0x1F0)
+#define EFM32_DI_EUI64_1 (EFM32_DI+0x1F4)
+#define EFM32_DI_MEM_INFO_FLASH (EFM32_DI+0x1F8)
+#define EFM32_DI_MEM_INFO_RAM (EFM32_DI+0x1FA)
+#define EFM32_DI_PART_NUMBER (EFM32_DI+0x1FC)
+#define EFM32_DI_PART_FAMILY (EFM32_DI+0x1FE)
+#define EFM32_DI_PROD_REV (EFM32_DI+0x1FF)
+
+/* top 24 bits of eui */
+#define EFM32_DI_EUI_SILABS 0x000b57
+
+#define EFM32_DI_PART_FAMILY_GECKO 71
+#define EFM32_DI_PART_FAMILY_GIANT_GECKO 72
+#define EFM32_DI_PART_FAMILY_TINY_GECKO 73
+#define EFM32_DI_PART_FAMILY_LEOPARD_GECKO 74
+#define EFM32_DI_PART_FAMILY_WONDER_GECKO 75
+#define EFM32_DI_PART_FAMILY_ZERO_GECKO 76
+#define EFM32_DI_PART_FAMILY_EZR_WONDER_GECKO 120
+#define EFM32_DI_PART_FAMILY_EZR_LEOPARD_GECKO 121
+
+/* -------------------------------------------------------------------------- */
+/* Helper functions */
+/* -------------------------------------------------------------------------- */
+
+/**
+ * Reads the EFM32 Extended Unique Identifier
+ */
+uint64_t efm32_read_eui(target *t)
+{
+ uint64_t eui;
+
+ eui = (uint64_t)target_mem_read32(t, EFM32_DI_EUI64_1) << 32;
+ eui |= (uint64_t)target_mem_read32(t, EFM32_DI_EUI64_0) << 0;
+
+ return eui;
+}
+/**
+ * Reads the EFM32 flash size in kiB
+ */
+uint16_t efm32_read_flash_size(target *t)
+{
+ return target_mem_read16(t, EFM32_DI_MEM_INFO_FLASH);
+}
+/**
+ * Reads the EFM32 RAM size in kiB
+ */
+uint16_t efm32_read_ram_size(target *t)
+{
+ return target_mem_read16(t, EFM32_DI_MEM_INFO_RAM);
+}
+/**
+ * Reads the EFM32 Part Number
+ */
+uint16_t efm32_read_part_number(target *t)
+{
+ return target_mem_read16(t, EFM32_DI_PART_NUMBER);
+}
+/**
+ * Reads the EFM32 Part Family
+ */
+uint8_t efm32_read_part_family(target *t)
+{
+ return target_mem_read8(t, EFM32_DI_PART_FAMILY);
+}
+/**
+ * Reads the EFM32 Radio part number (EZR parts only)
+ */
+uint16_t efm32_read_radio_part_number(target *t)
+{
+ return target_mem_read16(t, EFM32_DI_RADIO_OPN);
+}
+
+
+
+
+static void efm32_add_flash(target *t, uint32_t addr, size_t length,
+ size_t page_size)
+{
+ struct target_flash *f = calloc(1, sizeof(*f));
+ f->start = addr;
+ f->length = length;
+ f->blocksize = page_size;
+ f->erase = efm32_flash_erase;
+ f->write = target_flash_write_buffered;
+ f->done = target_flash_done_buffered;
+ f->write_buf = efm32_flash_write;
+ f->buf_size = page_size;
+ target_add_flash(t, f);
+}
+
+char variant_string[40];
+bool efm32_probe(target *t)
+{
+ /* Read the extended unique identifier */
+ uint64_t eui = efm32_read_eui(t);
+
+ /* /\* Check top 24 bits of eui are silabs *\/ */
+ if (((eui >> 40) & 0xFFFFFF) != EFM32_DI_EUI_SILABS)
+ return false;
+
+ /* Read the part number and family */
+ uint16_t part_number = efm32_read_part_number(t);
+ uint8_t part_family = efm32_read_part_family(t);
+ uint16_t radio_number; /* optional, for ezr parts */
+ uint32_t flash_page_size;
+
+ switch(part_family) {
+ case EFM32_DI_PART_FAMILY_GECKO:
+ sprintf(variant_string,
+ "EFM32 Gecko");
+ flash_page_size = 512;
+ break;
+ case EFM32_DI_PART_FAMILY_GIANT_GECKO:
+ sprintf(variant_string,
+ "EFM32 Giant Gecko");
+ flash_page_size = 2048; /* Could be 2048 or 4096, assume 2048 */
+ break;
+ case EFM32_DI_PART_FAMILY_TINY_GECKO:
+ sprintf(variant_string,
+ "EFM32 Tiny Gecko");
+ flash_page_size = 512;
+ break;
+ case EFM32_DI_PART_FAMILY_LEOPARD_GECKO:
+ sprintf(variant_string,
+ "EFM32 Leopard Gecko");
+ flash_page_size = 2048; /* Could be 2048 or 4096, assume 2048 */
+ break;
+ case EFM32_DI_PART_FAMILY_WONDER_GECKO:
+ sprintf(variant_string,
+ "EFM32 Wonder Gecko");
+ flash_page_size = 2048;
+ break;
+ case EFM32_DI_PART_FAMILY_ZERO_GECKO:
+ sprintf(variant_string,
+ "EFM32 Zero Gecko");
+ flash_page_size = 1024;
+ break;
+ case EFM32_DI_PART_FAMILY_EZR_WONDER_GECKO:
+ radio_number = efm32_read_radio_part_number(t); /* on-chip radio */
+
+ sprintf(variant_string,
+ "EZR32WG%d (radio si%d)",
+ part_number, radio_number);
+
+ flash_page_size = 2048;
+ break;
+ case EFM32_DI_PART_FAMILY_EZR_LEOPARD_GECKO:
+ radio_number = efm32_read_radio_part_number(t); /* on-chip radio */
+
+ sprintf(variant_string,
+ "EZR32LG%d (radio si%d)",
+ part_number, radio_number);
+
+ flash_page_size = 2048;
+ break;
+ default: /* Unknown family */
+ return false;
+ }
+
+ /* Read memory sizes, convert to bytes */
+ uint32_t flash_size = efm32_read_flash_size(t) * 0x400;
+ uint32_t ram_size = efm32_read_ram_size(t) * 0x400;
+
+ /* Setup Target */
+ t->driver = variant_string;
+ gdb_outf("flash size %d page size %d\n", flash_size, flash_page_size);
+ target_add_ram (t, SRAM_BASE, ram_size);
+ efm32_add_flash(t, 0x00000000, flash_size, flash_page_size);
+ target_add_commands(t, efm32_cmd_list, "EFM32");
+
+ return true;
+}
+
+/**
+ * Erase flash row by row
+ */
+static int efm32_flash_erase(struct target_flash *f, uint32_t addr, size_t len)
+{
+ target *t = f->t;
+
+ /* Set WREN bit to enabel MSC write and erase functionality */
+ target_mem_write32(t, EFM32_MSC_WRITECTRL, 1);
+
+ while (len) {
+ /* Write address of first word in row to erase it */
+ target_mem_write32(t, EFM32_MSC_ADDRB, addr);
+ target_mem_write32(t, EFM32_MSC_WRITECMD, EFM32_MSC_WRITECMD_LADDRIM);
+
+ /* Issue the erase command */
+ target_mem_write32(t, EFM32_MSC_WRITECMD, EFM32_MSC_WRITECMD_ERASEPAGE );
+
+ /* Poll MSC Busy */
+ while ((target_mem_read32(t, EFM32_MSC_STATUS) & EFM32_MSC_STATUS_BUSY)) {
+ if (target_check_error(t))
+ return -1;
+ }
+
+ addr += f->blocksize;
+ len -= f->blocksize;
+ }
+
+ return 0;
+}
+
+/**
+ * Write flash page by page
+ */
+static int efm32_flash_write(struct target_flash *f,
+ uint32_t dest, const void *src, size_t len)
+{
+ (void)len;
+ target *t = f->t;
+
+ /* Write flashloader */
+ target_mem_write(t, SRAM_BASE, efm32_flash_write_stub,
+ sizeof(efm32_flash_write_stub));
+ /* Write Buffer */
+ target_mem_write(t, STUB_BUFFER_BASE, src, len);
+ /* Run flashloader */
+ return cortexm_run_stub(t, SRAM_BASE, dest, STUB_BUFFER_BASE, len, 0);
+
+ return 0;
+}
+
+/**
+ * Uses the MSC ERASEMAIN0 command to erase the entire flash
+ */
+static bool efm32_cmd_erase_all(target *t)
+{
+ /* Set WREN bit to enabel MSC write and erase functionality */
+ target_mem_write32(t, EFM32_MSC_WRITECTRL, 1);
+
+
+ /* Unlock mass erase */
+ target_mem_write32(t, EFM32_MSC_MASSLOCK, EFM32_MSC_MASSLOCK_LOCKKEY);
+
+ /* Erase operation */
+ target_mem_write32(t, EFM32_MSC_WRITECMD, EFM32_MSC_WRITECMD_ERASEMAIN0);
+
+ /* Poll MSC Busy */
+ while ((target_mem_read32(t, EFM32_MSC_STATUS) & EFM32_MSC_STATUS_BUSY)) {
+ if (target_check_error(t))
+ return false;
+ }
+
+ /* Relock mass erase */
+ target_mem_write32(t, EFM32_MSC_MASSLOCK, 0);
+
+ gdb_outf("Erase successful!\n");
+
+ return true;
+}
+
+/**
+ * Reads the 40-bit unique number
+ */
+static bool efm32_cmd_serial(target *t)
+{
+ /* Read the extended unique identifier */
+ uint64_t eui = efm32_read_eui(t) & 0xFFFFFFFFFF;
+
+ /* Bottom 40 bits are unique number */
+ gdb_outf("Unique Number: 0x%010llx\n", eui);
+
+ return true;
+}
diff --git a/src/include/target.h b/src/include/target.h
index bff556d..dcc83dd 100644
--- a/src/include/target.h
+++ b/src/include/target.h
@@ -271,6 +271,6 @@ bool sam3x_probe(target *t);
bool nrf51_probe(target *t);
bool samd_probe(target *t);
bool kinetis_probe(target *t);
+bool efm32_probe(target *t);
#endif
-