|  | /* | 
|  | * Copyright 2023 Google LLC | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  |  | 
|  | #include "hw/top_matcha/sw/autogen/top_matcha.h" | 
|  | #include "sw/device/lib/arch/device.h" | 
|  | #include "sw/device/lib/dif/dif_rv_timer.h" | 
|  | #include "sw/device/lib/dif/dif_smc_ctrl.h" | 
|  | #include "sw/device/lib/dif/dif_uart.h" | 
|  | #include "sw/device/lib/runtime/hart.h" | 
|  | #include "sw/device/lib/runtime/irq.h" | 
|  | #include "sw/device/lib/runtime/print.h" | 
|  | #include "sw/device/lib/testing/test_framework/check.h" | 
|  | #include "sw/device/lib/testing/test_framework/ottf_test_config.h" | 
|  | #include "sw/device/lib/testing/test_framework/test_util.h" | 
|  | #include "sw/device/tests/smc/smc_rv_timer_test_fpga_nexus_bin_c.h" | 
|  |  | 
|  | OTTF_DEFINE_TEST_CONFIG(); | 
|  |  | 
|  | static dif_rv_timer_t rv_timer; | 
|  | static dif_smc_ctrl_t smc_ctrl; | 
|  | static dif_uart_t uart; | 
|  | static volatile bool timer_isr_seen = false; | 
|  |  | 
|  | void ottf_timer_isr(void) { | 
|  | CHECK(!timer_isr_seen); | 
|  | timer_isr_seen = true; | 
|  | CHECK_DIF_OK( | 
|  | dif_rv_timer_counter_set_enabled(&rv_timer, 0, kDifToggleDisabled)); | 
|  | CHECK_DIF_OK(dif_rv_timer_irq_acknowledge( | 
|  | &rv_timer, kDifRvTimerIrqTimerExpiredHart0Timer0)); | 
|  | } | 
|  |  | 
|  | void _ottf_main(void) { | 
|  | // Initialize the UART to enable logging for non-DV simulation platforms. | 
|  | if (kDeviceType != kDeviceSimDV) { | 
|  | init_uart(TOP_MATCHA_UART0_BASE_ADDR, &uart); | 
|  | } | 
|  |  | 
|  | LOG_INFO("Begin RV_TIMER test."); | 
|  | test_status_set(kTestStatusInTest); | 
|  | irq_timer_ctrl(true); | 
|  | irq_global_ctrl(true); | 
|  | dif_rv_timer_tick_params_t tick_params; | 
|  | CHECK_DIF_OK(dif_rv_timer_approximate_tick_params(kClockFreqPeripheralHz, | 
|  | 1000000, &tick_params)); | 
|  |  | 
|  | CHECK_DIF_OK(dif_rv_timer_init( | 
|  | mmio_region_from_addr(TOP_MATCHA_RV_TIMER_BASE_ADDR), &rv_timer)); | 
|  | CHECK_DIF_OK(dif_rv_timer_set_tick_params(&rv_timer, 0, tick_params)); | 
|  | CHECK_DIF_OK(dif_rv_timer_irq_set_enabled( | 
|  | &rv_timer, kDifRvTimerIrqTimerExpiredHart0Timer0, kDifToggleEnabled)); | 
|  |  | 
|  | uint64_t counter_start, counter_end; | 
|  | CHECK_DIF_OK(dif_rv_timer_counter_read(&rv_timer, 0, &counter_start)); | 
|  | CHECK_DIF_OK(dif_rv_timer_arm(&rv_timer, 0, 0, counter_start + 1000)); | 
|  | CHECK_DIF_OK( | 
|  | dif_rv_timer_counter_set_enabled(&rv_timer, 0, kDifToggleEnabled)); | 
|  | while (true) { | 
|  | wait_for_interrupt(); | 
|  | if (timer_isr_seen) { | 
|  | break; | 
|  | } | 
|  | } | 
|  | CHECK_DIF_OK(dif_rv_timer_counter_read(&rv_timer, 0, &counter_end)); | 
|  | CHECK((counter_end - counter_start) >= 1000); | 
|  | CHECK((counter_end - counter_start) < 2000); | 
|  |  | 
|  | LOG_INFO("Begin RV_TIMER test on SMC."); | 
|  | // Copy embedded binary to SMC RAM. | 
|  | if (kDeviceType == kDeviceFpgaNexus) { | 
|  | memcpy((void *)TOP_MATCHA_RAM_SMC_BASE_ADDR, smc_bin, smc_bin_len); | 
|  | } | 
|  | CHECK_DIF_OK(dif_smc_ctrl_init( | 
|  | mmio_region_from_addr(TOP_MATCHA_SMC_CTRL_BASE_ADDR), &smc_ctrl)); | 
|  | CHECK_DIF_OK(dif_smc_ctrl_set_en(&smc_ctrl)); | 
|  |  | 
|  | // Note: the SMC must end the simulation through testing or otherwise, as the | 
|  | // secure core indefinitely sleeps. | 
|  | asm volatile("wfi"); | 
|  | __builtin_unreachable(); | 
|  | } |