Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
d5bf59152f |
@ -20,6 +20,7 @@ SRC = \
|
|||||||
adiv5.c \
|
adiv5.c \
|
||||||
adiv5_jtagdp.c \
|
adiv5_jtagdp.c \
|
||||||
adiv5_swdp.c \
|
adiv5_swdp.c \
|
||||||
|
aducm36x.c \
|
||||||
command.c \
|
command.c \
|
||||||
cortexa.c \
|
cortexa.c \
|
||||||
cortexm.c \
|
cortexm.c \
|
||||||
@ -65,7 +66,7 @@ SRC = \
|
|||||||
|
|
||||||
include $(PLATFORM_DIR)/Makefile.inc
|
include $(PLATFORM_DIR)/Makefile.inc
|
||||||
|
|
||||||
OPT_FLAGS ?= -Os
|
OPT_FLAGS ?= -Os -nolibc
|
||||||
CFLAGS += $(OPT_FLAGS)
|
CFLAGS += $(OPT_FLAGS)
|
||||||
LDFLAGS += $(OPT_FLAGS)
|
LDFLAGS += $(OPT_FLAGS)
|
||||||
|
|
||||||
|
300
src/target/aducm36x.c
Normal file
300
src/target/aducm36x.c
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2023 by Christopher Are *
|
||||||
|
* c.are@jcsmith.fr *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This version for ADuCM36x is largely based on the following flash *
|
||||||
|
* drivers: *
|
||||||
|
* - aducm360.c *
|
||||||
|
* Copyright (C) 2015 by Ivan Buliev *
|
||||||
|
* i.buliev@mikrosistemi.com *
|
||||||
|
* - aduc702x.c *
|
||||||
|
* Copyright (C) 2008 by Kevin McGuire *
|
||||||
|
* Copyright (C) 2008 by Marcel Wijlaars *
|
||||||
|
* Copyright (C) 2009 by Michael Ashton *
|
||||||
|
* and *
|
||||||
|
* - stm32f1x.c *
|
||||||
|
* 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 *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "general.h"
|
||||||
|
#include "target.h"
|
||||||
|
#include "target_internal.h"
|
||||||
|
#include "cortexm.h"
|
||||||
|
#include "adiv5.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define ADUCM36x_CPUID_ID 0x412FC231 // 41 = ARM; 2 = Revision; F = Always 0xF; C23 = Cortex-M3; 1 = Patch
|
||||||
|
|
||||||
|
#define ADUCM36x_SRAM_BASE 0x20000000
|
||||||
|
#define ADUCM36x_SRAM_SIZE 0x5FFFU // 8kB SRAM
|
||||||
|
#define ADUCM36x_FLASH_BASE 0x00000000
|
||||||
|
#define ADUCM36x_FLASH_SIZE 0x3FFFFU // 256kB
|
||||||
|
|
||||||
|
#define ADUCM36x_FLASH_CTRL 0x40002800
|
||||||
|
#define ADUCM36x_FLASH_FEESTA 0x0000
|
||||||
|
#define ADUCM36x_FLASH_FEECON0 0x0004
|
||||||
|
#define ADUCM36x_FLASH_FEECMD 0x0008
|
||||||
|
#define ADUCM36x_FLASH_FEEADR0L 0x0010
|
||||||
|
#define ADUCM36x_FLASH_FEEADR0H 0x0014
|
||||||
|
#define ADUCM36x_FLASH_FEEADR1L 0x0018
|
||||||
|
#define ADUCM36x_FLASH_FEEADR1H 0x001C
|
||||||
|
#define ADUCM36x_FLASH_FEEKEY 0x0020
|
||||||
|
#define ADUCM36x_FLASH_FEEPROL 0x0028
|
||||||
|
#define ADUCM36x_FLASH_FEEPROH 0x002C
|
||||||
|
#define ADUCM36x_FLASH_FEESIGL 0x0030
|
||||||
|
#define ADUCM36x_FLASH_FEESIGH 0x0034
|
||||||
|
#define ADUCM36x_FLASH_FEECON1 0x0038
|
||||||
|
#define ADUCM36x_FLASH_FEEADRAL 0x0048
|
||||||
|
#define ADUCM36x_FLASH_FEEADRAH 0x004C
|
||||||
|
#define ADUCM36x_FLASH_FEEAEN0 0x0078
|
||||||
|
#define ADUCM36x_FLASH_FEEAEN1 0x007C
|
||||||
|
#define ADUCM36x_FLASH_FEEAEN2 0x0080
|
||||||
|
|
||||||
|
#define ADUCM36x_FLASH_BLOCKSIZE 16384U
|
||||||
|
#define ADUCM36x_FLASH_PAGESIZE 2048U
|
||||||
|
#define ADUCM36x_FLASH_PAGE_MSK (0xFFFFFFFFu & ~(ADUCM36x_FLASH_PAGESIZE - 1U))
|
||||||
|
|
||||||
|
|
||||||
|
static bool aducm36x_attach(target *t);
|
||||||
|
static int aducm36x_flash_erase(struct target_flash *f, long unsigned int addr, unsigned int len);
|
||||||
|
static int aducm36x_flash_write(struct target_flash *f, long unsigned int dest, const void *src, unsigned int len);
|
||||||
|
|
||||||
|
static bool aducm36x_flash_mass_erase(target *t);
|
||||||
|
static bool aducm36x_page_erase(target *t, uint32_t paddr);
|
||||||
|
|
||||||
|
static bool aducm36x_check_flash_completion(target *t, unsigned int timeout_ms);
|
||||||
|
static bool aducm36x_set_write_enable(target *t, int enable);
|
||||||
|
static void aducm36x_flash_unlock(target *t);
|
||||||
|
|
||||||
|
|
||||||
|
static void aducm36x_add_flash(target *t) {
|
||||||
|
struct target_flash *f = calloc(1, sizeof(*f));
|
||||||
|
if (!f) { /* calloc failed: heap exhaustion */
|
||||||
|
DEBUG_WARN("calloc: failed in %s\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
f->start = ADUCM36x_FLASH_BASE;
|
||||||
|
f->length = ADUCM36x_FLASH_SIZE;
|
||||||
|
f->blocksize = ADUCM36x_FLASH_BLOCKSIZE;
|
||||||
|
f->erase = aducm36x_flash_erase;
|
||||||
|
f->write = aducm36x_flash_write;
|
||||||
|
f->erased = 0xffU;
|
||||||
|
target_add_flash(t, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool aducm36x_probe(target *t) {
|
||||||
|
/* Positively identify the target device somehow */
|
||||||
|
if (target_mem_read32(t, CORTEXM_CPUID) != ADUCM36x_CPUID_ID)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
t->driver = "Analog Device - ADuCM36x";
|
||||||
|
//t->mass_erase = aducm36x_flash_mass_erase;
|
||||||
|
t->attach = aducm36x_attach;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool aducm36x_attach(target *t) {
|
||||||
|
if (!cortexm_attach(t))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Because we are in attach, which can be called multiple times for a device, we *must*
|
||||||
|
* free any existing map before rebuilding it. Failure to do so will result in unpredictable behaviour.
|
||||||
|
*/
|
||||||
|
target_mem_map_free(t);
|
||||||
|
aducm36x_add_flash(t);
|
||||||
|
target_add_ram(t, ADUCM36x_SRAM_BASE, ADUCM36x_SRAM_SIZE);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------- */
|
||||||
|
/*
|
||||||
|
* chip erase 2.4/ 21 ms
|
||||||
|
* page erase 2.4/ 21 ms
|
||||||
|
* page programm 0.9/ 12 ms
|
||||||
|
*/
|
||||||
|
static int aducm36x_flash_erase(struct target_flash *f, long unsigned int addr, unsigned int len) {
|
||||||
|
int32_t result = true;
|
||||||
|
target *t = f->t;
|
||||||
|
DEBUG_INFO("Erase addr 0x%08" PRIx32 " len 0x%" PRIx32 "\n", addr, (uint32_t)len);
|
||||||
|
|
||||||
|
if (addr & (f->blocksize - 1U)) {
|
||||||
|
DEBUG_WARN("Unaligned erase\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((addr < f->start) || (addr >= f->start + f->length)) {
|
||||||
|
DEBUG_WARN("Address is invalid\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
addr -= f->start;
|
||||||
|
len = ALIGN(len, f->blocksize);
|
||||||
|
len = MIN(len, f->length - addr);
|
||||||
|
const bool full_erase = addr == f->start && len == f->length;
|
||||||
|
|
||||||
|
if (full_erase) {
|
||||||
|
aducm36x_flash_mass_erase(t);
|
||||||
|
} else {
|
||||||
|
while (len) {
|
||||||
|
result = aducm36x_page_erase(t, addr);
|
||||||
|
if (!result) {
|
||||||
|
DEBUG_WARN("Erase failed!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= ADUCM36x_FLASH_PAGESIZE) {
|
||||||
|
const uint32_t chunk = len & ADUCM36x_FLASH_PAGE_MSK;
|
||||||
|
len -= chunk;
|
||||||
|
addr += chunk;
|
||||||
|
} else {
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int aducm36x_flash_write(struct target_flash *f, long unsigned int dest, const void *src, unsigned int len) {
|
||||||
|
int32_t result = true;
|
||||||
|
target *t = f->t;
|
||||||
|
|
||||||
|
DEBUG_INFO("RP Write %08" PRIx32 " len 0x%" PRIx32 "\n", dest, (uint32_t)len);
|
||||||
|
if ((dest & 0xff) || (len & 0xff)) {
|
||||||
|
DEBUG_WARN("Unaligned erase\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest -= f->start;
|
||||||
|
|
||||||
|
/* Clear any old status */
|
||||||
|
target_mem_read32(t, ADUCM36x_FLASH_CTRL + ADUCM36x_FLASH_FEESTA);
|
||||||
|
|
||||||
|
/* Enable the writing to the flash*/
|
||||||
|
aducm36x_set_write_enable(t, 1);
|
||||||
|
|
||||||
|
/* Unlock for writing */
|
||||||
|
aducm36x_flash_unlock(t);
|
||||||
|
|
||||||
|
/* Use generic CortexM write function to do the work */
|
||||||
|
cortexm_mem_write_sized(t, dest, src, len, ALIGN_WORD);
|
||||||
|
|
||||||
|
/* Check the result */
|
||||||
|
result = aducm36x_check_flash_completion(t, 50);
|
||||||
|
if (result != true) {
|
||||||
|
DEBUG_WARN("flash write failed at 0x%08" PRIx32, dest);
|
||||||
|
aducm36x_set_write_enable(t, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool aducm36x_flash_mass_erase(target *t) {
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
/* Clear any old status */
|
||||||
|
target_mem_read32(t, ADUCM36x_FLASH_CTRL + ADUCM36x_FLASH_FEESTA);
|
||||||
|
|
||||||
|
/* Enable the writing to the flash*/
|
||||||
|
aducm36x_set_write_enable(t, 1);
|
||||||
|
|
||||||
|
/* Unlock for writing */
|
||||||
|
aducm36x_flash_unlock(t);
|
||||||
|
|
||||||
|
/* Issue the 'MASSERASE' command */
|
||||||
|
target_mem_write32(t, ADUCM36x_FLASH_CTRL+ADUCM36x_FLASH_FEECMD, 0x00000003);
|
||||||
|
|
||||||
|
/* Check the result */
|
||||||
|
result = aducm36x_check_flash_completion(t, 3500);
|
||||||
|
if (result != true) {
|
||||||
|
DEBUG_WARN("mass erase failed.");
|
||||||
|
aducm36x_set_write_enable(t, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool aducm36x_page_erase(target *t, uint32_t paddr) {
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
/* Clear any old status */
|
||||||
|
target_mem_read32(t, ADUCM36x_FLASH_CTRL + ADUCM36x_FLASH_FEESTA);
|
||||||
|
|
||||||
|
/* Enable the writing to the flash*/
|
||||||
|
aducm36x_set_write_enable(t, 1);
|
||||||
|
|
||||||
|
/* Unlock for writing */
|
||||||
|
aducm36x_flash_unlock(t);
|
||||||
|
|
||||||
|
/* Write the sector address */
|
||||||
|
target_mem_write32(t, ADUCM36x_FLASH_CTRL+ADUCM36x_FLASH_FEEADR0L, paddr & 0xFFFF);
|
||||||
|
target_mem_write32(t, ADUCM36x_FLASH_CTRL+ADUCM36x_FLASH_FEEADR0H, (paddr>>16) & 0xFFFF);
|
||||||
|
/* Issue the 'ERASEPAGE' command */
|
||||||
|
target_mem_write32(t, ADUCM36x_FLASH_CTRL+ADUCM36x_FLASH_FEECMD, 0x00000001);
|
||||||
|
|
||||||
|
/* Check the result */
|
||||||
|
result = aducm36x_check_flash_completion(t, 50);
|
||||||
|
if (result != true) {
|
||||||
|
DEBUG_WARN("page erase failed at 0x%08" PRIx32, paddr);
|
||||||
|
aducm36x_set_write_enable(t, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------- */
|
||||||
|
/* sets FEECON0 bit 2
|
||||||
|
* enable = 1 enables writes & erases, 0 disables them */
|
||||||
|
static bool aducm36x_set_write_enable(target *t, int enable) {
|
||||||
|
/* don't bother to preserve int enable bit here */
|
||||||
|
uint32_t value;
|
||||||
|
|
||||||
|
value = target_mem_read32(t, ADUCM36x_FLASH_CTRL + ADUCM36x_FLASH_FEECON0);
|
||||||
|
if (enable)
|
||||||
|
value |= 0x00000004;
|
||||||
|
else
|
||||||
|
value &= ~0x00000004;
|
||||||
|
target_mem_write32(t, ADUCM36x_FLASH_CTRL + ADUCM36x_FLASH_FEECON0, value);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------- */
|
||||||
|
/* wait up to timeout_ms for controller to not be busy,
|
||||||
|
* then check whether the command passed or failed. */
|
||||||
|
static bool aducm36x_check_flash_completion(target *t, unsigned int timeout_ms) {
|
||||||
|
uint32_t v = 1;
|
||||||
|
platform_timeout timeout;
|
||||||
|
|
||||||
|
platform_timeout_set(&timeout, timeout_ms);
|
||||||
|
while (1) {
|
||||||
|
v = target_mem_read32(t, ADUCM36x_FLASH_CTRL + ADUCM36x_FLASH_FEESTA);
|
||||||
|
if ((v & 0x00000001) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (platform_timeout_is_expired(&timeout))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(v & 0x00000004)) /* b2 */
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aducm36x_flash_unlock(target *t)
|
||||||
|
{
|
||||||
|
target_mem_write32(t, ADUCM36x_FLASH_CTRL + ADUCM36x_FLASH_FEEKEY, 0x0000F456);
|
||||||
|
target_mem_write32(t, ADUCM36x_FLASH_CTRL + ADUCM36x_FLASH_FEEKEY, 0x0000F123);
|
||||||
|
}
|
@ -462,6 +462,7 @@ bool cortexm_probe(ADIv5_AP_t *ap)
|
|||||||
PROBE(ch32f1_probe);
|
PROBE(ch32f1_probe);
|
||||||
PROBE(stm32f1_probe); /* Care for other STM32F1 clones (?) */
|
PROBE(stm32f1_probe); /* Care for other STM32F1 clones (?) */
|
||||||
PROBE(lpc15xx_probe); /* Thanks to JojoS for testing */
|
PROBE(lpc15xx_probe); /* Thanks to JojoS for testing */
|
||||||
|
PROBE(aducm36x_probe);
|
||||||
} else if (ap->ap_partno == 0x471) { /* Cortex-M0 ROM */
|
} else if (ap->ap_partno == 0x471) { /* Cortex-M0 ROM */
|
||||||
PROBE(lpc11xx_probe); /* LPC24C11 */
|
PROBE(lpc11xx_probe); /* LPC24C11 */
|
||||||
PROBE(lpc43xx_probe);
|
PROBE(lpc43xx_probe);
|
||||||
|
@ -198,4 +198,5 @@ bool efm32_probe(target *t);
|
|||||||
bool msp432_probe(target *t);
|
bool msp432_probe(target *t);
|
||||||
bool ke04_probe(target *t);
|
bool ke04_probe(target *t);
|
||||||
bool rp_probe(target *t);
|
bool rp_probe(target *t);
|
||||||
|
bool aducm36x_probe(target *t);
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user