blob: 5edc069a87d90604a5f9779c99271e53cd28cc2b [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include "sw/device/lib/dif/dif_otp_ctrl.h"
#include <cstring>
#include <limits>
#include <ostream>
#include "gtest/gtest.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/base/testing/mock_mmio.h"
#include "otp_ctrl_regs.h" // Generated.
namespace dif_otp_ctrl_unittest {
namespace {
using ::mock_mmio::LeInt;
using ::mock_mmio::MmioTest;
using ::mock_mmio::MockDevice;
using ::testing::Each;
using ::testing::ElementsAre;
class OtpTest : public testing::Test, public MmioTest {
protected:
dif_otp_ctrl_t otp_ = {.base_addr = dev().region()};
};
class ConfigTest : public OtpTest {};
TEST_F(ConfigTest, Basic) {
dif_otp_ctrl_config_t config = {
.check_timeout = 100'000,
.integrity_period_mask = 0x3'ffff,
.consistency_period_mask = 0x3ff'ffff,
};
EXPECT_READ32(OTP_CTRL_CHECK_REGWEN_REG_OFFSET,
{{OTP_CTRL_CHECK_REGWEN_CHECK_REGWEN_BIT, true}});
EXPECT_WRITE32(OTP_CTRL_CHECK_TIMEOUT_REG_OFFSET, config.check_timeout);
EXPECT_WRITE32(OTP_CTRL_INTEGRITY_CHECK_PERIOD_REG_OFFSET,
config.integrity_period_mask);
EXPECT_WRITE32(OTP_CTRL_CONSISTENCY_CHECK_PERIOD_REG_OFFSET,
config.consistency_period_mask);
EXPECT_EQ(dif_otp_ctrl_configure(&otp_, config), kDifOk);
}
TEST_F(ConfigTest, Locked) {
EXPECT_READ32(OTP_CTRL_CHECK_REGWEN_REG_OFFSET,
{{OTP_CTRL_CHECK_REGWEN_CHECK_REGWEN_BIT, false}});
EXPECT_EQ(dif_otp_ctrl_configure(&otp_, {}), kDifLocked);
}
TEST_F(ConfigTest, IsConfigLocked) {
bool flag;
EXPECT_READ32(OTP_CTRL_CHECK_REGWEN_REG_OFFSET,
{{OTP_CTRL_CHECK_REGWEN_CHECK_REGWEN_BIT, true}});
EXPECT_EQ(dif_otp_ctrl_config_is_locked(&otp_, &flag), kDifOk);
EXPECT_FALSE(flag);
EXPECT_READ32(OTP_CTRL_CHECK_REGWEN_REG_OFFSET,
{{OTP_CTRL_CHECK_REGWEN_CHECK_REGWEN_BIT, false}});
EXPECT_EQ(dif_otp_ctrl_config_is_locked(&otp_, &flag), kDifOk);
EXPECT_TRUE(flag);
}
TEST_F(ConfigTest, LockConfig) {
EXPECT_WRITE32(OTP_CTRL_CHECK_REGWEN_REG_OFFSET,
{{OTP_CTRL_CHECK_REGWEN_CHECK_REGWEN_BIT, true}});
EXPECT_EQ(dif_otp_ctrl_lock_config(&otp_), kDifOk);
}
TEST_F(ConfigTest, NullArgs) {
EXPECT_EQ(dif_otp_ctrl_configure(nullptr, {}), kDifBadArg);
bool flag;
EXPECT_EQ(dif_otp_ctrl_config_is_locked(nullptr, &flag), kDifBadArg);
EXPECT_EQ(dif_otp_ctrl_config_is_locked(&otp_, nullptr), kDifBadArg);
EXPECT_EQ(dif_otp_ctrl_lock_config(nullptr), kDifBadArg);
}
class CheckTest : public OtpTest {};
TEST_F(CheckTest, Integrity) {
EXPECT_READ32(OTP_CTRL_CHECK_REGWEN_REG_OFFSET,
{{OTP_CTRL_CHECK_REGWEN_CHECK_REGWEN_BIT, true}});
EXPECT_WRITE32(OTP_CTRL_CHECK_TRIGGER_REG_OFFSET,
{{OTP_CTRL_CHECK_TRIGGER_INTEGRITY_BIT, true}});
EXPECT_EQ(dif_otp_ctrl_check_integrity(&otp_), kDifOk);
}
TEST_F(CheckTest, Consistency) {
EXPECT_READ32(OTP_CTRL_CHECK_REGWEN_REG_OFFSET,
{{OTP_CTRL_CHECK_REGWEN_CHECK_REGWEN_BIT, true}});
EXPECT_WRITE32(OTP_CTRL_CHECK_TRIGGER_REG_OFFSET,
{{OTP_CTRL_CHECK_TRIGGER_CONSISTENCY_BIT, true}});
EXPECT_EQ(dif_otp_ctrl_check_consistency(&otp_), kDifOk);
}
TEST_F(CheckTest, Locked) {
EXPECT_READ32(OTP_CTRL_CHECK_REGWEN_REG_OFFSET,
{{OTP_CTRL_CHECK_REGWEN_CHECK_REGWEN_BIT, false}});
EXPECT_EQ(dif_otp_ctrl_check_integrity(&otp_), kDifLocked);
EXPECT_READ32(OTP_CTRL_CHECK_REGWEN_REG_OFFSET,
{{OTP_CTRL_CHECK_REGWEN_CHECK_REGWEN_BIT, false}});
EXPECT_EQ(dif_otp_ctrl_check_consistency(&otp_), kDifLocked);
}
TEST_F(CheckTest, NullArgs) {
EXPECT_EQ(dif_otp_ctrl_check_integrity(nullptr), kDifBadArg);
EXPECT_EQ(dif_otp_ctrl_check_consistency(nullptr), kDifBadArg);
}
class ReadLockTest : public OtpTest {};
TEST_F(ReadLockTest, IsLocked) {
bool flag;
EXPECT_READ32(
OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_REG_OFFSET,
{{OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_CREATOR_SW_CFG_READ_LOCK_BIT, true}});
EXPECT_EQ(dif_otp_ctrl_reading_is_locked(
&otp_, kDifOtpCtrlPartitionCreatorSwCfg, &flag),
kDifOk);
EXPECT_FALSE(flag);
EXPECT_READ32(
OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_REG_OFFSET,
{{OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_CREATOR_SW_CFG_READ_LOCK_BIT,
false}});
EXPECT_EQ(dif_otp_ctrl_reading_is_locked(
&otp_, kDifOtpCtrlPartitionCreatorSwCfg, &flag),
kDifOk);
EXPECT_TRUE(flag);
EXPECT_READ32(
OTP_CTRL_OWNER_SW_CFG_READ_LOCK_REG_OFFSET,
{{OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_CREATOR_SW_CFG_READ_LOCK_BIT, true}});
EXPECT_EQ(dif_otp_ctrl_reading_is_locked(
&otp_, kDifOtpCtrlPartitionOwnerSwCfg, &flag),
kDifOk);
EXPECT_FALSE(flag);
EXPECT_READ32(
OTP_CTRL_OWNER_SW_CFG_READ_LOCK_REG_OFFSET,
{{OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_CREATOR_SW_CFG_READ_LOCK_BIT,
false}});
EXPECT_EQ(dif_otp_ctrl_reading_is_locked(
&otp_, kDifOtpCtrlPartitionOwnerSwCfg, &flag),
kDifOk);
EXPECT_TRUE(flag);
}
TEST_F(ReadLockTest, Lock) {
EXPECT_WRITE32(
OTP_CTRL_VENDOR_TEST_READ_LOCK_REG_OFFSET,
{{OTP_CTRL_VENDOR_TEST_READ_LOCK_VENDOR_TEST_READ_LOCK_BIT, true}});
EXPECT_EQ(dif_otp_ctrl_lock_reading(&otp_, kDifOtpCtrlPartitionVendorTest),
kDifOk);
EXPECT_WRITE32(
OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_REG_OFFSET,
{{OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_CREATOR_SW_CFG_READ_LOCK_BIT, true}});
EXPECT_EQ(dif_otp_ctrl_lock_reading(&otp_, kDifOtpCtrlPartitionCreatorSwCfg),
kDifOk);
EXPECT_WRITE32(
OTP_CTRL_OWNER_SW_CFG_READ_LOCK_REG_OFFSET,
{{OTP_CTRL_CREATOR_SW_CFG_READ_LOCK_CREATOR_SW_CFG_READ_LOCK_BIT, true}});
EXPECT_EQ(dif_otp_ctrl_lock_reading(&otp_, kDifOtpCtrlPartitionOwnerSwCfg),
kDifOk);
}
TEST_F(ReadLockTest, HwPartition) {
bool flag;
EXPECT_EQ(dif_otp_ctrl_lock_reading(&otp_, kDifOtpCtrlPartitionHwCfg),
kDifBadArg);
EXPECT_EQ(
dif_otp_ctrl_reading_is_locked(&otp_, kDifOtpCtrlPartitionSecret0, &flag),
kDifBadArg);
}
TEST_F(ReadLockTest, NullArgs) {
bool flag;
EXPECT_EQ(dif_otp_ctrl_reading_is_locked(
nullptr, kDifOtpCtrlPartitionOwnerSwCfg, &flag),
kDifBadArg);
EXPECT_EQ(dif_otp_ctrl_reading_is_locked(
&otp_, kDifOtpCtrlPartitionOwnerSwCfg, nullptr),
kDifBadArg);
EXPECT_EQ(dif_otp_ctrl_lock_reading(nullptr, kDifOtpCtrlPartitionOwnerSwCfg),
kDifBadArg);
}
class StatusTest : public OtpTest {};
TEST_F(StatusTest, Idle) {
dif_otp_ctrl_status_t status;
EXPECT_READ32(OTP_CTRL_STATUS_REG_OFFSET,
{{OTP_CTRL_STATUS_DAI_IDLE_BIT, true}});
EXPECT_READ32(OTP_CTRL_ERR_CODE_REG_OFFSET, 0);
EXPECT_EQ(dif_otp_ctrl_get_status(&otp_, &status), kDifOk);
EXPECT_EQ(status.codes, 1 << kDifOtpCtrlStatusCodeDaiIdle);
EXPECT_THAT(status.causes, Each(kDifOtpCtrlErrorOk));
}
TEST_F(StatusTest, Errors) {
dif_otp_ctrl_status_t status;
EXPECT_READ32(OTP_CTRL_STATUS_REG_OFFSET,
{
{OTP_CTRL_STATUS_DAI_IDLE_BIT, true},
{OTP_CTRL_STATUS_HW_CFG_ERROR_BIT, true},
{OTP_CTRL_STATUS_LCI_ERROR_BIT, true},
});
EXPECT_READ32(OTP_CTRL_ERR_CODE_REG_OFFSET,
{{OTP_CTRL_ERR_CODE_ERR_CODE_3_OFFSET,
OTP_CTRL_ERR_CODE_ERR_CODE_0_VALUE_MACRO_ECC_CORR_ERROR},
{OTP_CTRL_ERR_CODE_ERR_CODE_9_OFFSET,
OTP_CTRL_ERR_CODE_ERR_CODE_0_VALUE_MACRO_ERROR}});
EXPECT_EQ(dif_otp_ctrl_get_status(&otp_, &status), kDifOk);
EXPECT_EQ(status.codes, (1 << kDifOtpCtrlStatusCodeDaiIdle) |
(1 << kDifOtpCtrlStatusCodeHwCfgError) |
(1 << kDifOtpCtrlStatusCodeLciError));
EXPECT_EQ(status.causes[kDifOtpCtrlStatusCodeHwCfgError],
kDifOtpCtrlErrorMacroRecoverableRead);
EXPECT_EQ(status.causes[kDifOtpCtrlStatusCodeLciError],
kDifOtpCtrlErrorMacroUnspecified);
}
TEST_F(StatusTest, NullArgs) {
dif_otp_ctrl_status_t status;
EXPECT_EQ(dif_otp_ctrl_get_status(nullptr, &status), kDifBadArg);
EXPECT_EQ(dif_otp_ctrl_get_status(&otp_, nullptr), kDifBadArg);
}
class DaiReadTest : public OtpTest {};
TEST_F(DaiReadTest, Read32) {
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, true}});
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
OTP_CTRL_PARAM_MANUF_STATE_OFFSET);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_CMD_RD_BIT, true}});
EXPECT_EQ(dif_otp_ctrl_dai_read_start(&otp_, kDifOtpCtrlPartitionHwCfg,
/*address=*/0x20),
kDifOk);
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, true}});
EXPECT_READ32(OTP_CTRL_DIRECT_ACCESS_RDATA_0_REG_OFFSET, 0x12345678);
uint32_t val;
EXPECT_EQ(dif_otp_ctrl_dai_read32_end(&otp_, &val), kDifOk);
EXPECT_EQ(val, 0x12345678);
}
TEST_F(DaiReadTest, Read64) {
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, true}});
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
OTP_CTRL_PARAM_SECRET2_OFFSET + 0x8);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_CMD_RD_BIT, true}});
EXPECT_EQ(dif_otp_ctrl_dai_read_start(&otp_, kDifOtpCtrlPartitionSecret2,
/*address=*/0x8),
kDifOk);
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, true}});
EXPECT_READ32(OTP_CTRL_DIRECT_ACCESS_RDATA_1_REG_OFFSET, 0x12345678);
EXPECT_READ32(OTP_CTRL_DIRECT_ACCESS_RDATA_0_REG_OFFSET, 0x90abcdef);
uint64_t val;
EXPECT_EQ(dif_otp_ctrl_dai_read64_end(&otp_, &val), kDifOk);
EXPECT_EQ(val, 0x1234567890abcdef);
}
TEST_F(DaiReadTest, Unaligned) {
EXPECT_EQ(dif_otp_ctrl_dai_read_start(&otp_, kDifOtpCtrlPartitionHwCfg,
/*address=*/0b01),
kDifUnaligned);
EXPECT_EQ(dif_otp_ctrl_dai_read_start(&otp_, kDifOtpCtrlPartitionSecret2,
/*address=*/0b100),
kDifUnaligned);
}
TEST_F(DaiReadTest, OutOfRange) {
EXPECT_EQ(dif_otp_ctrl_dai_read_start(&otp_, kDifOtpCtrlPartitionHwCfg,
/*address=*/0x100),
kDifOutOfRange);
}
TEST_F(DaiReadTest, Busy) {
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, false}});
EXPECT_EQ(dif_otp_ctrl_dai_read_start(&otp_, kDifOtpCtrlPartitionHwCfg,
/*address=*/0x0),
kDifUnavailable);
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, false}});
uint32_t val32;
EXPECT_EQ(dif_otp_ctrl_dai_read32_end(&otp_, &val32), kDifUnavailable);
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, false}});
uint64_t val64;
EXPECT_EQ(dif_otp_ctrl_dai_read64_end(&otp_, &val64), kDifUnavailable);
}
TEST_F(DaiReadTest, NullArgs) {
EXPECT_EQ(dif_otp_ctrl_dai_read_start(nullptr, kDifOtpCtrlPartitionHwCfg,
/*address=*/0x0),
kDifBadArg);
uint32_t val32;
EXPECT_EQ(dif_otp_ctrl_dai_read32_end(nullptr, &val32), kDifBadArg);
EXPECT_EQ(dif_otp_ctrl_dai_read32_end(&otp_, nullptr), kDifBadArg);
uint64_t val64;
EXPECT_EQ(dif_otp_ctrl_dai_read64_end(nullptr, &val64), kDifBadArg);
EXPECT_EQ(dif_otp_ctrl_dai_read64_end(&otp_, nullptr), kDifBadArg);
}
class DaiProgramTest : public OtpTest {};
TEST_F(DaiProgramTest, Program32) {
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, true}});
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
OTP_CTRL_PARAM_MANUF_STATE_OFFSET);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_WDATA_0_REG_OFFSET, 0x12345678);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_CMD_WR_BIT, true}});
EXPECT_EQ(dif_otp_ctrl_dai_program32(&otp_, kDifOtpCtrlPartitionHwCfg,
/*address=*/0x20, /*value=*/0x12345678),
kDifOk);
}
TEST_F(DaiProgramTest, Program64) {
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, true}});
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
OTP_CTRL_PARAM_SECRET2_OFFSET + 0x8);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_WDATA_0_REG_OFFSET, 0x90abcdef);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_WDATA_1_REG_OFFSET, 0x12345678);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_CMD_WR_BIT, true}});
EXPECT_EQ(
dif_otp_ctrl_dai_program64(&otp_, kDifOtpCtrlPartitionSecret2,
/*address=*/0x8, /*value=*/0x1234567890abcdef),
kDifOk);
}
TEST_F(DaiProgramTest, BadPartition) {
EXPECT_EQ(dif_otp_ctrl_dai_program32(&otp_, kDifOtpCtrlPartitionSecret1,
/*address=*/0x0, /*value=*/42),
kDifError);
EXPECT_EQ(dif_otp_ctrl_dai_program64(&otp_, kDifOtpCtrlPartitionHwCfg,
/*address=*/0x0, /*value=*/42),
kDifError);
// LC is never writeable.
EXPECT_EQ(dif_otp_ctrl_dai_program32(&otp_, kDifOtpCtrlPartitionLifeCycle,
/*address=*/0x0, /*value=*/42),
kDifError);
}
TEST_F(DaiProgramTest, Unaligned) {
EXPECT_EQ(dif_otp_ctrl_dai_program32(&otp_, kDifOtpCtrlPartitionHwCfg,
/*address=*/0b01, /*value=*/42),
kDifUnaligned);
EXPECT_EQ(dif_otp_ctrl_dai_program64(&otp_, kDifOtpCtrlPartitionSecret2,
/*address=*/0b100, /*value=*/42),
kDifUnaligned);
}
TEST_F(DaiProgramTest, OutOfRange) {
// Check that we can't write a digest directly.
EXPECT_EQ(dif_otp_ctrl_dai_program32(
&otp_, kDifOtpCtrlPartitionCreatorSwCfg,
/*address=*/OTP_CTRL_PARAM_CREATOR_SW_CFG_DIGEST_OFFSET,
/*value=*/42),
kDifOutOfRange);
// Same digest check for 64-bit.
EXPECT_EQ(dif_otp_ctrl_dai_program64(
&otp_, kDifOtpCtrlPartitionSecret2,
/*address=*/OTP_CTRL_PARAM_SECRET2_DIGEST_OFFSET, /*value=*/42),
kDifOutOfRange);
}
TEST_F(DaiProgramTest, Busy) {
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, false}});
EXPECT_EQ(dif_otp_ctrl_dai_program32(&otp_, kDifOtpCtrlPartitionHwCfg,
/*address=*/0x0, /*value=*/42),
kDifUnavailable);
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, false}});
EXPECT_EQ(dif_otp_ctrl_dai_program64(&otp_, kDifOtpCtrlPartitionSecret0,
/*address=*/0x0, /*value=*/42),
kDifUnavailable);
}
TEST_F(DaiProgramTest, NullArgs) {
EXPECT_EQ(dif_otp_ctrl_dai_program32(nullptr, kDifOtpCtrlPartitionHwCfg,
/*address=*/0x0, /*value=*/42),
kDifBadArg);
EXPECT_EQ(dif_otp_ctrl_dai_program64(nullptr, kDifOtpCtrlPartitionSecret0,
/*address=*/0x0, /*value=*/42),
kDifBadArg);
}
class DaiDigestTest : public OtpTest {};
TEST_F(DaiDigestTest, DigestSw) {
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, true}});
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
OTP_CTRL_PARAM_CREATOR_SW_CFG_DIGEST_OFFSET);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_WDATA_0_REG_OFFSET, 0x00abcdef);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_WDATA_1_REG_OFFSET, 0xabcdef00);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_CMD_WR_BIT, true}});
EXPECT_EQ(dif_otp_ctrl_dai_digest(&otp_, kDifOtpCtrlPartitionCreatorSwCfg,
/*digest=*/0xabcdef0000abcdef),
kDifOk);
}
TEST_F(DaiDigestTest, DigestHw) {
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, true}});
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_ADDRESS_REG_OFFSET,
OTP_CTRL_PARAM_DEVICE_ID_OFFSET);
EXPECT_WRITE32(OTP_CTRL_DIRECT_ACCESS_CMD_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_CMD_DIGEST_BIT, true}});
EXPECT_EQ(
dif_otp_ctrl_dai_digest(&otp_, kDifOtpCtrlPartitionHwCfg, /*digest=*/0),
kDifOk);
}
TEST_F(DaiDigestTest, BadPartition) {
EXPECT_EQ(dif_otp_ctrl_dai_digest(&otp_, kDifOtpCtrlPartitionLifeCycle,
/*digest=*/0),
kDifError);
}
TEST_F(DaiDigestTest, Busy) {
EXPECT_READ32(
OTP_CTRL_DIRECT_ACCESS_REGWEN_REG_OFFSET,
{{OTP_CTRL_DIRECT_ACCESS_REGWEN_DIRECT_ACCESS_REGWEN_BIT, false}});
EXPECT_EQ(
dif_otp_ctrl_dai_digest(&otp_, kDifOtpCtrlPartitionHwCfg, /*digest=*/0),
kDifUnavailable);
}
TEST_F(DaiDigestTest, BadDigest) {
EXPECT_EQ(dif_otp_ctrl_dai_digest(&otp_, kDifOtpCtrlPartitionHwCfg,
/*digest=*/0xabcdef0000abcdef),
kDifBadArg);
EXPECT_EQ(dif_otp_ctrl_dai_digest(&otp_, kDifOtpCtrlPartitionCreatorSwCfg,
/*digest=*/0),
kDifBadArg);
}
TEST_F(DaiDigestTest, NullArgs) {
EXPECT_EQ(dif_otp_ctrl_dai_digest(nullptr, kDifOtpCtrlPartitionCreatorSwCfg,
/*digest=*/0xabcdef0000abcdef),
kDifBadArg);
}
struct DigestParams {
dif_otp_ctrl_partition_t partition;
ptrdiff_t reg0, reg1;
};
class GetDigest : public OtpTest,
public testing::WithParamInterface<DigestParams> {};
TEST_P(GetDigest, GetDigest) {
if (GetParam().partition == kDifOtpCtrlPartitionLifeCycle) {
uint64_t digest;
EXPECT_EQ(dif_otp_ctrl_get_digest(&otp_, GetParam().partition, &digest),
kDifBadArg);
return;
}
EXPECT_READ32(GetParam().reg1, 0xabcdef99);
EXPECT_READ32(GetParam().reg0, 0x99abcdef);
uint64_t digest;
EXPECT_EQ(dif_otp_ctrl_get_digest(&otp_, GetParam().partition, &digest),
kDifOk);
EXPECT_EQ(digest, 0xabcdef9999abcdef);
}
TEST_P(GetDigest, BadDigest) {
if (GetParam().partition == kDifOtpCtrlPartitionLifeCycle) {
return;
}
EXPECT_READ32(GetParam().reg1, 0x0);
EXPECT_READ32(GetParam().reg0, 0x0);
uint64_t digest;
EXPECT_EQ(dif_otp_ctrl_get_digest(&otp_, GetParam().partition, &digest),
kDifError);
}
TEST_P(GetDigest, NullArgs) {
uint64_t digest;
EXPECT_EQ(dif_otp_ctrl_get_digest(nullptr, GetParam().partition, &digest),
kDifBadArg);
EXPECT_EQ(dif_otp_ctrl_get_digest(&otp_, GetParam().partition, nullptr),
kDifBadArg);
}
INSTANTIATE_TEST_SUITE_P(AllDigests, GetDigest,
testing::Values(
DigestParams{
kDifOtpCtrlPartitionCreatorSwCfg,
OTP_CTRL_CREATOR_SW_CFG_DIGEST_0_REG_OFFSET,
OTP_CTRL_CREATOR_SW_CFG_DIGEST_1_REG_OFFSET,
},
DigestParams{
kDifOtpCtrlPartitionOwnerSwCfg,
OTP_CTRL_OWNER_SW_CFG_DIGEST_0_REG_OFFSET,
OTP_CTRL_OWNER_SW_CFG_DIGEST_1_REG_OFFSET,
},
DigestParams{
kDifOtpCtrlPartitionHwCfg,
OTP_CTRL_HW_CFG_DIGEST_0_REG_OFFSET,
OTP_CTRL_HW_CFG_DIGEST_1_REG_OFFSET,
},
DigestParams{
kDifOtpCtrlPartitionSecret0,
OTP_CTRL_SECRET0_DIGEST_0_REG_OFFSET,
OTP_CTRL_SECRET0_DIGEST_1_REG_OFFSET,
},
DigestParams{
kDifOtpCtrlPartitionSecret1,
OTP_CTRL_SECRET1_DIGEST_0_REG_OFFSET,
OTP_CTRL_SECRET1_DIGEST_1_REG_OFFSET,
},
DigestParams{
kDifOtpCtrlPartitionSecret2,
OTP_CTRL_SECRET2_DIGEST_0_REG_OFFSET,
OTP_CTRL_SECRET2_DIGEST_1_REG_OFFSET,
},
DigestParams{
kDifOtpCtrlPartitionLifeCycle,
0,
0,
}));
class BlockingIoTest : public OtpTest {
protected:
static constexpr size_t kWords = 4;
};
TEST_F(BlockingIoTest, Read) {
for (size_t i = 0; i < kWords; ++i) {
auto offset =
OTP_CTRL_PARAM_OWNER_SW_CFG_OFFSET + 0x10 + i * sizeof(uint32_t);
EXPECT_READ32(OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET + offset, i + 1);
}
std::vector<uint32_t> buf(kWords);
EXPECT_EQ(dif_otp_ctrl_read_blocking(&otp_, kDifOtpCtrlPartitionOwnerSwCfg,
0x10, buf.data(), buf.size()),
kDifOk);
EXPECT_THAT(buf, ElementsAre(1, 2, 3, 4));
}
TEST_F(BlockingIoTest, BadPartition) {
std::vector<uint32_t> buf(kWords);
EXPECT_EQ(dif_otp_ctrl_read_blocking(&otp_, kDifOtpCtrlPartitionHwCfg, 0x10,
buf.data(), buf.size()),
kDifError);
}
TEST_F(BlockingIoTest, Unaligned) {
std::vector<uint32_t> buf(kWords);
EXPECT_EQ(dif_otp_ctrl_read_blocking(&otp_, kDifOtpCtrlPartitionOwnerSwCfg,
0x11, buf.data(), buf.size()),
kDifUnaligned);
}
TEST_F(BlockingIoTest, OutOfRange) {
std::vector<uint32_t> buf(0x2f0);
EXPECT_EQ(dif_otp_ctrl_read_blocking(&otp_, kDifOtpCtrlPartitionOwnerSwCfg,
0x300, buf.data(), buf.size()),
kDifOutOfRange);
EXPECT_EQ(dif_otp_ctrl_read_blocking(&otp_, kDifOtpCtrlPartitionOwnerSwCfg,
0x10, buf.data(), 0x330),
kDifOutOfRange);
}
TEST_F(BlockingIoTest, NullArgs) {
std::vector<uint32_t> buf(kWords);
EXPECT_EQ(dif_otp_ctrl_read_blocking(nullptr, kDifOtpCtrlPartitionOwnerSwCfg,
0x10, buf.data(), buf.size()),
kDifBadArg);
EXPECT_EQ(dif_otp_ctrl_read_blocking(&otp_, kDifOtpCtrlPartitionOwnerSwCfg,
0x10, nullptr, buf.size()),
kDifBadArg);
}
} // namespace
} // namespace dif_otp_ctrl_unittest