tests/intel_adsp: Add clock calibration test

Now that we have easy access to code on the host, it's trivial to
check the clock against host timestamps with high precision.

Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
This commit is contained in:
Andy Ross 2022-01-23 18:48:28 -08:00 committed by Anas Nashif
commit 3da9c9213e
5 changed files with 55 additions and 1 deletions

View file

@ -32,6 +32,7 @@ void z_cavs_ipc_isr(const void *devarg)
const struct device *dev = devarg; const struct device *dev = devarg;
const struct cavs_ipc_config *config = dev->config; const struct cavs_ipc_config *config = dev->config;
struct cavs_ipc_data *devdata = dev->data; struct cavs_ipc_data *devdata = dev->data;
volatile struct cavs_ipc *regs = config->regs; volatile struct cavs_ipc *regs = config->regs;
k_spinlock_key_t key = k_spin_lock(&devdata->lock); k_spinlock_key_t key = k_spin_lock(&devdata->lock);

View file

@ -324,6 +324,8 @@ async def ipc_delay_done():
await asyncio.sleep(0.1) await asyncio.sleep(0.1)
dsp.HIPCTDA = 1<<31 dsp.HIPCTDA = 1<<31
ipc_timestamp = 0
# Super-simple command language, driven by the test code on the DSP # Super-simple command language, driven by the test code on the DSP
def ipc_command(data, ext_data): def ipc_command(data, ext_data):
send_msg = False send_msg = False
@ -338,6 +340,12 @@ def ipc_command(data, ext_data):
send_msg = True send_msg = True
elif data == 3: # set ADSPCS elif data == 3: # set ADSPCS
dsp.ADSPCS = ext_data 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: else:
log.warning(f"cavstool: Unrecognized IPC command 0x{data:x} ext 0x{ext_data:x}") log.warning(f"cavstool: Unrecognized IPC command 0x{data:x} ext 0x{ext_data:x}")

View file

@ -96,4 +96,8 @@ void test_host_ipc(void)
zassert_true(ret, "send failed"); zassert_true(ret, "send failed");
zassert_true(done_flag, "done interrupt failed to fire"); zassert_true(done_flag, "done interrupt failed to fire");
zassert_true(cavs_ipc_is_complete(CAVS_HOST_DEV), "sync message incomplete"); 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);
} }

View file

@ -3,8 +3,43 @@
*/ */
#include <zephyr.h> #include <zephyr.h>
#include <ztest.h> #include <ztest.h>
#include <stdlib.h>
#include "tests.h" #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) void test_main(void)
{ {
ztest_test_suite(intel_adsp, ztest_test_suite(intel_adsp,
@ -12,7 +47,8 @@ void test_main(void)
ztest_unit_test(test_cpu_halt), ztest_unit_test(test_cpu_halt),
ztest_unit_test(test_post_boot_ipi), ztest_unit_test(test_post_boot_ipi),
ztest_unit_test(test_cpu_behavior), 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); ztest_run_test_suite(intel_adsp);

View file

@ -4,6 +4,8 @@
#ifndef ZEPHYR_TESTS_INTEL_ADSP_TESTS_H #ifndef ZEPHYR_TESTS_INTEL_ADSP_TESTS_H
#define ZEPHYR_TESTS_INTEL_ADSP_TESTS_H #define ZEPHYR_TESTS_INTEL_ADSP_TESTS_H
#include <cavs_ipc.h>
/* Helper to escape from infinite polling loops with a test failure /* Helper to escape from infinite polling loops with a test failure
* instead of a hang. Spins with a relaxation loop so that it works * instead of a hang. Spins with a relaxation loop so that it works
* in interrupt context and doesn't stress shared resources like SRAM * 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 */ /* The host writes the given value to ADSPCS */
IPCCMD_ADSPCS, IPCCMD_ADSPCS,
/* The host emits a (real/host time) timestamp into the log stream */
IPCCMD_TIMESTAMP,
}; };
void test_post_boot_ipi(void); void test_post_boot_ipi(void);