diff mbox series

[U-Boot,v2,24/26] mmc: use the right voltage level for MMC DDR and HS200 modes

Message ID 1506004213-22620-25-git-send-email-jjhiblot@ti.com
State Accepted
Commit bc1e3272ff3437f7cfc5e8bf1d1f2767f6d78262
Delegated to: Jaehoon Chung
Headers show
Series mmc: Add support for HS200 and UHS modes | expand

Commit Message

Jean-Jacques Hiblot Sept. 21, 2017, 2:30 p.m. UTC
HS200 only supports 1.2v and 1.8v signal voltages. DDR52 supports 3.3v/1.8v
or 1.2v signal voltages.
Select the lowest voltage available when using those modes.

Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
---
 drivers/mmc/mmc.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 include/mmc.h     | 20 +++++++++++++---
 2 files changed, 84 insertions(+), 4 deletions(-)

Comments

Jaehoon Chung Sept. 22, 2017, 1:54 p.m. UTC | #1
On 09/21/2017 11:30 PM, Jean-Jacques Hiblot wrote:
> HS200 only supports 1.2v and 1.8v signal voltages. DDR52 supports 3.3v/1.8v
> or 1.2v signal voltages.
> Select the lowest voltage available when using those modes.
> 
> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
> ---
>  drivers/mmc/mmc.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  include/mmc.h     | 20 +++++++++++++---
>  2 files changed, 84 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
> index 6d1bf94..2d447dd 100644
> --- a/drivers/mmc/mmc.c
> +++ b/drivers/mmc/mmc.c
> @@ -767,6 +767,7 @@ static int mmc_get_capabilities(struct mmc *mmc)
>  	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
>  
>  	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
> +	mmc->cardtype = cardtype;
>  
>  	if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
>  			EXT_CSD_CARD_TYPE_HS200_1_8V)) {
> @@ -1441,10 +1442,30 @@ struct mode_width_tuning {
>  	uint tuning;
>  };
>  
> +int mmc_voltage_to_mv(enum mmc_voltage voltage)
> +{
> +	switch (voltage) {
> +	case MMC_SIGNAL_VOLTAGE_000: return 0;
> +	case MMC_SIGNAL_VOLTAGE_330: return 3300;
> +	case MMC_SIGNAL_VOLTAGE_180: return 1800;
> +	case MMC_SIGNAL_VOLTAGE_120: return 1200;

Plz, change line.
case xxx:
	return xxx;

> +	}
> +	return -EINVAL;
> +}
> +
>  static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
>  {
> +	int err;

Initialized err = 0

> +
> +	if (mmc->signal_voltage == signal_voltage)
> +		return 0;

return err; or use return ret?

> +
>  	mmc->signal_voltage = signal_voltage;
> -	return mmc_set_ios(mmc);
> +	err = mmc_set_ios(mmc);
> +	if (err)
> +		debug("unable to set voltage (err %d)\n", err);
> +
> +	return err;
>  }
>  
>  static const struct mode_width_tuning sd_modes_by_pref[] = {
> @@ -1584,6 +1605,43 @@ static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
>  	return -EBADMSG;
>  }
>  
> +static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
> +				  uint32_t allowed_mask)
> +{
> +	u32 card_mask = 0;
> +
> +	switch (mode) {
> +	case MMC_HS_200:
> +		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V)
> +			card_mask |= MMC_SIGNAL_VOLTAGE_180;
> +		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V)
> +			card_mask |= MMC_SIGNAL_VOLTAGE_120;
> +		break;
> +	case MMC_DDR_52:
> +		if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
> +			card_mask |= MMC_SIGNAL_VOLTAGE_330 |
> +				     MMC_SIGNAL_VOLTAGE_180;
> +		if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V)
> +			card_mask |= MMC_SIGNAL_VOLTAGE_120;
> +		break;
> +	default:
> +		card_mask |= MMC_SIGNAL_VOLTAGE_330;
> +		break;
> +	}
> +
> +	while (card_mask & allowed_mask) {
> +		enum mmc_voltage best_match;
> +
> +		best_match = 1 << (ffs(card_mask & allowed_mask) - 1);
> +		if (!mmc_set_signal_voltage(mmc,  best_match))
> +			return 0;

Just return 0?

> +
> +		allowed_mask &= ~best_match;
> +	}
> +
> +	return -ENOTSUPP;
> +}
> +
>  static const struct mode_width_tuning mmc_modes_by_pref[] = {
>  	{
>  		.mode = MMC_HS_200,
> @@ -1655,10 +1713,17 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
>  	for_each_mmc_mode_by_pref(card_caps, mwt) {
>  		for_each_supported_width(card_caps & mwt->widths,
>  					 mmc_is_mode_ddr(mwt->mode), ecbw) {
> +			enum mmc_voltage old_voltage;
>  			debug("trying mode %s width %d (at %d MHz)\n",
>  			      mmc_mode_name(mwt->mode),
>  			      bus_width(ecbw->cap),
>  			      mmc_mode2freq(mmc, mwt->mode) / 1000000);
> +			old_voltage = mmc->signal_voltage;
> +			err = mmc_set_lowest_voltage(mmc, mwt->mode,
> +						     MMC_ALL_SIGNAL_VOLTAGE);
> +			if (err)
> +				continue;
> +
>  			/* configure the bus width (card + host) */
>  			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
>  				    EXT_CSD_BUS_WIDTH,
> @@ -1702,6 +1767,7 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
>  			if (!err)
>  				return 0;
>  error:
> +			mmc_set_signal_voltage(mmc, old_voltage);

doesn't need to check the return value?

>  			/* if an error occured, revert to a safer bus mode */
>  			mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
>  				   EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
> diff --git a/include/mmc.h b/include/mmc.h
> index a9ebc88..c11f698 100644
> --- a/include/mmc.h
> +++ b/include/mmc.h
> @@ -311,11 +311,15 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
>  
>  enum mmc_voltage {
>  	MMC_SIGNAL_VOLTAGE_000 = 0,
> -	MMC_SIGNAL_VOLTAGE_120,
> -	MMC_SIGNAL_VOLTAGE_180,
> -	MMC_SIGNAL_VOLTAGE_330
> +	MMC_SIGNAL_VOLTAGE_120 = 1,
> +	MMC_SIGNAL_VOLTAGE_180 = 2,
> +	MMC_SIGNAL_VOLTAGE_330 = 4,
>  };
>  
> +#define MMC_ALL_SIGNAL_VOLTAGE (MMC_SIGNAL_VOLTAGE_120 |\
> +				MMC_SIGNAL_VOLTAGE_180 |\
> +				MMC_SIGNAL_VOLTAGE_330)
> +
>  /* Maximum block size for MMC */
>  #define MMC_MAX_BLOCK_LEN	512
>  
> @@ -588,6 +592,8 @@ struct mmc {
>  #endif
>  #endif
>  	u8 *ext_csd;
> +	u32 cardtype;		/* cardtype read from the MMC */
> +	enum mmc_voltage current_voltage;
>  	enum bus_mode selected_mode; /* mode currently used */
>  	enum bus_mode best_mode; /* best mode is the supported mode with the
>  				  * highest bandwidth. It may not always be the
> @@ -647,6 +653,14 @@ int mmc_init(struct mmc *mmc);
>  int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size);
>  
>  /**
> + * mmc_voltage_to_mv() - Convert a mmc_voltage in mV
> + *
> + * @voltage:	The mmc_voltage to convert
> + * @return the value in mV if OK, -EINVAL on error (invalid mmc_voltage value)
> + */
> +int mmc_voltage_to_mv(enum mmc_voltage voltage);
> +
> +/**
>   * mmc_set_clock() - change the bus clock
>   * @mmc:	MMC struct
>   * @clock:	bus frequency in Hz
>
diff mbox series

Patch

diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 6d1bf94..2d447dd 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -767,6 +767,7 @@  static int mmc_get_capabilities(struct mmc *mmc)
 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
 
 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
+	mmc->cardtype = cardtype;
 
 	if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
 			EXT_CSD_CARD_TYPE_HS200_1_8V)) {
@@ -1441,10 +1442,30 @@  struct mode_width_tuning {
 	uint tuning;
 };
 
+int mmc_voltage_to_mv(enum mmc_voltage voltage)
+{
+	switch (voltage) {
+	case MMC_SIGNAL_VOLTAGE_000: return 0;
+	case MMC_SIGNAL_VOLTAGE_330: return 3300;
+	case MMC_SIGNAL_VOLTAGE_180: return 1800;
+	case MMC_SIGNAL_VOLTAGE_120: return 1200;
+	}
+	return -EINVAL;
+}
+
 static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
 {
+	int err;
+
+	if (mmc->signal_voltage == signal_voltage)
+		return 0;
+
 	mmc->signal_voltage = signal_voltage;
-	return mmc_set_ios(mmc);
+	err = mmc_set_ios(mmc);
+	if (err)
+		debug("unable to set voltage (err %d)\n", err);
+
+	return err;
 }
 
 static const struct mode_width_tuning sd_modes_by_pref[] = {
@@ -1584,6 +1605,43 @@  static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
 	return -EBADMSG;
 }
 
+static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
+				  uint32_t allowed_mask)
+{
+	u32 card_mask = 0;
+
+	switch (mode) {
+	case MMC_HS_200:
+		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V)
+			card_mask |= MMC_SIGNAL_VOLTAGE_180;
+		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V)
+			card_mask |= MMC_SIGNAL_VOLTAGE_120;
+		break;
+	case MMC_DDR_52:
+		if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
+			card_mask |= MMC_SIGNAL_VOLTAGE_330 |
+				     MMC_SIGNAL_VOLTAGE_180;
+		if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V)
+			card_mask |= MMC_SIGNAL_VOLTAGE_120;
+		break;
+	default:
+		card_mask |= MMC_SIGNAL_VOLTAGE_330;
+		break;
+	}
+
+	while (card_mask & allowed_mask) {
+		enum mmc_voltage best_match;
+
+		best_match = 1 << (ffs(card_mask & allowed_mask) - 1);
+		if (!mmc_set_signal_voltage(mmc,  best_match))
+			return 0;
+
+		allowed_mask &= ~best_match;
+	}
+
+	return -ENOTSUPP;
+}
+
 static const struct mode_width_tuning mmc_modes_by_pref[] = {
 	{
 		.mode = MMC_HS_200,
@@ -1655,10 +1713,17 @@  static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
 	for_each_mmc_mode_by_pref(card_caps, mwt) {
 		for_each_supported_width(card_caps & mwt->widths,
 					 mmc_is_mode_ddr(mwt->mode), ecbw) {
+			enum mmc_voltage old_voltage;
 			debug("trying mode %s width %d (at %d MHz)\n",
 			      mmc_mode_name(mwt->mode),
 			      bus_width(ecbw->cap),
 			      mmc_mode2freq(mmc, mwt->mode) / 1000000);
+			old_voltage = mmc->signal_voltage;
+			err = mmc_set_lowest_voltage(mmc, mwt->mode,
+						     MMC_ALL_SIGNAL_VOLTAGE);
+			if (err)
+				continue;
+
 			/* configure the bus width (card + host) */
 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
 				    EXT_CSD_BUS_WIDTH,
@@ -1702,6 +1767,7 @@  static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
 			if (!err)
 				return 0;
 error:
+			mmc_set_signal_voltage(mmc, old_voltage);
 			/* if an error occured, revert to a safer bus mode */
 			mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
 				   EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
diff --git a/include/mmc.h b/include/mmc.h
index a9ebc88..c11f698 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -311,11 +311,15 @@  static inline bool mmc_is_tuning_cmd(uint cmdidx)
 
 enum mmc_voltage {
 	MMC_SIGNAL_VOLTAGE_000 = 0,
-	MMC_SIGNAL_VOLTAGE_120,
-	MMC_SIGNAL_VOLTAGE_180,
-	MMC_SIGNAL_VOLTAGE_330
+	MMC_SIGNAL_VOLTAGE_120 = 1,
+	MMC_SIGNAL_VOLTAGE_180 = 2,
+	MMC_SIGNAL_VOLTAGE_330 = 4,
 };
 
+#define MMC_ALL_SIGNAL_VOLTAGE (MMC_SIGNAL_VOLTAGE_120 |\
+				MMC_SIGNAL_VOLTAGE_180 |\
+				MMC_SIGNAL_VOLTAGE_330)
+
 /* Maximum block size for MMC */
 #define MMC_MAX_BLOCK_LEN	512
 
@@ -588,6 +592,8 @@  struct mmc {
 #endif
 #endif
 	u8 *ext_csd;
+	u32 cardtype;		/* cardtype read from the MMC */
+	enum mmc_voltage current_voltage;
 	enum bus_mode selected_mode; /* mode currently used */
 	enum bus_mode best_mode; /* best mode is the supported mode with the
 				  * highest bandwidth. It may not always be the
@@ -647,6 +653,14 @@  int mmc_init(struct mmc *mmc);
 int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size);
 
 /**
+ * mmc_voltage_to_mv() - Convert a mmc_voltage in mV
+ *
+ * @voltage:	The mmc_voltage to convert
+ * @return the value in mV if OK, -EINVAL on error (invalid mmc_voltage value)
+ */
+int mmc_voltage_to_mv(enum mmc_voltage voltage);
+
+/**
  * mmc_set_clock() - change the bus clock
  * @mmc:	MMC struct
  * @clock:	bus frequency in Hz