From d5bf59152f68aed714b90b0e34a019e686a825f6 Mon Sep 17 00:00:00 2001 From: JackCarterSmith Date: Sun, 8 Jan 2023 15:49:59 +0100 Subject: [PATCH] ADuCM36x experimental support --- src/Makefile | 3 +- src/target/aducm36x.c | 300 +++++++++++++++++++++++++++++++++++ src/target/cortexm.c | 1 + src/target/target_internal.h | 1 + 4 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 src/target/aducm36x.c diff --git a/src/Makefile b/src/Makefile index 472b1abc..5bc65c00 100644 --- a/src/Makefile +++ b/src/Makefile @@ -20,6 +20,7 @@ SRC = \ adiv5.c \ adiv5_jtagdp.c \ adiv5_swdp.c \ + aducm36x.c \ command.c \ cortexa.c \ cortexm.c \ @@ -65,7 +66,7 @@ SRC = \ include $(PLATFORM_DIR)/Makefile.inc -OPT_FLAGS ?= -Os +OPT_FLAGS ?= -Os -nolibc CFLAGS += $(OPT_FLAGS) LDFLAGS += $(OPT_FLAGS) diff --git a/src/target/aducm36x.c b/src/target/aducm36x.c new file mode 100644 index 00000000..73b00312 --- /dev/null +++ b/src/target/aducm36x.c @@ -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); +} diff --git a/src/target/cortexm.c b/src/target/cortexm.c index 7452b29b..346a6c0a 100644 --- a/src/target/cortexm.c +++ b/src/target/cortexm.c @@ -462,6 +462,7 @@ bool cortexm_probe(ADIv5_AP_t *ap) PROBE(ch32f1_probe); PROBE(stm32f1_probe); /* Care for other STM32F1 clones (?) */ PROBE(lpc15xx_probe); /* Thanks to JojoS for testing */ + PROBE(aducm36x_probe); } else if (ap->ap_partno == 0x471) { /* Cortex-M0 ROM */ PROBE(lpc11xx_probe); /* LPC24C11 */ PROBE(lpc43xx_probe); diff --git a/src/target/target_internal.h b/src/target/target_internal.h index b92e1411..732185fa 100644 --- a/src/target/target_internal.h +++ b/src/target/target_internal.h @@ -198,4 +198,5 @@ bool efm32_probe(target *t); bool msp432_probe(target *t); bool ke04_probe(target *t); bool rp_probe(target *t); +bool aducm36x_probe(target *t); #endif