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

Last change on this file since 276 was 276, checked in by bouyer, 11 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: 7.0 KB
Line 
1/**
2 * \file    : sdcard.c
3 * \date    : 30 August 2012
4 * \author  : Cesar Fuguet
5 *
6 * This file defines the driver of a SD Card device using an SPI controller
7 */
8
9#include <sdcard.h>
10
11#define in_reset        __attribute__((section (".reset")))
12#define in_reset_data   __attribute__((section (".reset_data")))
13
14/**
15 * \param   sdcard: Initialized pointer to the block device
16 *
17 * \return  void
18 *
19 * \brief   Enable SD Card select signal
20 */
21in_reset static void _sdcard_enable(struct sdcard_dev * sdcard)
22{
23    spi_ss_assert(sdcard->spi, sdcard->slave_id);
24}
25
26/**
27 * \param   sdcard: Initialized pointer to the block device
28 *
29 * \return  void
30 *
31 * \brief   Disable SD Card select signal
32 */
33in_reset static void _sdcard_disable(struct sdcard_dev * sdcard)
34{
35    spi_ss_deassert(sdcard->spi, sdcard->slave_id);
36}
37
38/**
39 * \param   tick_count: SD Card clock ticks number
40 *
41 * \return  void
42 *
43 * \brief   Enable SD Card clock
44 *          The tick count is byte measured (1 tick, 8 clock)
45 */
46in_reset static void _sdcard_gen_tick(struct sdcard_dev * sdcard, size_t tick_count)
47{
48    volatile register int i = 0;
49    while(i++ < tick_count) spi_put_tx(sdcard->spi, 0xFF, 0);
50}
51
52/**
53 * \param   sdcard: Initialized pointer to the block device
54 *
55 * \return  char from the SD card
56 *
57 * \brief   Get a byte from the SD Card
58 */
59in_reset static unsigned char _sdcard_receive_char(struct sdcard_dev * sdcard)
60{
61    _sdcard_gen_tick(sdcard, 1);
62
63    return spi_get_rx(sdcard->spi, 0);
64}
65
66/**
67 * \param   sdcard: Initialized pointer to the block device
68 *
69 * \return  sdcard response
70 *
71 * \brief   Wait for a valid response after the send of a command
72 *          This function can return if one of the next two conditions are true:
73 *           1. Bit valid received
74 *           2. Timeout (not valid bit received after SDCARD_COMMAND_TIMEOUT
75 *              wait ticks)
76 */
77in_reset static unsigned char _sdcard_wait_response(struct sdcard_dev * sdcard)
78{
79    unsigned char sdcard_rsp;
80    register int  iter;
81
82    iter       = 0;
83    sdcard_rsp = _sdcard_receive_char(sdcard);
84    while (
85            (iter < SDCARD_COMMAND_TIMEOUT) &&
86            !SDCARD_CHECK_R1_VALID(sdcard_rsp)
87          )
88    {
89        sdcard_rsp = _sdcard_receive_char(sdcard);
90        iter++;
91    }
92
93    return sdcard_rsp;
94}
95
96/**
97 * \params  sdcard: Initialized pointer to the block device
98 *
99 * \return  void
100 *
101 * \brief   Wait data block start marker
102 */
103in_reset static void _sdcard_wait_data_block(struct sdcard_dev * sdcard)
104{
105        while (_sdcard_receive_char(sdcard) != 0xFE);
106}
107
108/**
109 * \param   sdcard  : Initialized pointer to block device
110 * \param   index   : SD card CMD index
111 * \param   app     : Type of command, 0 for normal command or 1 for application specific
112 * \param   args    : SD card CMD arguments
113 *
114 * \return  response first byte
115 *
116 * \brief   Send command to the SD card
117 */
118in_reset static int _sdcard_send_command    (
119        struct sdcard_dev * sdcard ,
120        int                 index  ,
121        int                 app    ,
122        void *              args   ,
123        unsigned            crc7   )
124{
125    unsigned char sdcard_rsp;
126    unsigned char * _args;
127
128    _sdcard_gen_tick(sdcard, 5); 
129
130    if (app == SDCARD_ACMD)
131    {
132        spi_put_tx(sdcard->spi, 0x40 | 55         , 0 );/* CMD and START bit */
133        spi_put_tx(sdcard->spi, 0x00              , 0 );/* Argument[0]       */
134        spi_put_tx(sdcard->spi, 0x00              , 0 );/* Argument[1]       */
135        spi_put_tx(sdcard->spi, 0x00              , 0 );/* Argument[2]       */
136        spi_put_tx(sdcard->spi, 0x00              , 0 );/* Argument[3]       */
137        spi_put_tx(sdcard->spi, 0x01 | (crc7 << 1), 0 );/* END bit           */
138
139        sdcard_rsp = _sdcard_wait_response(sdcard);
140        if (SDCARD_CHECK_R1_ERROR(sdcard_rsp))
141        {
142            return sdcard_rsp;       
143        }
144    }
145
146    _args = (unsigned char *) args;
147
148    _sdcard_gen_tick(sdcard, 1); 
149
150    spi_put_tx(sdcard->spi, 0x40 | index      , 0 );
151    spi_put_tx(sdcard->spi, _args[0]          , 0 );
152    spi_put_tx(sdcard->spi, _args[1]          , 0 );
153    spi_put_tx(sdcard->spi, _args[2]          , 0 );
154    spi_put_tx(sdcard->spi, _args[3]          , 0 );
155    spi_put_tx(sdcard->spi, 0x01 | (crc7 << 1), 0 );
156
157    return _sdcard_wait_response(sdcard);
158}
159
160in_reset int sdcard_dev_open(struct sdcard_dev * sdcard, struct spi_dev * spi, int ss)
161{
162    unsigned char args[4];
163        unsigned char sdcard_rsp;
164        unsigned int  iter;
165
166        sdcard->spi      = spi;
167    sdcard->slave_id = ss;
168
169        /*
170     * Supply SD card ramp up time (min 74 cycles)
171     */
172        _sdcard_gen_tick(sdcard, 10);
173
174    /*
175     * Assert slave select signal
176     * Send CMD0 (Reset Command)
177     * Deassert slave select signal
178     */
179        _sdcard_enable(sdcard);
180
181    args[0] = 0;
182    args[1] = 0;
183    args[2] = 0;
184    args[3] = 0;
185        sdcard_rsp = _sdcard_send_command(sdcard, 0, SDCARD_CMD, args, 0x4A);
186        if ( sdcard_rsp != 0x01 )
187        {
188                return sdcard_rsp;
189        }
190
191        _sdcard_disable(sdcard);
192        _sdcard_enable(sdcard);
193
194        iter = 0;
195        while( iter++ < SDCARD_COMMAND_TIMEOUT )
196        {
197                sdcard_rsp = _sdcard_send_command(sdcard, 41, SDCARD_ACMD, args, 0x00);
198                if( sdcard_rsp == 0x01 )
199                {
200                        continue;
201                }
202
203                break;
204        }
205
206        _sdcard_disable(sdcard);
207
208        return sdcard_rsp;
209}
210
211in_reset int sdcard_dev_read(struct sdcard_dev * sdcard, void * buf, size_t count)
212{
213    unsigned char args[4];
214    unsigned char sdcard_rsp;
215    register int  i;
216
217    for (i = 0; i < 4; i++)
218        args[i] = (sdcard->access_pointer >> (32 - (i+1)*8)) & 0xFF;
219
220    _sdcard_enable(sdcard);
221
222    sdcard_rsp = _sdcard_send_command(sdcard, 17, SDCARD_CMD, args, 0x00);
223    if ( SDCARD_CHECK_R1_ERROR(sdcard_rsp) )
224    {
225        _sdcard_disable(sdcard);
226        return sdcard_rsp;
227    }
228
229    _sdcard_wait_data_block(sdcard);
230
231    for ( i = 0; i < count; i++ )
232    {
233        *((char *) buf + i) = _sdcard_receive_char(sdcard);
234    }
235
236    /*
237     * Get the remainder of the block bytes and the CRC16 (comes
238     * at the end of the data block)
239     */
240    while( i++ < (sdcard->block_length + 2) ) _sdcard_receive_char(sdcard);
241
242    _sdcard_disable(sdcard);
243
244    /*
245     * Move the access pointer to the next block
246     */
247    sdcard->access_pointer += sdcard->block_length;
248
249    return 0;
250}
251
252in_reset size_t sdcard_dev_write(struct sdcard_dev *sdcard, void * buf, size_t count)
253{
254        return 0;
255}
256
257in_reset void sdcard_dev_lseek(struct sdcard_dev * sdcard, size_t blk_pos)
258{
259    sdcard->access_pointer = sdcard->block_length * blk_pos;
260}
261
262in_reset size_t sdcard_dev_get_capacity(struct sdcard_dev * sdcard)
263{
264        return sdcard->capacity;
265}
266
267in_reset int sdcard_dev_set_blocklen(struct sdcard_dev * sdcard, size_t len)
268{
269    unsigned char args[4];
270    unsigned char sdcard_rsp;
271    register int i;
272
273    for (i = 0; i < 4; i++)
274        args[i] = (len >> (32 - (i+1)*8)) & 0xFF;
275
276    _sdcard_enable(sdcard);
277
278    sdcard_rsp = _sdcard_send_command(sdcard, 16, SDCARD_CMD, args, 0x00);
279    if ( SDCARD_CHECK_R1_ERROR(sdcard_rsp) )
280    {
281        _sdcard_disable(sdcard);
282        return sdcard_rsp;
283    }
284
285    _sdcard_disable(sdcard);
286
287    sdcard->block_length = len;
288
289        return 0;
290}
291
292#undef in_reset
293
294/*
295 * vim: tabstop=4 : shiftwidth=4 : expandtab : softtabstop=4
296 */
Note: See TracBrowser for help on using the repository browser.