Commit 60443712 authored by Fredrik Soderstedt's avatar Fredrik Soderstedt Committed by Chris Ball

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: default avatarFredrik Soderstedt <fredrik.soderstedt@stericsson.com>
Reviewed-by: default avatarJohan Rudholm <jrudholm@gmail.com>
Acked By: Girish K S <girish.shivananjappa@linaro.org>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent 07a68216
...@@ -461,6 +461,24 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) ...@@ -461,6 +461,24 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
*/ */
card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP]; card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP];
card->ext_csd.boot_ro_lockable = true; 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) { if (card->ext_csd.rev >= 5) {
...@@ -607,7 +625,23 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) ...@@ -607,7 +625,23 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
(card->ext_csd.raw_sectors[2] == (card->ext_csd.raw_sectors[2] ==
bw_ext_csd[EXT_CSD_SEC_CNT + 2]) && bw_ext_csd[EXT_CSD_SEC_CNT + 2]) &&
(card->ext_csd.raw_sectors[3] == (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) if (err)
err = -EINVAL; err = -EINVAL;
...@@ -676,11 +710,10 @@ static struct device_type mmc_type = { ...@@ -676,11 +710,10 @@ static struct device_type mmc_type = {
* mmc_switch command. * mmc_switch command.
*/ */
static int mmc_select_powerclass(struct mmc_card *card, static int mmc_select_powerclass(struct mmc_card *card,
unsigned int bus_width, u8 *ext_csd) unsigned int bus_width)
{ {
int err = 0; int err = 0;
unsigned int pwrclass_val; unsigned int pwrclass_val = 0;
unsigned int index = 0;
struct mmc_host *host; struct mmc_host *host;
BUG_ON(!card); BUG_ON(!card);
...@@ -688,9 +721,6 @@ static int mmc_select_powerclass(struct mmc_card *card, ...@@ -688,9 +721,6 @@ static int mmc_select_powerclass(struct mmc_card *card,
host = card->host; host = card->host;
BUG_ON(!host); BUG_ON(!host);
if (ext_csd == NULL)
return 0;
/* Power class selection is supported for versions >= 4.0 */ /* Power class selection is supported for versions >= 4.0 */
if (card->csd.mmca_vsn < CSD_SPEC_VER_4) if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
return 0; return 0;
...@@ -702,13 +732,13 @@ static int mmc_select_powerclass(struct mmc_card *card, ...@@ -702,13 +732,13 @@ static int mmc_select_powerclass(struct mmc_card *card,
switch (1 << host->ios.vdd) { switch (1 << host->ios.vdd) {
case MMC_VDD_165_195: case MMC_VDD_165_195:
if (host->ios.clock <= 26000000) 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) else if (host->ios.clock <= 52000000)
index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ? pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
EXT_CSD_PWR_CL_52_195 : card->ext_csd.raw_pwr_cl_52_195 :
EXT_CSD_PWR_CL_DDR_52_195; card->ext_csd.raw_pwr_cl_ddr_52_195;
else if (host->ios.clock <= 200000000) else if (host->ios.clock <= 200000000)
index = EXT_CSD_PWR_CL_200_195; pwrclass_val = card->ext_csd.raw_pwr_cl_200_195;
break; break;
case MMC_VDD_27_28: case MMC_VDD_27_28:
case MMC_VDD_28_29: case MMC_VDD_28_29:
...@@ -720,13 +750,13 @@ static int mmc_select_powerclass(struct mmc_card *card, ...@@ -720,13 +750,13 @@ static int mmc_select_powerclass(struct mmc_card *card,
case MMC_VDD_34_35: case MMC_VDD_34_35:
case MMC_VDD_35_36: case MMC_VDD_35_36:
if (host->ios.clock <= 26000000) 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) else if (host->ios.clock <= 52000000)
index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ? pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
EXT_CSD_PWR_CL_52_360 : card->ext_csd.raw_pwr_cl_52_360 :
EXT_CSD_PWR_CL_DDR_52_360; card->ext_csd.raw_pwr_cl_ddr_52_360;
else if (host->ios.clock <= 200000000) else if (host->ios.clock <= 200000000)
index = EXT_CSD_PWR_CL_200_360; pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
break; break;
default: default:
pr_warning("%s: Voltage range not supported " pr_warning("%s: Voltage range not supported "
...@@ -734,8 +764,6 @@ static int mmc_select_powerclass(struct mmc_card *card, ...@@ -734,8 +764,6 @@ static int mmc_select_powerclass(struct mmc_card *card,
return -EINVAL; return -EINVAL;
} }
pwrclass_val = ext_csd[index];
if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8)) if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8))
pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >> pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >>
EXT_CSD_PWR_CL_8BIT_SHIFT; EXT_CSD_PWR_CL_8BIT_SHIFT;
...@@ -1131,7 +1159,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, ...@@ -1131,7 +1159,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ? ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4; 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) if (err)
pr_warning("%s: power class selection to bus width %d" pr_warning("%s: power class selection to bus width %d"
" failed\n", mmc_hostname(card->host), " failed\n", mmc_hostname(card->host),
...@@ -1164,8 +1192,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, ...@@ -1164,8 +1192,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
bus_width = bus_widths[idx]; bus_width = bus_widths[idx];
if (bus_width == MMC_BUS_WIDTH_1) if (bus_width == MMC_BUS_WIDTH_1)
ddr = 0; /* no DDR for 1-bit width */ ddr = 0; /* no DDR for 1-bit width */
err = mmc_select_powerclass(card, ext_csd_bits[idx][0], err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
ext_csd);
if (err) if (err)
pr_warning("%s: power class selection to " pr_warning("%s: power class selection to "
"bus width %d failed\n", "bus width %d failed\n",
...@@ -1195,8 +1222,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, ...@@ -1195,8 +1222,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
} }
if (!err && ddr) { if (!err && ddr) {
err = mmc_select_powerclass(card, ext_csd_bits[idx][1], err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
ext_csd);
if (err) if (err)
pr_warning("%s: power class selection to " pr_warning("%s: power class selection to "
"bus width %d ddr %d failed\n", "bus width %d ddr %d failed\n",
......
...@@ -94,7 +94,11 @@ struct mmc_ext_csd { ...@@ -94,7 +94,11 @@ struct mmc_ext_csd {
u8 raw_ext_csd_structure; /* 194 */ u8 raw_ext_csd_structure; /* 194 */
u8 raw_card_type; /* 196 */ u8 raw_card_type; /* 196 */
u8 out_of_int_time; /* 198 */ u8 out_of_int_time; /* 198 */
u8 raw_s_a_timeout; /* 217 */ u8 raw_pwr_cl_52_195; /* 200 */
u8 raw_pwr_cl_26_195; /* 201 */
u8 raw_pwr_cl_52_360; /* 202 */
u8 raw_pwr_cl_26_360; /* 203 */
u8 raw_s_a_timeout; /* 217 */
u8 raw_hc_erase_gap_size; /* 221 */ u8 raw_hc_erase_gap_size; /* 221 */
u8 raw_erase_timeout_mult; /* 223 */ u8 raw_erase_timeout_mult; /* 223 */
u8 raw_hc_erase_grp_size; /* 224 */ u8 raw_hc_erase_grp_size; /* 224 */
...@@ -102,6 +106,10 @@ struct mmc_ext_csd { ...@@ -102,6 +106,10 @@ struct mmc_ext_csd {
u8 raw_sec_erase_mult; /* 230 */ u8 raw_sec_erase_mult; /* 230 */
u8 raw_sec_feature_support;/* 231 */ u8 raw_sec_feature_support;/* 231 */
u8 raw_trim_mult; /* 232 */ u8 raw_trim_mult; /* 232 */
u8 raw_pwr_cl_200_195; /* 236 */
u8 raw_pwr_cl_200_360; /* 237 */
u8 raw_pwr_cl_ddr_52_195; /* 238 */
u8 raw_pwr_cl_ddr_52_360; /* 239 */
u8 raw_bkops_status; /* 246 */ u8 raw_bkops_status; /* 246 */
u8 raw_sectors[4]; /* 212 - 4 bytes */ u8 raw_sectors[4]; /* 212 - 4 bytes */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment