source: trunk/softs/tsar_boot/io_drivers/ioc.c @ 276

Last change on this file since 276 was 276, checked in by bouyer, 12 years ago

A boot loader to be stored in ROM of a TSAR platform.
Based on Cesar FUGUET's work.
Platform-specific files are in a subdirectory, e.g. platform_fpga_de2-115,
so the same code can be targetted to different platforms.
The platform is selected with the PLATFORM_DIR environnement variable.
The supported variant are soclib and fpga, the later being the default
and the former selected by defining the SOCLIB environnement variable.
The boot loader embeds a binary device tree describing the platform,
to be used by the loaded software.

File size: 9.7 KB
Line 
1#include <ioc.h>
2#include <defs.h>
3
4#define in_reset        __attribute__((section (".reset")))
5#define in_reset_data   __attribute__((section (".reset_data")))
6#define in_unckdata     __attribute__((section (".unckdata")))
7
8in_unckdata   int volatile _ioc_lock    = 0;
9in_reset_data int volatile _ioc_done    = 0;
10in_reset_data int volatile _ioc_status;
11
12#ifndef SOCLIB_IOC
13/*in_reset_data volatile unsigned int _ioc_init_ok = 0;*/
14
15static in_reset_data struct sdcard_dev  _sdcard_device;
16static in_reset_data struct spi_dev   * _spi_device   = ( struct spi_dev * )IOC_BASE;
17#endif
18
19//////////////////////////////////////////////////////////////////////////////////////////
20//  I/O BLOCK_DEVICE
21// The three functions below use the three variables _ioc_lock _ioc_done,
22// and _ioc_status for synchronsation.
23// - As the IOC component can be used by several programs running in parallel,
24// the _ioc_lock variable guaranties exclusive access to the device.
25// The _ioc_read() and _ioc_write() functions use atomic LL/SC to get the lock.
26// and set _ioc_lock to a non zero value.
27// The _ioc_write() and _ioc_read() functions are blocking, polling the _ioc_lock
28// variable until the device is available.
29// - When the tranfer is completed, the ISR routine activated by the IOC IRQ
30// set the _ioc_done variable to a non-zero value. Possible address errors detected
31// by the IOC peripheral are reported by the ISR in the _ioc_status variable.
32// The _ioc_completed() function is polling the _ioc_done variable, waiting for
33// tranfer conpletion. When the completion is signaled, the _ioc_completed() function
34// reset the _ioc_done variable to zero, and releases the _ioc_lock variable.
35//
36// In a multi-tasks environment, this polling policy must be replaced by a
37// descheduling policy for the requesting process.
38//////////////////////////////////////////////////////////////////////
39
40//////////////////////////////////////////////////////////////////////
41//  _dcache_buf_invalidate()
42// Invalidate all cache lines corresponding to a memory buffer.
43// This is used by the block_device driver.
44/////////////////////////////////////////////////////////////////////////
45//in_reset static void _dcache_buf_invalidate(const void * buffer, size_t size)
46//{
47//    size_t i;
48//    size_t dcache_line_size;
49//
50//    // retrieve dcache line size from config register (bits 12:10)
51//    asm volatile("mfc0 %0, $16, 1" : "=r" (dcache_line_size));
52//
53//    dcache_line_size = 2 << ((dcache_line_size>>10) & 0x7);
54//
55//    // iterate on lines to invalidate each one of them
56//    for ( i=0; i<size; i+=dcache_line_size )
57//        asm volatile(" cache %0, %1"
58//                :
59//                :"i" (0x11), "R" (*((char*)buffer+i)));
60//}
61
62///////////////////////////////////////////////////////////////////////////////////////
63//  _ioc_get_lock()
64// This blocking function is used by the _ioc_read() and _ioc_write() functions
65// to get _ioc_lock using LL/SC.
66///////////////////////////////////////////////////////////////////////////////////////
67in_reset void _ioc_get_lock()
68{
69    register unsigned int   proctime;
70    register unsigned int   delay;
71    register unsigned int*  plock = (unsigned int*)&_ioc_lock;         
72
73    asm volatile(
74        "mfc0 %0, $9    \n"
75        : "=r"(proctime)
76        : /* No inputs */
77    );
78
79    delay = (proctime & 0xF) << 4;
80
81    asm volatile ("_ioc_llsc:                   \n"
82                  "ll   $2,    0(%0)            \n" // $2 <= _ioc_lock
83                  "bnez $2,    _ioc_delay       \n" // random delay if busy
84                  "li   $3,    1                \n" // prepare argument for sc 
85                  "sc   $3,    0(%0)            \n" // try to set _ioc_busy
86                  "bnez $3,    _ioc_ok          \n" // exit if atomic
87                  "_ioc_delay:                  \n"
88                  "move $4,    %1               \n" // $4 <= delay
89                  "_ioc_loop:                   \n"
90                  "addi $4,    $4,    -1        \n" // $4 <= $4 - 1
91                  "beqz $4,    _ioc_loop        \n" // test end delay
92                  "j           _ioc_llsc        \n" // retry
93                  "_ioc_ok:                     \n"
94                  ::"r"(plock),"r"(delay):"$2","$3","$4");
95}
96
97in_reset int _ioc_init()
98{
99#ifndef SOCLIB_IOC
100    in_reset_data static char init_begin[] = "Initializing block device\n\r";
101    in_reset_data static char init_end[]   = "Finish block device initialization\n\r";
102
103    unsigned char sdcard_rsp;
104
105    boot_puts(init_begin);
106
107    /**
108     * Initializing the SPI controller
109     */
110    spi_dev_config (
111      _spi_device   ,
112      200000        , /**< SPI_clk: 200 Khz */
113      50000000      , /**< Sys_clk: 50  Mhz */
114      8             , /**< Charlen: 8       */
115      SPI_TX_NEGEDGE,
116      SPI_RX_POSEDGE
117    ); 
118
119    /**
120     * Initializing the SD Card
121     */
122    if ( (sdcard_rsp = sdcard_dev_open(&_sdcard_device, _spi_device, 0)) )
123        return sdcard_rsp;
124
125    if ( (sdcard_rsp = sdcard_dev_set_blocklen(&_sdcard_device, 512)) )
126        return sdcard_rsp;
127
128    /**
129     * Incrementing SDCARD clock frequency for normal function
130     */
131    spi_dev_config (
132        _spi_device ,
133        10000000    , /**< SPI_clkL 10 Mhz */
134        50000000    , /**< Sys_clk: 50 Mhz */
135        -1          , /**< Charlen: 8      */
136        -1          ,
137        -1
138    );
139
140    boot_puts(init_end);
141#endif
142
143    return 0;
144}
145
146///////////////////////////////////////////////////////////////////////////////////////
147//  _ioc_completed()
148// This blocking function cheks completion of an I/O transfer and reports errors.
149// It returns 0 if the transfer is successfully completed.
150// It returns -1 if an error has been reported.
151///////////////////////////////////////////////////////////////////////////////////////
152in_reset int _ioc_completed()
153{
154    unsigned int status = 0;
155
156#ifdef SOCLIB_IOC
157
158    unsigned int * ioc_address = ( unsigned int * )VCIBD_BASE;
159 
160    while ( 1 )
161    { 
162        status = ioread32(&ioc_address[BLOCK_DEVICE_STATUS]);
163
164        if (( status == BLOCK_DEVICE_READ_SUCCESS ) ||
165            ( status == BLOCK_DEVICE_READ_ERROR  ))
166        break;
167    }
168   
169#endif
170
171    return status;
172}
173
174//////////////////////////////////////////////////////////////////////////////////////
175//  _ioc_write()
176// Transfer data from a memory buffer to a file on the block_device.
177// - lba    : first block index on the disk
178// - buffer : base address of the memory buffer
179// - count  : number of blocks to be transfered
180// The source buffer must be in user address space.
181///////////////////////////////////////////////////////////////////////////////////////
182in_reset int _ioc_write(size_t lba, void* buffer, size_t count)
183{
184    // get the lock
185    // _ioc_get_lock();
186
187#ifdef SOCLIB_IOC
188
189    unsigned int * ioc_address = ( unsigned int * )VCIBD_BASE;
190
191    // block_device configuration
192    iowrite32( &ioc_address[BLOCK_DEVICE_BUFFER],
193            ( unsigned int ) buffer );
194
195    iowrite32( &ioc_address[BLOCK_DEVICE_COUNT],
196            ( unsigned int ) count );
197
198    iowrite32( &ioc_address[BLOCK_DEVICE_LBA],
199            ( unsigned int ) lba );
200
201    iowrite32( &ioc_address[BLOCK_DEVICE_IRQ_ENABLE],
202            ( unsigned int ) 0 );
203
204    iowrite32( &ioc_address[BLOCK_DEVICE_OP],
205            ( unsigned int ) BLOCK_DEVICE_WRITE);
206
207    _ioc_completed();
208
209#else   
210/*
211in_reset_data static char end_line[] =
212    "\n\r";
213in_reset_data static char error_init[] =
214    "ERROR during initialization of block device. Code: ";
215
216unsigned int sdcard_rsp;
217
218if ( _ioc_init_ok == 0 )
219{
220    if (( sdcard_rsp = _ioc_init(&_sdcard_device, 0) ))
221    {
222        boot_puts(error_init);
223        boot_putx(sdcard_rsp);
224        boot_puts(end_line);
225    }   
226
227    _ioc_init_ok = 1;
228}
229*/
230       
231    sdcard_dev_lseek(&_sdcard_device, lba);
232    sdcard_dev_write(&_sdcard_device, buffer, count*512);
233
234#endif
235
236// _ioc_lock = 0;
237
238    return 0;
239}
240
241/**
242 *  _ioc_read()
243 *
244 * Transfer data from a file on the block device to a memory buffer.
245 *
246 * \param lba    : first block index on the disk
247 * \param buffer : base address of the memory buffer
248 * \param count  : number of blocks to be transfered
249 *
250 * \note This is a blocking function. The function returns once the transfer
251 *       has finished
252 */
253in_reset int _ioc_read(size_t lba, void* buffer, size_t count)
254{
255    // get the lock
256    // _ioc_get_lock();
257
258#ifdef SOCLIB_IOC
259
260    unsigned int * ioc_address  = (unsigned int*)VCIBD_BASE;
261
262    // block_device configuration
263    iowrite32( &ioc_address[BLOCK_DEVICE_BUFFER],
264            ( unsigned int ) buffer );
265
266    iowrite32( &ioc_address[BLOCK_DEVICE_COUNT],
267            ( unsigned int ) count );
268
269    iowrite32( &ioc_address[BLOCK_DEVICE_LBA],
270            ( unsigned int ) lba );
271
272    iowrite32( &ioc_address[BLOCK_DEVICE_IRQ_ENABLE],
273            ( unsigned int ) 0 );
274
275    iowrite32( &ioc_address[BLOCK_DEVICE_OP],
276            ( unsigned int ) BLOCK_DEVICE_READ );
277
278    _ioc_completed();
279
280#else
281    in_reset_data static char error_read[] =
282        "ERROR during read on the SDCARD device. Code: ";
283    in_reset_data static char end_line[] =
284        "\n\r";
285/*
286in_reset_data static char error_init[] =
287    "ERROR during initialization of block device. Code: ";
288*/
289
290    unsigned int sdcard_rsp;
291
292/*
293if ( _ioc_init_ok == 0 )
294{
295    if (( sdcard_rsp = _ioc_init(&_sdcard_device, 0) ))
296    {
297        boot_puts(error_init);
298        boot_putx(sdcard_rsp);
299        boot_puts(end_line);
300    }   
301   
302    _ioc_init_ok = 1;
303}
304*/
305
306    sdcard_dev_lseek(&_sdcard_device, lba);
307
308    if (( sdcard_rsp = sdcard_dev_read (&_sdcard_device, buffer, count*512) ))
309    {
310        boot_puts(error_read); 
311        boot_putx(sdcard_rsp);
312        boot_puts(end_line);
313    }   
314   
315#endif
316
317    //_ioc_lock = 0;
318    //
319    //_dcache_buf_invalidate(buffer, count);
320
321    return 0;
322}
323#undef in_reset
324#undef in_reset_data
325#undef in_unckdata
326
327/*
328 * vim: tabstop=4 : shiftwidth=4 : expandtab
329 */
Note: See TracBrowser for help on using the repository browser.