mirror of
https://github.com/torvalds/linux.git
synced 2024-11-12 07:01:57 +00:00
mmc: Support for high speed SD cards
Modern SD cards support a clock speed of 50 MHz. Make sure we test for this capability and do the song and dance required to activate it. Activating high speed support actually modifies the TRAN_SPEED field of the CSD. But as the spec says that the cards must report 50 MHz, we might as well skip re-reading the CSD. Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
This commit is contained in:
parent
73778120c4
commit
7ccd266e67
@ -1157,6 +1157,116 @@ static void mmc_read_scrs(struct mmc_host *host)
|
||||
mmc_deselect_cards(host);
|
||||
}
|
||||
|
||||
static void mmc_read_switch_caps(struct mmc_host *host)
|
||||
{
|
||||
int err;
|
||||
struct mmc_card *card;
|
||||
struct mmc_request mrq;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_data data;
|
||||
unsigned char *status;
|
||||
struct scatterlist sg;
|
||||
|
||||
status = kmalloc(64, GFP_KERNEL);
|
||||
if (!status) {
|
||||
printk(KERN_WARNING "%s: Unable to allocate buffer for "
|
||||
"reading switch capabilities.\n",
|
||||
mmc_hostname(host));
|
||||
return;
|
||||
}
|
||||
|
||||
list_for_each_entry(card, &host->cards, node) {
|
||||
if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
|
||||
continue;
|
||||
if (!mmc_card_sd(card))
|
||||
continue;
|
||||
if (card->scr.sda_vsn < SCR_SPEC_VER_1)
|
||||
continue;
|
||||
|
||||
err = mmc_select_card(host, card);
|
||||
if (err != MMC_ERR_NONE) {
|
||||
mmc_card_set_dead(card);
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
|
||||
cmd.opcode = SD_SWITCH;
|
||||
cmd.arg = 0x00FFFFF1;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||
|
||||
memset(&data, 0, sizeof(struct mmc_data));
|
||||
|
||||
mmc_set_data_timeout(&data, card, 0);
|
||||
|
||||
data.blksz = 64;
|
||||
data.blocks = 1;
|
||||
data.flags = MMC_DATA_READ;
|
||||
data.sg = &sg;
|
||||
data.sg_len = 1;
|
||||
|
||||
memset(&mrq, 0, sizeof(struct mmc_request));
|
||||
|
||||
mrq.cmd = &cmd;
|
||||
mrq.data = &data;
|
||||
|
||||
sg_init_one(&sg, status, 64);
|
||||
|
||||
mmc_wait_for_req(host, &mrq);
|
||||
|
||||
if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
|
||||
mmc_card_set_dead(card);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (status[13] & 0x02)
|
||||
card->sw_caps.hs_max_dtr = 50000000;
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
|
||||
cmd.opcode = SD_SWITCH;
|
||||
cmd.arg = 0x80FFFFF1;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||
|
||||
memset(&data, 0, sizeof(struct mmc_data));
|
||||
|
||||
mmc_set_data_timeout(&data, card, 0);
|
||||
|
||||
data.blksz = 64;
|
||||
data.blocks = 1;
|
||||
data.flags = MMC_DATA_READ;
|
||||
data.sg = &sg;
|
||||
data.sg_len = 1;
|
||||
|
||||
memset(&mrq, 0, sizeof(struct mmc_request));
|
||||
|
||||
mrq.cmd = &cmd;
|
||||
mrq.data = &data;
|
||||
|
||||
sg_init_one(&sg, status, 64);
|
||||
|
||||
mmc_wait_for_req(host, &mrq);
|
||||
|
||||
if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
|
||||
mmc_card_set_dead(card);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((status[16] & 0xF) != 1) {
|
||||
printk(KERN_WARNING "%s: Problem switching card "
|
||||
"into high-speed mode!\n",
|
||||
mmc_hostname(host));
|
||||
continue;
|
||||
}
|
||||
|
||||
mmc_card_set_highspeed(card);
|
||||
}
|
||||
|
||||
kfree(status);
|
||||
|
||||
mmc_deselect_cards(host);
|
||||
}
|
||||
|
||||
static unsigned int mmc_calculate_clock(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_card *card;
|
||||
@ -1164,9 +1274,12 @@ static unsigned int mmc_calculate_clock(struct mmc_host *host)
|
||||
|
||||
list_for_each_entry(card, &host->cards, node)
|
||||
if (!mmc_card_dead(card)) {
|
||||
if (mmc_card_highspeed(card)) {
|
||||
if (mmc_card_highspeed(card) && mmc_card_sd(card)) {
|
||||
if (max_dtr > card->sw_caps.hs_max_dtr)
|
||||
max_dtr = card->sw_caps.hs_max_dtr;
|
||||
} else if (mmc_card_highspeed(card) && !mmc_card_sd(card)) {
|
||||
if (max_dtr > card->ext_csd.hs_max_dtr)
|
||||
max_dtr = card->ext_csd.hs_max_dtr;
|
||||
max_dtr = card->ext_csd.hs_max_dtr;
|
||||
} else if (max_dtr > card->csd.max_dtr) {
|
||||
max_dtr = card->csd.max_dtr;
|
||||
}
|
||||
@ -1288,9 +1401,10 @@ static void mmc_setup(struct mmc_host *host)
|
||||
|
||||
mmc_read_csds(host);
|
||||
|
||||
if (host->mode == MMC_MODE_SD)
|
||||
if (host->mode == MMC_MODE_SD) {
|
||||
mmc_read_scrs(host);
|
||||
else
|
||||
mmc_read_switch_caps(host);
|
||||
} else
|
||||
mmc_process_ext_csds(host);
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,10 @@ struct sd_scr {
|
||||
#define SD_SCR_BUS_WIDTH_4 (1<<2)
|
||||
};
|
||||
|
||||
struct sd_switch_caps {
|
||||
unsigned int hs_max_dtr;
|
||||
};
|
||||
|
||||
struct mmc_host;
|
||||
|
||||
/*
|
||||
@ -66,7 +70,7 @@ struct mmc_card {
|
||||
#define MMC_STATE_BAD (1<<2) /* unrecognised device */
|
||||
#define MMC_STATE_SDCARD (1<<3) /* is an SD card */
|
||||
#define MMC_STATE_READONLY (1<<4) /* card is read-only */
|
||||
#define MMC_STATE_HIGHSPEED (1<<5) /* card is in mmc4 highspeed mode */
|
||||
#define MMC_STATE_HIGHSPEED (1<<5) /* card is in high speed mode */
|
||||
u32 raw_cid[4]; /* raw card CID */
|
||||
u32 raw_csd[4]; /* raw card CSD */
|
||||
u32 raw_scr[2]; /* raw card SCR */
|
||||
@ -74,6 +78,7 @@ struct mmc_card {
|
||||
struct mmc_csd csd; /* card specific */
|
||||
struct mmc_ext_csd ext_csd; /* mmc v4 extended card specific */
|
||||
struct sd_scr scr; /* extra SD information */
|
||||
struct sd_switch_caps sw_caps; /* switch (CMD6) caps */
|
||||
};
|
||||
|
||||
#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT)
|
||||
|
@ -82,6 +82,7 @@
|
||||
/* class 8 */
|
||||
/* This is basically the same command as for MMC with some quirks. */
|
||||
#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
|
||||
#define SD_SWITCH 6 /* adtc [31:0] See below R1 */
|
||||
|
||||
/* Application commands */
|
||||
#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */
|
||||
@ -100,6 +101,19 @@
|
||||
* [02:00] Command Set
|
||||
*/
|
||||
|
||||
/*
|
||||
* SD_SWITCH argument format:
|
||||
*
|
||||
* [31] Check (0) or switch (1)
|
||||
* [30:24] Reserved (0)
|
||||
* [23:20] Function group 6
|
||||
* [19:16] Function group 5
|
||||
* [15:12] Function group 4
|
||||
* [11:8] Function group 3
|
||||
* [7:4] Function group 2
|
||||
* [3:0] Function group 1
|
||||
*/
|
||||
|
||||
/*
|
||||
MMC status in R1
|
||||
Type
|
||||
@ -284,6 +298,14 @@ struct _mmc_csd {
|
||||
#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */
|
||||
#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */
|
||||
|
||||
/*
|
||||
* SCR field definitions
|
||||
*/
|
||||
|
||||
#define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */
|
||||
#define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */
|
||||
#define SCR_SPEC_VER_2 2 /* Implements system specification 2.00 */
|
||||
|
||||
/*
|
||||
* SD bus widths
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user