Austin Appleby | fe18d19 | 2021-10-27 18:22:56 -0700 | [diff] [blame] | 1 | //! Timer driver. |
| 2 | |
Austin Appleby | fe18d19 | 2021-10-27 18:22:56 -0700 | [diff] [blame] | 3 | use kernel::common::cells::OptionalCell; |
| 4 | use kernel::common::registers::{register_bitfields, register_structs, ReadWrite, WriteOnly}; |
| 5 | use kernel::common::StaticRef; |
| 6 | use kernel::hil::time; |
| 7 | use kernel::hil::time::{Ticks, Ticks64, Time}; |
| 8 | use kernel::ReturnCode; |
| 9 | |
Austin Appleby | cac7a5d | 2021-11-09 18:21:23 -0800 | [diff] [blame] | 10 | const PRESCALE: u16 = ((crate::chip::CHIP_CPU_FREQ / 10_000) - 1) as u16; // 10Khz |
Austin Appleby | fe18d19 | 2021-10-27 18:22:56 -0700 | [diff] [blame] | 11 | |
| 12 | /// 10KHz `Frequency` |
| 13 | #[derive(Debug)] |
| 14 | pub struct Freq10KHz; |
| 15 | impl time::Frequency for Freq10KHz { |
| 16 | fn frequency() -> u32 { |
| 17 | 10_000 |
| 18 | } |
| 19 | } |
| 20 | |
| 21 | register_structs! { |
| 22 | pub TimerRegisters { |
Austin Appleby | bad2b0e | 2022-01-20 15:26:20 -0800 | [diff] [blame] | 23 | // There's a bug in register_structs! - if the register map is |
| 24 | // non-contiguous, you have to put a read-only register at the end of |
| 25 | // each chunk or the addresses in the generated code are wrong. :/ |
| 26 | (0x000 => alert_test: ReadWrite<u32>), |
| 27 | (0x004 => ctrl: ReadWrite<u32, ctrl::Register>), |
| 28 | (0x008 => _fake_register_to_fix_bug), |
Austin Appleby | fe18d19 | 2021-10-27 18:22:56 -0700 | [diff] [blame] | 29 | |
| 30 | (0x100 => config: ReadWrite<u32, config::Register>), |
| 31 | |
| 32 | (0x104 => value_low: ReadWrite<u32>), |
| 33 | (0x108 => value_high: ReadWrite<u32>), |
| 34 | |
| 35 | (0x10c => compare_low: ReadWrite<u32>), |
| 36 | (0x110 => compare_high: ReadWrite<u32>), |
| 37 | |
| 38 | (0x114 => intr_enable: ReadWrite<u32, intr::Register>), |
| 39 | (0x118 => intr_state: ReadWrite<u32, intr::Register>), |
| 40 | (0x11c => intr_test: WriteOnly<u32, intr::Register>), |
| 41 | (0x120 => @END), |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | register_bitfields![u32, |
| 46 | ctrl [ |
| 47 | enable OFFSET(0) NUMBITS(1) [] |
| 48 | ], |
| 49 | config [ |
| 50 | prescale OFFSET(0) NUMBITS(12) [], |
| 51 | step OFFSET(16) NUMBITS(8) [] |
| 52 | ], |
| 53 | intr [ |
| 54 | timer0 OFFSET(0) NUMBITS(1) [] |
| 55 | ] |
| 56 | ]; |
| 57 | |
| 58 | pub struct RvTimer<'a> { |
| 59 | registers: StaticRef<TimerRegisters>, |
| 60 | alarm_client: OptionalCell<&'a dyn time::AlarmClient>, |
| 61 | overflow_client: OptionalCell<&'a dyn time::OverflowClient>, |
| 62 | } |
| 63 | |
| 64 | impl<'a> RvTimer<'a> { |
| 65 | const fn new(base: StaticRef<TimerRegisters>) -> RvTimer<'a> { |
| 66 | RvTimer { |
| 67 | registers: base, |
| 68 | alarm_client: OptionalCell::empty(), |
| 69 | overflow_client: OptionalCell::empty(), |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | pub fn setup(&self) { |
| 74 | let regs = self.registers; |
| 75 | // Set proper prescaler and the like |
| 76 | regs.config |
| 77 | .write(config::prescale.val(PRESCALE as u32) + config::step.val(1u32)); |
| 78 | regs.compare_high.set(0); |
| 79 | regs.value_low.set(0xFFFF_0000); |
| 80 | regs.intr_enable.write(intr::timer0::CLEAR); |
Austin Appleby | bad2b0e | 2022-01-20 15:26:20 -0800 | [diff] [blame] | 81 | regs.ctrl.set(1); |
Austin Appleby | fe18d19 | 2021-10-27 18:22:56 -0700 | [diff] [blame] | 82 | } |
| 83 | |
| 84 | pub fn service_interrupt(&self) { |
| 85 | let regs = self.registers; |
| 86 | regs.intr_enable.write(intr::timer0::CLEAR); |
| 87 | regs.intr_state.write(intr::timer0::SET); |
| 88 | self.alarm_client.map(|client| { |
| 89 | client.alarm(); |
| 90 | }); |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | impl time::Time for RvTimer<'_> { |
| 95 | type Frequency = Freq10KHz; |
| 96 | type Ticks = Ticks64; |
| 97 | |
| 98 | fn now(&self) -> Ticks64 { |
| 99 | // RISC-V has a 64-bit counter but you can only read 32 bits |
| 100 | // at once, which creates a race condition if the lower register |
| 101 | // wraps between the reads. So the recommended approach is to read |
| 102 | // low, read high, read low, and if the second low is lower, re-read |
| 103 | // high. -pal 8/6/20 |
| 104 | let first_low: u32 = self.registers.value_low.get(); |
| 105 | let mut high: u32 = self.registers.value_high.get(); |
| 106 | let second_low: u32 = self.registers.value_low.get(); |
| 107 | if second_low < first_low { |
| 108 | // Wraparound |
| 109 | high = self.registers.value_high.get(); |
| 110 | } |
| 111 | Ticks64::from(((high as u64) << 32) | second_low as u64) |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | impl<'a> time::Counter<'a> for RvTimer<'a> { |
| 116 | fn set_overflow_client(&'a self, client: &'a dyn time::OverflowClient) { |
| 117 | self.overflow_client.set(client); |
| 118 | } |
| 119 | |
| 120 | fn start(&self) -> ReturnCode { |
| 121 | ReturnCode::SUCCESS |
| 122 | } |
| 123 | |
| 124 | fn stop(&self) -> ReturnCode { |
| 125 | // RISCV counter can't be stopped... |
| 126 | ReturnCode::EBUSY |
| 127 | } |
| 128 | |
| 129 | fn reset(&self) -> ReturnCode { |
| 130 | // RISCV counter can't be reset |
| 131 | ReturnCode::FAIL |
| 132 | } |
| 133 | |
| 134 | fn is_running(&self) -> bool { |
| 135 | true |
| 136 | } |
| 137 | } |
| 138 | |
| 139 | impl<'a> time::Alarm<'a> for RvTimer<'a> { |
| 140 | fn set_alarm_client(&self, client: &'a dyn time::AlarmClient) { |
| 141 | self.alarm_client.set(client); |
| 142 | } |
| 143 | |
| 144 | fn set_alarm(&self, reference: Self::Ticks, dt: Self::Ticks) { |
| 145 | // This does not handle the 64-bit wraparound case. |
| 146 | // Because mtimer fires if the counter is >= the compare, |
| 147 | // handling wraparound requires setting compare to the |
| 148 | // maximum value, issuing a callback on the overflow client |
| 149 | // if there is one, spinning until it wraps around to 0, then |
| 150 | // setting the compare to the correct value. |
| 151 | let regs = self.registers; |
| 152 | let now = self.now(); |
| 153 | let mut expire = reference.wrapping_add(dt); |
| 154 | |
| 155 | if !now.within_range(reference, expire) { |
| 156 | expire = now; |
| 157 | } |
| 158 | |
| 159 | let val = expire.into_u64(); |
| 160 | let high = (val >> 32) as u32; |
| 161 | let low = (val & 0xffffffff) as u32; |
| 162 | |
| 163 | // Recommended approach for setting the two compare registers |
| 164 | // (RISC-V Privileged Architectures 3.1.15) -pal 8/6/20 |
| 165 | regs.compare_low.set(0xffffffff); |
| 166 | regs.compare_high.set(high); |
| 167 | regs.compare_low.set(low); |
| 168 | //debug!("TIMER: set to {}", expire.into_u64()); |
| 169 | self.registers.intr_enable.write(intr::timer0::SET); |
| 170 | } |
| 171 | |
| 172 | fn get_alarm(&self) -> Self::Ticks { |
| 173 | let mut val: u64 = (self.registers.compare_high.get() as u64) << 32; |
| 174 | val |= self.registers.compare_low.get() as u64; |
| 175 | Ticks64::from(val) |
| 176 | } |
| 177 | |
| 178 | fn disarm(&self) -> ReturnCode { |
| 179 | // You clear the RISCV mtime interrupt by writing to the compare |
| 180 | // registers. Since the only way to do so is to set a new alarm, |
| 181 | // and this is also the only way to re-enable the interrupt, disabling |
| 182 | // the interrupt is sufficient. Calling set_alarm will clear the |
| 183 | // pending interrupt before re-enabling. -pal 8/6/20 |
| 184 | self.registers.intr_enable.write(intr::timer0::CLEAR); |
| 185 | ReturnCode::SUCCESS |
| 186 | } |
| 187 | |
| 188 | fn is_armed(&self) -> bool { |
| 189 | self.registers.intr_enable.is_set(intr::timer0) |
| 190 | } |
| 191 | |
| 192 | fn minimum_dt(&self) -> Self::Ticks { |
| 193 | Self::Ticks::from(1 as u64) |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | const TIMER_BASE: StaticRef<TimerRegisters> = |
| 198 | unsafe { StaticRef::new(0x4010_0000 as *const TimerRegisters) }; |
| 199 | |
| 200 | pub static mut TIMER: RvTimer = RvTimer::new(TIMER_BASE); |