diff --git a/framework_lib/src/ccgx/binary.rs b/framework_lib/src/ccgx/binary.rs index 9206efb4..98d44a3d 100644 --- a/framework_lib/src/ccgx/binary.rs +++ b/framework_lib/src/ccgx/binary.rs @@ -104,14 +104,18 @@ fn read_metadata( file_buffer: &[u8], flash_row_size: usize, metadata_offset: u32, - ccgx: SiliconId, + ccgx: SiliconFamily, ) -> Option<(u32, u32)> { let buffer = read_256_bytes(file_buffer, metadata_offset, flash_row_size)?; match ccgx { - SiliconId::Ccg3 => parse_metadata_ccg3(&buffer), - SiliconId::Ccg5 | SiliconId::Ccg6Adl | SiliconId::Ccg6 => parse_metadata_cyacd(&buffer), - SiliconId::Ccg8 => parse_metadata_cyacd2(&buffer) - .map(|(fw_row_start, fw_size)| (fw_row_start / (flash_row_size as u32), fw_size)), + SiliconFamily::Ccg3 => parse_metadata_ccg3(&buffer), + SiliconFamily::Ccg5 | SiliconFamily::Ccg6Adl | SiliconFamily::Ccg6 => { + parse_metadata_cyacd(&buffer) + } + SiliconFamily::Ccg8D | SiliconFamily::Ccg8S | SiliconFamily::Ccg8Cfp => { + parse_metadata_cyacd2(&buffer) + .map(|(fw_row_start, fw_size)| (fw_row_start / (flash_row_size as u32), fw_size)) + } } } @@ -141,7 +145,7 @@ fn read_version( file_buffer: &[u8], flash_row_size: usize, metadata_offset: u32, - ccgx: SiliconId, + ccgx: SiliconFamily, ) -> Option { let (fw_row_start, fw_size) = read_metadata(file_buffer, flash_row_size, metadata_offset, ccgx)?; @@ -169,13 +173,15 @@ fn read_version( } /// Parse all PD information, given a binary file (buffer) -pub fn read_versions(file_buffer: &[u8], ccgx: SiliconId) -> Option { +pub fn read_versions(file_buffer: &[u8], ccgx: SiliconFamily) -> Option { let (flash_row_size, f1_metadata_row, fw2_metadata_row) = match ccgx { - SiliconId::Ccg3 => (SMALL_ROW, 0x03FF, 0x03FE), - SiliconId::Ccg5 => (LARGE_ROW, FW1_METADATA_ROW, FW2_METADATA_ROW_CCG5), - SiliconId::Ccg6Adl => (SMALL_ROW, FW1_METADATA_ROW, FW2_METADATA_ROW_CCG6), - SiliconId::Ccg6 => (SMALL_ROW, FW1_METADATA_ROW, FW2_METADATA_ROW_CCG6), - SiliconId::Ccg8 => (LARGE_ROW, FW1_METADATA_ROW_CCG8, FW2_METADATA_ROW_CCG8), + SiliconFamily::Ccg3 => (SMALL_ROW, 0x03FF, 0x03FE), + SiliconFamily::Ccg5 => (LARGE_ROW, 0x1FE, 0x1FF), + SiliconFamily::Ccg6Adl => (SMALL_ROW, 0x1FE, 0x1FD), + SiliconFamily::Ccg6 => (SMALL_ROW, 0x1FE, 0x1FD), + SiliconFamily::Ccg8D => (LARGE_ROW, 0x3FE, 0x3FF), + SiliconFamily::Ccg8S => (LARGE_ROW, 0x3FE, 0x3FF), + SiliconFamily::Ccg8Cfp => (LARGE_ROW, 0x1FE, 0x1FF), }; let backup_fw = read_version(file_buffer, flash_row_size, f1_metadata_row, ccgx)?; let main_fw = read_version(file_buffer, flash_row_size, fw2_metadata_row, ccgx)?; @@ -212,14 +218,18 @@ mod tests { pd_bin_path.push("test_bins/dp-pd-3.0.17.100.bin"); let data = fs::read(pd_bin_path).unwrap(); - let ccg3_ver = read_versions(&data, SiliconId::Ccg3); - let ccg5_ver = read_versions(&data, SiliconId::Ccg5); - let ccg6_ver = read_versions(&data, SiliconId::Ccg6); - let ccg8_ver = read_versions(&data, SiliconId::Ccg8); + let ccg3_ver = read_versions(&data, SiliconFamily::Ccg3); + let ccg5_ver = read_versions(&data, SiliconFamily::Ccg5); + let ccg6_ver = read_versions(&data, SiliconFamily::Ccg6); + let ccg8d_ver = read_versions(&data, SiliconFamily::Ccg8D); + let ccg8s_ver = read_versions(&data, SiliconFamily::Ccg8S); + let ccg8cfp_ver = read_versions(&data, SiliconFamily::Ccg8Cfp); assert!(ccg3_ver.is_some()); assert!(ccg5_ver.is_none()); assert!(ccg6_ver.is_none()); - assert!(ccg8_ver.is_none()); + assert!(ccg8d_ver.is_none()); + assert!(ccg8s_ver.is_none()); + assert!(ccg8cfp_ver.is_none()); assert_eq!( ccg3_ver, @@ -274,14 +284,18 @@ mod tests { pd_bin_path.push("test_bins/tgl-pd-3.8.0.bin"); let data = fs::read(pd_bin_path).unwrap(); - let ccg3_ver = read_versions(&data, SiliconId::Ccg3); - let ccg5_ver = read_versions(&data, SiliconId::Ccg5); - let ccg6_ver = read_versions(&data, SiliconId::Ccg6); - let ccg8_ver = read_versions(&data, SiliconId::Ccg8); + let ccg3_ver = read_versions(&data, SiliconFamily::Ccg3); + let ccg5_ver = read_versions(&data, SiliconFamily::Ccg5); + let ccg6_ver = read_versions(&data, SiliconFamily::Ccg6); + let ccg8d_ver = read_versions(&data, SiliconFamily::Ccg8D); + let ccg8s_ver = read_versions(&data, SiliconFamily::Ccg8S); + let ccg8cfp_ver = read_versions(&data, SiliconFamily::Ccg8Cfp); assert!(ccg3_ver.is_none()); assert!(ccg5_ver.is_some()); assert!(ccg6_ver.is_none()); - assert!(ccg8_ver.is_none()); + assert!(ccg8d_ver.is_none()); + assert!(ccg8s_ver.is_none()); + assert!(ccg8cfp_ver.is_none()); assert_eq!( ccg5_ver, @@ -336,14 +350,18 @@ mod tests { pd_bin_path.push("test_bins/adl-pd-0.1.33.bin"); let data = fs::read(pd_bin_path).unwrap(); - let ccg3_ver = read_versions(&data, SiliconId::Ccg3); - let ccg5_ver = read_versions(&data, SiliconId::Ccg5); - let ccg6_ver = read_versions(&data, SiliconId::Ccg6); - let ccg8_ver = read_versions(&data, SiliconId::Ccg8); + let ccg3_ver = read_versions(&data, SiliconFamily::Ccg3); + let ccg5_ver = read_versions(&data, SiliconFamily::Ccg5); + let ccg6_ver = read_versions(&data, SiliconFamily::Ccg6); + let ccg8d_ver = read_versions(&data, SiliconFamily::Ccg8D); + let ccg8s_ver = read_versions(&data, SiliconFamily::Ccg8S); + let ccg8cfp_ver = read_versions(&data, SiliconFamily::Ccg8Cfp); assert!(ccg3_ver.is_none()); assert!(ccg5_ver.is_none()); assert!(ccg6_ver.is_some()); - assert!(ccg8_ver.is_none()); + assert!(ccg8d_ver.is_none()); + assert!(ccg8s_ver.is_none()); + assert!(ccg8cfp_ver.is_none()); assert_eq!( ccg6_ver, @@ -398,14 +416,18 @@ mod tests { pd_bin_path.push("test_bins/mtl-pd-0.0.A.bin"); let data = fs::read(pd_bin_path).unwrap(); - let ccg3_ver = read_versions(&data, SiliconId::Ccg3); - let ccg5_ver = read_versions(&data, SiliconId::Ccg5); - let ccg6_ver = read_versions(&data, SiliconId::Ccg6); - let ccg8_ver = read_versions(&data, SiliconId::Ccg8); + let ccg3_ver = read_versions(&data, SiliconFamily::Ccg3); + let ccg5_ver = read_versions(&data, SiliconFamily::Ccg5); + let ccg6_ver = read_versions(&data, SiliconFamily::Ccg6); + let ccg8d_ver = read_versions(&data, SiliconFamily::Ccg8D); + let ccg8s_ver = read_versions(&data, SiliconFamily::Ccg8S); + let ccg8cfp_ver = read_versions(&data, SiliconFamily::Ccg8Cfp); assert!(ccg3_ver.is_none()); assert!(ccg5_ver.is_none()); assert!(ccg6_ver.is_some()); - assert!(ccg8_ver.is_none()); + assert!(ccg8d_ver.is_none()); + assert!(ccg8s_ver.is_none()); + assert!(ccg8cfp_ver.is_none()); assert_eq!( ccg6_ver, @@ -460,14 +482,18 @@ mod tests { pd_bin_path.push("test_bins/dogwood-pd-0.0E.bin"); let data = fs::read(pd_bin_path).unwrap(); - let ccg3_ver = read_versions(&data, SiliconId::Ccg3); - let ccg5_ver = read_versions(&data, SiliconId::Ccg5); - let ccg6_ver = read_versions(&data, SiliconId::Ccg6); - let ccg8_ver = read_versions(&data, SiliconId::Ccg8); + let ccg3_ver = read_versions(&data, SiliconFamily::Ccg3); + let ccg5_ver = read_versions(&data, SiliconFamily::Ccg5); + let ccg6_ver = read_versions(&data, SiliconFamily::Ccg6); + let ccg8d_ver = read_versions(&data, SiliconFamily::Ccg8D); + let ccg8s_ver = read_versions(&data, SiliconFamily::Ccg8S); + let ccg8cfp_ver = read_versions(&data, SiliconFamily::Ccg8Cfp); assert!(ccg3_ver.is_none()); assert!(ccg5_ver.is_none()); assert!(ccg6_ver.is_some()); - assert!(ccg8_ver.is_none()); + assert!(ccg8d_ver.is_none()); + assert!(ccg8s_ver.is_none()); + assert!(ccg8cfp_ver.is_none()); assert_eq!( ccg6_ver, @@ -522,17 +548,21 @@ mod tests { pd_bin_path.push("test_bins/fl16-pd-0.0.03.bin"); let data = fs::read(pd_bin_path).unwrap(); - let ccg3_ver = read_versions(&data, SiliconId::Ccg3); - let ccg5_ver = read_versions(&data, SiliconId::Ccg5); - let ccg6_ver = read_versions(&data, SiliconId::Ccg6); - let ccg8_ver = read_versions(&data, SiliconId::Ccg8); + let ccg3_ver = read_versions(&data, SiliconFamily::Ccg3); + let ccg5_ver = read_versions(&data, SiliconFamily::Ccg5); + let ccg6_ver = read_versions(&data, SiliconFamily::Ccg6); + let ccg8d_ver = read_versions(&data, SiliconFamily::Ccg8D); + let ccg8s_ver = read_versions(&data, SiliconFamily::Ccg8S); + let ccg8cfp_ver = read_versions(&data, SiliconFamily::Ccg8Cfp); assert!(ccg3_ver.is_none()); assert!(ccg5_ver.is_none()); assert!(ccg6_ver.is_none()); - assert!(ccg8_ver.is_some()); + assert!(ccg8d_ver.is_some()); + assert!(ccg8s_ver.is_some()); + assert!(ccg8cfp_ver.is_none()); assert_eq!( - ccg8_ver, + ccg8d_ver, Some({ PdFirmwareFile { backup_fw: PdFirmware { @@ -584,17 +614,21 @@ mod tests { pd_bin_path.push("test_bins/fl16-ai300-pd-0.0.22.bin"); let data = fs::read(pd_bin_path).unwrap(); - let ccg3_ver = read_versions(&data, SiliconId::Ccg3); - let ccg5_ver = read_versions(&data, SiliconId::Ccg5); - let ccg6_ver = read_versions(&data, SiliconId::Ccg6); - let ccg8_ver = read_versions(&data, SiliconId::Ccg8); + let ccg3_ver = read_versions(&data, SiliconFamily::Ccg3); + let ccg5_ver = read_versions(&data, SiliconFamily::Ccg5); + let ccg6_ver = read_versions(&data, SiliconFamily::Ccg6); + let ccg8d_ver = read_versions(&data, SiliconFamily::Ccg8D); + let ccg8s_ver = read_versions(&data, SiliconFamily::Ccg8S); + let ccg8cfp_ver = read_versions(&data, SiliconFamily::Ccg8Cfp); assert!(ccg3_ver.is_none()); assert!(ccg5_ver.is_none()); assert!(ccg6_ver.is_none()); - assert!(ccg8_ver.is_some()); + assert!(ccg8d_ver.is_some()); + assert!(ccg8s_ver.is_some()); + assert!(ccg8cfp_ver.is_none()); assert_eq!( - ccg8_ver, + ccg8d_ver, Some({ PdFirmwareFile { backup_fw: PdFirmware { @@ -646,17 +680,21 @@ mod tests { pd_bin_path.push("test_bins/gn22-pd-0.0.22.bin"); let data = fs::read(pd_bin_path).unwrap(); - let ccg3_ver = read_versions(&data, SiliconId::Ccg3); - let ccg5_ver = read_versions(&data, SiliconId::Ccg5); - let ccg6_ver = read_versions(&data, SiliconId::Ccg6); - let ccg8_ver = read_versions(&data, SiliconId::Ccg8); + let ccg3_ver = read_versions(&data, SiliconFamily::Ccg3); + let ccg5_ver = read_versions(&data, SiliconFamily::Ccg5); + let ccg6_ver = read_versions(&data, SiliconFamily::Ccg6); + let ccg8d_ver = read_versions(&data, SiliconFamily::Ccg8D); + let ccg8s_ver = read_versions(&data, SiliconFamily::Ccg8S); + let ccg8cfp_ver = read_versions(&data, SiliconFamily::Ccg8Cfp); assert!(ccg3_ver.is_none()); assert!(ccg5_ver.is_none()); assert!(ccg6_ver.is_none()); - assert!(ccg8_ver.is_some()); + assert!(ccg8d_ver.is_some()); + assert!(ccg8s_ver.is_some()); + assert!(ccg8cfp_ver.is_none()); assert_eq!( - ccg8_ver, + ccg8s_ver, Some({ PdFirmwareFile { backup_fw: PdFirmware { @@ -701,4 +739,70 @@ mod tests { }) ); } + + #[test] + fn can_parse_ccg8_binary_cfp() { + let mut pd_bin_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + pd_bin_path.push("test_bins/sakura-pd-1.0.0A.bin"); + + let data = fs::read(pd_bin_path).unwrap(); + let ccg3_ver = read_versions(&data, SiliconFamily::Ccg3); + let ccg5_ver = read_versions(&data, SiliconFamily::Ccg5); + let ccg6_ver = read_versions(&data, SiliconFamily::Ccg6); + let ccg8d_ver = read_versions(&data, SiliconFamily::Ccg8D); + let ccg8s_ver = read_versions(&data, SiliconFamily::Ccg8S); + let ccg8cfp_ver = read_versions(&data, SiliconFamily::Ccg8Cfp); + assert!(ccg3_ver.is_none()); + assert!(ccg5_ver.is_none()); + assert!(ccg6_ver.is_none()); + assert!(ccg8d_ver.is_none()); + assert!(ccg8s_ver.is_none()); + assert!(ccg8cfp_ver.is_some()); + + assert_eq!( + ccg8cfp_ver, + Some({ + PdFirmwareFile { + backup_fw: PdFirmware { + silicon_id: 0x11CE, + silicon_family: 0x3E81, + base_version: BaseVersion { + major: 3, + minor: 8, + patch: 0x50, + build_number: 10, + }, + app_version: AppVersion { + application: Application::Notebook, + major: 1, + minor: 0, + circuit: 0x0A, + }, + start_row: 108, + size: 79092, + row_size: 0x100, + }, + main_fw: PdFirmware { + silicon_id: 0x11CE, + silicon_family: 0x3E81, + base_version: BaseVersion { + major: 3, + minor: 8, + patch: 0x50, + build_number: 10, + }, + app_version: AppVersion { + application: Application::Notebook, + major: 1, + minor: 0, + circuit: 0x0A, + }, + start_row: 7, + size: 24120, + row_size: 0x100, + }, + } + }) + ); + } } diff --git a/framework_lib/src/ccgx/hid.rs b/framework_lib/src/ccgx/hid.rs index d38739db..163e3b52 100644 --- a/framework_lib/src/ccgx/hid.rs +++ b/framework_lib/src/ccgx/hid.rs @@ -2,7 +2,7 @@ use hidapi::{DeviceInfo, HidApi, HidDevice, HidError}; use crate::ccgx; use crate::ccgx::device::{decode_flash_row_size, FwMode}; -use crate::ccgx::{BaseVersion, SiliconId}; +use crate::ccgx::{BaseVersion, SiliconFamily}; use crate::os_specific; use crate::util; @@ -287,12 +287,13 @@ pub fn find_devices(api: &HidApi, filter_devs: &[u16], sn: Option<&str>) -> Vec< } pub fn flash_firmware(fw_binary: &[u8]) { - let versions = if let Some(versions) = ccgx::binary::read_versions(fw_binary, SiliconId::Ccg3) { - versions - } else { - println!("Incompatible firmware. Need CCG3 firmware."); - return; - }; + let versions = + if let Some(versions) = ccgx::binary::read_versions(fw_binary, SiliconFamily::Ccg3) { + versions + } else { + println!("Incompatible firmware. Need CCG3 firmware."); + return; + }; // Not sure if there's a better way to check whether the firmware is for DP or HDMI card let dp_string = b"F\0r\0a\0m\0e\0w\0o\0r\0k\x006\x03D\0i\0s\0p\0l\0a\0y\0P\0o\0r\0t\0 \0E\0x\0p\0a\0n\0s\0i\0o\0n\0 \0C\0a\0r\0d\0"; diff --git a/framework_lib/src/ccgx/mod.rs b/framework_lib/src/ccgx/mod.rs index fb0c8e76..99b3ad8b 100644 --- a/framework_lib/src/ccgx/mod.rs +++ b/framework_lib/src/ccgx/mod.rs @@ -23,11 +23,6 @@ pub mod device; #[cfg(feature = "hidapi")] pub mod hid; -const FW1_METADATA_ROW: u32 = 0x1FE; -const FW1_METADATA_ROW_CCG8: u32 = 0x3FE; -const FW2_METADATA_ROW_CCG5: u32 = 0x1FF; -const FW2_METADATA_ROW_CCG6: u32 = 0x1FD; -const FW2_METADATA_ROW_CCG8: u32 = 0x3FF; const METADATA_OFFSET: usize = 0xC0; // TODO: Is this 0x40 on ADL? const CCG8_METADATA_OFFSET: usize = 0x80; const CCG3_METADATA_OFFSET: usize = 0x40; @@ -102,14 +97,21 @@ struct CyAcd2Metadata { _md_crc32: u32, } +/// Silicon family of a CCGX controller +/// +/// These are the values stored in the silicon family field of a firmware binary, +/// not the silicon ID that the HPI READ_SILICON_ID register reports. The two are +/// different: CCG8D and CCG8S share silicon ID 0x11C5 but differ in family. #[non_exhaustive] #[derive(Debug, PartialEq, FromPrimitive, Clone, Copy)] -pub enum SiliconId { +pub enum SiliconFamily { Ccg3 = 0x1D00, Ccg5 = 0x2100, Ccg6Adl = 0x3000, Ccg6 = 0x30A0, - Ccg8 = 0x3580, + Ccg8D = 0x3580, + Ccg8S = 0x3581, + Ccg8Cfp = 0x3E81, } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index 41477625..b920b22b 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -33,7 +33,7 @@ use crate::capsule_content::{ use crate::ccgx::device::{FwMode, PdController, PdPort}; #[cfg(feature = "hidapi")] use crate::ccgx::hid::{check_ccg_fw_version, find_devices, DP_CARD_PID, HDMI_CARD_PID}; -use crate::ccgx::{self, MainPdVersions, PdVersions, SiliconId::*}; +use crate::ccgx::{self, MainPdVersions, PdVersions, SiliconFamily::*}; use crate::chromium_ec; use crate::chromium_ec::commands::BoardIdType; use crate::chromium_ec::commands::DeckStateMode; @@ -2610,8 +2610,15 @@ fn analyze_ccgx_pd_fw(data: &[u8]) { println!("FW 2"); ccgx::binary::print_fw(&versions.main_fw); - } else if let Some(versions) = ccgx::binary::read_versions(data, Ccg8) { - println!("Detected CCG8 firmware"); + } else if let Some(versions) = ccgx::binary::read_versions(data, Ccg8D) { + println!("Detected CCG8D/CCG8S firmware"); + println!("FW 1"); + ccgx::binary::print_fw(&versions.backup_fw); + + println!("FW 2"); + ccgx::binary::print_fw(&versions.main_fw); + } else if let Some(versions) = ccgx::binary::read_versions(data, Ccg8Cfp) { + println!("Detected CCG8 CFP firmware"); println!("FW 1"); ccgx::binary::print_fw(&versions.backup_fw); diff --git a/framework_lib/test_bins/sakura-pd-1.0.0A.bin b/framework_lib/test_bins/sakura-pd-1.0.0A.bin new file mode 100644 index 00000000..4862ed39 Binary files /dev/null and b/framework_lib/test_bins/sakura-pd-1.0.0A.bin differ