Re: [PATCH v2 07/12] mmc: sd: set current limit for uhs cards

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

 



On Mar 16, 2011, at 8:00 AM, Nath, Arindam wrote:

> Hi Philip,
> 
> 
>> -----Original Message-----
>> From: Philip Rakity [mailto:prakity@xxxxxxxxxxx]
>> Sent: Wednesday, March 16, 2011 8:22 PM
>> To: Nath, Arindam
>> Cc: cjb@xxxxxxxxxx; zhangfei.gao@xxxxxxxxx; subhashj@xxxxxxxxxxxxxx;
>> linux-mmc@xxxxxxxxxxxxxxx; Su, Henry; Lu, Aaron; anath.amd@xxxxxxxxx
>> Subject: Re: [PATCH v2 07/12] mmc: sd: set current limit for uhs cards
>> 
>> 
>> On Mar 16, 2011, at 7:32 AM, Nath, Arindam wrote:
>> 
>>> Hi Philip,
>>> 
>>> 
>>>> -----Original Message-----
>>>> From: Philip Rakity [mailto:prakity@xxxxxxxxxxx]
>>>> Sent: Wednesday, March 16, 2011 7:56 PM
>>>> To: Nath, Arindam
>>>> Cc: cjb@xxxxxxxxxx; zhangfei.gao@xxxxxxxxx; subhashj@xxxxxxxxxxxxxx;
>>>> linux-mmc@xxxxxxxxxxxxxxx; Su, Henry; Lu, Aaron; anath.amd@xxxxxxxxx
>>>> Subject: Re: [PATCH v2 07/12] mmc: sd: set current limit for uhs
>> cards
>>>> 
>>>> 
>>>> On Mar 4, 2011, at 3:32 AM, Arindam Nath wrote:
>>>> 
>>>>> We decide on the current limit to be set for the card based on the
>>>>> Capability of Host Controller to provide current at 1.8V
>> signalling,
>>>>> and the maximum current limit of the card as indicated by CMD6
>>>>> mode 0. We then set the current limit for the card using CMD6 mode
>> 1.
>>>>> 
>>>>> Signed-off-by: Arindam Nath <arindam.nath@xxxxxxx>
>>>>> ---
>>>>> drivers/mmc/core/sd.c    |   45
>>>> +++++++++++++++++++++++++++++++++++++++++++++
>>>>> drivers/mmc/host/sdhci.c |   24 ++++++++++++++++++++++++
>>>>> include/linux/mmc/card.h |    9 +++++++++
>>>>> include/linux/mmc/host.h |    1 +
>>>>> 4 files changed, 79 insertions(+), 0 deletions(-)
>>>>> 
>>>>> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
>>>>> index ec0d8e6..df98a2c 100644
>>>>> --- a/drivers/mmc/core/sd.c
>>>>> +++ b/drivers/mmc/core/sd.c
>>>>> @@ -550,6 +550,46 @@ static int sd_set_bus_speed_mode(struct
>> mmc_card
>>>> *card, u8 *status)
>>>>> 	return 0;
>>>>> }
>>>>> 
>>>>> +static int sd_set_current_limit(struct mmc_card *card, u8 *status)
>>>>> +{
>>>>> +	struct mmc_host *host = card->host;
>>>>> +	int mmc_host_max_current_180, current_limit;
>>>>> +	int err;
>>>>> +
>>>>> +	/* sanity check */
>>>>> +	if (!host->ops->get_max_current_180)
>>>>> +		return 0;
>>>> 
>>>> a better name would be get_max_current rather than
>> get_max_current_180
>>> 
>>> The Max Current Capabilities register reports maximum currents for
>> 1.8V, 3.0V and 3.3V. Since we are only interested in the maximum
>> current at 1.8V, so I have added *_180 to the variable names to make it
>> explicit.
>> 
>> understand but that is the usage now and if we need to extend the code
>> the name becomes misleading.
> 
> Okay. I will remove *_180 in next version.
> 
>>> 
>>>> 
>>>> do you want a test for get_max_current_180 < 400 ? and return 0
>> have
>>>> it do the switch
>>>> by setting the value ?
>>> 
>>> As mentioned in the Physical Layer spec v3.01, <400mA falls under the
>> default current limit, so we don't need to set it in case any or all of
>> the above conditions fail.
>> 
>> if future cards have memory or power is not removed they will they
>> retain the old setting ?  if so better to explicitly initialize.
> 
> Can you please elaborate this a little further?

Power to the sd slot is supplied via a regulator.  This is turned on at power on.
sometime in the future a reboot is done.  power is NOT removed.  The device does not reset
into the default state.   Have seen this on some boards.

> 
> Thanks,
> Arindam
> 
>> 
>>> 
>>> Thanks,
>>> Arindam
>>> 
>>>>> +
>>>>> +	/* Maximum current supported by host at 1.8V */
>>>>> +	mmc_host_max_current_180 = host->ops->get_max_current_180(host);
>>>>> +
>>>>> +	if (mmc_host_max_current_180 >= 800) {
>>>>> +		if (card->sw_caps.uhs_curr_limit & SD_MAX_CURRENT_800)
>>>>> +			current_limit = SD_SET_CURRENT_LIMIT_800;
>>>>> +		else if (card->sw_caps.uhs_curr_limit & SD_MAX_CURRENT_600)
>>>>> +			current_limit = SD_SET_CURRENT_LIMIT_600;
>>>>> +		else if (card->sw_caps.uhs_curr_limit & SD_MAX_CURRENT_400)
>>>>> +			current_limit = SD_SET_CURRENT_LIMIT_400;
>>>>> +	} else if (mmc_host_max_current_180 >= 600) {
>>>>> +		if (card->sw_caps.uhs_curr_limit & SD_MAX_CURRENT_600)
>>>>> +			current_limit = SD_SET_CURRENT_LIMIT_600;
>>>>> +		else if (card->sw_caps.uhs_curr_limit & SD_MAX_CURRENT_400)
>>>>> +			current_limit = SD_SET_CURRENT_LIMIT_400;
>>>>> +	} else if (mmc_host_max_current_180 >= 400)
>>>>> +		if (card->sw_caps.uhs_curr_limit & SD_MAX_CURRENT_400)
>>>>> +			current_limit = SD_SET_CURRENT_LIMIT_400;
>>>> 
>>>> or
>>>>       else
>>>>              current_limit = SD_SET_CURRENT_LIMIT_200;
>>>>> +
>>>>> +	err = mmc_sd_switch(card, 1, 3, current_limit, status);
>>>>> +	if (err)
>>>>> +		return err;
>>>>> +
>>>>> +	if (((status[15] >> 4) & 0x0F) != current_limit)
>>>>> +		printk(KERN_WARNING "%s: Problem setting current limit!\n",
>>>>> +			mmc_hostname(card->host));
>>>>> +
>>>>> +	return 0;
>>>>> +}
>>>>> +
>>>>> /*
>>>>> * UHS-I specific initialization procedure
>>>>> */
>>>>> @@ -590,6 +630,11 @@ static int mmc_sd_init_uhs_card(struct
>> mmc_card
>>>> *card)
>>>>> 
>>>>> 	/* Set bus speed mode of the card */
>>>>> 	err = sd_set_bus_speed_mode(card, status);
>>>>> +	if (err)
>>>>> +		goto out;
>>>>> +
>>>>> +	/* Set current limit for the card */
>>>>> +	err = sd_set_current_limit(card, status);
>>>>> 
>>>>> out:
>>>>> 	kfree(status);
>>>>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>>>>> index f127fa2..245cc39 100644
>>>>> --- a/drivers/mmc/host/sdhci.c
>>>>> +++ b/drivers/mmc/host/sdhci.c
>>>>> @@ -1462,12 +1462,36 @@ static int
>>>> sdhci_start_signal_voltage_switch(struct mmc_host *mmc)
>>>>> 	return -EAGAIN;
>>>>> }
>>>>> 
>>>> 
>>>> better name is sdhci_get_max_current
>>>> 
>>>>> +static int sdhci_get_max_current_180(struct mmc_host *mmc)
>>>>> +{
>>>>> +	struct sdhci_host *host;
>>>>> +	u32 max_current_caps;
>>>>> +	unsigned long flags;
>>>>> +	int max_current_180;
>>>>> +
>>>>> +	host = mmc_priv(mmc);
>>>>> +
>>>>> +	spin_lock_irqsave(&host->lock, flags);
>>>>> +
>>>>> +	max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT);
>>>>> +
>>>>> +	spin_unlock_irqrestore(&host->lock, flags);
>>>>> +
>>>>> +	/* Maximum current is 4 times the register value for 1.8V */
>>>>> +	max_current_180 = ((max_current_caps &
>>>> SDHCI_MAX_CURRENT_180_MASK) >>
>>>>> +			   SDHCI_MAX_CURRENT_180_SHIFT) *
>>>>> +			   SDHCI_MAX_CURRENT_MULTIPLIER;
>>>> 
>>>> SDHCI_MAX_CURRENT_SHIFT is better name.
>>>> 
>>>>> +
>>>>> +	return max_current_180;
>>>>> +}
>>>>> +
>>>>> static const struct mmc_host_ops sdhci_ops = {
>>>>> 	.request	= sdhci_request,
>>>>> 	.set_ios	= sdhci_set_ios,
>>>>> 	.get_ro		= sdhci_get_ro,
>>>>> 	.enable_sdio_irq = sdhci_enable_sdio_irq,
>>>>> 	.start_signal_voltage_switch	=
>>>> sdhci_start_signal_voltage_switch,
>>>>> +	.get_max_current_180		= sdhci_get_max_current_180,
>>>> 
>>>> .get_max_current = sdhci_get_max_current;
>>>>> };
>>>>> 
>>>>> 
>>>> 
>> /**********************************************************************
>>>> *******\
>>>>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>>>>> index 0b24c41..a6811ae 100644
>>>>> --- a/include/linux/mmc/card.h
>>>>> +++ b/include/linux/mmc/card.h
>>>>> @@ -98,6 +98,15 @@ struct sd_switch_caps {
>>>>> #define SD_DRIVER_TYPE_C	0x04
>>>>> #define SD_DRIVER_TYPE_D	0x08
>>>>> 	unsigned int		uhs_curr_limit;
>>>>> +#define SD_SET_CURRENT_LIMIT_200	0
>>>>> +#define SD_SET_CURRENT_LIMIT_400	1
>>>>> +#define SD_SET_CURRENT_LIMIT_600	2
>>>>> +#define SD_SET_CURRENT_LIMIT_800	3
>>>>> +
>>>>> +#define SD_MAX_CURRENT_200	(1 << SD_SET_CURRENT_LIMIT_200)
>>>>> +#define SD_MAX_CURRENT_400	(1 << SD_SET_CURRENT_LIMIT_400)
>>>>> +#define SD_MAX_CURRENT_600	(1 << SD_SET_CURRENT_LIMIT_600)
>>>>> +#define SD_MAX_CURRENT_800	(1 << SD_SET_CURRENT_LIMIT_800)
>>>>> };
>>>>> 
>>>>> struct sdio_cccr {
>>>>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>>>>> index 4dfff6d..e84cd05 100644
>>>>> --- a/include/linux/mmc/host.h
>>>>> +++ b/include/linux/mmc/host.h
>>>>> @@ -128,6 +128,7 @@ struct mmc_host_ops {
>>>>> 	void	(*init_card)(struct mmc_host *host, struct mmc_card *card);
>>>>> 
>>>>> 	int	(*start_signal_voltage_switch)(struct mmc_host *host);
>>>>> +	int	(*get_max_current_180)(struct mmc_host *mmc);
>>>>> };
>>>>> 
>>>>> struct mmc_card;
>>>>> --
>>>>> 1.7.1
>>>>> 
>>>> 
>>> 
>>> 
>> 
> 
> 

--
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