(ec: &CrosEc)
| 8 | use crate::os_specific; |
| 9 | |
| 10 | pub fn get_version(ec: &CrosEc) -> EcResult<Option<Vec<u8>>> { |
| 11 | let res = EcRequestGetGpuPcie {}.send_command(ec)?; |
| 12 | let vendor: Option<GpuVendor> = FromPrimitive::from_u8(res.gpu_vendor); |
| 13 | info!("GPU vendor: {:?}", vendor); |
| 14 | if vendor != Some(GpuVendor::NvidiaGn22) { |
| 15 | info!("No compatible retimer present (vendor mismatch)"); |
| 16 | return Ok(None); |
| 17 | }; |
| 18 | info!("NVIDIA GPU detected, checking retimer..."); |
| 19 | |
| 20 | // I2C Port on the EC |
| 21 | let i2c_port = 5; |
| 22 | // 8-bit I2C address of the retimer |
| 23 | // EC passthrough needs 7-bit, so shift one over before sending to EC |
| 24 | let i2c_addr = 0x10; |
| 25 | |
| 26 | // Check safe mode |
| 27 | info!( |
| 28 | "Reading retimer at I2C port {} addr 0x{:02X}", |
| 29 | i2c_port, |
| 30 | i2c_addr >> 1 |
| 31 | ); |
| 32 | let i2c_response = i2c_read(ec, i2c_port, i2c_addr >> 1, 0x00, 0x01)?; |
| 33 | info!( |
| 34 | "I2C response: status=0x{:02X}, data_len={}", |
| 35 | i2c_response.i2c_status, |
| 36 | i2c_response.data.len() |
| 37 | ); |
| 38 | if i2c_response.i2c_status == 0x01 { |
| 39 | // NAK |
| 40 | warn!("Unable to communicate with dGPU Retimer. Try to force it on by plugging a cable into the dGPU"); |
| 41 | } |
| 42 | let Some(&safe_mode) = i2c_response.data.first() else { |
| 43 | info!("Failed to read retimer safe mode status (empty response)"); |
| 44 | return Ok(None); |
| 45 | }; |
| 46 | info!("Retimer safe mode status: {}", safe_mode); |
| 47 | if safe_mode == 0 { |
| 48 | // Safe mode not enabled, enable it |
| 49 | i2c_write(ec, i2c_port, i2c_addr >> 1, 0x00, &[0x01])?; |
| 50 | } |
| 51 | |
| 52 | // Wake up from low power mode |
| 53 | for _ in 0..3 { |
| 54 | let i2c_response = i2c_read(ec, i2c_port, (i2c_addr + 2) >> 1, 0x70, 0x01)?; |
| 55 | if i2c_response.data.first() == Some(&0) { |
| 56 | continue; |
| 57 | } |
| 58 | i2c_write(ec, i2c_port, (i2c_addr + 2) >> 1, 0x70, &[0x00])?; |
| 59 | os_specific::sleep(50_000); |
| 60 | } |
| 61 | |
| 62 | // Read version |
| 63 | let i2c_response = i2c_read(ec, i2c_port, (i2c_addr + 18) >> 1, 0x01, 0x04)?; |
| 64 | |
| 65 | Ok(Some(i2c_response.data)) |
| 66 | } |
no test coverage detected