|
@@ -452,6 +452,66 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
|
|
|
+{
|
|
|
+ unsigned int bus_speed = 0, timing = 0;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If the host doesn't support any of the UHS-I modes, fallback on
|
|
|
+ * default speed.
|
|
|
+ */
|
|
|
+ if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
|
|
|
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50)))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
|
|
|
+ (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) {
|
|
|
+ bus_speed = UHS_SDR104_BUS_SPEED;
|
|
|
+ timing = MMC_TIMING_UHS_SDR104;
|
|
|
+ card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
|
|
|
+ } else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
|
|
|
+ (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
|
|
|
+ bus_speed = UHS_DDR50_BUS_SPEED;
|
|
|
+ timing = MMC_TIMING_UHS_DDR50;
|
|
|
+ card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
|
|
|
+ } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
|
|
|
+ MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
|
|
|
+ SD_MODE_UHS_SDR50)) {
|
|
|
+ bus_speed = UHS_SDR50_BUS_SPEED;
|
|
|
+ timing = MMC_TIMING_UHS_SDR50;
|
|
|
+ card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
|
|
|
+ } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
|
|
|
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
|
|
|
+ (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
|
|
|
+ bus_speed = UHS_SDR25_BUS_SPEED;
|
|
|
+ timing = MMC_TIMING_UHS_SDR25;
|
|
|
+ card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
|
|
|
+ } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
|
|
|
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
|
|
|
+ MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
|
|
|
+ SD_MODE_UHS_SDR12)) {
|
|
|
+ bus_speed = UHS_SDR12_BUS_SPEED;
|
|
|
+ timing = MMC_TIMING_UHS_SDR12;
|
|
|
+ card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
|
|
|
+ }
|
|
|
+
|
|
|
+ card->sd_bus_speed = bus_speed;
|
|
|
+ err = mmc_sd_switch(card, 1, 0, bus_speed, status);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ if ((status[16] & 0xF) != bus_speed)
|
|
|
+ printk(KERN_WARNING "%s: Problem setting bus speed mode!\n",
|
|
|
+ mmc_hostname(card->host));
|
|
|
+ else {
|
|
|
+ mmc_set_timing(card->host, timing);
|
|
|
+ mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* UHS-I specific initialization procedure
|
|
|
*/
|
|
@@ -485,6 +545,11 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
|
|
|
|
|
|
/* Set the driver strength for the card */
|
|
|
err = sd_select_driver_type(card, status);
|
|
|
+ if (err)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ /* Set bus speed mode of the card */
|
|
|
+ err = sd_set_bus_speed_mode(card, status);
|
|
|
|
|
|
out:
|
|
|
kfree(status);
|