[top/dv] add test chip_sw_uart_tx_rx_alt_clk_freq
Extend from chip_sw_uart_rand_baudrate with following added settings.
- Configure LC to RMA state, so that it allows clkmgr to use external clock.
- Configure clkmgr to select external clock.
- Randomize `LOW_SPEED_SEL`, so that uart core clock frequency can be either
ext_clk_freq / 4 or ext_clk_freq / 2.
Signed-off-by: Weicai Yang <weicai@google.com>
diff --git a/hw/top_earlgrey/data/chip_testplan.hjson b/hw/top_earlgrey/data/chip_testplan.hjson
index 1d2275d..f5e6faa 100644
--- a/hw/top_earlgrey/data/chip_testplan.hjson
+++ b/hw/top_earlgrey/data/chip_testplan.hjson
@@ -61,15 +61,16 @@
}
{
name: chip_sw_uart_tx_rx_alt_clk_freq
- desc: '''Verify the transmission of UART while randomizing the core clock frequency.
+ desc: '''Verify the transmission of UART via using external clock as uart core clock.
- Run the chip_uart_tx_rx test with the core clock frequency randomized between known
- bounds.
-
- TODO: Find out what the range is for the core clock frequency randomization.
+ Extend from chip_sw_uart_rand_baudrate with following added settings.
+ - Configure LC to RMA state, so that it allows clkmgr to use external clock.
+ - Configure clkmgr to select external clock.
+ - Randomize `LOW_SPEED_SEL`, so that uart core clock frequency can be either
+ ext_clk_freq / 4 or ext_clk_freq / 2.
'''
milestone: V1
- tests: []
+ tests: ["chip_sw_uart_tx_rx_alt_clk_freq", "chip_sw_uart_tx_rx_alt_clk_freq_low_speed"]
}
// GPIO (pre-verified IP) integration tests:
diff --git a/hw/top_earlgrey/dv/chip_sim_cfg.hjson b/hw/top_earlgrey/dv/chip_sim_cfg.hjson
index d531da4..a36e98c 100644
--- a/hw/top_earlgrey/dv/chip_sim_cfg.hjson
+++ b/hw/top_earlgrey/dv/chip_sim_cfg.hjson
@@ -230,6 +230,22 @@
reseed: 20
}
{
+ name: chip_sw_uart_tx_rx_alt_clk_freq
+ uvm_test_seq: chip_sw_uart_rand_baudrate_vseq
+ sw_images: ["sw/device/tests/uart_tx_rx_test:1"]
+ en_run_modes: ["sw_test_mode"]
+ run_opts: ["+use_otp_image=LcStRma", "+use_extclk=1"]
+ reseed: 10
+ }
+ {
+ name: chip_sw_uart_tx_rx_alt_clk_freq_low_speed
+ uvm_test_seq: chip_sw_uart_rand_baudrate_vseq
+ sw_images: ["sw/device/tests/uart_tx_rx_test:1"]
+ en_run_modes: ["sw_test_mode"]
+ run_opts: ["+use_otp_image=LcStRma", "+use_extclk=1", "extclk_low_speed_sel=1"]
+ reseed: 10
+ }
+ {
name: chip_sw_spi_device_tx_rx
uvm_test_seq: chip_sw_spi_tx_rx_vseq
sw_images: ["sw/device/tests/spi_tx_rx_test:1"]
diff --git a/hw/top_earlgrey/dv/env/seq_lib/chip_sw_uart_rand_baudrate_vseq.sv b/hw/top_earlgrey/dv/env/seq_lib/chip_sw_uart_rand_baudrate_vseq.sv
index 06751aa..5218031 100644
--- a/hw/top_earlgrey/dv/env/seq_lib/chip_sw_uart_rand_baudrate_vseq.sv
+++ b/hw/top_earlgrey/dv/env/seq_lib/chip_sw_uart_rand_baudrate_vseq.sv
@@ -2,9 +2,9 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-`define CALC_NCO(baud_rate, nco_width, clk_freq_mhz) \
- (baud_rate == BaudRate1p5Mbps && clk_freq_mhz == 24) ? 16'hffff : \
- (longint'(baud_rate) * (2**(nco_width+4))) / (clk_freq_mhz * 1000_000)
+`define CALC_NCO(baud_rate, nco_width, clk_freq_khz) \
+ (baud_rate == BaudRate1p5Mbps && clk_freq_khz == 24_000) ? 16'hffff : \
+ (longint'(baud_rate) * (2**(nco_width+4))) / (clk_freq_khz * 1000)
class chip_sw_uart_rand_baudrate_vseq extends chip_sw_uart_tx_rx_vseq;
`uvm_object_utils(chip_sw_uart_rand_baudrate_vseq)
@@ -13,19 +13,38 @@
localparam NCO_WIDTH = 16;
- rand baud_rate_e baud_rate;
- rand int uart_clk_freq_mhz = 24;
+ // Clkmgr external clock settings
+ bit use_extclk = 0;
+ bit extclk_low_speed_sel = 0;
- // Use the fixed 24Mhz, override it in extended vseq
- constraint uart_clk_freq_mhz_c {
- uart_clk_freq_mhz == 24;
- }
+ int uart_clk_freq_khz; // use khz to avoid fractional value
+
+ rand baud_rate_e baud_rate;
constraint baud_rate_c {
// constrain nco not over nco width
- `CALC_NCO(baud_rate, NCO_WIDTH, uart_clk_freq_mhz) < (1 << NCO_WIDTH);
+ `CALC_NCO(baud_rate, NCO_WIDTH, uart_clk_freq_khz) < (1 << NCO_WIDTH);
}
+ function void pre_randomize();
+ super.pre_randomize();
+ void'($value$plusargs("use_extclk=%0d", use_extclk));
+ void'($value$plusargs("extclk_low_speed_sel=%0d", extclk_low_speed_sel));
+ if (use_extclk) begin
+ // Uart bus clock is in div4 domain
+ uart_clk_freq_khz = cfg.clk_freq_mhz * 1000 / 4;
+
+ if (extclk_low_speed_sel) uart_clk_freq_khz = uart_clk_freq_khz * 2;
+ end else begin
+ // internal uart bus clock is 24Mhz
+ uart_clk_freq_khz = 24_0000;
+ end
+ `uvm_info(`gfn,
+ $sformatf("External clock freq: %0dmhz, use_extclk: %0d, extclk_low_speed_sel: %0d",
+ cfg.clk_freq_mhz, use_extclk, extclk_low_speed_sel),
+ UVM_MEDIUM)
+ endfunction
+
virtual task dut_init(string reset_kind = "HARD");
super.dut_init(reset_kind);
cfg.uart_baud_rate = baud_rate;
@@ -33,14 +52,32 @@
virtual task cpu_init();
// sw_symbol_backdoor_overwrite takes an array as the input
- bit [7:0] uart_freq[8] = {<< byte {cfg.uart_baud_rate}};
+ bit [7:0] uart_freq_arr[8] = {<< byte {cfg.uart_baud_rate}};
super.cpu_init();
- $display("wcy0 %p", uart_freq);
- sw_symbol_backdoor_overwrite("kUartBaudrate", uart_freq);
- `uvm_info(`gfn, $sformatf("Configure uart core clk %0d Mhz, baud_rate: %s",
- uart_clk_freq_mhz, baud_rate.name), UVM_LOW)
+ sw_symbol_backdoor_overwrite("kUartBaudrate", uart_freq_arr);
+ `uvm_info(`gfn, $sformatf("Backdoor_overwrite: configure uart core clk %0d khz, baud_rate: %s",
+ uart_clk_freq_khz, baud_rate.name), UVM_LOW)
+ if (use_extclk) begin
+ bit [7:0] use_extclk_arr[] = {use_extclk};
+ bit [7:0] low_speed_sel_arr[] = {extclk_low_speed_sel};
+ bit [7:0] uart_clk_freq_arr[8] = {<< byte {uart_clk_freq_khz * 1000}};
+
+ sw_symbol_backdoor_overwrite("kUseExtClk", use_extclk_arr);
+ `uvm_info(`gfn, $sformatf("Backdoor_overwrite: configure uart use_extclk: %0d", use_extclk),
+ UVM_LOW)
+
+ sw_symbol_backdoor_overwrite("kUseLowSpeedSel", low_speed_sel_arr);
+ `uvm_info(`gfn, $sformatf("Backdoor_overwrite: configure low_speed_sel: %0d",
+ extclk_low_speed_sel), UVM_LOW)
+
+ // SW relies on kClockFreqPeripheralHz to calcuate NCO and it's hard-coded to 24Mhz in SW.
+ // this value is changed when extclk is used
+ sw_symbol_backdoor_overwrite("kClockFreqPeripheralHz", uart_clk_freq_arr);
+ `uvm_info(`gfn, $sformatf("Backdoor_overwrite: configure uart use_extclk: %0d",
+ uart_clk_freq_khz), UVM_LOW)
+ end
endtask
endclass : chip_sw_uart_rand_baudrate_vseq
diff --git a/sw/device/lib/dif/dif_clkmgr.c b/sw/device/lib/dif/dif_clkmgr.c
index 35a93dc..e01b3aa 100644
--- a/sw/device/lib/dif/dif_clkmgr.c
+++ b/sw/device/lib/dif/dif_clkmgr.c
@@ -148,3 +148,21 @@
return kDifOk;
}
+
+dif_result_t dif_clkmgr_external_clock_set_enabled(const dif_clkmgr_t *clkmgr,
+ bool is_low_speed) {
+ uint32_t extclk_ctrl_reg = 0;
+
+ if (clkmgr == NULL) {
+ return kDifBadArg;
+ }
+
+ extclk_ctrl_reg = bitfield_field32_write(
+ extclk_ctrl_reg, CLKMGR_EXTCLK_CTRL_SEL_FIELD, kMultiBitBool4True);
+ extclk_ctrl_reg = bitfield_field32_write(
+ extclk_ctrl_reg, CLKMGR_EXTCLK_CTRL_LOW_SPEED_SEL_FIELD,
+ is_low_speed ? kMultiBitBool4True : kMultiBitBool4False);
+ mmio_region_write32(clkmgr->base_addr, CLKMGR_EXTCLK_CTRL_REG_OFFSET,
+ extclk_ctrl_reg);
+ return kDifOk;
+}
diff --git a/sw/device/lib/dif/dif_clkmgr.h b/sw/device/lib/dif/dif_clkmgr.h
index 53b06c7..f3f82fe 100644
--- a/sw/device/lib/dif/dif_clkmgr.h
+++ b/sw/device/lib/dif/dif_clkmgr.h
@@ -148,6 +148,21 @@
const dif_clkmgr_t *clkmgr, dif_clkmgr_hintable_clock_t clock,
dif_toggle_t *state);
+/**
+ * Enable chip to use the external clock.
+ *
+ * @param clkmgr Clock Manager Handle.
+ * @param is_low_speed External clock is low speed or high speed.
+ * High speed - external clock is close to nominal speeds (e.g. external clock
+ * is 96MHz and nominal frequency is 96MHz-100MHz). Low speed - external clock
+ * is half of nominal speeds (e.g. external clock is 48MHz and nominal frequency
+ * is 96MHz-100MHz).
+ *
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_clkmgr_external_clock_set_enabled(const dif_clkmgr_t *clkmgr,
+ bool is_low_speed);
+
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
diff --git a/sw/device/tests/sim_dv/meson.build b/sw/device/tests/sim_dv/meson.build
index afb23c9..3c40442 100644
--- a/sw/device/tests/sim_dv/meson.build
+++ b/sw/device/tests/sim_dv/meson.build
@@ -30,12 +30,16 @@
link_with: static_library(
'uart_tx_rx_test_lib',
sources: [
+ hw_ip_lc_ctrl_reg_h,
+ hw_ip_clkmgr_reg_h,
# TODO, remove it once pinout configuration is provided
hw_top_earlgrey_pinmux_reg_h,
'uart_tx_rx_test.c'],
dependencies: [
sw_lib_dif_uart,
sw_lib_dif_rv_plic,
+ sw_lib_dif_lc_ctrl,
+ sw_lib_dif_clkmgr,
sw_lib_irq,
sw_lib_mmio,
sw_lib_runtime_log,
diff --git a/sw/device/tests/sim_dv/uart_tx_rx_test.c b/sw/device/tests/sim_dv/uart_tx_rx_test.c
index 9f387d2..fdc046f 100644
--- a/sw/device/tests/sim_dv/uart_tx_rx_test.c
+++ b/sw/device/tests/sim_dv/uart_tx_rx_test.c
@@ -5,6 +5,8 @@
#include "sw/device/lib/arch/device.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/dif/dif_base.h"
+#include "sw/device/lib/dif/dif_clkmgr.h"
+#include "sw/device/lib/dif/dif_lc_ctrl.h"
#include "sw/device/lib/dif/dif_rv_plic.h"
#include "sw/device/lib/dif/dif_uart.h"
#include "sw/device/lib/irq.h"
@@ -65,6 +67,14 @@
*/
static volatile const uint8_t kUartIdx = 0x0;
+/**
+ * Indicates if ext_clk is used and what speed.
+ *
+ * Similar to `kUartIdx`, this may be overridden in DV testbench
+ */
+static volatile const uint8_t kUseExtClk = 0x0;
+static volatile const uint8_t kUseLowSpeedSel = 0x0;
+
// A set of bytes to be send out of TX.
static const uint8_t kUartTxData[UART_DATASET_SIZE] = {
0xe8, 0x50, 0xc6, 0xb4, 0xbe, 0x16, 0xed, 0x55, 0x16, 0x1d, 0xe6, 0x1c,
@@ -491,6 +501,28 @@
return true;
}
+void config_external_clock(void) {
+ dif_lc_ctrl_t lc;
+ dif_clkmgr_t clkmgr;
+ mmio_region_t lc_ctrl_base_addr =
+ mmio_region_from_addr(TOP_EARLGREY_LC_CTRL_BASE_ADDR);
+ mmio_region_t clkmgr_base_addr =
+ mmio_region_from_addr(TOP_EARLGREY_CLKMGR_AON_BASE_ADDR);
+
+ CHECK_DIF_OK(dif_lc_ctrl_init(lc_ctrl_base_addr, &lc));
+ CHECK_DIF_OK(dif_clkmgr_init(clkmgr_base_addr, &clkmgr));
+
+ LOG_INFO("Read and check LC state.");
+ dif_lc_ctrl_state_t curr_state;
+ CHECK_DIF_OK(dif_lc_ctrl_get_state(&lc, &curr_state));
+ CHECK(curr_state == kDifLcCtrlStateRma,
+ "LC State isn't in kDifLcCtrlStateRma!");
+
+ // Enable external clock
+ LOG_INFO("Configure clkmgr to enable external clock");
+ CHECK_DIF_OK(dif_clkmgr_external_clock_set_enabled(&clkmgr, kUseLowSpeedSel));
+}
+
const test_config_t kTestConfig;
bool test_main(void) {
@@ -512,6 +544,10 @@
kTopEarlgreyPinmuxInselIor11, kTopEarlgreyPinmuxPeripheralInUart3Rx,
kTopEarlgreyPinmuxMioOutIor12, kTopEarlgreyPinmuxOutselUart3Tx);
+ if (kUseExtClk) {
+ config_external_clock();
+ }
+
// Initialize the UART.
mmio_region_t chosen_uart_region = mmio_region_from_addr(uart_base_addr);
uart_init_with_irqs(chosen_uart_region, &uart);