1 /* Copyright (c) 2022 Intel Corporation
2  * SPDX-License-Identifier: Apache-2.0
3  */
4 #include <zephyr/ztest.h>
5 #include <zephyr/drivers/ipm.h>
6 #include "tests.h"
7 
8 #define IPM_DEV device_get_binding("ipm_cavs_host")
9 
10 /* Two values impossible to transmit in a cAVS ID */
11 #define ID_INBOUND 0xfffffff0
12 #define ID_INVALID 0xffffffff
13 
14 static K_SEM_DEFINE(ipm_sem, 0, 1);
15 
16 static const uint32_t msg[] = { 29, 15, 58, 71, 99 };
17 
18 static uint32_t received_id = ID_INVALID;
19 static volatile uint32_t *received_data;
20 
ipm_msg(const struct device * ipmdev,void * user_data,uint32_t id,volatile void * data)21 static void ipm_msg(const struct device *ipmdev, void *user_data,
22 		    uint32_t id, volatile void *data)
23 {
24 	zassert_equal(ipmdev, IPM_DEV, "wrong device");
25 	zassert_equal(user_data, NULL, "wrong user_data pointer");
26 	zassert_equal(received_id, ID_INBOUND, "unexpected message");
27 
28 	received_id = id;
29 	received_data = data;
30 
31 	k_sem_give(&ipm_sem);
32 }
33 
msg_transact(bool do_wait)34 static void msg_transact(bool do_wait)
35 {
36 	/* Send an IPCCMD_RETURN_MSG, this will send us a return
37 	 * message with msg[0] as the ID (on cAVS 1.8+, otherwise
38 	 * zero).
39 	 */
40 	received_id = ID_INBOUND;
41 	ipm_send(IPM_DEV, do_wait, IPCCMD_RETURN_MSG, msg, sizeof(msg));
42 
43 	/* Wait for the return message */
44 	k_sem_take(&ipm_sem, K_FOREVER);
45 
46 	zassert_equal(received_id,
47 		      IS_ENABLED(IPM_CAVS_HOST_REGWORD) ? msg[0] : 0,
48 		      "wrong return message ID");
49 
50 	received_id = ID_INVALID;
51 
52 	/* Now whitebox the message protocol: copy the message buffer
53 	 * (on the host side!) from the outbox to the inbox. That
54 	 * will write into our "already received" inbox buffer memory.
55 	 * We do this using the underlying intel_adsp_ipc API, which works
56 	 * only because we know it works. Note that on cAVS 1.8+, the
57 	 * actual in-use amount of the message will be one word
58 	 * shorter (because the first word is sent as IPC ext_data),
59 	 * but it won't be inspected below.
60 	 */
61 	for (int i = 0; i < ARRAY_SIZE(msg); i++) {
62 		intel_adsp_ipc_send_message_sync(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_WINCOPY,
63 			(i << 16) | i, K_FOREVER);
64 	}
65 
66 	/* Validate data */
67 	for (int i = 0; i < ARRAY_SIZE(msg); i++) {
68 		zassert_equal(msg[i], received_data[i], "wrong message data");
69 	}
70 }
71 
72 /* This is a little whiteboxey. It relies on the knowledge that an
73  * IPM message is nothing but a IPC message with the "id" parameter
74  * passed as data (and, on cAVS 1.8+ only, the first word of the
75  * message buffer passed as ext_data).
76  */
ZTEST(intel_adsp,test_ipm_cavs_host)77 ZTEST(intel_adsp, test_ipm_cavs_host)
78 {
79 	/* Restore IPM driver state (we've been mucking with intel_adsp_ipc tests) */
80 	intel_adsp_ipc_set_message_handler(INTEL_ADSP_IPC_HOST_DEV, ipm_handler, (void *)IPM_DEV);
81 	intel_adsp_ipc_set_done_handler(INTEL_ADSP_IPC_HOST_DEV, NULL, NULL);
82 
83 	ipm_register_callback(IPM_DEV, ipm_msg, NULL);
84 
85 	/* Do it twice just for coverage on the wait parameter */
86 	msg_transact(true);
87 	msg_transact(false);
88 }
89