| // 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/testing/sram_ctrl_testutils.h" |
| |
| #include "sw/device/lib/base/mmio.h" |
| #include "sw/device/lib/dif/dif_sram_ctrl.h" |
| #include "sw/device/lib/runtime/ibex.h" |
| #include "sw/device/lib/runtime/log.h" |
| #include "sw/device/lib/testing/check.h" |
| |
| void sram_ctrl_testutils_write(uintptr_t address, |
| const sram_ctrl_testutils_data_t *data) { |
| mmio_region_t region = mmio_region_from_addr(address); |
| for (size_t index = 0; index < SRAM_CTRL_TESTUTILS_DATA_NUM_WORDS; ++index) { |
| mmio_region_write32(region, index, data->words[index]); |
| } |
| } |
| |
| /** |
| * Reads data from `address` in SRAM and compares against `expected`. |
| * |
| * The read data is word by word compared against the expected data. |
| * Caller can request to check for equality or inequality through `eq`. |
| */ |
| static bool read_from_ram_check(uintptr_t address, |
| const sram_ctrl_testutils_data_t *expected, |
| bool eq) { |
| mmio_region_t region = mmio_region_from_addr(address); |
| for (size_t index = 0; index < SRAM_CTRL_TESTUTILS_DATA_NUM_WORDS; ++index) { |
| uint32_t read_word = mmio_region_read32(region, index); |
| if ((read_word == expected->words[index]) != eq) { |
| LOG_INFO("READ_WORD[%x], CONTROL_WORD[%x], INDEX = %d", read_word, |
| expected->words[index], index); |
| |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| bool sram_ctrl_testutils_read_check_eq( |
| uintptr_t address, const sram_ctrl_testutils_data_t *expected) { |
| if (!read_from_ram_check(address, expected, true)) { |
| LOG_INFO("Equality check failure"); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool sram_ctrl_testutils_read_check_neq( |
| uintptr_t address, const sram_ctrl_testutils_data_t *expected) { |
| if (!read_from_ram_check(address, expected, false)) { |
| LOG_INFO("Inequality check failure"); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Checks whether the SRAM scramble operation has finished. |
| */ |
| static bool scramble_finished(const dif_sram_ctrl_t *sram_ctrl) { |
| dif_sram_ctrl_status_bitfield_t status; |
| CHECK_DIF_OK(dif_sram_ctrl_get_status(sram_ctrl, &status)); |
| return status & kDifSramCtrlStatusScrKeyValid; |
| } |
| |
| void sram_ctrl_testutils_scramble(const dif_sram_ctrl_t *sram_ctrl) { |
| CHECK_DIF_OK(dif_sram_ctrl_request_new_key(sram_ctrl)); |
| |
| // Calculate the timeout time. |
| // The SRAM Controller documentation says that it takes approximately 800 |
| // cycles to perform the SRAM scrambling operation (50 cycles were added to |
| // this number to be on a safe side). |
| // |
| // The calculation is equivalent of (1us / clk) * 850 (clock period expressed |
| // in micro seconds multiplied by number of cycles needed to perform |
| // the RAM scrambling operation). |
| // |
| // Expressing this calculation in 1us / (clk / 850) is less intuitive, but |
| // makes more sense when dealing with the integer division, as when the clock |
| // frequency is greater than 1 million hertz, the first expression will give |
| // inaccurate results due to clock period being zero. It should not be a |
| // problem with the second version, as clock frequency won't be less than |
| // 850. We add 1 microsecond to account for flooring. |
| uint32_t usec = 1000000 / (kClockFreqCpuHz / 850) + 1; |
| |
| // Loop until new scrambling key has been obtained. |
| LOG_INFO("Waiting for SRAM scrambling to finish"); |
| IBEX_SPIN_FOR(scramble_finished(sram_ctrl), usec); |
| } |