blob: 2c8cf63237af89d74053672f52c10fafc648edfa [file] [log] [blame]
/*
* 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/ip/ml_top/data/ml_top_regs.h" // Generated.
#include "hw/top_matcha/sw/autogen/top_matcha.h"
#include "sw/device/lib/arch/device.h"
#include "sw/device/lib/dif/dif_ml_top.h"
#include "sw/device/lib/dif/dif_rv_plic.h"
#include "sw/device/lib/dif/dif_rv_timer.h"
#include "sw/device/lib/dif/dif_tlul_mailbox.h"
#include "sw/device/lib/dif/dif_uart.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"
/*
* Sample program to run some code on all cores in the system.
* SMC - Print to UART and orchestrate ML core/programs.
* Kelvin - SW program built to run on Kelvin.
*/
OTTF_DEFINE_TEST_CONFIG();
static dif_uart_t smc_uart;
static dif_tlul_mailbox_t tlul_mailbox;
static dif_rv_plic_t plic_smc;
static dif_rv_timer_t rv_timer;
static dif_ml_top_t ml_top;
static volatile bool ml_top_done = false;
static volatile bool bin_loaded = false;
static volatile uint32_t ml_result = 0;
void ottf_external_isr(void) {
dif_rv_plic_irq_id_t plic_irq_id;
CHECK_DIF_OK(dif_rv_plic_irq_claim(&plic_smc, kTopMatchaPlicTargetIbex0Smc,
&plic_irq_id));
top_matcha_plic_peripheral_smc_t peripheral_id =
top_matcha_plic_interrupt_for_peripheral_smc[plic_irq_id];
CHECK(peripheral_id == kTopMatchaPlicPeripheralTlulMailboxSmc ||
peripheral_id == kTopMatchaPlicPeripheralMlTop,
"Unexpected peripheral in ISR: %d", peripheral_id);
switch (peripheral_id) {
case kTopMatchaPlicPeripheralTlulMailboxSmc: {
uint32_t rx;
CHECK_DIF_OK(dif_tlul_mailbox_irq_acknowledge(&tlul_mailbox,
kDifTlulMailboxIrqRtirq));
CHECK_DIF_OK(dif_tlul_mailbox_read_message(&tlul_mailbox, &rx));
bin_loaded = true;
break;
}
case kTopMatchaPlicPeripheralMlTop: {
mmio_region_t base_addr =
mmio_region_from_addr(TOP_MATCHA_ML_TOP_CORE_BASE_ADDR);
// Reset and halt Kelvin
// NB: Kelvin needs a few cycles in reset with a clock,
// so set the reset bit and the gate in two transactions.
mmio_region_write32(
base_addr, ML_TOP_CTRL_REG_OFFSET,
ML_TOP_CTRL_REG_RESVAL);
mmio_region_write32(
base_addr, ML_TOP_CTRL_REG_OFFSET,
ML_TOP_CTRL_REG_RESVAL | (1 << ML_TOP_CTRL_FREEZE_BIT));
ml_result = mmio_region_read32(base_addr, ML_TOP_INTR_STATE_REG_OFFSET);
// Write 1 to clear INTR_STATE
mmio_region_write32(base_addr, ML_TOP_INTR_STATE_REG_OFFSET, ml_result);
uint32_t intr_state =
mmio_region_read32(base_addr, ML_TOP_INTR_STATE_REG_OFFSET);
CHECK(intr_state == 0,
"ML Top interrupt reset failed: expect 0, actual 0x%x", intr_state);
ml_top_done = true;
break;
}
default:
LOG_FATAL("Peripheral is not implemented!");
}
CHECK_DIF_OK(dif_rv_plic_irq_complete(&plic_smc, kTopMatchaPlicTargetIbex0Smc,
plic_irq_id));
}
/*
* Configures all the relevant interrupts in PLIC_SMC.
*/
static void plic_smc_configure_irqs(dif_rv_plic_t *plic) {
// Set ML_TOP IRQ priorities to MAX
CHECK_DIF_OK(dif_rv_plic_irq_set_priority(
plic, kTopMatchaPlicIrqIdMlTopFinish, kDifRvPlicMaxPriority));
CHECK_DIF_OK(dif_rv_plic_irq_set_priority(plic, kTopMatchaPlicIrqIdMlTopFault,
kDifRvPlicMaxPriority));
// Set Ibex IRQ priority threshold level
CHECK_DIF_OK(dif_rv_plic_target_set_threshold(
plic, kTopMatchaPlicTargetIbex0Smc, kDifRvPlicMinPriority));
// Enable Mailbox IRQs
CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(
plic, kTopMatchaPlicIrqIdTlulMailboxSmcRtirq,
kTopMatchaPlicTargetIbex0Smc, kDifToggleEnabled));
CHECK_DIF_OK(dif_rv_plic_irq_set_priority(
plic, kTopMatchaPlicIrqIdTlulMailboxSmcRtirq, 1));
// Enable ML core IRQs
CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(plic, kTopMatchaPlicIrqIdMlTopFinish,
kTopMatchaPlicTargetIbex0Smc,
kDifToggleEnabled));
CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(plic, kTopMatchaPlicIrqIdMlTopFault,
kTopMatchaPlicTargetIbex0Smc,
kDifToggleEnabled));
}
void _ottf_main(void) {
init_uart(TOP_MATCHA_SMC_UART_BASE_ADDR, &smc_uart);
LOG_INFO("kelvin_test_smc");
// Configure Mailbox.
CHECK_DIF_OK(dif_tlul_mailbox_init(
mmio_region_from_addr(TOP_MATCHA_TLUL_MAILBOX_SMC_BASE_ADDR),
&tlul_mailbox));
CHECK_DIF_OK(dif_tlul_mailbox_irq_set_enabled(
&tlul_mailbox, kDifTlulMailboxIrqRtirq, kDifToggleEnabled));
CHECK_DIF_OK(dif_tlul_mailbox_irq_set_enabled(
&tlul_mailbox, kDifTlulMailboxIrqWtirq, kDifToggleEnabled));
CHECK_DIF_OK(dif_tlul_mailbox_irq_set_enabled(
&tlul_mailbox, kDifTlulMailboxIrqEirq, kDifToggleEnabled));
// Init ML_TOP
CHECK_DIF_OK(dif_ml_top_init(
mmio_region_from_addr(TOP_MATCHA_ML_TOP_CORE_BASE_ADDR), &ml_top));
CHECK_DIF_OK(dif_ml_top_irq_set_enabled(&ml_top, kDifMlTopIrqFinish,
kDifToggleEnabled));
CHECK_DIF_OK(dif_ml_top_irq_set_enabled(&ml_top, kDifMlTopIrqFault,
kDifToggleEnabled));
dif_ml_top_reset_ctrl_en(&ml_top);
// Set interrupt.
CHECK_DIF_OK(dif_rv_plic_init(
mmio_region_from_addr(TOP_MATCHA_RV_PLIC_SMC_BASE_ADDR), &plic_smc));
plic_smc_configure_irqs(&plic_smc);
irq_global_ctrl(true);
irq_external_ctrl(true);
// Set timer.
dif_rv_timer_tick_params_t tick_params;
CHECK_DIF_OK(dif_rv_timer_init(
mmio_region_from_addr(TOP_MATCHA_RV_TIMER_SMC_BASE_ADDR), &rv_timer));
CHECK_DIF_OK(dif_rv_timer_approximate_tick_params(kClockFreqPeripheralHz,
1000, &tick_params));
CHECK_DIF_OK(dif_rv_timer_set_tick_params(&rv_timer, 0, tick_params));
CHECK_DIF_OK(
dif_rv_timer_counter_set_enabled(&rv_timer, 0, kDifToggleEnabled));
uint32_t bin_index = 0;
while (true) {
uint64_t timer_start, timer_end;
bin_loaded = false;
while (!bin_loaded) {
asm volatile("wfi");
}
// Start up Kelvin.
ml_top_done = false;
ml_result = 0;
CHECK_DIF_OK(dif_rv_timer_counter_read(&rv_timer, 0, &timer_start));
mmio_region_t base_addr =
mmio_region_from_addr(TOP_MATCHA_ML_TOP_CORE_BASE_ADDR);
mmio_region_write32(base_addr, ML_TOP_CTRL_REG_OFFSET, 0x0);
while (!ml_top_done) {
asm volatile("wfi");
}
CHECK_DIF_OK(dif_rv_timer_counter_read(&rv_timer, 0, &timer_end));
LOG_INFO("Test %d: Finish in %d ms", ++bin_index,
(uint32_t)(timer_end - timer_start));
uint32_t tx = ml_result;
CHECK_DIF_OK(dif_tlul_mailbox_send_message(&tlul_mailbox, &tx));
}
}