source: trunk/hal/tsar_mips32/drivers/soclib_sdc.c @ 550

Last change on this file since 550 was 550, checked in by nicolas.van.phan@…, 3 years ago

Add SD card driver in kernel

File size: 13.6 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : sdc_driver.c
3// Date     : 31/08/2012
4// Author   : cesar fuguet
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7
8// #include <hard_config.h>
9#include <soclib_sdc.h>
10//#include <tty0.h>
11//#include <utils.h>
12#include <hal_kernel_types.h>
13#include <chdev.h>
14#include <dev_ioc.h>
15#include <thread.h>
16#include <printk.h>
17
18#define SYSCLK_FREQ           (RESET_SYSTEM_CLK * 1000)
19#define SDCARD_RESET_ITER_MAX 4
20
21///////////////////////////////////////////////////////////////////////////////
22//   Global variables
23///////////////////////////////////////////////////////////////////////////////
24
25__attribute__((section(".kdata")))
26static struct sdcard_dev sdcard;
27
28__attribute__((section(".kdata")))
29static struct spi_dev*   spi;
30
31///////////////////////////////////////////////////////////////////////////////
32// This function enables SD Card select signal
33///////////////////////////////////////////////////////////////////////////////
34static void _sdc_enable()
35{
36    spi_ss_assert(sdcard.spi, sdcard.slave_id);
37}
38
39///////////////////////////////////////////////////////////////////////////////
40// This function disables SD Card select signal
41///////////////////////////////////////////////////////////////////////////////
42static void _sdc_disable()
43{
44    spi_ss_deassert(sdcard.spi, sdcard.slave_id);
45}
46
47///////////////////////////////////////////////////////////////////////////////
48// This function writes on the SPI tx register to generate SD card clock ticks
49// - tick_count: number of ticks to generate (1 tick -> 8 clocks)
50///////////////////////////////////////////////////////////////////////////////
51static void _sdc_gen_tick(unsigned int tick_count)
52{
53    register int i = 0;
54    while(i++ < tick_count) spi_put_tx(sdcard.spi, 0xFF, 0);
55}
56
57///////////////////////////////////////////////////////////////////////////////
58// This function changes the SD card access pointer position in terms of
59// blocks
60// - lba: number of logical block to move the pointer
61///////////////////////////////////////////////////////////////////////////////
62void _sdc_lseek(unsigned int lba)
63{
64    sdcard.access_pointer = sdcard.block_length * lba;
65}
66
67///////////////////////////////////////////////////////////////////////////////
68// This function gets a byte from the SD card
69///////////////////////////////////////////////////////////////////////////////
70static unsigned char _sdc_receive_char()
71{
72    _sdc_gen_tick(1);
73
74    return spi_get_rx(sdcard.spi, 0);
75}
76
77///////////////////////////////////////////////////////////////////////////////
78// This function returns when a valid response from the SD card is received or
79// a timeout has been triggered
80// Returns the SD card response value
81///////////////////////////////////////////////////////////////////////////////
82static unsigned char _sdc_wait_response()
83{
84    unsigned char sdcard_rsp;
85    register int  iter;
86
87    iter       = 0;
88    sdcard_rsp = _sdc_receive_char();
89    while (
90            (iter < SDCARD_COMMAND_TIMEOUT) &&
91            !SDCARD_CHECK_R1_VALID(sdcard_rsp)
92          )
93    {
94        sdcard_rsp = _sdc_receive_char();
95        iter++;
96    }
97
98    return sdcard_rsp;
99}
100
101///////////////////////////////////////////////////////////////////////////////
102// This function returns when a data block from the SD card is received (data
103// block start marker received).
104// It must be called after a read command
105///////////////////////////////////////////////////////////////////////////////
106static void _sdc_wait_data_block()
107{
108        while (_sdc_receive_char() != 0xFE);
109}
110
111///////////////////////////////////////////////////////////////////////////////
112// This function sends a command to the SD card
113// - index: CMD index
114// - app: type of command
115// - args: CMD arguments vector
116// - crc7: CRC (7 bits) to send
117///////////////////////////////////////////////////////////////////////////////
118static int _sdc_send_command ( int      index,
119                               int      app  ,
120                               void *   args ,
121                               unsigned crc7 )
122{
123    unsigned char sdcard_rsp;
124    unsigned char * _args;
125
126    _sdc_gen_tick(5); 
127
128    if (app == SDCARD_ACMD)
129    {
130        spi_put_tx(sdcard.spi, 0x40 | 55         , 0 );// CMD and START bit
131        spi_put_tx(sdcard.spi, 0x00              , 0 );// Argument[0]
132        spi_put_tx(sdcard.spi, 0x00              , 0 );// Argument[1]
133        spi_put_tx(sdcard.spi, 0x00              , 0 );// Argument[2]
134        spi_put_tx(sdcard.spi, 0x00              , 0 );// Argument[3]
135        spi_put_tx(sdcard.spi, 0x01 | (crc7 << 1), 0 );// END bit
136
137        sdcard_rsp = _sdc_wait_response();
138        if (SDCARD_CHECK_R1_ERROR(sdcard_rsp))
139        {
140            return sdcard_rsp;       
141        }
142    }
143
144    _args = (unsigned char *) args;
145
146    _sdc_gen_tick(1); 
147
148    spi_put_tx(sdcard.spi, 0x40 | index      , 0 );
149    spi_put_tx(sdcard.spi, _args[0]          , 0 );
150    spi_put_tx(sdcard.spi, _args[1]          , 0 );
151    spi_put_tx(sdcard.spi, _args[2]          , 0 );
152    spi_put_tx(sdcard.spi, _args[3]          , 0 );
153    spi_put_tx(sdcard.spi, 0x01 | (crc7 << 1), 0 );
154
155    return _sdc_wait_response();
156}
157
158///////////////////////////////////////////////////////////////////////////////
159// This function initializes the SD card (reset procedure)
160// - channel: channel index (only channel 0 is supported)
161// Returns 0 if success, other value if failure
162///////////////////////////////////////////////////////////////////////////////
163static int _sdc_open( unsigned int channel )
164{
165        unsigned char args[4];
166        unsigned char sdcard_rsp;
167        unsigned int  iter, ersp;
168
169        sdcard.spi      = spi;
170        sdcard.slave_id = channel;
171
172        // supply SD card ramp up time (min 74 cycles)
173        _sdc_gen_tick(10);
174
175        // Assert slave select signal
176        // Send CMD0 (Reset Command)
177        // Deassert slave select signal
178        _sdc_enable();
179
180        args[0] = 0;
181        args[1] = 0;
182        args[2] = 0;
183        args[3] = 0;
184        sdcard_rsp = _sdc_send_command(0, SDCARD_CMD, args, 0x4A);
185
186        if ( sdcard_rsp != 0x01 )
187        {
188                printk("[SDC ERROR] card CMD0 failed\n");
189                return sdcard_rsp;
190        }
191
192        _sdc_disable();
193
194        // send CMD8. If card is pre-v2, It will reply with illegal command.
195        // Otherwise we announce sdhc support.
196        _sdc_enable();
197        args[0] = 0;
198        args[1] = 0;
199        args[2] = 0x01;
200        args[3] = 0x01;
201        sdcard_rsp = _sdc_send_command(8, SDCARD_CMD, args, 0x63);
202        if (!SDCARD_CHECK_R1_VALID(sdcard_rsp))
203    {
204                printk("[SDC ERROR] card CMD8 failed\n");
205                return sdcard_rsp;
206        }
207        if (!SDCARD_CHECK_R1_ERROR(sdcard_rsp))
208    {
209                // no error, command accepted. get whole reply
210                ersp = _sdc_receive_char();
211                ersp = (ersp << 8) | _sdc_receive_char();
212                ersp = (ersp << 8) | _sdc_receive_char();
213                ersp = (ersp << 8) | _sdc_receive_char();
214                if ((ersp & 0xffff) != 0x0101) 
215        {
216                        // voltage mismatch
217                        printk("[SDC ERROR] card CMD8 mismatch : ersp = %x\n");
218                        return sdcard_rsp;
219                }
220                printk("[SDC WARNING] v2 or later ");
221                sdcard.sdhc = 1;
222        }
223    else if ((sdcard_rsp & SDCARD_R1_ILLEGAL_CMD) == 0)
224    {
225                // other error
226                printk("[SDC ERROR] card CMD8 error\n");
227                return sdcard_rsp;
228        }
229    else
230    {
231                sdcard.sdhc = 0;
232        }
233        _sdc_disable();
234
235        // send CMD41, enabling the card
236        _sdc_enable();
237        args[0] = sdcard.sdhc ? 0x40: 0;
238        args[1] = 0;
239        args[2] = 0;
240        args[3] = 0;
241
242        iter = 0;
243        while( iter++ < SDCARD_COMMAND_TIMEOUT )
244        {
245                sdcard_rsp = _sdc_send_command(41, SDCARD_ACMD, args, 0x00);
246                if( sdcard_rsp == 0x01 )
247                {
248                        continue;
249                }
250
251                break;
252        }
253
254        _sdc_disable();
255        if (sdcard_rsp)
256    {
257                printk("[SDC ERROR] ACMD41 failed\n");
258                return sdcard_rsp;
259        }
260        if (sdcard.sdhc != 0)
261    {
262                // get the card capacity to see if it's really HC
263                _sdc_enable();
264                args[0] = sdcard.sdhc ? 0x40: 0;
265                args[1] = 0;
266                args[2] = 0;
267                args[3] = 0;
268        sdcard_rsp = _sdc_send_command(58, SDCARD_CMD, args, 0x00);
269                if (sdcard_rsp)
270        {
271                        printk("[SDC ERROR] CMD58 failed\n");
272                        return sdcard_rsp;
273                }
274                ersp = _sdc_receive_char();
275                ersp = (ersp << 8) | _sdc_receive_char();
276                ersp = (ersp << 8) | _sdc_receive_char();
277                ersp = (ersp << 8) | _sdc_receive_char();
278                if (ersp & 0x40000000)
279        {
280                        printk(" SDHC ");
281                } 
282        else
283        {
284                        sdcard.sdhc = 0;
285                }
286                _sdc_disable();
287        }
288        printk("card detected\n");
289        return 0;
290}
291
292///////////////////////////////////////////////////////////////////////////////
293// This function sets the block size in the SD card.
294// - len: block size in bytes (only 512 bytes supported)
295// Returns 0 if success, other value if failure
296///////////////////////////////////////////////////////////////////////////////
297static unsigned int _sdc_set_block_size(unsigned int len)
298{
299    unsigned char args[4];
300    unsigned char sdcard_rsp;
301    register int i;
302
303    // For now, supported block size is 512 bytes
304    if (len != 512) return 1;
305
306    // When using high capacity SDCARD, the block_length is not a number of bytes
307    // but a number of blocks (transfer unit)
308    if (sdcard.sdhc)
309    {
310        sdcard.block_length = len / 512;
311        return 0;
312    }
313
314    for (i = 0; i < 4; i++)
315    {
316        args[i] = (len >> (32 - (i+1)*8)) & 0xFF;
317    }
318
319    _sdc_enable();
320
321    sdcard_rsp = _sdc_send_command(16, SDCARD_CMD, args, 0x00);
322    if ( SDCARD_CHECK_R1_ERROR(sdcard_rsp) )
323    {
324        _sdc_disable();
325        return sdcard_rsp;
326    }
327
328    _sdc_disable();
329
330    sdcard.block_length = len;
331
332        return 0;
333}
334
335/////////////////////////////////////////////////////////////////////////////////
336//           Extern functions
337/////////////////////////////////////////////////////////////////////////////////
338
339////////////////////////
340void soclib_sdc_init( chdev_t* chdev )
341{
342    spi = (struct spi_dev*)SEG_IOC_BASE;
343
344    // initializing the SPI controller
345    _spi_init (
346        spi           ,
347        200000        , /**< SPI_clk: 200 Khz */
348        SYSCLK_FREQ   , /**< Sys_clk          */
349        8             , /**< Charlen: 8       */
350        SPI_TX_NEGEDGE,
351        SPI_RX_POSEDGE
352    );
353
354    // initializing the SD Card
355    unsigned int iter = 0;
356    unsigned char sdcard_rsp;
357    unsigned int i;
358
359    while(1)
360    {
361        printk("[SDC WARNING] Trying to initialize SD card...\n");
362
363        sdcard_rsp = _sdc_open( 0 );  // only channel 0
364        if (sdcard_rsp == 0)
365        {
366            printk("OK\n");
367            break;
368        }
369
370        printk("KO\n");
371
372        for (i = 0; i < 1000; i++);
373
374        if (++iter >= SDCARD_RESET_ITER_MAX)
375        {
376            assert( false, __FUNCTION__, "\n[SDC ERROR] During SD card reset / card response = %x \n", sdcard_rsp);
377        }
378    }
379
380    // set the block length of the SD Card
381    sdcard_rsp = _sdc_set_block_size(512);
382    if (sdcard_rsp)
383    {
384        assert( false, __FUNCTION__, "[SDC ERROR] During SD card block size initialization\n");
385    }
386
387    // incrementing SDCARD clock frequency for normal function
388    _spi_init (
389        spi         ,
390        10000000    , // SPI_clk 10 Mhz
391        SYSCLK_FREQ , // Sys_clk
392        -1          , // Charlen: 8
393        -1          ,
394        -1
395    );
396
397    printk("[SDC WARNING] Finish SD card initialization\n\r");
398
399    /* Initialize the chdev */
400    // get extended pointer on SOCLIB_BDV peripheral base address
401        xptr_t  sdc_xp = chdev->base;
402
403    // set driver specific fields
404    chdev->cmd = &soclib_sdc_cmd;
405    chdev->isr = &soclib_sdc_isr;
406
407} // end soclib_sdc_init()
408
409/////////////////////////////////////////////////////
410void __attribute__ ((noinline)) soclib_sdc_cmd( xptr_t th_xp )
411{
412    cxy_t      th_cxy = GET_CXY( th_xp );
413    thread_t * th_ptr = GET_PTR( th_xp );
414
415    // get command arguments and extended pointer on IOC device
416    uint32_t        cmd_type =         hal_remote_lw ( XPTR( th_cxy , &th_ptr->ioc_cmd.type   ) );
417    unsigned int    lba      =         hal_remote_lw ( XPTR( th_cxy , &th_ptr->ioc_cmd.lba ) );
418    xptr_t          buf_xp   = (xptr_t)hal_remote_lwd( XPTR( th_cxy , &th_ptr->ioc_cmd.buf_xp ) );
419    unsigned int    count    =         hal_remote_lw ( XPTR( th_cxy , &th_ptr->ioc_cmd.count  ) );
420
421    unsigned char args[4];
422    unsigned char sdcard_rsp;
423    unsigned int i;
424    unsigned int curr = lba;
425    unsigned int last = lba + count;
426
427    if ( cmd_type == IOC_SYNC_READ )  // read access
428    {
429        for ( ; curr < last ; curr++ )
430        {
431            _sdc_lseek(curr);
432
433            for (i = 0; i < 4; i++)
434            {
435                args[i] = (sdcard.access_pointer >> (32 - (i+1)*8)) & 0xFF;
436            }
437
438            _sdc_enable();
439
440            sdcard_rsp = _sdc_send_command(17, SDCARD_CMD, args, 0x00);
441            if ( SDCARD_CHECK_R1_ERROR(sdcard_rsp) )
442            {
443                _sdc_disable();
444                return sdcard_rsp;
445            }
446
447            _sdc_wait_data_block();
448
449            if (spi_get_data(sdcard.spi, buf_xp, 512 ))
450            {
451                _sdc_disable();
452                return 1;
453            }
454
455            // Get the CRC16 (comes at the end of the data block)
456            _sdc_receive_char(); // first byte
457            _sdc_receive_char(); // second byte
458
459            _sdc_disable();
460
461            buf_xp += 512;
462        }
463    }
464    else            // write access
465    {
466        assert( false, __FUNCTION__, "[SDC ERROR] function _sdc_write() not iplemented yet\n");
467    }
468}  // _end sdc_access()
469
470///////////////////////////////////////////////////////////////////////////////
471// This ISR handles the IRQ generated by a SDC controler
472///////////////////////////////////////////////////////////////////////////////
473void __attribute__ ((noinline)) soclib_sdc_isr( chdev_t * chdev )
474{
475    assert( false, __FUNCTION__, "\n[GIET ERROR] _sdc_isr() not implemented\n");
476}
477
478// Local Variables:
479// tab-width: 4
480// c-basic-offset: 4
481// c-file-offsets:((innamespace . 0)(inline-open . 0))
482// indent-tabs-mode: nil
483// End:
484// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
Note: See TracBrowser for help on using the repository browser.