stm32f4xx/
trng.rs
1use 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 CED OFFSET(5) NUMBITS(1) [
28 ENABLE = 0,
29 DISABLE = 1
30 ],
31 IE OFFSET(3) NUMBITS(1) [],
33 RNGEN OFFSET(2) NUMBITS(1) []
35 ],
36 Status [
37 SEIS OFFSET(6) NUMBITS(1) [],
39 CEIS OFFSET(5) NUMBITS(1) [],
41 SECS OFFSET(2) NUMBITS(1) [],
43 CECS OFFSET(1) NUMBITS(1) [],
45 DRDY OFFSET(0) NUMBITS(1) []
47 ],
48 Data [
49 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 self.registers.data.read(Data::RNDATA);
93
94 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 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 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}