Commit | Line | Data |
---|---|---|
b81fd263 SP |
1 | /* |
2 | * skl-sst-ipc.c - Intel skl IPC Support | |
3 | * | |
4 | * Copyright (C) 2014-15, Intel Corporation. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as version 2, as | |
8 | * published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * General Public License for more details. | |
14 | */ | |
15 | #include <linux/device.h> | |
16 | ||
17 | #include "../common/sst-dsp.h" | |
18 | #include "../common/sst-dsp-priv.h" | |
19 | #include "skl-sst-dsp.h" | |
20 | #include "skl-sst-ipc.h" | |
21 | ||
22 | ||
23 | #define IPC_IXC_STATUS_BITS 24 | |
24 | ||
25 | /* Global Message - Generic */ | |
26 | #define IPC_GLB_TYPE_SHIFT 24 | |
27 | #define IPC_GLB_TYPE_MASK (0xf << IPC_GLB_TYPE_SHIFT) | |
28 | #define IPC_GLB_TYPE(x) ((x) << IPC_GLB_TYPE_SHIFT) | |
29 | ||
30 | /* Global Message - Reply */ | |
31 | #define IPC_GLB_REPLY_STATUS_SHIFT 24 | |
32 | #define IPC_GLB_REPLY_STATUS_MASK ((0x1 << IPC_GLB_REPLY_STATUS_SHIFT) - 1) | |
33 | #define IPC_GLB_REPLY_STATUS(x) ((x) << IPC_GLB_REPLY_STATUS_SHIFT) | |
34 | ||
35 | #define IPC_TIMEOUT_MSECS 3000 | |
36 | ||
37 | #define IPC_EMPTY_LIST_SIZE 8 | |
38 | ||
39 | #define IPC_MSG_TARGET_SHIFT 30 | |
40 | #define IPC_MSG_TARGET_MASK 0x1 | |
41 | #define IPC_MSG_TARGET(x) (((x) & IPC_MSG_TARGET_MASK) \ | |
42 | << IPC_MSG_TARGET_SHIFT) | |
43 | ||
44 | #define IPC_MSG_DIR_SHIFT 29 | |
45 | #define IPC_MSG_DIR_MASK 0x1 | |
46 | #define IPC_MSG_DIR(x) (((x) & IPC_MSG_DIR_MASK) \ | |
47 | << IPC_MSG_DIR_SHIFT) | |
48 | /* Global Notification Message */ | |
49 | #define IPC_GLB_NOTIFY_TYPE_SHIFT 16 | |
50 | #define IPC_GLB_NOTIFY_TYPE_MASK 0xFF | |
51 | #define IPC_GLB_NOTIFY_TYPE(x) (((x) >> IPC_GLB_NOTIFY_TYPE_SHIFT) \ | |
52 | & IPC_GLB_NOTIFY_TYPE_MASK) | |
53 | ||
54 | #define IPC_GLB_NOTIFY_MSG_TYPE_SHIFT 24 | |
55 | #define IPC_GLB_NOTIFY_MSG_TYPE_MASK 0x1F | |
56 | #define IPC_GLB_NOTIFY_MSG_TYPE(x) (((x) >> IPC_GLB_NOTIFY_MSG_TYPE_SHIFT) \ | |
57 | & IPC_GLB_NOTIFY_MSG_TYPE_MASK) | |
58 | ||
59 | #define IPC_GLB_NOTIFY_RSP_SHIFT 29 | |
60 | #define IPC_GLB_NOTIFY_RSP_MASK 0x1 | |
61 | #define IPC_GLB_NOTIFY_RSP_TYPE(x) (((x) >> IPC_GLB_NOTIFY_RSP_SHIFT) \ | |
62 | & IPC_GLB_NOTIFY_RSP_MASK) | |
63 | ||
64 | /* Pipeline operations */ | |
65 | ||
66 | /* Create pipeline message */ | |
67 | #define IPC_PPL_MEM_SIZE_SHIFT 0 | |
68 | #define IPC_PPL_MEM_SIZE_MASK 0x7FF | |
69 | #define IPC_PPL_MEM_SIZE(x) (((x) & IPC_PPL_MEM_SIZE_MASK) \ | |
70 | << IPC_PPL_MEM_SIZE_SHIFT) | |
71 | ||
72 | #define IPC_PPL_TYPE_SHIFT 11 | |
73 | #define IPC_PPL_TYPE_MASK 0x1F | |
74 | #define IPC_PPL_TYPE(x) (((x) & IPC_PPL_TYPE_MASK) \ | |
75 | << IPC_PPL_TYPE_SHIFT) | |
76 | ||
77 | #define IPC_INSTANCE_ID_SHIFT 16 | |
78 | #define IPC_INSTANCE_ID_MASK 0xFF | |
79 | #define IPC_INSTANCE_ID(x) (((x) & IPC_INSTANCE_ID_MASK) \ | |
80 | << IPC_INSTANCE_ID_SHIFT) | |
81 | ||
82 | /* Set pipeline state message */ | |
83 | #define IPC_PPL_STATE_SHIFT 0 | |
84 | #define IPC_PPL_STATE_MASK 0x1F | |
85 | #define IPC_PPL_STATE(x) (((x) & IPC_PPL_STATE_MASK) \ | |
86 | << IPC_PPL_STATE_SHIFT) | |
87 | ||
88 | /* Module operations primary register */ | |
89 | #define IPC_MOD_ID_SHIFT 0 | |
90 | #define IPC_MOD_ID_MASK 0xFFFF | |
91 | #define IPC_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \ | |
92 | << IPC_MOD_ID_SHIFT) | |
93 | ||
94 | #define IPC_MOD_INSTANCE_ID_SHIFT 16 | |
95 | #define IPC_MOD_INSTANCE_ID_MASK 0xFF | |
96 | #define IPC_MOD_INSTANCE_ID(x) (((x) & IPC_MOD_INSTANCE_ID_MASK) \ | |
97 | << IPC_MOD_INSTANCE_ID_SHIFT) | |
98 | ||
99 | /* Init instance message extension register */ | |
100 | #define IPC_PARAM_BLOCK_SIZE_SHIFT 0 | |
101 | #define IPC_PARAM_BLOCK_SIZE_MASK 0xFFFF | |
102 | #define IPC_PARAM_BLOCK_SIZE(x) (((x) & IPC_PARAM_BLOCK_SIZE_MASK) \ | |
103 | << IPC_PARAM_BLOCK_SIZE_SHIFT) | |
104 | ||
105 | #define IPC_PPL_INSTANCE_ID_SHIFT 16 | |
106 | #define IPC_PPL_INSTANCE_ID_MASK 0xFF | |
107 | #define IPC_PPL_INSTANCE_ID(x) (((x) & IPC_PPL_INSTANCE_ID_MASK) \ | |
108 | << IPC_PPL_INSTANCE_ID_SHIFT) | |
109 | ||
110 | #define IPC_CORE_ID_SHIFT 24 | |
111 | #define IPC_CORE_ID_MASK 0x1F | |
112 | #define IPC_CORE_ID(x) (((x) & IPC_CORE_ID_MASK) \ | |
113 | << IPC_CORE_ID_SHIFT) | |
114 | ||
115 | /* Bind/Unbind message extension register */ | |
116 | #define IPC_DST_MOD_ID_SHIFT 0 | |
117 | #define IPC_DST_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \ | |
118 | << IPC_DST_MOD_ID_SHIFT) | |
119 | ||
120 | #define IPC_DST_MOD_INSTANCE_ID_SHIFT 16 | |
121 | #define IPC_DST_MOD_INSTANCE_ID(x) (((x) & IPC_MOD_INSTANCE_ID_MASK) \ | |
122 | << IPC_DST_MOD_INSTANCE_ID_SHIFT) | |
123 | ||
124 | #define IPC_DST_QUEUE_SHIFT 24 | |
125 | #define IPC_DST_QUEUE_MASK 0x7 | |
126 | #define IPC_DST_QUEUE(x) (((x) & IPC_DST_QUEUE_MASK) \ | |
127 | << IPC_DST_QUEUE_SHIFT) | |
128 | ||
129 | #define IPC_SRC_QUEUE_SHIFT 27 | |
130 | #define IPC_SRC_QUEUE_MASK 0x7 | |
131 | #define IPC_SRC_QUEUE(x) (((x) & IPC_SRC_QUEUE_MASK) \ | |
132 | << IPC_SRC_QUEUE_SHIFT) | |
6c5768b3 D |
133 | /* Load Module count */ |
134 | #define IPC_LOAD_MODULE_SHIFT 0 | |
135 | #define IPC_LOAD_MODULE_MASK 0xFF | |
136 | #define IPC_LOAD_MODULE_CNT(x) (((x) & IPC_LOAD_MODULE_MASK) \ | |
137 | << IPC_LOAD_MODULE_SHIFT) | |
b81fd263 SP |
138 | |
139 | /* Save pipeline messgae extension register */ | |
140 | #define IPC_DMA_ID_SHIFT 0 | |
141 | #define IPC_DMA_ID_MASK 0x1F | |
142 | #define IPC_DMA_ID(x) (((x) & IPC_DMA_ID_MASK) \ | |
143 | << IPC_DMA_ID_SHIFT) | |
144 | /* Large Config message extension register */ | |
145 | #define IPC_DATA_OFFSET_SZ_SHIFT 0 | |
146 | #define IPC_DATA_OFFSET_SZ_MASK 0xFFFFF | |
147 | #define IPC_DATA_OFFSET_SZ(x) (((x) & IPC_DATA_OFFSET_SZ_MASK) \ | |
148 | << IPC_DATA_OFFSET_SZ_SHIFT) | |
149 | #define IPC_DATA_OFFSET_SZ_CLEAR ~(IPC_DATA_OFFSET_SZ_MASK \ | |
150 | << IPC_DATA_OFFSET_SZ_SHIFT) | |
151 | ||
152 | #define IPC_LARGE_PARAM_ID_SHIFT 20 | |
153 | #define IPC_LARGE_PARAM_ID_MASK 0xFF | |
154 | #define IPC_LARGE_PARAM_ID(x) (((x) & IPC_LARGE_PARAM_ID_MASK) \ | |
155 | << IPC_LARGE_PARAM_ID_SHIFT) | |
156 | ||
157 | #define IPC_FINAL_BLOCK_SHIFT 28 | |
158 | #define IPC_FINAL_BLOCK_MASK 0x1 | |
159 | #define IPC_FINAL_BLOCK(x) (((x) & IPC_FINAL_BLOCK_MASK) \ | |
160 | << IPC_FINAL_BLOCK_SHIFT) | |
161 | ||
162 | #define IPC_INITIAL_BLOCK_SHIFT 29 | |
163 | #define IPC_INITIAL_BLOCK_MASK 0x1 | |
164 | #define IPC_INITIAL_BLOCK(x) (((x) & IPC_INITIAL_BLOCK_MASK) \ | |
165 | << IPC_INITIAL_BLOCK_SHIFT) | |
166 | #define IPC_INITIAL_BLOCK_CLEAR ~(IPC_INITIAL_BLOCK_MASK \ | |
167 | << IPC_INITIAL_BLOCK_SHIFT) | |
168 | ||
169 | enum skl_ipc_msg_target { | |
170 | IPC_FW_GEN_MSG = 0, | |
171 | IPC_MOD_MSG = 1 | |
172 | }; | |
173 | ||
174 | enum skl_ipc_msg_direction { | |
175 | IPC_MSG_REQUEST = 0, | |
176 | IPC_MSG_REPLY = 1 | |
177 | }; | |
178 | ||
179 | /* Global Message Types */ | |
180 | enum skl_ipc_glb_type { | |
181 | IPC_GLB_GET_FW_VERSION = 0, /* Retrieves firmware version */ | |
182 | IPC_GLB_LOAD_MULTIPLE_MODS = 15, | |
183 | IPC_GLB_UNLOAD_MULTIPLE_MODS = 16, | |
184 | IPC_GLB_CREATE_PPL = 17, | |
185 | IPC_GLB_DELETE_PPL = 18, | |
186 | IPC_GLB_SET_PPL_STATE = 19, | |
187 | IPC_GLB_GET_PPL_STATE = 20, | |
188 | IPC_GLB_GET_PPL_CONTEXT_SIZE = 21, | |
189 | IPC_GLB_SAVE_PPL = 22, | |
190 | IPC_GLB_RESTORE_PPL = 23, | |
191 | IPC_GLB_NOTIFY = 26, | |
192 | IPC_GLB_MAX_IPC_MSG_NUMBER = 31 /* Maximum message number */ | |
193 | }; | |
194 | ||
195 | enum skl_ipc_glb_reply { | |
196 | IPC_GLB_REPLY_SUCCESS = 0, | |
197 | ||
198 | IPC_GLB_REPLY_UNKNOWN_MSG_TYPE = 1, | |
199 | IPC_GLB_REPLY_ERROR_INVALID_PARAM = 2, | |
200 | ||
201 | IPC_GLB_REPLY_BUSY = 3, | |
202 | IPC_GLB_REPLY_PENDING = 4, | |
203 | IPC_GLB_REPLY_FAILURE = 5, | |
204 | IPC_GLB_REPLY_INVALID_REQUEST = 6, | |
205 | ||
206 | IPC_GLB_REPLY_OUT_OF_MEMORY = 7, | |
207 | IPC_GLB_REPLY_OUT_OF_MIPS = 8, | |
208 | ||
209 | IPC_GLB_REPLY_INVALID_RESOURCE_ID = 9, | |
210 | IPC_GLB_REPLY_INVALID_RESOURCE_STATE = 10, | |
211 | ||
212 | IPC_GLB_REPLY_MOD_MGMT_ERROR = 100, | |
213 | IPC_GLB_REPLY_MOD_LOAD_CL_FAILED = 101, | |
214 | IPC_GLB_REPLY_MOD_LOAD_INVALID_HASH = 102, | |
215 | ||
216 | IPC_GLB_REPLY_MOD_UNLOAD_INST_EXIST = 103, | |
217 | IPC_GLB_REPLY_MOD_NOT_INITIALIZED = 104, | |
218 | ||
219 | IPC_GLB_REPLY_INVALID_CONFIG_PARAM_ID = 120, | |
220 | IPC_GLB_REPLY_INVALID_CONFIG_DATA_LEN = 121, | |
221 | IPC_GLB_REPLY_GATEWAY_NOT_INITIALIZED = 140, | |
222 | IPC_GLB_REPLY_GATEWAY_NOT_EXIST = 141, | |
223 | ||
224 | IPC_GLB_REPLY_PPL_NOT_INITIALIZED = 160, | |
225 | IPC_GLB_REPLY_PPL_NOT_EXIST = 161, | |
226 | IPC_GLB_REPLY_PPL_SAVE_FAILED = 162, | |
227 | IPC_GLB_REPLY_PPL_RESTORE_FAILED = 163, | |
228 | ||
229 | IPC_MAX_STATUS = ((1<<IPC_IXC_STATUS_BITS)-1) | |
230 | }; | |
231 | ||
232 | enum skl_ipc_notification_type { | |
233 | IPC_GLB_NOTIFY_GLITCH = 0, | |
234 | IPC_GLB_NOTIFY_OVERRUN = 1, | |
235 | IPC_GLB_NOTIFY_UNDERRUN = 2, | |
236 | IPC_GLB_NOTIFY_END_STREAM = 3, | |
237 | IPC_GLB_NOTIFY_PHRASE_DETECTED = 4, | |
238 | IPC_GLB_NOTIFY_RESOURCE_EVENT = 5, | |
239 | IPC_GLB_NOTIFY_LOG_BUFFER_STATUS = 6, | |
240 | IPC_GLB_NOTIFY_TIMESTAMP_CAPTURED = 7, | |
241 | IPC_GLB_NOTIFY_FW_READY = 8 | |
242 | }; | |
243 | ||
244 | /* Module Message Types */ | |
245 | enum skl_ipc_module_msg { | |
246 | IPC_MOD_INIT_INSTANCE = 0, | |
247 | IPC_MOD_CONFIG_GET = 1, | |
248 | IPC_MOD_CONFIG_SET = 2, | |
249 | IPC_MOD_LARGE_CONFIG_GET = 3, | |
250 | IPC_MOD_LARGE_CONFIG_SET = 4, | |
251 | IPC_MOD_BIND = 5, | |
252 | IPC_MOD_UNBIND = 6, | |
253 | IPC_MOD_SET_DX = 7 | |
254 | }; | |
255 | ||
256 | static void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data, | |
257 | size_t tx_size) | |
258 | { | |
259 | if (tx_size) | |
260 | memcpy(msg->tx_data, tx_data, tx_size); | |
261 | } | |
262 | ||
263 | static bool skl_ipc_is_dsp_busy(struct sst_dsp *dsp) | |
264 | { | |
265 | u32 hipci; | |
266 | ||
267 | hipci = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCI); | |
268 | return (hipci & SKL_ADSP_REG_HIPCI_BUSY); | |
269 | } | |
270 | ||
271 | /* Lock to be held by caller */ | |
272 | static void skl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) | |
273 | { | |
274 | struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->header); | |
275 | ||
276 | if (msg->tx_size) | |
277 | sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size); | |
278 | sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCIE, | |
279 | header->extension); | |
280 | sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCI, | |
281 | header->primary | SKL_ADSP_REG_HIPCI_BUSY); | |
282 | } | |
283 | ||
284 | static struct ipc_message *skl_ipc_reply_get_msg(struct sst_generic_ipc *ipc, | |
285 | u64 ipc_header) | |
286 | { | |
287 | struct ipc_message *msg = NULL; | |
288 | struct skl_ipc_header *header = (struct skl_ipc_header *)(&ipc_header); | |
289 | ||
290 | if (list_empty(&ipc->rx_list)) { | |
291 | dev_err(ipc->dev, "ipc: rx list is empty but received 0x%x\n", | |
292 | header->primary); | |
293 | goto out; | |
294 | } | |
295 | ||
296 | msg = list_first_entry(&ipc->rx_list, struct ipc_message, list); | |
297 | ||
298 | out: | |
299 | return msg; | |
300 | ||
301 | } | |
302 | ||
303 | static int skl_ipc_process_notification(struct sst_generic_ipc *ipc, | |
304 | struct skl_ipc_header header) | |
305 | { | |
306 | struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc); | |
307 | ||
308 | if (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { | |
309 | switch (IPC_GLB_NOTIFY_TYPE(header.primary)) { | |
310 | ||
311 | case IPC_GLB_NOTIFY_UNDERRUN: | |
312 | dev_err(ipc->dev, "FW Underrun %x\n", header.primary); | |
313 | break; | |
314 | ||
315 | case IPC_GLB_NOTIFY_RESOURCE_EVENT: | |
316 | dev_err(ipc->dev, "MCPS Budget Violation: %x\n", | |
317 | header.primary); | |
318 | break; | |
319 | ||
320 | case IPC_GLB_NOTIFY_FW_READY: | |
321 | skl->boot_complete = true; | |
322 | wake_up(&skl->boot_wait); | |
323 | break; | |
324 | ||
325 | default: | |
326 | dev_err(ipc->dev, "ipc: Unhandled error msg=%x", | |
327 | header.primary); | |
328 | break; | |
329 | } | |
330 | } | |
331 | ||
332 | return 0; | |
333 | } | |
334 | ||
335 | static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, | |
336 | struct skl_ipc_header header) | |
337 | { | |
338 | struct ipc_message *msg; | |
339 | u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK; | |
340 | u64 *ipc_header = (u64 *)(&header); | |
341 | ||
342 | msg = skl_ipc_reply_get_msg(ipc, *ipc_header); | |
343 | if (msg == NULL) { | |
344 | dev_dbg(ipc->dev, "ipc: rx list is empty\n"); | |
345 | return; | |
346 | } | |
347 | ||
348 | /* first process the header */ | |
349 | switch (reply) { | |
350 | case IPC_GLB_REPLY_SUCCESS: | |
351 | dev_info(ipc->dev, "ipc FW reply %x: success\n", header.primary); | |
cce1c7f3 MJ |
352 | /* copy the rx data from the mailbox */ |
353 | sst_dsp_inbox_read(ipc->dsp, msg->rx_data, msg->rx_size); | |
b81fd263 SP |
354 | break; |
355 | ||
356 | case IPC_GLB_REPLY_OUT_OF_MEMORY: | |
357 | dev_err(ipc->dev, "ipc fw reply: %x: no memory\n", header.primary); | |
358 | msg->errno = -ENOMEM; | |
359 | break; | |
360 | ||
361 | case IPC_GLB_REPLY_BUSY: | |
362 | dev_err(ipc->dev, "ipc fw reply: %x: Busy\n", header.primary); | |
363 | msg->errno = -EBUSY; | |
364 | break; | |
365 | ||
366 | default: | |
367 | dev_err(ipc->dev, "Unknown ipc reply: 0x%x", reply); | |
368 | msg->errno = -EINVAL; | |
369 | break; | |
370 | } | |
371 | ||
28f3b6f1 OA |
372 | if (reply != IPC_GLB_REPLY_SUCCESS) { |
373 | dev_err(ipc->dev, "ipc FW reply: reply=%d", reply); | |
374 | dev_err(ipc->dev, "FW Error Code: %u\n", | |
375 | ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); | |
376 | } | |
377 | ||
b81fd263 SP |
378 | list_del(&msg->list); |
379 | sst_ipc_tx_msg_reply_complete(ipc, msg); | |
380 | } | |
381 | ||
382 | irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) | |
383 | { | |
384 | struct sst_dsp *dsp = context; | |
385 | struct skl_sst *skl = sst_dsp_get_thread_context(dsp); | |
386 | struct sst_generic_ipc *ipc = &skl->ipc; | |
387 | struct skl_ipc_header header = {0}; | |
388 | u32 hipcie, hipct, hipcte; | |
389 | int ipc_irq = 0; | |
390 | ||
6cb00333 SP |
391 | if (dsp->intr_status & SKL_ADSPIS_CL_DMA) |
392 | skl_cldma_process_intr(dsp); | |
393 | ||
b81fd263 SP |
394 | /* Here we handle IPC interrupts only */ |
395 | if (!(dsp->intr_status & SKL_ADSPIS_IPC)) | |
396 | return IRQ_NONE; | |
397 | ||
398 | hipcie = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCIE); | |
399 | hipct = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCT); | |
400 | ||
401 | /* reply message from DSP */ | |
402 | if (hipcie & SKL_ADSP_REG_HIPCIE_DONE) { | |
403 | sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL, | |
404 | SKL_ADSP_REG_HIPCCTL_DONE, 0); | |
405 | ||
406 | /* clear DONE bit - tell DSP we have completed the operation */ | |
407 | sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCIE, | |
408 | SKL_ADSP_REG_HIPCIE_DONE, SKL_ADSP_REG_HIPCIE_DONE); | |
409 | ||
410 | ipc_irq = 1; | |
411 | ||
412 | /* unmask Done interrupt */ | |
413 | sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL, | |
414 | SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE); | |
415 | } | |
416 | ||
417 | /* New message from DSP */ | |
418 | if (hipct & SKL_ADSP_REG_HIPCT_BUSY) { | |
419 | hipcte = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCTE); | |
420 | header.primary = hipct; | |
421 | header.extension = hipcte; | |
422 | dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x", | |
423 | header.primary); | |
424 | dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x", | |
425 | header.extension); | |
426 | ||
427 | if (IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) { | |
428 | /* Handle Immediate reply from DSP Core */ | |
429 | skl_ipc_process_reply(ipc, header); | |
430 | } else { | |
431 | dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n"); | |
432 | skl_ipc_process_notification(ipc, header); | |
433 | } | |
434 | /* clear busy interrupt */ | |
435 | sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCT, | |
436 | SKL_ADSP_REG_HIPCT_BUSY, SKL_ADSP_REG_HIPCT_BUSY); | |
437 | ipc_irq = 1; | |
438 | } | |
439 | ||
440 | if (ipc_irq == 0) | |
441 | return IRQ_NONE; | |
442 | ||
443 | skl_ipc_int_enable(dsp); | |
444 | ||
445 | /* continue to send any remaining messages... */ | |
446 | queue_kthread_work(&ipc->kworker, &ipc->kwork); | |
447 | ||
448 | return IRQ_HANDLED; | |
449 | } | |
450 | ||
451 | void skl_ipc_int_enable(struct sst_dsp *ctx) | |
452 | { | |
453 | sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_ADSPIC, | |
454 | SKL_ADSPIC_IPC, SKL_ADSPIC_IPC); | |
455 | } | |
456 | ||
457 | void skl_ipc_int_disable(struct sst_dsp *ctx) | |
458 | { | |
459 | sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPIC, | |
460 | SKL_ADSPIC_IPC, 0); | |
461 | } | |
462 | ||
463 | void skl_ipc_op_int_enable(struct sst_dsp *ctx) | |
464 | { | |
465 | /* enable IPC DONE interrupt */ | |
466 | sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL, | |
467 | SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE); | |
468 | ||
469 | /* Enable IPC BUSY interrupt */ | |
470 | sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL, | |
471 | SKL_ADSP_REG_HIPCCTL_BUSY, SKL_ADSP_REG_HIPCCTL_BUSY); | |
472 | } | |
473 | ||
84c9e283 JK |
474 | void skl_ipc_op_int_disable(struct sst_dsp *ctx) |
475 | { | |
476 | /* disable IPC DONE interrupt */ | |
477 | sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_HIPCCTL, | |
478 | SKL_ADSP_REG_HIPCCTL_DONE, 0); | |
479 | ||
480 | /* Disable IPC BUSY interrupt */ | |
481 | sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_HIPCCTL, | |
482 | SKL_ADSP_REG_HIPCCTL_BUSY, 0); | |
483 | ||
484 | } | |
485 | ||
b81fd263 SP |
486 | bool skl_ipc_int_status(struct sst_dsp *ctx) |
487 | { | |
488 | return sst_dsp_shim_read_unlocked(ctx, | |
489 | SKL_ADSP_REG_ADSPIS) & SKL_ADSPIS_IPC; | |
490 | } | |
491 | ||
492 | int skl_ipc_init(struct device *dev, struct skl_sst *skl) | |
493 | { | |
494 | struct sst_generic_ipc *ipc; | |
495 | int err; | |
496 | ||
497 | ipc = &skl->ipc; | |
498 | ipc->dsp = skl->dsp; | |
499 | ipc->dev = dev; | |
500 | ||
501 | ipc->tx_data_max_size = SKL_ADSP_W1_SZ; | |
502 | ipc->rx_data_max_size = SKL_ADSP_W0_UP_SZ; | |
503 | ||
504 | err = sst_ipc_init(ipc); | |
505 | if (err) | |
506 | return err; | |
507 | ||
508 | ipc->ops.tx_msg = skl_ipc_tx_msg; | |
509 | ipc->ops.tx_data_copy = skl_ipc_tx_data_copy; | |
510 | ipc->ops.is_dsp_busy = skl_ipc_is_dsp_busy; | |
511 | ||
512 | return 0; | |
513 | } | |
514 | ||
515 | void skl_ipc_free(struct sst_generic_ipc *ipc) | |
516 | { | |
517 | /* Disable IPC DONE interrupt */ | |
518 | sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL, | |
519 | SKL_ADSP_REG_HIPCCTL_DONE, 0); | |
520 | ||
521 | /* Disable IPC BUSY interrupt */ | |
522 | sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL, | |
523 | SKL_ADSP_REG_HIPCCTL_BUSY, 0); | |
a750ba5f SP |
524 | |
525 | sst_ipc_fini(ipc); | |
b81fd263 SP |
526 | } |
527 | ||
528 | int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, | |
529 | u16 ppl_mem_size, u8 ppl_type, u8 instance_id) | |
530 | { | |
531 | struct skl_ipc_header header = {0}; | |
532 | u64 *ipc_header = (u64 *)(&header); | |
533 | int ret; | |
534 | ||
535 | header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); | |
536 | header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); | |
537 | header.primary |= IPC_GLB_TYPE(IPC_GLB_CREATE_PPL); | |
538 | header.primary |= IPC_INSTANCE_ID(instance_id); | |
539 | header.primary |= IPC_PPL_TYPE(ppl_type); | |
540 | header.primary |= IPC_PPL_MEM_SIZE(ppl_mem_size); | |
541 | ||
542 | dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); | |
543 | ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); | |
544 | if (ret < 0) { | |
545 | dev_err(ipc->dev, "ipc: create pipeline fail, err: %d\n", ret); | |
546 | return ret; | |
547 | } | |
548 | ||
549 | return ret; | |
550 | } | |
551 | EXPORT_SYMBOL_GPL(skl_ipc_create_pipeline); | |
552 | ||
553 | int skl_ipc_delete_pipeline(struct sst_generic_ipc *ipc, u8 instance_id) | |
554 | { | |
555 | struct skl_ipc_header header = {0}; | |
556 | u64 *ipc_header = (u64 *)(&header); | |
557 | int ret; | |
558 | ||
559 | header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); | |
560 | header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); | |
561 | header.primary |= IPC_GLB_TYPE(IPC_GLB_DELETE_PPL); | |
562 | header.primary |= IPC_INSTANCE_ID(instance_id); | |
563 | ||
564 | dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); | |
565 | ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); | |
566 | if (ret < 0) { | |
567 | dev_err(ipc->dev, "ipc: delete pipeline failed, err %d\n", ret); | |
568 | return ret; | |
569 | } | |
570 | ||
571 | return 0; | |
572 | } | |
573 | EXPORT_SYMBOL_GPL(skl_ipc_delete_pipeline); | |
574 | ||
575 | int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc, | |
576 | u8 instance_id, enum skl_ipc_pipeline_state state) | |
577 | { | |
578 | struct skl_ipc_header header = {0}; | |
579 | u64 *ipc_header = (u64 *)(&header); | |
580 | int ret; | |
581 | ||
582 | header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); | |
583 | header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); | |
584 | header.primary |= IPC_GLB_TYPE(IPC_GLB_SET_PPL_STATE); | |
585 | header.primary |= IPC_INSTANCE_ID(instance_id); | |
586 | header.primary |= IPC_PPL_STATE(state); | |
587 | ||
588 | dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); | |
589 | ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); | |
590 | if (ret < 0) { | |
591 | dev_err(ipc->dev, "ipc: set pipeline state failed, err: %d\n", ret); | |
592 | return ret; | |
593 | } | |
594 | return ret; | |
595 | } | |
596 | EXPORT_SYMBOL_GPL(skl_ipc_set_pipeline_state); | |
597 | ||
598 | int | |
599 | skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, u8 instance_id, int dma_id) | |
600 | { | |
601 | struct skl_ipc_header header = {0}; | |
602 | u64 *ipc_header = (u64 *)(&header); | |
603 | int ret; | |
604 | ||
605 | header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); | |
606 | header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); | |
607 | header.primary |= IPC_GLB_TYPE(IPC_GLB_SAVE_PPL); | |
608 | header.primary |= IPC_INSTANCE_ID(instance_id); | |
609 | ||
610 | header.extension = IPC_DMA_ID(dma_id); | |
611 | dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); | |
612 | ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); | |
613 | if (ret < 0) { | |
614 | dev_err(ipc->dev, "ipc: save pipeline failed, err: %d\n", ret); | |
615 | return ret; | |
616 | } | |
617 | ||
618 | return ret; | |
619 | } | |
620 | EXPORT_SYMBOL_GPL(skl_ipc_save_pipeline); | |
621 | ||
622 | int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id) | |
623 | { | |
624 | struct skl_ipc_header header = {0}; | |
625 | u64 *ipc_header = (u64 *)(&header); | |
626 | int ret; | |
627 | ||
628 | header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); | |
629 | header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); | |
630 | header.primary |= IPC_GLB_TYPE(IPC_GLB_RESTORE_PPL); | |
631 | header.primary |= IPC_INSTANCE_ID(instance_id); | |
632 | ||
633 | dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); | |
634 | ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); | |
635 | if (ret < 0) { | |
636 | dev_err(ipc->dev, "ipc: restore pipeline failed, err: %d\n", ret); | |
637 | return ret; | |
638 | } | |
639 | ||
640 | return ret; | |
641 | } | |
642 | EXPORT_SYMBOL_GPL(skl_ipc_restore_pipeline); | |
643 | ||
644 | int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id, | |
645 | u16 module_id, struct skl_ipc_dxstate_info *dx) | |
646 | { | |
647 | struct skl_ipc_header header = {0}; | |
648 | u64 *ipc_header = (u64 *)(&header); | |
649 | int ret; | |
650 | ||
651 | header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); | |
652 | header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); | |
653 | header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_DX); | |
654 | header.primary |= IPC_MOD_INSTANCE_ID(instance_id); | |
655 | header.primary |= IPC_MOD_ID(module_id); | |
656 | ||
657 | dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, | |
658 | header.primary, header.extension); | |
659 | ret = sst_ipc_tx_message_wait(ipc, *ipc_header, | |
aaec7e9f | 660 | dx, sizeof(*dx), NULL, 0); |
b81fd263 SP |
661 | if (ret < 0) { |
662 | dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret); | |
663 | return ret; | |
664 | } | |
665 | ||
666 | return ret; | |
667 | } | |
668 | EXPORT_SYMBOL_GPL(skl_ipc_set_dx); | |
669 | ||
670 | int skl_ipc_init_instance(struct sst_generic_ipc *ipc, | |
671 | struct skl_ipc_init_instance_msg *msg, void *param_data) | |
672 | { | |
673 | struct skl_ipc_header header = {0}; | |
674 | u64 *ipc_header = (u64 *)(&header); | |
675 | int ret; | |
676 | u32 *buffer = (u32 *)param_data; | |
677 | /* param_block_size must be in dwords */ | |
678 | u16 param_block_size = msg->param_data_size / sizeof(u32); | |
679 | ||
680 | print_hex_dump(KERN_DEBUG, NULL, DUMP_PREFIX_NONE, | |
681 | 16, 4, buffer, param_block_size, false); | |
682 | ||
683 | header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); | |
684 | header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); | |
685 | header.primary |= IPC_GLB_TYPE(IPC_MOD_INIT_INSTANCE); | |
686 | header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); | |
687 | header.primary |= IPC_MOD_ID(msg->module_id); | |
688 | ||
689 | header.extension = IPC_CORE_ID(msg->core_id); | |
690 | header.extension |= IPC_PPL_INSTANCE_ID(msg->ppl_instance_id); | |
691 | header.extension |= IPC_PARAM_BLOCK_SIZE(param_block_size); | |
692 | ||
693 | dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, | |
694 | header.primary, header.extension); | |
695 | ret = sst_ipc_tx_message_wait(ipc, *ipc_header, param_data, | |
696 | msg->param_data_size, NULL, 0); | |
697 | ||
698 | if (ret < 0) { | |
699 | dev_err(ipc->dev, "ipc: init instance failed\n"); | |
700 | return ret; | |
701 | } | |
702 | ||
703 | return ret; | |
704 | } | |
705 | EXPORT_SYMBOL_GPL(skl_ipc_init_instance); | |
706 | ||
707 | int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc, | |
708 | struct skl_ipc_bind_unbind_msg *msg) | |
709 | { | |
710 | struct skl_ipc_header header = {0}; | |
711 | u64 *ipc_header = (u64 *)(&header); | |
712 | u8 bind_unbind = msg->bind ? IPC_MOD_BIND : IPC_MOD_UNBIND; | |
713 | int ret; | |
714 | ||
715 | header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); | |
716 | header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); | |
717 | header.primary |= IPC_GLB_TYPE(bind_unbind); | |
718 | header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); | |
719 | header.primary |= IPC_MOD_ID(msg->module_id); | |
720 | ||
721 | header.extension = IPC_DST_MOD_ID(msg->dst_module_id); | |
722 | header.extension |= IPC_DST_MOD_INSTANCE_ID(msg->dst_instance_id); | |
723 | header.extension |= IPC_DST_QUEUE(msg->dst_queue); | |
724 | header.extension |= IPC_SRC_QUEUE(msg->src_queue); | |
725 | ||
726 | dev_dbg(ipc->dev, "In %s hdr=%x ext=%x\n", __func__, header.primary, | |
727 | header.extension); | |
728 | ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); | |
729 | if (ret < 0) { | |
730 | dev_err(ipc->dev, "ipc: bind/unbind faileden"); | |
731 | return ret; | |
732 | } | |
733 | ||
734 | return ret; | |
735 | } | |
736 | EXPORT_SYMBOL_GPL(skl_ipc_bind_unbind); | |
737 | ||
6c5768b3 D |
738 | /* |
739 | * In order to load a module we need to send IPC to initiate that. DMA will | |
740 | * performed to load the module memory. The FW supports multiple module load | |
741 | * at single shot, so we can send IPC with N modules represented by | |
742 | * module_cnt | |
743 | */ | |
744 | int skl_ipc_load_modules(struct sst_generic_ipc *ipc, | |
745 | u8 module_cnt, void *data) | |
746 | { | |
747 | struct skl_ipc_header header = {0}; | |
748 | u64 *ipc_header = (u64 *)(&header); | |
749 | int ret; | |
750 | ||
751 | header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); | |
752 | header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); | |
753 | header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_MULTIPLE_MODS); | |
754 | header.primary |= IPC_LOAD_MODULE_CNT(module_cnt); | |
755 | ||
756 | ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data, | |
757 | (sizeof(u16) * module_cnt), NULL, 0); | |
758 | if (ret < 0) | |
759 | dev_err(ipc->dev, "ipc: load modules failed :%d\n", ret); | |
760 | ||
761 | return ret; | |
762 | } | |
763 | EXPORT_SYMBOL_GPL(skl_ipc_load_modules); | |
764 | ||
765 | int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, u8 module_cnt, | |
766 | void *data) | |
767 | { | |
768 | struct skl_ipc_header header = {0}; | |
769 | u64 *ipc_header = (u64 *)(&header); | |
770 | int ret; | |
771 | ||
772 | header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); | |
773 | header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); | |
774 | header.primary |= IPC_GLB_TYPE(IPC_GLB_UNLOAD_MULTIPLE_MODS); | |
775 | header.primary |= IPC_LOAD_MODULE_CNT(module_cnt); | |
776 | ||
777 | ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data, | |
778 | (sizeof(u16) * module_cnt), NULL, 0); | |
779 | if (ret < 0) | |
780 | dev_err(ipc->dev, "ipc: unload modules failed :%d\n", ret); | |
781 | ||
782 | return ret; | |
783 | } | |
784 | EXPORT_SYMBOL_GPL(skl_ipc_unload_modules); | |
785 | ||
b81fd263 SP |
786 | int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, |
787 | struct skl_ipc_large_config_msg *msg, u32 *param) | |
788 | { | |
789 | struct skl_ipc_header header = {0}; | |
790 | u64 *ipc_header = (u64 *)(&header); | |
791 | int ret = 0; | |
792 | size_t sz_remaining, tx_size, data_offset; | |
793 | ||
794 | header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); | |
795 | header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); | |
796 | header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_SET); | |
797 | header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); | |
798 | header.primary |= IPC_MOD_ID(msg->module_id); | |
799 | ||
800 | header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size); | |
801 | header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id); | |
802 | header.extension |= IPC_FINAL_BLOCK(0); | |
803 | header.extension |= IPC_INITIAL_BLOCK(1); | |
804 | ||
805 | sz_remaining = msg->param_data_size; | |
806 | data_offset = 0; | |
807 | while (sz_remaining != 0) { | |
808 | tx_size = sz_remaining > SKL_ADSP_W1_SZ | |
809 | ? SKL_ADSP_W1_SZ : sz_remaining; | |
810 | if (tx_size == sz_remaining) | |
811 | header.extension |= IPC_FINAL_BLOCK(1); | |
812 | ||
813 | dev_dbg(ipc->dev, "In %s primary=%#x ext=%#x\n", __func__, | |
814 | header.primary, header.extension); | |
815 | dev_dbg(ipc->dev, "transmitting offset: %#x, size: %#x\n", | |
816 | (unsigned)data_offset, (unsigned)tx_size); | |
817 | ret = sst_ipc_tx_message_wait(ipc, *ipc_header, | |
818 | ((char *)param) + data_offset, | |
819 | tx_size, NULL, 0); | |
820 | if (ret < 0) { | |
821 | dev_err(ipc->dev, | |
822 | "ipc: set large config fail, err: %d\n", ret); | |
823 | return ret; | |
824 | } | |
825 | sz_remaining -= tx_size; | |
826 | data_offset = msg->param_data_size - sz_remaining; | |
827 | ||
828 | /* clear the fields */ | |
829 | header.extension &= IPC_INITIAL_BLOCK_CLEAR; | |
830 | header.extension &= IPC_DATA_OFFSET_SZ_CLEAR; | |
831 | /* fill the fields */ | |
832 | header.extension |= IPC_INITIAL_BLOCK(0); | |
833 | header.extension |= IPC_DATA_OFFSET_SZ(data_offset); | |
834 | } | |
835 | ||
836 | return ret; | |
837 | } | |
838 | EXPORT_SYMBOL_GPL(skl_ipc_set_large_config); | |
cce1c7f3 MJ |
839 | |
840 | int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, | |
841 | struct skl_ipc_large_config_msg *msg, u32 *param) | |
842 | { | |
843 | struct skl_ipc_header header = {0}; | |
844 | u64 *ipc_header = (u64 *)(&header); | |
845 | int ret = 0; | |
846 | size_t sz_remaining, rx_size, data_offset; | |
847 | ||
848 | header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); | |
849 | header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); | |
850 | header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_GET); | |
851 | header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); | |
852 | header.primary |= IPC_MOD_ID(msg->module_id); | |
853 | ||
854 | header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size); | |
855 | header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id); | |
856 | header.extension |= IPC_FINAL_BLOCK(1); | |
857 | header.extension |= IPC_INITIAL_BLOCK(1); | |
858 | ||
859 | sz_remaining = msg->param_data_size; | |
860 | data_offset = 0; | |
861 | ||
862 | while (sz_remaining != 0) { | |
863 | rx_size = sz_remaining > SKL_ADSP_W1_SZ | |
864 | ? SKL_ADSP_W1_SZ : sz_remaining; | |
865 | if (rx_size == sz_remaining) | |
866 | header.extension |= IPC_FINAL_BLOCK(1); | |
867 | ||
868 | ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, | |
869 | ((char *)param) + data_offset, | |
870 | msg->param_data_size); | |
871 | if (ret < 0) { | |
872 | dev_err(ipc->dev, | |
873 | "ipc: get large config fail, err: %d\n", ret); | |
874 | return ret; | |
875 | } | |
876 | sz_remaining -= rx_size; | |
877 | data_offset = msg->param_data_size - sz_remaining; | |
878 | ||
879 | /* clear the fields */ | |
880 | header.extension &= IPC_INITIAL_BLOCK_CLEAR; | |
881 | header.extension &= IPC_DATA_OFFSET_SZ_CLEAR; | |
882 | /* fill the fields */ | |
883 | header.extension |= IPC_INITIAL_BLOCK(1); | |
884 | header.extension |= IPC_DATA_OFFSET_SZ(data_offset); | |
885 | } | |
886 | ||
887 | return ret; | |
888 | } | |
889 | EXPORT_SYMBOL_GPL(skl_ipc_get_large_config); |