nrf52/
ficr.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//! Factory Information Configuration Registers (FICR)
6//!
7//! Factory information configuration registers (FICR) are pre-programmed in
8//! factory and cannot be erased by the user. These registers contain
9//! chip-specific information and configuration.
10//!
11//! - Author: Pat Pannuto <ppannuto@berkeley.edu>
12//! - Date: November 27, 2017
13
14use core::fmt;
15use kernel::utilities::registers::interfaces::Readable;
16use kernel::utilities::registers::{register_bitfields, ReadOnly};
17use kernel::utilities::StaticRef;
18
19const FICR_BASE: StaticRef<FicrRegisters> =
20    unsafe { StaticRef::new(0x10000000 as *const FicrRegisters) };
21
22/// Struct of the FICR registers
23///
24/// Section 13.1 of <https://infocenter.nordicsemi.com/pdf/nRF52832_PS_v1.0.pdf>
25/// Section  4.4 of <https://infocenter.nordicsemi.com/pdf/nRF52840_PS_v1.1.pdf>
26/// The structure is identical for the data mapped here, differences start
27/// at address 0x350.
28#[repr(C)]
29struct FicrRegisters {
30    /// Reserved
31    _reserved0: [u32; 4],
32    /// Code memory page size
33    /// - Address: 0x010 - 0x014
34    codepagesize: ReadOnly<u32, CodePageSize::Register>,
35    /// Code memory size
36    /// - Address: 0x014 - 0x018
37    codesize: ReadOnly<u32, CodeSize::Register>,
38    /// Reserved
39    _reserved1: [u32; 18],
40    /// Device identifier
41    /// - Address: 0x060 - 0x064
42    deviceid0: ReadOnly<u32, DeviceId0::Register>,
43    /// Device identifier
44    /// - Address: 0x064 - 0x068
45    deviceid1: ReadOnly<u32, DeviceId1::Register>,
46    /// Reserved
47    _reserved2: [u32; 6],
48    /// Encryption Root
49    /// - Address: 0x080 - 0x090
50    er: [ReadOnly<u32, EncryptionRoot::Register>; 4],
51    /// Identity Root
52    /// - Address: 0x090 - 0x0A0
53    ir: [ReadOnly<u32, IdentityRoot::Register>; 4],
54    /// Device address type
55    /// - Address: 0x0A0 - 0x0A4
56    deviceaddrtype: ReadOnly<u32, DeviceAddressType::Register>,
57    /// Device address
58    /// - Address: 0x0A4 - 0x0A8
59    deviceaddr0: ReadOnly<u32, DeviceAddress0::Register>,
60    /// Device address
61    /// - Address: 0x0A8 - 0x0AC
62    deviceaddr1: ReadOnly<u32, DeviceAddress1::Register>,
63    /// Reserved
64    _reserved3: [u32; 21],
65    /// Part code
66    /// - Address: 0x100 - 0x104
67    info_part: ReadOnly<u32, InfoPart::Register>,
68    /// Part Variant, Hardware version and Production configuration
69    /// - Address: 0x104 - 0x108
70    info_variant: ReadOnly<u32, InfoVariant::Register>,
71    /// Package option
72    /// - Address: 0x108 - 0x10C
73    info_package: ReadOnly<u32, InfoPackage::Register>,
74    /// RAM variant
75    /// - Address: 0x10C - 0x110
76    info_ram: ReadOnly<u32, InfoRam::Register>,
77    /// Flash variant
78    /// - Address: 0x110 - 0x114
79    info_flash: ReadOnly<u32, InfoFlash::Register>,
80}
81
82register_bitfields! [u32,
83    /// Code memory page size
84    CodePageSize [
85        /// Code memory page size
86        CODEPAGESIZE OFFSET(0) NUMBITS(32)
87    ],
88    /// Code memory size
89    CodeSize [
90        /// Code memory size in number of pages
91        CODESIZE OFFSET(0) NUMBITS(32)
92    ],
93    /// Device Identifier
94    DeviceId0 [
95        /// 32 LSB of 64 bit unique device identifier
96        DEVICEID OFFSET(0) NUMBITS(32)
97    ],
98    /// Device Identifier
99    DeviceId1 [
100        /// 32 MSB of 64 bit unique device identifier
101        DEVICEID OFFSET(0) NUMBITS(32)
102    ],
103    /// Encryption Root
104    EncryptionRoot [
105        /// Encryption Root, word n
106        ER OFFSET(0) NUMBITS(32)
107    ],
108    /// Identity Root
109    IdentityRoot [
110        /// Identity Root, word n
111        IR OFFSET(0) NUMBITS(32)
112    ],
113    /// Device address type
114    DeviceAddressType [
115        /// Device address type
116        DEVICEADDRESSTYPE OFFSET(0) NUMBITS(1) [
117            /// Public
118            PUBLIC = 0,
119            /// Random
120            RANDOM = 1
121        ]
122    ],
123    /// Device address 1
124    DeviceAddress0 [
125        /// 32 LSB of 48 bit device address
126        DEVICEADDRESS OFFSET(0) NUMBITS(32)
127    ],
128    /// Device address 2
129    DeviceAddress1 [
130        /// 16 MSB of 48 bit device address
131        DEVICEADDRESS OFFSET(0) NUMBITS(16)
132    ],
133    /// Part code
134    InfoPart [
135        PART OFFSET(0) NUMBITS(32) [
136            /// nRF52832
137            N52832 = 0x52832,
138            /// nRF52833
139            N52833 = 0x52833,
140            /// nRF52840
141            N52840 = 0x52840,
142            /// Unspecified
143            Unspecified = 0xffffffff
144        ]
145    ],
146    /// Part Variant, Hardware version and Production configuration
147    InfoVariant [
148        /// Part Variant, Hardware version and Production configuration, encoded as ASCII
149        // Note, some of these are not present in datasheets
150        // but are in nrf52.svd or are observed in the wild
151        VARIANT OFFSET(0) NUMBITS(32) [
152            /// AAA0
153            AAA0 = 0x41414130,
154            /// AAAA
155            AAAA = 0x41414141,
156            /// AAAB
157            AAAB = 0x41414142,
158            /// AAB0
159            AAB0 = 0x41414230,
160            /// AABA
161            AABA = 0x41414241,
162            /// AABB
163            AABB = 0x41414242,
164            /// AAC0
165            AAC0 = 0x41414330,
166            /// AACA
167            AACA = 0x41414341,
168            /// AACB
169            AACB = 0x41414342,
170            /// ABBA
171            ABBA = 0x41424241,
172            /// AAD0
173            AAD0 = 0x41414430,
174            /// AAD1
175            AAD1 = 0x41414431,
176            /// AADA
177            AADA = 0x41414441,
178            /// AAE0
179            AAE0 = 0x41414530,
180            /// AAEA
181            AAEA = 0x41414541,
182            /// AAF0
183            AAF0 = 0x41414630,
184            /// BAAA
185            BAAA = 0x42414141,
186            /// CAAA
187            CAAA = 0x43414141,
188            /// Unspecified
189            Unspecified = 0xffffffff
190        ]
191    ],
192    /// Package option
193    // Note, some of these are not present in datasheet but is in nrf52.svd
194    InfoPackage [
195        PACKAGE OFFSET(0) NUMBITS(32) [
196            /// QFxx - 48-pin QFN
197            QF = 0x2000,
198            /// CHxx - 7x8 WLCSP 56 balls
199            CH = 0x2001,
200            /// CIxx - 7x8 WLCSP 56 balls<
201            CI = 0x2002,
202            /// QIxx - 73-pin aQFN
203            QI = 0x2004,
204            /// CKxx - 7x8 WLCSP 56 balls with backside coating for light protection
205            CK = 0x2005,
206            /// Unspecified
207            Unspecified = 0xffffffff
208        ]
209    ],
210    /// RAM variant
211    InfoRam [
212        RAM OFFSET(0) NUMBITS(32) [
213            /// 16 kByte RAM
214            K16 = 0x10,
215            /// 32 kByte RAM
216            K32 = 0x20,
217            /// 64 kByte RAM
218            K64 = 0x40,
219            /// 128 kByte RAM
220            K128 = 0x80,
221            /// 256 kByte RAM
222            K256 = 0x100,
223            Unspecified = 0xffffffff
224
225        ]
226    ],
227    /// Flash
228    InfoFlash [
229        FLASH OFFSET(0) NUMBITS(32) [
230            /// 128 kByte FLASH
231            K128 = 0x80,
232            /// 256 kByte FLASH
233            K256 = 0x100,
234            /// 512 kByte FLASH
235            K512 = 0x200,
236            /// 1024 kByte FLASH
237            K1024 = 0x400,
238            /// 2048 kByte FLASH
239            K2048 = 0x800,
240            /// Unspecified
241            Unspecified = 0xffffffff
242        ]
243    ]
244];
245
246/// Variant describes part variant, hardware version, and production configuration.
247#[derive(PartialEq, Debug)]
248#[repr(u32)]
249pub(crate) enum Variant {
250    AAA0 = 0x41414130,
251    AAAA = 0x41414141,
252    AAAB = 0x41414142,
253    AAB0 = 0x41414230,
254    AABA = 0x41414241,
255    AABB = 0x41414242,
256    AAC0 = 0x41414330,
257    AACA = 0x41414341,
258    AACB = 0x41414342,
259    AAD0 = 0x41414430,
260    AAD1 = 0x41414431,
261    AADA = 0x41414441,
262    AAE0 = 0x41414530,
263    AAEA = 0x41414541,
264    AAF0 = 0x41414630,
265    ABBA = 0x41424241,
266    BAAA = 0x42414141,
267    CAAA = 0x43414141,
268    Unspecified = 0xffffffff,
269}
270
271#[derive(PartialEq, Debug)]
272#[repr(u32)]
273enum Part {
274    N52832 = 0x52832,
275    N52833 = 0x52833,
276    N52840 = 0x52840,
277    Unspecified = 0xffffffff,
278}
279
280#[derive(PartialEq, Debug)]
281#[repr(u32)]
282enum Package {
283    QF = 0x2000,
284    CH = 0x2001,
285    CI = 0x2002,
286    QI = 0x2004,
287    CK = 0x2005,
288    Unspecified = 0xffffffff,
289}
290
291#[derive(PartialEq, Debug)]
292#[repr(u32)]
293enum Ram {
294    K16 = 0x10,
295    K32 = 0x20,
296    K64 = 0x40,
297    K128 = 0x80,
298    K256 = 0x100,
299    Unspecified = 0xffffffff,
300}
301
302#[derive(Debug)]
303#[repr(u32)]
304enum Flash {
305    K128 = 0x80,
306    K256 = 0x100,
307    K512 = 0x200,
308    K1024 = 0x400,
309    K2048 = 0x800,
310    Unspecified = 0xffffffff,
311}
312
313#[derive(Debug)]
314#[repr(u32)]
315pub enum AddressType {
316    Public = 0x0,
317    Random = 0x1,
318}
319
320pub struct Ficr {
321    registers: StaticRef<FicrRegisters>,
322}
323
324impl Ficr {
325    pub(crate) const fn new() -> Ficr {
326        Ficr {
327            registers: FICR_BASE,
328        }
329    }
330
331    fn part(&self) -> Part {
332        match self.registers.info_part.get() {
333            0x52832 => Part::N52832,
334            0x52833 => Part::N52833,
335            0x52840 => Part::N52840,
336            _ => Part::Unspecified,
337        }
338    }
339
340    pub(crate) fn variant(&self) -> Variant {
341        // If you update this, make sure to update
342        // `has_updated_approtect_logic()` as well.
343        match self.registers.info_variant.get() {
344            0x41414130 => Variant::AAA0,
345            0x41414141 => Variant::AAAA,
346            0x41414142 => Variant::AAAB,
347            0x41414230 => Variant::AAB0,
348            0x41414241 => Variant::AABA,
349            0x41414242 => Variant::AABB,
350            0x41414330 => Variant::AAC0,
351            0x41414341 => Variant::AACA,
352            0x41414342 => Variant::AACB,
353            0x41424241 => Variant::ABBA,
354            0x41414430 => Variant::AAD0,
355            0x41414431 => Variant::AAD1,
356            0x41414441 => Variant::AADA,
357            0x41414530 => Variant::AAE0,
358            0x41414541 => Variant::AAEA,
359            0x41414630 => Variant::AAF0,
360            0x42414141 => Variant::BAAA,
361            0x43414141 => Variant::CAAA,
362            _ => Variant::Unspecified,
363        }
364    }
365
366    /// Returns if this variant of the nRF52 has the updated APPROTECT logic.
367    /// This changed occurred towards the end of 2021 with chips becoming widely
368    /// available/used in 2023.
369    ///
370    /// See <https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/working-with-the-nrf52-series-improved-approtect>.
371    /// for more information.
372    pub(crate) fn has_updated_approtect_logic(&self) -> bool {
373        // We assume that an unspecified version means that it is new and this
374        // module hasn't been updated to recognize it.
375        match self.variant() {
376            Variant::AAF0 | Variant::Unspecified => true,
377            _ => false,
378        }
379    }
380
381    fn package(&self) -> Package {
382        match self.registers.info_package.get() {
383            0x2000 => Package::QF,
384            0x2001 => Package::CH,
385            0x2002 => Package::CI,
386            0x2004 => Package::QI,
387            0x2005 => Package::CK,
388            _ => Package::Unspecified,
389        }
390    }
391
392    fn ram(&self) -> Ram {
393        match self.registers.info_ram.get() {
394            0x10 => Ram::K16,
395            0x20 => Ram::K32,
396            0x40 => Ram::K64,
397            0x80 => Ram::K128,
398            0x100 => Ram::K256,
399            _ => Ram::Unspecified,
400        }
401    }
402
403    fn flash(&self) -> Flash {
404        match self.registers.info_flash.get() {
405            0x80 => Flash::K128,
406            0x100 => Flash::K256,
407            0x200 => Flash::K512,
408            0x400 => Flash::K1024,
409            0x800 => Flash::K2048,
410            _ => Flash::Unspecified,
411        }
412    }
413
414    pub fn id(&self) -> [u8; 8] {
415        let lo = self.registers.deviceid0.read(DeviceId0::DEVICEID);
416        let hi = self.registers.deviceid1.read(DeviceId1::DEVICEID);
417        let mut addr = [0; 8];
418        addr[..4].copy_from_slice(&lo.to_le_bytes());
419        addr[4..].copy_from_slice(&hi.to_le_bytes());
420        addr
421    }
422
423    pub fn address(&self) -> [u8; 6] {
424        let lo = self
425            .registers
426            .deviceaddr0
427            .read(DeviceAddress0::DEVICEADDRESS);
428        let hi = self
429            .registers
430            .deviceaddr1
431            .read(DeviceAddress1::DEVICEADDRESS) as u16;
432        let mut addr = [0; 6];
433        addr[..4].copy_from_slice(&lo.to_le_bytes());
434        addr[4..].copy_from_slice(&hi.to_le_bytes());
435        addr
436    }
437
438    pub fn address_type(&self) -> AddressType {
439        match self
440            .registers
441            .deviceaddrtype
442            .read(DeviceAddressType::DEVICEADDRESSTYPE)
443        {
444            0x0 => AddressType::Public,
445            _ => AddressType::Random,
446        }
447    }
448
449    /// Return a MAC address string that has been hardcoded on this chip in the
450    /// format `46:db:52:cd:93:9e`.
451    pub fn address_str(&self, buf: &'static mut [u8; 17]) -> &'static str {
452        let lo = self
453            .registers
454            .deviceaddr0
455            .read(DeviceAddress0::DEVICEADDRESS);
456        let hi = self
457            .registers
458            .deviceaddr1
459            .read(DeviceAddress1::DEVICEADDRESS);
460
461        let h: [u8; 16] = *b"0123456789abcdef";
462
463        buf[0] = h[((hi >> 12) & 0xf) as usize];
464        buf[1] = h[((hi >> 8) & 0xf) as usize];
465        buf[2] = b':';
466        buf[3] = h[((hi >> 4) & 0xf) as usize];
467        buf[4] = h[((hi >> 0) & 0xf) as usize];
468        buf[5] = b':';
469        buf[6] = h[((lo >> 28) & 0xf) as usize];
470        buf[7] = h[((lo >> 24) & 0xf) as usize];
471        buf[8] = b':';
472        buf[9] = h[((lo >> 20) & 0xf) as usize];
473        buf[10] = h[((lo >> 16) & 0xf) as usize];
474        buf[11] = b':';
475        buf[12] = h[((lo >> 12) & 0xf) as usize];
476        buf[13] = h[((lo >> 8) & 0xf) as usize];
477        buf[14] = b':';
478        buf[15] = h[((lo >> 4) & 0xf) as usize];
479        buf[16] = h[((lo >> 0) & 0xf) as usize];
480
481        // Safe because we use only ascii characters in this buffer.
482        unsafe { &*(core::ptr::from_ref::<[u8]>(buf) as *const str) }
483    }
484}
485
486impl fmt::Display for Ficr {
487    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
488        write!(
489            f,
490            "NRF52 HW INFO: Variant: {:?}, Part: {:?}, Package: {:?}, Ram: {:?}, Flash: {:?}",
491            self.variant(),
492            self.part(),
493            self.package(),
494            self.ram(),
495            self.flash()
496        )
497    }
498}
499
500/// Static instance for the board. Only one (read-only) set of factory registers.
501pub static mut FICR_INSTANCE: Ficr = Ficr::new();