歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

ALSA 驅動中dma的配置

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

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

Copyright © Linux教程網 All Rights Reserved