1 /* Copyright (c) 2022 Intel Corporation
2  * SPDX-License-Identifier: Apache-2.0
3  */
4 #ifndef ZEPHYR_INCLUDE_INTEL_ADSP_IPC_H
5 #define ZEPHYR_INCLUDE_INTEL_ADSP_IPC_H
6 
7 #include <intel_adsp_ipc_devtree.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/device.h>
10 #include <zephyr/pm/device.h>
11 
12 struct intel_adsp_ipc_config {
13 	volatile struct intel_adsp_ipc *regs;
14 };
15 
16 /**
17  * @brief Intel ADSP IPC Message Handler Callback.
18  *
19  * This function, once registered via intel_adsp_ipc_set_message_handler(),
20  * is invoked in interrupt context to service messages sent from the
21  * foreign/connected IPC context. The message contents of the TDR and
22  * TDD registers are provided in the data/ext_data argument.
23  *
24  * The function should return true if processing of the message is
25  * complete and return notification to the other side (via the TDA
26  * register) is desired immediately. Returning false means that no
27  * return "DONE" interrupt will occur until intel_adsp_ipc_complete() is
28  * called on this device at some point in the future.
29  *
30  * @note Further messages on the link will not be transmitted or
31  * received while an in-progress message remains incomplete!
32  *
33  * @param dev IPC device.
34  * @param arg Registered argument from intel_adsp_ipc_set_message_handler().
35  * @param data Message data from other side (low bits of TDR register).
36  * @param ext_dat Extended message data (TDD register).
37  * @return true if the message is completely handled.
38  */
39 typedef bool (*intel_adsp_ipc_handler_t)(const struct device *dev, void *arg,
40 	uint32_t data, uint32_t ext_data);
41 
42 /**
43  * @brief Intel ADSP IPC Message Complete Callback.
44  *
45  * This function, once registered via intel_adsp_ipc_set_done_handler(), is
46  * invoked in interrupt context when a "DONE" return interrupt is
47  * received from the other side of the connection (indicating that a
48  * previously sent message is finished processing).
49  *
50  * @note On Intel ADSP hardware the DONE interrupt is transmitted
51  * synchronously with the interrupt being cleared on the remote
52  * device. It is not possible to delay processing. This callback
53  * will still occur, but protocols which rely on notification of
54  * asynchronous command processing will need modification.
55  *
56  * @param dev IPC device.
57  * @param arg Registered argument from intel_adsp_ipc_set_done_handler().
58  * @return True if IPC completion will be done externally, otherwise false.
59  * @note Returning True will cause this API to skip writing IPC registers
60  * signalling IPC message completion and those actions should be done by
61  * external code manually. Returning false from the handler will perform
62  * writing to IPC registers signalling message completion normally by this API.
63  */
64 typedef bool (*intel_adsp_ipc_done_t)(const struct device *dev, void *arg);
65 
66 struct intel_adsp_ipc_data {
67 	struct k_sem sem;
68 	struct k_spinlock lock;
69 	intel_adsp_ipc_handler_t handle_message;
70 	void *handler_arg;
71 	intel_adsp_ipc_done_t done_notify;
72 	void *done_arg;
73 	bool tx_ack_pending;
74 };
75 
76 void z_intel_adsp_ipc_isr(const void *devarg);
77 
78 /**
79  * @brief Register message callback handler.
80  *
81  * This function registers a handler function for received messages.
82  *
83  * @param dev IPC device.
84  * @param fn Callback function.
85  * @param arg Value to pass as the "arg" parameter to the function.
86  */
87 void intel_adsp_ipc_set_message_handler(const struct device *dev,
88 	intel_adsp_ipc_handler_t fn, void *arg);
89 
90 /**
91  * @brief Register done callback handler.
92  *
93  * This function registers a handler function for message completion
94  * notifications.
95  *
96  * @param dev IPC device.
97  * @param fn Callback function.
98  * @param arg Value to pass as the "arg" parameter to the function.
99  */
100 void intel_adsp_ipc_set_done_handler(const struct device *dev,
101 	intel_adsp_ipc_done_t fn, void *arg);
102 
103 /** @brief Initialize Intel ADSP IPC device.
104  *
105  * Initialize the device. Must be called before any API calls or
106  * interrupts can be serviced.
107  *
108  * @param dev IPC device.
109  * @return Zero on success, negative codes for error.
110  */
111 int intel_adsp_ipc_init(const struct device *dev);
112 
113 /** @brief Complete an in-progress message.
114  *
115  * Notify the other side that the current in-progress message is
116  * complete. This is a noop if no message is in progress.
117  *
118  * @note Further messages on the link will not be transmitted or
119  * received while an in-progress message remains incomplete!
120  *
121  * @param dev IPC device.
122  */
123 void intel_adsp_ipc_complete(const struct device *dev);
124 
125 /** @brief Message-in-progress predicate.
126  *
127  * Returns false if a message has been received but not yet completed
128  * via intel_adsp_ipc_complete(), true otherwise.
129  *
130  * @param dev IPC device.
131  * @return True if no message is in progress.
132  */
133 bool intel_adsp_ipc_is_complete(const struct device *dev);
134 
135 /** @brief Send an IPC message.
136  *
137  * Sends a message to the other side of an IPC link. The data and
138  * ext_data parameters are passed using the IDR/IDD registers.
139  * Returns 0 if the message was sent, negative error values:
140  * -EBUSY if there is already IPC message processed (intel_adsp_ipc_is_complete returns false).
141  * -ESHUTDOWN if IPC device will not send the message as it undergoes power
142  * transition.
143  *
144  * @param dev IPC device.
145  * @param data 30 bits value to transmit with the message (IDR register).
146  * @param ext_data Extended value to transmit with the message (IDD register).
147  * @return message successfully transmitted.
148  */
149 int intel_adsp_ipc_send_message(const struct device *dev,
150 	uint32_t data, uint32_t ext_data);
151 
152 /** @brief Send an IPC message, block until completion.
153  *
154  * As for intel_adsp_ipc_send_message(), but blocks the current thread until
155  * the completion of the message or the expiration of the provided
156  * timeout. Returns immediately if IPC device is during power transition.
157  *
158  * @param dev IPC device
159  * @param data 30 bits value to transmit with the message (IDR register)
160  * @param ext_data Extended value to transmit with the message (IDD register)
161  * @param timeout Maximum time to wait, or K_FOREVER, or K_NO_WAIT
162  * @return returns 0 if message successfully transmited, otherwise error code.
163  */
164 int intel_adsp_ipc_send_message_sync(const struct device *dev,
165 	uint32_t data, uint32_t ext_data, k_timeout_t timeout);
166 
167 
168 /** @brief Send an emergency IPC message.
169  *
170  * Sends a message to the other side of an IPC link. The data and ext_data parameters are passed
171  * using the IDR/IDD registers. Waits in a loop until it is possible to send a message.
172  *
173  * @param dev IPC device.
174  * @param data 30 bits value to transmit with the message (IDR register).
175  * @param ext_data Extended value to transmit with the message (IDD register).
176  */
177 void intel_adsp_ipc_send_message_emergency(const struct device *dev, uint32_t data,
178 					   uint32_t ext_data);
179 
180 #ifdef CONFIG_PM_DEVICE
181 
182 typedef int (*intel_adsp_ipc_resume_handler_t)(const struct device *dev, void *arg);
183 
184 typedef int (*intel_adsp_ipc_suspend_handler_t)(const struct device *dev, void *arg);
185 
186 /**
187  * @brief Registers resume callback handler used to resume Device from suspended state.
188  *
189  * @param dev IPC device.
190  * @param fn Callback function.
191  * @param arg Value to pass as the "arg" parameter to the function.
192  */
193 void intel_adsp_ipc_set_resume_handler(const struct device *dev,
194 	intel_adsp_ipc_resume_handler_t fn, void *arg);
195 
196 /**
197  * @brief Registers suspend callback handler used to suspend active Device.
198  *
199  * @param dev IPC device.
200  * @param fn Callback function.
201  * @param arg Value to pass as the "arg" parameter to the function.
202  */
203 void intel_adsp_ipc_set_suspend_handler(const struct device *dev,
204 	intel_adsp_ipc_suspend_handler_t fn, void *arg);
205 
206 struct ipc_control_driver_api {
207 	intel_adsp_ipc_resume_handler_t resume_fn;
208 	void *resume_fn_args;
209 	intel_adsp_ipc_suspend_handler_t suspend_fn;
210 	void *suspend_fn_args;
211 };
212 
213 #endif /* CONFIG_PM_DEVICE */
214 #endif /* ZEPHYR_INCLUDE_INTEL_ADSP_IPC_H */
215