diff options
Diffstat (limited to 'drivers/mmc/core/mmc.c')
| -rw-r--r-- | drivers/mmc/core/mmc.c | 113 | 
1 files changed, 58 insertions, 55 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index df19777068a6..b61b52f9da3d 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -618,6 +618,24 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)  			(ext_csd[EXT_CSD_SUPPORTED_MODE] & 0x1) &&  			!(ext_csd[EXT_CSD_FW_CONFIG] & 0x1);  	} + +	/* eMMC v5.1 or later */ +	if (card->ext_csd.rev >= 8) { +		card->ext_csd.cmdq_support = ext_csd[EXT_CSD_CMDQ_SUPPORT] & +					     EXT_CSD_CMDQ_SUPPORTED; +		card->ext_csd.cmdq_depth = (ext_csd[EXT_CSD_CMDQ_DEPTH] & +					    EXT_CSD_CMDQ_DEPTH_MASK) + 1; +		/* Exclude inefficiently small queue depths */ +		if (card->ext_csd.cmdq_depth <= 2) { +			card->ext_csd.cmdq_support = false; +			card->ext_csd.cmdq_depth = 0; +		} +		if (card->ext_csd.cmdq_support) { +			pr_debug("%s: Command Queue supported depth %u\n", +				 mmc_hostname(card->host), +				 card->ext_csd.cmdq_depth); +		} +	}  out:  	return err;  } @@ -1003,19 +1021,6 @@ static int mmc_select_bus_width(struct mmc_card *card)  	return err;  } -/* Caller must hold re-tuning */ -static int mmc_switch_status(struct mmc_card *card) -{ -	u32 status; -	int err; - -	err = mmc_send_status(card, &status); -	if (err) -		return err; - -	return mmc_switch_status_error(card->host, status); -} -  /*   * Switch to the high-speed mode   */ @@ -1025,13 +1030,8 @@ static int mmc_select_hs(struct mmc_card *card)  	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,  			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, -			   card->ext_csd.generic_cmd6_time, -			   true, false, true); -	if (!err) { -		mmc_set_timing(card->host, MMC_TIMING_MMC_HS); -		err = mmc_switch_status(card); -	} - +			   card->ext_csd.generic_cmd6_time, MMC_TIMING_MMC_HS, +			   true, true, true);  	if (err)  		pr_warn("%s: switch to high-speed failed, err:%d\n",  			mmc_hostname(card->host), err); @@ -1058,10 +1058,12 @@ static int mmc_select_hs_ddr(struct mmc_card *card)  	ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?  		EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4; -	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, -			EXT_CSD_BUS_WIDTH, -			ext_csd_bits, -			card->ext_csd.generic_cmd6_time); +	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, +			   EXT_CSD_BUS_WIDTH, +			   ext_csd_bits, +			   card->ext_csd.generic_cmd6_time, +			   MMC_TIMING_MMC_DDR52, +			   true, true, true);  	if (err) {  		pr_err("%s: switch to bus width %d ddr failed\n",  			mmc_hostname(host), 1 << bus_width); @@ -1104,9 +1106,6 @@ static int mmc_select_hs_ddr(struct mmc_card *card)  	if (err)  		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330); -	if (!err) -		mmc_set_timing(host, MMC_TIMING_MMC_DDR52); -  	return err;  } @@ -1128,7 +1127,7 @@ static int mmc_select_hs400(struct mmc_card *card)  	val = EXT_CSD_TIMING_HS;  	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,  			   EXT_CSD_HS_TIMING, val, -			   card->ext_csd.generic_cmd6_time, +			   card->ext_csd.generic_cmd6_time, 0,  			   true, false, true);  	if (err) {  		pr_err("%s: switch to high-speed from hs200 failed, err:%d\n", @@ -1163,7 +1162,7 @@ static int mmc_select_hs400(struct mmc_card *card)  	      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;  	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,  			   EXT_CSD_HS_TIMING, val, -			   card->ext_csd.generic_cmd6_time, +			   card->ext_csd.generic_cmd6_time, 0,  			   true, false, true);  	if (err) {  		pr_err("%s: switch to hs400 failed, err:%d\n", @@ -1206,7 +1205,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card)  	/* Switch HS400 to HS DDR */  	val = EXT_CSD_TIMING_HS;  	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, -			   val, card->ext_csd.generic_cmd6_time, +			   val, card->ext_csd.generic_cmd6_time, 0,  			   true, false, true);  	if (err)  		goto out_err; @@ -1220,7 +1219,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card)  	/* Switch HS DDR to HS */  	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,  			   EXT_CSD_BUS_WIDTH_8, card->ext_csd.generic_cmd6_time, -			   true, false, true); +			   0, true, false, true);  	if (err)  		goto out_err; @@ -1234,14 +1233,19 @@ int mmc_hs400_to_hs200(struct mmc_card *card)  	val = EXT_CSD_TIMING_HS200 |  	      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;  	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, -			   val, card->ext_csd.generic_cmd6_time, +			   val, card->ext_csd.generic_cmd6_time, 0,  			   true, false, true);  	if (err)  		goto out_err;  	mmc_set_timing(host, MMC_TIMING_MMC_HS200); -	err = mmc_switch_status(card); +	/* +	 * For HS200, CRC errors are not a reliable way to know the switch +	 * failed. If there really is a problem, we would expect tuning will +	 * fail and the result ends up the same. +	 */ +	err = __mmc_switch_status(card, false);  	if (err)  		goto out_err; @@ -1281,16 +1285,23 @@ static int mmc_select_hs400es(struct mmc_card *card)  		goto out_err;  	/* Switch card to HS mode */ -	err = mmc_select_hs(card); -	if (err) +	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, +			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, +			   card->ext_csd.generic_cmd6_time, 0, +			   true, false, true); +	if (err) { +		pr_err("%s: switch to hs for hs400es failed, err:%d\n", +			mmc_hostname(host), err);  		goto out_err; +	} -	mmc_set_clock(host, card->ext_csd.hs_max_dtr); - +	mmc_set_timing(host, MMC_TIMING_MMC_HS);  	err = mmc_switch_status(card);  	if (err)  		goto out_err; +	mmc_set_clock(host, card->ext_csd.hs_max_dtr); +  	/* Switch card to DDR with strobe bit */  	val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;  	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, @@ -1308,7 +1319,7 @@ static int mmc_select_hs400es(struct mmc_card *card)  	      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;  	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,  			   EXT_CSD_HS_TIMING, val, -			   card->ext_csd.generic_cmd6_time, +			   card->ext_csd.generic_cmd6_time, 0,  			   true, false, true);  	if (err) {  		pr_err("%s: switch to hs400es failed, err:%d\n", @@ -1390,14 +1401,20 @@ static int mmc_select_hs200(struct mmc_card *card)  		      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;  		err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,  				   EXT_CSD_HS_TIMING, val, -				   card->ext_csd.generic_cmd6_time, +				   card->ext_csd.generic_cmd6_time, 0,  				   true, false, true);  		if (err)  			goto err;  		old_timing = host->ios.timing;  		mmc_set_timing(host, MMC_TIMING_MMC_HS200); -		err = mmc_switch_status(card); +		/* +		 * For HS200, CRC errors are not a reliable way to know the +		 * switch failed. If there really is a problem, we would expect +		 * tuning will fail and the result ends up the same. +		 */ +		err = __mmc_switch_status(card, false); +  		/*  		 * mmc_select_timing() assumes timing has not changed if  		 * it is a switch error. @@ -1480,7 +1497,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,  	u32 cid[4];  	u32 rocr; -	BUG_ON(!host);  	WARN_ON(!host->claimed);  	/* Set correct bus mode for MMC before attempting init */ @@ -1854,7 +1870,7 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)  	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,  			EXT_CSD_POWER_OFF_NOTIFICATION, -			notify_type, timeout, true, false, false); +			notify_type, timeout, 0, true, false, false);  	if (err)  		pr_err("%s: Power Off Notification timed out, %u\n",  		       mmc_hostname(card->host), timeout); @@ -1870,9 +1886,6 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)   */  static void mmc_remove(struct mmc_host *host)  { -	BUG_ON(!host); -	BUG_ON(!host->card); -  	mmc_remove_card(host->card);  	host->card = NULL;  } @@ -1892,9 +1905,6 @@ static void mmc_detect(struct mmc_host *host)  {  	int err; -	BUG_ON(!host); -	BUG_ON(!host->card); -  	mmc_get_card(host->card);  	/* @@ -1920,9 +1930,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)  	unsigned int notify_type = is_suspend ? EXT_CSD_POWER_OFF_SHORT :  					EXT_CSD_POWER_OFF_LONG; -	BUG_ON(!host); -	BUG_ON(!host->card); -  	mmc_claim_host(host);  	if (mmc_card_suspended(host->card)) @@ -1979,9 +1986,6 @@ static int _mmc_resume(struct mmc_host *host)  {  	int err = 0; -	BUG_ON(!host); -	BUG_ON(!host->card); -  	mmc_claim_host(host);  	if (!mmc_card_suspended(host->card)) @@ -2114,7 +2118,6 @@ int mmc_attach_mmc(struct mmc_host *host)  	int err;  	u32 ocr, rocr; -	BUG_ON(!host);  	WARN_ON(!host->claimed);  	/* Set correct bus mode for MMC before attempting attach */  |