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

Commit 248dec2f authored by Adrian Hunter's avatar Adrian Hunter Committed by Matt Wagantall
Browse files

mmc: sdhci: Add HS400 support to SDHCI driver



MMC core already has support for HS400.  Add HS400
support to SDHCI driver.  The SDHC Standard specification
does not define HS400 so consequently HS400 support is
non-standard.  However HS400 is not selected without
the host controller setting the corresponding capability
flags so host controllers not yet supporting HS400
will not be affected.  To support that, a quirk
SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 is introduced to
enable the use of capabilities register reserved bit-63
to indicate HS400 support.

Because HS400 is non-standard for SDHCI, it is possible
that different vendors will do things in different ways.
However HS200 support faced the same issue but currently
there is only one solution.  As such, no attempt has
been made to provide for alternate HS400 solutions except
for SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400.

Change-Id: I4544634df92a1a963fcfe30dc2b9cf8edc92a42d
Signed-off-by: default avatarAdrian Hunter <adrian.hunter@intel.com>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
[venkatg@codeaurora.org: Resolve conflicts with QUIRK2 definitions]
Git-commit: e9fb05d5bca7428f2749d059559e9657c710fe53
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git


Signed-off-by: default avatarVenkat Gopalakrishnan <venkatg@codeaurora.org>
parent 823fc8e9
Loading
Loading
Loading
Loading
+12 −1
Original line number Diff line number Diff line
@@ -1277,6 +1277,9 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
	case MMC_TIMING_UHS_DDR50:
		preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50);
		break;
	case MMC_TIMING_MMC_HS400:
		preset = sdhci_readw(host, SDHCI_PRESET_FOR_HS400);
		break;
	default:
		pr_warn("%s: Invalid UHS-I mode selected\n",
			mmc_hostname(host->mmc));
@@ -1770,6 +1773,8 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
	else if ((timing == MMC_TIMING_UHS_DDR50) ||
		 (timing == MMC_TIMING_MMC_DDR52))
		ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
	else if (timing == MMC_TIMING_MMC_HS400)
		ctrl_2 |= SDHCI_CTRL_HS400; /* Non-standard */
	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
}
EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
@@ -1858,7 +1863,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
		u16 clk, ctrl_2;

		/* In case of UHS-I modes, set High Speed Enable */
		if ((ios->timing == MMC_TIMING_MMC_HS200) ||
		if ((ios->timing == MMC_TIMING_MMC_HS400) ||
		    (ios->timing == MMC_TIMING_MMC_HS200) ||
		    (ios->timing == MMC_TIMING_MMC_DDR52) ||
		    (ios->timing == MMC_TIMING_UHS_SDR50) ||
		    (ios->timing == MMC_TIMING_UHS_SDR104) ||
@@ -2229,6 +2235,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
	 * tuning function has to be executed.
	 */
	switch (host->timing) {
	case MMC_TIMING_MMC_HS400:
	case MMC_TIMING_MMC_HS200:
	case MMC_TIMING_UHS_SDR104:
		break;
@@ -3606,6 +3613,10 @@ int sdhci_add_host(struct sdhci_host *host)
	} else if (caps[1] & SDHCI_SUPPORT_SDR50)
		mmc->caps |= MMC_CAP_UHS_SDR50;

	if (host->quirks2 & SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 &&
	    (caps[1] & SDHCI_SUPPORT_HS400))
		mmc->caps2 |= MMC_CAP2_HS400;

	if ((caps[1] & SDHCI_SUPPORT_DDR50) &&
		!(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50))
		mmc->caps |= MMC_CAP_UHS_DDR50;
+3 −0
Original line number Diff line number Diff line
@@ -169,6 +169,7 @@
#define   SDHCI_CTRL_UHS_SDR50		0x0002
#define   SDHCI_CTRL_UHS_SDR104		0x0003
#define   SDHCI_CTRL_UHS_DDR50		0x0004
#define   SDHCI_CTRL_HS400		0x0005 /* Non-standard */
#define  SDHCI_CTRL_VDD_180		0x0008
#define  SDHCI_CTRL_DRV_TYPE_MASK	0x0030
#define   SDHCI_CTRL_DRV_TYPE_B		0x0000
@@ -211,6 +212,7 @@
#define  SDHCI_RETUNING_MODE_SHIFT		14
#define  SDHCI_CLOCK_MUL_MASK	0x00FF0000
#define  SDHCI_CLOCK_MUL_SHIFT	16
#define  SDHCI_SUPPORT_HS400	0x80000000 /* Non-standard */

#define SDHCI_CAPABILITIES_1	0x44

@@ -244,6 +246,7 @@
#define SDHCI_PRESET_FOR_SDR50 0x6A
#define SDHCI_PRESET_FOR_SDR104        0x6C
#define SDHCI_PRESET_FOR_DDR50 0x6E
#define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */
#define SDHCI_PRESET_DRV_MASK  0xC000
#define SDHCI_PRESET_DRV_SHIFT  14
#define SDHCI_PRESET_CLKGEN_SEL_MASK   0x400
+6 −1
Original line number Diff line number Diff line
@@ -168,7 +168,12 @@ struct sdhci_host {
 * Some SDHC controllers do not require data buffers alignment, skip
 * the bounce buffer logic when preparing data
 */
#define SDHCI_QUIRK2_ADMA_SKIP_DATA_ALIGNMENT             (1<<13)
#define SDHCI_QUIRK2_ADMA_SKIP_DATA_ALIGNMENT		(1<<17)

/* Controller has nonstandard clock management */
#define SDHCI_QUIRK_NONSTANDARD_CLOCK			(1<<18)
/* Capability register bit-63 indicates HS400 support */
#define SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400		(1<<19)

	int irq;		/* Device IRQ */
	void __iomem *ioaddr;	/* Mapped address */