Skip to content

Commit 409318c

Browse files
committed
eeprom: Make --dump-gpu-descriptor-file more reliable
I often noticed it returning invalid data. Using 16 bit addressing seems to work better. Signed-off-by: Daniel Schaefer <dhs@frame.work>
1 parent b10db43 commit 409318c

2 files changed

Lines changed: 62 additions & 1 deletion

File tree

framework_lib/src/chromium_ec/i2c_passthrough.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,66 @@ pub fn i2c_read(
121121
})
122122
}
123123

124+
/// I2C read with 16-bit addressing (for larger EEPROMs like 24C32+)
125+
/// Always sends a 2-byte address, even for addr=0
126+
pub fn i2c_read_16bit_addr(
127+
ec: &CrosEc,
128+
i2c_port: u8,
129+
i2c_addr: u16,
130+
addr: u16,
131+
len: u16,
132+
) -> EcResult<EcI2cPassthruResponse> {
133+
trace!(
134+
"i2c_read_16bit_addr(i2c_port: 0x{:X}, i2c_addr: 0x{:X}, addr: 0x{:X}, len: 0x{:X})",
135+
i2c_port,
136+
i2c_addr,
137+
addr,
138+
len
139+
);
140+
if usize::from(len) > MAX_I2C_CHUNK {
141+
return EcResult::Err(EcError::DeviceError(format!(
142+
"i2c_read too long. Must be <128, is: {}",
143+
len
144+
)));
145+
}
146+
// Always use 16-bit addressing (big-endian for EEPROM)
147+
let addr_bytes = u16::to_be_bytes(addr).to_vec();
148+
let messages = vec![
149+
EcParamsI2cPassthruMsg {
150+
addr_and_flags: i2c_addr,
151+
transfer_len: addr_bytes.len() as u16,
152+
},
153+
EcParamsI2cPassthruMsg {
154+
addr_and_flags: i2c_addr + I2C_READ_FLAG,
155+
transfer_len: len, // How much to read
156+
},
157+
];
158+
let msgs_len = size_of::<EcParamsI2cPassthruMsg>() * messages.len();
159+
let msgs_buffer: &[u8] = unsafe { util::any_vec_as_u8_slice(&messages) };
160+
161+
let params = EcParamsI2cPassthru {
162+
port: i2c_port,
163+
messages: messages.len() as u8,
164+
msg: [], // Messages are copied right after this struct
165+
};
166+
let params_len = size_of::<EcParamsI2cPassthru>();
167+
let params_buffer: &[u8] = unsafe { util::any_as_u8_slice(&params) };
168+
169+
let mut buffer: Vec<u8> = vec![0; params_len + msgs_len + addr_bytes.len()];
170+
buffer[0..params_len].copy_from_slice(params_buffer);
171+
buffer[params_len..params_len + msgs_len].copy_from_slice(msgs_buffer);
172+
buffer[params_len + msgs_len..].copy_from_slice(&addr_bytes);
173+
174+
let data = ec.send_command(EcCommands::I2cPassthrough as u16, 0, &buffer)?;
175+
let res: _EcI2cPassthruResponse = unsafe { std::ptr::read(data.as_ptr() as *const _) };
176+
let res_data = &data[size_of::<_EcI2cPassthruResponse>()..];
177+
debug_assert!(res.messages as usize == messages.len() || res.messages == 0);
178+
Ok(EcI2cPassthruResponse {
179+
i2c_status: res.i2c_status,
180+
data: res_data.to_vec(),
181+
})
182+
}
183+
124184
/* Write address and bytes in a single I2C transfer */
125185
pub fn i2c_write_block(
126186
ec: &CrosEc,

framework_lib/src/chromium_ec/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1295,7 +1295,8 @@ impl CrosEc {
12951295
let remaining = len - data.len() as u16;
12961296
let chunk_len = std::cmp::min(i2c_passthrough::MAX_I2C_CHUNK, remaining.into());
12971297
let offset = addr + data.len() as u16;
1298-
let i2c_response = i2c_passthrough::i2c_read(
1298+
// Use 16-bit addressing for GPU EEPROM (required for larger EEPROMs)
1299+
let i2c_response = i2c_passthrough::i2c_read_16bit_addr(
12991300
self,
13001301
eeprom_port,
13011302
eeprom_addr,

0 commit comments

Comments
 (0)