From 33c9da2aa57073e6e5d55dccbc18ec0d579829c6 Mon Sep 17 00:00:00 2001 From: "linlin.xu" Date: Tue, 12 Aug 2025 16:27:14 -0700 Subject: [PATCH 1/3] Add OTP driver. --- src/lib.rs | 1 + src/otp.rs | 1282 ++++++++++++++++++++++++++++++ src/otp/common.rs | 122 +++ src/otp/hal.rs | 334 ++++++++ src/tests/functional/mod.rs | 1 + src/tests/functional/otp_test.rs | 567 +++++++++++++ 6 files changed, 2307 insertions(+) create mode 100644 src/otp.rs create mode 100644 src/otp/common.rs create mode 100644 src/otp/hal.rs create mode 100644 src/tests/functional/otp_test.rs diff --git a/src/lib.rs b/src/lib.rs index 5a5bd51..de7267d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ pub mod hace_controller; pub mod hash; pub mod hmac; pub mod i2c; +pub mod otp; pub mod pinctrl; pub mod rsa; pub mod spi; diff --git a/src/otp.rs b/src/otp.rs new file mode 100644 index 0000000..1af7199 --- /dev/null +++ b/src/otp.rs @@ -0,0 +1,1282 @@ +use crate::{ + common::{DummyDelay, Logger}, + otp::common::*, +}; +use ast1060_pac::{Scu, Secure}; +use core::fmt::Debug; +use core::fmt::Write; +use embedded_hal::delay::DelayNs; + +type SbRegBlock = ast1060_pac::secure::RegisterBlock; + +pub mod common; +pub mod hal; + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[repr(u8)] +pub enum OtpSoak { + Default = 0, + NormalProg = 1, + SoakProg = 2, +} + +pub struct OtpController { + pub sb: &'static SbRegBlock, + pub scu: Scu, + pub locked: bool, + pub session_active: bool, + pub logger: L, +} + +impl proposed_traits::otp::ErrorType for OtpController { + type Error = OtpError; +} + +macro_rules! otp_debug { + ($logger:expr, $($arg:tt)*) => { + let mut buf: heapless::String<64> = heapless::String::new(); + write!(buf, $($arg)*).unwrap(); + $logger.debug(buf.as_str()); + }; +} + +macro_rules! otp_error { + ($logger:expr, $($arg:tt)*) => { + let mut buf: heapless::String<64> = heapless::String::new(); + write!(buf, $($arg)*).unwrap(); + $logger.error(buf.as_str()); + }; +} + +//major minor build +const OTP_VER: &str = "2.1.1"; + +const ID0_AST1060A1: u32 = 0xA001_0000; +const ID1_AST1060A1: u32 = 0xA001_0000; +const ID0_AST1060A2: u32 = 0xA003_0000; +const ID1_AST1060A2: u32 = 0xA003_0000; +const ID0_AST1060A2_ENG: u32 = 0x8003_0000; +const ID1_AST1060A2_ENG: u32 = 0x8003_0000; +const OTP_AST1060A1: u32 = 3; +const OTP_AST1060A2: u32 = 4; +const OTP_PASSWD: u32 = 0x349f_e38a; +const OTP_READ_CMD: u32 = 0x23b1_e361; +const OTP_WRITE_CMD: u32 = 0x23b1_e362; +const OTP_COMP_CMD: u32 = 0x23b1_e363; +const OTP_PROG_CMD: u32 = 0x23b1_e364; + +const OTP_MEM_LIMIT: u32 = 2144; //67kbits +const OTP_MEM_LIMIT_DATA: usize = 2048; +const OTP_MEM_ECC_OFFSET: u32 = 1792; //DWORD + +/// timing +const OTP_TIMING_200US: u32 = 0x0419_1388; +const OTP_TIMING_600US: u32 = 0x0419_3a98; +const OTP_OP_RETRIES: u8 = 20; +///OTP memory layout +/// +/// OTP region protection +pub const OTP_CONF_OFFSET: u32 = 0x800; +pub const OTP_MEM_LOCK_ENBLE: u32 = 1 << 31; +pub const OTP_KEY_PROT_ENBLE: u32 = 1 << 29; +pub const OTP_STRAP_PROT_ENBLE: u32 = 1 << 25; +pub const OTP_CONF_PROT_ENBLE: u32 = 1 << 24; +//data secure,user,ecc +pub const OTP_USER_ECC_PROT_ENBLE: u32 = 1 << 23; +const OTP_SECURE_PROT_ENBLE: u32 = 1 << 22; +pub const OTP_SECURE_SIZE_BIT_POS: u32 = 16; +const OTP_SECURE_SIZE_MASK: u32 = 0x3f; + +#[derive(Debug, Clone, Copy)] +pub struct SoakProInfo { + pub address: u32, + pub data: u32, +} +/// Write MRA +/// Write MRB +/// Write MR +pub static SOAK_PROG_DEFAULT: &[SoakProInfo] = &[ + SoakProInfo { + address: 0x3000, + data: 0, + }, + SoakProInfo { + address: 0x5000, + data: 0, + }, + SoakProInfo { + address: 0x1000, + data: 0, + }, +]; +pub static SOAK_PROG_NORMAL: &[SoakProInfo] = &[ + SoakProInfo { + address: 0x3000, + data: 0x1320, + }, + SoakProInfo { + address: 0x5000, + data: 0x1008, + }, + SoakProInfo { + address: 0x1000, + data: 0x0024, + }, +]; +pub static SOAK_PROG_SOAK: &[SoakProInfo] = &[ + SoakProInfo { + address: 0x3000, + data: 0x1320, + }, + SoakProInfo { + address: 0x5000, + data: 0x0007, + }, + SoakProInfo { + address: 0x1000, + data: 0x0100, + }, +]; + +pub struct RegionInfo { + region_type: AspeedOtpRegion, + start: usize, + cdw_size: usize, + alignment: usize, //data aligment +} +pub static REGION_IDS: &[AspeedOtpRegion] = &[ + AspeedOtpRegion::Data, + AspeedOtpRegion::Configuration, + AspeedOtpRegion::Strap, + AspeedOtpRegion::ScuProtection, +]; + +pub static REGION_INFO: &[RegionInfo] = &[ + RegionInfo { + region_type: AspeedOtpRegion::Data, + start: 0, + cdw_size: OTP_MEM_LIMIT_DATA, + alignment: 4, + }, + RegionInfo { + //[otpcfg0, otpcfg31] + region_type: AspeedOtpRegion::Configuration, + start: 0x800, + cdw_size: 32, + alignment: 4, + }, + RegionInfo { + //[otpcfg16, otpcfg27] + region_type: AspeedOtpRegion::Strap, + start: 0xC00, + cdw_size: 2, + alignment: 4, + }, + RegionInfo { + //[otpcfg28, otpcfg29] + region_type: AspeedOtpRegion::ScuProtection, + start: 0xE08, + cdw_size: 2, + alignment: 4, + }, +]; +static mut DATA_REGION: [u32; OTP_MEM_LIMIT_DATA] = [0; OTP_MEM_LIMIT_DATA]; + +impl OtpController { + pub fn new(scu: Scu, logger: L) -> Self { + let locked: bool = false; + let session_active = false; + let sb = unsafe { &*Secure::PTR }; + Self { + sb, + scu, + locked, + session_active, + logger, + } + } + pub fn chip_version(&self) -> AspeedChipVersion { + let revid0 = self.scu.scu004().read().bits(); + let revid1 = self.scu.scu014().read().bits(); + + if revid0 == ID0_AST1060A1 && revid1 == ID1_AST1060A1 { + return AspeedChipVersion::Ast1060A1; + } else if revid0 == ID0_AST1060A2 && revid1 == ID1_AST1060A2 + || revid0 == ID0_AST1060A2_ENG && revid1 == ID1_AST1060A2_ENG + { + return AspeedChipVersion::Ast1060A2; + } + AspeedChipVersion::Unknown + } + pub fn wait_complete(&self) -> bool { + let mut tries: u32 = 1000; + let mut delay = DummyDelay {}; + + delay.delay_ns(100_000); // 100us + + //check if OTP controller is idle (1) + //OTP memory is idle + while !self.sb.secure014().read().otpctrl_sts().bit() + || !self.sb.secure014().read().otpmemory_sts().bit() + { + tries -= 1; + if tries == 0 { + break; + } + } + if self.sb.secure014().read().otpctrl_sts().bit() + && self.sb.secure014().read().otpmemory_sts().bit() + { + return true; + } + false + } + + pub fn otp_write(&self, otp_addr: u32, data: u32) -> bool { + self.sb.secure010().write(|w| unsafe { w.bits(otp_addr) }); + self.sb.secure020().write(|w| unsafe { w.bits(data) }); + self.sb + .secure004() + .write(|w| unsafe { w.bits(OTP_WRITE_CMD) }); + self.wait_complete() + } + + pub fn otp_soak(&self, otp_soak: OtpSoak) -> bool { + match otp_soak { + OtpSoak::Default => { + self.otp_write(SOAK_PROG_DEFAULT[0].address, SOAK_PROG_DEFAULT[0].data); + self.otp_write(SOAK_PROG_DEFAULT[1].address, SOAK_PROG_DEFAULT[1].data); + self.otp_write(SOAK_PROG_DEFAULT[2].address, SOAK_PROG_DEFAULT[2].data); + } + OtpSoak::NormalProg => { + self.otp_write(SOAK_PROG_NORMAL[0].address, SOAK_PROG_NORMAL[0].data); + self.otp_write(SOAK_PROG_NORMAL[1].address, SOAK_PROG_NORMAL[1].data); + self.otp_write(SOAK_PROG_NORMAL[2].address, SOAK_PROG_NORMAL[2].data); + self.sb + .secure008() + .write(|w| unsafe { w.bits(OTP_TIMING_200US) }); + } + OtpSoak::SoakProg => { + self.otp_write(SOAK_PROG_SOAK[0].address, SOAK_PROG_SOAK[0].data); + self.otp_write(SOAK_PROG_SOAK[1].address, SOAK_PROG_SOAK[1].data); + self.otp_write(SOAK_PROG_SOAK[2].address, SOAK_PROG_SOAK[2].data); + self.sb + .secure008() + .write(|w| unsafe { w.bits(OTP_TIMING_600US) }); + } + } + self.wait_complete() + } + /// + /// Read 2 DWORD data + /// + pub fn otp_read_data(&self, otp_addr: u32, buffer: &mut [u32]) -> Result<(), OtpError> { + if buffer.len() < 2 { + return Err(OtpError::ReadFailed); + } + self.sb.secure010().write(|w| unsafe { w.bits(otp_addr) }); + self.sb + .secure004() + .write(|w| unsafe { w.bits(OTP_READ_CMD) }); + if !self.wait_complete() { + return Err(OtpError::ReadFailed); + } + buffer[0] = self.sb.secure020().read().bits(); + buffer[1] = self.sb.secure024().read().bits(); + Ok(()) + } + /// + /// Read whole data region to the static buffer + /// + pub fn otp_read_data_region(&self) -> Result<(), OtpError> { + for i in (0..OTP_MEM_LIMIT_DATA).step_by(2) { + unsafe { + self.otp_read_data(i as u32, &mut DATA_REGION[i..i + 1])?; + } + } + Ok(()) + } + /// + /// Read configruation + /// + fn otp_read_conf(&self, addr: u32) -> Result { + self.sb.secure010().write(|w| unsafe { w.bits(addr) }); + self.sb + .secure004() + .write(|w| unsafe { w.bits(OTP_READ_CMD) }); + if !self.wait_complete() { + return Err(OtpError::ReadFailed); + } + let data = self.sb.secure020().read().bits(); + Ok(data) + } + + /// This function does OTPCONFGX read. + /// # Arguments + /// + /// * `reg_idx` - OTPCFG register number eg. 1-OTPCFG1 + /// The address offset: 0x800 (OTPFCG0),0x802 (OTPFCG1) + /// A00(OTPCFG8-15), C00(OTPCFG16-31) + fn otp_read_conf_idx(&self, reg_idx: u32) -> Result { + let mut addr = OTP_CONF_OFFSET; + + addr |= (reg_idx / 8) * 0x200; + addr |= (reg_idx % 8) * 0x2; + + self.otp_read_conf(addr) + } + + fn otp_prog(&mut self, otp_addr: u32, prog_bit: u32) -> Result<(), OtpError> { + if self.otp_write(0, prog_bit) { + self.sb.secure010().write(|w| unsafe { w.bits(otp_addr) }); + self.sb.secure020().write(|w| unsafe { w.bits(prog_bit) }); + self.sb + .secure004() + .write(|w| unsafe { w.bits(OTP_PROG_CMD) }); + if !self.wait_complete() { + Err(OtpError::Timeout) + } else { + Ok(()) + } + } else { + Err(OtpError::WriteFailed) + } + } + /// + /// Inverse the data + /// + fn otp_prog_bit_helper( + &mut self, + value: u32, + address: u32, + bit_offset: u32, + ) -> Result<(), OtpError> { + let mut prog_bit: u32 = 0; + + if address & 0x1 == 0 { + //even address, default data is 0x0 + if value != 0 { + prog_bit = !(0x1 << bit_offset); + } + } else { + //odd address, default data is 0xffff_ffff + if value == 0 { + prog_bit = 0x1 << bit_offset; + } + } + if prog_bit > 0 { + self.otp_prog(address, prog_bit) + } else { + Err(OtpError::Timeout) + } + } + //lock registers + pub fn otp_lock_reg(&self) { + self.sb + .secure000() + .write(|w| unsafe { w.prot_key().bits(1) }); + } + pub fn otp_unlock_reg(&self) { + self.sb + .secure000() + .write(|w| unsafe { w.prot_key().bits(OTP_PASSWD) }); + } + fn verify_bit(&mut self, value: u32, otp_addr: u32, bit_offset: u32) -> Result<(), OtpError> { + let mut ret: [u32; 2] = [0, 0]; + let addr: u32; + let mut success: bool = false; + if otp_addr & 0x1 == 0 { + addr = otp_addr; + } else { + //make it even + addr = otp_addr - 1; + } + self.otp_read_data(addr, &mut ret)?; + + if otp_addr & 0x1 == 0 { + if (ret[0] >> bit_offset) & 1 == value { + success = true; + } + } else { + //Odd address takes takes the 2nd Dword + if (ret[1] >> bit_offset) & 1 == value { + success = true; + } + } + if !success { + return Err(OtpError::VerificationFailed); + } + Ok(()) + } + + /// + /// bit program + /// + pub fn otp_prog_dc_b( + &mut self, + value: u32, + address: u32, + bit_offset: u32, + ) -> Result<(), OtpError> { + let mut pass: bool = false; + + self.otp_soak(OtpSoak::NormalProg); + self.otp_prog_bit_helper(value, address, bit_offset)?; + for _i in 0..OTP_OP_RETRIES { + if !self.verify_bit(value, address, bit_offset).is_ok() { + self.otp_soak(OtpSoak::SoakProg); + self.otp_prog_bit_helper(value, address, bit_offset)?; + if self.verify_bit(value, address, bit_offset).is_ok() { + self.otp_soak(OtpSoak::NormalProg); + } else { + pass = true; + break; + } + } else { + pass = true; + break; + } + } + if !pass { + return Err(OtpError::Timeout); + } + Ok(()) + } + /// + /// program a DWORD. will do verification after program a DWORD for efficiency + /// * `ignore` - bit position mask. don't program the bits shown in the mask + /// + fn otp_prog_dw(&mut self, value: u32, ignore: u32, address: u32) -> Result<(), OtpError> { + let mut result: Result<(), OtpError>; + let mut bit_value: u32; + let mut prog_bit: u32; + //1-bit at a time + for bit_pos in 0..32 { + if (ignore >> bit_pos) & 0x1 == 0x1 { + //don't do anything + continue; + } + bit_value = (value >> bit_pos) & 0x1; + //inverse + if address & 0x1 == 0 { + if bit_value == 0x1 { + prog_bit = !(0x1 << bit_pos); + } else { + continue; + } + } else if bit_value == 0x1 { + continue; + } else { + prog_bit = 0x1 << bit_pos; + } + result = self.otp_prog(address, prog_bit); + if result != Ok(()) { + return result; + } + } + Ok(()) + } + + /// + /// verify 1 DWORD from odd/even address + /// + pub fn verify_dw(&self, address: u32, data: u32, ignore: u32, compare: &mut u32) -> bool { + let mut ret: [u32; 2] = [0, 0]; + let addr; + let otp_addr = address & !(1 << 15); + + if otp_addr & 0x1 == 0 { + addr = otp_addr; + } else { + addr = otp_addr - 1; + } + if self.otp_read_data(addr, &mut ret) != Ok(()) { + return false; + } + if otp_addr & 0x1 == 0 { + //retrieve 1st DWORD + if (data & !ignore) == (ret[0] & !ignore) { + *compare = 0; + return true; + } + *compare = data ^ ret[0]; + false + } else { + //odd address: retrieve 2nd DWORD + if (data & !ignore) == (ret[1] & !ignore) { + *compare = !0; + return true; + } + *compare = !(data ^ ret[1]); + false + } + } + + /// + /// verify 2 DWORD + /// + pub fn verify_2dw( + &mut self, + address: u32, + value: &[u32], + ignore: &[u32], + num_dw: u32, + compare: &mut [u32], + ) -> bool { + let mut ret: [u32; 2] = [0, 0]; + + let otp_addr = address & !(1 << 15); + + if num_dw == 1 { + return self.verify_dw(address, value[0], ignore[0], &mut compare[0]); + } else if num_dw == 2 { + //otp_addr should already be even + if self.otp_read_data(otp_addr, &mut ret) != Ok(()) { + return false; + } + if (value[0] & !ignore[0]) == (ret[0] & !ignore[0]) + && (value[1] & !ignore[1]) == (ret[1] & !ignore[1]) + { + compare[0] = 0; + compare[1] = !0; + return true; + } + compare[0] = value[0] ^ ret[0]; + compare[1] = !(value[1] ^ ret[1]); + } + false + } + + /// + /// Check if prorammed data is valid + /// + pub fn is_program_data_valid(&mut self, addr: u32, otp_data: u32, buffer_data: u32) -> bool { + for i in 0..32 { + if addr & 0x1 == 0 { + //even location, default is 0x0000_0000 + //only able to write b'1 + //it's already b'1, can't program it b'0 + if ((otp_data >> i) & 0x1) == 1 && ((buffer_data >> i) & 0x1) == 0 { + return false; + } + } else if ((otp_data >> i) & 0x1) == 0 && ((buffer_data >> i) & 0x1) == 1 { + return false; + } + } + true + } + /// + /// Program 2 DWORD and verify in data region + /// + pub fn otp_prog_verify_2dw( + &mut self, + address: u32, + otp_data: &[u32], + buffer: &[u32], + ignore: &[u32], + ) -> Result<(), OtpError> { + let mut ignore_mask: [u32; 2] = [0, 0]; + let mut compare: [u32; 2] = [0, 0]; + let mut pass: bool; + let mut verify_size = 0; + ignore_mask[0] = ignore[0]; + ignore_mask[1] = ignore[1]; + let data0_masked = otp_data[0] & !ignore_mask[0]; + let buf0_masked = buffer[0] & !ignore_mask[0]; + let data1_masked = otp_data[1] & !ignore_mask[1]; + let buf1_masked = buffer[1] & !ignore_mask[1]; + //if bits to be programmed is the same as + //already programmed bits, no need to program + if data0_masked == buf0_masked { + ignore_mask[0] = 0xffff_ffff; + } + if data1_masked == buf1_masked { + ignore_mask[1] = 0xffff_ffff; + } + + //check if data to be written is the same on otp + if data0_masked == buf0_masked && data1_masked == buf1_masked { + otp_debug!( + self.logger, + "otp_prog_verify_2dw: data is the same, no need to program" + ); + return Ok(()); + } + if ignore_mask[0] != 0xffff_ffff + && !self.is_program_data_valid(address, data0_masked, buf0_masked) + { + return Err(OtpError::WriteFailed); + } + if ignore_mask[1] != 0xffff_ffff + && !self.is_program_data_valid(address + 1, data1_masked, buf1_masked) + { + return Err(OtpError::WriteFailed); + } + if !self.otp_soak(OtpSoak::NormalProg) { + return Err(OtpError::Timeout); + } + + //ignore + if ignore_mask[0] != 0xffff_ffff { + self.otp_prog_dw(buffer[0], ignore_mask[0], address)?; + verify_size += 1; + } + if ignore_mask[1] != 0xffff_ffff { + self.otp_prog_dw(buffer[1], ignore_mask[1], address + 1)?; + verify_size += 1; + } + pass = false; + for _j in 0..OTP_OP_RETRIES { + if !self.verify_2dw(address, buffer, &ignore_mask, verify_size, &mut compare) { + self.otp_soak(OtpSoak::SoakProg); + if compare[0] != 0 { + self.otp_prog_dw(compare[0], ignore_mask[0], address)?; + } + if verify_size == 2 && compare[1] != !0 { + self.otp_prog_dw(compare[1], ignore_mask[1], address + 1)?; + } + if !self.verify_2dw(address, buffer, &ignore_mask, verify_size, &mut compare) { + self.otp_soak(OtpSoak::NormalProg); + } else { + pass = true; + break; + } + } else { + pass = true; + break; + } + } + if !pass { + self.otp_soak(OtpSoak::Default); + return Err(OtpError::WriteFailed); + } + Ok(()) + } + + /// + /// bit programing retry + /// + pub fn otp_prog_verify_retry(&mut self, addr: u32, data: u32, ignore: u32) -> bool { + let mut compare: u32 = 0; + let mut pass: bool = false; + + for _j in 0..OTP_OP_RETRIES { + if !self.verify_dw(addr, data, ignore, &mut compare) { + self.otp_soak(OtpSoak::SoakProg); + if let Err(_e) = self.otp_prog_dw(compare, ignore, addr) { + pass = false; + break; + } + if !self.verify_dw(addr, data, ignore, &mut compare) { + self.otp_soak(OtpSoak::NormalProg); + } else { + pass = true; + break; + } + } else { + pass = true; + break; + } + } + pass + } + /// + /// Program OTP data region + /// starts from "address" with "buffer" contents + /// + pub fn aspeed_otp_prog_data( + &mut self, + address: usize, + buffer: &mut [u32], + ) -> Result<(), OtpError> { + let mut result = Ok(()); + let ignore: u32 = 0; //ignore bits mask + let mut addr: u32; + let len: usize = buffer.len(); + let mut pass: bool; + let compare: u32 = 0; + + if address + len > OTP_MEM_LIMIT_DATA || address & 0x3 != 0 { + return Err(OtpError::InvalidAddress); + } + self.otp_unlock_reg(); + + for i in 0..len { + addr = (address + i) as u32; + self.otp_soak(OtpSoak::NormalProg); + result = self.otp_prog_dw(buffer[i], ignore, addr); + if result != Ok(()) { + return result; + } + pass = self.otp_prog_verify_retry(buffer[i], ignore, addr); + if !pass { + self.otp_soak(OtpSoak::Default); + result = Err(OtpError::WriteFailed); + break; + } + } + self.otp_lock_reg(); + result + } + //lock otp memory + pub fn otp_lock_mem(&mut self) -> Result<(), OtpError> { + if !self.is_otp_locked() && self.otp_prog(0, 31).is_ok() { + self.locked = true; + } + Ok(()) + } + pub fn is_otp_locked(&self) -> bool { + let otp_conf: u32 = self.otp_read_conf_idx(0).unwrap_or_default(); + otp_conf & OTP_MEM_LOCK_ENBLE == OTP_MEM_LOCK_ENBLE + } + pub fn is_key_protected(&self) -> bool { + let otp_conf: u32 = self.otp_read_conf_idx(0).unwrap_or_default(); + otp_conf & OTP_KEY_PROT_ENBLE == OTP_KEY_PROT_ENBLE + } + + pub fn update_prot_info(&self, session: &mut SessionInfo) { + session.chip_version = self.chip_version(); + match session.chip_version { + AspeedChipVersion::Ast1060A1 => { + session.version_name = *b"AST1060A1\0"; + } + AspeedChipVersion::Ast1060A2 => { + session.version_name = *b"AST1060A2\0"; + } + _ => { + session.version_name = *b"ASUnknown\0"; + } + } + let otp_conf: u32 = self.otp_read_conf_idx(0).unwrap_or_default(); + session.protection_status.memory_locked = + otp_conf & OTP_MEM_LOCK_ENBLE == OTP_MEM_LOCK_ENBLE; + session.protection_status.strap_protected = + otp_conf & OTP_STRAP_PROT_ENBLE == OTP_STRAP_PROT_ENBLE; + session.protection_status.user_ecc_protected = + otp_conf & OTP_USER_ECC_PROT_ENBLE == OTP_USER_ECC_PROT_ENBLE; + + session.protection_status.security_protected = + otp_conf & OTP_SECURE_PROT_ENBLE == OTP_SECURE_PROT_ENBLE; + let mut secure_size = otp_conf >> OTP_SECURE_SIZE_BIT_POS; + if secure_size != 0 { + secure_size = (secure_size & (OTP_SECURE_SIZE_MASK + 1)) << 5; + } + session.protection_status.security_size = secure_size; + } + pub fn get_sw_revision(&self, sw_rid: &mut [u32; 2]) { + sw_rid[0] = self.sb.secure068().read().bits(); + sw_rid[1] = self.sb.secure06c().read().bits(); + } + pub fn get_tool_verion(&self) -> &[u8] { + return OTP_VER.as_bytes(); + } + pub fn get_key_count(&self) -> u8 { + let key_num = self.sb.secure078().read().sec_boot_key_number_regs().bits(); + + key_num + } + pub fn otp_strap_status(&self, os: &mut [StrapStatus]) -> Result<(), OtpError> { + let mut otpstrap_raw: [u32; 2] = [0; 2]; + + for j in 0..64 { + os[j].value = false; + os[j].remaining_writes = 6; + os[j].writable_option = 0xff; + os[j].protected = false; + } + let strap_end: usize = 28; // Final strap address to process + + self.otp_soak(OtpSoak::Default); + + for i in (16..strap_end).step_by(2) { + let option = ((i - 16) / 2) as u8; + + otpstrap_raw[0] = self.otp_read_conf_idx(i.try_into().unwrap())?; + otpstrap_raw[1] = self.otp_read_conf_idx((i + 1).try_into().unwrap())?; + for j in 0..32 { + let bit_value = ((otpstrap_raw[0] >> j) & 0x1) as u8; + + if bit_value == 0 && os[j].writable_option == 0xff { + os[j].writable_option = option; + } + if bit_value == 1 { + os[j].remaining_writes -= 1; + } + os[j].value ^= bit_value != 0; + os[j].options[option as usize] = bit_value; + } + + for j in 32..64 { + let bit_value = ((otpstrap_raw[1] >> (j - 32)) & 0x1) as u8; + + if bit_value == 0 && os[j].writable_option == 0xff { + os[j].writable_option = option; + } + if bit_value == 1 { + os[j].remaining_writes -= 1; + } + os[j].value ^= bit_value != 0; + os[j].options[option as usize] = bit_value; + } + } + otpstrap_raw[0] = self.otp_read_conf_idx(30)?; + otpstrap_raw[1] = self.otp_read_conf_idx(31)?; + + for j in 0..32 { + if (otpstrap_raw[0] >> j) & 0x1 == 1 { + os[j].protected = true; + } + } + + for j in 32..64 { + if (otpstrap_raw[1] >> (j - 32)) & 0x1 == 1 { + os[j].protected = true; + } + } + Ok(()) + } + + /// + /// Read from data region + /// + fn aspeed_otp_read_data(&self, offset: usize, buffer: &mut [u32]) -> Result<(), OtpError> { + let mut temp: [u32; 2] = [0, 0]; + let cdw_len: usize = buffer.len(); + if cdw_len + offset > OTP_MEM_LIMIT_DATA { + return Err(OtpError::BoundaryError); + } + if offset & 0x4 != 0 { + return Err(OtpError::AlignmentError); + } + for i in (offset..offset + cdw_len).step_by(2) { + let idx = i - offset; + match self.otp_read_data(i as u32, &mut temp) { + Ok(()) => { + buffer[idx] = temp[0]; + buffer[idx + 1] = temp[1]; + } + Err(e) => return Err(e), + } + } + Ok(()) + } + + /// + /// Read from configuration region + /// + fn aspeed_otp_read_conf(&self, offset: u32, buffer: &mut [u32]) -> Result<(), OtpError> { + let mut result: Result<(), OtpError> = Ok(()); + let cdw_len = buffer.len() as u32; + if cdw_len + offset > 32 { + return Err(OtpError::BoundaryError); + } + self.otp_unlock_reg(); + self.otp_soak(OtpSoak::Default); + for i in offset..offset + cdw_len { + let idx = (i - offset) as usize; + buffer[idx] = match self.otp_read_conf_idx(i) { + Ok(value) => value, + Err(_e) => { + result = Err(_e); + break; + } + }; + } + self.otp_lock_reg(); + result + } + /// + ///Read OTP strap into buffer. + ///buf: output OTP strap into buffer. + /// + fn aspeed_otp_read_strap(&self, offset: usize, buf: &mut [u32]) -> Result<(), OtpError> { + let mut strap_status: [StrapStatus; 64] = [StrapStatus { + value: false, + protected: false, + options: [0; 7], + remaining_writes: 6, + writable_option: 0xff, + }; 64]; + let cdw_len = buf.len(); + + if cdw_len + offset > 2 { + return Err(OtpError::BoundaryError); + } + self.otp_unlock_reg(); + let result = self.otp_strap_status(&mut strap_status); + if result == Ok(()) { + for i in offset..offset + cdw_len { + let idx = i - offset; + buf[idx] = 0; + for j in 0..32 { + buf[idx] |= (strap_status[i * 32 + j].value as u32) << j; + } + } + } + self.otp_lock_reg(); + result + } + + /// + ///Read OTP protect into buffer. + ///offset-offset to scu protect region + ///OTPCFG28,OTPCFG29 + /// + pub fn aspeed_otp_read_scuprot( + &self, + offset: usize, + buffer: &mut [u32], + ) -> Result<(), OtpError> { + let mut result: Result<(), OtpError> = Ok(()); + let cdw_len = buffer.len(); + + if cdw_len + offset > 2 { + return Err(OtpError::BoundaryError); + } + self.otp_unlock_reg(); + + if result == Ok(()) { + for i in offset..offset + cdw_len { + let idx = i - offset; + buffer[idx] = match self.otp_read_conf_idx(28 + offset as u32) { + Ok(value) => value, + Err(_e) => { + result = Err(_e); + break; + } + }; + } + } + self.otp_lock_reg(); + result + } + + /// + /// Write data to data region + /// + pub fn otp_prog_data(&mut self, offset: usize, data: &[u32]) -> Result<(), OtpError> { + let mut result: Result<(), OtpError> = Ok(()); + let ignore: [u32; 2] = [0, 0]; + let cdw_len = data.len(); + + if cdw_len + offset > OTP_MEM_LIMIT_DATA { + return Err(OtpError::BoundaryError); + } + if offset & 0x3 != 0 { + return Err(OtpError::AlignmentError); + } + self.otp_unlock_reg(); + //Read whole data region + //self.otp_read_data_region()?; + + for i in (offset..offset + cdw_len).step_by(2) { + let idx0 = i - offset; + let idx1 = i; + unsafe { + result = self.otp_read_data(idx1 as u32, &mut DATA_REGION[idx1..idx1 + 2]); + if result != Ok(()) { + otp_debug!( + self.logger, + "otp_prog_data: read fail {:?}", + result.unwrap() + ); + break; + } + otp_debug!(self.logger, "otp_prog_data: idx0={:}, idx1={:}", idx0, idx1); + result = self.otp_prog_verify_2dw( + i as u32, + &DATA_REGION[idx1..idx1 + 2], + &data[idx0..idx0 + 2], + &ignore, + ); + if result != Ok(()) { + break; + } + } + } + + self.otp_soak(OtpSoak::Default); + self.otp_lock_reg(); + result + } + + /// + /// Program strap bits + /// All non proteced bits will be programmed + /// + pub fn otp_prog_strap(&mut self, start_bit: usize, strap: &[u32]) -> Result<(), OtpError> { + let mut prog_address: u32; + let mut bit: u32; + let mut offset: u32; + let mut prog_flag: u32; + let mut count_prot: u32 = 0; + let mut count_cant_write: u32 = 0; + + if start_bit > 63 { + return Err(OtpError::InvalidAddress); + } + + let mut os: [StrapStatus; 64] = [StrapStatus { + value: false, + protected: false, + options: [0; 7], + remaining_writes: 6, + writable_option: 0xff, + }; 64]; + + self.otp_strap_status(&mut os)?; + //all strap bits + for i in start_bit..64 { + prog_address = OTP_CONF_OFFSET; + if i < 32 { + offset = i as u32; + bit = (strap[0] >> (offset - start_bit as u32)) & 0x1; + prog_address |= ((os[i].writable_option as u32 * 2 + 16) / 8) * 0x200; + prog_address |= ((os[i].writable_option as u32 * 2 + 16) % 8) * 0x2; + } else { + offset = (i - 32) as u32; + if i - start_bit < 32 { + bit = (strap[0] >> offset) & 0x1; + } else { + bit = (strap[1] >> (offset - start_bit as u32)) & 0x1; + } + prog_address |= ((os[i].writable_option as u32 * 2 + 17) / 8) * 0x200; + prog_address |= ((os[i].writable_option as u32 * 2 + 17) % 8) * 0x2; + } + //check if program bit value is the same as the programmed bit value + if bit == os[i].value as u32 { + prog_flag = 0; //no need to proram + otp_debug!(self.logger, "otp_prog_strap: bit {:} no need to program", i); + } else { + prog_flag = 1; + otp_debug!( + self.logger, + "otp_prog_strap: program bit {:} from {:} to {:}", + i, + os[i].value as u32, + bit + ); + } + //bit to be prgrammed is protected + if os[i].protected && prog_flag == 1 { + count_prot += 1; + continue; + } + if os[i].remaining_writes == 0 && prog_flag == 1 { + count_cant_write += 1; + continue; + } + if prog_flag == 1 { + match self.otp_prog_dc_b(1, prog_address, offset) { + Ok(()) => {} + Err(_e) => { + return Err(_e); + } + } + } + } + self.otp_soak(OtpSoak::Default); + if count_prot > 0 || count_cant_write > 0 { + //return Err() + } + Ok(()) + } + + /// + /// OTP conf + /// + pub fn otp_prog_conf(&mut self, start_conf: usize, conf: &[u32]) -> Result<(), OtpError> { + let mut result: Result<(), OtpError> = Ok(()); + let conf_ignore: u32 = 0; + let mut otp_conf: u32; + let mut pass: bool = false; + let mut addr: usize; + let mut data_masked: u32; + let mut buf_masked: u32; + let cdw_len = conf.len(); + + if cdw_len + start_conf > 32 { + return Err(OtpError::BoundaryError); + } + self.otp_unlock_reg(); + self.otp_soak(OtpSoak::Default); + for i in start_conf..start_conf + cdw_len { + //from 0 + let idx = i - start_conf; + //read conf from OTP + otp_conf = match self.otp_read_conf_idx(i as u32) { + Ok(value) => value, + Err(_e) => { + result = Err(_e); + break; + } + }; + data_masked = otp_conf & !conf_ignore; + buf_masked = conf[idx] & !conf_ignore; + addr = REGION_INFO[AspeedOtpRegion::Configuration as usize].start; + addr |= (i / 8) * 0x200; + addr |= (i % 8) * 0x2; + otp_debug!(self.logger, "otp_prog_conf: addr = {:#x}", addr); + if data_masked == buf_masked { + pass = true; + continue; + } + self.otp_soak(OtpSoak::NormalProg); + result = self.otp_prog_dw(conf[idx], conf_ignore, addr as u32); + if result != Ok(()) { + break; + } + pass = self.otp_prog_verify_retry(addr as u32, conf[idx], conf_ignore); + + if !pass { + break; + } + } + self.otp_soak(OtpSoak::Default); + self.otp_lock_reg(); + if !pass { + return Err(OtpError::WriteFailed); + } + result + } + + /// + /// SCU protect + /// + pub fn otp_prog_scu_protect(&mut self, start: usize, otp_scu: &[u32]) -> Result<(), OtpError> { + let mut scu_pro: [u32; 2] = [0; 2]; + let ignore: u32 = 0; + let mut data_masked: u32; + let mut buf_masked: u32; + let mut addr: usize; + let mut pass: bool = false; + let scupro_start = REGION_INFO[AspeedOtpRegion::ScuProtection as usize].start; + let cdw_size = otp_scu.len(); + let total_size = REGION_INFO[AspeedOtpRegion::ScuProtection as usize].cdw_size; + + if start + cdw_size > total_size { + return Err(OtpError::BoundaryError); + } + scu_pro[0] = self.otp_read_conf_idx(28)?; + scu_pro[1] = self.otp_read_conf_idx(29)?; + self.otp_unlock_reg(); + self.otp_soak(OtpSoak::Default); + + for i in start..start + cdw_size { + let idx = i - start; + data_masked = scu_pro[i] & !ignore; + buf_masked = otp_scu[idx] & !ignore; + addr = scupro_start + i * 2; + if data_masked == buf_masked { + pass = true; + continue; + } + self.otp_soak(OtpSoak::Default); + self.otp_prog_dw(otp_scu[idx], ignore, addr as u32)?; + + pass = self.otp_prog_verify_retry(addr as u32, otp_scu[idx], ignore); + + if !pass { + break; + } + } + self.otp_soak(OtpSoak::Default); + self.otp_lock_reg(); + if !pass { + return Err(OtpError::WriteFailed); + } + Ok(()) + } + + pub fn total_capacity(&self) -> usize { + let mut cdw_size: usize = 0; + + cdw_size += REGION_INFO[AspeedOtpRegion::Data as usize].cdw_size; + cdw_size += REGION_INFO[AspeedOtpRegion::Configuration as usize].cdw_size; + cdw_size << 2 + } + + pub fn region_capacity(&self, region: AspeedOtpRegion) -> usize { + REGION_INFO[region as usize].cdw_size << 2 + } + fn region_alignment(&self, region: AspeedOtpRegion) -> usize { + REGION_INFO[region as usize].alignment + } + + fn is_region_protected(&self, region: AspeedOtpRegion) -> Result { + let mut protected: bool = false; + + self.otp_unlock_reg(); + let otp_conf: u32 = self.otp_read_conf_idx(0).unwrap_or_default(); + self.otp_lock_reg(); + match region { + AspeedOtpRegion::Data => { + if otp_conf & OTP_USER_ECC_PROT_ENBLE == OTP_USER_ECC_PROT_ENBLE + && otp_conf & OTP_SECURE_PROT_ENBLE == OTP_SECURE_PROT_ENBLE + { + protected = true; + } + } + AspeedOtpRegion::Configuration => { + if otp_conf & OTP_STRAP_PROT_ENBLE == OTP_STRAP_PROT_ENBLE { + protected = true; + } + } + AspeedOtpRegion::Strap => { + if otp_conf & OTP_STRAP_PROT_ENBLE == OTP_STRAP_PROT_ENBLE { + protected = true; + } + } + AspeedOtpRegion::ScuProtection => { + if otp_conf & OTP_STRAP_PROT_ENBLE == OTP_STRAP_PROT_ENBLE { + protected = true; + } + } + } + Ok(protected) + } + + /// Enable protection for a specific region + /// + /// # Parameters + /// - `region`: The region to protect + /// + /// # Returns + /// - `Ok(())`: Protection enabled successfully + /// - `Err(Self::Error)`: Failed to enable protection + fn enable_region_protection(&mut self, region: AspeedOtpRegion) -> Result<(), OtpError> { + let mut value: [u32; 1] = [0; 1]; + + if self.is_region_protected(region) == Ok(true) { + return Ok(()); + } + match region { + AspeedOtpRegion::Data => { + value[0] = OTP_USER_ECC_PROT_ENBLE | OTP_SECURE_PROT_ENBLE; + } + AspeedOtpRegion::Configuration => { + value[0] = OTP_STRAP_PROT_ENBLE; + } + AspeedOtpRegion::Strap => { + value[0] = OTP_STRAP_PROT_ENBLE; + } + AspeedOtpRegion::ScuProtection => { + value[0] = OTP_STRAP_PROT_ENBLE; + } + } + self.otp_prog_conf(0, &value) + } + fn is_feature_supported(&self, feature: &str) -> Result { + Ok(false) + } + fn list_regions(&self) -> Result<&[AspeedOtpRegion], OtpError> { + Ok(REGION_IDS) + } + fn get_region_info(&self, region: AspeedOtpRegion) -> Result<(usize, usize, usize), OtpError> { + Ok(( + REGION_INFO[region as usize].start, + REGION_INFO[region as usize].cdw_size, + REGION_INFO[region as usize].alignment, + )) + } +} diff --git a/src/otp/common.rs b/src/otp/common.rs new file mode 100644 index 0000000..de93502 --- /dev/null +++ b/src/otp/common.rs @@ -0,0 +1,122 @@ +use proposed_traits::otp::*; +/// ASPEED chip version information +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum AspeedChipVersion { + /// AST1030 A0 revision + Ast1030A0, + /// AST1030 A1 revision + Ast1030A1, + /// AST1035 A1 revision + Ast1035A1, + /// AST1060 A1 revision + Ast1060A1, + /// AST1060 A2 revision + Ast1060A2, + /// Unknown or unsupported version + Unknown, +} + +/// Memory region types in ASPEED OTP +/// Data region: +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum AspeedOtpRegion { + /// Data region (2048 double-words, 0x0000-0x0FFF) + Data, + /// Configuration region (32 double-words, 0x800-0x81F) + Configuration, + /// Strap region (64 bits, multiple programming options) + Strap, + /// SCU protection region (2 double-words, 0x1C-0x1D) + ScuProtection, +} + +#[derive(Debug, Eq, PartialEq, Copy, Clone)] +#[non_exhaustive] +pub enum OtpError { + InvalidAddress, + InvalidBufSize, + MemoryLocked, + WriteFailed, + ReadFailed, + LockFailed, + VerificationFailed, + WriteExhausted, + NoSession, + RegionProtected, + AlignmentError, + BoundaryError, + Timeout, + UnknowRevID, + Unknown, +} +use crate::otp::common::OtpError::*; +impl proposed_traits::otp::Error for OtpError { + fn kind(&self) -> ErrorKind { + match *self { + Self::InvalidAddress => ErrorKind::InvalidAddress, + Self::MemoryLocked => ErrorKind::MemoryLocked, + Self::WriteFailed => ErrorKind::WriteFailed, + Self::ReadFailed => ErrorKind::ReadFailed, + Self::LockFailed => ErrorKind::LockFailed, + self::VerificationFailed => ErrorKind::VerificationFailed, + self::WriteExhausted => ErrorKind::WriteExhausted, + self::NoSession => ErrorKind::NoSession, + self::RegionProtected => ErrorKind::RegionProtected, + self::AlignmentError => ErrorKind::AlignmentError, + self::BoundaryError | self::InvalidBufSize => ErrorKind::BoundaryError, + self::Timeout => ErrorKind::Timeout, + Self::Unknown | self::UnknowRevID => ErrorKind::Unknown, + } + } +} + +/// Protection status for different OTP regions +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] +pub struct ProtectionStatus { + /// Memory lock status (prevents all modifications) + pub memory_locked: bool, + /// Key return protection status + pub key_protected: bool, + /// Strap region protection status + pub strap_protected: bool, + /// Configuration region protection status + pub config_protected: bool, + /// User region protection status + pub user_ecc_protected: bool, + /// Security region protection status + pub security_protected: bool, + /// Security region size in bytes + pub security_size: u32, +} + +/// Strap bit programming status +#[derive(Debug, Clone, Copy)] +pub struct StrapStatus { + /// Current strap bit value + pub value: bool, + /// Programming options available + pub options: [u8; 7], + /// Remaining write attempts + pub remaining_writes: u8, + /// Next writable option + pub writable_option: u8, + /// Protection status for this strap bit + pub protected: bool, +} + +/// Session information provided during OTP session establishment +#[derive(Debug, Clone)] +pub struct SessionInfo { + /// Chip version detected + pub chip_version: AspeedChipVersion, + /// Version name string + pub version_name: [u8; 10], + /// Current protection status + pub protection_status: ProtectionStatus, + /// Tool version information + pub tool_version: [u8; 32], + /// Software revision ID + pub software_revision: u32, + /// Number of cryptographic keys stored + pub key_count: u32, +} diff --git a/src/otp/hal.rs b/src/otp/hal.rs new file mode 100644 index 0000000..a6a9c1d --- /dev/null +++ b/src/otp/hal.rs @@ -0,0 +1,334 @@ +use crate::{ + common::Logger, + otp::{ + common::{ + AspeedChipVersion, AspeedOtpRegion, OtpError, ProtectionStatus, SessionInfo, + StrapStatus, + }, + OtpController, OTP_MEM_LIMIT, + }, +}; +use proposed_traits::otp::{ + OtpIdentification, OtpMemory, OtpMemoryLayout, OtpProtection, OtpRegions, OtpSession, +}; + +impl OtpMemory for OtpController { + /// + /// Read 1 DWORD + /// + fn read(&self, address: usize) -> Result { + let mut buffer: [u32; 1] = [0]; + if let Err(e) = self.read_region(AspeedOtpRegion::Data, address, &mut buffer) { + return Err(e); + } + Ok(buffer[0]) + } + fn write(&mut self, address: usize, data: u32) -> Result<(), Self::Error> { + let ignore_mask: [u32; 2] = [0, 0xffff_ffff]; + let mut buffer: [u32; 2] = [0, 0]; + let mut otp_data: [u32; 2] = [0, 0]; + if self.locked { + return Err(OtpError::MemoryLocked); + } + if address > OTP_MEM_LIMIT as usize { + return Err(OtpError::InvalidAddress); + } + otp_data[0] = self.read(address)?; + buffer[0] = data; + self.otp_prog_verify_2dw(address as u32, &otp_data, &buffer, &ignore_mask) + } + + fn lock(&mut self) -> Result<(), Self::Error> { + self.otp_lock_mem() + } + + fn is_locked(&self) -> bool { + self.is_otp_locked() + } +} + +impl OtpSession for OtpController { + type SessionInfo = SessionInfo; + /// Session information type returned when establishing a session + /// Establish an OTP session with hardware access + /// + /// # Returns + /// - `Ok(SessionInfo)`: Session established successfully + /// - `Err(Self::Error)`: Failed to establish session + fn begin_session(&mut self) -> Result { + if self.session_active { + return Err(OtpError::NoSession); + } + let ver_bytes = self.get_tool_verion(); + let mut session_info = SessionInfo { + chip_version: AspeedChipVersion::Ast1060A2, + version_name: *b"AST1060A2\0", + protection_status: ProtectionStatus { + memory_locked: false, + key_protected: false, + strap_protected: false, + config_protected: false, + user_ecc_protected: false, + security_protected: false, + security_size: 0, + }, + tool_version: [0; 32], + software_revision: 0x1234_5678, + key_count: 5, + }; + if ver_bytes.len() > session_info.tool_version.len() { + return Err(OtpError::BoundaryError); + } + self.update_prot_info(&mut session_info); + session_info.chip_version = self.chip_version(); + session_info.tool_version[..ver_bytes.len()].copy_from_slice(ver_bytes); + session_info.key_count = self.get_key_count() as u32; + + self.session_active = true; + + Ok(session_info) + } + + /// Terminate the OTP session and release resources + /// + /// # Returns + /// - `Ok(())`: Session terminated successfully + /// - `Err(Self::Error)`: Failed to terminate session properly + fn end_session(&mut self) -> Result<(), Self::Error> { + if !self.session_active { + return Err(OtpError::NoSession); + } + self.session_active = false; + Ok(()) + } + + /// Check if a session is currently active + fn is_session_active(&self) -> bool { + self.session_active + } +} + +impl OtpRegions for OtpController { + /// Region identifier type + type Region = AspeedOtpRegion; + + /// Read data from a specific OTP region + /// + /// # Parameters + /// - `region`: The region to read from + /// - `offset`: Offset within the region. For strap, it's strap_bit_offset + /// - `buffer`: Buffer to store read data + /// + /// # Returns + /// - `Ok(())`: Data read successfully + /// - `Err(Self::Error)`: Read operation failed + fn read_region( + &self, + region: Self::Region, + offset: usize, + buffer: &mut [u32], + ) -> Result<(), Self::Error> { + match region { + AspeedOtpRegion::Data => self.aspeed_otp_read_data(offset, buffer), + AspeedOtpRegion::Configuration => self.aspeed_otp_read_conf(offset as u32, buffer), + AspeedOtpRegion::Strap => { + if buffer.len() < 2 { + return Err(OtpError::InvalidBufSize); + } + let mut strap_status: [StrapStatus; 64] = [StrapStatus { + value: false, + protected: false, + options: [0; 7], + remaining_writes: 6, + writable_option: 0xff, + }; 64]; + match self.otp_strap_status(&mut strap_status) { + Ok(()) => { + buffer[0] = 0; + for i in 0usize..32 { + buffer[0] |= (strap_status[i].value as u32) << i; + } + buffer[1] = 0; + for i in 32usize..64 { + buffer[1] |= (strap_status[i].value as u32) << (i - 32); + } + return Ok(()); + } + Err(e) => { + return Err(e); + } + } + } + AspeedOtpRegion::ScuProtection => self.aspeed_otp_read_scuprot(offset, buffer), + } + } + + /// Write data to a specific OTP region + /// + /// # Parameters + /// - `region`: The region to write to + /// - `offset`: Offset within the region. For strap, it's strap_bit_offset + /// - `data`: Data to write + /// + /// # Returns + /// - `Ok(())`: Data written successfully + /// - `Err(Self::Error)`: Write operation failed + fn write_region( + &mut self, + region: Self::Region, + offset: usize, + data: &[u32], + ) -> Result<(), Self::Error> { + match region { + AspeedOtpRegion::Data => self.otp_prog_data(offset, data), + AspeedOtpRegion::Configuration => self.otp_prog_conf(offset, data), + AspeedOtpRegion::Strap => self.otp_prog_strap(offset, data), + AspeedOtpRegion::ScuProtection => self.otp_prog_scu_protect(offset, data), + } + } + /// Get the capacity of a specific region + /// + /// # Parameters + /// - `region`: The region to query + /// + /// # Returns + /// The capacity of the region in elements of type T + fn region_capacity(&self, region: Self::Region) -> usize { + self.region_capacity(region) + } + /// Get the alignment requirement for a specific region + /// + /// # Parameters + /// - `region`: The region to query + /// + /// # Returns + /// The alignment requirement in bytes + fn region_alignment(&self, region: Self::Region) -> usize { + self.region_alignment(region) + } +} + +impl OtpProtection for OtpController { + type Region = AspeedOtpRegion; + + /// Check if a specific region is protected + /// + /// # Parameters + /// - `region`: The region to check + /// + /// # Returns + /// - `Ok(bool)`: Protection status (true = protected) + /// - `Err(Self::Error)`: Failed to check protection status + fn is_region_protected(&self, region: Self::Region) -> Result { + self.is_region_protected(region) + } + + /// Enable protection for a specific region + /// + /// # Parameters + /// - `region`: The region to protect + /// + /// # Returns + /// - `Ok(())`: Protection enabled successfully + /// - `Err(Self::Error)`: Failed to enable protection + fn enable_region_protection(&mut self, region: Self::Region) -> Result<(), Self::Error> { + self.enable_region_protection(region) + } + + /// Check if the entire memory is globally locked + /// + /// # Returns + /// - `Ok(bool)`: Lock status (true = locked) + /// - `Err(Self::Error)`: Failed to check lock status + fn is_globally_locked(&self) -> Result { + Ok(self.is_otp_locked()) + } + + /// Enable global memory lock (typically irreversible) + /// + /// This operation permanently locks all OTP regions and usually cannot be undone. + /// Use with extreme caution. + /// + /// # Returns + /// - `Ok(())`: Global lock enabled successfully + /// - `Err(Self::Error)`: Failed to enable global lock + fn enable_global_lock(&mut self) -> Result<(), Self::Error> { + self.otp_lock_mem() + } +} + +impl OtpIdentification for OtpController { + /// Chip version or identifier type + type ChipVersion = AspeedChipVersion; + + /// Get the chip version or hardware identifier + /// + /// # Returns + /// - `Ok(ChipVersion)`: Hardware version information + /// - `Err(Self::Error)`: Failed to read chip identification + fn get_chip_version(&self) -> Result { + Ok(self.chip_version()) + } + + /// Check if a specific feature is supported by this chip version + /// + /// # Parameters + /// - `feature`: Feature identifier to check + /// + /// # Returns + /// - `Ok(bool)`: Feature support status (true = supported) + /// - `Err(Self::Error)`: Failed to check feature support + fn is_feature_supported(&self, feature: &str) -> Result { + self.is_feature_supported(feature) + } +} + +impl OtpMemoryLayout for OtpController { + /// Region identifier type + type Region = AspeedOtpRegion; + + /// Get the total memory capacity in bytes + fn total_capacity(&self) -> usize { + self.total_capacity() + } + + /// Get the minimum alignment requirement for write operations + /// + /// # Returns + /// Alignment requirement in bytes (e.g., 1, 4, 8) + fn write_alignment(&self) -> usize { + 4 + } + + /// Get the size of the minimum programmable unit + /// + /// # Returns + /// Size in bytes of the smallest unit that can be programmed independently + fn programming_granularity(&self) -> usize { + 4 + } + + /// List all available memory regions + /// + /// Returns an iterator over available regions. The exact collection type + /// depends on the implementation (could be array, slice, or heap-allocated). + /// + /// # Returns + /// - `Ok(regions)`: Iterator over available regions + /// - `Err(Self::Error)`: Failed to enumerate regions + fn list_regions(&self) -> Result<&[Self::Region], Self::Error> { + self.list_regions() + } + + /// Get detailed information about a specific region + /// + /// # Parameters + /// - `region`: The region to query + /// + /// # Returns + /// - `Ok((start_addr, size, alignment))`: Region details + /// - `Err(Self::Error)`: Failed to get region information + fn get_region_info(&self, region: Self::Region) -> Result<(usize, usize, usize), Self::Error> { + self.get_region_info(region) + } +} diff --git a/src/tests/functional/mod.rs b/src/tests/functional/mod.rs index f37c0d5..370b23f 100644 --- a/src/tests/functional/mod.rs +++ b/src/tests/functional/mod.rs @@ -5,6 +5,7 @@ pub mod gpio_test; pub mod hash_test; pub mod hmac_test; pub mod i2c_test; +pub mod otp_test; pub mod rsa_test; pub mod rsa_test_vec; pub mod timer_test; diff --git a/src/tests/functional/otp_test.rs b/src/tests/functional/otp_test.rs new file mode 100644 index 0000000..78cb6cd --- /dev/null +++ b/src/tests/functional/otp_test.rs @@ -0,0 +1,567 @@ +// Licensed under the Apache-2.0 license + +use crate::common::{DummyDelay, Logger, UartLogger}; +use crate::otp::common::{AspeedOtpRegion, StrapStatus}; +use crate::otp::{ + OtpController, OTP_CONF_OFFSET, OTP_CONF_PROT_ENBLE, OTP_KEY_PROT_ENBLE, OTP_MEM_LOCK_ENBLE, + OTP_SECURE_SIZE_BIT_POS, OTP_STRAP_PROT_ENBLE, OTP_USER_ECC_PROT_ENBLE, +}; +use crate::uart::{self, Config, UartController}; +use ast1060_pac::Peripherals; +use embedded_io::Write; +use proposed_traits::otp::OtpRegions; + +/// OTPCFG in OTP memory +/// OTPCFG0-31 +fn test_otp_read_conf( + uart: &mut UartController<'_>, + otp: &mut OtpController, + conf_reg: u32, +) { + writeln!(uart, "########## test read OTPCFG ######\r").unwrap(); + + let mut data: [u32; 32] = [0; 32]; + match otp.read_region(AspeedOtpRegion::Configuration, 0, &mut data) { + Ok(()) => { + for i in 0..data.len() { + writeln!( + uart, + "read OTPCFG{:#x} ok: {:#x}\r", + conf_reg + u32::try_from(i).unwrap(), + data[i] + ) + .unwrap(); + } + } + Err(e) => { + writeln!(uart, "read OTPCFG{:#x} err: {e:?}\r", conf_reg).unwrap(); + } + } +} + +fn test_otp_write_conf_b( + uart: &mut UartController<'_>, + otp: &mut OtpController, + otp_addr: u32, + otp_bit_offset: u32, + otp_value: u32, +) { + let mut conf0: u32 = 0; + read_otp_conf(uart, otp, 0, &mut conf0); + if conf0 & OTP_MEM_LOCK_ENBLE != 0 { + writeln!(uart, "OTP memory is locked!\r").unwrap(); + return; + } + if otp_addr != 4 && otp_addr != 10 && otp_addr != 11 && otp_addr < 16 { + if conf0 & OTP_CONF_PROT_ENBLE != 0 { + writeln!(uart, "OTP config region is protected!\r").unwrap(); + return; + } + } else if otp_addr == 10 || otp_addr == 11 { + let mut otp_rid: [u32; 2] = [0, 0]; + let mut sw_rid: [u32; 2] = [0, 0]; + read_otp_conf(uart, otp, 10, &mut otp_rid[0]); + read_otp_conf(uart, otp, 11, &mut otp_rid[1]); + otp.get_sw_revision(&mut sw_rid); + + if otp_addr == 10 { + otp_rid[0] |= 1 << otp_bit_offset; + } else { + otp_rid[1] |= 1 << otp_bit_offset; + } + + if otp_rid[1] > sw_rid[1] { + writeln!( + uart, + "update revision id should not be bigger than current SW revision id!\r" + ) + .unwrap(); + return; + } + if otp_rid[1] == sw_rid[1] || otp_rid[0] > sw_rid[0] { + writeln!( + uart, + "update revision id should not be bigger than current SW revision id!\r" + ) + .unwrap(); + return; + } + } else if otp_addr == 4 { + if conf0 & OTP_KEY_PROT_ENBLE != 0 { + writeln!(uart, "OTPCFG4 is protected!\r").unwrap(); + return; + } + if (otp_bit_offset <= 7) || (otp_bit_offset >= 16 && otp_bit_offset <= 23) { + let key_num = otp.get_key_count(); + let retire: u32; + if otp_bit_offset >= 16 { + retire = otp_bit_offset - 16; + } else { + retire = otp_bit_offset; + } + if retire >= u32::from(key_num) { + writeln!( + uart, + "retire key is equal or greater than current boot key!\r" + ) + .unwrap(); + return; + } + } + } else if otp_addr >= 16 && otp_addr <= 31 { + if conf0 & OTP_STRAP_PROT_ENBLE != 0 { + writeln!(uart, "OTP strap region is protected!\r").unwrap(); + return; + } + if otp_addr < 28 { + let mut otp_strap_pro: u32 = 0; + if otp_addr % 2 == 0 { + read_otp_conf(uart, otp, 30, &mut otp_strap_pro); + } else { + read_otp_conf(uart, otp, 31, &mut otp_strap_pro); + } + if otp_strap_pro >> otp_bit_offset & 1 != 0 { + writeln!( + uart, + "OTPCFG{:#x}[{:#x}] is protected!\r", + otp_addr, otp_bit_offset + ) + .unwrap(); + } + } + } + let mut conf: u32 = 0; + read_otp_conf(uart, otp, otp_addr, &mut conf); + if (conf >> otp_bit_offset & 0x1) == otp_value { + writeln!( + uart, + "OTPCFG{:#x}[{:#x}] = 1; no need to program\r", + otp_addr, otp_bit_offset + ) + .unwrap(); + return; + } + if (conf >> otp_bit_offset & 0x1) == 1 && otp_value == 0 { + writeln!( + uart, + "OTPCFG{:#x}[{:#x}] = 1; cannot be cleared\r", + otp_addr, otp_bit_offset + ) + .unwrap(); + return; + } + let mut prog_addr: u32 = OTP_CONF_OFFSET; + prog_addr |= (otp_addr / 8) * 0x200; + prog_addr |= (otp_addr % 8) * 0x2; + match otp.otp_prog_dc_b(otp_value, prog_addr, otp_bit_offset) { + Ok(()) => { + writeln!( + uart, + "program OTPCFG{:#x}[{:#x}] successfully!\r", + otp_addr, otp_bit_offset + ) + .unwrap(); + } + Err(e) => { + writeln!(uart, "program OTPCFG{:#x} err: {e:?}\r", otp_addr).unwrap(); + } + } +} + +fn test_otp_write_conf_d( + uart: &mut UartController<'_>, + otp: &mut OtpController, + offset: u8, +) { + let mut data: [u32; 2] = [0xabcd_beef, 0x1234_5678]; + + match otp.write_region(AspeedOtpRegion::Configuration, offset as usize, &mut data) { + Ok(()) => { + writeln!(uart, "write OTPCONF{:#x} success\r", offset).unwrap(); + } + Err(e) => { + writeln!(uart, "write OTPCONF{:#x} err: {e:?}\r", offset).unwrap(); + } + } +} + +fn read_otp_conf( + uart: &mut UartController<'_>, + otp: &mut OtpController, + idx: u32, + conf: &mut u32, +) { + let mut data = [0; 1]; + match otp.read_region(AspeedOtpRegion::Configuration, idx as usize, &mut data) { + Ok(()) => { + *conf = data[0]; + } + Err(e) => { + writeln!(uart, "read OTPCFG0x0 err: {e:?}\r").unwrap(); + } + } +} + +fn read_otp_data( + uart: &mut UartController<'_>, + otp: &mut OtpController, + offset: u32, + data: &mut [u32], +) { + if let Err(e) = otp.read_region(AspeedOtpRegion::Data, 0, data) { + writeln!(uart, "read OTPDATA{:#x} err: {e:?}\r", offset).unwrap(); + } +} + +fn test_otp_write_strap_b( + uart: &mut UartController<'_>, + otp: &mut OtpController, + bit_offset: u8, + value: u8, +) { + writeln!(uart, "########## test write OTPSTRAP ######\r").unwrap(); + if bit_offset >= 64 || (value != 0 && value != 1) { + writeln!(uart, "invalid offset or program value\r").unwrap(); + return; + } + + let mut conf0: u32 = 0; + read_otp_conf(uart, otp, 0, &mut conf0); + if conf0 & OTP_MEM_LOCK_ENBLE != 0 { + writeln!(uart, "OTP memory is locked!\r").unwrap(); + return; + } + + if conf0 & OTP_STRAP_PROT_ENBLE != 0 { + writeln!(uart, "OTP strap region is protected!\r").unwrap(); + return; + } + + let mut strap_status: [StrapStatus; 64] = [StrapStatus { + value: false, + protected: false, + options: [0; 7], + remaining_writes: 6, + writable_option: 0xff, + }; 64]; + if let Err(e) = otp.otp_strap_status(&mut strap_status) { + writeln!(uart, "otp_strap_status error: {e:?}\r").unwrap(); + return; + } + //test_otp_read_strap(uart, otp, u32::from(bit_offset), 1); + if value == strap_status[bit_offset as usize].value as u8 { + writeln!(uart, "The value is same as before.\r").unwrap(); + return; + } + if strap_status[bit_offset as usize].protected { + writeln!(uart, "This bit is protected and is not writable.\r").unwrap(); + return; + } + if strap_status[bit_offset as usize].remaining_writes == 0 { + writeln!(uart, "This bit has no remaining chance to write.\r").unwrap(); + return; + } + writeln!( + uart, + "Write 1 to OTPSTRAP[{:#x}] OPTION[{:#x}], that value changes from {:#x} to {:#x} \r", + bit_offset, + strap_status[bit_offset as usize].writable_option + 1, + strap_status[bit_offset as usize].value as u8, + strap_status[bit_offset as usize].value as u8 ^ 1 + ) + .unwrap(); + + let mut prog_addr: u32 = OTP_CONF_OFFSET; + let offset: u32; + if bit_offset < 32 { + offset = u32::from(bit_offset); + prog_addr |= + ((u32::from(strap_status[bit_offset as usize].writable_option) * 2 + 16) / 8) * 0x200; + prog_addr |= + ((u32::from(strap_status[bit_offset as usize].writable_option) * 2 + 16) % 8) * 0x2; + } else { + offset = u32::from(bit_offset) - 32; + prog_addr |= + ((u32::from(strap_status[bit_offset as usize].writable_option) * 2 + 17) / 8) * 0x200; + prog_addr |= + ((u32::from(strap_status[bit_offset as usize].writable_option) * 2 + 17) % 8) * 0x2; + } + match otp.otp_prog_dc_b(1, prog_addr, offset) { + Ok(()) => { + writeln!(uart, "program OTPSTRAP[{:#x}] successfully!\r", offset).unwrap(); + } + Err(e) => { + writeln!(uart, "program OTPSTRAP err: {e:?}\r").unwrap(); + } + } +} + +fn test_otp_write_strap_d( + uart: &mut UartController<'_>, + otp: &mut OtpController, + start_bit: usize, + strap: &[u32], +) { + writeln!( + uart, + "OTPSTRAP start_bit {:}, strap = {:?}\r", + start_bit, strap + ) + .unwrap(); + match otp.write_region(AspeedOtpRegion::Strap, start_bit, &strap) { + Ok(()) => { + writeln!(uart, "program OTPSTRAP dword success\r").unwrap(); + } + Err(e) => { + writeln!(uart, "program OTPSTRAP dword err: {e:?}\r").unwrap(); + } + } +} + +fn test_otp_read_strap( + uart: &mut UartController<'_>, + otp: &mut OtpController, + start: u32, + count: u32, +) { + writeln!(uart, "########## test read OTPSTRAP ######\r").unwrap(); + let remains: u32 = 6; + let mut strap_status: [StrapStatus; 64] = [StrapStatus { + value: false, + protected: false, + options: [0; 7], + remaining_writes: 6, + writable_option: 0xff, + }; 64]; + writeln!(uart, "BIT(hex) Value Option Status\r").unwrap(); + writeln!(uart, "------------------------------------------\r").unwrap(); + if otp.otp_strap_status(&mut strap_status).is_ok() { + for i in start..start + count { + write!( + uart, + "0x{:<8x} {:<7} ", + i, strap_status[i as usize].value as u8 + ) + .unwrap(); + for j in 0..remains { + write!(uart, "{} ", strap_status[i as usize].options[j as usize]).unwrap(); + } + write!(uart, " ").unwrap(); + if strap_status[i as usize].protected { + writeln!(uart, "protected and not writable").unwrap(); + } else { + write!(uart, "not protected ").unwrap(); + if strap_status[i as usize].remaining_writes == 0 { + writeln!(uart, "and no remaining times to write.\r").unwrap(); + } else { + writeln!( + uart, + "and still can write {} times.\r", + strap_status[i as usize].remaining_writes + ) + .unwrap(); + } + } + } + } else { + writeln!(uart, "read otp strap fail!\r").unwrap(); + } + + // trait API + let mut buffer: [u32; 2] = [0, 0]; + match otp.read_region(AspeedOtpRegion::Strap, 0, &mut buffer) { + Ok(()) => { + writeln!(uart, "read OTPSTRAP {:?}\r", buffer).unwrap(); + } + Err(e) => { + writeln!(uart, "read OTPSTRAP err: {e:?}\r").unwrap(); + } + } +} + +fn test_otp_write_data_b( + uart: &mut UartController<'_>, + otp: &mut OtpController, + otp_addr: u32, + bit_offset: u32, + value: u32, +) { + let mut conf0: u32 = 0; + read_otp_conf(uart, otp, 0, &mut conf0); + if conf0 & OTP_MEM_LOCK_ENBLE != 0 { + writeln!(uart, "OTP memory is locked!\r").unwrap(); + return; + } + let sec_area_size = (conf0 >> OTP_SECURE_SIZE_BIT_POS) & 0x3f; + if sec_area_size == 0 { + if conf0 & OTP_USER_ECC_PROT_ENBLE != 0 { + writeln!(uart, "OTP data region is protected!\r").unwrap(); + return; + } + } else if otp_addr < sec_area_size && otp_addr > 16 { + writeln!( + uart, + "OTP secure region is not readable, skip it to prevent unpredictable result!\r" + ) + .unwrap(); + return; + } else if otp_addr < sec_area_size { + writeln!(uart, "OTP secure region is protected!\r").unwrap(); + return; + } else if conf0 & OTP_USER_ECC_PROT_ENBLE != 0 { + writeln!(uart, "OTP data region is protected!\r").unwrap(); + return; + } + + let mut data: [u32; 2] = [0; 2]; + let otp_bit: u32; + if otp_addr % 2 == 0 { + read_otp_data(uart, otp, otp_addr, &mut data); + otp_bit = (data[0] >> bit_offset) & 0x1; + if otp_bit == 1 && value == 0 { + writeln!(uart, "OTPDATA{:#x}[{:#x}] = 1\r", otp_addr, bit_offset).unwrap(); + writeln!(uart, "OTP is programmed, which can't be cleared!\r").unwrap(); + return; + } + } else { + read_otp_data(uart, otp, otp_addr - 1, &mut data); + otp_bit = (data[1] >> bit_offset) & 0x1; + if otp_bit == 0 && value == 1 { + writeln!(uart, "OTPDATA{:#x}[{:#x}] = 1\r", otp_addr, bit_offset).unwrap(); + writeln!(uart, "OTP is programmed, which can't be written!\r").unwrap(); + return; + } + } + + if otp_bit == value { + writeln!( + uart, + "OTPDATA{:#x}[{:#x}] = {}\r", + otp_addr, bit_offset, value + ) + .unwrap(); + writeln!(uart, "No need to program!\r").unwrap(); + return; + } + + writeln!( + uart, + "Program OTPDATA{:#x}[{:#x}] to {}\r", + otp_addr, bit_offset, value + ) + .unwrap(); + + match otp.otp_prog_dc_b(value, otp_addr, bit_offset) { + Ok(()) => { + writeln!( + uart, + "program OTPDATA{:#x}[{:#x}] successfully!\r", + otp_addr, bit_offset + ) + .unwrap(); + } + Err(e) => { + writeln!( + uart, + "program OTPDATA{:#x}[{:#x}] err: {e:?}\r", + otp_addr, bit_offset + ) + .unwrap(); + } + } +} + +fn test_otp_write_data_d( + uart: &mut UartController<'_>, + otp: &mut OtpController, + otp_addr: u32, + data: &[u32], +) { + match otp.write_region(AspeedOtpRegion::Data, otp_addr as usize, data) { + Ok(()) => { + writeln!(uart, "write OTPDATA{:#x} success\r", otp_addr).unwrap(); + } + Err(e) => { + writeln!(uart, "write OTPDATA{:#x} err: {e:?}\r", otp_addr).unwrap(); + } + } +} + +fn test_otp_read_data( + uart: &mut UartController<'_>, + otp: &mut OtpController, + conf_reg: u32, +) { + writeln!(uart, "########## test read OTPDATA ######\r").unwrap(); + + let mut data: [u32; 32] = [0; 32]; + match otp.read_region(AspeedOtpRegion::Data, 0, &mut data) { + Ok(()) => { + for i in 0..data.len() { + writeln!( + uart, + "read OTPDATA{:#x} ok: {:#x}\r", + conf_reg + u32::try_from(i).unwrap(), + data[i as usize] + ) + .unwrap(); + } + } + Err(e) => { + writeln!(uart, "read OTPDATA{:#x} err: {e:?}\r", conf_reg).unwrap(); + } + } +} + +pub fn test_otp(uart: &mut UartController<'_>) { + let peripherals = unsafe { Peripherals::steal() }; + let scu = peripherals.scu; + let mut delay = DummyDelay {}; + let mut dbg_uart = UartController::new(peripherals.uart, &mut delay); + unsafe { + dbg_uart.init(&Config { + baud_rate: 115_200, + word_length: uart::WordLength::Eight as u8, + parity: uart::Parity::None, + stop_bits: uart::StopBits::One, + clock: 24_000_000, + }); + } + let mut otp_controller = OtpController::new(scu, UartLogger::new(&mut dbg_uart)); + //otp_controller.otp_unlock_reg(); + + //test otpcfg + if false { + test_otp_read_conf(uart, &mut otp_controller, 0); + //test_otp_write_conf_b(uart, &mut otp_controller, 0, 5, 1); + //test_otp_write_conf_b(uart, &mut otp_controller, 0, 5, 1); + //test_otp_write_conf_b(uart, &mut otp_controller, 0, 5, 0); + test_otp_write_conf_d(uart, &mut otp_controller, 5); + test_otp_read_conf(uart, &mut otp_controller, 0); + } + + //test otpstrap + if true { + test_otp_read_strap(uart, &mut otp_controller, 0, 32); + for i in 1u8..8 { + test_otp_write_strap_b(uart, &mut otp_controller, 0, i & 0x1); + } + + //let strap: [u32; 2] = [0xffff_ffff, 0xffff_ffff]; + //test_otp_write_strap_d(uart, &mut otp_controller, 30, &strap); + + test_otp_read_strap(uart, &mut otp_controller, 0, 64); + } + + //test otpdata + if false { + test_otp_read_data(uart, &mut otp_controller, 0); + //test_otp_write_data_b(uart, &mut otp_controller, 0, 0, 0); + + let data = [0xabcd_dead, 0x1234_5678]; + test_otp_write_data_d(uart, &mut otp_controller, 4, &data); + test_otp_read_data(uart, &mut otp_controller, 0); + } + + //otp_controller.otp_lock_reg(); +} From a09e343dac3fc279d8b397171aabd5cb09837df6 Mon Sep 17 00:00:00 2001 From: "linlin.xu" Date: Tue, 12 Aug 2025 17:42:29 -0700 Subject: [PATCH 2/3] Fix clippy errors. --- src/main.rs | 5 + src/otp.rs | 158 +++++++++++++++---------------- src/otp/common.rs | 7 +- src/otp/hal.rs | 31 +++--- src/tests/functional/otp_test.rs | 10 +- 5 files changed, 110 insertions(+), 101 deletions(-) diff --git a/src/main.rs b/src/main.rs index 0587686..2779e8b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,6 +22,7 @@ use aspeed_ddk::tests::functional::gpio_test; use aspeed_ddk::tests::functional::hash_test::run_hash_tests; use aspeed_ddk::tests::functional::hmac_test::run_hmac_tests; use aspeed_ddk::tests::functional::i2c_test; +use aspeed_ddk::tests::functional::otp_test; use aspeed_ddk::tests::functional::rsa_test::run_rsa_tests; use aspeed_ddk::tests::functional::timer_test::run_timer_tests; use panic_halt as _; @@ -171,6 +172,10 @@ fn main() -> ! { test_wdt(&mut uart_controller); run_timer_tests(&mut uart_controller); + if false { + otp_test::test_otp(&mut uart_controller); + } + let test_spicontroller = false; if test_spicontroller { spi::spitest::test_fmc(&mut uart_controller); diff --git a/src/otp.rs b/src/otp.rs index 1af7199..5aa3d52 100644 --- a/src/otp.rs +++ b/src/otp.rs @@ -1,6 +1,6 @@ use crate::{ common::{DummyDelay, Logger}, - otp::common::*, + otp::common::{AspeedChipVersion, AspeedOtpRegion, OtpError, SessionInfo, StrapStatus}, }; use ast1060_pac::{Scu, Secure}; use core::fmt::Debug; @@ -57,17 +57,17 @@ const ID0_AST1060A2: u32 = 0xA003_0000; const ID1_AST1060A2: u32 = 0xA003_0000; const ID0_AST1060A2_ENG: u32 = 0x8003_0000; const ID1_AST1060A2_ENG: u32 = 0x8003_0000; -const OTP_AST1060A1: u32 = 3; -const OTP_AST1060A2: u32 = 4; +//const OTP_AST1060A1: u32 = 3; +//const OTP_AST1060A2: u32 = 4; const OTP_PASSWD: u32 = 0x349f_e38a; const OTP_READ_CMD: u32 = 0x23b1_e361; const OTP_WRITE_CMD: u32 = 0x23b1_e362; -const OTP_COMP_CMD: u32 = 0x23b1_e363; +//const OTP_COMP_CMD: u32 = 0x23b1_e363; const OTP_PROG_CMD: u32 = 0x23b1_e364; const OTP_MEM_LIMIT: u32 = 2144; //67kbits const OTP_MEM_LIMIT_DATA: usize = 2048; -const OTP_MEM_ECC_OFFSET: u32 = 1792; //DWORD +//const OTP_MEM_ECC_OFFSET: u32 = 1792; //DWORD /// timing const OTP_TIMING_200US: u32 = 0x0419_1388; @@ -291,7 +291,7 @@ impl OtpController { pub fn otp_read_data_region(&self) -> Result<(), OtpError> { for i in (0..OTP_MEM_LIMIT_DATA).step_by(2) { unsafe { - self.otp_read_data(i as u32, &mut DATA_REGION[i..i + 1])?; + self.otp_read_data(u32::try_from(i).unwrap(), &mut DATA_REGION[i..=i])?; } } Ok(()) @@ -315,8 +315,8 @@ impl OtpController { /// # Arguments /// /// * `reg_idx` - OTPCFG register number eg. 1-OTPCFG1 - /// The address offset: 0x800 (OTPFCG0),0x802 (OTPFCG1) - /// A00(OTPCFG8-15), C00(OTPCFG16-31) + /// The address offset: 0x800 (OTPFCG0),0x802 (OTPFCG1) + /// A00(OTPCFG8-15), C00(OTPCFG16-31) fn otp_read_conf_idx(&self, reg_idx: u32) -> Result { let mut addr = OTP_CONF_OFFSET; @@ -333,12 +333,13 @@ impl OtpController { self.sb .secure004() .write(|w| unsafe { w.bits(OTP_PROG_CMD) }); - if !self.wait_complete() { - Err(OtpError::Timeout) - } else { + if self.wait_complete() { Ok(()) + } else { + Err(OtpError::Timeout) } } else { + otp_error!(self.logger, "otp_prog failed"); Err(OtpError::WriteFailed) } } @@ -383,14 +384,13 @@ impl OtpController { } fn verify_bit(&mut self, value: u32, otp_addr: u32, bit_offset: u32) -> Result<(), OtpError> { let mut ret: [u32; 2] = [0, 0]; - let addr: u32; let mut success: bool = false; - if otp_addr & 0x1 == 0 { - addr = otp_addr; + let addr: u32 = if otp_addr & 0x1 == 0 { + otp_addr } else { //make it even - addr = otp_addr - 1; - } + otp_addr - 1 + }; self.otp_read_data(addr, &mut ret)?; if otp_addr & 0x1 == 0 { @@ -423,7 +423,7 @@ impl OtpController { self.otp_soak(OtpSoak::NormalProg); self.otp_prog_bit_helper(value, address, bit_offset)?; for _i in 0..OTP_OP_RETRIES { - if !self.verify_bit(value, address, bit_offset).is_ok() { + if self.verify_bit(value, address, bit_offset).is_err() { self.otp_soak(OtpSoak::SoakProg); self.otp_prog_bit_helper(value, address, bit_offset)?; if self.verify_bit(value, address, bit_offset).is_ok() { @@ -482,14 +482,14 @@ impl OtpController { /// pub fn verify_dw(&self, address: u32, data: u32, ignore: u32, compare: &mut u32) -> bool { let mut ret: [u32; 2] = [0, 0]; - let addr; + let otp_addr = address & !(1 << 15); - if otp_addr & 0x1 == 0 { - addr = otp_addr; + let addr = if otp_addr & 0x1 == 0 { + otp_addr } else { - addr = otp_addr - 1; - } + otp_addr - 1 + }; if self.otp_read_data(addr, &mut ret) != Ok(()) { return false; } @@ -627,7 +627,10 @@ impl OtpController { } pass = false; for _j in 0..OTP_OP_RETRIES { - if !self.verify_2dw(address, buffer, &ignore_mask, verify_size, &mut compare) { + if self.verify_2dw(address, buffer, &ignore_mask, verify_size, &mut compare) { + pass = true; + break; + } else { self.otp_soak(OtpSoak::SoakProg); if compare[0] != 0 { self.otp_prog_dw(compare[0], ignore_mask[0], address)?; @@ -641,9 +644,6 @@ impl OtpController { pass = true; break; } - } else { - pass = true; - break; } } if !pass { @@ -661,21 +661,21 @@ impl OtpController { let mut pass: bool = false; for _j in 0..OTP_OP_RETRIES { - if !self.verify_dw(addr, data, ignore, &mut compare) { + if self.verify_dw(addr, data, ignore, &mut compare) { + pass = true; + break; + } else { self.otp_soak(OtpSoak::SoakProg); if let Err(_e) = self.otp_prog_dw(compare, ignore, addr) { pass = false; break; } - if !self.verify_dw(addr, data, ignore, &mut compare) { - self.otp_soak(OtpSoak::NormalProg); - } else { + if self.verify_dw(addr, data, ignore, &mut compare) { pass = true; break; + } else { + self.otp_soak(OtpSoak::NormalProg); } - } else { - pass = true; - break; } } pass @@ -694,7 +694,6 @@ impl OtpController { let mut addr: u32; let len: usize = buffer.len(); let mut pass: bool; - let compare: u32 = 0; if address + len > OTP_MEM_LIMIT_DATA || address & 0x3 != 0 { return Err(OtpError::InvalidAddress); @@ -702,7 +701,7 @@ impl OtpController { self.otp_unlock_reg(); for i in 0..len { - addr = (address + i) as u32; + addr = u32::try_from(address + i).unwrap(); self.otp_soak(OtpSoak::NormalProg); result = self.otp_prog_dw(buffer[i], ignore, addr); if result != Ok(()) { @@ -876,8 +875,8 @@ impl OtpController { let idx = (i - offset) as usize; buffer[idx] = match self.otp_read_conf_idx(i) { Ok(value) => value, - Err(_e) => { - result = Err(_e); + Err(e) => { + result = Err(e); break; } }; @@ -909,7 +908,7 @@ impl OtpController { let idx = i - offset; buf[idx] = 0; for j in 0..32 { - buf[idx] |= (strap_status[i * 32 + j].value as u32) << j; + buf[idx] |= u32::from(strap_status[i * 32 + j].value) << j; } } } @@ -938,10 +937,10 @@ impl OtpController { if result == Ok(()) { for i in offset..offset + cdw_len { let idx = i - offset; - buffer[idx] = match self.otp_read_conf_idx(28 + offset as u32) { + buffer[idx] = match self.otp_read_conf_idx(28 + u32::try_from(offset).unwrap()) { Ok(value) => value, - Err(_e) => { - result = Err(_e); + Err(e) => { + result = Err(e); break; } }; @@ -973,7 +972,10 @@ impl OtpController { let idx0 = i - offset; let idx1 = i; unsafe { - result = self.otp_read_data(idx1 as u32, &mut DATA_REGION[idx1..idx1 + 2]); + result = self.otp_read_data( + u32::try_from(idx1).unwrap(), + &mut DATA_REGION[idx1..idx1 + 2], + ); if result != Ok(()) { otp_debug!( self.logger, @@ -984,7 +986,7 @@ impl OtpController { } otp_debug!(self.logger, "otp_prog_data: idx0={:}, idx1={:}", idx0, idx1); result = self.otp_prog_verify_2dw( - i as u32, + u32::try_from(i).unwrap(), &DATA_REGION[idx1..idx1 + 2], &data[idx0..idx0 + 2], &ignore, @@ -1029,22 +1031,22 @@ impl OtpController { for i in start_bit..64 { prog_address = OTP_CONF_OFFSET; if i < 32 { - offset = i as u32; - bit = (strap[0] >> (offset - start_bit as u32)) & 0x1; - prog_address |= ((os[i].writable_option as u32 * 2 + 16) / 8) * 0x200; - prog_address |= ((os[i].writable_option as u32 * 2 + 16) % 8) * 0x2; + offset = u32::try_from(i).unwrap(); + bit = (strap[0] >> (offset - u32::try_from(start_bit).unwrap())) & 0x1; + prog_address |= ((u32::from(os[i].writable_option) * 2 + 16) / 8) * 0x200; + prog_address |= ((u32::from(os[i].writable_option) * 2 + 16) % 8) * 0x2; } else { - offset = (i - 32) as u32; + offset = u32::try_from(i - 32).unwrap(); if i - start_bit < 32 { bit = (strap[0] >> offset) & 0x1; } else { - bit = (strap[1] >> (offset - start_bit as u32)) & 0x1; + bit = (strap[1] >> (offset - u32::try_from(start_bit).unwrap())) & 0x1; } - prog_address |= ((os[i].writable_option as u32 * 2 + 17) / 8) * 0x200; - prog_address |= ((os[i].writable_option as u32 * 2 + 17) % 8) * 0x2; + prog_address |= ((u32::from(os[i].writable_option) * 2 + 17) / 8) * 0x200; + prog_address |= ((u32::from(os[i].writable_option) * 2 + 17) % 8) * 0x2; } //check if program bit value is the same as the programmed bit value - if bit == os[i].value as u32 { + if bit == u32::from(os[i].value) { prog_flag = 0; //no need to proram otp_debug!(self.logger, "otp_prog_strap: bit {:} no need to program", i); } else { @@ -1053,7 +1055,7 @@ impl OtpController { self.logger, "otp_prog_strap: program bit {:} from {:} to {:}", i, - os[i].value as u32, + u32::from(os[i].value), bit ); } @@ -1069,8 +1071,8 @@ impl OtpController { if prog_flag == 1 { match self.otp_prog_dc_b(1, prog_address, offset) { Ok(()) => {} - Err(_e) => { - return Err(_e); + Err(e) => { + return Err(e); } } } @@ -1104,10 +1106,10 @@ impl OtpController { //from 0 let idx = i - start_conf; //read conf from OTP - otp_conf = match self.otp_read_conf_idx(i as u32) { + otp_conf = match self.otp_read_conf_idx(u32::try_from(i).unwrap()) { Ok(value) => value, - Err(_e) => { - result = Err(_e); + Err(e) => { + result = Err(e); break; } }; @@ -1122,11 +1124,11 @@ impl OtpController { continue; } self.otp_soak(OtpSoak::NormalProg); - result = self.otp_prog_dw(conf[idx], conf_ignore, addr as u32); + result = self.otp_prog_dw(conf[idx], conf_ignore, u32::try_from(addr).unwrap()); if result != Ok(()) { break; } - pass = self.otp_prog_verify_retry(addr as u32, conf[idx], conf_ignore); + pass = self.otp_prog_verify_retry(u32::try_from(addr).unwrap(), conf[idx], conf_ignore); if !pass { break; @@ -1172,9 +1174,9 @@ impl OtpController { continue; } self.otp_soak(OtpSoak::Default); - self.otp_prog_dw(otp_scu[idx], ignore, addr as u32)?; + self.otp_prog_dw(otp_scu[idx], ignore, u32::try_from(addr).unwrap())?; - pass = self.otp_prog_verify_retry(addr as u32, otp_scu[idx], ignore); + pass = self.otp_prog_verify_retry(u32::try_from(addr).unwrap(), otp_scu[idx], ignore); if !pass { break; @@ -1199,15 +1201,16 @@ impl OtpController { pub fn region_capacity(&self, region: AspeedOtpRegion) -> usize { REGION_INFO[region as usize].cdw_size << 2 } + #[allow(clippy::unused_self)] fn region_alignment(&self, region: AspeedOtpRegion) -> usize { REGION_INFO[region as usize].alignment } - + #[allow(clippy::match_same_arms)] fn is_region_protected(&self, region: AspeedOtpRegion) -> Result { let mut protected: bool = false; self.otp_unlock_reg(); - let otp_conf: u32 = self.otp_read_conf_idx(0).unwrap_or_default(); + let otp_conf: u32 = self.otp_read_conf_idx(0)?; self.otp_lock_reg(); match region { AspeedOtpRegion::Data => { @@ -1218,7 +1221,7 @@ impl OtpController { } } AspeedOtpRegion::Configuration => { - if otp_conf & OTP_STRAP_PROT_ENBLE == OTP_STRAP_PROT_ENBLE { + if otp_conf & OTP_CONF_PROT_ENBLE == OTP_CONF_PROT_ENBLE { protected = true; } } @@ -1227,11 +1230,7 @@ impl OtpController { protected = true; } } - AspeedOtpRegion::ScuProtection => { - if otp_conf & OTP_STRAP_PROT_ENBLE == OTP_STRAP_PROT_ENBLE { - protected = true; - } - } + AspeedOtpRegion::ScuProtection => {} } Ok(protected) } @@ -1255,28 +1254,27 @@ impl OtpController { value[0] = OTP_USER_ECC_PROT_ENBLE | OTP_SECURE_PROT_ENBLE; } AspeedOtpRegion::Configuration => { - value[0] = OTP_STRAP_PROT_ENBLE; + value[0] = OTP_CONF_PROT_ENBLE; } AspeedOtpRegion::Strap => { value[0] = OTP_STRAP_PROT_ENBLE; } - AspeedOtpRegion::ScuProtection => { - value[0] = OTP_STRAP_PROT_ENBLE; - } + AspeedOtpRegion::ScuProtection => {} } self.otp_prog_conf(0, &value) } - fn is_feature_supported(&self, feature: &str) -> Result { + fn is_feature_supported(&self, _feature: &str) -> Result { Ok(false) } fn list_regions(&self) -> Result<&[AspeedOtpRegion], OtpError> { Ok(REGION_IDS) } fn get_region_info(&self, region: AspeedOtpRegion) -> Result<(usize, usize, usize), OtpError> { - Ok(( - REGION_INFO[region as usize].start, - REGION_INFO[region as usize].cdw_size, - REGION_INFO[region as usize].alignment, - )) + for each in REGION_INFO { + if each.region_type == region { + return Ok((each.start, each.cdw_size, each.alignment)); + } + } + Err(OtpError::Unknown) } } diff --git a/src/otp/common.rs b/src/otp/common.rs index de93502..cf50fbe 100644 --- a/src/otp/common.rs +++ b/src/otp/common.rs @@ -1,4 +1,4 @@ -use proposed_traits::otp::*; +use proposed_traits::otp::ErrorKind; /// ASPEED chip version information #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum AspeedChipVersion { @@ -49,7 +49,10 @@ pub enum OtpError { UnknowRevID, Unknown, } -use crate::otp::common::OtpError::*; +use crate::otp::common::OtpError::{ + AlignmentError, BoundaryError, InvalidBufSize, NoSession, RegionProtected, Timeout, + UnknowRevID, VerificationFailed, WriteExhausted, +}; impl proposed_traits::otp::Error for OtpError { fn kind(&self) -> ErrorKind { match *self { diff --git a/src/otp/hal.rs b/src/otp/hal.rs index a6a9c1d..5401923 100644 --- a/src/otp/hal.rs +++ b/src/otp/hal.rs @@ -18,9 +18,7 @@ impl OtpMemory for OtpController { /// fn read(&self, address: usize) -> Result { let mut buffer: [u32; 1] = [0]; - if let Err(e) = self.read_region(AspeedOtpRegion::Data, address, &mut buffer) { - return Err(e); - } + self.read_region(AspeedOtpRegion::Data, address, &mut buffer)?; Ok(buffer[0]) } fn write(&mut self, address: usize, data: u32) -> Result<(), Self::Error> { @@ -35,7 +33,12 @@ impl OtpMemory for OtpController { } otp_data[0] = self.read(address)?; buffer[0] = data; - self.otp_prog_verify_2dw(address as u32, &otp_data, &buffer, &ignore_mask) + self.otp_prog_verify_2dw( + u32::try_from(address).unwrap(), + &otp_data, + &buffer, + &ignore_mask, + ) } fn lock(&mut self) -> Result<(), Self::Error> { @@ -82,7 +85,7 @@ impl OtpSession for OtpController { self.update_prot_info(&mut session_info); session_info.chip_version = self.chip_version(); session_info.tool_version[..ver_bytes.len()].copy_from_slice(ver_bytes); - session_info.key_count = self.get_key_count() as u32; + session_info.key_count = u32::from(self.get_key_count()); self.session_active = true; @@ -116,7 +119,7 @@ impl OtpRegions for OtpController { /// /// # Parameters /// - `region`: The region to read from - /// - `offset`: Offset within the region. For strap, it's strap_bit_offset + /// - `offset`: Offset within the region. For strap, it's `strap_bit_offset` /// - `buffer`: Buffer to store read data /// /// # Returns @@ -130,7 +133,9 @@ impl OtpRegions for OtpController { ) -> Result<(), Self::Error> { match region { AspeedOtpRegion::Data => self.aspeed_otp_read_data(offset, buffer), - AspeedOtpRegion::Configuration => self.aspeed_otp_read_conf(offset as u32, buffer), + AspeedOtpRegion::Configuration => { + self.aspeed_otp_read_conf(u32::try_from(offset).unwrap(), buffer) + } AspeedOtpRegion::Strap => { if buffer.len() < 2 { return Err(OtpError::InvalidBufSize); @@ -146,17 +151,15 @@ impl OtpRegions for OtpController { Ok(()) => { buffer[0] = 0; for i in 0usize..32 { - buffer[0] |= (strap_status[i].value as u32) << i; + buffer[0] |= u32::from(strap_status[i].value) << i; } buffer[1] = 0; for i in 32usize..64 { - buffer[1] |= (strap_status[i].value as u32) << (i - 32); + buffer[1] |= u32::from(strap_status[i].value) << (i - 32); } - return Ok(()); - } - Err(e) => { - return Err(e); + Ok(()) } + Err(e) => Err(e), } } AspeedOtpRegion::ScuProtection => self.aspeed_otp_read_scuprot(offset, buffer), @@ -167,7 +170,7 @@ impl OtpRegions for OtpController { /// /// # Parameters /// - `region`: The region to write to - /// - `offset`: Offset within the region. For strap, it's strap_bit_offset + /// - `offset`: Offset within the region. For strap, it's `strap_bit_offset` /// - `data`: Data to write /// /// # Returns diff --git a/src/tests/functional/otp_test.rs b/src/tests/functional/otp_test.rs index 78cb6cd..22e78f9 100644 --- a/src/tests/functional/otp_test.rs +++ b/src/tests/functional/otp_test.rs @@ -533,7 +533,7 @@ pub fn test_otp(uart: &mut UartController<'_>) { //test otpcfg if false { test_otp_read_conf(uart, &mut otp_controller, 0); - //test_otp_write_conf_b(uart, &mut otp_controller, 0, 5, 1); + test_otp_write_conf_b(uart, &mut otp_controller, 0, 5, 1); //test_otp_write_conf_b(uart, &mut otp_controller, 0, 5, 1); //test_otp_write_conf_b(uart, &mut otp_controller, 0, 5, 0); test_otp_write_conf_d(uart, &mut otp_controller, 5); @@ -541,14 +541,14 @@ pub fn test_otp(uart: &mut UartController<'_>) { } //test otpstrap - if true { + if false { test_otp_read_strap(uart, &mut otp_controller, 0, 32); for i in 1u8..8 { test_otp_write_strap_b(uart, &mut otp_controller, 0, i & 0x1); } - //let strap: [u32; 2] = [0xffff_ffff, 0xffff_ffff]; - //test_otp_write_strap_d(uart, &mut otp_controller, 30, &strap); + let strap: [u32; 2] = [0xffff_ffff, 0xffff_ffff]; + test_otp_write_strap_d(uart, &mut otp_controller, 30, &strap); test_otp_read_strap(uart, &mut otp_controller, 0, 64); } @@ -556,7 +556,7 @@ pub fn test_otp(uart: &mut UartController<'_>) { //test otpdata if false { test_otp_read_data(uart, &mut otp_controller, 0); - //test_otp_write_data_b(uart, &mut otp_controller, 0, 0, 0); + test_otp_write_data_b(uart, &mut otp_controller, 0, 0, 0); let data = [0xabcd_dead, 0x1234_5678]; test_otp_write_data_d(uart, &mut otp_controller, 4, &data); From 335436abece85c6862e61b7bfd577718f88c6b44 Mon Sep 17 00:00:00 2001 From: "linlin.xu" Date: Wed, 13 Aug 2025 10:13:49 -0700 Subject: [PATCH 3/3] Fix more clippy errors. --- src/otp.rs | 66 ++++++++++++---------- src/otp/common.rs | 3 + src/otp/hal.rs | 3 + src/tests/functional/otp_test.rs | 97 +++++++++++++------------------- 4 files changed, 83 insertions(+), 86 deletions(-) diff --git a/src/otp.rs b/src/otp.rs index 5aa3d52..ad11b81 100644 --- a/src/otp.rs +++ b/src/otp.rs @@ -1,3 +1,5 @@ +// Licensed under the Apache-2.0 license + use crate::{ common::{DummyDelay, Logger}, otp::common::{AspeedChipVersion, AspeedOtpRegion, OtpError, SessionInfo, StrapStatus}, @@ -630,21 +632,19 @@ impl OtpController { if self.verify_2dw(address, buffer, &ignore_mask, verify_size, &mut compare) { pass = true; break; - } else { - self.otp_soak(OtpSoak::SoakProg); - if compare[0] != 0 { - self.otp_prog_dw(compare[0], ignore_mask[0], address)?; - } - if verify_size == 2 && compare[1] != !0 { - self.otp_prog_dw(compare[1], ignore_mask[1], address + 1)?; - } - if !self.verify_2dw(address, buffer, &ignore_mask, verify_size, &mut compare) { - self.otp_soak(OtpSoak::NormalProg); - } else { - pass = true; - break; - } } + self.otp_soak(OtpSoak::SoakProg); + if compare[0] != 0 { + self.otp_prog_dw(compare[0], ignore_mask[0], address)?; + } + if verify_size == 2 && compare[1] != !0 { + self.otp_prog_dw(compare[1], ignore_mask[1], address + 1)?; + } + if self.verify_2dw(address, buffer, &ignore_mask, verify_size, &mut compare) { + pass = true; + break; + } + self.otp_soak(OtpSoak::NormalProg); } if !pass { self.otp_soak(OtpSoak::Default); @@ -664,19 +664,17 @@ impl OtpController { if self.verify_dw(addr, data, ignore, &mut compare) { pass = true; break; - } else { - self.otp_soak(OtpSoak::SoakProg); - if let Err(_e) = self.otp_prog_dw(compare, ignore, addr) { - pass = false; - break; - } - if self.verify_dw(addr, data, ignore, &mut compare) { - pass = true; - break; - } else { - self.otp_soak(OtpSoak::NormalProg); - } } + self.otp_soak(OtpSoak::SoakProg); + if let Err(_e) = self.otp_prog_dw(compare, ignore, addr) { + pass = false; + break; + } + if self.verify_dw(addr, data, ignore, &mut compare) { + pass = true; + break; + } + self.otp_soak(OtpSoak::NormalProg); } pass } @@ -684,6 +682,7 @@ impl OtpController { /// Program OTP data region /// starts from "address" with "buffer" contents /// + #[allow(clippy::needless_range_loop)] pub fn aspeed_otp_prog_data( &mut self, address: usize, @@ -774,6 +773,7 @@ impl OtpController { key_num } + #[allow(clippy::needless_range_loop)] pub fn otp_strap_status(&self, os: &mut [StrapStatus]) -> Result<(), OtpError> { let mut otpstrap_raw: [u32; 2] = [0; 2]; @@ -788,7 +788,7 @@ impl OtpController { self.otp_soak(OtpSoak::Default); for i in (16..strap_end).step_by(2) { - let option = ((i - 16) / 2) as u8; + let option = u8::try_from((i - 16) / 2).unwrap(); otpstrap_raw[0] = self.otp_read_conf_idx(i.try_into().unwrap())?; otpstrap_raw[1] = self.otp_read_conf_idx((i + 1).try_into().unwrap())?; @@ -849,7 +849,7 @@ impl OtpController { } for i in (offset..offset + cdw_len).step_by(2) { let idx = i - offset; - match self.otp_read_data(i as u32, &mut temp) { + match self.otp_read_data(u32::try_from(i).unwrap(), &mut temp) { Ok(()) => { buffer[idx] = temp[0]; buffer[idx + 1] = temp[1]; @@ -865,7 +865,7 @@ impl OtpController { /// fn aspeed_otp_read_conf(&self, offset: u32, buffer: &mut [u32]) -> Result<(), OtpError> { let mut result: Result<(), OtpError> = Ok(()); - let cdw_len = buffer.len() as u32; + let cdw_len = u32::try_from(buffer.len()).unwrap(); if cdw_len + offset > 32 { return Err(OtpError::BoundaryError); } @@ -888,6 +888,7 @@ impl OtpController { ///Read OTP strap into buffer. ///buf: output OTP strap into buffer. /// + #[allow(dead_code)] fn aspeed_otp_read_strap(&self, offset: usize, buf: &mut [u32]) -> Result<(), OtpError> { let mut strap_status: [StrapStatus; 64] = [StrapStatus { value: false, @@ -1006,6 +1007,7 @@ impl OtpController { /// Program strap bits /// All non proteced bits will be programmed /// + #[allow(clippy::needless_range_loop)] pub fn otp_prog_strap(&mut self, start_bit: usize, strap: &[u32]) -> Result<(), OtpError> { let mut prog_address: u32; let mut bit: u32; @@ -1145,6 +1147,7 @@ impl OtpController { /// /// SCU protect /// + #[allow(clippy::needless_range_loop)] pub fn otp_prog_scu_protect(&mut self, start: usize, otp_scu: &[u32]) -> Result<(), OtpError> { let mut scu_pro: [u32; 2] = [0; 2]; let ignore: u32 = 0; @@ -1263,12 +1266,17 @@ impl OtpController { } self.otp_prog_conf(0, &value) } + #[allow(clippy::unused_self)] + #[allow(clippy::unnecessary_wraps)] fn is_feature_supported(&self, _feature: &str) -> Result { Ok(false) } + #[allow(clippy::unused_self)] + #[allow(clippy::unnecessary_wraps)] fn list_regions(&self) -> Result<&[AspeedOtpRegion], OtpError> { Ok(REGION_IDS) } + #[allow(clippy::unused_self)] fn get_region_info(&self, region: AspeedOtpRegion) -> Result<(usize, usize, usize), OtpError> { for each in REGION_INFO { if each.region_type == region { diff --git a/src/otp/common.rs b/src/otp/common.rs index cf50fbe..d5996c1 100644 --- a/src/otp/common.rs +++ b/src/otp/common.rs @@ -1,3 +1,5 @@ +// Licensed under the Apache-2.0 license + use proposed_traits::otp::ErrorKind; /// ASPEED chip version information #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -74,6 +76,7 @@ impl proposed_traits::otp::Error for OtpError { } /// Protection status for different OTP regions +#[allow(clippy::struct_excessive_bools)] #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] pub struct ProtectionStatus { /// Memory lock status (prevents all modifications) diff --git a/src/otp/hal.rs b/src/otp/hal.rs index 5401923..fe7edc6 100644 --- a/src/otp/hal.rs +++ b/src/otp/hal.rs @@ -1,3 +1,5 @@ +// Licensed under the Apache-2.0 license + use crate::{ common::Logger, otp::{ @@ -125,6 +127,7 @@ impl OtpRegions for OtpController { /// # Returns /// - `Ok(())`: Data read successfully /// - `Err(Self::Error)`: Read operation failed + #[allow(clippy::needless_range_loop)] fn read_region( &self, region: Self::Region, diff --git a/src/tests/functional/otp_test.rs b/src/tests/functional/otp_test.rs index 22e78f9..a36ce27 100644 --- a/src/tests/functional/otp_test.rs +++ b/src/tests/functional/otp_test.rs @@ -23,22 +23,22 @@ fn test_otp_read_conf( let mut data: [u32; 32] = [0; 32]; match otp.read_region(AspeedOtpRegion::Configuration, 0, &mut data) { Ok(()) => { - for i in 0..data.len() { + for (i, each) in data.iter().enumerate() { writeln!( uart, "read OTPCFG{:#x} ok: {:#x}\r", conf_reg + u32::try_from(i).unwrap(), - data[i] + each ) .unwrap(); } } Err(e) => { - writeln!(uart, "read OTPCFG{:#x} err: {e:?}\r", conf_reg).unwrap(); + writeln!(uart, "read OTPCFG{conf_reg:#x} err: {e:?}\r").unwrap(); } } } - +#[allow(clippy::too_many_lines)] fn test_otp_write_conf_b( uart: &mut UartController<'_>, otp: &mut OtpController, @@ -91,14 +91,13 @@ fn test_otp_write_conf_b( writeln!(uart, "OTPCFG4 is protected!\r").unwrap(); return; } - if (otp_bit_offset <= 7) || (otp_bit_offset >= 16 && otp_bit_offset <= 23) { + if (otp_bit_offset <= 7) || (16..=23).contains(&otp_bit_offset) { let key_num = otp.get_key_count(); - let retire: u32; - if otp_bit_offset >= 16 { - retire = otp_bit_offset - 16; + let retire: u32 = if otp_bit_offset >= 16 { + otp_bit_offset - 16 } else { - retire = otp_bit_offset; - } + otp_bit_offset + }; if retire >= u32::from(key_num) { writeln!( uart, @@ -108,7 +107,7 @@ fn test_otp_write_conf_b( return; } } - } else if otp_addr >= 16 && otp_addr <= 31 { + } else if (16..=31).contains(&otp_addr) { if conf0 & OTP_STRAP_PROT_ENBLE != 0 { writeln!(uart, "OTP strap region is protected!\r").unwrap(); return; @@ -123,8 +122,7 @@ fn test_otp_write_conf_b( if otp_strap_pro >> otp_bit_offset & 1 != 0 { writeln!( uart, - "OTPCFG{:#x}[{:#x}] is protected!\r", - otp_addr, otp_bit_offset + "OTPCFG{otp_addr:#x}[{otp_bit_offset:#x}] is protected!\r", ) .unwrap(); } @@ -135,8 +133,7 @@ fn test_otp_write_conf_b( if (conf >> otp_bit_offset & 0x1) == otp_value { writeln!( uart, - "OTPCFG{:#x}[{:#x}] = 1; no need to program\r", - otp_addr, otp_bit_offset + "OTPCFG{otp_addr:#x}[{otp_bit_offset:#x}] = 1; no need to program\r", ) .unwrap(); return; @@ -144,8 +141,7 @@ fn test_otp_write_conf_b( if (conf >> otp_bit_offset & 0x1) == 1 && otp_value == 0 { writeln!( uart, - "OTPCFG{:#x}[{:#x}] = 1; cannot be cleared\r", - otp_addr, otp_bit_offset + "OTPCFG{otp_addr:#x}[{otp_bit_offset:#x}] = 1; cannot be cleared\r", ) .unwrap(); return; @@ -157,13 +153,12 @@ fn test_otp_write_conf_b( Ok(()) => { writeln!( uart, - "program OTPCFG{:#x}[{:#x}] successfully!\r", - otp_addr, otp_bit_offset + "program OTPCFG{otp_addr:#x}[{otp_bit_offset:#x}] successfully!\r", ) .unwrap(); } Err(e) => { - writeln!(uart, "program OTPCFG{:#x} err: {e:?}\r", otp_addr).unwrap(); + writeln!(uart, "program OTPCFG{otp_addr:#x} err: {e:?}\r").unwrap(); } } } @@ -173,14 +168,14 @@ fn test_otp_write_conf_d( otp: &mut OtpController, offset: u8, ) { - let mut data: [u32; 2] = [0xabcd_beef, 0x1234_5678]; + let data: [u32; 2] = [0xabcd_beef, 0x1234_5678]; - match otp.write_region(AspeedOtpRegion::Configuration, offset as usize, &mut data) { + match otp.write_region(AspeedOtpRegion::Configuration, offset as usize, &data) { Ok(()) => { - writeln!(uart, "write OTPCONF{:#x} success\r", offset).unwrap(); + writeln!(uart, "write OTPCONF{offset:#x} success\r").unwrap(); } Err(e) => { - writeln!(uart, "write OTPCONF{:#x} err: {e:?}\r", offset).unwrap(); + writeln!(uart, "write OTPCONF{offset:#x} err: {e:?}\r").unwrap(); } } } @@ -209,7 +204,7 @@ fn read_otp_data( data: &mut [u32], ) { if let Err(e) = otp.read_region(AspeedOtpRegion::Data, 0, data) { - writeln!(uart, "read OTPDATA{:#x} err: {e:?}\r", offset).unwrap(); + writeln!(uart, "read OTPDATA{offset:#x} err: {e:?}\r").unwrap(); } } @@ -249,7 +244,7 @@ fn test_otp_write_strap_b( return; } //test_otp_read_strap(uart, otp, u32::from(bit_offset), 1); - if value == strap_status[bit_offset as usize].value as u8 { + if value == u8::from(strap_status[bit_offset as usize].value) { writeln!(uart, "The value is same as before.\r").unwrap(); return; } @@ -266,8 +261,8 @@ fn test_otp_write_strap_b( "Write 1 to OTPSTRAP[{:#x}] OPTION[{:#x}], that value changes from {:#x} to {:#x} \r", bit_offset, strap_status[bit_offset as usize].writable_option + 1, - strap_status[bit_offset as usize].value as u8, - strap_status[bit_offset as usize].value as u8 ^ 1 + u8::from(strap_status[bit_offset as usize].value), + u8::from(strap_status[bit_offset as usize].value) ^ 1 ) .unwrap(); @@ -288,7 +283,7 @@ fn test_otp_write_strap_b( } match otp.otp_prog_dc_b(1, prog_addr, offset) { Ok(()) => { - writeln!(uart, "program OTPSTRAP[{:#x}] successfully!\r", offset).unwrap(); + writeln!(uart, "program OTPSTRAP[{offset:#x}] successfully!\r").unwrap(); } Err(e) => { writeln!(uart, "program OTPSTRAP err: {e:?}\r").unwrap(); @@ -302,13 +297,8 @@ fn test_otp_write_strap_d( start_bit: usize, strap: &[u32], ) { - writeln!( - uart, - "OTPSTRAP start_bit {:}, strap = {:?}\r", - start_bit, strap - ) - .unwrap(); - match otp.write_region(AspeedOtpRegion::Strap, start_bit, &strap) { + writeln!(uart, "OTPSTRAP start_bit {start_bit:}, strap = {strap:?}\r",).unwrap(); + match otp.write_region(AspeedOtpRegion::Strap, start_bit, strap) { Ok(()) => { writeln!(uart, "program OTPSTRAP dword success\r").unwrap(); } @@ -340,7 +330,8 @@ fn test_otp_read_strap( write!( uart, "0x{:<8x} {:<7} ", - i, strap_status[i as usize].value as u8 + i, + u8::from(strap_status[i as usize].value) ) .unwrap(); for j in 0..remains { @@ -371,7 +362,7 @@ fn test_otp_read_strap( let mut buffer: [u32; 2] = [0, 0]; match otp.read_region(AspeedOtpRegion::Strap, 0, &mut buffer) { Ok(()) => { - writeln!(uart, "read OTPSTRAP {:?}\r", buffer).unwrap(); + writeln!(uart, "read OTPSTRAP {buffer:?}\r").unwrap(); } Err(e) => { writeln!(uart, "read OTPSTRAP err: {e:?}\r").unwrap(); @@ -419,7 +410,7 @@ fn test_otp_write_data_b( read_otp_data(uart, otp, otp_addr, &mut data); otp_bit = (data[0] >> bit_offset) & 0x1; if otp_bit == 1 && value == 0 { - writeln!(uart, "OTPDATA{:#x}[{:#x}] = 1\r", otp_addr, bit_offset).unwrap(); + writeln!(uart, "OTPDATA{otp_addr:#x}[{bit_offset:#x}] = 1\r").unwrap(); writeln!(uart, "OTP is programmed, which can't be cleared!\r").unwrap(); return; } @@ -427,27 +418,21 @@ fn test_otp_write_data_b( read_otp_data(uart, otp, otp_addr - 1, &mut data); otp_bit = (data[1] >> bit_offset) & 0x1; if otp_bit == 0 && value == 1 { - writeln!(uart, "OTPDATA{:#x}[{:#x}] = 1\r", otp_addr, bit_offset).unwrap(); + writeln!(uart, "OTPDATA{otp_addr:#x}[{bit_offset:#x}] = 1\r").unwrap(); writeln!(uart, "OTP is programmed, which can't be written!\r").unwrap(); return; } } if otp_bit == value { - writeln!( - uart, - "OTPDATA{:#x}[{:#x}] = {}\r", - otp_addr, bit_offset, value - ) - .unwrap(); + writeln!(uart, "OTPDATA{otp_addr:#x}[{bit_offset:#x}] = {value}\r",).unwrap(); writeln!(uart, "No need to program!\r").unwrap(); return; } writeln!( uart, - "Program OTPDATA{:#x}[{:#x}] to {}\r", - otp_addr, bit_offset, value + "Program OTPDATA{otp_addr:#x}[{bit_offset:#x}] to {value}\r", ) .unwrap(); @@ -455,16 +440,14 @@ fn test_otp_write_data_b( Ok(()) => { writeln!( uart, - "program OTPDATA{:#x}[{:#x}] successfully!\r", - otp_addr, bit_offset + "program OTPDATA{otp_addr:#x}[{bit_offset:#x}] successfully!\r", ) .unwrap(); } Err(e) => { writeln!( uart, - "program OTPDATA{:#x}[{:#x}] err: {e:?}\r", - otp_addr, bit_offset + "program OTPDATA{otp_addr:#x}[{bit_offset:#x}] err: {e:?}\r", ) .unwrap(); } @@ -479,10 +462,10 @@ fn test_otp_write_data_d( ) { match otp.write_region(AspeedOtpRegion::Data, otp_addr as usize, data) { Ok(()) => { - writeln!(uart, "write OTPDATA{:#x} success\r", otp_addr).unwrap(); + writeln!(uart, "write OTPDATA{otp_addr:#x} success\r").unwrap(); } Err(e) => { - writeln!(uart, "write OTPDATA{:#x} err: {e:?}\r", otp_addr).unwrap(); + writeln!(uart, "write OTPDATA{otp_addr:#x} err: {e:?}\r").unwrap(); } } } @@ -497,18 +480,18 @@ fn test_otp_read_data( let mut data: [u32; 32] = [0; 32]; match otp.read_region(AspeedOtpRegion::Data, 0, &mut data) { Ok(()) => { - for i in 0..data.len() { + for (i, each) in data.iter().enumerate() { writeln!( uart, "read OTPDATA{:#x} ok: {:#x}\r", conf_reg + u32::try_from(i).unwrap(), - data[i as usize] + each ) .unwrap(); } } Err(e) => { - writeln!(uart, "read OTPDATA{:#x} err: {e:?}\r", conf_reg).unwrap(); + writeln!(uart, "read OTPDATA{conf_reg:#x} err: {e:?}\r").unwrap(); } } }