summaryrefslogtreecommitdiffstats
path: root/ports/beagleboneblack/am335x_sd.c
blob: ac2392c49bd20f36e06e7d18b6b1ee9d92358c53 (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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
/*
 * Copyright (c) 2015 Jarielle Catbagan <jcatbagan93@gmail.com>
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.apache.org/licenses/LICENSE-2.0
 */

#include "stddefs.h"
#include "am335x.h"
#include "sd.h"

uint16_t sdrca;

int
sdcmd(uint32_t cmd, uint32_t arg, uint32_t resp[4])
{
	/* Clear the SD_STAT register for proper update of status bits after CMD invocation */
	MMCHS0_REG(SD_STAT) = 0xFFFFFFFF;

	MMCHS0_REG(SD_ARG) = arg;
	MMCHS0_REG(SD_CMD) = cmd;

	/* CMDx complete? */
	while (!(MMCHS0_REG(SD_STAT) & (SD_STAT_CC | SD_STAT_ERRI)));

	resp[0] = MMCHS0_REG(SD_RSP10);
	resp[1] = MMCHS0_REG(SD_RSP32);
	resp[2] = MMCHS0_REG(SD_RSP54);
	resp[3] = MMCHS0_REG(SD_RSP76);

	/* CMDx error? */
	if (MMCHS0_REG(SD_STAT) & SD_STAT_ERRI)
		return(-1);
	else
		return(0);
}

int
sdCardCmd(int interface, int cmd, unsigned long arg, unsigned char *resp)
{
	return(-1);
}

int
sdInit(int interface, int verbosity)
{
	uint32_t cmd, arg, resp[4];

	/* Enable MMC0 clocks */
	CM_PER_REG(CM_PER_MMC0_CLKCTRL) |= CM_PER_MMC0_CLKCTRL_MODULEMODE_ENABLE;
	while (CM_PER_REG(CM_PER_MMC0_CLKCTRL) & CM_PER_MMC0_CLKCTRL_IDLEST);

	/* Reset the MMC/SD controller */
	MMCHS0_REG(SD_SYSCONFIG) = SD_SYSCONFIG_SOFTRESET;
	while (!(MMCHS0_REG(SD_SYSSTATUS) & SD_SYSSTATUS_RESETDONE));

	/* Reset the command and data lines */
	MMCHS0_REG(SD_SYSCTL) |= SD_SYSCTL_SRA;
	while (MMCHS0_REG(SD_SYSCTL) & SD_SYSCTL_SRA);

	/* Configure the MMC/SD controller capabilities to enable 3.0 V operating voltage */
	MMCHS0_REG(SD_CAPA) = SD_CAPA_VS30;

	/* Configure SD_IE register to update certain status bits in SD_STAT */
	MMCHS0_REG(SD_IE) = SD_IE_BADA_ENABLE | SD_IE_CERR_ENABLE | SD_IE_ACE_ENABLE |
		SD_IE_DEB_ENABLE | SD_IE_DCRC_ENABLE | SD_IE_DTO_ENABLE | SD_IE_CIE_ENABLE |
		SD_IE_CEB_ENABLE | SD_IE_CCRC_ENABLE | SD_IE_CIRQ_ENABLE | SD_IE_CREM_ENABLE |
		SD_IE_CINS_ENABLE | SD_IE_BRR_ENABLE | SD_IE_BWR_ENABLE |
		SD_IE_TC_ENABLE | SD_IE_CC_ENABLE;

	/* Disable open-drain mode (only used for MMC cards) and 8-bit data width  */
	MMCHS0_REG(SD_CON) &= ~(SD_CON_OD | SD_CON_DW8);

	/* Configure the operating voltage to 3.0 V */
	MMCHS0_REG(SD_HCTL) &= ~(SD_HCTL_SDVS);
	MMCHS0_REG(SD_HCTL) |= SD_HCTL_SDVS_VS30;

	/* Set the data width to 4-bits */
	MMCHS0_REG(SD_HCTL) |= SD_HCTL_DTW;

	/* Turn on the bus */
	MMCHS0_REG(SD_HCTL) |= SD_HCTL_SDBP;
	while (!(MMCHS0_REG(SD_HCTL) & SD_HCTL_SDBP));

	/* Enable the internal clock */
	MMCHS0_REG(SD_SYSCTL) |= SD_SYSCTL_ICE;

	/* Configure Clock Frequency Select to 100 KHz */
	MMCHS0_REG(SD_SYSCTL) = (MMCHS0_REG(SD_SYSCTL) & ~(SD_SYSCTL_CLKD)) | (960 << 6);

	/* Wait for clock to stabilize */
	while (!(MMCHS0_REG(SD_SYSCTL) & SD_SYSCTL_ICS));

	/* Configure SD_SYSCONFIG */
	MMCHS0_REG(SD_SYSCONFIG) &= ~(SD_SYSCONFIG_CLOCKACTIVITY | SD_SYSCONFIG_SIDLEMODE);
	MMCHS0_REG(SD_SYSCONFIG) |= SD_SYSCONFIG_SIDLEMODE_WKUP | SD_SYSCONFIG_ENAWAKEUP_ENABLE |
		SD_SYSCONFIG_AUTOIDLE_AUTOGATE;

	/* Enable the clock to the SD card */
	MMCHS0_REG(SD_SYSCTL) |= SD_SYSCTL_CEN_ENABLE;

	/* Perform the Initialization Stream as specified in the AM335x TRM, Section 18.3.3.2
	   "Card Detection, Identicication, and Selection" */
	MMCHS0_REG(SD_CON) |= SD_CON_INIT;
	/* Clear the SD_STAT register */
	MMCHS0_REG(SD_STAT) = 0xFFFFFFFF;
	MMCHS0_REG(SD_ARG) = 0x00000000;
	MMCHS0_REG(SD_CMD) = 0x00000000;
	while (!(MMCHS0_REG(SD_STAT) & SD_STAT_CC));
	/* Clear CC flag in SD_STAT */
	MMCHS0_REG(SD_STAT) |= SD_STAT_CC;
	MMCHS0_REG(SD_CON) &= ~SD_CON_INIT;

	/* Change the clock frequency to 6 MHz and set the DTO to the maximum value setting */
	MMCHS0_REG(SD_SYSCTL) &= ~SD_SYSCTL_DTO;
	MMCHS0_REG(SD_SYSCTL) |= SD_SYSCTL_DTO_TCF_2_27;
	MMCHS0_REG(SD_SYSCTL) = (MMCHS0_REG(SD_SYSCTL) & ~SD_SYSCTL_CLKD) | (16 << 6);

	/* Wait for clock to stabilize */
	while ((MMCHS0_REG(SD_SYSCTL) & SD_SYSCTL_ICS) != SD_SYSCTL_ICS);

	/* Send CMD0/GO_IDLE_STATE to reset the SD card connected to MMC0 interface */
	arg = 0x00000000;
	cmd = SD_CMD_CMD0_GO_IDLE_STATE | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
		SD_CMD_CICE_DISABLE | SD_CMD_CCCE_DISABLE | SD_CMD_RSP_TYPE_NO_RESPONSE;
	if (sdcmd(cmd, arg, resp) == -1)
		return(-1);

	/* Send CMD8/SEND_IF_COND to verify that the SD card satisfies MMC/SD controller
	   requirements */
	arg = 0x00000188;
	cmd = SD_CMD_CMD8_SEND_IF_COND | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
		SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R7;
	if (sdcmd(cmd, arg, resp) == -1)
		return(-1);

	/* Determine what type of SD card is connected, i.e. standard capacity, high capacity, etc. 
	 * We perform a CMD55/ACMD41 loop until the "Card power up status bit" is set in the OCR
	 * register from the SD card to determine when we have a valid response */
	do {
		arg = 0x00000000;
		cmd = SD_CMD_CMD55_APP_CMD | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
			SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
		if (sdcmd(cmd, arg, resp) == -1)
			return(-1);

		arg = 0x40060000;
		cmd = SD_CMD_ACMD41_SD_SEND_OP_COND | SD_CMD_CMD_TYPE_NORMAL |
			SD_CMD_DP_NO_DATA_PRESENT | SD_CMD_CICE_DISABLE | SD_CMD_CCCE_DISABLE |
			SD_CMD_RSP_TYPE_R3;
		if (sdcmd(cmd, arg, resp) == -1)
			return(-1);
	} while (!(resp[0] & SD_RSP10_R3_CARD_POWER_UP_STATUS));

	/* Check SD_RSP10 to determine whether the card connected is high capacity or not */
	if (resp[0] & SD_RSP10_R3_CARD_CAPACITY_STATUS)
		sdInfoTbl[interface].highcapacity = 1;
	else
		sdInfoTbl[interface].highcapacity = 0;

	/* Send CMD2 to get SD's CID and to put the card into Identification State */
	arg = 0x00000000;
	cmd = SD_CMD_CMD2_ALL_SEND_CID | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
		SD_CMD_CICE_DISABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R2;
	if (sdcmd(cmd, arg, resp) == -1)
		return(-1);

	/* Send CMD3, i.e. request new relative address (RCA) and to put the card into
	   Stand-by State */
	arg = 0x00000000;
	cmd = SD_CMD_CMD3_SEND_RELATIVE_ADDR | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
		SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R6;
	if (sdcmd(cmd, arg, resp) == -1)
		return(-1);

	/* Save the RCA published from the SD card, this will be used in future CMDx commands */
	sdrca = (MMCHS0_REG(SD_RSP10) >> 16) & 0xFFFF;

	/* Wait for the SD card to enter Stand-by State */
	do {
		arg = (sdrca << 16) & 0xFFFF0000;
		cmd = SD_CMD_CMD13_SEND_STATUS | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
			SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
		if (sdcmd(cmd, arg, resp) == -1)
			return(-1);
	} while ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_STANDBY);

	/* Put the card with the RCA obtained previously into Transfer State via CMD7 */
	arg = (sdrca << 16) & 0xFFFF0000;
	cmd = SD_CMD_CMD7_SELECT_DESELECT_CARD | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
		SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1B;
	if (sdcmd(cmd, arg, resp) == -1)
		return(-1);

	/* Wait for the SD card to enter Transfer State */
	do {
		arg = (sdrca << 16) & 0xFFFF0000;
		cmd = SD_CMD_CMD13_SEND_STATUS | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
			SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
		if (sdcmd(cmd, arg, resp) == -1)
			return(-1);
	} while ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_TRANSFER);

	/* Set the bus-width to 4-bits */

	/* Send CMD55 to get ready to configure the bus-width via ACMD6 */
	arg = (sdrca << 16) & 0xFFFF0000;
	cmd = SD_CMD_CMD55_APP_CMD | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
		SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
	if (sdcmd(cmd, arg, resp) == -1)
		return(-1);

	/* Send ACMD6, SET_BUS_WIDTH to set the bus-width to 4-bits */
	arg = 0x00000002;
	cmd = SD_CMD_ACMD6_SET_BUS_WIDTH | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
		SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
	if (sdcmd(cmd, arg, resp) == -1)
		return(-1);

	/* Put the SD card into Stand-by State */
	arg = 0x00000000;
	cmd = SD_CMD_CMD7_SELECT_DESELECT_CARD | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
		SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_NO_RESPONSE;
	if (sdcmd(cmd, arg, resp) == -1)
		return(-1);

	/* Wait for the SD card to enter Stand-by State */
	do {
		arg = (sdrca << 16) & 0xFFFF0000;
		cmd = SD_CMD_CMD13_SEND_STATUS | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
			SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
		if (sdcmd(cmd, arg, resp) == -1)
			return(-1);
	} while ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_STANDBY);

	/* This point is reached when SD controller initialization and SD card
	   communication is successful */
	return(0);
}

int
sdRead(int interface, char *buf, int blknum, int blkcount)
{
	uint32_t cmd, arg, resp[4];
	uint32_t *wordptr = (uint32_t *) buf;
	int byteindex;

	/* Get the SD card's status via CMD13 */
	arg = (sdrca << 16) & 0xFFFF0000;
	cmd = SD_CMD_CMD13_SEND_STATUS | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
		SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
	if (sdcmd(cmd, arg, resp) == -1)
		return(-1);

	/* Ensure that the card is in Transfer State before proceeding */
	if ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_TRANSFER) {
		arg = (sdrca << 16) & 0xFFFF0000;
		cmd = SD_CMD_CMD7_SELECT_DESELECT_CARD | SD_CMD_CMD_TYPE_NORMAL |
			SD_CMD_DP_NO_DATA_PRESENT | SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE |
			SD_CMD_RSP_TYPE_R1B;
		if (sdcmd(cmd, arg, resp) == -1)
			return(-1);

		/* Wait for the SD card to enter Transfer State */
		do {
			arg = (sdrca << 16) & 0xFFFF0000;
			cmd = SD_CMD_CMD13_SEND_STATUS | SD_CMD_CMD_TYPE_NORMAL |
				SD_CMD_DP_NO_DATA_PRESENT | SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE |
				SD_CMD_RSP_TYPE_R1;
			if (sdcmd(cmd, arg, resp) == -1)
				return(-1);
		} while ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_TRANSFER);
	}

	/* Set the block length and the number of blocks to read */
	MMCHS0_REG(SD_BLK) = SD_BLKSIZE | (blkcount << 16);
	/* Send CMD18, i.e. read multiple blocks */
	arg = blknum;
	cmd = SD_CMD_CMD18_READ_MULTIPLE_BLOCK | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_DATA_PRESENT |
		SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1 | SD_CMD_MSBS_MULTIPLE |
		SD_CMD_DDIR_READ | SD_CMD_ACEN_CMD12_ENABLE | SD_CMD_BCE_ENABLE;
	if (sdcmd(cmd, arg, resp) == -1)
		return(-1);

	/* Check the data buffer to see if there is data to be read */
	do {
		while (!(MMCHS0_REG(SD_STAT) & SD_STAT_BRR));

		/* Clear the BRR status bit in SD_STAT */
		MMCHS0_REG(SD_STAT) |= SD_STAT_BRR;

		for (byteindex = 0; byteindex < (SD_BLKSIZE / 4); byteindex++) {
			*wordptr = (MMCHS0_REG(SD_DATA));
			wordptr++;
		}
	} while (!(MMCHS0_REG(SD_STAT) & SD_STAT_TC));

	/* Put the SD card into Stand-by State */
	arg = 0;
	cmd = SD_CMD_CMD7_SELECT_DESELECT_CARD | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
		SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_NO_RESPONSE;
	if (sdcmd(cmd, arg, resp) == -1)
		return(-1);

	/* Wait for the SD card to enter Stand-by State */
	do {
		arg = (sdrca << 16) & 0xFFFF0000;
		cmd = SD_CMD_CMD13_SEND_STATUS | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
			SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
		if (sdcmd(cmd, arg, resp) == -1)
			return(-1);
	} while ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_STANDBY);

	return(0);
}

int
sdWrite(int interface, char *buf, int blknum, int blkcount)
{
	uint32_t cmd, arg, resp[4];
	uint32_t *wordptr = (uint32_t *) buf;
	int byteindex;

	/* Get the SD card's status by sending CMD13 */
	arg = (sdrca << 16) & 0xFFFF0000;
	cmd = SD_CMD_CMD13_SEND_STATUS | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
		SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
	if (sdcmd(cmd, arg, resp) == -1)
		return(-1);

	/* Ensure that the card is in the Transfer State before proceeding */
	if ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_TRANSFER) {
		arg = (sdrca << 16) & 0xFFFF0000;
		cmd  = SD_CMD_CMD7_SELECT_DESELECT_CARD | SD_CMD_CMD_TYPE_NORMAL |
			SD_CMD_DP_NO_DATA_PRESENT | SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE |
			SD_CMD_RSP_TYPE_R1B;
		if (sdcmd(cmd, arg, resp) == -1)
			return(-1);

		/* Wait for SD card to enter Transfer State */
		do {
			arg = (sdrca << 16) & 0xFFFF0000;
			cmd = SD_CMD_CMD13_SEND_STATUS | SD_CMD_CMD_TYPE_NORMAL |
				SD_CMD_DP_NO_DATA_PRESENT | SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE |
				SD_CMD_RSP_TYPE_R1;
			if (sdcmd(cmd, arg, resp) == -1)
				return(-1);
		} while ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_TRANSFER);
	}

	/* Set the block length in bytes and the number of blocks to write to the SD card */
	MMCHS0_REG(SD_BLK) = SD_BLKSIZE | ( blkcount << 16);
	/* Send CMD25, that is write the number of blocks specified in 'blkcount' from 'buf' to the
	 * location that is 512 byte aligned in the SD card specified by the block number 'blknum'
	 */
	arg = blknum;
	cmd = SD_CMD_CMD25_WRITE_MULTIPLE_BLOCK | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_DATA_PRESENT |
		SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1 | SD_CMD_MSBS_MULTIPLE |
		SD_CMD_DDIR_WRITE | SD_CMD_ACEN_CMD12_ENABLE | SD_CMD_BCE_ENABLE;
	if (sdcmd(cmd, arg, resp) == -1)
		return(-1);

	/* Write the data */
	do {
		/* Wait until data is ready to be written */
		while (!(MMCHS0_REG(SD_STAT) & (SD_STAT_BWR | SD_STAT_TC)));

		if (MMCHS0_REG(SD_STAT) & SD_STAT_TC)
			break;

		/* Clear the BWR status bit in SD_STAT */
		MMCHS0_REG(SD_STAT) |= SD_STAT_BWR;

		for (byteindex = 0; byteindex < (SD_BLKSIZE / 4); byteindex++)
			MMCHS0_REG(SD_DATA) = *wordptr++;
	} while (!(MMCHS0_REG(SD_STAT) & SD_STAT_TC));

	/* Put the SD card into Stand-by State */
	arg = 0x00000000;
	cmd = SD_CMD_CMD7_SELECT_DESELECT_CARD | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
		SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_NO_RESPONSE;
	if (sdcmd(cmd, arg, resp) == -1)
		return(-1);

	/* Wait for SD card to enter Stand-by State */
	do {
		arg= (sdrca << 16) & 0xFFFF0000;
		cmd  = SD_CMD_CMD13_SEND_STATUS | SD_CMD_CMD_TYPE_NORMAL | SD_CMD_DP_NO_DATA_PRESENT |
			SD_CMD_CICE_ENABLE | SD_CMD_CCCE_ENABLE | SD_CMD_RSP_TYPE_R1;
		if (sdcmd(cmd, arg, resp) == -1)
			return(-1);
	} while ((resp[0] & SD_RSP10_R1_CURRENT_STATE) != SD_RSP10_R1_CURRENT_STATE_STANDBY);

	return(0);
}

int
sdInstalled(int interface)
{
	if ((MMCHS0_REG(SD_CON) & SD_CON_CDP) == SD_CON_CDP_ACTIVE_HIGH)
		if (MMCHS0_REG(SD_PSTATE) & SD_PSTATE_CINS)
			return(1);
		else
			return(0);
	else
		if (MMCHS0_REG(SD_PSTATE) & SD_PSTATE_CINS)
			return(0);
		else
			return(1);
}

int
sdPowerup(int tot)
{
	return(-1);
}

int
sdReadCxD(int interface, unsigned char *buf, int cmd)
{
	return(-1);
}