]>
Commit | Line | Data |
---|---|---|
160131bf PP |
1 | /* |
2 | This code was original written by Ulrich Radig and modified by | |
3 | Embedded Artists AB (www.embeddedartists.com). | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 2 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program; if not, write to the Free Software | |
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | */ | |
19 | ||
20 | #include <config.h> | |
21 | #include <common.h> | |
22 | #include <asm/arch/hardware.h> | |
23 | #include <asm/arch/spi.h> | |
24 | ||
25 | #define MMC_Enable() PUT32(IO1CLR, 1l << 22) | |
26 | #define MMC_Disable() PUT32(IO1SET, 1l << 22) | |
27 | #define mmc_spi_cfg() spi_set_clock(8); spi_set_cfg(0, 1, 0); | |
28 | ||
29 | static unsigned char Write_Command_MMC (unsigned char *CMD); | |
30 | static void MMC_Read_Block(unsigned char *CMD, unsigned char *Buffer, | |
31 | unsigned short int Bytes); | |
32 | ||
33 | /* initialize the hardware */ | |
34 | int mmc_hw_init(void) | |
35 | { | |
36 | unsigned long a; | |
37 | unsigned short int Timeout = 0; | |
38 | unsigned char b; | |
39 | unsigned char CMD[] = {0x40, 0x00, 0x00, 0x00, 0x00, 0x95}; | |
40 | ||
41 | /* set-up GPIO and SPI */ | |
42 | (*((volatile unsigned long *)PINSEL2)) &= ~(1l << 3); /* clear bit 3 */ | |
43 | (*((volatile unsigned long *)IO1DIR)) |= (1l << 22); /* set bit 22 (output) */ | |
44 | ||
45 | MMC_Disable(); | |
46 | ||
47 | spi_lock(); | |
48 | spi_set_clock(248); | |
49 | spi_set_cfg(0, 1, 0); | |
50 | MMC_Enable(); | |
51 | ||
52 | /* waste some time */ | |
53 | for(a=0; a < 20000; a++) | |
54 | asm("nop"); | |
55 | ||
56 | /* Put the MMC/SD-card into SPI-mode */ | |
57 | for (b = 0; b < 10; b++) /* Sends min 74+ clocks to the MMC/SD-card */ | |
58 | spi_write(0xff); | |
59 | ||
60 | /* Sends command CMD0 to MMC/SD-card */ | |
61 | while (Write_Command_MMC(CMD) != 1) { | |
62 | if (Timeout++ > 200) { | |
63 | MMC_Disable(); | |
64 | spi_unlock(); | |
65 | return(1); /* Abort with command 1 (return 1) */ | |
66 | } | |
67 | } | |
68 | /* Sends Command CMD1 an MMC/SD-card */ | |
69 | Timeout = 0; | |
70 | CMD[0] = 0x41;/* Command 1 */ | |
71 | CMD[5] = 0xFF; | |
72 | ||
73 | while (Write_Command_MMC(CMD) != 0) { | |
74 | if (Timeout++ > 200) { | |
75 | MMC_Disable(); | |
76 | spi_unlock(); | |
77 | return (2); /* Abort with command 2 (return 2) */ | |
78 | } | |
79 | } | |
80 | ||
81 | MMC_Disable(); | |
82 | spi_unlock(); | |
83 | ||
84 | return 0; | |
85 | } | |
86 | ||
87 | /* ############################################################################ | |
88 | Sends a command to the MMC/SD-card | |
89 | ######################################################################### */ | |
90 | static unsigned char Write_Command_MMC (unsigned char *CMD) | |
91 | { | |
92 | unsigned char a, tmp = 0xff; | |
93 | unsigned short int Timeout = 0; | |
94 | ||
95 | MMC_Disable(); | |
96 | spi_write(0xFF); | |
97 | MMC_Enable(); | |
98 | ||
99 | for (a = 0; a < 0x06; a++) | |
100 | spi_write(*CMD++); | |
101 | ||
102 | while (tmp == 0xff) { | |
103 | tmp = spi_read(); | |
104 | if (Timeout++ > 5000) | |
105 | break; | |
106 | } | |
107 | ||
108 | return (tmp); | |
109 | } | |
110 | ||
111 | /* ############################################################################ | |
112 | Routine to read the CID register from the MMC/SD-card (16 bytes) | |
113 | ######################################################################### */ | |
114 | void MMC_Read_Block(unsigned char *CMD, unsigned char *Buffer, unsigned short | |
115 | int Bytes) | |
116 | { | |
117 | unsigned short int a; | |
118 | ||
119 | spi_lock(); | |
120 | mmc_spi_cfg(); | |
121 | MMC_Enable(); | |
122 | ||
123 | if (Write_Command_MMC(CMD) != 0) { | |
124 | MMC_Disable(); | |
125 | spi_unlock(); | |
126 | return; | |
127 | } | |
128 | ||
129 | while (spi_read() != 0xfe) {}; | |
130 | for (a = 0; a < Bytes; a++) | |
131 | *Buffer++ = spi_read(); | |
132 | ||
133 | /* Read the CRC-byte */ | |
134 | spi_read(); /* CRC - byte is discarded */ | |
135 | spi_read(); /* CRC - byte is discarded */ | |
136 | /* set MMC_Chip_Select to high (MMC/SD-card Inaktiv) */ | |
137 | MMC_Disable(); | |
138 | spi_unlock(); | |
139 | ||
140 | return; | |
141 | } | |
142 | ||
143 | /* ############################################################################ | |
144 | Routine to read a block (512 bytes) from the MMC/SD-card | |
145 | ######################################################################### */ | |
146 | unsigned char mmc_read_sector (unsigned long addr,unsigned char *Buffer) | |
147 | { | |
148 | /* Command 16 to read aBlocks from the MMC/SD - caed */ | |
149 | unsigned char CMD[] = {0x51,0x00,0x00,0x00,0x00,0xFF}; | |
150 | ||
151 | /* The addres on the MMC/SD-card is in bytes, | |
152 | addr is transformed from blocks to bytes and the result is | |
153 | placed into the command */ | |
154 | ||
155 | addr = addr << 9; /* addr = addr * 512 */ | |
156 | ||
157 | CMD[1] = ((addr & 0xFF000000) >> 24); | |
158 | CMD[2] = ((addr & 0x00FF0000) >> 16); | |
159 | CMD[3] = ((addr & 0x0000FF00) >> 8 ); | |
160 | ||
161 | MMC_Read_Block(CMD, Buffer, 512); | |
162 | ||
163 | return (0); | |
164 | } | |
165 | ||
166 | /* ############################################################################ | |
167 | Routine to write a block (512 byte) to the MMC/SD-card | |
168 | ######################################################################### */ | |
169 | unsigned char mmc_write_sector (unsigned long addr,unsigned char *Buffer) | |
170 | { | |
171 | unsigned char tmp, a; | |
172 | unsigned short int b; | |
173 | /* Command 24 to write a block to the MMC/SD - card */ | |
174 | unsigned char CMD[] = {0x58, 0x00, 0x00, 0x00, 0x00, 0xFF}; | |
175 | ||
176 | /* The addres on the MMC/SD-card is in bytes, | |
177 | addr is transformed from blocks to bytes and the result is | |
178 | placed into the command */ | |
179 | ||
180 | addr = addr << 9; /* addr = addr * 512 */ | |
181 | ||
182 | CMD[1] = ((addr & 0xFF000000) >> 24); | |
183 | CMD[2] = ((addr & 0x00FF0000) >> 16); | |
184 | CMD[3] = ((addr & 0x0000FF00) >> 8 ); | |
185 | ||
186 | spi_lock(); | |
187 | mmc_spi_cfg(); | |
188 | MMC_Enable(); | |
189 | ||
190 | /* Send command CMD24 to the MMC/SD-card (Write 1 Block/512 Bytes) */ | |
191 | tmp = Write_Command_MMC(CMD); | |
192 | if (tmp != 0) { | |
193 | MMC_Disable(); | |
194 | spi_unlock(); | |
195 | return(tmp); | |
196 | } | |
197 | ||
198 | /* Do a short delay and send a clock-pulse to the MMC/SD-card */ | |
199 | for (a = 0; a < 100; a++) | |
200 | spi_read(); | |
201 | ||
202 | /* Send a start byte to the MMC/SD-card */ | |
203 | spi_write(0xFE); | |
204 | ||
205 | /* Write the block (512 bytes) to the MMC/SD-card */ | |
206 | for (b = 0; b < 512; b++) | |
207 | spi_write(*Buffer++); | |
208 | ||
209 | /* write the CRC-Byte */ | |
210 | spi_write(0xFF); /* write a dummy CRC */ | |
211 | spi_write(0xFF); /* CRC code is not used */ | |
212 | ||
213 | /* Wait for MMC/SD-card busy */ | |
214 | while (spi_read() != 0xff) {}; | |
215 | ||
216 | /* set MMC_Chip_Select to high (MMC/SD-card inactive) */ | |
217 | MMC_Disable(); | |
218 | spi_unlock(); | |
219 | return (0); | |
220 | } | |
221 | ||
222 | /* ######################################################################### | |
223 | Routine to read the CSD register from the MMC/SD-card (16 bytes) | |
224 | ######################################################################### */ | |
225 | unsigned char mmc_read_csd (unsigned char *Buffer) | |
226 | { | |
227 | /* Command to read the CSD register */ | |
228 | unsigned char CMD[] = {0x49, 0x00, 0x00, 0x00, 0x00, 0xFF}; | |
229 | ||
230 | MMC_Read_Block(CMD, Buffer, 16); | |
231 | ||
232 | return (0); | |
233 | } |