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