diff --git a/efm32.md b/efm32.md new file mode 100644 index 00000000000..461f988140a --- /dev/null +++ b/efm32.md @@ -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* \ No newline at end of file diff --git a/src/target/efm32.c b/src/target/efm32.c index 09a209f2f34..c6b5c21a4e3 100644 --- a/src/target/efm32.c +++ b/src/target/efm32.c @@ -69,17 +69,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_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 + 0x030U) -#define EFM32_MSC_LOCK(msc) (msc + (msc == 0x400c0000U ? 0x3cU : 0x40U)) -#define EFM32_MSC_MASSLOCK(msc) (msc + 0x054U) +#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) @@ -104,6 +104,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) */ @@ -256,7 +257,49 @@ 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) /* -------------------------------------------------------------------------- */ /* Constants */ @@ -332,6 +375,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 */ @@ -392,6 +439,15 @@ 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) { @@ -400,6 +456,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; } @@ -413,6 +471,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; } @@ -435,6 +495,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; } @@ -450,6 +513,8 @@ static uint16_t efm32_read_part_number(target_s *t, uint8_t di_version) return target_mem32_read8(t, EFM32_V1_DI_PART_NUMBER); case 2: return target_mem32_read32(t, EFM32_V2_DI_PART) & 0xffffU; + case 3: + return target_mem32_read32(t, EFR32FG23_DI_PART) & 0xffffU; default: return 0; } @@ -463,6 +528,8 @@ static uint8_t efm32_read_part_family(target_s *t, uint8_t di_version) return target_mem32_read8(t, EFM32_V1_DI_PART_FAMILY); case 2: 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; } @@ -520,6 +587,9 @@ 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 */ @@ -542,6 +612,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; @@ -554,15 +627,48 @@ 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 */ + + /* Check for known EFR32FG23 OUIs */ + if (familynum == 23 && (family == 0 || family == 3 || family == 5)) { + /* Use Device Identification version 3 for EFR32FG23 */ + di_version = 3; + +#ifndef DEBUG_INFO_IS_NOOP + uint16_t devicenum = pn & 0xffff; /* Extract DEVICENUM from bits 0-15 */ + + /* 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 found\n"); + DEBUG_INFO("EFR32xG23 Family (decimal): %u\n", family); + DEBUG_INFO("EFR32xG23 FamilyNUM (decimal): %u\n", familynum); + DEBUG_INFO("EFR32xG23 Device : %c%03u\n", letter, number); +#endif + } 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) + 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); @@ -600,6 +706,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; @@ -616,6 +724,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); @@ -649,8 +760,6 @@ static bool efm32_flash_erase(target_flash_s *f, target_addr_t addr, size_t len) /* 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; @@ -749,6 +858,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; @@ -781,6 +895,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; @@ -970,7 +1088,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; }