strat9_bus_drivers/
qcom_ssc_block_bus.rs1use crate::{BusChild, BusDriver, BusError, PowerState, mmio::MmioRegion};
2use alloc::{string::String, vec::Vec};
3
4const AXI_HALTREQ_REG: usize = 0x0;
5const AXI_HALTACK_REG: usize = 0x4;
6const AXI_IDLE_REG: usize = 0x8;
7
8const SSCAON_CONFIG0_CLAMP_EN_OVRD: u32 = 1 << 4;
9const SSCAON_CONFIG0_CLAMP_EN_OVRD_VAL: u32 = 1 << 5;
10const SSCAON_CONFIG1_CFG: u32 = 1 << 31;
11
12const MAX_HALT_WAIT: u32 = 10000;
13
14const COMPATIBLE: &[&str] = &["qcom,ssc-block-bus"];
15
16pub struct QcomSscBlockBus {
17 halt_regs: MmioRegion,
18 config0_regs: MmioRegion,
19 config1_regs: MmioRegion,
20 power_state: PowerState,
21 children: Vec<BusChild>,
22}
23
24impl QcomSscBlockBus {
25 pub fn new() -> Self {
27 Self {
28 halt_regs: MmioRegion::new(),
29 config0_regs: MmioRegion::new(),
30 config1_regs: MmioRegion::new(),
31 power_state: PowerState::Off,
32 children: Vec::new(),
33 }
34 }
35
36 pub fn init_halt_regs(&mut self, base: usize) {
38 self.halt_regs.init(base, 0x10);
39 }
40
41 pub fn init_config_regs(&mut self, config0_base: usize, config1_base: usize) {
43 self.config0_regs.init(config0_base, 0x10);
44 self.config1_regs.init(config1_base, 0x10);
45 }
46
47 fn ensure_mapped(&self) -> Result<(), BusError> {
55 if self.halt_regs.is_valid() && self.config0_regs.is_valid() && self.config1_regs.is_valid()
56 {
57 Ok(())
58 } else {
59 Err(BusError::InitFailed)
60 }
61 }
62
63 fn bus_init(&self) -> Result<(), BusError> {
65 self.ensure_mapped()?;
66
67 self.config0_regs
68 .clear_bits32(0, SSCAON_CONFIG0_CLAMP_EN_OVRD_VAL);
69 self.config0_regs
70 .set_bits32(0, SSCAON_CONFIG0_CLAMP_EN_OVRD);
71 self.config1_regs.clear_bits32(0, SSCAON_CONFIG1_CFG);
72
73 self.halt_regs.write32(AXI_HALTREQ_REG, 0);
74
75 for _ in 0..MAX_HALT_WAIT {
76 let idle = self.halt_regs.read32(AXI_IDLE_REG);
77 if idle != 0 {
78 return Ok(());
79 }
80 }
81
82 Err(BusError::Timeout)
85 }
86
87 fn bus_deinit(&self) -> Result<(), BusError> {
92 self.ensure_mapped()?;
93
94 self.halt_regs.write32(AXI_HALTREQ_REG, 1);
95
96 let mut halted = false;
97 for _ in 0..MAX_HALT_WAIT {
98 let ack = self.halt_regs.read32(AXI_HALTACK_REG);
99 if ack != 0 {
100 halted = true;
101 break;
102 }
103 }
104
105 self.config0_regs
106 .set_bits32(0, SSCAON_CONFIG0_CLAMP_EN_OVRD_VAL);
107 self.config1_regs.set_bits32(0, SSCAON_CONFIG1_CFG);
108
109 if halted {
110 Ok(())
111 } else {
112 Err(BusError::Timeout)
113 }
114 }
115
116 pub fn add_child(&mut self, child: BusChild) {
118 self.children.push(child);
119 }
120}
121
122impl BusDriver for QcomSscBlockBus {
123 fn name(&self) -> &str {
125 "qcom-ssc-block-bus"
126 }
127
128 fn compatible(&self) -> &[&str] {
130 COMPATIBLE
131 }
132
133 fn init(&mut self, base: usize) -> Result<(), BusError> {
135 self.halt_regs.init(base, 0x10);
136 self.bus_init()?;
137 self.power_state = PowerState::On;
138 Ok(())
139 }
140
141 fn shutdown(&mut self) -> Result<(), BusError> {
143 let res = self.bus_deinit();
144 self.power_state = PowerState::Off;
145 res
146 }
147
148 fn read_reg(&self, offset: usize) -> Result<u32, BusError> {
150 if !self.halt_regs.is_valid() {
151 return Err(BusError::InitFailed);
152 }
153 self.halt_regs.check_user_offset(offset)?;
154 Ok(self.halt_regs.read32(offset))
155 }
156
157 fn write_reg(&mut self, offset: usize, value: u32) -> Result<(), BusError> {
159 if !self.halt_regs.is_valid() {
160 return Err(BusError::InitFailed);
161 }
162 self.halt_regs.check_user_offset(offset)?;
163 self.halt_regs.write32(offset, value);
164 Ok(())
165 }
166
167 fn children(&self) -> Vec<BusChild> {
169 self.children.clone()
170 }
171}