[sw/silicon_creator] Add driver for retention SRAM
Add a simple driver that provides typed access to the retention SRAM
and a function to clear it.
This change puts in place a temporary memory map that will need to
be updated when #5760 is finalized.
Signed-off-by: Michael Munday <mike.munday@lowrisc.org>
diff --git a/sw/device/silicon_creator/lib/drivers/meson.build b/sw/device/silicon_creator/lib/drivers/meson.build
index c81a33b..e7a36c5 100644
--- a/sw/device/silicon_creator/lib/drivers/meson.build
+++ b/sw/device/silicon_creator/lib/drivers/meson.build
@@ -318,6 +318,35 @@
suite: 'mask_rom',
)
+# Mask ROM retention SRAM driver
+sw_silicon_creator_lib_driver_retention_sram = declare_dependency(
+ link_with: static_library(
+ 'sw_silicon_creator_lib_driver_retention_sram',
+ sources: [
+ hw_ip_sram_ctrl_reg_h,
+ 'retention_sram.c',
+ ],
+ dependencies: [
+ sw_silicon_creator_lib_base_abs_mmio,
+ ],
+ ),
+)
+
+sw_silicon_creator_lib_driver_retention_sram_functest = declare_dependency(
+ link_with: static_library(
+ 'sw_silicon_creator_lib_driver_retention_sram_functest',
+ sources: ['retention_sram_functest.c'],
+ dependencies: [
+ sw_silicon_creator_lib_driver_retention_sram,
+ ],
+ ),
+)
+mask_rom_tests += {
+ 'sw_silicon_creator_lib_driver_retention_sram_functest': {
+ 'library': sw_silicon_creator_lib_driver_retention_sram_functest,
+ }
+}
+
# Mask ROM watchdog driver
sw_silicon_creator_lib_driver_watchdog = declare_dependency(
link_with: static_library(
@@ -393,6 +422,7 @@
'watchdog_functest.c'
],
dependencies: [
+ sw_silicon_creator_lib_driver_retention_sram,
sw_silicon_creator_lib_driver_rstmgr,
sw_silicon_creator_lib_driver_watchdog,
],
diff --git a/sw/device/silicon_creator/lib/drivers/retention_sram.c b/sw/device/silicon_creator/lib/drivers/retention_sram.c
new file mode 100644
index 0000000..56f2c0e
--- /dev/null
+++ b/sw/device/silicon_creator/lib/drivers/retention_sram.c
@@ -0,0 +1,19 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "sw/device/silicon_creator/lib/drivers/retention_sram.h"
+
+#include <assert.h>
+
+#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
+
+volatile retention_sram_t *retention_sram_get(void) {
+ static_assert(sizeof(retention_sram_t) == TOP_EARLGREY_RAM_RET_AON_SIZE_BYTES,
+ "Unexpected retention SRAM size.");
+ return (volatile retention_sram_t *)TOP_EARLGREY_RAM_RET_AON_BASE_ADDR;
+}
+
+void retention_sram_clear(void) {
+ *retention_sram_get() = (retention_sram_t){0};
+}
diff --git a/sw/device/silicon_creator/lib/drivers/retention_sram.h b/sw/device/silicon_creator/lib/drivers/retention_sram.h
new file mode 100644
index 0000000..6744448
--- /dev/null
+++ b/sw/device/silicon_creator/lib/drivers/retention_sram.h
@@ -0,0 +1,84 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_DRIVERS_RETENTION_SRAM_H_
+#define OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_DRIVERS_RETENTION_SRAM_H_
+
+#include "sw/device/lib/base/macros.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The retention SRAM is memory that is used to retain information, such as a
+ * boot service request, across a device reset. If the reset reason is 'power
+ * on' (POR) all fields will be initialized to zero by the mask ROM.
+ *
+ * TODO(lowRISC/opentitan#5760): the memory map for the retention SRAM is not
+ * yet finalized. When it is the layout and content of this structure should
+ * be frozen.
+ */
+typedef struct retention_sram {
+ /**
+ * A boot services request.
+ *
+ * TODO(lowRISC/opentitan#5760): enumerate boot service identifiers.
+ */
+ uint32_t boot_info;
+
+ /**
+ * Space reserved for future allocation by the silicon creator.
+ *
+ * TODO(lowRISC/opentitan#5760): the size / offset of this allocation should
+ * be reviewed.
+ */
+ uint32_t reserved_creator[447];
+
+ /**
+ * Panic record.
+ *
+ * TODO(lowRISC/opentitan#5760): placeholder, this is for saving a detailed
+ * crashdump record when the CPU is able to respond to a fault or alert
+ * escalation. The size / offset of this allocation should be reviewed.
+ */
+ uint32_t panic_record[256 / sizeof(uint32_t)];
+
+ /**
+ * Space reserved for allocation by the silicon owner.
+ *
+ * The silcon creator boot stages will not modify this field except for
+ * clearing it at initial power on.
+ *
+ * Tests that need to trigger (or detect) a device reset may use this field to
+ * preserve state information across resets.
+ *
+ * TODO(lowRISC/opentitan#5760): the size / offset of this allocation should
+ * be reviewed.
+ */
+ uint32_t reserved_owner[2048 / sizeof(uint32_t)];
+} retention_sram_t;
+
+OT_ASSERT_MEMBER_OFFSET(retention_sram_t, boot_info, 0);
+OT_ASSERT_MEMBER_OFFSET(retention_sram_t, panic_record, 1792);
+OT_ASSERT_MEMBER_OFFSET(retention_sram_t, reserved_owner, 2048);
+OT_ASSERT_SIZE(retention_sram_t, 4096);
+
+/**
+ * Returns a typed pointer to the retention SRAM.
+ *
+ * @return A pointer to the retention SRAM.
+ */
+volatile retention_sram_t *retention_sram_get(void);
+
+/**
+ * Clear the retention SRAM by setting every word to 0.
+ */
+void retention_sram_clear(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_DRIVERS_RETENTION_SRAM_H_
diff --git a/sw/device/silicon_creator/lib/drivers/retention_sram_functest.c b/sw/device/silicon_creator/lib/drivers/retention_sram_functest.c
new file mode 100644
index 0000000..ab92318
--- /dev/null
+++ b/sw/device/silicon_creator/lib/drivers/retention_sram_functest.c
@@ -0,0 +1,48 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "sw/device/lib/base/memory.h"
+#include "sw/device/lib/runtime/log.h"
+#include "sw/device/lib/runtime/print.h"
+#include "sw/device/silicon_creator/lib/drivers/retention_sram.h"
+#include "sw/device/silicon_creator/lib/error.h"
+#include "sw/device/silicon_creator/lib/test_main.h"
+
+#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
+
+static rom_error_t retention_sram_clear_test(void) {
+ // Set every bit in the retention SRAM to one.
+ // Note: memset cannot be used directly because it discards the volatile
+ // qualifier.
+ volatile retention_sram_t *ret = retention_sram_get();
+ retention_sram_t ones;
+ memset(&ones, 0xff, sizeof(retention_sram_t));
+ *ret = ones;
+
+ // Clear the retention SRAM (set every bit to zero).
+ retention_sram_clear();
+
+ // Check that the retention SRAM was fully cleared.
+ // Note: memcmp cannot be used directly because it discards the volatile
+ // qualifier.
+ retention_sram_t zeros;
+ memset(&zeros, 0, sizeof(retention_sram_t));
+ retention_sram_t result = *ret;
+ if (memcmp(&zeros, &result, sizeof(retention_sram_t)) != 0) {
+ LOG_ERROR("Retention SRAM not cleared.");
+ return kErrorUnknown; // Unreachable.
+ }
+ return kErrorOk;
+}
+
+const test_config_t kTestConfig;
+
+bool test_main(void) {
+ rom_error_t result = kErrorOk;
+ EXECUTE_TEST(result, retention_sram_clear_test);
+ return result == kErrorOk;
+}
diff --git a/sw/device/silicon_creator/lib/drivers/watchdog_functest.c b/sw/device/silicon_creator/lib/drivers/watchdog_functest.c
index 1d478ff..972d3d7 100644
--- a/sw/device/silicon_creator/lib/drivers/watchdog_functest.c
+++ b/sw/device/silicon_creator/lib/drivers/watchdog_functest.c
@@ -13,6 +13,7 @@
#include "sw/device/lib/runtime/print.h"
#include "sw/device/lib/testing/check.h"
#include "sw/device/silicon_creator/lib/base/abs_mmio.h"
+#include "sw/device/silicon_creator/lib/drivers/retention_sram.h"
#include "sw/device/silicon_creator/lib/drivers/rstmgr.h"
#include "sw/device/silicon_creator/lib/drivers/watchdog.h"
#include "sw/device/silicon_creator/lib/error.h"
@@ -21,9 +22,6 @@
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
#include "rstmgr_regs.h"
-void *const kRetentionRamBase = (void *)TOP_EARLGREY_RAM_RET_AON_BASE_ADDR;
-const size_t kRetentionRamSize = TOP_EARLGREY_RAM_RET_AON_SIZE_BYTES;
-
// Tests that we can pet the watchdog and avoid a reset.
rom_error_t watchdog_pet_test(void) {
watchdog_init(500);
@@ -68,10 +66,13 @@
// This test assumes the reset reason is unique.
CHECK(bitfield_popcount32(reason) == 1, "Expected exactly 1 reset reason.");
- volatile test_phase_t *phase = (volatile test_phase_t *)kRetentionRamBase;
+ // Use the part of the retention SRAM reserved for the silicon owner to
+ // store the test phase.
+ volatile uint32_t *phase = &retention_sram_get()->reserved_owner[0];
+
if (bitfield_bit32_read(reason, kRstmgrReasonPowerOn)) {
// Power-on: zero out the retention RAM.
- memset(kRetentionRamBase, 0, kRetentionRamSize);
+ retention_sram_clear();
*phase = kTestPhasePet;
EXECUTE_TEST(result, watchdog_pet_test);
diff --git a/sw/device/silicon_creator/lib/irq_asm_functest.c b/sw/device/silicon_creator/lib/irq_asm_functest.c
index d33036c..dd5f757 100644
--- a/sw/device/silicon_creator/lib/irq_asm_functest.c
+++ b/sw/device/silicon_creator/lib/irq_asm_functest.c
@@ -13,6 +13,7 @@
#include "sw/device/lib/runtime/print.h"
#include "sw/device/lib/testing/check.h"
#include "sw/device/silicon_creator/lib/base/abs_mmio.h"
+#include "sw/device/silicon_creator/lib/drivers/retention_sram.h"
#include "sw/device/silicon_creator/lib/drivers/rstmgr.h"
#include "sw/device/silicon_creator/lib/drivers/watchdog.h"
#include "sw/device/silicon_creator/lib/error.h"
@@ -20,9 +21,6 @@
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
-void *const kRetentionRamBase = (void *)TOP_EARLGREY_RAM_RET_AON_BASE_ADDR;
-const size_t kRetentionRamSize = TOP_EARLGREY_RAM_RET_AON_SIZE_BYTES;
-
/**
* Exception handler written in assembly.
*
@@ -51,10 +49,13 @@
// This test assumes the reset reason is unique.
CHECK(bitfield_popcount32(reason) == 1, "Expected exactly 1 reset reason.");
- volatile test_phase_t *phase = (volatile test_phase_t *)kRetentionRamBase;
+ // Use the part of the retention SRAM reserved for the silicon owner to
+ // store the test phase.
+ volatile uint32_t *phase = &retention_sram_get()->reserved_owner[0];
+
if (bitfield_bit32_read(reason, kRstmgrReasonPowerOn)) {
// Power-on: zero out the retention RAM.
- memset(kRetentionRamBase, 0, kRetentionRamSize);
+ retention_sram_clear();
LOG_INFO("Calling exception handler to reset device.");
*phase = kTestPhaseReset;
diff --git a/sw/device/silicon_creator/lib/meson.build b/sw/device/silicon_creator/lib/meson.build
index 62000c3..a1c55a3 100644
--- a/sw/device/silicon_creator/lib/meson.build
+++ b/sw/device/silicon_creator/lib/meson.build
@@ -236,6 +236,7 @@
],
dependencies: [
sw_silicon_creator_lib_irq_asm,
+ sw_silicon_creator_lib_driver_retention_sram,
sw_silicon_creator_lib_driver_rstmgr,
sw_silicon_creator_lib_driver_watchdog,
],
diff --git a/test/systemtest/earlgrey/config.py b/test/systemtest/earlgrey/config.py
index e8c626c..63f2c64 100644
--- a/test/systemtest/earlgrey/config.py
+++ b/test/systemtest/earlgrey/config.py
@@ -134,6 +134,10 @@
"test_dir": "sw/device/silicon_creator/testing",
},
{
+ "name": "sw_silicon_creator_lib_driver_retention_sram_functest",
+ "test_dir": "sw/device/silicon_creator/testing",
+ },
+ {
"name": "sw_silicon_creator_lib_driver_alert_functest",
"test_dir": "sw/device/silicon_creator/testing",
# TODO(lowRISC/opentitan#6965) This test resets the chip and appears to