diff --git a/soc/xtensa/intel_adsp/common/cavs_ipc.c b/soc/xtensa/intel_adsp/common/cavs_ipc.c index 94661bcde61..d9f552984d0 100644 --- a/soc/xtensa/intel_adsp/common/cavs_ipc.c +++ b/soc/xtensa/intel_adsp/common/cavs_ipc.c @@ -32,6 +32,7 @@ void z_cavs_ipc_isr(const void *devarg) const struct device *dev = devarg; const struct cavs_ipc_config *config = dev->config; struct cavs_ipc_data *devdata = dev->data; + volatile struct cavs_ipc *regs = config->regs; k_spinlock_key_t key = k_spin_lock(&devdata->lock); diff --git a/soc/xtensa/intel_adsp/tools/cavstool.py b/soc/xtensa/intel_adsp/tools/cavstool.py index ef480c0b606..9ea521c0dcb 100755 --- a/soc/xtensa/intel_adsp/tools/cavstool.py +++ b/soc/xtensa/intel_adsp/tools/cavstool.py @@ -324,6 +324,8 @@ async def ipc_delay_done(): await asyncio.sleep(0.1) dsp.HIPCTDA = 1<<31 +ipc_timestamp = 0 + # Super-simple command language, driven by the test code on the DSP def ipc_command(data, ext_data): send_msg = False @@ -338,6 +340,12 @@ def ipc_command(data, ext_data): send_msg = True elif data == 3: # set ADSPCS dsp.ADSPCS = ext_data + elif data == 4: # echo back microseconds since last timestamp command + global ipc_timestamp + t = round(time.time() * 1e6) + ext_data = t - ipc_timestamp + ipc_timestamp = t + send_msg = True else: log.warning(f"cavstool: Unrecognized IPC command 0x{data:x} ext 0x{ext_data:x}") diff --git a/tests/boards/intel_adsp/smoke/src/hostipc.c b/tests/boards/intel_adsp/smoke/src/hostipc.c index 30350081e8d..331d5e043d7 100644 --- a/tests/boards/intel_adsp/smoke/src/hostipc.c +++ b/tests/boards/intel_adsp/smoke/src/hostipc.c @@ -96,4 +96,8 @@ void test_host_ipc(void) zassert_true(ret, "send failed"); zassert_true(done_flag, "done interrupt failed to fire"); zassert_true(cavs_ipc_is_complete(CAVS_HOST_DEV), "sync message incomplete"); + + /* Clean up. Further tests might want to use IPC */ + cavs_ipc_set_message_handler(CAVS_HOST_DEV, NULL, NULL); + cavs_ipc_set_done_handler(CAVS_HOST_DEV, NULL, NULL); } diff --git a/tests/boards/intel_adsp/smoke/src/main.c b/tests/boards/intel_adsp/smoke/src/main.c index fe126818d78..5b0c2de270d 100644 --- a/tests/boards/intel_adsp/smoke/src/main.c +++ b/tests/boards/intel_adsp/smoke/src/main.c @@ -3,8 +3,43 @@ */ #include #include +#include #include "tests.h" +static bool clock_msg(const struct device *dev, void *arg, + uint32_t data, uint32_t ext_data) +{ + *(uint32_t *)arg = data; + return true; +} + +void test_clock_calibrate(void) +{ + static volatile uint32_t host_dt; + uint32_t cyc0, cyc1, hz, diff; + + /* Prime the host script's timestamp */ + cyc0 = k_cycle_get_32(); + cavs_ipc_send_message(CAVS_HOST_DEV, IPCCMD_TIMESTAMP, 0); + + k_msleep(1000); + host_dt = 0; + cavs_ipc_set_message_handler(CAVS_HOST_DEV, clock_msg, (void *)&host_dt); + + /* Now do it again, but with a handler to catch the result */ + cyc1 = k_cycle_get_32(); + cavs_ipc_send_message(CAVS_HOST_DEV, IPCCMD_TIMESTAMP, 0); + WAIT_FOR(host_dt != 0); + cavs_ipc_set_message_handler(CAVS_HOST_DEV, NULL, NULL); + + hz = 1000000ULL * (cyc1 - cyc0) / host_dt; + printk("CLOCK: %lld Hz\n", (1000000ULL * (cyc1 - cyc0)) / host_dt); + + /* Make sure we're within 1% of spec */ + diff = abs(hz - CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC); + zassert_true((hz / MIN(1, diff)) > 100, "clock rate wrong"); +} + void test_main(void) { ztest_test_suite(intel_adsp, @@ -12,7 +47,8 @@ void test_main(void) ztest_unit_test(test_cpu_halt), ztest_unit_test(test_post_boot_ipi), ztest_unit_test(test_cpu_behavior), - ztest_unit_test(test_host_ipc) + ztest_unit_test(test_host_ipc), + ztest_unit_test(test_clock_calibrate) ); ztest_run_test_suite(intel_adsp); diff --git a/tests/boards/intel_adsp/smoke/src/tests.h b/tests/boards/intel_adsp/smoke/src/tests.h index c87f357fb2d..1f0840fc7db 100644 --- a/tests/boards/intel_adsp/smoke/src/tests.h +++ b/tests/boards/intel_adsp/smoke/src/tests.h @@ -4,6 +4,8 @@ #ifndef ZEPHYR_TESTS_INTEL_ADSP_TESTS_H #define ZEPHYR_TESTS_INTEL_ADSP_TESTS_H +#include + /* Helper to escape from infinite polling loops with a test failure * instead of a hang. Spins with a relaxation loop so that it works * in interrupt context and doesn't stress shared resources like SRAM @@ -33,6 +35,9 @@ enum cavstool_cmd { /* The host writes the given value to ADSPCS */ IPCCMD_ADSPCS, + + /* The host emits a (real/host time) timestamp into the log stream */ + IPCCMD_TIMESTAMP, }; void test_post_boot_ipi(void);