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

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

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

File size: 11.9 KB
RevLine 
[258]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>
[320]9#include <hard_config.h>
[258]10#include <dma_driver.h>
[456]11#include <tty0.h>
[258]12#include <vmem.h>
[320]13#include <utils.h>
[345]14#include <io.h>
[258]15
[263]16#if !defined(X_SIZE)
17# error: You must define X_SIZE in the hard_config.h file
[258]18#endif
19
[263]20#if !defined(Y_SIZE)
21# error: You must define X_SIZE in the hard_config.h file
[258]22#endif
23
[263]24#if !defined(X_WIDTH)
25# error: You must define X_WIDTH in the hard_config.h file
[258]26#endif
27
[263]28#if !defined(Y_WIDTH)
29# error: You must define X_WIDTH in the hard_config.h file
[258]30#endif
31
[263]32#if !defined(NB_DMA_CHANNELS)
33# error: You must define NB_DMA_CHANNELS in the hard_config.h file
[258]34#endif
35
[320]36#if !defined(SEG_DMA_BASE)
37# error: You must define SEG_DMA_BASE in the hard_config.h file
38#endif
39
[333]40#if !defined(PERI_CLUSTER_INCREMENT)
41# error: You must define PERI_CLUSTER_INCREMENT in the hard_config.h file
[320]42#endif
43
[345]44extern volatile unsigned int _ptabs_vaddr[];
[258]45
[345]46///////////////////////////////////////////////////////////////////////////////
47// This low level function returns the value contained in register "index"
48// in the DMA component contained in cluster "cluster_xy"
49///////////////////////////////////////////////////////////////////////////////
[496]50
51#if NB_DMA_CHANNELS > 0
[345]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}
[496]65#endif
[345]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///////////////////////////////////////////////////////////////////////////////
[496]71
72#if NB_DMA_CHANNELS > 0
[345]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}
[496]87#endif
[345]88
[437]89////////////////////////////////////////////////
[263]90unsigned int _dma_init( unsigned int cluster_xy,
[258]91                        unsigned int channel_id )
92{
93#if NB_DMA_CHANNELS > 0
[263]94
[258]95    // parameters checking
[263]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; 
[258]100    if (channel_id >= NB_DMA_CHANNELS)  return 1; 
101
102    // disable interrupt for selected channel
[345]103    _dma_set_register(cluster_xy, channel_id, DMA_IRQ_DISABLE, 1);
[258]104    return 0;
105#else
106    return 1;
107#endif
108}
109
[437]110//////////////////////////////////////////////////
[263]111unsigned int _dma_reset( unsigned int cluster_xy, 
[258]112                         unsigned int channel_id ) 
113{
114#if NB_DMA_CHANNELS > 0
[263]115
[258]116    // parameters checking
[263]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; 
[258]121    if (channel_id >= NB_DMA_CHANNELS)  return 1; 
122
123    // reset selected channel
[345]124    _dma_set_register(cluster_xy, channel_id, DMA_RESET, 0);
[258]125    return 0;
126#else
127    return 1;
128#endif
129}
130
[437]131//////////////////////////////////////////////////////
[263]132unsigned int _dma_get_status( unsigned int cluster_xy, 
[258]133                              unsigned int channel_id ) 
134{
135#if NB_DMA_CHANNELS > 0
[263]136
[258]137    // parameters checking
[263]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; 
[258]142    if (channel_id >= NB_DMA_CHANNELS)  return 1;
143
144    // get selected channel status
[345]145    return _dma_get_register(cluster_xy, channel_id, DMA_LEN);
[258]146#else
[267]147    return DMA_IDLE;
[258]148#endif
149}
150
[437]151////////////////////////////////////////////////////////
[343]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
[258]157{
158#if NB_DMA_CHANNELS > 0
[263]159
[258]160    // selected channel configuration and lauching
[345]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);
[343]171
[258]172#endif
173}
[343]174
[437]175///////////////////////////////////////////////////////
[343]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    {
[437]189        _puts("\n[DMA ERROR] in _dma_physical_copy() : illegal DMA channel ");
[343]190        _exit();
191    }
192
193    // check buffers alignment constraints
194    if ( (dst_paddr & 0x3)   || (src_paddr & 0x3) || (size & 0x3) )
195    {
[437]196        _puts("\n[DMA ERROR] in _dma_physical_copy() : buffer unaligned\n");
[343]197        _exit();
198    }
199
200#if GIET_DEBUG_DMA_DRIVER
[437]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");
[343]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
[437]230_puts("\n[DMA DEBUG] _dma_physical_copy() : ... waiting on DMA_STATUS register\n");
[343]231#endif
232
233    }
234   
235    // analyse status
236    if( status != DMA_SUCCESS )
237    {
[437]238        _puts("\n[DMA ERROR] in _dma_physical_copy() : bad DMA_STATUS");
[343]239        _exit();
240    }
[437]241
[343]242    // reset dma channel
243    _dma_reset( cluster_xy, channel_id );
244
245#if GIET_DEBUG_DMA_DRIVER
[437]246_puts("\n[DMA DEBUG] exit _dma_physical_copy() at cycle ");
247_putd( _get_proctime() );
248_puts("\n");
[343]249#endif
250
251#else // NB_DMA_CHANNELS == 0
[437]252
253    _puts("\n[DMA ERROR] in _dma_physical_copy() : NB_DMA_CHANNELS == 0\n");
[343]254    _exit();
[437]255
[343]256#endif
257}
258
[437]259
260////////////////////////////////////////
[343]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
[258]267{
268#if NB_DMA_CHANNELS > 0
269
[343]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    {
[437]275        _puts("\n[DMA ERROR] in _dma_copy() : illegal DMA channel ");
[343]276        _exit();
277    }
[258]278
[343]279    // check buffers alignment constraints
280    if ( (dst_vaddr & 0x3)   || (src_vaddr & 0x3) || (size & 0x3) )
281    {
[437]282        _puts("\n[DMA ERROR] in _dma_copy() : buffer unaligned\n");
[343]283        _exit();
284    }
285
[258]286    unsigned int ppn;
287    unsigned int flags;
288
289#if GIET_DEBUG_DMA_DRIVER
[437]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");
[258]305#endif
306
307    // checking alignment constraints
[343]308    if ( (((unsigned int)dst_vaddr) & 0x3) ||
309         (((unsigned int)src_vaddr) & 0x3) ||
[258]310         (size & 0x3) )
311    {
[437]312        _puts("\n[DMA ERROR] in _dma_copy() : buffer unaligned\n");
[258]313        _exit();
314    }
315
[343]316    // get vspace page table pointer
[345]317    unsigned int pt = _ptabs_vaddr[vspace_id];
[258]318
[343]319    // get src_paddr buffer physical addresse
[481]320    _v2p_translate( (page_table_t*)pt,              // page table pointer
321                     src_vaddr>>12,                  // vpn
322                     &ppn,                           // ppn
323                     &flags );                       // flags
[258]324    unsigned long long src_paddr = (((unsigned long long)ppn) << 12) | 
[343]325                                   (unsigned long long)(src_vaddr & 0x00000FFF);
[258]326
[343]327    // get dst_paddr buffer physical addresse
[481]328    _v2p_translate( (page_table_t*)pt,              // page table pointer
329                     dst_vaddr>>12,                  // vpn
330                     &ppn,                           // ppn
331                     &flags );                       // flags
[258]332    unsigned long long dst_paddr = (((unsigned long long)ppn) << 12) | 
[343]333                                   (unsigned long long)(dst_vaddr & 0x00000FFF);
[258]334
335#if GIET_DEBUG_DMA_DRIVER
[437]336_puts("\n - src_paddr   = ");
337_putl( src_paddr );
338_puts("\n - dst_paddr   = ");
339_putl( dst_paddr );
340_puts("\n");
[258]341#endif
342
343    // dma channel configuration & lauching
[343]344    _dma_start_transfer(  cluster_xy, channel_id, dst_paddr, src_paddr, size ); 
[258]345
346    // scan dma channel status
[263]347    unsigned int status = _dma_get_status( cluster_xy, channel_id );
[258]348    while( (status != DMA_SUCCESS) && 
349           (status != DMA_READ_ERROR) &&
350           (status != DMA_WRITE_ERROR) )
351    {
[263]352        status = _dma_get_status( cluster_xy, channel_id );
[258]353
354#if GIET_DEBUG_DMA_DRIVER
[437]355_puts("\n[DMA DEBUG] _dma_copy() : ... waiting on DMA_STATUS register\n");
[258]356#endif
357
358    }
359   
360    // analyse status
361    if( status != DMA_SUCCESS )
362    {
[437]363        _puts("\n[DMA ERROR] in _dma_copy() : bad DMA_STATUS\n");
[258]364        _exit();
365    }
366    // reset dma channel
[263]367    _dma_reset( cluster_xy, channel_id );
[258]368
369#if GIET_DEBUG_DMA_DRIVER
[437]370_puts("\n[DMA DEBUG] exit _dma_copy() at cycle ");
371_putd( _get_proctime() );
372_puts("\n");
[258]373#endif
374
375#else // NB_DMA_CHANNELS == 0
[437]376
377    _puts("\n[DMA ERROR] in _dma_copy() : NB_DMA_CHANNELS == 0\n");
[258]378    _exit();
[437]379
[258]380#endif
381} // end _dma_copy
382
[437]383/////////////////////////////////////
[320]384void _dma_isr( unsigned int irq_type,
385               unsigned int irq_id,
386               unsigned int channel )
387{
[437]388    _puts("\n[DMA ERROR] _dma_isr() not implemented\n");
[320]389    _exit();
390}
[258]391
392
393
[320]394
[258]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.