summaryrefslogtreecommitdiff
path: root/gnu
diff options
context:
space:
mode:
authorMalte Frank Gerdes <malte.f.gerdes@gmail.com>2020-10-10 15:31:14 +0200
committerLudovic Courtès <ludo@gnu.org>2020-10-22 17:10:25 +0200
commitcad55e91fd5a481279e6286a2728761b8da7c07a (patch)
tree11ba19040d5b5747390ff7f08827c4104943cd0b /gnu
parent2eacb95ad50ff75ed303207aa4141906175df5ce (diff)
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>
Diffstat (limited to 'gnu')
-rw-r--r--gnu/local.mk2
-rw-r--r--gnu/packages/embedded.scm124
-rw-r--r--gnu/packages/patches/openocd-nrf52.patch827
3 files changed, 65 insertions, 888 deletions
diff --git a/gnu/local.mk b/gnu/local.mk
index 607f78b1f3a..31385d0db61 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -37,6 +37,7 @@
37# Copyright © 2020 Brice Waegeneire <brice@waegenei.re> 37# Copyright © 2020 Brice Waegeneire <brice@waegenei.re>
38# Copyright © 2020 Tanguy Le Carrour <tanguy@bioneland.org> 38# Copyright © 2020 Tanguy Le Carrour <tanguy@bioneland.org>
39# Copyright © 2020 Martin Becze <mjbecze@riseup.net> 39# Copyright © 2020 Martin Becze <mjbecze@riseup.net>
40# Copyright © 2020 Malte Frank Gerdes <mate.f.gerdes@gmail.com>
40# 41#
41# This file is part of GNU Guix. 42# This file is part of GNU Guix.
42# 43#
@@ -1393,7 +1394,6 @@ dist_patch_DATA = \
1393 %D%/packages/patches/openfoam-4.1-cleanup.patch \ 1394 %D%/packages/patches/openfoam-4.1-cleanup.patch \
1394 %D%/packages/patches/openjdk-10-idlj-reproducibility.patch \ 1395 %D%/packages/patches/openjdk-10-idlj-reproducibility.patch \
1395 %D%/packages/patches/openmpi-mtl-priorities.patch \ 1396 %D%/packages/patches/openmpi-mtl-priorities.patch \
1396 %D%/packages/patches/openocd-nrf52.patch \
1397 %D%/packages/patches/openssh-hurd.patch \ 1397 %D%/packages/patches/openssh-hurd.patch \
1398 %D%/packages/patches/openresolv-restartcmd-guix.patch \ 1398 %D%/packages/patches/openresolv-restartcmd-guix.patch \
1399 %D%/packages/patches/openscad-parser-boost-1.72.patch \ 1399 %D%/packages/patches/openscad-parser-boost-1.72.patch \
diff --git a/gnu/packages/embedded.scm b/gnu/packages/embedded.scm
index 1eacb72a45a..cc26b17ea61 100644
--- a/gnu/packages/embedded.scm
+++ b/gnu/packages/embedded.scm
@@ -514,67 +514,71 @@ language.")
514 (license license:bsd-2))) 514 (license license:bsd-2)))
515 515
516(define-public openocd 516(define-public openocd
517 (package 517 (let ((commit "9a877a83a1c8b1f105cdc0de46c5cbc4d9e8799e")
518 (name "openocd") 518 (revision "0"))
519 (version "0.10.0") 519 (package
520 (source (origin 520 (name "openocd")
521 (method url-fetch) 521 (version (string-append "0.10.0-" revision "."
522 (uri (string-append "mirror://sourceforge/openocd/openocd/" 522 (string-take commit 7)))
523 version "/openocd-" version ".tar.gz")) 523 (source (origin
524 (sha256 524 (method git-fetch)
525 (base32 525 (uri (git-reference
526 "09p57y3c2spqx4vjjlz1ljm1lcd0j9q8g76ywxqgn3yc34wv18zd")) 526 (url "https://git.code.sf.net/p/openocd/code")
527 ;; FIXME: Remove after nrf52 patch is merged. 527 (commit commit)))
528 (patches 528 (file-name (string-append name "-" version "-checkout"))
529 (search-patches "openocd-nrf52.patch")))) 529 (sha256
530 (build-system gnu-build-system) 530 (base32
531 (native-inputs 531 "1q536cp80v2bcy6xwk08f1r2ljyw13jchx3a1z7d3ni3vqql7rc6"))))
532 `(("autoconf" ,autoconf) 532 (build-system gnu-build-system)
533 ("automake" ,automake) 533 (native-inputs
534 ("libtool" ,libtool) 534 `(("autoconf" ,autoconf)
535 ("pkg-config" ,pkg-config))) 535 ("automake" ,automake)
536 (inputs 536 ("libtool" ,libtool)
537 `(("hidapi" ,hidapi) 537 ("which" ,base:which)
538 ("jimtcl" ,jimtcl) 538 ("pkg-config" ,pkg-config)))
539 ("libftdi" ,libftdi) 539 (inputs
540 ("libjaylink" ,libjaylink) 540 `(("hidapi" ,hidapi)
541 ("libusb-compat" ,libusb-compat))) 541 ("jimtcl" ,jimtcl)
542 (arguments 542 ("libftdi" ,libftdi)
543 '(#:configure-flags 543 ("libjaylink" ,libjaylink)
544 (append (list "--disable-werror" 544 ("libusb-compat" ,libusb-compat)))
545 "--enable-sysfsgpio" 545 (arguments
546 "--disable-internal-jimtcl" 546 '(#:configure-flags
547 "--disable-internal-libjaylink") 547 (append (list "--disable-werror"
548 (map (lambda (programmer) 548 "--enable-sysfsgpio"
549 (string-append "--enable-" programmer)) 549 "--disable-internal-jimtcl"
550 '("amtjtagaccel" "armjtagew" "buspirate" "ftdi" 550 "--disable-internal-libjaylink")
551 "gw16012" "jlink" "opendous" "osbdm" 551 (map (lambda (programmer)
552 "parport" "aice" "cmsis-dap" "dummy" "jtag_vpi" 552 (string-append "--enable-" programmer))
553 "remote-bitbang" "rlink" "stlink" "ti-icdi" "ulink" 553 '("amtjtagaccel" "armjtagew" "buspirate" "ftdi"
554 "usbprog" "vsllink" "usb-blaster-2" "usb_blaster" 554 "gw16012" "jlink" "opendous" "osbdm"
555 "presto" "openjtag"))) 555 "parport" "aice" "cmsis-dap" "dummy" "jtag_vpi"
556 #:phases 556 "remote-bitbang" "rlink" "stlink" "ti-icdi" "ulink"
557 (modify-phases %standard-phases 557 "usbprog" "vsllink" "usb-blaster-2" "usb_blaster"
558 ;; Required because of patched sources. 558 "presto" "openjtag")))
559 (add-before 'configure 'autoreconf 559 #:phases
560 (lambda _ (invoke "autoreconf" "-vfi") #t)) 560 (modify-phases %standard-phases
561 (add-after 'autoreconf 'change-udev-group 561 (replace 'bootstrap
562 (lambda _ 562 (lambda _
563 (substitute* "contrib/60-openocd.rules" 563 (patch-shebang "bootstrap")
564 (("plugdev") "dialout")) 564 (invoke "./bootstrap" "nosubmodule")))
565 #t)) 565 (add-after 'autoreconf 'change-udev-group
566 (add-after 'install 'install-udev-rules 566 (lambda _
567 (lambda* (#:key outputs #:allow-other-keys) 567 (substitute* "contrib/60-openocd.rules"
568 (install-file "contrib/60-openocd.rules" 568 (("plugdev") "dialout"))
569 (string-append 569 #t))
570 (assoc-ref outputs "out") 570 (add-after 'install 'install-udev-rules
571 "/lib/udev/rules.d/")) 571 (lambda* (#:key outputs #:allow-other-keys)
572 #t))))) 572 (install-file "contrib/60-openocd.rules"
573 (home-page "http://openocd.org") 573 (string-append
574 (synopsis "On-Chip Debugger") 574 (assoc-ref outputs "out")
575 (description "OpenOCD provides on-chip programming and debugging support 575 "/lib/udev/rules.d/"))
576 #t)))))
577 (home-page "http://openocd.org")
578 (synopsis "On-Chip Debugger")
579 (description "OpenOCD provides on-chip programming and debugging support
576with a layered architecture of JTAG interface and TAP support.") 580with a layered architecture of JTAG interface and TAP support.")
577 (license license:gpl2+))) 581 (license license:gpl2+))))
578 582
579;; The commits for all propeller tools are the stable versions published at 583;; The commits for all propeller tools are the stable versions published at
580;; https://github.com/propellerinc/propgcc in the release_1_0. According to 584;; https://github.com/propellerinc/propgcc in the release_1_0. According to
diff --git a/gnu/packages/patches/openocd-nrf52.patch b/gnu/packages/patches/openocd-nrf52.patch
deleted file mode 100644
index 0ec4348cb4f..00000000000
--- a/gnu/packages/patches/openocd-nrf52.patch
+++ /dev/null
@@ -1,827 +0,0 @@
1This patch adds support for nRF52 series devices. It is patchset 7 from
2<http://openocd.zylin.com/#/c/3511/>, which has been tested, but not
3merged yet in master.
4
5From: Michael Dietz <mjdietzx@gmail.com>
6Date: Mon, 30 May 2016 12:50:44 +0000 (-0700)
7Subject: Added support for nRF52 Series Devices.
8X-Git-Url: http://openocd.zylin.com/gitweb?p=openocd.git;a=commitdiff_plain;h=9ba15633e221d9d72e320372ba8f49d3f30d4bce
9
10Added support for nRF52 Series Devices.
11
12Both nrf52.c and nrf52.cfg are based off of previous nRF51 files.
13- Some possible race conditions with NVMC have been fixed in nRF52.c
14- Removed nrf51_get_probed_chip_if_halted() as the core does not have to be halted to perform operations where it is called.
15- Only registers that are needed by openOCD are defined, some registers in nRF51 don't exist in nRF52 and are removed.
16- Some all around cleanup has been done.
17- The protection mechanism is completely different on nRF52 and this has not been implemented yet - just prints a warning and returns for now.
18
19Change-Id: I4dd42c86f33f450709bb981806c2655f04aa6201
20Signed-off-by: Michael Dietz <mjdietzx@gmail.com>
21---
22
23diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
24index 727e4f2..839667c 100644
25--- a/src/flash/nor/Makefile.am
26+++ b/src/flash/nor/Makefile.am
27@@ -36,6 +36,7 @@ NOR_DRIVERS = \
28 %D%/niietcm4.c \
29 %D%/non_cfi.c \
30 %D%/nrf51.c \
31+ %D%/nrf52.c \
32 %D%/numicro.c \
33 %D%/ocl.c \
34 %D%/pic32mx.c \
35diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
36index 56a5cb2..071273e 100644
37--- a/src/flash/nor/drivers.c
38+++ b/src/flash/nor/drivers.c
39@@ -48,6 +48,7 @@ extern struct flash_driver mdr_flash;
40 extern struct flash_driver mrvlqspi_flash;
41 extern struct flash_driver niietcm4_flash;
42 extern struct flash_driver nrf51_flash;
43+extern struct flash_driver nrf52_flash;
44 extern struct flash_driver numicro_flash;
45 extern struct flash_driver ocl_flash;
46 extern struct flash_driver pic32mx_flash;
47@@ -100,6 +101,7 @@ static struct flash_driver *flash_drivers[] = {
48 &mrvlqspi_flash,
49 &niietcm4_flash,
50 &nrf51_flash,
51+ &nrf52_flash,
52 &numicro_flash,
53 &ocl_flash,
54 &pic32mx_flash,
55diff --git a/src/flash/nor/nrf52.c b/src/flash/nor/nrf52.c
56new file mode 100644
57index 0000000..7f2bd35
58--- /dev/null
59+++ b/src/flash/nor/nrf52.c
60@@ -0,0 +1,733 @@
61+/***************************************************************************
62+ * Copyright (C) 2013 Synapse Product Development *
63+ * Andrey Smirnov <andrew.smironv@gmail.com> *
64+ * Angus Gratton <gus@projectgus.com> *
65+ * Erdem U. Altunyurt <spamjunkeater@gmail.com> *
66+ * *
67+ * This program is free software; you can redistribute it and/or modify *
68+ * it under the terms of the GNU General Public License as published by *
69+ * the Free Software Foundation; either version 2 of the License, or *
70+ * (at your option) any later version. *
71+ * *
72+ * This program is distributed in the hope that it will be useful, *
73+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
74+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
75+ * GNU General Public License for more details. *
76+ * *
77+ * You should have received a copy of the GNU General Public License *
78+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
79+ ***************************************************************************/
80+
81+#ifdef HAVE_CONFIG_H
82+#include "config.h"
83+#endif
84+
85+#include <stdlib.h>
86+
87+#include "imp.h"
88+#include <target/algorithm.h>
89+#include <target/armv7m.h>
90+#include <helper/types.h>
91+
92+/* nRF52 Register addresses used by openOCD. */
93+#define NRF52_FLASH_BASE_ADDR (0x0)
94+
95+#define NRF52_FICR_BASE_ADDR (0x10000000)
96+#define NRF52_FICR_CODEPAGESIZE_ADDR (NRF52_FICR_BASE_ADDR | 0x010)
97+#define NRF52_FICR_CODESIZE_ADDR (NRF52_FICR_BASE_ADDR | 0x014)
98+
99+#define NRF52_UICR_BASE_ADDR (0x10001000)
100+
101+#define NRF52_NVMC_BASE_ADDR (0x4001E000)
102+#define NRF52_NVMC_READY_ADDR (NRF52_NVMC_BASE_ADDR | 0x400)
103+#define NRF52_NVMC_CONFIG_ADDR (NRF52_NVMC_BASE_ADDR | 0x504)
104+#define NRF52_NVMC_ERASEPAGE_ADDR (NRF52_NVMC_BASE_ADDR | 0x508)
105+#define NRF52_NVMC_ERASEALL_ADDR (NRF52_NVMC_BASE_ADDR | 0x50C)
106+#define NRF52_NVMC_ERASEUICR_ADDR (NRF52_NVMC_BASE_ADDR | 0x514)
107+
108+/* nRF52 bit fields. */
109+enum nrf52_nvmc_config_bits {
110+ NRF52_NVMC_CONFIG_REN = 0x0,
111+ NRF52_NVMC_CONFIG_WEN = 0x01,
112+ NRF52_NVMC_CONFIG_EEN = 0x02
113+};
114+
115+enum nrf52_nvmc_ready_bits {
116+ NRF52_NVMC_BUSY = 0x0,
117+ NRF52_NVMC_READY = 0x01
118+};
119+
120+/* nRF52 state information. */
121+struct nrf52_info {
122+ uint32_t code_page_size; /* Size of FLASH page in bytes. */
123+ uint32_t code_memory_size; /* Size of Code FLASH region in bytes. */
124+
125+ struct {
126+ bool probed;
127+ int (*write) (struct flash_bank *bank,
128+ struct nrf52_info *chip,
129+ const uint8_t *buffer, uint32_t offset, uint32_t count);
130+ } bank[2]; /* There are two regions in nRF52 FLASH - Code and UICR. */
131+ struct target *target;
132+};
133+
134+static int nrf52_protect_check(struct flash_bank *bank);
135+
136+static int nrf52_probe(struct flash_bank *bank)
137+{
138+ int res;
139+ struct nrf52_info *chip = bank->driver_priv;
140+ assert(chip != NULL);
141+
142+ res = target_read_u32(chip->target,
143+ NRF52_FICR_CODEPAGESIZE_ADDR,
144+ &chip->code_page_size);
145+ if (res != ERROR_OK) {
146+ LOG_ERROR("Couldn't read code page size");
147+ return res;
148+ }
149+
150+ res = target_read_u32(chip->target,
151+ NRF52_FICR_CODESIZE_ADDR,
152+ &chip->code_memory_size);
153+ if (res != ERROR_OK) {
154+ LOG_ERROR("Couldn't read code memory size");
155+ return res;
156+ }
157+
158+ chip->code_memory_size = chip->code_memory_size * chip->code_page_size;
159+
160+ if (bank->base == NRF52_FLASH_BASE_ADDR) {
161+ bank->size = chip->code_memory_size;
162+ bank->num_sectors = bank->size / chip->code_page_size;
163+ bank->sectors = calloc(bank->num_sectors,
164+ sizeof((bank->sectors)[0]));
165+ if (!bank->sectors)
166+ return ERROR_FLASH_BANK_NOT_PROBED;
167+
168+ /* Fill out the sector information: All nRF51 sectors are the same size. */
169+ for (int i = 0; i < bank->num_sectors; i++) {
170+ bank->sectors[i].size = chip->code_page_size;
171+ bank->sectors[i].offset = i * chip->code_page_size;
172+
173+ /* Mark as unknown. */
174+ bank->sectors[i].is_erased = -1;
175+ bank->sectors[i].is_protected = -1;
176+ }
177+
178+ nrf52_protect_check(bank);
179+
180+ chip->bank[0].probed = true;
181+ } else { /* This is the UICR bank. */
182+ bank->size = chip->code_page_size;
183+ bank->num_sectors = 1;
184+ bank->sectors = calloc(bank->num_sectors,
185+ sizeof((bank->sectors)[0]));
186+ if (!bank->sectors)
187+ return ERROR_FLASH_BANK_NOT_PROBED;
188+
189+ bank->sectors[0].size = bank->size;
190+ bank->sectors[0].offset = 0;
191+
192+ bank->sectors[0].is_erased = -1;
193+ bank->sectors[0].is_protected = -1;
194+
195+ chip->bank[1].probed = true;
196+ }
197+
198+ return ERROR_OK;
199+}
200+
201+static int nrf52_bank_is_probed(struct flash_bank *bank)
202+{
203+ struct nrf52_info *chip = bank->driver_priv;
204+ assert(chip != NULL);
205+
206+ return chip->bank[bank->bank_number].probed;
207+}
208+
209+static int nrf52_auto_probe(struct flash_bank *bank)
210+{
211+ if (!nrf52_bank_is_probed(bank))
212+ return nrf52_probe(bank);
213+ else
214+ return ERROR_OK;
215+}
216+
217+static int nrf52_wait_for_nvmc(struct nrf52_info *chip)
218+{
219+ int res;
220+ uint32_t ready;
221+ int timeout = 100;
222+
223+ do {
224+ res = target_read_u32(chip->target, NRF52_NVMC_READY_ADDR, &ready);
225+ if (res != ERROR_OK) {
226+ LOG_ERROR("Couldn't read NVMC_READY register");
227+ return res;
228+ }
229+
230+ if (ready == NRF52_NVMC_READY)
231+ return ERROR_OK;
232+
233+ alive_sleep(1);
234+ } while (timeout--);
235+
236+ LOG_DEBUG("Timed out waiting for the NVMC to be ready");
237+ return ERROR_FLASH_BUSY;
238+}
239+
240+static int nrf52_nvmc_erase_enable(struct nrf52_info *chip)
241+{
242+ int res;
243+
244+ res = nrf52_wait_for_nvmc(chip);
245+ if (res != ERROR_OK)
246+ return res;
247+
248+ res = target_write_u32(chip->target,
249+ NRF52_NVMC_CONFIG_ADDR,
250+ NRF52_NVMC_CONFIG_EEN);
251+ if (res != ERROR_OK) {
252+ LOG_ERROR("Failed to configure the NVMC for erasing");
253+ return res;
254+ }
255+
256+ return res;
257+}
258+
259+static int nrf52_nvmc_write_enable(struct nrf52_info *chip)
260+{
261+ int res;
262+
263+ res = nrf52_wait_for_nvmc(chip);
264+ if (res != ERROR_OK)
265+ return res;
266+
267+ res = target_write_u32(chip->target,
268+ NRF52_NVMC_CONFIG_ADDR,
269+ NRF52_NVMC_CONFIG_WEN);
270+ if (res != ERROR_OK) {
271+ LOG_ERROR("Failed to configure the NVMC for writing");
272+ return res;
273+ }
274+
275+ return res;
276+}
277+
278+static int nrf52_nvmc_read_only(struct nrf52_info *chip)
279+{
280+ int res;
281+
282+ res = nrf52_wait_for_nvmc(chip);
283+ if (res != ERROR_OK)
284+ return res;
285+
286+ res = target_write_u32(chip->target,
287+ NRF52_NVMC_CONFIG_ADDR,
288+ NRF52_NVMC_CONFIG_REN);
289+ if (res != ERROR_OK) {
290+ LOG_ERROR("Failed to configure the NVMC for read-only");
291+ return res;
292+ }
293+
294+ return res;
295+}
296+
297+static int nrf52_nvmc_generic_erase(struct nrf52_info *chip,
298+ uint32_t erase_register,
299+ uint32_t erase_value)
300+{
301+ int res;
302+
303+ res = nrf52_nvmc_erase_enable(chip);
304+ if (res != ERROR_OK)
305+ return res;
306+
307+ res = target_write_u32(chip->target,
308+ erase_register,
309+ erase_value);
310+ if (res != ERROR_OK)
311+ LOG_ERROR("Failed to write NVMC erase register");
312+
313+ return nrf52_nvmc_read_only(chip);
314+}
315+
316+static int nrf52_protect_check(struct flash_bank *bank)
317+{
318+ LOG_WARNING("nrf52_protect_check() is not implemented for nRF52 series devices yet");
319+ return ERROR_OK;
320+}
321+
322+static int nrf52_protect(struct flash_bank *bank, int set, int first, int last)
323+{
324+ LOG_WARNING("nrf52_protect() is not implemented for nRF52 series devices yet");
325+ return ERROR_OK;
326+}
327+
328+static struct flash_sector *nrf52_find_sector_by_address(struct flash_bank *bank, uint32_t address)
329+{
330+ struct nrf52_info *chip = bank->driver_priv;
331+ assert(chip != NULL);
332+
333+ for (int i = 0; i < bank->num_sectors; i++)
334+ if (bank->sectors[i].offset <= address &&
335+ address < (bank->sectors[i].offset + chip->code_page_size)) {
336+ return &bank->sectors[i];
337+ }
338+
339+ return NULL;
340+}
341+
342+static int nrf52_erase_all(struct nrf52_info *chip)
343+{
344+ LOG_DEBUG("Erasing all non-volatile memory");
345+ return nrf52_nvmc_generic_erase(chip,
346+ NRF52_NVMC_ERASEALL_ADDR,
347+ 0x01);
348+}
349+
350+static int nrf52_erase_page(struct flash_bank *bank,
351+ struct nrf52_info *chip,
352+ struct flash_sector *sector)
353+{
354+ int res;
355+
356+ LOG_DEBUG("Erasing page at 0x%"PRIx32, sector->offset);
357+ if (sector->is_protected == 1) {
358+ LOG_ERROR("Cannot erase protected sector at 0x%" PRIx32, sector->offset);
359+ return ERROR_FAIL;
360+ }
361+
362+ if (bank->base == NRF52_UICR_BASE_ADDR) {
363+ res = nrf52_nvmc_generic_erase(chip,
364+ NRF52_NVMC_ERASEUICR_ADDR,
365+ 0x00000001);
366+ } else {
367+ res = nrf52_nvmc_generic_erase(chip,
368+ NRF52_NVMC_ERASEPAGE_ADDR,
369+ sector->offset);
370+ }
371+
372+ if (res == ERROR_OK)
373+ sector->is_erased = 1;
374+ return res;
375+}
376+
377+static const uint8_t nrf52_flash_write_code[] = {
378+ /* See contrib/loaders/flash/cortex-m0.S */
379+ /* <wait_fifo>: */
380+ 0x0d, 0x68, /* ldr r5, [r1, #0] */
381+ 0x00, 0x2d, /* cmp r5, #0 */
382+ 0x0b, 0xd0, /* beq.n 1e <exit> */
383+ 0x4c, 0x68, /* ldr r4, [r1, #4] */
384+ 0xac, 0x42, /* cmp r4, r5 */
385+ 0xf9, 0xd0, /* beq.n 0 <wait_fifo> */
386+ 0x20, 0xcc, /* ldmia r4!, {r5} */
387+ 0x20, 0xc3, /* stmia r3!, {r5} */
388+ 0x94, 0x42, /* cmp r4, r2 */
389+ 0x01, 0xd3, /* bcc.n 18 <no_wrap> */
390+ 0x0c, 0x46, /* mov r4, r1 */
391+ 0x08, 0x34, /* adds r4, #8 */
392+ /* <no_wrap>: */
393+ 0x4c, 0x60, /* str r4, [r1, #4] */
394+ 0x04, 0x38, /* subs r0, #4 */
395+ 0xf0, 0xd1, /* bne.n 0 <wait_fifo> */
396+ /* <exit>: */
397+ 0x00, 0xbe /* bkpt 0x0000 */
398+};
399+
400+
401+/* Start a low level flash write for the specified region */
402+static int nrf52_ll_flash_write(struct nrf52_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes)
403+{
404+ struct target *target = chip->target;
405+ uint32_t buffer_size = 8192;
406+ struct working_area *write_algorithm;
407+ struct working_area *source;
408+ uint32_t address = NRF52_FLASH_BASE_ADDR + offset;
409+ struct reg_param reg_params[4];
410+ struct armv7m_algorithm armv7m_info;
411+ int retval = ERROR_OK;
412+
413+ LOG_DEBUG("Writing buffer to flash offset=0x%"PRIx32" bytes=0x%"PRIx32, offset, bytes);
414+ assert(bytes % 4 == 0);
415+
416+ /* allocate working area with flash programming code */
417+ if (target_alloc_working_area(target, sizeof(nrf52_flash_write_code),
418+ &write_algorithm) != ERROR_OK) {
419+ LOG_WARNING("no working area available, falling back to slow memory writes");
420+
421+ for (; bytes > 0; bytes -= 4) {
422+ retval = target_write_memory(chip->target,
423+ offset, 4, 1, buffer);
424+ if (retval != ERROR_OK)
425+ return retval;
426+
427+ retval = nrf52_wait_for_nvmc(chip);
428+ if (retval != ERROR_OK)
429+ return retval;
430+
431+ offset += 4;
432+ buffer += 4;
433+ }
434+
435+ return ERROR_OK;
436+ }
437+
438+ LOG_WARNING("using fast async flash loader. This is currently supported");
439+ LOG_WARNING("only with ST-Link and CMSIS-DAP. If you have issues, add");
440+ LOG_WARNING("\"set WORKAREASIZE 0\" before sourcing nrf52.cfg to disable it");
441+
442+ retval = target_write_buffer(target, write_algorithm->address,
443+ sizeof(nrf52_flash_write_code),
444+ nrf52_flash_write_code);
445+ if (retval != ERROR_OK)
446+ return retval;
447+
448+ /* memory buffer */
449+ while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) {
450+ buffer_size /= 2;
451+ buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */
452+ if (buffer_size <= 256) {
453+ /* free working area, write algorithm already allocated */
454+ target_free_working_area(target, write_algorithm);
455+
456+ LOG_WARNING("No large enough working area available, can't do block memory writes");
457+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
458+ }
459+ }
460+
461+ armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
462+ armv7m_info.core_mode = ARM_MODE_THREAD;
463+
464+ init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT); /* byte count */
465+ init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* buffer start */
466+ init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* buffer end */
467+ init_reg_param(&reg_params[3], "r3", 32, PARAM_IN_OUT); /* target address */
468+
469+ buf_set_u32(reg_params[0].value, 0, 32, bytes);
470+ buf_set_u32(reg_params[1].value, 0, 32, source->address);
471+ buf_set_u32(reg_params[2].value, 0, 32, source->address + source->size);
472+ buf_set_u32(reg_params[3].value, 0, 32, address);
473+
474+ retval = target_run_flash_async_algorithm(target, buffer, bytes/4, 4,
475+ 0, NULL,
476+ 4, reg_params,
477+ source->address, source->size,
478+ write_algorithm->address, 0,
479+ &armv7m_info);
480+
481+ target_free_working_area(target, source);
482+ target_free_working_area(target, write_algorithm);
483+
484+ destroy_reg_param(&reg_params[0]);
485+ destroy_reg_param(&reg_params[1]);
486+ destroy_reg_param(&reg_params[2]);
487+ destroy_reg_param(&reg_params[3]);
488+
489+ return retval;
490+}
491+
492+/* Check and erase flash sectors in specified range, then start a low level page write.
493+ start/end must be sector aligned.
494+*/
495+static int nrf52_write_pages(struct flash_bank *bank, uint32_t start, uint32_t end, const uint8_t *buffer)
496+{
497+ int res;
498+ uint32_t offset;
499+ struct flash_sector *sector;
500+ struct nrf52_info *chip = bank->driver_priv;
501+ assert(chip != NULL);
502+
503+ assert(start % chip->code_page_size == 0);
504+ assert(end % chip->code_page_size == 0);
505+
506+ /* Erase all sectors */
507+ for (offset = start; offset < end; offset += chip->code_page_size) {
508+ sector = nrf52_find_sector_by_address(bank, offset);
509+
510+ if (sector == NULL) {
511+ LOG_ERROR("Invalid sector @ 0x%08"PRIx32, offset);
512+ return ERROR_FLASH_SECTOR_INVALID;
513+ }
514+
515+ if (sector->is_protected == 1) {
516+ LOG_ERROR("Can't erase protected sector @ 0x%08"PRIx32, offset);
517+ return ERROR_FAIL;
518+ }
519+
520+ if (sector->is_erased != 1) { /* 1 = erased, 0= not erased, -1 = unknown */
521+ res = nrf52_erase_page(bank, chip, sector);
522+ if (res != ERROR_OK) {
523+ LOG_ERROR("Failed to erase sector @ 0x%08"PRIx32, sector->offset);
524+ return res;
525+ }
526+ }
527+ sector->is_erased = 1;
528+ }
529+
530+ res = nrf52_nvmc_write_enable(chip);
531+ if (res != ERROR_OK)
532+ return res;
533+
534+ res = nrf52_ll_flash_write(chip, start, buffer, (end - start));
535+ if (res != ERROR_OK) {
536+ LOG_ERROR("Failed to write FLASH");
537+ nrf52_nvmc_read_only(chip);
538+ return res;
539+ }
540+
541+ return nrf52_nvmc_read_only(chip);
542+}
543+
544+static int nrf52_erase(struct flash_bank *bank, int first, int last)
545+{
546+ int res = ERROR_OK;
547+ struct nrf52_info *chip = bank->driver_priv;
548+ assert(chip != NULL);
549+
550+ /* For each sector to be erased */
551+ for (int s = first; s <= last && res == ERROR_OK; s++)
552+ res = nrf52_erase_page(bank, chip, &bank->sectors[s]);
553+
554+ return res;
555+}
556+
557+static int nrf52_code_flash_write(struct flash_bank *bank,
558+ struct nrf52_info *chip,
559+ const uint8_t *buffer, uint32_t offset, uint32_t count)
560+{
561+ int res;
562+ /* Need to perform reads to fill any gaps we need to preserve in the first page,
563+ before the start of buffer, or in the last page, after the end of buffer */
564+ uint32_t first_page = offset / chip->code_page_size;
565+ uint32_t last_page = DIV_ROUND_UP(offset+count, chip->code_page_size);
566+
567+ uint32_t first_page_offset = first_page * chip->code_page_size;
568+ uint32_t last_page_offset = last_page * chip->code_page_size;
569+
570+ LOG_DEBUG("Padding write from 0x%08"PRIx32"-0x%08"PRIx32" as 0x%08"PRIx32"-0x%08"PRIx32,
571+ offset, offset+count, first_page_offset, last_page_offset);
572+
573+ uint32_t page_cnt = last_page - first_page;
574+ uint8_t buffer_to_flash[page_cnt * chip->code_page_size];
575+
576+ /* Fill in any space between start of first page and start of buffer */
577+ uint32_t pre = offset - first_page_offset;
578+ if (pre > 0) {
579+ res = target_read_memory(bank->target, first_page_offset, 1, pre, buffer_to_flash);
580+ if (res != ERROR_OK)
581+ return res;
582+ }
583+
584+ /* Fill in main contents of buffer */
585+ memcpy(buffer_to_flash + pre, buffer, count);
586+
587+ /* Fill in any space between end of buffer and end of last page */
588+ uint32_t post = last_page_offset - (offset + count);
589+ if (post > 0) {
590+ /* Retrieve the full row contents from Flash */
591+ res = target_read_memory(bank->target, offset + count, 1, post, buffer_to_flash + pre + count);
592+ if (res != ERROR_OK)
593+ return res;
594+ }
595+
596+ return nrf52_write_pages(bank, first_page_offset, last_page_offset, buffer_to_flash);
597+}
598+
599+static int nrf52_uicr_flash_write(struct flash_bank *bank,
600+ struct nrf52_info *chip,
601+ const uint8_t *buffer, uint32_t offset, uint32_t count)
602+{
603+ int res;
604+ uint32_t nrf52_uicr_size = chip->code_page_size;
605+ uint8_t uicr[nrf52_uicr_size];
606+ struct flash_sector *sector = &bank->sectors[0];
607+
608+ if ((offset + count) > nrf52_uicr_size)
609+ return ERROR_FAIL;
610+
611+ res = target_read_memory(bank->target, NRF52_UICR_BASE_ADDR, 1, nrf52_uicr_size, uicr);
612+
613+ if (res != ERROR_OK)
614+ return res;
615+
616+ if (sector->is_erased != 1) {
617+ res = nrf52_erase_page(bank, chip, sector);
618+ if (res != ERROR_OK)
619+ return res;
620+ }
621+
622+ memcpy(&uicr[offset], buffer, count);
623+
624+ res = nrf52_nvmc_write_enable(chip);
625+ if (res != ERROR_OK)
626+ return res;
627+
628+ res = nrf52_ll_flash_write(chip, NRF52_UICR_BASE_ADDR, uicr, nrf52_uicr_size);
629+ if (res != ERROR_OK) {
630+ nrf52_nvmc_read_only(chip);
631+ return res;
632+ }
633+
634+ return nrf52_nvmc_read_only(chip);
635+}
636+
637+
638+static int nrf52_write(struct flash_bank *bank, const uint8_t *buffer,
639+ uint32_t offset, uint32_t count)
640+{
641+ struct nrf52_info *chip = bank->driver_priv;
642+ assert(chip != NULL);
643+
644+ return chip->bank[bank->bank_number].write(bank, chip, buffer, offset, count);
645+}
646+
647+
648+FLASH_BANK_COMMAND_HANDLER(nrf52_flash_bank_command)
649+{
650+ static struct nrf52_info *chip;
651+
652+ assert(bank != NULL);
653+
654+ switch (bank->base) {
655+ case NRF52_FLASH_BASE_ADDR:
656+ bank->bank_number = 0;
657+ break;
658+ case NRF52_UICR_BASE_ADDR:
659+ bank->bank_number = 1;
660+ break;
661+ default:
662+ LOG_ERROR("Invalid bank address 0x%08" PRIx32, bank->base);
663+ return ERROR_FAIL;
664+ }
665+
666+ if (!chip) {
667+ /* Create a new chip */
668+ chip = calloc(1, sizeof(*chip));
669+ assert(chip != NULL);
670+
671+ chip->target = bank->target;
672+ }
673+
674+ switch (bank->base) {
675+ case NRF52_FLASH_BASE_ADDR:
676+ chip->bank[bank->bank_number].write = nrf52_code_flash_write;
677+ break;
678+ case NRF52_UICR_BASE_ADDR:
679+ chip->bank[bank->bank_number].write = nrf52_uicr_flash_write;
680+ break;
681+ }
682+
683+ chip->bank[bank->bank_number].probed = false;
684+ bank->driver_priv = chip;
685+
686+ return ERROR_OK;
687+}
688+
689+COMMAND_HANDLER(nrf52_handle_mass_erase_command)
690+{
691+ int res;
692+ struct flash_bank *bank = NULL;
693+ struct target *target = get_current_target(CMD_CTX);
694+
695+ res = get_flash_bank_by_addr(target, NRF52_FLASH_BASE_ADDR, true, &bank);
696+ if (res != ERROR_OK)
697+ return res;
698+
699+ assert(bank != NULL);
700+
701+ struct nrf52_info *chip = bank->driver_priv;
702+ assert(chip != NULL);
703+
704+ res = nrf52_erase_all(chip);
705+ if (res != ERROR_OK) {
706+ LOG_ERROR("Failed to erase the chip");
707+ nrf52_protect_check(bank);
708+ return res;
709+ }
710+
711+ for (int i = 0; i < bank->num_sectors; i++)
712+ bank->sectors[i].is_erased = 1;
713+
714+ res = nrf52_protect_check(bank);
715+ if (res != ERROR_OK) {
716+ LOG_ERROR("Failed to check chip's write protection");
717+ return res;
718+ }
719+
720+ res = get_flash_bank_by_addr(target, NRF52_UICR_BASE_ADDR, true, &bank);
721+ if (res != ERROR_OK)
722+ return res;
723+
724+ bank->sectors[0].is_erased = 1;
725+
726+ return ERROR_OK;
727+}
728+
729+static int nrf52_info(struct flash_bank *bank, char *buf, int buf_size)
730+{
731+ int res;
732+ uint32_t ficr[2];
733+ struct nrf52_info *chip = bank->driver_priv;
734+ assert(chip != NULL);
735+
736+ res = target_read_u32(chip->target, NRF52_FICR_CODEPAGESIZE_ADDR, &ficr[0]);
737+ if (res != ERROR_OK) {
738+ LOG_ERROR("Couldn't read NVMC_READY register");
739+ return res;
740+ }
741+
742+ res = target_read_u32(chip->target, NRF52_FICR_CODESIZE_ADDR, &ficr[1]);
743+ if (res != ERROR_OK) {
744+ LOG_ERROR("Couldn't read NVMC_READY register");
745+ return res;
746+ }
747+
748+ snprintf(buf, buf_size,
749+ "\n--------nRF52 Series Device--------\n\n"
750+ "\n[factory information control block]\n"
751+ "code page size: %"PRIu32"B\n"
752+ "code memory size: %"PRIu32"kB\n",
753+ ficr[0],
754+ (ficr[1] * ficr[0]) / 1024);
755+
756+ return ERROR_OK;
757+}
758+
759+static const struct command_registration nrf52_exec_command_handlers[] = {
760+ {
761+ .name = "mass_erase",
762+ .handler = nrf52_handle_mass_erase_command,
763+ .mode = COMMAND_EXEC,
764+ .help = "Erase all flash contents of the chip.",
765+ },
766+ COMMAND_REGISTRATION_DONE
767+};
768+
769+static const struct command_registration nrf52_command_handlers[] = {
770+ {
771+ .name = "nrf52",
772+ .mode = COMMAND_ANY,
773+ .help = "nrf52 flash command group",
774+ .usage = "",
775+ .chain = nrf52_exec_command_handlers,
776+ },
777+ COMMAND_REGISTRATION_DONE
778+};
779+
780+struct flash_driver nrf52_flash = {
781+ .name = "nrf52",
782+ .commands = nrf52_command_handlers,
783+ .flash_bank_command = nrf52_flash_bank_command,
784+ .info = nrf52_info,
785+ .erase = nrf52_erase,
786+ .protect = nrf52_protect,
787+ .write = nrf52_write,
788+ .read = default_flash_read,
789+ .probe = nrf52_probe,
790+ .auto_probe = nrf52_auto_probe,
791+ .erase_check = default_flash_blank_check,
792+ .protect_check = nrf52_protect_check,
793+};
794diff --git a/tcl/target/nrf52.cfg b/tcl/target/nrf52.cfg
795index c1cbf1a..41a22ff 100644
796--- a/tcl/target/nrf52.cfg
797+++ b/tcl/target/nrf52.cfg
798@@ -10,6 +10,13 @@ if { [info exists CHIPNAME] } {
799 set _CHIPNAME nrf52
800 }
801
802+# Work-area is a space in RAM used for flash programming, by default use 16kB.
803+if { [info exists WORKAREASIZE] } {
804+ set _WORKAREASIZE $WORKAREASIZE
805+} else {
806+ set _WORKAREASIZE 0x4000
807+}
808+
809 if { [info exists CPUTAPID] } {
810 set _CPUTAPID $CPUTAPID
811 } else {
812@@ -22,7 +29,15 @@ set _TARGETNAME $_CHIPNAME.cpu
813 target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME
814
815 adapter_khz 10000
816+$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
817
818 if { ![using_hla] } {
819 cortex_m reset_config sysresetreq
820 }
821+
822+flash bank $_CHIPNAME.flash nrf52 0x00000000 0 1 1 $_TARGETNAME
823+flash bank $_CHIPNAME.uicr nrf52 0x10001000 0 1 1 $_TARGETNAME
824+
825+adapter_khz 1000
826+
827+$_TARGETNAME configure -event reset-end {}