MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / arch / arm / mach-moxacpu / ahb_dma.c
blobad72a9c50aa4a0cb96fcd1d50ae7287ee8c8daf7
1 /*
2 ahb_dma.c programmed by Ivan Wang
3 AHB dma program for audio 2004/8/13 06:00pm
4 */
5 #include <linux/module.h>
6 #include <linux/mm.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>
12 #include <asm/io.h>
13 #include <asm/arch/ahb_dma.h>
15 ahb_dma_data_t *ahb_dma_alloc(void)
17 ahb_dma_data_t *priv;
18 priv=(ahb_dma_data_t *)kmalloc(sizeof(ahb_dma_data_t), GFP_KERNEL);
19 return priv;
22 void ahb_dma_free(ahb_dma_data_t *priv)
24 int size;
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);
33 #endif
35 ahb_dma_reset(priv);
36 kfree(priv);
39 /*
40 You must given:
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
45 llp_count: LLP count
46 channel: ahb dma channel
47 hw is it hardware handshake?
49 int ahb_dma_init(ahb_dma_data_t *priv)
51 int i,size;
52 ahb_lld_t *lld=0;
53 ahb_lld_t *lld_phys=0;
55 if(priv==0) {
56 printk("NULL priv data!\n");
57 return 0;
60 if(priv->llp_count) {
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);
68 #endif
69 if(priv->ahb_dma_lld==0) {
70 printk("ahb_dma_lld allocate memory fail!\n");
71 return 0;
75 priv->channel_base=(priv->base)+0x100+((priv->channel)*0x20);
76 priv->llp_last_idx=0;
77 priv->llp_free_idx=0;
78 priv->ahb_last_lld=0;
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
86 lld[i].control=0;
88 if(i==priv->llp_count-1)
89 lld[i].llp=0;
90 else
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;
99 return 1;
103 LLP count =3 (example)
104 0 => 1 => 2 => 3
106 +---------+
107 You must prepared:
108 src: source address
109 dest:dest address
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)
114 size: dma count
115 irq: (0/1)==>(disable/enable)
117 void ahb_dma_add(ahb_dma_data_t *priv,ahb_dma_parm_t *parm)
119 unsigned int val;
120 ahb_lld_t *lld;
121 ahb_lld_t *lld_phys;
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
134 else
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;
145 } else {
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;
164 else
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)
205 u32 status=0;
206 u32 temp;
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
216 return status;