Faster flashing with SMFI (#32)

* WIP: support for new flashing API

* Add SPI flashing support to tool

* Add timeouts when flashing with ectool

* Test SPI reading

* Use chunks for SPI commands

* Sanity test of flash size

* Read rom in sectors

* Relocate memmap region, remove PMC3

* Use ectool to flash

* Remove debugging of spi command

* Fix flashing over smfi
This commit is contained in:
Jeremy Soller
2020-02-26 09:04:40 -07:00
committed by GitHub
parent a7e47d8d58
commit 657437e1ce
34 changed files with 826 additions and 791 deletions

165
tool/src/spi.rs Normal file
View File

@@ -0,0 +1,165 @@
use crate::{
Error,
Timeout,
};
pub trait Spi {
unsafe fn reset(&mut self) -> Result<(), Error>;
unsafe fn read(&mut self, data: &mut [u8]) -> Result<usize, Error>;
unsafe fn write(&mut self, data: &[u8]) -> Result<usize, Error>;
}
pub struct SpiRom<'a, S: Spi, T: Timeout> {
spi: &'a mut S,
timeout: T,
}
impl<'a, S: Spi, T: Timeout> SpiRom<'a, S, T> {
pub fn new(spi: &'a mut S, timeout: T) -> Self {
Self {
spi,
timeout,
}
}
pub unsafe fn status(&mut self) -> Result<u8, Error> {
let mut status = [0];
self.spi.reset()?;
self.spi.write(&[0x05])?;
self.spi.read(&mut status)?;
Ok(status[0])
}
pub unsafe fn status_wait(&mut self, mask: u8, value: u8) -> Result<(), Error> {
self.timeout.reset();
while self.timeout.running() {
if self.status()? & mask == value {
return Ok(());
}
}
Err(Error::Timeout)
}
pub unsafe fn write_disable(&mut self) -> Result<(), Error> {
self.spi.reset()?;
self.spi.write(&[0x04])?;
// Poll status for busy unset and write enable unset
self.status_wait(3, 0)?;
Ok(())
}
pub unsafe fn write_enable(&mut self) -> Result<(), Error> {
self.spi.reset()?;
self.spi.write(&[0x06])?;
// Poll status for busy unset and write enable set
self.status_wait(3, 2)?;
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<usize, Error> {
if (address & 0xFF00_0000) > 0 {
return Err(Error::Parameter);
}
self.write_enable()?;
self.spi.reset()?;
self.spi.write(&[
0xD7,
(address >> 16) as u8,
(address >> 8) as u8,
address as u8,
])?;
// Poll status for busy unset
self.status_wait(1, 0)?;
self.write_disable()?;
//TODO: dynamically figure out this value
Ok(1024)
}
pub unsafe fn read_at(&mut self, address: u32, data: &mut [u8]) -> Result<usize, Error> {
if (address & 0xFF00_0000) > 0 {
return Err(Error::Parameter);
}
self.spi.reset()?;
self.spi.write(&[
0x0B,
(address >> 16) as u8,
(address >> 8) as u8,
address as u8,
0,
])?;
self.spi.read(data)
}
pub unsafe fn write_at(&mut self, address: u32, data: &[u8]) -> Result<usize, Error> {
if (address & 0xFF00_0000) > 0 {
return Err(Error::Parameter);
}
self.write_enable()?;
for (i, word) in data.chunks(2).enumerate() {
let low = *word.get(0).unwrap_or(&0xFF);
let high = *word.get(1).unwrap_or(&0xFF);
self.spi.reset()?;
if i == 0 {
self.spi.write(&[
0xAD,
(address >> 16) as u8,
(address >> 8) as u8,
address as u8,
low,
high
])?;
} else {
self.spi.write(&[
0xAD,
low,
high
])?;
}
// Poll status for busy unset
self.status_wait(1, 0)?;
}
self.write_disable()?;
Ok(data.len())
}
}
impl<'a, S: Spi, T: Timeout> Drop for SpiRom<'a, S, T> {
fn drop(&mut self) {
unsafe {
let _ = self.write_disable();
}
}
}