blob: c012c31e3fa2208f7632b539bbf67d91701409ce [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/arch/device.h"
#include "sw/device/lib/base/abs_mmio.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/dif/dif_base.h"
#include "sw/device/lib/dif/dif_flash_ctrl.h"
#include "sw/device/lib/dif/dif_otp_ctrl.h"
#include "sw/device/lib/dif/dif_rstmgr.h"
#include "sw/device/lib/runtime/hart.h"
#include "sw/device/lib/runtime/irq.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/testing/flash_ctrl_testutils.h"
#include "sw/device/lib/testing/otp_ctrl_testutils.h"
#include "sw/device/lib/testing/rand_testutils.h"
#include "sw/device/lib/testing/test_framework/check.h"
#include "sw/device/lib/testing/test_framework/ottf_main.h"
#include "sw/device/lib/testing/test_framework/status.h"
#include "flash_ctrl_regs.h"
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
#include "otp_ctrl_regs.h"
static dif_rstmgr_t rstmgr;
static dif_otp_ctrl_t otp_ctrl;
static dif_flash_ctrl_state_t flash_ctrl;
enum {
kFlashWordSize = FLASH_CTRL_PARAM_BYTES_PER_WORD,
kFlashPageSize = FLASH_CTRL_PARAM_BYTES_PER_PAGE,
kFlashStartAddr = TOP_EARLGREY_FLASH_CTRL_MEM_BASE_ADDR,
kFlashMpRegions = FLASH_CTRL_PARAM_NUM_REGIONS
};
OTTF_DEFINE_TEST_CONFIG();
// Expected data for the scramble seed, directly backdoor loaded by the
// test environment. The data has to be backdoor loaded because the
// life cycle state used in this test does not permit the isolated
// partition to be written.
OT_SECTION(".non_volatile_scratch") uint32_t kIsoPartExpData[16];
static void check_iso_data(dif_flash_ctrl_state_t *flash_ctrl) {
// Disable scramble on expected data page
uint32_t exp_data_addr = (uint32_t)&kIsoPartExpData;
uint32_t base_page = (exp_data_addr - kFlashStartAddr) / kFlashPageSize;
dif_flash_ctrl_region_properties_t exp_page = {
.rd_en = kMultiBitBool4True,
.prog_en = kMultiBitBool4False,
.erase_en = kMultiBitBool4False,
.scramble_en = kMultiBitBool4False,
.ecc_en = kMultiBitBool4False,
.high_endurance_en = kMultiBitBool4False};
uint32_t addr;
addr = flash_ctrl_testutils_data_region_setup_properties(
flash_ctrl, base_page, /*data_region=*/kFlashMpRegions - 1,
/*region_size=*/1, exp_page);
// Double check that the region address covers the area we care about.
CHECK((exp_data_addr >= (addr + kFlashStartAddr)) &&
(exp_data_addr < (addr + kFlashPageSize + kFlashStartAddr)));
// Enable access to isolated page.
dif_flash_ctrl_region_properties_t iso_page = {
.rd_en = kMultiBitBool4True,
.prog_en = kMultiBitBool4False,
.erase_en = kMultiBitBool4False,
.scramble_en = kMultiBitBool4False,
.ecc_en = kMultiBitBool4False,
.high_endurance_en = kMultiBitBool4False};
addr = flash_ctrl_testutils_info_region_setup_properties(
flash_ctrl, /*page_id=*/3,
/*bank=*/0, /*partition_id=*/0, iso_page);
uint32_t read_data[16];
CHECK(flash_ctrl_testutils_read(flash_ctrl, addr, /*partition_id=*/0,
read_data, kDifFlashCtrlPartitionTypeInfo,
ARRAYSIZE(read_data), 0));
CHECK_ARRAYS_EQ(kIsoPartExpData, read_data, ARRAYSIZE(read_data),
"Isolated info page data mismatch.");
};
bool test_main(void) {
CHECK_DIF_OK(dif_rstmgr_init(
mmio_region_from_addr(TOP_EARLGREY_RSTMGR_AON_BASE_ADDR), &rstmgr));
CHECK_DIF_OK(dif_otp_ctrl_init(
mmio_region_from_addr(TOP_EARLGREY_OTP_CTRL_CORE_BASE_ADDR), &otp_ctrl));
CHECK_DIF_OK(dif_flash_ctrl_init_state(
&flash_ctrl,
mmio_region_from_addr(TOP_EARLGREY_FLASH_CTRL_CORE_BASE_ADDR)));
bool secret1_locked = false;
CHECK_DIF_OK(dif_otp_ctrl_is_digest_computed(
&otp_ctrl, kDifOtpCtrlPartitionSecret1, &secret1_locked));
if (!secret1_locked) {
LOG_INFO("Powered up for the first time, program and lock otp");
// Check Isolated partition data is correct prior to enabling scrambling.
check_iso_data(&flash_ctrl);
// Populate the scramble seeds in otp.
rand_testutils_reseed();
// The secret partition must be 64b aligned...for some reason.
// Figure out that part later.
enum {
kFlashAddrKeyOffset = OTP_CTRL_PARAM_FLASH_ADDR_KEY_SEED_OFFSET -
OTP_CTRL_PARAM_SECRET1_OFFSET,
kFlashDataKeyOffset = OTP_CTRL_PARAM_FLASH_DATA_KEY_SEED_OFFSET -
OTP_CTRL_PARAM_SECRET1_OFFSET,
kSramDataKeyOffset = OTP_CTRL_PARAM_SRAM_DATA_KEY_SEED_OFFSET -
OTP_CTRL_PARAM_SECRET1_OFFSET
};
for (uint32_t i = 0; i < OTP_CTRL_PARAM_FLASH_ADDR_KEY_SEED_SIZE;
i += kFlashWordSize) {
uint64_t val =
(uint64_t)rand_testutils_gen32() << 32 | rand_testutils_gen32();
CHECK_DIF_OK(dif_otp_ctrl_dai_program64(&otp_ctrl,
kDifOtpCtrlPartitionSecret1,
kFlashAddrKeyOffset + i, val));
otp_ctrl_testutils_wait_for_dai(&otp_ctrl);
};
for (uint32_t i = 0; i < OTP_CTRL_PARAM_FLASH_DATA_KEY_SEED_SIZE;
i += kFlashWordSize) {
uint64_t val =
(uint64_t)rand_testutils_gen32() << 32 | rand_testutils_gen32();
CHECK_DIF_OK(dif_otp_ctrl_dai_program64(&otp_ctrl,
kDifOtpCtrlPartitionSecret1,
kFlashDataKeyOffset + i, val));
otp_ctrl_testutils_wait_for_dai(&otp_ctrl);
};
for (uint32_t i = 0; i < OTP_CTRL_PARAM_SRAM_DATA_KEY_SEED_SIZE;
i += kFlashWordSize) {
uint64_t val =
(uint64_t)rand_testutils_gen32() << 32 | rand_testutils_gen32();
CHECK_DIF_OK(dif_otp_ctrl_dai_program64(
&otp_ctrl, kDifOtpCtrlPartitionSecret1, kSramDataKeyOffset + i, val));
otp_ctrl_testutils_wait_for_dai(&otp_ctrl);
};
// Lock the secret1 partition.
otp_ctrl_testutils_lock_partition(&otp_ctrl, kDifOtpCtrlPartitionSecret1,
0);
// Inform rom to setup scramble next round.
uint32_t otp_val = 0;
otp_val = bitfield_field32_write(
otp_val, FLASH_CTRL_DEFAULT_REGION_SCRAMBLE_EN_FIELD,
kMultiBitBool4True);
CHECK_DIF_OK(dif_otp_ctrl_dai_program32(
&otp_ctrl, kDifOtpCtrlPartitionCreatorSwCfg,
(OTP_CTRL_PARAM_CREATOR_SW_CFG_FLASH_DATA_DEFAULT_CFG_OFFSET -
OTP_CTRL_PARAM_CREATOR_SW_CFG_OFFSET),
otp_val));
otp_ctrl_testutils_wait_for_dai(&otp_ctrl);
// Check to see if there are any otp_ctrl errors.
dif_otp_ctrl_status_t status;
CHECK_DIF_OK(dif_otp_ctrl_get_status(&otp_ctrl, &status));
// There should not have been any errors.
// The only bit that should be asserted is the IDLE bit.
LOG_INFO("otp_ctrl status: 0x%x", status.codes);
CHECK(status.codes == 1 << OTP_CTRL_STATUS_DAI_IDLE_BIT);
// Reset the device.
LOG_INFO("Completed first phase, wait for reset");
CHECK_DIF_OK(dif_rstmgr_software_device_reset(&rstmgr));
wait_for_interrupt();
return false;
} else if (secret1_locked) {
// Check Isolated partition data is correct after scramble enabled.
check_iso_data(&flash_ctrl);
LOG_INFO("Hello World");
return true;
}
return false;
}