Skip to content

Commit e8acfa7

Browse files
committed
--expansion-bay: Read eeprom directly and dump extra details
Signed-off-by: Daniel Schaefer <[email protected]>
1 parent 85c4b2f commit e8acfa7

File tree

3 files changed

+87
-0
lines changed

3 files changed

+87
-0
lines changed

EXAMPLES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,13 @@ Expansion Bay
317317
Serial Number: FRAXXXXXXXXXXXXXXX
318318
Config: Pcie4x2
319319
Vendor: SsdHolder
320+
Expansion Bay EEPROM
321+
Valid: true
322+
HW Version: 8.0
320323
```
321324

325+
Add `-vv` for more verbose details.
326+
322327
## Check charger and battery status (Framework 12/13/16)
323328

324329
```

framework_lib/src/chromium_ec/mod.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,6 +1177,34 @@ impl CrosEc {
11771177
Ok(result.valid)
11781178
}
11791179

1180+
pub fn read_ec_gpu_chunk(&self, addr: u16, len: u16) -> EcResult<Vec<u8>> {
1181+
let eeprom_port = 0x05;
1182+
let eeprom_addr = 0x50;
1183+
let mut data: Vec<u8> = Vec::with_capacity(len.into());
1184+
1185+
while data.len() < len.into() {
1186+
let remaining = len - data.len() as u16;
1187+
let chunk_len = std::cmp::min(i2c_passthrough::MAX_I2C_CHUNK, remaining.into());
1188+
let offset = addr + data.len() as u16;
1189+
let i2c_response = i2c_passthrough::i2c_read(
1190+
self,
1191+
eeprom_port,
1192+
eeprom_addr,
1193+
offset,
1194+
chunk_len as u16,
1195+
)?;
1196+
if let Err(EcError::DeviceError(err)) = i2c_response.is_successful() {
1197+
return Err(EcError::DeviceError(format!(
1198+
"I2C read was not successful: {:?}",
1199+
err
1200+
)));
1201+
}
1202+
data.extend(i2c_response.data);
1203+
}
1204+
1205+
Ok(data)
1206+
}
1207+
11801208
pub fn write_ec_gpu_chunk(&self, offset: u16, data: &[u8]) -> EcResult<()> {
11811209
let result = i2c_passthrough::i2c_write(self, 5, 0x50, offset, data)?;
11821210
result.is_successful()
@@ -1226,6 +1254,15 @@ impl CrosEc {
12261254
Ok(())
12271255
}
12281256

1257+
pub fn read_gpu_desc_header(&self) -> EcResult<GpuCfgDescriptor> {
1258+
let bytes =
1259+
self.read_ec_gpu_chunk(0x00, core::mem::size_of::<GpuCfgDescriptor>() as u16)?;
1260+
let header: *const GpuCfgDescriptor = unsafe { std::mem::transmute(bytes.as_ptr()) };
1261+
let header = unsafe { *header };
1262+
1263+
Ok(header)
1264+
}
1265+
12291266
/// Requests recent console output from EC and constantly asks for more
12301267
/// Prints the output and returns it when an error is encountered
12311268
pub fn console_read(&self) -> EcResult<()> {
@@ -1633,3 +1670,28 @@ pub struct IntrusionStatus {
16331670
/// That means we only know if it was opened at least once, while off, not how many times.
16341671
pub vtr_open_count: u8,
16351672
}
1673+
1674+
#[derive(Clone, Debug, Copy, PartialEq)]
1675+
#[repr(C, packed)]
1676+
pub struct GpuCfgDescriptor {
1677+
/// Expansion bay card magic value that is unique
1678+
pub magic: [u8; 4],
1679+
/// Length of header following this field
1680+
pub length: u32,
1681+
/// descriptor version, if EC max version is lower than this, ec cannot parse
1682+
pub desc_ver_major: u16,
1683+
pub desc_ver_minor: u16,
1684+
/// Hardware major version
1685+
pub hardware_version: u16,
1686+
/// Hardware minor revision
1687+
pub hardware_revision: u16,
1688+
/// 18 digit Framework Serial that starts with FRA
1689+
/// the first 10 digits must be allocated by framework
1690+
pub serial: [u8; 20],
1691+
/// Length of descriptor following heade
1692+
pub descriptor_length: u32,
1693+
/// CRC of descriptor
1694+
pub descriptor_crc32: u32,
1695+
/// CRC of header before this value
1696+
pub crc32: u32,
1697+
}

framework_lib/src/commandline/mod.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,26 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
884884
if let Err(err) = ec.check_bay_status() {
885885
error!("{:?}", err);
886886
}
887+
if let Ok(header) = ec.read_gpu_desc_header() {
888+
println!(" Expansion Bay EEPROM");
889+
println!(
890+
" Valid: {:?}",
891+
header.magic == [0x32, 0xAC, 0x00, 0x00]
892+
);
893+
println!(" HW Version: {}.{}", { header.hardware_version }, {
894+
header.hardware_revision
895+
});
896+
if log_enabled!(Level::Info) {
897+
println!(" Hdr Length {} B", { header.length });
898+
println!(" Desc Ver: {}.{}", { header.desc_ver_major }, {
899+
header.desc_ver_minor
900+
});
901+
println!(" Serialnumber:{:X?}", { header.serial });
902+
println!(" Desc Length: {} B", { header.descriptor_length });
903+
println!(" Desc CRC: {:X}", { header.descriptor_crc32 });
904+
println!(" Hdr CRC: {:X}", { header.crc32 });
905+
}
906+
}
887907
} else if let Some(maybe_limit) = args.charge_limit {
888908
print_err(handle_charge_limit(&ec, maybe_limit));
889909
} else if let Some((limit, soc)) = args.charge_current_limit {

0 commit comments

Comments
 (0)