All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC] mmc: Non Default UHS Drive Strength must use board specific code
@ 2011-05-17 20:58 Philip Rakity
  2011-05-18  5:49 ` Nath, Arindam
  0 siblings, 1 reply; 4+ messages in thread
From: Philip Rakity @ 2011-05-17 20:58 UTC (permalink / raw)
  To: linux-mmc; +Cc: Arindam Nath


Note:  This is being send out for comment.  We are still in the process of testing this change
but we would like to have community review at this time.


SD 3.0 introduced additional drive strengths for UHS.
The card and the host can indicate 4 drive strengths as a bit
mask.  Without local design knowledge of the board it is not
possible to select the correct drive strength.  Unfortunately
there is not the equivalent of ethernet auto-negotiate in the
SD 3.0 Physical Spec at this time.

We punt the problem by asking any platform specific code to
handle the drive strength problem.  If non is defined we default
the drive strength to the manadory TYPE_B value.

Signed-off-by: Philip Rakity <prakity@marvell.com>
---
 drivers/mmc/core/core.c  |   15 ++++++++++
 drivers/mmc/core/core.h  |    5 +++
 drivers/mmc/core/sd.c    |   65 ++++++++++++++++++++++++----------------------
 drivers/mmc/host/sdhci.c |   16 +++++++++++
 drivers/mmc/host/sdhci.h |    5 +++
 include/linux/mmc/host.h |   13 ++++++---
 6 files changed, 84 insertions(+), 35 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 68091dd..49df27b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -964,6 +964,21 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11
 	return err;
 }
 
+unsigned int mmc_select_drive_strength(struct mmc_host *host,
+			unsigned int bus_mode,
+			unsigned int max_dtr,
+			unsigned int host_drv_type,
+			unsigned int card_drv_type)
+{
+	if (host->ops->select_drive_strength)
+		return host->ops->select_drive_strength(host,
+			bus_mode, max_dtr,
+			host_drv_type, card_drv_type);
+
+	/* return default strength if no handler in driver */
+	return MMC_SET_DRIVER_TYPE_B;
+}
+
 /*
  * Select timing parameters for host.
  */
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index d9411ed..8bc289c 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -43,6 +43,11 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage,
 			   bool cmd11);
 void mmc_set_timing(struct mmc_host *host, unsigned int timing);
 void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
+unsigned int mmc_select_drive_strength(struct mmc_host *host,
+			unsigned int bus_mode,
+			unsigned int max_dtr,
+			unsigned int host_drv_type,
+			unsigned int card_drv_type);
 
 static inline void mmc_delay(unsigned int ms)
 {
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 596d0b9..a268ead 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -405,54 +405,57 @@ out:
 	return err;
 }
 
+
 static int sd_select_driver_type(struct mmc_card *card, u8 *status)
 {
-	int host_drv_type = 0, card_drv_type = 0;
+	unsigned int host_drv_type = MMC_SET_DRIVER_TYPE_B;
+	unsigned int card_drv_type = MMC_SET_DRIVER_TYPE_B;
 	int err;
+	unsigned char drive_strength;
 
 	/*
 	 * If the host doesn't support any of the Driver Types A,C or D,
-	 * default Driver Type B is used.
+	 * or there is no board specific handler then default Driver
+	 * Type B is used.
 	 */
 	if (!(card->host->caps & (MMC_CAP_DRIVER_TYPE_A | MMC_CAP_DRIVER_TYPE_C
 	    | MMC_CAP_DRIVER_TYPE_D)))
 		return 0;
 
-	if (card->host->caps & MMC_CAP_DRIVER_TYPE_A) {
-		host_drv_type = MMC_SET_DRIVER_TYPE_A;
-		if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A)
-			card_drv_type = MMC_SET_DRIVER_TYPE_A;
-		else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B)
-			card_drv_type = MMC_SET_DRIVER_TYPE_B;
-		else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
-			card_drv_type = MMC_SET_DRIVER_TYPE_C;
-	} else if (card->host->caps & MMC_CAP_DRIVER_TYPE_C) {
-		host_drv_type = MMC_SET_DRIVER_TYPE_C;
-		if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
-			card_drv_type = MMC_SET_DRIVER_TYPE_C;
-	} else if (!(card->host->caps & MMC_CAP_DRIVER_TYPE_D)) {
-		/*
-		 * If we are here, that means only the default driver type
-		 * B is supported by the host.
-		 */
-		host_drv_type = MMC_SET_DRIVER_TYPE_B;
-		if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B)
-			card_drv_type = MMC_SET_DRIVER_TYPE_B;
-		else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
-			card_drv_type = MMC_SET_DRIVER_TYPE_C;
-	}
+	if (card->host->caps & MMC_CAP_DRIVER_TYPE_A)
+		host_drv_type |= MMC_SET_DRIVER_TYPE_A;
+
+	if (card->host->caps & MMC_CAP_DRIVER_TYPE_C)
+		host_drv_type |= MMC_SET_DRIVER_TYPE_C;
+
+	if (card->host->caps & MMC_CAP_DRIVER_TYPE_D)
+		host_drv_type |= MMC_SET_DRIVER_TYPE_D;
 
-	err = mmc_sd_switch(card, 1, 2, card_drv_type, status);
+	if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A)
+		card_drv_type |= MMC_SET_DRIVER_TYPE_A;
+
+	if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
+		card_drv_type |= MMC_SET_DRIVER_TYPE_C;
+
+	if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_D)
+		card_drv_type |= MMC_SET_DRIVER_TYPE_D;
+
+	drive_strength = mmc_select_drive_strength(card->host,
+		card->sw_caps.sd3_bus_mode,
+		card->sw_caps.uhs_max_dtr,
+		host_drv_type, card_drv_type);
+
+	err = mmc_sd_switch(card, 1, 2, drive_strength, status);
 	if (err)
 		return err;
 
-	if ((status[15] & 0xF) != card_drv_type) {
-		printk(KERN_WARNING "%s: Problem setting driver strength!\n",
-			mmc_hostname(card->host));
+	if ((status[15] & 0xF) != drive_strength) {
+		printk(KERN_WARNING "%s: Problem setting driver strength %d\n",
+			mmc_hostname(card->host), drive_strength);
 		return 0;
 	}
 
-	mmc_set_driver_type(card->host, host_drv_type);
+	mmc_set_driver_type(card->host, drive_strength);
 
 	return 0;
 }
@@ -488,7 +491,7 @@ static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
 			card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
 	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
 		    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
-		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
+		   (card->sw_caps.uhs_max_dtr & SD_MODE_UHS_SDR25)) {
 			bus_speed = UHS_SDR25_BUS_SPEED;
 			timing = MMC_TIMING_UHS_SDR25;
 			card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index cc63f5e..ebeb986 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1766,6 +1766,21 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable)
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
+static unsigned int sdhci_select_drive_strength(struct mmc_host *host,
+			unsigned int bus_mode,
+			unsigned int max_dtr,
+			unsigned int host_drv_type,
+			unsigned int card_drv_type)
+{
+	if (host->ops->select_drive_strength)
+		return host->ops->select_drive_strength(host,
+			bus_mode, max_dtr,
+			host_drv_type, card_drv_type);
+
+	/* return default strength if no handler in driver */
+	return MMC_SET_DRIVER_TYPE_B;
+}
+
 static const struct mmc_host_ops sdhci_ops = {
 	.request	= sdhci_request,
 	.set_ios	= sdhci_set_ios,
@@ -1774,6 +1789,7 @@ static const struct mmc_host_ops sdhci_ops = {
 	.start_signal_voltage_switch	= sdhci_start_signal_voltage_switch,
 	.execute_tuning			= sdhci_execute_tuning,
 	.enable_preset_value		= sdhci_enable_preset_value,
+	.select_drive_strength		= sdhci_select_drive_strength,
 };
 
 /*****************************************************************************\
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 7e28eec..8f48aca 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -271,6 +271,11 @@ struct sdhci_ops {
 	void	(*platform_reset_enter)(struct sdhci_host *host, u8 mask);
 	void	(*platform_reset_exit)(struct sdhci_host *host, u8 mask);
 	int	(*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
+	unsigned int	(*select_drive_strength)(struct sdhci_host *host,
+			unsigned int bus_mode,
+			unsigned int max_dtr,
+			unsigned int host_drv_type,
+			unsigned int card_drv_type);
 
 };
 
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index de32e6a..6c2aeab 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -70,10 +70,10 @@ struct mmc_ios {
 
 	unsigned char	drv_type;		/* driver type (A, B, C, D) */
 
-#define MMC_SET_DRIVER_TYPE_B	0
-#define MMC_SET_DRIVER_TYPE_A	1
-#define MMC_SET_DRIVER_TYPE_C	2
-#define MMC_SET_DRIVER_TYPE_D	3
+#define MMC_SET_DRIVER_TYPE_B	(1<<0)
+#define MMC_SET_DRIVER_TYPE_A	(1<<1)
+#define MMC_SET_DRIVER_TYPE_C	(1<<2)
+#define MMC_SET_DRIVER_TYPE_D	(1<<3)
 };
 
 struct mmc_host_ops {
@@ -139,6 +139,11 @@ struct mmc_host_ops {
 	int	(*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
 	int	(*execute_tuning)(struct mmc_host *host);
 	void	(*enable_preset_value)(struct mmc_host *host, bool enable);
+	unsigned int	(*select_drive_strength)(struct mmc_host *host,
+			unsigned int bus_mode,
+			unsigned int max_dtr,
+			unsigned int host_drv_type,
+			unsigned int card_drv_type);
 };
 
 struct mmc_card;
-- 
1.7.0.4



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* RE: [RFC] mmc: Non Default UHS Drive Strength must use board specific code
  2011-05-17 20:58 [RFC] mmc: Non Default UHS Drive Strength must use board specific code Philip Rakity
@ 2011-05-18  5:49 ` Nath, Arindam
  2011-05-18 15:04   ` Philip Rakity
  2011-05-18 18:36   ` [RFC v2] " Philip Rakity
  0 siblings, 2 replies; 4+ messages in thread
From: Nath, Arindam @ 2011-05-18  5:49 UTC (permalink / raw)
  To: Philip Rakity, linux-mmc

Hi Philip,


> -----Original Message-----
> From: Philip Rakity [mailto:prakity@marvell.com]
> Sent: Wednesday, May 18, 2011 2:29 AM
> To: linux-mmc@vger.kernel.org
> Cc: Nath, Arindam
> Subject: [RFC] mmc: Non Default UHS Drive Strength must use board
> specific code
> 
> 
> Note:  This is being send out for comment.  We are still in the process
> of testing this change
> but we would like to have community review at this time.
> 
> 
> SD 3.0 introduced additional drive strengths for UHS.
> The card and the host can indicate 4 drive strengths as a bit
> mask.  Without local design knowledge of the board it is not
> possible to select the correct drive strength.  Unfortunately
> there is not the equivalent of ethernet auto-negotiate in the
> SD 3.0 Physical Spec at this time.
> 
> We punt the problem by asking any platform specific code to
> handle the drive strength problem.  If non is defined we default
> the drive strength to the manadory TYPE_B value.
> 
> Signed-off-by: Philip Rakity <prakity@marvell.com>
> ---
>  drivers/mmc/core/core.c  |   15 ++++++++++
>  drivers/mmc/core/core.h  |    5 +++
>  drivers/mmc/core/sd.c    |   65 ++++++++++++++++++++++++--------------
> --------
>  drivers/mmc/host/sdhci.c |   16 +++++++++++
>  drivers/mmc/host/sdhci.h |    5 +++
>  include/linux/mmc/host.h |   13 ++++++---
>  6 files changed, 84 insertions(+), 35 deletions(-)
> 
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index 68091dd..49df27b 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -964,6 +964,21 @@ int mmc_set_signal_voltage(struct mmc_host *host,
> int signal_voltage, bool cmd11
>  	return err;
>  }
> 
> +unsigned int mmc_select_drive_strength(struct mmc_host *host,
> +			unsigned int bus_mode,
> +			unsigned int max_dtr,
> +			unsigned int host_drv_type,
> +			unsigned int card_drv_type)
> +{
> +	if (host->ops->select_drive_strength)
> +		return host->ops->select_drive_strength(host,
> +			bus_mode, max_dtr,
> +			host_drv_type, card_drv_type);
> +
> +	/* return default strength if no handler in driver */
> +	return MMC_SET_DRIVER_TYPE_B;
> +}
> +
>  /*
>   * Select timing parameters for host.
>   */
> diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
> index d9411ed..8bc289c 100644
> --- a/drivers/mmc/core/core.h
> +++ b/drivers/mmc/core/core.h
> @@ -43,6 +43,11 @@ int mmc_set_signal_voltage(struct mmc_host *host,
> int signal_voltage,
>  			   bool cmd11);
>  void mmc_set_timing(struct mmc_host *host, unsigned int timing);
>  void mmc_set_driver_type(struct mmc_host *host, unsigned int
> drv_type);
> +unsigned int mmc_select_drive_strength(struct mmc_host *host,
> +			unsigned int bus_mode,
> +			unsigned int max_dtr,
> +			unsigned int host_drv_type,
> +			unsigned int card_drv_type);
> 
>  static inline void mmc_delay(unsigned int ms)
>  {
> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> index 596d0b9..a268ead 100644
> --- a/drivers/mmc/core/sd.c
> +++ b/drivers/mmc/core/sd.c
> @@ -405,54 +405,57 @@ out:
>  	return err;
>  }
> 
> +
>  static int sd_select_driver_type(struct mmc_card *card, u8 *status)
>  {
> -	int host_drv_type = 0, card_drv_type = 0;
> +	unsigned int host_drv_type = MMC_SET_DRIVER_TYPE_B;
> +	unsigned int card_drv_type = MMC_SET_DRIVER_TYPE_B;
>  	int err;
> +	unsigned char drive_strength;
> 
>  	/*
>  	 * If the host doesn't support any of the Driver Types A,C or D,
> -	 * default Driver Type B is used.
> +	 * or there is no board specific handler then default Driver
> +	 * Type B is used.
>  	 */
>  	if (!(card->host->caps & (MMC_CAP_DRIVER_TYPE_A |
> MMC_CAP_DRIVER_TYPE_C
>  	    | MMC_CAP_DRIVER_TYPE_D)))
>  		return 0;
> 
> -	if (card->host->caps & MMC_CAP_DRIVER_TYPE_A) {
> -		host_drv_type = MMC_SET_DRIVER_TYPE_A;
> -		if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A)
> -			card_drv_type = MMC_SET_DRIVER_TYPE_A;
> -		else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B)
> -			card_drv_type = MMC_SET_DRIVER_TYPE_B;
> -		else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
> -			card_drv_type = MMC_SET_DRIVER_TYPE_C;
> -	} else if (card->host->caps & MMC_CAP_DRIVER_TYPE_C) {
> -		host_drv_type = MMC_SET_DRIVER_TYPE_C;
> -		if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
> -			card_drv_type = MMC_SET_DRIVER_TYPE_C;
> -	} else if (!(card->host->caps & MMC_CAP_DRIVER_TYPE_D)) {
> -		/*
> -		 * If we are here, that means only the default driver type
> -		 * B is supported by the host.
> -		 */
> -		host_drv_type = MMC_SET_DRIVER_TYPE_B;
> -		if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B)
> -			card_drv_type = MMC_SET_DRIVER_TYPE_B;
> -		else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
> -			card_drv_type = MMC_SET_DRIVER_TYPE_C;
> -	}
> +	if (card->host->caps & MMC_CAP_DRIVER_TYPE_A)
> +		host_drv_type |= MMC_SET_DRIVER_TYPE_A;
> +
> +	if (card->host->caps & MMC_CAP_DRIVER_TYPE_C)
> +		host_drv_type |= MMC_SET_DRIVER_TYPE_C;
> +
> +	if (card->host->caps & MMC_CAP_DRIVER_TYPE_D)
> +		host_drv_type |= MMC_SET_DRIVER_TYPE_D;
> 
> -	err = mmc_sd_switch(card, 1, 2, card_drv_type, status);
> +	if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A)
> +		card_drv_type |= MMC_SET_DRIVER_TYPE_A;
> +
> +	if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
> +		card_drv_type |= MMC_SET_DRIVER_TYPE_C;
> +
> +	if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_D)
> +		card_drv_type |= MMC_SET_DRIVER_TYPE_D;
> +
> +	drive_strength = mmc_select_drive_strength(card->host,
> +		card->sw_caps.sd3_bus_mode,
> +		card->sw_caps.uhs_max_dtr,
> +		host_drv_type, card_drv_type);
> +
> +	err = mmc_sd_switch(card, 1, 2, drive_strength, status);
>  	if (err)
>  		return err;
> 
> -	if ((status[15] & 0xF) != card_drv_type) {
> -		printk(KERN_WARNING "%s: Problem setting driver
> strength!\n",
> -			mmc_hostname(card->host));
> +	if ((status[15] & 0xF) != drive_strength) {
> +		printk(KERN_WARNING "%s: Problem setting driver strength
> %d\n",
> +			mmc_hostname(card->host), drive_strength);
>  		return 0;
>  	}
> 
> -	mmc_set_driver_type(card->host, host_drv_type);
> +	mmc_set_driver_type(card->host, drive_strength);
> 
>  	return 0;
>  }
> @@ -488,7 +491,7 @@ static int sd_set_bus_speed_mode(struct mmc_card
> *card, u8 *status)
>  			card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
>  	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
>  		    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
> -		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
> +		   (card->sw_caps.uhs_max_dtr & SD_MODE_UHS_SDR25)) {

I think this line should not be changed, otherwise it will lose its purpose.

>  			bus_speed = UHS_SDR25_BUS_SPEED;
>  			timing = MMC_TIMING_UHS_SDR25;
>  			card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index cc63f5e..ebeb986 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -1766,6 +1766,21 @@ static void sdhci_enable_preset_value(struct
> mmc_host *mmc, bool enable)
>  	spin_unlock_irqrestore(&host->lock, flags);
>  }
> 
> +static unsigned int sdhci_select_drive_strength(struct mmc_host *host,
> +			unsigned int bus_mode,
> +			unsigned int max_dtr,
> +			unsigned int host_drv_type,
> +			unsigned int card_drv_type)
> +{
> +	if (host->ops->select_drive_strength)
> +		return host->ops->select_drive_strength(host,
> +			bus_mode, max_dtr,
> +			host_drv_type, card_drv_type);
> +
> +	/* return default strength if no handler in driver */
> +	return MMC_SET_DRIVER_TYPE_B;
> +}
> +
>  static const struct mmc_host_ops sdhci_ops = {
>  	.request	= sdhci_request,
>  	.set_ios	= sdhci_set_ios,
> @@ -1774,6 +1789,7 @@ static const struct mmc_host_ops sdhci_ops = {
>  	.start_signal_voltage_switch	=
> sdhci_start_signal_voltage_switch,
>  	.execute_tuning			= sdhci_execute_tuning,
>  	.enable_preset_value		= sdhci_enable_preset_value,
> +	.select_drive_strength		= sdhci_select_drive_strength,

Do we need this here? Host Controllers who want to support this should provide their own sdhci_ops function in their respective mmc/host files. For other controllers, mmc_select_drive_strength() will always return TYPE_B as you mentioned above.

>  };
> 
> 
> /**********************************************************************
> *******\
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index 7e28eec..8f48aca 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -271,6 +271,11 @@ struct sdhci_ops {
>  	void	(*platform_reset_enter)(struct sdhci_host *host, u8 mask);
>  	void	(*platform_reset_exit)(struct sdhci_host *host, u8 mask);
>  	int	(*set_uhs_signaling)(struct sdhci_host *host, unsigned int
> uhs);
> +	unsigned int	(*select_drive_strength)(struct sdhci_host
> *host,
> +			unsigned int bus_mode,
> +			unsigned int max_dtr,
> +			unsigned int host_drv_type,
> +			unsigned int card_drv_type);
> 
>  };
> 
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index de32e6a..6c2aeab 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -70,10 +70,10 @@ struct mmc_ios {
> 
>  	unsigned char	drv_type;		/* driver type (A, B, C, D)
> */
> 
> -#define MMC_SET_DRIVER_TYPE_B	0
> -#define MMC_SET_DRIVER_TYPE_A	1
> -#define MMC_SET_DRIVER_TYPE_C	2
> -#define MMC_SET_DRIVER_TYPE_D	3
> +#define MMC_SET_DRIVER_TYPE_B	(1<<0)
> +#define MMC_SET_DRIVER_TYPE_A	(1<<1)
> +#define MMC_SET_DRIVER_TYPE_C	(1<<2)
> +#define MMC_SET_DRIVER_TYPE_D	(1<<3)

These defines if changed will have a different meaning altogether. The defines actually correspond to the "Function Name" column of Table 4-11 of the Physical Layer spec v3.01, which is used by mmc_sd_switch() to set the driver type for the card.

Thanks,
Arindam

>  };
> 
>  struct mmc_host_ops {
> @@ -139,6 +139,11 @@ struct mmc_host_ops {
>  	int	(*start_signal_voltage_switch)(struct mmc_host *host,
> struct mmc_ios *ios);
>  	int	(*execute_tuning)(struct mmc_host *host);
>  	void	(*enable_preset_value)(struct mmc_host *host, bool enable);
> +	unsigned int	(*select_drive_strength)(struct mmc_host *host,
> +			unsigned int bus_mode,
> +			unsigned int max_dtr,
> +			unsigned int host_drv_type,
> +			unsigned int card_drv_type);
>  };
> 
>  struct mmc_card;
> --
> 1.7.0.4
> 
> 



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [RFC] mmc: Non Default UHS Drive Strength must use board specific code
  2011-05-18  5:49 ` Nath, Arindam
@ 2011-05-18 15:04   ` Philip Rakity
  2011-05-18 18:36   ` [RFC v2] " Philip Rakity
  1 sibling, 0 replies; 4+ messages in thread
From: Philip Rakity @ 2011-05-18 15:04 UTC (permalink / raw)
  To: Nath, Arindam; +Cc: linux-mmc


On May 17, 2011, at 10:49 PM, Nath, Arindam wrote:

> Hi Philip,
> 
> 
>> -----Original Message-----
>> From: Philip Rakity [mailto:prakity@marvell.com]
>> Sent: Wednesday, May 18, 2011 2:29 AM
>> To: linux-mmc@vger.kernel.org
>> Cc: Nath, Arindam
>> Subject: [RFC] mmc: Non Default UHS Drive Strength must use board
>> specific code
>> 
>> 
>> Note:  This is being send out for comment.  We are still in the process
>> of testing this change
>> but we would like to have community review at this time.
>> 
>> 
>> SD 3.0 introduced additional drive strengths for UHS.
>> The card and the host can indicate 4 drive strengths as a bit
>> mask.  Without local design knowledge of the board it is not
>> possible to select the correct drive strength.  Unfortunately
>> there is not the equivalent of ethernet auto-negotiate in the
>> SD 3.0 Physical Spec at this time.
>> 
>> We punt the problem by asking any platform specific code to
>> handle the drive strength problem.  If non is defined we default
>> the drive strength to the manadory TYPE_B value.
>> 
>> Signed-off-by: Philip Rakity <prakity@marvell.com>
>> ---
>> drivers/mmc/core/core.c  |   15 ++++++++++
>> drivers/mmc/core/core.h  |    5 +++
>> drivers/mmc/core/sd.c    |   65 ++++++++++++++++++++++++--------------
>> --------
>> drivers/mmc/host/sdhci.c |   16 +++++++++++
>> drivers/mmc/host/sdhci.h |    5 +++
>> include/linux/mmc/host.h |   13 ++++++---
>> 6 files changed, 84 insertions(+), 35 deletions(-)
>> 
>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>> index 68091dd..49df27b 100644
>> --- a/drivers/mmc/core/core.c
>> +++ b/drivers/mmc/core/core.c
>> @@ -964,6 +964,21 @@ int mmc_set_signal_voltage(struct mmc_host *host,
>> int signal_voltage, bool cmd11
>> 	return err;
>> }
>> 
>> +unsigned int mmc_select_drive_strength(struct mmc_host *host,
>> +			unsigned int bus_mode,
>> +			unsigned int max_dtr,
>> +			unsigned int host_drv_type,
>> +			unsigned int card_drv_type)
>> +{
>> +	if (host->ops->select_drive_strength)
>> +		return host->ops->select_drive_strength(host,
>> +			bus_mode, max_dtr,
>> +			host_drv_type, card_drv_type);
>> +
>> +	/* return default strength if no handler in driver */
>> +	return MMC_SET_DRIVER_TYPE_B;
>> +}
>> +
>> /*
>>  * Select timing parameters for host.
>>  */
>> diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
>> index d9411ed..8bc289c 100644
>> --- a/drivers/mmc/core/core.h
>> +++ b/drivers/mmc/core/core.h
>> @@ -43,6 +43,11 @@ int mmc_set_signal_voltage(struct mmc_host *host,
>> int signal_voltage,
>> 			   bool cmd11);
>> void mmc_set_timing(struct mmc_host *host, unsigned int timing);
>> void mmc_set_driver_type(struct mmc_host *host, unsigned int
>> drv_type);
>> +unsigned int mmc_select_drive_strength(struct mmc_host *host,
>> +			unsigned int bus_mode,
>> +			unsigned int max_dtr,
>> +			unsigned int host_drv_type,
>> +			unsigned int card_drv_type);
>> 
>> static inline void mmc_delay(unsigned int ms)
>> {
>> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
>> index 596d0b9..a268ead 100644
>> --- a/drivers/mmc/core/sd.c
>> +++ b/drivers/mmc/core/sd.c
>> @@ -405,54 +405,57 @@ out:
>> 	return err;
>> }
>> 
>> +
>> static int sd_select_driver_type(struct mmc_card *card, u8 *status)
>> {
>> -	int host_drv_type = 0, card_drv_type = 0;
>> +	unsigned int host_drv_type = MMC_SET_DRIVER_TYPE_B;
>> +	unsigned int card_drv_type = MMC_SET_DRIVER_TYPE_B;
>> 	int err;
>> +	unsigned char drive_strength;
>> 
>> 	/*
>> 	 * If the host doesn't support any of the Driver Types A,C or D,
>> -	 * default Driver Type B is used.
>> +	 * or there is no board specific handler then default Driver
>> +	 * Type B is used.
>> 	 */
>> 	if (!(card->host->caps & (MMC_CAP_DRIVER_TYPE_A |
>> MMC_CAP_DRIVER_TYPE_C
>> 	    | MMC_CAP_DRIVER_TYPE_D)))
>> 		return 0;
>> 
>> -	if (card->host->caps & MMC_CAP_DRIVER_TYPE_A) {
>> -		host_drv_type = MMC_SET_DRIVER_TYPE_A;
>> -		if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A)
>> -			card_drv_type = MMC_SET_DRIVER_TYPE_A;
>> -		else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B)
>> -			card_drv_type = MMC_SET_DRIVER_TYPE_B;
>> -		else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
>> -			card_drv_type = MMC_SET_DRIVER_TYPE_C;
>> -	} else if (card->host->caps & MMC_CAP_DRIVER_TYPE_C) {
>> -		host_drv_type = MMC_SET_DRIVER_TYPE_C;
>> -		if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
>> -			card_drv_type = MMC_SET_DRIVER_TYPE_C;
>> -	} else if (!(card->host->caps & MMC_CAP_DRIVER_TYPE_D)) {
>> -		/*
>> -		 * If we are here, that means only the default driver type
>> -		 * B is supported by the host.
>> -		 */
>> -		host_drv_type = MMC_SET_DRIVER_TYPE_B;
>> -		if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B)
>> -			card_drv_type = MMC_SET_DRIVER_TYPE_B;
>> -		else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
>> -			card_drv_type = MMC_SET_DRIVER_TYPE_C;
>> -	}
>> +	if (card->host->caps & MMC_CAP_DRIVER_TYPE_A)
>> +		host_drv_type |= MMC_SET_DRIVER_TYPE_A;
>> +
>> +	if (card->host->caps & MMC_CAP_DRIVER_TYPE_C)
>> +		host_drv_type |= MMC_SET_DRIVER_TYPE_C;
>> +
>> +	if (card->host->caps & MMC_CAP_DRIVER_TYPE_D)
>> +		host_drv_type |= MMC_SET_DRIVER_TYPE_D;
>> 
>> -	err = mmc_sd_switch(card, 1, 2, card_drv_type, status);
>> +	if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A)
>> +		card_drv_type |= MMC_SET_DRIVER_TYPE_A;
>> +
>> +	if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
>> +		card_drv_type |= MMC_SET_DRIVER_TYPE_C;
>> +
>> +	if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_D)
>> +		card_drv_type |= MMC_SET_DRIVER_TYPE_D;
>> +
>> +	drive_strength = mmc_select_drive_strength(card->host,
>> +		card->sw_caps.sd3_bus_mode,
>> +		card->sw_caps.uhs_max_dtr,
>> +		host_drv_type, card_drv_type);
>> +
>> +	err = mmc_sd_switch(card, 1, 2, drive_strength, status);
>> 	if (err)
>> 		return err;
>> 
>> -	if ((status[15] & 0xF) != card_drv_type) {
>> -		printk(KERN_WARNING "%s: Problem setting driver
>> strength!\n",
>> -			mmc_hostname(card->host));
>> +	if ((status[15] & 0xF) != drive_strength) {
>> +		printk(KERN_WARNING "%s: Problem setting driver strength
>> %d\n",
>> +			mmc_hostname(card->host), drive_strength);
>> 		return 0;
>> 	}
>> 
>> -	mmc_set_driver_type(card->host, host_drv_type);
>> +	mmc_set_driver_type(card->host, drive_strength);
>> 
>> 	return 0;
>> }
>> @@ -488,7 +491,7 @@ static int sd_set_bus_speed_mode(struct mmc_card
>> *card, u8 *status)
>> 			card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
>> 	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
>> 		    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
>> -		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
>> +		   (card->sw_caps.uhs_max_dtr & SD_MODE_UHS_SDR25)) {
> 
> I think this line should not be changed, otherwise it will lose its purpose.

typo -- will fix

> 
>> 			bus_speed = UHS_SDR25_BUS_SPEED;
>> 			timing = MMC_TIMING_UHS_SDR25;
>> 			card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>> index cc63f5e..ebeb986 100644
>> --- a/drivers/mmc/host/sdhci.c
>> +++ b/drivers/mmc/host/sdhci.c
>> @@ -1766,6 +1766,21 @@ static void sdhci_enable_preset_value(struct
>> mmc_host *mmc, bool enable)
>> 	spin_unlock_irqrestore(&host->lock, flags);
>> }
>> 
>> +static unsigned int sdhci_select_drive_strength(struct mmc_host *host,
>> +			unsigned int bus_mode,
>> +			unsigned int max_dtr,
>> +			unsigned int host_drv_type,
>> +			unsigned int card_drv_type)
>> +{
>> +	if (host->ops->select_drive_strength)
>> +		return host->ops->select_drive_strength(host,
>> +			bus_mode, max_dtr,
>> +			host_drv_type, card_drv_type);
>> +
>> +	/* return default strength if no handler in driver */
>> +	return MMC_SET_DRIVER_TYPE_B;
>> +}
>> +
>> static const struct mmc_host_ops sdhci_ops = {
>> 	.request	= sdhci_request,
>> 	.set_ios	= sdhci_set_ios,
>> @@ -1774,6 +1789,7 @@ static const struct mmc_host_ops sdhci_ops = {
>> 	.start_signal_voltage_switch	=
>> sdhci_start_signal_voltage_switch,
>> 	.execute_tuning			= sdhci_execute_tuning,
>> 	.enable_preset_value		= sdhci_enable_preset_value,
>> +	.select_drive_strength		= sdhci_select_drive_strength,
> 
> Do we need this here? Host Controllers who want to support this should provide their own sdhci_ops function in their respective mmc/host files. For other controllers, mmc_select_drive_strength() will always return TYPE_B as you mentioned above.
> 

without this there is no hook into the platform specific code to handle the setting of drive strength.


>> };
>> 
>> 
>> /**********************************************************************
>> *******\
>> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
>> index 7e28eec..8f48aca 100644
>> --- a/drivers/mmc/host/sdhci.h
>> +++ b/drivers/mmc/host/sdhci.h
>> @@ -271,6 +271,11 @@ struct sdhci_ops {
>> 	void	(*platform_reset_enter)(struct sdhci_host *host, u8 mask);
>> 	void	(*platform_reset_exit)(struct sdhci_host *host, u8 mask);
>> 	int	(*set_uhs_signaling)(struct sdhci_host *host, unsigned int
>> uhs);
>> +	unsigned int	(*select_drive_strength)(struct sdhci_host
>> *host,
>> +			unsigned int bus_mode,
>> +			unsigned int max_dtr,
>> +			unsigned int host_drv_type,
>> +			unsigned int card_drv_type);
>> 
>> };
>> 
>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> index de32e6a..6c2aeab 100644
>> --- a/include/linux/mmc/host.h
>> +++ b/include/linux/mmc/host.h
>> @@ -70,10 +70,10 @@ struct mmc_ios {
>> 
>> 	unsigned char	drv_type;		/* driver type (A, B, C, D)
>> */
>> 
>> -#define MMC_SET_DRIVER_TYPE_B	0
>> -#define MMC_SET_DRIVER_TYPE_A	1
>> -#define MMC_SET_DRIVER_TYPE_C	2
>> -#define MMC_SET_DRIVER_TYPE_D	3
>> +#define MMC_SET_DRIVER_TYPE_B	(1<<0)
>> +#define MMC_SET_DRIVER_TYPE_A	(1<<1)
>> +#define MMC_SET_DRIVER_TYPE_C	(1<<2)
>> +#define MMC_SET_DRIVER_TYPE_D	(1<<3)
> 
> These defines if changed will have a different meaning altogether. The defines actually correspond to the "Function Name" column of Table 4-11 of the Physical Layer spec v3.01, which is used by mmc_sd_switch() to set the driver type for the card.

will add the comment  about Function Name and rework code.

> 
> Thanks,
> Arindam
> 
>> };
>> 
>> struct mmc_host_ops {
>> @@ -139,6 +139,11 @@ struct mmc_host_ops {
>> 	int	(*start_signal_voltage_switch)(struct mmc_host *host,
>> struct mmc_ios *ios);
>> 	int	(*execute_tuning)(struct mmc_host *host);
>> 	void	(*enable_preset_value)(struct mmc_host *host, bool enable);
>> +	unsigned int	(*select_drive_strength)(struct mmc_host *host,
>> +			unsigned int bus_mode,
>> +			unsigned int max_dtr,
>> +			unsigned int host_drv_type,
>> +			unsigned int card_drv_type);
>> };
>> 
>> struct mmc_card;
>> --
>> 1.7.0.4
>> 
>> 
> 
> 


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [RFC v2] mmc: Non Default UHS Drive Strength must use board specific code
  2011-05-18  5:49 ` Nath, Arindam
  2011-05-18 15:04   ` Philip Rakity
@ 2011-05-18 18:36   ` Philip Rakity
  1 sibling, 0 replies; 4+ messages in thread
From: Philip Rakity @ 2011-05-18 18:36 UTC (permalink / raw)
  To: linux-mmc; +Cc: Arindam Nath

incorporates comments by Arindam -- additional feedback please

Philiip

v2
---
host.h
revert DRIVE_STRENGTH to values vs bit mask.  add comment.
add new defines for bit mask to allow multiple values
to be selected.

sd.c
fix accidental edit in sd.c (sd_set_bus_speed_mode)
change to explicitly use _MASK for passing drive strengths
to mmc_select_drive_strength (sd_select_driver_type)

core.c
add comment to mmc_select_drive_strength to explicitly
indicate it returns one value vs a mask of values.

---
SD 3.0 introduced additional drive strengths for UHS.
The card and the host can indicate 4 drive strengths as a bit
mask.  Without local design knowledge of the board it is not
possible to select the correct drive strength.  Unfortunately
there is not the equivalent of ethernet auto-negotiate in the
SD 3.0 Physical Spec at this time.

We punt the problem by asking any platform specific code to
handle the drive strength problem.  If non is defined we default
the drive strength to the manadory TYPE_B value.

Signed-off-by: Philip Rakity <prakity@marvell.com>
---
 drivers/mmc/core/core.c  |   16 +++++++++++
 drivers/mmc/core/core.h  |    5 +++
 drivers/mmc/core/sd.c    |   63 ++++++++++++++++++++++++----------------------
 drivers/mmc/host/sdhci.c |   16 +++++++++++
 drivers/mmc/host/sdhci.h |    5 +++
 include/linux/mmc/host.h |   11 ++++++++
 6 files changed, 86 insertions(+), 30 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 68091dd..636bfc9 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -964,6 +964,22 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11
 	return err;
 }
 
+/* returns MMC_SET_DRIVER_TYPE_X (one value) not mask */
+unsigned int mmc_select_drive_strength(struct mmc_host *host,
+			unsigned int bus_mode,
+			unsigned int max_dtr,
+			unsigned int host_drv_type,
+			unsigned int card_drv_type)
+{
+	if (host->ops->select_drive_strength)
+		return host->ops->select_drive_strength(host,
+			bus_mode, max_dtr,
+			host_drv_type, card_drv_type);
+
+	/* return default strength if no handler in driver */
+	return MMC_SET_DRIVER_TYPE_B;
+}
+
 /*
  * Select timing parameters for host.
  */
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index d9411ed..8bc289c 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -43,6 +43,11 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage,
 			   bool cmd11);
 void mmc_set_timing(struct mmc_host *host, unsigned int timing);
 void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
+unsigned int mmc_select_drive_strength(struct mmc_host *host,
+			unsigned int bus_mode,
+			unsigned int max_dtr,
+			unsigned int host_drv_type,
+			unsigned int card_drv_type);
 
 static inline void mmc_delay(unsigned int ms)
 {
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 596d0b9..bb5cd54 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -405,54 +405,57 @@ out:
 	return err;
 }
 
+
 static int sd_select_driver_type(struct mmc_card *card, u8 *status)
 {
-	int host_drv_type = 0, card_drv_type = 0;
+	unsigned int host_drv_type = MMC_DRIVER_TYPE_B_MASK;
+	unsigned int card_drv_type = MMC_DRIVER_TYPE_B_MASK;
 	int err;
+	unsigned char drive_strength;
 
 	/*
 	 * If the host doesn't support any of the Driver Types A,C or D,
-	 * default Driver Type B is used.
+	 * or there is no board specific handler then default Driver
+	 * Type B is used.
 	 */
 	if (!(card->host->caps & (MMC_CAP_DRIVER_TYPE_A | MMC_CAP_DRIVER_TYPE_C
 	    | MMC_CAP_DRIVER_TYPE_D)))
 		return 0;
 
-	if (card->host->caps & MMC_CAP_DRIVER_TYPE_A) {
-		host_drv_type = MMC_SET_DRIVER_TYPE_A;
-		if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A)
-			card_drv_type = MMC_SET_DRIVER_TYPE_A;
-		else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B)
-			card_drv_type = MMC_SET_DRIVER_TYPE_B;
-		else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
-			card_drv_type = MMC_SET_DRIVER_TYPE_C;
-	} else if (card->host->caps & MMC_CAP_DRIVER_TYPE_C) {
-		host_drv_type = MMC_SET_DRIVER_TYPE_C;
-		if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
-			card_drv_type = MMC_SET_DRIVER_TYPE_C;
-	} else if (!(card->host->caps & MMC_CAP_DRIVER_TYPE_D)) {
-		/*
-		 * If we are here, that means only the default driver type
-		 * B is supported by the host.
-		 */
-		host_drv_type = MMC_SET_DRIVER_TYPE_B;
-		if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B)
-			card_drv_type = MMC_SET_DRIVER_TYPE_B;
-		else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
-			card_drv_type = MMC_SET_DRIVER_TYPE_C;
-	}
+	if (card->host->caps & MMC_CAP_DRIVER_TYPE_A)
+		host_drv_type |= MMC_DRIVER_TYPE_A_MASK;
+
+	if (card->host->caps & MMC_CAP_DRIVER_TYPE_C)
+		host_drv_type |= MMC_DRIVER_TYPE_C_MASK;
+
+	if (card->host->caps & MMC_CAP_DRIVER_TYPE_D)
+		host_drv_type |= MMC_DRIVER_TYPE_D_MASK;
 
-	err = mmc_sd_switch(card, 1, 2, card_drv_type, status);
+	if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A)
+		card_drv_type |= MMC_DRIVER_TYPE_A_MASK;
+
+	if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
+		card_drv_type |= MMC_DRIVER_TYPE_C_MASK;
+
+	if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_D)
+		card_drv_type |= MMC_DRIVER_TYPE_D_MASK;
+
+	drive_strength = mmc_select_drive_strength(card->host,
+		card->sw_caps.sd3_bus_mode,
+		card->sw_caps.uhs_max_dtr,
+		host_drv_type, card_drv_type);
+
+	err = mmc_sd_switch(card, 1, 2, drive_strength, status);
 	if (err)
 		return err;
 
-	if ((status[15] & 0xF) != card_drv_type) {
-		printk(KERN_WARNING "%s: Problem setting driver strength!\n",
-			mmc_hostname(card->host));
+	if ((status[15] & 0xF) != drive_strength) {
+		printk(KERN_WARNING "%s: Problem setting driver strength %d\n",
+			mmc_hostname(card->host), drive_strength);
 		return 0;
 	}
 
-	mmc_set_driver_type(card->host, host_drv_type);
+	mmc_set_driver_type(card->host, drive_strength);
 
 	return 0;
 }
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index cc63f5e..ebeb986 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1766,6 +1766,21 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable)
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
+static unsigned int sdhci_select_drive_strength(struct mmc_host *host,
+			unsigned int bus_mode,
+			unsigned int max_dtr,
+			unsigned int host_drv_type,
+			unsigned int card_drv_type)
+{
+	if (host->ops->select_drive_strength)
+		return host->ops->select_drive_strength(host,
+			bus_mode, max_dtr,
+			host_drv_type, card_drv_type);
+
+	/* return default strength if no handler in driver */
+	return MMC_SET_DRIVER_TYPE_B;
+}
+
 static const struct mmc_host_ops sdhci_ops = {
 	.request	= sdhci_request,
 	.set_ios	= sdhci_set_ios,
@@ -1774,6 +1789,7 @@ static const struct mmc_host_ops sdhci_ops = {
 	.start_signal_voltage_switch	= sdhci_start_signal_voltage_switch,
 	.execute_tuning			= sdhci_execute_tuning,
 	.enable_preset_value		= sdhci_enable_preset_value,
+	.select_drive_strength		= sdhci_select_drive_strength,
 };
 
 /*****************************************************************************\
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 7e28eec..8f48aca 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -271,6 +271,11 @@ struct sdhci_ops {
 	void	(*platform_reset_enter)(struct sdhci_host *host, u8 mask);
 	void	(*platform_reset_exit)(struct sdhci_host *host, u8 mask);
 	int	(*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
+	unsigned int	(*select_drive_strength)(struct sdhci_host *host,
+			unsigned int bus_mode,
+			unsigned int max_dtr,
+			unsigned int host_drv_type,
+			unsigned int card_drv_type);
 
 };
 
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index de32e6a..d4bcf9c 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -70,10 +70,16 @@ struct mmc_ios {
 
 	unsigned char	drv_type;		/* driver type (A, B, C, D) */
 
+/* Driver Strength Function Name */
 #define MMC_SET_DRIVER_TYPE_B	0
 #define MMC_SET_DRIVER_TYPE_A	1
 #define MMC_SET_DRIVER_TYPE_C	2
 #define MMC_SET_DRIVER_TYPE_D	3
+
+#define MMC_DRIVER_TYPE_B_MASK	(1<<MMC_SET_DRIVER_TYPE_B)
+#define MMC_DRIVER_TYPE_A_MASK	(1<<MMC_SET_DRIVER_TYPE_A)
+#define MMC_DRIVER_TYPE_C_MASK	(1<<MMC_SET_DRIVER_TYPE_C)
+#define MMC_DRIVER_TYPE_D_MASK	(1<<MMC_SET_DRIVER_TYPE_D)
 };
 
 struct mmc_host_ops {
@@ -139,6 +145,11 @@ struct mmc_host_ops {
 	int	(*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
 	int	(*execute_tuning)(struct mmc_host *host);
 	void	(*enable_preset_value)(struct mmc_host *host, bool enable);
+	unsigned int	(*select_drive_strength)(struct mmc_host *host,
+			unsigned int bus_mode,
+			unsigned int max_dtr,
+			unsigned int host_drv_type,
+			unsigned int card_drv_type);
 };
 
 struct mmc_card;
-- 
1.7.0.4



^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2011-05-18 18:51 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-17 20:58 [RFC] mmc: Non Default UHS Drive Strength must use board specific code Philip Rakity
2011-05-18  5:49 ` Nath, Arindam
2011-05-18 15:04   ` Philip Rakity
2011-05-18 18:36   ` [RFC v2] " Philip Rakity

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.