1 /******************************************************************************
2 * *
3 * License Agreement *
4 * *
5 * Copyright (c) 2011 Altera Corporation, San Jose, California, USA. *
6 * All rights reserved. *
7 * *
8 * Permission is hereby granted, free of charge, to any person obtaining a *
9 * copy of this software and associated documentation files (the "Software"), *
10 * to deal in the Software without restriction, including without limitation *
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
12 * and/or sell copies of the Software, and to permit persons to whom the *
13 * Software is furnished to do so, subject to the following conditions: *
14 * *
15 * The above copyright notice and this permission notice shall be included in *
16 * all copies or substantial portions of the Software. *
17 * *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
24 * DEALINGS IN THE SOFTWARE. *
25 * *
26 * *
27 ******************************************************************************/
28
29 /*
30 * Altera HAL driver suitable for Nios II to drive the altera_avalon_sgdma
31 * controller.
32 *
33 * The routines contained in this file are intended for developers who
34 * wish to manage descriptors in their own application code. No facility
35 * for automatic descriptor buffer management is provided. Use this API if
36 * you want to:
37 * - Construct your own descriptors or descriptor chains in your
38 * application code
39 * - Use the SGDMA controller for simple "one off" transfers or for
40 * chains of transfers that you setup manually.
41 *
42 * Author: JRK
43 */
44
45 #include "io.h"
46 #include "sys/alt_irq.h"
47 #include "sys/alt_errno.h"
48 #include "sys/alt_cache.h"
49
50 #include "altera_avalon_sgdma.h"
51 #include "altera_avalon_sgdma_regs.h"
52
53 /* The list of registered SGDMA components */
54 ALT_LLIST_HEAD(alt_sgdma_list);
55
56 /*
57 * alt_avalon_sgdma_do_async_transfer
58 *
59 * Set up and commence a non-blocking transfer of one of more
60 * descriptors (or descriptor chain).
61 *
62 * If the SGDMA controller is busy at the time of this call, the
63 * routine will immediately reutrn -EBUSY; the application can then
64 * decide how to proceed without being blocked.
65 *
66 * If a callback routine has been previously registered with this
67 * particular SGDMA controller, the transfer will be set up to
68 * issue an interrupt on error, EOP, or chain completion. Otherwise,
69 * no interrupt is registered, and it is the responsibility of the
70 * aplication developer to check for and suitably handle errors
71 * and completion.
72 *
73 * Arguments:
74 * - *dev: Pointer to SGDMA device (instance) struct.
75 * - *desc: Pointer to single (ready to run) descriptor. The descriptor
76 * is expected to have its "next" descriptor field initialized either
77 * to a non-ready descriptor, or to the next in a chain.
78 *
79 * Returns:
80 * - 0 for success, or various errors defined in <errno.h>
81 */
alt_avalon_sgdma_do_async_transfer(alt_sgdma_dev * dev,alt_sgdma_descriptor * desc)82 int alt_avalon_sgdma_do_async_transfer(
83 alt_sgdma_dev *dev,
84 alt_sgdma_descriptor *desc)
85 {
86 alt_u32 control;
87
88 /* Return with error immediately if controller is busy */
89 if( (IORD_ALTERA_AVALON_SGDMA_STATUS(dev->base) &
90 ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK) ) {
91 return -EBUSY;
92 }
93
94 /* Clear Run */
95 IOWR_ALTERA_AVALON_SGDMA_CONTROL(dev->base,
96 (IORD_ALTERA_AVALON_SGDMA_CONTROL(dev->base) &
97 ~ALTERA_AVALON_SGDMA_CONTROL_RUN_MSK) );
98
99 /*
100 * Clear any (previous) status register information
101 * that might occlude our error checking later.
102 */
103 IOWR_ALTERA_AVALON_SGDMA_STATUS(dev->base, 0xFF);
104
105 /* Point the controller at the descriptor */
106 IOWR_ALTERA_AVALON_SGDMA_NEXT_DESC_POINTER(dev->base, (alt_u32) desc);
107
108 /*
109 * If a callback routine has been previously registered which will be
110 * called from the SGDMA ISR. Set up controller to:
111 * - Run
112 * - Stop on an error with any particular descriptor
113 * - Include any control register bits registered with along with
114 * the callback routine (effectively, interrupts are controlled
115 * via the control bits set during callback-register time).
116 */
117 if(dev->callback) {
118 control = IORD_ALTERA_AVALON_SGDMA_CONTROL(dev->base);
119
120 control |= (dev->chain_control |
121 ALTERA_AVALON_SGDMA_CONTROL_RUN_MSK |
122 ALTERA_AVALON_SGDMA_CONTROL_STOP_DMA_ER_MSK );
123
124 IOWR_ALTERA_AVALON_SGDMA_CONTROL(dev->base, control);
125 }
126 /*
127 * No callback has been registered. Set up controller to:
128 * - Run
129 * - Stop on an error with any particular descriptor
130 * - Disable interrupt generation
131 */
132 else {
133 control = IORD_ALTERA_AVALON_SGDMA_CONTROL(dev->base);
134
135 control |= (ALTERA_AVALON_SGDMA_CONTROL_RUN_MSK |
136 ALTERA_AVALON_SGDMA_CONTROL_STOP_DMA_ER_MSK );
137 control &= ~ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK;
138
139 IOWR_ALTERA_AVALON_SGDMA_CONTROL(dev->base, control);
140 }
141
142 /*
143 * Error detection/handling should be performed at the application
144 * or callback level as appropriate.
145 */
146 return 0;
147 }
148
149
150 /*
151 * alt_avalon_sgdma_do_sync_transfer
152 *
153 * Send a fully formed descriptor (or list of descriptors) to SGDMA
154 * for transfer. This routine will block both before transfer (if the
155 * controller is busy), and until the requested transfer has completed.
156 *
157 * If an error is detected during the transfer it is abandoned and the
158 * controller's status register contents are returned to the caller.
159 *
160 * Additional error information is available in the status bits of
161 * each descriptor that the SGDMA processed; it is the responsibility
162 * of the user's application to search through the descriptor (or list
163 * of descriptors) to gather specific error information.
164 *
165 * Arguments:
166 * - *dev: Pointer to SGDMA device (instance) struct.
167 * - *desc: Pointer to single (ready to run) descriptor. The descriptor
168 * is expected to have its "next" descriptor field initialized either
169 * to a non-ready descriptor, or to the next in a chain.
170 *
171 * Returns:
172 * - status: Content of SGDMA status register.
173 */
alt_avalon_sgdma_do_sync_transfer(alt_sgdma_dev * dev,alt_sgdma_descriptor * desc)174 alt_u8 alt_avalon_sgdma_do_sync_transfer(
175 alt_sgdma_dev *dev,
176 alt_sgdma_descriptor *desc)
177 {
178 alt_u8 status;
179
180 /* Wait for any pending transfers to complete */
181 while ( (IORD_ALTERA_AVALON_SGDMA_STATUS(dev->base) &
182 ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK) );
183
184
185 /* Clear Run */
186 IOWR_ALTERA_AVALON_SGDMA_CONTROL(dev->base,
187 (IORD_ALTERA_AVALON_SGDMA_CONTROL(dev->base) &
188 ~ALTERA_AVALON_SGDMA_CONTROL_RUN_MSK) );
189
190 /*
191 * Clear any (previous) status register information
192 * that might occlude our error checking later.
193 */
194 IOWR_ALTERA_AVALON_SGDMA_STATUS(dev->base, 0xFF);
195
196 /* Point the controller at the descriptor */
197 IOWR_ALTERA_AVALON_SGDMA_NEXT_DESC_POINTER(dev->base, (alt_u32) desc);
198
199 /*
200 * Set up SGDMA controller to:
201 * - Disable interrupt generation
202 * - Run once a valid descriptor is written to controller
203 * - Stop on an error with any particular descriptor
204 */
205 IOWR_ALTERA_AVALON_SGDMA_CONTROL(dev->base,
206 (ALTERA_AVALON_SGDMA_CONTROL_RUN_MSK |
207 ALTERA_AVALON_SGDMA_CONTROL_STOP_DMA_ER_MSK |
208 IORD_ALTERA_AVALON_SGDMA_CONTROL(dev->base)) );
209
210 /* Wait for the descriptor (chain) to complete */
211 while ( (IORD_ALTERA_AVALON_SGDMA_STATUS(dev->base) &
212 ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK) );
213
214 /* Clear Run */
215 IOWR_ALTERA_AVALON_SGDMA_CONTROL(dev->base,
216 (IORD_ALTERA_AVALON_SGDMA_CONTROL(dev->base) &
217 ~ALTERA_AVALON_SGDMA_CONTROL_RUN_MSK) );
218
219 /* Get & clear status register contents */
220 status = IORD_ALTERA_AVALON_SGDMA_STATUS(dev->base);
221 IOWR_ALTERA_AVALON_SGDMA_STATUS(dev->base, 0xFF);
222
223 return status;
224 }
225
226 /*
227 * SGDMA Descriptor construction routines.
228 *
229 * General information:
230 * These routines construct a single SGDMA descriptor in the memory
231 * pointed to in alt_avalon_sgdma-descriptor *desc.
232 *
233 * The completed descriptor is made ready to run by setting its "Owned
234 * by HW" bit; once the SGDMA controller receives the descriptor (and
235 * its RUN bit is asserted), the descriptor will be processed.
236 *
237 * The descriptor under construction's "next" value is set to the "next"
238 * descriptor passed to this routine, but the "next" descriptor's "Owned
239 * by HW" bit is explicitly negated; once the SGDMA completes processing of
240 * *desc it will not continue to *next until it, too, is made ready. You
241 * can subsequently call the appropriate descriptor construction routine
242 * on *next to make it ready, too.
243 *
244 * You are responsible for the creation of both the descriptor under
245 * constuction as well as the "next" descriptor in the chain.
246 *
247 * Important: descriptors must be in a memory device mastered by the SGDMA
248 * controller's "chain read" and "chain write" Avalon master-ports. Care must be
249 * taken to ensure that both *desc and *next point to areas of memory mastered
250 * by the controller.
251 */
252
alt_avalon_sgdma_construct_mem_to_mem_desc(alt_sgdma_descriptor * desc,alt_sgdma_descriptor * next,alt_u32 * read_addr,alt_u32 * write_addr,alt_u16 length,int read_fixed,int write_fixed)253 void alt_avalon_sgdma_construct_mem_to_mem_desc(
254 alt_sgdma_descriptor *desc,
255 alt_sgdma_descriptor *next,
256 alt_u32 *read_addr,
257 alt_u32 *write_addr,
258 alt_u16 length,
259 int read_fixed,
260 int write_fixed)
261 {
262 alt_avalon_sgdma_construct_mem_to_mem_desc_burst(desc, next, read_addr,
263 write_addr, length, read_fixed, write_fixed, 0, 0);
264 }
265 /*
266 * alt_avalon_sgdma_construct_mem_to_mem_desc
267 *
268 * This routine constructs a single SGDMA descriptor in the memory
269 * specified in alt_avalon_sgdma-descriptor *desc for an Avalon
270 * memory-to-memory transfer.
271 *
272 * Arguments:
273 * - *desc: Pointer to descriptor being constructed.
274 * - *next: Pointer to "next" descriptor. This need not be a complete or
275 * functional descriptor, but must be properly allocated as described above.
276 * - *read_addr: First read address for the DMA transfer
277 * - *write_addr: First write address for the DMA transfer
278 * - length: Number of bytes for this transfer
279 * - read_fixed: If non-zero, DMA will read from a fixed address.
280 * - write_fixed: If non-zer, DMA will write to a fixed address.
281 */
alt_avalon_sgdma_construct_mem_to_mem_desc_burst(alt_sgdma_descriptor * desc,alt_sgdma_descriptor * next,alt_u32 * read_addr,alt_u32 * write_addr,alt_u16 length,int read_fixed,int write_fixed,int read_burst,int write_burst)282 void alt_avalon_sgdma_construct_mem_to_mem_desc_burst(
283 alt_sgdma_descriptor *desc,
284 alt_sgdma_descriptor *next,
285 alt_u32 *read_addr,
286 alt_u32 *write_addr,
287 alt_u16 length,
288 int read_fixed,
289 int write_fixed,
290 int read_burst,
291 int write_burst)
292 {
293 alt_avalon_sgdma_construct_descriptor_burst(
294 desc,
295 next,
296 read_addr,
297 write_addr,
298 length,
299 0, // Generate EOP: N/A in mem-to-mem mode
300 read_fixed,
301 write_fixed,
302 read_burst,
303 write_burst,
304 (alt_u8) 0x0); // Atlantic channel: N/A in mem-to-mem mode
305 }
306
alt_avalon_sgdma_construct_stream_to_mem_desc(alt_sgdma_descriptor * desc,alt_sgdma_descriptor * next,alt_u32 * write_addr,alt_u16 length_or_eop,int write_fixed)307 void alt_avalon_sgdma_construct_stream_to_mem_desc(
308 alt_sgdma_descriptor *desc,
309 alt_sgdma_descriptor *next,
310 alt_u32 *write_addr,
311 alt_u16 length_or_eop,
312 int write_fixed)
313 {
314 alt_avalon_sgdma_construct_stream_to_mem_desc_burst(desc, next, write_addr,
315 length_or_eop, write_fixed, 0);
316 }
317 /*
318 * alt_avalon_sgdma_construct_stream_to_mem_desc
319 *
320 * This routine constructs a single SGDMA descriptor in the memory
321 * specified in alt_avalon_sgdma-descriptor *desc) for an Avalon
322 * Streaming interface-to-Avalon transfer.
323 *
324 * The source (read) data for the transfer comes from the Avalon
325 * Streaming Interface connected to the SGDMA controller's streaming
326 * read-port.
327 *
328 * Arguments:
329 * - *desc: Pointer to descriptor being constructed.
330 * - *next: Pointer to "next" descriptor. This need not be a complete or
331 * functional descriptor, but must be properly allocated as described above.
332 * - *write_addr: First write address for the DMA transfer
333 * - length_or_eop: Number of bytes for this transfer. If set to zero (0x0),
334 * the transfer will continue until an EOP signal is received from the Avalon
335 * Streaming interface
336 * - write_fixed: If non-zero, SGDMA will write to a fixed address.
337 */
alt_avalon_sgdma_construct_stream_to_mem_desc_burst(alt_sgdma_descriptor * desc,alt_sgdma_descriptor * next,alt_u32 * write_addr,alt_u16 length_or_eop,int write_fixed,int write_burst)338 void alt_avalon_sgdma_construct_stream_to_mem_desc_burst(
339 alt_sgdma_descriptor *desc,
340 alt_sgdma_descriptor *next,
341 alt_u32 *write_addr,
342 alt_u16 length_or_eop,
343 int write_fixed,
344 int write_burst)
345 {
346 alt_avalon_sgdma_construct_descriptor_burst(
347 desc,
348 next,
349 (alt_u32) 0x0, // Read addr: N/A in stream-to-mem mode
350 write_addr,
351 length_or_eop,
352 0x0, // Generate EOP: N/A in stream-to-mem mode
353 0x0, // Read fixed: N/A in stream-to-mem mode
354 write_fixed,
355 0, // Read_burst : N/A in stream-to-mem mode
356 write_burst,
357 (alt_u8) 0x0); // Atlantic channel: N/A in stream-to-mem mode
358 }
359
alt_avalon_sgdma_construct_mem_to_stream_desc(alt_sgdma_descriptor * desc,alt_sgdma_descriptor * next,alt_u32 * read_addr,alt_u16 length,int read_fixed,int generate_sop,int generate_eop,alt_u8 atlantic_channel)360 void alt_avalon_sgdma_construct_mem_to_stream_desc(
361 alt_sgdma_descriptor *desc,
362 alt_sgdma_descriptor *next,
363 alt_u32 *read_addr,
364 alt_u16 length,
365 int read_fixed,
366 int generate_sop,
367 int generate_eop,
368 alt_u8 atlantic_channel)
369 {
370 alt_avalon_sgdma_construct_mem_to_stream_desc_burst(desc, next, read_addr,
371 length, read_fixed, generate_sop, generate_eop, 0, atlantic_channel);
372
373 }
374 /*
375 * alt_avalon_sgdma_construct_mem_to_stream_desc
376 *
377 * This routine constructs a single SGDMA descriptor in the memory
378 * specified in alt_avalon_sgdma-descriptor *desc) for an Avalon to
379 * Avalon Streaming interface transfer.
380 *
381 * The destination (write) data for the transfer goes to the Avalon
382 * Streaming Interface connected to the SGDMA controller's streaming
383 * write-port.
384 *
385 * Arguments:
386 * - *desc: Pointer to descriptor being constructed.
387 * - *next: Pointer to "next" descriptor. This need not be a complete or
388 * functional descriptor, but must be properly allocated as described above.
389 * - *read_addr: First read address for the transfer
390 * - length: Number of bytes for this transfer
391 * - read_fixed: If non-zero, SGDMA will read from a fixed address.
392 * - generate_sop: If non-zero, SGDMA will generate a start-of-packet (SOP)
393 * on the Avalon Streaming interface when commencing the transfer.
394 * - generate_eop: If non-zero, SGDMA will generate an end-of-packet (EOP)
395 * on the Avalon Streaming interface when completing the transfer.
396 * - atlantic_channel: 8-bit channel identification number that will be
397 * passed to the Avalon Streaming interface.
398 */
alt_avalon_sgdma_construct_mem_to_stream_desc_burst(alt_sgdma_descriptor * desc,alt_sgdma_descriptor * next,alt_u32 * read_addr,alt_u16 length,int read_fixed,int generate_sop,int generate_eop,int read_burst,alt_u8 atlantic_channel)399 void alt_avalon_sgdma_construct_mem_to_stream_desc_burst(
400 alt_sgdma_descriptor *desc,
401 alt_sgdma_descriptor *next,
402 alt_u32 *read_addr,
403 alt_u16 length,
404 int read_fixed,
405 int generate_sop,
406 int generate_eop,
407 int read_burst,
408 alt_u8 atlantic_channel)
409 {
410 alt_avalon_sgdma_construct_descriptor_burst(
411 desc,
412 next,
413 read_addr,
414 (alt_u32) 0x0, // Write address N/A in mem-to-stream mode
415 length,
416 generate_eop,
417 read_fixed,
418 generate_sop,
419 read_burst,
420 0, // Write_burst : N/A in mem-to-stream mode
421 atlantic_channel);
422 }
423
424 /*
425 * alt_avalon_sgdma_register_callback
426 *
427 * Associate a user-specifiC routine with the SGDMA interrupt handler.
428 * If a callback is registered, all non-blocking SGDMA transfers will
429 * enable interrupts that will cause the callback to be executed.
430 * The callback runs as part of the interrupt service routine, and
431 * great care must be taken to follow the guidelines for acceptable
432 * interrupt service routine behavior as described in the Nios II
433 * Software Developer's Handbook.
434 *
435 * Note: To disable callbacks after registering one, this routine
436 * may be called passing 0x0 to the callback argument.
437 *
438 * Arguments:
439 * - *dev: Pointer to SGDMA device (instance) struct.
440 * - callback: Pointer to callback routine to execute at interrupt level
441 * - chain_control: SGDMA control register contents. This value will be
442 * OR'd together with control bits to:
443 * (1) Set the the SGDMA "run" bit, and
444 * (2) Stop SGDMA on any error
445 * in the SGDMA control register, when an asynchronous transfer is initiated.
446 * This allows you to control the conditions that will generate an interrupt
447 * from SGDMA. If you want interrupts to be generated (and thus call the
448 * callback routine), you MUST set one or more bits in the chain_control
449 * variable that correspond to SGDMA control register interrupt enable bits
450 * for interrupts to be generated, as well as the master inerrupt enable bit.
451 */
alt_avalon_sgdma_register_callback(alt_sgdma_dev * dev,alt_avalon_sgdma_callback callback,alt_u32 chain_control,void * context)452 void alt_avalon_sgdma_register_callback(
453 alt_sgdma_dev *dev,
454 alt_avalon_sgdma_callback callback,
455 alt_u32 chain_control,
456 void *context)
457 {
458 dev->callback = callback;
459 dev->callback_context = context;
460 dev->chain_control = chain_control;
461 }
462
463
464 /*
465 * alt_avalon_sgdma_start
466 *
467 * Start the DMA engine. The descriptor pointed to in the controller's
468 * "Next descriptor pointer" and subsequent descriptor, will be processed.
469 *
470 * Arguments:
471 * - *dev: Pointer to SGDMA device (instance) struct.
472 */
alt_avalon_sgdma_start(alt_sgdma_dev * dev)473 void alt_avalon_sgdma_start(alt_sgdma_dev *dev)
474 {
475 alt_u32 control;
476
477 control = IORD_ALTERA_AVALON_SGDMA_CONTROL(dev->base);
478 control |= ALTERA_AVALON_SGDMA_CONTROL_RUN_MSK;
479 IOWR_ALTERA_AVALON_SGDMA_CONTROL(dev->base, control);
480 }
481
482 /*
483 * alt_avalon_sgdma_stop
484 *
485 * Stop the DMA engine (following completion of the current buffer descriptor).
486 *
487 * Arguments:
488 * - *dev: Pointer to SGDMA device (instance) struct
489 */
alt_avalon_sgdma_stop(alt_sgdma_dev * dev)490 void alt_avalon_sgdma_stop(alt_sgdma_dev *dev)
491 {
492 alt_u32 control;
493
494 control = IORD_ALTERA_AVALON_SGDMA_CONTROL(dev->base);
495 control &= ~ALTERA_AVALON_SGDMA_CONTROL_RUN_MSK;
496 IOWR_ALTERA_AVALON_SGDMA_CONTROL(dev->base, control);
497 }
498
499 /*
500 * alt_avalon_sgdma_check_descriptor_status
501 *
502 * This routine will report:
503 * - Any errors reported by the SGDMA controller specific
504 * to a particular descriptor by retirning -EIO
505 * - The descriptor currently in use ("Owned by HW" bit set)
506 * by returning -EINPROGRESS.
507 *
508 * Arguments:
509 * - *desc: Pointer to descriptor to examine
510 *
511 * Returns:
512 * - 0 if the descriptor is error-free, not "owned by hardware", or
513 * a previously requested transfer has appeared to have completed
514 * normally. Or, various error conditions defined in <errno.h>
515 */
alt_avalon_sgdma_check_descriptor_status(alt_sgdma_descriptor * desc)516 int alt_avalon_sgdma_check_descriptor_status(alt_sgdma_descriptor *desc)
517 {
518 /* Errors take precedence */
519 if( IORD_8DIRECT(&desc->status, 0) &
520 ( ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_CRC_MSK |
521 ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_PARITY_MSK |
522 ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_OVERFLOW_MSK |
523 ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_SYNC_MSK |
524 ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_UEOP_MSK |
525 ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_MEOP_MSK |
526 ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_MSOP_MSK ) ) {
527 return -EIO;
528 }
529
530 if( IORD_8DIRECT(&desc->control, 0) &
531 ALTERA_AVALON_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK) {
532 return -EINPROGRESS;
533 }
534
535 return 0;
536 }
537
538 /*
539 * alt_avalon_sgdma_open - Retrieve a pointer to the SGDMA
540 *
541 * Search the list of registered SGDMAs for one with the supplied name.
542 *
543 * The return value will be NULL on failure, and non-NULL otherwise.
544 *
545 * Arguments:
546 * - *name: Character pointer to name of SGDMA peripheral as registered
547 * with the HAL. For example, an SGDMA controller named "my_sgdma"
548 * in SOPC Builder would be oped by asking for "/dev/my_sgdma".
549 *
550 * Returns:
551 * - Pointer to SGDMA device instance struct, or null if the device
552 * could not be opened.
553 */
alt_avalon_sgdma_open(const char * name)554 alt_sgdma_dev* alt_avalon_sgdma_open (const char* name)
555 {
556 alt_sgdma_dev* dev;
557
558 dev = (alt_sgdma_dev*) alt_find_dev (name, &alt_sgdma_list);
559
560 if (NULL == dev) {
561 ALT_ERRNO = ENODEV;
562 }
563
564 return dev;
565 }
566
567
alt_avalon_sgdma_construct_descriptor(alt_sgdma_descriptor * desc,alt_sgdma_descriptor * next,alt_u32 * read_addr,alt_u32 * write_addr,alt_u16 length_or_eop,int generate_eop,int read_fixed,int write_fixed_or_sop,alt_u8 atlantic_channel)568 void alt_avalon_sgdma_construct_descriptor(
569 alt_sgdma_descriptor *desc,
570 alt_sgdma_descriptor *next,
571 alt_u32 *read_addr,
572 alt_u32 *write_addr,
573 alt_u16 length_or_eop,
574 int generate_eop,
575 int read_fixed,
576 int write_fixed_or_sop,
577 alt_u8 atlantic_channel)
578 {
579 alt_avalon_sgdma_construct_descriptor_burst(desc, next, read_addr,
580 write_addr, length_or_eop, generate_eop, read_fixed, write_fixed_or_sop,
581 0, 0, atlantic_channel);
582 }
583
584 /*
585 * alt_avalon_sgdma_enable_desc_poll
586 *
587 * Enables descriptor polling mode with specified frequency. User needs to make
588 * sure this feature is supported by hardware. There is no effect if hardware
589 * does not support this feature.
590 *
591 * Arguments:
592 * - *dev: Pointer to SGDMA device (instance) struct
593 * - frequency: Frequency value to set. Only lower 11-bit value of frequency
594 will write to control register.
595 *
596 * Returns:
597 * - None
598 */
alt_avalon_sgdma_enable_desc_poll(alt_sgdma_dev * dev,alt_u32 frequency)599 void alt_avalon_sgdma_enable_desc_poll(alt_sgdma_dev *dev, alt_u32 frequency)
600 {
601 alt_u32 control;
602
603 control = IORD_ALTERA_AVALON_SGDMA_CONTROL(dev->base);
604 /* Clear descriptor polling frequency */
605 control &= ~ALTERA_AVALON_SGDMA_CONTROL_DESC_POLL_FREQ_MSK;
606
607 control |= ALTERA_AVALON_SGDMA_CONTROL_DESC_POLL_EN_MSK |
608 ((frequency << ALTERA_AVALON_SGDMA_CONTROL_DESC_POLL_FREQ_OFST) &
609 ALTERA_AVALON_SGDMA_CONTROL_DESC_POLL_FREQ_MSK);
610 IOWR_ALTERA_AVALON_SGDMA_CONTROL(dev->base, control);
611
612 return;
613 }
614
615 /*
616 * alt_avalon_sgdma_disable_desc_poll
617 *
618 * Disables descriptor polling mode.
619 *
620 * Arguments:
621 * - *dev: Pointer to SGDMA device (instance) struct
622 *
623 * Returns:
624 * - None
625 */
alt_avalon_sgdma_disable_desc_poll(alt_sgdma_dev * dev)626 void alt_avalon_sgdma_disable_desc_poll(alt_sgdma_dev *dev)
627 {
628 alt_u32 control;
629
630 control = IORD_ALTERA_AVALON_SGDMA_CONTROL(dev->base);
631 control &= ~ALTERA_AVALON_SGDMA_CONTROL_DESC_POLL_EN_MSK;
632
633 IOWR_ALTERA_AVALON_SGDMA_CONTROL(dev->base, control);
634
635 return;
636 }
637
638 /*******************************************************************************
639 * Altera HAL support & Private API
640 ******************************************************************************/
641 /*
642 * alt_avalon_sgdma_construct_descriptor
643 *
644 * This is a genertic routine that the SGDMA mode-specific routines
645 * call to populate a descriptor.
646 */
alt_avalon_sgdma_construct_descriptor_burst(alt_sgdma_descriptor * desc,alt_sgdma_descriptor * next,alt_u32 * read_addr,alt_u32 * write_addr,alt_u16 length_or_eop,int generate_eop,int read_fixed,int write_fixed_or_sop,int read_burst,int write_burst,alt_u8 atlantic_channel)647 void alt_avalon_sgdma_construct_descriptor_burst(
648 alt_sgdma_descriptor *desc,
649 alt_sgdma_descriptor *next,
650 alt_u32 *read_addr,
651 alt_u32 *write_addr,
652 alt_u16 length_or_eop,
653 int generate_eop,
654 int read_fixed,
655 int write_fixed_or_sop,
656 int read_burst,
657 int write_burst,
658 alt_u8 atlantic_channel)
659 {
660 /*
661 * Mark the "next" descriptor as "not" owned by hardware. This prevents
662 * The SGDMA controller from continuing to process the chain. This is
663 * done as a single IO write to bypass cache, without flushing
664 * the entire descriptor, since only the 8-bit descriptor status must
665 * be flushed.
666 */
667 IOWR_8DIRECT(&next->control, 0,
668 (next->control & ~ALTERA_AVALON_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK));
669
670 desc->read_addr = read_addr;
671 desc->write_addr = write_addr;
672 desc->next = (alt_u32 *) next;
673 desc->read_addr_pad = 0x0;
674 desc->write_addr_pad = 0x0;
675 desc->next_pad = 0x0;
676 desc->bytes_to_transfer = length_or_eop;
677 desc->actual_bytes_transferred = 0;
678 desc->status = 0x0;
679
680 /* SGDMA burst not currently supported */
681 desc->read_burst = read_burst;
682 desc->write_burst = write_burst;
683
684 /*
685 * Set the descriptor control block as follows:
686 * - Set "owned by hardware" bit
687 * - Optionally set "generte EOP" bit
688 * - Optionally set the "read from fixed address" bit
689 * - Optionally set the "write to fixed address bit (which serves
690 * serves as a "generate SOP" control bit in memory-to-stream mode).
691 * - Set the 4-bit atlantic channel, if specified
692 *
693 * Note that this step is performed after all other descriptor information
694 * has been filled out so that, if the controller already happens to be
695 * pointing at this descriptor, it will not run (via the "owned by hardware"
696 * bit) until all other descriptor information has been set up.
697 */
698 desc->control = (
699 (ALTERA_AVALON_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK) |
700 (generate_eop ?
701 ALTERA_AVALON_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK : 0x0) |
702 (read_fixed ?
703 ALTERA_AVALON_SGDMA_DESCRIPTOR_CONTROL_READ_FIXED_ADDRESS_MSK : 0x0) |
704 (write_fixed_or_sop ?
705 ALTERA_AVALON_SGDMA_DESCRIPTOR_CONTROL_WRITE_FIXED_ADDRESS_MSK : 0x0) |
706 (atlantic_channel ? ( (atlantic_channel & 0x0F) << 3) : 0)
707 );
708
709 /*
710 * Flush completed buffer out of cache. This is done rather than
711 * individual cache-bypassed writes to take advantage of any
712 * burst-capabilities in the memory we're writing to.
713 */
714 alt_dcache_flush(desc, sizeof(alt_sgdma_descriptor));
715 }
716
717 /*
718 * alt_avalon_sgdma_irq()
719 *
720 * Interrupt handler for the Scatter-Gather DMA controller.
721 */
722 #ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT
alt_avalon_sgdma_irq(void * context)723 static void alt_avalon_sgdma_irq(void *context)
724 #else
725 static void alt_avalon_sgdma_irq(void *context, alt_u32 id)
726 #endif
727 {
728 alt_sgdma_dev *dev = (alt_sgdma_dev *) context;
729 alt_irq_context cpu_sr;
730
731 /*
732 * Clear the pending interrupt request from the SGDMA controller.
733 * Writing 1 to bit-31 of the control register clears the interrupt.
734 * Note: This is explicitly done before calling user interrupt-handling
735 * code rather than after; if user ISR code initiates another SGDMA
736 * transfer which completes quickly, reading the control register after
737 * the callback routine may result in a lost interrupt.
738 */
739 IOWR_ALTERA_AVALON_SGDMA_CONTROL(dev->base,
740 IORD_ALTERA_AVALON_SGDMA_CONTROL(dev->base) | 0x80000000);
741
742 /* Dummy read to ensure IRQ is negated before the ISR returns */
743 IORD_ALTERA_AVALON_SGDMA_CONTROL(dev->base);
744
745 /*
746 * Other interrupts are explicitly disabled if callbacks
747 * are registered because there is no guarantee that they are
748 * preemption-safe. This allows the driver to support
749 * interrupt preemption.
750 */
751 if(dev->callback) {
752 cpu_sr = alt_irq_disable_all();
753 (dev->callback)(dev->callback_context);
754 alt_irq_enable_all(cpu_sr);
755 }
756 }
757
758 /*
759 * alt_avalon_sgdma_init()
760 *
761 * Initializes the Scatter-Gather DMA controller. This routine is called
762 * from the ALTERA_AVALON_SGDMA_INIT macro and is called automatically
763 * by alt_sys_init.c
764 *
765 * This routine disables interrupts, future descriptor processing,
766 * registers a specific instance of the device with the HAL,
767 * and installs an interrupt handler for the device.
768 */
alt_avalon_sgdma_init(alt_sgdma_dev * dev,alt_u32 ic_id,alt_u32 irq)769 void alt_avalon_sgdma_init (alt_sgdma_dev *dev, alt_u32 ic_id, alt_u32 irq)
770 {
771 extern alt_llist alt_sgdma_list;
772
773 /*
774 * Halt any current transactions (reset the device)
775 * SW reset is written twice per SGDMA documentation
776 */
777 IOWR_ALTERA_AVALON_SGDMA_CONTROL(dev->base,
778 ALTERA_AVALON_SGDMA_CONTROL_SOFTWARERESET_MSK);
779 IOWR_ALTERA_AVALON_SGDMA_CONTROL(dev->base,
780 ALTERA_AVALON_SGDMA_CONTROL_SOFTWARERESET_MSK);
781
782 /*
783 * Disable interrupts, halt future descriptor processing,
784 * and clear status register content
785 */
786 IOWR_ALTERA_AVALON_SGDMA_CONTROL(dev->base, 0x0);
787 IOWR_ALTERA_AVALON_SGDMA_STATUS(dev->base, 0xFF);
788
789 /* Register this instance of the SGDMA controller with HAL */
790 alt_dev_llist_insert((alt_dev_llist*) dev, &alt_sgdma_list);
791
792 /* Install IRQ handler */
793 #ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT
794 alt_ic_isr_register(ic_id, irq, alt_avalon_sgdma_irq, dev, 0x0);
795 #else
796 alt_irq_register(irq, dev, alt_avalon_sgdma_irq);
797 #endif
798 }
799