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

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
Loading
Loading
Loading
Loading
+50 −24
Original line number Diff line number Diff line
@@ -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_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 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
		(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 @@ static struct device_type mmc_type = {
 * 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 @@ static int mmc_select_powerclass(struct mmc_card *card,
	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 @@ static int mmc_select_powerclass(struct mmc_card *card,
	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 @@ static int mmc_select_powerclass(struct mmc_card *card,
	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 @@ static int mmc_select_powerclass(struct mmc_card *card,
		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 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,

		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 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
			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 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
		}

		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",
+9 −1
Original line number Diff line number Diff line
@@ -94,6 +94,10 @@ struct mmc_ext_csd {
	u8			raw_ext_csd_structure;	/* 194 */
	u8			raw_card_type;		/* 196 */
	u8			out_of_int_time;	/* 198 */
	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_erase_timeout_mult;	/* 223 */
@@ -102,6 +106,10 @@ struct mmc_ext_csd {
	u8			raw_sec_erase_mult;	/* 230 */
	u8			raw_sec_feature_support;/* 231 */
	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_sectors[4];		/* 212 - 4 bytes */