blob: 25d4471c65433d46d98ca997693bb69cedae5690 [file] [log] [blame]
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +01001/*
2 * Copyright (c) 2016, Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the Intel Corporation nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
29 * Keyon Jie <yang.jie@linux.intel.com>
30 */
31
32#include <stdint.h>
33#include <stddef.h>
34#include <errno.h>
Pierre-Louis Bossart81708a52018-04-04 18:46:50 -050035#include <sof/sof.h>
36#include <sof/lock.h>
37#include <sof/list.h>
38#include <sof/stream.h>
39#include <sof/alloc.h>
40#include <sof/ipc.h>
41#include <sof/debug.h>
Liam Girdwood78e7f302018-04-11 16:53:02 +010042#include <platform/platform.h>
Pierre-Louis Bossart81708a52018-04-04 18:46:50 -050043#include <sof/audio/component.h>
44#include <sof/audio/pipeline.h>
45#include <sof/audio/buffer.h>
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010046
Liam Girdwood3488cce2017-08-10 11:59:08 +010047/*
48 * Components, buffers and pipelines all use the same set of monotonic ID
49 * numbers passed in by the host. They are stored in different lists, hence
Pierre-Louis Bossartf9458092017-11-09 15:24:07 -060050 * more than 1 list may need to be searched for the corresponding component.
Liam Girdwood3488cce2017-08-10 11:59:08 +010051 */
52
Liam Girdwood425aa5e2017-06-06 20:34:10 +010053struct ipc_comp_dev *ipc_get_comp(struct ipc *ipc, uint32_t id)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010054{
55 struct ipc_comp_dev *icd;
Liam Girdwood425aa5e2017-06-06 20:34:10 +010056 struct list_item *clist;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010057
Liam Girdwood425aa5e2017-06-06 20:34:10 +010058 list_for_item(clist, &ipc->comp_list) {
59 icd = container_of(clist, struct ipc_comp_dev, list);
Liam Girdwood3488cce2017-08-10 11:59:08 +010060 switch (icd->type) {
61 case COMP_TYPE_COMPONENT:
62 if (icd->cd->comp.id == id)
63 return icd;
64 break;
65 case COMP_TYPE_BUFFER:
66 if (icd->cb->ipc_buffer.comp.id == id)
67 return icd;
68 break;
69 case COMP_TYPE_PIPELINE:
70 if (icd->pipeline->ipc_pipe.comp_id == id)
71 return icd;
72 break;
73 default:
74 break;
75 }
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010076 }
77
Liam Girdwood425aa5e2017-06-06 20:34:10 +010078 return NULL;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +010079}
80
Pan Xiulie92ef972018-03-02 17:20:27 +080081int ipc_get_posn_offset(struct ipc *ipc, struct pipeline *pipe)
82{
83 int i;
84 uint32_t posn_size = sizeof(struct sof_ipc_stream_posn);
85
86 for (i = 0; i < PLATFORM_MAX_STREAMS; i++) {
87 if (ipc->posn_map[i] == pipe)
88 return pipe->posn_offset;
89 }
90
91 for (i = 0; i < PLATFORM_MAX_STREAMS; i++) {
92 if (ipc->posn_map[i] == NULL) {
93 ipc->posn_map[i] = pipe;
94 pipe->posn_offset = i * posn_size;
95 return pipe->posn_offset;
96 }
97 }
98
99 return -EINVAL;
100}
101
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100102int ipc_comp_new(struct ipc *ipc, struct sof_ipc_comp *comp)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100103{
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100104 struct comp_dev *cd;
105 struct ipc_comp_dev *icd;
106 int ret = 0;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100107
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100108 /* check whether component already exists */
109 icd = ipc_get_comp(ipc, comp->id);
110 if (icd != NULL) {
111 trace_ipc_error("eCe");
Ranjani Sridharan210989d2018-03-25 17:34:04 -0700112 trace_error_value(comp->id);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100113 return -EINVAL;
114 }
115
116 /* create component */
117 cd = comp_new(comp);
118 if (cd == NULL) {
119 trace_ipc_error("eCn");
120 return -EINVAL;
121 }
122
123 /* allocate the IPC component container */
Liam Girdwood1f6aee52018-03-01 16:13:05 +0000124 icd = rzalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM,
125 sizeof(struct ipc_comp_dev));
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100126 if (icd == NULL) {
127 trace_ipc_error("eCm");
128 rfree(cd);
129 return -ENOMEM;
130 }
131 icd->cd = cd;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100132 icd->type = COMP_TYPE_COMPONENT;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100133
134 /* add new component to the list */
135 list_item_append(&icd->list, &ipc->comp_list);
136 return ret;
137}
138
Liam Girdwood3488cce2017-08-10 11:59:08 +0100139int ipc_comp_free(struct ipc *ipc, uint32_t comp_id)
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100140{
141 struct ipc_comp_dev *icd;
142
143 /* check whether component exists */
144 icd = ipc_get_comp(ipc, comp_id);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100145 if (icd == NULL)
Liam Girdwood3488cce2017-08-10 11:59:08 +0100146 return -ENODEV;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100147
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100148 /* free component and remove from list */
149 comp_free(icd->cd);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100150 list_item_del(&icd->list);
Liam Girdwood50f7b0e2017-06-06 12:52:15 +0100151 rfree(icd);
Liam Girdwood3488cce2017-08-10 11:59:08 +0100152
153 return 0;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100154}
155
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100156int ipc_buffer_new(struct ipc *ipc, struct sof_ipc_buffer *desc)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100157{
Liam Girdwood3488cce2017-08-10 11:59:08 +0100158 struct ipc_comp_dev *ibd;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100159 struct comp_buffer *buffer;
160 int ret = 0;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100161
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100162 /* check whether buffer already exists */
Liam Girdwood3488cce2017-08-10 11:59:08 +0100163 ibd = ipc_get_comp(ipc, desc->comp.id);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100164 if (ibd != NULL) {
165 trace_ipc_error("eBe");
Ranjani Sridharan210989d2018-03-25 17:34:04 -0700166 trace_error_value(desc->comp.id);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100167 return -EINVAL;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100168 }
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100169
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100170 /* register buffer with pipeline */
171 buffer = buffer_new(desc);
172 if (buffer == NULL) {
173 trace_ipc_error("eBn");
174 rfree(ibd);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100175 return -ENOMEM;
176 }
177
Liam Girdwood1f6aee52018-03-01 16:13:05 +0000178 ibd = rzalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM,
179 sizeof(struct ipc_comp_dev));
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100180 if (ibd == NULL) {
181 rfree(buffer);
182 return -ENOMEM;
183 }
184 ibd->cb = buffer;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100185 ibd->type = COMP_TYPE_BUFFER;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100186
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100187 /* add new buffer to the list */
Liam Girdwood3488cce2017-08-10 11:59:08 +0100188 list_item_append(&ibd->list, &ipc->comp_list);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100189 return ret;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100190}
191
Liam Girdwood3488cce2017-08-10 11:59:08 +0100192int ipc_buffer_free(struct ipc *ipc, uint32_t buffer_id)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100193{
Liam Girdwood3488cce2017-08-10 11:59:08 +0100194 struct ipc_comp_dev *ibd;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100195
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100196 /* check whether buffer exists */
Liam Girdwood3488cce2017-08-10 11:59:08 +0100197 ibd = ipc_get_comp(ipc, buffer_id);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100198 if (ibd == NULL)
Liam Girdwood3488cce2017-08-10 11:59:08 +0100199 return -ENODEV;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100200
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100201 /* free buffer and remove from list */
202 buffer_free(ibd->cb);
203 list_item_del(&ibd->list);
204 rfree(ibd);
Liam Girdwood3488cce2017-08-10 11:59:08 +0100205
206 return 0;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100207}
208
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100209int ipc_comp_connect(struct ipc *ipc,
210 struct sof_ipc_pipe_comp_connect *connect)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100211{
Pierre-Louis Bossart4ccf81d2017-09-25 14:52:09 -0500212 struct ipc_comp_dev *icd_source;
213 struct ipc_comp_dev *icd_sink;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100214
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100215 /* check whether the components already exist */
216 icd_source = ipc_get_comp(ipc, connect->source_id);
217 if (icd_source == NULL) {
218 trace_ipc_error("eCr");
Ranjani Sridharan210989d2018-03-25 17:34:04 -0700219 trace_error_value(connect->source_id);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100220 return -EINVAL;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100221 }
222
223 icd_sink = ipc_get_comp(ipc, connect->sink_id);
224 if (icd_sink == NULL) {
225 trace_ipc_error("eCn");
Ranjani Sridharan210989d2018-03-25 17:34:04 -0700226 trace_error_value(connect->sink_id);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100227 return -EINVAL;
228 }
229
Liam Girdwood3488cce2017-08-10 11:59:08 +0100230 /* check source and sink types */
231 if (icd_source->type == COMP_TYPE_BUFFER &&
232 icd_sink->type == COMP_TYPE_COMPONENT)
233 return pipeline_buffer_connect(icd_source->pipeline,
234 icd_source->cb, icd_sink->cd);
235 else if (icd_source->type == COMP_TYPE_COMPONENT &&
236 icd_sink->type == COMP_TYPE_BUFFER)
237 return pipeline_comp_connect(icd_source->pipeline,
238 icd_source->cd, icd_sink->cb);
239 else {
240 trace_ipc_error("eCt");
Ranjani Sridharan210989d2018-03-25 17:34:04 -0700241 trace_error_value(connect->source_id);
242 trace_error_value(connect->sink_id);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100243 return -EINVAL;
244 }
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100245}
246
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100247
248int ipc_pipeline_new(struct ipc *ipc,
249 struct sof_ipc_pipe_new *pipe_desc)
250{
Liam Girdwood3488cce2017-08-10 11:59:08 +0100251 struct ipc_comp_dev *ipc_pipe;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100252 struct pipeline *pipe;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100253 struct ipc_comp_dev *icd;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100254
255 /* check whether the pipeline already exists */
Liam Girdwood3488cce2017-08-10 11:59:08 +0100256 ipc_pipe = ipc_get_comp(ipc, pipe_desc->comp_id);
257 if (ipc_pipe != NULL) {
258 trace_ipc_error("ePi");
Ranjani Sridharan210989d2018-03-25 17:34:04 -0700259 trace_error_value(pipe_desc->comp_id);
Liam Girdwood3488cce2017-08-10 11:59:08 +0100260 return -EINVAL;
261 }
262
263 /* find the scheduling component */
264 icd = ipc_get_comp(ipc, pipe_desc->sched_id);
265 if (icd == NULL) {
266 trace_ipc_error("ePs");
Ranjani Sridharan210989d2018-03-25 17:34:04 -0700267 trace_error_value(pipe_desc->sched_id);
Liam Girdwood3488cce2017-08-10 11:59:08 +0100268 return -EINVAL;
269 }
270 if (icd->type != COMP_TYPE_COMPONENT) {
271 trace_ipc_error("ePc");
272 return -EINVAL;
273 }
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100274
275 /* create the pipeline */
Liam Girdwood3488cce2017-08-10 11:59:08 +0100276 pipe = pipeline_new(pipe_desc, icd->cd);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100277 if (pipe == NULL) {
278 trace_ipc_error("ePn");
279 return -ENOMEM;
280 }
281
282 /* allocate the IPC pipeline container */
Liam Girdwood1f6aee52018-03-01 16:13:05 +0000283 ipc_pipe = rzalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM,
Liam Girdwood3488cce2017-08-10 11:59:08 +0100284 sizeof(struct ipc_comp_dev));
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100285 if (ipc_pipe == NULL) {
Liam Girdwood3488cce2017-08-10 11:59:08 +0100286 pipeline_free(pipe);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100287 return -ENOMEM;
288 }
289
290 ipc_pipe->pipeline = pipe;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100291 ipc_pipe->type = COMP_TYPE_PIPELINE;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100292
293 /* add new pipeline to the list */
Liam Girdwood3488cce2017-08-10 11:59:08 +0100294 list_item_append(&ipc_pipe->list, &ipc->comp_list);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100295 return 0;
296}
297
Liam Girdwood3488cce2017-08-10 11:59:08 +0100298int ipc_pipeline_free(struct ipc *ipc, uint32_t comp_id)
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100299{
Liam Girdwood3488cce2017-08-10 11:59:08 +0100300 struct ipc_comp_dev *ipc_pipe;
301 int ret;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100302
303 /* check whether pipeline exists */
Liam Girdwood3488cce2017-08-10 11:59:08 +0100304 ipc_pipe = ipc_get_comp(ipc, comp_id);
305 if (ipc_pipe == NULL)
306 return -ENODEV;
307
308 /* free buffer and remove from list */
309 ret = pipeline_free(ipc_pipe->pipeline);
310 if (ret < 0) {
311 trace_ipc_error("ePf");
312 return ret;
313 }
314
315 list_item_del(&ipc_pipe->list);
316 rfree(ipc_pipe);
317
318 return 0;
319}
320
Liam Girdwood6506fd92017-09-23 23:04:34 +0100321int ipc_pipeline_complete(struct ipc *ipc, uint32_t comp_id)
Liam Girdwood3488cce2017-08-10 11:59:08 +0100322{
323 struct ipc_comp_dev *ipc_pipe;
324
325 /* check whether pipeline exists */
326 ipc_pipe = ipc_get_comp(ipc, comp_id);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100327 if (ipc_pipe == NULL)
Liam Girdwood6506fd92017-09-23 23:04:34 +0100328 return -EINVAL;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100329
330 /* free buffer and remove from list */
Liam Girdwood6506fd92017-09-23 23:04:34 +0100331 return pipeline_complete(ipc_pipe->pipeline);
Liam Girdwood3488cce2017-08-10 11:59:08 +0100332}
333
Liam Girdwoodec219862017-08-21 16:57:28 +0100334int ipc_comp_dai_config(struct ipc *ipc, struct sof_ipc_dai_config *config)
Liam Girdwood3488cce2017-08-10 11:59:08 +0100335{
Ranjani Sridharan4157d932018-07-26 11:36:34 -0700336 struct sof_ipc_comp_dai *dai;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100337 struct ipc_comp_dev *icd;
338 struct list_item *clist;
Ranjani Sridharan4157d932018-07-26 11:36:34 -0700339 struct comp_dev *dev;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100340 int ret = 0;
341
342 /* for each component */
343 list_for_item(clist, &ipc->comp_list) {
344 icd = container_of(clist, struct ipc_comp_dev, list);
345 switch (icd->type) {
346 case COMP_TYPE_COMPONENT:
347
348 /* make sure we only config DAI comps */
349 switch (icd->cd->comp.type) {
350 case SOF_COMP_DAI:
351 case SOF_COMP_SG_DAI:
Ranjani Sridharan4157d932018-07-26 11:36:34 -0700352 dev = icd->cd;
353 dai = (struct sof_ipc_comp_dai *)&dev->comp;
354
355 /*
356 * set config if comp dai_index matches
357 * config dai_index.
358 */
359 if (dai->dai_index == config->dai_index &&
360 dai->type == config->type) {
361 ret = comp_dai_config(dev, config);
362 if (ret < 0) {
363 trace_ipc_error("eCD");
364 return ret;
365 }
Liam Girdwood3488cce2017-08-10 11:59:08 +0100366 }
367 break;
368 default:
369 break;
370 }
371
372 break;
373 /* ignore non components */
374 default:
375 break;
376 }
377 }
378
379 return ret;
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100380}
381
Liam Girdwood78e7f302018-04-11 16:53:02 +0100382#ifdef CONFIG_HOST_PTABLE
383/*
384 * Parse the host page tables and create the audio DMA SG configuration
385 * for host audio DMA buffer. This involves creating a dma_sg_elem for each
386 * page table entry and adding each elem to a list in struct dma_sg_config.
387 */
388int ipc_parse_page_descriptors(uint8_t *page_table,
389 struct sof_ipc_host_buffer *ring,
390 struct list_item *elem_list,
391 uint32_t direction)
392{
393 int i;
394 uint32_t idx;
395 uint32_t phy_addr;
396 struct dma_sg_elem *e;
397
398 /* the ring size may be not multiple of the page size, the last
399 * page may be not full used. The used size should be in range
400 * of (ring->pages - 1, ring->pages] * PAGES.
401 */
402 if ((ring->size <= HOST_PAGE_SIZE * (ring->pages - 1)) ||
403 (ring->size > HOST_PAGE_SIZE * ring->pages)) {
404 /* error buffer size */
405 trace_ipc_error("eBs");
406 return -EINVAL;
407 }
408
409 for (i = 0; i < ring->pages; i++) {
410 idx = (((i << 2) + i)) >> 1;
411 phy_addr = page_table[idx] | (page_table[idx + 1] << 8)
412 | (page_table[idx + 2] << 16);
413
414 if (i & 0x1)
415 phy_addr <<= 8;
416 else
417 phy_addr <<= 12;
418 phy_addr &= 0xfffff000;
419
420 /* allocate new host DMA elem and add it to our list */
421 e = rzalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM, sizeof(*e));
422 if (!e)
423 return -ENOMEM;
424
425 if (direction == SOF_IPC_STREAM_PLAYBACK)
426 e->src = phy_addr;
427 else
428 e->dest = phy_addr;
429
430 /* the last page may be not full used */
431 if (i == (ring->pages - 1))
432 e->size = ring->size - HOST_PAGE_SIZE * i;
433 else
434 e->size = HOST_PAGE_SIZE;
435
436 list_item_append(&e->list, elem_list);
437 }
438
439 return 0;
440}
441
442static void dma_complete(void *data, uint32_t type, struct dma_sg_elem *next)
443{
444 completion_t *complete = data;
445
446 if (type == DMA_IRQ_TYPE_LLIST)
447 wait_completed(complete);
448}
449
450/*
451 * Copy the audio buffer page tables from the host to the DSP max of 4K.
452 */
453int ipc_get_page_descriptors(struct dma *dmac, uint8_t *page_table,
454 struct sof_ipc_host_buffer *ring)
455{
456 struct dma_sg_config config;
457 struct dma_sg_elem elem;
458 completion_t complete;
459 int chan;
460 int ret = 0;
461
462 /* get DMA channel from DMAC */
463 chan = dma_channel_get(dmac, 0);
464 if (chan < 0) {
465 trace_ipc_error("ePC");
466 return chan;
467 }
468
469 /* set up DMA configuration */
470 config.direction = DMA_DIR_HMEM_TO_LMEM;
471 config.src_width = sizeof(uint32_t);
472 config.dest_width = sizeof(uint32_t);
473 config.cyclic = 0;
474 list_init(&config.elem_list);
475
476 /* set up DMA descriptor */
477 elem.dest = (uint32_t)page_table;
478 elem.src = ring->phy_addr;
479
480 /* source buffer size is always PAGE_SIZE bytes */
481 /* 20 bits for each page, round up to 32 */
482 elem.size = (ring->pages * 5 * 16 + 31) / 32;
483 list_item_prepend(&elem.list, &config.elem_list);
484
485 ret = dma_set_config(dmac, chan, &config);
486 if (ret < 0) {
487 trace_ipc_error("ePs");
488 goto out;
489 }
490
491 /* set up callback */
492 dma_set_cb(dmac, chan, DMA_IRQ_TYPE_LLIST, dma_complete, &complete);
493
494 wait_init(&complete);
495
496 /* start the copy of page table to DSP */
Pierre-Louis Bossarte5dab2a2018-05-18 18:39:10 -0500497 ret = dma_start(dmac, chan);
498 if (ret < 0) {
499 trace_ipc_error("ePt");
500 goto out;
501 }
Liam Girdwood78e7f302018-04-11 16:53:02 +0100502
503 /* wait for DMA to complete */
504 complete.timeout = PLATFORM_HOST_DMA_TIMEOUT;
505 ret = wait_for_completion_timeout(&complete);
506
507 /* compressed page tables now in buffer at _ipc->page_table */
508out:
509 dma_channel_put(dmac, chan);
510 return ret;
511}
512#endif
513
Pierre-Louis Bossart81708a52018-04-04 18:46:50 -0500514int ipc_init(struct sof *sof)
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100515{
Pan Xiulie92ef972018-03-02 17:20:27 +0800516 int i;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100517 trace_ipc("IPI");
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100518
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100519 /* init ipc data */
Pierre-Louis Bossart81708a52018-04-04 18:46:50 -0500520 sof->ipc = rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM, sizeof(*sof->ipc));
521 sof->ipc->comp_data = rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM,
522 SOF_IPC_MSG_MAX_SIZE);
523 sof->ipc->dmat = sof->dmat;
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100524
Pan Xiulie92ef972018-03-02 17:20:27 +0800525 for (i = 0; i < PLATFORM_MAX_STREAMS; i++)
Pierre-Louis Bossart81708a52018-04-04 18:46:50 -0500526 sof->ipc->posn_map[i] = NULL;
Pan Xiulie92ef972018-03-02 17:20:27 +0800527
Pierre-Louis Bossart81708a52018-04-04 18:46:50 -0500528 list_init(&sof->ipc->comp_list);
Liam Girdwood425aa5e2017-06-06 20:34:10 +0100529
Pierre-Louis Bossart81708a52018-04-04 18:46:50 -0500530 return platform_ipc_init(sof->ipc);
Liam Girdwoodc0dfb4e2016-09-21 15:57:22 +0100531}