[opentitantool] Add the EEPROM bootstrap protocol
Signed-off-by: Chris Frantz <cfrantz@google.com>
diff --git a/sw/host/opentitanlib/BUILD b/sw/host/opentitanlib/BUILD
index 086d5e8..16bc302 100644
--- a/sw/host/opentitanlib/BUILD
+++ b/sw/host/opentitanlib/BUILD
@@ -19,6 +19,7 @@
"src/backend/ti50emulator.rs",
"src/backend/ultradebug.rs",
"src/backend/verilator.rs",
+ "src/bootstrap/eeprom.rs",
"src/bootstrap/legacy.rs",
"src/bootstrap/mod.rs",
"src/bootstrap/primitive.rs",
diff --git a/sw/host/opentitanlib/src/bootstrap/eeprom.rs b/sw/host/opentitanlib/src/bootstrap/eeprom.rs
new file mode 100644
index 0000000..a2eaa42
--- /dev/null
+++ b/sw/host/opentitanlib/src/bootstrap/eeprom.rs
@@ -0,0 +1,53 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+use anyhow::Result;
+
+use crate::app::TransportWrapper;
+use crate::bootstrap::{Bootstrap, UpdateProtocol};
+use crate::spiflash::SpiFlash;
+use crate::transport::Capability;
+
+/// Implements the SPI EEPROM bootstrap protocol.
+pub struct Eeprom;
+
+impl Eeprom {
+ /// Creates a new `Eeprom` protocol updater.
+ pub fn new() -> Self {
+ Eeprom
+ }
+}
+
+impl UpdateProtocol for Eeprom {
+ fn verify_capabilities(
+ &self,
+ _container: &Bootstrap,
+ transport: &TransportWrapper,
+ ) -> Result<()> {
+ transport
+ .capabilities()?
+ .request(Capability::GPIO | Capability::SPI)
+ .ok()?;
+ Ok(())
+ }
+
+ fn uses_common_bootstrap_reset(&self) -> bool {
+ true
+ }
+
+ /// Performs the update protocol using the `transport` with the firmware `payload`.
+ fn update(
+ &self,
+ container: &Bootstrap,
+ transport: &TransportWrapper,
+ payload: &[u8],
+ ) -> Result<()> {
+ let spi = container.spi_params.create(transport)?;
+ let flash = SpiFlash::from_spi(&*spi)?;
+ flash.chip_erase(&*spi)?;
+ flash.program(&*spi, 0, payload)?;
+ SpiFlash::chip_reset(&*spi)?;
+ Ok(())
+ }
+}
diff --git a/sw/host/opentitanlib/src/bootstrap/mod.rs b/sw/host/opentitanlib/src/bootstrap/mod.rs
index 99db9df..a119e5f 100644
--- a/sw/host/opentitanlib/src/bootstrap/mod.rs
+++ b/sw/host/opentitanlib/src/bootstrap/mod.rs
@@ -18,6 +18,7 @@
use crate::io::uart::UartParams;
use crate::transport::Capability;
+mod eeprom;
mod legacy;
mod primitive;
mod rescue;
@@ -133,9 +134,7 @@
BootstrapProtocol::Primitive => Box::new(primitive::Primitive::new(&options)),
BootstrapProtocol::Legacy => Box::new(legacy::Legacy::new(&options)),
BootstrapProtocol::Rescue => Box::new(rescue::Rescue::new(&options)),
- BootstrapProtocol::Eeprom => {
- unimplemented!();
- }
+ BootstrapProtocol::Eeprom => Box::new(eeprom::Eeprom::new()),
BootstrapProtocol::Emulator => {
// Not intended to be implemented by this struct.
unimplemented!();
diff --git a/sw/host/opentitanlib/src/spiflash/flash.rs b/sw/host/opentitanlib/src/spiflash/flash.rs
index 3f509f3..e0ac370 100644
--- a/sw/host/opentitanlib/src/spiflash/flash.rs
+++ b/sw/host/opentitanlib/src/spiflash/flash.rs
@@ -231,6 +231,14 @@
Ok(())
}
+ /// Erase the entire EEPROM via the CHIP_ERASE opcode.
+ pub fn chip_erase(&self, spi: &dyn Target) -> Result<()> {
+ Self::set_write_enable(spi)?;
+ spi.run_transaction(&mut [Transfer::Write(&[Self::CHIP_ERASE])])?;
+ Self::wait_for_busy_clear(spi)?;
+ Ok(())
+ }
+
/// Erase a segment of the SPI flash starting at `address` for `length` bytes.
/// The address and length must be sector aligned.
pub fn erase(&self, spi: &dyn Target, address: u32, length: u32) -> Result<()> {
@@ -311,4 +319,11 @@
}
Ok(())
}
+
+ /// Send the software reset sequence to the `spi` target.
+ pub fn chip_reset(spi: &dyn Target) -> Result<()> {
+ spi.run_transaction(&mut [Transfer::Write(&[Self::RESET_ENABLE])])?;
+ spi.run_transaction(&mut [Transfer::Write(&[Self::RESET])])?;
+ Ok(())
+ }
}