Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added bmputil-cli
Binary file not shown.
159 changes: 139 additions & 20 deletions src/target/efm32.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
#include "target_internal.h"
#include "cortexm.h"
#include "adiv5.h"
#include "gdb_packet.h"
#include "exception.h"

#define SRAM_BASE 0x20000000U
#define STUB_BUFFER_BASE ALIGN(SRAM_BASE + sizeof(efm32_flash_write_stub), 4U)
Expand Down Expand Up @@ -69,17 +71,17 @@ const command_s efm32_cmd_list[] = {
/* Memory System Controller (MSC) Registers */
/* -------------------------------------------------------------------------- */

#define EFM32_MSC_WRITECTRL(msc) (msc + 0x008U)
#define EFM32_MSC_WRITECMD(msc) (msc + 0x00cU)
#define EFM32_MSC_ADDRB(msc) (msc + 0x010U)
#define EFM32_MSC_WDATA(msc) (msc + 0x018U)
#define EFM32_MSC_STATUS(msc) (msc + 0x01cU)
#define EFM32_MSC_IF(msc) (msc + 0x030U)
#define EFM32_MSC_LOCK(msc) (msc + (msc == 0x400c0000U ? 0x3cU : 0x40U))
#define EFM32_MSC_MASSLOCK(msc) (msc + 0x054U)
#define EFM32_MSC_WRITECTRL(msc) (msc + 0x00CU) //(msc + 0x008U)
#define EFM32_MSC_WRITECMD(msc) (msc + 0x010U)
#define EFM32_MSC_ADDRB(msc) (msc + 0x014U)
#define EFM32_MSC_WDATA(msc) (msc + 0x018U)
#define EFM32_MSC_STATUS(msc) (msc + 0x01CU)
#define EFM32_MSC_IF(msc) (msc + 0x020U)
#define EFM32_MSC_LOCK(msc) (msc + 0x03CU)
#define EFM32_MSC_MASSLOCK(msc) (msc + 0x040U)

#define EFM32_MSC_LOCK_LOCKKEY 0x1b71U
#define EFM32_MSC_MASSLOCK_LOCKKEY 0x631aU
#define EFM32_MSC_LOCK_LOCKKEY 0x7025U
#define EFM32_MSC_MASSLOCK_LOCKKEY 0x0000U

#define EFM32_MSC_WRITECMD_LADDRIM (1U << 0U)
#define EFM32_MSC_WRITECMD_ERASEPAGE (1U << 1U)
Expand All @@ -104,6 +106,7 @@ const command_s efm32_cmd_list[] = {
#define EFM32_LOCK_BITS (EFM32_INFO + 0x4000U)
#define EFM32_V1_DI (EFM32_INFO + 0x8000U)
#define EFM32_V2_DI (EFM32_INFO + 0x81b0U)
#define EFR32FG23_DI (EFM32_INFO + 0x8000U)

/* -------------------------------------------------------------------------- */
/* Lock Bits (LB) */
Expand Down Expand Up @@ -176,6 +179,7 @@ const command_s efm32_cmd_list[] = {
#define EFM32_V1_DI_PROD_REV (EFM32_V1_DI + 0x1ffU)

/* top 24 bits of eui */
// Page 65 - https://www.silabs.com/documents/public/reference-manuals/EZR32LG-RM.pdf
#define EFM32_V1_DI_EUI_SILABS 0x000b57U

/* -------------------------------------------------------------------------- */
Expand Down Expand Up @@ -256,7 +260,52 @@ const command_s efm32_cmd_list[] = {
#define EFM32_V2_DI_OPA2CAL7 (EFM32_V2_DI + 0x1fcU) /* OPA2 Calibration Register for DRIVESTRENGTH 3, INCBW=0 */

/* top 24 bits of eui */
#define EFM32_V2_DI_EUI_ENERGYMICRO 0xd0cf5e
#define EFM32_V2_DI_EUI_ENERGYMICRO 0x666d71 //0xd0cf5e

/* -------------------------------------------------------------------------- */
/* Device Information (DI) Area for EFR32FG23 */
/* -------------------------------------------------------------------------- */

#define EFR32FG23_DI_INFO (EFR32FG23_DI + 0x000U)
#define EFR32FG23_DI_PART (EFR32FG23_DI + 0x004U)
#define EFR32FG23_DI_MEMINFO (EFR32FG23_DI + 0x008U)
#define EFR32FG23_DI_MSIZE (EFR32FG23_DI + 0x00cU)
#define EFR32FG23_DI_PKGINFO (EFR32FG23_DI + 0x010U)
#define EFR32FG23_DI_CUSTOMINFO (EFR32FG23_DI + 0x014U)
#define EFR32FG23_DI_SWFIX (EFR32FG23_DI + 0x018U)
#define EFR32FG23_DI_SWCAPA0 (EFR32FG23_DI + 0x01cU)
#define EFR32FG23_DI_SWCAPA1 (EFR32FG23_DI + 0x020U)
#define EFR32FG23_DI_EXTINFO (EFR32FG23_DI + 0x028U)
#define EFR32FG23_DI_EUI48L (EFR32FG23_DI + 0x040U)
#define EFR32FG23_DI_EUI48H (EFR32FG23_DI + 0x044U)
#define EFR32FG23_DI_EUI64L (EFR32FG23_DI + 0x048U)
#define EFR32FG23_DI_EUI64H (EFR32FG23_DI + 0x04CU)
#define EFR32FG23_DI_CALTEMP (EFR32FG23_DI + 0x050U)
#define EFR32FG23_DI_EMUTEMP (EFR32FG23_DI + 0x054U)
#define EFR32FG23_DI_HFRCODPLLCALn (EFR32FG23_DI + 0x058U)
#define EFR32FG23_DI_HFRCOEM23CALn (EFR32FG23_DI + 0x0A0U)
#define EFR32FG23_DI_MODULENAME0 (EFR32FG23_DI + 0x130U)
#define EFR32FG23_DI_MODULENAME1 (EFR32FG23_DI + 0x134U)
#define EFR32FG23_DI_MODULENAME2 (EFR32FG23_DI + 0x138U)
#define EFR32FG23_DI_MODULENAME3 (EFR32FG23_DI + 0x13CU)
#define EFR32FG23_DI_MODULENAME4 (EFR32FG23_DI + 0x140U)
#define EFR32FG23_DI_MODULENAME5 (EFR32FG23_DI + 0x144U)
#define EFR32FG23_DI_MODULENAME6 (EFR32FG23_DI + 0x148U)
#define EFR32FG23_DI_MODULEINFO (EFR32FG23_DI + 0x14CU)
#define EFR32FG23_DI_MODXOCAL (EFR32FG23_DI + 0x150U)
#define EFR32FG23_DI_HFXOCAL (EFR32FG23_DI + 0x17CU)
#define EFR32FG23_DI_IADC0GAIN0 (EFR32FG23_DI + 0x180U)
#define EFR32FG23_DI_IADC0GAIN1 (EFR32FG23_DI + 0x184U)
#define EFR32FG23_DI_IADC0OFFSETCAL0 (EFR32FG23_DI + 0x188U)
#define EFR32FG23_DI_IADC0NORMALOFFSETCAL0 (EFR32FG23_DI + 0x18CU)
#define EFR32FG23_DI_IADC0NORMALOFFSETCAL1 (EFR32FG23_DI + 0x190U)
#define EFR32FG23_DI_IADC0HISPDOFFSETCAL0 (EFR32FG23_DI + 0x194U)
#define EFR32FG23_DI_IADC0HISPDOFFSETCAL1 (EFR32FG23_DI + 0x198U)
#define EFR32FG23_DI_LEGACY (EFR32FG23_DI + 0x1FCU)
#define EFR32FG23_DI_RTHERM (EFR32FG23_DI + 0x25CU)

/* top 24 bits of eui */
#define EFR32FG23_DI_EUI_ENERGYMICRO 0xf4b3b1

/* -------------------------------------------------------------------------- */
/* Constants */
Expand Down Expand Up @@ -332,6 +381,10 @@ static const efm32_device_s efm32_devices[] = {
{61, true, 2048, "EFR32FG14P", 0x400e0000, 2048, 16384, "Flex Gecko"},
{62, true, 2048, "EFR32FG14B", 0x400e0000, 2048, 16384, "Flex Gecko"},
{63, true, 2048, "EFR32FG14V", 0x400e0000, 2048, 16384, "Flex Gecko"},
/* For EFR32xG23 devices */
{0, true, 8192, "EFR32FG23", 0x40030000, 1024, 0, "Flex Gecko"},
{3, true, 8192, "EFR32ZG23", 0x40030000, 1024, 0, "Z-wave Gecko"},
{5, true, 8192, "EFR32PG23", 0x40030000, 1024, 0, "Pearl Gecko"},
};

/* miscchip */
Expand Down Expand Up @@ -392,6 +445,14 @@ static uint64_t efm32_v2_read_unique(target_s *t, uint8_t di_version)
return ((uint64_t)target_mem32_read32(t, EFM32_V2_DI_UNIQUEH) << 32U) | target_mem32_read32(t, EFM32_V2_DI_UNIQUEL);
}

static uint64_t efr32fg23_read_unique(target_s *t, uint8_t di_version)
{
if (di_version != 3)
return 0;

return (((uint64_t)target_mem32_read32(t, EFR32FG23_DI_EUI64H) & 0x000FU) << 32U ) | target_mem32_read32(t, EFR32FG23_DI_EUI64L);
}

/* Reads the EFM32 flash size in kiB */
static uint16_t efm32_read_flash_size(target_s *t, uint8_t di_version)
{
Expand All @@ -400,6 +461,8 @@ static uint16_t efm32_read_flash_size(target_s *t, uint8_t di_version)
return target_mem32_read16(t, EFM32_V1_DI_MEM_INFO_FLASH);
case 2:
return target_mem32_read32(t, EFM32_V2_DI_MSIZE) & 0xffffU;
case 3:
return target_mem32_read16(t, EFR32FG23_DI_MSIZE);
default:
return 0;
}
Expand All @@ -413,6 +476,8 @@ static uint16_t efm32_read_ram_size(target_s *t, uint8_t di_version)
return target_mem32_read16(t, EFM32_V1_DI_MEM_INFO_RAM);
case 2:
return (target_mem32_read32(t, EFM32_V2_DI_MSIZE) >> 16U) & 0xffffU;
case 3:
return (target_mem32_read32(t, EFR32FG23_DI_MSIZE) >> 16U) & 0xffffU;
default:
return 0;
}
Expand All @@ -435,6 +500,9 @@ static uint32_t efm32_flash_page_size(target_s *t, uint8_t di_version)
case 2U:
mem_info_page_size = (target_mem32_read32(t, EFM32_V2_DI_MEMINFO) >> 24U) & 0xffU;
break;
case 3U:
mem_info_page_size = target_mem32_read8(t, EFR32FG23_DI_MEMINFO);
break;
default:
return 0;
}
Expand All @@ -449,7 +517,9 @@ static uint16_t efm32_read_part_number(target_s *t, uint8_t di_version)
case 1:
return target_mem32_read8(t, EFM32_V1_DI_PART_NUMBER);
case 2:
return target_mem32_read32(t, EFM32_V2_DI_PART) & 0xffffU;
return target_mem32_read32(t, EFM32_V2_DI_PART) & 0xffffU;
case 3:
return target_mem32_read32(t, EFR32FG23_DI_PART) & 0xffffU;
default:
return 0;
}
Expand All @@ -462,7 +532,9 @@ static uint8_t efm32_read_part_family(target_s *t, uint8_t di_version)
case 1:
return target_mem32_read8(t, EFM32_V1_DI_PART_FAMILY);
case 2:
return (target_mem32_read32(t, EFM32_V2_DI_PART) >> 16U) & 0xffU;
return (target_mem32_read32(t, EFM32_V2_DI_PART) >> 16U) & 0xffU;
case 3:
return (target_mem32_read32(t, EFR32FG23_DI_PART) >> 24U) & 0x3fU;
default:
return 0;
}
Expand Down Expand Up @@ -520,6 +592,8 @@ static void efm32_add_flash(target_s *t, target_addr_t addr, size_t length, size
/* Lookup device */
static efm32_device_s const *efm32_get_device(target_s *t, uint8_t di_version)
{
if(di_version == 0) return NULL;

uint8_t part_family = efm32_read_part_family(t, di_version);

/* Search for family */
Expand All @@ -542,6 +616,9 @@ typedef struct efm32_priv {

bool efm32_probe(target_s *t)
{
/* Different devices have differente addresses for the DI area. Until we know what the device is,
* we use a bit of brute force until we find the right one. */

/* Check if the OUI in the EUI is silabs or energymicro.
* Use this to identify the Device Identification (DI) version */
uint8_t di_version;
Expand All @@ -554,15 +631,45 @@ bool efm32_probe(target_s *t)
/* Device Identification (DI) version 2 */
di_version = 2;
} else {
/* Unknown OUI - assume version 1 */
di_version = 1;
/* Check for an EFR32xG23 device. Criteria
* DI_PART FAMILY is 0,3,5,8
* DI_FAMILYNUM is 23
*/
uint32_t pn = target_mem32_read32(t, EFR32FG23_DI_PART);
uint8_t family = (pn >> 24) & 0x3f; // Extract bits 29-24 (6 bits)
uint8_t familynum = (pn >> 16) & 0x3f; /* Extract family ID from bits 21-16 */
uint16_t devicenum = pn & 0xffff; /* Extract DEVICENUM from bits 0-15 */

/* Check for known EFR32FG23 OUIs */
if (familynum == 23 && (family == 0 || family == 3 || family == 5)) {
/* Use Device Identification version 3 for EFR32FG23 */
di_version = 3;
DEBUG_INFO("EFR32xG23 Device found\n");
DEBUG_INFO("EFR32xG23 Family (decimal): %u\n", family);
DEBUG_INFO("EFR32xG23 FamilyNUM (decimal): %u\n", familynum);
/* Convert device number to letter-number format (e.g., 1123 -> B123) */
char letter = 'A' + (devicenum / 1000);
uint16_t number = devicenum % 1000;
DEBUG_INFO("EFR32xG23 Device : %c%03u\n", letter, number);
}
else {
DEBUG_INFO("Could not determine EFM32/EFR32 device type, assuming version 1.");
di_version = 1;
}
}

/* Read the part family, and reject if unknown */
efm32_device_s const *device = efm32_get_device(t, di_version);
if (!device)
{
DEBUG_ERROR("Could not find the EFM32 device in the lookup table.\n");
return false;
}

DEBUG_INFO("Found EFM32/EFR32 device: %s\n", device->name);

t->attach = cortexm_attach;
t->detach = cortexm_detach;
t->mass_erase = efm32_mass_erase;
uint16_t part_number = efm32_read_part_number(t, di_version);

Expand All @@ -573,6 +680,7 @@ bool efm32_probe(target_s *t)
uint32_t ram_size = ram_kib * 0x400U;
uint32_t flash_page_size = device->flash_page_size;


efm32_priv_s *priv_storage = calloc(1, sizeof(*priv_storage));
if (!priv_storage) { /* calloc failed: heap exhaustion */
DEBUG_ERROR("calloc: failed in %s\n", __func__);
Expand Down Expand Up @@ -600,6 +708,8 @@ bool efm32_probe(target_s *t)
efm32_add_flash(t, 0x0fe10000, device->bootloader_size, flash_page_size);
}

target_mem32_write32(t, 0x40008064U, 0xFFFFFFFFU);
target_mem32_write32(t, 0x40008068U, 0x1FFFFFFFU);
target_add_commands(t, efm32_cmd_list, "EFM32");

return true;
Expand All @@ -616,6 +726,9 @@ static bool efm32_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)

uint32_t msc = priv_storage->device->msc_addr;

/* Set WREN bit to enable MSC write and erase functionality */
target_mem32_write32(t, EFM32_MSC_WRITECTRL(msc), 1);

/* Unlock */
target_mem32_write32(t, EFM32_MSC_LOCK(msc), EFM32_MSC_LOCK_LOCKKEY);

Expand All @@ -642,15 +755,12 @@ static bool efm32_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
else
len = 0;
}

return true;
}

/* Write flash page by page */
static bool efm32_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len)
{
(void)len;

target_s *t = f->t;

efm32_priv_s *priv_storage = (efm32_priv_s *)t->target_storage;
Expand Down Expand Up @@ -749,6 +859,11 @@ static bool efm32_cmd_serial(target_s *t, int argc, const char **argv)
unique = efm32_v2_read_unique(t, di_version);
break;

case 3:
/* Read unique number */
unique = efr32fg23_read_unique(t, di_version);
break;

default:
tc_printf(t, "Bad DI version %u! This driver doesn't know about this DI version\n", di_version);
return false;
Expand Down Expand Up @@ -781,6 +896,10 @@ static bool efm32_cmd_efm_info(target_s *t, int argc, const char **argv)
tc_printf(t, "DI version 2 (energy micro remix?) base 0x%08" PRIx32 "\n\n", EFM32_V2_DI);
break;

case 3:
tc_printf(t, "DI version EFR32xG23 base 0x%08" PRIx32 "\n\n", EFR32FG23_DI);
break;

default:
tc_printf(t, "Bad DI version %u! This driver doesn't know about this DI version\n", di_version);
return false;
Expand Down Expand Up @@ -970,7 +1089,7 @@ bool efm32_aap_probe(adiv5_access_port_s *ap)
snprintf(priv_storage->aap_driver_string, sizeof(priv_storage->aap_driver_string),
"EFM32 Authentication Access Port rev.%hu", aap_revision);
t->driver = priv_storage->aap_driver_string;
t->regs_size = 0;
t->regs_size = 4;

return true;
}
Expand Down Expand Up @@ -1005,4 +1124,4 @@ static bool efm32_aap_mass_erase(target_s *const t, platform_timeout_s *const pr
DEBUG_INFO("EFM32: AAP STATUS=%08" PRIx32 "\n", status);

return true;
}
}
49 changes: 49 additions & 0 deletions src/target/efm32.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# EFM/EFR Family

| Series | Device | Family |
|--------|--------|--------|
| **Series 0** | EFM32ZG | Zero Gecko |
| | EFM32HG | Happy Gecko |
| | EFM32TG | Tiny Gecko |
| | EFM32G | Gecko |
| | EFM32LG | Leopard Gecko |
| | EFM32GG | Giant Gecko |
| | EFM32WG | Wonder Gecko |
| **Series 1** | EFM32PG1 | Pearl Gecko |
| | EFR32MG1 | Mighty Gecko |
| | EFR32BG1 | Blue Gecko |
| | EFR32FG1 | Flex Gecko |
| | EFM32PG12 | Pearl Gecko |
| | EFR32MG12 | Mighty Gecko |
| | EFR32BG12 | Blue Gecko |
| | EFR32FG12 | Flex Gecko |
| | EFR32MG13 | Mighty Gecko |
| | EFR32BG13 | Blue Gecko |
| | EFR32FG13 | Flex Gecko |
| | EFR32MG14 | Mighty Gecko |
| | EFR32FG14 | Flex Gecko |
| | EFM32GG11 | Giant Gecko |
| | EFM32TG11 | Tiny Gecko |
| **Series 2** | EFR32BG21 | Blue Gecko |
| | EFR32MG21 | Mighty Gecko |
| | EFR32BG22 | Blue Gecko |
| | EFR32FG22 | Flex Gecko |
| | EFR32MG22 | Mighty Gecko |
| | EFM32PG22 | Pearl Gecko |
| | EFR32FG23 | Flex Gecko |
| | EFR32SG23 | Sidewalk Gecko |
| | EFR32ZG23 | Z-Wave Gecko |
| | EFM32PG23 | Pearl Gecko |
| | EFR32BG24 | Blue Gecko |
| | EFR32MG24 | Mighty Gecko |
| | EFR32FG25 | Flex Gecko |
| | EFR32BG27 | Blue Gecko |
| | EFR32MG27 | Mighty Gecko |
| | EFR32FG28 | Flex Gecko |
| | EFR32SG28 | Sidewalk Gecko |
| | EFR32ZG28 | Z-Wave Gecko |
| | EFM32PG28 | Pearl Gecko |



*Source: https://github.com/SiliconLabs/peripheral_examples/blob/master/README.md*