sifive/
clint.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//! Create a timer using the Machine Timer registers.
6
7use core::marker::PhantomData;
8use core::num::NonZeroU32;
9
10use kernel::hil::time::{self, Alarm, ConvertTicks, Frequency, Ticks, Ticks64, Time};
11use kernel::utilities::cells::OptionalCell;
12use kernel::utilities::registers::interfaces::Writeable;
13use kernel::utilities::registers::{register_structs, ReadWrite};
14use kernel::utilities::StaticRef;
15use kernel::ErrorCode;
16use rv32i::machine_timer::MachineTimer;
17
18register_structs! {
19    pub ClintRegisters {
20        (0x0000 => msip: ReadWrite<u32>),
21        (0x0004 => _reserved),
22        (0x4000 => compare_low: ReadWrite<u32>),
23        (0x4004 => compare_high: ReadWrite<u32>),
24        (0x4008 => _reserved2),
25        (0xBFF8 => value_low: ReadWrite<u32>),
26        (0xBFFC => value_high: ReadWrite<u32>),
27        (0xC000 => @END),
28    }
29}
30
31pub struct Clint<'a, F: Frequency> {
32    registers: StaticRef<ClintRegisters>,
33    client: OptionalCell<&'a dyn time::AlarmClient>,
34    mtimer: MachineTimer<'a>,
35    _freq: PhantomData<F>,
36}
37
38impl<'a, F: Frequency> Clint<'a, F> {
39    pub fn new(base: &'a StaticRef<ClintRegisters>) -> Self {
40        Self {
41            registers: *base,
42            client: OptionalCell::empty(),
43            mtimer: MachineTimer::new(
44                &base.compare_low,
45                &base.compare_high,
46                &base.value_low,
47                &base.value_high,
48            ),
49            _freq: PhantomData,
50        }
51    }
52
53    pub fn handle_interrupt(&self) {
54        self.disable_machine_timer();
55
56        self.client.map(|client| {
57            client.alarm();
58        });
59    }
60
61    pub fn disable_machine_timer(&self) {
62        self.registers.compare_high.set(0xFFFF_FFFF);
63        self.registers.compare_low.set(0xFFFF_FFFF);
64    }
65}
66
67impl<F: Frequency> Time for Clint<'_, F> {
68    type Frequency = F;
69    type Ticks = Ticks64;
70
71    fn now(&self) -> Ticks64 {
72        self.mtimer.now()
73    }
74}
75
76impl<'a, F: Frequency> time::Alarm<'a> for Clint<'a, F> {
77    fn set_alarm_client(&self, client: &'a dyn time::AlarmClient) {
78        self.client.set(client);
79    }
80
81    fn set_alarm(&self, reference: Self::Ticks, dt: Self::Ticks) {
82        self.mtimer.set_alarm(reference, dt)
83    }
84
85    fn get_alarm(&self) -> Self::Ticks {
86        self.mtimer.get_alarm()
87    }
88
89    fn disarm(&self) -> Result<(), ErrorCode> {
90        self.mtimer.disarm()
91    }
92
93    fn is_armed(&self) -> bool {
94        self.mtimer.is_armed()
95    }
96
97    fn minimum_dt(&self) -> Self::Ticks {
98        self.mtimer.minimum_dt()
99    }
100}
101
102/// SchedulerTimer Implementation for RISC-V mtimer. Notably, this implementation should only be
103/// used by a chip if that chip has multiple hardware timer peripherals such that a different
104/// hardware timer can be used to provide alarms to capsules and userspace. This
105/// implementation will not work alongside other uses of the machine timer.
106impl<F: Frequency> kernel::platform::scheduler_timer::SchedulerTimer for Clint<'_, F> {
107    fn start(&self, us: NonZeroU32) {
108        let now = self.now();
109        let tics = self.ticks_from_us(us.get());
110        self.set_alarm(now, tics);
111    }
112
113    fn get_remaining_us(&self) -> Option<NonZeroU32> {
114        // We need to convert from native tics to us, multiplication could overflow in 32-bit
115        // arithmetic. So we convert to 64-bit.
116        let diff = self.get_alarm().wrapping_sub(self.now()).into_u64();
117
118        // If next alarm is more than one second away from now, alarm must have expired.
119        // Use this formulation to protect against errors when the alarm has passed.
120        // 1 second was chosen because it is significantly greater than the 400ms max value allowed
121        // by start(), and requires no computational overhead (e.g. using 500ms would require
122        // dividing the returned ticks by 2)
123        // However, if the alarm frequency is slow enough relative to the cpu frequency, it is
124        // possible this will be evaluated while now() == get_alarm(), so we special case that
125        // result where the alarm has fired but the subtraction has not overflowed
126        if diff >= <Self as Time>::Frequency::frequency() as u64 {
127            None
128        } else {
129            let hertz = <Self as Time>::Frequency::frequency() as u64;
130            NonZeroU32::new(((diff * 1_000_000) / hertz) as u32)
131        }
132    }
133
134    fn reset(&self) {
135        self.disable_machine_timer();
136    }
137
138    fn arm(&self) {
139        // Arm and disarm are optional, but controlling the mtimer interrupt
140        // should be re-enabled if Tock moves to a design that allows direct control of
141        // interrupt enables
142        //csr::CSR.mie.modify(csr::mie::mie::mtimer::SET);
143    }
144
145    fn disarm(&self) {
146        //csr::CSR.mie.modify(csr::mie::mie::mtimer::CLEAR);
147    }
148}