1use crate::{BusChild, BusDriver, BusError, PowerState, mmio::MmioRegion};
2use alloc::{string::String, vec::Vec};
3use core::sync::atomic::{AtomicU64, Ordering};
4
5const ARB_ERR_CAP_CLEAR: u32 = 0x0001;
6const ARB_ERR_CAP_STATUS_TIMEOUT: u32 = 1 << 12;
7const ARB_ERR_CAP_STATUS_TEA: u32 = 1 << 11;
8const ARB_ERR_CAP_STATUS_WRITE: u32 = 1 << 1;
9const ARB_ERR_CAP_STATUS_VALID: u32 = 1 << 0;
10
11const ARB_BP_CAP_CLEAR: u32 = 1 << 0;
12const ARB_BP_CAP_STATUS_WRITE: u32 = 1 << 1;
13const ARB_BP_CAP_STATUS_VALID: u32 = 1 << 0;
14
15const COMPATIBLE: &[&str] = &[
16 "brcm,bcm7038-gisb-arb",
17 "brcm,bcm7278-gisb-arb",
18 "brcm,bcm7400-gisb-arb",
19 "brcm,bcm74165-gisb-arb",
20 "brcm,bcm7435-gisb-arb",
21 "brcm,bcm7445-gisb-arb",
22];
23
24#[derive(Clone, Copy)]
25pub struct GisbOffsets {
26 pub arb_timer: usize,
27 pub arb_bp_cap_clr: usize,
28 pub arb_bp_cap_addr: usize,
29 pub arb_bp_cap_status: usize,
30 pub arb_bp_cap_master: Option<usize>,
31 pub arb_err_cap_clr: usize,
32 pub arb_err_cap_addr: usize,
33 pub arb_err_cap_status: usize,
34 pub arb_err_cap_master: Option<usize>,
35 pub arb_err_cap_hi_addr: Option<usize>,
36}
37
38pub const BCM7038_OFFSETS: GisbOffsets = GisbOffsets {
39 arb_timer: 0x00C,
40 arb_bp_cap_clr: 0x014,
41 arb_bp_cap_addr: 0x0B8,
42 arb_bp_cap_status: 0x0C0,
43 arb_bp_cap_master: None,
44 arb_err_cap_clr: 0x0C4,
45 arb_err_cap_addr: 0x0C8,
46 arb_err_cap_status: 0x0D0,
47 arb_err_cap_master: None,
48 arb_err_cap_hi_addr: None,
49};
50
51pub const BCM7445_OFFSETS: GisbOffsets = GisbOffsets {
52 arb_timer: 0x008,
53 arb_bp_cap_clr: 0x010,
54 arb_bp_cap_addr: 0x1D8,
55 arb_bp_cap_status: 0x1E0,
56 arb_bp_cap_master: Some(0x1E4),
57 arb_err_cap_clr: 0x7E4,
58 arb_err_cap_addr: 0x7EC,
59 arb_err_cap_status: 0x7F4,
60 arb_err_cap_master: Some(0x7F8),
61 arb_err_cap_hi_addr: Some(0x7E8),
62};
63
64pub const BCM7278_OFFSETS: GisbOffsets = GisbOffsets {
65 arb_timer: 0x008,
66 arb_bp_cap_clr: 0x01C,
67 arb_bp_cap_addr: 0x220,
68 arb_bp_cap_status: 0x230,
69 arb_bp_cap_master: Some(0x234),
70 arb_err_cap_clr: 0x7F8,
71 arb_err_cap_addr: 0x7E0,
72 arb_err_cap_status: 0x7F0,
73 arb_err_cap_master: Some(0x7F4),
74 arb_err_cap_hi_addr: None,
75};
76
77pub struct GisbErrorInfo {
78 pub address: u64,
79 pub master: Option<u32>,
80 pub is_write: bool,
81 pub is_timeout: bool,
82 pub is_tea: bool,
83}
84
85pub struct BrcmstbGisb {
86 regs: MmioRegion,
87 offsets: GisbOffsets,
88 error_count: AtomicU64,
89 big_endian: bool,
90 saved_timeout: u32,
91 master_names: Vec<String>,
92 power_state: PowerState,
93}
94
95impl BrcmstbGisb {
96 pub fn new(offsets: GisbOffsets) -> Self {
98 Self {
99 regs: MmioRegion::new(),
100 offsets,
101 error_count: AtomicU64::new(0),
102 big_endian: false,
103 saved_timeout: 0,
104 master_names: Vec::new(),
105 power_state: PowerState::Off,
106 }
107 }
108
109 pub fn set_big_endian(&mut self, big_endian: bool) {
111 self.big_endian = big_endian;
112 }
113
114 pub fn set_master_names<I: IntoIterator<Item = String>>(&mut self, names: I) {
122 self.master_names.clear();
123 self.master_names.extend(names);
124 }
125
126 pub fn add_master_name(&mut self, name: String) {
130 self.master_names.push(name);
131 }
132
133 pub fn master_name(&self, master: Option<u32>) -> alloc::string::String {
139 match master {
140 None => alloc::format!("none"),
141 Some(id) => match self.master_names.get(id as usize) {
142 Some(name) => name.clone(),
143 None => alloc::format!("master{}", id),
144 },
145 }
146 }
147
148 fn read_gisb(&self, offset: usize) -> u32 {
150 let val = self.regs.read32(offset);
151 if self.big_endian {
152 val.swap_bytes()
153 } else {
154 val
155 }
156 }
157
158 fn write_gisb(&self, offset: usize, val: u32) {
160 let val = if self.big_endian {
161 val.swap_bytes()
162 } else {
163 val
164 };
165 self.regs.write32(offset, val);
166 }
167
168 pub fn get_timeout(&self) -> u32 {
170 self.read_gisb(self.offsets.arb_timer)
171 }
172
173 pub fn set_timeout(&self, val: u32) {
175 self.write_gisb(self.offsets.arb_timer, val);
176 }
177
178 pub fn format_error(&self, info: &GisbErrorInfo) -> alloc::string::String {
182 let kind = if info.is_timeout {
183 "timeout"
184 } else if info.is_tea {
185 "tea"
186 } else {
187 "error"
188 };
189 let rw = if info.is_write { "write" } else { "read" };
190 alloc::format!(
191 "gisb {} {} addr=0x{:016x} master={}",
192 kind,
193 rw,
194 info.address,
195 self.master_name(info.master)
196 )
197 }
198
199 pub fn handle_timeout_irq(&self) -> Option<GisbErrorInfo> {
201 let status = self.read_gisb(self.offsets.arb_err_cap_status);
202 if status & ARB_ERR_CAP_STATUS_VALID == 0 {
203 return None;
204 }
205
206 let addr_lo = self.read_gisb(self.offsets.arb_err_cap_addr);
207 let addr_hi = self
208 .offsets
209 .arb_err_cap_hi_addr
210 .map(|off| self.read_gisb(off))
211 .unwrap_or(0);
212 let master = self
213 .offsets
214 .arb_err_cap_master
215 .map(|off| self.read_gisb(off));
216
217 let info = GisbErrorInfo {
218 address: ((addr_hi as u64) << 32) | (addr_lo as u64),
219 master,
220 is_write: (status & ARB_ERR_CAP_STATUS_WRITE) != 0,
221 is_timeout: (status & ARB_ERR_CAP_STATUS_TIMEOUT) != 0,
222 is_tea: (status & ARB_ERR_CAP_STATUS_TEA) != 0,
223 };
224
225 self.write_gisb(self.offsets.arb_err_cap_clr, ARB_ERR_CAP_CLEAR);
226
227 Some(info)
228 }
229
230 pub fn handle_bp_irq(&self) -> Option<GisbErrorInfo> {
232 let status = self.read_gisb(self.offsets.arb_bp_cap_status);
233 if status & ARB_BP_CAP_STATUS_VALID == 0 {
234 return None;
235 }
236
237 let addr = self.read_gisb(self.offsets.arb_bp_cap_addr);
238 let master = self
239 .offsets
240 .arb_bp_cap_master
241 .map(|off| self.read_gisb(off));
242
243 let info = GisbErrorInfo {
244 address: addr as u64,
245 master,
246 is_write: (status & ARB_BP_CAP_STATUS_WRITE) != 0,
247 is_timeout: false,
248 is_tea: false,
249 };
250
251 self.write_gisb(self.offsets.arb_bp_cap_clr, ARB_BP_CAP_CLEAR);
252
253 Some(info)
254 }
255}
256
257impl BusDriver for BrcmstbGisb {
258 fn name(&self) -> &str {
260 "brcmstb-gisb"
261 }
262
263 fn compatible(&self) -> &[&str] {
265 COMPATIBLE
266 }
267
268 fn init(&mut self, base: usize) -> Result<(), BusError> {
270 self.regs.init(base, 0x800);
271 self.power_state = PowerState::On;
272 Ok(())
273 }
274
275 fn shutdown(&mut self) -> Result<(), BusError> {
277 self.power_state = PowerState::Off;
278 Ok(())
279 }
280
281 fn suspend(&mut self) -> Result<(), BusError> {
283 self.saved_timeout = self.get_timeout();
284 self.power_state = PowerState::Suspended;
285 Ok(())
286 }
287
288 fn resume(&mut self) -> Result<(), BusError> {
290 self.set_timeout(self.saved_timeout);
291 self.power_state = PowerState::On;
292 Ok(())
293 }
294
295 fn read_reg(&self, offset: usize) -> Result<u32, BusError> {
297 if !self.regs.is_valid() {
298 return Err(BusError::InitFailed);
299 }
300 self.regs.check_user_offset(offset)?;
301 Ok(self.read_gisb(offset))
302 }
303
304 fn write_reg(&mut self, offset: usize, value: u32) -> Result<(), BusError> {
306 if !self.regs.is_valid() {
307 return Err(BusError::InitFailed);
308 }
309 self.regs.check_user_offset(offset)?;
310 self.write_gisb(offset, value);
311 Ok(())
312 }
313
314 fn error_count(&self) -> u64 {
316 self.error_count.load(Ordering::Relaxed)
317 }
318
319 fn handle_irq(&mut self) -> bool {
321 let timeout = self.handle_timeout_irq();
322 let bp = self.handle_bp_irq();
323 if timeout.is_some() || bp.is_some() {
324 self.error_count.fetch_add(1, Ordering::Relaxed);
325 true
326 } else {
327 false
328 }
329 }
330}