From 0aef6c677418772247eb830d5344a48860ecf2d7 Mon Sep 17 00:00:00 2001 From: Chuck McManis Date: Sun, 20 Nov 2016 14:15:58 -0800 Subject: [PATCH 1/4] SAM4L: Add extended reset to target interface This adds a new function to the internal target interface to allow the target to get control before reset is complete so that it can do any additional work. On this target there is a proprietary internal bit that has to be reset in some cases to allow the core to continue operating. --- src/Makefile | 1 + src/gdb_main.c | 4 +- src/platforms/common/swdptap.c | 6 + src/target/cortexm.c | 6 + src/target/cortexm.h | 1 + src/target/sam4l.c | 407 +++++++++++++++++++++++++++++++++ src/target/target_internal.h | 2 + 7 files changed, 426 insertions(+), 1 deletion(-) create mode 100644 src/target/sam4l.c diff --git a/src/Makefile b/src/Makefile index 666c0806..8bc2659d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -48,6 +48,7 @@ SRC = \ nrf51.c \ platform.c \ sam3x.c \ + sam4l.c \ samd.c \ stm32f1.c \ stm32f4.c \ diff --git a/src/gdb_main.c b/src/gdb_main.c index 6e9e9583..d41d6053 100644 --- a/src/gdb_main.c +++ b/src/gdb_main.c @@ -96,7 +96,9 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall) int size; bool single_step = false; - DEBUG("Entring GDB protocol main loop\n"); + /* + DEBUG("Entering GDB protocol main loop\n"); + */ /* GDB protocol main loop */ while(1) { SET_IDLE_STATE(1); diff --git a/src/platforms/common/swdptap.c b/src/platforms/common/swdptap.c index bcc3ccb3..c7c48ac5 100644 --- a/src/platforms/common/swdptap.c +++ b/src/platforms/common/swdptap.c @@ -36,7 +36,9 @@ static void swdptap_turnaround(uint8_t dir) if(dir == olddir) return; olddir = dir; +#if 0 DEBUG("%s", dir ? "\n-> ":"\n<- "); +#endif if(dir) SWDIO_MODE_FLOAT(); @@ -56,14 +58,18 @@ bool swdptap_bit_in(void) gpio_set(SWCLK_PORT, SWCLK_PIN); gpio_clear(SWCLK_PORT, SWCLK_PIN); +#if 0 DEBUG("%d", ret?1:0); +#endif return ret != 0; } void swdptap_bit_out(bool val) { +#if 0 DEBUG("%d", val); +#endif swdptap_turnaround(0); diff --git a/src/target/cortexm.c b/src/target/cortexm.c index 96c8fded..7e587a46 100644 --- a/src/target/cortexm.c +++ b/src/target/cortexm.c @@ -262,6 +262,7 @@ bool cortexm_probe(ADIv5_AP_t *ap) PROBE(lpc15xx_probe); PROBE(lpc43xx_probe); PROBE(sam3x_probe); + PROBE(sam4l_probe); PROBE(nrf51_probe); PROBE(samd_probe); PROBE(lmi_probe); @@ -442,6 +443,11 @@ static void cortexm_reset(target *t) target_mem_write32(t, CORTEXM_AIRCR, CORTEXM_AIRCR_VECTKEY | CORTEXM_AIRCR_SYSRESETREQ); + /* If target needs to do something extra (see Atmel SAM4L for example) */ + if ((t->target_options & CORTEXM_TOPT_EXTENDED_RESET) != 0) { + t->extended_reset(t); + } + /* Poll for release from reset */ while (target_mem_read32(t, CORTEXM_DHCSR) & CORTEXM_DHCSR_S_RESET_ST); diff --git a/src/target/cortexm.h b/src/target/cortexm.h index bf1d821d..7d42f193 100644 --- a/src/target/cortexm.h +++ b/src/target/cortexm.h @@ -155,6 +155,7 @@ #define ARM_THUMB_BREAKPOINT 0xBE00 #define CORTEXM_TOPT_INHIBIT_SRST (1 << 2) +#define CORTEXM_TOPT_EXTENDED_RESET (1 << 3) bool cortexm_probe(ADIv5_AP_t *ap); ADIv5_AP_t *cortexm_ap(target *t); diff --git a/src/target/sam4l.c b/src/target/sam4l.c new file mode 100644 index 00000000..1b1eb81a --- /dev/null +++ b/src/target/sam4l.c @@ -0,0 +1,407 @@ +/* + * vim: set noexpandtab ts=4: + * + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2016 Chuck McManis + * + * 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 . + */ + +/* This file implements Atmel SAM4 target specific functions for detecting + * the device, providing the XML memory map and Flash memory programming. + * + * Supported devices: SAM4L2, SAM4L4, SAM4L8 + */ + +#include "general.h" +#include "target.h" +#include "target_internal.h" +#include "cortexm.h" + +/* + * Flash Controller defines + */ +#define FLASHCALW_BASE 0x400A0000 + +/* Flash Control Register */ +#define FLASHCALW_FCR (FLASHCALW_BASE + 0x00) +#define FLASHALCW_FCR_WS1OPT (1 << 7) +#define FLASHALCW_FCR_FWS (1 << 6) +#define FLASHALCW_FCR_ECCE (1 << 4) +#define FLASHALCW_FCR_PROGE (1 << 3) +#define FLASHALCW_FCR_LOCKE (1 << 2) +#define FLASHALCW_FCR_FRDY (1 << 0) + +/* Flash Command Register */ +#define FLASHCALW_FCMD (FLASHCALW_BASE + 0x04) +#define FLASHCALW_FCMD_KEY_MASK 0xff +#define FLASHCALW_FCMD_KEY_SHIFT 24 +#define FLASHCALW_FCMD_PAGEN_MASK 0xffff +#define FLASHCALW_FCMD_PAGEN_SHIFT 8 +#define FLASHCALW_FCMD_CMD_MASK 0x3f +#define FLASHCALW_FCMD_CMD_SHIFT 0 + +#define FLASH_CMD_NOP 0 +#define FLASH_CMD_WP 1 /* Write Page */ +#define FLASH_CMD_EP 2 /* Erase Page */ +#define FLASH_CMD_CPB 3 /* Clear Page Buffer */ +#define FLASH_CMD_LP 4 /* Lock page region */ +#define FLASH_CMD_UP 5 /* Unlock page region */ +#define FLASH_CMD_EA 6 /* Erase All */ +#define FLASH_CMD_WGPB 7 /* Write General Purpose Fuse Bit */ +#define FLASH_CMD_EGPB 8 /* Erase General Purpose Fuse Bit */ +#define FLASH_CMD_SSB 9 /* Set Security Fuses */ +#define FLASH_CMD_PGPFB 10 /* Program General Purpose Fuse Byte */ +#define FLASH_CMD_EAGPF 11 /* Erase All GP Fuses */ +#define FLASH_CMD_QPR 12 /* Quick Page Read (erase check) */ +#define FLASH_CMD_WUP 13 /* Write User Page */ +#define FLASH_CMD_EUP 14 /* Erase User Page */ +#define FLASH_CMD_QPRUP 15 /* Quick Page Read User Page */ +#define FLASH_CMD_HSEN 16 /* High Speed Enable */ +#define FLASH_CMD_HSDIS 17 /* High Speed Disable */ + +/* Flash Status Register */ +#define FLASHCALW_FSR (FLASHCALW_BASE + 0x08) +#define FLASHCALW_FSR_LOCK(x) (1 << (16 + (x))) +#define FLASHCALW_FSR_ECCERR (1 << 9) +#define FLASHCALW_FSR_ECCERR2 (1 << 8) +#define FLASHCALW_FSR_HSMODE (1 << 6) +#define FLASHCALW_FSR_QPRR (1 << 5) +#define FLASHCALW_FSR_SECURITY (1 << 4) +#define FLASHCALW_FSR_PROGE (1 << 3) +#define FLASHCALW_FSR_LOCKE (1 << 2) +#define FLASHCALW_FSR_FRDY (1 << 0) + +/* Flash Parameter Register */ +#define FLASHCALW_FPR (FLASHCALW_BASE + 0x0a) +#define FLASHCALW_FPR_PSZ_MASK 0x7 /* page size */ +#define FLASHCALW_FPR_PSZ_SHIFT 8 +#define FLASHCALW_FPR_FSZ_MASK 0xf /* flash size */ +#define FLASHCALW_FPR_FSZ_SHIFT 0 + +/* Flash Version Register */ +#define FLASHCALW_FVR (FLASHCALW_BASE + 0x10) +#define FLASHCALW_FVR_VARIANT_MASK 0xf +#define FLASHCALW_FVR_VARIANT_SHIFT 16 +#define FLASHCALW_FVR_VERSION_MASK 0xfff +#define FLASHCALW_FVR_VERSION_SHIFT 0 + +/* Flash General Purpose Registers (high) */ +#define FLASHCALW_FGPFRHI (FLASHCALW_BASE + 0x14) +/* Flash General Purpose Registers (low) */ +#define FLASHCALW_FGPFRLO (FLASHCALW_BASE + 0x18) + +static int sam4_flash_erase(struct target_flash *f, target_addr addr, size_t len); +int sam4_flash_write(struct target_flash *f, target_addr dest, + const void *src, size_t len); + +const struct command_s sam4l_cmds[] = { + {NULL, NULL, NULL} +}; + +/* why Atmel couldn't make it sequential ... */ +static const size_t __ram_size[16] = { + 48 * 1024, /* 0: 48K */ + 1 * 1024, /* 1: 1K */ + 2 * 1024, /* 2: 2K */ + 6 * 1024, /* 3: 6K */ + 24 * 1024, /* 4: 24K */ + 4 * 1024, /* 5: 4K */ + 80 * 1024, /* 6: 80K */ + 160 * 1024, /* 7: 160K */ + 8 * 1024, /* 8: 8K */ + 16 * 1024, /* 9: 16K */ + 32 * 1024, /* 10: 32K */ + 64 * 1024, /* 11: 64K */ + 128 * 1024, /* 12: 128K */ + 256 * 1024, /* 13: 256K */ + 96 * 1024, /* 14: 96K */ + 512 * 1024 /* 15: 512K */ +}; + +static const size_t __nvp_size[16] = { + 0, /* 0: none */ + 8 * 1024, /* 1: 8K */ + 16 * 1024, /* 2: 16K */ + 32 * 1024, /* 3: 32K */ + 0, /* 4: reserved */ + 64 * 1024, /* 5: 64K */ + 0, /* 6: reserved */ + 128 * 1024, /* 7: 128K */ + 0, /* 8: reserved */ + 256 * 1024, /* 9: 256K */ + 512 * 1024, /* 10: 512K */ + 0, /* 11: reserved */ + 1024 * 1024, /* 12: 1024K (1M) */ + 0, /* 13: reserved */ + 2048 * 1024, /* 14: 2048K (2M) */ + 0 /* 15: reserved */ +}; + + +#define SAM4L_PAGE_SIZE 512 +#define SAM4L_ARCH 0xb0 +#define SAM4L_CHIPID_CIDR 0x400E0740 +#define CHIPID_CIDR_ARCH_MASK 0xff +#define CHIPID_CIDR_ARCH_SHIFT 20 +#define CHIPID_CIDR_SRAMSIZ_MASK 0xf +#define CHIPID_CIDR_SRAMSIZ_SHIFT 16 +#define CHIPID_CIDR_NVPSIZ_MASK 0xf +#define CHIPID_CIDR_NVPSIZ_SHIFT 8 + +/* All variants of 4L have a 512 byte page */ +#define SAM4_PAGE_SIZE 512 + +/* Arbitrary time to wait for FLASH controller to be ready */ +#define FLASH_TIMEOUT 10000 + +/* + * Populate a target_flash struct with the necessary function pointers + * and constants to describe our flash. + */ +static void sam4_add_flash(target *t, uint32_t addr, size_t length) +{ + struct target_flash *f = calloc(1, sizeof(struct target_flash)); + f->start = addr; + f->length = length; + f->blocksize = 512; + f->erase = sam4_flash_erase; + f->write = target_flash_write_buffered; + f->done = target_flash_done_buffered; + f->write_buf = sam4_flash_write; + f->buf_size = 512;; + f->align = 512; + f->erased = 0xff; + /* add it into the target structures flash chain */ + target_add_flash(t, f); +} + +/* Return size of RAM */ +static size_t sam_ram_size(uint32_t idcode) { + return __ram_size[((idcode >> CHIPID_CIDR_SRAMSIZ_SHIFT) & CHIPID_CIDR_SRAMSIZ_MASK)]; +} + +/* Return size of FLASH */ +static size_t sam_nvp_size(uint32_t idcode) { + return __nvp_size[((idcode >> CHIPID_CIDR_NVPSIZ_SHIFT) & CHIPID_CIDR_NVPSIZ_MASK)]; +} + +#define SMAP_BASE 0x400a3000 +#define SMAP_CR (SMAP_BASE + 0x00) +#define SMAP_SR (SMAP_BASE + 0x04) +#define SMAP_SR_DONE (1 << 0) +#define SMAP_SR_HCR (1 << 1) +#define SMAP_SR_BERR (1 << 2) +#define SMAP_SR_FAIL (1 << 3) +#define SMAP_SR_LCK (1 << 4) +#define SMAP_SR_EN (1 << 8) +#define SMAP_SR_PROT (1 << 9) +#define SMAP_SR_DBGP (1 << 10) + + +#define SMAP_SCR (SMAP_BASE + 0x08) +#define SMAP_ADDR (SMAP_BASE + 0x0c) +#define SMAP_LEN (SMAP_BASE + 0x10) +#define SMAP_DATA (SMAP_BASE + 0x14) +#define SMAP_VERS (SMAP_BASE + 0x28) +#define SMAP_CHIPID (SMAP_BASE + 0xf0) +#define SMAP_EXTID (SMAP_BASE + 0xf4) +#define SMAP_IDR (SMAP_BASE + 0xfc) + +static void sam4l_reset(target *t); + +/* + * The probe function, look where the CIDR register should be, see if + * it matches the SAM4L architecture code. + * + * Figure out from the register how much RAM and FLASH this variant has. + */ +bool sam4l_probe(target *t) +{ + uint32_t reg; + size_t ram_size, flash_size; + + DEBUG("\nSAM4L: Probe function called\n"); + t->idcode = target_mem_read32(t, SAM4L_CHIPID_CIDR); + if (((t->idcode >> CHIPID_CIDR_ARCH_SHIFT) & CHIPID_CIDR_ARCH_MASK) == SAM4L_ARCH) { + t->driver = "Atmel SAM4L"; +/* Check to see if our extended reset will fix this */ + t->target_options |= CORTEXM_TOPT_INHIBIT_SRST; + t->target_options |= CORTEXM_TOPT_EXTENDED_RESET; + t->extended_reset = sam4l_reset; + ram_size = sam_ram_size(t->idcode); + target_add_ram(t, 0x20000000, ram_size); + flash_size = sam_nvp_size(t->idcode); + sam4_add_flash(t, 0x0, flash_size); + DEBUG("\nSAM4L: RAM = 0x%x (%dK), FLASH = 0x%x (%dK)\n", + ram_size, ram_size / 1024, flash_size, flash_size / 1024); + + target_mem_write32(t, SMAP_CR, 0x1); /* enable SMAP */ + DEBUG("\nSAM4L: SMAP Enabled\n"); + DEBUG("\nSAM4L: Orig CHIPID = 0x%08lx\n", t->idcode); + reg = target_mem_read32(t, SMAP_CHIPID); + DEBUG("\nSAM4L: SMAP CHIPID = 0x%08lx\n", reg); + reg = target_mem_read32(t, SMAP_SR); + DEBUG("\nSAM4L: SMAP is %s\n", (reg & SMAP_SR_EN) ? "Enabled" : "Disabled"); + DEBUG("\nSAM4L: Debugger is %s\n", (reg & SMAP_SR_DBGP) ? "Present" : "Not Present"); + DEBUG("\nSAM4L: Core is %s\n", (reg & SMAP_SR_HCR) ? "In Reset" : "Running"); + sam4l_reset(t); + reg = target_mem_read32(t, SMAP_SR); + DEBUG("\nSAM4L: Core is %s\n", (reg & SMAP_SR_HCR) ? "In Reset" : "Running"); + + DEBUG("\nSAM4L: SAM4L Selected.\n"); + if (target_check_error(t)) { + DEBUG("SAM4L: target_check_error returned true\n"); + } + return true; + } + return false; +} + +/* + * We've been reset, make sure we take the core out of reset + */ +void +sam4l_reset(target *t) +{ + uint32_t reg; + int i; + + DEBUG("SAM4L: Extended Reset\n"); + reg = target_mem_read32(t, SMAP_SR); + DEBUG("\nSAM4L: SMAP_SR has 0x%08lx\n", reg); + if ((reg & SMAP_SR_HCR) != 0) { + target_mem_write32(t, SMAP_SCR, SMAP_SR_HCR); + i = 0; + do { + reg = target_mem_read32(t, SMAP_SR); + i++; + } while (((reg & SMAP_SR_HCR) != 0) && (i < 100)); + if (i == 100) { + DEBUG("\nSAM4L: Reset failed. SMAP_SR has 0x%08lx\n", reg); + } + } + target_check_error(t); +} + +/* + * sam4_flash_command + * + * Helper function, wait for the flash controller to be ready to receive a + * command. Then send it the command, page number, and the authorization + * key (always 0xA5) in the command register. + * + * Need the target struct to call the mem_read32 and mem_write32 function + * pointers. + */ +static int +sam4_flash_command(target *t, uint32_t page, uint32_t cmd) +{ + uint32_t cmd_reg; + uint32_t status; + int timeout; + DEBUG("\nSAM4L: sam4_flash_command: FSR: 0x%08x, page = %d, command = %d\n", + (unsigned int)(FLASHCALW_FSR), (int) page, (int) cmd); + for (timeout = 0; timeout < FLASH_TIMEOUT; timeout++) { + status = target_mem_read32(t, FLASHCALW_FSR); + if (status & FLASHCALW_FSR_FRDY) { + break; + } + } + if (timeout == FLASH_TIMEOUT) { + DEBUG("\nSAM4L: sam4_flash_command: Not ready! Status = 0x%08x\n", (unsigned int) status); + return -1; /* Failed */ + } + cmd_reg = (cmd & FLASHCALW_FCMD_CMD_MASK) | + ((page & FLASHCALW_FCMD_PAGEN_MASK) << FLASHCALW_FCMD_PAGEN_SHIFT) | + (0xA5 << FLASHCALW_FCMD_KEY_SHIFT); + DEBUG("\nSAM4L: sam4_flash_command: Wrting command word 0x%08x\n", (unsigned int) cmd_reg); + target_mem_write32(t, FLASHCALW_FCMD, cmd_reg); + return 0; +} + +/* + * Write data from 'src' into flash using the algorithim provided by + * Atmel in their data sheet. + */ +int +sam4_flash_write(struct target_flash *f, target_addr addr, const void *src, size_t len) +{ + target *t = f->t; + uint32_t *src_data = (uint32_t *)src; + uint16_t page; + + DEBUG("\nSAM4L: sam4_flash_write: addr = 0x%08lx, len %d\n", addr, len); + /* This will fail with unaligned writes */ + while (len) { + + page = addr / SAM4L_PAGE_SIZE; + /* clear the page buffer */ + if (sam4_flash_command(t, 0, FLASH_CMD_CPB)) { + return -1; + } + /* Fill it with data to write */ + target_mem_write(t, addr, src_data, SAM4L_PAGE_SIZE); +#if 0 + for (ndx = 0; ndx < SAM4L_PAGE_SIZE; ndx += 4) { +/* + target_mem_write32(t, addr, *src_data); + addr += 4; +*/ + /* + * the page buffer overlaps flash, its only 512 bytes long + * and no matter where you write it from it goes to the page + * you point it to. So we don't need the specific address here + * instead we just write 0 - pagelen (512) and that fills our + * buffer correctly. + */ + target_mem_write32(t, addr+ndx, *src_data); + src_data++; + } +#endif + /* write the page */ + if (sam4_flash_command(t, page, FLASH_CMD_WP)) { + return -1; + } + len -= SAM4L_PAGE_SIZE; + addr += SAM4L_PAGE_SIZE; + } + return 0; +} + +/* + * Erase flash across the addresses specified by addr and len + */ +static int +sam4_flash_erase(struct target_flash *f, target_addr addr, size_t len) +{ + target *t = f->t; + uint16_t page; + + DEBUG("SAM4L: flash erase address 0x%08x for %d bytes\n", + (unsigned int) addr, (unsigned int) len); + /* force len to be an integral number of pages */ + /* len = (len + (SAM4_PAGE_SIZE - 1)) & ~SAM4_PAGE_SIZE; */ + + while (len) { + page = addr / SAM4_PAGE_SIZE; + if (sam4_flash_command(t, page, FLASH_CMD_EP)) { + return -1; + } + len -= SAM4_PAGE_SIZE; + addr += SAM4_PAGE_SIZE; + } + return 0; +} diff --git a/src/target/target_internal.h b/src/target/target_internal.h index 75bd743b..33f16632 100644 --- a/src/target/target_internal.h +++ b/src/target/target_internal.h @@ -99,6 +99,7 @@ struct target_s { /* Halt/resume functions */ void (*reset)(target *t); + void (*extended_reset)(target *t); void (*halt_request)(target *t); enum target_halt_reason (*halt_poll)(target *t, target_addr *watch); void (*halt_resume)(target *t, bool step); @@ -176,6 +177,7 @@ bool lpc11xx_probe(target *t); bool lpc15xx_probe(target *t); bool lpc43xx_probe(target *t); bool sam3x_probe(target *t); +bool sam4l_probe(target *t); bool nrf51_probe(target *t); bool samd_probe(target *t); bool kinetis_probe(target *t); From 469ecbf0f9b4cbf4d0b304dddd146343cb4e4ea7 Mon Sep 17 00:00:00 2001 From: Chuck McManis Date: Thu, 1 Dec 2016 23:45:57 -0800 Subject: [PATCH 2/4] SAM4L: Add target driver for SAM4L This commit adds a target driver for SAM4L and it depends on the extended reset change. --- src/target/sam4l.c | 117 +++++++++++++++++++++++---------------------- 1 file changed, 60 insertions(+), 57 deletions(-) diff --git a/src/target/sam4l.c b/src/target/sam4l.c index 1b1eb81a..9071d9f4 100644 --- a/src/target/sam4l.c +++ b/src/target/sam4l.c @@ -103,8 +103,9 @@ /* Flash General Purpose Registers (low) */ #define FLASHCALW_FGPFRLO (FLASHCALW_BASE + 0x18) -static int sam4_flash_erase(struct target_flash *f, target_addr addr, size_t len); -int sam4_flash_write(struct target_flash *f, target_addr dest, +static void sam4l_extended_reset(target *t); +static int sam4l_flash_erase(struct target_flash *f, target_addr addr, size_t len); +static int sam4l_flash_write_buf(struct target_flash *f, target_addr dest, const void *src, size_t len); const struct command_s sam4l_cmds[] = { @@ -171,18 +172,17 @@ static const size_t __nvp_size[16] = { * Populate a target_flash struct with the necessary function pointers * and constants to describe our flash. */ -static void sam4_add_flash(target *t, uint32_t addr, size_t length) +static void sam4l_add_flash(target *t, uint32_t addr, size_t length) { struct target_flash *f = calloc(1, sizeof(struct target_flash)); f->start = addr; f->length = length; f->blocksize = 512; - f->erase = sam4_flash_erase; + f->erase = sam4l_flash_erase; f->write = target_flash_write_buffered; f->done = target_flash_done_buffered; - f->write_buf = sam4_flash_write; + f->write_buf = sam4l_flash_write_buf; f->buf_size = 512;; - f->align = 512; f->erased = 0xff; /* add it into the target structures flash chain */ target_add_flash(t, f); @@ -220,7 +220,6 @@ static size_t sam_nvp_size(uint32_t idcode) { #define SMAP_EXTID (SMAP_BASE + 0xf4) #define SMAP_IDR (SMAP_BASE + 0xfc) -static void sam4l_reset(target *t); /* * The probe function, look where the CIDR register should be, see if @@ -230,37 +229,29 @@ static void sam4l_reset(target *t); */ bool sam4l_probe(target *t) { - uint32_t reg; size_t ram_size, flash_size; DEBUG("\nSAM4L: Probe function called\n"); t->idcode = target_mem_read32(t, SAM4L_CHIPID_CIDR); if (((t->idcode >> CHIPID_CIDR_ARCH_SHIFT) & CHIPID_CIDR_ARCH_MASK) == SAM4L_ARCH) { t->driver = "Atmel SAM4L"; -/* Check to see if our extended reset will fix this */ +#ifdef SAM4_DISABLE_SRST + /* Check to see if our extended reset will fix this */ t->target_options |= CORTEXM_TOPT_INHIBIT_SRST; +#endif + /* this option says we need to do "extra" stuff after reset */ t->target_options |= CORTEXM_TOPT_EXTENDED_RESET; - t->extended_reset = sam4l_reset; + t->extended_reset = sam4l_extended_reset; ram_size = sam_ram_size(t->idcode); target_add_ram(t, 0x20000000, ram_size); flash_size = sam_nvp_size(t->idcode); - sam4_add_flash(t, 0x0, flash_size); + sam4l_add_flash(t, 0x0, flash_size); DEBUG("\nSAM4L: RAM = 0x%x (%dK), FLASH = 0x%x (%dK)\n", - ram_size, ram_size / 1024, flash_size, flash_size / 1024); + (unsigned int) ram_size, (unsigned int) (ram_size / 1024), + (unsigned int) flash_size, (unsigned int)(flash_size / 1024)); - target_mem_write32(t, SMAP_CR, 0x1); /* enable SMAP */ - DEBUG("\nSAM4L: SMAP Enabled\n"); - DEBUG("\nSAM4L: Orig CHIPID = 0x%08lx\n", t->idcode); - reg = target_mem_read32(t, SMAP_CHIPID); - DEBUG("\nSAM4L: SMAP CHIPID = 0x%08lx\n", reg); - reg = target_mem_read32(t, SMAP_SR); - DEBUG("\nSAM4L: SMAP is %s\n", (reg & SMAP_SR_EN) ? "Enabled" : "Disabled"); - DEBUG("\nSAM4L: Debugger is %s\n", (reg & SMAP_SR_DBGP) ? "Present" : "Not Present"); - DEBUG("\nSAM4L: Core is %s\n", (reg & SMAP_SR_HCR) ? "In Reset" : "Running"); - sam4l_reset(t); - reg = target_mem_read32(t, SMAP_SR); - DEBUG("\nSAM4L: Core is %s\n", (reg & SMAP_SR_HCR) ? "In Reset" : "Running"); - + /* enable SMAP if not, check for HCR and reset if set */ + sam4l_extended_reset(t); DEBUG("\nSAM4L: SAM4L Selected.\n"); if (target_check_error(t)) { DEBUG("SAM4L: target_check_error returned true\n"); @@ -274,30 +265,34 @@ bool sam4l_probe(target *t) * We've been reset, make sure we take the core out of reset */ void -sam4l_reset(target *t) +sam4l_extended_reset(target *t) { uint32_t reg; int i; DEBUG("SAM4L: Extended Reset\n"); + /* enable SMAP in case we're dealing with a non-TCK SRST */ + target_mem_write32(t, SMAP_CR, 0x1); /* enable SMAP */ reg = target_mem_read32(t, SMAP_SR); - DEBUG("\nSAM4L: SMAP_SR has 0x%08lx\n", reg); + DEBUG("\nSAM4L: SMAP_SR has 0x%08lx\n", (long unsigned int) reg); if ((reg & SMAP_SR_HCR) != 0) { + /* write '1' bit to the status clear register */ target_mem_write32(t, SMAP_SCR, SMAP_SR_HCR); - i = 0; - do { + /* waiting 250 loops for it to reset is arbitrary, it should happen right away */ + for (i = 0; i < 250; i++) { reg = target_mem_read32(t, SMAP_SR); - i++; - } while (((reg & SMAP_SR_HCR) != 0) && (i < 100)); - if (i == 100) { - DEBUG("\nSAM4L: Reset failed. SMAP_SR has 0x%08lx\n", reg); + } + /* not sure what to do if we can't reset that bit */ + if (i > 249) { + DEBUG("\nSAM4L: Reset failed. SMAP_SR has 0x%08lx\n", (long unsigned int) reg); } } + /* reset bus error if for some reason SMAP was disabled */ target_check_error(t); } /* - * sam4_flash_command + * sam4l_flash_command * * Helper function, wait for the flash controller to be ready to receive a * command. Then send it the command, page number, and the authorization @@ -307,13 +302,14 @@ sam4l_reset(target *t) * pointers. */ static int -sam4_flash_command(target *t, uint32_t page, uint32_t cmd) +sam4l_flash_command(target *t, uint32_t page, uint32_t cmd) { uint32_t cmd_reg; uint32_t status; int timeout; - DEBUG("\nSAM4L: sam4_flash_command: FSR: 0x%08x, page = %d, command = %d\n", + DEBUG("\nSAM4L: sam4l_flash_command: FSR: 0x%08x, page = %d, command = %d\n", (unsigned int)(FLASHCALW_FSR), (int) page, (int) cmd); + /* wait for Flash controller ready */ for (timeout = 0; timeout < FLASH_TIMEOUT; timeout++) { status = target_mem_read32(t, FLASHCALW_FSR); if (status & FLASHCALW_FSR_FRDY) { @@ -321,14 +317,17 @@ sam4_flash_command(target *t, uint32_t page, uint32_t cmd) } } if (timeout == FLASH_TIMEOUT) { - DEBUG("\nSAM4L: sam4_flash_command: Not ready! Status = 0x%08x\n", (unsigned int) status); + DEBUG("\nSAM4L: sam4l_flash_command: Not ready! Status = 0x%08x\n", (unsigned int) status); return -1; /* Failed */ } + /* load up the new command */ cmd_reg = (cmd & FLASHCALW_FCMD_CMD_MASK) | ((page & FLASHCALW_FCMD_PAGEN_MASK) << FLASHCALW_FCMD_PAGEN_SHIFT) | (0xA5 << FLASHCALW_FCMD_KEY_SHIFT); - DEBUG("\nSAM4L: sam4_flash_command: Wrting command word 0x%08x\n", (unsigned int) cmd_reg); + DEBUG("\nSAM4L: sam4l_flash_command: Wrting command word 0x%08x\n", (unsigned int) cmd_reg); + /* and kick it off */ target_mem_write32(t, FLASHCALW_FCMD, cmd_reg); + /* don't actually wait for it to finish, the next command will stall if it is not done */ return 0; } @@ -336,30 +335,31 @@ sam4_flash_command(target *t, uint32_t page, uint32_t cmd) * Write data from 'src' into flash using the algorithim provided by * Atmel in their data sheet. */ -int -sam4_flash_write(struct target_flash *f, target_addr addr, const void *src, size_t len) +static int +sam4l_flash_write_buf(struct target_flash *f, target_addr addr, const void *src, size_t len) { target *t = f->t; uint32_t *src_data = (uint32_t *)src; + uint32_t ndx; uint16_t page; - DEBUG("\nSAM4L: sam4_flash_write: addr = 0x%08lx, len %d\n", addr, len); - /* This will fail with unaligned writes */ + DEBUG("\nSAM4L: sam4l_flash_write_buf: addr = 0x%08lx, len %d\n", (long unsigned int) addr, (int) len); + /* This will fail with unaligned writes, the write_buf version */ while (len) { - page = addr / SAM4L_PAGE_SIZE; + /* clear the page buffer */ - if (sam4_flash_command(t, 0, FLASH_CMD_CPB)) { + if (sam4l_flash_command(t, 0, FLASH_CMD_CPB)) { return -1; } - /* Fill it with data to write */ - target_mem_write(t, addr, src_data, SAM4L_PAGE_SIZE); -#if 0 + + /* Now fill page buffer with our 512 bytes of data */ + + /* I did try to use target_mem_write however that resulted in the + * last 64 bits (8 bytes) to be incorrect on even pages (0, 2, 4, ...) + * since it works this way I've not investigated further. + */ for (ndx = 0; ndx < SAM4L_PAGE_SIZE; ndx += 4) { -/* - target_mem_write32(t, addr, *src_data); - addr += 4; -*/ /* * the page buffer overlaps flash, its only 512 bytes long * and no matter where you write it from it goes to the page @@ -370,11 +370,11 @@ sam4_flash_write(struct target_flash *f, target_addr addr, const void *src, size target_mem_write32(t, addr+ndx, *src_data); src_data++; } -#endif /* write the page */ - if (sam4_flash_command(t, page, FLASH_CMD_WP)) { + if (sam4l_flash_command(t, page, FLASH_CMD_WP)) { return -1; } + /* it should be done after one page, but in case it isn't */ len -= SAM4L_PAGE_SIZE; addr += SAM4L_PAGE_SIZE; } @@ -385,19 +385,22 @@ sam4_flash_write(struct target_flash *f, target_addr addr, const void *src, size * Erase flash across the addresses specified by addr and len */ static int -sam4_flash_erase(struct target_flash *f, target_addr addr, size_t len) +sam4l_flash_erase(struct target_flash *f, target_addr addr, size_t len) { target *t = f->t; uint16_t page; DEBUG("SAM4L: flash erase address 0x%08x for %d bytes\n", (unsigned int) addr, (unsigned int) len); - /* force len to be an integral number of pages */ - /* len = (len + (SAM4_PAGE_SIZE - 1)) & ~SAM4_PAGE_SIZE; */ + /* + * NB: if addr isn't aligned to a page boundary, or length + * is not an even multiple of page sizes, we may end up + * erasing data we didn't intend to. + */ while (len) { page = addr / SAM4_PAGE_SIZE; - if (sam4_flash_command(t, page, FLASH_CMD_EP)) { + if (sam4l_flash_command(t, page, FLASH_CMD_EP)) { return -1; } len -= SAM4_PAGE_SIZE; From a3c2592e44a27a2236dc12abf4f5a0d3804dde01 Mon Sep 17 00:00:00 2001 From: Chuck McManis Date: Sun, 4 Dec 2016 13:15:45 -0800 Subject: [PATCH 3/4] Review feedback --- src/gdb_main.c | 3 -- src/platforms/common/swdptap.c | 6 +-- src/target/cortexm.c | 2 +- src/target/sam4l.c | 83 ++++++++++++++++------------------ 4 files changed, 42 insertions(+), 52 deletions(-) diff --git a/src/gdb_main.c b/src/gdb_main.c index d41d6053..23642433 100644 --- a/src/gdb_main.c +++ b/src/gdb_main.c @@ -96,9 +96,6 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall) int size; bool single_step = false; - /* - DEBUG("Entering GDB protocol main loop\n"); - */ /* GDB protocol main loop */ while(1) { SET_IDLE_STATE(1); diff --git a/src/platforms/common/swdptap.c b/src/platforms/common/swdptap.c index c7c48ac5..64cdc58a 100644 --- a/src/platforms/common/swdptap.c +++ b/src/platforms/common/swdptap.c @@ -36,7 +36,7 @@ static void swdptap_turnaround(uint8_t dir) if(dir == olddir) return; olddir = dir; -#if 0 +#ifdef DEBUG_SWD_BITS DEBUG("%s", dir ? "\n-> ":"\n<- "); #endif @@ -58,7 +58,7 @@ bool swdptap_bit_in(void) gpio_set(SWCLK_PORT, SWCLK_PIN); gpio_clear(SWCLK_PORT, SWCLK_PIN); -#if 0 +#ifdef DEBUG_SWD_BITS DEBUG("%d", ret?1:0); #endif @@ -67,7 +67,7 @@ bool swdptap_bit_in(void) void swdptap_bit_out(bool val) { -#if 0 +#ifdef DEBUG_SWD_BITS DEBUG("%d", val); #endif diff --git a/src/target/cortexm.c b/src/target/cortexm.c index 7e587a46..887d8356 100644 --- a/src/target/cortexm.c +++ b/src/target/cortexm.c @@ -262,7 +262,7 @@ bool cortexm_probe(ADIv5_AP_t *ap) PROBE(lpc15xx_probe); PROBE(lpc43xx_probe); PROBE(sam3x_probe); - PROBE(sam4l_probe); + PROBE(sam4l_probe); PROBE(nrf51_probe); PROBE(samd_probe); PROBE(lmi_probe); diff --git a/src/target/sam4l.c b/src/target/sam4l.c index 9071d9f4..8b82e40a 100644 --- a/src/target/sam4l.c +++ b/src/target/sam4l.c @@ -1,5 +1,4 @@ /* - * vim: set noexpandtab ts=4: * * This file is part of the Black Magic Debug project. * @@ -106,11 +105,7 @@ static void sam4l_extended_reset(target *t); static int sam4l_flash_erase(struct target_flash *f, target_addr addr, size_t len); static int sam4l_flash_write_buf(struct target_flash *f, target_addr dest, - const void *src, size_t len); - -const struct command_s sam4l_cmds[] = { - {NULL, NULL, NULL} -}; + const void *src, size_t len); /* why Atmel couldn't make it sequential ... */ static const size_t __ram_size[16] = { @@ -152,6 +147,7 @@ static const size_t __nvp_size[16] = { }; +/* All variants of 4L have a 512 byte page */ #define SAM4L_PAGE_SIZE 512 #define SAM4L_ARCH 0xb0 #define SAM4L_CHIPID_CIDR 0x400E0740 @@ -162,8 +158,6 @@ static const size_t __nvp_size[16] = { #define CHIPID_CIDR_NVPSIZ_MASK 0xf #define CHIPID_CIDR_NVPSIZ_SHIFT 8 -/* All variants of 4L have a 512 byte page */ -#define SAM4_PAGE_SIZE 512 /* Arbitrary time to wait for FLASH controller to be ready */ #define FLASH_TIMEOUT 10000 @@ -177,12 +171,12 @@ static void sam4l_add_flash(target *t, uint32_t addr, size_t length) struct target_flash *f = calloc(1, sizeof(struct target_flash)); f->start = addr; f->length = length; - f->blocksize = 512; + f->blocksize = SAM4L_PAGE_SIZE; f->erase = sam4l_flash_erase; f->write = target_flash_write_buffered; f->done = target_flash_done_buffered; f->write_buf = sam4l_flash_write_buf; - f->buf_size = 512;; + f->buf_size = SAM4L_PAGE_SIZE; f->erased = 0xff; /* add it into the target structures flash chain */ target_add_flash(t, f); @@ -264,7 +258,7 @@ bool sam4l_probe(target *t) /* * We've been reset, make sure we take the core out of reset */ -void +static void sam4l_extended_reset(target *t) { uint32_t reg; @@ -307,7 +301,7 @@ sam4l_flash_command(target *t, uint32_t page, uint32_t cmd) uint32_t cmd_reg; uint32_t status; int timeout; - DEBUG("\nSAM4L: sam4l_flash_command: FSR: 0x%08x, page = %d, command = %d\n", + DEBUG("\nSAM4L: sam4l_flash_command: FSR: 0x%08x, page = %d, command = %d\n", (unsigned int)(FLASHCALW_FSR), (int) page, (int) cmd); /* wait for Flash controller ready */ for (timeout = 0; timeout < FLASH_TIMEOUT; timeout++) { @@ -345,38 +339,37 @@ sam4l_flash_write_buf(struct target_flash *f, target_addr addr, const void *src, DEBUG("\nSAM4L: sam4l_flash_write_buf: addr = 0x%08lx, len %d\n", (long unsigned int) addr, (int) len); /* This will fail with unaligned writes, the write_buf version */ - while (len) { - page = addr / SAM4L_PAGE_SIZE; + page = addr / SAM4L_PAGE_SIZE; - /* clear the page buffer */ - if (sam4l_flash_command(t, 0, FLASH_CMD_CPB)) { - return -1; - } + if (len != SAM4L_PAGE_SIZE) { + return -1; + } - /* Now fill page buffer with our 512 bytes of data */ + /* clear the page buffer */ + if (sam4l_flash_command(t, 0, FLASH_CMD_CPB)) { + return -1; + } - /* I did try to use target_mem_write however that resulted in the - * last 64 bits (8 bytes) to be incorrect on even pages (0, 2, 4, ...) - * since it works this way I've not investigated further. + /* Now fill page buffer with our 512 bytes of data */ + + /* I did try to use target_mem_write however that resulted in the + * last 64 bits (8 bytes) to be incorrect on even pages (0, 2, 4, ...) + * since it works this way I've not investigated further. + */ + for (ndx = 0; ndx < SAM4L_PAGE_SIZE; ndx += 4) { + /* + * the page buffer overlaps flash, its only 512 bytes long + * and no matter where you write it from it goes to the page + * you point it to. So we don't need the specific address here + * instead we just write 0 - pagelen (512) and that fills our + * buffer correctly. */ - for (ndx = 0; ndx < SAM4L_PAGE_SIZE; ndx += 4) { - /* - * the page buffer overlaps flash, its only 512 bytes long - * and no matter where you write it from it goes to the page - * you point it to. So we don't need the specific address here - * instead we just write 0 - pagelen (512) and that fills our - * buffer correctly. - */ - target_mem_write32(t, addr+ndx, *src_data); - src_data++; - } - /* write the page */ - if (sam4l_flash_command(t, page, FLASH_CMD_WP)) { - return -1; - } - /* it should be done after one page, but in case it isn't */ - len -= SAM4L_PAGE_SIZE; - addr += SAM4L_PAGE_SIZE; + target_mem_write32(t, addr+ndx, *src_data); + src_data++; + } + /* write the page */ + if (sam4l_flash_command(t, page, FLASH_CMD_WP)) { + return -1; } return 0; } @@ -390,21 +383,21 @@ sam4l_flash_erase(struct target_flash *f, target_addr addr, size_t len) target *t = f->t; uint16_t page; - DEBUG("SAM4L: flash erase address 0x%08x for %d bytes\n", + DEBUG("SAM4L: flash erase address 0x%08x for %d bytes\n", (unsigned int) addr, (unsigned int) len); /* * NB: if addr isn't aligned to a page boundary, or length * is not an even multiple of page sizes, we may end up * erasing data we didn't intend to. - */ + */ while (len) { - page = addr / SAM4_PAGE_SIZE; + page = addr / SAM4L_PAGE_SIZE; if (sam4l_flash_command(t, page, FLASH_CMD_EP)) { return -1; } - len -= SAM4_PAGE_SIZE; - addr += SAM4_PAGE_SIZE; + len -= SAM4L_PAGE_SIZE; + addr += SAM4L_PAGE_SIZE; } return 0; } From 085c980215de2b5346b78629d7654aa82ba757b4 Mon Sep 17 00:00:00 2001 From: Chuck McManis Date: Sun, 4 Dec 2016 13:51:27 -0800 Subject: [PATCH 4/4] Remove EXTENDED_RESET define --- src/target/cortexm.c | 2 +- src/target/cortexm.h | 1 - src/target/sam4l.c | 7 +------ 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/target/cortexm.c b/src/target/cortexm.c index 887d8356..59fce89d 100644 --- a/src/target/cortexm.c +++ b/src/target/cortexm.c @@ -444,7 +444,7 @@ static void cortexm_reset(target *t) CORTEXM_AIRCR_VECTKEY | CORTEXM_AIRCR_SYSRESETREQ); /* If target needs to do something extra (see Atmel SAM4L for example) */ - if ((t->target_options & CORTEXM_TOPT_EXTENDED_RESET) != 0) { + if (t->extended_reset != NULL) { t->extended_reset(t); } diff --git a/src/target/cortexm.h b/src/target/cortexm.h index 7d42f193..bf1d821d 100644 --- a/src/target/cortexm.h +++ b/src/target/cortexm.h @@ -155,7 +155,6 @@ #define ARM_THUMB_BREAKPOINT 0xBE00 #define CORTEXM_TOPT_INHIBIT_SRST (1 << 2) -#define CORTEXM_TOPT_EXTENDED_RESET (1 << 3) bool cortexm_probe(ADIv5_AP_t *ap); ADIv5_AP_t *cortexm_ap(target *t); diff --git a/src/target/sam4l.c b/src/target/sam4l.c index 8b82e40a..cdb90726 100644 --- a/src/target/sam4l.c +++ b/src/target/sam4l.c @@ -229,12 +229,7 @@ bool sam4l_probe(target *t) t->idcode = target_mem_read32(t, SAM4L_CHIPID_CIDR); if (((t->idcode >> CHIPID_CIDR_ARCH_SHIFT) & CHIPID_CIDR_ARCH_MASK) == SAM4L_ARCH) { t->driver = "Atmel SAM4L"; -#ifdef SAM4_DISABLE_SRST - /* Check to see if our extended reset will fix this */ - t->target_options |= CORTEXM_TOPT_INHIBIT_SRST; -#endif - /* this option says we need to do "extra" stuff after reset */ - t->target_options |= CORTEXM_TOPT_EXTENDED_RESET; + /* this function says we need to do "extra" stuff after reset */ t->extended_reset = sam4l_extended_reset; ram_size = sam_ram_size(t->idcode); target_add_ram(t, 0x20000000, ram_size);