mmc: core: Fix select power class after resume
Use the saved values in card->ext_csd when selecting power class.
By doing this the power class will be selected even if mmc_init_card
is called with oldcard != NULL, which is the case after a suspend/resume.
Today ext_csd is NULL if mmc_init_card is called with oldcard != NULL
and power class will not be selected.
According to the eMMC specification the POWER_CLASS value is reset after
power failure, H/W reset assertion and any CMD0 reset.
Signed-off-by: Fredrik Soderstedt <fredrik.soderstedt@stericsson.com>
Reviewed-by: Johan Rudholm <jrudholm@gmail.com>
Acked By: Girish K S <girish.shivananjappa@linaro.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index dd6810e..3a69b94 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -461,6 +461,24 @@
*/
card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP];
card->ext_csd.boot_ro_lockable = true;
+
+ /* Save power class values */
+ card->ext_csd.raw_pwr_cl_52_195 =
+ ext_csd[EXT_CSD_PWR_CL_52_195];
+ card->ext_csd.raw_pwr_cl_26_195 =
+ ext_csd[EXT_CSD_PWR_CL_26_195];
+ card->ext_csd.raw_pwr_cl_52_360 =
+ ext_csd[EXT_CSD_PWR_CL_52_360];
+ card->ext_csd.raw_pwr_cl_26_360 =
+ ext_csd[EXT_CSD_PWR_CL_26_360];
+ card->ext_csd.raw_pwr_cl_200_195 =
+ ext_csd[EXT_CSD_PWR_CL_200_195];
+ card->ext_csd.raw_pwr_cl_200_360 =
+ ext_csd[EXT_CSD_PWR_CL_200_360];
+ card->ext_csd.raw_pwr_cl_ddr_52_195 =
+ ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
+ card->ext_csd.raw_pwr_cl_ddr_52_360 =
+ ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
}
if (card->ext_csd.rev >= 5) {
@@ -607,7 +625,23 @@
(card->ext_csd.raw_sectors[2] ==
bw_ext_csd[EXT_CSD_SEC_CNT + 2]) &&
(card->ext_csd.raw_sectors[3] ==
- bw_ext_csd[EXT_CSD_SEC_CNT + 3]));
+ bw_ext_csd[EXT_CSD_SEC_CNT + 3]) &&
+ (card->ext_csd.raw_pwr_cl_52_195 ==
+ bw_ext_csd[EXT_CSD_PWR_CL_52_195]) &&
+ (card->ext_csd.raw_pwr_cl_26_195 ==
+ bw_ext_csd[EXT_CSD_PWR_CL_26_195]) &&
+ (card->ext_csd.raw_pwr_cl_52_360 ==
+ bw_ext_csd[EXT_CSD_PWR_CL_52_360]) &&
+ (card->ext_csd.raw_pwr_cl_26_360 ==
+ bw_ext_csd[EXT_CSD_PWR_CL_26_360]) &&
+ (card->ext_csd.raw_pwr_cl_200_195 ==
+ bw_ext_csd[EXT_CSD_PWR_CL_200_195]) &&
+ (card->ext_csd.raw_pwr_cl_200_360 ==
+ bw_ext_csd[EXT_CSD_PWR_CL_200_360]) &&
+ (card->ext_csd.raw_pwr_cl_ddr_52_195 ==
+ bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
+ (card->ext_csd.raw_pwr_cl_ddr_52_360 ==
+ bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
if (err)
err = -EINVAL;
@@ -676,11 +710,10 @@
* mmc_switch command.
*/
static int mmc_select_powerclass(struct mmc_card *card,
- unsigned int bus_width, u8 *ext_csd)
+ unsigned int bus_width)
{
int err = 0;
- unsigned int pwrclass_val;
- unsigned int index = 0;
+ unsigned int pwrclass_val = 0;
struct mmc_host *host;
BUG_ON(!card);
@@ -688,9 +721,6 @@
host = card->host;
BUG_ON(!host);
- if (ext_csd == NULL)
- return 0;
-
/* Power class selection is supported for versions >= 4.0 */
if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
return 0;
@@ -702,13 +732,13 @@
switch (1 << host->ios.vdd) {
case MMC_VDD_165_195:
if (host->ios.clock <= 26000000)
- index = EXT_CSD_PWR_CL_26_195;
+ pwrclass_val = card->ext_csd.raw_pwr_cl_26_195;
else if (host->ios.clock <= 52000000)
- index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
- EXT_CSD_PWR_CL_52_195 :
- EXT_CSD_PWR_CL_DDR_52_195;
+ pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+ card->ext_csd.raw_pwr_cl_52_195 :
+ card->ext_csd.raw_pwr_cl_ddr_52_195;
else if (host->ios.clock <= 200000000)
- index = EXT_CSD_PWR_CL_200_195;
+ pwrclass_val = card->ext_csd.raw_pwr_cl_200_195;
break;
case MMC_VDD_27_28:
case MMC_VDD_28_29:
@@ -720,13 +750,13 @@
case MMC_VDD_34_35:
case MMC_VDD_35_36:
if (host->ios.clock <= 26000000)
- index = EXT_CSD_PWR_CL_26_360;
+ pwrclass_val = card->ext_csd.raw_pwr_cl_26_360;
else if (host->ios.clock <= 52000000)
- index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
- EXT_CSD_PWR_CL_52_360 :
- EXT_CSD_PWR_CL_DDR_52_360;
+ pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+ card->ext_csd.raw_pwr_cl_52_360 :
+ card->ext_csd.raw_pwr_cl_ddr_52_360;
else if (host->ios.clock <= 200000000)
- index = EXT_CSD_PWR_CL_200_360;
+ pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
break;
default:
pr_warning("%s: Voltage range not supported "
@@ -734,8 +764,6 @@
return -EINVAL;
}
- pwrclass_val = ext_csd[index];
-
if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8))
pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >>
EXT_CSD_PWR_CL_8BIT_SHIFT;
@@ -1131,7 +1159,7 @@
ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
- err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
+ err = mmc_select_powerclass(card, ext_csd_bits);
if (err)
pr_warning("%s: power class selection to bus width %d"
" failed\n", mmc_hostname(card->host),
@@ -1164,8 +1192,7 @@
bus_width = bus_widths[idx];
if (bus_width == MMC_BUS_WIDTH_1)
ddr = 0; /* no DDR for 1-bit width */
- err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
- ext_csd);
+ err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
if (err)
pr_warning("%s: power class selection to "
"bus width %d failed\n",
@@ -1195,8 +1222,7 @@
}
if (!err && ddr) {
- err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
- ext_csd);
+ err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
if (err)
pr_warning("%s: power class selection to "
"bus width %d ddr %d failed\n",