1 /* Copyright 2023 The ChromiumOS Authors
2  * SPDX-License-Identifier: Apache-2.0
3  */
4 #include <stdlib.h>
5 #include <zephyr/kernel.h>
6 #include <zephyr/ztest.h>
7 #include <soc.h>
8 
9 /* Simple test of SOC-specific hardware on the MediaTek Audio DSP
10  * family.  Right now just CPU speed and host mailbox interrupts.
11  */
12 
13 #define NOM_HZ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC
14 
ccount(void)15 static uint32_t ccount(void)
16 {
17 	uint32_t t;
18 
19 	__asm__ volatile("rsr %0, CCOUNT" : "=r"(t));
20 	return t;
21 }
22 
cpu_hz(void)23 static uint32_t cpu_hz(void)
24 {
25 	uint32_t t0 = k_cycle_get_32(), cc0 = ccount();
26 
27 	k_msleep(100);
28 
29 	uint32_t t1 = k_cycle_get_32(), cc1 = ccount();
30 	uint32_t hz = ((uint64_t)cc1 - cc0) * NOM_HZ / (t1 - t0);
31 
32 	printk("(measured %u Hz CPU clock vs. %d Hz timer)\n", hz, NOM_HZ);
33 	return hz;
34 }
35 
ZTEST(mtk_adsp,cpu_freq)36 ZTEST(mtk_adsp, cpu_freq)
37 {
38 	int freqs[] = { 26, 370, 540, 720 };
39 
40 	for (int i = 0; i < ARRAY_SIZE(freqs); i++) {
41 		printk("Checking CPU freq entry %d (expect %d MHz)\n", i, freqs[i]);
42 		mtk_adsp_set_cpu_freq(freqs[i]);
43 
44 		/* Compute error as an inverse, i.e. "one part in":
45 		 * 100 means 1% off, 1000 is 0.1%, etc...
46 		 */
47 		uint32_t hz0 = 1000000 * freqs[i], hz = cpu_hz();
48 		int32_t err = hz0 / abs((int32_t)(hz0 - hz));
49 
50 		zassert_true(err > 200);
51 	}
52 }
53 
54 #define MBOX0 DEVICE_DT_GET(DT_INST(0, mediatek_mbox))
55 #define MBOX1 DEVICE_DT_GET(DT_INST(1, mediatek_mbox))
56 
57 K_SEM_DEFINE(mbox_sem, 0, 1);
58 static bool mbox1_fired;
59 
mbox_fn(const struct device * mbox,void * arg)60 static void mbox_fn(const struct device *mbox, void *arg)
61 {
62 	zassert_equal(mbox, MBOX1);
63 	zassert_equal(arg, NULL);
64 	mbox1_fired = true;
65 	k_sem_give(&mbox_sem);
66 }
67 
68 
69 /* Test in/out interrupts from the host.  This relies on a SOF driver
70  * on the host, which has the behavior of "replying" with an interrupt
71  * on mbox1 after receiving a "command" on mbox0 (you can also see it
72  * whine about the invalid IPC message in the kernel logs).  SOF
73  * ignores the message bytes (it uses a DRAM area instead), so we just
74  * write them blindly.  It's only a partial test of the hardware, but
75  * easy to run and exercises the core functionality.
76  *
77  * Note that there's a catch: SOF's "reply" comes after a timeout
78  * (it's an invalid command, afterall) which is 165 seconds!  But the
79  * test does pass.
80  */
ZTEST(mtk_adsp,mbox)81 ZTEST(mtk_adsp, mbox)
82 {
83 	mtk_adsp_mbox_set_handler(MBOX1, 1, mbox_fn, NULL);
84 
85 	for (int i = 0; i < MTK_ADSP_MBOX_MSG_WORDS; i++) {
86 		mtk_adsp_mbox_set_msg(MBOX0, i, 0x01010100 | i);
87 	}
88 
89 	/* First signal the host with a reply on the second channel,
90 	 * that effects a reply to anything it thinks it might have
91 	 * sent us
92 	 */
93 	mtk_adsp_mbox_signal(MBOX1, 1);
94 
95 	mtk_adsp_mbox_signal(MBOX0, 0);
96 
97 	printk("Waiting for reply from SOF driver, be patient: long timeout...\n");
98 	k_sem_take(&mbox_sem, K_FOREVER);
99 	zassert_true(mbox1_fired);
100 }
101 
mtk_adsp_setup(void)102 static void *mtk_adsp_setup(void)
103 {
104 	return NULL;
105 }
106 
107 ZTEST_SUITE(mtk_adsp, NULL, mtk_adsp_setup, NULL, NULL, NULL);
108