diff options
author | Ulf Hansson <ulf.hansson@linaro.org> | 2013-09-16 05:28:42 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2013-10-30 20:26:30 -0400 |
commit | ce69d37b7d8fa692c45d71d94aa0c921859b82ce (patch) | |
tree | aef1e93b62424f07b72ddd322a64e6435b27d932 | |
parent | 6904115095ad60ced638eb1e36e0e4e5e7de00b0 (diff) |
mmc: core: Prevent violation of specs while initializing cards
According to eMMC/SD/SDIO specs, the VDD (VCC) voltage level must be
maintained during the initialization sequence. If we want/need to tune
the voltage level, a complete power cycle of the card must be executed.
Most host drivers conforms to the specifications by only allowing to
change VDD voltage level at the MMC_POWER_UP state, but some also cares
about MMC_POWER_ON state, which they should'nt. This patch will not
break those drivers, but they could clean up code to better reflect
what is expected from the protocol layer.
A big re-work of the mmc_select_voltage function is done to only change
VDD voltage level if the host supports MMC_CAP2_FULL_PWR_CYCLE.
Otherwise only validation of the host and card ocr mask will be done.
A very nice side-effect of this patch is that we now don't need to
reset the negotiated ocr mask at the mmc_power_off function, since now
it will actually reflect the present voltage level, which safely can be
used at the next power up and re-initialization. Moreover, we then only
need to execute mmc_select_voltage from the attach sequence.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r-- | drivers/mmc/core/core.c | 31 | ||||
-rw-r--r-- | drivers/mmc/core/mmc.c | 1 | ||||
-rw-r--r-- | drivers/mmc/core/sd.c | 1 | ||||
-rw-r--r-- | drivers/mmc/core/sdio.c | 17 |
4 files changed, 13 insertions, 37 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 529d2eff6095..63672aba0e98 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -1358,21 +1358,20 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) | |||
1358 | int bit; | 1358 | int bit; |
1359 | 1359 | ||
1360 | ocr &= host->ocr_avail; | 1360 | ocr &= host->ocr_avail; |
1361 | if (!ocr) { | ||
1362 | dev_warn(mmc_dev(host), "no support for card's volts\n"); | ||
1363 | return 0; | ||
1364 | } | ||
1361 | 1365 | ||
1362 | bit = ffs(ocr); | 1366 | if (host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) { |
1363 | if (bit) { | 1367 | bit = ffs(ocr) - 1; |
1364 | bit -= 1; | ||
1365 | |||
1366 | ocr &= 3 << bit; | 1368 | ocr &= 3 << bit; |
1367 | 1369 | mmc_power_cycle(host, ocr); | |
1368 | mmc_host_clk_hold(host); | ||
1369 | host->ios.vdd = bit; | ||
1370 | mmc_set_ios(host); | ||
1371 | mmc_host_clk_release(host); | ||
1372 | } else { | 1370 | } else { |
1373 | pr_warning("%s: host doesn't support card's voltages\n", | 1371 | bit = fls(ocr) - 1; |
1374 | mmc_hostname(host)); | 1372 | ocr &= 3 << bit; |
1375 | ocr = 0; | 1373 | if (bit != host->ios.vdd) |
1374 | dev_warn(mmc_dev(host), "exceeding card's volts\n"); | ||
1376 | } | 1375 | } |
1377 | 1376 | ||
1378 | return ocr; | 1377 | return ocr; |
@@ -1571,14 +1570,6 @@ void mmc_power_off(struct mmc_host *host) | |||
1571 | host->ios.clock = 0; | 1570 | host->ios.clock = 0; |
1572 | host->ios.vdd = 0; | 1571 | host->ios.vdd = 0; |
1573 | 1572 | ||
1574 | |||
1575 | /* | ||
1576 | * Reset ocr mask to be the highest possible voltage supported for | ||
1577 | * this card. This value will be used at next power up. | ||
1578 | */ | ||
1579 | if (host->card) | ||
1580 | host->card->ocr = 1 << (fls(host->ocr_avail) - 1); | ||
1581 | |||
1582 | if (!mmc_host_is_spi(host)) { | 1573 | if (!mmc_host_is_spi(host)) { |
1583 | host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; | 1574 | host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; |
1584 | host->ios.chip_select = MMC_CS_DONTCARE; | 1575 | host->ios.chip_select = MMC_CS_DONTCARE; |
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index eb7161c11587..18ce81a85c9b 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c | |||
@@ -1535,7 +1535,6 @@ static int mmc_resume(struct mmc_host *host) | |||
1535 | 1535 | ||
1536 | mmc_claim_host(host); | 1536 | mmc_claim_host(host); |
1537 | mmc_power_up(host, host->card->ocr); | 1537 | mmc_power_up(host, host->card->ocr); |
1538 | mmc_select_voltage(host, host->card->ocr); | ||
1539 | err = mmc_init_card(host, host->card->ocr, host->card); | 1538 | err = mmc_init_card(host, host->card->ocr, host->card); |
1540 | mmc_release_host(host); | 1539 | mmc_release_host(host); |
1541 | 1540 | ||
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 398065c57edf..53db60a76dae 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c | |||
@@ -1103,7 +1103,6 @@ static int mmc_sd_resume(struct mmc_host *host) | |||
1103 | 1103 | ||
1104 | mmc_claim_host(host); | 1104 | mmc_claim_host(host); |
1105 | mmc_power_up(host, host->card->ocr); | 1105 | mmc_power_up(host, host->card->ocr); |
1106 | mmc_select_voltage(host, host->card->ocr); | ||
1107 | err = mmc_sd_init_card(host, host->card->ocr, host->card); | 1106 | err = mmc_sd_init_card(host, host->card->ocr, host->card); |
1108 | mmc_release_host(host); | 1107 | mmc_release_host(host); |
1109 | 1108 | ||
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index e0a135a635f5..b7c19e894dd3 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c | |||
@@ -987,7 +987,6 @@ static int mmc_sdio_resume(struct mmc_host *host) | |||
987 | /* Restore power if needed */ | 987 | /* Restore power if needed */ |
988 | if (!mmc_card_keep_power(host)) { | 988 | if (!mmc_card_keep_power(host)) { |
989 | mmc_power_up(host, host->card->ocr); | 989 | mmc_power_up(host, host->card->ocr); |
990 | mmc_select_voltage(host, host->card->ocr); | ||
991 | /* | 990 | /* |
992 | * Tell runtime PM core we just powered up the card, | 991 | * Tell runtime PM core we just powered up the card, |
993 | * since it still believes the card is powered off. | 992 | * since it still believes the card is powered off. |
@@ -1045,7 +1044,6 @@ static int mmc_sdio_resume(struct mmc_host *host) | |||
1045 | static int mmc_sdio_power_restore(struct mmc_host *host) | 1044 | static int mmc_sdio_power_restore(struct mmc_host *host) |
1046 | { | 1045 | { |
1047 | int ret; | 1046 | int ret; |
1048 | u32 ocr, rocr; | ||
1049 | 1047 | ||
1050 | BUG_ON(!host); | 1048 | BUG_ON(!host); |
1051 | BUG_ON(!host->card); | 1049 | BUG_ON(!host->card); |
@@ -1067,28 +1065,17 @@ static int mmc_sdio_power_restore(struct mmc_host *host) | |||
1067 | * for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and | 1065 | * for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and |
1068 | * harmless in other situations. | 1066 | * harmless in other situations. |
1069 | * | 1067 | * |
1070 | * With these steps taken, mmc_select_voltage() is also required to | ||
1071 | * restore the correct voltage setting of the card. | ||
1072 | */ | 1068 | */ |
1073 | 1069 | ||
1074 | sdio_reset(host); | 1070 | sdio_reset(host); |
1075 | mmc_go_idle(host); | 1071 | mmc_go_idle(host); |
1076 | mmc_send_if_cond(host, host->ocr_avail); | 1072 | mmc_send_if_cond(host, host->ocr_avail); |
1077 | 1073 | ||
1078 | ret = mmc_send_io_op_cond(host, 0, &ocr); | 1074 | ret = mmc_send_io_op_cond(host, 0, NULL); |
1079 | if (ret) | 1075 | if (ret) |
1080 | goto out; | 1076 | goto out; |
1081 | 1077 | ||
1082 | if (host->ocr_avail_sdio) | 1078 | ret = mmc_sdio_init_card(host, host->card->ocr, host->card, |
1083 | host->ocr_avail = host->ocr_avail_sdio; | ||
1084 | |||
1085 | rocr = mmc_select_voltage(host, ocr & ~0x7F); | ||
1086 | if (!rocr) { | ||
1087 | ret = -EINVAL; | ||
1088 | goto out; | ||
1089 | } | ||
1090 | |||
1091 | ret = mmc_sdio_init_card(host, rocr, host->card, | ||
1092 | mmc_card_keep_power(host)); | 1079 | mmc_card_keep_power(host)); |
1093 | if (!ret && host->sdio_irqs) | 1080 | if (!ret && host->sdio_irqs) |
1094 | mmc_signal_sdio_irq(host); | 1081 | mmc_signal_sdio_irq(host); |