diff mbox

[v2,3/3] gnu: Add openocd.

Message ID 20161026210807.27390-4-theodoros.for@openmailbox.org
State New
Headers show

Commit Message

Theodoros Foradis Oct. 26, 2016, 9:08 p.m. UTC
* gnu/packages/embedded.scm (openocd): New variable.
* gnu/packages/patches/openocd-nrf52.patch: New file.
* gnu/local.mk (dist_patch_DATA): Add the patch.
---
 gnu/local.mk                             |   1 +
 gnu/packages/embedded.scm                |  70 +++
 gnu/packages/patches/openocd-nrf52.patch | 843 +++++++++++++++++++++++++++++++
 3 files changed, 914 insertions(+)
 create mode 100644 gnu/packages/patches/openocd-nrf52.patch

Comments

Efraim Flashner Oct. 27, 2016, 6:24 a.m. UTC | #1
On Thu, Oct 27, 2016 at 12:08:07AM +0300, Theodoros Foradis wrote:
> * gnu/packages/embedded.scm (openocd): New variable.
> * gnu/packages/patches/openocd-nrf52.patch: New file.
> * gnu/local.mk (dist_patch_DATA): Add the patch.
> ---
>  gnu/local.mk                             |   1 +
>  gnu/packages/embedded.scm                |  70 +++
>  gnu/packages/patches/openocd-nrf52.patch | 843 +++++++++++++++++++++++++++++++
>  3 files changed, 914 insertions(+)
>  create mode 100644 gnu/packages/patches/openocd-nrf52.patch
> 
> diff --git a/gnu/local.mk b/gnu/local.mk
> index 9019b98..b2db850 100644
> --- a/gnu/local.mk
> +++ b/gnu/local.mk
> @@ -742,6 +742,7 @@ dist_patch_DATA =						\
>    %D%/packages/patches/openjpeg-CVE-2016-5157.patch		\
>    %D%/packages/patches/openjpeg-CVE-2016-7163.patch		\
>    %D%/packages/patches/openjpeg-use-after-free-fix.patch	\
> +  %D%/packages/patches/openocd-nrf52.patch			\
>    %D%/packages/patches/openssh-memory-exhaustion.patch		\
>    %D%/packages/patches/openssl-runpath.patch			\
>    %D%/packages/patches/openssl-1.1.0-c-rehash-in.patch		\
> diff --git a/gnu/packages/embedded.scm b/gnu/packages/embedded.scm
> index 0b4f9ab..f65523d 100644
> --- a/gnu/packages/embedded.scm
> +++ b/gnu/packages/embedded.scm
> @@ -28,11 +28,16 @@
>    #:use-module (guix build-system trivial)
>    #:use-module (guix build utils)
>    #:use-module (gnu packages)
> +  #:use-module (gnu packages autotools)
>    #:use-module (gnu packages cross-base)
>    #:use-module (gnu packages flex)
>    #:use-module (gnu packages gcc)
>    #:use-module (gnu packages gdb)
> +  #:use-module (gnu packages hidapi)
> +  #:use-module (gnu packages libftdi)
> +  #:use-module (gnu packages libusb)
>    #:use-module (gnu packages perl)
> +  #:use-module (gnu packages pkg-config)
>    #:use-module (gnu packages texinfo))
>  
>  ;; We must not use the released GCC sources here, because the cross-compiler
> @@ -236,3 +241,68 @@ languages are C and C++.")
>                             "--enable-languages=c,c++"
>                             "--disable-nls")
>       ,@(package-arguments gdb)))))
> +
> +;; We build openocd from git, because the JTAG library libjaylink
> +;; is not included in tarball releases.
> +(define-public openocd
> +  (let* ((commit "674141e8a7a6413cb803d90c2a20150260015f81")
> +         (revision "1"))
> +    (package
> +      (name "openocd")
> +      (version (string-append "0.9.0-" revision "."
> +                              (string-take commit 7)))
> +      (source (origin
> +                (method git-fetch)
> +                (uri (git-reference
> +                      (url (string-append "git://git.code.sf.net/p/" name "/code.git"))
> +                      (commit commit)
> +                      (recursive? #t)))
> +                (sha256
> +                 (base32 "0p8rcqhkx3f29j08w33fkp8xnzj4xxa41lzdfq5wd1i4x8s07s0p"))
> +                (file-name (string-append name "-" version "-checkout.tar.xz"))

    quick nit-pick, since it's a checkout it doesn't need the .tar.xz

> +                (patches
> +                 (search-patches "openocd-nrf52.patch"))))
> +      (build-system gnu-build-system)
> +      (arguments
> +       '(#:configure-flags
> +         (append (list "--disable-werror")
> +                 (map (lambda (programmer)
> +                        (string-append "--enable-" programmer))
> +                      '("amtjtagaccel" "armjtagew" "buspirate" "ftdi"
> +                        "gw16012" "jlink" "oocd_trace" "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
> +           (add-before 'configure 'autoreconf
> +             (lambda _
> +               (zero? (system* "autoreconf" "-vfi"))))
> +           (add-after 'autoreconf 'patch-configure
> +             (lambda _
> +               (substitute* "configure"
> +                 (("SHELL = /bin/sh") (string-append "SHELL = " (which "sh"))))
> +               (substitute* "configure"
> +                 (("srcdir/src/jtag/drivers/libjaylink/configure.gnu")
> +                  (string-append "echo -e '#!" (which "sh") "\nexec \"`dirname \"'\\$'0\"`
> +/configure\" --enable-subproject-build \"'\\$'@\"' > \"
> +$srcdir/src/jtag/drivers/libjaylink/configure.gnu\"")))
> +               #t)))))
> +      (inputs
> +       `(("hidapi" ,hidapi)
> +         ("libftdi" ,libftdi)
> +         ("libusb" ,libusb)
> +         ("libusb-compat" ,libusb-compat)))
> +      (native-inputs
> +       `(("autoconf" ,autoconf)
> +         ("automake" ,automake)
> +         ("libtool" ,libtool)
> +         ("pkg-config" ,pkg-config)))
> +      (home-page "http://openocd.org")
> +      (synopsis "Open On-Chip Debugger")
> +      (description
> +       "OpenOCD provides on-chip programming and debugging support with a
> +layered architecture of JTAG interface and TAP support.")
> +      (license (list license:gpl2       ;; openocd and git2cl submodule
> +                     license:gpl2+      ;; libjaylink submodule
> +                     license:bsd-2))))) ;; jimctl submodule
Ricardo Wurmus Oct. 28, 2016, 6:14 a.m. UTC | #2
Theodoros Foradis <theodoros.for@openmailbox.org> writes:

> +;; We build openocd from git, because the JTAG library libjaylink
> +;; is not included in tarball releases.

Is there a separate release of libjaylink?  Does the git version bundle
libjaylink?  I’d prefer packaging proper releases of libjaylink and
openocd, if that’s the case.

> +(define-public openocd
> +  (let* ((commit "674141e8a7a6413cb803d90c2a20150260015f81")
> +         (revision "1"))
> +    (package
> +      (name "openocd")
> +      (version (string-append "0.9.0-" revision "."
> +                              (string-take commit 7)))
> +      (source (origin
> +                (method git-fetch)
> +                (uri (git-reference
> +                      (url (string-append "git://git.code.sf.net/p/" name "/code.git"))
> +                      (commit commit)
> +                      (recursive? #t)))
> +                (sha256
> +                 (base32 "0p8rcqhkx3f29j08w33fkp8xnzj4xxa41lzdfq5wd1i4x8s07s0p"))
> +                (file-name (string-append name "-" version "-checkout.tar.xz"))
> +                (patches
> +                 (search-patches "openocd-nrf52.patch"))))
> +      (build-system gnu-build-system)
> +      (arguments
> +       '(#:configure-flags
> +         (append (list "--disable-werror")
> +                 (map (lambda (programmer)
> +                        (string-append "--enable-" programmer))
> +                      '("amtjtagaccel" "armjtagew" "buspirate" "ftdi"
> +                        "gw16012" "jlink" "oocd_trace" "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
> +           (add-before 'configure 'autoreconf
> +             (lambda _
> +               (zero? (system* "autoreconf" "-vfi"))))
> +           (add-after 'autoreconf 'patch-configure
> +             (lambda _
> +               (substitute* "configure"
> +                 (("SHELL = /bin/sh") (string-append "SHELL = "
> (which "sh"))))

Is this really necessary?  Or can we just pass “SHELL” as a configure
flag to override?

> +               (substitute* "configure"
> +                 (("srcdir/src/jtag/drivers/libjaylink/configure.gnu")
> +                  (string-append "echo -e '#!" (which "sh") "\nexec \"`dirname \"'\\$'0\"`
> +/configure\" --enable-subproject-build \"'\\$'@\"' > \"
> +$srcdir/src/jtag/drivers/libjaylink/configure.gnu\"")))

This isn’t clear to me.  What happens here?  Why is the additional
configure flag needed?  Could you add a comment as to the intent of this
substitution?

> +               #t)))))
> +      (inputs
> +       `(("hidapi" ,hidapi)
> +         ("libftdi" ,libftdi)
> +         ("libusb" ,libusb)
> +         ("libusb-compat" ,libusb-compat)))

Both libusb AND libusb-compat?

> +      (native-inputs
> +       `(("autoconf" ,autoconf)
> +         ("automake" ,automake)
> +         ("libtool" ,libtool)
> +         ("pkg-config" ,pkg-config)))
> +      (home-page "http://openocd.org")
> +      (synopsis "Open On-Chip Debugger")

s/Open//

I know that that’s what OpenOCD stands for, but everything is free
software (or “open source”) in Guix anyway, so we usually don’t mention
“free” or “open”.

> +      (description
> +       "OpenOCD provides on-chip programming and debugging support with a
> +layered architecture of JTAG interface and TAP support.")
> +      (license (list license:gpl2       ;; openocd and git2cl submodule
> +                     license:gpl2+      ;; libjaylink submodule
> +                     license:bsd-2))))) ;; jimctl submodule

Please use a single “;” for margin comments like this.

> diff --git a/gnu/packages/patches/openocd-nrf52.patch b/gnu/packages/patches/openocd-nrf52.patch
> new file mode 100644
> index 0000000..d136735
> --- /dev/null
> +++ b/gnu/packages/patches/openocd-nrf52.patch
> @@ -0,0 +1,843 @@
> +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.

Nitpick: please use two spaces between sentences and surround the URL in
<…>, so that the space between URL and comma can be removed.

~~ Ricardo
Theodoros Foradis Oct. 28, 2016, 5:36 p.m. UTC | #3
Ricardo Wurmus writes:

> Theodoros Foradis <theodoros.for@openmailbox.org> writes:
>
>> +;; We build openocd from git, because the JTAG library libjaylink
>> +;; is not included in tarball releases.
>
> Is there a separate release of libjaylink?  Does the git version bundle
> libjaylink?  I’d prefer packaging proper releases of libjaylink and
> openocd, if that’s the case.
>

The git version does not bundle libjaylink. It is included in a
submodule. Should it be make clear in that initial comment?

>> +(define-public openocd
>> +  (let* ((commit "674141e8a7a6413cb803d90c2a20150260015f81")
>> +         (revision "1"))
>> +    (package
>> +      (name "openocd")
>> +      (version (string-append "0.9.0-" revision "."
>> +                              (string-take commit 7)))
>> +      (source (origin
>> +                (method git-fetch)
>> +                (uri (git-reference
>> +                      (url (string-append "git://git.code.sf.net/p/" name "/code.git"))
>> +                      (commit commit)
>> +                      (recursive? #t)))
>> +                (sha256
>> +                 (base32 "0p8rcqhkx3f29j08w33fkp8xnzj4xxa41lzdfq5wd1i4x8s07s0p"))
>> +                (file-name (string-append name "-" version "-checkout.tar.xz"))
>> +                (patches
>> +                 (search-patches "openocd-nrf52.patch"))))
>> +      (build-system gnu-build-system)
>> +      (arguments
>> +       '(#:configure-flags
>> +         (append (list "--disable-werror")
>> +                 (map (lambda (programmer)
>> +                        (string-append "--enable-" programmer))
>> +                      '("amtjtagaccel" "armjtagew" "buspirate" "ftdi"
>> +                        "gw16012" "jlink" "oocd_trace" "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
>> +           (add-before 'configure 'autoreconf
>> +             (lambda _
>> +               (zero? (system* "autoreconf" "-vfi"))))
>> +           (add-after 'autoreconf 'patch-configure
>> +             (lambda _
>> +               (substitute* "configure"
>> +                 (("SHELL = /bin/sh") (string-append "SHELL = "
>> (which "sh"))))
>
> Is this really necessary?  Or can we just pass “SHELL” as a configure
> flag to override?
>

This is in fact not necessary, and removed.

>> +               (substitute* "configure"
>> +                 (("srcdir/src/jtag/drivers/libjaylink/configure.gnu")
>> +                  (string-append "echo -e '#!" (which "sh") "\nexec \"`dirname \"'\\$'0\"`
>> +/configure\" --enable-subproject-build \"'\\$'@\"' > \"
>> +$srcdir/src/jtag/drivers/libjaylink/configure.gnu\"")))
>
> This isn’t clear to me.  What happens here?  Why is the additional
> configure flag needed?  Could you add a comment as to the intent of this
> substitution?
>

This substitution was changed, to substitute with an empty string. The
actual intention of the substitution was to replace /bin/sh in the generated
configure.gnu, which proved to be unneeded, so it's just removed, and
the file will be run with the correct /bin/sh.

>> +               #t)))))
>> +      (inputs
>> +       `(("hidapi" ,hidapi)
>> +         ("libftdi" ,libftdi)
>> +         ("libusb" ,libusb)
>> +         ("libusb-compat" ,libusb-compat)))
>
> Both libusb AND libusb-compat?
>

Yes, it won't build without both.

>> +      (native-inputs
>> +       `(("autoconf" ,autoconf)
>> +         ("automake" ,automake)
>> +         ("libtool" ,libtool)
>> +         ("pkg-config" ,pkg-config)))
>> +      (home-page "http://openocd.org")
>> +      (synopsis "Open On-Chip Debugger")
>
> s/Open//
>
> I know that that’s what OpenOCD stands for, but everything is free
> software (or “open source”) in Guix anyway, so we usually don’t mention
> “free” or “open”.
>

Understood. I removed it.

>> +      (description
>> +       "OpenOCD provides on-chip programming and debugging support with a
>> +layered architecture of JTAG interface and TAP support.")
>> +      (license (list license:gpl2       ;; openocd and git2cl submodule
>> +                     license:gpl2+      ;; libjaylink submodule
>> +                     license:bsd-2))))) ;; jimctl submodule
>
> Please use a single “;” for margin comments like this.
>

Done.

>> diff --git a/gnu/packages/patches/openocd-nrf52.patch b/gnu/packages/patches/openocd-nrf52.patch
>> new file mode 100644
>> index 0000000..d136735
>> --- /dev/null
>> +++ b/gnu/packages/patches/openocd-nrf52.patch
>> @@ -0,0 +1,843 @@
>> +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.
>
> Nitpick: please use two spaces between sentences and surround the URL in
> <…>, so that the space between URL and comma can be removed.
>
> ~~ Ricardo

Changed this as well. Thanks for the information, and excuse me for
ignoring those conventions.

I reply to this with the updated patches.

Theodoros Foradis (3):
      gnu: Add gdb-arm-none-eabi.
      gnu: Add hidapi.
      gnu: Add openocd.

 gnu/local.mk                             |   1 +
 gnu/packages/embedded.scm                |  77 ++++++++
 gnu/packages/libusb.scm                  |  38 ++++
 gnu/packages/patches/openocd-nrf52.patch | 843 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 959 insertions(+)
diff mbox

Patch

diff --git a/gnu/local.mk b/gnu/local.mk
index 9019b98..b2db850 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -742,6 +742,7 @@  dist_patch_DATA =						\
   %D%/packages/patches/openjpeg-CVE-2016-5157.patch		\
   %D%/packages/patches/openjpeg-CVE-2016-7163.patch		\
   %D%/packages/patches/openjpeg-use-after-free-fix.patch	\
+  %D%/packages/patches/openocd-nrf52.patch			\
   %D%/packages/patches/openssh-memory-exhaustion.patch		\
   %D%/packages/patches/openssl-runpath.patch			\
   %D%/packages/patches/openssl-1.1.0-c-rehash-in.patch		\
diff --git a/gnu/packages/embedded.scm b/gnu/packages/embedded.scm
index 0b4f9ab..f65523d 100644
--- a/gnu/packages/embedded.scm
+++ b/gnu/packages/embedded.scm
@@ -28,11 +28,16 @@ 
   #:use-module (guix build-system trivial)
   #:use-module (guix build utils)
   #:use-module (gnu packages)
+  #:use-module (gnu packages autotools)
   #:use-module (gnu packages cross-base)
   #:use-module (gnu packages flex)
   #:use-module (gnu packages gcc)
   #:use-module (gnu packages gdb)
+  #:use-module (gnu packages hidapi)
+  #:use-module (gnu packages libftdi)
+  #:use-module (gnu packages libusb)
   #:use-module (gnu packages perl)
+  #:use-module (gnu packages pkg-config)
   #:use-module (gnu packages texinfo))
 
 ;; We must not use the released GCC sources here, because the cross-compiler
@@ -236,3 +241,68 @@  languages are C and C++.")
                            "--enable-languages=c,c++"
                            "--disable-nls")
      ,@(package-arguments gdb)))))
+
+;; We build openocd from git, because the JTAG library libjaylink
+;; is not included in tarball releases.
+(define-public openocd
+  (let* ((commit "674141e8a7a6413cb803d90c2a20150260015f81")
+         (revision "1"))
+    (package
+      (name "openocd")
+      (version (string-append "0.9.0-" revision "."
+                              (string-take commit 7)))
+      (source (origin
+                (method git-fetch)
+                (uri (git-reference
+                      (url (string-append "git://git.code.sf.net/p/" name "/code.git"))
+                      (commit commit)
+                      (recursive? #t)))
+                (sha256
+                 (base32 "0p8rcqhkx3f29j08w33fkp8xnzj4xxa41lzdfq5wd1i4x8s07s0p"))
+                (file-name (string-append name "-" version "-checkout.tar.xz"))
+                (patches
+                 (search-patches "openocd-nrf52.patch"))))
+      (build-system gnu-build-system)
+      (arguments
+       '(#:configure-flags
+         (append (list "--disable-werror")
+                 (map (lambda (programmer)
+                        (string-append "--enable-" programmer))
+                      '("amtjtagaccel" "armjtagew" "buspirate" "ftdi"
+                        "gw16012" "jlink" "oocd_trace" "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
+           (add-before 'configure 'autoreconf
+             (lambda _
+               (zero? (system* "autoreconf" "-vfi"))))
+           (add-after 'autoreconf 'patch-configure
+             (lambda _
+               (substitute* "configure"
+                 (("SHELL = /bin/sh") (string-append "SHELL = " (which "sh"))))
+               (substitute* "configure"
+                 (("srcdir/src/jtag/drivers/libjaylink/configure.gnu")
+                  (string-append "echo -e '#!" (which "sh") "\nexec \"`dirname \"'\\$'0\"`
+/configure\" --enable-subproject-build \"'\\$'@\"' > \"
+$srcdir/src/jtag/drivers/libjaylink/configure.gnu\"")))
+               #t)))))
+      (inputs
+       `(("hidapi" ,hidapi)
+         ("libftdi" ,libftdi)
+         ("libusb" ,libusb)
+         ("libusb-compat" ,libusb-compat)))
+      (native-inputs
+       `(("autoconf" ,autoconf)
+         ("automake" ,automake)
+         ("libtool" ,libtool)
+         ("pkg-config" ,pkg-config)))
+      (home-page "http://openocd.org")
+      (synopsis "Open On-Chip Debugger")
+      (description
+       "OpenOCD provides on-chip programming and debugging support with a
+layered architecture of JTAG interface and TAP support.")
+      (license (list license:gpl2       ;; openocd and git2cl submodule
+                     license:gpl2+      ;; libjaylink submodule
+                     license:bsd-2))))) ;; jimctl submodule
diff --git a/gnu/packages/patches/openocd-nrf52.patch b/gnu/packages/patches/openocd-nrf52.patch
new file mode 100644
index 0000000..d136735
--- /dev/null
+++ b/gnu/packages/patches/openocd-nrf52.patch
@@ -0,0 +1,843 @@ 
+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 c167e8f..b6a2be3 100644
+--- a/src/flash/nor/Makefile.am
++++ b/src/flash/nor/Makefile.am
+@@ -37,6 +37,7 @@ NOR_DRIVERS = \
+ 	niietcm4.c \
+ 	non_cfi.c \
+ 	nrf51.c \
++	nrf52.c \
+ 	numicro.c \
+ 	ocl.c \
+ 	pic32mx.c \
+diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
+index 56a5cb2..3e071bd 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(&reg_params[0], "r0", 32, PARAM_IN_OUT);	/* byte count */
++	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);	/* buffer start */
++	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);	/* buffer end */
++	init_reg_param(&reg_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(&reg_params[0]);
++	destroy_reg_param(&reg_params[1]);
++	destroy_reg_param(&reg_params[2]);
++	destroy_reg_param(&reg_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..a2567ff 100644
+--- a/tcl/target/nrf52.cfg
++++ b/tcl/target/nrf52.cfg
+@@ -5,15 +5,22 @@
+ source [find target/swj-dp.tcl]
+ 
+ if { [info exists CHIPNAME] } {
+-	set _CHIPNAME $CHIPNAME
++   set _CHIPNAME $CHIPNAME
+ } else {
+-	set _CHIPNAME nrf52
++   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
++   set _CPUTAPID $CPUTAPID
+ } else {
+-	set _CPUTAPID 0x2ba01477
++   set _CPUTAPID 0x2ba01477
+ }
+ 
+ swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID
+@@ -21,8 +28,15 @@ swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID
+ 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
++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 {}