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 add_master_name(&mut self, name: String) {
116 self.master_names.push(name);
117 }
118
119 fn read_gisb(&self, offset: usize) -> u32 {
121 let val = self.regs.read32(offset);
122 if self.big_endian {
123 val.swap_bytes()
124 } else {
125 val
126 }
127 }
128
129 fn write_gisb(&self, offset: usize, val: u32) {
131 let val = if self.big_endian {
132 val.swap_bytes()
133 } else {
134 val
135 };
136 self.regs.write32(offset, val);
137 }
138
139 pub fn get_timeout(&self) -> u32 {
141 self.read_gisb(self.offsets.arb_timer)
142 }
143
144 pub fn set_timeout(&self, val: u32) {
146 self.write_gisb(self.offsets.arb_timer, val);
147 }
148
149 pub fn handle_timeout_irq(&self) -> Option<GisbErrorInfo> {
151 let status = self.read_gisb(self.offsets.arb_err_cap_status);
152 if status & ARB_ERR_CAP_STATUS_VALID == 0 {
153 return None;
154 }
155
156 let addr_lo = self.read_gisb(self.offsets.arb_err_cap_addr);
157 let addr_hi = self
158 .offsets
159 .arb_err_cap_hi_addr
160 .map(|off| self.read_gisb(off))
161 .unwrap_or(0);
162 let master = self
163 .offsets
164 .arb_err_cap_master
165 .map(|off| self.read_gisb(off));
166
167 let info = GisbErrorInfo {
168 address: ((addr_hi as u64) << 32) | (addr_lo as u64),
169 master,
170 is_write: (status & ARB_ERR_CAP_STATUS_WRITE) != 0,
171 is_timeout: (status & ARB_ERR_CAP_STATUS_TIMEOUT) != 0,
172 is_tea: (status & ARB_ERR_CAP_STATUS_TEA) != 0,
173 };
174
175 self.write_gisb(self.offsets.arb_err_cap_clr, ARB_ERR_CAP_CLEAR);
176
177 Some(info)
178 }
179
180 pub fn handle_bp_irq(&self) -> Option<GisbErrorInfo> {
182 let status = self.read_gisb(self.offsets.arb_bp_cap_status);
183 if status & ARB_BP_CAP_STATUS_VALID == 0 {
184 return None;
185 }
186
187 let addr = self.read_gisb(self.offsets.arb_bp_cap_addr);
188 let master = self
189 .offsets
190 .arb_bp_cap_master
191 .map(|off| self.read_gisb(off));
192
193 let info = GisbErrorInfo {
194 address: addr as u64,
195 master,
196 is_write: (status & ARB_BP_CAP_STATUS_WRITE) != 0,
197 is_timeout: false,
198 is_tea: false,
199 };
200
201 self.write_gisb(self.offsets.arb_bp_cap_clr, ARB_BP_CAP_CLEAR);
202
203 Some(info)
204 }
205}
206
207impl BusDriver for BrcmstbGisb {
208 fn name(&self) -> &str {
210 "brcmstb-gisb"
211 }
212
213 fn compatible(&self) -> &[&str] {
215 COMPATIBLE
216 }
217
218 fn init(&mut self, base: usize) -> Result<(), BusError> {
220 self.regs.init(base, 0x800);
221 self.power_state = PowerState::On;
222 Ok(())
223 }
224
225 fn shutdown(&mut self) -> Result<(), BusError> {
227 self.power_state = PowerState::Off;
228 Ok(())
229 }
230
231 fn suspend(&mut self) -> Result<(), BusError> {
233 self.saved_timeout = self.get_timeout();
234 self.power_state = PowerState::Suspended;
235 Ok(())
236 }
237
238 fn resume(&mut self) -> Result<(), BusError> {
240 self.set_timeout(self.saved_timeout);
241 self.power_state = PowerState::On;
242 Ok(())
243 }
244
245 fn read_reg(&self, offset: usize) -> Result<u32, BusError> {
247 if !self.regs.is_valid() {
248 return Err(BusError::InitFailed);
249 }
250 Ok(self.read_gisb(offset))
251 }
252
253 fn write_reg(&mut self, offset: usize, value: u32) -> Result<(), BusError> {
255 if !self.regs.is_valid() {
256 return Err(BusError::InitFailed);
257 }
258 self.write_gisb(offset, value);
259 Ok(())
260 }
261
262 fn error_count(&self) -> u64 {
264 self.error_count.load(Ordering::Relaxed)
265 }
266
267 fn handle_irq(&mut self) -> bool {
269 let timeout = self.handle_timeout_irq();
270 let bp = self.handle_bp_irq();
271 if timeout.is_some() || bp.is_some() {
272 self.error_count.fetch_add(1, Ordering::Relaxed);
273 true
274 } else {
275 false
276 }
277 }
278}