source: trunk/boot/tsar_mips32/boot_spi_driver.c @ 572

Last change on this file since 572 was 547, checked in by nicolas.van.phan@…, 6 years ago

Implement bootloader SPI SD card driver (VERY SLOW)

Rectify boot_spi_driver frequency

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