[sw, dif_clkmgr] Add clock manager DIF unit tests.
Also fix typo in meson build target for generated clock manager
header.
Signed-off-by: Michael Munday <mike.munday@lowrisc.org>
diff --git a/meson.build b/meson.build
index 8183a7c..246bb55 100644
--- a/meson.build
+++ b/meson.build
@@ -209,7 +209,7 @@
hw_ip_aes_reg_h = gen_hw_hdr.process('hw/ip/aes/data/aes.hjson')
hw_ip_alert_handler_reg_h = gen_hw_hdr.process('hw/ip/alert_handler/data/alert_handler.hjson')
hw_ip_aon_timer_reg_h = gen_hw_hdr.process('hw/ip/aon_timer/data/aon_timer.hjson')
-hw_ip_clkgmr_reg_h = gen_hw_hdr.process('hw/' + TOPNAME + '/ip/clkmgr/data/autogen/clkmgr.hjson')
+hw_ip_clkmgr_reg_h = gen_hw_hdr.process('hw/' + TOPNAME + '/ip/clkmgr/data/autogen/clkmgr.hjson')
hw_ip_flash_ctrl_reg_h = gen_hw_hdr.process('hw/' + TOPNAME + '/ip/flash_ctrl/data/autogen/flash_ctrl.hjson')
hw_ip_gpio_reg_h = gen_hw_hdr.process('hw/ip/gpio/data/gpio.hjson')
hw_ip_hmac_reg_h = gen_hw_hdr.process('hw/ip/hmac/data/hmac.hjson')
diff --git a/sw/device/lib/dif/dif_clkmgr.md b/sw/device/lib/dif/dif_clkmgr.md
index 0d3ec4c..7cbc294 100644
--- a/sw/device/lib/dif/dif_clkmgr.md
+++ b/sw/device/lib/dif/dif_clkmgr.md
@@ -11,7 +11,7 @@
---------------|----------------------|-------------|------------------
Implementation | [DIF_EXISTS][] | Done |
Implementation | [DIF_USED_IN_TREE][] | Not Started |
-Tests | [DIF_TEST_UNIT][] | Not Started |
+Tests | [DIF_TEST_UNIT][] | Done |
Tests | [DIF_TEST_SANITY][] | Not Started |
[DIF_EXISTS]: {{< relref "/doc/project/checklist.md#dif_exists" >}}
diff --git a/sw/device/lib/dif/meson.build b/sw/device/lib/dif/meson.build
index cabfee9..6937d7c 100644
--- a/sw/device/lib/dif/meson.build
+++ b/sw/device/lib/dif/meson.build
@@ -7,7 +7,7 @@
link_with: static_library(
'clkmgr_ot',
sources: [
- hw_ip_clkgmr_reg_h,
+ hw_ip_clkmgr_reg_h,
'dif_clkmgr.c',
],
dependencies: [
diff --git a/sw/device/tests/dif/dif_clkmgr_unittest.cc b/sw/device/tests/dif/dif_clkmgr_unittest.cc
new file mode 100644
index 0000000..2f61ab2
--- /dev/null
+++ b/sw/device/tests/dif/dif_clkmgr_unittest.cc
@@ -0,0 +1,314 @@
+// 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_clkmgr.h"
+
+#include "gtest/gtest.h"
+#include "sw/device/lib/base/mmio.h"
+#include "sw/device/lib/testing/mock_mmio.h"
+
+// Generated.
+#include "clkmgr_regs.h"
+
+// Last bits are not provided by the generated header.
+// TODO: https://github.com/lowRISC/opentitan/issues/3932
+#define CLKMGR_CLK_ENABLES_LAST_BIT CLKMGR_CLK_ENABLES_CLK_USB_PERI_EN_BIT
+#define CLKMGR_CLK_HINTS_LAST_BIT CLKMGR_CLK_HINTS_CLK_MAIN_OTBN_HINT_BIT
+#define CLKMGR_CLK_HINTS_STATUS_LAST_BIT \
+ CLKMGR_CLK_HINTS_STATUS_CLK_MAIN_OTBN_VAL_BIT
+
+namespace dif_clkmgr_unittest {
+namespace {
+using mock_mmio::MmioTest;
+using mock_mmio::MockDevice;
+using testing::Test;
+
+class ClkMgrTest : public Test, public MmioTest {
+ protected:
+ const dif_clkmgr_params_t params_ = {
+ .base_addr = dev().region(),
+ .last_gateable_clock = CLKMGR_CLK_ENABLES_LAST_BIT,
+ .last_hintable_clock = CLKMGR_CLK_HINTS_LAST_BIT};
+ dif_clkmgr_t clkmgr_;
+ ClkMgrTest() {
+ EXPECT_EQ(CLKMGR_CLK_HINTS_LAST_BIT, CLKMGR_CLK_HINTS_STATUS_LAST_BIT);
+ EXPECT_EQ(dif_clkmgr_init(params_, &clkmgr_), kDifClkmgrOk);
+ }
+};
+
+class InitTest : public ClkMgrTest {};
+
+TEST_F(InitTest, Error) {
+ // Null handle.
+ EXPECT_EQ(dif_clkmgr_init(params_, nullptr), kDifClkmgrBadArg);
+
+ // Out-of-bounds last gateable clock.
+ {
+ dif_clkmgr_t clkmgr;
+ dif_clkmgr_params_t bad_gateable = params_;
+ bad_gateable.last_gateable_clock = CLKMGR_PARAM_REG_WIDTH;
+ EXPECT_EQ(dif_clkmgr_init(bad_gateable, &clkmgr), kDifClkmgrBadArg);
+ }
+ {
+ dif_clkmgr_t clkmgr;
+ dif_clkmgr_params_t bad_gateable = params_;
+ bad_gateable.last_gateable_clock =
+ std::numeric_limits<dif_clkmgr_gateable_clock_t>::max();
+ EXPECT_EQ(dif_clkmgr_init(bad_gateable, &clkmgr), kDifClkmgrBadArg);
+ }
+
+ // Out-of-bounds last hintable clock.
+ {
+ dif_clkmgr_t clkmgr;
+ dif_clkmgr_params_t bad_hintable = params_;
+ bad_hintable.last_hintable_clock = CLKMGR_PARAM_REG_WIDTH;
+ EXPECT_EQ(dif_clkmgr_init(bad_hintable, &clkmgr), kDifClkmgrBadArg);
+ }
+ {
+ dif_clkmgr_t clkmgr;
+ dif_clkmgr_params_t bad_hintable = params_;
+ bad_hintable.last_hintable_clock =
+ std::numeric_limits<dif_clkmgr_hintable_clock_t>::max();
+ EXPECT_EQ(dif_clkmgr_init(bad_hintable, &clkmgr), kDifClkmgrBadArg);
+ }
+}
+
+class GateableClockTest : public ClkMgrTest {};
+
+TEST_F(GateableClockTest, SetEnabled) {
+ // Disable gateable clock.
+ EXPECT_MASK32(CLKMGR_CLK_ENABLES_REG_OFFSET,
+ {{CLKMGR_CLK_ENABLES_CLK_IO_DIV4_PERI_EN_BIT, 0x1, false}});
+ EXPECT_EQ(dif_clkmgr_gateable_clock_set_enabled(
+ &clkmgr_, CLKMGR_CLK_ENABLES_CLK_IO_DIV4_PERI_EN_BIT,
+ kDifClkmgrToggleDisabled),
+ kDifClkmgrOk);
+
+ // Enable gateable clock.
+ EXPECT_MASK32(CLKMGR_CLK_ENABLES_REG_OFFSET,
+ {{CLKMGR_CLK_ENABLES_CLK_USB_PERI_EN_BIT, 0x1, true}});
+ EXPECT_EQ(dif_clkmgr_gateable_clock_set_enabled(
+ &clkmgr_, CLKMGR_CLK_ENABLES_CLK_USB_PERI_EN_BIT,
+ kDifClkmgrToggleEnabled),
+ kDifClkmgrOk);
+}
+
+TEST_F(GateableClockTest, SetEnabledError) {
+ // Null handle.
+ EXPECT_EQ(dif_clkmgr_gateable_clock_set_enabled(
+ nullptr, CLKMGR_CLK_ENABLES_CLK_IO_DIV4_PERI_EN_BIT,
+ kDifClkmgrToggleEnabled),
+ kDifClkmgrBadArg);
+
+ // Out-of-bounds index [~0].
+ EXPECT_EQ(
+ dif_clkmgr_gateable_clock_set_enabled(
+ &clkmgr_, std::numeric_limits<dif_clkmgr_gateable_clock_t>::max(),
+ kDifClkmgrToggleEnabled),
+ kDifClkmgrBadArg);
+
+ // Out-of-bounds index [last+1].
+ EXPECT_EQ(
+ dif_clkmgr_gateable_clock_set_enabled(
+ &clkmgr_, CLKMGR_CLK_ENABLES_LAST_BIT + 1, kDifClkmgrToggleDisabled),
+ kDifClkmgrBadArg);
+}
+
+TEST_F(GateableClockTest, GetEnabled) {
+ // Get gateable clock status (enabled).
+ {
+ bool enabled = false;
+ EXPECT_READ32(CLKMGR_CLK_ENABLES_REG_OFFSET,
+ {{CLKMGR_CLK_ENABLES_CLK_IO_DIV4_PERI_EN_BIT, true}});
+ EXPECT_EQ(
+ dif_clkmgr_gateable_clock_get_enabled(
+ &clkmgr_, CLKMGR_CLK_ENABLES_CLK_IO_DIV4_PERI_EN_BIT, &enabled),
+ kDifClkmgrOk);
+ EXPECT_TRUE(enabled);
+ }
+
+ // Get gateable clock status (disabled).
+ {
+ bool enabled = true;
+ EXPECT_READ32(CLKMGR_CLK_ENABLES_REG_OFFSET,
+ {{CLKMGR_CLK_ENABLES_CLK_USB_PERI_EN_BIT, false}});
+ EXPECT_EQ(dif_clkmgr_gateable_clock_get_enabled(
+ &clkmgr_, CLKMGR_CLK_ENABLES_CLK_USB_PERI_EN_BIT, &enabled),
+ kDifClkmgrOk);
+ EXPECT_FALSE(enabled);
+ }
+}
+
+TEST_F(GateableClockTest, GetEnabledError) {
+ bool enabled = false;
+
+ // Null handle.
+ EXPECT_EQ(dif_clkmgr_gateable_clock_get_enabled(
+ nullptr, CLKMGR_CLK_ENABLES_CLK_IO_DIV4_PERI_EN_BIT, &enabled),
+ kDifClkmgrBadArg);
+
+ // Null result.
+ EXPECT_EQ(dif_clkmgr_gateable_clock_get_enabled(
+ &clkmgr_, CLKMGR_CLK_ENABLES_CLK_IO_DIV4_PERI_EN_BIT, nullptr),
+ kDifClkmgrBadArg);
+
+ // Out-of-bounds index [~0].
+ EXPECT_EQ(
+ dif_clkmgr_gateable_clock_get_enabled(
+ &clkmgr_, std::numeric_limits<dif_clkmgr_gateable_clock_t>::max(),
+ &enabled),
+ kDifClkmgrBadArg);
+
+ // Out-of-bounds index [last+1].
+ EXPECT_EQ(dif_clkmgr_gateable_clock_get_enabled(
+ &clkmgr_, CLKMGR_CLK_ENABLES_LAST_BIT + 1, &enabled),
+ kDifClkmgrBadArg);
+}
+
+class HintableClockTest : public ClkMgrTest {};
+
+TEST_F(HintableClockTest, SetHint) {
+ // Disable hint.
+ EXPECT_MASK32(CLKMGR_CLK_HINTS_REG_OFFSET,
+ {{CLKMGR_CLK_HINTS_CLK_MAIN_AES_HINT_BIT, 0x1, false}});
+ EXPECT_EQ(dif_clkmgr_hintable_clock_set_hint(
+ &clkmgr_, CLKMGR_CLK_HINTS_CLK_MAIN_AES_HINT_BIT,
+ kDifClkmgrToggleDisabled),
+ kDifClkmgrOk);
+
+ // Enable hint.
+ EXPECT_MASK32(CLKMGR_CLK_HINTS_REG_OFFSET,
+ {{CLKMGR_CLK_HINTS_LAST_BIT, 0x1, true}});
+ EXPECT_EQ(dif_clkmgr_hintable_clock_set_hint(
+ &clkmgr_, CLKMGR_CLK_HINTS_LAST_BIT, kDifClkmgrToggleEnabled),
+ kDifClkmgrOk);
+}
+
+TEST_F(HintableClockTest, SetHintError) {
+ // Null handle.
+ EXPECT_EQ(dif_clkmgr_hintable_clock_set_hint(
+ nullptr, CLKMGR_CLK_HINTS_CLK_MAIN_AES_HINT_BIT,
+ kDifClkmgrToggleEnabled),
+ kDifClkmgrBadArg);
+
+ // Out-of-bounds index [~0].
+ EXPECT_EQ(
+ dif_clkmgr_hintable_clock_set_hint(
+ &clkmgr_, std::numeric_limits<dif_clkmgr_hintable_clock_t>::max(),
+ kDifClkmgrToggleEnabled),
+ kDifClkmgrBadArg);
+
+ // Out-of-bounds index [last+1].
+ EXPECT_EQ(
+ dif_clkmgr_hintable_clock_set_hint(
+ &clkmgr_, CLKMGR_CLK_HINTS_LAST_BIT + 1, kDifClkmgrToggleDisabled),
+ kDifClkmgrBadArg);
+}
+
+TEST_F(HintableClockTest, GetHint) {
+ // Get hint state (enabled).
+ {
+ bool enabled = false;
+ EXPECT_READ32(CLKMGR_CLK_HINTS_REG_OFFSET,
+ {{CLKMGR_CLK_HINTS_CLK_MAIN_AES_HINT_BIT, true}});
+ EXPECT_EQ(dif_clkmgr_hintable_clock_get_hint(
+ &clkmgr_, CLKMGR_CLK_HINTS_CLK_MAIN_AES_HINT_BIT, &enabled),
+ kDifClkmgrOk);
+ EXPECT_TRUE(enabled);
+ }
+
+ // Get hint state (disabled).
+ {
+ bool enabled = true;
+ EXPECT_READ32(CLKMGR_CLK_HINTS_REG_OFFSET,
+ {{CLKMGR_CLK_HINTS_CLK_MAIN_OTBN_HINT_BIT, false}});
+ EXPECT_EQ(dif_clkmgr_hintable_clock_get_hint(
+ &clkmgr_, CLKMGR_CLK_HINTS_CLK_MAIN_OTBN_HINT_BIT, &enabled),
+ kDifClkmgrOk);
+ EXPECT_FALSE(enabled);
+ }
+}
+
+TEST_F(HintableClockTest, GetHintError) {
+ bool enabled = false;
+
+ // Null handle.
+ EXPECT_EQ(dif_clkmgr_hintable_clock_get_hint(
+ nullptr, CLKMGR_CLK_HINTS_CLK_MAIN_AES_HINT_BIT, &enabled),
+ kDifClkmgrBadArg);
+
+ // Null result.
+ EXPECT_EQ(dif_clkmgr_hintable_clock_get_hint(
+ &clkmgr_, CLKMGR_CLK_HINTS_CLK_MAIN_AES_HINT_BIT, nullptr),
+ kDifClkmgrBadArg);
+
+ // Out-of-bounds index [~0].
+ EXPECT_EQ(
+ dif_clkmgr_hintable_clock_get_hint(
+ &clkmgr_, std::numeric_limits<dif_clkmgr_hintable_clock_t>::max(),
+ &enabled),
+ kDifClkmgrBadArg);
+
+ // Out-of-bounds index [last+1].
+ EXPECT_EQ(dif_clkmgr_hintable_clock_get_hint(
+ &clkmgr_, CLKMGR_CLK_HINTS_LAST_BIT + 1, &enabled),
+ kDifClkmgrBadArg);
+}
+
+TEST_F(HintableClockTest, GetEnabled) {
+ // Get hintable clock status (enabled).
+ {
+ bool enabled = true;
+ EXPECT_READ32(CLKMGR_CLK_HINTS_STATUS_REG_OFFSET,
+ {{CLKMGR_CLK_HINTS_STATUS_CLK_MAIN_AES_VAL_BIT, false}});
+ EXPECT_EQ(
+ dif_clkmgr_hintable_clock_get_enabled(
+ &clkmgr_, CLKMGR_CLK_HINTS_STATUS_CLK_MAIN_AES_VAL_BIT, &enabled),
+ kDifClkmgrOk);
+ EXPECT_FALSE(enabled);
+ }
+
+ // Get hintable clock status (disabled).
+ {
+ bool enabled = false;
+ EXPECT_READ32(CLKMGR_CLK_HINTS_STATUS_REG_OFFSET,
+ {{CLKMGR_CLK_HINTS_STATUS_CLK_MAIN_OTBN_VAL_BIT, true}});
+ EXPECT_EQ(
+ dif_clkmgr_hintable_clock_get_enabled(
+ &clkmgr_, CLKMGR_CLK_HINTS_STATUS_CLK_MAIN_OTBN_VAL_BIT, &enabled),
+ kDifClkmgrOk);
+ EXPECT_TRUE(enabled);
+ }
+}
+
+TEST_F(HintableClockTest, GetEnabledError) {
+ bool enabled = false;
+
+ // Null handle.
+ EXPECT_EQ(
+ dif_clkmgr_hintable_clock_get_enabled(
+ nullptr, CLKMGR_CLK_HINTS_STATUS_CLK_MAIN_AES_VAL_BIT, &enabled),
+ kDifClkmgrBadArg);
+
+ // Null result.
+ EXPECT_EQ(
+ dif_clkmgr_hintable_clock_get_enabled(
+ &clkmgr_, CLKMGR_CLK_HINTS_STATUS_CLK_MAIN_AES_VAL_BIT, nullptr),
+ kDifClkmgrBadArg);
+
+ // Out-of-bounds index [~0].
+ EXPECT_EQ(
+ dif_clkmgr_hintable_clock_get_enabled(
+ &clkmgr_, std::numeric_limits<dif_clkmgr_hintable_clock_t>::max(),
+ &enabled),
+ kDifClkmgrBadArg);
+
+ // Out-of-bounds index [last+1].
+ EXPECT_EQ(dif_clkmgr_hintable_clock_get_enabled(
+ &clkmgr_, CLKMGR_CLK_HINTS_STATUS_LAST_BIT + 1, &enabled),
+ kDifClkmgrBadArg);
+}
+
+} // namespace
+} // namespace dif_clkmgr_unittest
diff --git a/sw/device/tests/dif/meson.build b/sw/device/tests/dif/meson.build
index 0c43caf..18da744 100644
--- a/sw/device/tests/dif/meson.build
+++ b/sw/device/tests/dif/meson.build
@@ -210,6 +210,22 @@
cpp_args: ['-DMOCK_MMIO'],
))
+test('dif_clkmgr_unittest', executable(
+ 'dif_clkmgr_unittest',
+ sources: [
+ hw_ip_clkmgr_reg_h,
+ meson.source_root() / 'sw/device/lib/dif/dif_clkmgr.c',
+ 'dif_clkmgr_unittest.cc',
+ ],
+ dependencies: [
+ sw_vendor_gtest,
+ sw_lib_testing_mock_mmio,
+ ],
+ native: true,
+ c_args: ['-DMOCK_MMIO'],
+ cpp_args: ['-DMOCK_MMIO'],
+))
+
dif_plic_smoketest_lib = declare_dependency(
link_with: static_library(
'dif_plic_smoketest_lib',