summaryrefslogtreecommitdiff
path: root/arch/arm/cpu/arm720t/lpc2292/mmc_hw.c
blob: bd6a5b120604fb2f2c3bd9b2ed805614e1999877 (plain)
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
/*
    This code was original written by Ulrich Radig and modified by
    Embedded Artists AB (www.embeddedartists.com).

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <config.h>
#include <common.h>
#include <asm/arch/hardware.h>
#include <asm/arch/spi.h>

#define MMC_Enable() PUT32(IO1CLR, 1l << 22)
#define MMC_Disable() PUT32(IO1SET, 1l << 22)
#define mmc_spi_cfg() spi_set_clock(8); spi_set_cfg(0, 1, 0);

static unsigned char Write_Command_MMC (unsigned char *CMD);
static void MMC_Read_Block(unsigned char *CMD, unsigned char *Buffer,
		    unsigned short int Bytes);

/* initialize the hardware */
int mmc_hw_init(void)
{
	unsigned long a;
	unsigned short int Timeout = 0;
	unsigned char b;
	unsigned char CMD[] = {0x40, 0x00, 0x00, 0x00, 0x00, 0x95};

	/* set-up GPIO and SPI */
	(*((volatile unsigned long *)PINSEL2)) &= ~(1l << 3); /* clear bit 3 */
	(*((volatile unsigned long *)IO1DIR)) |= (1l << 22); /* set bit 22 (output) */

	MMC_Disable();

	spi_lock();
	spi_set_clock(248);
	spi_set_cfg(0, 1, 0);
	MMC_Enable();

	/* waste some time */
	for(a=0; a < 20000; a++)
		asm("nop");

	/* Put the MMC/SD-card into SPI-mode */
	for (b = 0; b < 10; b++) /* Sends min 74+ clocks to the MMC/SD-card */
		spi_write(0xff);

	/* Sends command CMD0 to MMC/SD-card */
	while (Write_Command_MMC(CMD) != 1) {
		if (Timeout++ > 200) {
			MMC_Disable();
			spi_unlock();
			return(1); /* Abort with command 1 (return 1) */
		}
	}
	/* Sends Command CMD1 an MMC/SD-card */
	Timeout = 0;
	CMD[0] = 0x41;/* Command 1 */
	CMD[5] = 0xFF;

	while (Write_Command_MMC(CMD) != 0) {
		if (Timeout++ > 200) {
			MMC_Disable();
			spi_unlock();
			return (2); /* Abort with command 2 (return 2) */
		}
	}

	MMC_Disable();
	spi_unlock();

	return 0;
}

/* ############################################################################
   Sends a command to the MMC/SD-card
   ######################################################################### */
static unsigned char Write_Command_MMC (unsigned char *CMD)
{
	unsigned char a, tmp = 0xff;
	unsigned short int Timeout = 0;

	MMC_Disable();
	spi_write(0xFF);
	MMC_Enable();

	for (a = 0; a < 0x06; a++)
		spi_write(*CMD++);

	while (tmp == 0xff) {
		tmp = spi_read();
		if (Timeout++ > 5000)
		  break;
	}

	return (tmp);
}

/* ############################################################################
   Routine to read the CID register from the MMC/SD-card (16 bytes)
   ######################################################################### */
void MMC_Read_Block(unsigned char *CMD, unsigned char *Buffer, unsigned short
	int Bytes)
{
	unsigned short int a;

	spi_lock();
	mmc_spi_cfg();
	MMC_Enable();

	if (Write_Command_MMC(CMD) != 0) {
		MMC_Disable();
		spi_unlock();
		return;
	}

	while (spi_read() != 0xfe) {};
	for (a = 0; a < Bytes; a++)
		*Buffer++ = spi_read();

	/* Read the CRC-byte */
	spi_read(); /* CRC - byte is discarded */
	spi_read(); /* CRC - byte is discarded */
	/* set MMC_Chip_Select to high (MMC/SD-card Inaktiv) */
	MMC_Disable();
	spi_unlock();

	return;
}

/* ############################################################################
   Routine to read a block (512 bytes) from the MMC/SD-card
   ######################################################################### */
unsigned char mmc_read_sector (unsigned long addr,unsigned char *Buffer)
{
	/* Command 16 to read aBlocks from the MMC/SD - caed */
	unsigned char CMD[] = {0x51,0x00,0x00,0x00,0x00,0xFF};

	/* The address on the MMC/SD-card is in bytes,
	addr is transformed from blocks to bytes and the result is
	placed into the command */

	addr = addr << 9; /* addr = addr * 512 */

	CMD[1] = ((addr & 0xFF000000) >> 24);
	CMD[2] = ((addr & 0x00FF0000) >> 16);
	CMD[3] = ((addr & 0x0000FF00) >> 8 );

	MMC_Read_Block(CMD, Buffer, 512);

	return (0);
}

/* ############################################################################
   Routine to write a block (512 byte) to the MMC/SD-card
   ######################################################################### */
unsigned char mmc_write_sector (unsigned long addr,unsigned char *Buffer)
{
	unsigned char tmp, a;
	unsigned short int b;
	/* Command 24 to write a block to the MMC/SD - card */
	unsigned char CMD[] = {0x58, 0x00, 0x00, 0x00, 0x00, 0xFF};

	/* The address on the MMC/SD-card is in bytes,
	addr is transformed from blocks to bytes and the result is
	placed into the command */

	addr = addr << 9; /* addr = addr * 512 */

	CMD[1] = ((addr & 0xFF000000) >> 24);
	CMD[2] = ((addr & 0x00FF0000) >> 16);
	CMD[3] = ((addr & 0x0000FF00) >> 8 );

	spi_lock();
	mmc_spi_cfg();
	MMC_Enable();

	/* Send command CMD24 to the MMC/SD-card (Write 1 Block/512 Bytes) */
	tmp = Write_Command_MMC(CMD);
	if (tmp != 0) {
		MMC_Disable();
		spi_unlock();
		return(tmp);
	}

	/* Do a short delay and send a clock-pulse to the MMC/SD-card */
	for (a = 0; a < 100; a++)
		spi_read();

	/* Send a start byte to the MMC/SD-card */
	spi_write(0xFE);

	/* Write the block (512 bytes) to the MMC/SD-card */
	for (b = 0; b < 512; b++)
		spi_write(*Buffer++);

	/* write the CRC-Byte */
	spi_write(0xFF); /* write a dummy CRC */
	spi_write(0xFF); /* CRC code is not used */

	/* Wait for MMC/SD-card busy */
	while (spi_read() != 0xff) {};

	/* set MMC_Chip_Select to high (MMC/SD-card inactive) */
	MMC_Disable();
	spi_unlock();
	return (0);
}

/* #########################################################################
   Routine to read the CSD register from the MMC/SD-card (16 bytes)
   ######################################################################### */
unsigned char mmc_read_csd (unsigned char *Buffer)
{
	/* Command to read the CSD register */
	unsigned char CMD[] = {0x49, 0x00, 0x00, 0x00, 0x00, 0xFF};

	MMC_Read_Block(CMD, Buffer, 16);

	return (0);
}