sof-audio.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054
  1. // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
  2. //
  3. // This file is provided under a dual BSD/GPLv2 license. When using or
  4. // redistributing this file, you may do so under either license.
  5. //
  6. // Copyright(c) 2019 Intel Corporation
  7. //
  8. // Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
  9. //
  10. #include <linux/bitfield.h>
  11. #include <trace/events/sof.h>
  12. #include "sof-audio.h"
  13. #include "ops.h"
  14. /*
  15. * Check if a DAI widget is an aggregated DAI. Aggregated DAI's have names ending in numbers
  16. * starting with 0. For example: in the case of a SDW speaker with 2 amps, the topology contains
  17. * 2 DAI's names alh-copier.SDW1.Playback.0 and alh-copier-SDW1.Playback.1. In this case, only the
  18. * DAI alh-copier.SDW1.Playback.0 is set up in the firmware. The other DAI,
  19. * alh-copier.SDW1.Playback.1 in topology is for the sake of completeness to show aggregation for
  20. * the speaker amp and does not need any firmware configuration.
  21. */
  22. static bool is_aggregated_dai(struct snd_sof_widget *swidget)
  23. {
  24. return (WIDGET_IS_DAI(swidget->id) &&
  25. isdigit(swidget->widget->name[strlen(swidget->widget->name) - 1]) &&
  26. swidget->widget->name[strlen(swidget->widget->name) - 1] != '0');
  27. }
  28. static bool is_virtual_widget(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget,
  29. const char *func)
  30. {
  31. switch (widget->id) {
  32. case snd_soc_dapm_out_drv:
  33. case snd_soc_dapm_output:
  34. case snd_soc_dapm_input:
  35. dev_dbg(sdev->dev, "%s: %s is a virtual widget\n", func, widget->name);
  36. return true;
  37. default:
  38. return false;
  39. }
  40. }
  41. static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_sof_widget *widget)
  42. {
  43. const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
  44. struct snd_sof_route *sroute;
  45. list_for_each_entry(sroute, &sdev->route_list, list)
  46. if (sroute->src_widget == widget || sroute->sink_widget == widget) {
  47. if (sroute->setup && tplg_ops && tplg_ops->route_free)
  48. tplg_ops->route_free(sdev, sroute);
  49. sroute->setup = false;
  50. }
  51. }
  52. static int sof_widget_free_unlocked(struct snd_sof_dev *sdev,
  53. struct snd_sof_widget *swidget)
  54. {
  55. const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
  56. struct snd_sof_pipeline *spipe = swidget->spipe;
  57. int err = 0;
  58. int ret;
  59. if (!swidget->private)
  60. return 0;
  61. trace_sof_widget_free(swidget);
  62. /* only free when use_count is 0 */
  63. if (--swidget->use_count)
  64. return 0;
  65. /* reset route setup status for all routes that contain this widget */
  66. sof_reset_route_setup_status(sdev, swidget);
  67. /* free DAI config and continue to free widget even if it fails */
  68. if (WIDGET_IS_DAI(swidget->id)) {
  69. struct snd_sof_dai_config_data data;
  70. unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_FREE;
  71. data.dai_data = DMA_CHAN_INVALID;
  72. if (tplg_ops && tplg_ops->dai_config) {
  73. err = tplg_ops->dai_config(sdev, swidget, flags, &data);
  74. if (err < 0)
  75. dev_err(sdev->dev, "failed to free config for widget %s\n",
  76. swidget->widget->name);
  77. }
  78. }
  79. /* continue to disable core even if IPC fails */
  80. if (tplg_ops && tplg_ops->widget_free) {
  81. ret = tplg_ops->widget_free(sdev, swidget);
  82. if (ret < 0 && !err)
  83. err = ret;
  84. }
  85. /*
  86. * decrement ref count for cores associated with all modules in the pipeline and clear
  87. * the complete flag
  88. */
  89. if (swidget->id == snd_soc_dapm_scheduler) {
  90. int i;
  91. for_each_set_bit(i, &spipe->core_mask, sdev->num_cores) {
  92. ret = snd_sof_dsp_core_put(sdev, i);
  93. if (ret < 0) {
  94. dev_err(sdev->dev, "failed to disable target core: %d for pipeline %s\n",
  95. i, swidget->widget->name);
  96. if (!err)
  97. err = ret;
  98. }
  99. }
  100. swidget->spipe->complete = 0;
  101. }
  102. /*
  103. * free the scheduler widget (same as pipe_widget) associated with the current swidget.
  104. * skip for static pipelines
  105. */
  106. if (swidget->spipe && swidget->dynamic_pipeline_widget &&
  107. swidget->id != snd_soc_dapm_scheduler) {
  108. ret = sof_widget_free_unlocked(sdev, swidget->spipe->pipe_widget);
  109. if (ret < 0 && !err)
  110. err = ret;
  111. }
  112. if (!err)
  113. dev_dbg(sdev->dev, "widget %s freed\n", swidget->widget->name);
  114. return err;
  115. }
  116. int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
  117. {
  118. guard(mutex)(&swidget->setup_mutex);
  119. return sof_widget_free_unlocked(sdev, swidget);
  120. }
  121. EXPORT_SYMBOL(sof_widget_free);
  122. static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev,
  123. struct snd_sof_widget *swidget)
  124. {
  125. const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
  126. struct snd_sof_pipeline *spipe = swidget->spipe;
  127. bool use_count_decremented = false;
  128. int ret;
  129. int i;
  130. /* skip if there is no private data */
  131. if (!swidget->private)
  132. return 0;
  133. trace_sof_widget_setup(swidget);
  134. /* widget already set up */
  135. if (++swidget->use_count > 1)
  136. return 0;
  137. /*
  138. * The scheduler widget for a pipeline is not part of the connected DAPM
  139. * widget list and it needs to be set up before the widgets in the pipeline
  140. * are set up. The use_count for the scheduler widget is incremented for every
  141. * widget in a given pipeline to ensure that it is freed only after the last
  142. * widget in the pipeline is freed. Skip setting up scheduler widget for static pipelines.
  143. */
  144. if (swidget->dynamic_pipeline_widget && swidget->id != snd_soc_dapm_scheduler) {
  145. if (!swidget->spipe || !swidget->spipe->pipe_widget) {
  146. dev_err(sdev->dev, "No pipeline set for %s\n", swidget->widget->name);
  147. ret = -EINVAL;
  148. goto use_count_dec;
  149. }
  150. ret = sof_widget_setup_unlocked(sdev, swidget->spipe->pipe_widget);
  151. if (ret < 0)
  152. goto use_count_dec;
  153. }
  154. /* update ref count for cores associated with all modules in the pipeline */
  155. if (swidget->id == snd_soc_dapm_scheduler) {
  156. for_each_set_bit(i, &spipe->core_mask, sdev->num_cores) {
  157. ret = snd_sof_dsp_core_get(sdev, i);
  158. if (ret < 0) {
  159. dev_err(sdev->dev, "failed to enable target core %d for pipeline %s\n",
  160. i, swidget->widget->name);
  161. goto pipe_widget_free;
  162. }
  163. }
  164. }
  165. /* setup widget in the DSP */
  166. if (tplg_ops && tplg_ops->widget_setup) {
  167. ret = tplg_ops->widget_setup(sdev, swidget);
  168. if (ret < 0)
  169. goto pipe_widget_free;
  170. }
  171. /* send config for DAI components */
  172. if (WIDGET_IS_DAI(swidget->id)) {
  173. unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS;
  174. /*
  175. * The config flags saved during BE DAI hw_params will be used for IPC3. IPC4 does
  176. * not use the flags argument.
  177. */
  178. if (tplg_ops && tplg_ops->dai_config) {
  179. ret = tplg_ops->dai_config(sdev, swidget, flags, NULL);
  180. if (ret < 0)
  181. goto widget_free;
  182. }
  183. }
  184. /* restore kcontrols for widget */
  185. if (tplg_ops && tplg_ops->control && tplg_ops->control->widget_kcontrol_setup) {
  186. ret = tplg_ops->control->widget_kcontrol_setup(sdev, swidget);
  187. if (ret < 0)
  188. goto widget_free;
  189. }
  190. dev_dbg(sdev->dev, "widget %s setup complete\n", swidget->widget->name);
  191. return 0;
  192. widget_free:
  193. /* widget use_count will be decremented by sof_widget_free() */
  194. sof_widget_free_unlocked(sdev, swidget);
  195. use_count_decremented = true;
  196. pipe_widget_free:
  197. if (swidget->id != snd_soc_dapm_scheduler) {
  198. sof_widget_free_unlocked(sdev, swidget->spipe->pipe_widget);
  199. } else {
  200. int j;
  201. /* decrement ref count for all cores that were updated previously */
  202. for_each_set_bit(j, &spipe->core_mask, sdev->num_cores) {
  203. if (j >= i)
  204. break;
  205. snd_sof_dsp_core_put(sdev, j);
  206. }
  207. }
  208. use_count_dec:
  209. if (!use_count_decremented)
  210. swidget->use_count--;
  211. return ret;
  212. }
  213. int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
  214. {
  215. guard(mutex)(&swidget->setup_mutex);
  216. return sof_widget_setup_unlocked(sdev, swidget);
  217. }
  218. EXPORT_SYMBOL(sof_widget_setup);
  219. int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsource,
  220. struct snd_soc_dapm_widget *wsink)
  221. {
  222. const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
  223. struct snd_sof_widget *src_widget = wsource->dobj.private;
  224. struct snd_sof_widget *sink_widget = wsink->dobj.private;
  225. struct snd_sof_route *sroute;
  226. bool route_found = false;
  227. /* ignore routes involving virtual widgets in topology */
  228. if (is_virtual_widget(sdev, src_widget->widget, __func__) ||
  229. is_virtual_widget(sdev, sink_widget->widget, __func__))
  230. return 0;
  231. /* skip route if source/sink widget is not set up */
  232. if (!src_widget->use_count || !sink_widget->use_count)
  233. return 0;
  234. /* find route matching source and sink widgets */
  235. list_for_each_entry(sroute, &sdev->route_list, list)
  236. if (sroute->src_widget == src_widget && sroute->sink_widget == sink_widget) {
  237. route_found = true;
  238. break;
  239. }
  240. if (!route_found) {
  241. dev_err(sdev->dev, "error: cannot find SOF route for source %s -> %s sink\n",
  242. wsource->name, wsink->name);
  243. return -EINVAL;
  244. }
  245. /* nothing to do if route is already set up */
  246. if (sroute->setup)
  247. return 0;
  248. if (tplg_ops && tplg_ops->route_setup) {
  249. int ret = tplg_ops->route_setup(sdev, sroute);
  250. if (ret < 0)
  251. return ret;
  252. }
  253. sroute->setup = true;
  254. return 0;
  255. }
  256. static bool sof_widget_in_same_direction(struct snd_sof_widget *swidget, int dir)
  257. {
  258. return swidget->spipe->direction == dir;
  259. }
  260. static int sof_set_up_same_dir_widget_routes(struct snd_sof_dev *sdev,
  261. struct snd_soc_dapm_widget *wsource,
  262. struct snd_soc_dapm_widget *wsink)
  263. {
  264. struct snd_sof_widget *src_widget = wsource->dobj.private;
  265. struct snd_sof_widget *sink_widget = wsink->dobj.private;
  266. /*
  267. * skip setting up route if source and sink are in different directions (ex. playback and
  268. * echo ref) if the direction is set in topology. These will be set up later. It is enough
  269. * to check if the direction_valid is set for one of the widgets as all widgets will have
  270. * the direction set in topology if one is set.
  271. */
  272. if (sink_widget->spipe && sink_widget->spipe->direction_valid &&
  273. !sof_widget_in_same_direction(sink_widget, src_widget->spipe->direction))
  274. return 0;
  275. return sof_route_setup(sdev, wsource, wsink);
  276. }
  277. static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
  278. struct snd_soc_dapm_widget_list *list, int dir)
  279. {
  280. struct snd_soc_dapm_widget *widget;
  281. struct snd_sof_route *sroute;
  282. struct snd_soc_dapm_path *p;
  283. int ret = 0;
  284. int i;
  285. /*
  286. * Set up connections between widgets in the sink/source paths based on direction.
  287. * Some non-SOF widgets exist in topology either for compatibility or for the
  288. * purpose of connecting a pipeline from a host to a DAI in order to receive the DAPM
  289. * events. But they are not handled by the firmware. So ignore them.
  290. */
  291. if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
  292. for_each_dapm_widgets(list, i, widget) {
  293. if (!widget->dobj.private)
  294. continue;
  295. snd_soc_dapm_widget_for_each_sink_path(widget, p) {
  296. if (!widget_in_list(list, p->sink))
  297. continue;
  298. if (p->sink->dobj.private) {
  299. ret = sof_set_up_same_dir_widget_routes(sdev, widget,
  300. p->sink);
  301. if (ret < 0)
  302. return ret;
  303. }
  304. }
  305. }
  306. } else {
  307. for_each_dapm_widgets(list, i, widget) {
  308. if (!widget->dobj.private)
  309. continue;
  310. snd_soc_dapm_widget_for_each_source_path(widget, p) {
  311. if (!widget_in_list(list, p->source))
  312. continue;
  313. if (p->source->dobj.private) {
  314. ret = sof_set_up_same_dir_widget_routes(sdev, p->source,
  315. widget);
  316. if (ret < 0)
  317. return ret;
  318. }
  319. }
  320. }
  321. }
  322. /*
  323. * The above loop handles connections between widgets that belong to the DAPM widget list.
  324. * This is not sufficient to handle loopback cases between pipelines configured with
  325. * different directions, e.g. a sidetone or an amplifier feedback connected to a speaker
  326. * protection module.
  327. */
  328. list_for_each_entry(sroute, &sdev->route_list, list) {
  329. bool src_widget_in_dapm_list, sink_widget_in_dapm_list;
  330. if (sroute->setup)
  331. continue;
  332. src_widget_in_dapm_list = widget_in_list(list, sroute->src_widget->widget);
  333. sink_widget_in_dapm_list = widget_in_list(list, sroute->sink_widget->widget);
  334. /*
  335. * no need to set up the route if both the source and sink widgets are not in the
  336. * DAPM list
  337. */
  338. if (!src_widget_in_dapm_list && !sink_widget_in_dapm_list)
  339. continue;
  340. /*
  341. * set up the route only if both the source and sink widgets are in the DAPM list
  342. * but are in different directions. The ones in the same direction would already
  343. * have been set up in the previous loop.
  344. */
  345. if (src_widget_in_dapm_list && sink_widget_in_dapm_list) {
  346. struct snd_sof_widget *src_widget, *sink_widget;
  347. src_widget = sroute->src_widget->widget->dobj.private;
  348. sink_widget = sroute->sink_widget->widget->dobj.private;
  349. /*
  350. * it is enough to check if the direction_valid is set for one of the
  351. * widgets as all widgets will have the direction set in topology if one
  352. * is set.
  353. */
  354. if (src_widget && sink_widget &&
  355. src_widget->spipe && src_widget->spipe->direction_valid &&
  356. sof_widget_in_same_direction(sink_widget, src_widget->spipe->direction))
  357. continue;
  358. }
  359. ret = sof_route_setup(sdev, sroute->src_widget->widget,
  360. sroute->sink_widget->widget);
  361. if (ret < 0)
  362. return ret;
  363. }
  364. return 0;
  365. }
  366. static void
  367. sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget,
  368. struct snd_soc_dapm_widget_list *list, int dir)
  369. {
  370. const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
  371. struct snd_sof_widget *swidget = widget->dobj.private;
  372. const struct sof_ipc_tplg_widget_ops *widget_ops;
  373. struct snd_soc_dapm_path *p;
  374. if (is_virtual_widget(sdev, widget, __func__))
  375. return;
  376. if (!swidget)
  377. goto sink_unprepare;
  378. if (swidget->spipe && swidget->spipe->direction_valid &&
  379. !sof_widget_in_same_direction(swidget, dir))
  380. return;
  381. /* skip widgets in use, those already unprepared or aggregated DAIs */
  382. if (!swidget->prepared || swidget->use_count > 0 || is_aggregated_dai(swidget))
  383. goto sink_unprepare;
  384. widget_ops = tplg_ops ? tplg_ops->widget : NULL;
  385. if (widget_ops && widget_ops[widget->id].ipc_unprepare)
  386. /* unprepare the source widget */
  387. widget_ops[widget->id].ipc_unprepare(swidget);
  388. swidget->prepared = false;
  389. sink_unprepare:
  390. /* unprepare all widgets in the sink paths */
  391. snd_soc_dapm_widget_for_each_sink_path(widget, p) {
  392. if (!widget_in_list(list, p->sink))
  393. continue;
  394. if (!p->walking && p->sink->dobj.private) {
  395. p->walking = true;
  396. sof_unprepare_widgets_in_path(sdev, p->sink, list, dir);
  397. p->walking = false;
  398. }
  399. }
  400. }
  401. static int
  402. sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget,
  403. struct snd_pcm_hw_params *fe_params,
  404. struct snd_sof_platform_stream_params *platform_params,
  405. struct snd_pcm_hw_params *pipeline_params, int dir,
  406. struct snd_soc_dapm_widget_list *list)
  407. {
  408. const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
  409. struct snd_sof_widget *swidget = widget->dobj.private;
  410. const struct sof_ipc_tplg_widget_ops *widget_ops;
  411. struct snd_soc_dapm_path *p;
  412. int ret;
  413. if (is_virtual_widget(sdev, widget, __func__))
  414. return 0;
  415. if (!swidget)
  416. goto sink_prepare;
  417. widget_ops = tplg_ops ? tplg_ops->widget : NULL;
  418. if (!widget_ops)
  419. return 0;
  420. if (swidget->spipe && swidget->spipe->direction_valid &&
  421. !sof_widget_in_same_direction(swidget, dir))
  422. return 0;
  423. /* skip widgets already prepared or aggregated DAI widgets*/
  424. if (!widget_ops[widget->id].ipc_prepare || swidget->prepared ||
  425. is_aggregated_dai(swidget))
  426. goto sink_prepare;
  427. /* prepare the source widget */
  428. ret = widget_ops[widget->id].ipc_prepare(swidget, fe_params, platform_params,
  429. pipeline_params, dir);
  430. if (ret < 0) {
  431. dev_err(sdev->dev, "failed to prepare widget %s\n", widget->name);
  432. return ret;
  433. }
  434. swidget->prepared = true;
  435. sink_prepare:
  436. /* prepare all widgets in the sink paths */
  437. snd_soc_dapm_widget_for_each_sink_path(widget, p) {
  438. if (!widget_in_list(list, p->sink))
  439. continue;
  440. if (!p->walking && p->sink->dobj.private) {
  441. p->walking = true;
  442. ret = sof_prepare_widgets_in_path(sdev, p->sink, fe_params,
  443. platform_params, pipeline_params, dir,
  444. list);
  445. p->walking = false;
  446. if (ret < 0) {
  447. /* unprepare the source widget */
  448. if (widget_ops[widget->id].ipc_unprepare &&
  449. swidget && swidget->prepared && swidget->use_count == 0) {
  450. widget_ops[widget->id].ipc_unprepare(swidget);
  451. swidget->prepared = false;
  452. }
  453. return ret;
  454. }
  455. }
  456. }
  457. return 0;
  458. }
  459. /*
  460. * free all widgets in the sink path starting from the source widget
  461. * (DAI type for capture, AIF type for playback)
  462. */
  463. static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget,
  464. int dir, struct snd_sof_pcm *spcm)
  465. {
  466. struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
  467. struct snd_sof_widget *swidget = widget->dobj.private;
  468. struct snd_soc_dapm_path *p;
  469. int err;
  470. int ret = 0;
  471. if (is_virtual_widget(sdev, widget, __func__))
  472. return 0;
  473. if (!swidget)
  474. goto sink_free;
  475. if (swidget->spipe && swidget->spipe->direction_valid &&
  476. !sof_widget_in_same_direction(swidget, dir))
  477. return 0;
  478. /* skip aggregated DAIs */
  479. if (is_aggregated_dai(swidget))
  480. goto sink_free;
  481. err = sof_widget_free(sdev, widget->dobj.private);
  482. if (err < 0)
  483. ret = err;
  484. sink_free:
  485. /* free all widgets in the sink paths even in case of error to keep use counts balanced */
  486. snd_soc_dapm_widget_for_each_sink_path(widget, p) {
  487. if (!p->walking) {
  488. if (!widget_in_list(list, p->sink))
  489. continue;
  490. p->walking = true;
  491. err = sof_free_widgets_in_path(sdev, p->sink, dir, spcm);
  492. if (err < 0)
  493. ret = err;
  494. p->walking = false;
  495. }
  496. }
  497. return ret;
  498. }
  499. /*
  500. * set up all widgets in the sink path starting from the source widget
  501. * (DAI type for capture, AIF type for playback).
  502. * The error path in this function ensures that all successfully set up widgets getting freed.
  503. */
  504. static int sof_set_up_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget,
  505. int dir, struct snd_sof_pcm *spcm)
  506. {
  507. struct snd_sof_pcm_stream_pipeline_list *pipeline_list = &spcm->stream[dir].pipeline_list;
  508. struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
  509. struct snd_sof_widget *swidget = widget->dobj.private;
  510. struct snd_sof_pipeline *spipe;
  511. struct snd_soc_dapm_path *p;
  512. int ret;
  513. if (is_virtual_widget(sdev, widget, __func__))
  514. return 0;
  515. if (swidget) {
  516. int i;
  517. if (swidget->spipe && swidget->spipe->direction_valid &&
  518. !sof_widget_in_same_direction(swidget, dir))
  519. return 0;
  520. /* skip aggregated DAIs */
  521. if (is_aggregated_dai(swidget))
  522. goto sink_setup;
  523. ret = sof_widget_setup(sdev, swidget);
  524. if (ret < 0)
  525. return ret;
  526. /* skip populating the pipe_widgets array if it is NULL */
  527. if (!pipeline_list->pipelines)
  528. goto sink_setup;
  529. /*
  530. * Add the widget's pipe_widget to the list of pipelines to be triggered if not
  531. * already in the list. This will result in the pipelines getting added in the
  532. * order source to sink.
  533. */
  534. for (i = 0; i < pipeline_list->count; i++) {
  535. spipe = pipeline_list->pipelines[i];
  536. if (spipe == swidget->spipe)
  537. break;
  538. }
  539. if (i == pipeline_list->count) {
  540. pipeline_list->count++;
  541. pipeline_list->pipelines[i] = swidget->spipe;
  542. }
  543. }
  544. sink_setup:
  545. snd_soc_dapm_widget_for_each_sink_path(widget, p) {
  546. if (!p->walking) {
  547. if (!widget_in_list(list, p->sink))
  548. continue;
  549. p->walking = true;
  550. ret = sof_set_up_widgets_in_path(sdev, p->sink, dir, spcm);
  551. p->walking = false;
  552. if (ret < 0) {
  553. if (swidget)
  554. sof_widget_free(sdev, swidget);
  555. return ret;
  556. }
  557. }
  558. }
  559. return 0;
  560. }
  561. static int
  562. sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
  563. struct snd_pcm_hw_params *fe_params,
  564. struct snd_sof_platform_stream_params *platform_params, int dir,
  565. enum sof_widget_op op)
  566. {
  567. struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
  568. struct snd_soc_dapm_widget *widget;
  569. char *str;
  570. int ret = 0;
  571. int i;
  572. if (!list)
  573. return 0;
  574. for_each_dapm_widgets(list, i, widget) {
  575. /* starting widget for playback is of AIF type */
  576. if (dir == SNDRV_PCM_STREAM_PLAYBACK && widget->id != snd_soc_dapm_aif_in)
  577. continue;
  578. /* starting widget for capture is DAI type */
  579. if (dir == SNDRV_PCM_STREAM_CAPTURE && widget->id != snd_soc_dapm_dai_out &&
  580. widget->id != snd_soc_dapm_output)
  581. continue;
  582. switch (op) {
  583. case SOF_WIDGET_SETUP:
  584. ret = sof_set_up_widgets_in_path(sdev, widget, dir, spcm);
  585. str = "set up";
  586. break;
  587. case SOF_WIDGET_FREE:
  588. ret = sof_free_widgets_in_path(sdev, widget, dir, spcm);
  589. str = "free";
  590. break;
  591. case SOF_WIDGET_PREPARE:
  592. {
  593. struct snd_pcm_hw_params pipeline_params;
  594. str = "prepare";
  595. /*
  596. * When walking the list of connected widgets, the pipeline_params for each
  597. * widget is modified by the source widget in the path. Use a local
  598. * copy of the runtime params as the pipeline_params so that the runtime
  599. * params does not get overwritten.
  600. */
  601. memcpy(&pipeline_params, fe_params, sizeof(*fe_params));
  602. ret = sof_prepare_widgets_in_path(sdev, widget, fe_params, platform_params,
  603. &pipeline_params, dir, list);
  604. break;
  605. }
  606. case SOF_WIDGET_UNPREPARE:
  607. sof_unprepare_widgets_in_path(sdev, widget, list, dir);
  608. break;
  609. default:
  610. dev_err(sdev->dev, "Invalid widget op %d\n", op);
  611. return -EINVAL;
  612. }
  613. if (ret < 0) {
  614. dev_err(sdev->dev, "Failed to %s connected widgets\n", str);
  615. return ret;
  616. }
  617. }
  618. return 0;
  619. }
  620. int sof_widget_list_prepare(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
  621. struct snd_pcm_hw_params *fe_params,
  622. struct snd_sof_platform_stream_params *platform_params,
  623. int dir)
  624. {
  625. /*
  626. * Prepare widgets for set up. The prepare step is used to allocate memory, assign
  627. * instance ID and pick the widget configuration based on the runtime PCM params.
  628. */
  629. return sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params,
  630. dir, SOF_WIDGET_PREPARE);
  631. }
  632. void sof_widget_list_unprepare(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir)
  633. {
  634. struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
  635. /* unprepare the widget */
  636. sof_walk_widgets_in_order(sdev, spcm, NULL, NULL, dir, SOF_WIDGET_UNPREPARE);
  637. snd_soc_dapm_dai_free_widgets(&list);
  638. spcm->stream[dir].list = NULL;
  639. }
  640. int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
  641. struct snd_pcm_hw_params *fe_params,
  642. struct snd_sof_platform_stream_params *platform_params,
  643. int dir)
  644. {
  645. const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
  646. struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
  647. struct snd_soc_dapm_widget *widget;
  648. int i, ret;
  649. /* nothing to set up or setup has been already done */
  650. if (!list || spcm->setup_done[dir])
  651. return 0;
  652. /* Set up is used to send the IPC to the DSP to create the widget */
  653. ret = sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params,
  654. dir, SOF_WIDGET_SETUP);
  655. if (ret < 0) {
  656. sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params,
  657. dir, SOF_WIDGET_UNPREPARE);
  658. return ret;
  659. }
  660. /*
  661. * error in setting pipeline connections will result in route status being reset for
  662. * routes that were successfully set up when the widgets are freed.
  663. */
  664. ret = sof_setup_pipeline_connections(sdev, list, dir);
  665. if (ret < 0)
  666. goto widget_free;
  667. /* complete pipelines */
  668. for_each_dapm_widgets(list, i, widget) {
  669. struct snd_sof_widget *swidget = widget->dobj.private;
  670. struct snd_sof_widget *pipe_widget;
  671. struct snd_sof_pipeline *spipe;
  672. if (!swidget || sdev->dspless_mode_selected)
  673. continue;
  674. spipe = swidget->spipe;
  675. if (!spipe) {
  676. dev_err(sdev->dev, "no pipeline found for %s\n",
  677. swidget->widget->name);
  678. ret = -EINVAL;
  679. goto widget_free;
  680. }
  681. pipe_widget = spipe->pipe_widget;
  682. if (!pipe_widget) {
  683. dev_err(sdev->dev, "error: no pipeline widget found for %s\n",
  684. swidget->widget->name);
  685. ret = -EINVAL;
  686. goto widget_free;
  687. }
  688. if (spipe->complete)
  689. continue;
  690. if (tplg_ops && tplg_ops->pipeline_complete) {
  691. spipe->complete = tplg_ops->pipeline_complete(sdev, pipe_widget);
  692. if (spipe->complete < 0) {
  693. ret = spipe->complete;
  694. goto widget_free;
  695. }
  696. }
  697. }
  698. spcm->setup_done[dir] = true;
  699. return 0;
  700. widget_free:
  701. sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params, dir,
  702. SOF_WIDGET_FREE);
  703. sof_walk_widgets_in_order(sdev, spcm, NULL, NULL, dir, SOF_WIDGET_UNPREPARE);
  704. return ret;
  705. }
  706. int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir)
  707. {
  708. struct snd_sof_pcm_stream_pipeline_list *pipeline_list = &spcm->stream[dir].pipeline_list;
  709. struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
  710. int ret;
  711. /* nothing to free */
  712. if (!list || !spcm->setup_done[dir])
  713. return 0;
  714. /* send IPC to free widget in the DSP */
  715. ret = sof_walk_widgets_in_order(sdev, spcm, NULL, NULL, dir, SOF_WIDGET_FREE);
  716. spcm->setup_done[dir] = false;
  717. pipeline_list->count = 0;
  718. return ret;
  719. }
  720. /*
  721. * helper to determine if there are only D0i3 compatible
  722. * streams active
  723. */
  724. bool snd_sof_dsp_only_d0i3_compatible_stream_active(struct snd_sof_dev *sdev)
  725. {
  726. struct snd_pcm_substream *substream;
  727. struct snd_sof_pcm *spcm;
  728. bool d0i3_compatible_active = false;
  729. int dir;
  730. list_for_each_entry(spcm, &sdev->pcm_list, list) {
  731. for_each_pcm_streams(dir) {
  732. substream = spcm->stream[dir].substream;
  733. if (!substream || !substream->runtime)
  734. continue;
  735. /*
  736. * substream->runtime being not NULL indicates
  737. * that the stream is open. No need to check the
  738. * stream state.
  739. */
  740. if (!spcm->stream[dir].d0i3_compatible)
  741. return false;
  742. d0i3_compatible_active = true;
  743. }
  744. }
  745. return d0i3_compatible_active;
  746. }
  747. EXPORT_SYMBOL(snd_sof_dsp_only_d0i3_compatible_stream_active);
  748. bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev)
  749. {
  750. struct snd_sof_pcm *spcm;
  751. list_for_each_entry(spcm, &sdev->pcm_list, list) {
  752. if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].suspend_ignored ||
  753. spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored)
  754. return true;
  755. }
  756. return false;
  757. }
  758. /*
  759. * Generic object lookup APIs.
  760. */
  761. struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_soc_component *scomp,
  762. const char *name)
  763. {
  764. struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
  765. struct snd_sof_pcm *spcm;
  766. list_for_each_entry(spcm, &sdev->pcm_list, list) {
  767. /* match with PCM dai name */
  768. if (strcmp(spcm->pcm.dai_name, name) == 0)
  769. return spcm;
  770. /* match with playback caps name if set */
  771. if (*spcm->pcm.caps[0].name &&
  772. !strcmp(spcm->pcm.caps[0].name, name))
  773. return spcm;
  774. /* match with capture caps name if set */
  775. if (*spcm->pcm.caps[1].name &&
  776. !strcmp(spcm->pcm.caps[1].name, name))
  777. return spcm;
  778. }
  779. return NULL;
  780. }
  781. struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp,
  782. unsigned int comp_id,
  783. int *direction)
  784. {
  785. struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
  786. struct snd_sof_pcm *spcm;
  787. int dir;
  788. list_for_each_entry(spcm, &sdev->pcm_list, list) {
  789. for_each_pcm_streams(dir) {
  790. if (spcm->stream[dir].comp_id == comp_id) {
  791. *direction = dir;
  792. return spcm;
  793. }
  794. }
  795. }
  796. return NULL;
  797. }
  798. struct snd_sof_widget *snd_sof_find_swidget(struct snd_soc_component *scomp,
  799. const char *name)
  800. {
  801. struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
  802. struct snd_sof_widget *swidget;
  803. list_for_each_entry(swidget, &sdev->widget_list, list) {
  804. if (strcmp(name, swidget->widget->name) == 0)
  805. return swidget;
  806. }
  807. return NULL;
  808. }
  809. /* find widget by stream name and direction */
  810. struct snd_sof_widget *
  811. snd_sof_find_swidget_sname(struct snd_soc_component *scomp,
  812. const char *pcm_name, int dir)
  813. {
  814. struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
  815. struct snd_sof_widget *swidget;
  816. enum snd_soc_dapm_type type;
  817. if (dir == SNDRV_PCM_STREAM_PLAYBACK)
  818. type = snd_soc_dapm_aif_in;
  819. else
  820. type = snd_soc_dapm_aif_out;
  821. list_for_each_entry(swidget, &sdev->widget_list, list) {
  822. if (!strcmp(pcm_name, swidget->widget->sname) &&
  823. swidget->id == type)
  824. return swidget;
  825. }
  826. return NULL;
  827. }
  828. struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp,
  829. const char *name)
  830. {
  831. struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
  832. struct snd_sof_dai *dai;
  833. list_for_each_entry(dai, &sdev->dai_list, list) {
  834. if (dai->name && (strcmp(name, dai->name) == 0))
  835. return dai;
  836. }
  837. return NULL;
  838. }
  839. static int sof_dai_get_param(struct snd_soc_pcm_runtime *rtd, int param_type)
  840. {
  841. struct snd_soc_component *component =
  842. snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
  843. struct snd_sof_dai *dai =
  844. snd_sof_find_dai(component, (char *)rtd->dai_link->name);
  845. struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
  846. const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
  847. /* use the tplg configured mclk if existed */
  848. if (!dai)
  849. return 0;
  850. if (tplg_ops && tplg_ops->dai_get_param)
  851. return tplg_ops->dai_get_param(sdev, dai, param_type);
  852. return 0;
  853. }
  854. /*
  855. * Helper to get SSP MCLK from a pcm_runtime.
  856. * Return 0 if not exist.
  857. */
  858. int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd)
  859. {
  860. return sof_dai_get_param(rtd, SOF_DAI_PARAM_INTEL_SSP_MCLK);
  861. }
  862. EXPORT_SYMBOL(sof_dai_get_mclk);
  863. /*
  864. * Helper to get SSP BCLK from a pcm_runtime.
  865. * Return 0 if not exist.
  866. */
  867. int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd)
  868. {
  869. return sof_dai_get_param(rtd, SOF_DAI_PARAM_INTEL_SSP_BCLK);
  870. }
  871. EXPORT_SYMBOL(sof_dai_get_bclk);
  872. /*
  873. * Helper to get SSP TDM slot number from a pcm_runtime.
  874. * Return 0 if not exist.
  875. */
  876. int sof_dai_get_tdm_slots(struct snd_soc_pcm_runtime *rtd)
  877. {
  878. return sof_dai_get_param(rtd, SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS);
  879. }
  880. EXPORT_SYMBOL(sof_dai_get_tdm_slots);