2 ahb_dma.c programmed by Ivan Wang
3 AHB dma program for audio 2004/8/13 06:00pm
5 #include <linux/module.h>
7 #include <linux/device.h>
8 #include <linux/dma-mapping.h>
9 #include <linux/dmapool.h>
10 #include <linux/slab.h>
11 #include <asm/types.h>
13 #include <asm/arch/ahb_dma.h>
15 ahb_dma_data_t
*ahb_dma_alloc(void)
18 priv
=(ahb_dma_data_t
*)kmalloc(sizeof(ahb_dma_data_t
), GFP_KERNEL
);
22 void ahb_dma_free(ahb_dma_data_t
*priv
)
26 size
=sizeof(ahb_lld_t
)*(priv
->llp_count
);
27 if(priv
->ahb_dma_lld
) {
28 #if 0 // mask by Victor Yu. 05-19-2005
29 consistent_free((void *)priv
->ahb_dma_lld
,size
,(dma_addr_t
)priv
->ahb_dma_lld_phys
);
30 //printk("free 0x%x whit 0x%x size 0x%x\n",priv->ahb_dma_lld,priv->ahb_dma_lld_phys,size);
31 #else // add by Victor Yu. 05-19-2005
32 dma_free_coherent(NULL
, size
, (void *)priv
->ahb_dma_lld
, (dma_addr_t
)priv
->ahb_dma_lld_phys
);
41 base: base address of ahb dma
42 llp_master: LLP master channel number
43 src_data_master: source data channel number
44 dest_data_master: dest data channel number
46 channel: ahb dma channel
47 hw is it hardware handshake?
49 int ahb_dma_init(ahb_dma_data_t
*priv
)
53 ahb_lld_t
*lld_phys
=0;
56 printk("NULL priv data!\n");
61 size
=sizeof(ahb_lld_t
)*(priv
->llp_count
);
62 #if 0 // mask by Victor Yu. 05-19-2005
63 priv
->ahb_dma_lld
=(ahb_lld_t
*)consistent_alloc(GFP_DMA
|GFP_KERNEL
,
64 size
,(dma_addr_t
*)&priv
->ahb_dma_lld_phys
);
65 //printk("priv->ahb_dma_lld=0x%x phys=0x%x size=0x%x\n",(int)priv->ahb_dma_lld,(int)priv->ahb_dma_lld_phys,size);
66 #else // add by Victor Yu. 05-19-2005
67 priv
->ahb_dma_lld
= dma_alloc_coherent(NULL
, size
, (dma_addr_t
*)&priv
->ahb_dma_lld_phys
, GFP_DMA
|GFP_KERNEL
);
69 if(priv
->ahb_dma_lld
==0) {
70 printk("ahb_dma_lld allocate memory fail!\n");
75 priv
->channel_base
=(priv
->base
)+0x100+((priv
->channel
)*0x20);
80 lld
=priv
->ahb_dma_lld
;
81 lld_phys
=priv
->ahb_dma_lld_phys
;
82 /* initialize value */
83 for(i
=0;i
<priv
->llp_count
;i
++) {
84 lld
[i
].source
=0; //source
85 lld
[i
].dest
=0; //dest,16bit
88 if(i
==priv
->llp_count
-1)
91 lld
[i
].llp
=(unsigned int)(&lld_phys
[i
+1])|(priv
->llp_master
); //use second channel
92 //printk("ahb_dma_lld[%d].llp\n",i,ahb_dma_lld[i].llp);
95 *(unsigned int *)(priv
->channel_base
+AHBDMA_CHANNEL_LLP_0x10
)=0;
96 *(unsigned int *)(priv
->channel_base
+AHBDMA_CHANNEL_CFG_0x4
)=0x0; //enabled all interrupt
97 *(unsigned int *)(priv
->base
+AHBDMA_ENABLE_0x24
)=0x1; //enable DMA controller
98 *(unsigned int *)(priv
->channel_base
+AHBDMA_CHANNEL_CSR_0x0
)=0;
103 LLP count =3 (example)
110 sw: source width (0/1/2=>8/16/32)
111 dw: dest width (0/1/2=>8/16/32)
112 sctl: source control (0/1/2/3=>inc/dec/fix/x)
113 dctl: dest coontrol (0/1/2/3=>inc/dec/fix/x)
115 irq: (0/1)==>(disable/enable)
117 void ahb_dma_add(ahb_dma_data_t
*priv
,ahb_dma_parm_t
*parm
)
123 //printk("add priv=0x%x\n",priv);
124 lld
=priv
->ahb_dma_lld
;
125 lld_phys
=priv
->ahb_dma_lld_phys
;
127 if(priv
->llp_free_idx
==0) { //first to call ahb_dma_add
128 *(unsigned int *)(priv
->channel_base
+AHBDMA_CHANNEL_TXSZ_0x14
)=parm
->size
;
129 *(unsigned int *)(priv
->channel_base
+AHBDMA_CHANNEL_SRC_0x8
)=parm
->src
;
130 *(unsigned int *)(priv
->channel_base
+AHBDMA_CHANNEL_DST_0xC
)=parm
->dest
;
132 if (priv
->llp_count
== 0)
133 *(unsigned int *)(priv
->channel_base
+AHBDMA_CHANNEL_LLP_0x10
)= 0; //john modified, for no LLP
135 *(unsigned int *)(priv
->channel_base
+AHBDMA_CHANNEL_LLP_0x10
)=
136 (unsigned int)(&lld_phys
[0])|priv
->llp_master
;
138 val
=(((1-(parm
->irq
))<<31)&0x80000000)|
139 ((parm
->sw
<<11)&0x00003800)|((parm
->dw
<<8)&0x00000700)|
140 ((priv
->hw_handshake
<<7)&0x00000080)|
141 ((parm
->sctl
<<5)&0x00000060)|((parm
->dctl
<<3)&0x00000018)|
142 ((priv
->src_data_master
<<2)&0x4)|
143 ((priv
->dest_data_master
<<1)&0x2);
144 *(unsigned int *)(priv
->channel_base
+AHBDMA_CHANNEL_CSR_0x0
)=val
;
146 val
=((parm
->irq
<<28)&0x10000000)|
147 ((parm
->sw
<<25)&0x0e000000)|((parm
->dw
<<22)&0x01c00000)|
148 ((parm
->sctl
<<20)&0x00300000)|((parm
->dctl
<<18)&0x000c0000)|
149 ((priv
->src_data_master
<<17)&0x00020000)|
150 ((priv
->dest_data_master
<<16)&0x00010000)|(parm
->size
);
151 lld
[priv
->llp_free_idx
-1].source
=parm
->src
;
152 lld
[priv
->llp_free_idx
-1].dest
=parm
->dest
;
153 lld
[priv
->llp_free_idx
-1].control
=val
;
154 lld
[priv
->llp_free_idx
-1].llp
=0;
156 if(priv
->ahb_last_lld
)
157 priv
->ahb_last_lld
->llp
=(unsigned int)(&lld_phys
[priv
->llp_free_idx
-1])|priv
->llp_master
;
158 priv
->ahb_last_lld
=&lld
[priv
->llp_free_idx
-1];
161 if (priv
->llp_count
) { //john add check
162 if(priv
->llp_free_idx
==priv
->llp_count
)
163 priv
->llp_free_idx
=1;
165 priv
->llp_free_idx
++;
169 inline void ahb_dma_start(ahb_dma_data_t
*priv
)
171 *(volatile unsigned int *)(priv
->channel_base
+AHBDMA_CHANNEL_CSR_0x0
)|=0x1;
174 void ahb_dma_reset(ahb_dma_data_t
*priv
)
176 priv
->llp_last_idx
=0;
177 priv
->llp_free_idx
=0;
178 priv
->ahb_last_lld
=0;
180 //printk("ahb_dma_stop\n");
181 *(unsigned int *)(priv
->base
+AHBDMA_ENABLE_0x24
)=0; //disable DMA controller
182 *(unsigned int *)(priv
->channel_base
+AHBDMA_CHANNEL_CSR_0x0
)=0; //disable DMA channel 0
183 *(unsigned int *)(priv
->channel_base
+AHBDMA_CHANNEL_LLP_0x10
)=0;
184 *(unsigned int *)(priv
->channel_base
+AHBDMA_CHANNEL_TXSZ_0x14
)=0; //no transfer size (use LLP)
185 *(unsigned int *)(priv
->channel_base
+AHBDMA_CHANNEL_CFG_0x4
)=0; //disable all interrupt
188 inline void ahbdma_clear_int(ahb_dma_data_t
*priv
)
190 *(volatile unsigned int *)(priv
->base
+AHBDMA_ISR_0x8
)=1<<(priv
->channel
);
193 //john add, get ext DMA address
194 // so we can get DMA lenth
195 inline u32
ahbdma_get_dest_addr(ahb_dma_data_t
*priv
)
197 return *(volatile u32
*)(priv
->channel_base
+AHBDMA_CHANNEL_DST_0xC
);
200 // John add, to get interrupt status
201 // Bit 0 indicate interrupt created,
202 // bit 1 indicate interrupt error
203 u32
ahbdma_get_status(ahb_dma_data_t
*priv
)
208 temp
= *(volatile u32
*)(priv
->base
+AHBDMA_INT_ERR_0x0C
);
209 if ( temp
& (1<<(priv
->channel
)) )
210 status
|= INT_ERROR
; //error
212 temp
= *(volatile u32
*)(priv
->base
+AHBDMA_INT_TC_0x04
);
213 if ( temp
& (1<<(priv
->channel
)) )
214 status
|= INT_TRIGGER
; //complete