]> git.sur5r.net Git - openocd/blobdiff - src/flash/nor/efm32.c
flash: efm32: add support for EFR-familty (e.g. bluegecko)
[openocd] / src / flash / nor / efm32.c
index 858bb0a70885257d3f3799baef33b39e8ebe4b59..b8453e1ddca462adf037da214f7aace32225cf6f 100644 (file)
  *                                                                         *
  *   Copyright (C) 2013 by Roman Dmitrienko                                *
  *   me@iamroman.org                                                       *
- *
+ *                                                                         *
+ *   Copyright (C) 2014 Nemui Trinomius                                    *
+ *   nemuisan_kawausogasuki@live.jp                                        *
+ *                                                                         *
  *   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 2 of the License, or     *
@@ -22,9 +25,7 @@
  *   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, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
 #define EFM_FAMILY_ID_TINY_GECKO        73
 #define EFM_FAMILY_ID_LEOPARD_GECKO     74
 #define EFM_FAMILY_ID_WONDER_GECKO      75
+#define EFM_FAMILY_ID_ZERO_GECKO        76
+#define EFM_FAMILY_ID_HAPPY_GECKO      77
+#define EZR_FAMILY_ID_WONDER_GECKO             120
+#define EZR_FAMILY_ID_LEOPARD_GECKO            121
+#define EZR_FAMILY_ID_HAPPY_GECKO               122
+#define EFR_FAMILY_ID_MIGHTY_GECKO     16
+#define EFR_FAMILY_ID_BLUE_GECKO       20
 
 #define EFM32_FLASH_ERASE_TMO           100
 #define EFM32_FLASH_WDATAREADY_TMO      100
@@ -57,7 +65,7 @@
 #define EFM32_MSC_LOCK_BITS             (EFM32_MSC_INFO_BASE+0x4000)
 #define EFM32_MSC_DEV_INFO              (EFM32_MSC_INFO_BASE+0x8000)
 
-/* PAGE_SIZE is only present in Leopard and Giant Gecko MCUs */
+/* PAGE_SIZE is only present in Leopard, Giant and Wonder Gecko MCUs */
 #define EFM32_MSC_DI_PAGE_SIZE          (EFM32_MSC_DEV_INFO+0x1e7)
 #define EFM32_MSC_DI_FLASH_SZ           (EFM32_MSC_DEV_INFO+0x1f8)
 #define EFM32_MSC_DI_RAM_SZ             (EFM32_MSC_DEV_INFO+0x1fa)
 #define EFM32_MSC_DI_PROD_REV           (EFM32_MSC_DEV_INFO+0x1ff)
 
 #define EFM32_MSC_REGBASE               0x400c0000
-#define EFM32_MSC_WRITECTRL             (EFM32_MSC_REGBASE+0x008)
+#define EFR32_MSC_REGBASE               0x400e0000
+#define EFM32_MSC_REG_WRITECTRL         0x008
 #define EFM32_MSC_WRITECTRL_WREN_MASK   0x1
-#define EFM32_MSC_WRITECMD              (EFM32_MSC_REGBASE+0x00c)
+#define EFM32_MSC_REG_WRITECMD          0x00c
 #define EFM32_MSC_WRITECMD_LADDRIM_MASK 0x1
 #define EFM32_MSC_WRITECMD_ERASEPAGE_MASK 0x2
 #define EFM32_MSC_WRITECMD_WRITEONCE_MASK 0x8
-#define EFM32_MSC_ADDRB                 (EFM32_MSC_REGBASE+0x010)
-#define EFM32_MSC_WDATA                 (EFM32_MSC_REGBASE+0x018)
-#define EFM32_MSC_STATUS                (EFM32_MSC_REGBASE+0x01c)
+#define EFM32_MSC_REG_ADDRB             0x010
+#define EFM32_MSC_REG_WDATA             0x018
+#define EFM32_MSC_REG_STATUS            0x01c
 #define EFM32_MSC_STATUS_BUSY_MASK      0x1
 #define EFM32_MSC_STATUS_LOCKED_MASK    0x2
 #define EFM32_MSC_STATUS_INVADDR_MASK   0x4
 #define EFM32_MSC_STATUS_WDATAREADY_MASK 0x8
 #define EFM32_MSC_STATUS_WORDTIMEOUT_MASK 0x10
 #define EFM32_MSC_STATUS_ERASEABORTED_MASK 0x20
-#define EFM32_MSC_LOCK                  (EFM32_MSC_REGBASE+0x03c)
+#define EFM32_MSC_REG_LOCK              0x03c
+#define EFR32_MSC_REG_LOCK              0x040
 #define EFM32_MSC_LOCK_LOCKKEY          0x1b71
 
 struct efm32x_flash_bank {
        int probed;
        uint32_t lb_page[LOCKBITS_PAGE_SZ/4];
+       uint32_t reg_base;
+       uint32_t reg_lock;
 };
 
 struct efm32_info {
@@ -98,7 +110,7 @@ struct efm32_info {
        uint16_t page_size;
 };
 
-static int efm32x_write(struct flash_bank *bank, uint8_t *buffer,
+static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer,
        uint32_t offset, uint32_t count);
 
 static int efm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_sz)
@@ -126,11 +138,30 @@ static int efm32x_get_prod_rev(struct flash_bank *bank, uint8_t *prev)
        return target_read_u8(bank->target, EFM32_MSC_DI_PROD_REV, prev);
 }
 
+static int efm32x_read_reg_u32(struct flash_bank *bank, target_addr_t offset,
+                              uint32_t *value)
+{
+       struct efm32x_flash_bank *efm32x_info = bank->driver_priv;
+       uint32_t base = efm32x_info->reg_base;
+
+       return target_read_u32(bank->target, base + offset, value);
+}
+
+static int efm32x_write_reg_u32(struct flash_bank *bank, target_addr_t offset,
+                              uint32_t value)
+{
+       struct efm32x_flash_bank *efm32x_info = bank->driver_priv;
+       uint32_t base = efm32x_info->reg_base;
+
+       return target_write_u32(bank->target, base + offset, value);
+}
+
 static int efm32x_read_info(struct flash_bank *bank,
        struct efm32_info *efm32_info)
 {
        int ret;
        uint32_t cpuid = 0;
+       struct efm32x_flash_bank *efm32x_info = bank->driver_priv;
 
        memset(efm32_info, 0, sizeof(struct efm32_info));
 
@@ -139,11 +170,13 @@ static int efm32x_read_info(struct flash_bank *bank,
                return ret;
 
        if (((cpuid >> 4) & 0xfff) == 0xc23) {
-               /* Cortex M3 device */
+               /* Cortex-M3 device */
        } else if (((cpuid >> 4) & 0xfff) == 0xc24) {
-               /* Cortex M4 device */
+               /* Cortex-M4 device (WONDER GECKO) */
+       } else if (((cpuid >> 4) & 0xfff) == 0xc60) {
+               /* Cortex-M0+ device */
        } else {
-               LOG_ERROR("Target is not CortexM3 or M4");
+               LOG_ERROR("Target is not Cortex-Mx Device");
                return ERROR_FAIL;
        }
 
@@ -167,9 +200,22 @@ static int efm32x_read_info(struct flash_bank *bank,
        if (ERROR_OK != ret)
                return ret;
 
+       if (EFR_FAMILY_ID_BLUE_GECKO == efm32_info->part_family ||
+           EFR_FAMILY_ID_MIGHTY_GECKO == efm32_info->part_family) {
+               efm32x_info->reg_base = EFR32_MSC_REGBASE;
+               efm32x_info->reg_lock = EFR32_MSC_REG_LOCK;
+       } else {
+               efm32x_info->reg_base = EFM32_MSC_REGBASE;
+               efm32x_info->reg_lock = EFM32_MSC_REG_LOCK;
+       }
+
        if (EFM_FAMILY_ID_GECKO == efm32_info->part_family ||
                        EFM_FAMILY_ID_TINY_GECKO == efm32_info->part_family)
                efm32_info->page_size = 512;
+       else if (EFM_FAMILY_ID_ZERO_GECKO == efm32_info->part_family ||
+                       EFM_FAMILY_ID_HAPPY_GECKO == efm32_info->part_family ||
+                       EZR_FAMILY_ID_HAPPY_GECKO == efm32_info->part_family)
+               efm32_info->page_size = 1024;
        else if (EFM_FAMILY_ID_GIANT_GECKO == efm32_info->part_family ||
                        EFM_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family) {
                if (efm32_info->prod_rev >= 18) {
@@ -194,7 +240,11 @@ static int efm32x_read_info(struct flash_bank *bank,
                        LOG_ERROR("Invalid page size %u", efm32_info->page_size);
                        return ERROR_FAIL;
                }
-       } else if (EFM_FAMILY_ID_WONDER_GECKO == efm32_info->part_family) {
+       } else if (EFM_FAMILY_ID_WONDER_GECKO == efm32_info->part_family ||
+                       EZR_FAMILY_ID_WONDER_GECKO == efm32_info->part_family ||
+                       EZR_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family ||
+                       EFR_FAMILY_ID_BLUE_GECKO == efm32_info->part_family ||
+                       EFR_FAMILY_ID_MIGHTY_GECKO == efm32_info->part_family) {
                uint8_t pg_size = 0;
                ret = target_read_u8(bank->target, EFM32_MSC_DI_PAGE_SIZE,
                        &pg_size);
@@ -214,6 +264,82 @@ static int efm32x_read_info(struct flash_bank *bank,
        return ERROR_OK;
 }
 
+/*
+ * Helper to create a human friendly string describing a part
+ */
+static int efm32x_decode_info(struct efm32_info *info, char *buf, int buf_size)
+{
+       int printed = 0;
+
+       switch (info->part_family) {
+               case EZR_FAMILY_ID_WONDER_GECKO:
+               case EZR_FAMILY_ID_LEOPARD_GECKO:
+               case EZR_FAMILY_ID_HAPPY_GECKO:
+                       printed = snprintf(buf, buf_size, "EZR32 ");
+                       break;
+               case EFR_FAMILY_ID_MIGHTY_GECKO:
+               case EFR_FAMILY_ID_BLUE_GECKO:
+                       printed = snprintf(buf, buf_size, "EFR32 ");
+                       break;
+               default:
+                       printed = snprintf(buf, buf_size, "EFM32 ");
+       }
+
+       buf += printed;
+       buf_size -= printed;
+
+       if (0 >= buf_size)
+               return ERROR_BUF_TOO_SMALL;
+
+       switch (info->part_family) {
+               case EFM_FAMILY_ID_GECKO:
+                       printed = snprintf(buf, buf_size, "Gecko");
+                       break;
+               case EFM_FAMILY_ID_GIANT_GECKO:
+                       printed = snprintf(buf, buf_size, "Giant Gecko");
+                       break;
+               case EFM_FAMILY_ID_TINY_GECKO:
+                       printed = snprintf(buf, buf_size, "Tiny Gecko");
+                       break;
+               case EFM_FAMILY_ID_LEOPARD_GECKO:
+               case EZR_FAMILY_ID_LEOPARD_GECKO:
+                       printed = snprintf(buf, buf_size, "Leopard Gecko");
+                       break;
+               case EFM_FAMILY_ID_WONDER_GECKO:
+               case EZR_FAMILY_ID_WONDER_GECKO:
+                       printed = snprintf(buf, buf_size, "Wonder Gecko");
+                       break;
+               case EFM_FAMILY_ID_ZERO_GECKO:
+                       printed = snprintf(buf, buf_size, "Zero Gecko");
+                       break;
+               case EFM_FAMILY_ID_HAPPY_GECKO:
+               case EZR_FAMILY_ID_HAPPY_GECKO:
+                       printed = snprintf(buf, buf_size, "Happy Gecko");
+                       break;
+               case EFR_FAMILY_ID_BLUE_GECKO:
+                       printed = snprintf(buf, buf_size, "Blue Gecko");
+                       break;
+               case EFR_FAMILY_ID_MIGHTY_GECKO:
+                       printed = snprintf(buf, buf_size, "Mighty Gecko");
+                       break;
+       }
+
+       buf += printed;
+       buf_size -= printed;
+
+       if (0 >= buf_size)
+               return ERROR_BUF_TOO_SMALL;
+
+       printed = snprintf(buf, buf_size, " - Rev: %d", info->prod_rev);
+       buf += printed;
+       buf_size -= printed;
+
+       if (0 >= buf_size)
+               return ERROR_BUF_TOO_SMALL;
+
+       return ERROR_OK;
+}
+
 /* flash bank efm32 <base> <size> 0 0 <target#>
  */
 FLASH_BANK_COMMAND_HANDLER(efm32x_flash_bank_command)
@@ -239,7 +365,7 @@ static int efm32x_set_reg_bits(struct flash_bank *bank, uint32_t reg,
        int ret = 0;
        uint32_t reg_val = 0;
 
-       ret = target_read_u32(bank->target, reg, &reg_val);
+       ret = efm32x_read_reg_u32(bank, reg, &reg_val);
        if (ERROR_OK != ret)
                return ret;
 
@@ -248,18 +374,19 @@ static int efm32x_set_reg_bits(struct flash_bank *bank, uint32_t reg,
        else
                reg_val &= ~bitmask;
 
-       return target_write_u32(bank->target, reg, reg_val);
+       return efm32x_write_reg_u32(bank, reg, reg_val);
 }
 
 static int efm32x_set_wren(struct flash_bank *bank, int write_enable)
 {
-       return efm32x_set_reg_bits(bank, EFM32_MSC_WRITECTRL,
+       return efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECTRL,
                EFM32_MSC_WRITECTRL_WREN_MASK, write_enable);
 }
 
 static int efm32x_msc_lock(struct flash_bank *bank, int lock)
 {
-       return target_write_u32(bank->target, EFM32_MSC_LOCK,
+       struct efm32x_flash_bank *efm32x_info = bank->driver_priv;
+       return efm32x_write_reg_u32(bank, efm32x_info->reg_lock,
                (lock ? 0 : EFM32_MSC_LOCK_LOCKKEY));
 }
 
@@ -270,7 +397,7 @@ static int efm32x_wait_status(struct flash_bank *bank, int timeout,
        uint32_t status = 0;
 
        while (1) {
-               ret = target_read_u32(bank->target, EFM32_MSC_STATUS, &status);
+               ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status);
                if (ERROR_OK != ret)
                        break;
 
@@ -309,16 +436,16 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr)
 
        LOG_DEBUG("erasing flash page at 0x%08" PRIx32, addr);
 
-       ret = target_write_u32(bank->target, EFM32_MSC_ADDRB, addr);
+       ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr);
        if (ERROR_OK != ret)
                return ret;
 
-       ret = efm32x_set_reg_bits(bank, EFM32_MSC_WRITECMD,
+       ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD,
                EFM32_MSC_WRITECMD_LADDRIM_MASK, 1);
        if (ERROR_OK != ret)
                return ret;
 
-       ret = target_read_u32(bank->target, EFM32_MSC_STATUS, &status);
+       ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status);
        if (ERROR_OK != ret)
                return ret;
 
@@ -332,7 +459,7 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr)
                return ERROR_FAIL;
        }
 
-       ret = efm32x_set_reg_bits(bank, EFM32_MSC_WRITECMD,
+       ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD,
                EFM32_MSC_WRITECMD_ERASEPAGE_MASK, 1);
        if (ERROR_OK != ret)
                return ret;
@@ -380,10 +507,10 @@ static int efm32x_read_lock_data(struct flash_bank *bank)
        uint32_t *ptr = NULL;
        int ret = 0;
 
-       assert(!(bank->num_sectors & 0x1f));
+       assert(bank->num_sectors > 0);
 
-       data_size = bank->num_sectors / 8; /* number of data bytes */
-       data_size /= 4; /* ...and data dwords */
+       /* calculate the number of 32-bit words to read (one lock bit per sector) */
+       data_size = (bank->num_sectors + 31) / 32;
 
        ptr = efm32x_info->lb_page;
 
@@ -499,7 +626,7 @@ static int efm32x_protect(struct flash_bank *bank, int set, int first, int last)
        return ERROR_OK;
 }
 
-static int efm32x_write_block(struct flash_bank *bank, uint8_t *buf,
+static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf,
        uint32_t offset, uint32_t count)
 {
        struct target *target = bank->target;
@@ -509,6 +636,7 @@ static int efm32x_write_block(struct flash_bank *bank, uint8_t *buf,
        uint32_t address = bank->base + offset;
        struct reg_param reg_params[5];
        struct armv7m_algorithm armv7m_info;
+       struct efm32x_flash_bank *efm32x_info = bank->driver_priv;
        int ret = ERROR_OK;
 
        /* see contrib/loaders/flash/efm32.S for src */
@@ -518,10 +646,7 @@ static int efm32x_write_block(struct flash_bank *bank, uint8_t *buf,
                /* #define EFM32_MSC_ADDRB_OFFSET          0x010 */
                /* #define EFM32_MSC_WDATA_OFFSET          0x018 */
                /* #define EFM32_MSC_STATUS_OFFSET         0x01c */
-               /* #define EFM32_MSC_LOCK_OFFSET           0x03c */
 
-                       0x15, 0x4e,    /* ldr     r6, =#0x1b71 */
-                       0xc6, 0x63,    /* str     r6, [r0, #EFM32_MSC_LOCK_OFFSET] */
                        0x01, 0x26,    /* movs    r6, #1 */
                        0x86, 0x60,    /* str     r6, [r0, #EFM32_MSC_WRITECTRL_OFFSET] */
 
@@ -580,17 +705,15 @@ static int efm32x_write_block(struct flash_bank *bank, uint8_t *buf,
                /* exit: */
                        0x30, 0x46,    /* mov     r0, r6 */
                        0x00, 0xbe,    /* bkpt    #0 */
-
-               /* LOCKKEY */
-                       0x71, 0x1b, 0x00, 0x00
        };
 
+
        /* flash write code */
        if (target_alloc_working_area(target, sizeof(efm32x_flash_write_code),
                        &write_algorithm) != ERROR_OK) {
                LOG_WARNING("no working area available, can't do block memory writes");
                return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-       };
+       }
 
        ret = target_write_buffer(target, write_algorithm->address,
                        sizeof(efm32x_flash_write_code), efm32x_flash_write_code);
@@ -609,7 +732,7 @@ static int efm32x_write_block(struct flash_bank *bank, uint8_t *buf,
                        LOG_WARNING("no large enough working area available, can't do block memory writes");
                        return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
                }
-       };
+       }
 
        init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */
        init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);    /* count (word-32bit) */
@@ -617,7 +740,7 @@ static int efm32x_write_block(struct flash_bank *bank, uint8_t *buf,
        init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);    /* buffer end */
        init_reg_param(&reg_params[4], "r4", 32, PARAM_IN_OUT); /* target address */
 
-       buf_set_u32(reg_params[0].value, 0, 32, EFM32_MSC_REGBASE);
+       buf_set_u32(reg_params[0].value, 0, 32, efm32x_info->reg_base);
        buf_set_u32(reg_params[1].value, 0, 32, count);
        buf_set_u32(reg_params[2].value, 0, 32, source->address);
        buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size);
@@ -682,16 +805,16 @@ static int efm32x_write_word(struct flash_bank *bank, uint32_t addr,
        /* if not called, GDB errors will be reported during large writes */
        keep_alive();
 
-       ret = target_write_u32(bank->target, EFM32_MSC_ADDRB, addr);
+       ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr);
        if (ERROR_OK != ret)
                return ret;
 
-       ret = efm32x_set_reg_bits(bank, EFM32_MSC_WRITECMD,
+       ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD,
                EFM32_MSC_WRITECMD_LADDRIM_MASK, 1);
        if (ERROR_OK != ret)
                return ret;
 
-       ret = target_read_u32(bank->target, EFM32_MSC_STATUS, &status);
+       ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status);
        if (ERROR_OK != ret)
                return ret;
 
@@ -712,13 +835,13 @@ static int efm32x_write_word(struct flash_bank *bank, uint32_t addr,
                return ret;
        }
 
-       ret = target_write_u32(bank->target, EFM32_MSC_WDATA, val);
+       ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_WDATA, val);
        if (ERROR_OK != ret) {
                LOG_ERROR("WDATA write failed");
                return ret;
        }
 
-       ret = target_write_u32(bank->target, EFM32_MSC_WRITECMD,
+       ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_WRITECMD,
                EFM32_MSC_WRITECMD_WRITEONCE_MASK);
        if (ERROR_OK != ret) {
                LOG_ERROR("WRITECMD write failed");
@@ -735,7 +858,7 @@ static int efm32x_write_word(struct flash_bank *bank, uint32_t addr,
        return ERROR_OK;
 }
 
-static int efm32x_write(struct flash_bank *bank, uint8_t *buffer,
+static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer,
                uint32_t offset, uint32_t count)
 {
        struct target *target = bank->target;
@@ -763,7 +886,7 @@ static int efm32x_write(struct flash_bank *bank, uint8_t *buffer,
                }
                LOG_INFO("odd number of bytes to write (%" PRIu32 "), extending to %" PRIu32 " "
                        "and padding with 0xff", old_count, count);
-               memset(buffer, 0xff, count);
+               memset(new_buffer, 0xff, count);
                buffer = memcpy(new_buffer, buffer, old_count);
        }
 
@@ -819,6 +942,7 @@ static int efm32x_probe(struct flash_bank *bank)
        int ret;
        int i;
        uint32_t base_address = 0x00000000;
+       char buf[256];
 
        efm32x_info->probed = 0;
        memset(efm32x_info->lb_page, 0xff, LOCKBITS_PAGE_SZ);
@@ -827,28 +951,11 @@ static int efm32x_probe(struct flash_bank *bank)
        if (ERROR_OK != ret)
                return ret;
 
-       switch (efm32_mcu_info.part_family) {
-               case EFM_FAMILY_ID_GECKO:
-                       LOG_INFO("Gecko MCU detected");
-                       break;
-               case EFM_FAMILY_ID_GIANT_GECKO:
-                       LOG_INFO("Giant Gecko MCU detected");
-                       break;
-               case EFM_FAMILY_ID_TINY_GECKO:
-                       LOG_INFO("Tiny Gecko MCU detected");
-                       break;
-               case EFM_FAMILY_ID_LEOPARD_GECKO:
-                       LOG_INFO("Leopard Gecko MCU detected");
-                       break;
-               case EFM_FAMILY_ID_WONDER_GECKO:
-                       LOG_INFO("Wonder Gecko MCU detected");
-                       break;
-               default:
-                       LOG_ERROR("Unsupported MCU family %d",
-                               efm32_mcu_info.part_family);
-                       return ERROR_FAIL;
-       }
+       ret = efm32x_decode_info(&efm32_mcu_info, buf, sizeof(buf));
+       if (ERROR_OK != ret)
+               return ret;
 
+       LOG_INFO("detected part: %s", buf);
        LOG_INFO("flash size = %dkbytes", efm32_mcu_info.flash_sz_kib);
        LOG_INFO("flash page size = %dbytes", efm32_mcu_info.page_size);
 
@@ -925,7 +1032,6 @@ static int get_efm32x_info(struct flash_bank *bank, char *buf, int buf_size)
 {
        struct efm32_info info;
        int ret = 0;
-       int printed = 0;
 
        ret = efm32x_read_info(bank, &info);
        if (ERROR_OK != ret) {
@@ -933,48 +1039,53 @@ static int get_efm32x_info(struct flash_bank *bank, char *buf, int buf_size)
                return ret;
        }
 
-       printed = snprintf(buf, buf_size, "EFM32 ");
-       buf += printed;
-       buf_size -= printed;
+       return efm32x_decode_info(&info, buf, buf_size);
+}
 
-       if (0 >= buf_size)
-               return ERROR_BUF_TOO_SMALL;
+COMMAND_HANDLER(efm32x_handle_debuglock_command)
+{
+       struct target *target = NULL;
 
-       switch (info.part_family) {
-               case EFM_FAMILY_ID_GECKO:
-                       printed = snprintf(buf, buf_size, "Gecko");
-                       break;
-               case EFM_FAMILY_ID_GIANT_GECKO:
-                       printed = snprintf(buf, buf_size, "Giant Gecko");
-                       break;
-               case EFM_FAMILY_ID_TINY_GECKO:
-                       printed = snprintf(buf, buf_size, "Tiny Gecko");
-                       break;
-               case EFM_FAMILY_ID_LEOPARD_GECKO:
-                       printed = snprintf(buf, buf_size, "Leopard Gecko");
-                       break;
-               case EFM_FAMILY_ID_WONDER_GECKO:
-                       printed = snprintf(buf, buf_size, "Wonder Gecko");
-                       break;
-       }
+       if (CMD_ARGC < 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
 
-       buf += printed;
-       buf_size -= printed;
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
 
-       if (0 >= buf_size)
-               return ERROR_BUF_TOO_SMALL;
+       struct efm32x_flash_bank *efm32x_info = bank->driver_priv;
 
-       printed = snprintf(buf, buf_size, " - Rev: %d", info.prod_rev);
-       buf += printed;
-       buf_size -= printed;
+       target = bank->target;
 
-       if (0 >= buf_size)
-               return ERROR_BUF_TOO_SMALL;
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       uint32_t *ptr;
+       ptr = efm32x_info->lb_page + 127;
+       *ptr = 0;
+
+       retval = efm32x_write_lock_data(bank);
+       if (ERROR_OK != retval) {
+               LOG_ERROR("Failed to write LB page");
+               return retval;
+       }
+
+       command_print(CMD_CTX, "efm32x debug interface locked, reset the device to apply");
 
        return ERROR_OK;
 }
 
 static const struct command_registration efm32x_exec_command_handlers[] = {
+       {
+               .name = "debuglock",
+               .handler = efm32x_handle_debuglock_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id",
+               .help = "Lock the debug interface of the device.",
+       },
        COMMAND_REGISTRATION_DONE
 };