tool: 0.1.3 - add backup ROM flashing
This commit is contained in:
parent
ff639a7836
commit
a8b38d6b37
2
tool/Cargo.lock
generated
2
tool/Cargo.lock
generated
@ -15,7 +15,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "system76_ectool"
|
name = "system76_ectool"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"redox_hwio 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"redox_hwio 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "system76_ectool"
|
name = "system76_ectool"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "System76 EC tool"
|
description = "System76 EC tool"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
@ -231,6 +231,10 @@ impl<'a, T: Timeout> EcSpi<'a, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: Timeout> Spi for EcSpi<'a, T> {
|
impl<'a, T: Timeout> Spi for EcSpi<'a, T> {
|
||||||
|
fn target(&self) -> SpiTarget {
|
||||||
|
self.target
|
||||||
|
}
|
||||||
|
|
||||||
/// Disable SPI chip, must be done before and after a transaction
|
/// Disable SPI chip, must be done before and after a transaction
|
||||||
unsafe fn reset(&mut self) -> Result<(), Error> {
|
unsafe fn reset(&mut self) -> Result<(), Error> {
|
||||||
let flags = self.flags(false, true);
|
let flags = self.flags(false, true);
|
||||||
|
@ -93,7 +93,6 @@ unsafe fn flash_read<S: Spi>(spi: &mut SpiRom<S, StdTimeout>, rom: &mut [u8], se
|
|||||||
|
|
||||||
unsafe fn flash_inner(ec: &mut Ec<StdTimeout>, firmware: &Firmware, target: SpiTarget, scratch: bool) -> Result<(), Error> {
|
unsafe fn flash_inner(ec: &mut Ec<StdTimeout>, firmware: &Firmware, target: SpiTarget, scratch: bool) -> Result<(), Error> {
|
||||||
let rom_size = 128 * 1024;
|
let rom_size = 128 * 1024;
|
||||||
let sector_size = 1024;
|
|
||||||
|
|
||||||
let mut new_rom = firmware.data.to_vec();
|
let mut new_rom = firmware.data.to_vec();
|
||||||
while new_rom.len() < rom_size {
|
while new_rom.len() < rom_size {
|
||||||
@ -105,6 +104,7 @@ unsafe fn flash_inner(ec: &mut Ec<StdTimeout>, firmware: &Firmware, target: SpiT
|
|||||||
&mut spi_bus,
|
&mut spi_bus,
|
||||||
StdTimeout::new(Duration::new(1, 0))
|
StdTimeout::new(Duration::new(1, 0))
|
||||||
);
|
);
|
||||||
|
let sector_size = spi.sector_size();
|
||||||
|
|
||||||
let mut rom = vec![0xFF; rom_size];
|
let mut rom = vec![0xFF; rom_size];
|
||||||
flash_read(&mut spi, &mut rom, sector_size)?;
|
flash_read(&mut spi, &mut rom, sector_size)?;
|
||||||
@ -168,8 +168,7 @@ unsafe fn flash_inner(ec: &mut Ec<StdTimeout>, firmware: &Firmware, target: SpiT
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn flash(path: &str) -> Result<(), Error> {
|
unsafe fn flash(path: &str, target: SpiTarget) -> Result<(), Error> {
|
||||||
let target = SpiTarget::Main;
|
|
||||||
let scratch = true;
|
let scratch = true;
|
||||||
|
|
||||||
//TODO: remove unwraps
|
//TODO: remove unwraps
|
||||||
@ -258,7 +257,7 @@ unsafe fn info() -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,6 +299,7 @@ unsafe fn fan_set(index: u8, duty: u8) -> Result<(), Error> {
|
|||||||
fn usage() {
|
fn usage() {
|
||||||
eprintln!(" console");
|
eprintln!(" console");
|
||||||
eprintln!(" flash [file]");
|
eprintln!(" flash [file]");
|
||||||
|
eprintln!(" flash_backup [file]");
|
||||||
eprintln!(" fan [index] <duty>");
|
eprintln!(" fan [index] <duty>");
|
||||||
eprintln!(" info");
|
eprintln!(" info");
|
||||||
eprintln!(" print [message]");
|
eprintln!(" print [message]");
|
||||||
@ -352,7 +352,20 @@ fn main() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"flash" => match args.next() {
|
"flash" => match args.next() {
|
||||||
Some(path) => match unsafe { flash(&path) } {
|
Some(path) => match unsafe { flash(&path, SpiTarget::Main) } {
|
||||||
|
Ok(()) => (),
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("failed to flash '{}': {:X?}", path, err);
|
||||||
|
process::exit(1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
eprintln!("no file provided");
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flash_backup" => match args.next() {
|
||||||
|
Some(path) => match unsafe { flash(&path, SpiTarget::Backup) } {
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("failed to flash '{}': {:X?}", path, err);
|
eprintln!("failed to flash '{}': {:X?}", path, err);
|
||||||
|
@ -4,11 +4,13 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub trait Spi {
|
pub trait Spi {
|
||||||
|
fn target(&self) -> SpiTarget;
|
||||||
unsafe fn reset(&mut self) -> Result<(), Error>;
|
unsafe fn reset(&mut self) -> Result<(), Error>;
|
||||||
unsafe fn read(&mut self, data: &mut [u8]) -> Result<usize, Error>;
|
unsafe fn read(&mut self, data: &mut [u8]) -> Result<usize, Error>;
|
||||||
unsafe fn write(&mut self, data: &[u8]) -> Result<usize, Error>;
|
unsafe fn write(&mut self, data: &[u8]) -> Result<usize, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub enum SpiTarget {
|
pub enum SpiTarget {
|
||||||
Main,
|
Main,
|
||||||
Backup,
|
Backup,
|
||||||
@ -27,6 +29,13 @@ impl<'a, S: Spi, T: Timeout> SpiRom<'a, S, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sector_size(&self) -> usize {
|
||||||
|
match self.spi.target() {
|
||||||
|
SpiTarget::Main => 1024,
|
||||||
|
SpiTarget::Backup => 4096,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub unsafe fn status(&mut self) -> Result<u8, Error> {
|
pub unsafe fn status(&mut self) -> Result<u8, Error> {
|
||||||
let mut status = [0];
|
let mut status = [0];
|
||||||
|
|
||||||
@ -67,30 +76,21 @@ impl<'a, S: Spi, T: Timeout> SpiRom<'a, S, T> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn erase_chip(&mut self) -> Result<(), Error> {
|
|
||||||
self.write_enable()?;
|
|
||||||
|
|
||||||
self.spi.reset()?;
|
|
||||||
self.spi.write(&[0x60])?;
|
|
||||||
|
|
||||||
// Poll status for busy unset
|
|
||||||
self.status_wait(1, 0)?;
|
|
||||||
|
|
||||||
self.write_disable()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn erase_sector(&mut self, address: u32) -> Result<(), Error> {
|
pub unsafe fn erase_sector(&mut self, address: u32) -> Result<(), Error> {
|
||||||
if (address & 0xFF00_0000) > 0 {
|
if (address & 0xFF00_0000) > 0 {
|
||||||
return Err(Error::Parameter);
|
return Err(Error::Parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let instruction = match self.spi.target() {
|
||||||
|
SpiTarget::Main => 0xD7,
|
||||||
|
SpiTarget::Backup => 0x20,
|
||||||
|
};
|
||||||
|
|
||||||
self.write_enable()?;
|
self.write_enable()?;
|
||||||
|
|
||||||
self.spi.reset()?;
|
self.spi.reset()?;
|
||||||
self.spi.write(&[
|
self.spi.write(&[
|
||||||
0xD7,
|
instruction,
|
||||||
(address >> 16) as u8,
|
(address >> 16) as u8,
|
||||||
(address >> 8) as u8,
|
(address >> 8) as u8,
|
||||||
address as u8,
|
address as u8,
|
||||||
@ -127,30 +127,55 @@ impl<'a, S: Spi, T: Timeout> SpiRom<'a, S, T> {
|
|||||||
|
|
||||||
self.write_enable()?;
|
self.write_enable()?;
|
||||||
|
|
||||||
for (i, word) in data.chunks(2).enumerate() {
|
match self.spi.target() {
|
||||||
let low = *word.get(0).unwrap_or(&0xFF);
|
SpiTarget::Main => for (i, word) in data.chunks(2).enumerate() {
|
||||||
let high = *word.get(1).unwrap_or(&0xFF);
|
let low = *word.get(0).unwrap_or(&0xFF);
|
||||||
|
let high = *word.get(1).unwrap_or(&0xFF);
|
||||||
|
|
||||||
self.spi.reset()?;
|
self.spi.reset()?;
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
self.spi.write(&[
|
self.spi.write(&[
|
||||||
0xAD,
|
0xAD,
|
||||||
(address >> 16) as u8,
|
(address >> 16) as u8,
|
||||||
(address >> 8) as u8,
|
(address >> 8) as u8,
|
||||||
address as u8,
|
address as u8,
|
||||||
low,
|
low,
|
||||||
high
|
high
|
||||||
])?;
|
])?;
|
||||||
} else {
|
} else {
|
||||||
self.spi.write(&[
|
self.spi.write(&[
|
||||||
0xAD,
|
0xAD,
|
||||||
low,
|
low,
|
||||||
high
|
high
|
||||||
])?;
|
])?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Poll status for busy unset
|
// Poll status for busy unset
|
||||||
self.status_wait(1, 0)?;
|
self.status_wait(1, 0)?;
|
||||||
|
},
|
||||||
|
SpiTarget::Backup => for (i, page) in data.chunks(256).enumerate() {
|
||||||
|
let page_address = address + i as u32 * 256;
|
||||||
|
if page_address % 256 != 0 {
|
||||||
|
return Err(Error::Parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if i > 0 {
|
||||||
|
// Write enable clears after each page is written
|
||||||
|
self.write_enable()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.spi.reset()?;
|
||||||
|
self.spi.write(&[
|
||||||
|
0xF2,
|
||||||
|
(page_address >> 16) as u8,
|
||||||
|
(page_address >> 8) as u8,
|
||||||
|
page_address as u8,
|
||||||
|
])?;
|
||||||
|
self.spi.write(&page)?;
|
||||||
|
|
||||||
|
// Poll status for busy unset
|
||||||
|
self.status_wait(1, 0)?;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
self.write_disable()?;
|
self.write_disable()?;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user