44//
55// Copyright (C) 2023 Loongson Technology Corporation Limited
66// Author: Yingkun Meng <mengyingkun@loongson.cn>
7+ // Binbin ZHou <zhoubinbin@loongson.cn>
78//
89
910#include <linux/module.h>
1617#include <sound/pcm_params.h>
1718#include "loongson_i2s.h"
1819
19- /* DMA dma_order Register */
20+ /* Internal DMA dma_order Register */
2021#define DMA_ORDER_STOP BIT(4) /* DMA stop */
2122#define DMA_ORDER_START BIT(3) /* DMA start */
2223#define DMA_ORDER_ASK_VALID BIT(2) /* DMA ask valid flag */
2728#define DMA_ORDER_CTRL_MASK (0x0fUL) /* Control mask */
2829
2930/*
30- * DMA registers descriptor.
31+ * Internal DMA registers descriptor.
3132 */
32- struct loongson_dma_desc {
33+ struct loongson_idma_desc {
3334 u32 order ; /* Next descriptor address register */
3435 u32 saddr ; /* Source address register */
3536 u32 daddr ; /* Device address register */
@@ -44,17 +45,17 @@ struct loongson_dma_desc {
4445} __packed ;
4546
4647struct loongson_runtime_data {
47- struct loongson_dma_data * dma_data ;
48+ struct loongson_idma_data * dma_data ;
4849
49- struct loongson_dma_desc * dma_desc_arr ;
50+ struct loongson_idma_desc * dma_desc_arr ;
5051 dma_addr_t dma_desc_arr_phy ;
5152 int dma_desc_arr_size ;
5253
53- struct loongson_dma_desc * dma_pos_desc ;
54+ struct loongson_idma_desc * dma_pos_desc ;
5455 dma_addr_t dma_pos_desc_phy ;
5556};
5657
57- static const struct snd_pcm_hardware ls_pcm_hardware = {
58+ static const struct snd_pcm_hardware loongson_idma_hardware = {
5859 .info = SNDRV_PCM_INFO_MMAP |
5960 SNDRV_PCM_INFO_INTERLEAVED |
6061 SNDRV_PCM_INFO_MMAP_VALID |
@@ -67,12 +68,11 @@ static const struct snd_pcm_hardware ls_pcm_hardware = {
6768 .period_bytes_min = 128 ,
6869 .period_bytes_max = 128 * 1024 ,
6970 .periods_min = 1 ,
70- .periods_max = PAGE_SIZE / sizeof (struct loongson_dma_desc ),
71+ .periods_max = PAGE_SIZE / sizeof (struct loongson_idma_desc ),
7172 .buffer_bytes_max = 1024 * 1024 ,
7273};
7374
74- static struct
75- loongson_dma_desc * dma_desc_save (struct loongson_runtime_data * prtd )
75+ static struct loongson_idma_desc * dma_desc_save (struct loongson_runtime_data * prtd )
7676{
7777 void __iomem * order_reg = prtd -> dma_data -> order_addr ;
7878 u64 val ;
@@ -88,8 +88,8 @@ loongson_dma_desc *dma_desc_save(struct loongson_runtime_data *prtd)
8888 return prtd -> dma_pos_desc ;
8989}
9090
91- static int loongson_pcm_trigger (struct snd_soc_component * component ,
92- struct snd_pcm_substream * substream , int cmd )
91+ static int loongson_idma_pcm_trigger (struct snd_soc_component * component ,
92+ struct snd_pcm_substream * substream , int cmd )
9393{
9494 struct loongson_runtime_data * prtd = substream -> runtime -> private_data ;
9595 struct device * dev = substream -> pcm -> card -> dev ;
@@ -131,17 +131,17 @@ static int loongson_pcm_trigger(struct snd_soc_component *component,
131131 return 0 ;
132132}
133133
134- static int loongson_pcm_hw_params (struct snd_soc_component * component ,
135- struct snd_pcm_substream * substream ,
136- struct snd_pcm_hw_params * params )
134+ static int loongson_idma_pcm_hw_params (struct snd_soc_component * component ,
135+ struct snd_pcm_substream * substream ,
136+ struct snd_pcm_hw_params * params )
137137{
138138 struct snd_pcm_runtime * runtime = substream -> runtime ;
139139 struct device * dev = substream -> pcm -> card -> dev ;
140140 struct loongson_runtime_data * prtd = runtime -> private_data ;
141141 size_t buf_len = params_buffer_bytes (params );
142142 size_t period_len = params_period_bytes (params );
143143 dma_addr_t order_addr , mem_addr ;
144- struct loongson_dma_desc * desc ;
144+ struct loongson_idma_desc * desc ;
145145 u32 num_periods ;
146146 int i ;
147147
@@ -195,12 +195,12 @@ static int loongson_pcm_hw_params(struct snd_soc_component *component,
195195}
196196
197197static snd_pcm_uframes_t
198- loongson_pcm_pointer (struct snd_soc_component * component ,
199- struct snd_pcm_substream * substream )
198+ loongson_idma_pcm_pointer (struct snd_soc_component * component ,
199+ struct snd_pcm_substream * substream )
200200{
201201 struct snd_pcm_runtime * runtime = substream -> runtime ;
202202 struct loongson_runtime_data * prtd = runtime -> private_data ;
203- struct loongson_dma_desc * desc ;
203+ struct loongson_idma_desc * desc ;
204204 snd_pcm_uframes_t x ;
205205 u64 addr ;
206206
@@ -213,22 +213,22 @@ loongson_pcm_pointer(struct snd_soc_component *component,
213213 return x ;
214214}
215215
216- static irqreturn_t loongson_pcm_dma_irq (int irq , void * devid )
216+ static irqreturn_t loongson_idma_pcm_dma_irq (int irq , void * devid )
217217{
218218 struct snd_pcm_substream * substream = devid ;
219219
220220 snd_pcm_period_elapsed (substream );
221221 return IRQ_HANDLED ;
222222}
223223
224- static int loongson_pcm_open (struct snd_soc_component * component ,
225- struct snd_pcm_substream * substream )
224+ static int loongson_idma_pcm_open (struct snd_soc_component * component ,
225+ struct snd_pcm_substream * substream )
226226{
227227 struct snd_pcm_runtime * runtime = substream -> runtime ;
228228 struct snd_soc_pcm_runtime * rtd = snd_soc_substream_to_rtd (substream );
229229 struct snd_card * card = substream -> pcm -> card ;
230230 struct loongson_runtime_data * prtd ;
231- struct loongson_dma_data * dma_data ;
231+ struct loongson_idma_data * dma_data ;
232232
233233 /*
234234 * For mysterious reasons (and despite what the manual says)
@@ -241,7 +241,7 @@ static int loongson_pcm_open(struct snd_soc_component *component,
241241 SNDRV_PCM_HW_PARAM_BUFFER_BYTES , 128 );
242242 snd_pcm_hw_constraint_integer (substream -> runtime ,
243243 SNDRV_PCM_HW_PARAM_PERIODS );
244- snd_soc_set_runtime_hwparams (substream , & ls_pcm_hardware );
244+ snd_soc_set_runtime_hwparams (substream , & loongson_idma_hardware );
245245
246246 prtd = kzalloc_obj (* prtd );
247247 if (!prtd )
@@ -277,8 +277,8 @@ static int loongson_pcm_open(struct snd_soc_component *component,
277277 return - ENOMEM ;
278278}
279279
280- static int loongson_pcm_close (struct snd_soc_component * component ,
281- struct snd_pcm_substream * substream )
280+ static int loongson_idma_pcm_close (struct snd_soc_component * component ,
281+ struct snd_pcm_substream * substream )
282282{
283283 struct snd_card * card = substream -> pcm -> card ;
284284 struct loongson_runtime_data * prtd = substream -> runtime -> private_data ;
@@ -293,21 +293,21 @@ static int loongson_pcm_close(struct snd_soc_component *component,
293293 return 0 ;
294294}
295295
296- static int loongson_pcm_mmap (struct snd_soc_component * component ,
297- struct snd_pcm_substream * substream ,
298- struct vm_area_struct * vma )
296+ static int loongson_idma_pcm_mmap (struct snd_soc_component * component ,
297+ struct snd_pcm_substream * substream ,
298+ struct vm_area_struct * vma )
299299{
300300 return remap_pfn_range (vma , vma -> vm_start ,
301- substream -> dma_buffer .addr >> PAGE_SHIFT ,
302- vma -> vm_end - vma -> vm_start , vma -> vm_page_prot );
301+ substream -> dma_buffer .addr >> PAGE_SHIFT ,
302+ vma -> vm_end - vma -> vm_start , vma -> vm_page_prot );
303303}
304304
305- static int loongson_pcm_new (struct snd_soc_component * component ,
306- struct snd_soc_pcm_runtime * rtd )
305+ static int loongson_idma_pcm_new (struct snd_soc_component * component ,
306+ struct snd_soc_pcm_runtime * rtd )
307307{
308308 struct snd_card * card = rtd -> card -> snd_card ;
309309 struct snd_pcm_substream * substream ;
310- struct loongson_dma_data * dma_data ;
310+ struct loongson_idma_data * dma_data ;
311311 unsigned int i ;
312312 int ret ;
313313
@@ -319,7 +319,7 @@ static int loongson_pcm_new(struct snd_soc_component *component,
319319 dma_data = snd_soc_dai_get_dma_data (snd_soc_rtd_to_cpu (rtd , 0 ),
320320 substream );
321321 ret = devm_request_irq (card -> dev , dma_data -> irq ,
322- loongson_pcm_dma_irq ,
322+ loongson_idma_pcm_dma_irq ,
323323 IRQF_TRIGGER_HIGH , LS_I2S_DRVNAME ,
324324 substream );
325325 if (ret < 0 ) {
@@ -330,16 +330,76 @@ static int loongson_pcm_new(struct snd_soc_component *component,
330330
331331 return snd_pcm_set_fixed_buffer_all (rtd -> pcm , SNDRV_DMA_TYPE_DEV ,
332332 card -> dev ,
333- ls_pcm_hardware .buffer_bytes_max );
333+ loongson_idma_hardware .buffer_bytes_max );
334334}
335335
336- const struct snd_soc_component_driver loongson_i2s_component = {
336+ /* Internal DMA component */
337+ const struct snd_soc_component_driver loongson_i2s_idma_component = {
337338 .name = LS_I2S_DRVNAME ,
338- .open = loongson_pcm_open ,
339- .close = loongson_pcm_close ,
340- .hw_params = loongson_pcm_hw_params ,
341- .trigger = loongson_pcm_trigger ,
342- .pointer = loongson_pcm_pointer ,
343- .mmap = loongson_pcm_mmap ,
344- .pcm_new = loongson_pcm_new ,
339+ .open = loongson_idma_pcm_open ,
340+ .close = loongson_idma_pcm_close ,
341+ .hw_params = loongson_idma_pcm_hw_params ,
342+ .trigger = loongson_idma_pcm_trigger ,
343+ .pointer = loongson_idma_pcm_pointer ,
344+ .mmap = loongson_idma_pcm_mmap ,
345+ .pcm_new = loongson_idma_pcm_new ,
346+ };
347+ EXPORT_SYMBOL_GPL (loongson_i2s_idma_component );
348+
349+ static const struct snd_pcm_hardware loongson_edma_hardware = {
350+ .info = SNDRV_PCM_INFO_MMAP |
351+ SNDRV_PCM_INFO_INTERLEAVED |
352+ SNDRV_PCM_INFO_MMAP_VALID |
353+ SNDRV_PCM_INFO_RESUME |
354+ SNDRV_PCM_INFO_PAUSE ,
355+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
356+ SNDRV_PCM_FMTBIT_S20_3LE |
357+ SNDRV_PCM_FMTBIT_S24_LE ,
358+ .period_bytes_min = 128 ,
359+ .period_bytes_max = 128 * 1024 ,
360+ .periods_min = 1 ,
361+ .periods_max = 64 ,
362+ .buffer_bytes_max = 1024 * 1024 ,
363+ };
364+
365+ const struct snd_dmaengine_pcm_config loongson_dmaengine_pcm_config = {
366+ .pcm_hardware = & loongson_edma_hardware ,
367+ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config ,
368+ .prealloc_buffer_size = 128 * 1024 ,
369+ };
370+ EXPORT_SYMBOL_GPL (loongson_dmaengine_pcm_config );
371+
372+ /* External DMA component */
373+ static int loongson_edma_pcm_open (struct snd_soc_component * component ,
374+ struct snd_pcm_substream * substream )
375+ {
376+ struct snd_pcm_runtime * runtime = substream -> runtime ;
377+
378+ if (substream -> pcm -> device & 1 ) {
379+ runtime -> hw .info &= ~SNDRV_PCM_INFO_INTERLEAVED ;
380+ runtime -> hw .info |= SNDRV_PCM_INFO_NONINTERLEAVED ;
381+ }
382+
383+ if (substream -> pcm -> device & 2 )
384+ runtime -> hw .info &= ~(SNDRV_PCM_INFO_MMAP |
385+ SNDRV_PCM_INFO_MMAP_VALID );
386+ /*
387+ * For mysterious reasons (and despite what the manual says)
388+ * playback samples are lost if the DMA count is not a multiple
389+ * of the DMA burst size. Let's add a rule to enforce that.
390+ */
391+ snd_pcm_hw_constraint_step (runtime , 0 ,
392+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES , 128 );
393+ snd_pcm_hw_constraint_step (runtime , 0 ,
394+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES , 128 );
395+ snd_pcm_hw_constraint_integer (substream -> runtime ,
396+ SNDRV_PCM_HW_PARAM_PERIODS );
397+
398+ return 0 ;
399+ }
400+
401+ const struct snd_soc_component_driver loongson_i2s_edma_component = {
402+ .name = LS_I2S_DRVNAME ,
403+ .open = loongson_edma_pcm_open ,
345404};
405+ EXPORT_SYMBOL_GPL (loongson_i2s_edma_component );
0 commit comments