1use crate::pm::{disable_clock, enable_clock, Clock, HSBClock, PBBClock};
56use core::cell::Cell;
57use kernel::deferred_call::{DeferredCall, DeferredCallClient};
58use kernel::hil::crc::{Client, Crc, CrcAlgorithm, CrcOutput};
59use kernel::utilities::cells::OptionalCell;
60use kernel::utilities::leasable_buffer::SubSliceMut;
61use kernel::utilities::registers::interfaces::{Readable, Writeable};
62use kernel::utilities::registers::{
63 register_bitfields, FieldValue, InMemoryRegister, ReadOnly, ReadWrite, WriteOnly,
64};
65use kernel::utilities::StaticRef;
66use kernel::ErrorCode;
67
68pub const BASE_ADDRESS: StaticRef<CrccuRegisters> =
70 unsafe { StaticRef::new(0x400A4000 as *const CrccuRegisters) };
71
72#[repr(C)]
73pub struct CrccuRegisters {
74 dscr: ReadWrite<u32, DescriptorBaseAddress::Register>,
76 _reserved0: u32,
77 dmaen: WriteOnly<u32, DmaEnable::Register>,
78 dmadis: WriteOnly<u32, DmaDisable::Register>,
79 dmasr: ReadOnly<u32, DmaStatus::Register>,
80 dmaier: WriteOnly<u32, DmaInterrupt::Register>,
81 dmaidr: WriteOnly<u32, DmaInterrupt::Register>,
82 dmaimr: ReadOnly<u32, DmaInterrupt::Register>,
83 dmaisr: ReadOnly<u32, DmaInterrupt::Register>,
84 _reserved1: [u32; 4],
85 cr: WriteOnly<u32, Control::Register>,
86 mr: ReadWrite<u32, Mode::Register>,
87 sr: ReadOnly<u32, Status::Register>,
88 ier: WriteOnly<u32, Interrupt::Register>,
89 idr: WriteOnly<u32, Interrupt::Register>,
90 imr: ReadOnly<u32, Interrupt::Register>,
91 isr: ReadOnly<u32, Interrupt::Register>,
92}
93
94register_bitfields![u32,
95 DescriptorBaseAddress [
96 DSCR OFFSET(9) NUMBITS(23) []
98 ],
99
100 DmaEnable [
101 DMAEN 0
103 ],
104
105 DmaDisable [
106 DMADIS 0
108 ],
109
110 DmaStatus [
111 DMASR 0
113 ],
114
115 DmaInterrupt [
116 DMA 0
118 ],
119
120 Control [
121 RESET 0
123 ],
124
125 Mode [
126 DIVIDER OFFSET(4) NUMBITS(4) [],
128 PTYPE OFFSET(2) NUMBITS(2) [
130 Ccit8023 = 0,
131 Castagnoli = 1,
132 Ccit16 = 2
133 ],
134 COMPARE OFFSET(1) NUMBITS(1) [],
136 ENABLE OFFSET(0) NUMBITS(1) [
138 Enabled = 1,
139 Disabled = 0
140 ]
141 ],
142
143 Status [
144 CRC OFFSET(0) NUMBITS(32)
146 ],
147
148 Interrupt [
149 ERR 0
151 ]
152];
153
154#[repr(C)]
155#[repr(align(512))]
156struct Descriptor {
157 addr: InMemoryRegister<u32>,
159 ctrl: InMemoryRegister<u32>,
161 _res: [u32; 2],
162 crc: InMemoryRegister<u32>,
164}
165
166impl Descriptor {
167 pub fn new() -> Descriptor {
168 Descriptor {
169 addr: InMemoryRegister::new(0),
170 ctrl: InMemoryRegister::new(TCR::default().0),
171 _res: [0; 2],
172 crc: InMemoryRegister::new(0),
173 }
174 }
175}
176
177#[derive(Copy, Clone)]
179#[repr(C)]
180struct TCR(u32);
181
182impl TCR {
183 const fn new(enable_interrupt: bool, trwidth: TrWidth, btsize: u16) -> Self {
184 TCR((!enable_interrupt as u32) << 27 | (trwidth as u32) << 24 | (btsize as u32))
185 }
186
187 const fn default() -> Self {
188 Self::new(false, TrWidth::Byte, 0)
189 }
190
191 fn interrupt_enabled(self) -> bool {
192 (self.0 & (1 << 27)) == 0
193 }
194
195 #[allow(dead_code)]
196 fn get_btsize(self) -> u16 {
197 (self.0 & 0xffff) as u16
198 }
199}
200
201fn poly_for_alg(alg: CrcAlgorithm) -> FieldValue<u32, Mode::Register> {
202 match alg {
203 CrcAlgorithm::Crc32 => Mode::PTYPE::Ccit8023,
204 CrcAlgorithm::Crc32C => Mode::PTYPE::Castagnoli,
205 CrcAlgorithm::Crc16CCITT => Mode::PTYPE::Ccit16,
206 }
209}
210
211fn post_process(result: u32, alg: CrcAlgorithm) -> CrcOutput {
212 match alg {
213 CrcAlgorithm::Crc32 => CrcOutput::Crc32(reverse_and_invert(result)),
214 CrcAlgorithm::Crc32C => CrcOutput::Crc32C(reverse_and_invert(result)),
215 CrcAlgorithm::Crc16CCITT => CrcOutput::Crc16CCITT(result as u16),
216 }
219}
220
221fn reverse_and_invert(n: u32) -> u32 {
222 let mut out: u32 = 0;
223
224 for j in 0..32 {
226 let i = 31 - j;
227 out |= ((n & (1 << i)) >> i) << j;
228 }
229
230 out ^ 0xffffffff
232}
233
234#[allow(dead_code)]
236enum TrWidth {
237 Byte,
238 HalfWord,
239 Word,
240}
241
242#[derive(Copy, Clone, PartialEq)]
243enum State {
244 Invalid,
245 Initialized,
246 Enabled,
247}
248
249pub struct Crccu<'a> {
251 registers: StaticRef<CrccuRegisters>,
252 client: OptionalCell<&'a dyn Client>,
253 state: Cell<State>,
254 algorithm: OptionalCell<CrcAlgorithm>,
255
256 current_full_buffer: Cell<(*mut u8, usize)>,
259
260 compute_requested: Cell<bool>,
263
264 descriptor: Descriptor,
269
270 deferred_call: DeferredCall,
271}
272
273impl Crccu<'_> {
274 pub fn new(base_addr: StaticRef<CrccuRegisters>) -> Self {
275 Self {
276 registers: base_addr,
277 client: OptionalCell::empty(),
278 state: Cell::new(State::Invalid),
279 algorithm: OptionalCell::empty(),
280 current_full_buffer: Cell::new((core::ptr::null_mut::<u8>(), 0)),
281 compute_requested: Cell::new(false),
282 descriptor: Descriptor::new(),
283 deferred_call: DeferredCall::new(),
284 }
285 }
286
287 fn init(&self) {
288 if self.state.get() == State::Invalid {
289 self.descriptor.addr.set(0);
290 self.descriptor.ctrl.set(TCR::default().0);
291 self.descriptor.crc.set(0);
292 self.state.set(State::Initialized);
293 }
294 }
295
296 fn enable(&self) {
298 if self.state.get() != State::Enabled {
299 enable_clock(Clock::HSB(HSBClock::CRCCU));
301 enable_clock(Clock::PBB(PBBClock::CRCCU));
302 self.state.set(State::Enabled);
303 }
304 }
305
306 fn disable(&self) {
308 if self.state.get() == State::Enabled {
309 disable_clock(Clock::PBB(PBBClock::CRCCU));
310 disable_clock(Clock::HSB(HSBClock::CRCCU));
311 self.state.set(State::Initialized);
312 }
313 }
314
315 pub fn handle_interrupt(&self) {
317 if self.registers.isr.is_set(Interrupt::ERR) {
318 }
320
321 if self.registers.dmaisr.is_set(DmaInterrupt::DMA) {
322 if TCR(self.descriptor.ctrl.get()).interrupt_enabled() {
325 self.registers.mr.write(Mode::ENABLE::Disabled);
336
337 let window_addr = self.descriptor.addr.get();
339 let window_len = TCR(self.descriptor.ctrl.get()).get_btsize() as usize;
340
341 self.descriptor.addr.set(0);
343 self.descriptor.ctrl.set(TCR::default().0);
344 self.descriptor.crc.set(0);
345
346 self.registers.dmaidr.write(DmaInterrupt::DMA::SET);
348
349 self.registers.dmadis.write(DmaDisable::DMADIS::SET);
351
352 let (full_buffer_addr, full_buffer_len) = self.current_full_buffer.get();
355 let mut data = SubSliceMut::<'static, u8>::new(unsafe {
356 core::slice::from_raw_parts_mut(full_buffer_addr, full_buffer_len)
357 });
358
359 let start_offset = (window_addr as usize) - (full_buffer_addr as usize);
361 data.slice(start_offset..(start_offset + window_len));
362
363 self.client.map(move |client| {
366 client.input_done(Ok(()), data);
367 });
368 }
369 }
370 }
371}
372impl DeferredCallClient for Crccu<'_> {
373 fn handle_deferred_call(&self) {
374 let result = post_process(
378 self.registers.sr.read(Status::CRC),
379 self.algorithm.unwrap_or_panic(), );
381
382 self.registers.cr.write(Control::RESET::SET);
385 self.descriptor.ctrl.set(TCR::default().0);
386 self.compute_requested.set(false);
387
388 self.client.map(|client| {
389 client.crc_done(Ok(result));
390 });
391 }
392
393 fn register(&'static self) {
394 self.deferred_call.register(self);
395 }
396}
397
398impl<'a> Crc<'a> for Crccu<'a> {
400 fn set_client(&self, client: &'a dyn Client) {
402 self.client.set(client);
403 }
404
405 fn algorithm_supported(&self, algorithm: CrcAlgorithm) -> bool {
406 match algorithm {
409 CrcAlgorithm::Crc32 => true,
410 CrcAlgorithm::Crc32C => true,
411 CrcAlgorithm::Crc16CCITT => true,
412 }
413 }
414
415 fn set_algorithm(&self, algorithm: CrcAlgorithm) -> Result<(), ErrorCode> {
416 if TCR(self.descriptor.ctrl.get()).interrupt_enabled() || self.compute_requested.get() {
419 return Err(ErrorCode::BUSY);
421 }
422
423 self.init();
424 self.descriptor.addr.set(0);
426 self.descriptor.ctrl.set(TCR::default().0);
427 self.descriptor.crc.set(0);
428 self.algorithm.set(algorithm);
429
430 self.registers.cr.write(Control::RESET::SET);
432
433 Ok(())
434 }
435
436 fn input(
437 &self,
438 mut data: SubSliceMut<'static, u8>,
439 ) -> Result<(), (ErrorCode, SubSliceMut<'static, u8>)> {
440 let algorithm = if let Some(algorithm) = self.algorithm.get() {
441 algorithm
442 } else {
443 return Err((ErrorCode::RESERVE, data));
444 };
445
446 if TCR(self.descriptor.ctrl.get()).interrupt_enabled() || self.compute_requested.get() {
447 return Err((ErrorCode::BUSY, data));
449 }
450
451 self.init();
454
455 let len = data.len() as u16;
457 let ctrl = TCR::new(true, TrWidth::Byte, len);
458
459 if data.len() > u16::MAX as usize {
462 let window_ptr = data.as_ptr();
465 data.reset();
466 let start_ptr = data.as_ptr();
467 let start_offset = unsafe { window_ptr.offset_from(start_ptr) } as usize;
469
470 data.slice(start_offset..=(start_offset + u16::MAX as usize));
474 }
475
476 self.enable();
477
478 self.registers.dmaier.write(DmaInterrupt::DMA::SET);
480
481 self.registers.ier.write(Interrupt::ERR::SET);
483
484 self.descriptor.addr.set(data.as_ptr() as u32);
489 self.descriptor.ctrl.set(ctrl.0);
490 self.descriptor.crc.set(0); let full_slice = data.take();
496 let full_slice_ptr_len = (full_slice.as_mut_ptr(), full_slice.len());
497 self.current_full_buffer.set(full_slice_ptr_len);
498
499 self.registers
513 .dscr
514 .set(core::ptr::addr_of!(self.descriptor) as u32);
515
516 self.registers.mr.write(
518 Mode::DIVIDER.val(0)
519 + poly_for_alg(algorithm)
520 + Mode::COMPARE::CLEAR
521 + Mode::ENABLE::Enabled,
522 );
523
524 self.registers.dmaen.write(DmaEnable::DMAEN::SET);
526
527 Ok(())
528 }
529
530 fn compute(&self) -> Result<(), ErrorCode> {
531 if TCR(self.descriptor.ctrl.get()).interrupt_enabled() || self.compute_requested.get() {
536 return Err(ErrorCode::BUSY);
538 }
539
540 self.compute_requested.set(true);
542
543 self.deferred_call.set();
546
547 Ok(())
548 }
549
550 fn disable(&self) {
551 Crccu::disable(self);
552 }
553}