strat9_bus_drivers/
mips_cdmm.rs1use crate::{BusChild, BusDriver, BusError, PowerState, mmio::MmioRegion};
2use alloc::{string::String, vec::Vec};
3
4const CDMM_DRB_SIZE: usize = 64;
5
6const CDMM_ACSR_DEVTYPE_SHIFT: u32 = 24;
7const CDMM_ACSR_DEVTYPE_MASK: u32 = 0xFF << CDMM_ACSR_DEVTYPE_SHIFT;
8const CDMM_ACSR_DEVSIZE_SHIFT: u32 = 16;
9const CDMM_ACSR_DEVSIZE_MASK: u32 = 0x1F << CDMM_ACSR_DEVSIZE_SHIFT;
10const CDMM_ACSR_DEVREV_SHIFT: u32 = 12;
11const CDMM_ACSR_DEVREV_MASK: u32 = 0xF << CDMM_ACSR_DEVREV_SHIFT;
12const CDMM_ACSR_UW: u32 = 1 << 3;
13const CDMM_ACSR_UR: u32 = 1 << 2;
14const CDMM_ACSR_SW: u32 = 1 << 1;
15const CDMM_ACSR_SR: u32 = 1 << 0;
16
17const MAX_DRBS: usize = 256;
18
19const COMPATIBLE: &[&str] = &["mti,mips-cdmm"];
20
21#[derive(Debug, Clone)]
22pub struct CdmmDevice {
23 pub dev_type: u8,
24 pub dev_size: u8,
25 pub dev_rev: u8,
26 pub drb_offset: usize,
27 pub user_write: bool,
28 pub user_read: bool,
29 pub super_write: bool,
30 pub super_read: bool,
31}
32
33pub struct MipsCdmm {
34 regs: MmioRegion,
35 devices: Vec<CdmmDevice>,
36 total_drbs: usize,
37 power_state: PowerState,
38}
39
40impl MipsCdmm {
41 pub fn new() -> Self {
43 Self {
44 regs: MmioRegion::new(),
45 devices: Vec::new(),
46 total_drbs: 0,
47 power_state: PowerState::Off,
48 }
49 }
50
51 pub fn discover_devices(&mut self) {
53 self.devices.clear();
54 if !self.regs.is_valid() {
55 return;
56 }
57
58 let mut drb = 0;
59 while drb < MAX_DRBS {
60 let offset = drb * CDMM_DRB_SIZE;
61 let acsr = self.regs.read32(offset);
62
63 let dev_type = ((acsr & CDMM_ACSR_DEVTYPE_MASK) >> CDMM_ACSR_DEVTYPE_SHIFT) as u8;
64 let dev_size = ((acsr & CDMM_ACSR_DEVSIZE_MASK) >> CDMM_ACSR_DEVSIZE_SHIFT) as u8;
65 let dev_rev = ((acsr & CDMM_ACSR_DEVREV_MASK) >> CDMM_ACSR_DEVREV_SHIFT) as u8;
66
67 if dev_type == 0 {
68 break;
69 }
70
71 let block_count = if dev_size == 0 { 1 } else { dev_size as usize };
72
73 self.devices.push(CdmmDevice {
74 dev_type,
75 dev_size,
76 dev_rev,
77 drb_offset: offset,
78 user_write: (acsr & CDMM_ACSR_UW) != 0,
79 user_read: (acsr & CDMM_ACSR_UR) != 0,
80 super_write: (acsr & CDMM_ACSR_SW) != 0,
81 super_read: (acsr & CDMM_ACSR_SR) != 0,
82 });
83
84 drb += block_count;
85 }
86
87 self.total_drbs = drb;
88 }
89
90 pub fn device_read32(&self, dev_index: usize, offset: usize) -> Result<u32, BusError> {
92 let dev = self
93 .devices
94 .get(dev_index)
95 .ok_or(BusError::DeviceNotFound)?;
96 Ok(self.regs.read32(dev.drb_offset + offset))
97 }
98
99 pub fn device_write32(
101 &self,
102 dev_index: usize,
103 offset: usize,
104 val: u32,
105 ) -> Result<(), BusError> {
106 let dev = self
107 .devices
108 .get(dev_index)
109 .ok_or(BusError::DeviceNotFound)?;
110 self.regs.write32(dev.drb_offset + offset, val);
111 Ok(())
112 }
113}
114
115impl BusDriver for MipsCdmm {
116 fn name(&self) -> &str {
118 "mips-cdmm"
119 }
120
121 fn compatible(&self) -> &[&str] {
123 COMPATIBLE
124 }
125
126 fn init(&mut self, base: usize) -> Result<(), BusError> {
128 self.regs.init(base, MAX_DRBS * CDMM_DRB_SIZE);
129 self.discover_devices();
130 self.power_state = PowerState::On;
131 Ok(())
132 }
133
134 fn shutdown(&mut self) -> Result<(), BusError> {
136 self.power_state = PowerState::Off;
137 Ok(())
138 }
139
140 fn read_reg(&self, offset: usize) -> Result<u32, BusError> {
142 if !self.regs.is_valid() {
143 return Err(BusError::InitFailed);
144 }
145 Ok(self.regs.read32(offset))
146 }
147
148 fn write_reg(&mut self, offset: usize, value: u32) -> Result<(), BusError> {
150 if !self.regs.is_valid() {
151 return Err(BusError::InitFailed);
152 }
153 self.regs.write32(offset, value);
154 Ok(())
155 }
156
157 fn children(&self) -> Vec<BusChild> {
159 self.devices
160 .iter()
161 .enumerate()
162 .map(|(i, d)| BusChild {
163 name: alloc::format!("cdmm-dev-{:02x}", d.dev_type),
164 base_addr: d.drb_offset as u64,
165 size: (d.dev_size.max(1) as u64) * (CDMM_DRB_SIZE as u64),
166 })
167 .collect()
168 }
169}