source: trunk/softs/tsar_boot/drivers/reset_ioc_spi.c @ 1008

Last change on this file since 1008 was 992, checked in by alain, 10 years ago

Introduce a new driver for SD Card using the 4bits wide SD bus.
THere is now 5 supported block device peripherals, and the driver names
have been re-organised: reset_ioc_xxx with xxx in (bdv, hba, rdk, spi, sdc)

File size: 11.8 KB
Line 
1/**
2 * \file    : reset_ioc_spi.c
3 * \date    : 30 August 2012
4 * \author  : Cesar Fuguet <cesar.fuguet-tortolero@lip6.fr>
5 *
6 * This file defines the driver of a SD Card device using an SPI controller
7 */
8
9#include <reset_ioc_spi.h>
10#include <reset_tty.h>
11#include <reset_utils.h>
12#include <defs.h>
13#include <spi.h>
14
15#ifndef SEG_IOC_BASE
16#error "SEG_IOC_BASE constant must be defined in the hard_config.h file"
17#endif
18
19static struct sdcard_dev         _sdcard_device;
20static struct spi_dev *const     _spi_device = (struct spi_dev*)SEG_IOC_BASE;
21
22static const int sdcard_reset_retries = 4;
23static const int spi_init_clkfreq     = 200000  ; /* Hz */
24static const int spi_func_clkfreq     = 10000000; /* Hz */
25
26/**
27 * \param   sdcard: Initialized pointer to the block device
28 *
29 * \return  void
30 *
31 * \brief   Enable SD Card select signal
32 */
33static void _sdcard_enable(struct sdcard_dev * sdcard)
34{
35    spi_ss_assert(sdcard->spi, sdcard->slave_id);
36}
37
38/**
39 * \param   sdcard: Initialized pointer to the block device
40 *
41 * \return  void
42 *
43 * \brief   Disable SD Card select signal
44 */
45static void _sdcard_disable(struct sdcard_dev * sdcard)
46{
47    spi_ss_deassert(sdcard->spi, sdcard->slave_id);
48}
49
50/**
51 * \param   tick_count: SD Card clock ticks number
52 *
53 * \return  void
54 *
55 * \brief   Enable SD Card clock
56 *          The tick count is byte measured (1 tick, 8 clock)
57 */
58static void _sdcard_gen_tick(struct sdcard_dev * sdcard, unsigned int tick_count)
59{
60    register int i = 0;
61    while(i++ < tick_count) spi_put_tx(sdcard->spi, 0xFF, 0);
62}
63
64/**
65 * \param   sdcard: Initialized pointer to the block device
66 *
67 * \return  char from the SD card
68 *
69 * \brief   Get a byte from the SD Card
70 */
71static unsigned char _sdcard_receive_char(struct sdcard_dev * sdcard)
72{
73    _sdcard_gen_tick(sdcard, 1);
74
75    return spi_get_rx(sdcard->spi, 0);
76}
77
78/**
79 * \param   sdcard: Initialized pointer to the block device
80 *
81 * \return  sdcard response
82 *
83 * \brief   Wait for a valid response after the send of a command
84 *          This function can return if one of the next two conditions are true:
85 *           1. Bit valid received
86 *           2. Timeout (not valid bit received after SDCARD_COMMAND_TIMEOUT
87 *              wait ticks)
88 */
89static unsigned char _sdcard_wait_response(struct sdcard_dev * sdcard)
90{
91    unsigned char sdcard_rsp;
92    register int  iter;
93
94    iter       = 0;
95    sdcard_rsp = _sdcard_receive_char(sdcard);
96    while (
97            (iter < SDCARD_COMMAND_TIMEOUT) &&
98            !SDCARD_CHECK_R1_VALID(sdcard_rsp)
99          )
100    {
101        sdcard_rsp = _sdcard_receive_char(sdcard);
102        iter++;
103    }
104
105    return sdcard_rsp;
106}
107
108/**
109 * \params  sdcard: Initialized pointer to the block device
110 *
111 * \return  void
112 *
113 * \brief   Wait data block start marker
114 */
115static void _sdcard_wait_data_block(struct sdcard_dev * sdcard)
116{
117        while (_sdcard_receive_char(sdcard) != 0xFE);
118}
119
120/**
121 * \param   sdcard  : Initialized pointer to block device
122 * \param   index   : SD card CMD index
123 * \param   app     : Type of command, 0 for normal command or 1 for application
124 *                    specific
125 * \param   args    : SD card CMD arguments
126 *
127 * \return  response first byte
128 *
129 * \brief   Send command to the SD card
130 */
131static int _sdcard_send_command    (
132        struct sdcard_dev * sdcard ,
133        int                 index  ,
134        int                 app    ,
135        void *              args   ,
136        unsigned            crc7   )
137{
138    unsigned char sdcard_rsp;
139    unsigned char * _args;
140
141    _sdcard_gen_tick(sdcard, 5); 
142
143    if (app == SDCARD_ACMD)
144    {
145        spi_put_tx(sdcard->spi, 0x40 | 55         , 0 );/* CMD and START bit */
146        spi_put_tx(sdcard->spi, 0x00              , 0 );/* Argument[0]       */
147        spi_put_tx(sdcard->spi, 0x00              , 0 );/* Argument[1]       */
148        spi_put_tx(sdcard->spi, 0x00              , 0 );/* Argument[2]       */
149        spi_put_tx(sdcard->spi, 0x00              , 0 );/* Argument[3]       */
150        spi_put_tx(sdcard->spi, 0x01 | (crc7 << 1), 0 );/* END bit           */
151
152        sdcard_rsp = _sdcard_wait_response(sdcard);
153        if (SDCARD_CHECK_R1_ERROR(sdcard_rsp))
154        {
155            return sdcard_rsp;       
156        }
157    }
158
159    _args = (unsigned char *) args;
160
161    _sdcard_gen_tick(sdcard, 1); 
162
163    spi_put_tx(sdcard->spi, 0x40 | index      , 0 );
164    spi_put_tx(sdcard->spi, _args[0]          , 0 );
165    spi_put_tx(sdcard->spi, _args[1]          , 0 );
166    spi_put_tx(sdcard->spi, _args[2]          , 0 );
167    spi_put_tx(sdcard->spi, _args[3]          , 0 );
168    spi_put_tx(sdcard->spi, 0x01 | (crc7 << 1), 0 );
169
170    return _sdcard_wait_response(sdcard);
171}
172
173int sdcard_dev_open(struct sdcard_dev * sdcard, struct spi_dev * spi, int ss)
174{
175        unsigned char args[4];
176        unsigned char sdcard_rsp;
177        unsigned int  iter, ersp;
178
179        sdcard->spi      = spi;
180        sdcard->slave_id = ss;
181
182        /*
183        * Supply SD card ramp up time (min 74 cycles)
184        */
185        _sdcard_gen_tick(sdcard, 10);
186
187        /*
188        * Assert slave select signal
189        * Send CMD0 (Reset Command)
190        * Deassert slave select signal
191        */
192        _sdcard_enable(sdcard);
193
194        args[0] = 0;
195        args[1] = 0;
196        args[2] = 0;
197        args[3] = 0;
198        sdcard_rsp = _sdcard_send_command(sdcard, 0, SDCARD_CMD, args, 0x4A);
199        if ( sdcard_rsp != 0x01 )
200        {
201                reset_puts("card CMD0 failed ");
202                return sdcard_rsp;
203        }
204
205        _sdcard_disable(sdcard);
206        /*
207         * send CMD8. If card is pre-v2, It will reply with illegal command.
208         * Otherwise we announce sdhc support.
209         */
210        _sdcard_enable(sdcard);
211        args[0] = 0;
212        args[1] = 0;
213        args[2] = 0x01;
214        args[3] = 0x01;
215        sdcard_rsp = _sdcard_send_command(sdcard, 8, SDCARD_CMD, args, 0x63);
216        if (!SDCARD_CHECK_R1_VALID(sdcard_rsp)) {
217                reset_puts("card CMD8 failed ");
218                return sdcard_rsp;
219        }
220        if (!SDCARD_CHECK_R1_ERROR(sdcard_rsp)) {
221                /* no error, command accepted. get whole reply */
222                ersp = _sdcard_receive_char(sdcard);
223                ersp = (ersp << 8) | _sdcard_receive_char(sdcard);
224                ersp = (ersp << 8) | _sdcard_receive_char(sdcard);
225                ersp = (ersp << 8) | _sdcard_receive_char(sdcard);
226                if ((ersp & 0xffff) != 0x0101) {
227                        /* voltage mismatch */
228                        reset_puts("card CMD8 mismatch: ");
229                        reset_putx(ersp);
230                        return sdcard_rsp;
231                }
232                reset_puts("v2 or later ");
233                sdcard->sdhc = 1;
234        } else if ((sdcard_rsp & SDCARD_R1_ILLEGAL_CMD) == 0) {
235                /* other error */
236                reset_puts("card CMD8 error ");
237                return sdcard_rsp;
238        } else {
239                sdcard->sdhc = 0;
240        }
241        _sdcard_disable(sdcard);
242        /* send CMD41, enabling the card */
243        _sdcard_enable(sdcard);
244        args[0] = sdcard->sdhc ? 0x40: 0;
245        args[1] = 0;
246        args[2] = 0;
247        args[3] = 0;
248
249        iter = 0;
250        while( iter++ < SDCARD_COMMAND_TIMEOUT )
251        {
252                sdcard_rsp = _sdcard_send_command(sdcard, 41, SDCARD_ACMD, args, 0x00);
253                if( sdcard_rsp == 0x01 )
254                {
255                        continue;
256                }
257
258                break;
259        }
260
261        _sdcard_disable(sdcard);
262        if (sdcard_rsp) {
263                reset_puts("SD ACMD41 failed ");
264                return sdcard_rsp;
265        }
266        if (sdcard->sdhc != 0) {
267                /* get the card capacity to see if it's really HC */
268                _sdcard_enable(sdcard);
269                args[0] = sdcard->sdhc ? 0x40: 0;
270                args[1] = 0;
271                args[2] = 0;
272                args[3] = 0;
273                sdcard_rsp = _sdcard_send_command(sdcard, 58, SDCARD_CMD,
274                    args, 0x00);
275                if (sdcard_rsp) {
276                        reset_puts("SD CMD58 failed ");
277                        return sdcard_rsp;
278                }
279                ersp = _sdcard_receive_char(sdcard);
280                ersp = (ersp << 8) | _sdcard_receive_char(sdcard);
281                ersp = (ersp << 8) | _sdcard_receive_char(sdcard);
282                ersp = (ersp << 8) | _sdcard_receive_char(sdcard);
283                if (ersp & 0x40000000) {
284                        reset_puts("SDHC ");
285                } else {
286                        sdcard->sdhc = 0;
287                }
288                _sdcard_disable(sdcard);
289        }
290        reset_puts("card detected ");
291        return 0;
292}
293
294///////////////////////////////////////////////////////////////////////////////
295int sdcard_dev_read(struct sdcard_dev * sdcard, void * buf, unsigned int count)
296{
297    unsigned char args[4];
298    unsigned char sdcard_rsp;
299    register int  i;
300
301    for (i = 0; i < 4; i++)
302    {
303        args[i] = (sdcard->access_pointer >> (32 - (i+1)*8)) & 0xFF;
304    }
305
306    _sdcard_enable(sdcard);
307
308    sdcard_rsp = _sdcard_send_command(sdcard, 17, SDCARD_CMD, args, 0x00);
309    if ( SDCARD_CHECK_R1_ERROR(sdcard_rsp) )
310    {
311        _sdcard_disable(sdcard);
312        return sdcard_rsp;
313    }
314
315    _sdcard_wait_data_block(sdcard);
316
317    spi_get_data(sdcard->spi, buf, count);
318
319    /*
320     * Get the remainder of the block bytes and the CRC16 (comes
321     * at the end of the data block)
322     */
323    i = count;
324    while( i++ < (512 + 2) ) _sdcard_receive_char(sdcard);
325
326    _sdcard_disable(sdcard);
327
328    /*
329     * Move the access pointer to the next block
330     */
331    sdcard->access_pointer += sdcard->block_length;
332
333    return 0;
334}
335
336////////////////////////////////////////////////////////////////////////////////////////
337unsigned int sdcard_dev_write(struct sdcard_dev *sdcard, void * buf, unsigned int count)
338{
339        return 0;
340}
341
342///////////////////////////////////////////////////////////////////////
343void sdcard_dev_lseek(struct sdcard_dev * sdcard, unsigned int blk_pos)
344{
345    sdcard->access_pointer = sdcard->block_length * blk_pos;
346}
347
348/////////////////////////////////////////////////////////////////////////
349int sdcard_dev_set_blocklen(struct sdcard_dev * sdcard, unsigned int len)
350{
351    unsigned char args[4];
352    unsigned char sdcard_rsp;
353    register int i;
354
355    if (len != 512)
356        return 1;
357
358    if (sdcard->sdhc) {
359        sdcard->block_length = 1;
360        return 0;
361    }
362
363    for (i = 0; i < 4; i++)
364        args[i] = (len >> (32 - (i+1)*8)) & 0xFF;
365
366    _sdcard_enable(sdcard);
367
368    sdcard_rsp = _sdcard_send_command(sdcard, 16, SDCARD_CMD, args, 0x00);
369    if ( SDCARD_CHECK_R1_ERROR(sdcard_rsp) )
370    {
371        _sdcard_disable(sdcard);
372        return sdcard_rsp;
373    }
374
375    _sdcard_disable(sdcard);
376
377    sdcard->block_length = len;
378
379        return 0;
380}
381
382////////////////////
383int reset_spi_init()
384{
385    unsigned char sdcard_rsp;
386
387    reset_puts("Initializing block device\n\r");
388
389    /**
390     * Initializing the SPI controller
391     */
392    spi_dev_config (
393      _spi_device            ,
394      spi_init_clkfreq       ,
395      RESET_SYSTEM_CLK * 1000,
396      8                      ,
397      SPI_TX_NEGEDGE         ,
398      SPI_RX_POSEDGE
399    );
400
401    /**
402     * Initializing the SD Card
403     */
404    unsigned int iter = 0;
405    while(1)
406    {
407        reset_puts("Trying to initialize SD card... ");
408
409        sdcard_rsp = sdcard_dev_open(&_sdcard_device, _spi_device, 0);
410        if (sdcard_rsp == 0)
411        {
412            reset_puts("OK\n");
413            break;
414        }
415
416        reset_puts("KO\n");
417        reset_sleep(1000);
418        if (++iter >= sdcard_reset_retries)
419        {
420            reset_puts("\nERROR: During SD card reset to IDLE state\n"
421                      "/ card response = ");
422            reset_putx(sdcard_rsp);
423            reset_puts("\n");
424            reset_exit();
425        }
426    }
427
428    /**
429     * Set the block length of the SD Card
430     */
431    sdcard_rsp = sdcard_dev_set_blocklen(&_sdcard_device, 512);
432    if (sdcard_rsp)
433    {
434        reset_puts("ERROR: During SD card blocklen initialization\n");
435        reset_exit();
436    }
437
438    /**
439     * Incrementing SDCARD clock frequency for normal function
440     */
441    spi_dev_config (
442        _spi_device            ,
443        spi_func_clkfreq       ,
444        RESET_SYSTEM_CLK * 1000,
445        -1                     ,
446        -1                     ,
447        -1
448    );
449
450    reset_puts("Finish block device initialization\n\r");
451
452    return 0;
453}  // end reset_spi_init()
454
455////////////////////////////////////////////////////////////////////////
456int reset_spi_read( unsigned int lba, void* buffer, unsigned int count )
457{
458    unsigned int rsp;
459    unsigned int i;
460
461    sdcard_dev_lseek(&_sdcard_device, lba);
462
463    for(i = 0; i < count; i++)
464    {
465        unsigned char* buf = (unsigned char *) buffer + (512 * i);
466
467        if (( rsp = sdcard_dev_read ( &_sdcard_device, buf, 512 ) ))
468        {
469            reset_puts("ERROR in reset_spi_read() in SDCARD access / code = ");
470            reset_putx( rsp );
471            reset_puts("\n");
472            return 1;
473        }
474    }
475    return 0;
476}  // end reset_spi_read()
477
478/*
479 * vim: tabstop=4 : softtabstop=4 : shiftwidth=4 : expandtab
480 */
Note: See TracBrowser for help on using the repository browser.