1 /*
2 * Copyright (c) 2022, 2025 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <errno.h>
8
9 #include <zephyr/init.h>
10 #include <zephyr/spinlock.h>
11
12 #include <intel_adsp_ipc.h>
13 #include <zephyr/ipc/backends/intel_adsp_host_ipc.h>
14
15 static struct ipc_ept intel_adsp_ipc_ept;
16 static struct intel_adsp_ipc_ept_priv_data intel_adsp_ipc_priv_data;
17 static struct ipc_ept_cfg intel_adsp_ipc_ept_cfg;
18
intel_adsp_ipc_set_message_handler(const struct device * dev,intel_adsp_ipc_handler_t fn,void * arg)19 void intel_adsp_ipc_set_message_handler(const struct device *dev, intel_adsp_ipc_handler_t fn,
20 void *arg)
21 {
22 struct intel_adsp_ipc_data *devdata = dev->data;
23 k_spinlock_key_t key = k_spin_lock(&devdata->lock);
24
25 devdata->handle_message = fn;
26 devdata->handler_arg = arg;
27 k_spin_unlock(&devdata->lock, key);
28 }
29
intel_adsp_ipc_set_done_handler(const struct device * dev,intel_adsp_ipc_done_t fn,void * arg)30 void intel_adsp_ipc_set_done_handler(const struct device *dev, intel_adsp_ipc_done_t fn, void *arg)
31 {
32 struct intel_adsp_ipc_data *devdata = dev->data;
33 k_spinlock_key_t key = k_spin_lock(&devdata->lock);
34
35 devdata->done_notify = fn;
36 devdata->done_arg = arg;
37 k_spin_unlock(&devdata->lock, key);
38 }
39
intel_adsp_ipc_receive_cb(const void * data,size_t len,void * priv)40 static void intel_adsp_ipc_receive_cb(const void *data, size_t len, void *priv)
41 {
42 const struct device *dev = INTEL_ADSP_IPC_HOST_DEV;
43 struct intel_adsp_ipc_data *devdata = dev->data;
44 struct intel_adsp_ipc_ept_priv_data *priv_data =
45 (struct intel_adsp_ipc_ept_priv_data *)priv;
46 bool done = true;
47
48 if (len == INTEL_ADSP_IPC_CB_MSG) {
49 const struct intel_adsp_ipc_msg *msg = (const struct intel_adsp_ipc_msg *)data;
50
51 if (devdata->handle_message != NULL) {
52 done = devdata->handle_message(dev, devdata->handler_arg, msg->data,
53 msg->ext_data);
54 }
55
56 if (done) {
57 priv_data->cb_ret = INTEL_ADSP_IPC_CB_RET_OKAY;
58 } else {
59 priv_data->cb_ret = -EBADMSG;
60 }
61 } else if (len == INTEL_ADSP_IPC_CB_DONE) {
62 bool external_completion = false;
63
64 if (devdata->done_notify != NULL) {
65 external_completion = devdata->done_notify(dev, devdata->done_arg);
66 }
67
68 if (external_completion) {
69 priv_data->cb_ret = INTEL_ADSP_IPC_CB_RET_EXT_COMPLETE;
70 } else {
71 priv_data->cb_ret = INTEL_ADSP_IPC_CB_RET_OKAY;
72 }
73 }
74 }
75
intel_adsp_ipc_complete(const struct device * dev)76 void intel_adsp_ipc_complete(const struct device *dev)
77 {
78 int ret;
79
80 ret = ipc_service_send(&intel_adsp_ipc_ept, NULL, INTEL_ADSP_IPC_SEND_DONE);
81
82 ARG_UNUSED(ret);
83 }
84
intel_adsp_ipc_is_complete(const struct device * dev)85 bool intel_adsp_ipc_is_complete(const struct device *dev)
86 {
87 int ret;
88
89 ret = ipc_service_send(&intel_adsp_ipc_ept, NULL, INTEL_ADSP_IPC_SEND_IS_COMPLETE);
90
91 return ret == 0;
92 }
93
intel_adsp_ipc_send_message(const struct device * dev,uint32_t data,uint32_t ext_data)94 int intel_adsp_ipc_send_message(const struct device *dev, uint32_t data, uint32_t ext_data)
95 {
96 struct intel_adsp_ipc_msg msg = {.data = data, .ext_data = ext_data};
97 int ret;
98
99 ret = ipc_service_send(&intel_adsp_ipc_ept, &msg, INTEL_ADSP_IPC_SEND_MSG);
100
101 if (ret < 0) {
102 return ret;
103 }
104
105 return 0;
106 }
107
intel_adsp_ipc_send_message_sync(const struct device * dev,uint32_t data,uint32_t ext_data,k_timeout_t timeout)108 int intel_adsp_ipc_send_message_sync(const struct device *dev, uint32_t data, uint32_t ext_data,
109 k_timeout_t timeout)
110 {
111 struct intel_adsp_ipc_msg msg = {
112 .data = data,
113 .ext_data = ext_data,
114 .timeout = timeout,
115 };
116 int ret;
117
118 ret = ipc_service_send(&intel_adsp_ipc_ept, &msg, INTEL_ADSP_IPC_SEND_MSG_SYNC);
119
120 if (ret < 0) {
121 return ret;
122 }
123
124 return 0;
125 }
126
intel_adsp_ipc_send_message_emergency(const struct device * dev,uint32_t data,uint32_t ext_data)127 void intel_adsp_ipc_send_message_emergency(const struct device *dev, uint32_t data,
128 uint32_t ext_data)
129 {
130 struct intel_adsp_ipc_msg msg = {.data = data, .ext_data = ext_data};
131 int ret;
132
133 ret = ipc_service_send(&intel_adsp_ipc_ept, &msg, INTEL_ADSP_IPC_SEND_MSG_EMERGENCY);
134
135 ARG_UNUSED(ret);
136 }
137
138 static struct ipc_ept_cfg intel_adsp_ipc_ept_cfg = {
139 .name = "intel_adsp_ipc_ept",
140 .cb = {
141 .received = intel_adsp_ipc_receive_cb,
142 },
143 .priv = (void *)&intel_adsp_ipc_priv_data,
144 };
145
intel_adsp_ipc_old_init(void)146 static int intel_adsp_ipc_old_init(void)
147 {
148 int ret;
149 const struct device *ipc_dev = INTEL_ADSP_IPC_HOST_DEV;
150
151 ret = ipc_service_register_endpoint(ipc_dev, &intel_adsp_ipc_ept, &intel_adsp_ipc_ept_cfg);
152
153 return ret;
154 }
155
156 /* Backend is at PRE_KERNEL_2:0, so we need to init after that. */
157 SYS_INIT(intel_adsp_ipc_old_init, PRE_KERNEL_2, 1);
158