summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_sd_common.c
blob: 86dd37355be3bb53822f6a92b83595d8710f0a36 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/*
	io_sd_common.c

	By chishm (Michael Chisholm)

	Common SD card routines

	SD routines partially based on sd.s by Romman

 Copyright (c) 2006 Michael "Chishm" Chisholm

 Redistribution and use in source and binary forms, with or without modification,
 are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation and/or
     other materials provided with the distribution.
  3. The name of the author may not be used to endorse or promote products derived
     from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

	2006-08-07 - Chishm
		* Moved the SD initialization to a common function
		* Increased timeouts for slower cards

	2006-08-08 - Chishm
		* Init aborts when it doesn't get a valid response to APP_CMD - speeds up detection when no card is inserted
*/

#include "io_sd_common.h"

#define MAX_STARTUP_TRIES 1000	// Arbitrary value, check if the card is ready 20 times before giving up
#define RESPONSE_TIMEOUT 256	// Number of clocks sent to the SD card before giving up

/*
Improved CRC7 function provided by cory1492
Calculates the CRC of an SD command, and includes the end bit in the byte
*/
u8 _SD_CRC7(u8* data, int cnt) {
    int i, a;
    u8 crc, temp;

    crc = 0;
    for (a = 0; a < cnt; a++)
    {
        temp = data[a];
        for (i = 0; i < 8; i++)
        {
            crc <<= 1;
            if ((temp & 0x80) ^ (crc & 0x80)) crc ^= 0x09;
            temp <<= 1;
        }
    }
    crc = (crc << 1) | 1;
    return(crc);
}

/*
Calculates the CRC16 for a sector of data. Calculates it
as 4 separate lots, merged into one buffer. This is used
for 4 SD data lines, not for 1 data line alone.
*/
void _SD_CRC16 (u8* buff, int buffLength, u8* crc16buff) {
	u32 a, b, c, d;
	int count;
	u32 bitPattern = 0x80808080;	// r7
	u32 crcConst = 0x1021;	// r8
	u32 dataByte = 0;	// r2

	a = 0;	// r3
	b = 0;	// r4
	c = 0;	// r5
	d = 0;	// r6

	buffLength = buffLength * 8;


	do {
		if (bitPattern & 0x80) dataByte = *buff++;

		a = a << 1;
		if ( a & 0x10000) a ^= crcConst;
		if (dataByte & (bitPattern >> 24)) a ^= crcConst;

		b = b << 1;
		if (b & 0x10000) b ^= crcConst;
		if (dataByte & (bitPattern >> 25)) b ^= crcConst;

		c = c << 1;
		if (c & 0x10000) c ^= crcConst;
		if (dataByte & (bitPattern >> 26)) c ^= crcConst;

		d = d << 1;
		if (d & 0x10000) d ^= crcConst;
		if (dataByte & (bitPattern >> 27)) d ^= crcConst;

		bitPattern = (bitPattern >> 4) | (bitPattern << 28);
	} while (buffLength-=4);

	count = 16;	// r8

	do {
		bitPattern = bitPattern << 4;
		if (a & 0x8000) bitPattern |= 8;
		if (b & 0x8000) bitPattern |= 4;
		if (c & 0x8000) bitPattern |= 2;
		if (d & 0x8000) bitPattern |= 1;

		a = a << 1;
		b = b << 1;
		c = c << 1;
		d = d << 1;

		count--;

		if (!(count & 0x01)) {
			*crc16buff++ = (u8)(bitPattern & 0xff);
		}
	} while (count != 0);

	return;
}

/*
Initialise the SD card, after it has been sent into an Idle state
cmd_6byte_response: a pointer to a function that sends the SD card a command and gets a 6 byte response
cmd_17byte_response: a pointer to a function that sends the SD card a command and gets a 17 byte response
use4bitBus: initialise card to use a 4 bit data bus when communicating with the card
RCA: a pointer to the location to store the card's Relative Card Address, preshifted up by 16 bits.
*/
bool _SD_InitCard (_SD_FN_CMD_6BYTE_RESPONSE cmd_6byte_response,
					_SD_FN_CMD_17BYTE_RESPONSE cmd_17byte_response,
					bool use4bitBus,
					u32 *RCA)
{
	u8 responseBuffer[17] = {0};
	int i;

	for (i = 0; i < MAX_STARTUP_TRIES ; i++) {
		cmd_6byte_response (responseBuffer, APP_CMD, 0);
		// Check that the card gave the correct response
		if (responseBuffer[0] != APP_CMD) {
			return false;
		}
		if (
			cmd_6byte_response (responseBuffer, SD_APP_OP_COND, SD_OCR_VALUE) &&
			((responseBuffer[1] & 0x80) != 0))
		{
			// Card is ready to receive commands now
			break;
		}
	}
	if (i >= MAX_STARTUP_TRIES) {
		return false;
	}

	// The card's name, as assigned by the manufacturer
	cmd_17byte_response (responseBuffer, ALL_SEND_CID, 0);

	// Get a new address
	for (i = 0; i < MAX_STARTUP_TRIES ; i++) {
		cmd_6byte_response (responseBuffer, SEND_RELATIVE_ADDR, 0);
		*RCA = (responseBuffer[1] << 24) | (responseBuffer[2] << 16);
		if ((responseBuffer[3] & 0x1e) != (SD_STATE_STBY << 1)) {
			break;
		}
	}
 	if (i >= MAX_STARTUP_TRIES) {
		return false;
	}

	// Some cards won't go to higher speeds unless they think you checked their capabilities
	cmd_17byte_response (responseBuffer, SEND_CSD, *RCA);

	// Only this card should respond to all future commands
	cmd_6byte_response (responseBuffer, SELECT_CARD, *RCA);

	if (use4bitBus) {
		// Set a 4 bit data bus
		cmd_6byte_response (responseBuffer, APP_CMD, *RCA);
		cmd_6byte_response (responseBuffer, SET_BUS_WIDTH, 2); // 4-bit mode.
	}

	// Use 512 byte blocks
	cmd_6byte_response (responseBuffer, SET_BLOCKLEN, 512); // 512 byte blocks

	// Wait until card is ready for data
	i = 0;
	do {
		if (i >= RESPONSE_TIMEOUT) {
			return false;
		}
		i++;
	} while (!cmd_6byte_response (responseBuffer, SEND_STATUS, *RCA) && ((responseBuffer[3] & 0x1f) != ((SD_STATE_TRAN << 1) | READY_FOR_DATA)));

	return true;
}