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