blob: 8f5277e10d9824dec8681d150c796f5ba7a3cf86 [file] [log] [blame]
wdenk7a428cc2003-06-15 22:40:42 +00001/*
2 * (C) Copyright 2003
3 * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24#include <config.h>
25#include <common.h>
26#include <mmc.h>
27#include <asm/errno.h>
28#include <asm/arch/hardware.h>
wdenk2c9b05d2003-09-10 22:30:53 +000029#include <part.h>
wdenk7a428cc2003-06-15 22:40:42 +000030
Andy Fleming724ecf02008-10-30 16:31:39 -050031#include "mmc.h"
32
wdenk7a428cc2003-06-15 22:40:42 +000033#ifdef CONFIG_MMC
34
stefano babic43300a12007-11-20 10:40:24 +010035extern int fat_register_device(block_dev_desc_t * dev_desc, int part_no);
wdenk2c9b05d2003-09-10 22:30:53 +000036
37static block_dev_desc_t mmc_dev;
38
stefano babic43300a12007-11-20 10:40:24 +010039block_dev_desc_t *mmc_get_dev(int dev)
wdenk2c9b05d2003-09-10 22:30:53 +000040{
stefano babic43300a12007-11-20 10:40:24 +010041 return ((block_dev_desc_t *) & mmc_dev);
wdenk2c9b05d2003-09-10 22:30:53 +000042}
wdenk7a428cc2003-06-15 22:40:42 +000043
wdenk57b2d802003-06-27 21:31:46 +000044/*
wdenk7a428cc2003-06-15 22:40:42 +000045 * FIXME needs to read cid and csd info to determine block size
46 * and other parameters
47 */
48static uchar mmc_buf[MMC_BLOCK_SIZE];
stefano babic43300a12007-11-20 10:40:24 +010049static uchar spec_ver;
wdenk7a428cc2003-06-15 22:40:42 +000050static int mmc_ready = 0;
stefano babic43300a12007-11-20 10:40:24 +010051static int wide = 0;
wdenk7a428cc2003-06-15 22:40:42 +000052
stefano babic43300a12007-11-20 10:40:24 +010053static uint32_t *
wdenk7a428cc2003-06-15 22:40:42 +000054/****************************************************/
55mmc_cmd(ushort cmd, ushort argh, ushort argl, ushort cmdat)
56/****************************************************/
57{
stefano babic43300a12007-11-20 10:40:24 +010058 static uint32_t resp[4], a, b, c;
wdenk7a428cc2003-06-15 22:40:42 +000059 ulong status;
stefano babic43300a12007-11-20 10:40:24 +010060 int i;
wdenk7a428cc2003-06-15 22:40:42 +000061
stefano babic43300a12007-11-20 10:40:24 +010062 debug("mmc_cmd %u 0x%04x 0x%04x 0x%04x\n", cmd, argh, argl,
63 cmdat | wide);
wdenk7a428cc2003-06-15 22:40:42 +000064 MMC_STRPCL = MMC_STRPCL_STOP_CLK;
65 MMC_I_MASK = ~MMC_I_MASK_CLK_IS_OFF;
stefano babic43300a12007-11-20 10:40:24 +010066 while (!(MMC_I_REG & MMC_I_REG_CLK_IS_OFF)) ;
67 MMC_CMD = cmd;
68 MMC_ARGH = argh;
69 MMC_ARGL = argl;
70 MMC_CMDAT = cmdat | wide;
wdenk7a428cc2003-06-15 22:40:42 +000071 MMC_I_MASK = ~MMC_I_MASK_END_CMD_RES;
72 MMC_STRPCL = MMC_STRPCL_START_CLK;
stefano babic43300a12007-11-20 10:40:24 +010073 while (!(MMC_I_REG & MMC_I_REG_END_CMD_RES)) ;
wdenk7a428cc2003-06-15 22:40:42 +000074
75 status = MMC_STAT;
stefano babic43300a12007-11-20 10:40:24 +010076 debug("MMC status 0x%08x\n", status);
wdenk2a831612005-04-06 00:04:16 +000077 if (status & MMC_STAT_TIME_OUT_RESPONSE) {
wdenk7a428cc2003-06-15 22:40:42 +000078 return 0;
79 }
80
stefano babic43300a12007-11-20 10:40:24 +010081 /* Linux says:
82 * Did I mention this is Sick. We always need to
83 * discard the upper 8 bits of the first 16-bit word.
84 */
85 a = (MMC_RES & 0xffff);
86 for (i = 0; i < 4; i++) {
87 b = (MMC_RES & 0xffff);
88 c = (MMC_RES & 0xffff);
89 resp[i] = (a << 24) | (b << 8) | (c >> 8);
90 a = c;
91 debug("MMC resp[%d] = %#08x\n", i, resp[i]);
wdenk7a428cc2003-06-15 22:40:42 +000092 }
wdenk7a428cc2003-06-15 22:40:42 +000093
wdenk7a428cc2003-06-15 22:40:42 +000094 return resp;
95}
96
97int
98/****************************************************/
stefano babic43300a12007-11-20 10:40:24 +010099mmc_block_read(uchar * dst, ulong src, ulong len)
wdenk7a428cc2003-06-15 22:40:42 +0000100/****************************************************/
101{
wdenk7a428cc2003-06-15 22:40:42 +0000102 ushort argh, argl;
103 ulong status;
104
wdenk2a831612005-04-06 00:04:16 +0000105 if (len == 0) {
wdenk7a428cc2003-06-15 22:40:42 +0000106 return 0;
107 }
108
stefano babic43300a12007-11-20 10:40:24 +0100109 debug("mmc_block_rd dst %lx src %lx len %d\n", (ulong) dst, src, len);
wdenk7a428cc2003-06-15 22:40:42 +0000110
111 argh = len >> 16;
112 argl = len & 0xffff;
113
114 /* set block len */
stefano babic43300a12007-11-20 10:40:24 +0100115 mmc_cmd(MMC_CMD_SET_BLOCKLEN, argh, argl, MMC_CMDAT_R1);
wdenk7a428cc2003-06-15 22:40:42 +0000116
117 /* send read command */
118 argh = src >> 16;
119 argl = src & 0xffff;
120 MMC_STRPCL = MMC_STRPCL_STOP_CLK;
121 MMC_RDTO = 0xffff;
122 MMC_NOB = 1;
123 MMC_BLKLEN = len;
Haavard Skinnemoen31e5ad02008-05-22 11:09:59 +0200124 mmc_cmd(MMC_CMD_READ_SINGLE_BLOCK, argh, argl,
stefano babic43300a12007-11-20 10:40:24 +0100125 MMC_CMDAT_R1 | MMC_CMDAT_READ | MMC_CMDAT_BLOCK |
126 MMC_CMDAT_DATA_EN);
wdenk57b2d802003-06-27 21:31:46 +0000127
wdenk7a428cc2003-06-15 22:40:42 +0000128 MMC_I_MASK = ~MMC_I_MASK_RXFIFO_RD_REQ;
wdenk2a831612005-04-06 00:04:16 +0000129 while (len) {
130 if (MMC_I_REG & MMC_I_REG_RXFIFO_RD_REQ) {
131#ifdef CONFIG_PXA27X
132 int i;
stefano babic43300a12007-11-20 10:40:24 +0100133 for (i = min(len, 32); i; i--) {
134 *dst++ = *((volatile uchar *)&MMC_RXFIFO);
wdenk2a831612005-04-06 00:04:16 +0000135 len--;
136 }
137#else
wdenk7a428cc2003-06-15 22:40:42 +0000138 *dst++ = MMC_RXFIFO;
139 len--;
wdenk2a831612005-04-06 00:04:16 +0000140#endif
wdenk7a428cc2003-06-15 22:40:42 +0000141 }
142 status = MMC_STAT;
wdenk2a831612005-04-06 00:04:16 +0000143 if (status & MMC_STAT_ERRORS) {
wdenk7a428cc2003-06-15 22:40:42 +0000144 printf("MMC_STAT error %lx\n", status);
145 return -1;
146 }
147 }
148 MMC_I_MASK = ~MMC_I_MASK_DATA_TRAN_DONE;
stefano babic43300a12007-11-20 10:40:24 +0100149 while (!(MMC_I_REG & MMC_I_REG_DATA_TRAN_DONE)) ;
wdenk7a428cc2003-06-15 22:40:42 +0000150 status = MMC_STAT;
wdenk2a831612005-04-06 00:04:16 +0000151 if (status & MMC_STAT_ERRORS) {
wdenk7a428cc2003-06-15 22:40:42 +0000152 printf("MMC_STAT error %lx\n", status);
153 return -1;
154 }
155 return 0;
156}
157
158int
159/****************************************************/
stefano babic43300a12007-11-20 10:40:24 +0100160mmc_block_write(ulong dst, uchar * src, int len)
wdenk7a428cc2003-06-15 22:40:42 +0000161/****************************************************/
162{
wdenk7a428cc2003-06-15 22:40:42 +0000163 ushort argh, argl;
164 ulong status;
165
wdenk2a831612005-04-06 00:04:16 +0000166 if (len == 0) {
wdenk7a428cc2003-06-15 22:40:42 +0000167 return 0;
168 }
169
stefano babic43300a12007-11-20 10:40:24 +0100170 debug("mmc_block_wr dst %lx src %lx len %d\n", dst, (ulong) src, len);
wdenk7a428cc2003-06-15 22:40:42 +0000171
172 argh = len >> 16;
173 argl = len & 0xffff;
174
175 /* set block len */
stefano babic43300a12007-11-20 10:40:24 +0100176 mmc_cmd(MMC_CMD_SET_BLOCKLEN, argh, argl, MMC_CMDAT_R1);
wdenk7a428cc2003-06-15 22:40:42 +0000177
178 /* send write command */
179 argh = dst >> 16;
180 argl = dst & 0xffff;
181 MMC_STRPCL = MMC_STRPCL_STOP_CLK;
182 MMC_NOB = 1;
183 MMC_BLKLEN = len;
stefano babic43300a12007-11-20 10:40:24 +0100184 mmc_cmd(MMC_CMD_WRITE_BLOCK, argh, argl,
185 MMC_CMDAT_R1 | MMC_CMDAT_WRITE | MMC_CMDAT_BLOCK |
186 MMC_CMDAT_DATA_EN);
wdenk57b2d802003-06-27 21:31:46 +0000187
wdenk7a428cc2003-06-15 22:40:42 +0000188 MMC_I_MASK = ~MMC_I_MASK_TXFIFO_WR_REQ;
wdenk2a831612005-04-06 00:04:16 +0000189 while (len) {
190 if (MMC_I_REG & MMC_I_REG_TXFIFO_WR_REQ) {
stefano babic43300a12007-11-20 10:40:24 +0100191 int i, bytes = min(32, len);
wdenk7a428cc2003-06-15 22:40:42 +0000192
stefano babic43300a12007-11-20 10:40:24 +0100193 for (i = 0; i < bytes; i++) {
wdenk7a428cc2003-06-15 22:40:42 +0000194 MMC_TXFIFO = *src++;
195 }
wdenk2a831612005-04-06 00:04:16 +0000196 if (bytes < 32) {
wdenk7a428cc2003-06-15 22:40:42 +0000197 MMC_PRTBUF = MMC_PRTBUF_BUF_PART_FULL;
198 }
199 len -= bytes;
200 }
201 status = MMC_STAT;
wdenk2a831612005-04-06 00:04:16 +0000202 if (status & MMC_STAT_ERRORS) {
wdenk7a428cc2003-06-15 22:40:42 +0000203 printf("MMC_STAT error %lx\n", status);
204 return -1;
205 }
206 }
207 MMC_I_MASK = ~MMC_I_MASK_DATA_TRAN_DONE;
stefano babic43300a12007-11-20 10:40:24 +0100208 while (!(MMC_I_REG & MMC_I_REG_DATA_TRAN_DONE)) ;
wdenk7a428cc2003-06-15 22:40:42 +0000209 MMC_I_MASK = ~MMC_I_MASK_PRG_DONE;
stefano babic43300a12007-11-20 10:40:24 +0100210 while (!(MMC_I_REG & MMC_I_REG_PRG_DONE)) ;
wdenk7a428cc2003-06-15 22:40:42 +0000211 status = MMC_STAT;
wdenk2a831612005-04-06 00:04:16 +0000212 if (status & MMC_STAT_ERRORS) {
wdenk7a428cc2003-06-15 22:40:42 +0000213 printf("MMC_STAT error %lx\n", status);
214 return -1;
215 }
216 return 0;
217}
218
wdenk7a428cc2003-06-15 22:40:42 +0000219int
220/****************************************************/
stefano babic43300a12007-11-20 10:40:24 +0100221mmc_read(ulong src, uchar * dst, int size)
wdenk7a428cc2003-06-15 22:40:42 +0000222/****************************************************/
223{
224 ulong end, part_start, part_end, part_len, aligned_start, aligned_end;
225 ulong mmc_block_size, mmc_block_address;
226
wdenk2a831612005-04-06 00:04:16 +0000227 if (size == 0) {
wdenk7a428cc2003-06-15 22:40:42 +0000228 return 0;
229 }
230
wdenk2a831612005-04-06 00:04:16 +0000231 if (!mmc_ready) {
wdenk7a428cc2003-06-15 22:40:42 +0000232 printf("Please initial the MMC first\n");
233 return -1;
234 }
235
236 mmc_block_size = MMC_BLOCK_SIZE;
237 mmc_block_address = ~(mmc_block_size - 1);
238
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200239 src -= CONFIG_SYS_MMC_BASE;
wdenk7a428cc2003-06-15 22:40:42 +0000240 end = src + size;
241 part_start = ~mmc_block_address & src;
242 part_end = ~mmc_block_address & end;
243 aligned_start = mmc_block_address & src;
244 aligned_end = mmc_block_address & end;
245
246 /* all block aligned accesses */
stefano babic43300a12007-11-20 10:40:24 +0100247 debug
248 ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
249 src, (ulong) dst, end, part_start, part_end, aligned_start,
250 aligned_end);
wdenk2a831612005-04-06 00:04:16 +0000251 if (part_start) {
wdenk7a428cc2003-06-15 22:40:42 +0000252 part_len = mmc_block_size - part_start;
stefano babic43300a12007-11-20 10:40:24 +0100253 debug
254 ("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
255 src, (ulong) dst, end, part_start, part_end, aligned_start,
256 aligned_end);
257 if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) <
258 0) {
wdenk7a428cc2003-06-15 22:40:42 +0000259 return -1;
260 }
stefano babic43300a12007-11-20 10:40:24 +0100261 memcpy(dst, mmc_buf + part_start, part_len);
wdenk7a428cc2003-06-15 22:40:42 +0000262 dst += part_len;
263 src += part_len;
264 }
stefano babic43300a12007-11-20 10:40:24 +0100265 debug
266 ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
267 src, (ulong) dst, end, part_start, part_end, aligned_start,
268 aligned_end);
wdenk2a831612005-04-06 00:04:16 +0000269 for (; src < aligned_end; src += mmc_block_size, dst += mmc_block_size) {
stefano babic43300a12007-11-20 10:40:24 +0100270 debug
271 ("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
272 src, (ulong) dst, end, part_start, part_end, aligned_start,
273 aligned_end);
274 if ((mmc_block_read((uchar *) (dst), src, mmc_block_size)) < 0) {
wdenk7a428cc2003-06-15 22:40:42 +0000275 return -1;
276 }
277 }
stefano babic43300a12007-11-20 10:40:24 +0100278 debug
279 ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
280 src, (ulong) dst, end, part_start, part_end, aligned_start,
281 aligned_end);
wdenk2a831612005-04-06 00:04:16 +0000282 if (part_end && src < end) {
stefano babic43300a12007-11-20 10:40:24 +0100283 debug
284 ("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
285 src, (ulong) dst, end, part_start, part_end, aligned_start,
286 aligned_end);
wdenk2a831612005-04-06 00:04:16 +0000287 if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0) {
wdenk7a428cc2003-06-15 22:40:42 +0000288 return -1;
289 }
290 memcpy(dst, mmc_buf, part_end);
291 }
292 return 0;
293}
294
295int
296/****************************************************/
stefano babic43300a12007-11-20 10:40:24 +0100297mmc_write(uchar * src, ulong dst, int size)
wdenk7a428cc2003-06-15 22:40:42 +0000298/****************************************************/
299{
300 ulong end, part_start, part_end, part_len, aligned_start, aligned_end;
301 ulong mmc_block_size, mmc_block_address;
302
wdenk2a831612005-04-06 00:04:16 +0000303 if (size == 0) {
wdenk7a428cc2003-06-15 22:40:42 +0000304 return 0;
305 }
306
wdenk2a831612005-04-06 00:04:16 +0000307 if (!mmc_ready) {
wdenk7a428cc2003-06-15 22:40:42 +0000308 printf("Please initial the MMC first\n");
309 return -1;
310 }
311
312 mmc_block_size = MMC_BLOCK_SIZE;
313 mmc_block_address = ~(mmc_block_size - 1);
314
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200315 dst -= CONFIG_SYS_MMC_BASE;
wdenk7a428cc2003-06-15 22:40:42 +0000316 end = dst + size;
317 part_start = ~mmc_block_address & dst;
318 part_end = ~mmc_block_address & end;
319 aligned_start = mmc_block_address & dst;
320 aligned_end = mmc_block_address & end;
321
322 /* all block aligned accesses */
stefano babic43300a12007-11-20 10:40:24 +0100323 debug
324 ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
325 src, (ulong) dst, end, part_start, part_end, aligned_start,
326 aligned_end);
wdenk2a831612005-04-06 00:04:16 +0000327 if (part_start) {
wdenk7a428cc2003-06-15 22:40:42 +0000328 part_len = mmc_block_size - part_start;
stefano babic43300a12007-11-20 10:40:24 +0100329 debug
330 ("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
331 (ulong) src, dst, end, part_start, part_end, aligned_start,
332 aligned_end);
333 if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) <
334 0) {
wdenk7a428cc2003-06-15 22:40:42 +0000335 return -1;
336 }
stefano babic43300a12007-11-20 10:40:24 +0100337 memcpy(mmc_buf + part_start, src, part_len);
338 if ((mmc_block_write(aligned_start, mmc_buf, mmc_block_size)) <
339 0) {
wdenk7a428cc2003-06-15 22:40:42 +0000340 return -1;
341 }
342 dst += part_len;
343 src += part_len;
344 }
stefano babic43300a12007-11-20 10:40:24 +0100345 debug
346 ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
347 src, (ulong) dst, end, part_start, part_end, aligned_start,
348 aligned_end);
wdenk2a831612005-04-06 00:04:16 +0000349 for (; dst < aligned_end; src += mmc_block_size, dst += mmc_block_size) {
stefano babic43300a12007-11-20 10:40:24 +0100350 debug
351 ("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
352 src, (ulong) dst, end, part_start, part_end, aligned_start,
353 aligned_end);
354 if ((mmc_block_write(dst, (uchar *) src, mmc_block_size)) < 0) {
wdenk7a428cc2003-06-15 22:40:42 +0000355 return -1;
356 }
357 }
stefano babic43300a12007-11-20 10:40:24 +0100358 debug
359 ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
360 src, (ulong) dst, end, part_start, part_end, aligned_start,
361 aligned_end);
wdenk2a831612005-04-06 00:04:16 +0000362 if (part_end && dst < end) {
stefano babic43300a12007-11-20 10:40:24 +0100363 debug
364 ("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
365 src, (ulong) dst, end, part_start, part_end, aligned_start,
366 aligned_end);
wdenk2a831612005-04-06 00:04:16 +0000367 if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0) {
wdenk7a428cc2003-06-15 22:40:42 +0000368 return -1;
369 }
370 memcpy(mmc_buf, src, part_end);
wdenk2a831612005-04-06 00:04:16 +0000371 if ((mmc_block_write(aligned_end, mmc_buf, mmc_block_size)) < 0) {
wdenk7a428cc2003-06-15 22:40:42 +0000372 return -1;
373 }
374 }
375 return 0;
376}
377
wdenk2c9b05d2003-09-10 22:30:53 +0000378ulong
wdenk7a428cc2003-06-15 22:40:42 +0000379/****************************************************/
Jean-Christophe PLAGNIOL-VILLARDdf5d1ab2008-02-17 14:15:32 +0100380mmc_bread(int dev_num, ulong blknr, lbaint_t blkcnt, void *dst)
wdenk7a428cc2003-06-15 22:40:42 +0000381/****************************************************/
382{
383 int mmc_block_size = MMC_BLOCK_SIZE;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200384 ulong src = blknr * mmc_block_size + CONFIG_SYS_MMC_BASE;
wdenk7a428cc2003-06-15 22:40:42 +0000385
stefano babic43300a12007-11-20 10:40:24 +0100386 mmc_read(src, (uchar *) dst, blkcnt * mmc_block_size);
wdenk7a428cc2003-06-15 22:40:42 +0000387 return blkcnt;
388}
389
stefano babic43300a12007-11-20 10:40:24 +0100390#ifdef __GNUC__
391#define likely(x) __builtin_expect(!!(x), 1)
392#define unlikely(x) __builtin_expect(!!(x), 0)
393#else
394#define likely(x) (x)
395#define unlikely(x) (x)
396#endif
397
398#define UNSTUFF_BITS(resp,start,size) \
399 ({ \
400 const int __size = size; \
401 const uint32_t __mask = (__size < 32 ? 1 << __size : 0) - 1; \
402 const int32_t __off = 3 - ((start) / 32); \
403 const int32_t __shft = (start) & 31; \
404 uint32_t __res; \
405 \
406 __res = resp[__off] >> __shft; \
407 if (__size + __shft > 32) \
408 __res |= resp[__off-1] << ((32 - __shft) % 32); \
409 __res & __mask; \
410 })
411
412/*
413 * Given the decoded CSD structure, decode the raw CID to our CID structure.
414 */
415static void mmc_decode_cid(uint32_t * resp)
416{
417 if (IF_TYPE_SD == mmc_dev.if_type) {
418 /*
419 * SD doesn't currently have a version field so we will
420 * have to assume we can parse this.
421 */
422 sprintf((char *)mmc_dev.vendor,
423 "Man %02x OEM %c%c \"%c%c%c%c%c\" Date %02u/%04u",
424 UNSTUFF_BITS(resp, 120, 8), UNSTUFF_BITS(resp, 112, 8),
425 UNSTUFF_BITS(resp, 104, 8), UNSTUFF_BITS(resp, 96, 8),
426 UNSTUFF_BITS(resp, 88, 8), UNSTUFF_BITS(resp, 80, 8),
427 UNSTUFF_BITS(resp, 72, 8), UNSTUFF_BITS(resp, 64, 8),
428 UNSTUFF_BITS(resp, 8, 4), UNSTUFF_BITS(resp, 12,
429 8) + 2000);
430 sprintf((char *)mmc_dev.revision, "%d.%d",
431 UNSTUFF_BITS(resp, 60, 4), UNSTUFF_BITS(resp, 56, 4));
432 sprintf((char *)mmc_dev.product, "%u",
433 UNSTUFF_BITS(resp, 24, 32));
434 } else {
435 /*
436 * The selection of the format here is based upon published
437 * specs from sandisk and from what people have reported.
438 */
439 switch (spec_ver) {
440 case 0: /* MMC v1.0 - v1.2 */
441 case 1: /* MMC v1.4 */
442 sprintf((char *)mmc_dev.vendor,
443 "Man %02x%02x%02x \"%c%c%c%c%c%c%c\" Date %02u/%04u",
444 UNSTUFF_BITS(resp, 120, 8), UNSTUFF_BITS(resp,
445 112,
446 8),
447 UNSTUFF_BITS(resp, 104, 8), UNSTUFF_BITS(resp,
448 96, 8),
449 UNSTUFF_BITS(resp, 88, 8), UNSTUFF_BITS(resp,
450 80, 8),
451 UNSTUFF_BITS(resp, 72, 8), UNSTUFF_BITS(resp,
452 64, 8),
453 UNSTUFF_BITS(resp, 56, 8), UNSTUFF_BITS(resp,
454 48, 8),
455 UNSTUFF_BITS(resp, 12, 4), UNSTUFF_BITS(resp, 8,
456 4) +
457 1997);
458 sprintf((char *)mmc_dev.revision, "%d.%d",
459 UNSTUFF_BITS(resp, 44, 4), UNSTUFF_BITS(resp,
460 40, 4));
461 sprintf((char *)mmc_dev.product, "%u",
462 UNSTUFF_BITS(resp, 16, 24));
463 break;
464
465 case 2: /* MMC v2.0 - v2.2 */
466 case 3: /* MMC v3.1 - v3.3 */
467 case 4: /* MMC v4 */
468 sprintf((char *)mmc_dev.vendor,
469 "Man %02x OEM %04x \"%c%c%c%c%c%c\" Date %02u/%04u",
470 UNSTUFF_BITS(resp, 120, 8), UNSTUFF_BITS(resp,
471 104,
472 16),
473 UNSTUFF_BITS(resp, 96, 8), UNSTUFF_BITS(resp,
474 88, 8),
475 UNSTUFF_BITS(resp, 80, 8), UNSTUFF_BITS(resp,
476 72, 8),
477 UNSTUFF_BITS(resp, 64, 8), UNSTUFF_BITS(resp,
478 56, 8),
479 UNSTUFF_BITS(resp, 12, 4), UNSTUFF_BITS(resp, 8,
480 4) +
481 1997);
482 sprintf((char *)mmc_dev.product, "%u",
483 UNSTUFF_BITS(resp, 16, 32));
484 sprintf((char *)mmc_dev.revision, "N/A");
485 break;
486
487 default:
488 printf("MMC card has unknown MMCA version %d\n",
489 spec_ver);
490 break;
491 }
492 }
493 printf("%s card.\nVendor: %s\nProduct: %s\nRevision: %s\n",
494 (IF_TYPE_SD == mmc_dev.if_type) ? "SD" : "MMC", mmc_dev.vendor,
495 mmc_dev.product, mmc_dev.revision);
496}
497
498/*
499 * Given a 128-bit response, decode to our card CSD structure.
500 */
501static void mmc_decode_csd(uint32_t * resp)
502{
503 unsigned int mult, csd_struct;
504
505 if (IF_TYPE_SD == mmc_dev.if_type) {
506 csd_struct = UNSTUFF_BITS(resp, 126, 2);
507 if (csd_struct != 0) {
508 printf("SD: unrecognised CSD structure version %d\n",
509 csd_struct);
510 return;
511 }
512 } else {
513 /*
514 * We only understand CSD structure v1.1 and v1.2.
515 * v1.2 has extra information in bits 15, 11 and 10.
516 */
517 csd_struct = UNSTUFF_BITS(resp, 126, 2);
518 if (csd_struct != 1 && csd_struct != 2) {
519 printf("MMC: unrecognised CSD structure version %d\n",
520 csd_struct);
521 return;
522 }
523
524 spec_ver = UNSTUFF_BITS(resp, 122, 4);
525 mmc_dev.if_type = IF_TYPE_MMC;
526 }
527
528 mult = 1 << (UNSTUFF_BITS(resp, 47, 3) + 2);
529 mmc_dev.lba = (1 + UNSTUFF_BITS(resp, 62, 12)) * mult;
530 mmc_dev.blksz = 1 << UNSTUFF_BITS(resp, 80, 4);
531
532 /* FIXME: The following just makes assumes that's the partition type -- should really read it */
533 mmc_dev.part_type = PART_TYPE_DOS;
534 mmc_dev.dev = 0;
535 mmc_dev.lun = 0;
536 mmc_dev.type = DEV_TYPE_HARDDISK;
537 mmc_dev.removable = 0;
538 mmc_dev.block_read = mmc_bread;
539
Jean-Christophe PLAGNIOL-VILLARDc4fb57c2008-07-12 14:36:34 +0200540 printf("Detected: %lu blocks of %lu bytes (%luMB) ",
541 mmc_dev.lba,
542 mmc_dev.blksz,
543 mmc_dev.lba * mmc_dev.blksz / (1024 * 1024));
stefano babic43300a12007-11-20 10:40:24 +0100544}
545
wdenk7a428cc2003-06-15 22:40:42 +0000546int
547/****************************************************/
Andy Fleming9b81c6e2008-10-30 16:21:00 -0500548mmc_legacy_init(int verbose)
wdenk7a428cc2003-06-15 22:40:42 +0000549/****************************************************/
550{
stefano babic43300a12007-11-20 10:40:24 +0100551 int retries, rc = -ENODEV;
552 uint32_t cid_resp[4];
553 uint32_t *resp;
554 uint16_t rca = 0;
wdenk7a428cc2003-06-15 22:40:42 +0000555
stefano babic43300a12007-11-20 10:40:24 +0100556 /* Reset device interface type */
557 mmc_dev.if_type = IF_TYPE_UNKNOWN;
558
559#if defined (CONFIG_LUBBOCK) || (defined (CONFIG_GUMSTIX) && !defined(CONFIG_PXA27X))
560 set_GPIO_mode(GPIO6_MMCCLK_MD);
561 set_GPIO_mode(GPIO8_MMCCS0_MD);
wdenk7a428cc2003-06-15 22:40:42 +0000562#endif
stefano babic43300a12007-11-20 10:40:24 +0100563 CKEN |= CKEN12_MMC; /* enable MMC unit clock */
wdenk7a428cc2003-06-15 22:40:42 +0000564
stefano babic43300a12007-11-20 10:40:24 +0100565 MMC_CLKRT = MMC_CLKRT_0_3125MHZ;
566 MMC_RESTO = MMC_RES_TO_MAX;
567 MMC_SPI = MMC_SPI_DISABLE;
wdenk7a428cc2003-06-15 22:40:42 +0000568
569 /* reset */
Haavard Skinnemoen31e5ad02008-05-22 11:09:59 +0200570 mmc_cmd(MMC_CMD_GO_IDLE_STATE, 0, 0, MMC_CMDAT_INIT | MMC_CMDAT_R0);
stefano babic43300a12007-11-20 10:40:24 +0100571 udelay(200000);
572 retries = 3;
573 while (retries--) {
574 resp = mmc_cmd(MMC_CMD_APP_CMD, 0, 0, MMC_CMDAT_R1);
575 if (!(resp[0] & 0x00000020)) { /* Card does not support APP_CMD */
576 debug("Card does not support APP_CMD\n");
577 break;
578 }
579
Adrian Filipi32a953d2008-07-18 11:52:02 -0400580 /* Select 3.2-3.3V and 3.3-3.4V */
581 resp = mmc_cmd(SD_CMD_APP_SEND_OP_COND, 0x0030, 0x0000,
Haavard Skinnemoen31e5ad02008-05-22 11:09:59 +0200582 MMC_CMDAT_R3 | (retries < 2 ? 0
583 : MMC_CMDAT_INIT));
stefano babic43300a12007-11-20 10:40:24 +0100584 if (resp[0] & 0x80000000) {
585 mmc_dev.if_type = IF_TYPE_SD;
586 debug("Detected SD card\n");
587 break;
588 }
wdenk2a831612005-04-06 00:04:16 +0000589#ifdef CONFIG_PXA27X
590 udelay(10000);
591#else
stefano babic43300a12007-11-20 10:40:24 +0100592 udelay(200000);
593#endif
594 }
595
596 if (retries <= 0 || !(IF_TYPE_SD == mmc_dev.if_type)) {
597 debug("Failed to detect SD Card, trying MMC\n");
598 resp =
599 mmc_cmd(MMC_CMD_SEND_OP_COND, 0x00ff, 0x8000, MMC_CMDAT_R3);
600
601 retries = 10;
602 while (retries-- && resp && !(resp[0] & 0x80000000)) {
603#ifdef CONFIG_PXA27X
604 udelay(10000);
605#else
606 udelay(200000);
wdenk2a831612005-04-06 00:04:16 +0000607#endif
stefano babic43300a12007-11-20 10:40:24 +0100608 resp =
609 mmc_cmd(MMC_CMD_SEND_OP_COND, 0x00ff, 0x8000,
610 MMC_CMDAT_R3);
611 }
wdenk7a428cc2003-06-15 22:40:42 +0000612 }
613
614 /* try to get card id */
stefano babic43300a12007-11-20 10:40:24 +0100615 resp =
616 mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, 0, MMC_CMDAT_R2 | MMC_CMDAT_BUSY);
wdenk2a831612005-04-06 00:04:16 +0000617 if (resp) {
stefano babic43300a12007-11-20 10:40:24 +0100618 memcpy(cid_resp, resp, sizeof(cid_resp));
wdenk7a428cc2003-06-15 22:40:42 +0000619
620 /* MMC exists, get CSD too */
Haavard Skinnemoen31e5ad02008-05-22 11:09:59 +0200621 resp = mmc_cmd(MMC_CMD_SET_RELATIVE_ADDR, 0, 0, MMC_CMDAT_R1);
stefano babic43300a12007-11-20 10:40:24 +0100622 if (IF_TYPE_SD == mmc_dev.if_type)
623 rca = ((resp[0] & 0xffff0000) >> 16);
624 resp = mmc_cmd(MMC_CMD_SEND_CSD, rca, 0, MMC_CMDAT_R2);
wdenk2a831612005-04-06 00:04:16 +0000625 if (resp) {
stefano babic43300a12007-11-20 10:40:24 +0100626 mmc_decode_csd(resp);
wdenk7a428cc2003-06-15 22:40:42 +0000627 rc = 0;
628 mmc_ready = 1;
wdenk7a428cc2003-06-15 22:40:42 +0000629 }
stefano babic43300a12007-11-20 10:40:24 +0100630
631 mmc_decode_cid(cid_resp);
wdenk7a428cc2003-06-15 22:40:42 +0000632 }
633
stefano babic43300a12007-11-20 10:40:24 +0100634 MMC_CLKRT = 0; /* 20 MHz */
635 resp = mmc_cmd(MMC_CMD_SELECT_CARD, rca, 0, MMC_CMDAT_R1);
636
wdenk2a831612005-04-06 00:04:16 +0000637#ifdef CONFIG_PXA27X
stefano babic43300a12007-11-20 10:40:24 +0100638 if (IF_TYPE_SD == mmc_dev.if_type) {
639 resp = mmc_cmd(MMC_CMD_APP_CMD, rca, 0, MMC_CMDAT_R1);
640 resp = mmc_cmd(SD_CMD_APP_SET_BUS_WIDTH, 0, 2, MMC_CMDAT_R1);
641 wide = MMC_CMDAT_SD_4DAT;
642 }
wdenk2a831612005-04-06 00:04:16 +0000643#endif
wdenk7a428cc2003-06-15 22:40:42 +0000644
stefano babic43300a12007-11-20 10:40:24 +0100645 fat_register_device(&mmc_dev, 1); /* partitions start counting with 1 */
wdenk7a428cc2003-06-15 22:40:42 +0000646
647 return rc;
648}
649
stefano babic43300a12007-11-20 10:40:24 +0100650#endif /* CONFIG_MMC */