d81ba8c3174dd8b39c9073f5a439cb9aa8da9d8a
[u-boot-openmoko/mini2440.git] / cpu / arm920t / s3c24x0 / mmc.c
blobd81ba8c3174dd8b39c9073f5a439cb9aa8da9d8a
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 #define CONFIG_MMC_WIDE
38 static S3C2410_SDI *sdi;
40 static block_dev_desc_t mmc_dev;
42 block_dev_desc_t * mmc_get_dev(int dev)
44 return ((block_dev_desc_t *)&mmc_dev);
48 * FIXME needs to read cid and csd info to determine block size
49 * and other parameters
51 static uchar mmc_buf[MMC_BLOCK_SIZE];
52 static mmc_csd_t mmc_csd;
53 static int mmc_ready = 0;
54 static int wide = 0;
57 #define CMD_F_RESP 0x01
58 #define CMD_F_RESP_LONG 0x02
60 static u_int32_t *mmc_cmd(ushort cmd, ulong arg, ushort flags)
62 static u_int32_t resp[5];
64 u_int32_t ccon, csta;
65 u_int32_t csta_rdy_bit = S3C2410_SDICMDSTAT_CMDSENT;
67 memset(resp, 0, sizeof(resp));
69 debug("mmc_cmd CMD%d arg=0x%08x flags=%x\n", cmd, arg, flags);
71 sdi->SDICSTA = 0xffffffff;
72 sdi->SDIDSTA = 0xffffffff;
73 sdi->SDIFSTA = 0xffffffff;
75 sdi->SDICARG = arg;
77 ccon = cmd & S3C2410_SDICMDCON_INDEX;
78 ccon |= S3C2410_SDICMDCON_SENDERHOST|S3C2410_SDICMDCON_CMDSTART;
80 if (flags & CMD_F_RESP) {
81 ccon |= S3C2410_SDICMDCON_WAITRSP;
82 csta_rdy_bit = S3C2410_SDICMDSTAT_RSPFIN; /* 1 << 9 */
85 if (flags & CMD_F_RESP_LONG)
86 ccon |= S3C2410_SDICMDCON_LONGRSP;
88 sdi->SDICCON = ccon;
90 while (1) {
91 csta = sdi->SDICSTA;
92 if (csta & csta_rdy_bit)
93 break;
94 if (csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) {
95 printf("===============> MMC CMD Timeout\n");
96 sdi->SDICSTA |= S3C2410_SDICMDSTAT_CMDTIMEOUT;
97 break;
101 debug("final MMC CMD status 0x%x\n", csta);
103 sdi->SDICSTA |= csta_rdy_bit;
105 if (flags & CMD_F_RESP) {
106 resp[0] = sdi->SDIRSP0;
107 resp[1] = sdi->SDIRSP1;
108 resp[2] = sdi->SDIRSP2;
109 resp[3] = sdi->SDIRSP3;
112 return resp;
115 #define FIFO_FILL(host) ((host->SDIFSTA & S3C2410_SDIFSTA_COUNTMASK) >> 2)
117 static int mmc_block_read(uchar *dst, ulong src, ulong len)
119 u_int32_t dcon, fifo;
120 u_int32_t *dst_u32 = (u_int32_t *)dst;
121 u_int32_t *resp;
123 if (len == 0)
124 return 0;
126 debug("mmc_block_rd dst %lx src %lx len %d\n", (ulong)dst, src, len);
128 /* set block len */
129 resp = mmc_cmd(MMC_CMD_SET_BLOCKLEN, len, CMD_F_RESP);
130 sdi->SDIBSIZE = len;
132 //sdi->SDIPRE = 0xff;
134 /* setup data */
135 dcon = (len >> 9) & S3C2410_SDIDCON_BLKNUM;
136 dcon |= S3C2410_SDIDCON_BLOCKMODE;
137 dcon |= S3C2410_SDIDCON_RXAFTERCMD|S3C2410_SDIDCON_XFER_RXSTART;
138 if (wide)
139 dcon |= S3C2410_SDIDCON_WIDEBUS;
140 #if defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
141 dcon |= S3C2440_SDIDCON_DS_WORD | S3C2440_SDIDCON_DATSTART;
142 #endif
143 sdi->SDIDCON = dcon;
145 /* send read command */
146 resp = mmc_cmd(MMC_CMD_READ_BLOCK, src, CMD_F_RESP);
148 while (len > 0) {
149 u_int32_t sdidsta = sdi->SDIDSTA;
150 fifo = FIFO_FILL(sdi);
151 if (sdidsta & (S3C2410_SDIDSTA_FIFOFAIL|
152 S3C2410_SDIDSTA_CRCFAIL|
153 S3C2410_SDIDSTA_RXCRCFAIL|
154 S3C2410_SDIDSTA_DATATIMEOUT)) {
155 printf("mmc_block_read: err SDIDSTA=0x%08x\n", sdidsta);
156 return -EIO;
159 while (fifo--) {
160 //debug("dst_u32 = 0x%08x\n", dst_u32);
161 *(dst_u32++) = sdi->SDIDAT;
162 if (len >= 4)
163 len -= 4;
164 else {
165 len = 0;
166 break;
171 debug("waiting for SDIDSTA (currently 0x%08x\n", sdi->SDIDSTA);
172 while (!(sdi->SDIDSTA & (1 << 4))) {}
173 debug("done waiting for SDIDSTA (currently 0x%08x\n", sdi->SDIDSTA);
175 sdi->SDIDCON = 0;
177 if (!(sdi->SDIDSTA & S3C2410_SDIDSTA_XFERFINISH))
178 debug("mmc_block_read; transfer not finished!\n");
180 return 0;
183 static int mmc_block_write(ulong dst, uchar *src, int len)
185 printf("MMC block write not yet supported on S3C2410!\n");
186 return -1;
190 int mmc_read(ulong src, uchar *dst, int size)
192 ulong end, part_start, part_end, part_len, aligned_start, aligned_end;
193 ulong mmc_block_size, mmc_block_address;
195 if (size == 0)
196 return 0;
198 if (!mmc_ready) {
199 printf("Please initialize the MMC first\n");
200 return -1;
203 mmc_block_size = MMC_BLOCK_SIZE;
204 mmc_block_address = ~(mmc_block_size - 1);
206 src -= CFG_MMC_BASE;
207 end = src + size;
208 part_start = ~mmc_block_address & src;
209 part_end = ~mmc_block_address & end;
210 aligned_start = mmc_block_address & src;
211 aligned_end = mmc_block_address & end;
213 /* all block aligned accesses */
214 debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
215 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
216 if (part_start) {
217 part_len = mmc_block_size - part_start;
218 debug("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
219 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
220 if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < 0)
221 return -1;
223 memcpy(dst, mmc_buf+part_start, part_len);
224 dst += part_len;
225 src += part_len;
227 debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
228 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
229 for (; src < aligned_end; src += mmc_block_size, dst += mmc_block_size) {
230 debug("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
231 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
232 if ((mmc_block_read((uchar *)(dst), src, mmc_block_size)) < 0)
233 return -1;
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 if (part_end && src < end) {
238 debug("pe 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(mmc_buf, aligned_end, mmc_block_size)) < 0)
241 return -1;
243 memcpy(dst, mmc_buf, part_end);
245 return 0;
248 int mmc_write(uchar *src, ulong dst, int size)
250 ulong end, part_start, part_end, part_len, aligned_start, aligned_end;
251 ulong mmc_block_size, mmc_block_address;
253 if (size == 0)
254 return 0;
256 if (!mmc_ready) {
257 printf("Please initialize the MMC first\n");
258 return -1;
261 mmc_block_size = MMC_BLOCK_SIZE;
262 mmc_block_address = ~(mmc_block_size - 1);
264 dst -= CFG_MMC_BASE;
265 end = dst + size;
266 part_start = ~mmc_block_address & dst;
267 part_end = ~mmc_block_address & end;
268 aligned_start = mmc_block_address & dst;
269 aligned_end = mmc_block_address & end;
271 /* all block aligned accesses */
272 debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
273 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
274 if (part_start) {
275 part_len = mmc_block_size - part_start;
276 debug("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
277 (ulong)src, dst, end, part_start, part_end, aligned_start, aligned_end);
278 if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < 0)
279 return -1;
281 memcpy(mmc_buf+part_start, src, part_len);
282 if ((mmc_block_write(aligned_start, mmc_buf, mmc_block_size)) < 0)
283 return -1;
285 dst += part_len;
286 src += part_len;
288 debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
289 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
290 for (; dst < aligned_end; src += mmc_block_size, dst += mmc_block_size) {
291 debug("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
292 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
293 if ((mmc_block_write(dst, (uchar *)src, mmc_block_size)) < 0)
294 return -1;
297 debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
298 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
299 if (part_end && dst < end) {
300 debug("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
301 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
302 if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0)
303 return -1;
305 memcpy(mmc_buf, src, part_end);
306 if ((mmc_block_write(aligned_end, mmc_buf, mmc_block_size)) < 0)
307 return -1;
310 return 0;
313 ulong mmc_bread(int dev_num, ulong blknr, ulong blkcnt, void *dst)
315 int mmc_block_size = MMC_BLOCK_SIZE;
316 ulong src = blknr * mmc_block_size + CFG_MMC_BASE;
318 mmc_read(src, dst, blkcnt*mmc_block_size);
319 return blkcnt;
322 /* MMC_DEFAULT_RCA should probably be just 1, but this may break other code
323 that expects it to be shifted. */
324 static u_int16_t rca = MMC_DEFAULT_RCA >> 16;
326 static u_int32_t mmc_size(const struct mmc_csd *csd)
328 u_int32_t block_len, mult, blocknr;
330 block_len = csd->read_bl_len << 12;
331 mult = csd->c_size_mult1 << 8;
332 blocknr = (csd->c_size+1) * mult;
334 return blocknr * block_len;
337 struct sd_cid {
338 char pnm_0; /* product name */
339 char oid_1; /* OEM/application ID */
340 char oid_0;
341 uint8_t mid; /* manufacturer ID */
342 char pnm_4;
343 char pnm_3;
344 char pnm_2;
345 char pnm_1;
346 uint8_t psn_2; /* product serial number */
347 uint8_t psn_1;
348 uint8_t psn_0; /* MSB */
349 uint8_t prv; /* product revision */
350 uint8_t crc; /* CRC7 checksum, b0 is unused and set to 1 */
351 uint8_t mdt_1; /* manufacturing date, LSB, RRRRyyyy yyyymmmm */
352 uint8_t mdt_0; /* MSB */
353 uint8_t psn_3; /* LSB */
356 static void print_mmc_cid(mmc_cid_t *cid)
358 printf("MMC found. Card desciption is:\n");
359 printf("Manufacturer ID = %02x%02x%02x\n",
360 cid->id[0], cid->id[1], cid->id[2]);
361 printf("HW/FW Revision = %x %x\n",cid->hwrev, cid->fwrev);
362 cid->hwrev = cid->fwrev = 0; /* null terminate string */
363 printf("Product Name = %s\n",cid->name);
364 printf("Serial Number = %02x%02x%02x\n",
365 cid->sn[0], cid->sn[1], cid->sn[2]);
366 printf("Month = %d\n",cid->month);
367 printf("Year = %d\n",1997 + cid->year);
370 static void print_sd_cid(const struct sd_cid *cid)
372 printf("Manufacturer: 0x%02x, OEM \"%c%c\"\n",
373 cid->mid, cid->oid_0, cid->oid_1);
374 printf("Product name: \"%c%c%c%c%c\", revision %d.%d\n",
375 cid->pnm_0, cid->pnm_1, cid->pnm_2, cid->pnm_3, cid->pnm_4,
376 cid->prv >> 4, cid->prv & 15);
377 printf("Serial number: %u\n",
378 cid->psn_0 << 24 | cid->psn_1 << 16 | cid->psn_2 << 8 |
379 cid->psn_3);
380 printf("Manufacturing date: %d/%d\n",
381 cid->mdt_1 & 15,
382 2000+((cid->mdt_0 & 15) << 4)+((cid->mdt_1 & 0xf0) >> 4));
383 printf("CRC: 0x%02x, b0 = %d\n",
384 cid->crc >> 1, cid->crc & 1);
387 int mmc_init(int verbose)
389 int retries, rc = -ENODEV;
390 int is_sd = 0;
391 u_int32_t *resp;
392 S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
394 sdi = S3C2410_GetBase_SDI();
396 debug("mmc_init(PCLK=%u)\n", get_PCLK());
398 clk_power->CLKCON |= (1 << 9);
400 sdi->SDIBSIZE = 512;
401 #if defined(CONFIG_S3C2410)
402 /* S3C2410 has some bug that prevents reliable operation at higher speed */
403 //sdi->SDIPRE = 0x3e; /* SDCLK = PCLK/2 / (SDIPRE+1) = 396kHz */
404 sdi->SDIPRE = 0x02; /* 2410: SDCLK = PCLK/2 / (SDIPRE+1) = 11MHz */
405 sdi->SDIDTIMER = 0xffff;
406 #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
407 sdi->SDIPRE = 0x05; /* 2410: SDCLK = PCLK / (SDIPRE+1) = 11MHz */
408 sdi->SDIDTIMER = 0x7fffff;
409 #endif
410 sdi->SDIIMSK = 0x0;
411 sdi->SDICON = S3C2410_SDICON_FIFORESET|S3C2410_SDICON_CLOCKTYPE;
412 udelay(125000); /* FIXME: 74 SDCLK cycles */
414 mmc_csd.c_size = 0;
416 /* reset */
417 retries = 10;
418 resp = mmc_cmd(MMC_CMD_RESET, 0, 0);
420 printf("trying to detect SD Card...\n");
421 while (retries--) {
422 udelay(100000);
423 resp = mmc_cmd(55, 0x00000000, CMD_F_RESP);
424 resp = mmc_cmd(41, 0x00300000, CMD_F_RESP);
426 if (resp[0] & (1 << 31)) {
427 is_sd = 1;
428 break;
432 if (retries == 0 && !is_sd) {
433 retries = 10;
434 printf("failed to detect SD Card, trying MMC\n");
435 resp = mmc_cmd(MMC_CMD_SEND_OP_COND, 0x00ffc000, CMD_F_RESP);
436 while (retries-- && resp && !(resp[4] & 0x80)) {
437 debug("resp %x %x\n", resp[0], resp[1]);
438 udelay(50);
439 resp = mmc_cmd(1, 0x00ffff00, CMD_F_RESP);
443 /* try to get card id */
444 resp = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, CMD_F_RESP|CMD_F_RESP_LONG);
445 if (resp) {
446 if (!is_sd) {
447 /* TODO configure mmc driver depending on card
448 attributes */
449 mmc_cid_t *cid = (mmc_cid_t *)resp;
451 if (verbose)
452 print_mmc_cid(cid);
453 sprintf((char *) mmc_dev.vendor,
454 "Man %02x%02x%02x Snr %02x%02x%02x",
455 cid->id[0], cid->id[1], cid->id[2],
456 cid->sn[0], cid->sn[1], cid->sn[2]);
457 sprintf((char *) mmc_dev.product,"%s",cid->name);
458 sprintf((char *) mmc_dev.revision,"%x %x",
459 cid->hwrev, cid->fwrev);
461 else {
462 struct sd_cid *cid = (struct sd_cid *) resp;
464 if (verbose)
465 print_sd_cid(cid);
466 sprintf((char *) mmc_dev.vendor,
467 "Man %02 OEM %c%c \"%c%c%c%c%c\"",
468 cid->mid, cid->oid_0, cid->oid_1,
469 cid->pnm_0, cid->pnm_1, cid->pnm_2, cid->pnm_3,
470 cid->pnm_4);
471 sprintf((char *) mmc_dev.product, "%d",
472 cid->psn_0 << 24 | cid->psn_1 << 16 |
473 cid->psn_2 << 8 | cid->psn_3);
474 sprintf((char *) mmc_dev.revision, "%d.%d",
475 cid->prv >> 4, cid->prv & 15);
478 /* fill in device description */
479 mmc_dev.if_type = IF_TYPE_MMC;
480 mmc_dev.part_type = PART_TYPE_DOS;
481 mmc_dev.dev = 0;
482 mmc_dev.lun = 0;
483 mmc_dev.type = 0;
484 /* FIXME fill in the correct size (is set to 32MByte) */
485 mmc_dev.blksz = 512;
486 mmc_dev.lba = 0x10000;
487 mmc_dev.removable = 0;
488 mmc_dev.block_read = mmc_bread;
490 /* MMC exists, get CSD too */
491 resp = mmc_cmd(MMC_CMD_SET_RCA, MMC_DEFAULT_RCA, CMD_F_RESP);
492 if (is_sd)
493 rca = resp[0] >> 16;
495 resp = mmc_cmd(MMC_CMD_SEND_CSD, rca<<16, CMD_F_RESP|CMD_F_RESP_LONG);
496 if (resp) {
497 mmc_csd_t *csd = (mmc_csd_t *)resp;
498 memcpy(&mmc_csd, csd, sizeof(csd));
499 rc = 0;
500 mmc_ready = 1;
501 /* FIXME add verbose printout for csd */
502 printf("READ_BL_LEN=%u, C_SIZE_MULT=%u, C_SIZE=%u\n",
503 csd->read_bl_len, csd->c_size_mult1, csd->c_size);
504 printf("size = %u\n", mmc_size(csd));
508 resp = mmc_cmd(MMC_CMD_SELECT_CARD, rca<<16, CMD_F_RESP);
510 #ifdef CONFIG_MMC_WIDE
511 if (is_sd) {
512 resp = mmc_cmd(55, rca<<16, CMD_F_RESP);
513 resp = mmc_cmd(6, 0x02, CMD_F_RESP);
514 wide = 1;
516 #endif
518 fat_register_device(&mmc_dev,1); /* partitions start counting with 1 */
520 return rc;
524 mmc_ident(block_dev_desc_t *dev)
526 return 0;
530 mmc2info(ulong addr)
532 /* FIXME hard codes to 32 MB device */
533 if (addr >= CFG_MMC_BASE && addr < CFG_MMC_BASE + 0x02000000)
534 return 1;
536 return 0;
539 #endif /* defined(CONFIG_MMC) && defined(CONFIG_MMC_S3C) */