acp6x-pdm-dma.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * AMD ALSA SoC Yellow Carp PDM Driver
  4. *
  5. * Copyright 2021 Advanced Micro Devices, Inc.
  6. */
  7. #include <linux/platform_device.h>
  8. #include <linux/module.h>
  9. #include <linux/err.h>
  10. #include <linux/io.h>
  11. #include <sound/pcm_params.h>
  12. #include <sound/soc.h>
  13. #include <sound/soc-dai.h>
  14. #include <linux/pm_runtime.h>
  15. #include "acp6x.h"
  16. #define DRV_NAME "acp_yc_pdm_dma"
  17. static const struct snd_pcm_hardware acp6x_pdm_hardware_capture = {
  18. .info = SNDRV_PCM_INFO_INTERLEAVED |
  19. SNDRV_PCM_INFO_BLOCK_TRANSFER |
  20. SNDRV_PCM_INFO_MMAP |
  21. SNDRV_PCM_INFO_MMAP_VALID |
  22. SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
  23. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  24. .channels_min = 2,
  25. .channels_max = 2,
  26. .rates = SNDRV_PCM_RATE_48000,
  27. .rate_min = 48000,
  28. .rate_max = 48000,
  29. .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE,
  30. .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
  31. .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
  32. .periods_min = CAPTURE_MIN_NUM_PERIODS,
  33. .periods_max = CAPTURE_MAX_NUM_PERIODS,
  34. };
  35. static void acp6x_init_pdm_ring_buffer(u32 physical_addr, u32 buffer_size,
  36. u32 watermark_size, void __iomem *acp_base)
  37. {
  38. acp6x_writel(physical_addr, acp_base + ACP_WOV_RX_RINGBUFADDR);
  39. acp6x_writel(buffer_size, acp_base + ACP_WOV_RX_RINGBUFSIZE);
  40. acp6x_writel(watermark_size, acp_base + ACP_WOV_RX_INTR_WATERMARK_SIZE);
  41. acp6x_writel(0x01, acp_base + ACPAXI2AXI_ATU_CTRL);
  42. }
  43. static void acp6x_enable_pdm_clock(void __iomem *acp_base)
  44. {
  45. u32 pdm_clk_enable, pdm_ctrl;
  46. pdm_clk_enable = ACP_PDM_CLK_FREQ_MASK;
  47. pdm_ctrl = 0x00;
  48. acp6x_writel(pdm_clk_enable, acp_base + ACP_WOV_CLK_CTRL);
  49. pdm_ctrl = acp6x_readl(acp_base + ACP_WOV_MISC_CTRL);
  50. pdm_ctrl |= ACP_WOV_MISC_CTRL_MASK;
  51. acp6x_writel(pdm_ctrl, acp_base + ACP_WOV_MISC_CTRL);
  52. }
  53. static void acp6x_enable_pdm_interrupts(void __iomem *acp_base)
  54. {
  55. u32 ext_int_ctrl;
  56. ext_int_ctrl = acp6x_readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
  57. ext_int_ctrl |= PDM_DMA_INTR_MASK;
  58. acp6x_writel(ext_int_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL);
  59. }
  60. static void acp6x_disable_pdm_interrupts(void __iomem *acp_base)
  61. {
  62. u32 ext_int_ctrl;
  63. ext_int_ctrl = acp6x_readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
  64. ext_int_ctrl &= ~PDM_DMA_INTR_MASK;
  65. acp6x_writel(ext_int_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL);
  66. }
  67. static bool acp6x_check_pdm_dma_status(void __iomem *acp_base)
  68. {
  69. bool pdm_dma_status;
  70. u32 pdm_enable, pdm_dma_enable;
  71. pdm_dma_status = false;
  72. pdm_enable = acp6x_readl(acp_base + ACP_WOV_PDM_ENABLE);
  73. pdm_dma_enable = acp6x_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
  74. if ((pdm_enable & ACP_PDM_ENABLE) && (pdm_dma_enable & ACP_PDM_DMA_EN_STATUS))
  75. pdm_dma_status = true;
  76. return pdm_dma_status;
  77. }
  78. static int acp6x_start_pdm_dma(void __iomem *acp_base)
  79. {
  80. u32 pdm_enable;
  81. u32 pdm_dma_enable;
  82. int timeout;
  83. pdm_enable = 0x01;
  84. pdm_dma_enable = 0x01;
  85. acp6x_enable_pdm_clock(acp_base);
  86. acp6x_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE);
  87. acp6x_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE);
  88. timeout = 0;
  89. while (++timeout < ACP_COUNTER) {
  90. pdm_dma_enable = acp6x_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
  91. if ((pdm_dma_enable & 0x02) == ACP_PDM_DMA_EN_STATUS)
  92. return 0;
  93. udelay(DELAY_US);
  94. }
  95. return -ETIMEDOUT;
  96. }
  97. static int acp6x_stop_pdm_dma(void __iomem *acp_base)
  98. {
  99. u32 pdm_enable, pdm_dma_enable;
  100. int timeout;
  101. pdm_enable = 0x00;
  102. pdm_dma_enable = 0x00;
  103. pdm_enable = acp6x_readl(acp_base + ACP_WOV_PDM_ENABLE);
  104. pdm_dma_enable = acp6x_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
  105. if (pdm_dma_enable & 0x01) {
  106. pdm_dma_enable = 0x02;
  107. acp6x_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE);
  108. timeout = 0;
  109. while (++timeout < ACP_COUNTER) {
  110. pdm_dma_enable = acp6x_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
  111. if ((pdm_dma_enable & 0x02) == 0x00)
  112. break;
  113. udelay(DELAY_US);
  114. }
  115. if (timeout == ACP_COUNTER)
  116. return -ETIMEDOUT;
  117. }
  118. if (pdm_enable == ACP_PDM_ENABLE) {
  119. pdm_enable = ACP_PDM_DISABLE;
  120. acp6x_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE);
  121. }
  122. acp6x_writel(0x01, acp_base + ACP_WOV_PDM_FIFO_FLUSH);
  123. return 0;
  124. }
  125. static void acp6x_config_dma(struct pdm_stream_instance *rtd, int direction)
  126. {
  127. u16 page_idx;
  128. u32 low, high, val;
  129. dma_addr_t addr;
  130. addr = rtd->dma_addr;
  131. val = PDM_PTE_OFFSET;
  132. /* Group Enable */
  133. acp6x_writel(ACP_SRAM_PTE_OFFSET | BIT(31), rtd->acp6x_base +
  134. ACPAXI2AXI_ATU_BASE_ADDR_GRP_1);
  135. acp6x_writel(PAGE_SIZE_4K_ENABLE, rtd->acp6x_base +
  136. ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1);
  137. for (page_idx = 0; page_idx < rtd->num_pages; page_idx++) {
  138. /* Load the low address of page int ACP SRAM through SRBM */
  139. low = lower_32_bits(addr);
  140. high = upper_32_bits(addr);
  141. acp6x_writel(low, rtd->acp6x_base + ACP_SCRATCH_REG_0 + val);
  142. high |= BIT(31);
  143. acp6x_writel(high, rtd->acp6x_base + ACP_SCRATCH_REG_0 + val + 4);
  144. val += 8;
  145. addr += PAGE_SIZE;
  146. }
  147. }
  148. static int acp6x_pdm_dma_open(struct snd_soc_component *component,
  149. struct snd_pcm_substream *substream)
  150. {
  151. struct snd_pcm_runtime *runtime;
  152. struct pdm_dev_data *adata;
  153. struct pdm_stream_instance *pdm_data;
  154. int ret;
  155. runtime = substream->runtime;
  156. adata = dev_get_drvdata(component->dev);
  157. pdm_data = kzalloc(sizeof(*pdm_data), GFP_KERNEL);
  158. if (!pdm_data)
  159. return -EINVAL;
  160. if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  161. runtime->hw = acp6x_pdm_hardware_capture;
  162. ret = snd_pcm_hw_constraint_integer(runtime,
  163. SNDRV_PCM_HW_PARAM_PERIODS);
  164. if (ret < 0) {
  165. dev_err(component->dev, "set integer constraint failed\n");
  166. kfree(pdm_data);
  167. return ret;
  168. }
  169. acp6x_enable_pdm_interrupts(adata->acp6x_base);
  170. if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  171. adata->capture_stream = substream;
  172. pdm_data->acp6x_base = adata->acp6x_base;
  173. runtime->private_data = pdm_data;
  174. return ret;
  175. }
  176. static int acp6x_pdm_dma_hw_params(struct snd_soc_component *component,
  177. struct snd_pcm_substream *substream,
  178. struct snd_pcm_hw_params *params)
  179. {
  180. struct pdm_stream_instance *rtd;
  181. size_t size, period_bytes;
  182. rtd = substream->runtime->private_data;
  183. if (!rtd)
  184. return -EINVAL;
  185. size = params_buffer_bytes(params);
  186. period_bytes = params_period_bytes(params);
  187. rtd->dma_addr = substream->runtime->dma_addr;
  188. rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
  189. acp6x_config_dma(rtd, substream->stream);
  190. acp6x_init_pdm_ring_buffer(PDM_MEM_WINDOW_START, size,
  191. period_bytes, rtd->acp6x_base);
  192. return 0;
  193. }
  194. static u64 acp6x_pdm_get_byte_count(struct pdm_stream_instance *rtd,
  195. int direction)
  196. {
  197. union acp_pdm_dma_count byte_count;
  198. byte_count.bcount.high =
  199. acp6x_readl(rtd->acp6x_base + ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH);
  200. byte_count.bcount.low =
  201. acp6x_readl(rtd->acp6x_base + ACP_WOV_RX_LINEARPOSITIONCNTR_LOW);
  202. return byte_count.bytescount;
  203. }
  204. static snd_pcm_uframes_t acp6x_pdm_dma_pointer(struct snd_soc_component *comp,
  205. struct snd_pcm_substream *stream)
  206. {
  207. struct pdm_stream_instance *rtd;
  208. u32 pos, buffersize;
  209. u64 bytescount;
  210. rtd = stream->runtime->private_data;
  211. buffersize = frames_to_bytes(stream->runtime,
  212. stream->runtime->buffer_size);
  213. bytescount = acp6x_pdm_get_byte_count(rtd, stream->stream);
  214. if (bytescount > rtd->bytescount)
  215. bytescount -= rtd->bytescount;
  216. pos = do_div(bytescount, buffersize);
  217. return bytes_to_frames(stream->runtime, pos);
  218. }
  219. static int acp6x_pdm_dma_new(struct snd_soc_component *component,
  220. struct snd_soc_pcm_runtime *rtd)
  221. {
  222. struct device *parent = component->dev->parent;
  223. snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
  224. parent, MIN_BUFFER, MAX_BUFFER);
  225. return 0;
  226. }
  227. static int acp6x_pdm_dma_close(struct snd_soc_component *component,
  228. struct snd_pcm_substream *substream)
  229. {
  230. struct pdm_dev_data *adata = dev_get_drvdata(component->dev);
  231. acp6x_disable_pdm_interrupts(adata->acp6x_base);
  232. adata->capture_stream = NULL;
  233. return 0;
  234. }
  235. static int acp6x_pdm_dai_trigger(struct snd_pcm_substream *substream,
  236. int cmd, struct snd_soc_dai *dai)
  237. {
  238. struct pdm_stream_instance *rtd;
  239. int ret;
  240. bool pdm_status;
  241. unsigned int ch_mask;
  242. rtd = substream->runtime->private_data;
  243. ret = 0;
  244. switch (substream->runtime->channels) {
  245. case TWO_CH:
  246. ch_mask = 0x00;
  247. break;
  248. default:
  249. return -EINVAL;
  250. }
  251. switch (cmd) {
  252. case SNDRV_PCM_TRIGGER_START:
  253. case SNDRV_PCM_TRIGGER_RESUME:
  254. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  255. acp6x_writel(ch_mask, rtd->acp6x_base + ACP_WOV_PDM_NO_OF_CHANNELS);
  256. acp6x_writel(PDM_DECIMATION_FACTOR, rtd->acp6x_base +
  257. ACP_WOV_PDM_DECIMATION_FACTOR);
  258. rtd->bytescount = acp6x_pdm_get_byte_count(rtd, substream->stream);
  259. pdm_status = acp6x_check_pdm_dma_status(rtd->acp6x_base);
  260. if (!pdm_status)
  261. ret = acp6x_start_pdm_dma(rtd->acp6x_base);
  262. break;
  263. case SNDRV_PCM_TRIGGER_STOP:
  264. case SNDRV_PCM_TRIGGER_SUSPEND:
  265. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  266. pdm_status = acp6x_check_pdm_dma_status(rtd->acp6x_base);
  267. if (pdm_status)
  268. ret = acp6x_stop_pdm_dma(rtd->acp6x_base);
  269. break;
  270. default:
  271. ret = -EINVAL;
  272. break;
  273. }
  274. return ret;
  275. }
  276. static const struct snd_soc_dai_ops acp6x_pdm_dai_ops = {
  277. .trigger = acp6x_pdm_dai_trigger,
  278. };
  279. static struct snd_soc_dai_driver acp6x_pdm_dai_driver = {
  280. .capture = {
  281. .rates = SNDRV_PCM_RATE_48000,
  282. .formats = SNDRV_PCM_FMTBIT_S32_LE,
  283. .channels_min = 2,
  284. .channels_max = 2,
  285. .rate_min = 48000,
  286. .rate_max = 48000,
  287. },
  288. .ops = &acp6x_pdm_dai_ops,
  289. };
  290. static const struct snd_soc_component_driver acp6x_pdm_component = {
  291. .name = DRV_NAME,
  292. .open = acp6x_pdm_dma_open,
  293. .close = acp6x_pdm_dma_close,
  294. .hw_params = acp6x_pdm_dma_hw_params,
  295. .pointer = acp6x_pdm_dma_pointer,
  296. .pcm_construct = acp6x_pdm_dma_new,
  297. .legacy_dai_naming = 1,
  298. };
  299. static int acp6x_pdm_audio_probe(struct platform_device *pdev)
  300. {
  301. struct resource *res;
  302. struct pdm_dev_data *adata;
  303. int status;
  304. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  305. if (!res) {
  306. dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
  307. return -ENODEV;
  308. }
  309. adata = devm_kzalloc(&pdev->dev, sizeof(*adata), GFP_KERNEL);
  310. if (!adata)
  311. return -ENOMEM;
  312. adata->acp6x_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
  313. if (!adata->acp6x_base)
  314. return -ENOMEM;
  315. adata->capture_stream = NULL;
  316. dev_set_drvdata(&pdev->dev, adata);
  317. status = devm_snd_soc_register_component(&pdev->dev,
  318. &acp6x_pdm_component,
  319. &acp6x_pdm_dai_driver, 1);
  320. if (status) {
  321. dev_err(&pdev->dev, "Fail to register acp pdm dai\n");
  322. return -ENODEV;
  323. }
  324. pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS);
  325. pm_runtime_use_autosuspend(&pdev->dev);
  326. pm_runtime_enable(&pdev->dev);
  327. pm_runtime_allow(&pdev->dev);
  328. return 0;
  329. }
  330. static int acp6x_pdm_audio_remove(struct platform_device *pdev)
  331. {
  332. pm_runtime_disable(&pdev->dev);
  333. return 0;
  334. }
  335. static int __maybe_unused acp6x_pdm_resume(struct device *dev)
  336. {
  337. struct pdm_dev_data *adata;
  338. struct snd_pcm_runtime *runtime;
  339. struct pdm_stream_instance *rtd;
  340. u32 period_bytes, buffer_len;
  341. adata = dev_get_drvdata(dev);
  342. if (adata->capture_stream && adata->capture_stream->runtime) {
  343. runtime = adata->capture_stream->runtime;
  344. rtd = runtime->private_data;
  345. period_bytes = frames_to_bytes(runtime, runtime->period_size);
  346. buffer_len = frames_to_bytes(runtime, runtime->buffer_size);
  347. acp6x_config_dma(rtd, SNDRV_PCM_STREAM_CAPTURE);
  348. acp6x_init_pdm_ring_buffer(PDM_MEM_WINDOW_START, buffer_len,
  349. period_bytes, adata->acp6x_base);
  350. }
  351. acp6x_enable_pdm_interrupts(adata->acp6x_base);
  352. return 0;
  353. }
  354. static int __maybe_unused acp6x_pdm_suspend(struct device *dev)
  355. {
  356. struct pdm_dev_data *adata;
  357. adata = dev_get_drvdata(dev);
  358. acp6x_disable_pdm_interrupts(adata->acp6x_base);
  359. return 0;
  360. }
  361. static int __maybe_unused acp6x_pdm_runtime_resume(struct device *dev)
  362. {
  363. struct pdm_dev_data *adata;
  364. adata = dev_get_drvdata(dev);
  365. acp6x_enable_pdm_interrupts(adata->acp6x_base);
  366. return 0;
  367. }
  368. static const struct dev_pm_ops acp6x_pdm_pm_ops = {
  369. SET_RUNTIME_PM_OPS(acp6x_pdm_suspend, acp6x_pdm_runtime_resume, NULL)
  370. SET_SYSTEM_SLEEP_PM_OPS(acp6x_pdm_suspend, acp6x_pdm_resume)
  371. };
  372. static struct platform_driver acp6x_pdm_dma_driver = {
  373. .probe = acp6x_pdm_audio_probe,
  374. .remove = acp6x_pdm_audio_remove,
  375. .driver = {
  376. .name = "acp_yc_pdm_dma",
  377. .pm = &acp6x_pdm_pm_ops,
  378. },
  379. };
  380. module_platform_driver(acp6x_pdm_dma_driver);
  381. MODULE_AUTHOR("[email protected]");
  382. MODULE_DESCRIPTION("AMD ACP6x YC PDM Driver");
  383. MODULE_LICENSE("GPL v2");
  384. MODULE_ALIAS("platform:" DRV_NAME);