tool: 0.1.3 - add backup ROM flashing
This commit is contained in:
		
							
								
								
									
										2
									
								
								tool/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								tool/Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -15,7 +15,7 @@ dependencies = [ | ||||
|  | ||||
| [[package]] | ||||
| name = "system76_ectool" | ||||
| version = "0.1.2" | ||||
| version = "0.1.3" | ||||
| dependencies = [ | ||||
|  "redox_hwio 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| [package] | ||||
| name = "system76_ectool" | ||||
| version = "0.1.2" | ||||
| version = "0.1.3" | ||||
| edition = "2018" | ||||
| description = "System76 EC tool" | ||||
| license = "MIT" | ||||
|   | ||||
| @@ -231,6 +231,10 @@ impl<'a, T: Timeout> 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 | ||||
|     unsafe fn reset(&mut self) -> Result<(), Error> { | ||||
|         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> { | ||||
|     let rom_size = 128 * 1024; | ||||
|     let sector_size = 1024; | ||||
|  | ||||
|     let mut new_rom = firmware.data.to_vec(); | ||||
|     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, | ||||
|         StdTimeout::new(Duration::new(1, 0)) | ||||
|     ); | ||||
|     let sector_size = spi.sector_size(); | ||||
|  | ||||
|     let mut rom = vec![0xFF; rom_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(()) | ||||
| } | ||||
|  | ||||
| unsafe fn flash(path: &str) -> Result<(), Error> { | ||||
|     let target = SpiTarget::Main; | ||||
| unsafe fn flash(path: &str, target: SpiTarget) -> Result<(), Error> { | ||||
|     let scratch = true; | ||||
|  | ||||
|     //TODO: remove unwraps | ||||
| @@ -258,7 +257,7 @@ unsafe fn info() -> Result<(), Error> { | ||||
|         } | ||||
|         println!(); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| @@ -300,6 +299,7 @@ unsafe fn fan_set(index: u8, duty: u8) -> Result<(), Error> { | ||||
| fn usage() { | ||||
|     eprintln!("  console"); | ||||
|     eprintln!("  flash [file]"); | ||||
|     eprintln!("  flash_backup [file]"); | ||||
|     eprintln!("  fan [index] <duty>"); | ||||
|     eprintln!("  info"); | ||||
|     eprintln!("  print [message]"); | ||||
| @@ -352,7 +352,20 @@ fn main() { | ||||
|                 }, | ||||
|             }, | ||||
|             "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(()) => (), | ||||
|                     Err(err) => { | ||||
|                         eprintln!("failed to flash '{}': {:X?}", path, err); | ||||
|   | ||||
| @@ -4,11 +4,13 @@ use crate::{ | ||||
| }; | ||||
|  | ||||
| pub trait Spi { | ||||
|     fn target(&self) -> SpiTarget; | ||||
|     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>; | ||||
| } | ||||
|  | ||||
| #[derive(Clone, Copy)] | ||||
| pub enum SpiTarget { | ||||
|     Main, | ||||
|     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> { | ||||
|         let mut status = [0]; | ||||
|  | ||||
| @@ -67,30 +76,21 @@ impl<'a, S: Spi, T: Timeout> SpiRom<'a, S, T> { | ||||
|         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> { | ||||
|         if (address & 0xFF00_0000) > 0 { | ||||
|             return Err(Error::Parameter); | ||||
|         } | ||||
|  | ||||
|         let instruction = match self.spi.target() { | ||||
|             SpiTarget::Main => 0xD7, | ||||
|             SpiTarget::Backup => 0x20, | ||||
|         }; | ||||
|  | ||||
|         self.write_enable()?; | ||||
|  | ||||
|         self.spi.reset()?; | ||||
|         self.spi.write(&[ | ||||
|             0xD7, | ||||
|             instruction, | ||||
|             (address >> 16) as u8, | ||||
|             (address >> 8) as u8, | ||||
|             address as u8, | ||||
| @@ -127,30 +127,55 @@ impl<'a, S: Spi, T: Timeout> SpiRom<'a, S, T> { | ||||
|  | ||||
|         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); | ||||
|         match self.spi.target() { | ||||
|             SpiTarget::Main => 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 | ||||
|                 ])?; | ||||
|             } | ||||
|                 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)?; | ||||
|                 // Poll status for busy unset | ||||
|                 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()?; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user