Bitbang I2C
This commit is contained in:
70
usb4/Cargo.lock
generated
70
usb4/Cargo.lock
generated
@@ -1,29 +1,5 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "1.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "byteorder"
|
|
||||||
version = "1.3.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.0.65"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "0.1.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "coreboot-collector"
|
name = "coreboot-collector"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -47,37 +23,12 @@ dependencies = [
|
|||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "i2cdev"
|
|
||||||
version = "0.4.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3c0eb3d9b6b02dc2508ee23439170004e44344bab9d53a490eb1f64c885b5003"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"byteorder",
|
|
||||||
"libc",
|
|
||||||
"nix",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.80"
|
version = "0.2.80"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
|
checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nix"
|
|
||||||
version = "0.14.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"cc",
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"void",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "numtoa"
|
name = "numtoa"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
@@ -169,22 +120,15 @@ version = "0.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "usb4"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"coreboot-collector",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.2"
|
version = "0.9.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "void"
|
|
||||||
version = "1.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "you-ass-bee-see"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"coreboot-collector",
|
|
||||||
"i2cdev",
|
|
||||||
]
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "you-ass-bee-see"
|
name = "usb4"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Jeremy Soller <jeremy@system76.com>"]
|
authors = ["Jeremy Soller <jeremy@system76.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
@@ -8,4 +8,3 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
coreboot-collector = { path = "../tools/coreboot-collector" }
|
coreboot-collector = { path = "../tools/coreboot-collector" }
|
||||||
i2cdev = "0.4.4"
|
|
||||||
|
391
usb4/src/main.rs
391
usb4/src/main.rs
@@ -1,7 +1,11 @@
|
|||||||
use coreboot_collector::sideband::Sideband;
|
use coreboot_collector::sideband::Sideband;
|
||||||
use i2cdev::core::I2CDevice;
|
use std::{
|
||||||
use i2cdev::linux::LinuxI2CDevice;
|
fs,
|
||||||
use std::{fs, thread, time};
|
rc::Rc,
|
||||||
|
process,
|
||||||
|
thread,
|
||||||
|
time
|
||||||
|
};
|
||||||
|
|
||||||
const IECS_CMD: u8 = 8;
|
const IECS_CMD: u8 = 8;
|
||||||
const IECS_DATA: u8 = 9;
|
const IECS_DATA: u8 = 9;
|
||||||
@@ -13,71 +17,319 @@ const CMD_BLKW: u32 = 0x574b4c42;
|
|||||||
const CMD_BOPS: u32 = 0x53504f42;
|
const CMD_BOPS: u32 = 0x53504f42;
|
||||||
const CMD_PCYC: u32 = 0x43594350;
|
const CMD_PCYC: u32 = 0x43594350;
|
||||||
|
|
||||||
const GPIO_FORCE_POWER: (u8, u8) = (0x6E, 0x82); // GPP_A23
|
|
||||||
|
|
||||||
fn read<I: I2CDevice>(dev: &mut I, reg: u8) -> Result<u32, I::Error> {
|
#[repr(u64)]
|
||||||
let bytes = dev.smbus_read_block_data(reg)?;
|
pub enum GpioPadMode {
|
||||||
//TODO: return error on bytes.len() != 4
|
Gpio = 0 << 10,
|
||||||
|
Nf1 = 1 << 10,
|
||||||
|
Nf2 = 2 << 10,
|
||||||
|
Nf3 = 3 << 10,
|
||||||
|
Nf4 = 4 << 10,
|
||||||
|
Nf5 = 5 << 10,
|
||||||
|
Nf6 = 6 << 10,
|
||||||
|
Nf7 = 7 << 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Gpio {
|
||||||
|
//TODO: this should probably be locked
|
||||||
|
sideband: Rc<Sideband>,
|
||||||
|
port: u8,
|
||||||
|
pad: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Gpio {
|
||||||
|
const PAD_MODE: u64 = 0b111 << 10;
|
||||||
|
const RX_DIS: u64 = 1 << 9;
|
||||||
|
const TX_DIS: u64 = 1 << 8;
|
||||||
|
const RX: u64 = 1 << 1;
|
||||||
|
const TX: u64 = 1 << 0;
|
||||||
|
|
||||||
|
pub fn new(sideband: Rc<Sideband>, port: u8, pad: u8) -> Self {
|
||||||
|
Self { sideband, port, pad }
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn get_config(&self) -> u64 {
|
||||||
|
self.sideband.gpio(self.port, self.pad)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn set_config(&mut self, config: u64) {
|
||||||
|
self.sideband.set_gpio(self.port, self.pad, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn get_mask(&self, mask: u64) -> bool {
|
||||||
|
self.get_config() & mask == mask
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn set_mask(&mut self, mask: u64, value: bool) {
|
||||||
|
let mut config = self.get_config();
|
||||||
|
if value {
|
||||||
|
config |= mask;
|
||||||
|
} else {
|
||||||
|
config &= !mask;
|
||||||
|
}
|
||||||
|
self.set_config(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn set_pad_mode(&mut self, mode: GpioPadMode) {
|
||||||
|
let mut config = self.get_config();
|
||||||
|
config &= !Self::PAD_MODE;
|
||||||
|
config |= mode as u64;
|
||||||
|
self.set_config(config);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn enable_rx(&mut self, value: bool) {
|
||||||
|
self.set_mask(Self::RX_DIS, !value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn enable_tx(&mut self, value: bool) {
|
||||||
|
self.set_mask(Self::TX_DIS, !value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn get_rx(&self) -> bool {
|
||||||
|
self.get_mask(Self::RX)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn get_tx(&self) -> bool {
|
||||||
|
self.get_mask(Self::TX)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn set_tx(&mut self, value: bool) {
|
||||||
|
self.set_mask(Self::TX, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct I2CBitbang {
|
||||||
|
scl: Gpio,
|
||||||
|
scl_config: u64,
|
||||||
|
sda: Gpio,
|
||||||
|
sda_config: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl I2CBitbang {
|
||||||
|
pub unsafe fn new(mut scl: Gpio, mut sda: Gpio) -> Self {
|
||||||
|
//TODO: will this transmit something invalid?
|
||||||
|
|
||||||
|
let scl_config = scl.get_config();
|
||||||
|
scl.enable_rx(true);
|
||||||
|
scl.enable_tx(false);
|
||||||
|
scl.set_tx(false);
|
||||||
|
scl.set_pad_mode(GpioPadMode::Gpio);
|
||||||
|
|
||||||
|
let sda_config = sda.get_config();
|
||||||
|
sda.enable_rx(true);
|
||||||
|
sda.enable_tx(false);
|
||||||
|
sda.set_tx(false);
|
||||||
|
sda.set_pad_mode(GpioPadMode::Gpio);
|
||||||
|
|
||||||
|
Self { scl, scl_config, sda, sda_config, }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delay half half of period
|
||||||
|
fn delay(&self) {
|
||||||
|
// Hard coded to 5 us, which is half of the period 10 us for a frequency of 100 KHz
|
||||||
|
thread::sleep(time::Duration::from_micros(5));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pull SCL low
|
||||||
|
unsafe fn clr_scl(&mut self) {
|
||||||
|
self.scl.enable_tx(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release SCL, bus pulls it high
|
||||||
|
unsafe fn set_scl(&mut self) {
|
||||||
|
self.scl.enable_tx(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pull SDA low
|
||||||
|
unsafe fn clr_sda(&mut self) {
|
||||||
|
self.sda.enable_tx(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release SDA, bus pulls it high
|
||||||
|
unsafe fn set_sda(&mut self) {
|
||||||
|
self.sda.enable_tx(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn start(&mut self) {
|
||||||
|
self.set_scl();
|
||||||
|
self.set_sda();
|
||||||
|
self.delay();
|
||||||
|
self.clr_sda();
|
||||||
|
self.delay();
|
||||||
|
self.clr_scl();
|
||||||
|
self.delay();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn stop(&mut self) {
|
||||||
|
self.clr_sda();
|
||||||
|
self.delay();
|
||||||
|
self.set_scl();
|
||||||
|
self.delay();
|
||||||
|
self.set_sda();
|
||||||
|
self.delay();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn write_bit(&mut self, bit: bool) {
|
||||||
|
if bit {
|
||||||
|
self.set_sda();
|
||||||
|
} else {
|
||||||
|
self.clr_sda();
|
||||||
|
}
|
||||||
|
self.delay();
|
||||||
|
self.set_scl();
|
||||||
|
self.delay();
|
||||||
|
self.clr_scl();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn read_bit(&mut self) -> bool {
|
||||||
|
self.set_sda();
|
||||||
|
self.delay();
|
||||||
|
self.set_scl();
|
||||||
|
self.delay();
|
||||||
|
let bit = self.sda.get_rx();
|
||||||
|
self.clr_scl();
|
||||||
|
bit
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn write_byte(&mut self, byte: u8, start: bool) -> bool {
|
||||||
|
if start {
|
||||||
|
self.start();
|
||||||
|
}
|
||||||
|
for i in (0..8).rev() {
|
||||||
|
self.write_bit(byte & (1 << i) != 0);
|
||||||
|
}
|
||||||
|
self.read_bit()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn read_byte(&mut self, ack: bool) -> u8 {
|
||||||
|
let mut byte = 0;
|
||||||
|
for i in (0..8).rev() {
|
||||||
|
if self.read_bit() {
|
||||||
|
byte |= 1 << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.write_bit(!ack);
|
||||||
|
byte
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn smbus_block_write(&mut self, address: u8, command: u8, bytes: &[u8]) -> usize {
|
||||||
|
// Only 32 bytes can be processed at a time
|
||||||
|
if bytes.len() > 32 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
if self.write_byte(address << 1, true) {
|
||||||
|
if self.write_byte(command, false) {
|
||||||
|
if self.write_byte(bytes.len() as u8, false) {
|
||||||
|
for byte in bytes.iter() {
|
||||||
|
if self.write_byte(*byte, false) {
|
||||||
|
count += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.stop();
|
||||||
|
count
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn smbus_block_read(&mut self, address: u8, command: u8) -> Vec<u8> {
|
||||||
|
//TODO: use static buffer?
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
if self.write_byte(address << 1, true) {
|
||||||
|
if self.write_byte(command, false) {
|
||||||
|
if self.write_byte(address << 1 | 1, true) {
|
||||||
|
let count = self.read_byte(true);
|
||||||
|
for _i in 0..count {
|
||||||
|
bytes.push(self.read_byte(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.stop();
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for I2CBitbang {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
//TODO: will this transmit something invalid?
|
||||||
|
self.scl.set_config(self.scl_config);
|
||||||
|
self.sda.set_config(self.sda_config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Retimer {
|
||||||
|
i2c: I2CBitbang,
|
||||||
|
address: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Retimer {
|
||||||
|
pub fn new(i2c: I2CBitbang, address: u8) -> Self {
|
||||||
|
Self { i2c, address }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn read(&mut self, reg: u8) -> Result<u32, String> {
|
||||||
|
let bytes = self.i2c.smbus_block_read(self.address, reg);
|
||||||
|
if bytes.len() == 4 {
|
||||||
Ok(
|
Ok(
|
||||||
bytes[0] as u32 |
|
bytes[0] as u32 |
|
||||||
(bytes[1] as u32) << 8 |
|
(bytes[1] as u32) << 8 |
|
||||||
(bytes[2] as u32) << 16 |
|
(bytes[2] as u32) << 16 |
|
||||||
(bytes[3] as u32) << 24
|
(bytes[3] as u32) << 24
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
Err(format!("Retimer::read: read {} bytes instead of 4", bytes.len()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write<I: I2CDevice>(dev: &mut I, reg: u8, data: u32) -> Result<(), I::Error> {
|
pub unsafe fn write(&mut self, reg: u8, data: u32) -> Result<(), String> {
|
||||||
let bytes = [
|
let bytes = [
|
||||||
data as u8,
|
data as u8,
|
||||||
(data >> 8) as u8,
|
(data >> 8) as u8,
|
||||||
(data >> 16) as u8,
|
(data >> 16) as u8,
|
||||||
(data >> 24) as u8,
|
(data >> 24) as u8,
|
||||||
];
|
];
|
||||||
dev.smbus_write_block_data(reg, &bytes)
|
let count = self.i2c.smbus_block_write(self.address, reg, &bytes);
|
||||||
|
if count == 4 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(format!("Retimer::write: wrote {} bytes instead of 4", count))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn command<I: I2CDevice>(dev: &mut I, cmd: u32) -> Result<u32, I::Error> {
|
pub unsafe fn command(&mut self, cmd: u32) -> Result<(), String> {
|
||||||
write(dev, IECS_CMD, cmd)?;
|
self.write(IECS_CMD, cmd)?;
|
||||||
loop {
|
//TODO: is this the right number of retries?
|
||||||
let status = read(dev, IECS_CMD)?;
|
let retries = 1000;
|
||||||
|
for _i in 0..retries {
|
||||||
|
let status = self.read(IECS_CMD)?;
|
||||||
if status != cmd {
|
if status != cmd {
|
||||||
//TODO: perform error checking here
|
if status == 0 {
|
||||||
return Ok(status);
|
return Ok(());
|
||||||
|
} else {
|
||||||
|
return Err(format!("Retimer::command: read 0x{:X} instead of 0", status));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Err(format!("Retimer::command: timed out after {} retries", retries))
|
||||||
fn main() {
|
}
|
||||||
//TODO: check model
|
|
||||||
|
|
||||||
let sideband = unsafe { Sideband::new(0xFD00_0000).unwrap() };
|
|
||||||
|
|
||||||
// Set FORCE_POWER high
|
|
||||||
unsafe {
|
|
||||||
let (port, pad) = GPIO_FORCE_POWER;
|
|
||||||
let mut value = sideband.gpio(port, pad);
|
|
||||||
value |= 1;
|
|
||||||
sideband.set_gpio(port, pad, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sleep 40ms
|
unsafe fn flash_retimer(retimer: &mut Retimer) -> Result<(), String> {
|
||||||
thread::sleep(time::Duration::from_millis(40));
|
eprintln!("Vendor: {:X}", retimer.read(0)?);
|
||||||
|
eprintln!("Device: {:X}", retimer.read(1)?);
|
||||||
let mut dev = LinuxI2CDevice::new("/dev/i2c-11", 0x40).unwrap();
|
|
||||||
eprintln!("Vendor: {:X}", read(&mut dev, 0).unwrap());
|
|
||||||
eprintln!("Device: {:X}", read(&mut dev, 1).unwrap());
|
|
||||||
|
|
||||||
let image = fs::read("../models/galp5/usb4-retimer.rom").unwrap();
|
|
||||||
|
|
||||||
for i in 2..=32 {
|
|
||||||
println!("{}: {:X}", i, read(&mut dev, i).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
write(&mut dev, IECS_DATA, 0).unwrap();
|
|
||||||
println!("IECS_DATA: {:X}", read(&mut dev, IECS_DATA).unwrap());
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
let image = fs::read("../models/galp5/usb4-retimer.rom").unwrap();
|
||||||
|
|
||||||
eprintln!("Set offset to 0");
|
eprintln!("Set offset to 0");
|
||||||
write(&mut dev, IECS_DATA, 0).unwrap();
|
write(&mut dev, IECS_DATA, 0).unwrap();
|
||||||
let status = command(&mut dev, CMD_BOPS).unwrap();
|
let status = command(&mut dev, CMD_BOPS).unwrap();
|
||||||
@@ -125,11 +377,56 @@ fn main() {
|
|||||||
eprintln!("Successfully flashed retimer");
|
eprintln!("Successfully flashed retimer");
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Set FORCE_POWER low
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn retimer_access(i2c: I2CBitbang) -> i32 {
|
||||||
|
let mut retimer = Retimer::new(i2c, 0x40);
|
||||||
|
match flash_retimer(&mut retimer) {
|
||||||
|
Ok(()) => 0,
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Failed to flash retimer: {}", err);
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn i2c_access(sideband: Rc<Sideband>) -> i32 {
|
||||||
|
let scl = Gpio::new(sideband.clone(), 0x6A, 0x06); // GPP_C3
|
||||||
|
let sda = Gpio::new(sideband.clone(), 0x6A, 0x08); // GPP_C4
|
||||||
|
let i2c = I2CBitbang::new(scl, sda);
|
||||||
|
retimer_access(i2c)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn force_power(sideband: Rc<Sideband>) -> i32 {
|
||||||
|
let mut force_power = Gpio::new(sideband.clone(), 0x6E, 0x82); // GPP_A23
|
||||||
|
|
||||||
|
println!("Set FORCE_POWER high");
|
||||||
|
force_power.set_tx(true);
|
||||||
|
|
||||||
|
println!("Sleep 40 ms");
|
||||||
|
thread::sleep(time::Duration::from_millis(40));
|
||||||
|
|
||||||
|
let exit_status = i2c_access(sideband);
|
||||||
|
|
||||||
|
eprintln!("Set FORCE_POWER low");
|
||||||
|
force_power.set_tx(false);
|
||||||
|
|
||||||
|
exit_status
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
//TODO: check model
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let (port, pad) = GPIO_FORCE_POWER;
|
let sideband = match Sideband::new(0xFD00_0000) {
|
||||||
let mut value = sideband.gpio(port, pad);
|
Ok(ok) => Rc::new(ok),
|
||||||
value &= !1;
|
Err(err) => {
|
||||||
sideband.set_gpio(port, pad, value);
|
eprintln!("Failed to access sideband: {}", err);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
process::exit(force_power(sideband));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user