/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2011 by Andreas Fritiofson *
* andreas.fritiofson@gmail.com *
* *
* 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 *
* (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 <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "imp.h"
#include <helper/binarybuffer.h>
#include <target/algorithm.h>
#include <target/armv7m.h>
#include <target/cortex_m.h>
/* keep family IDs in decimal */
#define EFM_FAMILY_ID_GECKO 71
#define EFM_FAMILY_ID_GIANT_GECKO 72
#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 EFM32_FLASH_ERASE_TMO 100
#define EFM32_FLASH_WDATAREADY_TMO 100
#define EFM32_FLASH_WRITE_TMO 100
/* size in bytes, not words; must fit all Gecko devices */
#define LOCKBITS_PAGE_SZ 512
#define EFM32_MSC_INFO_BASE 0x0fe00000
#define EFM32_MSC_USER_DATA EFM32_MSC_INFO_BASE
#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, 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_PART_NUM (EFM32_MSC_DEV_INFO+0x1fc)
#define EFM32_MSC_DI_PART_FAMILY (EFM32_MSC_DEV_INFO+0x1fe)
#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 EFM32_MSC_WRITECTRL_WREN_MASK 0x1
#define EFM32_MSC_WRITECMD (EFM32_MSC_REGBASE+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_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_LOCK_LOCKKEY 0x1b71
struct efm32x_flash_bank {
int probed;
uint32_t lb_page[LOCKBITS_PAGE_SZ/4];
};
struct efm32_info {
uint16_t flash_sz_kib;
uint16_t ram_sz_kib;
uint16_t part_num;
uint8_t part_family;
uint8_t prod_rev;
uint16_t page_size;
};
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)
{
return target_read_u16(bank->target, EFM32_MSC_DI_FLASH_SZ, flash_sz);
}
static int efm32x_get_ram_size(struct flash_bank *bank, uint16_t *ram_sz)
{
return target_read_u16(bank->target, EFM32_MSC_DI_RAM_SZ, ram_sz);
}
static int efm32x_get_part_num(struct flash_bank *bank, uint16_t *pnum)
{
return target_read_u16(bank->target, EFM32_MSC_DI_PART_NUM, pnum);
}
static int efm32x_get_part_family(struct flash_bank *bank, uint8_t *pfamily)
{
return target_read_u8(bank->target, EFM32_MSC_DI_PART_FAMILY, pfamily);
}
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_info(struct flash_bank *bank,
struct efm32_info *efm32_info)
{
int ret;
uint32_t cpuid = 0;
memset(efm32_info, 0, sizeof(struct efm32_info));
ret = target_read_u32(bank->target, CPUID, &cpuid);
if (ERROR_OK != ret)
return ret;
if (((cpuid >> 4) & 0xfff) == 0xc23) {
/* Cortex-M3 device */
} else if (((cpuid >> 4) & 0xfff) == 0xc24) {
/* Cortex-M4 device (WONDER GECKO) */
} else if (((cpuid >> 4) & 0xfff) == 0xc60) {
/* Cortex-M0+ device */
} else {
LOG_ERROR("Target is not Cortex-Mx Device");
return ERROR_FAIL;
}
ret = efm32x_get_flash_size(bank, &(efm32_info->flash_sz_kib));
if (ERROR_OK != ret)
return ret;
ret = efm32x_get_ram_size(bank, &(efm32_info->ram_sz_kib));
if (ERROR_OK != ret)
return ret;
ret = efm32x_get_part_num(bank, &(