| @@ -19,6 +19,7 @@ · 18 unmodified lines |
| 19 | | 19 | |
| 20 | #define SOF_IPC4_GAIN_PARAM_ID 0 | 20 | #define SOF_IPC4_GAIN_PARAM_ID 0 |
| 21 | #define SOF_IPC4_TPLG_ABI_SIZE 6 | 21 | #define SOF_IPC4_TPLG_ABI_SIZE 6 |
| | 22 | #define SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS 2 |
| 22 | | 23 | |
| 23 | static DEFINE_IDA(alh_group_ida); | 24 | static DEFINE_IDA(alh_group_ida); |
| 24 | static DEFINE_IDA(pipeline_ida); | 25 | static DEFINE_IDA(pipeline_ida); |
| @@ -26,6 +27,8 @@ static DEFINE_IDA(pipeline_ida); · 1 unmodified line |
| 26 | static const struct sof_topology_token ipc4_sched_tokens[] = { | 27 | static const struct sof_topology_token ipc4_sched_tokens[] = { |
| 27 | {SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, | 28 | {SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, |
| 28 | offsetof(struct sof_ipc4_pipeline, lp_mode)}, | 29 | offsetof(struct sof_ipc4_pipeline, lp_mode)}, |
| | 30 | {SOF_TKN_SCHED_USE_CHAIN_DMA, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, |
| | 31 | offsetof(struct sof_ipc4_pipeline, use_chain_dma)}, |
| 29 | {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, | 32 | {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, |
| 30 | offsetof(struct sof_ipc4_pipeline, core_id)}, | 33 | offsetof(struct sof_ipc4_pipeline, core_id)}, |
| 31 | }; | 34 | }; |
| @@ -475,6 +478,8 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) · 443 unmodified lines |
| 475 | struct snd_soc_component *scomp = swidget->scomp; | 478 | struct snd_soc_component *scomp = swidget->scomp; |
| 476 | struct snd_sof_dai *dai = swidget->private; | 479 | struct snd_sof_dai *dai = swidget->private; |
| 477 | struct sof_ipc4_copier *ipc4_copier; | 480 | struct sof_ipc4_copier *ipc4_copier; |
| | 481 | struct snd_sof_widget *pipe_widget; |
| | 482 | struct sof_ipc4_pipeline *pipeline; |
| 478 | int node_type = 0; | 483 | int node_type = 0; |
| 479 | int ret; | 484 | int ret; |
| 480 | | 485 | |
| @@ -512,6 +517,16 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) · 31 unmodified lines |
| 512 | | 517 | |
| 513 | ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type); | 518 | ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type); |
| 514 | | 519 | |
| | 520 | pipe_widget = swidget->spipe->pipe_widget; |
| | 521 | pipeline = pipe_widget->private; |
| | 522 | if (pipeline->use_chain_dma && ipc4_copier->dai_type != SOF_DAI_INTEL_HDA) { |
| | 523 | dev_err(scomp->dev, |
| | 524 | "Bad DAI type '%d', Chained DMA is only supported by HDA DAIs (%d).\n", |
| | 525 | ipc4_copier->dai_type, SOF_DAI_INTEL_HDA); |
| | 526 | ret = -ENODEV; |
| | 527 | goto free_available_fmt; |
| | 528 | } |
| | 529 | |
| 515 | switch (ipc4_copier->dai_type) { | 530 | switch (ipc4_copier->dai_type) { |
| 516 | case SOF_DAI_INTEL_ALH: | 531 | case SOF_DAI_INTEL_ALH: |
| 517 | { | 532 | { |
| @@ -643,6 +658,12 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget) · 125 unmodified lines |
| 643 | | 658 | |
| 644 | swidget->core = pipeline->core_id; | 659 | swidget->core = pipeline->core_id; |
| 645 | | 660 | |
| | 661 | if (pipeline->use_chain_dma) { |
| | 662 | dev_dbg(scomp->dev, "Set up chain DMA for %s\n", swidget->widget->name); |
| | 663 | swidget->private = pipeline; |
| | 664 | return 0; |
| | 665 | } |
| | 666 | |
| 646 | /* parse one set of pipeline tokens */ | 667 | /* parse one set of pipeline tokens */ |
| 647 | ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples, | 668 | ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples, |
| 648 | swidget->num_tuples, sizeof(*swidget), 1); | 669 | swidget->num_tuples, sizeof(*swidget), 1); |
| @@ -1103,11 +1124,21 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) · 454 unmodified lines |
| 1103 | pipeline->mem_usage = 0; | 1124 | pipeline->mem_usage = 0; |
| 1104 | | 1125 | |
| 1105 | if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) { | 1126 | if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) { |
| | 1127 | if (pipeline->use_chain_dma) { |
| | 1128 | pipeline->msg.primary = 0; |
| | 1129 | pipeline->msg.extension = 0; |
| | 1130 | } |
| 1106 | ipc4_copier = swidget->private; | 1131 | ipc4_copier = swidget->private; |
| 1107 | } else if (WIDGET_IS_DAI(swidget->id)) { | 1132 | } else if (WIDGET_IS_DAI(swidget->id)) { |
| 1108 | struct snd_sof_dai *dai = swidget->private; | 1133 | struct snd_sof_dai *dai = swidget->private; |
| 1109 | | 1134 | |
| 1110 | ipc4_copier = dai->private; | 1135 | ipc4_copier = dai->private; |
| | 1136 | |
| | 1137 | if (pipeline->use_chain_dma) { |
| | 1138 | pipeline->msg.primary = 0; |
| | 1139 | pipeline->msg.extension = 0; |
| | 1140 | } |
| | 1141 | |
| 1111 | if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) { | 1142 | if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) { |
| 1112 | struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data; | 1143 | struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data; |
| 1113 | struct sof_ipc4_alh_configuration_blob *blob; | 1144 | struct sof_ipc4_alh_configuration_blob *blob; |
| @@ -1344,13 +1375,44 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, · 230 unmodified lines |
| 1344 | return ret; | 1375 | return ret; |
| 1345 | } | 1376 | } |
| 1346 | | 1377 | |
| 1347 | pipe_widget = swidget->spipe->pipe_widget; | | |
| 1348 | pipeline = pipe_widget->private; | | |
| 1349 | ipc4_copier = (struct sof_ipc4_copier *)swidget->private; | 1378 | ipc4_copier = (struct sof_ipc4_copier *)swidget->private; |
| 1350 | gtw_attr = ipc4_copier->gtw_attr; | 1379 | gtw_attr = ipc4_copier->gtw_attr; |
| 1351 | copier_data = &ipc4_copier->data; | 1380 | copier_data = &ipc4_copier->data; |
| 1352 | available_fmt = &ipc4_copier->available_fmt; | 1381 | available_fmt = &ipc4_copier->available_fmt; |
| 1353 | | 1382 | |
| | 1383 | pipe_widget = swidget->spipe->pipe_widget; |
| | 1384 | pipeline = pipe_widget->private; |
| | 1385 | |
| | 1386 | if (pipeline->use_chain_dma) { |
| | 1387 | u32 host_dma_id; |
| | 1388 | u32 fifo_size; |
| | 1389 | |
| | 1390 | host_dma_id = platform_params->stream_tag - 1; |
| | 1391 | pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(host_dma_id); |
| | 1392 | |
| | 1393 | /* Set SCS bit for S16_LE format only */ |
| | 1394 | if (params_format(fe_params) == SNDRV_PCM_FORMAT_S16_LE) |
| | 1395 | pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_SCS_MASK; |
| | 1396 | |
| | 1397 | /* |
| | 1398 | * Despite its name the bitfield 'fifo_size' is used to define DMA buffer |
| | 1399 | * size. The expression calculates 2ms buffer size. |
| | 1400 | */ |
| | 1401 | fifo_size = DIV_ROUND_UP((SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS * |
| | 1402 | params_rate(fe_params) * |
| | 1403 | params_channels(fe_params) * |
| | 1404 | params_physical_width(fe_params)), 8000); |
| | 1405 | pipeline->msg.extension |= SOF_IPC4_GLB_EXT_CHAIN_DMA_FIFO_SIZE(fifo_size); |
| | 1406 | |
| | 1407 | /* |
| | 1408 | * Chain DMA does not support stream timestamping, set node_id to invalid |
| | 1409 | * to skip the code in sof_ipc4_get_stream_start_offset(). |
| | 1410 | */ |
| | 1411 | copier_data->gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID; |
| | 1412 | |
| | 1413 | return 0; |
| | 1414 | } |
| | 1415 | |
| 1354 | /* | 1416 | /* |
| 1355 | * Use the input_pin_fmts to match pcm params for playback and the output_pin_fmts | 1417 | * Use the input_pin_fmts to match pcm params for playback and the output_pin_fmts |
| 1356 | * for capture. | 1418 | * for capture. |
| @@ -1375,6 +1437,12 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, · 18 unmodified lines |
| 1375 | case snd_soc_dapm_dai_in: | 1437 | case snd_soc_dapm_dai_in: |
| 1376 | case snd_soc_dapm_dai_out: | 1438 | case snd_soc_dapm_dai_out: |
| 1377 | { | 1439 | { |
| | 1440 | struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; |
| | 1441 | struct sof_ipc4_pipeline *pipeline = pipe_widget->private; |
| | 1442 | |
| | 1443 | if (pipeline->use_chain_dma) |
| | 1444 | return 0; |
| | 1445 | |
| 1378 | dai = swidget->private; | 1446 | dai = swidget->private; |
| 1379 | | 1447 | |
| 1380 | ipc4_copier = (struct sof_ipc4_copier *)dai->private; | 1448 | ipc4_copier = (struct sof_ipc4_copier *)dai->private; |
| @@ -1921,6 +1989,9 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget · 540 unmodified lines |
| 1921 | case snd_soc_dapm_scheduler: | 1989 | case snd_soc_dapm_scheduler: |
| 1922 | pipeline = swidget->private; | 1990 | pipeline = swidget->private; |
| 1923 | | 1991 | |
| | 1992 | if (pipeline->use_chain_dma) |
| | 1993 | return 0; |
| | 1994 | |
| 1924 | dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id, | 1995 | dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id, |
| 1925 | pipeline->mem_usage); | 1996 | pipeline->mem_usage); |
| 1926 | | 1997 | |
| @@ -1943,6 +2014,10 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget · 16 unmodified lines |
| 1943 | { | 2014 | { |
| 1944 | struct sof_ipc4_copier *ipc4_copier = swidget->private; | 2015 | struct sof_ipc4_copier *ipc4_copier = swidget->private; |
| 1945 | | 2016 | |
| | 2017 | pipeline = pipe_widget->private; |
| | 2018 | if (pipeline->use_chain_dma) |
| | 2019 | return 0; |
| | 2020 | |
| 1946 | ipc_size = ipc4_copier->ipc_config_size; | 2021 | ipc_size = ipc4_copier->ipc_config_size; |
| 1947 | ipc_data = ipc4_copier->ipc_config_data; | 2022 | ipc_data = ipc4_copier->ipc_config_data; |
| 1948 | | 2023 | |
| @@ -1955,6 +2030,10 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget · 6 unmodified lines |
| 1955 | struct snd_sof_dai *dai = swidget->private; | 2030 | struct snd_sof_dai *dai = swidget->private; |
| 1956 | struct sof_ipc4_copier *ipc4_copier = dai->private; | 2031 | struct sof_ipc4_copier *ipc4_copier = dai->private; |
| 1957 | | 2032 | |
| | 2033 | pipeline = pipe_widget->private; |
| | 2034 | if (pipeline->use_chain_dma) |
| | 2035 | return 0; |
| | 2036 | |
| 1958 | ipc_size = ipc4_copier->ipc_config_size; | 2037 | ipc_size = ipc4_copier->ipc_config_size; |
| 1959 | ipc_data = ipc4_copier->ipc_config_data; | 2038 | ipc_data = ipc4_copier->ipc_config_data; |
| 1960 | | 2039 | |
| @@ -2066,6 +2145,9 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget · 105 unmodified lines |
| 2066 | struct sof_ipc4_msg msg = {{ 0 }}; | 2145 | struct sof_ipc4_msg msg = {{ 0 }}; |
| 2067 | u32 header; | 2146 | u32 header; |
| 2068 | | 2147 | |
| | 2148 | if (pipeline->use_chain_dma) |
| | 2149 | return 0; |
| | 2150 | |
| 2069 | header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id); | 2151 | header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id); |
| 2070 | header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE); | 2152 | header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE); |
| 2071 | header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); | 2153 | header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); |
| @@ -2082,7 +2164,11 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget · 10 unmodified lines |
| 2082 | pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; | 2164 | pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; |
| 2083 | ida_free(&pipeline_ida, swidget->instance_id); | 2165 | ida_free(&pipeline_ida, swidget->instance_id); |
| 2084 | } else { | 2166 | } else { |
| 2085 | ida_free(&fw_module->m_ida, swidget->instance_id); | 2167 | struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; |
| | 2168 | struct sof_ipc4_pipeline *pipeline = pipe_widget->private; |
| | 2169 | |
| | 2170 | if (!pipeline->use_chain_dma) |
| | 2171 | ida_free(&fw_module->m_ida, swidget->instance_id); |
| 2086 | } | 2172 | } |
| 2087 | | 2173 | |
| 2088 | mutex_unlock(&ipc4_data->pipeline_state_mutex); | 2174 | mutex_unlock(&ipc4_data->pipeline_state_mutex); |
| @@ -2234,12 +2320,27 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * · 145 unmodified lines |
| 2234 | { | 2320 | { |
| 2235 | struct snd_sof_widget *src_widget = sroute->src_widget; | 2321 | struct snd_sof_widget *src_widget = sroute->src_widget; |
| 2236 | struct snd_sof_widget *sink_widget = sroute->sink_widget; | 2322 | struct snd_sof_widget *sink_widget = sroute->sink_widget; |
| | 2323 | struct snd_sof_widget *src_pipe_widget = src_widget->spipe->pipe_widget; |
| | 2324 | struct snd_sof_widget *sink_pipe_widget = sink_widget->spipe->pipe_widget; |
| 2237 | struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; | 2325 | struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; |
| 2238 | struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; | 2326 | struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; |
| | 2327 | struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private; |
| | 2328 | struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private; |
| 2239 | struct sof_ipc4_msg msg = {{ 0 }}; | 2329 | struct sof_ipc4_msg msg = {{ 0 }}; |
| 2240 | u32 header, extension; | 2330 | u32 header, extension; |
| 2241 | int ret; | 2331 | int ret; |
| 2242 | | 2332 | |
| | 2333 | /* no route set up if chain DMA is used */ |
| | 2334 | if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma) { |
| | 2335 | if (!src_pipeline->use_chain_dma || !sink_pipeline->use_chain_dma) { |
| | 2336 | dev_err(sdev->dev, |
| | 2337 | "use_chain_dma must be set for both src %s and sink %s pipelines\n", |
| | 2338 | src_widget->widget->name, sink_widget->widget->name); |
| | 2339 | return -EINVAL; |
| | 2340 | } |
| | 2341 | return 0; |
| | 2342 | } |
| | 2343 | |
| 2243 | sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, | 2344 | sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, |
| 2244 | SOF_PIN_TYPE_OUTPUT); | 2345 | SOF_PIN_TYPE_OUTPUT); |
| 2245 | if (sroute->src_queue_id < 0) { | 2346 | if (sroute->src_queue_id < 0) { |
| @@ -2310,9 +2411,17 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s · 64 unmodified lines |
| 2310 | struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; | 2411 | struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; |
| 2311 | struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; | 2412 | struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; |
| 2312 | struct sof_ipc4_msg msg = {{ 0 }}; | 2413 | struct sof_ipc4_msg msg = {{ 0 }}; |
| | 2414 | struct snd_sof_widget *src_pipe_widget = src_widget->spipe->pipe_widget; |
| | 2415 | struct snd_sof_widget *sink_pipe_widget = sink_widget->spipe->pipe_widget; |
| | 2416 | struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private; |
| | 2417 | struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private; |
| 2313 | u32 header, extension; | 2418 | u32 header, extension; |
| 2314 | int ret = 0; | 2419 | int ret = 0; |
| 2315 | | 2420 | |
| | 2421 | /* no route is set up if chain DMA is used */ |
| | 2422 | if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma) |
| | 2423 | return 0; |
| | 2424 | |
| 2316 | dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n", | 2425 | dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n", |
| 2317 | src_widget->widget->name, sroute->src_queue_id, | 2426 | src_widget->widget->name, sroute->src_queue_id, |
| 2318 | sink_widget->widget->name, sroute->dst_queue_id); | 2427 | sink_widget->widget->name, sroute->dst_queue_id); |
| @@ -2374,6 +2483,11 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget * · 55 unmodified lines |
| 2374 | | 2483 | |
| 2375 | switch (ipc4_copier->dai_type) { | 2484 | switch (ipc4_copier->dai_type) { |
| 2376 | case SOF_DAI_INTEL_HDA: | 2485 | case SOF_DAI_INTEL_HDA: |
| | 2486 | if (pipeline->use_chain_dma) { |
| | 2487 | pipeline->msg.primary &= ~SOF_IPC4_GLB_CHAIN_DMA_LINK_ID_MASK; |
| | 2488 | pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_LINK_ID(data->dai_data); |
| | 2489 | break; |
| | 2490 | } |
| 2377 | gtw_attr = ipc4_copier->gtw_attr; | 2491 | gtw_attr = ipc4_copier->gtw_attr; |
| 2378 | gtw_attr->lp_buffer_alloc = pipeline->lp_mode; | 2492 | gtw_attr->lp_buffer_alloc = pipeline->lp_mode; |
| 2379 | pipeline->skip_during_fe_trigger = true; | 2493 | pipeline->skip_during_fe_trigger = true; |