s3c2440的dma操作的一般步驟
一般的,在s3c2440中,要想進行dma傳輸,需要一下七個步驟:
本文引用地址:http://www.ex-cimer.com/article/201611/318126.htm一:
int s3c2410_dma_request(unsigned int channel,
struct s3c2410_dma_client *client,
void *dev)
s3c2410_dma_client的定義為:
struct s3c2410_dma_client {
char *name;
};
以uda1314的驅動為例,驅動中定義了兩個s3c2410_dma_client
static struct s3c2410_dma_client s3c2410iis_dma_out= {
.name = "I2SSDO",
};
static struct s3c2410_dma_client s3c2410iis_dma_in = {
.name = "I2SSDI",
};
二:
s3c2410_dma_config(dmach_t channel,int xferunit,int dcon)
s3c2410_dma_config(dmach_t channel,int xferunit,int dcon)
根據xferunit以及dcon設置通道的控制寄存器DCONx
xferunit為每次傳輸?shù)臄?shù)據大?。?:byte 1:half word 2:word
三:
int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn)
設置相應的dma通道完成一次dma傳輸后的回調函數(shù),也即是s3c2410_dma_enqueue完成后會調用的函數(shù)
回調函數(shù)應具有一下格式:
typedef void (*s3c2410_dma_cbfn_t)(struct s3c2410_dma_chan *,
void *buf, int size,
enum s3c2410_dma_buffresult result);
buf可以傳遞一些有用的數(shù)據,在uda1314的驅動中,傳遞的是audio_buf_t結構體
四:
int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
在1314驅動中,
flags = S3C2410_DMAF_AUTOSTART;
s3c2410_dma_setflags(channel, flags);
五:
int s3c2410_dma_devconfig(int channel,
enum s3c2410_dmasrc source,
int hwcfg,
unsigned long devaddr)
參數(shù)意義:
* source: S3C2410_DMASRC_HW: source is hardware
* S3C2410_DMASRC_MEM: source is memory
*
* hwcfg: the value for xxxSTCn register,
* bit 0: 0=increment pointer, 1=leave pointer
* bit 1: 0=soucre is AHB, 1=soucre is APB
*
* devaddr: physical address of the source
如果source為S3C2410_DMASRC_HW(外設), 配置它的S3C2410_DMA_DISRCC,S3C2410_DMA_DISRC,S3C2410_DMA_DIDSTC
如果source為S3C2410_DMASRC_MEM(內存),配置它的S3C2410_DMA_DISRCC,S3C2410_DMA_DIDST,S3C2410_DMA_DIDSTC
由此可見,地址方面,只配置涉及外設的地址
以uda1341的驅動為例,這幾個值為
source = S3C2410_DMASRC_MEM;
hwcfg = 3;
devaddr = 0x55000010;
六:
void *dma_alloc_coherent(struct device *dev,size_t size,dma_addr_t *dma_handle,int flag)
利用此函數(shù),申請dmabuf,建立一致性映射
以uda1314的驅動為例,調應的實例為:
dmabuf = dma_alloc_coherent(NULL, dmasize, &dmaphys, GFP_KERNEL);(在audio_setup_buf函數(shù)中)
dmabuf為虛擬地址,dmaphys是總線地址,虛擬地址用來讓驅動寫buf用,dmaphys用來傳給dma。
dma關心的是總線地址。
關于總線地址與物理地址的區(qū)別,這里有很好的說明http://hi.baidu.com/zengzhaonong/blog/item/eeb8003083276e9ba9018ee3.html,感謝儒雅,現(xiàn)摘錄如下:
1) 物理地址是與CPU相關的。在CPU的地址信號線上產生的就是物理地址。在程序指令中的虛擬地址經過段映射和頁面映射后,就生成了物理地址,這個物理地址被放到CPU的地址線上。
2) 總線地址,顧名思義,是與總線相關的,就是總線的地址線或在地址周期上產生的信號。外設使用的是總線地址。
3) 物理地址與總線地址之間的關系由系統(tǒng)的設計決定的。在x86平臺上,物理地址與PCI總線地址是相同的。在其他平臺上,也許會有某種轉換,通常是線性的轉換。
比如:CPU需要訪問物理地址是0xfa000的單元,那么在x86平臺上,會產生一個PCI總線上對0xfa000地址的訪問。這個單元或者是內存中,或者是某個卡上的存儲單元,甚至可能這個地址上沒有對應的存儲器。而在另外一個平臺上,或許在PCI總線上產生的訪問是針對地址為0x1fa000的單元。
上述函數(shù)是建立一致性映射。使用dma_map_single函數(shù)可以建立一致性映射:
2.當只有一個緩沖區(qū)要被傳輸?shù)臅r候,使用dma_map_single函數(shù)來映射它
dma_addr_t dma_map_single(struct device *dev,void *buffer,size_t size, enum dma_data_direction direction)
3.為page結構指針指向的緩沖區(qū)建立映射,單頁流式映射:
dma_addr_t dma_map_page(struct device *dev,struct page *page ,unsigned long offset ,size_t size,enum dma_data_direction direction);
4.分散/聚集映射
int dma_map_sg(struct device *dev,struct scatterlist *sg,int nents,enum dma_alloc_coherent direction);
還不知道哪種情況下用流式映射,哪種用一致映射。對于s3c2440,其mmc驅動中用到了分散聚集(流式)映射,聲卡驅動中又用到了一致映射。
七:
int s3c2410_dma_enqueue(unsigned int channel, void *id,
dma_addr_t data, int size)
發(fā)起一次dma傳輸
參數(shù)意義:
* id the device drivers id information for this buffer
* data the physical address of the buffer data
* size the size of the buffer in bytes
將dma_alloc_coherent中得到的dmaphys傳遞給s3c2410_dma_enqueue. s3c2410_dma_enqueue提交一次dma請求,當dma通道可用的時候通過s3c2410_dma_loadbuffer開始一次傳輸,傳輸完成后會產生irq中斷。其dma的中斷服務函數(shù)中會繼續(xù)啟動dma請求隊列中的請求,傳輸剩下的數(shù)據。
評論