diff options
| author | Malte Frank Gerdes <malte.f.gerdes@gmail.com> | 2020-10-10 15:31:14 +0200 |
|---|---|---|
| committer | Ludovic Courtès <ludo@gnu.org> | 2020-10-22 17:10:25 +0200 |
| commit | cad55e91fd5a481279e6286a2728761b8da7c07a (patch) | |
| tree | 11ba19040d5b5747390ff7f08827c4104943cd0b /gnu | |
| parent | 2eacb95ad50ff75ed303207aa4141906175df5ce (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.mk | 2 | ||||
| -rw-r--r-- | gnu/packages/embedded.scm | 124 | ||||
| -rw-r--r-- | gnu/packages/patches/openocd-nrf52.patch | 827 |
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 | ||
| 576 | with a layered architecture of JTAG interface and TAP support.") | 580 | with 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 @@ | |||
| 1 | This 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 | ||
| 3 | merged yet in master. | ||
| 4 | |||
| 5 | From: Michael Dietz <mjdietzx@gmail.com> | ||
| 6 | Date: Mon, 30 May 2016 12:50:44 +0000 (-0700) | ||
| 7 | Subject: Added support for nRF52 Series Devices. | ||
| 8 | X-Git-Url: http://openocd.zylin.com/gitweb?p=openocd.git;a=commitdiff_plain;h=9ba15633e221d9d72e320372ba8f49d3f30d4bce | ||
| 9 | |||
| 10 | Added support for nRF52 Series Devices. | ||
| 11 | |||
| 12 | Both 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 | |||
| 19 | Change-Id: I4dd42c86f33f450709bb981806c2655f04aa6201 | ||
| 20 | Signed-off-by: Michael Dietz <mjdietzx@gmail.com> | ||
| 21 | --- | ||
| 22 | |||
| 23 | diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am | ||
| 24 | index 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 \ | ||
| 35 | diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c | ||
| 36 | index 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, | ||
| 55 | diff --git a/src/flash/nor/nrf52.c b/src/flash/nor/nrf52.c | ||
| 56 | new file mode 100644 | ||
| 57 | index 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(®_params[0], "r0", 32, PARAM_IN_OUT); /* byte count */ | ||
| 465 | + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer start */ | ||
| 466 | + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer end */ | ||
| 467 | + init_reg_param(®_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(®_params[0]); | ||
| 485 | + destroy_reg_param(®_params[1]); | ||
| 486 | + destroy_reg_param(®_params[2]); | ||
| 487 | + destroy_reg_param(®_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 | +}; | ||
| 794 | diff --git a/tcl/target/nrf52.cfg b/tcl/target/nrf52.cfg | ||
| 795 | index 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 {} | ||
