Skip to main content

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