nrf52/
uicr.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 2022.
4
5//! User information configuration registers
6//!
7//! Minimal implementation to support activation of the reset button on
8//! nRF52-DK.
9
10use crate::ficr;
11use enum_primitive::cast::FromPrimitive;
12use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
13use kernel::utilities::registers::{register_bitfields, ReadWrite};
14use kernel::utilities::StaticRef;
15
16use crate::gpio::Pin;
17
18const UICR_BASE: StaticRef<UicrRegisters> =
19    unsafe { StaticRef::new(0x10001200 as *const UicrRegisters) };
20
21#[repr(C)]
22struct UicrRegisters {
23    /// Mapping of the nRESET function (see POWER chapter for details)
24    /// - Address: 0x200 - 0x204
25    pselreset0: ReadWrite<u32, Pselreset::Register>,
26    /// Mapping of the nRESET function (see POWER chapter for details)
27    /// - Address: 0x204 - 0x208
28    pselreset1: ReadWrite<u32, Pselreset::Register>,
29    /// Access Port protection
30    /// - Address: 0x208 - 0x20c
31    approtect: ReadWrite<u32, ApProtect::Register>,
32    /// Setting of pins dedicated to NFC functionality: NFC antenna or GPIO
33    /// - Address: 0x20c - 0x210
34    nfcpins: ReadWrite<u32, NfcPins::Register>,
35    _reserved1: [u32; 60],
36    /// External circuitry to be supplied from VDD pin.
37    /// - Address: 0x300 - 0x304
38    extsupply: ReadWrite<u32, ExtSupply::Register>,
39    /// GPIO reference voltage
40    /// - Address: 0x304 - 0x308
41    regout0: ReadWrite<u32, RegOut::Register>,
42}
43
44register_bitfields! [u32,
45    /// Task register
46    Pselreset [
47        /// GPIO number Px.nn onto which Reset is exposed
48        PIN OFFSET(0) NUMBITS(5) [],
49        /// GPIO port number Pn.xx onto with Reset is exposed
50        PORT OFFSET(5) NUMBITS(1) [],
51        /// Connection
52        CONNECTION OFFSET(31) NUMBITS(1) [
53            DISCONNECTED = 1,
54            CONNECTED = 0
55        ]
56    ],
57    /// Access port protection
58    ApProtect [
59        /// Ready event
60        PALL OFFSET(0) NUMBITS(8) [
61            /// Enable
62            ENABLED = 0x00,
63            /// Disable for later nRF52 variants
64            HWDISABLE = 0x5a,
65            /// Disable
66            DISABLED = 0xff
67        ]
68    ],
69    /// Setting of pins dedicated to NFC functionality: NFC antenna or GPIO
70    NfcPins [
71        /// Setting pins dedicated to NFC functionality
72        PROTECT OFFSET(0) NUMBITS(1) [
73            /// Operation as GPIO pins. Same protection as normal GPIO pins
74            DISABLED = 0,
75            /// Operation as NFC antenna pins. Configures the protection for
76            /// NFC operation
77            NFC = 1
78        ]
79    ],
80    /// Enable external circuitry to be supplied from VDD pin
81    ExtSupply [
82        /// Enable external circuitry to be supplied from VDD pin
83        EXTSUPPLY OFFSET(0) NUMBITS(1) [
84            /// No current can be drawn from the VDD pin
85            DISABLED = 0,
86            /// It is allowed to supply external circuitry from the VDD pin
87            ENABLED = 1
88        ]
89    ],
90    /// GPIO reference voltage / external output supply voltage
91    RegOut [
92        /// Output voltage from REG0 regulator stage
93        VOUT OFFSET(0) NUMBITS(3) [
94            V1_8 = 0,
95            V2_1 = 1,
96            V2_4 = 2,
97            V2_7 = 3,
98            V3_0 = 4,
99            V3_3 = 5,
100            DEFAULT = 7
101        ]
102    ]
103];
104
105pub struct Uicr {
106    registers: StaticRef<UicrRegisters>,
107}
108
109#[derive(Copy, Clone, PartialEq)]
110/// Output voltage from REG0 regulator stage.
111///
112/// The value is board dependent (e.g. the nRF52840dk board uses 1.8V
113/// whereas the nRF52840-Dongle requires 3.0V to light its LEDs).
114/// When a chip is out of the factory or fully erased, the default value (7)
115/// will output 1.8V.
116pub enum Regulator0Output {
117    V1_8 = 0,
118    V2_1 = 1,
119    V2_4 = 2,
120    V2_7 = 3,
121    V3_0 = 4,
122    V3_3 = 5,
123    DEFAULT = 7,
124}
125
126impl From<u32> for Regulator0Output {
127    fn from(val: u32) -> Self {
128        match val & 7 {
129            0 => Regulator0Output::V1_8,
130            1 => Regulator0Output::V2_1,
131            2 => Regulator0Output::V2_4,
132            3 => Regulator0Output::V2_7,
133            4 => Regulator0Output::V3_0,
134            5 => Regulator0Output::V3_3,
135            7 => Regulator0Output::DEFAULT,
136            _ => Regulator0Output::DEFAULT, // Invalid value, fall back to DEFAULT
137        }
138    }
139}
140
141impl Uicr {
142    pub const fn new() -> Uicr {
143        Uicr {
144            registers: UICR_BASE,
145        }
146    }
147
148    pub fn set_psel0_reset_pin(&self, pin: Pin) {
149        self.registers.pselreset0.set(pin as u32);
150    }
151
152    pub fn get_psel0_reset_pin(&self) -> Option<Pin> {
153        Pin::from_u32(self.registers.pselreset0.get())
154    }
155
156    pub fn set_psel1_reset_pin(&self, pin: Pin) {
157        self.registers.pselreset1.set(pin as u32);
158    }
159
160    pub fn get_psel1_reset_pin(&self) -> Option<Pin> {
161        Pin::from_u32(self.registers.pselreset1.get())
162    }
163
164    pub fn set_vout(&self, vout: Regulator0Output) {
165        self.registers.regout0.modify(RegOut::VOUT.val(vout as u32));
166    }
167
168    pub fn get_vout(&self) -> Regulator0Output {
169        Regulator0Output::from(self.registers.regout0.read(RegOut::VOUT))
170    }
171
172    pub fn set_nfc_pins_protection(&self, protected: bool) {
173        if protected {
174            self.registers.nfcpins.write(NfcPins::PROTECT::NFC);
175        } else {
176            self.registers.nfcpins.write(NfcPins::PROTECT::DISABLED);
177        }
178    }
179
180    pub fn is_nfc_pins_protection_enabled(&self) -> bool {
181        self.registers.nfcpins.matches_all(NfcPins::PROTECT::NFC)
182    }
183
184    pub fn is_ap_protect_enabled(&self) -> bool {
185        // We need to understand the variant of this nRF52 chip to correctly
186        // implement this function. Newer versions use a different value to
187        // indicate disabled.
188        let factory_config = ficr::Ficr::new();
189        let disabled_val = if factory_config.has_updated_approtect_logic() {
190            ApProtect::PALL::HWDISABLE
191        } else {
192            ApProtect::PALL::DISABLED
193        };
194
195        // Here we compare to the correct DISABLED value because any other value
196        // should enable the protection.
197        !self.registers.approtect.matches_all(disabled_val)
198    }
199
200    pub fn set_ap_protect(&self) {
201        self.registers.approtect.write(ApProtect::PALL::ENABLED);
202    }
203
204    /// Disable the access port protection in the UICR register. This is stored
205    /// in flash and is persistent. This behavior can also be accomplished
206    /// outside of tock by running `nrfjprog --recover`.
207    pub fn disable_ap_protect(&self) {
208        // We need to understand the variant of this nRF52 chip to correctly
209        // implement this function.
210        let factory_config = ficr::Ficr::new();
211        if factory_config.has_updated_approtect_logic() {
212            // Newer revisions of the chip require setting the APPROTECT
213            // register to `HwDisable`.
214            self.registers.approtect.write(ApProtect::PALL::HWDISABLE);
215        } else {
216            // All other revisions just use normal disable.
217            self.registers.approtect.write(ApProtect::PALL::DISABLED);
218        }
219    }
220}