1 /* Copyright (c) 2022 Intel Corporation
2  * SPDX-License-Identifier: Apache-2.0
3  */
4 #include <zephyr/kernel.h>
5 #include <zephyr/ztest.h>
6 #include <intel_adsp_ipc.h>
7 #include "tests.h"
8 
9 static volatile bool done_flag, msg_flag;
10 
11 #define RETURN_MSG_SYNC_VAL  0x12345
12 #define RETURN_MSG_ASYNC_VAL 0x54321
13 
ipc_message(const struct device * dev,void * arg,uint32_t data,uint32_t ext_data)14 static bool ipc_message(const struct device *dev, void *arg,
15 			uint32_t data, uint32_t ext_data)
16 {
17 	zassert_is_null(arg, "wrong message arg");
18 	zassert_equal(data, ext_data, "unequal message data/ext_data");
19 	zassert_true(data == RETURN_MSG_SYNC_VAL ||
20 		     data == RETURN_MSG_ASYNC_VAL, "unexpected msg data");
21 	msg_flag = true;
22 	return data == RETURN_MSG_SYNC_VAL;
23 }
24 
ipc_done(const struct device * dev,void * arg)25 static bool ipc_done(const struct device *dev, void *arg)
26 {
27 	zassert_is_null(arg, "wrong done arg");
28 	zassert_false(done_flag, "done called unexpectedly");
29 	done_flag = true;
30 	return false;
31 }
32 
ZTEST(intel_adsp,test_host_ipc)33 ZTEST(intel_adsp, test_host_ipc)
34 {
35 	int ret;
36 
37 	intel_adsp_ipc_set_message_handler(INTEL_ADSP_IPC_HOST_DEV, ipc_message, NULL);
38 	intel_adsp_ipc_set_done_handler(INTEL_ADSP_IPC_HOST_DEV, ipc_done, NULL);
39 
40 	/* Just send a message and wait for it to complete */
41 	printk("Simple message send...\n");
42 	done_flag = false;
43 	ret = intel_adsp_ipc_send_message(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_SIGNAL_DONE, 0);
44 	zassert_true(!ret, "send failed");
45 	AWAIT(intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV));
46 	AWAIT(done_flag);
47 
48 	/* Request the host to return a message which we will complete
49 	 * immediately.
50 	 */
51 	printk("Return message request...\n");
52 	done_flag = false;
53 	msg_flag = false;
54 	ret = intel_adsp_ipc_send_message(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_RETURN_MSG,
55 				RETURN_MSG_SYNC_VAL);
56 	zassert_true(!ret, "send failed");
57 	AWAIT(done_flag);
58 	AWAIT(intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV));
59 	AWAIT(msg_flag);
60 
61 	/* Do exactly the same thing again to check for state bugs
62 	 * (e.g. failing to signal done on one side or the other)
63 	 */
64 	printk("Return message request 2...\n");
65 	done_flag = false;
66 	msg_flag = false;
67 	ret = intel_adsp_ipc_send_message(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_RETURN_MSG,
68 				RETURN_MSG_SYNC_VAL);
69 	zassert_true(!ret, "send failed");
70 	AWAIT(done_flag);
71 	AWAIT(intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV));
72 	AWAIT(msg_flag);
73 
74 	/* Same, but we'll complete it asynchronously (1.8+ only) */
75 	printk("Return message request, async...\n");
76 	done_flag = false;
77 	msg_flag = false;
78 	ret = intel_adsp_ipc_send_message(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_RETURN_MSG,
79 				RETURN_MSG_ASYNC_VAL);
80 	zassert_true(!ret, "send failed");
81 	AWAIT(done_flag);
82 	AWAIT(intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV));
83 	AWAIT(msg_flag);
84 	intel_adsp_ipc_complete(INTEL_ADSP_IPC_HOST_DEV);
85 
86 	/* Now make a synchronous call with (on the host) a delayed
87 	 * completion and make sure the interrupt fires and wakes us
88 	 * up. (On 1.5 a delay isn't possible and this will complete
89 	 * immediately).
90 	 */
91 	printk("Synchronous message send...\n");
92 	done_flag = false;
93 	ret = intel_adsp_ipc_send_message_sync(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_ASYNC_DONE_DELAY,
94 					 0, K_FOREVER);
95 	zassert_true(!ret, "send failed");
96 	zassert_true(done_flag, "done interrupt failed to fire");
97 	zassert_true(intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV),
98 		"sync message incomplete");
99 
100 	/* Clean up. Further tests might want to use IPC */
101 	intel_adsp_ipc_set_message_handler(INTEL_ADSP_IPC_HOST_DEV, NULL, NULL);
102 	intel_adsp_ipc_set_done_handler(INTEL_ADSP_IPC_HOST_DEV, NULL, NULL);
103 }
104