summaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorArindam Nath <arindam.nath@amd.com>2011-05-05 08:48:58 +0200
committerChris Ball <cjb@laptop.org>2011-05-25 03:04:40 +0200
commit013909c4ffd16ded4895528b856fd8782df04dc6 (patch)
treeb74fe0c34dfd3c2348497b1aa3a34f5132ca4822 /drivers/mmc
parentmmc: sd: add support for signal voltage switch procedure (diff)
downloadlinux-013909c4ffd16ded4895528b856fd8782df04dc6.tar.xz
linux-013909c4ffd16ded4895528b856fd8782df04dc6.zip
mmc: sd: query function modes for uhs cards
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>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/core/sd.c68
1 files changed, 58 insertions, 10 deletions
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index b0cd285d272a..8285842f19e9 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -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;
@@ -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);