From 38bc5bbf829897cd69f0a52da97783b5ad2ac86b Mon Sep 17 00:00:00 2001 From: Eivind Alexander Bergem Date: Wed, 30 Sep 2020 09:44:03 +0200 Subject: [PATCH] Add LPC546xx support #741 #553 --- src/Makefile | 1 + src/target/cortexm.c | 1 + src/target/lpc546xx.c | 232 +++++++++++++++++++++++++++++++++++ src/target/target_internal.h | 1 + 4 files changed, 235 insertions(+) create mode 100644 src/target/lpc546xx.c diff --git a/src/Makefile b/src/Makefile index 7a14e76..0644791 100644 --- a/src/Makefile +++ b/src/Makefile @@ -39,6 +39,7 @@ SRC = \ lpc17xx.c \ lpc15xx.c \ lpc43xx.c \ + lpc546xx.c \ kinetis.c \ main.c \ morse.c \ diff --git a/src/target/cortexm.c b/src/target/cortexm.c index 10ea635..840200d 100644 --- a/src/target/cortexm.c +++ b/src/target/cortexm.c @@ -411,6 +411,7 @@ bool cortexm_probe(ADIv5_AP_t *ap, bool forced) PROBE(lpc11xx_probe); PROBE(lpc15xx_probe); PROBE(lpc43xx_probe); + PROBE(lpc546xx_probe); PROBE(sam3x_probe); PROBE(sam4l_probe); PROBE(nrf51_probe); diff --git a/src/target/lpc546xx.c b/src/target/lpc546xx.c new file mode 100644 index 0000000..fff18bf --- /dev/null +++ b/src/target/lpc546xx.c @@ -0,0 +1,232 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2014 Allen Ibara + * Copyright (C) 2015 Gareth McMullin + * Copyright (C) 2020 Eivind Bergem + * + * 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 3 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 . + */ + +#include "general.h" +#include "target.h" +#include "target_internal.h" +#include "cortexm.h" +#include "lpc_common.h" + +#define LPC546XX_CHIPID 0x40000FF8 + +#define IAP_ENTRYPOINT_LOCATION 0x03000204 + +#define LPC546XX_ETBAHB_SRAM_BASE 0x20000000 +#define LPC546XX_ETBAHB_SRAM_SIZE (160*1024) + +#define LPC546XX_WDT_MODE 0x4000C000 +#define LPC546XX_WDT_CNT 0x4000C004 +#define LPC546XX_WDT_FEED 0x4000C008 +#define LPC546XX_WDT_PERIOD_MAX 0xFFFFFF +#define LPC546XX_WDT_PROTECT (1 << 4) + +#define IAP_RAM_SIZE LPC546XX_ETBAHB_SRAM_SIZE +#define IAP_RAM_BASE LPC546XX_ETBAHB_SRAM_BASE + +#define IAP_PGM_CHUNKSIZE 4096 + +#define FLASH_NUM_SECTOR 15 + +static bool lpc546xx_cmd_erase(target *t, int argc, const char *argv[]); +static bool lpc546xx_cmd_reset(target *t, int argc, const char *argv[]); +static int lpc546xx_flash_init(target *t); +static int lpc546xx_flash_erase(struct target_flash *f, target_addr addr, size_t len); +static void lpc546xx_set_internal_clock(target *t); +static void lpc546xx_wdt_set_period(target *t); +static void lpc546xx_wdt_pet(target *t); + +const struct command_s lpc546xx_cmd_list[] = { + {"erase_mass", lpc546xx_cmd_erase, "Erase entire flash memory"}, + {"reset", lpc546xx_cmd_reset, "Reset target"}, + {NULL, NULL, NULL} +}; + +void lpc546xx_add_flash(target *t, uint32_t iap_entry, + uint8_t base_sector, uint32_t addr, + size_t len, size_t erasesize) +{ + struct lpc_flash *lf = lpc_add_flash(t, addr, len); + lf->f.erase = lpc546xx_flash_erase; + lf->f.blocksize = erasesize; + lf->f.buf_size = IAP_PGM_CHUNKSIZE; + lf->bank = 0; + lf->base_sector = base_sector; + lf->iap_entry = iap_entry; + lf->iap_ram = IAP_RAM_BASE; + lf->iap_msp = IAP_RAM_BASE + IAP_RAM_SIZE; + lf->wdt_kick = lpc546xx_wdt_pet; +} + +bool lpc546xx_probe(target *t) +{ + uint32_t chipid; + uint32_t iap_entry; + uint32_t flash_size; + + chipid = target_mem_read32(t, LPC546XX_CHIPID); + + switch(chipid) { + case 0x7F954605: + t->driver = "LPC54605J256"; + flash_size = 0x40000; + break; + case 0x7F954606: + t->driver = "LPC54606J256"; + flash_size = 0x40000; + break; + case 0x7F954607: + t->driver = "LPC54607J256"; + flash_size = 0x40000; + break; + case 0x7F954616: + t->driver = "LPC54616J256"; + flash_size = 0x40000; + break; + case 0xFFF54605: + t->driver = "LPC54605J512"; + flash_size = 0x80000; + break; + case 0xFFF54606: + t->driver = "LPC54606J512"; + flash_size = 0x80000; + break; + case 0xFFF54607: + t->driver = "LPC54607J512"; + flash_size = 0x80000; + break; + case 0xFFF54608: + t->driver = "LPC54608J512"; + flash_size = 0x80000; + break; + case 0xFFF54616: + t->driver = "LPC54616J512"; + flash_size = 0x80000; + break; + case 0xFFF54618: + t->driver = "LPC54618J512"; + flash_size = 0x80000; + break; + case 0xFFF54628: + t->driver = "LPC54628J512"; + flash_size = 0x80000; + break; + default: + return false; + } + + iap_entry = target_mem_read32(t, + IAP_ENTRYPOINT_LOCATION); + lpc546xx_add_flash(t, iap_entry, 0, 0x0, + flash_size, 0x8000); + target_add_ram(t, 0x20000000, 0x28000); + target_add_commands(t, lpc546xx_cmd_list, "Lpc546xx"); + t->target_options |= CORTEXM_TOPT_INHIBIT_SRST; + + return false; +} + +/* Reset all major systems _except_ debug */ +static bool lpc546xx_cmd_reset(target *t, int argc, const char *argv[]) +{ + (void)argc; + (void)argv; + + /* Cortex-M4 Application Interrupt and Reset Control Register */ + static const uint32_t AIRCR = 0xE000ED0C; + /* Magic value key */ + static const uint32_t reset_val = 0x05FA0004; + + /* System reset on target */ + target_mem_write(t, AIRCR, &reset_val, sizeof(reset_val)); + + return true; +} + +static bool lpc546xx_cmd_erase(target *t, int argc, const char *argv[]) +{ + (void)argc; + (void)argv; + + lpc546xx_flash_init(t); + struct lpc_flash *f = (struct lpc_flash *)t->flash; + + if (lpc_iap_call(f, NULL, IAP_CMD_PREPARE, 0, FLASH_NUM_SECTOR-1)) + return false; + + if (lpc_iap_call(f, NULL, IAP_CMD_ERASE, 0, FLASH_NUM_SECTOR-1, CPU_CLK_KHZ)) + return false; + + tc_printf(t, "Erase OK.\n"); + + return true; +} + +static int lpc546xx_flash_init(target *t) +{ + /* Deal with WDT */ + lpc546xx_wdt_set_period(t); + + /* /\* Force internal clock *\/ */ + lpc546xx_set_internal_clock(t); + + /* Initialize flash IAP */ + struct lpc_flash *f = (struct lpc_flash *)t->flash; + if (lpc_iap_call(f, NULL, IAP_CMD_INIT)) + return -1; + + return 0; +} + +static int lpc546xx_flash_erase(struct target_flash *tf, target_addr addr, size_t len) +{ + if (lpc546xx_flash_init(tf->t)) + return -1; + + return lpc_flash_erase(tf, addr, len); +} + +static void lpc546xx_set_internal_clock(target *t) +{ + /* Switch to 12 Mhz FRO */ + target_mem_write32(t, 0x40000000 + 0x248, 0); +} + +static void lpc546xx_wdt_set_period(target *t) +{ + /* Check if WDT is on */ + uint32_t wdt_mode = target_mem_read32(t, LPC546XX_WDT_MODE); + + /* If WDT on, we can't disable it, but we may be able to set a long period */ + if (wdt_mode && !(wdt_mode & LPC546XX_WDT_PROTECT)) + target_mem_write32(t, LPC546XX_WDT_CNT, LPC546XX_WDT_PERIOD_MAX); +} + +static void lpc546xx_wdt_pet(target *t) +{ + /* Check if WDT is on */ + uint32_t wdt_mode = target_mem_read32(t, LPC546XX_WDT_MODE); + + /* If WDT on, pet */ + if (wdt_mode) { + target_mem_write32(t, LPC546XX_WDT_FEED, 0xAA); + target_mem_write32(t, LPC546XX_WDT_FEED, 0xFF); + } +} diff --git a/src/target/target_internal.h b/src/target/target_internal.h index 7aa2c8a..c2288af 100644 --- a/src/target/target_internal.h +++ b/src/target/target_internal.h @@ -178,6 +178,7 @@ bool lpc11xx_probe(target *t); bool lpc15xx_probe(target *t); bool lpc17xx_probe(target *t); bool lpc43xx_probe(target *t); +bool lpc546xx_probe(target *t); bool sam3x_probe(target *t); bool sam4l_probe(target *t); bool nrf51_probe(target *t);