|
@@ -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);
|