Newer
Older
/*
* Copyright 2008, Freescale Semiconductor, Inc
* Andy Fleming
*
* Based vaguely on the Linux code
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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 <command.h>
#include <mmc.h>
#include <part.h>
#include <malloc.h>
#include <linux/list.h>
/* Set block count limit because of 16 bit register limit on some hardware*/
#ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT
#define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535
#endif
static struct list_head mmc_devices;
static int cur_dev_num = -1;
int __board_mmc_getcd(u8 *cd, struct mmc *mmc) {
return -1;
}
int board_mmc_getcd(u8 *cd, struct mmc *mmc)__attribute__((weak,
alias("__board_mmc_getcd")));
int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
{
return mmc->send_cmd(mmc, cmd, data);
}
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
int mmc_send_status(struct mmc *mmc, int timeout)
{
struct mmc_cmd cmd;
int err;
#ifdef CONFIG_MMC_TRACE
int status;
#endif
cmd.cmdidx = MMC_CMD_SEND_STATUS;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 0;
cmd.flags = 0;
do {
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
else if (cmd.response[0] & MMC_STATUS_RDY_FOR_DATA)
break;
udelay(1000);
if (cmd.response[0] & MMC_STATUS_MASK) {
printf("Status Error: 0x%08X\n", cmd.response[0]);
return COMM_ERR;
}
} while (timeout--);
if (!timeout) {
printf("Timeout waiting card ready\n");
return TIMEOUT;
}
return 0;
}
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
int mmc_set_blocklen(struct mmc *mmc, int len)
{
struct mmc_cmd cmd;
cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = len;
cmd.flags = 0;
return mmc_send_cmd(mmc, &cmd, NULL);
}
struct mmc *find_mmc_device(int dev_num)
{
struct mmc *m;
struct list_head *entry;
list_for_each(entry, &mmc_devices) {
m = list_entry(entry, struct mmc, link);
if (m->block_dev.dev == dev_num)
return m;
}
printf("MMC Device %d not found\n", dev_num);
return NULL;
}
static ulong
mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)
int timeout = 1000;
if ((start + blkcnt) > mmc->block_dev.lba) {
printf("MMC: block number 0x%lx exceeds max(0x%lx)\n",
start + blkcnt, mmc->block_dev.lba);
return 0;
}
if (blkcnt > 1)
cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
else
cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
if (mmc->high_capacity)
cmd.cmdarg = start;
else
cmd.cmdarg = start * mmc->write_bl_len;
cmd.resp_type = MMC_RSP_R1;
cmd.flags = 0;
data.src = src;
data.blocks = blkcnt;
data.blocksize = mmc->write_bl_len;
if (mmc_send_cmd(mmc, &cmd, &data)) {
printf("mmc write failed\n");
return 0;
/* SPI multiblock writes terminate using a special
* token, not a STOP_TRANSMISSION request.
*/
if (!mmc_host_is_spi(mmc) && blkcnt > 1) {
cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_R1b;
cmd.flags = 0;
if (mmc_send_cmd(mmc, &cmd, NULL)) {
printf("mmc fail to send stop cmd\n");
return 0;
/* Waiting for the ready status */
mmc_send_status(mmc, timeout);
static ulong
mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src)
{
lbaint_t cur, blocks_todo = blkcnt;
struct mmc *mmc = find_mmc_device(dev_num);
if (mmc_set_blocklen(mmc, mmc->write_bl_len))
return 0;
cur = (blocks_todo > CONFIG_SYS_MMC_MAX_BLK_COUNT) ?
CONFIG_SYS_MMC_MAX_BLK_COUNT : blocks_todo;
if(mmc_write_blocks(mmc, start, cur, src) != cur)
blocks_todo -= cur;
start += cur;
src += cur * mmc->write_bl_len;
} while (blocks_todo > 0);
return blkcnt;
}
int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt)
int timeout = 1000;
if (blkcnt > 1)
cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
else
cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
cmd.cmdarg = start;
cmd.cmdarg = start * mmc->read_bl_len;
cmd.resp_type = MMC_RSP_R1;
cmd.flags = 0;
data.dest = dst;
data.blocks = blkcnt;
data.blocksize = mmc->read_bl_len;
data.flags = MMC_DATA_READ;
if (mmc_send_cmd(mmc, &cmd, &data))
return 0;
if (blkcnt > 1) {
cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_R1b;
cmd.flags = 0;
if (mmc_send_cmd(mmc, &cmd, NULL)) {
printf("mmc fail to send stop cmd\n");
return 0;
}
/* Waiting for the ready status */
mmc_send_status(mmc, timeout);
return blkcnt;
}
static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
{
lbaint_t cur, blocks_todo = blkcnt;
if (blkcnt == 0)
return 0;
struct mmc *mmc = find_mmc_device(dev_num);
if ((start + blkcnt) > mmc->block_dev.lba) {
printf("MMC: block number 0x%lx exceeds max(0x%lx)\n",
start + blkcnt, mmc->block_dev.lba);
return 0;
}
if (mmc_set_blocklen(mmc, mmc->read_bl_len))
cur = (blocks_todo > CONFIG_SYS_MMC_MAX_BLK_COUNT) ?
CONFIG_SYS_MMC_MAX_BLK_COUNT : blocks_todo;
if(mmc_read_blocks(mmc, dst, start, cur) != cur)
return 0;
blocks_todo -= cur;
start += cur;
dst += cur * mmc->read_bl_len;
} while (blocks_todo > 0);
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
return blkcnt;
}
int mmc_go_idle(struct mmc* mmc)
{
struct mmc_cmd cmd;
int err;
udelay(1000);
cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_NONE;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
udelay(2000);
return 0;
}
int
sd_send_op_cond(struct mmc *mmc)
{
int timeout = 1000;
int err;
struct mmc_cmd cmd;
do {
cmd.cmdidx = MMC_CMD_APP_CMD;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 0;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
cmd.resp_type = MMC_RSP_R3;
/*
* Most cards do not answer if some reserved bits
* in the ocr are set. However, Some controller
* can set bit 7 (reserved for low voltages), but
* how to manage low voltages SD card is not yet
* specified.
*/
cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
(mmc->voltages & 0xff8000);
if (mmc->version == SD_VERSION_2)
cmd.cmdarg |= OCR_HCS;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
udelay(1000);
} while ((!(cmd.response[0] & OCR_BUSY)) && timeout--);
if (timeout <= 0)
return UNUSABLE_ERR;
if (mmc->version != SD_VERSION_2)
mmc->version = SD_VERSION_1_0;
if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
cmd.resp_type = MMC_RSP_R3;
cmd.cmdarg = 0;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
}
mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
mmc->rca = 0;
return 0;
}
int mmc_send_op_cond(struct mmc *mmc)
{
int timeout = 10000;
struct mmc_cmd cmd;
int err;
/* Some cards seem to need this */
mmc_go_idle(mmc);
/* Asking to the card its capabilities */
cmd.cmdidx = MMC_CMD_SEND_OP_COND;
cmd.resp_type = MMC_RSP_R3;
cmd.cmdarg = 0;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
udelay(1000);
do {
cmd.cmdidx = MMC_CMD_SEND_OP_COND;
cmd.resp_type = MMC_RSP_R3;
cmd.cmdarg = (mmc_host_is_spi(mmc) ? 0 :
(mmc->voltages &
(cmd.response[0] & OCR_VOLTAGE_MASK)) |
(cmd.response[0] & OCR_ACCESS_MODE));
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
udelay(1000);
} while (!(cmd.response[0] & OCR_BUSY) && timeout--);
if (timeout <= 0)
return UNUSABLE_ERR;
if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
cmd.resp_type = MMC_RSP_R3;
cmd.cmdarg = 0;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
}
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
mmc->rca = 0;
return 0;
}
int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd)
{
struct mmc_cmd cmd;
struct mmc_data data;
int err;
/* Get the Card Status Register */
cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 0;
cmd.flags = 0;
data.dest = ext_csd;
data.blocks = 1;
data.blocksize = 512;
data.flags = MMC_DATA_READ;
err = mmc_send_cmd(mmc, &cmd, &data);
return err;
}
int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
{
struct mmc_cmd cmd;
int timeout = 1000;
int ret;
cmd.cmdidx = MMC_CMD_SWITCH;
cmd.resp_type = MMC_RSP_R1b;
cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
(index << 16) |
(value << 8);
ret = mmc_send_cmd(mmc, &cmd, NULL);
/* Waiting for the ready status */
mmc_send_status(mmc, timeout);
return ret;
}
int mmc_change_freq(struct mmc *mmc)
{
char ext_csd[512];
char cardtype;
int err;
mmc->card_caps = 0;
if (mmc_host_is_spi(mmc))
return 0;
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
/* Only version 4 supports high-speed */
if (mmc->version < MMC_VERSION_4)
return 0;
mmc->card_caps |= MMC_MODE_4BIT;
err = mmc_send_ext_csd(mmc, ext_csd);
if (err)
return err;
if (ext_csd[212] || ext_csd[213] || ext_csd[214] || ext_csd[215])
mmc->high_capacity = 1;
cardtype = ext_csd[196] & 0xf;
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
if (err)
return err;
/* Now check to see that it worked */
err = mmc_send_ext_csd(mmc, ext_csd);
if (err)
return err;
/* No high-speed support */
if (!ext_csd[185])
return 0;
/* High Speed is set, there are two types: 52MHz and 26MHz */
if (cardtype & MMC_HS_52MHZ)
mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
else
mmc->card_caps |= MMC_MODE_HS;
return 0;
}
int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
{
struct mmc_cmd cmd;
struct mmc_data data;
/* Switch the frequency */
cmd.cmdidx = SD_CMD_SWITCH_FUNC;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = (mode << 31) | 0xffffff;
cmd.cmdarg &= ~(0xf << (group * 4));
cmd.cmdarg |= value << (group * 4);
cmd.flags = 0;
data.dest = (char *)resp;
data.blocksize = 64;
data.blocks = 1;
data.flags = MMC_DATA_READ;
return mmc_send_cmd(mmc, &cmd, &data);
}
int sd_change_freq(struct mmc *mmc)
{
int err;
struct mmc_cmd cmd;
uint scr[2];
uint switch_status[16];
struct mmc_data data;
int timeout;
mmc->card_caps = 0;
if (mmc_host_is_spi(mmc))
return 0;
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
/* Read the SCR to find out if this card supports higher speeds */
cmd.cmdidx = MMC_CMD_APP_CMD;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = mmc->rca << 16;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
cmd.cmdidx = SD_CMD_APP_SEND_SCR;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 0;
cmd.flags = 0;
timeout = 3;
retry_scr:
data.dest = (char *)&scr;
data.blocksize = 8;
data.blocks = 1;
data.flags = MMC_DATA_READ;
err = mmc_send_cmd(mmc, &cmd, &data);
if (err) {
if (timeout--)
goto retry_scr;
return err;
}
mmc->scr[0] = __be32_to_cpu(scr[0]);
mmc->scr[1] = __be32_to_cpu(scr[1]);
switch ((mmc->scr[0] >> 24) & 0xf) {
case 0:
mmc->version = SD_VERSION_1_0;
break;
case 1:
mmc->version = SD_VERSION_1_10;
break;
case 2:
mmc->version = SD_VERSION_2;
break;
default:
mmc->version = SD_VERSION_1_0;
break;
}
if (mmc->scr[0] & SD_DATA_4BIT)
mmc->card_caps |= MMC_MODE_4BIT;
/* Version 1.0 doesn't support switching */
if (mmc->version == SD_VERSION_1_0)
return 0;
timeout = 4;
while (timeout--) {
err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
(u8 *)&switch_status);
if (err)
return err;
/* The high-speed function is busy. Try again */
if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
break;
}
/* If high-speed isn't supported, we return */
if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
return 0;
err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)&switch_status);
if (err)
return err;
if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
mmc->card_caps |= MMC_MODE_HS;
return 0;
}
/* frequency bases */
/* divided by 10 to be nice to platforms without floating point */
10000,
100000,
1000000,
10000000,
};
/* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice
* to platforms without floating point.
*/
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
0, /* reserved */
10,
12,
13,
15,
20,
25,
30,
35,
40,
45,
50,
55,
60,
70,
80,
};
void mmc_set_ios(struct mmc *mmc)
{
mmc->set_ios(mmc);
}
void mmc_set_clock(struct mmc *mmc, uint clock)
{
if (clock > mmc->f_max)
clock = mmc->f_max;
if (clock < mmc->f_min)
clock = mmc->f_min;
mmc->clock = clock;
mmc_set_ios(mmc);
}
void mmc_set_bus_width(struct mmc *mmc, uint width)
{
mmc->bus_width = width;
mmc_set_ios(mmc);
}
int mmc_startup(struct mmc *mmc)
{
int err;
uint mult, freq;
u64 cmult, csize;
struct mmc_cmd cmd;
int timeout = 1000;
#ifdef CONFIG_MMC_SPI_CRC_ON
if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 1;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
}
#endif
cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
cmd.resp_type = MMC_RSP_R2;
cmd.cmdarg = 0;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
memcpy(mmc->cid, cmd.response, 16);
/*
* For MMC cards, set the Relative Address.
* For SD cards, get the Relatvie Address.
* This also puts the cards into Standby State
*/
if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
cmd.cmdarg = mmc->rca << 16;
cmd.resp_type = MMC_RSP_R6;
cmd.flags = 0;
if (IS_SD(mmc))
mmc->rca = (cmd.response[0] >> 16) & 0xffff;
}
/* Get the Card-Specific Data */
cmd.cmdidx = MMC_CMD_SEND_CSD;
cmd.resp_type = MMC_RSP_R2;
cmd.cmdarg = mmc->rca << 16;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
/* Waiting for the ready status */
mmc_send_status(mmc, timeout);
mmc->csd[0] = cmd.response[0];
mmc->csd[1] = cmd.response[1];
mmc->csd[2] = cmd.response[2];
mmc->csd[3] = cmd.response[3];
int version = (cmd.response[0] >> 26) & 0xf;
switch (version) {
case 0:
mmc->version = MMC_VERSION_1_2;
break;
case 1:
mmc->version = MMC_VERSION_1_4;
break;
case 2:
mmc->version = MMC_VERSION_2_2;
break;
case 3:
mmc->version = MMC_VERSION_3;
break;
case 4:
mmc->version = MMC_VERSION_4;
break;
default:
mmc->version = MMC_VERSION_1_2;
break;
}
}
/* divide frequency by 10, since the mults are 10x bigger */
freq = fbase[(cmd.response[0] & 0x7)];
mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
if (IS_SD(mmc))
mmc->write_bl_len = mmc->read_bl_len;
else
mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
if (mmc->high_capacity) {
csize = (mmc->csd[1] & 0x3f) << 16
| (mmc->csd[2] & 0xffff0000) >> 16;
cmult = 8;
} else {
csize = (mmc->csd[1] & 0x3ff) << 2
| (mmc->csd[2] & 0xc0000000) >> 30;
cmult = (mmc->csd[2] & 0x00038000) >> 15;
}
mmc->capacity = (csize + 1) << (cmult + 2);
mmc->capacity *= mmc->read_bl_len;
if (mmc->read_bl_len > 512)
mmc->read_bl_len = 512;
if (mmc->write_bl_len > 512)
mmc->write_bl_len = 512;
/* Select the card, and put it into Transfer Mode */
if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
cmd.cmdidx = MMC_CMD_SELECT_CARD;
cmd.resp_type = MMC_RSP_R1b;
cmd.cmdarg = mmc->rca << 16;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
/* check ext_csd version and capacity */
err = mmc_send_ext_csd(mmc, ext_csd);
if (!err & (ext_csd[192] >= 2)) {
mmc->capacity = ext_csd[212] << 0 | ext_csd[213] << 8 |
ext_csd[214] << 16 | ext_csd[215] << 24;
mmc->capacity *= 512;
}
}
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
if (IS_SD(mmc))
err = sd_change_freq(mmc);
else
err = mmc_change_freq(mmc);
if (err)
return err;
/* Restrict card's capabilities by what the host can do */
mmc->card_caps &= mmc->host_caps;
if (IS_SD(mmc)) {
if (mmc->card_caps & MMC_MODE_4BIT) {
cmd.cmdidx = MMC_CMD_APP_CMD;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = mmc->rca << 16;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 2;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
mmc_set_bus_width(mmc, 4);
}
if (mmc->card_caps & MMC_MODE_HS)
mmc_set_clock(mmc, 50000000);
else
mmc_set_clock(mmc, 25000000);
} else {
if (mmc->card_caps & MMC_MODE_4BIT) {
/* Set the card to use 4 bit*/
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
EXT_CSD_BUS_WIDTH_4);
if (err)
return err;
mmc_set_bus_width(mmc, 4);
} else if (mmc->card_caps & MMC_MODE_8BIT) {
/* Set the card to use 8 bit*/
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
EXT_CSD_BUS_WIDTH_8);
if (err)
return err;
mmc_set_bus_width(mmc, 8);
}
if (mmc->card_caps & MMC_MODE_HS) {
if (mmc->card_caps & MMC_MODE_HS_52MHz)
mmc_set_clock(mmc, 52000000);
else
mmc_set_clock(mmc, 26000000);
} else
mmc_set_clock(mmc, 20000000);
}
/* fill in device description */
mmc->block_dev.lun = 0;
mmc->block_dev.type = 0;
mmc->block_dev.blksz = mmc->read_bl_len;
mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
sprintf(mmc->block_dev.vendor, "Man %06x Snr %08x", mmc->cid[0] >> 8,
(mmc->cid[2] << 8) | (mmc->cid[3] >> 24));
sprintf(mmc->block_dev.product, "%c%c%c%c%c", mmc->cid[0] & 0xff,
(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff);
sprintf(mmc->block_dev.revision, "%d.%d", mmc->cid[2] >> 28,
(mmc->cid[2] >> 24) & 0xf);
init_part(&mmc->block_dev);
return 0;
}
int mmc_send_if_cond(struct mmc *mmc)
{
struct mmc_cmd cmd;
int err;
cmd.cmdidx = SD_CMD_SEND_IF_COND;
/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
cmd.cmdarg = ((mmc->voltages & 0xff8000) != 0) << 8 | 0xaa;
cmd.resp_type = MMC_RSP_R7;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
return UNUSABLE_ERR;
else
mmc->version = SD_VERSION_2;
return 0;
}
int mmc_register(struct mmc *mmc)
{
/* Setup the universal parts of the block interface just once */
mmc->block_dev.if_type = IF_TYPE_MMC;
mmc->block_dev.dev = cur_dev_num++;
mmc->block_dev.removable = 1;
mmc->block_dev.block_read = mmc_bread;
mmc->block_dev.block_write = mmc_bwrite;
INIT_LIST_HEAD (&mmc->link);
list_add_tail (&mmc->link, &mmc_devices);
return 0;
}
block_dev_desc_t *mmc_get_dev(int dev)
{
struct mmc *mmc = find_mmc_device(dev);
return mmc ? &mmc->block_dev : NULL;