mirror of
https://github.com/torvalds/linux.git
synced 2024-10-31 01:01:52 +00:00
mmc: sd: Fix sd current limit setting
Host has different current capabilities at different voltages, we need to record these settings seperately. The defined voltages are 1.8/3.0/3.3. For other voltages, we do not touch current limit setting. Before we set the current limit for the sd card, find out the host's operating voltage first and then find out the current capabilities of the host at that voltage to set the current limit. Signed-off-by: Aaron Lu <aaron.lu@amd.com> Reviewed-by: Philip Rakity <prakity@marvell.com> Signed-off-by: Chris Ball <cjb@laptop.org>
This commit is contained in:
parent
94c1814945
commit
55c4665ea0
@ -517,15 +517,54 @@ static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get host's max current setting at its current voltage */
|
||||
static u32 sd_get_host_max_current(struct mmc_host *host)
|
||||
{
|
||||
u32 voltage, max_current;
|
||||
|
||||
voltage = 1 << host->ios.vdd;
|
||||
switch (voltage) {
|
||||
case MMC_VDD_165_195:
|
||||
max_current = host->max_current_180;
|
||||
break;
|
||||
case MMC_VDD_29_30:
|
||||
case MMC_VDD_30_31:
|
||||
max_current = host->max_current_300;
|
||||
break;
|
||||
case MMC_VDD_32_33:
|
||||
case MMC_VDD_33_34:
|
||||
max_current = host->max_current_330;
|
||||
break;
|
||||
default:
|
||||
max_current = 0;
|
||||
}
|
||||
|
||||
return max_current;
|
||||
}
|
||||
|
||||
static int sd_set_current_limit(struct mmc_card *card, u8 *status)
|
||||
{
|
||||
int current_limit = SD_SET_CURRENT_NO_CHANGE;
|
||||
int err;
|
||||
u32 max_current;
|
||||
|
||||
/*
|
||||
* Current limit switch is only defined for SDR50, SDR104, and DDR50
|
||||
* bus speed modes. For other bus speed modes, we do not change the
|
||||
* current limit.
|
||||
*/
|
||||
if ((card->sd_bus_speed != UHS_SDR50_BUS_SPEED) &&
|
||||
(card->sd_bus_speed != UHS_SDR104_BUS_SPEED) &&
|
||||
(card->sd_bus_speed != UHS_DDR50_BUS_SPEED))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Host has different current capabilities when operating at
|
||||
* different voltages, so find out its max current first.
|
||||
*/
|
||||
max_current = sd_get_host_max_current(card->host);
|
||||
|
||||
/*
|
||||
* We only check host's capability here, if we set a limit that is
|
||||
* higher than the card's maximum current, the card will be using its
|
||||
* maximum current, e.g. if the card's maximum current is 300ma, and
|
||||
@ -533,18 +572,14 @@ static int sd_set_current_limit(struct mmc_card *card, u8 *status)
|
||||
* when we set current limit to 400/600/800ma, the card will draw its
|
||||
* maximum 300ma from the host.
|
||||
*/
|
||||
if ((card->sd_bus_speed == UHS_SDR50_BUS_SPEED) ||
|
||||
(card->sd_bus_speed == UHS_SDR104_BUS_SPEED) ||
|
||||
(card->sd_bus_speed == UHS_DDR50_BUS_SPEED)) {
|
||||
if (card->host->caps & MMC_CAP_MAX_CURRENT_800)
|
||||
current_limit = SD_SET_CURRENT_LIMIT_800;
|
||||
else if (card->host->caps & MMC_CAP_MAX_CURRENT_600)
|
||||
current_limit = SD_SET_CURRENT_LIMIT_600;
|
||||
else if (card->host->caps & MMC_CAP_MAX_CURRENT_400)
|
||||
current_limit = SD_SET_CURRENT_LIMIT_400;
|
||||
else if (card->host->caps & MMC_CAP_MAX_CURRENT_200)
|
||||
current_limit = SD_SET_CURRENT_LIMIT_200;
|
||||
}
|
||||
if (max_current >= 800)
|
||||
current_limit = SD_SET_CURRENT_LIMIT_800;
|
||||
else if (max_current >= 600)
|
||||
current_limit = SD_SET_CURRENT_LIMIT_600;
|
||||
else if (max_current >= 400)
|
||||
current_limit = SD_SET_CURRENT_LIMIT_400;
|
||||
else if (max_current >= 200)
|
||||
current_limit = SD_SET_CURRENT_LIMIT_200;
|
||||
|
||||
if (current_limit != SD_SET_CURRENT_NO_CHANGE) {
|
||||
err = mmc_sd_switch(card, 1, 3, current_limit, status);
|
||||
@ -677,6 +712,7 @@ struct device_type sd_type = {
|
||||
int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
|
||||
{
|
||||
int err;
|
||||
u32 max_current;
|
||||
|
||||
/*
|
||||
* Since we're changing the OCR value, we seem to
|
||||
@ -704,9 +740,12 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))
|
||||
ocr |= SD_OCR_S18R;
|
||||
|
||||
/* If the host can supply more than 150mA, XPC should be set to 1. */
|
||||
if (host->caps & (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
|
||||
MMC_CAP_SET_XPC_180))
|
||||
/*
|
||||
* If the host can supply more than 150mA at current voltage,
|
||||
* XPC should be set to 1.
|
||||
*/
|
||||
max_current = sd_get_host_max_current(host);
|
||||
if (max_current > 150)
|
||||
ocr |= SD_OCR_XPC;
|
||||
|
||||
try_again:
|
||||
|
@ -2906,53 +2906,28 @@ int sdhci_add_host(struct sdhci_host *host)
|
||||
}
|
||||
|
||||
if (caps[0] & SDHCI_CAN_VDD_330) {
|
||||
int max_current_330;
|
||||
|
||||
ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;
|
||||
|
||||
max_current_330 = ((max_current_caps &
|
||||
mmc->max_current_330 = ((max_current_caps &
|
||||
SDHCI_MAX_CURRENT_330_MASK) >>
|
||||
SDHCI_MAX_CURRENT_330_SHIFT) *
|
||||
SDHCI_MAX_CURRENT_MULTIPLIER;
|
||||
|
||||
if (max_current_330 > 150)
|
||||
mmc->caps |= MMC_CAP_SET_XPC_330;
|
||||
}
|
||||
if (caps[0] & SDHCI_CAN_VDD_300) {
|
||||
int max_current_300;
|
||||
|
||||
ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31;
|
||||
|
||||
max_current_300 = ((max_current_caps &
|
||||
mmc->max_current_300 = ((max_current_caps &
|
||||
SDHCI_MAX_CURRENT_300_MASK) >>
|
||||
SDHCI_MAX_CURRENT_300_SHIFT) *
|
||||
SDHCI_MAX_CURRENT_MULTIPLIER;
|
||||
|
||||
if (max_current_300 > 150)
|
||||
mmc->caps |= MMC_CAP_SET_XPC_300;
|
||||
}
|
||||
if (caps[0] & SDHCI_CAN_VDD_180) {
|
||||
int max_current_180;
|
||||
|
||||
ocr_avail |= MMC_VDD_165_195;
|
||||
|
||||
max_current_180 = ((max_current_caps &
|
||||
mmc->max_current_180 = ((max_current_caps &
|
||||
SDHCI_MAX_CURRENT_180_MASK) >>
|
||||
SDHCI_MAX_CURRENT_180_SHIFT) *
|
||||
SDHCI_MAX_CURRENT_MULTIPLIER;
|
||||
|
||||
if (max_current_180 > 150)
|
||||
mmc->caps |= MMC_CAP_SET_XPC_180;
|
||||
|
||||
/* Maximum current capabilities of the host at 1.8V */
|
||||
if (max_current_180 >= 800)
|
||||
mmc->caps |= MMC_CAP_MAX_CURRENT_800;
|
||||
else if (max_current_180 >= 600)
|
||||
mmc->caps |= MMC_CAP_MAX_CURRENT_600;
|
||||
else if (max_current_180 >= 400)
|
||||
mmc->caps |= MMC_CAP_MAX_CURRENT_400;
|
||||
else if (max_current_180 >= 200)
|
||||
mmc->caps |= MMC_CAP_MAX_CURRENT_200;
|
||||
}
|
||||
|
||||
mmc->ocr_avail = ocr_avail;
|
||||
|
@ -189,6 +189,9 @@ struct mmc_host {
|
||||
u32 ocr_avail_sd; /* SD-specific OCR */
|
||||
u32 ocr_avail_mmc; /* MMC-specific OCR */
|
||||
struct notifier_block pm_notify;
|
||||
u32 max_current_330;
|
||||
u32 max_current_300;
|
||||
u32 max_current_180;
|
||||
|
||||
#define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */
|
||||
#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
|
||||
@ -232,16 +235,9 @@ struct mmc_host {
|
||||
#define MMC_CAP_UHS_SDR50 (1 << 17) /* Host supports UHS SDR50 mode */
|
||||
#define MMC_CAP_UHS_SDR104 (1 << 18) /* Host supports UHS SDR104 mode */
|
||||
#define MMC_CAP_UHS_DDR50 (1 << 19) /* Host supports UHS DDR50 mode */
|
||||
#define MMC_CAP_SET_XPC_330 (1 << 20) /* Host supports >150mA current at 3.3V */
|
||||
#define MMC_CAP_SET_XPC_300 (1 << 21) /* Host supports >150mA current at 3.0V */
|
||||
#define MMC_CAP_SET_XPC_180 (1 << 22) /* Host supports >150mA current at 1.8V */
|
||||
#define MMC_CAP_DRIVER_TYPE_A (1 << 23) /* Host supports Driver Type A */
|
||||
#define MMC_CAP_DRIVER_TYPE_C (1 << 24) /* Host supports Driver Type C */
|
||||
#define MMC_CAP_DRIVER_TYPE_D (1 << 25) /* Host supports Driver Type D */
|
||||
#define MMC_CAP_MAX_CURRENT_200 (1 << 26) /* Host max current limit is 200mA */
|
||||
#define MMC_CAP_MAX_CURRENT_400 (1 << 27) /* Host max current limit is 400mA */
|
||||
#define MMC_CAP_MAX_CURRENT_600 (1 << 28) /* Host max current limit is 600mA */
|
||||
#define MMC_CAP_MAX_CURRENT_800 (1 << 29) /* Host max current limit is 800mA */
|
||||
#define MMC_CAP_CMD23 (1 << 30) /* CMD23 supported. */
|
||||
#define MMC_CAP_HW_RESET (1 << 31) /* Hardware reset */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user