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

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

Introducing various modifications in kernel initialisation

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