[V3] mmc: sdhci-pci: Workaround GLK firmware failing to restore the tuning value
diff mbox series

Message ID 20181119125307.22486-1-adrian.hunter@intel.com
State New
Headers show
Series
  • [V3] mmc: sdhci-pci: Workaround GLK firmware failing to restore the tuning value
Related show

Commit Message

Adrian Hunter Nov. 19, 2018, 12:53 p.m. UTC
GLK firmware can indicate that the tuning value will be restored after
runtime suspend, but not actually do that. Add a workaround that detects
such cases, and lets the driver do re-tuning instead.

Reported-by: Anisse Astier <anisse@astier.eu>
Tested-by: Anisse Astier <anisse@astier.eu>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: stable@vger.kernel.org
---


Changes in V3:

	Added Reported-by/Tested-by: Anisse Astier
	Added Cc: stable

Changes in V2:

	Use bitfield macros
	Tweak the rx delay value


 drivers/mmc/host/sdhci-pci-core.c | 79 ++++++++++++++++++++++++++++++-
 1 file changed, 77 insertions(+), 2 deletions(-)

Comments

Ulf Hansson Nov. 19, 2018, 1:19 p.m. UTC | #1
On 19 November 2018 at 13:53, Adrian Hunter <adrian.hunter@intel.com> wrote:
> GLK firmware can indicate that the tuning value will be restored after
> runtime suspend, but not actually do that. Add a workaround that detects
> such cases, and lets the driver do re-tuning instead.
>
> Reported-by: Anisse Astier <anisse@astier.eu>
> Tested-by: Anisse Astier <anisse@astier.eu>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> Cc: stable@vger.kernel.org

Thanks, applied for fixes!

Kind regards
Uffe

> ---
>
>
> Changes in V3:
>
>         Added Reported-by/Tested-by: Anisse Astier
>         Added Cc: stable
>
> Changes in V2:
>
>         Use bitfield macros
>         Tweak the rx delay value
>
>
>  drivers/mmc/host/sdhci-pci-core.c | 79 ++++++++++++++++++++++++++++++-
>  1 file changed, 77 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
> index e53333c695b3..c4115bae5db1 100644
> --- a/drivers/mmc/host/sdhci-pci-core.c
> +++ b/drivers/mmc/host/sdhci-pci-core.c
> @@ -12,6 +12,7 @@
>   *     - JMicron (hardware and technical support)
>   */
>
> +#include <linux/bitfield.h>
>  #include <linux/string.h>
>  #include <linux/delay.h>
>  #include <linux/highmem.h>
> @@ -462,6 +463,9 @@ struct intel_host {
>         u32     dsm_fns;
>         int     drv_strength;
>         bool    d3_retune;
> +       bool    rpm_retune_ok;
> +       u32     glk_rx_ctrl1;
> +       u32     glk_tun_val;
>  };
>
>  static const guid_t intel_dsm_guid =
> @@ -791,6 +795,77 @@ static int glk_emmc_add_host(struct sdhci_pci_slot *slot)
>         return ret;
>  }
>
> +#ifdef CONFIG_PM
> +#define GLK_RX_CTRL1   0x834
> +#define GLK_TUN_VAL    0x840
> +#define GLK_PATH_PLL   GENMASK(13, 8)
> +#define GLK_DLY                GENMASK(6, 0)
> +/* Workaround firmware failing to restore the tuning value */
> +static void glk_rpm_retune_wa(struct sdhci_pci_chip *chip, bool susp)
> +{
> +       struct sdhci_pci_slot *slot = chip->slots[0];
> +       struct intel_host *intel_host = sdhci_pci_priv(slot);
> +       struct sdhci_host *host = slot->host;
> +       u32 glk_rx_ctrl1;
> +       u32 glk_tun_val;
> +       u32 dly;
> +
> +       if (intel_host->rpm_retune_ok || !mmc_can_retune(host->mmc))
> +               return;
> +
> +       glk_rx_ctrl1 = sdhci_readl(host, GLK_RX_CTRL1);
> +       glk_tun_val = sdhci_readl(host, GLK_TUN_VAL);
> +
> +       if (susp) {
> +               intel_host->glk_rx_ctrl1 = glk_rx_ctrl1;
> +               intel_host->glk_tun_val = glk_tun_val;
> +               return;
> +       }
> +
> +       if (!intel_host->glk_tun_val)
> +               return;
> +
> +       if (glk_rx_ctrl1 != intel_host->glk_rx_ctrl1) {
> +               intel_host->rpm_retune_ok = true;
> +               return;
> +       }
> +
> +       dly = FIELD_PREP(GLK_DLY, FIELD_GET(GLK_PATH_PLL, glk_rx_ctrl1) +
> +                                 (intel_host->glk_tun_val << 1));
> +       if (dly == FIELD_GET(GLK_DLY, glk_rx_ctrl1))
> +               return;
> +
> +       glk_rx_ctrl1 = (glk_rx_ctrl1 & ~GLK_DLY) | dly;
> +       sdhci_writel(host, glk_rx_ctrl1, GLK_RX_CTRL1);
> +
> +       intel_host->rpm_retune_ok = true;
> +       chip->rpm_retune = true;
> +       mmc_retune_needed(host->mmc);
> +       pr_info("%s: Requiring re-tune after rpm resume", mmc_hostname(host->mmc));
> +}
> +
> +static void glk_rpm_retune_chk(struct sdhci_pci_chip *chip, bool susp)
> +{
> +       if (chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_EMMC &&
> +           !chip->rpm_retune)
> +               glk_rpm_retune_wa(chip, susp);
> +}
> +
> +static int glk_runtime_suspend(struct sdhci_pci_chip *chip)
> +{
> +       glk_rpm_retune_chk(chip, true);
> +
> +       return sdhci_cqhci_runtime_suspend(chip);
> +}
> +
> +static int glk_runtime_resume(struct sdhci_pci_chip *chip)
> +{
> +       glk_rpm_retune_chk(chip, false);
> +
> +       return sdhci_cqhci_runtime_resume(chip);
> +}
> +#endif
> +
>  #ifdef CONFIG_ACPI
>  static int ni_set_max_freq(struct sdhci_pci_slot *slot)
>  {
> @@ -879,8 +954,8 @@ static const struct sdhci_pci_fixes sdhci_intel_glk_emmc = {
>         .resume                 = sdhci_cqhci_resume,
>  #endif
>  #ifdef CONFIG_PM
> -       .runtime_suspend        = sdhci_cqhci_runtime_suspend,
> -       .runtime_resume         = sdhci_cqhci_runtime_resume,
> +       .runtime_suspend        = glk_runtime_suspend,
> +       .runtime_resume         = glk_runtime_resume,
>  #endif
>         .quirks                 = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
>         .quirks2                = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
> --
> 2.17.1
>

Patch
diff mbox series

diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index e53333c695b3..c4115bae5db1 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -12,6 +12,7 @@ 
  *     - JMicron (hardware and technical support)
  */
 
+#include <linux/bitfield.h>
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/highmem.h>
@@ -462,6 +463,9 @@  struct intel_host {
 	u32	dsm_fns;
 	int	drv_strength;
 	bool	d3_retune;
+	bool	rpm_retune_ok;
+	u32	glk_rx_ctrl1;
+	u32	glk_tun_val;
 };
 
 static const guid_t intel_dsm_guid =
@@ -791,6 +795,77 @@  static int glk_emmc_add_host(struct sdhci_pci_slot *slot)
 	return ret;
 }
 
+#ifdef CONFIG_PM
+#define GLK_RX_CTRL1	0x834
+#define GLK_TUN_VAL	0x840
+#define GLK_PATH_PLL	GENMASK(13, 8)
+#define GLK_DLY		GENMASK(6, 0)
+/* Workaround firmware failing to restore the tuning value */
+static void glk_rpm_retune_wa(struct sdhci_pci_chip *chip, bool susp)
+{
+	struct sdhci_pci_slot *slot = chip->slots[0];
+	struct intel_host *intel_host = sdhci_pci_priv(slot);
+	struct sdhci_host *host = slot->host;
+	u32 glk_rx_ctrl1;
+	u32 glk_tun_val;
+	u32 dly;
+
+	if (intel_host->rpm_retune_ok || !mmc_can_retune(host->mmc))
+		return;
+
+	glk_rx_ctrl1 = sdhci_readl(host, GLK_RX_CTRL1);
+	glk_tun_val = sdhci_readl(host, GLK_TUN_VAL);
+
+	if (susp) {
+		intel_host->glk_rx_ctrl1 = glk_rx_ctrl1;
+		intel_host->glk_tun_val = glk_tun_val;
+		return;
+	}
+
+	if (!intel_host->glk_tun_val)
+		return;
+
+	if (glk_rx_ctrl1 != intel_host->glk_rx_ctrl1) {
+		intel_host->rpm_retune_ok = true;
+		return;
+	}
+
+	dly = FIELD_PREP(GLK_DLY, FIELD_GET(GLK_PATH_PLL, glk_rx_ctrl1) +
+				  (intel_host->glk_tun_val << 1));
+	if (dly == FIELD_GET(GLK_DLY, glk_rx_ctrl1))
+		return;
+
+	glk_rx_ctrl1 = (glk_rx_ctrl1 & ~GLK_DLY) | dly;
+	sdhci_writel(host, glk_rx_ctrl1, GLK_RX_CTRL1);
+
+	intel_host->rpm_retune_ok = true;
+	chip->rpm_retune = true;
+	mmc_retune_needed(host->mmc);
+	pr_info("%s: Requiring re-tune after rpm resume", mmc_hostname(host->mmc));
+}
+
+static void glk_rpm_retune_chk(struct sdhci_pci_chip *chip, bool susp)
+{
+	if (chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_EMMC &&
+	    !chip->rpm_retune)
+		glk_rpm_retune_wa(chip, susp);
+}
+
+static int glk_runtime_suspend(struct sdhci_pci_chip *chip)
+{
+	glk_rpm_retune_chk(chip, true);
+
+	return sdhci_cqhci_runtime_suspend(chip);
+}
+
+static int glk_runtime_resume(struct sdhci_pci_chip *chip)
+{
+	glk_rpm_retune_chk(chip, false);
+
+	return sdhci_cqhci_runtime_resume(chip);
+}
+#endif
+
 #ifdef CONFIG_ACPI
 static int ni_set_max_freq(struct sdhci_pci_slot *slot)
 {
@@ -879,8 +954,8 @@  static const struct sdhci_pci_fixes sdhci_intel_glk_emmc = {
 	.resume			= sdhci_cqhci_resume,
 #endif
 #ifdef CONFIG_PM
-	.runtime_suspend	= sdhci_cqhci_runtime_suspend,
-	.runtime_resume		= sdhci_cqhci_runtime_resume,
+	.runtime_suspend	= glk_runtime_suspend,
+	.runtime_resume		= glk_runtime_resume,
 #endif
 	.quirks			= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
 	.quirks2		= SDHCI_QUIRK2_PRESET_VALUE_BROKEN |