Skip to content

Commit

Permalink
Decode additional Frameowork16 and AMD related memmap items
Browse files Browse the repository at this point in the history
TODO:

- [ ] Handle it better than just increasing EC_MEMMAP_SIZE*2
- [ ] Figure out all items and whether they apply to Lotus and also Azalea
- [ ] Figure out Lotus and Azalea fan names

Example:

```
cargo build && sudo ./target/debug/framework_tool --driver portio --expansion-bay
AMD
  Power Slider:     DC, Battery Saver (0b0001000)
  STT Table:        7
  CBP:              true ([0, 0])
  DTT Temp:         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Expansion Bay
  Serial Struct:    [0, 0, 0, 0]
  PD Version:       [0, 0, 0, 0]
  GPU CTRL:         0x8
    MUX Status:     GPU
    Board Status:   Present
    PCIe Config:    8x1
  Display On:       false
  GPU Type:         AMD R23M (2)
```

Reference data:

```
Fan Module
  Serial Struct:    [0, 0, 0, 0]
  Batt Manuf        2023-22-7
  PD Version:       [0, 0, 0, 0]
  GPU CTRL:         0x0
  Power Slider:     AC, Best Power Efficiency (0b1000000)
  Display On:       false
  STT Table:        13
  CBP:              true ([0, 0])
  GPU Type:         Initializing (0)
  DTT Temp:         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

dGPU Module
  Serial Struct:    [0, 0, 0, 0]
  Batt Manuf        2023-7-22
  PD Version:       [0, 0, 0, 0]
  GPU CTRL:         0x8
  Power Slider:     DC, Battery Saver (0b0001000)
  Display On:       false
  STT Table:        7
  CBP:              true ([0, 0])
  GPU Type:         AMD R23M (2)
  DTT Temp:         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
```

Signed-off-by: Daniel Schaefer <dhs@frame.work>
  • Loading branch information
JohnAZoidberg committed May 26, 2024
1 parent 70595f7 commit a889601
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 8 deletions.
2 changes: 1 addition & 1 deletion framework_lib/src/chromium_ec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -871,7 +871,7 @@ impl CrosEcDriver for CrosEc {
}

debug!("read_memory(offset={:#X}, size={:#X})", offset, length);
if offset + length > EC_MEMMAP_SIZE {
if offset + length > (EC_MEMMAP_SIZE * 2) {
return None;
}

Expand Down
6 changes: 5 additions & 1 deletion framework_lib/src/chromium_ec/portio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,11 @@ fn init() -> bool {
let res = ioperm(EC_LPC_ADDR_HOST_DATA as u64, 1, 1);
assert_eq!(res, 0);

let res = ioperm(NPC_MEMMAP_OFFSET as u64, super::EC_MEMMAP_SIZE as u64, 1);
let res = ioperm(
NPC_MEMMAP_OFFSET as u64,
(super::EC_MEMMAP_SIZE * 2) as u64,
1,
);
assert_eq!(res, 0);
}
}
Expand Down
5 changes: 5 additions & 0 deletions framework_lib/src/commandline/clap_std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ struct ClapCli {
#[arg(long)]
thermal: bool,

/// Print expansion bay information
#[arg(long)]
expansion_bay: bool,

/// Show information about USB-C PD ports
#[arg(long)]
pdports: bool,
Expand Down Expand Up @@ -196,6 +200,7 @@ pub fn parse(args: &[String]) -> Cli {
esrt: args.esrt,
power: args.power,
thermal: args.thermal,
expansion_bay: args.expansion_bay,
pdports: args.pdports,
pd_info: args.pd_info,
dp_hdmi_info: args.dp_hdmi_info,
Expand Down
6 changes: 5 additions & 1 deletion framework_lib/src/commandline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ pub struct Cli {
pub esrt: bool,
pub power: bool,
pub thermal: bool,
pub expansion_bay: bool,
pub pdports: bool,
pub privacy: bool,
pub pd_info: bool,
Expand Down Expand Up @@ -606,6 +607,8 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
power::get_and_print_power_info(&ec);
} else if args.thermal {
power::print_thermal(&ec);
} else if args.expansion_bay {
power::print_expansion_bay_info(&ec);
} else if args.pdports {
power::get_and_print_pd_info(&ec);
} else if args.info {
Expand Down Expand Up @@ -784,7 +787,8 @@ Options:
--version Show tool version information (Add -vv for more detailed information)
--esrt Display the UEFI ESRT table
--power Show current power status (battery and AC)
--thermal Show current power status (battery and AC)
--thermal Print thermal information (Temperatures and Fan speed)
--expansion-bay Print expansion bay information
--pdports Show information about USB-C PD ports
--info Show info from SMBIOS (Only on UEFI)
--pd-info Show details about the PD controllers
Expand Down
4 changes: 4 additions & 0 deletions framework_lib/src/commandline/uefi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pub fn parse(args: &[String]) -> Cli {
esrt: false,
power: false,
thermal: false,
expansion_bay: false,
pdports: false,
pd_info: false,
dp_hdmi_info: false,
Expand Down Expand Up @@ -131,6 +132,9 @@ pub fn parse(args: &[String]) -> Cli {
} else if arg == "--thermal" {
cli.thermal = true;
found_an_option = true;
} else if arg == "--expansion-bay" {
cli.expansion_bay = true;
found_an_option = true;
} else if arg == "--pdports" {
cli.pdports = true;
found_an_option = true;
Expand Down
126 changes: 121 additions & 5 deletions framework_lib/src/power.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,115 @@ fn in_c(t: u8) -> u8 {
}
}

pub fn print_expansion_bay_info(ec: &CrosEc) {
let platform = smbios::get_platform();
if !matches!(
platform,
Some(Platform::Framework13Amd) | Some(Platform::Framework16)
) {
println!("Only applicable to Framework 16 and Framework AMD systems");
return;
}

println!("AMD");
// TODO: This is also on Azalea?
let power_slider = ec.read_memory(0x151, 0x02).unwrap()[0];
let dc_ac = if power_slider <= 0b1000 { "DC" } else { "AC" };
let mode = match power_slider {
0b0000_0001 | 0b0001_0000 => "Best Performance",
0b0000_0010 | 0b0010_0000 => "Balanced",
0b0000_0100 | 0b0100_0000 => "Best Power Efficiency",
0b0000_1000 => "Battery Saver",
_ => "Unknown Mode",
};
println!(
" Power Slider: {}, {} ({:#09b})",
dc_ac, mode, power_slider
);

// TODO: This is also on Azalea?
let stt_table = ec.read_memory(0x154, 0x01).unwrap()[0];
println!(" STT Table: {:?}", stt_table);

// TODO: What's this? Always [0x00, 0x00] so far
// TODO: This is also on Azalea?
// Core Performance Boost
let cbp = ec.read_memory(0x155, 0x02).unwrap();
println!(" CBP: {} ({:?})", cbp == [0x00, 0x00], cbp);

// TODO: When is this changed?
// TODO: This is also on Azalea?
let dtt_temp = ec.read_memory(0x160, 0x0F).unwrap();
println!(" DTT Temp: {:?}", dtt_temp);

if !matches!(platform, Some(Platform::Framework16)) {
return;
}

println!("Expansion Bay");

// TODO: This is the serial struct in the Expansion Bay?
let serial_struct = ec.read_memory(0x140, 0x04).unwrap();
println!(" Serial Struct: {:?}", serial_struct);

// TODO: Why is this in the same namespace?
// let batt_manuf_day = ec.read_memory(0x144, 0x01).unwrap()[0];
// let batt_manuf_month = ec.read_memory(0x145, 0x01).unwrap()[0];
// let batt_manuf_year = ec.read_memory(0x146, 0x02).unwrap();
// let batt_manuf_year = u16::from_le_bytes([batt_manuf_year[0], batt_manuf_year[1]]);
// println!(" Batt Manuf {:?}-{:?}-{:?}", batt_manuf_year, batt_manuf_month, batt_manuf_day);

// TODO: This is the PD in the dGPU module?
let pd_ver = ec.read_memory(0x14C, 0x04).unwrap();
println!(" PD Version: {:?}", pd_ver);

let gpu_ctrl = ec.read_memory(0x150, 0x01).unwrap()[0];
// Unused, this is for the BIOS to set
let _set_mux_status = match gpu_ctrl & 0b11 {
0b00 => "EC Received and Clear",
0b01 => "BIOS Set APU",
0b10 => "BIOS Set GPU",
_ => "Unknown",
};
let mux_status = if (gpu_ctrl & 0b100) > 0 { "APU" } else { "GPU" };
let board_status = if (gpu_ctrl & 0b1000) > 0 {
"Present"
} else {
"Absent"
};
// Unused, set by BIOS: (gpu_ctrl & 0b10000)
let pcie_config = match gpu_ctrl & 0b01100000 {
0b00 => "8x1",
0b01 => "4x1",
0b10 => "4x2",
0b11 => "Disabled",
_ => "Unknown",
};
println!(" GPU CTRL: {:#x}", gpu_ctrl);
println!(" MUX Status: {}", mux_status);
println!(" Board Status: {}", board_status);
println!(" PCIe Config: {}", pcie_config);

// TODO: This seems like it's not correctly working? It's always false
let display_on = ec.read_memory(0x153, 0x01).unwrap()[0];
println!(" Display On: {:?}", display_on == 0x01);

let gpu_type = ec.read_memory(0x157, 0x01).unwrap()[0];
let gpu_name = match gpu_type {
0x00 => "Initializing",
0x01 => "Fan Only",
0x02 => "AMD R23M",
0x03 => "SSD",
0x04 => "PCIe Accessory",
_ => "Unknown",
};
println!(" GPU Type: {} ({:?})", gpu_name, gpu_type);

}

pub fn print_thermal(ec: &CrosEc) {
let temps = ec.read_memory(EC_MEMMAP_TEMP_SENSOR, 0x0F).unwrap();
println!("Temps: {:?}", temps);
let fans = ec.read_memory(EC_MEMMAP_FAN, 0x08).unwrap();

let platform = smbios::get_platform();
Expand All @@ -184,10 +291,13 @@ pub fn print_thermal(ec: &CrosEc) {
println!(" F57397_VCCGT: {:>4} C", in_c(temps[5]));
}
Some(Platform::Framework13Amd | Platform::Framework16) => {
println!(" F75303_Local: {:>4} C", in_c(temps[0]));
println!(" F75303_CPU: {:>4} C", in_c(temps[1]));
println!(" F75303_DDR: {:>4} C", in_c(temps[2]));
println!(" APU: {:>4} C", in_c(temps[3]));
// TODO: Check names. EC names are like this. But EC namespace spreadsheet is different
println!(" Ambient: {:>4} C", in_c(temps[0]));
println!(" Charger: {:>4} C", in_c(temps[1]));
println!(" APU: {:>4} C", in_c(temps[2]));
println!(" CPU: {:>4} C", in_c(temps[3]));
// TODO: Only display if dGPU is present
// TODO: Sometimes these show 0 even if the GPU is present. Why?
if matches!(platform, Some(Platform::Framework16)) {
println!(" dGPU VR: {:>4} C", in_c(temps[4]));
println!(" dGPU VRAM: {:>4} C", in_c(temps[5]));
Expand All @@ -208,7 +318,13 @@ pub fn print_thermal(ec: &CrosEc) {
}

let fan0 = u16::from_le_bytes([fans[0], fans[1]]);
println!(" Fan Speed: {:>4} RPM", fan0);
let fan1 = u16::from_le_bytes([fans[2], fans[3]]);
if matches!(platform, Some(Platform::Framework16)) {
println!(" Fan L Speed: {:>4} RPM", fan0);
println!(" Fan R Speed: {:>4} RPM", fan1);
} else {
println!(" Fan Speed: {:>4} RPM", fan0);
}
}

// TODO: Use Result
Expand Down

0 comments on commit a889601

Please sign in to comment.