source: soft/giet_vm/sys/drivers.c @ 162

Last change on this file since 162 was 160, checked in by karaoui, 12 years ago

giet-vm new version

File size: 27.4 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : drivers.c
3// Date     : 01/04/2012
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7// The drivers.c and drivers.h files are part ot the GIET nano kernel.
8// They contains the drivers for the peripherals available in the SoCLib library:
9// - vci_multi_tty
10// - vci_multi_timer
11// - vci_multi_dma
12// - vci_multi_icu
13// - vci_gcd
14// - vci_frame_buffer
15// - vci_block_device
16//
17// The following global parameters must be defined in the giet_config.h file:
18// - NB_PROCS  : number of PROCS per cluster (if not zero)
19// - NB_DMAS   : number of DMA channels per cluster (if not zero)
20// - NB_TIMERS : number of TIMERS per cluster (if not zero)
21// - NB_TTYS   : number of TTY terminals per cluster (if not zero)
22//
23// The following base addresses must be defined in the sys.ld file:
24// - seg_icu_base
25// - seg_timer_base
26// - seg_tty_base
27// - seg_gcd_base
28// - seg_dma_base
29// - seg_fb_base
30// - seg_ioc_base
31///////////////////////////////////////////////////////////////////////////////////
32
33#include <sys_handler.h>
34#include <giet_config.h>
35#include <drivers.h>
36#include <common.h>
37#include <hwr_mapping.h>
38#include <mips32_registers.h>
39#include <ctx_handler.h>
40
41#if !defined(NB_PROCS)
42# error: You must define NB_PROCS in 'giet_config.h' file!
43#endif
44#if !defined(NB_CLUSTERS)
45# error: You must define NB_CLUSTERS in 'giet_config.h' file!
46#endif
47#if !defined(CLUSTER_SPAN)
48# error: You must define CLUSTER_SPAN in 'giet_config.h' file!
49#endif
50#if !defined(NB_TTYS)
51# error: You must define NB_TTYS in 'giet_config.h' file!
52#endif
53#if !defined(NB_DMAS)
54# error: You must define NB_DMAS in 'giet_config.h' file!
55#endif
56#if !defined(NB_TIMERS)
57# error: You must define NB_TIMERS in 'giet_config.h' file!
58#endif
59
60/////////////////////////////////////////////////////////////////////////////
61//      Global (uncachable) variables
62/////////////////////////////////////////////////////////////////////////////
63
64#define in_unckdata __attribute__((section (".unckdata")))
65
66in_unckdata volatile unsigned int  _dma_status[NB_DMAS];
67in_unckdata volatile unsigned char _dma_busy[NB_DMAS] = { [0 ... NB_DMAS-1] = 0 };
68
69in_unckdata volatile unsigned char _ioc_status;
70in_unckdata volatile unsigned char _ioc_done = 0;
71in_unckdata volatile unsigned int  _ioc_lock = 0;
72
73in_unckdata volatile unsigned int  _tty_lock[NB_TTYS] = { [0 ... NB_TTYS-1] = 0 };
74in_unckdata volatile unsigned char _tty_get_buf[NB_TTYS];
75in_unckdata volatile unsigned char _tty_get_full[NB_TTYS] = { [0 ... NB_TTYS-1] = 0 };
76
77//////////////////////////////////////////////////////////////////////////////
78//      VciMultiTimer driver
79//////////////////////////////////////////////////////////////////////////////
80// The number of independant timers per cluster is defined by the
81// configuration parameter NB_TIMERS.
82// The total number of timers is NB_CLUSTERS * NB_TIMERS
83// The global timer index = cluster_id*NB_TIMER + timer_id
84//////////////////////////////////////////////////////////////////////////////
85
86//////////////////////////////////////////////////////////////////////////////
87// _timer_write()
88//
89// Write a 32-bit word in a memory mapped register of a timer device.
90// Returns 0 if success, > 0 if error.
91//////////////////////////////////////////////////////////////////////////////
92unsigned int _timer_write( unsigned int global_timer_index,
93                           unsigned int register_index, 
94                           unsigned int value )
95{
96    volatile unsigned int *timer_address;
97
98    unsigned int        cluster_id = global_timer_index / NB_TIMERS;
99    unsigned int        timer_id   = global_timer_index % NB_TIMERS;
100
101    /* parameters checking */
102    if ( register_index >= TIMER_SPAN)                  return 1;
103    if ( global_timer_index >= NB_CLUSTERS*NB_TIMERS )  return 1;
104
105    timer_address = (unsigned int*)&seg_timer_base + 
106                    ( cluster_id * CLUSTER_SPAN )  +
107                    ( timer_id * TIMER_SPAN );
108
109    timer_address[register_index] = value; /* write word */
110
111    return 0;
112}
113
114//////////////////////////////////////////////////////////////////////////////
115// _timer_read()
116//
117// Read a 32-bit word in a memory mapped register of a timer device.
118// Returns 0 if success, > 0 if error.
119//////////////////////////////////////////////////////////////////////////////
120unsigned int _timer_read(unsigned int global_timer_index,
121                         unsigned int register_index, 
122                         unsigned int *buffer)
123{
124    volatile unsigned int *timer_address;
125
126    unsigned int        cluster_id = global_timer_index / NB_TIMERS;
127    unsigned int        timer_id   = global_timer_index % NB_TIMERS;
128
129    /* parameters checking */
130    if ( register_index >= TIMER_SPAN)                  return 1;
131    if ( global_timer_index >= NB_CLUSTERS*NB_TIMERS )  return 1;
132
133    timer_address = (unsigned int*)&seg_timer_base + 
134                    ( cluster_id * CLUSTER_SPAN )  +
135                    ( timer_id * TIMER_SPAN );
136
137    *buffer = timer_address[register_index]; /* read word */
138
139    return 0;
140}
141
142/////////////////////////////////////////////////////////////////////////////////
143//      VciMultiTty driver
144/////////////////////////////////////////////////////////////////////////////////
145// The total number of TTYs is defined by the configuration parameter NB_TTYS.
146// The system terminal is TTY[0].
147// The TTYs are allocated to applications by the GIET in the boot phase.
148// The nummber of TTYs allocated to each application, and the TTY used by each
149// task can be defined in the mapping_info data structure.
150// For each user task, the tty_id is stored in the context of the task (slot 34),
151// and must be explicitely defined in the boot code.
152// The TTY address is always computed as : seg_tty_base + tty_id*TTY_SPAN
153///////////////////////////////////////////////////////////////////////////////////
154
155///////////////////////////////////////////////////////////////////////////////////
156// tty_get_lock()
157//
158// This blocking function is intended to be used by the _tty_write() function
159// to provide exclusive access to the TTY. It is not used yet, because it appears
160// that it creates livelock situations...
161///////////////////////////////////////////////////////////////////////////////////
162static inline void _tty_get_lock( unsigned int tty_id )
163{
164    register unsigned int delay = (_proctime() & 0xF) << 4;
165    register unsigned int *plock = (unsigned int*)&_tty_lock[tty_id];
166
167    asm volatile (
168            "_tty_llsc:             \n"
169            "ll   $2,    0(%0)      \n" /* $2 <= _tty_lock current value */
170            "bnez $2,    _tty_delay \n" /* delay if _tty_lock already taken */
171            "li   $3,    1          \n" /* $3 <= argument for sc */
172            "sc   $3,    0(%0)      \n" /* try to set _tty_lock */
173            "bnez $3,    _tty_ok    \n" /* exit if atomic */
174            "_tty_delay:            \n"
175            "move $4,    %1         \n" /* $4 <= delay */
176            "_tty_loop:             \n"
177            "addi $4,    $4,    -1  \n" /* $4 <= $4 - 1 */
178            "beqz $4,    _tty_loop  \n" /* test end delay */
179            "j           _tty_llsc  \n" /* retry */
180            "_tty_ok:               \n"
181            :
182            :"r"(plock), "r"(delay)
183            :"$2", "$3", "$4");
184}
185
186//////////////////////////////////////////////////////////////////////////////
187// _tty_write()
188//
189// Write one or several characters directly from a fixed-length user buffer to
190// the TTY_WRITE register of the TTY controler.
191// It doesn't use the TTY_PUT_IRQ interrupt and the associated kernel buffer.
192// This is a non blocking call: it tests the TTY_STATUS register, and stops
193// the transfer as soon as the TTY_STATUS[WRITE] bit is set.
194// The function returns  the number of characters that have been written.
195//////////////////////////////////////////////////////////////////////////////
196unsigned int _tty_write(const char *buffer, unsigned int length)
197{
198    volatile unsigned int *tty_address;
199
200    unsigned int proc_id;
201    unsigned int task_id;
202    unsigned int tty_id;
203    unsigned int nwritten;
204
205    proc_id = _procid();
206   
207    task_id = _scheduler[proc_id].current;
208    tty_id  = _scheduler[proc_id].context[task_id][CTX_TTY_ID];
209
210    tty_address = (unsigned int*)&seg_tty_base + tty_id*TTY_SPAN;
211
212    for (nwritten = 0; nwritten < length; nwritten++)
213    {
214        /* check tty's status */
215        if ((tty_address[TTY_STATUS] & 0x2) == 0x2)
216            break;
217        else
218            /* write character */
219            tty_address[TTY_WRITE] = (unsigned int)buffer[nwritten];
220    }
221    return nwritten;
222}
223
224//////////////////////////////////////////////////////////////////////////////
225// _tty_read_irq()
226//
227// This non-blocking function uses the TTY_GET_IRQ[tty_id] interrupt and
228// the associated // kernel buffer, that has been written by the ISR.
229// It fetches one single character from the _tty_get_buf[tty_id] kernel
230// buffer, writes this character to the user buffer, and resets the
231// _tty_get_full[tty_id] buffer.
232// Returns 0 if the kernel buffer is empty, 1 if the buffer is full.
233//////////////////////////////////////////////////////////////////////////////
234unsigned int _tty_read_irq(char *buffer, unsigned int length)
235{
236    unsigned int proc_id;
237    unsigned int task_id;
238    unsigned int tty_id;
239    unsigned int ret;
240
241    proc_id = _procid();
242    task_id = _scheduler[proc_id].current;
243    tty_id  = _scheduler[proc_id].context[task_id][CTX_TTY_ID];
244
245    if (_tty_get_full[tty_id] == 0) 
246    {
247        ret = 0;
248    }
249    else
250    {
251        *buffer = _tty_get_buf[tty_id];
252        _tty_get_full[tty_id] = 0;
253        ret = 1;
254    }
255    return ret;
256}
257
258////////////////////////////////////////////////////////////////////////////////
259// _tty_read()
260//
261// This non-blocking function fetches one character directly from the TTY_READ
262// register of the TTY controler, and writes this character to the user buffer.
263// It doesn't use the TTY_GET_IRQ interrupt and the associated kernel buffer.
264// It doesn't take the lock protecting exclusive access...
265// Returns 0 if the register is empty, 1 if the register is full.
266////////////////////////////////////////////////////////////////////////////////
267unsigned int _tty_read(char *buffer, unsigned int length)
268{
269    volatile unsigned int *tty_address;
270
271    unsigned int proc_id;
272    unsigned int task_id;
273    unsigned int tty_id;
274
275    proc_id = _procid();
276    task_id = _scheduler[proc_id].current;
277    tty_id  = _scheduler[proc_id].context[task_id][CTX_TTY_ID];
278
279    tty_address = (unsigned int*)&seg_tty_base + tty_id*TTY_SPAN;
280
281    if ((tty_address[TTY_STATUS] & 0x1) != 0x1) return 0;
282
283    *buffer = (char)tty_address[TTY_READ];
284    return 1;
285}
286
287////////////////////////////////////////////////////////////////////////////////
288//      VciMultiIcu driver
289////////////////////////////////////////////////////////////////////////////////
290// There is in principle one MULTI-ICU component per cluster, and the
291// number of independant ICUs is equal to NB_PROCS, because there is
292// one ICU per processor.
293////////////////////////////////////////////////////////////////////////////////
294
295////////////////////////////////////////////////////////////////////////////////
296// _icu_write()
297//
298// Write a 32-bit word in a memory mapped register of the ICU device. The
299// base address is deduced by the proc_id.
300// Returns 0 if success, > 0 if error.
301////////////////////////////////////////////////////////////////////////////////
302unsigned int _icu_write(unsigned int register_index, unsigned int value)
303{
304    volatile unsigned int *icu_address;
305    unsigned int proc_id;
306
307    /* parameters checking */
308    if (register_index >= ICU_END)
309        return 1;
310
311    proc_id = _procid();
312    icu_address = (unsigned int*)&seg_icu_base + (proc_id * ICU_SPAN);
313    icu_address[register_index] = value;   /* write word */
314    return 0;
315}
316
317////////////////////////////////////////////////////////////////////////////////
318// _icu_read()
319//
320// Read a 32-bit word in a memory mapped register of the ICU device. The
321// ICU base address is deduced by the proc_id.
322// Returns 0 if success, > 0 if error.
323////////////////////////////////////////////////////////////////////////////////
324unsigned int _icu_read(unsigned int register_index, unsigned int *buffer)
325{
326    volatile unsigned int *icu_address;
327    unsigned int proc_id;
328
329    /* parameters checking */
330    if (register_index >= ICU_END)
331        return 1;
332
333    proc_id = _procid();
334    icu_address = (unsigned int*)&seg_icu_base + (proc_id * ICU_SPAN);
335    *buffer = icu_address[register_index]; /* read word */
336    return 0;
337}
338
339////////////////////////////////////////////////////////////////////////////////
340//      VciGcd driver
341////////////////////////////////////////////////////////////////////////////////
342// The Greater Dommon Divider is a -very- simple hardware coprocessor
343// performing the computation of a GCD of two 32 bits integers.
344// It has no DMA capability.
345////////////////////////////////////////////////////////////////////////////////
346
347////////////////////////////////////////////////////////////////////////////////
348// _gcd_write()
349//
350// Write a 32-bit word in a memory mapped register of the GCD coprocessor.
351// Returns 0 if success, > 0 if error.
352////////////////////////////////////////////////////////////////////////////////
353unsigned int _gcd_write(unsigned int register_index, unsigned int value)
354{
355    volatile unsigned int *gcd_address;
356
357    /* parameters checking */
358    if (register_index >= GCD_END)
359        return 1;
360
361    gcd_address = (unsigned int*)&seg_gcd_base;
362    gcd_address[register_index] = value; /* write word */
363    return 0;
364}
365
366////////////////////////////////////////////////////////////////////////////////
367// _gcd_read()
368//
369// Read a 32-bit word in a memory mapped register of the GCD coprocessor.
370// Returns 0 if success, > 0 if error.
371////////////////////////////////////////////////////////////////////////////////
372unsigned int _gcd_read(unsigned int register_index, unsigned int *buffer)
373{
374    volatile unsigned int *gcd_address;
375
376    /* parameters checking */
377    if (register_index >= GCD_END)
378        return 1;
379
380    gcd_address = (unsigned int*)&seg_gcd_base;
381    *buffer = gcd_address[register_index]; /* read word */
382    return 0;
383}
384
385////////////////////////////////////////////////////////////////////////////////
386// VciBlockDevice driver
387////////////////////////////////////////////////////////////////////////////////
388// The VciBlockDevice is a simple external storage contrÃŽler.
389// The three functions below use the three variables _ioc_lock _ioc_done,  and
390// _ioc_status for synchronsation.
391// As the IOC component can be used by several programs running in parallel,
392// the _ioc_lock variable guaranties exclusive access to the device.  The
393// _ioc_read() and _ioc_write() functions use atomic LL/SC to get the lock.
394// and set _ioc_lock to a non zero value.  The _ioc_write() and _ioc_read()
395// functions are blocking, polling the _ioc_lock variable until the device is
396// available.
397// When the tranfer is completed, the ISR routine activated by the IOC IRQ
398// set the _ioc_done variable to a non-zero value. Possible address errors
399// detected by the IOC peripheral are reported by the ISR in the _ioc_status
400// variable.
401// The _ioc_completed() function is polling the _ioc_done variable, waiting for
402// tranfer conpletion. When the completion is signaled, the _ioc_completed()
403// function reset the _ioc_done variable to zero, and releases the _ioc_lock
404// variable.
405//
406// In a multi-processing environment, this polling policy should be replaced by
407// a descheduling policy for the requesting process.
408///////////////////////////////////////////////////////////////////////////////
409
410///////////////////////////////////////////////////////////////////////////////
411// _ioc_get_lock()
412//
413// This blocking helper is used by '_ioc_read()' and '_ioc_write()' functions
414// to get _ioc_lock using atomic LL/SC.
415///////////////////////////////////////////////////////////////////////////////
416static inline void _ioc_get_lock()
417{
418    register unsigned int delay = (_proctime() & 0xF) << 4;
419    register unsigned int *plock = (unsigned int*)&_ioc_lock;
420
421    asm volatile (
422            "_ioc_llsc:             \n"
423            "ll   $2,    0(%0)      \n" /* $2 <= _ioc_lock current value */
424            "bnez $2,    _ioc_delay \n" /* delay if _ioc_lock already taken */
425            "li   $3,    1          \n" /* $3 <= argument for sc */
426            "sc   $3,    0(%0)      \n" /* try to set _ioc_lock */
427            "bnez $3,    _ioc_ok    \n" /* exit if atomic */
428            "_ioc_delay:            \n"
429            "move $4,    %1         \n" /* $4 <= delay */
430            "_ioc_loop:             \n"
431            "addi $4,    $4,    -1  \n" /* $4 <= $4 - 1 */
432            "beqz $4,    _ioc_loop  \n" /* test end delay */
433            "j           _ioc_llsc  \n" /* retry */
434            "_ioc_ok:               \n"
435            :
436            :"r"(plock), "r"(delay)
437            :"$2", "$3", "$4");
438}
439
440///////////////////////////////////////////////////////////////////////////////
441//  _ioc_write()
442//
443// Transfer data from a memory buffer to a file on the block_device.
444// The source memory buffer must be in user address space.
445// - lba    : first block index on the disk.
446// - buffer : base address of the memory buffer.
447// - count  : number of blocks to be transfered.
448// Returns 0 if success, > 0 if error.
449///////////////////////////////////////////////////////////////////////////////
450unsigned int _ioc_write( unsigned int   lba, 
451                         const void*    buffer, 
452                         unsigned int   count)
453{
454    volatile unsigned int *ioc_address;
455
456    ioc_address = (unsigned int*)&seg_ioc_base;
457
458    /* buffer must be in user space */
459    unsigned int block_size = ioc_address[BLOCK_DEVICE_BLOCK_SIZE];
460
461    if (((unsigned int)buffer >= 0x80000000)
462            || (((unsigned int)buffer + block_size*count) >= 0x80000000))
463        return 1;
464
465    /* get the lock on ioc device */
466    _ioc_get_lock();
467
468    /* block_device configuration for the write transfer */
469    ioc_address[BLOCK_DEVICE_BUFFER] = (unsigned int)buffer;
470    ioc_address[BLOCK_DEVICE_COUNT] = count;
471    ioc_address[BLOCK_DEVICE_LBA] = lba;
472    ioc_address[BLOCK_DEVICE_IRQ_ENABLE] = 1;
473    ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_WRITE;
474
475    return 0;
476}
477
478///////////////////////////////////////////////////////////////////////////////
479// _ioc_read()
480//
481// Transfer data from a file on the block device to a memory buffer.
482// The destination memory buffer must be in user address space.
483// - lba    : first block index on the disk.
484// - buffer : base address of the memory buffer.
485// - count  : number of blocks to be transfered.
486// All cache lines corresponding to the the target buffer are invalidated
487// for cache coherence.
488// Returns 0 if success, > 0 if error.
489///////////////////////////////////////////////////////////////////////////////
490unsigned int _ioc_read( unsigned int    lba, 
491                        void*           buffer, 
492                        unsigned int    count )
493{
494    volatile unsigned int *ioc_address;
495
496    ioc_address = (unsigned int*)&seg_ioc_base;
497
498    /* buffer must be in user space */
499    unsigned int block_size = ioc_address[BLOCK_DEVICE_BLOCK_SIZE];
500
501    if (((unsigned int)buffer >= 0x80000000)
502            || (((unsigned int)buffer + block_size*count) >= 0x80000000))
503        return 1;
504
505    /* get the lock on ioc device */
506    _ioc_get_lock();
507
508    /* block_device configuration for the read transfer */
509    ioc_address[BLOCK_DEVICE_BUFFER] = (unsigned int)buffer;
510    ioc_address[BLOCK_DEVICE_COUNT] = count;
511    ioc_address[BLOCK_DEVICE_LBA] = lba;
512    ioc_address[BLOCK_DEVICE_IRQ_ENABLE] = 1;
513    ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_READ;
514
515    /* invalidation of data cache */
516    _dcache_buf_invalidate(buffer, block_size*count);
517
518    return 0;
519}
520
521/////////////////////////////////////////////////////////////////////////////////
522// _ioc_completed()
523//
524// This function checks completion of an I/O transfer and reports errors.
525// As it is a blocking call, the processor is stalled until the next interrupt.
526// Returns 0 if success, > 0 if error.
527/////////////////////////////////////////////////////////////////////////////////
528unsigned int _ioc_completed()
529{
530    unsigned int ret;
531
532    /* busy waiting */
533    while (_ioc_done == 0)
534        asm volatile("nop");
535
536    /* test IOC status */
537    if ((_ioc_status != BLOCK_DEVICE_READ_SUCCESS)
538            && (_ioc_status != BLOCK_DEVICE_WRITE_SUCCESS)) ret = 1;    /* error */
539    else                                                    ret = 0;    /* success */
540
541    /* reset synchronization variables */
542    _ioc_lock =0;
543    _ioc_done =0;
544
545    return ret;
546}
547
548//////////////////////////////////////////////////////////////////////////////////
549//      VciFrameBuffer driver
550//////////////////////////////////////////////////////////////////////////////////
551// The '_fb_sync_write' and '_fb_sync_read' functions use a memcpy strategy to
552// implement the transfer between a data buffer (user space) and the frame
553// buffer (kernel space). They are blocking until completion of the transfer.
554// The '_fb_write()', '_fb_read()' and '_fb_completed()' functions use the DMA
555// coprocessor to transfer data between the user buffer and the frame buffer.
556// These  functions use a polling policy to test the global variables _dma_busy[i]
557// and detect the transfer completion. 
558// There is  NB_PROCS DMA channels, that are indexed by the proc_id.
559// The _dma_busy[i] synchronisation variables (one per channel) are set by the OS,
560// and reset by the ISR.
561//////////////////////////////////////////////////////////////////////////////////
562
563//////////////////////////////////////////////////////////////////////////////////
564// _fb_sync_write()
565// Transfer data from an memory buffer to the frame_buffer device using
566// a memcpy. The source memory buffer must be in user address space.
567// - offset : offset (in bytes) in the frame buffer.
568// - buffer : base address of the memory buffer.
569// - length : number of bytes to be transfered.
570// Returns 0 if success, > 0 if error.
571//////////////////////////////////////////////////////////////////////////////////
572unsigned int _fb_sync_write( unsigned int       offset, 
573                             const void*        buffer, 
574                             unsigned int       length )
575{
576    volatile unsigned char *fb_address;
577
578    /* buffer must be in user space */
579    if (((unsigned int)buffer >= 0x80000000)
580            || (((unsigned int)buffer + length ) >= 0x80000000 ))
581        return 1;
582
583    fb_address = (unsigned char*)&seg_fb_base + offset;
584
585    /* buffer copy */
586    memcpy((void*)fb_address, (void*)buffer, length);
587
588    return 0;
589}
590
591//////////////////////////////////////////////////////////////////////////////////
592// _fb_sync_read()
593// Transfer data from the frame_buffer device to a memory buffer using
594// a memcpy. The destination memory buffer must be in user address space.
595// - offset : offset (in bytes) in the frame buffer.
596// - buffer : base address of the memory buffer.
597// - length : number of bytes to be transfered.
598// Returns 0 if success, > 0 if error.
599//////////////////////////////////////////////////////////////////////////////////
600unsigned int _fb_sync_read( unsigned int        offset, 
601                            const void*         buffer, 
602                            unsigned int        length )
603{
604    volatile unsigned char *fb_address;
605
606    /* parameters checking */
607    /* buffer must be in user space */
608    if (((unsigned int)buffer >= 0x80000000)
609            || (((unsigned int)buffer + length ) >= 0x80000000 ))
610        return 1;
611
612    fb_address = (unsigned char*)&seg_fb_base + offset;
613
614    /* buffer copy */
615    memcpy((void*)buffer, (void*)fb_address, length);
616
617    return 0;
618}
619
620//////////////////////////////////////////////////////////////////////////////////
621// _fb_write()
622// Transfer data from an memory buffer to the frame_buffer device using a DMA.
623// The source memory buffer must be in user address space.
624// - offset : offset (in bytes) in the frame buffer.
625// - buffer : base address of the memory buffer.
626// - length : number of bytes to be transfered.
627// Returns 0 if success, > 0 if error.
628//////////////////////////////////////////////////////////////////////////////////
629unsigned int _fb_write( unsigned int    offset, 
630                        const void*     buffer, 
631                        unsigned int    length )
632{
633    volatile unsigned char *fb_address;
634    volatile unsigned int *dma;
635
636    unsigned int proc_id;
637    unsigned int delay;
638    unsigned int i;
639
640    /* buffer must be in user space */
641    if (((unsigned int)buffer >= 0x80000000)
642            || (((unsigned int)buffer + length ) >= 0x80000000 ))
643        return 1;
644
645    proc_id = _procid();
646    fb_address = (unsigned char*)&seg_fb_base + offset;
647    dma = (unsigned int*)&seg_dma_base + (proc_id * DMA_SPAN);
648
649    /* waiting until DMA device is available */
650    while (_dma_busy[proc_id] != 0)
651    {
652        /* if the lock failed, busy wait with a pseudo random delay between bus
653         * accesses */
654        delay = (_proctime() & 0xF) << 4;
655        for (i = 0; i < delay; i++)
656            asm volatile("nop");
657    }
658    _dma_busy[proc_id] = 1;
659
660    /* DMA configuration for write transfer */
661    dma[DMA_IRQ_DISABLE] = 0;
662    dma[DMA_SRC] = (unsigned int)buffer;
663    dma[DMA_DST] = (unsigned int)fb_address;
664    dma[DMA_LEN] = (unsigned int)length;
665    return 0;
666}
667
668//////////////////////////////////////////////////////////////////////////////////
669// _fb_read()
670// Transfer data from the frame_buffer device to an memory buffer using a DMA.
671// The destination memory buffer must be in user address space.
672// - offset : offset (in bytes) in the frame buffer.
673// - buffer : base address of the memory buffer.
674// - length : number of bytes to be transfered.
675// All cache lines corresponding to the the target buffer are invalidated
676// for cache coherence.
677// Returns 0 if success, > 0 if error.
678//////////////////////////////////////////////////////////////////////////////////
679unsigned int _fb_read( unsigned int     offset, 
680                       const void*      buffer, 
681                       unsigned int     length )
682{
683    volatile unsigned char *fb_address;
684    volatile unsigned int *dma;
685
686    unsigned int proc_id;
687    unsigned int delay;
688    unsigned int i;
689
690    /* buffer must be in user space */
691    if (((unsigned int)buffer >= 0x80000000)
692            || (((unsigned int)buffer + length ) >= 0x80000000 ))
693        return 1;
694
695    proc_id = _procid();
696    fb_address = (unsigned char*)&seg_fb_base + offset;
697    dma = (unsigned int*)&seg_dma_base + (proc_id * DMA_SPAN);
698
699    /* waiting until DMA device is available */
700    while (_dma_busy[proc_id] != 0)
701    {
702        /* if the lock failed, busy wait with a pseudo random delay between bus
703         * accesses */
704        delay = (_proctime() & 0xF) << 4;
705        for (i = 0; i < delay; i++)
706            asm volatile("nop");
707    }
708    _dma_busy[proc_id] = 1;
709
710    /* DMA configuration for write transfer */
711    dma[DMA_IRQ_DISABLE] = 0;
712    dma[DMA_SRC] = (unsigned int)fb_address;
713    dma[DMA_DST] = (unsigned int)buffer;
714    dma[DMA_LEN] = (unsigned int)length;
715
716    /* invalidation of data cache */
717    _dcache_buf_invalidate(buffer, length);
718
719    return 0;
720}
721
722//////////////////////////////////////////////////////////////////////////////////
723// _fb_completed()
724// This function checks completion of a DMA transfer to or fom the frame buffer.
725// As it is a blocking call, the processor is stalled until the next interrupt.
726// Returns 0 if success, > 0 if error.
727//////////////////////////////////////////////////////////////////////////////////
728unsigned int _fb_completed()
729{
730    unsigned int proc_id;
731
732    proc_id = _procid();
733
734    while (_dma_busy[proc_id] != 0)
735        asm volatile("nop");
736
737    if (_dma_status[proc_id] != 0)
738        return 1;
739
740    return 0;
741}
742
Note: See TracBrowser for help on using the repository browser.