stm32f4xx/
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//! True random number generator
6
7use crate::clocks::{phclk, Stm32f4Clocks};
8use kernel::hil;
9use kernel::hil::entropy::Continue;
10use kernel::platform::chip::ClockInterface;
11use kernel::utilities::cells::OptionalCell;
12use kernel::utilities::registers::interfaces::{ReadWriteable, Readable};
13use kernel::utilities::registers::{register_bitfields, ReadOnly, ReadWrite};
14use kernel::utilities::StaticRef;
15use kernel::ErrorCode;
16
17#[repr(C)]
18pub struct RngRegisters {
19    cr: ReadWrite<u32, Control::Register>,
20    sr: ReadWrite<u32, Status::Register>,
21    data: ReadOnly<u32, Data::Register>,
22}
23
24register_bitfields![u32,
25    Control [
26        /// Clock error detection
27        CED OFFSET(5) NUMBITS(1) [
28            ENABLE = 0,
29            DISABLE = 1
30        ],
31        /// Interrupt enable
32        IE OFFSET(3) NUMBITS(1) [],
33        /// True random number generator enable
34        RNGEN OFFSET(2) NUMBITS(1) []
35    ],
36    Status [
37        /// Seed error interrupt status
38        SEIS OFFSET(6) NUMBITS(1) [],
39        /// Clock error interrupt status
40        CEIS OFFSET(5) NUMBITS(1) [],
41        /// Seed error current status
42        SECS OFFSET(2) NUMBITS(1) [],
43        /// Clock error current status
44        CECS OFFSET(1) NUMBITS(1) [],
45        /// Data ready
46        DRDY OFFSET(0) NUMBITS(1) []
47    ],
48    Data [
49        /// Random data
50        RNDATA OFFSET(0) NUMBITS(32) []
51    ]
52];
53
54pub struct Trng<'a> {
55    registers: StaticRef<RngRegisters>,
56    clock: RngClock<'a>,
57    client: OptionalCell<&'a dyn hil::entropy::Client32>,
58}
59
60impl<'a> Trng<'a> {
61    pub const fn new(
62        registers: StaticRef<RngRegisters>,
63        clocks: &'a dyn Stm32f4Clocks,
64    ) -> Trng<'a> {
65        Trng {
66            registers,
67            clock: RngClock(phclk::PeripheralClock::new(
68                phclk::PeripheralClockType::AHB2(phclk::HCLK2::RNG),
69                clocks,
70            )),
71            client: OptionalCell::empty(),
72        }
73    }
74
75    pub fn is_enabled_clock(&self) -> bool {
76        self.clock.is_enabled()
77    }
78
79    pub fn enable_clock(&self) {
80        self.clock.enable();
81    }
82
83    pub fn disable_clock(&self) {
84        self.clock.disable();
85    }
86
87    pub fn handle_interrupt(&self) {
88        if self.registers.sr.is_set(Status::SEIS) {
89            self.registers.sr.modify(Status::SEIS::CLEAR);
90
91            // Throw away the content of the data register.
92            self.registers.data.read(Data::RNDATA);
93
94            // Restart the rng.
95            self.registers.cr.modify(Control::RNGEN::CLEAR);
96            self.registers.cr.modify(Control::RNGEN::SET);
97            return;
98        } else if self.registers.sr.is_set(Status::CEIS) {
99            self.clock.0.configure_rng_clock();
100            self.registers.sr.modify(Status::CEIS::CLEAR);
101            return;
102        }
103
104        self.client.map(|client| {
105            let res = client.entropy_available(&mut TrngIter(self), Ok(()));
106            if let Continue::Done = res {
107                self.registers.cr.modify(Control::IE::CLEAR);
108                self.registers.cr.modify(Control::RNGEN::CLEAR);
109            }
110        });
111    }
112}
113
114struct RngClock<'a>(phclk::PeripheralClock<'a>);
115
116impl ClockInterface for RngClock<'_> {
117    fn is_enabled(&self) -> bool {
118        self.0.is_enabled()
119    }
120
121    fn enable(&self) {
122        self.0.enable();
123    }
124
125    fn disable(&self) {
126        self.0.disable();
127    }
128}
129
130struct TrngIter<'a, 'b: 'a>(&'a Trng<'b>);
131
132impl Iterator for TrngIter<'_, '_> {
133    type Item = u32;
134
135    fn next(&mut self) -> Option<u32> {
136        if self.0.registers.sr.is_set(Status::DRDY) {
137            // This also clears the DRDY bit in the Status register.
138            Some(self.0.registers.data.read(Data::RNDATA))
139        } else {
140            None
141        }
142    }
143}
144
145impl<'a> hil::entropy::Entropy32<'a> for Trng<'a> {
146    fn get(&self) -> Result<(), ErrorCode> {
147        // Enable interrupts.
148        self.registers.cr.modify(Control::IE::SET);
149        self.registers.cr.modify(Control::RNGEN::SET);
150
151        Ok(())
152    }
153
154    fn cancel(&self) -> Result<(), ErrorCode> {
155        self.registers.cr.modify(Control::RNGEN::CLEAR);
156        self.registers.cr.modify(Control::IE::CLEAR);
157
158        Ok(())
159    }
160
161    fn set_client(&'a self, client: &'a dyn hil::entropy::Client32) {
162        self.client.set(client);
163    }
164}