1use bitfield::bitfield;
6use bitflags::bitflags;
7use std::num::NonZeroU16;
8
9pub const MMC_BLOCK_SIZE: u64 = 512;
11
12pub const EXT_CSD_BARRIER_EN: usize = 31;
15pub const EXT_CSD_BARRIER_ENABLED: u8 = 1;
16
17pub const EXT_CSD_FLUSH_CACHE: usize = 32;
18pub const EXT_CSD_FLUSH_CACHE_FLUSH: u8 = 0x1;
19pub const EXT_CSD_FLUSH_CACHE_BARRIER: u8 = 0x2;
20
21pub const EXT_CSD_CACHE_CTRL: usize = 33;
22pub const EXT_CSD_CACHE_EN_MASK: u8 = 1;
23
24pub const EXT_CSD_PARTITION_CONFIG: usize = 179;
25pub const EXT_CSD_PARTITION_ACCESS_MASK: u8 = 0xf8;
26
27pub const EXT_CSD_PARTITON_SWITCH_TIME: usize = 199;
28
29pub const EXT_CSD_GENERIC_CMD6_TIME: usize = 248;
30
31pub const EXT_CSD_BARRIER_SUPPORT: usize = 486;
32pub const EXT_CSD_BARRIER_SUPPORT_MASK: u8 = 0x1;
33
34#[derive(Clone, Copy, Debug, PartialEq, enumn::N)]
35#[repr(u8)]
36pub enum MmcCommand {
40 Switch = 6,
41 SendStatus = 13,
42}
43
44impl MmcCommand {
45 fn response_type(&self) -> DcmdResponseType {
46 match self {
47 Self::Switch => DcmdResponseType::R1B,
48 Self::SendStatus => DcmdResponseType::R1,
49 }
50 }
51}
52
53impl From<MmcCommand> for u8 {
55 fn from(value: MmcCommand) -> Self {
56 value as u8
57 }
58}
59
60bitflags! {
61 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
62 pub struct MmcSendStatusResponse: u32 {
64 const CURRENT_STATE_STDBY = 0x3 << 9;
65 const CURRENT_STATE_TRAN = 0x4 << 9;
66 const CURRENT_STATE_DATA = 0x5 << 9;
67 const CURRENT_STATE_RECV = 0x6 << 9;
68 const CURRENT_STATE_SLP = 0xa << 9;
69 const READY_FOR_DATA = 1 << 8;
70 const SWITCH_ERR = 1 << 7;
71 const EXCEPTION_EVENT = 1 << 6;
72 const APP_CMD = 1 << 5;
73 }
74}
75
76#[derive(Clone, Copy, Debug, PartialEq, Eq)]
77pub enum Direction {
79 Read,
80 Write,
81}
82
83const TASK_DESCRIPTOR_ACT: u8 = 0b101;
85
86bitfield! {
87 #[derive(
88 Clone, Copy, Eq, PartialEq, zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::Immutable,
89 )]
90 pub struct CommandQueueTaskDescriptor(u128);
92 impl Debug;
93 bool, valid, set_valid: 0;
94 bool, end, set_end: 1;
95 bool, int, set_int: 2;
96 u8, act, set_act: 5, 3;
97 bool, forced_programming, set_forced_programming: 6;
98 u8, context_id, set_context_id: 10, 7;
99 bool, tag_request, set_tag_request: 11;
100 bool, data_direction, set_data_direction: 12;
101 bool, priority, set_priority: 13;
102 bool, qbr, set_qbr: 14;
103 bool, reliable_write, set_reliable_write: 15;
104 u16, block_count, set_block_count: 31, 16;
105 u64, block_offset, set_block_offset: 95, 32;
106 }
108
109impl CommandQueueTaskDescriptor {
110 fn new(direction: Direction, block_offset: u64, block_count: NonZeroU16) -> Self {
111 let mut this = Self(0);
112 this.set_valid(true);
113 this.set_end(true);
114 this.set_int(true);
115 this.set_act(TASK_DESCRIPTOR_ACT);
116 this.set_data_direction(direction == Direction::Read);
117 this.set_block_count(block_count.get());
118 this.set_block_offset(block_offset);
119 this
120 }
121}
122
123#[derive(Clone, Copy, Debug, PartialEq, Eq)]
124#[repr(u8)]
125pub enum DcmdResponseType {
126 NoResponse = 0b00,
128 R1 = 0b10,
130 R1B = 0b11,
132}
133
134impl DcmdResponseType {
135 pub const R4: Self = Self::R1;
136 pub const R5: Self = Self::R1;
137}
138
139impl From<DcmdResponseType> for u8 {
141 fn from(value: DcmdResponseType) -> Self {
142 value as u8
143 }
144}
145
146bitfield! {
147 #[derive(
148 Clone, Copy, Eq, PartialEq, zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::Immutable,
149 )]
150 pub struct CommandQueueDirectCmdTaskDescriptor(u128);
152 impl Debug;
153 pub bool, valid, set_valid: 0;
154 pub bool, end, set_end: 1;
155 pub bool, int, set_int: 2;
156 pub u8, act, set_act: 5, 3;
157 pub bool, qbr, set_qbr: 14;
158 pub u8, from into MmcCommand, _, set_cmd_index: 21, 16;
159 pub bool, cmd_timing, set_cmd_timing: 22;
160 pub u8, from into DcmdResponseType, _, set_response_type: 24, 23;
161 pub u32, cmd_arg, set_cmd_arg: 63, 32;
162}
163
164impl CommandQueueDirectCmdTaskDescriptor {
165 fn new(command: MmcCommand, command_arg: u32) -> Self {
166 let mut this = Self(0);
167 this.set_valid(true);
168 this.set_end(true);
169 this.set_act(TASK_DESCRIPTOR_ACT);
170 this.set_qbr(true);
171 this.set_int(true);
172 this.set_cmd_index(command);
173 let response_type = command.response_type();
174 this.set_response_type(response_type);
175 this.set_cmd_timing(response_type != DcmdResponseType::R1B);
178 this.set_cmd_arg(command_arg);
179 this
180 }
181}
182
183#[derive(Clone, Copy, Debug, PartialEq, Eq)]
184#[repr(transparent)]
185pub struct TransferBytes(u16);
189
190impl TransferBytes {
191 pub const MAX_BYTES: usize = u16::MAX as usize + 1;
193
194 pub const MAX_BLOCKS: u64 = Self::MAX_BYTES as u64 / MMC_BLOCK_SIZE;
196
197 pub const MAX: Self = Self(0);
198}
199
200impl From<TransferBytes> for u32 {
201 fn from(length: TransferBytes) -> u32 {
202 if length == TransferBytes::MAX { TransferBytes::MAX_BYTES as u32 } else { length.0 as u32 }
203 }
204}
205
206impl TryFrom<usize> for TransferBytes {
207 type Error = usize;
208
209 fn try_from(size: usize) -> Result<Self, Self::Error> {
210 if size == 0 {
211 Err(size)
212 } else if size < Self::MAX_BYTES {
213 debug_assert!(size <= u16::MAX as usize);
214 Ok(Self(size as u16))
215 } else if size == Self::MAX_BYTES {
216 Ok(Self::MAX)
217 } else {
218 Err(size)
219 }
220 }
221}
222
223#[derive(Clone, Copy, Debug, Eq, PartialEq)]
224#[repr(u8)]
225enum TransferAct {
226 Tran = 0b100,
228 Link = 0b110,
230}
231
232impl From<TransferAct> for u8 {
234 fn from(value: TransferAct) -> Self {
235 value as u8
236 }
237}
238
239bitfield! {
240 #[derive(
241 Clone, Copy, Eq, PartialEq, zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::Immutable,
242 )]
243 pub struct CommandQueueTransferDescriptor(u128);
245 impl Debug;
246 bool, valid, set_valid: 0;
247 bool, end, set_end: 1;
248 bool, int, set_int: 2;
249 u8, from into TransferAct, _, set_act: 5, 3;
250 u16, length, set_length: 31, 16;
252 u64, address, set_address: 95, 32;
253 }
255
256impl CommandQueueTransferDescriptor {
257 pub fn transfer(address: u64, length: TransferBytes, end: bool) -> Self {
259 let mut this = Self(0);
260 this.set_valid(true);
261 this.set_end(end);
262 this.set_int(false);
263 this.set_act(TransferAct::Tran);
264 this.set_length(length.0);
265 this.set_address(address);
266 this
267 }
268
269 pub fn link(address: u64) -> Self {
271 let mut this = Self(0);
272 this.set_valid(true);
273 this.set_end(false);
274 this.set_int(false);
275 this.set_act(TransferAct::Link);
276 this.set_address(address);
277 this
278 }
279}
280
281#[repr(C)]
282#[derive(
283 Debug, Clone, Copy, Eq, PartialEq, zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::Immutable,
284)]
285pub struct CommandQueueTDLEntry {
289 task: CommandQueueTaskDescriptor,
290 transfer: CommandQueueTransferDescriptor,
291}
292
293impl CommandQueueTDLEntry {
294 pub fn single_buffer(
300 direction: Direction,
301 block_offset: u64,
302 block_count: NonZeroU16,
303 phys_address: u64,
304 ) -> Result<Self, ()> {
305 let length = TransferBytes::try_from(block_count.get() as usize * MMC_BLOCK_SIZE as usize)
308 .map_err(|_| ())?;
309 Ok(Self {
310 task: CommandQueueTaskDescriptor::new(direction, block_offset, block_count),
311 transfer: CommandQueueTransferDescriptor::transfer(phys_address, length, true),
312 })
313 }
314
315 pub fn scatter_gather_buffers(
320 direction: Direction,
321 block_offset: u64,
322 block_count: NonZeroU16,
323 descriptors_phys_address: u64,
324 ) -> Self {
325 debug_assert!(
326 descriptors_phys_address
327 .is_multiple_of(std::mem::align_of::<CommandQueueTransferDescriptor>() as u64)
328 );
329 Self {
330 task: CommandQueueTaskDescriptor::new(direction, block_offset, block_count),
331 transfer: CommandQueueTransferDescriptor::link(descriptors_phys_address),
332 }
333 }
334}
335
336#[repr(C)]
337#[derive(
338 Debug, Clone, Copy, Eq, PartialEq, zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::Immutable,
339)]
340pub struct CommandQueueTDLDirectCmdEntry {
347 task: CommandQueueDirectCmdTaskDescriptor,
348 _transfer: u128,
349}
350
351impl CommandQueueTDLDirectCmdEntry {
352 pub fn new(command: MmcCommand, command_arg: u32) -> Self {
353 Self { task: CommandQueueDirectCmdTaskDescriptor::new(command, command_arg), _transfer: 0 }
354 }
355}
356
357pub const CQHCI_TASK_DESCRIPTOR_LIST_NUM_SLOTS: usize = 32;
358pub const CQHCI_TASK_DESCRIPTOR_LIST_DCMD_SLOT: u8 = 31;
359pub const CQHCI_TASK_DESCRIPTOR_LIST_SIZE: usize =
360 CQHCI_TASK_DESCRIPTOR_LIST_NUM_SLOTS * size_of::<CommandQueueTDLEntry>();
361
362pub const CQHCI_CQ_VER_OFFSET: usize = 0x0;
365pub const CQHCI_CQ_CAP_OFFSET: usize = 0x4;
366pub const CQHCI_CQ_CFG_OFFSET: usize = 0x8;
367pub const CQHCI_CQ_CTL_OFFSET: usize = 0xC;
368pub const CQHCI_CQ_IS_OFFSET: usize = 0x10;
369pub const CQHCI_CQ_ISTE_OFFSET: usize = 0x14;
370pub const CQHCI_CQ_ISGE_OFFSET: usize = 0x18;
371pub const CQHCI_CQ_IC_OFFSET: usize = 0x1c;
372pub const CQHCI_CQ_TDLBA_OFFSET: usize = 0x20;
373pub const CQHCI_CQ_TDLBAU_OFFSET: usize = 0x24;
374pub const CQHCI_CQ_TDBR_OFFSET: usize = 0x28;
375pub const CQHCI_CQ_TCN_OFFSET: usize = 0x2C;
376pub const CQHCI_CQ_DQS_OFFSET: usize = 0x30;
377pub const CQHCI_CQ_DPT_OFFSET: usize = 0x34;
378pub const CQHCI_CQ_TDPE_OFFSET: usize = 0x3C;
379pub const CQHCI_CQ_SSC1_OFFSET: usize = 0x40;
380pub const CQHCI_CQ_SSC2_OFFSET: usize = 0x44;
381pub const CQHCI_CQ_CRDCT_OFFSET: usize = 0x48;
382pub const CQHCI_CQ_RMEM_OFFSET: usize = 0x50;
383pub const CQHCI_CQ_TERRI_OFFSET: usize = 0x54;
384pub const CQHCI_CQ_CRI_OFFSET: usize = 0x58;
385pub const CQHCI_CQ_CRA_OFFSET: usize = 0x5C;
386pub const CQHCI_CQ_HCCAP_OFFSET: usize = 0x60;
387pub const CQHCI_CQ_HCCFG_OFFSET: usize = 0x64;
388pub const CQHCI_CQ_CRYPTO_NQP_OFFSET: usize = 0x70;
390pub const CQHCI_CQ_CRYPTO_NQDUN_OFFSET: usize = 0x74;
391pub const CQHCI_CQ_CRYPTO_NQIS_OFFSET: usize = 0x78;
392pub const CQHCI_CQ_CRYPTO_NQIE_OFFSET: usize = 0x7C;
393pub const CQHCI_CQ_CRYPTO_CAP_OFFSET: usize = 0x100;
394
395bitfield! {
396 #[derive(Clone, Copy)]
397 pub struct CqhciCqCapsRegister(u32);
398 impl Debug;
399 pub u16, timer_clock_freq, set_timer_clock_freq: 9, 0;
400 pub u8, timer_clock_freq_multiplier, set_timer_clock_freq_multiplier: 15, 12;
401 pub bool, crypto_support, set_crypto_support: 28;
402}
403
404bitflags! {
405 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
406 pub struct CqhciCqCfgRegister: u32 {
407 const DCMD_ENABLE = 1 << 12;
408 const TASK_DESC_128 = 1 << 8; const CRYPTO_ENABLE = 1 << 1;
410 const CQE_ENABLE = 1;
411 }
412}
413
414bitflags! {
415 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
416 pub struct CqhciCqCtlRegister: u32 {
417 const CLEAR_ALL_TASKS = 1 << 8;
418 const HALT = 1;
419 }
420}
421
422bitfield! {
423 #[derive(Clone, Copy)]
424 pub struct CqhciCqSendStatusConfiguration1Register(u32);
425 impl Debug;
426 pub u16, ssc_idle_timer, set_ssc_idle_timer: 15, 0;
427 pub u8, ssc_block_counter, set_ssc_block_counter: 19, 16;
428}
429
430bitfield! {
431 #[derive(Clone, Copy)]
432 pub struct CqhciCqSendStatusConfiguration2Register(u32);
433 impl Debug;
434 impl New;
435 pub u16, rca, set_rca: 15, 0;
436}
437
438bitfield! {
440 #[derive(Clone, Copy)]
441 pub struct CqhciCqInterruptStatusRegister(u32);
442 impl Debug;
443 pub bool, halt_complete, set_halt_complete: 0;
444 pub bool, task_complete, set_task_complete: 1;
445 pub bool, response_error_detected, set_response_error_detected: 2;
446 pub bool, task_cleared, set_task_cleared: 3;
447 pub bool, general_crypto_error, set_general_crypto_error: 4;
448 pub bool, invalid_crypto_config_error, set_invalid_crypto_config_error: 5;
449 pub bool, device_exception_event, set_device_exception_event: 6;
450 pub bool, host_controller_fatal_error, set_host_controller_fatal_error: 7;
451}
452
453impl CqhciCqInterruptStatusRegister {
454 pub fn is_error(&self) -> bool {
455 self.response_error_detected()
456 || self.general_crypto_error()
457 || self.invalid_crypto_config_error()
458 || self.device_exception_event()
459 || self.host_controller_fatal_error()
460 }
461}
462
463bitfield! {
464 #[derive(Clone, Copy)]
465 pub struct CqhciCqInterruptStatusEnableRegister(u32);
466 impl Debug;
467 pub bool, halt_complete, set_halt_complete: 0;
468 pub bool, task_complete, set_task_complete: 1;
469 pub bool, response_error_detected, set_response_error_detected: 2;
470 pub bool, task_cleared, set_task_cleared: 3;
471 pub bool, general_crypto_error, set_general_crypto_error: 4;
472 pub bool, invalid_crypto_config_error, set_invalid_crypto_config_error: 5;
473 pub bool, device_exception_event, set_device_exception_event: 6;
474 pub bool, host_controller_fatal_error, set_host_controller_fatal_error: 7;
475}
476
477impl CqhciCqInterruptStatusEnableRegister {
478 pub fn disabled() -> Self {
479 Self(0)
480 }
481 pub fn enabled() -> Self {
482 Self(0xff)
483 }
484}
485
486bitfield! {
487 #[derive(Clone, Copy)]
488 pub struct CqhciCqInterruptSignalEnableRegister(u32);
489 impl Debug;
490 pub bool, halt_complete, set_halt_complete: 0;
491 pub bool, task_complete, set_task_complete: 1;
492 pub bool, response_error_detected, set_response_error_detected: 2;
493 pub bool, task_cleared, set_task_cleared: 3;
494 pub bool, general_crypto_error, set_general_crypto_error: 4;
495 pub bool, invalid_crypto_config_error, set_invalid_crypto_config_error: 5;
496 pub bool, device_exception_event, set_device_exception_event: 6;
497 pub bool, host_controller_fatal_error, set_host_controller_fatal_error: 7;
498}
499
500impl CqhciCqInterruptSignalEnableRegister {
501 pub fn disabled() -> Self {
502 Self(0)
503 }
504 pub fn enabled() -> Self {
505 Self(0xff)
506 }
507}
508
509bitfield! {
510 #[derive(Clone, Copy)]
511 pub struct CqhciCqInterruptCoalescingRegister(u32);
512 impl Debug;
513 pub u8, ic_timeout_value, set_ic_timeout_value: 6, 0;
514 pub bool, ic_timeout_value_write_enable, set_ic_timeout_value_write_enable: 7;
515 pub u8, ic_counter_threshold, set_ic_counter_threshold: 12, 8;
516 pub bool, ic_counter_threshold_write_enable, set_ic_counter_threshold_write_enable: 15;
517 pub bool, ic_counter_timer_reset, set_ic_counter_timer_reset: 16;
518 pub bool, ic_status_bit, set_ic_status_bit: 20;
519 pub bool, ic_enable, set_ic_enable: 31;
520}
521
522impl CqhciCqInterruptCoalescingRegister {
523 pub fn disabled() -> Self {
524 let mut this = Self(0);
525 this.set_ic_enable(false);
526 this
527 }
528}
529
530bitfield! {
531 #[derive(Clone, Copy)]
532 pub struct CqhciCqTaskErrorRegister(u32);
533 impl Debug;
534 pub u8, response_mode_error_command_index, _: 5, 0;
535 pub u8, response_mode_error_task_id, _: 12, 8;
536 pub bool, response_mode_error_fields_valid, _: 15;
537 pub u8, data_transfer_error_command_index, _: 21, 16;
538 pub u8, data_transfer_error_task_id, _: 28, 24;
539 pub bool, data_transfer_error_fields_valid, _: 31;
540}