source: soft/giet_vm/giet_drivers/dma_driver.c @ 520

Last change on this file since 520 was 496, checked in by alain, 10 years ago

1) Introduce access functions to MMC intrumentation registers.
2) Use _printf for error or debug messages.

File size: 11.9 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : dma_driver.c
3// Date     : 23/11/2013
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7
8#include <giet_config.h>
9#include <hard_config.h>
10#include <dma_driver.h>
11#include <tty0.h>
12#include <vmem.h>
13#include <utils.h>
14#include <io.h>
15
16#if !defined(X_SIZE)
17# error: You must define X_SIZE in the hard_config.h file
18#endif
19
20#if !defined(Y_SIZE)
21# error: You must define X_SIZE in the hard_config.h file
22#endif
23
24#if !defined(X_WIDTH)
25# error: You must define X_WIDTH in the hard_config.h file
26#endif
27
28#if !defined(Y_WIDTH)
29# error: You must define X_WIDTH in the hard_config.h file
30#endif
31
32#if !defined(NB_DMA_CHANNELS)
33# error: You must define NB_DMA_CHANNELS in the hard_config.h file
34#endif
35
36#if !defined(SEG_DMA_BASE)
37# error: You must define SEG_DMA_BASE in the hard_config.h file
38#endif
39
40#if !defined(PERI_CLUSTER_INCREMENT)
41# error: You must define PERI_CLUSTER_INCREMENT in the hard_config.h file
42#endif
43
44extern volatile unsigned int _ptabs_vaddr[];
45
46///////////////////////////////////////////////////////////////////////////////
47// This low level function returns the value contained in register "index"
48// in the DMA component contained in cluster "cluster_xy"
49///////////////////////////////////////////////////////////////////////////////
50
51#if NB_DMA_CHANNELS > 0
52static
53unsigned int _dma_get_register( unsigned int cluster_xy, // cluster index
54                                unsigned int channel_id, // channel index
55                                unsigned int index )     // register index
56{
57    unsigned int vaddr =
58        SEG_DMA_BASE + 
59        (cluster_xy * PERI_CLUSTER_INCREMENT) +
60        (channel_id * DMA_SPAN) +
61        (index << 2);
62
63    return ioread32( (void*)vaddr );
64}
65#endif
66
67///////////////////////////////////////////////////////////////////////////////
68// This low level function sets a new value in register "index"
69// in the DMA component contained in cluster "cluster_xy"
70///////////////////////////////////////////////////////////////////////////////
71
72#if NB_DMA_CHANNELS > 0
73static
74void _dma_set_register( unsigned int cluster_xy,       // cluster index
75                        unsigned int channel_id,       // channel index
76                        unsigned int index,            // register index
77                        unsigned int value )           // value to be written
78{
79    unsigned int vaddr =
80        SEG_DMA_BASE + 
81        (cluster_xy * PERI_CLUSTER_INCREMENT) +
82        (channel_id * DMA_SPAN) +
83        (index << 2);
84
85    iowrite32( (void*)vaddr, value );
86}
87#endif
88
89////////////////////////////////////////////////
90unsigned int _dma_init( unsigned int cluster_xy,
91                        unsigned int channel_id )
92{
93#if NB_DMA_CHANNELS > 0
94
95    // parameters checking
96    unsigned int x = cluster_xy >> Y_WIDTH;
97    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
98    if (x >= X_SIZE)                    return 1; 
99    if (y >= Y_SIZE)                    return 1; 
100    if (channel_id >= NB_DMA_CHANNELS)  return 1; 
101
102    // disable interrupt for selected channel
103    _dma_set_register(cluster_xy, channel_id, DMA_IRQ_DISABLE, 1);
104    return 0;
105#else
106    return 1;
107#endif
108}
109
110//////////////////////////////////////////////////
111unsigned int _dma_reset( unsigned int cluster_xy, 
112                         unsigned int channel_id ) 
113{
114#if NB_DMA_CHANNELS > 0
115
116    // parameters checking
117    unsigned int x = cluster_xy >> Y_WIDTH;
118    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
119    if (x >= X_SIZE)                    return 1; 
120    if (y >= Y_SIZE)                    return 1; 
121    if (channel_id >= NB_DMA_CHANNELS)  return 1; 
122
123    // reset selected channel
124    _dma_set_register(cluster_xy, channel_id, DMA_RESET, 0);
125    return 0;
126#else
127    return 1;
128#endif
129}
130
131//////////////////////////////////////////////////////
132unsigned int _dma_get_status( unsigned int cluster_xy, 
133                              unsigned int channel_id ) 
134{
135#if NB_DMA_CHANNELS > 0
136
137    // parameters checking
138    unsigned int x = cluster_xy >> Y_WIDTH;
139    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
140    if (x >= X_SIZE)                    return 1; 
141    if (y >= Y_SIZE)                    return 1; 
142    if (channel_id >= NB_DMA_CHANNELS)  return 1;
143
144    // get selected channel status
145    return _dma_get_register(cluster_xy, channel_id, DMA_LEN);
146#else
147    return DMA_IDLE;
148#endif
149}
150
151////////////////////////////////////////////////////////
152void _dma_start_transfer( unsigned int       cluster_xy,  // DMA cluster
153                          unsigned int       channel_id,  // DMA channel
154                          unsigned long long dst_paddr,   // physical address
155                          unsigned long long src_paddr,   // physical address
156                          unsigned int       size )       // bytes
157{
158#if NB_DMA_CHANNELS > 0
159
160    // selected channel configuration and lauching
161    _dma_set_register(cluster_xy, channel_id, DMA_SRC,
162            (unsigned int)(src_paddr));
163    _dma_set_register(cluster_xy, channel_id, DMA_SRC_EXT,
164            (unsigned int)(src_paddr>>32));
165    _dma_set_register(cluster_xy, channel_id, DMA_DST,
166            (unsigned int)(dst_paddr));
167    _dma_set_register(cluster_xy, channel_id, DMA_DST_EXT,
168            (unsigned int)(dst_paddr>>32));
169    _dma_set_register(cluster_xy, channel_id, DMA_LEN,
170            (unsigned int)size);
171
172#endif
173}
174
175///////////////////////////////////////////////////////
176void _dma_physical_copy( unsigned int       cluster_xy,  // DMA cluster
177                         unsigned int       channel_id,  // DMA channel
178                         unsigned long long dst_paddr,   // destination physical address
179                         unsigned long long src_paddr,   // source physical address
180                         unsigned int       size )       // bytes
181{
182#if NB_DMA_CHANNELS > 0
183
184    // check DMA channel parameters
185    unsigned int x = cluster_xy >> Y_WIDTH;
186    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
187    if ( (x >= X_SIZE) || (y >= Y_SIZE) || (channel_id >= NB_DMA_CHANNELS) )
188    {
189        _puts("\n[DMA ERROR] in _dma_physical_copy() : illegal DMA channel ");
190        _exit();
191    }
192
193    // check buffers alignment constraints
194    if ( (dst_paddr & 0x3)   || (src_paddr & 0x3) || (size & 0x3) )
195    {
196        _puts("\n[DMA ERROR] in _dma_physical_copy() : buffer unaligned\n");
197        _exit();
198    }
199
200#if GIET_DEBUG_DMA_DRIVER
201_puts("\n[DMA DEBUG] enter _dma_physical_copy() for channel[");
202_putd( x );
203_puts(",");
204_putd( y );
205_puts(",");
206_putd( channel_id );
207_puts("] at cycle ");
208_putd( _get_proctime() );
209_puts("\n - src_paddr   = ");
210_putl( src_paddr );
211_puts("\n - dst_paddr   = ");
212_putl( dst_paddr );
213_puts("\n - bytes       = ");
214_putd( size );
215_puts("\n");
216#endif
217
218    // dma channel configuration & lauching
219    _dma_start_transfer( cluster_xy, channel_id, dst_paddr, src_paddr, size ); 
220
221    // scan dma channel status
222    unsigned int status = _dma_get_status( cluster_xy, channel_id );
223    while( (status != DMA_SUCCESS) && 
224           (status != DMA_READ_ERROR) &&
225           (status != DMA_WRITE_ERROR) )
226    {
227        status = _dma_get_status( cluster_xy, channel_id );
228
229#if GIET_DEBUG_DMA_DRIVER
230_puts("\n[DMA DEBUG] _dma_physical_copy() : ... waiting on DMA_STATUS register\n");
231#endif
232
233    }
234   
235    // analyse status
236    if( status != DMA_SUCCESS )
237    {
238        _puts("\n[DMA ERROR] in _dma_physical_copy() : bad DMA_STATUS");
239        _exit();
240    }
241
242    // reset dma channel
243    _dma_reset( cluster_xy, channel_id );
244
245#if GIET_DEBUG_DMA_DRIVER
246_puts("\n[DMA DEBUG] exit _dma_physical_copy() at cycle ");
247_putd( _get_proctime() );
248_puts("\n");
249#endif
250
251#else // NB_DMA_CHANNELS == 0
252
253    _puts("\n[DMA ERROR] in _dma_physical_copy() : NB_DMA_CHANNELS == 0\n");
254    _exit();
255
256#endif
257}
258
259
260////////////////////////////////////////
261void  _dma_copy( unsigned int cluster_xy,    // DMA cluster
262                 unsigned int channel_id,    // DMA channel
263                 unsigned int vspace_id,     // vspace index for v2p translation
264                 unsigned int dst_vaddr,     // dst_vaddr buffer vbase
265                 unsigned int src_vaddr,     // src_vaddr buffer vbase
266                 unsigned int size )         // bytes
267{
268#if NB_DMA_CHANNELS > 0
269
270    // check DMA channel parameters
271    unsigned int x = cluster_xy >> Y_WIDTH;
272    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
273    if ( (x >= X_SIZE) || (y >= Y_SIZE) || (channel_id >= NB_DMA_CHANNELS) )
274    {
275        _puts("\n[DMA ERROR] in _dma_copy() : illegal DMA channel ");
276        _exit();
277    }
278
279    // check buffers alignment constraints
280    if ( (dst_vaddr & 0x3)   || (src_vaddr & 0x3) || (size & 0x3) )
281    {
282        _puts("\n[DMA ERROR] in _dma_copy() : buffer unaligned\n");
283        _exit();
284    }
285
286    unsigned int ppn;
287    unsigned int flags;
288
289#if GIET_DEBUG_DMA_DRIVER
290_puts("\n[DMA DEBUG] enter _dma_copy() for channel[");
291_putd( x );
292_puts(",");
293_putd( y );
294_puts(",");
295_putd( channel_id );
296_puts("] at cycle ");
297_putd( _get_proctime() );
298_puts("\n - src_vaddr   = ");
299_putx( src_vaddr );
300_puts("\n - dst_vaddr   = ");
301_putx( dst_vaddr );
302_puts("\n - bytes       = ");
303_putd( size );
304_puts("\n");
305#endif
306
307    // checking alignment constraints
308    if ( (((unsigned int)dst_vaddr) & 0x3) ||
309         (((unsigned int)src_vaddr) & 0x3) ||
310         (size & 0x3) )
311    {
312        _puts("\n[DMA ERROR] in _dma_copy() : buffer unaligned\n");
313        _exit();
314    }
315
316    // get vspace page table pointer
317    unsigned int pt = _ptabs_vaddr[vspace_id];
318
319    // get src_paddr buffer physical addresse
320    _v2p_translate( (page_table_t*)pt,              // page table pointer
321                     src_vaddr>>12,                  // vpn
322                     &ppn,                           // ppn
323                     &flags );                       // flags
324    unsigned long long src_paddr = (((unsigned long long)ppn) << 12) | 
325                                   (unsigned long long)(src_vaddr & 0x00000FFF);
326
327    // get dst_paddr buffer physical addresse
328    _v2p_translate( (page_table_t*)pt,              // page table pointer
329                     dst_vaddr>>12,                  // vpn
330                     &ppn,                           // ppn
331                     &flags );                       // flags
332    unsigned long long dst_paddr = (((unsigned long long)ppn) << 12) | 
333                                   (unsigned long long)(dst_vaddr & 0x00000FFF);
334
335#if GIET_DEBUG_DMA_DRIVER
336_puts("\n - src_paddr   = ");
337_putl( src_paddr );
338_puts("\n - dst_paddr   = ");
339_putl( dst_paddr );
340_puts("\n");
341#endif
342
343    // dma channel configuration & lauching
344    _dma_start_transfer(  cluster_xy, channel_id, dst_paddr, src_paddr, size ); 
345
346    // scan dma channel status
347    unsigned int status = _dma_get_status( cluster_xy, channel_id );
348    while( (status != DMA_SUCCESS) && 
349           (status != DMA_READ_ERROR) &&
350           (status != DMA_WRITE_ERROR) )
351    {
352        status = _dma_get_status( cluster_xy, channel_id );
353
354#if GIET_DEBUG_DMA_DRIVER
355_puts("\n[DMA DEBUG] _dma_copy() : ... waiting on DMA_STATUS register\n");
356#endif
357
358    }
359   
360    // analyse status
361    if( status != DMA_SUCCESS )
362    {
363        _puts("\n[DMA ERROR] in _dma_copy() : bad DMA_STATUS\n");
364        _exit();
365    }
366    // reset dma channel
367    _dma_reset( cluster_xy, channel_id );
368
369#if GIET_DEBUG_DMA_DRIVER
370_puts("\n[DMA DEBUG] exit _dma_copy() at cycle ");
371_putd( _get_proctime() );
372_puts("\n");
373#endif
374
375#else // NB_DMA_CHANNELS == 0
376
377    _puts("\n[DMA ERROR] in _dma_copy() : NB_DMA_CHANNELS == 0\n");
378    _exit();
379
380#endif
381} // end _dma_copy
382
383/////////////////////////////////////
384void _dma_isr( unsigned int irq_type,
385               unsigned int irq_id,
386               unsigned int channel )
387{
388    _puts("\n[DMA ERROR] _dma_isr() not implemented\n");
389    _exit();
390}
391
392
393
394
395// tab-width: 4
396// c-basic-offset: 4
397// c-file-offsets:((innamespace . 0)(inline-open . 0))
398// indent-tabs-mode: nil
399// End:
400// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
401
Note: See TracBrowser for help on using the repository browser.