Skip to main content

strat9_bus_drivers/
mvebu_mbus.rs

1use crate::{BusChild, BusDriver, BusError, PowerState, mmio::MmioRegion};
2use alloc::{string::String, vec::Vec};
3
4const WIN_CTRL_OFF: usize = 0x00;
5const WIN_BASE_OFF: usize = 0x04;
6const WIN_REMAP_LO_OFF: usize = 0x08;
7const WIN_REMAP_HI_OFF: usize = 0x0C;
8
9const WIN_CTRL_ENABLE: u32 = 1 << 0;
10const WIN_CTRL_SYNCBARRIER: u32 = 1 << 1;
11const WIN_CTRL_TGT_MASK: u32 = 0xF0;
12const WIN_CTRL_TGT_SHIFT: u32 = 4;
13const WIN_CTRL_ATTR_MASK: u32 = 0xFF00;
14const WIN_CTRL_ATTR_SHIFT: u32 = 8;
15const WIN_CTRL_SIZE_MASK: u32 = 0xFFFF_0000;
16const WIN_CTRL_SIZE_SHIFT: u32 = 16;
17
18const DDR_BASE_CS_OFF: fn(usize) -> usize = |n| n * 8;
19const DDR_SIZE_CS_OFF: fn(usize) -> usize = |n| n * 8 + 4;
20
21const DDR_SIZE_ENABLED: u32 = 1 << 0;
22const DDR_SIZE_CS_MASK: u32 = 0x1C;
23const DDR_SIZE_CS_SHIFT: u32 = 2;
24const DDR_SIZE_MASK: u32 = 0xFFFF_FF00;
25
26const UNIT_SYNC_BARRIER_OFF: usize = 0x84;
27const UNIT_SYNC_BARRIER_ALL: u32 = 0xFFFF;
28
29const MBUS_BRIDGE_CTRL_OFF: usize = 0x00;
30const MBUS_BRIDGE_BASE_OFF: usize = 0x04;
31
32const MAX_WINS: usize = 20;
33
34const COMPATIBLE: &[&str] = &[
35    "marvell,armada370-mbus",
36    "marvell,armada380-mbus",
37    "marvell,armadaxp-mbus",
38    "marvell,dove-mbus",
39    "marvell,kirkwood-mbus",
40    "marvell,orion5x-88f5281-mbus",
41    "marvell,orion5x-88f5182-mbus",
42    "marvell,orion5x-88f5181-mbus",
43    "marvell,orion5x-88f6183-mbus",
44    "marvell,mv78xx0-mbus",
45];
46
47#[derive(Clone, Copy)]
48pub struct MbusWindowData {
49    pub ctrl: u32,
50    pub base: u32,
51    pub remap_lo: u32,
52    pub remap_hi: u32,
53}
54
55pub struct MvebuMbus {
56    mbus_regs: MmioRegion,
57    sdram_regs: MmioRegion,
58    bridge_regs: MmioRegion,
59    num_wins: usize,
60    has_bridge: bool,
61    hw_io_coherency: bool,
62    saved_wins: [MbusWindowData; MAX_WINS],
63    power_state: PowerState,
64}
65
66impl MvebuMbus {
67    /// Creates a new instance.
68    pub fn new(num_wins: usize, has_bridge: bool) -> Self {
69        Self {
70            mbus_regs: MmioRegion::new(),
71            sdram_regs: MmioRegion::new(),
72            bridge_regs: MmioRegion::new(),
73            num_wins,
74            has_bridge,
75            hw_io_coherency: false,
76            saved_wins: [MbusWindowData {
77                ctrl: 0,
78                base: 0,
79                remap_lo: 0,
80                remap_hi: 0,
81            }; MAX_WINS],
82            power_state: PowerState::Off,
83        }
84    }
85
86    /// Initializes sdram regs.
87    pub fn init_sdram_regs(&mut self, base: usize, size: usize) {
88        self.sdram_regs.init(base, size);
89    }
90
91    /// Initializes bridge regs.
92    pub fn init_bridge_regs(&mut self, base: usize, size: usize) {
93        self.bridge_regs.init(base, size);
94        self.has_bridge = true;
95    }
96
97    /// Sets hw io coherency.
98    pub fn set_hw_io_coherency(&mut self, enable: bool) {
99        self.hw_io_coherency = enable;
100    }
101
102    /// Performs the win offset operation.
103    fn win_offset(&self, win: usize) -> usize {
104        if win < 8 {
105            win * 0x10
106        } else {
107            0x90 + (win - 8) * 0x08
108        }
109    }
110
111    /// Returns whether remap is available.
112    fn has_remap(&self, win: usize) -> bool {
113        win < 8
114    }
115
116    /// Reads window.
117    pub fn read_window(&self, win: usize) -> MbusWindowData {
118        let off = self.win_offset(win);
119        MbusWindowData {
120            ctrl: self.mbus_regs.read32(off + WIN_CTRL_OFF),
121            base: self.mbus_regs.read32(off + WIN_BASE_OFF),
122            remap_lo: if self.has_remap(win) {
123                self.mbus_regs.read32(off + WIN_REMAP_LO_OFF)
124            } else {
125                0
126            },
127            remap_hi: if self.has_remap(win) {
128                self.mbus_regs.read32(off + WIN_REMAP_HI_OFF)
129            } else {
130                0
131            },
132        }
133    }
134
135    /// Performs the setup window operation.
136    pub fn setup_window(
137        &self,
138        win: usize,
139        base: u32,
140        size: u32,
141        target: u8,
142        attr: u8,
143        remap: Option<u64>,
144    ) {
145        let off = self.win_offset(win);
146
147        self.mbus_regs.write32(off + WIN_CTRL_OFF, 0);
148
149        self.mbus_regs
150            .write32(off + WIN_BASE_OFF, base & 0xFFFF_0000);
151
152        if self.has_remap(win) {
153            if let Some(r) = remap {
154                self.mbus_regs.write32(off + WIN_REMAP_LO_OFF, r as u32);
155                self.mbus_regs
156                    .write32(off + WIN_REMAP_HI_OFF, (r >> 32) as u32);
157            } else {
158                self.mbus_regs.write32(off + WIN_REMAP_LO_OFF, 0);
159                self.mbus_regs.write32(off + WIN_REMAP_HI_OFF, 0);
160            }
161        }
162
163        let size_field = ((size / 0x10000) - 1) as u32;
164        let ctrl = WIN_CTRL_ENABLE
165            | ((target as u32) << WIN_CTRL_TGT_SHIFT) & WIN_CTRL_TGT_MASK
166            | ((attr as u32) << WIN_CTRL_ATTR_SHIFT) & WIN_CTRL_ATTR_MASK
167            | (size_field << WIN_CTRL_SIZE_SHIFT) & WIN_CTRL_SIZE_MASK;
168
169        self.mbus_regs.write32(off + WIN_CTRL_OFF, ctrl);
170    }
171
172    /// Disables window.
173    pub fn disable_window(&self, win: usize) {
174        let off = self.win_offset(win);
175        self.mbus_regs.write32(off + WIN_CTRL_OFF, 0);
176        self.mbus_regs.write32(off + WIN_BASE_OFF, 0);
177        if self.has_remap(win) {
178            self.mbus_regs.write32(off + WIN_REMAP_LO_OFF, 0);
179            self.mbus_regs.write32(off + WIN_REMAP_HI_OFF, 0);
180        }
181    }
182
183    /// Performs the save windows operation.
184    pub fn save_windows(&mut self) {
185        for i in 0..self.num_wins {
186            self.saved_wins[i] = self.read_window(i);
187        }
188    }
189
190    /// Performs the restore windows operation.
191    pub fn restore_windows(&self) {
192        for i in 0..self.num_wins {
193            let off = self.win_offset(i);
194            let win = &self.saved_wins[i];
195            self.mbus_regs.write32(off + WIN_CTRL_OFF, 0);
196            self.mbus_regs.write32(off + WIN_BASE_OFF, win.base);
197            if self.has_remap(i) {
198                self.mbus_regs.write32(off + WIN_REMAP_LO_OFF, win.remap_lo);
199                self.mbus_regs.write32(off + WIN_REMAP_HI_OFF, win.remap_hi);
200            }
201            self.mbus_regs.write32(off + WIN_CTRL_OFF, win.ctrl);
202        }
203    }
204}
205
206impl BusDriver for MvebuMbus {
207    /// Performs the name operation.
208    fn name(&self) -> &str {
209        "mvebu-mbus"
210    }
211
212    /// Performs the compatible operation.
213    fn compatible(&self) -> &[&str] {
214        COMPATIBLE
215    }
216
217    /// Performs the init operation.
218    fn init(&mut self, base: usize) -> Result<(), BusError> {
219        self.mbus_regs.init(base, 0x200);
220        self.power_state = PowerState::On;
221        Ok(())
222    }
223
224    /// Performs the shutdown operation.
225    fn shutdown(&mut self) -> Result<(), BusError> {
226        self.power_state = PowerState::Off;
227        Ok(())
228    }
229
230    /// Performs the suspend operation.
231    fn suspend(&mut self) -> Result<(), BusError> {
232        self.save_windows();
233        self.power_state = PowerState::Suspended;
234        Ok(())
235    }
236
237    /// Performs the resume operation.
238    fn resume(&mut self) -> Result<(), BusError> {
239        self.restore_windows();
240        self.power_state = PowerState::On;
241        Ok(())
242    }
243
244    /// Reads reg.
245    fn read_reg(&self, offset: usize) -> Result<u32, BusError> {
246        if !self.mbus_regs.is_valid() {
247            return Err(BusError::InitFailed);
248        }
249        Ok(self.mbus_regs.read32(offset))
250    }
251
252    /// Writes reg.
253    fn write_reg(&mut self, offset: usize, value: u32) -> Result<(), BusError> {
254        if !self.mbus_regs.is_valid() {
255            return Err(BusError::InitFailed);
256        }
257        self.mbus_regs.write32(offset, value);
258        Ok(())
259    }
260}