Re: [RFC] mmc: Non Default UHS Drive Strength must use board specific code

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

> Hi Philip,
> 
> 
>> -----Original Message-----
>> From: Philip Rakity [mailto:prakity@xxxxxxxxxxx]
>> Sent: Wednesday, May 18, 2011 2:29 AM
>> To: linux-mmc@xxxxxxxxxxxxxxx
>> 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@xxxxxxxxxxx>
>> ---
>> 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
>> 
>> 
> 
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux