source: soft/giet_vm/giet_drivers/fbf_driver.c @ 287

Last change on this file since 287 was 275, checked in by cfuguet, 11 years ago
  • Adding volatile attribute for pointers used to address memory mapped hardware registers.
  • Removing the activation of interruptions before the execution of the ctx_switch function on the ioc_access function. This is to avoid been interrupted during the modification of task context variables.
File size: 15.8 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : fbf_driver.c
3// Date     : 23/05/2013
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7// The fbf_driver.c and fbf_driver.h files are part ot the GIET-VM kernel.
8// This driver supports the SoCLib vci_framebuffer component.
9//
10// It can exist only one frame buffer in the architecture.
11//
12// There exist two methods to access the VciFrameBuffer device:
13// 
14// 1) The _fb_sync_write() and _fb_sync_read() functions use a memcpy strategy
15// to implement the transfer between a data buffer (user space) and the frame
16// buffer (kernel space). They are blocking until completion of the transfer.
17//
18// 2) The _fb_cma_init(), _fb_cma_write() and _fb_cma_stop() functions use
19// the VciChbufDma component (non replicated) to transfer a flow of images from
20// an user space chained buffer (two buffers) to the frame buffer.
21// A CMA channel must be allocated to the task requesting it in the mapping_info,
22// and stored in the task context.
23///////////////////////////////////////////////////////////////////////////////////
24// The seg_fbf_base virtual address must be defined in giet_vsegs.ld file.
25///////////////////////////////////////////////////////////////////////////////////
26
27#include <giet_config.h>
28#include <fbf_driver.h>
29#include <utils.h>
30#include <dma_driver.h>
31#include <cma_driver.h>
32#include <tty_driver.h>
33#include <ctx_handler.h>
34#include <mmc_driver.h>
35#include <vmem.h>
36
37#if !defined(GIET_USE_IOMMU)
38# error: You must define GIET_USE_IOMMU in the giet_config.h file
39#endif
40
41#if !defined( USE_IOB )
42# error: You must define USE_IOB in the hard_config.h file
43#endif
44
45#define in_unckdata __attribute__((section (".unckdata")))
46
47////////////// memcpy approach //////////////////////////////////////////////////
48
49//////////////////////////////////////////////////////////////////////////////////
50// _fb_sync_write()
51// Transfer data from an memory buffer to the frame_buffer device using a memcpy.
52// - offset : offset (in bytes) in the frame buffer.
53// - buffer : base address of the memory buffer.
54// - length : number of bytes to be transfered.
55//////////////////////////////////////////////////////////////////////////////////
56
57unsigned int _fb_sync_write(unsigned int offset, 
58                            const void * buffer, 
59                            unsigned int length) 
60{
61    char* fb_address = (char *)&seg_fbf_base + offset;
62    _memcpy( fb_address, buffer, length);
63    return 0;
64}
65//////////////////////////////////////////////////////////////////////////////////
66// _fb_sync_read()
67// Transfer data from the frame_buffer device to a memory buffer using a memcpy.
68// - offset : offset (in bytes) in the frame buffer.
69// - buffer : base address of the memory buffer.
70// - length : number of bytes to be transfered.
71//////////////////////////////////////////////////////////////////////////////////
72unsigned int _fb_sync_read( unsigned int   offset, 
73                            void*          buffer, 
74                            unsigned int   length) 
75{
76    char* fb_address = (char *)&seg_fbf_base + offset;
77    _memcpy( buffer, fb_address, length);
78    return 0;
79}
80
81
82///////////////// CDMA approach //////////////////////////////////////////////////
83
84// This structure contains two chbuf descriptors that can be used by
85// the VciChbufDma component to tranfer a flow of images:
86// - The SRC chbuf descriptor contain two slots (two user buffers)
87// - The DST chbuf descriptor contains only one slot (frame buffer)
88
89typedef struct fb_cma_channel_s
90{
91    paddr_t       buf0;     // physical address + status for user buffer 0
92    paddr_t       buf1;     // physical address + status for user buffer 1
93    paddr_t       fbf;      // physical address + status for frame buffer
94    unsigned int  length;   // buffer length (number of bytes)
95    unsigned int  padding;  // unused (just to have channel size = 32 bytes)
96} fb_cma_channel_t;
97
98// array of FB_CMA channels descriptors (32 bytes per entry)
99// each entry contains one SRC and one DST chbuf descriptors.
100in_unckdata volatile fb_cma_channel_t
101_fb_cma_channel[NB_CMA_CHANNELS] __attribute__((aligned(64)));
102
103// array of physical addresses for the FB_CMA channels descriptors
104in_unckdata volatile paddr_t         
105_fb_cma_desc_paddr[NB_CMA_CHANNELS];
106
107//////////////////////////////////////////////////////////////////////////////////////
108// _fb_cma_init()
109// This function uses the _fb_cma_channel[] and _fb_cma_desc_paddr[] arrays,
110// (that are both indexed by the channel index), and does four things:
111//
112// 1) computes the physical addresses for the two source user buffers, for
113//    the destination frame buffer. It initialises the channel descriptor
114//    _fb_cma_channel[i], containing the SRC chbuf descriptor (two buffers),
115//    the DST chbuf descriptor (one single buffer), and the buffer length.
116//
117// 2) computes the physical address for the channel descriptor and register it
118//    in the _fb_cma_desc_paddr[i].
119//   
120// 3) makes a SYNC request to L2 cache for channel descriptor, because the
121//    channel descriptor is directly accessed in XRAM by the CMA component.
122//
123// 4) Starts the CMA hardware channel, that will poll the channel descriptor
124//    to fransfer an user buffer to the frame buffer as soon as the source
125//    user buffer is marked valid.
126//
127// Returns 0 if success, > 0 if error
128//////////////////////////////////////////////////////////////////////////////////////
129unsigned int _fb_cma_init( const void*  vbase0,  // first user buffer vbase address
130                           const void*  vbase1,  // second user buffer vbase address
131                           unsigned int length ) // buffer length (number of bytes)
132{
133#if NB_CMA_CHANNELS > 0
134
135    unsigned int  channel_id;          // CMA channel index
136    unsigned int  user_ptab;           // page table virtual address
137    unsigned int  ko;                  // unsuccessfull V2P translation
138    unsigned int  vaddr;               // virtual address
139    unsigned int  flags;               // protection flags
140    unsigned int  ppn;                 // physical page number
141    paddr_t       desc_paddr;          // physical address of channel descriptor
142
143    // get CMA channel index
144    channel_id = _get_context_slot(CTX_CMA_ID);
145    if ( channel_id >= NB_CMA_CHANNELS )
146    {
147        _tty_get_lock( 0 );
148        _puts("\n[GIET ERROR] in _fb_cma_init() : CMA channel index too large\n");
149        _tty_release_lock( 0 );
150        return 1;
151    }
152
153    // checking size for channel descriptor
154    if ( sizeof(fb_cma_channel_t) != 32 )
155    {
156        _tty_get_lock( 0 );
157        _puts("\n[GIET ERROR] in _fb_cma_init() : bad fb_cma_channel size\n");
158        _tty_release_lock( 0 );
159        return 1;
160    }
161
162    // checking channel descriptor alignment (32 bytes)
163    if ( (unsigned int)(&_fb_cma_channel[channel_id]) & 0x1F ) 
164    {
165        _tty_get_lock( 0 );
166        _puts("\n[GIET ERROR] in _fb_cma_init() : bad fb_cma_channel alignment\n");
167        _tty_release_lock( 0 );
168        return 1;
169    }
170
171    // checking user buffer virtual addresses and length alignment
172    if ( ((unsigned int)vbase0 & 0x3) || ((unsigned int)vbase1 & 0x3) || (length & 0x3) ) 
173    {
174        _tty_get_lock( 0 );
175        _puts("\n[GIET ERROR] in _fb_cma_init() : user buffer not word aligned\n");
176        _tty_release_lock( 0 );
177        return 1;
178    }
179
180    // get page table virtual address
181    user_ptab = _get_context_slot(CTX_PTAB_ID);
182
183    // compute and register frame buffer physical address
184    vaddr = ((unsigned int)&seg_fbf_base);
185    ko    = _v2p_translate( (page_table_t*) user_ptab, 
186                         (vaddr >> 12),
187                         &ppn, 
188                         &flags );
189    if (ko) 
190    {
191        _tty_get_lock( 0 );
192        _puts("\n[GIET ERROR] in _fb_cma_init() : frame buffer unmapped\n");
193        _tty_release_lock( 0 );
194        return 1;
195    }
196    _fb_cma_channel[channel_id].fbf = ((paddr_t)ppn << 12) | (vaddr & 0x00000FFF);
197
198    // Compute and register first user buffer physical address
199    vaddr = (unsigned int)vbase0; 
200    ko = _v2p_translate( (page_table_t*) user_ptab, 
201                         (vaddr >> 12),
202                         &ppn, 
203                         &flags );
204    if (ko) 
205    {
206        _tty_get_lock( 0 );
207        _puts("\n[GIET ERROR] in _fb_cma_init() : user buffer 0 unmapped\n");
208        _tty_release_lock( 0 );
209        return 1;
210    } 
211    if ((flags & PTE_U) == 0) 
212    {
213        _tty_get_lock( 0 );
214        _puts("[GIET ERROR] in _fb_cma_init() : user buffer 0 not in user space\n");
215        _tty_release_lock( 0 );
216        return 1; 
217    }
218    _fb_cma_channel[channel_id].buf0 = ((paddr_t)ppn << 12) | (vaddr & 0x00000FFF);
219
220    // Compute and register second user buffer physical address
221    vaddr = (unsigned int)vbase1; 
222    ko = _v2p_translate( (page_table_t*) user_ptab, 
223                         (vaddr >> 12),
224                         &ppn, 
225                         &flags );
226    if (ko) 
227    {
228        _tty_get_lock( 0 );
229        _puts("\n[GIET ERROR] in _fb_cma_init() : user buffer 1 unmapped\n");
230        _tty_release_lock( 0 );
231        return 1;
232    } 
233    if ((flags & PTE_U) == 0) 
234    {
235        _tty_get_lock( 0 );
236        _puts("[GIET ERROR] in _fb_cma_init() : user buffer 1 not in user space\n");
237        _tty_release_lock( 0 );
238        return 1; 
239    }
240    _fb_cma_channel[channel_id].buf1 = ((paddr_t)ppn << 12) | (vaddr & 0x00000FFF);
241
242    // register buffer length in channel descriptor
243    _fb_cma_channel[channel_id].length = length;
244
245    // Compute and register physical adress of the channel descriptor
246    vaddr = (unsigned int)(&_fb_cma_channel[channel_id]);
247    ko = _v2p_translate( (page_table_t*) user_ptab, 
248                         (vaddr >> 12),
249                         &ppn, 
250                         &flags );
251    if (ko) 
252    {
253        _tty_get_lock( 0 );
254        _puts("\n[GIET ERROR] in _fb_cma_init() : channel descriptor unmapped\n");
255        _tty_release_lock( 0 );
256        return 1;
257    } 
258    _fb_cma_desc_paddr[channel_id] = (((paddr_t)ppn) << 12) | (vaddr & 0x00000FFF);
259
260    desc_paddr                     = (((paddr_t)ppn) << 12) | (vaddr & 0x00000FFF);
261   
262
263#if GIET_DEBUG_FBF_DRIVER
264_tty_get_lock( 0 );
265_puts("\n[CMA DEBUG] fb_cma_init()");
266_puts("\n - fbf       pbase = ");
267_putl( _fb_cma_channel[channel_id].fbf );
268_puts("\n - buf0      pbase = ");
269_putl( _fb_cma_channel[channel_id].buf0 );
270_puts("\n - buf1      pbase = ");
271_putl( _fb_cma_channel[channel_id].buf1 );
272_puts("\n - channel   pbase = ");
273_putl( _fb_cma_desc_paddr[channel_id] );
274_puts("\n");
275_tty_release_lock( 0 );
276#endif
277
278    if ( USE_IOB )
279    {
280        // SYNC request for channel descriptor
281        _memc_sync( desc_paddr, 32 );
282    }
283
284    // CMA channel activation
285    unsigned int* cma_vbase = (unsigned int *)&seg_cma_base;
286    unsigned int  offset    = channel_id * CHBUF_CHANNEL_SPAN;
287
288    cma_vbase[offset + CHBUF_SRC_DESC]  = (unsigned int)(desc_paddr & 0xFFFFFFFF);
289    cma_vbase[offset + CHBUF_SRC_EXT]   = (unsigned int)(desc_paddr >> 32);
290    cma_vbase[offset + CHBUF_SRC_NBUFS] = 2;
291    cma_vbase[offset + CHBUF_DST_DESC]  = (unsigned int)(desc_paddr & 0xFFFFFFFF) + 16;
292    cma_vbase[offset + CHBUF_DST_EXT]   = (unsigned int)(desc_paddr >> 32);
293    cma_vbase[offset + CHBUF_DST_NBUFS] = 1;
294    cma_vbase[offset + CHBUF_BUF_SIZE]  = length;
295    cma_vbase[offset + CHBUF_PERIOD]    = 300;
296    cma_vbase[offset + CHBUF_RUN]       = 1;
297
298    return 0;
299
300#else
301
302    _tty_get_lock( 0 );
303    _puts("\n[GIET ERROR] in _fb_cma_init() : no CMA channel allocated\n");
304    _tty_release_lock( 0 );
305
306    return 1;
307#endif
308}
309////////////////////////////////////////////////////////////////////////////////////
310// _fb_cma_write()
311//
312// It updates the status of the SRC and DST chbuf descriptors, to allow the CMA
313// component to transfer the source user buffer to the frame buffer.
314//
315// If the IO Bridge component is used:
316// 1) it makes an INVAL request for the channel descriptor, before testing the
317//    source buffer status, because it is modified in XRAM by the CMA component.
318// 2) it makes a SYNC request for the source user buffer before activating the CMA
319//    transfer, because the data will be read from XRAM by the CMA component.
320// 3) it makes a SYNC request for the channel descriptor after modification
321//    of the SRC and DST status, because these descriptors will be read from XRAM
322//    by the CMA component.
323//
324// The buffer_id argument is the user buffer index (0 => buf0 / not 0 => buf1)
325// Returns 0 if success, > 0 if error
326////////////////////////////////////////////////////////////////////////////////////
327unsigned int _fb_cma_write( unsigned int buffer_id )
328{
329#if NB_CMA_CHANNELS > 0
330
331    volatile paddr_t buf_paddr;
332    unsigned int     buf_length;
333    unsigned int     full = 1;
334
335    unsigned int     count = 0;
336
337    // get CMA channel index
338    unsigned int channel_id = _get_context_slot(CTX_CMA_ID);
339
340#if GIET_DEBUG_FBF_DRIVER
341_tty_get_lock( 0 );
342_puts("\n[CMA DEBUG] fb_cma_write() for CMA channel ");
343_putd( channel_id );
344_puts(" / buf_id = ");
345_putd( buffer_id );
346_puts("\n");
347_tty_release_lock( 0 );
348#endif
349
350    // waiting buffer empty
351    while ( full )
352    { 
353        if ( USE_IOB )
354        {
355            // INVAL L2 cache for the channel descriptor,
356            _memc_inval( _fb_cma_desc_paddr[channel_id], 32 );
357
358            // INVAL L1 cache for the channel descriptor,
359            _dcache_buf_invalidate( &_fb_cma_channel[channel_id], 32 );
360        }
361
362        // read SRC buffer descriptor
363        if ( buffer_id == 0 ) buf_paddr = _fb_cma_channel[channel_id].buf0;
364        else                  buf_paddr = _fb_cma_channel[channel_id].buf1;
365        full = ( (unsigned int)(buf_paddr>>63) );
366
367        count++;
368        if ( count == 10 ) _exit();
369
370#if GIET_DEBUG_FBF_DRIVER
371_tty_get_lock( 0 );
372_puts(" - buffer descriptor = ");
373_putl( buf_paddr );
374_puts(" at cycle ");
375_putd( _get_proctime() );
376_puts("\n");
377_tty_release_lock( 0 );
378#endif
379
380    }
381
382    if ( USE_IOB )
383    {
384        // SYNC request for the user buffer because
385        // this buffer will be read from XRAM by the CMA component
386        _memc_sync( buf_paddr, _fb_cma_channel[channel_id].length );
387    }
388
389    // set SRC full
390    if ( buffer_id == 0 )
391    _fb_cma_channel[channel_id].buf0 = buf_paddr | 0x8000000000000000ULL;
392    else
393    _fb_cma_channel[channel_id].buf1 = buf_paddr | 0x8000000000000000ULL;
394
395    // set DST empty
396    _fb_cma_channel[channel_id].fbf  = _fb_cma_channel[channel_id].fbf
397                                       & 0x7FFFFFFFFFFFFFFFULL;
398
399    if ( USE_IOB )
400    {
401        // SYNC request for the channel descriptor, because
402        // it will be read in XRAM by the CMA component
403        _memc_sync( _fb_cma_desc_paddr[channel_id], 32 );
404    }
405
406    return 0;
407
408#else
409
410    _tty_get_lock( 0 );
411    _puts("\n[GIET ERROR] in _fb_cma_channel() : no CMA channel allocated\n");
412    _tty_release_lock( 0 );
413    return 1;
414
415#endif
416}
417//////////////////////////////////////////////////////////////////////////////////
418// _fb_cma_stop()
419// This function desactivates the CMA channel allocated to the calling task.
420// Returns 0 if success, > 0 if error
421//////////////////////////////////////////////////////////////////////////////////
422unsigned int _fb_cma_stop( unsigned int buffer_id )
423{
424#if NB_CMA_CHANNELS > 0
425
426    // get CMA channel allocated
427    unsigned int channel_id = _get_context_slot(CTX_CMA_ID);
428
429    // CMA channel desactivation
430    unsigned int* cma_vbase = (unsigned int *)&seg_cma_base;
431    unsigned int  offset     = channel_id * CHBUF_CHANNEL_SPAN;
432    cma_vbase[offset + CHBUF_RUN] = 0;
433    return 0;
434
435#else
436
437    _tty_get_lock( 0 );
438    _puts("\n[GIET ERROR] in _fb_cma_stop() : no CMA channel allocated\n");
439    _tty_release_lock( 0 );
440    return 1;
441
442#endif
443}
444   
445
446// Local Variables:
447// tab-width: 4
448// c-basic-offset: 4
449// c-file-offsets:((innamespace . 0)(inline-open . 0))
450// indent-tabs-mode: nil
451// End:
452// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
453
Note: See TracBrowser for help on using the repository browser.