aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorArindam Nath <arindam.nath@amd.com>2011-05-05 02:49:01 -0400
committerChris Ball <cjb@laptop.org>2011-05-24 23:53:45 -0400
commit49c468fcf878d2c86e31920cf54aa90c88418a66 (patch)
treed8088bf8fb1a011f05ebbdefef49f2a6f4739432 /drivers/mmc
parent758535c4e3cdd2b5b09565d9651aaa541aac3de8 (diff)
mmc: sd: add support for uhs bus speed mode selection
This patch adds support for setting UHS-I bus speed mode during UHS-I initialization procedure. Since both the host and card can support more than one bus speed, we select the highest speed based on both of their capabilities. First we set the bus speed mode for the card using CMD6 mode 1, and then we program the host controller to support the required speed mode. We also set High Speed Enable in case one of the UHS-I modes is selected. We take care to reset SD clock before setting UHS mode in the Host Control2 register, and then re-enable it as per the Host Controller spec v3.00. We then set the clock frequency for the UHS-I mode selected. 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.c65
-rw-r--r--drivers/mmc/host/sdhci.c40
-rw-r--r--drivers/mmc/host/sdhci.h6
3 files changed, 108 insertions, 3 deletions
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 5b7c99855635..6970b82171f7 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -452,6 +452,66 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status)
452 return 0; 452 return 0;
453} 453}
454 454
455static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
456{
457 unsigned int bus_speed = 0, timing = 0;
458 int err;
459
460 /*
461 * If the host doesn't support any of the UHS-I modes, fallback on
462 * default speed.
463 */
464 if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
465 MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50)))
466 return 0;
467
468 if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
469 (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) {
470 bus_speed = UHS_SDR104_BUS_SPEED;
471 timing = MMC_TIMING_UHS_SDR104;
472 card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
473 } else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
474 (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
475 bus_speed = UHS_DDR50_BUS_SPEED;
476 timing = MMC_TIMING_UHS_DDR50;
477 card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
478 } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
479 MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
480 SD_MODE_UHS_SDR50)) {
481 bus_speed = UHS_SDR50_BUS_SPEED;
482 timing = MMC_TIMING_UHS_SDR50;
483 card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
484 } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
485 MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
486 (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
487 bus_speed = UHS_SDR25_BUS_SPEED;
488 timing = MMC_TIMING_UHS_SDR25;
489 card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
490 } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
491 MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
492 MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
493 SD_MODE_UHS_SDR12)) {
494 bus_speed = UHS_SDR12_BUS_SPEED;
495 timing = MMC_TIMING_UHS_SDR12;
496 card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
497 }
498
499 card->sd_bus_speed = bus_speed;
500 err = mmc_sd_switch(card, 1, 0, bus_speed, status);
501 if (err)
502 return err;
503
504 if ((status[16] & 0xF) != bus_speed)
505 printk(KERN_WARNING "%s: Problem setting bus speed mode!\n",
506 mmc_hostname(card->host));
507 else {
508 mmc_set_timing(card->host, timing);
509 mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
510 }
511
512 return 0;
513}
514
455/* 515/*
456 * UHS-I specific initialization procedure 516 * UHS-I specific initialization procedure
457 */ 517 */
@@ -485,6 +545,11 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
485 545
486 /* Set the driver strength for the card */ 546 /* Set the driver strength for the card */
487 err = sd_select_driver_type(card, status); 547 err = sd_select_driver_type(card, status);
548 if (err)
549 goto out;
550
551 /* Set bus speed mode of the card */
552 err = sd_set_bus_speed_mode(card, status);
488 553
489out: 554out:
490 kfree(status); 555 kfree(status);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 409cde5970ae..8994493dd940 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1244,7 +1244,16 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1244 ctrl &= ~SDHCI_CTRL_HISPD; 1244 ctrl &= ~SDHCI_CTRL_HISPD;
1245 1245
1246 if (host->version >= SDHCI_SPEC_300) { 1246 if (host->version >= SDHCI_SPEC_300) {
1247 u16 ctrl_2; 1247 u16 clk, ctrl_2;
1248 unsigned int clock;
1249
1250 /* In case of UHS-I modes, set High Speed Enable */
1251 if ((ios->timing == MMC_TIMING_UHS_SDR50) ||
1252 (ios->timing == MMC_TIMING_UHS_SDR104) ||
1253 (ios->timing == MMC_TIMING_UHS_DDR50) ||
1254 (ios->timing == MMC_TIMING_UHS_SDR25) ||
1255 (ios->timing == MMC_TIMING_UHS_SDR12))
1256 ctrl |= SDHCI_CTRL_HISPD;
1248 1257
1249 ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); 1258 ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
1250 if (!(ctrl_2 & SDHCI_CTRL_PRESET_VAL_ENABLE)) { 1259 if (!(ctrl_2 & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
@@ -1267,8 +1276,6 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1267 * need to reset SD Clock Enable before changing High 1276 * need to reset SD Clock Enable before changing High
1268 * Speed Enable to avoid generating clock gliches. 1277 * Speed Enable to avoid generating clock gliches.
1269 */ 1278 */
1270 u16 clk;
1271 unsigned int clock;
1272 1279
1273 /* Reset SD Clock Enable */ 1280 /* Reset SD Clock Enable */
1274 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 1281 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
@@ -1282,6 +1289,33 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1282 host->clock = 0; 1289 host->clock = 0;
1283 sdhci_set_clock(host, clock); 1290 sdhci_set_clock(host, clock);
1284 } 1291 }
1292
1293 ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
1294
1295 /* Select Bus Speed Mode for host */
1296 ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
1297 if (ios->timing == MMC_TIMING_UHS_SDR12)
1298 ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
1299 else if (ios->timing == MMC_TIMING_UHS_SDR25)
1300 ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
1301 else if (ios->timing == MMC_TIMING_UHS_SDR50)
1302 ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
1303 else if (ios->timing == MMC_TIMING_UHS_SDR104)
1304 ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
1305 else if (ios->timing == MMC_TIMING_UHS_DDR50)
1306 ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
1307
1308 /* Reset SD Clock Enable */
1309 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
1310 clk &= ~SDHCI_CLOCK_CARD_EN;
1311 sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
1312
1313 sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
1314
1315 /* Re-enable SD Clock */
1316 clock = host->clock;
1317 host->clock = 0;
1318 sdhci_set_clock(host, clock);
1285 } else 1319 } else
1286 sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); 1320 sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
1287 1321
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 667bf8874be7..d96f6afcca1f 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -149,6 +149,12 @@
149#define SDHCI_ACMD12_ERR 0x3C 149#define SDHCI_ACMD12_ERR 0x3C
150 150
151#define SDHCI_HOST_CONTROL2 0x3E 151#define SDHCI_HOST_CONTROL2 0x3E
152#define SDHCI_CTRL_UHS_MASK 0x0007
153#define SDHCI_CTRL_UHS_SDR12 0x0000
154#define SDHCI_CTRL_UHS_SDR25 0x0001
155#define SDHCI_CTRL_UHS_SDR50 0x0002
156#define SDHCI_CTRL_UHS_SDR104 0x0003
157#define SDHCI_CTRL_UHS_DDR50 0x0004
152#define SDHCI_CTRL_VDD_180 0x0008 158#define SDHCI_CTRL_VDD_180 0x0008
153#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030 159#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030
154#define SDHCI_CTRL_DRV_TYPE_B 0x0000 160#define SDHCI_CTRL_DRV_TYPE_B 0x0000