nrf52/approtect.rs
1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2023.
4
5//! Access port protection
6//!
7//! <https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Fdif.html&cp=5_0_0_3_7_1&anchor=register.DISABLE>
8//!
9//! The logic around APPROTECT was changed in newer revisions of the nRF52
10//! series chips (Oct 2021) and later which requires more careful disabling of
11//! the access port (JTAG), both in the UICR register and in a software written
12//! register. This module enables the kernel to disable the protection on boot.
13//!
14//! Example code to disable the APPROTECT protection in software:
15//!
16//! ```rust,ignore
17//! let approtect = nrf52::approtect::Approtect::new();
18//! approtect.sw_disable_approtect();
19//! ```
20
21use crate::ficr;
22use kernel::utilities::registers::interfaces::Writeable;
23use kernel::utilities::registers::{register_bitfields, register_structs, ReadWrite};
24use kernel::utilities::StaticRef;
25
26const APPROTECT_BASE: StaticRef<ApprotectRegisters> =
27 unsafe { StaticRef::new(0x40000000 as *const ApprotectRegisters) };
28
29register_structs! {
30 ApprotectRegisters {
31 (0x000 => _reserved0),
32 (0x550 => forceprotect: ReadWrite<u32, Forceprotect::Register>),
33 (0x554 => _reserved1),
34 (0x558 => disable: ReadWrite<u32, Disable::Register>),
35 (0x55c => @END),
36 }
37}
38
39register_bitfields! [u32,
40 Forceprotect [
41 FORCEPROTECT OFFSET(0) NUMBITS(8) [
42 FORCE = 0
43 ]
44 ],
45 /// Access port protection
46 Disable [
47 DISABLE OFFSET(0) NUMBITS(8) [
48 SWDISABLE = 0x5a
49 ]
50 ]
51];
52
53pub struct Approtect {
54 registers: StaticRef<ApprotectRegisters>,
55}
56
57impl Approtect {
58 pub const fn new() -> Approtect {
59 Approtect {
60 registers: APPROTECT_BASE,
61 }
62 }
63
64 /// Software disable the Access Port Protection mechanism.
65 ///
66 /// On newer variants of the nRF52, to enable JTAG, APPROTECT must be
67 /// disabled both in the UICR register (hardware) and in this register
68 /// (software). For older variants this is just a no-op.
69 ///
70 /// - <https://devzone.nordicsemi.com/f/nordic-q-a/96590/how-to-disable-approtect-permanently-dfu-is-needed>
71 /// - <https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/working-with-the-nrf52-series-improved-approtect>
72 pub fn sw_disable_approtect(&self) {
73 let factory_config = ficr::Ficr::new();
74 match factory_config.variant() {
75 ficr::Variant::AAF0 | ficr::Variant::Unspecified => {
76 // Newer revisions of the chip require setting the APPROTECT
77 // software register to `SwDisable`. We assume that an unspecified
78 // version means that it is new and the FICR module hasn't been
79 // updated to recognize it.
80 self.registers.disable.write(Disable::DISABLE::SWDISABLE);
81 }
82
83 // Exhaustively list variants here to produce compiler error on
84 // adding a new variant, which would otherwise not match the above
85 // condition.
86 ficr::Variant::AAA0
87 | ficr::Variant::AAAA
88 | ficr::Variant::AAAB
89 | ficr::Variant::AAB0
90 | ficr::Variant::AABA
91 | ficr::Variant::AABB
92 | ficr::Variant::AAC0
93 | ficr::Variant::AACA
94 | ficr::Variant::AACB
95 | ficr::Variant::AAD0
96 | ficr::Variant::AAD1
97 | ficr::Variant::AADA
98 | ficr::Variant::AAE0
99 | ficr::Variant::AAEA
100 | ficr::Variant::ABBA
101 | ficr::Variant::BAAA
102 | ficr::Variant::CAAA => {
103 // All other revisions don't need this.
104 }
105 }
106 }
107}