strat9_bus_drivers/
qcom_ebi2.rs1use crate::{BusChild, BusDriver, BusError, PowerState, mmio::MmioRegion};
2use alloc::{string::String, vec::Vec};
3
4const EBI2_XMEM_CFG: usize = 0x0000;
5const EBI2_XMEM_CS0_SLOW_CFG: usize = 0x0008;
6const EBI2_XMEM_CS1_SLOW_CFG: usize = 0x000C;
7const EBI2_XMEM_CS2_SLOW_CFG: usize = 0x0010;
8const EBI2_XMEM_CS3_SLOW_CFG: usize = 0x0014;
9const EBI2_XMEM_CS4_SLOW_CFG: usize = 0x0018;
10const EBI2_XMEM_CS5_SLOW_CFG: usize = 0x001C;
11const EBI2_XMEM_CS0_FAST_CFG: usize = 0x0028;
12const EBI2_XMEM_CS1_FAST_CFG: usize = 0x002C;
13const EBI2_XMEM_CS2_FAST_CFG: usize = 0x0030;
14const EBI2_XMEM_CS3_FAST_CFG: usize = 0x0034;
15const EBI2_XMEM_CS4_FAST_CFG: usize = 0x0038;
16const EBI2_XMEM_CS5_FAST_CFG: usize = 0x003C;
17
18const CS0_ENABLE: u32 = 0x03;
19const CS1_ENABLE: u32 = 0x0C;
20const CS2_ENABLE: u32 = 0x10;
21const CS3_ENABLE: u32 = 0x20;
22const CS4_ENABLE: u32 = 0x180;
23const CS5_ENABLE: u32 = 0x600;
24
25const SLOW_RECOVERY_SHIFT: u32 = 28;
26const SLOW_WR_HOLD_SHIFT: u32 = 24;
27const SLOW_WR_DELTA_SHIFT: u32 = 16;
28const SLOW_RD_DELTA_SHIFT: u32 = 8;
29const SLOW_WR_WAIT_SHIFT: u32 = 4;
30const SLOW_RD_WAIT_SHIFT: u32 = 0;
31
32const FAST_RD_HOLD_SHIFT: u32 = 24;
33const FAST_ADV_OE_RECOVERY_SHIFT: u32 = 16;
34const FAST_ADDR_HOLD_ENA: u32 = 1 << 5;
35
36const NUM_CS: usize = 6;
37
38const CS_ENABLE_MASKS: [u32; NUM_CS] = [
39 CS0_ENABLE, CS1_ENABLE, CS2_ENABLE, CS3_ENABLE, CS4_ENABLE, CS5_ENABLE,
40];
41const CS_SLOW_OFFSETS: [usize; NUM_CS] = [
42 EBI2_XMEM_CS0_SLOW_CFG,
43 EBI2_XMEM_CS1_SLOW_CFG,
44 EBI2_XMEM_CS2_SLOW_CFG,
45 EBI2_XMEM_CS3_SLOW_CFG,
46 EBI2_XMEM_CS4_SLOW_CFG,
47 EBI2_XMEM_CS5_SLOW_CFG,
48];
49const CS_FAST_OFFSETS: [usize; NUM_CS] = [
50 EBI2_XMEM_CS0_FAST_CFG,
51 EBI2_XMEM_CS1_FAST_CFG,
52 EBI2_XMEM_CS2_FAST_CFG,
53 EBI2_XMEM_CS3_FAST_CFG,
54 EBI2_XMEM_CS4_FAST_CFG,
55 EBI2_XMEM_CS5_FAST_CFG,
56];
57
58const COMPATIBLE: &[&str] = &["qcom,msm8660-ebi2", "qcom,apq8060-ebi2"];
59
60pub struct Ebi2CsConfig {
61 pub recovery_cycles: u32,
62 pub wr_hold_cycles: u32,
63 pub wr_delta_cycles: u32,
64 pub rd_delta_cycles: u32,
65 pub wr_wait_cycles: u32,
66 pub rd_wait_cycles: u32,
67 pub rd_hold_cycles: u32,
68 pub adv_oe_recovery: u32,
69 pub addr_hold_ena: bool,
70}
71
72impl Ebi2CsConfig {
73 pub fn to_slow_reg(&self) -> u32 {
75 (self.recovery_cycles << SLOW_RECOVERY_SHIFT)
76 | (self.wr_hold_cycles << SLOW_WR_HOLD_SHIFT)
77 | (self.wr_delta_cycles << SLOW_WR_DELTA_SHIFT)
78 | (self.rd_delta_cycles << SLOW_RD_DELTA_SHIFT)
79 | (self.wr_wait_cycles << SLOW_WR_WAIT_SHIFT)
80 | (self.rd_wait_cycles << SLOW_RD_WAIT_SHIFT)
81 }
82
83 pub fn to_fast_reg(&self) -> u32 {
85 let mut val = (self.rd_hold_cycles << FAST_RD_HOLD_SHIFT)
86 | (self.adv_oe_recovery << FAST_ADV_OE_RECOVERY_SHIFT);
87 if self.addr_hold_ena {
88 val |= FAST_ADDR_HOLD_ENA;
89 }
90 val
91 }
92}
93
94pub struct QcomEbi2 {
95 regs: MmioRegion,
96 cs_configs: [Option<Ebi2CsConfig>; NUM_CS],
97 power_state: PowerState,
98 children: Vec<BusChild>,
99}
100
101impl QcomEbi2 {
102 pub fn new() -> Self {
104 Self {
105 regs: MmioRegion::new(),
106 cs_configs: [const { None }; NUM_CS],
107 power_state: PowerState::Off,
108 children: Vec::new(),
109 }
110 }
111
112 pub fn configure_cs(&mut self, cs: usize, config: Ebi2CsConfig) {
114 if cs < NUM_CS {
115 self.cs_configs[cs] = Some(config);
116 }
117 }
118
119 fn apply_config(&self) {
121 self.regs.write32(EBI2_XMEM_CFG, 0);
122
123 for cs in 0..NUM_CS {
124 if let Some(ref cfg) = self.cs_configs[cs] {
125 let mut xmem = self.regs.read32(EBI2_XMEM_CFG);
126 xmem |= CS_ENABLE_MASKS[cs];
127 self.regs.write32(EBI2_XMEM_CFG, xmem);
128
129 self.regs.write32(CS_SLOW_OFFSETS[cs], cfg.to_slow_reg());
130 self.regs.write32(CS_FAST_OFFSETS[cs], cfg.to_fast_reg());
131 }
132 }
133 }
134
135 pub fn add_child(&mut self, child: BusChild) {
137 self.children.push(child);
138 }
139}
140
141impl BusDriver for QcomEbi2 {
142 fn name(&self) -> &str {
144 "qcom-ebi2"
145 }
146
147 fn compatible(&self) -> &[&str] {
149 COMPATIBLE
150 }
151
152 fn init(&mut self, base: usize) -> Result<(), BusError> {
154 self.regs.init(base, 0x100);
155 self.apply_config();
156 self.power_state = PowerState::On;
157 Ok(())
158 }
159
160 fn shutdown(&mut self) -> Result<(), BusError> {
162 self.power_state = PowerState::Off;
163 Ok(())
164 }
165
166 fn read_reg(&self, offset: usize) -> Result<u32, BusError> {
168 if !self.regs.is_valid() {
169 return Err(BusError::InitFailed);
170 }
171 Ok(self.regs.read32(offset))
172 }
173
174 fn write_reg(&mut self, offset: usize, value: u32) -> Result<(), BusError> {
176 if !self.regs.is_valid() {
177 return Err(BusError::InitFailed);
178 }
179 self.regs.write32(offset, value);
180 Ok(())
181 }
182
183 fn children(&self) -> Vec<BusChild> {
185 self.children.clone()
186 }
187}