source: rtems/c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_m3sd.c @ ef4c461

4.115
Last change on this file since ef4c461 was ef4c461, checked in by Joel Sherrill <joel.sherrill@…>, on 10/09/14 at 20:35:10

arm/nds: Warning clean up

This patch eliminates most of the warnings in this BSP but attempts
very little clean up. This BSP includes copies of a lot of code
from free NDS libraries and modifications should be kept to a minimum.

  • Property mode set to 100644
File size: 12.5 KB
Line 
1/*
2        io_m3sd.c
3
4        Hardware Routines for reading a Secure Digital card
5        using the M3 SD
6
7        Some code based on M3 SD drivers supplied by M3Adapter.
8        Some code written by SaTa may have been unknowingly used.
9
10 Copyright (c) 2006 Michael "Chishm" Chisholm
11
12 Redistribution and use in source and binary forms, with or without modification,
13 are permitted provided that the following conditions are met:
14
15  1. Redistributions of source code must retain the above copyright notice,
16     this list of conditions and the following disclaimer.
17  2. Redistributions in binary form must reproduce the above copyright notice,
18     this list of conditions and the following disclaimer in the documentation and/or
19     other materials provided with the distribution.
20  3. The name of the author may not be used to endorse or promote products derived
21     from this software without specific prior written permission.
22
23 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
24 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
26 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
33        2006-07-25 - Chishm
34                * Improved startup function that doesn't delay hundreds of seconds
35                  before reporting no card inserted.
36                * Fixed writeData function to timeout on error
37                * writeSectors function now wait until the card is ready before continuing with a transfer
38
39        2006-08-05 - Chishm
40                * Tries multiple times to get a Relative Card Address at startup
41
42        2006-08-07 - Chishm
43                * Moved the SD initialization to a common function
44*/
45
46#include "io_m3sd.h"
47#include "io_sd_common.h"
48#include "io_m3_common.h"
49
50//---------------------------------------------------------------
51// M3SD register addresses
52
53#define REG_M3SD_DIR    (*(vu16*)0x08800000)    // direction control register
54#define REG_M3SD_DAT    (*(vu16*)0x09000000)    // SD data line, 8 bits at a time
55#define REG_M3SD_CMD    (*(vu16*)0x09200000)    // SD command byte
56#define REG_M3SD_ARGH   (*(vu16*)0x09400000)    // SD command argument, high halfword
57#define REG_M3SD_ARGL   (*(vu16*)0x09600000)    // SD command argument, low halfword
58#define REG_M3SD_STS    (*(vu16*)0x09800000)    // command and status register
59
60//---------------------------------------------------------------
61// Send / receive timeouts, to stop infinite wait loops
62#define NUM_STARTUP_CLOCKS 100  // Number of empty (0xFF when sending) bytes to send/receive to/from the card
63#define TRANSMIT_TIMEOUT 20000  // Time to wait for the M3 to respond to transmit or receive requests
64#define RESPONSE_TIMEOUT 256    // Number of clocks sent to the SD card before giving up
65#define WRITE_TIMEOUT   3000    // Time to wait for the card to finish writing
66
67//---------------------------------------------------------------
68// Variables required for tracking SD state
69static u32 _M3SD_relativeCardAddress = 0;       // Preshifted Relative Card Address
70
71//---------------------------------------------------------------
72// Internal M3 SD functions
73
74static inline void _M3SD_unlock (void) {
75        _M3_changeMode (M3_MODE_MEDIA);
76}
77
78static inline bool _M3SD_waitOnBusy (void) {
79        int i = 0;
80        while ( (REG_M3SD_STS & 0x01) == 0x00) {
81                i++;
82                if (i >= TRANSMIT_TIMEOUT) {
83                        return false;
84                }
85        }
86        return true;
87}
88
89static inline bool _M3SD_waitForDataReady (void) {
90        int i = 0;
91        while ( (REG_M3SD_STS & 0x40) == 0x00) {
92                i++;
93                if (i >= TRANSMIT_TIMEOUT) {
94                        return false;
95                }
96        }
97        return true;
98}
99
100
101static bool _M3SD_sendCommand (u16 command, u32 argument) {
102        REG_M3SD_STS = 0x8;
103        REG_M3SD_CMD = 0x40 + command;          // Include the start bit
104        REG_M3SD_ARGH = argument >> 16;
105        REG_M3SD_ARGL = argument;
106        // The CRC7 of the command is calculated by the M3
107
108        REG_M3SD_DIR=0x29;
109        if (!_M3SD_waitOnBusy()) {
110                REG_M3SD_DIR=0x09;
111                return false;
112        }
113        REG_M3SD_DIR=0x09;
114        return true;
115}
116
117static bool _M3SD_sendByte (u8 byte) {
118        int i = 0;
119        REG_M3SD_DAT = byte;
120        REG_M3SD_DIR = 0x03;
121        REG_M3SD_STS = 0x01;
122        while ((REG_M3SD_STS & 0x04) == 0) {
123                i++;
124                if (i >= TRANSMIT_TIMEOUT) {
125                        return false;
126                }
127        }
128        return true;
129}
130
131static u8 _M3SD_getByte (void) {
132        int i;
133        // Request 8 bits of data from the SD's CMD pin
134        REG_M3SD_DIR = 0x02;
135        REG_M3SD_STS = 0x02;
136        // Wait for the data to be ready
137        i = 0;
138        while ((REG_M3SD_STS & 0x08) == 0) {
139                i++;
140                if (i >= TRANSMIT_TIMEOUT) {
141                        // Return an empty byte if a timeout occurs
142                        return 0xFF;
143                }
144        }
145        i = 0;
146        while ((REG_M3SD_STS & 0x08) != 0) {
147                i++;
148                if (i >= TRANSMIT_TIMEOUT) {
149                        // Return an empty byte if a timeout occurs
150                        return 0xFF;
151                }
152        }
153        // Return the data
154        return (REG_M3SD_DAT & 0xff);
155}
156
157// Returns the response from the SD card to a previous command.
158static bool _M3SD_getResponse (u8* dest, u32 length) {
159        u32 i;
160        u8 dataByte;
161        int shiftAmount;
162
163        // Wait for the card to be non-busy
164        for (i = 0; i < RESPONSE_TIMEOUT; i++) {
165                dataByte = _M3SD_getByte();
166                if (dataByte != SD_CARD_BUSY) {
167                        break;
168                }
169        }
170
171        if (dest == NULL) {
172                return true;
173        }
174
175        // Still busy after the timeout has passed
176        if (dataByte == 0xff) {
177                return false;
178        }
179
180        // Read response into buffer
181        for ( i = 0; i < length; i++) {
182                dest[i] = dataByte;
183                dataByte = _M3SD_getByte();
184        }
185        // dataByte will contain the last piece of the response
186
187        // Send 16 more clocks, 8 more than the delay required between a response and the next command
188        i = _M3SD_getByte();
189        i = _M3SD_getByte();
190
191        // Shift response so that the bytes are correctly aligned
192        // The register may not contain properly aligned data
193        for (shiftAmount = 0; ((dest[0] << shiftAmount) & 0x80) != 0x00; shiftAmount++) {
194                if (shiftAmount >= 7) {
195                        return false;
196                }
197        }
198
199        for (i = 0; i < length - 1; i++) {
200                dest[i] = (dest[i] << shiftAmount) | (dest[i+1] >> (8-shiftAmount));
201        }
202        // Get the last piece of the response from dataByte
203        dest[i] = (dest[i] << shiftAmount) | (dataByte >> (8-shiftAmount));
204
205        return true;
206}
207
208
209static inline bool _M3SD_getResponse_R1 (u8* dest) {
210        return _M3SD_getResponse (dest, 6);
211}
212
213static inline bool _M3SD_getResponse_R1b (u8* dest) {
214        return _M3SD_getResponse (dest, 6);
215}
216
217static inline bool _M3SD_getResponse_R2 (u8* dest) {
218        return _M3SD_getResponse (dest, 17);
219}
220
221static inline bool _M3SD_getResponse_R3 (u8* dest) {
222        return _M3SD_getResponse (dest, 6);
223}
224
225static inline bool _M3SD_getResponse_R6 (u8* dest) {
226        return _M3SD_getResponse (dest, 6);
227}
228
229static void _M3SD_sendClocks (u32 numClocks) {
230        while (numClocks--) {
231                _M3SD_sendByte(0xff);
232        }
233}
234
235static void _M3SD_getClocks (u32 numClocks) {
236        while (numClocks--) {
237                _M3SD_getByte();
238        }
239}
240
241static bool _M3SD_cmd_6byte_response (u8* responseBuffer, u8 command, u32 data) {
242        _M3SD_sendCommand (command, data);
243        return _M3SD_getResponse (responseBuffer, 6);
244}
245
246static bool _M3SD_cmd_17byte_response (u8* responseBuffer, u8 command, u32 data) {
247        _M3SD_sendCommand (command, data);
248        return _M3SD_getResponse (responseBuffer, 17);
249}
250
251static bool _M3SD_initCard (void) {
252        // Give the card time to stabilise
253        _M3SD_sendClocks (NUM_STARTUP_CLOCKS);
254
255        // Reset the card
256        if (!_M3SD_sendCommand (GO_IDLE_STATE, 0)) {
257                return false;
258        }
259
260        _M3SD_getClocks (NUM_STARTUP_CLOCKS);
261
262        // Card is now reset, including it's address
263        _M3SD_relativeCardAddress = 0;
264
265        // Init the card
266        return _SD_InitCard (_M3SD_cmd_6byte_response,
267                                _M3SD_cmd_17byte_response,
268                                true,
269                                &_M3SD_relativeCardAddress);
270}
271
272static bool _M3SD_readData (void* buffer) {
273        u32 i;
274        u8* buff_u8 = (u8*)buffer;
275        u16* buff = (u16*)buffer;
276        u16 temp;
277
278        REG_M3SD_DIR = 0x49;
279        if (!_M3SD_waitForDataReady()) {
280                REG_M3SD_DIR = 0x09;
281                return false;
282        }
283        REG_M3SD_DIR = 0x09;
284
285        REG_M3SD_DIR =  0x8;
286        REG_M3SD_STS = 0x4;
287
288        i = REG_M3SD_DIR;
289        // Read data
290        i=256;
291        if ((u32)buff_u8 & 0x01) {
292                while(i--)
293                {
294                        temp = REG_M3SD_DIR;
295                        *buff_u8++ = temp & 0xFF;
296                        *buff_u8++ = temp >> 8;
297                }
298        } else {
299                while(i--)
300                        *buff++ = REG_M3SD_DIR;
301        }
302        // Read end checksum
303        i = REG_M3SD_DIR + REG_M3SD_DIR + REG_M3SD_DIR + REG_M3SD_DIR;
304
305        return true;
306}
307
308static void _M3SD_clkout (void) {
309        REG_M3SD_DIR = 0x4;
310        REG_M3SD_DIR = 0xc;
311/*      __asm volatile (
312        "ldr    r1, =0x08800000         \n"
313        "mov    r0, #0x04                       \n"
314        "strh   r0, [r1]                        \n"
315        "mov    r0, r0                          \n"
316        "mov    r0, r0                          \n"
317        "mov    r0, #0x0c                       \n"
318        "strh   r0, [r1]                        \n"
319        :                                       // Outputs
320        :                                       // Inputs
321        : "r0", "r1"            // Clobber list
322        );*/
323}
324
325static void _M3SD_clkin (void) {
326        REG_M3SD_DIR = 0x0;
327        REG_M3SD_DIR = 0x8;
328/*      __asm volatile (
329        "ldr    r1, =0x08800000         \n"
330        "mov    r0, #0x00                       \n"
331        "strh   r0, [r1]                        \n"
332        "mov    r0, r0                          \n"
333        "mov    r0, r0                          \n"
334        "mov    r0, #0x08                       \n"
335        "strh   r0, [r1]                        \n"
336        :                                       // Outputs
337        :                                       // Inputs
338        : "r0", "r1"            // Clobber list
339        );*/
340}
341
342static bool _M3SD_writeData (u8* data, u8* crc) {
343        int i;
344        u8 temp;
345
346        do {
347                _M3SD_clkin();
348        } while ((REG_M3SD_DAT & 0x100) == 0);
349
350        REG_M3SD_DAT = 0;       // Start bit
351
352        _M3SD_clkout();
353
354        for (i = 0; i < BYTES_PER_READ; i++) {
355                temp = (*data++);
356                REG_M3SD_DAT = temp >> 4;
357                _M3SD_clkout();
358                REG_M3SD_DAT = temp;
359                _M3SD_clkout();
360        }
361
362        if (crc != NULL) {
363                for (i = 0; i < 8; i++) {
364                        temp = (*crc++);
365                        REG_M3SD_DAT = temp >> 4;
366                        _M3SD_clkout();
367                        REG_M3SD_DAT = temp;
368                        _M3SD_clkout();
369                }
370        }
371
372        i = 32;
373        while (i--) {
374                temp += 2;              // a NOP to stop the compiler optimising out the loop
375        }
376
377        for (i = 0; i  < 32; i++) {
378                REG_M3SD_DAT = 0xff;
379                _M3SD_clkout();
380        }
381
382        do {
383                _M3SD_clkin();
384        } while ((REG_M3SD_DAT & 0x100) == 0);
385
386        return true;
387}
388
389//---------------------------------------------------------------
390// Functions needed for the external interface
391
392static bool _M3SD_startUp (void) {
393        _M3SD_unlock();
394        return _M3SD_initCard();
395}
396
397static bool _M3SD_isInserted (void) {
398        u8 responseBuffer [6];
399        // Make sure the card receives the command
400        if (!_M3SD_sendCommand (SEND_STATUS, 0)) {
401                return false;
402        }
403        // Make sure the card responds
404        if (!_M3SD_getResponse_R1 (responseBuffer)) {
405                return false;
406        }
407        // Make sure the card responded correctly
408        if (responseBuffer[0] != SEND_STATUS) {
409                return false;
410        }
411        return true;
412}
413
414static bool _M3SD_readSectors (u32 sector, u32 numSectors, void* buffer) {
415        u32 i;
416        u8* dest = (u8*) buffer;
417        u8 responseBuffer[6];
418
419        if (numSectors == 1) {
420                // If it's only reading one sector, use the (slightly faster) READ_SINGLE_BLOCK
421                if (!_M3SD_sendCommand (READ_SINGLE_BLOCK, sector * BYTES_PER_READ)) {
422                        return false;
423                }
424
425                if (!_M3SD_readData (buffer)) {
426                        return false;
427                }
428
429        } else {
430                // Stream the required number of sectors from the card
431                if (!_M3SD_sendCommand (READ_MULTIPLE_BLOCK, sector * BYTES_PER_READ)) {
432                        return false;
433                }
434
435                for(i=0; i < numSectors; i++, dest+=BYTES_PER_READ) {
436                        if (!_M3SD_readData(dest)) {
437                                return false;
438                        }
439                        REG_M3SD_STS = 0x8;
440                }
441
442                // Stop the streaming
443                _M3SD_sendCommand (STOP_TRANSMISSION, 0);
444                _M3SD_getResponse_R1b (responseBuffer);
445        }
446
447        return true;
448}
449
450static bool _M3SD_writeSectors (u32 sector, u32 numSectors, const void* buffer) {
451        u8 crc[8];
452        u8 responseBuffer[6];
453        u32 offset = sector * BYTES_PER_READ;
454        u8* data = (u8*) buffer;
455        int i;
456        // Precalculate the data CRC
457        _SD_CRC16 ( data, BYTES_PER_READ, crc);
458
459        while (numSectors--) {
460                // Send a single sector write command
461                _M3SD_sendCommand (WRITE_BLOCK, offset);
462                if (!_M3SD_getResponse_R1 (responseBuffer)) {
463                        return false;
464                }
465
466                REG_M3SD_DIR = 0x4;
467                REG_M3SD_STS = 0x0;
468
469                // Send the data
470                if (! _M3SD_writeData( data, crc)) {
471                        return false;
472                }
473
474                if (numSectors > 0) {
475                        offset += BYTES_PER_READ;
476                        data += BYTES_PER_READ;
477                        // Calculate the next CRC while waiting for the card to finish writing
478                        _SD_CRC16 ( data, BYTES_PER_READ, crc);
479                }
480
481                // Wait for the card to be ready for the next transfer
482                i = WRITE_TIMEOUT;
483                responseBuffer[3] = 0;
484                do {
485                        _M3SD_sendCommand (SEND_STATUS, _M3SD_relativeCardAddress);
486                        _M3SD_getResponse_R1 (responseBuffer);
487                        i--;
488                        if (i <= 0) {
489                                return false;
490                        }
491                } while (((responseBuffer[3] & 0x1f) != ((SD_STATE_TRAN << 1) | READY_FOR_DATA)));
492        }
493
494        return true;
495
496}
497
498static bool _M3SD_clearStatus (void) {
499        return _M3SD_initCard ();
500}
501
502static bool _M3SD_shutdown (void) {
503        _M3_changeMode (M3_MODE_ROM);
504        return true;
505}
506
507const IO_INTERFACE _io_m3sd = {
508        DEVICE_TYPE_M3SD,
509        FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
510        (FN_MEDIUM_STARTUP)&_M3SD_startUp,
511        (FN_MEDIUM_ISINSERTED)&_M3SD_isInserted,
512        (FN_MEDIUM_READSECTORS)&_M3SD_readSectors,
513        (FN_MEDIUM_WRITESECTORS)&_M3SD_writeSectors,
514        (FN_MEDIUM_CLEARSTATUS)&_M3SD_clearStatus,
515        (FN_MEDIUM_SHUTDOWN)&_M3SD_shutdown
516} ;
517
518
Note: See TracBrowser for help on using the repository browser.