歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> ALSA 驅動中dma的配置

ALSA 驅動中dma的配置

日期:2017/3/1 10:16:17   编辑:Linux編程

ALSA 驅動中dma的配置:

  1. /*
  2. * prepare DMA for pcm
  3. */
  4. int i2s_dma_prepare(struct snd_pcm_substream *substream)
  5. {
  6. struct snd_pcm_runtime *runtime = substream->runtime;
  7. struct sep0611_runtime_data *prtd = runtime->private_data;
  8. struct dma_info *p_dma_info;
  9. unsigned long i2s_fifo_width = 1; /* 16 bits in default */
  10. int ret;
  11. /* we need call the i2s_dma_prepare after set hw_params, such as in pcm_prepare */
  12. if(runtime->format == 0){
  13. printk("ERR:please ensure the hw_params has been set correctly\n");
  14. return -EINVAL;
  15. }
  16. p_dma_info = kmalloc(sizeof(struct dma_info), GFP_KERNEL);
  17. if(!p_dma_info){
  18. return -ENOMEM;
  19. }
  20. if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
  21. p_dma_info->trans_type = MEM_TO_DEV;
  22. p_dma_info->src_addr = prtd->dma_buffer;
  23. p_dma_info->dst_addr = I2S_BASE + I2S_TXDMA;
  24. /*
  25. * match with tx data of (S16_LE | S20_3LE | S24_3LE | S32_LE)
  26. */
  27. if(runtime->format != SNDRV_PCM_FORMAT_S16_LE)
  28. i2s_fifo_width = 2;
  29. /* CTLx and CFGx */
  30. p_dma_info->ctrl_hi = DMAC_DONE (0) | DMAC_BLK_TRAN_SZ(prtd->period_len/8);
  31. p_dma_info->ctrl_lo = DMAC_SRC_LLP_EN (1) | DMAC_DST_LLP_EN (0) | DMAC_SRC_MASTER_SEL(0)\
  32. | DMAC_DST_MASTER_SEL(1)| DMAC_TRAN_TYPE_FLOW_CTL(1)| DMAC_DST_SCAT_EN (0) \
  33. | DMAC_SRC_GATH_EN (0)| DMAC_SRC_BST_SZ (2)| DMAC_DST_BST_SZ (3) \
  34. | DMAC_SRC_INCR (0)| DMAC_DST_INCR (3)| DMAC_SRC_TRAN_WIDTH(3)\
  35. | DMAC_DST_TRAN_WIDTH(i2s_fifo_width) | DMAC_INT_EN(1);
  36. p_dma_info->cfg_hi = DMAC_DST_PER (7) | DMAC_SRC_PER (6) | DMAC_SRC_STAT_UPD_EN(0) \
  37. | DMAC_DST_STAT_UPD_EN(0) | DMAC_PROT_CTL (1) | DMAC_FIFO_MODE(0) \
  38. | DMAC_FLOW_CTL_MODE (0);
  39. p_dma_info->cfg_lo = DMAC_AUTO_RELOAD_DST(0) | DMAC_AUTO_RELOAD_SRC(0) | DMAC_MAX_AMBA_BST_LEN(0) \
  40. | DMAC_SRC_HS_POL (0) | DMAC_DST_HS_POL (0) | DMAC_BUS_LOCK (0) \
  41. | DMAC_CH_LOCK (0) | DMAC_BUS_LOCK_LEVEL(1)| DMAC_HW_SW_SEL_SRC (1) \
  42. | DMAC_HW_SW_SEL_DST (0) | DMAC_CH_SUSP (0) | DMAC_CH_PRIOR (0);
  43. }
  44. else{
  45. p_dma_info->trans_type = DEV_TO_MEM;
  46. p_dma_info->src_addr = I2S_BASE + I2S_RXDMA;
  47. p_dma_info->dst_addr = prtd->dma_buffer;
  48. /* CTLx and CFGx */
  49. p_dma_info->ctrl_hi = DMAC_DONE(0) | DMAC_BLK_TRAN_SZ(prtd->period_len/2);
  50. p_dma_info->ctrl_lo = DMAC_SRC_LLP_EN (0)| DMAC_DST_LLP_EN (1) | DMAC_SRC_MASTER_SEL (1) \
  51. | DMAC_DST_MASTER_SEL(0) | DMAC_TRAN_TYPE_FLOW_CTL(2) | DMAC_DST_SCAT_EN (0) \
  52. | DMAC_SRC_GATH_EN (0) | DMAC_SRC_BST_SZ (2) | DMAC_DST_BST_SZ (3) \
  53. | DMAC_SRC_INCR (3) | DMAC_DST_INCR (0) | DMAC_SRC_TRAN_WIDTH (i2s_fifo_width) \
  54. | DMAC_DST_TRAN_WIDTH(2) | DMAC_INT_EN(1);
  55. p_dma_info->cfg_hi = DMAC_DST_PER(7) | DMAC_SRC_PER(6) | DMAC_SRC_STAT_UPD_EN(0) \
  56. | DMAC_DST_STAT_UPD_EN(0) | DMAC_PROT_CTL (1) | DMAC_FIFO_MODE (0) \
  57. | DMAC_FLOW_CTL_MODE (0);
  58. p_dma_info->cfg_lo = DMAC_AUTO_RELOAD_DST(0) | DMAC_AUTO_RELOAD_SRC(0) | DMAC_MAX_AMBA_BST_LEN(0) \
  59. | DMAC_SRC_HS_POL (0) | DMAC_DST_HS_POL (0) | DMAC_BUS_LOCK (0) \
  60. | DMAC_CH_LOCK (0) | DMAC_BUS_LOCK_LEVEL (1) | DMAC_HW_SW_SEL_SRC (0) \
  61. | DMAC_HW_SW_SEL_DST (1) | DMAC_CH_SUSP (0) | DMAC_CH_PRIOR (0);
  62. }
  63. /* store p_dma_info in prtd */
  64. prtd->dma_info = p_dma_info;
  65. ret = <SPAN style="BACKGROUND-COLOR: rgb(255,255,255)">set_dma_cll</SPAN>(p_dma_info, prtd->buffer_len, prtd->period_len);
  66. if(ret < 0){
  67. return -ENOMEM;
  68. }
  69. load_first_llp(prtd->dma_info, prtd->dma_params->channel);
  70. return 0;
  71. }

其中函數set_dma_cll是設置dma鏈的,dma傳輸時用戶空間的buffer大小為64k,分為16個塊(block),每個塊為4k,dma啟用多塊傳輸,當一個塊傳輸完成後,都會會寫剛剛使用的那個LLI中的CTL寄存器中的高32位,將其中的第13位置1,並且會產生塊傳輸完成中斷,中斷處理程序會通知上層,往bufffer裡寫數據。dma鏈如下所示。

Copyright © Linux教程網 All Rights Reserved