Skip to main content

strat9_bus_drivers/
brcmstb_gisb.rs

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    /// Creates a new instance.
97    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    /// Sets big endian.
110    pub fn set_big_endian(&mut self, big_endian: bool) {
111        self.big_endian = big_endian;
112    }
113
114    /// Performs the add master name operation.
115    pub fn add_master_name(&mut self, name: String) {
116        self.master_names.push(name);
117    }
118
119    /// Reads gisb.
120    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    /// Writes gisb.
130    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    /// Returns timeout.
140    pub fn get_timeout(&self) -> u32 {
141        self.read_gisb(self.offsets.arb_timer)
142    }
143
144    /// Sets timeout.
145    pub fn set_timeout(&self, val: u32) {
146        self.write_gisb(self.offsets.arb_timer, val);
147    }
148
149    /// Handles timeout irq.
150    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    /// Handles bp irq.
181    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    /// Performs the name operation.
209    fn name(&self) -> &str {
210        "brcmstb-gisb"
211    }
212
213    /// Performs the compatible operation.
214    fn compatible(&self) -> &[&str] {
215        COMPATIBLE
216    }
217
218    /// Performs the init operation.
219    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    /// Performs the shutdown operation.
226    fn shutdown(&mut self) -> Result<(), BusError> {
227        self.power_state = PowerState::Off;
228        Ok(())
229    }
230
231    /// Performs the suspend operation.
232    fn suspend(&mut self) -> Result<(), BusError> {
233        self.saved_timeout = self.get_timeout();
234        self.power_state = PowerState::Suspended;
235        Ok(())
236    }
237
238    /// Performs the resume operation.
239    fn resume(&mut self) -> Result<(), BusError> {
240        self.set_timeout(self.saved_timeout);
241        self.power_state = PowerState::On;
242        Ok(())
243    }
244
245    /// Reads reg.
246    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    /// Writes reg.
254    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    /// Performs the error count operation.
263    fn error_count(&self) -> u64 {
264        self.error_count.load(Ordering::Relaxed)
265    }
266
267    /// Handles irq.
268    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}