Skip to content

Commit

Permalink
mmc: sd: query function modes for uhs cards
Browse files Browse the repository at this point in the history
SD cards which conform to Physical Layer Spec v3.01 can support
additional Bus Speed Modes, Driver Strength, and Current Limit
other than the default values. We use CMD6 mode 0 to read these
additional card functions. The values read here will be used
during UHS-I initialization steps.

Tested by Zhangfei Gao with a Toshiba uhs card and general hs card,
on mmp2 in SDMA mode.

Signed-off-by: Arindam Nath <arindam.nath@amd.com>
Reviewed-by: Philip Rakity <prakity@marvell.com>
Tested-by: Philip Rakity <prakity@marvell.com>
Acked-by: Zhangfei Gao <zhangfei.gao@marvell.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
  • Loading branch information
Arindam Nath authored and Chris Ball committed May 25, 2011
1 parent f2119df commit 013909c
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 10 deletions.
68 changes: 58 additions & 10 deletions drivers/mmc/core/sd.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ static int mmc_decode_scr(struct mmc_card *card)

scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
if (scr->sda_vsn == SCR_SPEC_VER_2)
/* Check if Physical Layer Spec v3.0 is supported */
scr->sda_spec3 = UNSTUFF_BITS(resp, 47, 1);

if (UNSTUFF_BITS(resp, 55, 1))
card->erased_byte = 0xFF;
Expand Down Expand Up @@ -274,29 +277,74 @@ static int mmc_read_switch(struct mmc_card *card)
status = kmalloc(64, GFP_KERNEL);
if (!status) {
printk(KERN_ERR "%s: could not allocate a buffer for "
"switch capabilities.\n", mmc_hostname(card->host));
"switch capabilities.\n",
mmc_hostname(card->host));
return -ENOMEM;
}

/* Find out the supported Bus Speed Modes. */
err = mmc_sd_switch(card, 0, 0, 1, status);
if (err) {
/* If the host or the card can't do the switch,
* fail more gracefully. */
if ((err != -EINVAL)
&& (err != -ENOSYS)
&& (err != -EFAULT))
/*
* If the host or the card can't do the switch,
* fail more gracefully.
*/
if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
goto out;

printk(KERN_WARNING "%s: problem reading switch "
"capabilities, performance might suffer.\n",
printk(KERN_WARNING "%s: problem reading Bus Speed modes.\n",
mmc_hostname(card->host));
err = 0;

goto out;
}

if (status[13] & 0x02)
card->sw_caps.hs_max_dtr = 50000000;
if (card->scr.sda_spec3) {
card->sw_caps.sd3_bus_mode = status[13];

/* Find out Driver Strengths supported by the card */
err = mmc_sd_switch(card, 0, 2, 1, status);
if (err) {
/*
* If the host or the card can't do the switch,
* fail more gracefully.
*/
if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
goto out;

printk(KERN_WARNING "%s: problem reading "
"Driver Strength.\n",
mmc_hostname(card->host));
err = 0;

goto out;
}

card->sw_caps.sd3_drv_type = status[9];

/* Find out Current Limits supported by the card */
err = mmc_sd_switch(card, 0, 3, 1, status);
if (err) {
/*
* If the host or the card can't do the switch,
* fail more gracefully.
*/
if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
goto out;

printk(KERN_WARNING "%s: problem reading "
"Current Limit.\n",
mmc_hostname(card->host));
err = 0;

goto out;
}

card->sw_caps.sd3_curr_limit = status[7];
} else {
if (status[13] & 0x02)
card->sw_caps.hs_max_dtr = 50000000;
}

out:
kfree(status);
Expand Down
4 changes: 4 additions & 0 deletions include/linux/mmc/card.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ struct mmc_ext_csd {

struct sd_scr {
unsigned char sda_vsn;
unsigned char sda_spec3;
unsigned char bus_widths;
#define SD_SCR_BUS_WIDTH_1 (1<<0)
#define SD_SCR_BUS_WIDTH_4 (1<<2)
Expand All @@ -80,6 +81,9 @@ struct sd_ssr {

struct sd_switch_caps {
unsigned int hs_max_dtr;
unsigned int sd3_bus_mode;
unsigned int sd3_drv_type;
unsigned int sd3_curr_limit;
};

struct sdio_cccr {
Expand Down

0 comments on commit 013909c

Please sign in to comment.