strat9_bus_drivers/
hisi_lpc.rs1use crate::{BusChild, BusDriver, BusError, PowerState, mmio::MmioRegion};
2use alloc::{string::String, vec::Vec};
3
4const LPC_REG_STARTUP_SIGNAL: usize = 0x00;
5const LPC_REG_OP_STATUS: usize = 0x04;
6const LPC_REG_OP_LEN: usize = 0x10;
7const LPC_REG_CMD: usize = 0x14;
8const LPC_REG_ADDR: usize = 0x20;
9const LPC_REG_WDATA: usize = 0x24;
10const LPC_REG_RDATA: usize = 0x28;
11
12const STARTUP_SIGNAL_START: u32 = 1 << 0;
13const OP_STATUS_IDLE: u32 = 1 << 0;
14const OP_STATUS_FINISHED: u32 = 1 << 1;
15const CMD_OP_READ: u32 = 0;
16const CMD_OP_WRITE: u32 = 1 << 0;
17const CMD_SAMEADDR: u32 = 1 << 3;
18
19const LPC_MAX_DWIDTH: u32 = 4;
20const LPC_PEROP_WAITCNT: u32 = 100;
21const LPC_MAX_WAITCNT: u32 = 1300;
22
23const COMPATIBLE: &[&str] = &["hisilicon,hip06-lpc", "hisilicon,hip07-lpc"];
24
25pub struct HisiLpc {
26 regs: MmioRegion,
27 power_state: PowerState,
28 children: Vec<BusChild>,
29}
30
31impl HisiLpc {
32 pub fn new() -> Self {
34 Self {
35 regs: MmioRegion::new(),
36 power_state: PowerState::Off,
37 children: Vec::new(),
38 }
39 }
40
41 fn wait_idle(&self) -> Result<(), BusError> {
43 for _ in 0..LPC_MAX_WAITCNT {
44 let status = self.regs.read32(LPC_REG_OP_STATUS);
45 if status & OP_STATUS_IDLE != 0 {
46 return Ok(());
47 }
48 }
49 Err(BusError::Timeout)
50 }
51
52 fn wait_finish(&self) -> Result<(), BusError> {
54 for _ in 0..LPC_MAX_WAITCNT {
55 let status = self.regs.read32(LPC_REG_OP_STATUS);
56 if status & OP_STATUS_FINISHED != 0 {
57 return Ok(());
58 }
59 }
60 Err(BusError::Timeout)
61 }
62
63 pub fn lpc_read(&self, addr: u32, width: u32) -> Result<u32, BusError> {
65 if width == 0 || width > LPC_MAX_DWIDTH {
66 return Err(BusError::InvalidArgument);
67 }
68
69 self.wait_idle()?;
70
71 self.regs.write32(LPC_REG_ADDR, addr);
72 self.regs.write32(LPC_REG_CMD, CMD_OP_READ);
73 self.regs.write32(LPC_REG_OP_LEN, width);
74 self.regs
75 .write32(LPC_REG_STARTUP_SIGNAL, STARTUP_SIGNAL_START);
76
77 self.wait_finish()?;
78
79 let mut result = 0u32;
80 for i in 0..width {
81 let byte = self.regs.read32(LPC_REG_RDATA) & 0xFF;
82 result |= byte << (i * 8);
83 }
84
85 Ok(result)
86 }
87
88 pub fn lpc_write(&self, addr: u32, width: u32, data: u32) -> Result<(), BusError> {
90 if width == 0 || width > LPC_MAX_DWIDTH {
91 return Err(BusError::InvalidArgument);
92 }
93
94 self.wait_idle()?;
95
96 self.regs.write32(LPC_REG_ADDR, addr);
97 self.regs.write32(LPC_REG_CMD, CMD_OP_WRITE);
98 self.regs.write32(LPC_REG_OP_LEN, width);
99
100 for i in 0..width {
101 self.regs.write32(LPC_REG_WDATA, (data >> (i * 8)) & 0xFF);
102 }
103
104 self.regs
105 .write32(LPC_REG_STARTUP_SIGNAL, STARTUP_SIGNAL_START);
106
107 self.wait_finish()?;
108
109 Ok(())
110 }
111
112 pub fn io_read8(&self, port: u16) -> Result<u8, BusError> {
114 self.lpc_read(port as u32, 1).map(|v| v as u8)
115 }
116
117 pub fn io_write8(&self, port: u16, val: u8) -> Result<(), BusError> {
119 self.lpc_write(port as u32, 1, val as u32)
120 }
121
122 pub fn io_read16(&self, port: u16) -> Result<u16, BusError> {
124 self.lpc_read(port as u32, 2).map(|v| v as u16)
125 }
126
127 pub fn io_write16(&self, port: u16, val: u16) -> Result<(), BusError> {
129 self.lpc_write(port as u32, 2, val as u32)
130 }
131
132 pub fn io_read32(&self, port: u16) -> Result<u32, BusError> {
134 self.lpc_read(port as u32, 4)
135 }
136
137 pub fn io_write32(&self, port: u16, val: u32) -> Result<(), BusError> {
139 self.lpc_write(port as u32, 4, val)
140 }
141
142 pub fn add_child(&mut self, child: BusChild) {
144 self.children.push(child);
145 }
146}
147
148impl BusDriver for HisiLpc {
149 fn name(&self) -> &str {
151 "hisi-lpc"
152 }
153
154 fn compatible(&self) -> &[&str] {
156 COMPATIBLE
157 }
158
159 fn init(&mut self, base: usize) -> Result<(), BusError> {
161 self.regs.init(base, 0x30);
162 self.wait_idle()?;
163 self.power_state = PowerState::On;
164 Ok(())
165 }
166
167 fn shutdown(&mut self) -> Result<(), BusError> {
169 self.power_state = PowerState::Off;
170 Ok(())
171 }
172
173 fn read_reg(&self, offset: usize) -> Result<u32, BusError> {
175 if !self.regs.is_valid() {
176 return Err(BusError::InitFailed);
177 }
178 Ok(self.regs.read32(offset))
179 }
180
181 fn write_reg(&mut self, offset: usize, value: u32) -> Result<(), BusError> {
183 if !self.regs.is_valid() {
184 return Err(BusError::InitFailed);
185 }
186 self.regs.write32(offset, value);
187 Ok(())
188 }
189
190 fn children(&self) -> Vec<BusChild> {
192 self.children.clone()
193 }
194}