MOXA linux-2.6.x / linux-2.6.19-uc1 from UC-7110-LX-BOOTLOADER-1.9_VERSION-4.2.tgz
[linux-2.6.19-moxart.git] / arch / arm / mach-moxart / ahb_dma.c
blob975e82316984bcd92c5ac2db8c67cf0ab5ef74ec
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/slab.h>
8 #include <asm/types.h>
9 #include <asm/io.h>
10 #include <asm/arch/ahb_dma.h>
13 ahb_dma_data_t *ahb_dma_alloc(void)
15 ahb_dma_data_t *priv;
16 priv=(ahb_dma_data_t *)kmalloc(sizeof(ahb_dma_data_t), GFP_KERNEL);
17 return priv;
20 void ahb_dma_free(ahb_dma_data_t *priv)
22 int size;
23 size=sizeof(ahb_lld_t)*(priv->llp_count);
24 if(priv->ahb_dma_lld)
26 consistent_free((void *)priv->ahb_dma_lld,size,(dma_addr_t)priv->ahb_dma_lld_phys);
27 //printk("free 0x%x whit 0x%x size 0x%x\n",priv->ahb_dma_lld,priv->ahb_dma_lld_phys,size);
29 ahb_dma_reset(priv);
30 kfree(priv);
33 /*
34 You must given:
35 base: base address of ahb dma
36 llp_master: LLP master channel number
37 src_data_master: source data channel number
38 dest_data_master: dest data channel number
39 llp_count: LLP count
40 channel: ahb dma channel
41 hw is it hardware handshake?
43 int ahb_dma_init(ahb_dma_data_t *priv)
45 int i,size;
46 ahb_lld_t *lld=0;
47 ahb_lld_t *lld_phys=0;
49 if(priv==0)
51 printk("NULL priv data!\n");
52 return 0;
55 if(priv->llp_count)
57 size=sizeof(ahb_lld_t)*(priv->llp_count);
58 priv->ahb_dma_lld=(ahb_lld_t *)consistent_alloc(GFP_DMA|GFP_KERNEL,
59 size,(dma_addr_t *)&priv->ahb_dma_lld_phys);
60 //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);
61 if(priv->ahb_dma_lld==0)
63 printk("ahb_dma_lld allocate memory fail!\n");
64 return 0;
68 priv->channel_base=(priv->base)+0x100+((priv->channel)*0x20);
69 priv->llp_last_idx=0;
70 priv->llp_free_idx=0;
71 priv->ahb_last_lld=0;
73 lld=priv->ahb_dma_lld;
74 lld_phys=priv->ahb_dma_lld_phys;
75 /* initialize value */
76 for(i=0;i<priv->llp_count;i++)
78 lld[i].source=0; //source
79 lld[i].dest=0; //dest,16bit
80 lld[i].control=0;
82 if(i==priv->llp_count-1)
83 lld[i].llp=0;
84 else
85 lld[i].llp=(unsigned int)(&lld_phys[i+1])|(priv->llp_master); //use second channel
86 //printk("ahb_dma_lld[%d].llp\n",i,ahb_dma_lld[i].llp);
89 *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_LLP_0x10)=0;
90 *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_CFG_0x4)=0x0; //enabled all interrupt
91 *(unsigned int *)(priv->base+AHBDMA_ENABLE_0x24)=0x1; //enable DMA controller
92 *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_CSR_0x0)=0;
93 return 1;
97 LLP count =3 (example)
98 0 => 1 => 2 => 3
99 ^ |
100 +---------+
101 You must prepared:
102 src: source address
103 dest:dest address
104 sw: source width (0/1/2=>8/16/32)
105 dw: dest width (0/1/2=>8/16/32)
106 sctl: source control (0/1/2/3=>inc/dec/fix/x)
107 dctl: dest coontrol (0/1/2/3=>inc/dec/fix/x)
108 size: dma count
109 irq: (0/1)==>(disable/enable)
111 void ahb_dma_add(ahb_dma_data_t *priv,ahb_dma_parm_t *parm)
113 unsigned int val;
114 ahb_lld_t *lld;
115 ahb_lld_t *lld_phys;
116 //printk("add priv=0x%x\n",priv);
117 lld=priv->ahb_dma_lld;
118 lld_phys=priv->ahb_dma_lld_phys;
120 if(priv->llp_free_idx==0) //first to call ahb_dma_add
122 *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_TXSZ_0x14)=parm->size;
123 *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_SRC_0x8)=parm->src;
124 *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_DST_0xC)=parm->dest;
126 if (priv->llp_count == 0)
127 *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_LLP_0x10)= 0; //john modified, for no LLP
128 else
129 *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_LLP_0x10)=
130 (unsigned int)(&lld_phys[0])|priv->llp_master;
132 val=(((1-(parm->irq))<<31)&0x80000000)|
133 ((parm->sw<<11)&0x00003800)|((parm->dw<<8)&0x00000700)|
134 ((priv->hw_handshake<<7)&0x00000080)|
135 ((parm->sctl<<5)&0x00000060)|((parm->dctl<<3)&0x00000018)|
136 ((priv->src_data_master<<2)&0x4)|
137 ((priv->dest_data_master<<1)&0x2);
138 *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_CSR_0x0)=val;
140 else
142 val=((parm->irq<<28)&0x10000000)|
143 ((parm->sw<<25)&0x0e000000)|((parm->dw<<22)&0x01c00000)|
144 ((parm->sctl<<20)&0x00300000)|((parm->dctl<<18)&0x000c0000)|
145 ((priv->src_data_master<<17)&0x00020000)|
146 ((priv->dest_data_master<<16)&0x00010000)|(parm->size);
147 lld[priv->llp_free_idx-1].source=parm->src;
148 lld[priv->llp_free_idx-1].dest=parm->dest;
149 lld[priv->llp_free_idx-1].control=val;
150 lld[priv->llp_free_idx-1].llp=0;
152 if(priv->ahb_last_lld)
153 priv->ahb_last_lld->llp=(unsigned int)(&lld_phys[priv->llp_free_idx-1])|priv->llp_master;
154 priv->ahb_last_lld=&lld[priv->llp_free_idx-1];
157 if (priv->llp_count) //john add check
159 if(priv->llp_free_idx==priv->llp_count)
160 priv->llp_free_idx=1;
161 else
162 priv->llp_free_idx++;
166 inline void ahb_dma_start(ahb_dma_data_t *priv)
168 *(volatile unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_CSR_0x0)|=0x1;
171 void ahb_dma_reset(ahb_dma_data_t *priv)
173 priv->llp_last_idx=0;
174 priv->llp_free_idx=0;
175 priv->ahb_last_lld=0;
177 //printk("ahb_dma_stop\n");
178 *(unsigned int *)(priv->base+AHBDMA_ENABLE_0x24)=0; //disable DMA controller
179 *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_CSR_0x0)=0; //disable DMA channel 0
180 *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_LLP_0x10)=0;
181 *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_TXSZ_0x14)=0; //no transfer size (use LLP)
182 *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_CFG_0x4)=0; //disable all interrupt
185 inline void ahbdma_clear_int(ahb_dma_data_t *priv)
187 *(volatile unsigned int *)(priv->base+AHBDMA_ISR_0x8)=1<<(priv->channel);
190 //john add, get ext DMA address
191 // so we can get DMA lenth
192 inline u32 ahbdma_get_dest_addr(ahb_dma_data_t *priv)
194 return *(volatile u32 *)(priv->channel_base+AHBDMA_CHANNEL_DST_0xC);
197 // John add, to get interrupt status
198 // Bit 0 indicate interrupt created,
199 // bit 1 indicate interrupt error
200 u32 ahbdma_get_status(ahb_dma_data_t *priv)
202 u32 status=0;
203 u32 temp;
205 temp = *(volatile u32 *)(priv->base+AHBDMA_INT_ERR_0x0C);
206 if ( temp & (1<<(priv->channel)) )
207 status |= INT_ERROR; //error
209 temp = *(volatile u32 *)(priv->base+AHBDMA_INT_TC_0x04);
210 if ( temp & (1<<(priv->channel)) )
211 status |= INT_TRIGGER; //complete
213 return status;