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]

 



Hi Subhash,


> -----Original Message-----
> From: Subhash Jadavani [mailto:subhashj@xxxxxxxxxxxxxx]
> Sent: Monday, March 21, 2011 1:14 PM
> To: Nath, Arindam; cjb@xxxxxxxxxx
> Cc: zhangfei.gao@xxxxxxxxx; prakity@xxxxxxxxxxx; linux-
> mmc@xxxxxxxxxxxxxxx; Su, Henry; Lu, Aaron; anath.amd@xxxxxxxxx
> Subject: RE: [PATCH v2 07/12] mmc: sd: set current limit for uhs cards
> 
> 
> 
> > -----Original Message-----
> > From: Arindam Nath [mailto:anath.amd@xxxxxxxxx] On Behalf Of Arindam
> > Nath
> > Sent: Friday, March 04, 2011 5:03 PM
> > To: cjb@xxxxxxxxxx
> > Cc: zhangfei.gao@xxxxxxxxx; prakity@xxxxxxxxxxx;
> > subhashj@xxxxxxxxxxxxxx; linux-mmc@xxxxxxxxxxxxxxx; henry.su@xxxxxxx;
> > aaron.lu@xxxxxxx; anath.amd@xxxxxxxxx; Arindam Nath
> > Subject: [PATCH v2 07/12] mmc: sd: set current limit for uhs cards
> >
> > 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;
> > +
> > +	/* 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;
> > +
> > +	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));
> 
> This is what SD3.01 spec says:
> "Current limit switch is only for SDR50, SDR104 and DDR50. Current
> limit
> does not act on the card in SDR12 and SDR25 modes."
> 
> But in this function you are not checking for the currently selected
> bus
> speed mode. If let's say you are in SDR12/SDR25 mode and if host
> supports
> MAX_CURRENT_800 then this function will try to the current limit to 800
> but
> card won't switch to it as SDR12/SDR25 mode doen't allow the current
> switch.
> 
> So basically your following check will always print the warning for
> SDR12/SDR25 mode.
> 
> 	if (((status[15] >> 4) & 0x0F) != current_limit)
> 		printk(KERN_WARNING "%s: Problem setting current limit!\n",
> 			mmc_hostname(card->host));
> 
> So in this function you should also check the current bus speed mode.
> If
> current bus_speed_mode is SDR12/SDR25/legacy then you should select the
> current limit to 200ma and for SDR104/SDR50/DDR50, you should select it
> depending on the host's Max. current limit.

Thanks for the correction. Yes, I verified from the spec what you said. I will modify the code accordingly.

Thanks,
Arindam

> 
> 
> > +
> > +	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;
> >  }
> >
> > +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;
> > +
> > +	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,
> >  };
> >
> >
> >
> /**********************************************************************
> > *******\
> > 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