Skip to main content

strat9_bus_drivers/
mips_cdmm.rs

1use 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    /// Creates a new instance.
42    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    /// Performs the discover devices operation.
52    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    /// Performs the device read32 operation.
91    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    /// Performs the device write32 operation.
100    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    /// Performs the name operation.
117    fn name(&self) -> &str {
118        "mips-cdmm"
119    }
120
121    /// Performs the compatible operation.
122    fn compatible(&self) -> &[&str] {
123        COMPATIBLE
124    }
125
126    /// Performs the init operation.
127    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    /// Performs the shutdown operation.
135    fn shutdown(&mut self) -> Result<(), BusError> {
136        self.power_state = PowerState::Off;
137        Ok(())
138    }
139
140    /// Reads reg.
141    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    /// Writes reg.
149    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    /// Performs the children operation.
158    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}