1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include <linux/kernel.h>
23#include <linux/mm.h>
24#include <linux/init.h>
25#include <linux/module.h>
26#include <linux/dma-mapping.h>
27
28#include <asm/system.h>
29#include <asm/io.h>
30#include <asm/ppc4xx_dma.h>
31
32void
33ppc4xx_set_sg_addr(int dmanr, phys_addr_t sg_addr)
34{
35 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
36 printk("ppc4xx_set_sg_addr: bad channel: %d\n", dmanr);
37 return;
38 }
39
40#ifdef PPC4xx_DMA_64BIT
41 mtdcr(DCRN_ASGH0 + (dmanr * 0x8), (u32)(sg_addr >> 32));
42#endif
43 mtdcr(DCRN_ASG0 + (dmanr * 0x8), (u32)sg_addr);
44}
45
46
47
48
49
50
51
52
53
54
55
56int
57ppc4xx_add_dma_sgl(sgl_handle_t handle, phys_addr_t src_addr, phys_addr_t dst_addr,
58 unsigned int count)
59{
60 sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
61 ppc_dma_ch_t *p_dma_ch;
62
63 if (!handle) {
64 printk("ppc4xx_add_dma_sgl: null handle\n");
65 return DMA_STATUS_BAD_HANDLE;
66 }
67
68 if (psgl->dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
69 printk("ppc4xx_add_dma_sgl: bad channel: %d\n", psgl->dmanr);
70 return DMA_STATUS_BAD_CHANNEL;
71 }
72
73 p_dma_ch = &dma_channels[psgl->dmanr];
74
75#ifdef DEBUG_4xxDMA
76 {
77 int error = 0;
78 unsigned int aligned =
79 (unsigned) src_addr | (unsigned) dst_addr | count;
80 switch (p_dma_ch->pwidth) {
81 case PW_8:
82 break;
83 case PW_16:
84 if (aligned & 0x1)
85 error = 1;
86 break;
87 case PW_32:
88 if (aligned & 0x3)
89 error = 1;
90 break;
91 case PW_64:
92 if (aligned & 0x7)
93 error = 1;
94 break;
95 default:
96 printk("ppc4xx_add_dma_sgl: invalid bus width: 0x%x\n",
97 p_dma_ch->pwidth);
98 return DMA_STATUS_GENERAL_ERROR;
99 }
100 if (error)
101 printk
102 ("Alignment warning: ppc4xx_add_dma_sgl src 0x%x dst 0x%x count 0x%x bus width var %d\n",
103 src_addr, dst_addr, count, p_dma_ch->pwidth);
104
105 }
106#endif
107
108 if ((unsigned) (psgl->ptail + 1) >= ((unsigned) psgl + SGL_LIST_SIZE)) {
109 printk("sgl handle out of memory \n");
110 return DMA_STATUS_OUT_OF_MEMORY;
111 }
112
113 if (!psgl->ptail) {
114 psgl->phead = (ppc_sgl_t *)
115 ((unsigned) psgl + sizeof (sgl_list_info_t));
116 psgl->phead_dma = psgl->dma_addr + sizeof(sgl_list_info_t);
117 psgl->ptail = psgl->phead;
118 psgl->ptail_dma = psgl->phead_dma;
119 } else {
120 if(p_dma_ch->int_on_final_sg) {
121
122
123 psgl->ptail->control_count &=
124 ~(SG_TCI_ENABLE | SG_ETI_ENABLE);
125 }
126 psgl->ptail->next = psgl->ptail_dma + sizeof(ppc_sgl_t);
127 psgl->ptail++;
128 psgl->ptail_dma += sizeof(ppc_sgl_t);
129 }
130
131 psgl->ptail->control = psgl->control;
132 psgl->ptail->src_addr = src_addr;
133 psgl->ptail->dst_addr = dst_addr;
134 psgl->ptail->control_count = (count >> p_dma_ch->shift) |
135 psgl->sgl_control;
136 psgl->ptail->next = (uint32_t) NULL;
137
138 return DMA_STATUS_GOOD;
139}
140
141
142
143
144void
145ppc4xx_enable_dma_sgl(sgl_handle_t handle)
146{
147 sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
148 ppc_dma_ch_t *p_dma_ch;
149 uint32_t sg_command;
150
151 if (!handle) {
152 printk("ppc4xx_enable_dma_sgl: null handle\n");
153 return;
154 } else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
155 printk("ppc4xx_enable_dma_sgl: bad channel in handle %d\n",
156 psgl->dmanr);
157 return;
158 } else if (!psgl->phead) {
159 printk("ppc4xx_enable_dma_sgl: sg list empty\n");
160 return;
161 }
162
163 p_dma_ch = &dma_channels[psgl->dmanr];
164 psgl->ptail->control_count &= ~SG_LINK;
165 sg_command = mfdcr(DCRN_ASGC);
166
167 ppc4xx_set_sg_addr(psgl->dmanr, psgl->phead_dma);
168
169 sg_command |= SSG_ENABLE(psgl->dmanr);
170
171 mtdcr(DCRN_ASGC, sg_command);
172}
173
174
175
176
177void
178ppc4xx_disable_dma_sgl(sgl_handle_t handle)
179{
180 sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
181 uint32_t sg_command;
182
183 if (!handle) {
184 printk("ppc4xx_enable_dma_sgl: null handle\n");
185 return;
186 } else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
187 printk("ppc4xx_enable_dma_sgl: bad channel in handle %d\n",
188 psgl->dmanr);
189 return;
190 }
191
192 sg_command = mfdcr(DCRN_ASGC);
193 sg_command &= ~SSG_ENABLE(psgl->dmanr);
194 mtdcr(DCRN_ASGC, sg_command);
195}
196
197
198
199
200
201
202
203
204int
205ppc4xx_get_dma_sgl_residue(sgl_handle_t handle, phys_addr_t * src_addr,
206 phys_addr_t * dst_addr)
207{
208 sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
209 ppc_dma_ch_t *p_dma_ch;
210 ppc_sgl_t *pnext, *sgl_addr;
211 uint32_t count_left;
212
213 if (!handle) {
214 printk("ppc4xx_get_dma_sgl_residue: null handle\n");
215 return DMA_STATUS_BAD_HANDLE;
216 } else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
217 printk("ppc4xx_get_dma_sgl_residue: bad channel in handle %d\n",
218 psgl->dmanr);
219 return DMA_STATUS_BAD_CHANNEL;
220 }
221
222 sgl_addr = (ppc_sgl_t *) __va(mfdcr(DCRN_ASG0 + (psgl->dmanr * 0x8)));
223 count_left = mfdcr(DCRN_DMACT0 + (psgl->dmanr * 0x8)) & SG_COUNT_MASK;
224
225 if (!sgl_addr) {
226 printk("ppc4xx_get_dma_sgl_residue: sgl addr register is null\n");
227 goto error;
228 }
229
230 pnext = psgl->phead;
231 while (pnext &&
232 ((unsigned) pnext < ((unsigned) psgl + SGL_LIST_SIZE) &&
233 (pnext != sgl_addr))
234 ) {
235 pnext++;
236 }
237
238 if (pnext == sgl_addr) {
239
240 *src_addr = pnext->src_addr;
241 *dst_addr = pnext->dst_addr;
242
243
244
245
246
247
248 pnext++;
249
250 while ((pnext != psgl->ptail) &&
251 ((unsigned) pnext < ((unsigned) psgl + SGL_LIST_SIZE))
252 ) {
253 count_left += pnext->control_count & SG_COUNT_MASK;
254 }
255
256 if (pnext != psgl->ptail) {
257 printk
258 ("ppc4xx_get_dma_sgl_residue error (1) psgl->ptail 0x%x handle 0x%x\n",
259 (unsigned int) psgl->ptail, (unsigned int) handle);
260 goto error;
261 }
262
263
264 p_dma_ch = &dma_channels[psgl->dmanr];
265 return (count_left << p_dma_ch->shift);
266
267 } else {
268
269 printk
270 ("get_dma_sgl_residue, unable to match current address 0x%x, handle 0x%x\n",
271 (unsigned int) sgl_addr, (unsigned int) handle);
272
273 }
274
275 error:
276 *src_addr = (phys_addr_t) NULL;
277 *dst_addr = (phys_addr_t) NULL;
278 return 0;
279}
280
281
282
283
284
285
286
287
288int
289ppc4xx_delete_dma_sgl_element(sgl_handle_t handle, phys_addr_t * src_dma_addr,
290 phys_addr_t * dst_dma_addr)
291{
292 sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
293
294 if (!handle) {
295 printk("ppc4xx_delete_sgl_element: null handle\n");
296 return DMA_STATUS_BAD_HANDLE;
297 } else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
298 printk("ppc4xx_delete_sgl_element: bad channel in handle %d\n",
299 psgl->dmanr);
300 return DMA_STATUS_BAD_CHANNEL;
301 }
302
303 if (!psgl->phead) {
304 printk("ppc4xx_delete_sgl_element: sgl list empty\n");
305 *src_dma_addr = (phys_addr_t) NULL;
306 *dst_dma_addr = (phys_addr_t) NULL;
307 return DMA_STATUS_SGL_LIST_EMPTY;
308 }
309
310 *src_dma_addr = (phys_addr_t) psgl->phead->src_addr;
311 *dst_dma_addr = (phys_addr_t) psgl->phead->dst_addr;
312
313 if (psgl->phead == psgl->ptail) {
314
315 psgl->phead = NULL;
316 psgl->ptail = NULL;
317 } else {
318 psgl->phead++;
319 psgl->phead_dma += sizeof(ppc_sgl_t);
320 }
321
322 return DMA_STATUS_GOOD;
323}
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354int
355ppc4xx_alloc_dma_handle(sgl_handle_t * phandle, unsigned int mode, unsigned int dmanr)
356{
357 sgl_list_info_t *psgl=NULL;
358 dma_addr_t dma_addr;
359 ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
360 uint32_t sg_command;
361 uint32_t ctc_settings;
362 void *ret;
363
364 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
365 printk("ppc4xx_alloc_dma_handle: invalid channel 0x%x\n", dmanr);
366 return DMA_STATUS_BAD_CHANNEL;
367 }
368
369 if (!phandle) {
370 printk("ppc4xx_alloc_dma_handle: null handle pointer\n");
371 return DMA_STATUS_NULL_POINTER;
372 }
373
374
375 ret = dma_alloc_coherent(NULL, DMA_PPC4xx_SIZE, &dma_addr, GFP_KERNEL);
376 if (ret != NULL) {
377 memset(ret, 0, DMA_PPC4xx_SIZE);
378 psgl = (sgl_list_info_t *) ret;
379 }
380
381 if (psgl == NULL) {
382 *phandle = (sgl_handle_t) NULL;
383 return DMA_STATUS_OUT_OF_MEMORY;
384 }
385
386 psgl->dma_addr = dma_addr;
387 psgl->dmanr = dmanr;
388
389
390
391
392
393
394
395 psgl->control = p_dma_ch->control;
396
397 psgl->control &= ~(DMA_TM_MASK | DMA_TD);
398
399 psgl->control |= (mode | DMA_CE_ENABLE);
400
401
402 if (mode == DMA_MODE_MM)
403 psgl->control |= DMA_ETD_OUTPUT | DMA_TCE_ENABLE;
404
405 if (p_dma_ch->int_enable) {
406
407 psgl->control |= DMA_CIE_ENABLE;
408 } else {
409 psgl->control &= ~DMA_CIE_ENABLE;
410 }
411
412 sg_command = mfdcr(DCRN_ASGC);
413 sg_command |= SSG_MASK_ENABLE(dmanr);
414
415
416 mtdcr(DCRN_ASGC, sg_command);
417 psgl->sgl_control = SG_ERI_ENABLE | SG_LINK;
418
419
420 ctc_settings = mfdcr(DCRN_DMACT0 + (dmanr * 0x8))
421 & (DMA_CTC_BSIZ_MSK | DMA_CTC_BTEN);
422 psgl->sgl_control |= ctc_settings;
423
424 if (p_dma_ch->int_enable) {
425 if (p_dma_ch->tce_enable)
426 psgl->sgl_control |= SG_TCI_ENABLE;
427 else
428 psgl->sgl_control |= SG_ETI_ENABLE;
429 }
430
431 *phandle = (sgl_handle_t) psgl;
432 return DMA_STATUS_GOOD;
433}
434
435
436
437
438
439void
440ppc4xx_free_dma_handle(sgl_handle_t handle)
441{
442 sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
443
444 if (!handle) {
445 printk("ppc4xx_free_dma_handle: got NULL\n");
446 return;
447 } else if (psgl->phead) {
448 printk("ppc4xx_free_dma_handle: list not empty\n");
449 return;
450 } else if (!psgl->dma_addr) {
451 printk("ppc4xx_free_dma_handle: no dma address\n");
452 return;
453 }
454
455 dma_free_coherent(NULL, DMA_PPC4xx_SIZE, (void *) psgl, 0);
456}
457
458EXPORT_SYMBOL(ppc4xx_alloc_dma_handle);
459EXPORT_SYMBOL(ppc4xx_free_dma_handle);
460EXPORT_SYMBOL(ppc4xx_add_dma_sgl);
461EXPORT_SYMBOL(ppc4xx_delete_dma_sgl_element);
462EXPORT_SYMBOL(ppc4xx_enable_dma_sgl);
463EXPORT_SYMBOL(ppc4xx_disable_dma_sgl);
464EXPORT_SYMBOL(ppc4xx_get_dma_sgl_residue);
465