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

Last change on this file since 345 was 345, checked in by cfuguet, 10 years ago

giet_vm optimizations:

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