gnu: openocd: Update to 9a877a83a1c8b1f105cdc0de46c5cbc4d9e8799e.
* gnu/packages/embedded.scm (openocd): Update to 9a877a83a1c8b1f105cdc0de46c5cbc4d9e8799e. [version]: Substitute release with current master. [source]: Remove openocd-nrf52.patch [arguments]: Replace bootstrap build phase. * gnu/local.mk: Remove openocd-nrf52.patch. * gnu/packages/patches/openocd-nrf52.patch: Remove file. Signed-off-by: Ludovic Courtès <ludo@gnu.org>master
parent
2eacb95ad5
commit
cad55e91fd
|
@ -37,6 +37,7 @@
|
|||
# Copyright © 2020 Brice Waegeneire <brice@waegenei.re>
|
||||
# Copyright © 2020 Tanguy Le Carrour <tanguy@bioneland.org>
|
||||
# Copyright © 2020 Martin Becze <mjbecze@riseup.net>
|
||||
# Copyright © 2020 Malte Frank Gerdes <mate.f.gerdes@gmail.com>
|
||||
#
|
||||
# This file is part of GNU Guix.
|
||||
#
|
||||
|
@ -1393,7 +1394,6 @@ dist_patch_DATA = \
|
|||
%D%/packages/patches/openfoam-4.1-cleanup.patch \
|
||||
%D%/packages/patches/openjdk-10-idlj-reproducibility.patch \
|
||||
%D%/packages/patches/openmpi-mtl-priorities.patch \
|
||||
%D%/packages/patches/openocd-nrf52.patch \
|
||||
%D%/packages/patches/openssh-hurd.patch \
|
||||
%D%/packages/patches/openresolv-restartcmd-guix.patch \
|
||||
%D%/packages/patches/openscad-parser-boost-1.72.patch \
|
||||
|
|
|
@ -514,67 +514,71 @@ language.")
|
|||
(license license:bsd-2)))
|
||||
|
||||
(define-public openocd
|
||||
(package
|
||||
(name "openocd")
|
||||
(version "0.10.0")
|
||||
(source (origin
|
||||
(method url-fetch)
|
||||
(uri (string-append "mirror://sourceforge/openocd/openocd/"
|
||||
version "/openocd-" version ".tar.gz"))
|
||||
(sha256
|
||||
(base32
|
||||
"09p57y3c2spqx4vjjlz1ljm1lcd0j9q8g76ywxqgn3yc34wv18zd"))
|
||||
;; FIXME: Remove after nrf52 patch is merged.
|
||||
(patches
|
||||
(search-patches "openocd-nrf52.patch"))))
|
||||
(build-system gnu-build-system)
|
||||
(native-inputs
|
||||
`(("autoconf" ,autoconf)
|
||||
("automake" ,automake)
|
||||
("libtool" ,libtool)
|
||||
("pkg-config" ,pkg-config)))
|
||||
(inputs
|
||||
`(("hidapi" ,hidapi)
|
||||
("jimtcl" ,jimtcl)
|
||||
("libftdi" ,libftdi)
|
||||
("libjaylink" ,libjaylink)
|
||||
("libusb-compat" ,libusb-compat)))
|
||||
(arguments
|
||||
'(#:configure-flags
|
||||
(append (list "--disable-werror"
|
||||
"--enable-sysfsgpio"
|
||||
"--disable-internal-jimtcl"
|
||||
"--disable-internal-libjaylink")
|
||||
(map (lambda (programmer)
|
||||
(string-append "--enable-" programmer))
|
||||
'("amtjtagaccel" "armjtagew" "buspirate" "ftdi"
|
||||
"gw16012" "jlink" "opendous" "osbdm"
|
||||
"parport" "aice" "cmsis-dap" "dummy" "jtag_vpi"
|
||||
"remote-bitbang" "rlink" "stlink" "ti-icdi" "ulink"
|
||||
"usbprog" "vsllink" "usb-blaster-2" "usb_blaster"
|
||||
"presto" "openjtag")))
|
||||
#:phases
|
||||
(modify-phases %standard-phases
|
||||
;; Required because of patched sources.
|
||||
(add-before 'configure 'autoreconf
|
||||
(lambda _ (invoke "autoreconf" "-vfi") #t))
|
||||
(add-after 'autoreconf 'change-udev-group
|
||||
(lambda _
|
||||
(substitute* "contrib/60-openocd.rules"
|
||||
(("plugdev") "dialout"))
|
||||
#t))
|
||||
(add-after 'install 'install-udev-rules
|
||||
(lambda* (#:key outputs #:allow-other-keys)
|
||||
(install-file "contrib/60-openocd.rules"
|
||||
(string-append
|
||||
(assoc-ref outputs "out")
|
||||
"/lib/udev/rules.d/"))
|
||||
#t)))))
|
||||
(home-page "http://openocd.org")
|
||||
(synopsis "On-Chip Debugger")
|
||||
(description "OpenOCD provides on-chip programming and debugging support
|
||||
(let ((commit "9a877a83a1c8b1f105cdc0de46c5cbc4d9e8799e")
|
||||
(revision "0"))
|
||||
(package
|
||||
(name "openocd")
|
||||
(version (string-append "0.10.0-" revision "."
|
||||
(string-take commit 7)))
|
||||
(source (origin
|
||||
(method git-fetch)
|
||||
(uri (git-reference
|
||||
(url "https://git.code.sf.net/p/openocd/code")
|
||||
(commit commit)))
|
||||
(file-name (string-append name "-" version "-checkout"))
|
||||
(sha256
|
||||
(base32
|
||||
"1q536cp80v2bcy6xwk08f1r2ljyw13jchx3a1z7d3ni3vqql7rc6"))))
|
||||
(build-system gnu-build-system)
|
||||
(native-inputs
|
||||
`(("autoconf" ,autoconf)
|
||||
("automake" ,automake)
|
||||
("libtool" ,libtool)
|
||||
("which" ,base:which)
|
||||
("pkg-config" ,pkg-config)))
|
||||
(inputs
|
||||
`(("hidapi" ,hidapi)
|
||||
("jimtcl" ,jimtcl)
|
||||
("libftdi" ,libftdi)
|
||||
("libjaylink" ,libjaylink)
|
||||
("libusb-compat" ,libusb-compat)))
|
||||
(arguments
|
||||
'(#:configure-flags
|
||||
(append (list "--disable-werror"
|
||||
"--enable-sysfsgpio"
|
||||
"--disable-internal-jimtcl"
|
||||
"--disable-internal-libjaylink")
|
||||
(map (lambda (programmer)
|
||||
(string-append "--enable-" programmer))
|
||||
'("amtjtagaccel" "armjtagew" "buspirate" "ftdi"
|
||||
"gw16012" "jlink" "opendous" "osbdm"
|
||||
"parport" "aice" "cmsis-dap" "dummy" "jtag_vpi"
|
||||
"remote-bitbang" "rlink" "stlink" "ti-icdi" "ulink"
|
||||
"usbprog" "vsllink" "usb-blaster-2" "usb_blaster"
|
||||
"presto" "openjtag")))
|
||||
#:phases
|
||||
(modify-phases %standard-phases
|
||||
(replace 'bootstrap
|
||||
(lambda _
|
||||
(patch-shebang "bootstrap")
|
||||
(invoke "./bootstrap" "nosubmodule")))
|
||||
(add-after 'autoreconf 'change-udev-group
|
||||
(lambda _
|
||||
(substitute* "contrib/60-openocd.rules"
|
||||
(("plugdev") "dialout"))
|
||||
#t))
|
||||
(add-after 'install 'install-udev-rules
|
||||
(lambda* (#:key outputs #:allow-other-keys)
|
||||
(install-file "contrib/60-openocd.rules"
|
||||
(string-append
|
||||
(assoc-ref outputs "out")
|
||||
"/lib/udev/rules.d/"))
|
||||
#t)))))
|
||||
(home-page "http://openocd.org")
|
||||
(synopsis "On-Chip Debugger")
|
||||
(description "OpenOCD provides on-chip programming and debugging support
|
||||
with a layered architecture of JTAG interface and TAP support.")
|
||||
(license license:gpl2+)))
|
||||
(license license:gpl2+))))
|
||||
|
||||
;; The commits for all propeller tools are the stable versions published at
|
||||
;; https://github.com/propellerinc/propgcc in the release_1_0. According to
|
||||
|
|
|
@ -1,827 +0,0 @@
|
|||
This patch adds support for nRF52 series devices. It is patchset 7 from
|
||||
<http://openocd.zylin.com/#/c/3511/>, which has been tested, but not
|
||||
merged yet in master.
|
||||
|
||||
From: Michael Dietz <mjdietzx@gmail.com>
|
||||
Date: Mon, 30 May 2016 12:50:44 +0000 (-0700)
|
||||
Subject: Added support for nRF52 Series Devices.
|
||||
X-Git-Url: http://openocd.zylin.com/gitweb?p=openocd.git;a=commitdiff_plain;h=9ba15633e221d9d72e320372ba8f49d3f30d4bce
|
||||
|
||||
Added support for nRF52 Series Devices.
|
||||
|
||||
Both nrf52.c and nrf52.cfg are based off of previous nRF51 files.
|
||||
- Some possible race conditions with NVMC have been fixed in nRF52.c
|
||||
- Removed nrf51_get_probed_chip_if_halted() as the core does not have to be halted to perform operations where it is called.
|
||||
- Only registers that are needed by openOCD are defined, some registers in nRF51 don't exist in nRF52 and are removed.
|
||||
- Some all around cleanup has been done.
|
||||
- The protection mechanism is completely different on nRF52 and this has not been implemented yet - just prints a warning and returns for now.
|
||||
|
||||
Change-Id: I4dd42c86f33f450709bb981806c2655f04aa6201
|
||||
Signed-off-by: Michael Dietz <mjdietzx@gmail.com>
|
||||
---
|
||||
|
||||
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
|
||||
index 727e4f2..839667c 100644
|
||||
--- a/src/flash/nor/Makefile.am
|
||||
+++ b/src/flash/nor/Makefile.am
|
||||
@@ -36,6 +36,7 @@ NOR_DRIVERS = \
|
||||
%D%/niietcm4.c \
|
||||
%D%/non_cfi.c \
|
||||
%D%/nrf51.c \
|
||||
+ %D%/nrf52.c \
|
||||
%D%/numicro.c \
|
||||
%D%/ocl.c \
|
||||
%D%/pic32mx.c \
|
||||
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
|
||||
index 56a5cb2..071273e 100644
|
||||
--- a/src/flash/nor/drivers.c
|
||||
+++ b/src/flash/nor/drivers.c
|
||||
@@ -48,6 +48,7 @@ extern struct flash_driver mdr_flash;
|
||||
extern struct flash_driver mrvlqspi_flash;
|
||||
extern struct flash_driver niietcm4_flash;
|
||||
extern struct flash_driver nrf51_flash;
|
||||
+extern struct flash_driver nrf52_flash;
|
||||
extern struct flash_driver numicro_flash;
|
||||
extern struct flash_driver ocl_flash;
|
||||
extern struct flash_driver pic32mx_flash;
|
||||
@@ -100,6 +101,7 @@ static struct flash_driver *flash_drivers[] = {
|
||||
&mrvlqspi_flash,
|
||||
&niietcm4_flash,
|
||||
&nrf51_flash,
|
||||
+ &nrf52_flash,
|
||||
&numicro_flash,
|
||||
&ocl_flash,
|
||||
&pic32mx_flash,
|
||||
diff --git a/src/flash/nor/nrf52.c b/src/flash/nor/nrf52.c
|
||||
new file mode 100644
|
||||
index 0000000..7f2bd35
|
||||
--- /dev/null
|
||||
+++ b/src/flash/nor/nrf52.c
|
||||
@@ -0,0 +1,733 @@
|
||||
+/***************************************************************************
|
||||
+ * Copyright (C) 2013 Synapse Product Development *
|
||||
+ * Andrey Smirnov <andrew.smironv@gmail.com> *
|
||||
+ * Angus Gratton <gus@projectgus.com> *
|
||||
+ * Erdem U. Altunyurt <spamjunkeater@gmail.com> *
|
||||
+ * *
|
||||
+ * 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 <stdlib.h>
|
||||
+
|
||||
+#include "imp.h"
|
||||
+#include <target/algorithm.h>
|
||||
+#include <target/armv7m.h>
|
||||
+#include <helper/types.h>
|
||||
+
|
||||
+/* nRF52 Register addresses used by openOCD. */
|
||||
+#define NRF52_FLASH_BASE_ADDR (0x0)
|
||||
+
|
||||
+#define NRF52_FICR_BASE_ADDR (0x10000000)
|
||||
+#define NRF52_FICR_CODEPAGESIZE_ADDR (NRF52_FICR_BASE_ADDR | 0x010)
|
||||
+#define NRF52_FICR_CODESIZE_ADDR (NRF52_FICR_BASE_ADDR | 0x014)
|
||||
+
|
||||
+#define NRF52_UICR_BASE_ADDR (0x10001000)
|
||||
+
|
||||
+#define NRF52_NVMC_BASE_ADDR (0x4001E000)
|
||||
+#define NRF52_NVMC_READY_ADDR (NRF52_NVMC_BASE_ADDR | 0x400)
|
||||
+#define NRF52_NVMC_CONFIG_ADDR (NRF52_NVMC_BASE_ADDR | 0x504)
|
||||
+#define NRF52_NVMC_ERASEPAGE_ADDR (NRF52_NVMC_BASE_ADDR | 0x508)
|
||||
+#define NRF52_NVMC_ERASEALL_ADDR (NRF52_NVMC_BASE_ADDR | 0x50C)
|
||||
+#define NRF52_NVMC_ERASEUICR_ADDR (NRF52_NVMC_BASE_ADDR | 0x514)
|
||||
+
|
||||
+/* nRF52 bit fields. */
|
||||
+enum nrf52_nvmc_config_bits {
|
||||
+ NRF52_NVMC_CONFIG_REN = 0x0,
|
||||
+ NRF52_NVMC_CONFIG_WEN = 0x01,
|
||||
+ NRF52_NVMC_CONFIG_EEN = 0x02
|
||||
+};
|
||||
+
|
||||
+enum nrf52_nvmc_ready_bits {
|
||||
+ NRF52_NVMC_BUSY = 0x0,
|
||||
+ NRF52_NVMC_READY = 0x01
|
||||
+};
|
||||
+
|
||||
+/* nRF52 state information. */
|
||||
+struct nrf52_info {
|
||||
+ uint32_t code_page_size; /* Size of FLASH page in bytes. */
|
||||
+ uint32_t code_memory_size; /* Size of Code FLASH region in bytes. */
|
||||
+
|
||||
+ struct {
|
||||
+ bool probed;
|
||||
+ int (*write) (struct flash_bank *bank,
|
||||
+ struct nrf52_info *chip,
|
||||
+ const uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
+ } bank[2]; /* There are two regions in nRF52 FLASH - Code and UICR. */
|
||||
+ struct target *target;
|
||||
+};
|
||||
+
|
||||
+static int nrf52_protect_check(struct flash_bank *bank);
|
||||
+
|
||||
+static int nrf52_probe(struct flash_bank *bank)
|
||||
+{
|
||||
+ int res;
|
||||
+ struct nrf52_info *chip = bank->driver_priv;
|
||||
+ assert(chip != NULL);
|
||||
+
|
||||
+ res = target_read_u32(chip->target,
|
||||
+ NRF52_FICR_CODEPAGESIZE_ADDR,
|
||||
+ &chip->code_page_size);
|
||||
+ if (res != ERROR_OK) {
|
||||
+ LOG_ERROR("Couldn't read code page size");
|
||||
+ return res;
|
||||
+ }
|
||||
+
|
||||
+ res = target_read_u32(chip->target,
|
||||
+ NRF52_FICR_CODESIZE_ADDR,
|
||||
+ &chip->code_memory_size);
|
||||
+ if (res != ERROR_OK) {
|
||||
+ LOG_ERROR("Couldn't read code memory size");
|
||||
+ return res;
|
||||
+ }
|
||||
+
|
||||
+ chip->code_memory_size = chip->code_memory_size * chip->code_page_size;
|
||||
+
|
||||
+ if (bank->base == NRF52_FLASH_BASE_ADDR) {
|
||||
+ bank->size = chip->code_memory_size;
|
||||
+ bank->num_sectors = bank->size / chip->code_page_size;
|
||||
+ bank->sectors = calloc(bank->num_sectors,
|
||||
+ sizeof((bank->sectors)[0]));
|
||||
+ if (!bank->sectors)
|
||||
+ return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
+
|
||||
+ /* Fill out the sector information: All nRF51 sectors are the same size. */
|
||||
+ for (int i = 0; i < bank->num_sectors; i++) {
|
||||
+ bank->sectors[i].size = chip->code_page_size;
|
||||
+ bank->sectors[i].offset = i * chip->code_page_size;
|
||||
+
|
||||
+ /* Mark as unknown. */
|
||||
+ bank->sectors[i].is_erased = -1;
|
||||
+ bank->sectors[i].is_protected = -1;
|
||||
+ }
|
||||
+
|
||||
+ nrf52_protect_check(bank);
|
||||
+
|
||||
+ chip->bank[0].probed = true;
|
||||
+ } else { /* This is the UICR bank. */
|
||||
+ bank->size = chip->code_page_size;
|
||||
+ bank->num_sectors = 1;
|
||||
+ bank->sectors = calloc(bank->num_sectors,
|
||||
+ sizeof((bank->sectors)[0]));
|
||||
+ if (!bank->sectors)
|
||||
+ return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
+
|
||||
+ bank->sectors[0].size = bank->size;
|
||||
+ bank->sectors[0].offset = 0;
|
||||
+
|
||||
+ bank->sectors[0].is_erased = -1;
|
||||
+ bank->sectors[0].is_protected = -1;
|
||||
+
|
||||
+ chip->bank[1].probed = true;
|
||||
+ }
|
||||
+
|
||||
+ return ERROR_OK;
|
||||
+}
|
||||
+
|
||||
+static int nrf52_bank_is_probed(struct flash_bank *bank)
|
||||
+{
|
||||
+ struct nrf52_info *chip = bank->driver_priv;
|
||||
+ assert(chip != NULL);
|
||||
+
|
||||
+ return chip->bank[bank->bank_number].probed;
|
||||
+}
|
||||
+
|
||||
+static int nrf52_auto_probe(struct flash_bank *bank)
|
||||
+{
|
||||
+ if (!nrf52_bank_is_probed(bank))
|
||||
+ return nrf52_probe(bank);
|
||||
+ else
|
||||
+ return ERROR_OK;
|
||||
+}
|
||||
+
|
||||
+static int nrf52_wait_for_nvmc(struct nrf52_info *chip)
|
||||
+{
|
||||
+ int res;
|
||||
+ uint32_t ready;
|
||||
+ int timeout = 100;
|
||||
+
|
||||
+ do {
|
||||
+ res = target_read_u32(chip->target, NRF52_NVMC_READY_ADDR, &ready);
|
||||
+ if (res != ERROR_OK) {
|
||||
+ LOG_ERROR("Couldn't read NVMC_READY register");
|
||||
+ return res;
|
||||
+ }
|
||||
+
|
||||
+ if (ready == NRF52_NVMC_READY)
|
||||
+ return ERROR_OK;
|
||||
+
|
||||
+ alive_sleep(1);
|
||||
+ } while (timeout--);
|
||||
+
|
||||
+ LOG_DEBUG("Timed out waiting for the NVMC to be ready");
|
||||
+ return ERROR_FLASH_BUSY;
|
||||
+}
|
||||
+
|
||||
+static int nrf52_nvmc_erase_enable(struct nrf52_info *chip)
|
||||
+{
|
||||
+ int res;
|
||||
+
|
||||
+ res = nrf52_wait_for_nvmc(chip);
|
||||
+ if (res != ERROR_OK)
|
||||
+ return res;
|
||||
+
|
||||
+ res = target_write_u32(chip->target,
|
||||
+ NRF52_NVMC_CONFIG_ADDR,
|
||||
+ NRF52_NVMC_CONFIG_EEN);
|
||||
+ if (res != ERROR_OK) {
|
||||
+ LOG_ERROR("Failed to configure the NVMC for erasing");
|
||||
+ return res;
|
||||
+ }
|
||||
+
|
||||
+ return res;
|
||||
+}
|
||||
+
|
||||
+static int nrf52_nvmc_write_enable(struct nrf52_info *chip)
|
||||
+{
|
||||
+ int res;
|
||||
+
|
||||
+ res = nrf52_wait_for_nvmc(chip);
|
||||
+ if (res != ERROR_OK)
|
||||
+ return res;
|
||||
+
|
||||
+ res = target_write_u32(chip->target,
|
||||
+ NRF52_NVMC_CONFIG_ADDR,
|
||||
+ NRF52_NVMC_CONFIG_WEN);
|
||||
+ if (res != ERROR_OK) {
|
||||
+ LOG_ERROR("Failed to configure the NVMC for writing");
|
||||
+ return res;
|
||||
+ }
|
||||
+
|
||||
+ return res;
|
||||
+}
|
||||
+
|
||||
+static int nrf52_nvmc_read_only(struct nrf52_info *chip)
|
||||
+{
|
||||
+ int res;
|
||||
+
|
||||
+ res = nrf52_wait_for_nvmc(chip);
|
||||
+ if (res != ERROR_OK)
|
||||
+ return res;
|
||||
+
|
||||
+ res = target_write_u32(chip->target,
|
||||
+ NRF52_NVMC_CONFIG_ADDR,
|
||||
+ NRF52_NVMC_CONFIG_REN);
|
||||
+ if (res != ERROR_OK) {
|
||||
+ LOG_ERROR("Failed to configure the NVMC for read-only");
|
||||
+ return res;
|
||||
+ }
|
||||
+
|
||||
+ return res;
|
||||
+}
|
||||
+
|
||||
+static int nrf52_nvmc_generic_erase(struct nrf52_info *chip,
|
||||
+ uint32_t erase_register,
|
||||
+ uint32_t erase_value)
|
||||
+{
|
||||
+ int res;
|
||||
+
|
||||
+ res = nrf52_nvmc_erase_enable(chip);
|
||||
+ if (res != ERROR_OK)
|
||||
+ return res;
|
||||
+
|
||||
+ res = target_write_u32(chip->target,
|
||||
+ erase_register,
|
||||
+ erase_value);
|
||||
+ if (res != ERROR_OK)
|
||||
+ LOG_ERROR("Failed to write NVMC erase register");
|
||||
+
|
||||
+ return nrf52_nvmc_read_only(chip);
|
||||
+}
|
||||
+
|
||||
+static int nrf52_protect_check(struct flash_bank *bank)
|
||||
+{
|
||||
+ LOG_WARNING("nrf52_protect_check() is not implemented for nRF52 series devices yet");
|
||||
+ return ERROR_OK;
|
||||
+}
|
||||
+
|
||||
+static int nrf52_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
+{
|
||||
+ LOG_WARNING("nrf52_protect() is not implemented for nRF52 series devices yet");
|
||||
+ return ERROR_OK;
|
||||
+}
|
||||
+
|
||||
+static struct flash_sector *nrf52_find_sector_by_address(struct flash_bank *bank, uint32_t address)
|
||||
+{
|
||||
+ struct nrf52_info *chip = bank->driver_priv;
|
||||
+ assert(chip != NULL);
|
||||
+
|
||||
+ for (int i = 0; i < bank->num_sectors; i++)
|
||||
+ if (bank->sectors[i].offset <= address &&
|
||||
+ address < (bank->sectors[i].offset + chip->code_page_size)) {
|
||||
+ return &bank->sectors[i];
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static int nrf52_erase_all(struct nrf52_info *chip)
|
||||
+{
|
||||
+ LOG_DEBUG("Erasing all non-volatile memory");
|
||||
+ return nrf52_nvmc_generic_erase(chip,
|
||||
+ NRF52_NVMC_ERASEALL_ADDR,
|
||||
+ 0x01);
|
||||
+}
|
||||
+
|
||||
+static int nrf52_erase_page(struct flash_bank *bank,
|
||||
+ struct nrf52_info *chip,
|
||||
+ struct flash_sector *sector)
|
||||
+{
|
||||
+ int res;
|
||||
+
|
||||
+ LOG_DEBUG("Erasing page at 0x%"PRIx32, sector->offset);
|
||||
+ if (sector->is_protected == 1) {
|
||||
+ LOG_ERROR("Cannot erase protected sector at 0x%" PRIx32, sector->offset);
|
||||
+ return ERROR_FAIL;
|
||||
+ }
|
||||
+
|
||||
+ if (bank->base == NRF52_UICR_BASE_ADDR) {
|
||||
+ res = nrf52_nvmc_generic_erase(chip,
|
||||
+ NRF52_NVMC_ERASEUICR_ADDR,
|
||||
+ 0x00000001);
|
||||
+ } else {
|
||||
+ res = nrf52_nvmc_generic_erase(chip,
|
||||
+ NRF52_NVMC_ERASEPAGE_ADDR,
|
||||
+ sector->offset);
|
||||
+ }
|
||||
+
|
||||
+ if (res == ERROR_OK)
|
||||
+ sector->is_erased = 1;
|
||||
+ return res;
|
||||
+}
|
||||
+
|
||||
+static const uint8_t nrf52_flash_write_code[] = {
|
||||
+ /* See contrib/loaders/flash/cortex-m0.S */
|
||||
+ /* <wait_fifo>: */
|
||||
+ 0x0d, 0x68, /* ldr r5, [r1, #0] */
|
||||
+ 0x00, 0x2d, /* cmp r5, #0 */
|
||||
+ 0x0b, 0xd0, /* beq.n 1e <exit> */
|
||||
+ 0x4c, 0x68, /* ldr r4, [r1, #4] */
|
||||
+ 0xac, 0x42, /* cmp r4, r5 */
|
||||
+ 0xf9, 0xd0, /* beq.n 0 <wait_fifo> */
|
||||
+ 0x20, 0xcc, /* ldmia r4!, {r5} */
|
||||
+ 0x20, 0xc3, /* stmia r3!, {r5} */
|
||||
+ 0x94, 0x42, /* cmp r4, r2 */
|
||||
+ 0x01, 0xd3, /* bcc.n 18 <no_wrap> */
|
||||
+ 0x0c, 0x46, /* mov r4, r1 */
|
||||
+ 0x08, 0x34, /* adds r4, #8 */
|
||||
+ /* <no_wrap>: */
|
||||
+ 0x4c, 0x60, /* str r4, [r1, #4] */
|
||||
+ 0x04, 0x38, /* subs r0, #4 */
|
||||
+ 0xf0, 0xd1, /* bne.n 0 <wait_fifo> */
|
||||
+ /* <exit>: */
|
||||
+ 0x00, 0xbe /* bkpt 0x0000 */
|
||||
+};
|
||||
+
|
||||
+
|
||||
+/* Start a low level flash write for the specified region */
|
||||
+static int nrf52_ll_flash_write(struct nrf52_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes)
|
||||
+{
|
||||
+ struct target *target = chip->target;
|
||||
+ uint32_t buffer_size = 8192;
|
||||
+ struct working_area *write_algorithm;
|
||||
+ struct working_area *source;
|
||||
+ uint32_t address = NRF52_FLASH_BASE_ADDR + offset;
|
||||
+ struct reg_param reg_params[4];
|
||||
+ struct armv7m_algorithm armv7m_info;
|
||||
+ int retval = ERROR_OK;
|
||||
+
|
||||
+ LOG_DEBUG("Writing buffer to flash offset=0x%"PRIx32" bytes=0x%"PRIx32, offset, bytes);
|
||||
+ assert(bytes % 4 == 0);
|
||||
+
|
||||
+ /* allocate working area with flash programming code */
|
||||
+ if (target_alloc_working_area(target, sizeof(nrf52_flash_write_code),
|
||||
+ &write_algorithm) != ERROR_OK) {
|
||||
+ LOG_WARNING("no working area available, falling back to slow memory writes");
|
||||
+
|
||||
+ for (; bytes > 0; bytes -= 4) {
|
||||
+ retval = target_write_memory(chip->target,
|
||||
+ offset, 4, 1, buffer);
|
||||
+ if (retval != ERROR_OK)
|
||||
+ return retval;
|
||||
+
|
||||
+ retval = nrf52_wait_for_nvmc(chip);
|
||||
+ if (retval != ERROR_OK)
|
||||
+ return retval;
|
||||
+
|
||||
+ offset += 4;
|
||||
+ buffer += 4;
|
||||
+ }
|
||||
+
|
||||
+ return ERROR_OK;
|
||||
+ }
|
||||
+
|
||||
+ LOG_WARNING("using fast async flash loader. This is currently supported");
|
||||
+ LOG_WARNING("only with ST-Link and CMSIS-DAP. If you have issues, add");
|
||||
+ LOG_WARNING("\"set WORKAREASIZE 0\" before sourcing nrf52.cfg to disable it");
|
||||
+
|
||||
+ retval = target_write_buffer(target, write_algorithm->address,
|
||||
+ sizeof(nrf52_flash_write_code),
|
||||
+ nrf52_flash_write_code);
|
||||
+ if (retval != ERROR_OK)
|
||||
+ return retval;
|
||||
+
|
||||
+ /* memory buffer */
|
||||
+ while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) {
|
||||
+ buffer_size /= 2;
|
||||
+ buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */
|
||||
+ if (buffer_size <= 256) {
|
||||
+ /* free working area, write algorithm already allocated */
|
||||
+ target_free_working_area(target, write_algorithm);
|
||||
+
|
||||
+ LOG_WARNING("No large enough working area available, can't do block memory writes");
|
||||
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||
+ armv7m_info.core_mode = ARM_MODE_THREAD;
|
||||
+
|
||||
+ init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* byte count */
|
||||
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer start */
|
||||
+ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer end */
|
||||
+ init_reg_param(®_params[3], "r3", 32, PARAM_IN_OUT); /* target address */
|
||||
+
|
||||
+ buf_set_u32(reg_params[0].value, 0, 32, bytes);
|
||||
+ buf_set_u32(reg_params[1].value, 0, 32, source->address);
|
||||
+ buf_set_u32(reg_params[2].value, 0, 32, source->address + source->size);
|
||||
+ buf_set_u32(reg_params[3].value, 0, 32, address);
|
||||
+
|
||||
+ retval = target_run_flash_async_algorithm(target, buffer, bytes/4, 4,
|
||||
+ 0, NULL,
|
||||
+ 4, reg_params,
|
||||
+ source->address, source->size,
|
||||
+ write_algorithm->address, 0,
|
||||
+ &armv7m_info);
|
||||
+
|
||||
+ target_free_working_area(target, source);
|
||||
+ target_free_working_area(target, write_algorithm);
|
||||
+
|
||||
+ destroy_reg_param(®_params[0]);
|
||||
+ destroy_reg_param(®_params[1]);
|
||||
+ destroy_reg_param(®_params[2]);
|
||||
+ destroy_reg_param(®_params[3]);
|
||||
+
|
||||
+ return retval;
|
||||
+}
|
||||
+
|
||||
+/* Check and erase flash sectors in specified range, then start a low level page write.
|
||||
+ start/end must be sector aligned.
|
||||
+*/
|
||||
+static int nrf52_write_pages(struct flash_bank *bank, uint32_t start, uint32_t end, const uint8_t *buffer)
|
||||
+{
|
||||
+ int res;
|
||||
+ uint32_t offset;
|
||||
+ struct flash_sector *sector;
|
||||
+ struct nrf52_info *chip = bank->driver_priv;
|
||||
+ assert(chip != NULL);
|
||||
+
|
||||
+ assert(start % chip->code_page_size == 0);
|
||||
+ assert(end % chip->code_page_size == 0);
|
||||
+
|
||||
+ /* Erase all sectors */
|
||||
+ for (offset = start; offset < end; offset += chip->code_page_size) {
|
||||
+ sector = nrf52_find_sector_by_address(bank, offset);
|
||||
+
|
||||
+ if (sector == NULL) {
|
||||
+ LOG_ERROR("Invalid sector @ 0x%08"PRIx32, offset);
|
||||
+ return ERROR_FLASH_SECTOR_INVALID;
|
||||
+ }
|
||||
+
|
||||
+ if (sector->is_protected == 1) {
|
||||
+ LOG_ERROR("Can't erase protected sector @ 0x%08"PRIx32, offset);
|
||||
+ return ERROR_FAIL;
|
||||
+ }
|
||||
+
|
||||
+ if (sector->is_erased != 1) { /* 1 = erased, 0= not erased, -1 = unknown */
|
||||
+ res = nrf52_erase_page(bank, chip, sector);
|
||||
+ if (res != ERROR_OK) {
|
||||
+ LOG_ERROR("Failed to erase sector @ 0x%08"PRIx32, sector->offset);
|
||||
+ return res;
|
||||
+ }
|
||||
+ }
|
||||
+ sector->is_erased = 1;
|
||||
+ }
|
||||
+
|
||||
+ res = nrf52_nvmc_write_enable(chip);
|
||||
+ if (res != ERROR_OK)
|
||||
+ return res;
|
||||
+
|
||||
+ res = nrf52_ll_flash_write(chip, start, buffer, (end - start));
|
||||
+ if (res != ERROR_OK) {
|
||||
+ LOG_ERROR("Failed to write FLASH");
|
||||
+ nrf52_nvmc_read_only(chip);
|
||||
+ return res;
|
||||
+ }
|
||||
+
|
||||
+ return nrf52_nvmc_read_only(chip);
|
||||
+}
|
||||
+
|
||||
+static int nrf52_erase(struct flash_bank *bank, int first, int last)
|
||||
+{
|
||||
+ int res = ERROR_OK;
|
||||
+ struct nrf52_info *chip = bank->driver_priv;
|
||||
+ assert(chip != NULL);
|
||||
+
|
||||
+ /* For each sector to be erased */
|
||||
+ for (int s = first; s <= last && res == ERROR_OK; s++)
|
||||
+ res = nrf52_erase_page(bank, chip, &bank->sectors[s]);
|
||||
+
|
||||
+ return res;
|
||||
+}
|
||||
+
|
||||
+static int nrf52_code_flash_write(struct flash_bank *bank,
|
||||
+ struct nrf52_info *chip,
|
||||
+ const uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
+{
|
||||
+ int res;
|
||||
+ /* Need to perform reads to fill any gaps we need to preserve in the first page,
|
||||
+ before the start of buffer, or in the last page, after the end of buffer */
|
||||
+ uint32_t first_page = offset / chip->code_page_size;
|
||||
+ uint32_t last_page = DIV_ROUND_UP(offset+count, chip->code_page_size);
|
||||
+
|
||||
+ uint32_t first_page_offset = first_page * chip->code_page_size;
|
||||
+ uint32_t last_page_offset = last_page * chip->code_page_size;
|
||||
+
|
||||
+ LOG_DEBUG("Padding write from 0x%08"PRIx32"-0x%08"PRIx32" as 0x%08"PRIx32"-0x%08"PRIx32,
|
||||
+ offset, offset+count, first_page_offset, last_page_offset);
|
||||
+
|
||||
+ uint32_t page_cnt = last_page - first_page;
|
||||
+ uint8_t buffer_to_flash[page_cnt * chip->code_page_size];
|
||||
+
|
||||
+ /* Fill in any space between start of first page and start of buffer */
|
||||
+ uint32_t pre = offset - first_page_offset;
|
||||
+ if (pre > 0) {
|
||||
+ res = target_read_memory(bank->target, first_page_offset, 1, pre, buffer_to_flash);
|
||||
+ if (res != ERROR_OK)
|
||||
+ return res;
|
||||
+ }
|
||||
+
|
||||
+ /* Fill in main contents of buffer */
|
||||
+ memcpy(buffer_to_flash + pre, buffer, count);
|
||||
+
|
||||
+ /* Fill in any space between end of buffer and end of last page */
|
||||
+ uint32_t post = last_page_offset - (offset + count);
|
||||
+ if (post > 0) {
|
||||
+ /* Retrieve the full row contents from Flash */
|
||||
+ res = target_read_memory(bank->target, offset + count, 1, post, buffer_to_flash + pre + count);
|
||||
+ if (res != ERROR_OK)
|
||||
+ return res;
|
||||
+ }
|
||||
+
|
||||
+ return nrf52_write_pages(bank, first_page_offset, last_page_offset, buffer_to_flash);
|
||||
+}
|
||||
+
|
||||
+static int nrf52_uicr_flash_write(struct flash_bank *bank,
|
||||
+ struct nrf52_info *chip,
|
||||
+ const uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
+{
|
||||
+ int res;
|
||||
+ uint32_t nrf52_uicr_size = chip->code_page_size;
|
||||
+ uint8_t uicr[nrf52_uicr_size];
|
||||
+ struct flash_sector *sector = &bank->sectors[0];
|
||||
+
|
||||
+ if ((offset + count) > nrf52_uicr_size)
|
||||
+ return ERROR_FAIL;
|
||||
+
|
||||
+ res = target_read_memory(bank->target, NRF52_UICR_BASE_ADDR, 1, nrf52_uicr_size, uicr);
|
||||
+
|
||||
+ if (res != ERROR_OK)
|
||||
+ return res;
|
||||
+
|
||||
+ if (sector->is_erased != 1) {
|
||||
+ res = nrf52_erase_page(bank, chip, sector);
|
||||
+ if (res != ERROR_OK)
|
||||
+ return res;
|
||||
+ }
|
||||
+
|
||||
+ memcpy(&uicr[offset], buffer, count);
|
||||
+
|
||||
+ res = nrf52_nvmc_write_enable(chip);
|
||||
+ if (res != ERROR_OK)
|
||||
+ return res;
|
||||
+
|
||||
+ res = nrf52_ll_flash_write(chip, NRF52_UICR_BASE_ADDR, uicr, nrf52_uicr_size);
|
||||
+ if (res != ERROR_OK) {
|
||||
+ nrf52_nvmc_read_only(chip);
|
||||
+ return res;
|
||||
+ }
|
||||
+
|
||||
+ return nrf52_nvmc_read_only(chip);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int nrf52_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
+ uint32_t offset, uint32_t count)
|
||||
+{
|
||||
+ struct nrf52_info *chip = bank->driver_priv;
|
||||
+ assert(chip != NULL);
|
||||
+
|
||||
+ return chip->bank[bank->bank_number].write(bank, chip, buffer, offset, count);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+FLASH_BANK_COMMAND_HANDLER(nrf52_flash_bank_command)
|
||||
+{
|
||||
+ static struct nrf52_info *chip;
|
||||
+
|
||||
+ assert(bank != NULL);
|
||||
+
|
||||
+ switch (bank->base) {
|
||||
+ case NRF52_FLASH_BASE_ADDR:
|
||||
+ bank->bank_number = 0;
|
||||
+ break;
|
||||
+ case NRF52_UICR_BASE_ADDR:
|
||||
+ bank->bank_number = 1;
|
||||
+ break;
|
||||
+ default:
|
||||
+ LOG_ERROR("Invalid bank address 0x%08" PRIx32, bank->base);
|
||||
+ return ERROR_FAIL;
|
||||
+ }
|
||||
+
|
||||
+ if (!chip) {
|
||||
+ /* Create a new chip */
|
||||
+ chip = calloc(1, sizeof(*chip));
|
||||
+ assert(chip != NULL);
|
||||
+
|
||||
+ chip->target = bank->target;
|
||||
+ }
|
||||
+
|
||||
+ switch (bank->base) {
|
||||
+ case NRF52_FLASH_BASE_ADDR:
|
||||
+ chip->bank[bank->bank_number].write = nrf52_code_flash_write;
|
||||
+ break;
|
||||
+ case NRF52_UICR_BASE_ADDR:
|
||||
+ chip->bank[bank->bank_number].write = nrf52_uicr_flash_write;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ chip->bank[bank->bank_number].probed = false;
|
||||
+ bank->driver_priv = chip;
|
||||
+
|
||||
+ return ERROR_OK;
|
||||
+}
|
||||
+
|
||||
+COMMAND_HANDLER(nrf52_handle_mass_erase_command)
|
||||
+{
|
||||
+ int res;
|
||||
+ struct flash_bank *bank = NULL;
|
||||
+ struct target *target = get_current_target(CMD_CTX);
|
||||
+
|
||||
+ res = get_flash_bank_by_addr(target, NRF52_FLASH_BASE_ADDR, true, &bank);
|
||||
+ if (res != ERROR_OK)
|
||||
+ return res;
|
||||
+
|
||||
+ assert(bank != NULL);
|
||||
+
|
||||
+ struct nrf52_info *chip = bank->driver_priv;
|
||||
+ assert(chip != NULL);
|
||||
+
|
||||
+ res = nrf52_erase_all(chip);
|
||||
+ if (res != ERROR_OK) {
|
||||
+ LOG_ERROR("Failed to erase the chip");
|
||||
+ nrf52_protect_check(bank);
|
||||
+ return res;
|
||||
+ }
|
||||
+
|
||||
+ for (int i = 0; i < bank->num_sectors; i++)
|
||||
+ bank->sectors[i].is_erased = 1;
|
||||
+
|
||||
+ res = nrf52_protect_check(bank);
|
||||
+ if (res != ERROR_OK) {
|
||||
+ LOG_ERROR("Failed to check chip's write protection");
|
||||
+ return res;
|
||||
+ }
|
||||
+
|
||||
+ res = get_flash_bank_by_addr(target, NRF52_UICR_BASE_ADDR, true, &bank);
|
||||
+ if (res != ERROR_OK)
|
||||
+ return res;
|
||||
+
|
||||
+ bank->sectors[0].is_erased = 1;
|
||||
+
|
||||
+ return ERROR_OK;
|
||||
+}
|
||||
+
|
||||
+static int nrf52_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
+{
|
||||
+ int res;
|
||||
+ uint32_t ficr[2];
|
||||
+ struct nrf52_info *chip = bank->driver_priv;
|
||||
+ assert(chip != NULL);
|
||||
+
|
||||
+ res = target_read_u32(chip->target, NRF52_FICR_CODEPAGESIZE_ADDR, &ficr[0]);
|
||||
+ if (res != ERROR_OK) {
|
||||
+ LOG_ERROR("Couldn't read NVMC_READY register");
|
||||
+ return res;
|
||||
+ }
|
||||
+
|
||||
+ res = target_read_u32(chip->target, NRF52_FICR_CODESIZE_ADDR, &ficr[1]);
|
||||
+ if (res != ERROR_OK) {
|
||||
+ LOG_ERROR("Couldn't read NVMC_READY register");
|
||||
+ return res;
|
||||
+ }
|
||||
+
|
||||
+ snprintf(buf, buf_size,
|
||||
+ "\n--------nRF52 Series Device--------\n\n"
|
||||
+ "\n[factory information control block]\n"
|
||||
+ "code page size: %"PRIu32"B\n"
|
||||
+ "code memory size: %"PRIu32"kB\n",
|
||||
+ ficr[0],
|
||||
+ (ficr[1] * ficr[0]) / 1024);
|
||||
+
|
||||
+ return ERROR_OK;
|
||||
+}
|
||||
+
|
||||
+static const struct command_registration nrf52_exec_command_handlers[] = {
|
||||
+ {
|
||||
+ .name = "mass_erase",
|
||||
+ .handler = nrf52_handle_mass_erase_command,
|
||||
+ .mode = COMMAND_EXEC,
|
||||
+ .help = "Erase all flash contents of the chip.",
|
||||
+ },
|
||||
+ COMMAND_REGISTRATION_DONE
|
||||
+};
|
||||
+
|
||||
+static const struct command_registration nrf52_command_handlers[] = {
|
||||
+ {
|
||||
+ .name = "nrf52",
|
||||
+ .mode = COMMAND_ANY,
|
||||
+ .help = "nrf52 flash command group",
|
||||
+ .usage = "",
|
||||
+ .chain = nrf52_exec_command_handlers,
|
||||
+ },
|
||||
+ COMMAND_REGISTRATION_DONE
|
||||
+};
|
||||
+
|
||||
+struct flash_driver nrf52_flash = {
|
||||
+ .name = "nrf52",
|
||||
+ .commands = nrf52_command_handlers,
|
||||
+ .flash_bank_command = nrf52_flash_bank_command,
|
||||
+ .info = nrf52_info,
|
||||
+ .erase = nrf52_erase,
|
||||
+ .protect = nrf52_protect,
|
||||
+ .write = nrf52_write,
|
||||
+ .read = default_flash_read,
|
||||
+ .probe = nrf52_probe,
|
||||
+ .auto_probe = nrf52_auto_probe,
|
||||
+ .erase_check = default_flash_blank_check,
|
||||
+ .protect_check = nrf52_protect_check,
|
||||
+};
|
||||
diff --git a/tcl/target/nrf52.cfg b/tcl/target/nrf52.cfg
|
||||
index c1cbf1a..41a22ff 100644
|
||||
--- a/tcl/target/nrf52.cfg
|
||||
+++ b/tcl/target/nrf52.cfg
|
||||
@@ -10,6 +10,13 @@ if { [info exists CHIPNAME] } {
|
||||
set _CHIPNAME nrf52
|
||||
}
|
||||
|
||||
+# Work-area is a space in RAM used for flash programming, by default use 16kB.
|
||||
+if { [info exists WORKAREASIZE] } {
|
||||
+ set _WORKAREASIZE $WORKAREASIZE
|
||||
+} else {
|
||||
+ set _WORKAREASIZE 0x4000
|
||||
+}
|
||||
+
|
||||
if { [info exists CPUTAPID] } {
|
||||
set _CPUTAPID $CPUTAPID
|
||||
} else {
|
||||
@@ -22,7 +29,15 @@ set _TARGETNAME $_CHIPNAME.cpu
|
||||
target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME
|
||||
|
||||
adapter_khz 10000
|
||||
+$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
|
||||
|
||||
if { ![using_hla] } {
|
||||
cortex_m reset_config sysresetreq
|
||||
}
|
||||
+
|
||||
+flash bank $_CHIPNAME.flash nrf52 0x00000000 0 1 1 $_TARGETNAME
|
||||
+flash bank $_CHIPNAME.uicr nrf52 0x10001000 0 1 1 $_TARGETNAME
|
||||
+
|
||||
+adapter_khz 1000
|
||||
+
|
||||
+$_TARGETNAME configure -event reset-end {}
|
Reference in New Issue