PageRenderTime 1500ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/sound/soc/sof/intel/hda-dai.c

http://github.com/torvalds/linux
C | 588 lines | 471 code | 70 blank | 47 comment | 40 complexity | 32469e9f3da5a2ea42c1d145998832d1 MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
  1. // SPDX-License-Identifier: (GPL-2.0 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) 2018 Intel Corporation. All rights reserved.
  7. //
  8. // Authors: Keyon Jie <yang.jie@linux.intel.com>
  9. //
  10. #include <sound/pcm_params.h>
  11. #include <sound/hdaudio_ext.h>
  12. #include "../sof-priv.h"
  13. #include "../sof-audio.h"
  14. #include "hda.h"
  15. #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
  16. struct hda_pipe_params {
  17. u8 host_dma_id;
  18. u8 link_dma_id;
  19. u32 ch;
  20. u32 s_freq;
  21. u32 s_fmt;
  22. u8 linktype;
  23. snd_pcm_format_t format;
  24. int link_index;
  25. int stream;
  26. unsigned int host_bps;
  27. unsigned int link_bps;
  28. };
  29. /*
  30. * This function checks if the host dma channel corresponding
  31. * to the link DMA stream_tag argument is assigned to one
  32. * of the FEs connected to the BE DAI.
  33. */
  34. static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd,
  35. int dir, int stream_tag)
  36. {
  37. struct snd_pcm_substream *fe_substream;
  38. struct hdac_stream *fe_hstream;
  39. struct snd_soc_dpcm *dpcm;
  40. for_each_dpcm_fe(rtd, dir, dpcm) {
  41. fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, dir);
  42. fe_hstream = fe_substream->runtime->private_data;
  43. if (fe_hstream->stream_tag == stream_tag)
  44. return true;
  45. }
  46. return false;
  47. }
  48. static struct hdac_ext_stream *
  49. hda_link_stream_assign(struct hdac_bus *bus,
  50. struct snd_pcm_substream *substream)
  51. {
  52. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  53. struct sof_intel_hda_stream *hda_stream;
  54. struct hdac_ext_stream *res = NULL;
  55. struct hdac_stream *stream = NULL;
  56. int stream_dir = substream->stream;
  57. if (!bus->ppcap) {
  58. dev_err(bus->dev, "stream type not supported\n");
  59. return NULL;
  60. }
  61. list_for_each_entry(stream, &bus->stream_list, list) {
  62. struct hdac_ext_stream *hstream =
  63. stream_to_hdac_ext_stream(stream);
  64. if (stream->direction != substream->stream)
  65. continue;
  66. hda_stream = hstream_to_sof_hda_stream(hstream);
  67. /* check if link is available */
  68. if (!hstream->link_locked) {
  69. if (stream->opened) {
  70. /*
  71. * check if the stream tag matches the stream
  72. * tag of one of the connected FEs
  73. */
  74. if (hda_check_fes(rtd, stream_dir,
  75. stream->stream_tag)) {
  76. res = hstream;
  77. break;
  78. }
  79. } else {
  80. res = hstream;
  81. /*
  82. * This must be a hostless stream.
  83. * So reserve the host DMA channel.
  84. */
  85. hda_stream->host_reserved = 1;
  86. break;
  87. }
  88. }
  89. }
  90. if (res) {
  91. /*
  92. * Decouple host and link DMA. The decoupled flag
  93. * is updated in snd_hdac_ext_stream_decouple().
  94. */
  95. if (!res->decoupled)
  96. snd_hdac_ext_stream_decouple(bus, res, true);
  97. spin_lock_irq(&bus->reg_lock);
  98. res->link_locked = 1;
  99. res->link_substream = substream;
  100. spin_unlock_irq(&bus->reg_lock);
  101. }
  102. return res;
  103. }
  104. static int hda_link_dma_params(struct hdac_ext_stream *stream,
  105. struct hda_pipe_params *params)
  106. {
  107. struct hdac_stream *hstream = &stream->hstream;
  108. unsigned char stream_tag = hstream->stream_tag;
  109. struct hdac_bus *bus = hstream->bus;
  110. struct hdac_ext_link *link;
  111. unsigned int format_val;
  112. snd_hdac_ext_stream_decouple(bus, stream, true);
  113. snd_hdac_ext_link_stream_reset(stream);
  114. format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch,
  115. params->format,
  116. params->link_bps, 0);
  117. dev_dbg(bus->dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
  118. format_val, params->s_freq, params->ch, params->format);
  119. snd_hdac_ext_link_stream_setup(stream, format_val);
  120. if (stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) {
  121. list_for_each_entry(link, &bus->hlink_list, list) {
  122. if (link->index == params->link_index)
  123. snd_hdac_ext_link_set_stream_id(link,
  124. stream_tag);
  125. }
  126. }
  127. stream->link_prepared = 1;
  128. return 0;
  129. }
  130. /* Send DAI_CONFIG IPC to the DAI that matches the dai_name and direction */
  131. static int hda_link_config_ipc(struct sof_intel_hda_stream *hda_stream,
  132. const char *dai_name, int channel, int dir)
  133. {
  134. struct sof_ipc_dai_config *config;
  135. struct snd_sof_dai *sof_dai;
  136. struct sof_ipc_reply reply;
  137. int ret = 0;
  138. list_for_each_entry(sof_dai, &hda_stream->sdev->dai_list, list) {
  139. if (!sof_dai->cpu_dai_name)
  140. continue;
  141. if (!strcmp(dai_name, sof_dai->cpu_dai_name) &&
  142. dir == sof_dai->comp_dai.direction) {
  143. config = sof_dai->dai_config;
  144. if (!config) {
  145. dev_err(hda_stream->sdev->dev,
  146. "error: no config for DAI %s\n",
  147. sof_dai->name);
  148. return -EINVAL;
  149. }
  150. /* update config with stream tag */
  151. config->hda.link_dma_ch = channel;
  152. /* send IPC */
  153. ret = sof_ipc_tx_message(hda_stream->sdev->ipc,
  154. config->hdr.cmd,
  155. config,
  156. config->hdr.size,
  157. &reply, sizeof(reply));
  158. if (ret < 0)
  159. dev_err(hda_stream->sdev->dev,
  160. "error: failed to set dai config for %s\n",
  161. sof_dai->name);
  162. return ret;
  163. }
  164. }
  165. return -EINVAL;
  166. }
  167. static int hda_link_hw_params(struct snd_pcm_substream *substream,
  168. struct snd_pcm_hw_params *params,
  169. struct snd_soc_dai *dai)
  170. {
  171. struct hdac_stream *hstream = substream->runtime->private_data;
  172. struct hdac_bus *bus = hstream->bus;
  173. struct hdac_ext_stream *link_dev;
  174. struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
  175. struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
  176. struct sof_intel_hda_stream *hda_stream;
  177. struct hda_pipe_params p_params = {0};
  178. struct hdac_ext_link *link;
  179. int stream_tag;
  180. int ret;
  181. /* get stored dma data if resuming from system suspend */
  182. link_dev = snd_soc_dai_get_dma_data(dai, substream);
  183. if (!link_dev) {
  184. link_dev = hda_link_stream_assign(bus, substream);
  185. if (!link_dev)
  186. return -EBUSY;
  187. snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
  188. }
  189. stream_tag = hdac_stream(link_dev)->stream_tag;
  190. hda_stream = hstream_to_sof_hda_stream(link_dev);
  191. /* update the DSP with the new tag */
  192. ret = hda_link_config_ipc(hda_stream, dai->name, stream_tag - 1,
  193. substream->stream);
  194. if (ret < 0)
  195. return ret;
  196. link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
  197. if (!link)
  198. return -EINVAL;
  199. /* set the stream tag in the codec dai dma params */
  200. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  201. snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0);
  202. else
  203. snd_soc_dai_set_tdm_slot(codec_dai, 0, stream_tag, 0, 0);
  204. p_params.s_fmt = snd_pcm_format_width(params_format(params));
  205. p_params.ch = params_channels(params);
  206. p_params.s_freq = params_rate(params);
  207. p_params.stream = substream->stream;
  208. p_params.link_dma_id = stream_tag - 1;
  209. p_params.link_index = link->index;
  210. p_params.format = params_format(params);
  211. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  212. p_params.link_bps = codec_dai->driver->playback.sig_bits;
  213. else
  214. p_params.link_bps = codec_dai->driver->capture.sig_bits;
  215. return hda_link_dma_params(link_dev, &p_params);
  216. }
  217. static int hda_link_pcm_prepare(struct snd_pcm_substream *substream,
  218. struct snd_soc_dai *dai)
  219. {
  220. struct hdac_ext_stream *link_dev =
  221. snd_soc_dai_get_dma_data(dai, substream);
  222. struct snd_sof_dev *sdev =
  223. snd_soc_component_get_drvdata(dai->component);
  224. struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
  225. int stream = substream->stream;
  226. if (link_dev->link_prepared)
  227. return 0;
  228. dev_dbg(sdev->dev, "hda: prepare stream dir %d\n", substream->stream);
  229. return hda_link_hw_params(substream, &rtd->dpcm[stream].hw_params,
  230. dai);
  231. }
  232. static int hda_link_pcm_trigger(struct snd_pcm_substream *substream,
  233. int cmd, struct snd_soc_dai *dai)
  234. {
  235. struct hdac_ext_stream *link_dev =
  236. snd_soc_dai_get_dma_data(dai, substream);
  237. struct sof_intel_hda_stream *hda_stream;
  238. struct snd_soc_pcm_runtime *rtd;
  239. struct hdac_ext_link *link;
  240. struct hdac_stream *hstream;
  241. struct hdac_bus *bus;
  242. int stream_tag;
  243. int ret;
  244. hstream = substream->runtime->private_data;
  245. bus = hstream->bus;
  246. rtd = snd_pcm_substream_chip(substream);
  247. link = snd_hdac_ext_bus_get_link(bus, asoc_rtd_to_codec(rtd, 0)->component->name);
  248. if (!link)
  249. return -EINVAL;
  250. hda_stream = hstream_to_sof_hda_stream(link_dev);
  251. dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
  252. switch (cmd) {
  253. case SNDRV_PCM_TRIGGER_RESUME:
  254. /* set up hw_params */
  255. ret = hda_link_pcm_prepare(substream, dai);
  256. if (ret < 0) {
  257. dev_err(dai->dev,
  258. "error: setting up hw_params during resume\n");
  259. return ret;
  260. }
  261. /* fallthrough */
  262. case SNDRV_PCM_TRIGGER_START:
  263. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  264. snd_hdac_ext_link_stream_start(link_dev);
  265. break;
  266. case SNDRV_PCM_TRIGGER_SUSPEND:
  267. case SNDRV_PCM_TRIGGER_STOP:
  268. /*
  269. * clear link DMA channel. It will be assigned when
  270. * hw_params is set up again after resume.
  271. */
  272. ret = hda_link_config_ipc(hda_stream, dai->name,
  273. DMA_CHAN_INVALID, substream->stream);
  274. if (ret < 0)
  275. return ret;
  276. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  277. stream_tag = hdac_stream(link_dev)->stream_tag;
  278. snd_hdac_ext_link_clear_stream_id(link, stream_tag);
  279. }
  280. link_dev->link_prepared = 0;
  281. /* fallthrough */
  282. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  283. snd_hdac_ext_link_stream_clear(link_dev);
  284. break;
  285. default:
  286. return -EINVAL;
  287. }
  288. return 0;
  289. }
  290. static int hda_link_hw_free(struct snd_pcm_substream *substream,
  291. struct snd_soc_dai *dai)
  292. {
  293. unsigned int stream_tag;
  294. struct sof_intel_hda_stream *hda_stream;
  295. struct hdac_bus *bus;
  296. struct hdac_ext_link *link;
  297. struct hdac_stream *hstream;
  298. struct snd_soc_pcm_runtime *rtd;
  299. struct hdac_ext_stream *link_dev;
  300. int ret;
  301. hstream = substream->runtime->private_data;
  302. bus = hstream->bus;
  303. rtd = snd_pcm_substream_chip(substream);
  304. link_dev = snd_soc_dai_get_dma_data(dai, substream);
  305. if (!link_dev) {
  306. dev_dbg(dai->dev,
  307. "%s: link_dev is not assigned\n", __func__);
  308. return -EINVAL;
  309. }
  310. hda_stream = hstream_to_sof_hda_stream(link_dev);
  311. /* free the link DMA channel in the FW */
  312. ret = hda_link_config_ipc(hda_stream, dai->name, DMA_CHAN_INVALID,
  313. substream->stream);
  314. if (ret < 0)
  315. return ret;
  316. link = snd_hdac_ext_bus_get_link(bus, asoc_rtd_to_codec(rtd, 0)->component->name);
  317. if (!link)
  318. return -EINVAL;
  319. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  320. stream_tag = hdac_stream(link_dev)->stream_tag;
  321. snd_hdac_ext_link_clear_stream_id(link, stream_tag);
  322. }
  323. snd_soc_dai_set_dma_data(dai, substream, NULL);
  324. snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK);
  325. link_dev->link_prepared = 0;
  326. /* free the host DMA channel reserved by hostless streams */
  327. hda_stream->host_reserved = 0;
  328. return 0;
  329. }
  330. static const struct snd_soc_dai_ops hda_link_dai_ops = {
  331. .hw_params = hda_link_hw_params,
  332. .hw_free = hda_link_hw_free,
  333. .trigger = hda_link_pcm_trigger,
  334. .prepare = hda_link_pcm_prepare,
  335. };
  336. #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
  337. #include "../compress.h"
  338. static struct snd_soc_cdai_ops sof_probe_compr_ops = {
  339. .startup = sof_probe_compr_open,
  340. .shutdown = sof_probe_compr_free,
  341. .set_params = sof_probe_compr_set_params,
  342. .trigger = sof_probe_compr_trigger,
  343. .pointer = sof_probe_compr_pointer,
  344. };
  345. #endif
  346. #endif
  347. /*
  348. * common dai driver for skl+ platforms.
  349. * some products who use this DAI array only physically have a subset of
  350. * the DAIs, but no harm is done here by adding the whole set.
  351. */
  352. struct snd_soc_dai_driver skl_dai[] = {
  353. {
  354. .name = "SSP0 Pin",
  355. .playback = {
  356. .channels_min = 1,
  357. .channels_max = 8,
  358. },
  359. .capture = {
  360. .channels_min = 1,
  361. .channels_max = 8,
  362. },
  363. },
  364. {
  365. .name = "SSP1 Pin",
  366. .playback = {
  367. .channels_min = 1,
  368. .channels_max = 8,
  369. },
  370. .capture = {
  371. .channels_min = 1,
  372. .channels_max = 8,
  373. },
  374. },
  375. {
  376. .name = "SSP2 Pin",
  377. .playback = {
  378. .channels_min = 1,
  379. .channels_max = 8,
  380. },
  381. .capture = {
  382. .channels_min = 1,
  383. .channels_max = 8,
  384. },
  385. },
  386. {
  387. .name = "SSP3 Pin",
  388. .playback = {
  389. .channels_min = 1,
  390. .channels_max = 8,
  391. },
  392. .capture = {
  393. .channels_min = 1,
  394. .channels_max = 8,
  395. },
  396. },
  397. {
  398. .name = "SSP4 Pin",
  399. .playback = {
  400. .channels_min = 1,
  401. .channels_max = 8,
  402. },
  403. .capture = {
  404. .channels_min = 1,
  405. .channels_max = 8,
  406. },
  407. },
  408. {
  409. .name = "SSP5 Pin",
  410. .playback = {
  411. .channels_min = 1,
  412. .channels_max = 8,
  413. },
  414. .capture = {
  415. .channels_min = 1,
  416. .channels_max = 8,
  417. },
  418. },
  419. {
  420. .name = "DMIC01 Pin",
  421. .capture = {
  422. .channels_min = 1,
  423. .channels_max = 4,
  424. },
  425. },
  426. {
  427. .name = "DMIC16k Pin",
  428. .capture = {
  429. .channels_min = 1,
  430. .channels_max = 4,
  431. },
  432. },
  433. #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
  434. {
  435. .name = "iDisp1 Pin",
  436. .ops = &hda_link_dai_ops,
  437. .playback = {
  438. .channels_min = 1,
  439. .channels_max = 8,
  440. },
  441. },
  442. {
  443. .name = "iDisp2 Pin",
  444. .ops = &hda_link_dai_ops,
  445. .playback = {
  446. .channels_min = 1,
  447. .channels_max = 8,
  448. },
  449. },
  450. {
  451. .name = "iDisp3 Pin",
  452. .ops = &hda_link_dai_ops,
  453. .playback = {
  454. .channels_min = 1,
  455. .channels_max = 8,
  456. },
  457. },
  458. {
  459. .name = "iDisp4 Pin",
  460. .ops = &hda_link_dai_ops,
  461. .playback = {
  462. .channels_min = 1,
  463. .channels_max = 8,
  464. },
  465. },
  466. {
  467. .name = "Analog CPU DAI",
  468. .ops = &hda_link_dai_ops,
  469. .playback = {
  470. .channels_min = 1,
  471. .channels_max = 16,
  472. },
  473. .capture = {
  474. .channels_min = 1,
  475. .channels_max = 16,
  476. },
  477. },
  478. {
  479. .name = "Digital CPU DAI",
  480. .ops = &hda_link_dai_ops,
  481. .playback = {
  482. .channels_min = 1,
  483. .channels_max = 16,
  484. },
  485. .capture = {
  486. .channels_min = 1,
  487. .channels_max = 16,
  488. },
  489. },
  490. {
  491. .name = "Alt Analog CPU DAI",
  492. .ops = &hda_link_dai_ops,
  493. .playback = {
  494. .channels_min = 1,
  495. .channels_max = 16,
  496. },
  497. .capture = {
  498. .channels_min = 1,
  499. .channels_max = 16,
  500. },
  501. },
  502. #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
  503. {
  504. .name = "Probe Extraction CPU DAI",
  505. .compress_new = snd_soc_new_compress,
  506. .cops = &sof_probe_compr_ops,
  507. .capture = {
  508. .stream_name = "Probe Extraction",
  509. .channels_min = 1,
  510. .channels_max = 8,
  511. .rates = SNDRV_PCM_RATE_48000,
  512. .rate_min = 48000,
  513. .rate_max = 48000,
  514. },
  515. },
  516. #endif
  517. #endif
  518. };