add SDHC support in mmc driver
[u-boot-openmoko/mini2440.git] / cpu / arm920t / s3c24x0 / mmc.c
blob454bb7a4802ee9fa5639c075eb2975e85a0b7d6e
1 /*
2 * u-boot S3C2410 MMC/SD card driver
3 * (C) Copyright 2006 by OpenMoko, Inc.
4 * Author: Harald Welte <laforge@openmoko.org>
6 * based on u-boot pxa MMC driver and linux/drivers/mmc/s3c2410mci.c
7 * (C) 2005-2005 Thomas Kleffel
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22 * MA 02111-1307 USA
25 #include <config.h>
26 #include <common.h>
27 #include <mmc.h>
28 #include <asm/errno.h>
29 #include <asm/io.h>
30 #include <s3c2410.h>
31 #include <part.h>
32 #include <fat.h>
34 #if defined(CONFIG_MMC) && defined(CONFIG_MMC_S3C)
36 #ifdef DEBUG
37 #define pr_debug(fmt, args...) printf(fmt, ##args)
38 #else
39 #define pr_debug(...) do { } while(0)
40 #endif
42 #define CONFIG_MMC_WIDE
44 static S3C2410_SDI *sdi;
46 static block_dev_desc_t mmc_dev;
48 block_dev_desc_t * mmc_get_dev(int dev)
50 return ((block_dev_desc_t *)&mmc_dev);
54 * FIXME needs to read cid and csd info to determine block size
55 * and other parameters
57 static uchar mmc_buf[MMC_BLOCK_SIZE];
58 static mmc_csd_t mmc_csd;
59 static int mmc_ready = 0;
60 static int wide = 0;
63 #define CMD_F_RESP 0x01
64 #define CMD_F_RESP_LONG 0x02
66 #define CMD_F_RESP_R7 CMD_F_RESP
68 static u_int32_t *mmc_cmd(ushort cmd, ulong arg, ushort flags)
70 static u_int32_t resp[5];
72 u_int32_t ccon, csta;
73 u_int32_t csta_rdy_bit = S3C2410_SDICMDSTAT_CMDSENT;
75 memset(resp, 0, sizeof(resp));
77 debug("mmc_cmd CMD%d arg=0x%08x flags=%x\n", cmd, arg, flags);
79 sdi->SDICSTA = 0xffffffff;
80 sdi->SDIDSTA = 0xffffffff;
81 sdi->SDIFSTA = 0xffffffff;
83 sdi->SDICARG = arg;
85 ccon = cmd & S3C2410_SDICMDCON_INDEX;
86 ccon |= S3C2410_SDICMDCON_SENDERHOST|S3C2410_SDICMDCON_CMDSTART;
88 if (flags & CMD_F_RESP) {
89 ccon |= S3C2410_SDICMDCON_WAITRSP;
90 csta_rdy_bit = S3C2410_SDICMDSTAT_RSPFIN; /* 1 << 9 */
93 if (flags & CMD_F_RESP_LONG)
94 ccon |= S3C2410_SDICMDCON_LONGRSP;
96 sdi->SDICCON = ccon;
98 while (1) {
99 csta = sdi->SDICSTA;
100 if (csta & csta_rdy_bit)
101 break;
102 if (csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) {
103 printf("===============> MMC CMD Timeout\n");
104 sdi->SDICSTA |= S3C2410_SDICMDSTAT_CMDTIMEOUT;
105 break;
109 debug("final MMC CMD status 0x%x\n", csta);
111 sdi->SDICSTA |= csta_rdy_bit;
113 if (flags & CMD_F_RESP) {
114 resp[0] = sdi->SDIRSP0;
115 resp[1] = sdi->SDIRSP1;
116 resp[2] = sdi->SDIRSP2;
117 resp[3] = sdi->SDIRSP3;
120 return resp;
123 #define FIFO_FILL(host) ((host->SDIFSTA & S3C2410_SDIFSTA_COUNTMASK) >> 2)
125 static int mmc_block_read(uchar *dst, ulong src, ulong len)
127 u_int32_t dcon, fifo;
128 u_int32_t *dst_u32 = (u_int32_t *)dst;
129 u_int32_t *resp;
131 if (len == 0)
132 return 0;
134 debug("mmc_block_rd dst %lx src %lx len %d\n", (ulong)dst, src, len);
136 /* set block len */
137 resp = mmc_cmd(MMC_CMD_SET_BLOCKLEN, len, CMD_F_RESP);
138 sdi->SDIBSIZE = len;
140 //sdi->SDIPRE = 0xff;
142 /* setup data */
143 dcon = (len >> 9) & S3C2410_SDIDCON_BLKNUM;
144 dcon |= S3C2410_SDIDCON_BLOCKMODE;
145 dcon |= S3C2410_SDIDCON_RXAFTERCMD|S3C2410_SDIDCON_XFER_RXSTART;
146 if (wide)
147 dcon |= S3C2410_SDIDCON_WIDEBUS;
148 #if defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
149 dcon |= S3C2440_SDIDCON_DS_WORD | S3C2440_SDIDCON_DATSTART;
150 #endif
151 sdi->SDIDCON = dcon;
153 /* send read command */
154 resp = mmc_cmd(MMC_CMD_READ_BLOCK, (mmc_dev.if_type == IF_TYPE_SDHC) ? (src >> 9) : src, CMD_F_RESP);
156 while (len > 0) {
157 u_int32_t sdidsta = sdi->SDIDSTA;
158 fifo = FIFO_FILL(sdi);
159 if (sdidsta & (S3C2410_SDIDSTA_FIFOFAIL|
160 S3C2410_SDIDSTA_CRCFAIL|
161 S3C2410_SDIDSTA_RXCRCFAIL|
162 S3C2410_SDIDSTA_DATATIMEOUT)) {
163 printf("mmc_block_read: err SDIDSTA=0x%08x\n", sdidsta);
164 return -EIO;
167 while (fifo--) {
168 //debug("dst_u32 = 0x%08x\n", dst_u32);
169 *(dst_u32++) = sdi->SDIDAT;
170 if (len >= 4)
171 len -= 4;
172 else {
173 len = 0;
174 break;
179 debug("waiting for SDIDSTA (currently 0x%08x\n", sdi->SDIDSTA);
180 while (!(sdi->SDIDSTA & (1 << 4))) {}
181 debug("done waiting for SDIDSTA (currently 0x%08x\n", sdi->SDIDSTA);
183 sdi->SDIDCON = 0;
185 if (!(sdi->SDIDSTA & S3C2410_SDIDSTA_XFERFINISH))
186 debug("mmc_block_read; transfer not finished!\n");
188 return 0;
191 static int mmc_block_write(ulong dst, uchar *src, int len)
193 printf("MMC block write not yet supported on S3C2410!\n");
194 return -1;
198 int mmc_read(ulong src, uchar *dst, int size)
200 ulong end, part_start, part_end, part_len, aligned_start, aligned_end;
201 ulong mmc_block_size, mmc_block_address;
203 if (size == 0)
204 return 0;
206 if (!mmc_ready) {
207 printf("Please initialize the MMC first\n");
208 return -1;
211 mmc_block_size = MMC_BLOCK_SIZE;
212 mmc_block_address = ~(mmc_block_size - 1);
214 src -= CFG_MMC_BASE;
215 end = src + size;
216 part_start = ~mmc_block_address & src;
217 part_end = ~mmc_block_address & end;
218 aligned_start = mmc_block_address & src;
219 aligned_end = mmc_block_address & end;
221 /* all block aligned accesses */
222 debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
223 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
224 if (part_start) {
225 part_len = mmc_block_size - part_start;
226 debug("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
227 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
228 if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < 0)
229 return -1;
231 memcpy(dst, mmc_buf+part_start, part_len);
232 dst += part_len;
233 src += part_len;
235 debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
236 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
237 for (; src < aligned_end; src += mmc_block_size, dst += mmc_block_size) {
238 debug("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
239 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
240 if ((mmc_block_read((uchar *)(dst), src, mmc_block_size)) < 0)
241 return -1;
243 debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
244 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
245 if (part_end && src < end) {
246 debug("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
247 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
248 if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0)
249 return -1;
251 memcpy(dst, mmc_buf, part_end);
253 return 0;
256 int mmc_write(uchar *src, ulong dst, int size)
258 ulong end, part_start, part_end, part_len, aligned_start, aligned_end;
259 ulong mmc_block_size, mmc_block_address;
261 if (size == 0)
262 return 0;
264 if (!mmc_ready) {
265 printf("Please initialize the MMC first\n");
266 return -1;
269 mmc_block_size = MMC_BLOCK_SIZE;
270 mmc_block_address = ~(mmc_block_size - 1);
272 dst -= CFG_MMC_BASE;
273 end = dst + size;
274 part_start = ~mmc_block_address & dst;
275 part_end = ~mmc_block_address & end;
276 aligned_start = mmc_block_address & dst;
277 aligned_end = mmc_block_address & end;
279 /* all block aligned accesses */
280 debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
281 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
282 if (part_start) {
283 part_len = mmc_block_size - part_start;
284 debug("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
285 (ulong)src, dst, end, part_start, part_end, aligned_start, aligned_end);
286 if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < 0)
287 return -1;
289 memcpy(mmc_buf+part_start, src, part_len);
290 if ((mmc_block_write(aligned_start, mmc_buf, mmc_block_size)) < 0)
291 return -1;
293 dst += part_len;
294 src += part_len;
296 debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
297 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
298 for (; dst < aligned_end; src += mmc_block_size, dst += mmc_block_size) {
299 debug("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
300 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
301 if ((mmc_block_write(dst, (uchar *)src, mmc_block_size)) < 0)
302 return -1;
305 debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
306 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
307 if (part_end && dst < end) {
308 debug("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
309 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
310 if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0)
311 return -1;
313 memcpy(mmc_buf, src, part_end);
314 if ((mmc_block_write(aligned_end, mmc_buf, mmc_block_size)) < 0)
315 return -1;
318 return 0;
321 ulong mmc_bread(int dev_num, ulong blknr, ulong blkcnt, void *dst)
323 int mmc_block_size = MMC_BLOCK_SIZE;
324 ulong src = blknr * mmc_block_size + CFG_MMC_BASE;
326 mmc_read(src, dst, blkcnt*mmc_block_size);
327 return blkcnt;
330 /* MMC_DEFAULT_RCA should probably be just 1, but this may break other code
331 that expects it to be shifted. */
332 static u_int16_t rca = MMC_DEFAULT_RCA >> 16;
334 static u_int32_t mmc_size(const struct mmc_csd *csd)
336 u_int32_t block_len, mult, blocknr;
338 block_len = csd->read_bl_len << 12;
339 mult = csd->c_size_mult1 << 8;
340 blocknr = (csd->c_size+1) * mult;
342 return blocknr * block_len;
345 struct sd_cid {
346 char pnm_0; /* product name */
347 char oid_1; /* OEM/application ID */
348 char oid_0;
349 uint8_t mid; /* manufacturer ID */
350 char pnm_4;
351 char pnm_3;
352 char pnm_2;
353 char pnm_1;
354 uint8_t psn_2; /* product serial number */
355 uint8_t psn_1;
356 uint8_t psn_0; /* MSB */
357 uint8_t prv; /* product revision */
358 uint8_t crc; /* CRC7 checksum, b0 is unused and set to 1 */
359 uint8_t mdt_1; /* manufacturing date, LSB, RRRRyyyy yyyymmmm */
360 uint8_t mdt_0; /* MSB */
361 uint8_t psn_3; /* LSB */
364 static void print_mmc_cid(mmc_cid_t *cid)
366 printf("MMC found. Card desciption is:\n");
367 printf("Manufacturer ID = %02x%02x%02x\n",
368 cid->id[0], cid->id[1], cid->id[2]);
369 printf("HW/FW Revision = %x %x\n",cid->hwrev, cid->fwrev);
370 cid->hwrev = cid->fwrev = 0; /* null terminate string */
371 printf("Product Name = %s\n",cid->name);
372 printf("Serial Number = %02x%02x%02x\n",
373 cid->sn[0], cid->sn[1], cid->sn[2]);
374 printf("Month = %d\n",cid->month);
375 printf("Year = %d\n",1997 + cid->year);
378 static void print_sd_cid(const struct sd_cid *cid)
380 printf("Manufacturer: 0x%02x, OEM \"%c%c\"\n",
381 cid->mid, cid->oid_0, cid->oid_1);
382 printf("Product name: \"%c%c%c%c%c\", revision %d.%d\n",
383 cid->pnm_0, cid->pnm_1, cid->pnm_2, cid->pnm_3, cid->pnm_4,
384 cid->prv >> 4, cid->prv & 15);
385 printf("Serial number: %u\n",
386 cid->psn_0 << 24 | cid->psn_1 << 16 | cid->psn_2 << 8 |
387 cid->psn_3);
388 printf("Manufacturing date: %d/%d\n",
389 cid->mdt_1 & 15,
390 2000+((cid->mdt_0 & 15) << 4)+((cid->mdt_1 & 0xf0) >> 4));
391 printf("CRC: 0x%02x, b0 = %d\n",
392 cid->crc >> 1, cid->crc & 1);
395 int mmc_init(int verbose)
397 int retries, rc = -ENODEV;
398 int is_sd = 0;
399 u_int32_t *resp;
400 S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
401 block_dev_desc_t *mmc_blkdev_p = &mmc_dev;
403 sdi = S3C2410_GetBase_SDI();
405 debug("mmc_init(PCLK=%u)\n", get_PCLK());
407 clk_power->CLKCON |= (1 << 9);
409 sdi->SDIBSIZE = 512;
410 #if defined(CONFIG_S3C2410)
411 /* S3C2410 has some bug that prevents reliable operation at higher speed */
412 //sdi->SDIPRE = 0x3e; /* SDCLK = PCLK/2 / (SDIPRE+1) = 396kHz */
413 sdi->SDIPRE = 0x02; /* 2410: SDCLK = PCLK/2 / (SDIPRE+1) = 11MHz */
414 sdi->SDIDTIMER = 0xffff;
415 #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
416 sdi->SDIPRE = 0x05; /* 2410: SDCLK = PCLK / (SDIPRE+1) = 11MHz */
417 sdi->SDIDTIMER = 0x7fffff;
418 #endif
419 sdi->SDIIMSK = 0x0;
420 sdi->SDICON = S3C2410_SDICON_FIFORESET|S3C2410_SDICON_CLOCKTYPE;
421 udelay(125000); /* FIXME: 74 SDCLK cycles */
423 mmc_csd.c_size = 0;
425 /* reset */
426 retries = 10;
427 resp = mmc_cmd(MMC_CMD_RESET, 0, 0);
429 mmc_dev.if_type = IF_TYPE_UNKNOWN;
430 if(verbose)
431 puts("mmc: Probing for SDHC ...\n");
433 /* Send supported voltage range */
434 /* SD cards 1.x do not answer to CMD8 */
435 resp = mmc_cmd(MMC_CMD_IF_COND, ((1 << 8) | 0xAA), CMD_F_RESP_R7);
436 if (!resp[0]) {
438 * ARC: No answer let's try SD 1.x
440 if(verbose)
441 puts("mmc: No answer to CMD8 trying SD\n");
442 mmc_blkdev_p->if_type = IF_TYPE_SD;
443 } else {
445 * ARC: probably an SDHC card
447 mmc_blkdev_p->if_type = IF_TYPE_SDHC;
448 if(verbose)
449 puts("mmc: SD 2.0 or later card found\n");
451 /* Check if the card supports this voltage */
452 if (resp[0] != ((1 << 8) | 0xAA)) {
453 pr_debug("mmc: Invalid voltage range\n");
454 return -ENODEV;
459 * ARC: HC (30) bit set according to response to
460 * CMD8 command
463 pr_debug("mmc: Sending ACMD41 %s HC set\n",
464 ((mmc_blkdev_p->if_type ==
465 IF_TYPE_SDHC) ? "with" : "without"));
467 printf("trying to detect SD Card...\n");
468 while (retries--) {
469 udelay(100000);
470 resp = mmc_cmd(55, 0x00000000, CMD_F_RESP);
471 resp = mmc_cmd(41, (mmc_blkdev_p->if_type == IF_TYPE_SDHC)? (0x00300000 | (1<<30)) : 0x00300000, CMD_F_RESP);
473 if (resp[0] & (1 << 31)) {
474 is_sd = 1;
475 break;
480 * ARC: check for HC bit, if its not set
481 * sd card is SD
483 if (is_sd && (resp[0] & 0xc0000000) == 0x80000000) {
484 mmc_dev.if_type = IF_TYPE_SD;
487 if (retries == 0 && !is_sd) {
488 retries = 10;
489 printf("failed to detect SD Card, trying MMC\n");
490 mmc_blkdev_p->if_type = IF_TYPE_MMC;
491 resp = mmc_cmd(MMC_CMD_SEND_OP_COND, 0x00ffc000, CMD_F_RESP);
492 while (retries-- && resp && !(resp[4] & 0x80)) {
493 debug("resp %x %x\n", resp[0], resp[1]);
494 udelay(50);
495 resp = mmc_cmd(1, 0x00ffff00, CMD_F_RESP);
499 /* try to get card id */
500 resp = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, CMD_F_RESP|CMD_F_RESP_LONG);
501 if (resp) {
502 if (!is_sd) {
503 /* TODO configure mmc driver depending on card
504 attributes */
505 mmc_cid_t *cid = (mmc_cid_t *)resp;
507 if (verbose)
508 print_mmc_cid(cid);
509 sprintf((char *) mmc_dev.vendor,
510 "Man %02x%02x%02x Snr %02x%02x%02x",
511 cid->id[0], cid->id[1], cid->id[2],
512 cid->sn[0], cid->sn[1], cid->sn[2]);
513 sprintf((char *) mmc_dev.product,"%s",cid->name);
514 sprintf((char *) mmc_dev.revision,"%x %x",
515 cid->hwrev, cid->fwrev);
517 else {
518 struct sd_cid *cid = (struct sd_cid *) resp;
520 if (verbose)
521 print_sd_cid(cid);
522 sprintf((char *) mmc_dev.vendor,
523 "Man %02 OEM %c%c \"%c%c%c%c%c\"",
524 cid->mid, cid->oid_0, cid->oid_1,
525 cid->pnm_0, cid->pnm_1, cid->pnm_2, cid->pnm_3,
526 cid->pnm_4);
527 sprintf((char *) mmc_dev.product, "%d",
528 cid->psn_0 << 24 | cid->psn_1 << 16 |
529 cid->psn_2 << 8 | cid->psn_3);
530 sprintf((char *) mmc_dev.revision, "%d.%d",
531 cid->prv >> 4, cid->prv & 15);
534 /* fill in device description */
535 if (mmc_dev.if_type == IF_TYPE_UNKNOWN)
536 mmc_dev.if_type = IF_TYPE_MMC;
537 mmc_dev.part_type = PART_TYPE_DOS;
538 mmc_dev.dev = 0;
539 mmc_dev.lun = 0;
540 mmc_dev.type = 0;
541 /* FIXME fill in the correct size (is set to 32MByte) */
542 mmc_dev.blksz = 512;
543 mmc_dev.lba = 0x10000;
544 mmc_dev.removable = 0;
545 mmc_dev.block_read = mmc_bread;
547 /* MMC exists, get CSD too */
548 resp = mmc_cmd(MMC_CMD_SET_RCA, MMC_DEFAULT_RCA, CMD_F_RESP);
549 if (is_sd)
550 rca = resp[0] >> 16;
552 resp = mmc_cmd(MMC_CMD_SEND_CSD, rca<<16, CMD_F_RESP|CMD_F_RESP_LONG);
553 if (resp) {
554 mmc_csd_t *csd = (mmc_csd_t *)resp;
555 memcpy(&mmc_csd, csd, sizeof(csd));
556 rc = 0;
557 mmc_ready = 1;
558 /* FIXME add verbose printout for csd */
559 printf("READ_BL_LEN=%u, C_SIZE_MULT=%u, C_SIZE=%u\n",
560 csd->read_bl_len, csd->c_size_mult1, csd->c_size);
561 printf("size = %u\n", mmc_size(csd));
565 resp = mmc_cmd(MMC_CMD_SELECT_CARD, rca<<16, CMD_F_RESP);
567 if (verbose)
568 printf("SD Card detected RCA: 0x%x type: %s\n",
569 rca, ((mmc_dev.if_type == IF_TYPE_SDHC) ? "SDHC" : ((mmc_dev.if_type == IF_TYPE_SD) ? "SD" : "MMC")));
571 #ifdef CONFIG_MMC_WIDE
572 if (is_sd) {
573 resp = mmc_cmd(55, rca<<16, CMD_F_RESP);
574 resp = mmc_cmd(6, 0x02, CMD_F_RESP);
575 wide = 1;
577 #endif
579 fat_register_device(&mmc_dev,1); /* partitions start counting with 1 */
581 return rc;
585 mmc_ident(block_dev_desc_t *dev)
587 return 0;
591 mmc2info(ulong addr)
593 /* FIXME hard codes to 32 MB device */
594 if (addr >= CFG_MMC_BASE && addr < CFG_MMC_BASE + 0x02000000)
595 return 1;
597 return 0;
600 #endif /* defined(CONFIG_MMC) && defined(CONFIG_MMC_S3C) */