mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 09:19:51 +00:00
mmc: sdhci-pci: Don't re-tune with runtime pm for some Intel devices
Make use of an Intel ACPI _DSM that indicates if re-tuning is needed after D3. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Tested-by: Ludovic Desroches <ludovic.desroches@microchip.com>
This commit is contained in:
parent
ac9f67b580
commit
c959a6b00f
1 changed files with 90 additions and 0 deletions
|
@ -259,6 +259,77 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {
|
||||||
.probe_slot = pch_hc_probe_slot,
|
.probe_slot = pch_hc_probe_slot,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
INTEL_DSM_FNS = 0,
|
||||||
|
INTEL_DSM_D3_RETUNE = 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct intel_host {
|
||||||
|
u32 dsm_fns;
|
||||||
|
bool d3_retune;
|
||||||
|
};
|
||||||
|
|
||||||
|
const u8 intel_dsm_uuid[] = {
|
||||||
|
0xA5, 0x3E, 0xC1, 0xF6, 0xCD, 0x65, 0x1F, 0x46,
|
||||||
|
0xAB, 0x7A, 0x29, 0xF7, 0xE8, 0xD5, 0xBD, 0x61,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __intel_dsm(struct intel_host *intel_host, struct device *dev,
|
||||||
|
unsigned int fn, u32 *result)
|
||||||
|
{
|
||||||
|
union acpi_object *obj;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), intel_dsm_uuid, 0, fn, NULL);
|
||||||
|
if (!obj)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
if (obj->type != ACPI_TYPE_BUFFER || obj->buffer.length < 1) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj->buffer.length >= 4)
|
||||||
|
*result = *(u32 *)obj->buffer.pointer;
|
||||||
|
else if (obj->buffer.length >= 2)
|
||||||
|
*result = *(u16 *)obj->buffer.pointer;
|
||||||
|
else
|
||||||
|
*result = *(u8 *)obj->buffer.pointer;
|
||||||
|
out:
|
||||||
|
ACPI_FREE(obj);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int intel_dsm(struct intel_host *intel_host, struct device *dev,
|
||||||
|
unsigned int fn, u32 *result)
|
||||||
|
{
|
||||||
|
if (fn > 31 || !(intel_host->dsm_fns & (1 << fn)))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
return __intel_dsm(intel_host, dev, fn, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void intel_dsm_init(struct intel_host *intel_host, struct device *dev,
|
||||||
|
struct mmc_host *mmc)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
err = __intel_dsm(intel_host, dev, INTEL_DSM_FNS, &intel_host->dsm_fns);
|
||||||
|
if (err) {
|
||||||
|
pr_debug("%s: DSM not supported, error %d\n",
|
||||||
|
mmc_hostname(mmc), err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_debug("%s: DSM function mask %#x\n",
|
||||||
|
mmc_hostname(mmc), intel_host->dsm_fns);
|
||||||
|
|
||||||
|
err = intel_dsm(intel_host, dev, INTEL_DSM_D3_RETUNE, &val);
|
||||||
|
intel_host->d3_retune = err ? true : !!val;
|
||||||
|
}
|
||||||
|
|
||||||
static void sdhci_pci_int_hw_reset(struct sdhci_host *host)
|
static void sdhci_pci_int_hw_reset(struct sdhci_host *host)
|
||||||
{
|
{
|
||||||
u8 reg;
|
u8 reg;
|
||||||
|
@ -359,8 +430,19 @@ static int bxt_get_cd(struct mmc_host *mmc)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void byt_read_dsm(struct sdhci_pci_slot *slot)
|
||||||
|
{
|
||||||
|
struct intel_host *intel_host = sdhci_pci_priv(slot);
|
||||||
|
struct device *dev = &slot->chip->pdev->dev;
|
||||||
|
struct mmc_host *mmc = slot->host->mmc;
|
||||||
|
|
||||||
|
intel_dsm_init(intel_host, dev, mmc);
|
||||||
|
slot->chip->rpm_retune = intel_host->d3_retune;
|
||||||
|
}
|
||||||
|
|
||||||
static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
|
static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
|
||||||
{
|
{
|
||||||
|
byt_read_dsm(slot);
|
||||||
slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
|
slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
|
||||||
MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
|
MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
|
||||||
MMC_CAP_CMD_DURING_TFR |
|
MMC_CAP_CMD_DURING_TFR |
|
||||||
|
@ -405,6 +487,8 @@ static int ni_byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
byt_read_dsm(slot);
|
||||||
|
|
||||||
err = ni_set_max_freq(slot);
|
err = ni_set_max_freq(slot);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
@ -416,6 +500,7 @@ static int ni_byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
|
||||||
|
|
||||||
static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
|
static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
|
||||||
{
|
{
|
||||||
|
byt_read_dsm(slot);
|
||||||
slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE |
|
slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE |
|
||||||
MMC_CAP_WAIT_WHILE_BUSY;
|
MMC_CAP_WAIT_WHILE_BUSY;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -423,6 +508,7 @@ static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
|
||||||
|
|
||||||
static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
|
static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
|
||||||
{
|
{
|
||||||
|
byt_read_dsm(slot);
|
||||||
slot->host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
|
slot->host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
|
||||||
slot->cd_idx = 0;
|
slot->cd_idx = 0;
|
||||||
slot->cd_override_level = true;
|
slot->cd_override_level = true;
|
||||||
|
@ -488,6 +574,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
|
||||||
SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 |
|
SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 |
|
||||||
SDHCI_QUIRK2_STOP_WITH_TC,
|
SDHCI_QUIRK2_STOP_WITH_TC,
|
||||||
.ops = &sdhci_intel_byt_ops,
|
.ops = &sdhci_intel_byt_ops,
|
||||||
|
.priv_size = sizeof(struct intel_host),
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = {
|
static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = {
|
||||||
|
@ -497,6 +584,7 @@ static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = {
|
||||||
.allow_runtime_pm = true,
|
.allow_runtime_pm = true,
|
||||||
.probe_slot = ni_byt_sdio_probe_slot,
|
.probe_slot = ni_byt_sdio_probe_slot,
|
||||||
.ops = &sdhci_intel_byt_ops,
|
.ops = &sdhci_intel_byt_ops,
|
||||||
|
.priv_size = sizeof(struct intel_host),
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
|
static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
|
||||||
|
@ -506,6 +594,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
|
||||||
.allow_runtime_pm = true,
|
.allow_runtime_pm = true,
|
||||||
.probe_slot = byt_sdio_probe_slot,
|
.probe_slot = byt_sdio_probe_slot,
|
||||||
.ops = &sdhci_intel_byt_ops,
|
.ops = &sdhci_intel_byt_ops,
|
||||||
|
.priv_size = sizeof(struct intel_host),
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
|
static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
|
||||||
|
@ -517,6 +606,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
|
||||||
.own_cd_for_runtime_pm = true,
|
.own_cd_for_runtime_pm = true,
|
||||||
.probe_slot = byt_sd_probe_slot,
|
.probe_slot = byt_sd_probe_slot,
|
||||||
.ops = &sdhci_intel_byt_ops,
|
.ops = &sdhci_intel_byt_ops,
|
||||||
|
.priv_size = sizeof(struct intel_host),
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Define Host controllers for Intel Merrifield platform */
|
/* Define Host controllers for Intel Merrifield platform */
|
||||||
|
|
Loading…
Reference in a new issue