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

Last change on this file since 159 was 158, checked in by alain, 12 years ago

Introducing the giet_vm and some example applications

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 vers.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    task_id = _scheduler[proc_id].current;
207    tty_id  = _scheduler[proc_id].context[task_id][CTX_TTY_ID];
208
209    tty_address = (unsigned int*)&seg_tty_base + tty_id*TTY_SPAN;
210
211    for (nwritten = 0; nwritten < length; nwritten++)
212    {
213        /* check tty's status */
214        if ((tty_address[TTY_STATUS] & 0x2) == 0x2)
215            break;
216        else
217            /* write character */
218            tty_address[TTY_WRITE] = (unsigned int)buffer[nwritten];
219    }
220    return nwritten;
221}
222
223//////////////////////////////////////////////////////////////////////////////
224// _tty_read_irq()
225//
226// This non-blocking function uses the TTY_GET_IRQ[tty_id] interrupt and
227// the associated // kernel buffer, that has been written by the ISR.
228// It fetches one single character from the _tty_get_buf[tty_id] kernel
229// buffer, writes this character to the user buffer, and resets the
230// _tty_get_full[tty_id] buffer.
231// Returns 0 if the kernel buffer is empty, 1 if the buffer is full.
232//////////////////////////////////////////////////////////////////////////////
233unsigned int _tty_read_irq(char *buffer, unsigned int length)
234{
235    unsigned int proc_id;
236    unsigned int task_id;
237    unsigned int tty_id;
238    unsigned int ret;
239
240    proc_id = _procid();
241    task_id = _scheduler[proc_id].current;
242    tty_id  = _scheduler[proc_id].context[task_id][CTX_TTY_ID];
243
244    if (_tty_get_full[tty_id] == 0) 
245    {
246        ret = 0;
247    }
248    else
249    {
250        *buffer = _tty_get_buf[tty_id];
251        _tty_get_full[tty_id] = 0;
252        ret = 1;
253    }
254    return ret;
255}
256
257////////////////////////////////////////////////////////////////////////////////
258// _tty_read()
259//
260// This non-blocking function fetches one character directly from the TTY_READ
261// register of the TTY controler, and writes this character to the user buffer.
262// It doesn't use the TTY_GET_IRQ interrupt and the associated kernel buffer.
263// It doesn't take the lock protecting exclusive access...
264// Returns 0 if the register is empty, 1 if the register is full.
265////////////////////////////////////////////////////////////////////////////////
266unsigned int _tty_read(char *buffer, unsigned int length)
267{
268    volatile unsigned int *tty_address;
269
270    unsigned int proc_id;
271    unsigned int task_id;
272    unsigned int tty_id;
273
274    proc_id = _procid();
275    task_id = _scheduler[proc_id].current;
276    tty_id  = _scheduler[proc_id].context[task_id][CTX_TTY_ID];
277
278    tty_address = (unsigned int*)&seg_tty_base + tty_id*TTY_SPAN;
279
280    if ((tty_address[TTY_STATUS] & 0x1) != 0x1) return 0;
281
282    *buffer = (char)tty_address[TTY_READ];
283    return 1;
284}
285
286////////////////////////////////////////////////////////////////////////////////
287//      VciMultiIcu driver
288////////////////////////////////////////////////////////////////////////////////
289// There is in principle one MULTI-ICU component per cluster, and the
290// number of independant ICUs is equal to NB_PROCS, because there is
291// one ICU per processor.
292////////////////////////////////////////////////////////////////////////////////
293
294////////////////////////////////////////////////////////////////////////////////
295// _icu_write()
296//
297// Write a 32-bit word in a memory mapped register of the ICU device. The
298// base address is deduced by the proc_id.
299// Returns 0 if success, > 0 if error.
300////////////////////////////////////////////////////////////////////////////////
301unsigned int _icu_write(unsigned int register_index, unsigned int value)
302{
303    volatile unsigned int *icu_address;
304    unsigned int proc_id;
305
306    /* parameters checking */
307    if (register_index >= ICU_END)
308        return 1;
309
310    proc_id = _procid();
311    icu_address = (unsigned int*)&seg_icu_base + (proc_id * ICU_SPAN);
312    icu_address[register_index] = value;   /* write word */
313    return 0;
314}
315
316////////////////////////////////////////////////////////////////////////////////
317// _icu_read()
318//
319// Read a 32-bit word in a memory mapped register of the ICU device. The
320// ICU base address is deduced by the proc_id.
321// Returns 0 if success, > 0 if error.
322////////////////////////////////////////////////////////////////////////////////
323unsigned int _icu_read(unsigned int register_index, unsigned int *buffer)
324{
325    volatile unsigned int *icu_address;
326    unsigned int proc_id;
327
328    /* parameters checking */
329    if (register_index >= ICU_END)
330        return 1;
331
332    proc_id = _procid();
333    icu_address = (unsigned int*)&seg_icu_base + (proc_id * ICU_SPAN);
334    *buffer = icu_address[register_index]; /* read word */
335    return 0;
336}
337
338////////////////////////////////////////////////////////////////////////////////
339//      VciGcd driver
340////////////////////////////////////////////////////////////////////////////////
341// The Greater Dommon Divider is a -very- simple hardware coprocessor
342// performing the computation of a GCD of two 32 bits integers.
343// It has no DMA capability.
344////////////////////////////////////////////////////////////////////////////////
345
346////////////////////////////////////////////////////////////////////////////////
347// _gcd_write()
348//
349// Write a 32-bit word in a memory mapped register of the GCD coprocessor.
350// Returns 0 if success, > 0 if error.
351////////////////////////////////////////////////////////////////////////////////
352unsigned int _gcd_write(unsigned int register_index, unsigned int value)
353{
354    volatile unsigned int *gcd_address;
355
356    /* parameters checking */
357    if (register_index >= GCD_END)
358        return 1;
359
360    gcd_address = (unsigned int*)&seg_gcd_base;
361    gcd_address[register_index] = value; /* write word */
362    return 0;
363}
364
365////////////////////////////////////////////////////////////////////////////////
366// _gcd_read()
367//
368// Read a 32-bit word in a memory mapped register of the GCD coprocessor.
369// Returns 0 if success, > 0 if error.
370////////////////////////////////////////////////////////////////////////////////
371unsigned int _gcd_read(unsigned int register_index, unsigned int *buffer)
372{
373    volatile unsigned int *gcd_address;
374
375    /* parameters checking */
376    if (register_index >= GCD_END)
377        return 1;
378
379    gcd_address = (unsigned int*)&seg_gcd_base;
380    *buffer = gcd_address[register_index]; /* read word */
381    return 0;
382}
383
384////////////////////////////////////////////////////////////////////////////////
385// VciBlockDevice driver
386////////////////////////////////////////////////////////////////////////////////
387// The VciBlockDevice is a simple external storage contrÃŽler.
388// The three functions below use the three variables _ioc_lock _ioc_done,  and
389// _ioc_status for synchronsation.
390// As the IOC component can be used by several programs running in parallel,
391// the _ioc_lock variable guaranties exclusive access to the device.  The
392// _ioc_read() and _ioc_write() functions use atomic LL/SC to get the lock.
393// and set _ioc_lock to a non zero value.  The _ioc_write() and _ioc_read()
394// functions are blocking, polling the _ioc_lock variable until the device is
395// available.
396// When the tranfer is completed, the ISR routine activated by the IOC IRQ
397// set the _ioc_done variable to a non-zero value. Possible address errors
398// detected by the IOC peripheral are reported by the ISR in the _ioc_status
399// variable.
400// The _ioc_completed() function is polling the _ioc_done variable, waiting for
401// tranfer conpletion. When the completion is signaled, the _ioc_completed()
402// function reset the _ioc_done variable to zero, and releases the _ioc_lock
403// variable.
404//
405// In a multi-processing environment, this polling policy should be replaced by
406// a descheduling policy for the requesting process.
407///////////////////////////////////////////////////////////////////////////////
408
409///////////////////////////////////////////////////////////////////////////////
410// _ioc_get_lock()
411//
412// This blocking helper is used by '_ioc_read()' and '_ioc_write()' functions
413// to get _ioc_lock using atomic LL/SC.
414///////////////////////////////////////////////////////////////////////////////
415static inline void _ioc_get_lock()
416{
417    register unsigned int delay = (_proctime() & 0xF) << 4;
418    register unsigned int *plock = (unsigned int*)&_ioc_lock;
419
420    asm volatile (
421            "_ioc_llsc:             \n"
422            "ll   $2,    0(%0)      \n" /* $2 <= _ioc_lock current value */
423            "bnez $2,    _ioc_delay \n" /* delay if _ioc_lock already taken */
424            "li   $3,    1          \n" /* $3 <= argument for sc */
425            "sc   $3,    0(%0)      \n" /* try to set _ioc_lock */
426            "bnez $3,    _ioc_ok    \n" /* exit if atomic */
427            "_ioc_delay:            \n"
428            "move $4,    %1         \n" /* $4 <= delay */
429            "_ioc_loop:             \n"
430            "addi $4,    $4,    -1  \n" /* $4 <= $4 - 1 */
431            "beqz $4,    _ioc_loop  \n" /* test end delay */
432            "j           _ioc_llsc  \n" /* retry */
433            "_ioc_ok:               \n"
434            :
435            :"r"(plock), "r"(delay)
436            :"$2", "$3", "$4");
437}
438
439///////////////////////////////////////////////////////////////////////////////
440//  _ioc_write()
441//
442// Transfer data from a memory buffer to a file on the block_device.
443// The source memory buffer must be in user address space.
444// - lba    : first block index on the disk.
445// - buffer : base address of the memory buffer.
446// - count  : number of blocks to be transfered.
447// Returns 0 if success, > 0 if error.
448///////////////////////////////////////////////////////////////////////////////
449unsigned int _ioc_write( unsigned int   lba, 
450                         const void*    buffer, 
451                         unsigned int   count)
452{
453    volatile unsigned int *ioc_address;
454
455    ioc_address = (unsigned int*)&seg_ioc_base;
456
457    /* buffer must be in user space */
458    unsigned int block_size = ioc_address[BLOCK_DEVICE_BLOCK_SIZE];
459
460    if (((unsigned int)buffer >= 0x80000000)
461            || (((unsigned int)buffer + block_size*count) >= 0x80000000))
462        return 1;
463
464    /* get the lock on ioc device */
465    _ioc_get_lock();
466
467    /* block_device configuration for the write transfer */
468    ioc_address[BLOCK_DEVICE_BUFFER] = (unsigned int)buffer;
469    ioc_address[BLOCK_DEVICE_COUNT] = count;
470    ioc_address[BLOCK_DEVICE_LBA] = lba;
471    ioc_address[BLOCK_DEVICE_IRQ_ENABLE] = 1;
472    ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_WRITE;
473
474    return 0;
475}
476
477///////////////////////////////////////////////////////////////////////////////
478// _ioc_read()
479//
480// Transfer data from a file on the block device to a memory buffer.
481// The destination memory buffer must be in user address space.
482// - lba    : first block index on the disk.
483// - buffer : base address of the memory buffer.
484// - count  : number of blocks to be transfered.
485// All cache lines corresponding to the the target buffer are invalidated
486// for cache coherence.
487// Returns 0 if success, > 0 if error.
488///////////////////////////////////////////////////////////////////////////////
489unsigned int _ioc_read( unsigned int    lba, 
490                        void*           buffer, 
491                        unsigned int    count )
492{
493    volatile unsigned int *ioc_address;
494
495    ioc_address = (unsigned int*)&seg_ioc_base;
496
497    /* buffer must be in user space */
498    unsigned int block_size = ioc_address[BLOCK_DEVICE_BLOCK_SIZE];
499
500    if (((unsigned int)buffer >= 0x80000000)
501            || (((unsigned int)buffer + block_size*count) >= 0x80000000))
502        return 1;
503
504    /* get the lock on ioc device */
505    _ioc_get_lock();
506
507    /* block_device configuration for the read transfer */
508    ioc_address[BLOCK_DEVICE_BUFFER] = (unsigned int)buffer;
509    ioc_address[BLOCK_DEVICE_COUNT] = count;
510    ioc_address[BLOCK_DEVICE_LBA] = lba;
511    ioc_address[BLOCK_DEVICE_IRQ_ENABLE] = 1;
512    ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_READ;
513
514    /* invalidation of data cache */
515    _dcache_buf_invalidate(buffer, block_size*count);
516
517    return 0;
518}
519
520/////////////////////////////////////////////////////////////////////////////////
521// _ioc_completed()
522//
523// This function checks completion of an I/O transfer and reports errors.
524// As it is a blocking call, the processor is stalled until the next interrupt.
525// Returns 0 if success, > 0 if error.
526/////////////////////////////////////////////////////////////////////////////////
527unsigned int _ioc_completed()
528{
529    unsigned int ret;
530
531    /* busy waiting */
532    while (_ioc_done == 0)
533        asm volatile("nop");
534
535    /* test IOC status */
536    if ((_ioc_status != BLOCK_DEVICE_READ_SUCCESS)
537            && (_ioc_status != BLOCK_DEVICE_WRITE_SUCCESS)) ret = 1;    /* error */
538    else                                                    ret = 0;    /* success */
539
540    /* reset synchronization variables */
541    _ioc_lock =0;
542    _ioc_done =0;
543
544    return ret;
545}
546
547//////////////////////////////////////////////////////////////////////////////////
548//      VciFrameBuffer driver
549//////////////////////////////////////////////////////////////////////////////////
550// The '_fb_sync_write' and '_fb_sync_read' functions use a memcpy strategy to
551// implement the transfer between a data buffer (user space) and the frame
552// buffer (kernel space). They are blocking until completion of the transfer.
553// The '_fb_write()', '_fb_read()' and '_fb_completed()' functions use the DMA
554// coprocessor to transfer data between the user buffer and the frame buffer.
555// These  functions use a polling policy to test the global variables _dma_busy[i]
556// and detect the transfer completion. 
557// There is  NB_PROCS DMA channels, that are indexed by the proc_id.
558// The _dma_busy[i] synchronisation variables (one per channel) are set by the OS,
559// and reset by the ISR.
560//////////////////////////////////////////////////////////////////////////////////
561
562//////////////////////////////////////////////////////////////////////////////////
563// _fb_sync_write()
564// Transfer data from an memory buffer to the frame_buffer device using
565// a memcpy. The source memory buffer must be in user address space.
566// - offset : offset (in bytes) in the frame buffer.
567// - buffer : base address of the memory buffer.
568// - length : number of bytes to be transfered.
569// Returns 0 if success, > 0 if error.
570//////////////////////////////////////////////////////////////////////////////////
571unsigned int _fb_sync_write( unsigned int       offset, 
572                             const void*        buffer, 
573                             unsigned int       length )
574{
575    volatile unsigned char *fb_address;
576
577    /* buffer must be in user space */
578    if (((unsigned int)buffer >= 0x80000000)
579            || (((unsigned int)buffer + length ) >= 0x80000000 ))
580        return 1;
581
582    fb_address = (unsigned char*)&seg_fb_base + offset;
583
584    /* buffer copy */
585    memcpy((void*)fb_address, (void*)buffer, length);
586
587    return 0;
588}
589
590//////////////////////////////////////////////////////////////////////////////////
591// _fb_sync_read()
592// Transfer data from the frame_buffer device to a memory buffer using
593// a memcpy. The destination memory buffer must be in user address space.
594// - offset : offset (in bytes) in the frame buffer.
595// - buffer : base address of the memory buffer.
596// - length : number of bytes to be transfered.
597// Returns 0 if success, > 0 if error.
598//////////////////////////////////////////////////////////////////////////////////
599unsigned int _fb_sync_read( unsigned int        offset, 
600                            const void*         buffer, 
601                            unsigned int        length )
602{
603    volatile unsigned char *fb_address;
604
605    /* parameters checking */
606    /* buffer must be in user space */
607    if (((unsigned int)buffer >= 0x80000000)
608            || (((unsigned int)buffer + length ) >= 0x80000000 ))
609        return 1;
610
611    fb_address = (unsigned char*)&seg_fb_base + offset;
612
613    /* buffer copy */
614    memcpy((void*)buffer, (void*)fb_address, length);
615
616    return 0;
617}
618
619//////////////////////////////////////////////////////////////////////////////////
620// _fb_write()
621// Transfer data from an memory buffer to the frame_buffer device using a DMA.
622// The source memory buffer must be in user address space.
623// - offset : offset (in bytes) in the frame buffer.
624// - buffer : base address of the memory buffer.
625// - length : number of bytes to be transfered.
626// Returns 0 if success, > 0 if error.
627//////////////////////////////////////////////////////////////////////////////////
628unsigned int _fb_write( unsigned int    offset, 
629                        const void*     buffer, 
630                        unsigned int    length )
631{
632    volatile unsigned char *fb_address;
633    volatile unsigned int *dma;
634
635    unsigned int proc_id;
636    unsigned int delay;
637    unsigned int i;
638
639    /* buffer must be in user space */
640    if (((unsigned int)buffer >= 0x80000000)
641            || (((unsigned int)buffer + length ) >= 0x80000000 ))
642        return 1;
643
644    proc_id = _procid();
645    fb_address = (unsigned char*)&seg_fb_base + offset;
646    dma = (unsigned int*)&seg_dma_base + (proc_id * DMA_SPAN);
647
648    /* waiting until DMA device is available */
649    while (_dma_busy[proc_id] != 0)
650    {
651        /* if the lock failed, busy wait with a pseudo random delay between bus
652         * accesses */
653        delay = (_proctime() & 0xF) << 4;
654        for (i = 0; i < delay; i++)
655            asm volatile("nop");
656    }
657    _dma_busy[proc_id] = 1;
658
659    /* DMA configuration for write transfer */
660    dma[DMA_IRQ_DISABLE] = 0;
661    dma[DMA_SRC] = (unsigned int)buffer;
662    dma[DMA_DST] = (unsigned int)fb_address;
663    dma[DMA_LEN] = (unsigned int)length;
664    return 0;
665}
666
667//////////////////////////////////////////////////////////////////////////////////
668// _fb_read()
669// Transfer data from the frame_buffer device to an memory buffer using a DMA.
670// The destination memory buffer must be in user address space.
671// - offset : offset (in bytes) in the frame buffer.
672// - buffer : base address of the memory buffer.
673// - length : number of bytes to be transfered.
674// All cache lines corresponding to the the target buffer are invalidated
675// for cache coherence.
676// Returns 0 if success, > 0 if error.
677//////////////////////////////////////////////////////////////////////////////////
678unsigned int _fb_read( unsigned int     offset, 
679                       const void*      buffer, 
680                       unsigned int     length )
681{
682    volatile unsigned char *fb_address;
683    volatile unsigned int *dma;
684
685    unsigned int proc_id;
686    unsigned int delay;
687    unsigned int i;
688
689    /* buffer must be in user space */
690    if (((unsigned int)buffer >= 0x80000000)
691            || (((unsigned int)buffer + length ) >= 0x80000000 ))
692        return 1;
693
694    proc_id = _procid();
695    fb_address = (unsigned char*)&seg_fb_base + offset;
696    dma = (unsigned int*)&seg_dma_base + (proc_id * DMA_SPAN);
697
698    /* waiting until DMA device is available */
699    while (_dma_busy[proc_id] != 0)
700    {
701        /* if the lock failed, busy wait with a pseudo random delay between bus
702         * accesses */
703        delay = (_proctime() & 0xF) << 4;
704        for (i = 0; i < delay; i++)
705            asm volatile("nop");
706    }
707    _dma_busy[proc_id] = 1;
708
709    /* DMA configuration for write transfer */
710    dma[DMA_IRQ_DISABLE] = 0;
711    dma[DMA_SRC] = (unsigned int)fb_address;
712    dma[DMA_DST] = (unsigned int)buffer;
713    dma[DMA_LEN] = (unsigned int)length;
714
715    /* invalidation of data cache */
716    _dcache_buf_invalidate(buffer, length);
717
718    return 0;
719}
720
721//////////////////////////////////////////////////////////////////////////////////
722// _fb_completed()
723// This function checks completion of a DMA transfer to or fom the frame buffer.
724// As it is a blocking call, the processor is stalled until the next interrupt.
725// Returns 0 if success, > 0 if error.
726//////////////////////////////////////////////////////////////////////////////////
727unsigned int _fb_completed()
728{
729    unsigned int proc_id;
730
731    proc_id = _procid();
732
733    while (_dma_busy[proc_id] != 0)
734        asm volatile("nop");
735
736    if (_dma_status[proc_id] != 0)
737        return 1;
738
739    return 0;
740}
741
Note: See TracBrowser for help on using the repository browser.