strat9_bus_drivers/
bt1_apb.rs1use 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 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 pub fn init_nodev_region(&mut self, base: usize, size: usize) {
38 self.nodev_regs.init(base, size);
39 }
40
41 pub fn set_clock_rate(&mut self, rate: u64) {
43 self.clock_rate = rate;
44 }
45
46 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 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 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 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 pub fn read_fault_address(&self) -> u32 {
77 self.regs.read32(APB_EHB_ADDR)
78 }
79
80 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 pub fn disable_irq(&self) {
91 self.regs.clear_bits32(APB_EHB_ISR, APB_EHB_ISR_MASK);
92 }
93
94 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 fn name(&self) -> &str {
103 "bt1-apb"
104 }
105
106 fn compatible(&self) -> &[&str] {
108 COMPATIBLE
109 }
110
111 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 fn shutdown(&mut self) -> Result<(), BusError> {
121 self.disable_irq();
122 self.power_state = PowerState::Off;
123 Ok(())
124 }
125
126 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 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 fn error_count(&self) -> u64 {
145 self.error_count.load(Ordering::Relaxed)
146 }
147
148 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}