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 bus_init(&self) -> Result<(), BusError> {
49 self.config0_regs
50 .clear_bits32(0, SSCAON_CONFIG0_CLAMP_EN_OVRD_VAL);
51 self.config0_regs
52 .set_bits32(0, SSCAON_CONFIG0_CLAMP_EN_OVRD);
53 self.config1_regs.clear_bits32(0, SSCAON_CONFIG1_CFG);
54
55 self.halt_regs.write32(AXI_HALTREQ_REG, 0);
56
57 for _ in 0..MAX_HALT_WAIT {
58 let idle = self.halt_regs.read32(AXI_IDLE_REG);
59 if idle != 0 {
60 return Ok(());
61 }
62 }
63
64 Ok(())
65 }
66
67 fn bus_deinit(&self) {
69 self.halt_regs.write32(AXI_HALTREQ_REG, 1);
70
71 for _ in 0..MAX_HALT_WAIT {
72 let ack = self.halt_regs.read32(AXI_HALTACK_REG);
73 if ack != 0 {
74 break;
75 }
76 }
77
78 self.config0_regs
79 .set_bits32(0, SSCAON_CONFIG0_CLAMP_EN_OVRD_VAL);
80 self.config1_regs.set_bits32(0, SSCAON_CONFIG1_CFG);
81 }
82
83 pub fn add_child(&mut self, child: BusChild) {
85 self.children.push(child);
86 }
87}
88
89impl BusDriver for QcomSscBlockBus {
90 fn name(&self) -> &str {
92 "qcom-ssc-block-bus"
93 }
94
95 fn compatible(&self) -> &[&str] {
97 COMPATIBLE
98 }
99
100 fn init(&mut self, base: usize) -> Result<(), BusError> {
102 self.halt_regs.init(base, 0x10);
103 self.bus_init()?;
104 self.power_state = PowerState::On;
105 Ok(())
106 }
107
108 fn shutdown(&mut self) -> Result<(), BusError> {
110 self.bus_deinit();
111 self.power_state = PowerState::Off;
112 Ok(())
113 }
114
115 fn read_reg(&self, offset: usize) -> Result<u32, BusError> {
117 if !self.halt_regs.is_valid() {
118 return Err(BusError::InitFailed);
119 }
120 Ok(self.halt_regs.read32(offset))
121 }
122
123 fn write_reg(&mut self, offset: usize, value: u32) -> Result<(), BusError> {
125 if !self.halt_regs.is_valid() {
126 return Err(BusError::InitFailed);
127 }
128 self.halt_regs.write32(offset, value);
129 Ok(())
130 }
131
132 fn children(&self) -> Vec<BusChild> {
134 self.children.clone()
135 }
136}