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 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 pub fn init_sdram_regs(&mut self, base: usize, size: usize) {
88 self.sdram_regs.init(base, size);
89 }
90
91 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 pub fn set_hw_io_coherency(&mut self, enable: bool) {
99 self.hw_io_coherency = enable;
100 }
101
102 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 fn has_remap(&self, win: usize) -> bool {
113 win < 8
114 }
115
116 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 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 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 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 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 fn name(&self) -> &str {
209 "mvebu-mbus"
210 }
211
212 fn compatible(&self) -> &[&str] {
214 COMPATIBLE
215 }
216
217 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 fn shutdown(&mut self) -> Result<(), BusError> {
226 self.power_state = PowerState::Off;
227 Ok(())
228 }
229
230 fn suspend(&mut self) -> Result<(), BusError> {
232 self.save_windows();
233 self.power_state = PowerState::Suspended;
234 Ok(())
235 }
236
237 fn resume(&mut self) -> Result<(), BusError> {
239 self.restore_windows();
240 self.power_state = PowerState::On;
241 Ok(())
242 }
243
244 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 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}