d5f697143aa044f11b0352e8baa842d1db941da8
[barrelfish] / usr / drivers / omap44xx / sdma / omap_sdma.c
1 /*
2  * Copyright (c) 2014, ETH Zurich.
3  * All rights reserved.
4  *
5  * This file is distributed under the terms in the attached LICENSE file.
6  * If you do not find this file, copies can be found by writing to:
7  * ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
8  */
9
10 #include <barrelfish/barrelfish.h>
11
12 #ifdef OMAP_SDMA_KERNELBENCH
13     #include <arch/armv7/gic.h>
14     #include <arm_hal.h>
15     #include <exceptions.h>
16     #include <kernel.h>
17 #else
18     #include <barrelfish/waitset.h>
19     #include <barrelfish/inthandler.h>
20     #include <driverkit/driverkit.h>
21 #endif
22
23 #include <string.h>
24
25 #include "omap_sdma.h"
26 #include <maps/omap44xx_map.h>
27
28 static omap44xx_sdma_t devsdma;
29 static bool allocated_channel[OMAP44XX_SDMA_NUM_CHANNEL];
30
31 static omap_sdma_irq_handler_t irq_callback;
32
33 static inline errval_t omap_sdma_read_csr(omap44xx_sdma_dma4_csr_t csr)
34 {
35     if (omap44xx_sdma_dma4_csr_misaligned_adrs_err_extract(csr)) {
36         return OMAP_SDMA_ERR_MISALIGNED_ADDRESS;
37     } else if (omap44xx_sdma_dma4_csr_supervisor_err_extract(csr)) {
38         return OMAP_SDMA_ERR_SUPERVISOR;
39     } else if (omap44xx_sdma_dma4_csr_trans_err_extract(csr)) {
40         return OMAP_SDMA_ERR_TRANSACTION;
41     }
42
43     return SYS_ERR_OK;
44 }
45
46 static void omap_sdma_irq_handler(void *arg)
47 {
48     uint32_t irqstatus = omap44xx_sdma_dma4_irqstatus_line_rd(&devsdma, OMAP44XX_SDMA_IRQ_LINE);
49
50     for (omap_sdma_channel_t channel=0; channel<OMAP44XX_SDMA_NUM_CHANNEL; channel++) {
51         bool active = (irqstatus >> channel) & 0x1;
52         if(!active) continue;
53
54         SDMA_PRINT("interrupt on channel %u\n", channel);
55
56         // read out status flags
57         omap44xx_sdma_dma4_csr_t csr = omap44xx_sdma_dma4_csr_rd(&devsdma, channel);
58
59         // check for errors
60         errval_t err = omap_sdma_read_csr(csr);
61
62         if (err_is_ok(err)) {
63             // no error found, check for "End of Block" event
64             if(omap44xx_sdma_dma4_csr_block_extract(csr)) {
65                 irq_callback(channel, err);
66             }
67         } else {
68             // OMAP4460 Multimedia Device Silicon Errata, Revision A:
69             // 1.7 sDMA Channel Is Not Disabled After A Transaction Error
70             if (err_no(err) == OMAP_SDMA_ERR_TRANSACTION) {
71                 // Workaround: disable channel by software
72                 omap44xx_sdma_dma4_ccr_enable_wrf(&devsdma, channel, 0);
73             }
74
75             irq_callback(channel, err);
76         }
77
78         // clear all read status flags
79         omap44xx_sdma_dma4_csr_wr(&devsdma, channel, csr);
80     }
81
82     SDMA_PRINT("interrupt finished\n");
83
84     // clear all set status bits
85     omap44xx_sdma_dma4_irqstatus_line_wr(&devsdma, OMAP44XX_SDMA_IRQ_LINE, irqstatus);
86 }
87
88
89 #ifdef OMAP_SDMA_KERNELBENCH
90 // This interrupt handler is for use in the SDMA kernel benchmark only!
91 // It depends on GCC's code generation to create the prologue and epilogue
92 // for it to be a valid interrupt handler.
93 //
94 // Vanilla Barrelfish is not designed handle interrupts in the kernel.
95 __attribute__((interrupt("IRQ")))
96 static void omap_sdma_kernel_irq_handler(void)
97 {
98     int irq = gic_get_active_irq();
99     if(irq == OMAP44XX_SDMA_IRQ) {
100         omap_sdma_irq_handler(NULL);
101     }
102     gic_ack_irq(irq);
103 }
104 #endif
105
106 static void omap_sdma_irq_config(omap_sdma_channel_t channel)
107 {
108     omap44xx_sdma_dma4_cicr_t dma4_cicr = omap44xx_sdma_dma4_cicr_rd(&devsdma, channel);
109
110     dma4_cicr = omap44xx_sdma_dma4_cicr_super_block_ie_insert(dma4_cicr, 0x0);
111     dma4_cicr = omap44xx_sdma_dma4_cicr_drain_ie_insert(dma4_cicr, 0x0);
112     dma4_cicr = omap44xx_sdma_dma4_cicr_misaligned_err_ie_insert(dma4_cicr, 0x1);
113     dma4_cicr = omap44xx_sdma_dma4_cicr_supervisor_err_ie_insert(dma4_cicr, 0x1);
114     dma4_cicr = omap44xx_sdma_dma4_cicr_trans_err_ie_insert(dma4_cicr, 0x1);
115     dma4_cicr = omap44xx_sdma_dma4_cicr_pkt_ie_insert(dma4_cicr, 0x0);
116     dma4_cicr = omap44xx_sdma_dma4_cicr_block_ie_insert(dma4_cicr, 0x1);
117     dma4_cicr = omap44xx_sdma_dma4_cicr_last_ie_insert(dma4_cicr, 0x0);
118     dma4_cicr = omap44xx_sdma_dma4_cicr_frame_ie_insert(dma4_cicr, 0x0);
119     dma4_cicr = omap44xx_sdma_dma4_cicr_half_ie_insert(dma4_cicr, 0x0);
120     dma4_cicr = omap44xx_sdma_dma4_cicr_drop_ie_insert(dma4_cicr, 0x0);
121
122     omap44xx_sdma_dma4_cicr_wr(&devsdma, channel, dma4_cicr);
123 }
124
125 /**
126  * \brief Initialzes a channel configuraton struct with its reset values.
127  */
128 void omap_sdma_init_channel_conf(struct omap_sdma_channel_conf *conf) {
129     // this function initializes the config struct with default values
130
131     // TRM reset values
132     conf->read_priority  = omap44xx_sdma_PORT_PRIORITY_LOW;
133     conf->write_priority = omap44xx_sdma_PORT_PRIORITY_LOW;
134
135     conf->color_mode = omap44xx_sdma_DISABLE_COLOR_MODE;
136     conf->color = 0x000000;
137
138     // no reset value here, use sane default
139     conf->write_mode = omap44xx_sdma_WRITE_MODE_LAST_NON_POSTED;
140
141     struct omap_sdma_transfer_size *transfer_size = &conf->transfer_size;
142     transfer_size->element_number = 0;
143     transfer_size->frame_number = 0;
144     transfer_size->data_type = omap44xx_sdma_DATA_TYPE_32BIT;
145
146     // default transfer config
147     struct omap_sdma_transfer_conf *src_conf = &conf->src_conf;
148     struct omap_sdma_transfer_conf *dst_conf = &conf->dst_conf;
149     src_conf->start_address = 0;
150     src_conf->addr_mode = omap44xx_sdma_ADDR_MODE_POST_INCR;
151     src_conf->element_index = 0;
152     src_conf->frame_index = 0;
153     src_conf->packed_transfer = omap44xx_sdma_SRC_PACKED_DISABLE;
154     src_conf->burst_mode = omap44xx_sdma_BURST_EN_SINGLE;
155
156     // use the same default values for the destination port
157     memcpy(dst_conf, src_conf, sizeof(struct omap_sdma_transfer_conf));
158
159     conf->enable_link = false;
160     conf->next_channel = 0;
161 }
162
163 static omap44xx_sdma_dma4_ccr_t omap_sdma_channel_conf_ccr(
164                                 omap44xx_sdma_dma4_ccr_t dma4_ccr,
165                                 struct omap_sdma_channel_conf *conf)
166 {
167     dma4_ccr = omap44xx_sdma_dma4_ccr_src_amode_insert(dma4_ccr, conf->src_conf.addr_mode);
168     dma4_ccr = omap44xx_sdma_dma4_ccr_dst_amode_insert(dma4_ccr, conf->dst_conf.addr_mode);
169
170     assert(
171         (conf->read_priority == omap44xx_sdma_PORT_PRIORITY_LOW) ||
172         (conf->read_priority == omap44xx_sdma_PORT_PRIORITY_HIGH)
173     );
174     dma4_ccr = omap44xx_sdma_dma4_ccr_read_priority_insert(dma4_ccr, conf->read_priority);
175
176     assert(
177         (conf->write_priority == omap44xx_sdma_PORT_PRIORITY_LOW) ||
178         (conf->write_priority == omap44xx_sdma_PORT_PRIORITY_HIGH)
179     );
180     dma4_ccr = omap44xx_sdma_dma4_ccr_write_priority_insert(dma4_ccr, conf->write_priority);
181
182     omap44xx_sdma_transparent_copy_t
183         transparent_copy = (conf->color_mode == omap44xx_sdma_TRANSPARENT_COPY);
184     omap44xx_sdma_const_fill_t
185         const_fill = (conf->color_mode == omap44xx_sdma_CONSTANT_FILL);
186
187     dma4_ccr = omap44xx_sdma_dma4_ccr_transparent_copy_enable_insert(dma4_ccr, transparent_copy);
188     dma4_ccr = omap44xx_sdma_dma4_ccr_const_fill_enable_insert(dma4_ccr, const_fill);
189
190     return dma4_ccr;
191 }
192
193
194 static omap44xx_sdma_dma4_color_t omap_sdma_channel_conf_color(
195                                 omap44xx_sdma_dma4_color_t dma4_color,
196                                 struct omap_sdma_channel_conf *conf)
197 {
198     // DMA4_COLORi can only be a 24 bit value
199     assert((conf->color & 0xFF000000) == 0);
200
201     return omap44xx_sdma_dma4_color_color_key_pattern_insert(dma4_color, conf->color);
202 }
203
204 static omap44xx_sdma_dma4_clnk_ctrl_t omap_sdma_channel_conf_clnk_ctrl(
205                                 omap44xx_sdma_dma4_clnk_ctrl_t dma4_clnk_ctrl,
206                                 struct omap_sdma_channel_conf *conf)
207 {
208     // if we enable channel linking, the next channel has to be valid
209     assert(!conf->enable_link || conf->next_channel < OMAP44XX_SDMA_NUM_CHANNEL);
210
211     dma4_clnk_ctrl = omap44xx_sdma_dma4_clnk_ctrl_nextlch_id_insert(
212         dma4_clnk_ctrl, conf->next_channel);
213     dma4_clnk_ctrl = omap44xx_sdma_dma4_clnk_ctrl_enable_lnk_insert(
214         dma4_clnk_ctrl, conf->enable_link ? 1 : 0);
215
216     return dma4_clnk_ctrl;
217 }
218
219 static omap44xx_sdma_dma4_csdp_t omap_sdma_channel_conf_csdp(
220                                 omap44xx_sdma_dma4_csdp_t dma4_csdp,
221                                 struct omap_sdma_channel_conf *conf)
222 {
223     assert(
224         (conf->write_mode == omap44xx_sdma_WRITE_MODE_NONE_POSTED) ||
225         (conf->write_mode == omap44xx_sdma_WRITE_MODE_ALL_POSTED) ||
226         (conf->write_mode == omap44xx_sdma_WRITE_MODE_LAST_NON_POSTED)
227     );
228
229     dma4_csdp = omap44xx_sdma_dma4_csdp_write_mode_insert(dma4_csdp, conf->write_mode);
230
231     // In memory to memory transfers, the endianness is always little endian
232     dma4_csdp = omap44xx_sdma_dma4_csdp_src_endian_insert(dma4_csdp, omap44xx_sdma_ENDIAN_LITTLE);
233     dma4_csdp = omap44xx_sdma_dma4_csdp_src_endian_lock_insert(dma4_csdp, omap44xx_sdma_ENDIAN_LOCK_ADAPT);
234
235     dma4_csdp = omap44xx_sdma_dma4_csdp_dst_endian_insert(dma4_csdp, omap44xx_sdma_ENDIAN_LITTLE);
236     dma4_csdp = omap44xx_sdma_dma4_csdp_dst_endian_lock_insert(dma4_csdp, omap44xx_sdma_ENDIAN_LOCK_ADAPT);
237
238     struct omap_sdma_transfer_conf *src_conf = &conf->src_conf;
239     dma4_csdp = omap44xx_sdma_dma4_csdp_src_burst_en_insert(dma4_csdp, src_conf->burst_mode);
240     dma4_csdp = omap44xx_sdma_dma4_csdp_src_packed_insert(dma4_csdp,
241         src_conf->packed_transfer
242             ? omap44xx_sdma_SRC_PACKED_ENABLE
243             : omap44xx_sdma_SRC_PACKED_DISABLE);
244
245     struct omap_sdma_transfer_conf *dst_conf = &conf->dst_conf;
246     dma4_csdp = omap44xx_sdma_dma4_csdp_dst_burst_en_insert(dma4_csdp, dst_conf->burst_mode);
247     dma4_csdp = omap44xx_sdma_dma4_csdp_dst_packed_insert(dma4_csdp,
248         dst_conf->packed_transfer
249             ? omap44xx_sdma_DST_PACKED_ENABLE
250             : omap44xx_sdma_DST_PACKED_DISABLE);
251
252     struct omap_sdma_transfer_size *transfer_size = &conf->transfer_size;
253
254     dma4_csdp = omap44xx_sdma_dma4_csdp_data_type_insert(dma4_csdp, transfer_size->data_type);
255
256     return dma4_csdp;
257 }
258
259 static void inline omap_sdma_channel_conf_assert_transfer_size(
260                                 struct omap_sdma_transfer_size *transfer_size)
261 {
262     assert(
263         (transfer_size->data_type == omap44xx_sdma_DATA_TYPE_8BIT) ||
264         (transfer_size->data_type == omap44xx_sdma_DATA_TYPE_16BIT) ||
265         (transfer_size->data_type == omap44xx_sdma_DATA_TYPE_32BIT)
266     );
267
268     // element number is 24 bit
269     assert((transfer_size->element_number & 0xFF000000) == 0);
270 }
271
272 static void inline omap_sdma_channel_conf_assert_transfer_conf(
273                                 struct omap_sdma_transfer_conf *transfer_conf)
274 {
275
276     // constant addressing mode is not allowed for memory to memory transfers
277     assert(
278         (transfer_conf->addr_mode == omap44xx_sdma_ADDR_MODE_POST_INCR) ||
279         (transfer_conf->addr_mode == omap44xx_sdma_ADDR_MODE_SINGLE_IDX) ||
280         (transfer_conf->addr_mode == omap44xx_sdma_ADDR_MODE_DOUBLE_IDX)
281     );
282
283     assert(
284         (transfer_conf->burst_mode == omap44xx_sdma_BURST_EN_SINGLE) ||
285         (transfer_conf->burst_mode == omap44xx_sdma_BURST_EN_16BYTE) ||
286         (transfer_conf->burst_mode == omap44xx_sdma_BURST_EN_32BYTE) ||
287         (transfer_conf->burst_mode == omap44xx_sdma_BURST_EN_64BYTE)
288     );
289
290     // if post-incrementing with burst transfers is used,
291     // data must be packed to DMA data-port width (TRM Section 16.4.7)
292     assert(
293         (transfer_conf->burst_mode == omap44xx_sdma_BURST_EN_SINGLE)    ||
294         (transfer_conf->addr_mode != omap44xx_sdma_ADDR_MODE_POST_INCR) ||
295         (transfer_conf->packed_transfer == omap44xx_sdma_SRC_PACKED_ENABLE)
296     );
297 }
298
299 /**
300  * \brief Configure an allocated channel with the given struct.
301  *
302  * \param channel   Channel to configure
303  * \param conf      Complete channel configuration
304  *
305  * This function will write all values of the struct to the SDMA device
306  * registers. Some basic santiy checks (using assert statements) are performed,
307  * but is it the callers responsibility to ensure that the configuration is
308  * sane and valid.
309  */
310 void omap_sdma_set_channel_conf(omap_sdma_channel_t channel,
311                                 struct omap_sdma_channel_conf *conf)
312 {
313     // check transfer config and size parameters
314     assert(channel < OMAP44XX_SDMA_NUM_CHANNEL);
315
316     omap_sdma_channel_conf_assert_transfer_size(&conf->transfer_size);
317
318     omap_sdma_channel_conf_assert_transfer_conf(&conf->src_conf);
319     omap_sdma_channel_conf_assert_transfer_conf(&conf->dst_conf);
320
321
322     // Channel Control Register
323     omap44xx_sdma_dma4_ccr_t dma4_ccr;
324     dma4_ccr = omap44xx_sdma_dma4_ccr_rd(&devsdma, channel);
325     dma4_ccr = omap_sdma_channel_conf_ccr(dma4_ccr, conf);
326     omap44xx_sdma_dma4_ccr_wr(&devsdma, channel, dma4_ccr);
327
328     // Channel Color Register
329     omap44xx_sdma_dma4_color_t dma4_color;
330     dma4_color = omap44xx_sdma_dma4_color_rd(&devsdma, channel);
331     dma4_color = omap_sdma_channel_conf_color(channel, conf);
332     omap44xx_sdma_dma4_color_wr(&devsdma, channel, dma4_color);
333
334     // Channel Link Control Register
335     omap44xx_sdma_dma4_clnk_ctrl_t dma4_clnk_ctrl;
336     dma4_clnk_ctrl = omap44xx_sdma_dma4_clnk_ctrl_rd(&devsdma, channel);
337     dma4_clnk_ctrl = omap_sdma_channel_conf_clnk_ctrl(channel, conf);
338     omap44xx_sdma_dma4_clnk_ctrl_wr(&devsdma, channel, dma4_clnk_ctrl);
339
340     // Channel Source Destination Parameters
341     omap44xx_sdma_dma4_csdp_t dma4_csdp;
342     dma4_csdp = omap44xx_sdma_dma4_csdp_rd(&devsdma, channel);
343     dma4_csdp = omap_sdma_channel_conf_csdp(channel, conf);
344     omap44xx_sdma_dma4_csdp_wr(&devsdma, channel, dma4_csdp);
345
346     // Channel Element Number
347     omap44xx_sdma_dma4_cen_wr(&devsdma, channel, conf->transfer_size.element_number);
348
349     // Channel Frame Number
350     omap44xx_sdma_dma4_cfn_wr(&devsdma, channel, conf->transfer_size.frame_number);
351
352     // Channel Source Element Index
353     omap44xx_sdma_dma4_csei_wr(&devsdma, channel, conf->src_conf.element_index);
354     // Channel Source Frame Index
355     omap44xx_sdma_dma4_csfi_wr(&devsdma, channel, conf->src_conf.frame_index);
356     // Channel Destination Element Index
357     omap44xx_sdma_dma4_cdei_wr(&devsdma, channel, conf->dst_conf.element_index);
358     // Channel Destination Frame Index
359     omap44xx_sdma_dma4_cdfi_wr(&devsdma, channel, conf->dst_conf.frame_index);
360
361     // Channel Source Start Address
362     omap44xx_sdma_dma4_cssa_wr(&devsdma, channel, conf->src_conf.start_address);
363
364     // Channel Source Destination Address
365     omap44xx_sdma_dma4_cdsa_wr(&devsdma, channel, conf->dst_conf.start_address);
366 }
367
368 /**
369  * \brief Start a SDMA transfer on a pre-configured channel
370  *
371  * \param channel   Pre-configured channel to enable
372  * \param interrupt Indicate an interrupt should be sent on completion or error
373  *
374  * It is the callers responsibility to ensure that the channel was configured
375  * properly before this function is called.
376  */
377 void omap_sdma_enable_channel(omap_sdma_channel_t channel, bool interrupt)
378 {
379     assert(channel < OMAP44XX_SDMA_NUM_CHANNEL);
380
381     // clear all channel status flags
382     omap44xx_sdma_dma4_csr_wr(&devsdma, channel, 0xFFFFFFFF);
383
384     uint32_t irqenable = omap44xx_sdma_dma4_irqenable_rd(&devsdma, OMAP44XX_SDMA_IRQ_LINE);
385     if (interrupt) {
386         // set channel
387         irqenable |= 1 << channel;
388         // reset irq status for this channel
389         omap44xx_sdma_dma4_irqstatus_line_wr(&devsdma, OMAP44XX_SDMA_IRQ_LINE, 1 << channel);
390     } else {
391         // clear channel
392         irqenable &= ~(1 << channel);
393     }
394     omap44xx_sdma_dma4_irqenable_wr(&devsdma, OMAP44XX_SDMA_IRQ_LINE, irqenable);
395
396     omap44xx_sdma_dma4_ccr_enable_wrf(&devsdma, channel, 1);
397 }
398
399 /**
400  * \brief Poll a enabled channel for completion of the transfer.
401  */
402 errval_t omap_sdma_poll_channel(omap_sdma_channel_t channel)
403 {
404     assert(channel < OMAP44XX_SDMA_NUM_CHANNEL);
405
406     // interrupts should be disabled in polling mode
407     assert((omap44xx_sdma_dma4_irqenable_rd(
408                 &devsdma, OMAP44XX_SDMA_IRQ_LINE) & 1 << channel) == 0x0
409     );
410
411     for (;;) {
412         omap44xx_sdma_dma4_csr_t csr = omap44xx_sdma_dma4_csr_rd(&devsdma, channel);
413
414         errval_t err = omap_sdma_read_csr(csr);
415
416         if (err_is_fail(err)) return err;
417
418         if(omap44xx_sdma_dma4_csr_block_extract(csr)) {
419             return err;
420         }
421     }
422 }
423
424 /**
425  * \brief Allocate a SDMA channel. Will return an error if there are no channels
426  * available.
427  */
428 errval_t omap_sdma_allocate_channel(omap_sdma_channel_t *channel)
429 {
430     assert(channel != NULL);
431
432     for (omap_sdma_channel_t c = 0; c<OMAP44XX_SDMA_NUM_CHANNEL; c++) {
433         if (!allocated_channel[c]) {
434             allocated_channel[c] = true;
435             *channel = c;
436             return SYS_ERR_OK;
437         }
438     }
439     return OMAP_SDMA_ERR_NO_AVAIL_CHANNEL;
440 }
441
442 /**
443  * \brief Frees a previously allocated SDMA channel.
444  */
445 void omap_sdma_free_channel(omap_sdma_channel_t channel)
446 {
447     assert(allocated_channel[channel]);
448     allocated_channel[channel] = false;
449 }
450
451 /**
452  * \brief Initializes this Mackerel wrapper.
453  *
454  * \param dev_base  Virtual address where the SDMA module is mapped to
455  * \param irq_cb    Mandatory interrupt callback
456  *
457  * The caller has map the SDMA hardware registers before calling this function.
458  * The interrupt callback is executed for every time an SDMA channel triggered
459  * an interrupt. The source channel and the the reason of the interrupt are
460  * passed to the callback as an the argument.
461  */
462 errval_t omap_sdma_init(mackerel_addr_t dev_base, omap_sdma_irq_handler_t irq_cb)
463 {
464     // init global variables
465     STATIC_ASSERT_SIZEOF(bool, 1);
466     memset(allocated_channel, false, OMAP44XX_SDMA_NUM_CHANNEL);
467
468     omap44xx_sdma_initialize(&devsdma, dev_base);
469
470     // check if we can read the revision
471     assert(omap44xx_sdma_dma4_revision_rd(&devsdma) == 0x10900);
472
473     assert(irq_cb != NULL);
474     irq_callback = irq_cb;
475
476     errval_t err = SYS_ERR_OK;
477 #ifdef OMAP_SDMA_KERNELBENCH
478     // in kernelspace, we hijack the normal interrupt handler by overwriting
479     // the global interrupt handler table entry.
480
481     // this is obvioulsy a hack (!) and ONLY for use in the sdma kernel
482     // benchmark which will not allow the kernel to continue after this
483     uintptr_t *irq_handler_entry = (uintptr_t*)
484                         (ETABLE_ADDR + JUMP_TABLE_OFFSET + ARM_EVECTOR_IRQ);
485     *irq_handler_entry = (uintptr_t) omap_sdma_kernel_irq_handler;
486
487     // enable the SDMA interrupt in the global interrupt controller
488     gic_enable_interrupt(OMAP44XX_SDMA_IRQ, GIC_IRQ_CPU_TRG_ALL, 0,
489                             GIC_IRQ_EDGE_TRIGGERED, GIC_IRQ_N_TO_N);
490 #else
491     // in userspace, register normal interrupt handler
492     err = inthandler_setup_arm(omap_sdma_irq_handler, NULL, OMAP44XX_SDMA_IRQ);
493 #endif
494
495     // set fifo depth to maximum burst size
496     omap44xx_sdma_dma4_gcr_max_channel_fifo_depth_wrf(&devsdma, 64);
497
498     // configure error and interrupt handling of the device
499     for(omap_sdma_channel_t channel = 0;
500         channel < OMAP44XX_SDMA_NUM_CHANNEL;
501         channel++)
502     {
503         omap_sdma_irq_config(channel);
504     }
505
506     return err;
507 }