diff options
| author | Fredrik Soderstedt <fredrik.soderstedt@stericsson.com> | 2013-04-23 10:27:07 -0400 |
|---|---|---|
| committer | Chris Ball <cjb@laptop.org> | 2013-05-26 14:23:18 -0400 |
| commit | 60443712195bbcbbff9af189bdd9d2c1ef0a5cae (patch) | |
| tree | 8556da51a7cc4f852f49cca47dff38bec7bee1a6 | |
| parent | 07a682160866e302d696f5c76d74024d575fb79d (diff) | |
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>
| -rw-r--r-- | drivers/mmc/core/mmc.c | 74 | ||||
| -rw-r--r-- | include/linux/mmc/card.h | 10 |
2 files changed, 59 insertions, 25 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index dd6810eebd3f..3a69b947130b 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c | |||
| @@ -461,6 +461,24 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) | |||
| 461 | */ | 461 | */ |
| 462 | card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP]; | 462 | card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP]; |
| 463 | card->ext_csd.boot_ro_lockable = true; | 463 | card->ext_csd.boot_ro_lockable = true; |
| 464 | |||
| 465 | /* Save power class values */ | ||
| 466 | card->ext_csd.raw_pwr_cl_52_195 = | ||
| 467 | ext_csd[EXT_CSD_PWR_CL_52_195]; | ||
| 468 | card->ext_csd.raw_pwr_cl_26_195 = | ||
| 469 | ext_csd[EXT_CSD_PWR_CL_26_195]; | ||
| 470 | card->ext_csd.raw_pwr_cl_52_360 = | ||
| 471 | ext_csd[EXT_CSD_PWR_CL_52_360]; | ||
| 472 | card->ext_csd.raw_pwr_cl_26_360 = | ||
| 473 | ext_csd[EXT_CSD_PWR_CL_26_360]; | ||
| 474 | card->ext_csd.raw_pwr_cl_200_195 = | ||
| 475 | ext_csd[EXT_CSD_PWR_CL_200_195]; | ||
| 476 | card->ext_csd.raw_pwr_cl_200_360 = | ||
| 477 | ext_csd[EXT_CSD_PWR_CL_200_360]; | ||
| 478 | card->ext_csd.raw_pwr_cl_ddr_52_195 = | ||
| 479 | ext_csd[EXT_CSD_PWR_CL_DDR_52_195]; | ||
| 480 | card->ext_csd.raw_pwr_cl_ddr_52_360 = | ||
| 481 | ext_csd[EXT_CSD_PWR_CL_DDR_52_360]; | ||
| 464 | } | 482 | } |
| 465 | 483 | ||
| 466 | if (card->ext_csd.rev >= 5) { | 484 | if (card->ext_csd.rev >= 5) { |
| @@ -607,7 +625,23 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) | |||
| 607 | (card->ext_csd.raw_sectors[2] == | 625 | (card->ext_csd.raw_sectors[2] == |
| 608 | bw_ext_csd[EXT_CSD_SEC_CNT + 2]) && | 626 | bw_ext_csd[EXT_CSD_SEC_CNT + 2]) && |
| 609 | (card->ext_csd.raw_sectors[3] == | 627 | (card->ext_csd.raw_sectors[3] == |
| 610 | bw_ext_csd[EXT_CSD_SEC_CNT + 3])); | 628 | bw_ext_csd[EXT_CSD_SEC_CNT + 3]) && |
| 629 | (card->ext_csd.raw_pwr_cl_52_195 == | ||
| 630 | bw_ext_csd[EXT_CSD_PWR_CL_52_195]) && | ||
| 631 | (card->ext_csd.raw_pwr_cl_26_195 == | ||
| 632 | bw_ext_csd[EXT_CSD_PWR_CL_26_195]) && | ||
| 633 | (card->ext_csd.raw_pwr_cl_52_360 == | ||
| 634 | bw_ext_csd[EXT_CSD_PWR_CL_52_360]) && | ||
| 635 | (card->ext_csd.raw_pwr_cl_26_360 == | ||
| 636 | bw_ext_csd[EXT_CSD_PWR_CL_26_360]) && | ||
| 637 | (card->ext_csd.raw_pwr_cl_200_195 == | ||
| 638 | bw_ext_csd[EXT_CSD_PWR_CL_200_195]) && | ||
| 639 | (card->ext_csd.raw_pwr_cl_200_360 == | ||
| 640 | bw_ext_csd[EXT_CSD_PWR_CL_200_360]) && | ||
| 641 | (card->ext_csd.raw_pwr_cl_ddr_52_195 == | ||
| 642 | bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) && | ||
| 643 | (card->ext_csd.raw_pwr_cl_ddr_52_360 == | ||
| 644 | bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360])); | ||
| 611 | if (err) | 645 | if (err) |
| 612 | err = -EINVAL; | 646 | err = -EINVAL; |
| 613 | 647 | ||
| @@ -676,11 +710,10 @@ static struct device_type mmc_type = { | |||
| 676 | * mmc_switch command. | 710 | * mmc_switch command. |
| 677 | */ | 711 | */ |
| 678 | static int mmc_select_powerclass(struct mmc_card *card, | 712 | static int mmc_select_powerclass(struct mmc_card *card, |
| 679 | unsigned int bus_width, u8 *ext_csd) | 713 | unsigned int bus_width) |
| 680 | { | 714 | { |
| 681 | int err = 0; | 715 | int err = 0; |
| 682 | unsigned int pwrclass_val; | 716 | unsigned int pwrclass_val = 0; |
| 683 | unsigned int index = 0; | ||
| 684 | struct mmc_host *host; | 717 | struct mmc_host *host; |
| 685 | 718 | ||
| 686 | BUG_ON(!card); | 719 | BUG_ON(!card); |
| @@ -688,9 +721,6 @@ static int mmc_select_powerclass(struct mmc_card *card, | |||
| 688 | host = card->host; | 721 | host = card->host; |
| 689 | BUG_ON(!host); | 722 | BUG_ON(!host); |
| 690 | 723 | ||
| 691 | if (ext_csd == NULL) | ||
| 692 | return 0; | ||
| 693 | |||
| 694 | /* Power class selection is supported for versions >= 4.0 */ | 724 | /* Power class selection is supported for versions >= 4.0 */ |
| 695 | if (card->csd.mmca_vsn < CSD_SPEC_VER_4) | 725 | if (card->csd.mmca_vsn < CSD_SPEC_VER_4) |
| 696 | return 0; | 726 | return 0; |
| @@ -702,13 +732,13 @@ static int mmc_select_powerclass(struct mmc_card *card, | |||
| 702 | switch (1 << host->ios.vdd) { | 732 | switch (1 << host->ios.vdd) { |
| 703 | case MMC_VDD_165_195: | 733 | case MMC_VDD_165_195: |
| 704 | if (host->ios.clock <= 26000000) | 734 | if (host->ios.clock <= 26000000) |
| 705 | index = EXT_CSD_PWR_CL_26_195; | 735 | pwrclass_val = card->ext_csd.raw_pwr_cl_26_195; |
| 706 | else if (host->ios.clock <= 52000000) | 736 | else if (host->ios.clock <= 52000000) |
| 707 | index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ? | 737 | pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ? |
| 708 | EXT_CSD_PWR_CL_52_195 : | 738 | card->ext_csd.raw_pwr_cl_52_195 : |
| 709 | EXT_CSD_PWR_CL_DDR_52_195; | 739 | card->ext_csd.raw_pwr_cl_ddr_52_195; |
| 710 | else if (host->ios.clock <= 200000000) | 740 | else if (host->ios.clock <= 200000000) |
| 711 | index = EXT_CSD_PWR_CL_200_195; | 741 | pwrclass_val = card->ext_csd.raw_pwr_cl_200_195; |
| 712 | break; | 742 | break; |
| 713 | case MMC_VDD_27_28: | 743 | case MMC_VDD_27_28: |
| 714 | case MMC_VDD_28_29: | 744 | case MMC_VDD_28_29: |
| @@ -720,13 +750,13 @@ static int mmc_select_powerclass(struct mmc_card *card, | |||
| 720 | case MMC_VDD_34_35: | 750 | case MMC_VDD_34_35: |
| 721 | case MMC_VDD_35_36: | 751 | case MMC_VDD_35_36: |
| 722 | if (host->ios.clock <= 26000000) | 752 | if (host->ios.clock <= 26000000) |
| 723 | index = EXT_CSD_PWR_CL_26_360; | 753 | pwrclass_val = card->ext_csd.raw_pwr_cl_26_360; |
| 724 | else if (host->ios.clock <= 52000000) | 754 | else if (host->ios.clock <= 52000000) |
| 725 | index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ? | 755 | pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ? |
| 726 | EXT_CSD_PWR_CL_52_360 : | 756 | card->ext_csd.raw_pwr_cl_52_360 : |
| 727 | EXT_CSD_PWR_CL_DDR_52_360; | 757 | card->ext_csd.raw_pwr_cl_ddr_52_360; |
| 728 | else if (host->ios.clock <= 200000000) | 758 | else if (host->ios.clock <= 200000000) |
| 729 | index = EXT_CSD_PWR_CL_200_360; | 759 | pwrclass_val = card->ext_csd.raw_pwr_cl_200_360; |
| 730 | break; | 760 | break; |
| 731 | default: | 761 | default: |
| 732 | pr_warning("%s: Voltage range not supported " | 762 | pr_warning("%s: Voltage range not supported " |
| @@ -734,8 +764,6 @@ static int mmc_select_powerclass(struct mmc_card *card, | |||
| 734 | return -EINVAL; | 764 | return -EINVAL; |
| 735 | } | 765 | } |
| 736 | 766 | ||
| 737 | pwrclass_val = ext_csd[index]; | ||
| 738 | |||
| 739 | if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8)) | 767 | if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8)) |
| 740 | pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >> | 768 | pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >> |
| 741 | EXT_CSD_PWR_CL_8BIT_SHIFT; | 769 | EXT_CSD_PWR_CL_8BIT_SHIFT; |
| @@ -1131,7 +1159,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, | |||
| 1131 | 1159 | ||
| 1132 | ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ? | 1160 | ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ? |
| 1133 | EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4; | 1161 | EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4; |
| 1134 | err = mmc_select_powerclass(card, ext_csd_bits, ext_csd); | 1162 | err = mmc_select_powerclass(card, ext_csd_bits); |
| 1135 | if (err) | 1163 | if (err) |
| 1136 | pr_warning("%s: power class selection to bus width %d" | 1164 | pr_warning("%s: power class selection to bus width %d" |
| 1137 | " failed\n", mmc_hostname(card->host), | 1165 | " failed\n", mmc_hostname(card->host), |
| @@ -1164,8 +1192,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, | |||
| 1164 | bus_width = bus_widths[idx]; | 1192 | bus_width = bus_widths[idx]; |
| 1165 | if (bus_width == MMC_BUS_WIDTH_1) | 1193 | if (bus_width == MMC_BUS_WIDTH_1) |
| 1166 | ddr = 0; /* no DDR for 1-bit width */ | 1194 | ddr = 0; /* no DDR for 1-bit width */ |
| 1167 | err = mmc_select_powerclass(card, ext_csd_bits[idx][0], | 1195 | err = mmc_select_powerclass(card, ext_csd_bits[idx][0]); |
| 1168 | ext_csd); | ||
| 1169 | if (err) | 1196 | if (err) |
| 1170 | pr_warning("%s: power class selection to " | 1197 | pr_warning("%s: power class selection to " |
| 1171 | "bus width %d failed\n", | 1198 | "bus width %d failed\n", |
| @@ -1195,8 +1222,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, | |||
| 1195 | } | 1222 | } |
| 1196 | 1223 | ||
| 1197 | if (!err && ddr) { | 1224 | if (!err && ddr) { |
| 1198 | err = mmc_select_powerclass(card, ext_csd_bits[idx][1], | 1225 | err = mmc_select_powerclass(card, ext_csd_bits[idx][1]); |
| 1199 | ext_csd); | ||
| 1200 | if (err) | 1226 | if (err) |
| 1201 | pr_warning("%s: power class selection to " | 1227 | pr_warning("%s: power class selection to " |
| 1202 | "bus width %d ddr %d failed\n", | 1228 | "bus width %d ddr %d failed\n", |
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index f31725ba49f3..6a98f32670b8 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h | |||
| @@ -94,7 +94,11 @@ struct mmc_ext_csd { | |||
| 94 | u8 raw_ext_csd_structure; /* 194 */ | 94 | u8 raw_ext_csd_structure; /* 194 */ |
| 95 | u8 raw_card_type; /* 196 */ | 95 | u8 raw_card_type; /* 196 */ |
| 96 | u8 out_of_int_time; /* 198 */ | 96 | u8 out_of_int_time; /* 198 */ |
| 97 | u8 raw_s_a_timeout; /* 217 */ | 97 | u8 raw_pwr_cl_52_195; /* 200 */ |
| 98 | u8 raw_pwr_cl_26_195; /* 201 */ | ||
| 99 | u8 raw_pwr_cl_52_360; /* 202 */ | ||
| 100 | u8 raw_pwr_cl_26_360; /* 203 */ | ||
| 101 | u8 raw_s_a_timeout; /* 217 */ | ||
| 98 | u8 raw_hc_erase_gap_size; /* 221 */ | 102 | u8 raw_hc_erase_gap_size; /* 221 */ |
| 99 | u8 raw_erase_timeout_mult; /* 223 */ | 103 | u8 raw_erase_timeout_mult; /* 223 */ |
| 100 | u8 raw_hc_erase_grp_size; /* 224 */ | 104 | u8 raw_hc_erase_grp_size; /* 224 */ |
| @@ -102,6 +106,10 @@ struct mmc_ext_csd { | |||
| 102 | u8 raw_sec_erase_mult; /* 230 */ | 106 | u8 raw_sec_erase_mult; /* 230 */ |
| 103 | u8 raw_sec_feature_support;/* 231 */ | 107 | u8 raw_sec_feature_support;/* 231 */ |
| 104 | u8 raw_trim_mult; /* 232 */ | 108 | u8 raw_trim_mult; /* 232 */ |
| 109 | u8 raw_pwr_cl_200_195; /* 236 */ | ||
| 110 | u8 raw_pwr_cl_200_360; /* 237 */ | ||
| 111 | u8 raw_pwr_cl_ddr_52_195; /* 238 */ | ||
| 112 | u8 raw_pwr_cl_ddr_52_360; /* 239 */ | ||
| 105 | u8 raw_bkops_status; /* 246 */ | 113 | u8 raw_bkops_status; /* 246 */ |
| 106 | u8 raw_sectors[4]; /* 212 - 4 bytes */ | 114 | u8 raw_sectors[4]; /* 212 - 4 bytes */ |
| 107 | 115 | ||
