Skip to main content

strat9_bus_drivers/
bt1_apb.rs

1use crate::{BusChild, BusDriver, BusError, PowerState, mmio::MmioRegion};
2use alloc::{string::String, vec::Vec};
3use core::sync::atomic::{AtomicU64, Ordering};
4
5const APB_EHB_ISR: usize = 0x00;
6const APB_EHB_ISR_PENDING: u32 = 1 << 0;
7const APB_EHB_ISR_MASK: u32 = 1 << 1;
8const APB_EHB_ADDR: usize = 0x04;
9const APB_EHB_TIMEOUT: usize = 0x08;
10
11const APB_EHB_TIMEOUT_MIN: u32 = 0x0000_03FF;
12const APB_EHB_TIMEOUT_MAX: u32 = 0xFFFF_FFFF;
13
14const COMPATIBLE: &[&str] = &["baikal,bt1-apb"];
15
16pub struct Bt1Apb {
17    regs: MmioRegion,
18    nodev_regs: MmioRegion,
19    error_count: AtomicU64,
20    clock_rate: u64,
21    power_state: PowerState,
22}
23
24impl Bt1Apb {
25    /// Creates a new instance.
26    pub fn new() -> Self {
27        Self {
28            regs: MmioRegion::new(),
29            nodev_regs: MmioRegion::new(),
30            error_count: AtomicU64::new(0),
31            clock_rate: 0,
32            power_state: PowerState::Off,
33        }
34    }
35
36    /// Initializes nodev region.
37    pub fn init_nodev_region(&mut self, base: usize, size: usize) {
38        self.nodev_regs.init(base, size);
39    }
40
41    /// Sets clock rate.
42    pub fn set_clock_rate(&mut self, rate: u64) {
43        self.clock_rate = rate;
44    }
45
46    /// Performs the timeout cycles to us operation.
47    pub fn timeout_cycles_to_us(&self, n: u32) -> u64 {
48        if self.clock_rate == 0 {
49            return 0;
50        }
51        (n as u64) * 1_000_000 / self.clock_rate
52    }
53
54    /// Performs the timeout us to cycles operation.
55    pub fn timeout_us_to_cycles(&self, timeout_us: u64) -> u32 {
56        if self.clock_rate == 0 {
57            return APB_EHB_TIMEOUT_MIN;
58        }
59        let n = timeout_us * self.clock_rate / 1_000_000;
60        (n as u32).clamp(APB_EHB_TIMEOUT_MIN, APB_EHB_TIMEOUT_MAX)
61    }
62
63    /// Returns timeout us.
64    pub fn get_timeout_us(&self) -> u64 {
65        let n = self.regs.read32(APB_EHB_TIMEOUT);
66        self.timeout_cycles_to_us(n)
67    }
68
69    /// Sets timeout us.
70    pub fn set_timeout_us(&self, timeout_us: u64) {
71        let n = self.timeout_us_to_cycles(timeout_us);
72        self.regs.write32(APB_EHB_TIMEOUT, n);
73    }
74
75    /// Reads fault address.
76    pub fn read_fault_address(&self) -> u32 {
77        self.regs.read32(APB_EHB_ADDR)
78    }
79
80    /// Enables irq.
81    pub fn enable_irq(&self) {
82        self.regs.modify32(
83            APB_EHB_ISR,
84            APB_EHB_ISR_PENDING | APB_EHB_ISR_MASK,
85            APB_EHB_ISR_MASK,
86        );
87    }
88
89    /// Disables irq.
90    pub fn disable_irq(&self) {
91        self.regs.clear_bits32(APB_EHB_ISR, APB_EHB_ISR_MASK);
92    }
93
94    /// Performs the clear pending operation.
95    pub fn clear_pending(&self) {
96        self.regs.clear_bits32(APB_EHB_ISR, APB_EHB_ISR_PENDING);
97    }
98}
99
100impl BusDriver for Bt1Apb {
101    /// Performs the name operation.
102    fn name(&self) -> &str {
103        "bt1-apb"
104    }
105
106    /// Performs the compatible operation.
107    fn compatible(&self) -> &[&str] {
108        COMPATIBLE
109    }
110
111    /// Performs the init operation.
112    fn init(&mut self, base: usize) -> Result<(), BusError> {
113        self.regs.init(base, 0x10);
114        self.enable_irq();
115        self.power_state = PowerState::On;
116        Ok(())
117    }
118
119    /// Performs the shutdown operation.
120    fn shutdown(&mut self) -> Result<(), BusError> {
121        self.disable_irq();
122        self.power_state = PowerState::Off;
123        Ok(())
124    }
125
126    /// Reads reg.
127    fn read_reg(&self, offset: usize) -> Result<u32, BusError> {
128        if !self.regs.is_valid() {
129            return Err(BusError::InitFailed);
130        }
131        Ok(self.regs.read32(offset))
132    }
133
134    /// Writes reg.
135    fn write_reg(&mut self, offset: usize, value: u32) -> Result<(), BusError> {
136        if !self.regs.is_valid() {
137            return Err(BusError::InitFailed);
138        }
139        self.regs.write32(offset, value);
140        Ok(())
141    }
142
143    /// Performs the error count operation.
144    fn error_count(&self) -> u64 {
145        self.error_count.load(Ordering::Relaxed)
146    }
147
148    /// Handles irq.
149    fn handle_irq(&mut self) -> bool {
150        let isr = self.regs.read32(APB_EHB_ISR);
151        if isr & APB_EHB_ISR_PENDING == 0 {
152            return false;
153        }
154        let _addr = self.read_fault_address();
155        self.error_count.fetch_add(1, Ordering::Relaxed);
156        self.clear_pending();
157        true
158    }
159}