[sw] Add lc_ctrl registers to opentitanlib bindgen Signed-off-by: Dan McArdle <dmcardle@opentitan.org>
diff --git a/sw/host/opentitanlib/bindgen/BUILD b/sw/host/opentitanlib/bindgen/BUILD index 4dee520..34790ba 100644 --- a/sw/host/opentitanlib/bindgen/BUILD +++ b/sw/host/opentitanlib/bindgen/BUILD
@@ -35,6 +35,9 @@ name = "dif", bindgen_flags = [ "--allowlist-type=dif_lc_ctrl_state", + "--allowlist-type=dif_lc_ctrl_token", + "--allowlist-var=LC_CTRL_.*_BIT", + "--allowlist-var=LC_CTRL_.*_REG_OFFSET", "--allowlist-type=dif_rstmgr_reset_info", ], cc_lib = ":difs",
diff --git a/sw/host/opentitanlib/bindgen/difs.h b/sw/host/opentitanlib/bindgen/difs.h index 775b9f3..b4bd77a 100644 --- a/sw/host/opentitanlib/bindgen/difs.h +++ b/sw/host/opentitanlib/bindgen/difs.h
@@ -4,6 +4,10 @@ // #ifndef OPENTITAN_SW_HOST_OPENTITANLIB_BINDGEN_DIFS_H_ #define OPENTITAN_SW_HOST_OPENTITANLIB_BINDGEN_DIFS_H_ + #include "sw/device/lib/dif/dif_lc_ctrl.h" #include "sw/device/lib/dif/dif_rstmgr.h" + +#include "lc_ctrl_regs.h" // Generated. + #endif // OPENTITAN_SW_HOST_OPENTITANLIB_BINDGEN_DIFS_H_
diff --git a/sw/host/opentitanlib/src/dif/lc_ctrl.rs b/sw/host/opentitanlib/src/dif/lc_ctrl.rs index fe3f534..4d9b2bd 100644 --- a/sw/host/opentitanlib/src/dif/lc_ctrl.rs +++ b/sw/host/opentitanlib/src/dif/lc_ctrl.rs
@@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::with_unknown; +use num_enum::IntoPrimitive; with_unknown! { pub enum DifLcCtrlState: u32 { @@ -29,6 +30,196 @@ Scrap = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateScrap as u32, PostTransition = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStatePostTransition as u32, Escalate = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateEscalate as u32, - StateInvalide = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateInvalid as u32, + StateInvalid = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateInvalid as u32, + } +} + +impl DifLcCtrlState { + /// Encode the given life cycle state in a redundant format where the + /// five-bit value is repeated six times. + pub fn redundant_encoding(&self) -> u32 { + let value: u32 = self.0; + assert_eq!(value & 0b11111, value); + (0..6).fold(0u32, |acc, _| (acc << 5) | value) + } +} + +pub struct DifLcCtrlToken(bindgen::dif::dif_lc_ctrl_token); + +impl From<[u8; 16]> for DifLcCtrlToken { + fn from(bytes: [u8; 16]) -> Self { + DifLcCtrlToken(bindgen::dif::dif_lc_ctrl_token { data: bytes }) + } +} + +impl DifLcCtrlToken { + /// Converts a 128-bit transition token into four native u32 words. These + /// values are suitable to write to [LcCtrlReg::TransitionToken0] and + /// friends. + pub fn into_register_values(self) -> [u32; 4] { + let mut out_words = [0u32; 4]; + let bytes = self.0.data; + bytes + .chunks_exact(std::mem::size_of::<u32>()) + .map(|chunk| u32::from_le_bytes(chunk.try_into().unwrap())) + .zip(&mut out_words) + .for_each(|(word, out)| *out = word); + out_words + } +} + +#[derive(IntoPrimitive, Clone, Debug)] +#[repr(u32)] +pub enum LcCtrlReg { + AlertTest = bindgen::dif::LC_CTRL_ALERT_TEST_REG_OFFSET, + Status = bindgen::dif::LC_CTRL_STATUS_REG_OFFSET, + ClaimTransitionIf = bindgen::dif::LC_CTRL_CLAIM_TRANSITION_IF_REG_OFFSET, + TransitionRegwen = bindgen::dif::LC_CTRL_TRANSITION_REGWEN_REG_OFFSET, + TransitionCmd = bindgen::dif::LC_CTRL_TRANSITION_CMD_REG_OFFSET, + TransitionCtrl = bindgen::dif::LC_CTRL_TRANSITION_CTRL_REG_OFFSET, + TransitionToken0 = bindgen::dif::LC_CTRL_TRANSITION_TOKEN_0_REG_OFFSET, + TransitionToken1 = bindgen::dif::LC_CTRL_TRANSITION_TOKEN_1_REG_OFFSET, + TransitionToken2 = bindgen::dif::LC_CTRL_TRANSITION_TOKEN_2_REG_OFFSET, + TransitionToken3 = bindgen::dif::LC_CTRL_TRANSITION_TOKEN_3_REG_OFFSET, + TransitionTarget = bindgen::dif::LC_CTRL_TRANSITION_TARGET_REG_OFFSET, + OtpVendorTestCtrl = bindgen::dif::LC_CTRL_OTP_VENDOR_TEST_CTRL_REG_OFFSET, + OtpVendorTestStatus = bindgen::dif::LC_CTRL_OTP_VENDOR_TEST_STATUS_REG_OFFSET, + LcState = bindgen::dif::LC_CTRL_LC_STATE_REG_OFFSET, + LcTransitionCnt = bindgen::dif::LC_CTRL_LC_TRANSITION_CNT_REG_OFFSET, + LcIdState = bindgen::dif::LC_CTRL_LC_ID_STATE_REG_OFFSET, + HwRev = bindgen::dif::LC_CTRL_HW_REV_REG_OFFSET, + DeviceId0 = bindgen::dif::LC_CTRL_DEVICE_ID_0_REG_OFFSET, + DeviceId1 = bindgen::dif::LC_CTRL_DEVICE_ID_1_REG_OFFSET, + DeviceId2 = bindgen::dif::LC_CTRL_DEVICE_ID_2_REG_OFFSET, + DeviceId3 = bindgen::dif::LC_CTRL_DEVICE_ID_3_REG_OFFSET, + DeviceId4 = bindgen::dif::LC_CTRL_DEVICE_ID_4_REG_OFFSET, + DeviceId5 = bindgen::dif::LC_CTRL_DEVICE_ID_5_REG_OFFSET, + DeviceId6 = bindgen::dif::LC_CTRL_DEVICE_ID_6_REG_OFFSET, + DeviceId7 = bindgen::dif::LC_CTRL_DEVICE_ID_7_REG_OFFSET, + ManufState0 = bindgen::dif::LC_CTRL_MANUF_STATE_0_REG_OFFSET, + ManufState1 = bindgen::dif::LC_CTRL_MANUF_STATE_1_REG_OFFSET, + ManufState2 = bindgen::dif::LC_CTRL_MANUF_STATE_2_REG_OFFSET, + ManufState3 = bindgen::dif::LC_CTRL_MANUF_STATE_3_REG_OFFSET, + ManufState4 = bindgen::dif::LC_CTRL_MANUF_STATE_4_REG_OFFSET, + ManufState5 = bindgen::dif::LC_CTRL_MANUF_STATE_5_REG_OFFSET, + ManufState6 = bindgen::dif::LC_CTRL_MANUF_STATE_6_REG_OFFSET, + ManufState7 = bindgen::dif::LC_CTRL_MANUF_STATE_7_REG_OFFSET, +} + +impl LcCtrlReg { + pub fn byte_offset(&self) -> u32 { + self.clone().into() + } + /// Converts the register's byte offset into a word offset for use with DMI. + /// https://docs.opentitan.org/hw/ip/lc_ctrl/doc/#life-cycle-tap-controller + pub fn word_offset(&self) -> u32 { + const BYTES_PER_WORD: u32 = std::mem::size_of::<u32>() as u32; + assert_eq!(self.byte_offset() % BYTES_PER_WORD, 0); + self.byte_offset() / BYTES_PER_WORD + } +} + +pub trait LcBit: Clone + Into<u32> { + /// Builds a register value from a collection of [LcBit] bits. + fn union<const N: usize>(bits: [Self; N]) -> u32 { + bits.into_iter() + .map(|bit| bit.into()) + .map(|bit: u32| 1 << bit) + .fold(0u32, |acc, shifted| acc | shifted) + } +} + +/// Bits of the lc_ctrl.STATUS register, aka [LcCtrlReg::Status]. +#[derive(IntoPrimitive, Clone, Debug)] +#[repr(u32)] +pub enum LcCtrlStatusBit { + Initialized = bindgen::dif::LC_CTRL_STATUS_INITIALIZED_BIT, + Ready = bindgen::dif::LC_CTRL_STATUS_READY_BIT, + TransitionSuccessful = bindgen::dif::LC_CTRL_STATUS_TRANSITION_SUCCESSFUL_BIT, + TransitionCountError = bindgen::dif::LC_CTRL_STATUS_TRANSITION_COUNT_ERROR_BIT, + TransitionError = bindgen::dif::LC_CTRL_STATUS_TRANSITION_ERROR_BIT, + TokenError = bindgen::dif::LC_CTRL_STATUS_TOKEN_ERROR_BIT, + FlashRmaError = bindgen::dif::LC_CTRL_STATUS_FLASH_RMA_ERROR_BIT, + OtpError = bindgen::dif::LC_CTRL_STATUS_OTP_ERROR_BIT, + StateError = bindgen::dif::LC_CTRL_STATUS_STATE_ERROR_BIT, + BusIntegError = bindgen::dif::LC_CTRL_STATUS_BUS_INTEG_ERROR_BIT, + OtpPartitionError = bindgen::dif::LC_CTRL_STATUS_OTP_PARTITION_ERROR_BIT, +} +impl LcBit for LcCtrlStatusBit {} + +/// Bits of the lc_ctrl.TRANSITION_REGWEN register, aka [LcCtrlReg::TransitionRegwen]. +#[derive(IntoPrimitive, Clone, Debug)] +#[repr(u32)] +pub enum LcCtrlTransitionRegwenBit { + TransitionRegwen = bindgen::dif::LC_CTRL_TRANSITION_REGWEN_TRANSITION_REGWEN_BIT, +} +impl LcBit for LcCtrlTransitionRegwenBit {} + +/// Bits of the lc_ctrl.TRANSITION_CMD register, aka [LcCtrlReg::TransitionCmd]. +#[derive(IntoPrimitive, Clone, Debug)] +#[repr(u32)] +pub enum LcCtrlTransitionCmdBit { + Start = bindgen::dif::LC_CTRL_TRANSITION_CMD_START_BIT, +} +impl LcBit for LcCtrlTransitionCmdBit {} + +/// Bits of the lc_ctrl.TRANSITION_CTRL register, aka [LcCtrlReg::TransitionCtrl]. +#[derive(IntoPrimitive, Clone, Debug)] +#[repr(u32)] +pub enum LcCtrlTransitionCtrlBit { + ExtClockEn = bindgen::dif::LC_CTRL_TRANSITION_CTRL_EXT_CLOCK_EN_BIT, +} +impl LcBit for LcCtrlTransitionCtrlBit {} + +#[cfg(test)] +mod tests { + use super::*; + + /// Raw is zero, so its redundant encoding is a fixed point. + #[test] + fn lc_ctrl_state_redundant_encoding_zero() { + assert_eq!(u32::from(DifLcCtrlState::Raw), 0); + assert_eq!(DifLcCtrlState::Raw.redundant_encoding(), 0); + } + + /// The redundant encoding of non-zero values shouldn't be a fixed point. + #[test] + fn lc_ctrl_state_redundant_encoding_nonzero() { + assert_ne!( + u32::from(DifLcCtrlState::Rma), + DifLcCtrlState::Rma.redundant_encoding() + ); + assert_eq!(DifLcCtrlState::Rma.redundant_encoding(), 0x2739ce73); + } + + #[test] + fn lc_ctrl_token() { + // This test assumes the system is little-endian. + let token_bytes: [u8; 16] = [ + 0x01, 0x02, 0x03, 0x04, // TOKEN_0 + 0x11, 0x12, 0x13, 0x14, // TOKEN_1 + 0x21, 0x22, 0x23, 0x24, // TOKEN_2 + 0x31, 0x32, 0x33, 0x34, // TOKEN_3 + ]; + let token = DifLcCtrlToken::from(token_bytes); + let words: [u32; 4] = token.into_register_values(); + assert_eq!(words, [0x04030201, 0x14131211, 0x24232221, 0x34333231]); + } + + #[test] + fn lc_ctrl_register_offsets() { + assert_eq!(LcCtrlReg::LcState.byte_offset(), 0x34); + assert_eq!(0x34 / 4, 0xd); + assert_eq!(LcCtrlReg::LcState.word_offset(), 0xd); + } + + #[test] + fn lc_bit_union() { + assert_eq!(LcBit::union([] as [LcCtrlStatusBit; 0]), 0); + assert_eq!(LcBit::union([LcCtrlStatusBit::Initialized]), 1); + assert_eq!( + LcBit::union([LcCtrlStatusBit::Initialized, LcCtrlStatusBit::Ready]), + 3 + ); } }