|
3 | 3 | //! The current implementation talks to them by tunneling I2C through EC host commands.
|
4 | 4 |
|
5 | 5 | use alloc::format;
|
6 |
| -use alloc::string::ToString; |
7 |
| -use alloc::vec; |
8 | 6 | use alloc::vec::Vec;
|
9 | 7 | #[cfg(feature = "uefi")]
|
10 | 8 | use core::prelude::rust_2021::derive;
|
11 | 9 |
|
12 | 10 | use crate::ccgx::{AppVersion, BaseVersion, ControllerVersion};
|
13 |
| -use crate::chromium_ec::command::EcCommands; |
14 |
| -use crate::chromium_ec::{CrosEc, CrosEcDriver, EcError, EcResult}; |
15 |
| -use crate::util::{self, assert_win_len, Config, Platform}; |
16 |
| -use std::mem::size_of; |
| 11 | +use crate::chromium_ec::i2c_passthrough::*; |
| 12 | +use crate::chromium_ec::{CrosEc, EcError, EcResult}; |
| 13 | +use crate::util::{assert_win_len, Config, Platform}; |
17 | 14 |
|
18 | 15 | use super::*;
|
19 | 16 |
|
20 |
| -/// Maximum transfer size for one I2C transaction supported by the chip |
21 |
| -const MAX_I2C_CHUNK: usize = 128; |
22 |
| - |
23 | 17 | enum ControlRegisters {
|
24 | 18 | DeviceMode = 0,
|
25 | 19 | SiliconId = 2, // Two bytes long, First LSB, then MSB
|
@@ -106,58 +100,6 @@ pub struct PdController {
|
106 | 100 | ec: CrosEc,
|
107 | 101 | }
|
108 | 102 |
|
109 |
| -fn passthrough_offset(dev_index: u16) -> u16 { |
110 |
| - dev_index * 0x4000 |
111 |
| -} |
112 |
| - |
113 |
| -#[repr(C, packed)] |
114 |
| -struct EcParamsI2cPassthruMsg { |
115 |
| - /// Slave address and flags |
116 |
| - addr_and_flags: u16, |
117 |
| - transfer_len: u16, |
118 |
| -} |
119 |
| - |
120 |
| -#[repr(C, packed)] |
121 |
| -struct EcParamsI2cPassthru { |
122 |
| - port: u8, |
123 |
| - /// How many messages |
124 |
| - messages: u8, |
125 |
| - msg: [EcParamsI2cPassthruMsg; 0], |
126 |
| -} |
127 |
| - |
128 |
| -#[repr(C, packed)] |
129 |
| -struct _EcI2cPassthruResponse { |
130 |
| - i2c_status: u8, |
131 |
| - /// How many messages |
132 |
| - messages: u8, |
133 |
| - data: [u8; 0], |
134 |
| -} |
135 |
| - |
136 |
| -struct EcI2cPassthruResponse { |
137 |
| - i2c_status: u8, // TODO: Can probably use enum |
138 |
| - data: Vec<u8>, |
139 |
| -} |
140 |
| - |
141 |
| -impl EcI2cPassthruResponse { |
142 |
| - fn is_successful(&self) -> EcResult<()> { |
143 |
| - if self.i2c_status & 1 > 0 { |
144 |
| - return Err(EcError::DeviceError( |
145 |
| - "I2C Transfer not acknowledged".to_string(), |
146 |
| - )); |
147 |
| - } |
148 |
| - if self.i2c_status & (1 << 1) > 0 { |
149 |
| - return Err(EcError::DeviceError("I2C Transfer timeout".to_string())); |
150 |
| - } |
151 |
| - // I'm not aware of any other errors, but there might be. |
152 |
| - // But I don't think multiple errors can be indicated at the same time |
153 |
| - assert_eq!(self.i2c_status, 0); |
154 |
| - Ok(()) |
155 |
| - } |
156 |
| -} |
157 |
| - |
158 |
| -/// Indicate that it's a read, not a write |
159 |
| -const I2C_READ_FLAG: u16 = 1 << 15; |
160 |
| - |
161 | 103 | #[derive(Debug, PartialEq)]
|
162 | 104 | pub enum FwMode {
|
163 | 105 | BootLoader = 0,
|
@@ -194,63 +136,20 @@ impl PdController {
|
194 | 136 | pub fn new(port: PdPort, ec: CrosEc) -> Self {
|
195 | 137 | PdController { port, ec }
|
196 | 138 | }
|
197 |
| - /// Wrapped with support for dev id |
198 |
| - /// TODO: Should move into chromium_ec module |
199 |
| - /// TODO: Must not call CrosEc::new() otherwise the driver isn't configurable! |
200 |
| - fn send_ec_command(&self, code: u16, dev_index: u16, data: &[u8]) -> EcResult<Vec<u8>> { |
201 |
| - let command_id = code + passthrough_offset(dev_index); |
202 |
| - self.ec.send_command(command_id, 0, data) |
203 |
| - } |
204 | 139 |
|
205 | 140 | fn i2c_read(&self, addr: u16, len: u16) -> EcResult<EcI2cPassthruResponse> {
|
206 | 141 | trace!(
|
207 | 142 | "I2C passthrough from I2C Port {} to I2C Addr {}",
|
208 | 143 | self.port.i2c_port().unwrap(),
|
209 | 144 | self.port.i2c_address()
|
210 | 145 | );
|
211 |
| - trace!("i2c_read(addr: {}, len: {})", addr, len); |
212 |
| - if usize::from(len) > MAX_I2C_CHUNK { |
213 |
| - return EcResult::Err(EcError::DeviceError(format!( |
214 |
| - "i2c_read too long. Must be <128, is: {}", |
215 |
| - len |
216 |
| - ))); |
217 |
| - } |
218 |
| - let addr_bytes = u16::to_le_bytes(addr); |
219 |
| - let messages = vec![ |
220 |
| - EcParamsI2cPassthruMsg { |
221 |
| - addr_and_flags: self.port.i2c_address(), |
222 |
| - transfer_len: addr_bytes.len() as u16, |
223 |
| - }, |
224 |
| - EcParamsI2cPassthruMsg { |
225 |
| - addr_and_flags: self.port.i2c_address() + I2C_READ_FLAG, |
226 |
| - transfer_len: len, // How much to read |
227 |
| - }, |
228 |
| - ]; |
229 |
| - let msgs_len = size_of::<EcParamsI2cPassthruMsg>() * messages.len(); |
230 |
| - let msgs_buffer: &[u8] = unsafe { util::any_vec_as_u8_slice(&messages) }; |
231 |
| - |
232 |
| - let params = EcParamsI2cPassthru { |
233 |
| - port: self.port.i2c_port()?, |
234 |
| - messages: messages.len() as u8, |
235 |
| - msg: [], // Messages are copied right after this struct |
236 |
| - }; |
237 |
| - let params_len = size_of::<EcParamsI2cPassthru>(); |
238 |
| - let params_buffer: &[u8] = unsafe { util::any_as_u8_slice(¶ms) }; |
239 |
| - |
240 |
| - let mut buffer: Vec<u8> = vec![0; params_len + msgs_len + addr_bytes.len()]; |
241 |
| - buffer[0..params_len].copy_from_slice(params_buffer); |
242 |
| - buffer[params_len..params_len + msgs_len].copy_from_slice(msgs_buffer); |
243 |
| - buffer[params_len + msgs_len..].copy_from_slice(&addr_bytes); |
244 |
| - |
245 |
| - let data = self.send_ec_command(EcCommands::I2cPassthrough as u16, 0, &buffer)?; |
246 |
| - let res: _EcI2cPassthruResponse = unsafe { std::ptr::read(data.as_ptr() as *const _) }; |
247 |
| - let res_data = &data[size_of::<_EcI2cPassthruResponse>()..]; |
248 |
| - // TODO: Seems to be either one, non-deterministically |
249 |
| - debug_assert!(res.messages as usize == messages.len() || res.messages == 0); |
250 |
| - Ok(EcI2cPassthruResponse { |
251 |
| - i2c_status: res.i2c_status, |
252 |
| - data: res_data.to_vec(), |
253 |
| - }) |
| 146 | + i2c_read( |
| 147 | + &self.ec, |
| 148 | + self.port.i2c_port().unwrap(), |
| 149 | + self.port.i2c_address(), |
| 150 | + addr, |
| 151 | + len, |
| 152 | + ) |
254 | 153 | }
|
255 | 154 |
|
256 | 155 | fn ccgx_read(&self, reg: ControlRegisters, len: u16) -> EcResult<Vec<u8>> {
|
|
0 commit comments