sam4l/
trng.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//! Implementation of the SAM4L TRNG. It provides an implementation of
6//! the Entropy32 trait.
7
8use crate::pm;
9use kernel::hil::entropy::{self, Continue};
10use kernel::utilities::cells::OptionalCell;
11use kernel::utilities::registers::interfaces::{Readable, Writeable};
12use kernel::utilities::registers::{register_bitfields, ReadOnly, WriteOnly};
13use kernel::utilities::StaticRef;
14use kernel::ErrorCode;
15
16#[repr(C)]
17struct TrngRegisters {
18    cr: WriteOnly<u32, Control::Register>,
19    _reserved0: [u32; 3],
20    ier: WriteOnly<u32, Interrupt::Register>,
21    idr: WriteOnly<u32, Interrupt::Register>,
22    imr: ReadOnly<u32, Interrupt::Register>,
23    isr: ReadOnly<u32, Interrupt::Register>,
24    _reserved1: [u32; 12],
25    odata: ReadOnly<u32, OutputData::Register>,
26}
27
28register_bitfields![u32,
29    Control [
30        /// Security Key
31        KEY OFFSET(8) NUMBITS(24) [],
32        /// Enables the TRNG to provide random values
33        ENABLE OFFSET(0) NUMBITS(1) [
34            Disable = 0,
35            Enable = 1
36        ]
37    ],
38
39    Interrupt [
40        /// Data Ready
41        DATRDY 0
42    ],
43
44    OutputData [
45        /// Output Data
46        ODATA OFFSET(0) NUMBITS(32) []
47    ]
48];
49
50const BASE_ADDRESS: StaticRef<TrngRegisters> =
51    unsafe { StaticRef::new(0x40068000 as *const TrngRegisters) };
52
53pub struct Trng<'a> {
54    regs: StaticRef<TrngRegisters>,
55    client: OptionalCell<&'a dyn entropy::Client32>,
56}
57
58const KEY: u32 = 0x524e47;
59
60impl<'a> Trng<'a> {
61    pub const fn new() -> Trng<'a> {
62        Trng {
63            regs: BASE_ADDRESS,
64            client: OptionalCell::empty(),
65        }
66    }
67
68    pub fn handle_interrupt(&self) {
69        self.regs.idr.write(Interrupt::DATRDY::SET);
70
71        self.client.map(|client| {
72            let result = client.entropy_available(&mut TrngIter(self), Ok(()));
73            if let Continue::Done = result {
74                // disable controller
75                self.regs
76                    .cr
77                    .write(Control::KEY.val(KEY) + Control::ENABLE::Disable);
78                pm::disable_clock(pm::Clock::PBA(pm::PBAClock::TRNG));
79            } else {
80                self.regs.ier.write(Interrupt::DATRDY::SET);
81            }
82        });
83    }
84}
85
86struct TrngIter<'a, 'b: 'a>(&'a Trng<'b>);
87
88impl Iterator for TrngIter<'_, '_> {
89    type Item = u32;
90
91    fn next(&mut self) -> Option<u32> {
92        if self.0.regs.isr.is_set(Interrupt::DATRDY) {
93            Some(self.0.regs.odata.read(OutputData::ODATA))
94        } else {
95            None
96        }
97    }
98}
99
100impl<'a> entropy::Entropy32<'a> for Trng<'a> {
101    fn get(&self) -> Result<(), ErrorCode> {
102        pm::enable_clock(pm::Clock::PBA(pm::PBAClock::TRNG));
103
104        self.regs
105            .cr
106            .write(Control::KEY.val(KEY) + Control::ENABLE::Enable);
107        self.regs.ier.write(Interrupt::DATRDY::SET);
108        Ok(())
109    }
110
111    fn cancel(&self) -> Result<(), ErrorCode> {
112        Err(ErrorCode::FAIL)
113    }
114
115    fn set_client(&'a self, client: &'a dyn entropy::Client32) {
116        self.client.set(client);
117    }
118}