blob: 4d9b2bdab21b72d36c95b5bc489d4df5812aad89 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
use crate::with_unknown;
use num_enum::IntoPrimitive;
with_unknown! {
pub enum DifLcCtrlState: u32 {
Raw = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateRaw as u32,
TestUnlocked0 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestUnlocked0 as u32,
TestLocked0 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestLocked0 as u32,
TestUnlocked1 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestUnlocked1 as u32,
TestLocked1 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestLocked1 as u32,
TestUnlocked2 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestUnlocked2 as u32,
TestLocked2 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestLocked2 as u32,
TestUnlocked3 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestUnlocked3 as u32,
TestLocked3 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestLocked3 as u32,
TestUnlocked4 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestUnlocked4 as u32,
TestLocked4 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestLocked4 as u32,
TestUnlocked5 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestUnlocked5 as u32,
TestLocked5 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestLocked5 as u32,
TestUnlocked6 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestUnlocked6 as u32,
TestLocked6 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestLocked6 as u32,
TestUnlocked7 = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateTestUnlocked7 as u32,
Dev = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateDev as u32,
Prod = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateProd as u32,
ProdEnd = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateProdEnd as u32,
Rma = bindgen::dif::dif_lc_ctrl_state_kDifLcCtrlStateRma as u32,
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,
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
);
}
}