Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c959a6b0 authored by Adrian Hunter's avatar Adrian Hunter Committed by Ulf Hansson
Browse files

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: default avatarAdrian Hunter <adrian.hunter@intel.com>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
Tested-by: default avatarLudovic Desroches <ludovic.desroches@microchip.com>
parent ac9f67b5
Loading
Loading
Loading
Loading
+90 −0
Original line number Diff line number Diff line
@@ -259,6 +259,77 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {
	.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)
{
	u8 reg;
@@ -359,8 +430,19 @@ static int bxt_get_cd(struct mmc_host *mmc)
	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)
{
	byt_read_dsm(slot);
	slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
				 MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
				 MMC_CAP_CMD_DURING_TFR |
@@ -405,6 +487,8 @@ static int ni_byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
{
	int err;

	byt_read_dsm(slot);

	err = ni_set_max_freq(slot);
	if (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)
{
	byt_read_dsm(slot);
	slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE |
				 MMC_CAP_WAIT_WHILE_BUSY;
	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)
{
	byt_read_dsm(slot);
	slot->host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
	slot->cd_idx = 0;
	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_STOP_WITH_TC,
	.ops		= &sdhci_intel_byt_ops,
	.priv_size	= sizeof(struct intel_host),
};

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,
	.probe_slot	= ni_byt_sdio_probe_slot,
	.ops		= &sdhci_intel_byt_ops,
	.priv_size	= sizeof(struct intel_host),
};

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,
	.probe_slot	= byt_sdio_probe_slot,
	.ops		= &sdhci_intel_byt_ops,
	.priv_size	= sizeof(struct intel_host),
};

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,
	.probe_slot	= byt_sd_probe_slot,
	.ops		= &sdhci_intel_byt_ops,
	.priv_size	= sizeof(struct intel_host),
};

/* Define Host controllers for Intel Merrifield platform */