summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZiyuan Xu <xzy.xu@rock-chips.com>2017-05-15 09:07:20 +0300
committerKever Yang <kever.yang@rock-chips.com>2017-07-18 17:08:31 +0300
commitd51d202ec07c059f3dd0a82408db55925991521f (patch)
treef018ce7ce4b6b7f45300a9057854824d615170fc
parentf7f28374a09e2a59430064a9e2c643ffcf55bd92 (diff)
downloadu-boot-d51d202ec07c059f3dd0a82408db55925991521f.tar.xz
mmc: sdhci: add support for UHS timing
To support UHS speed mode, controller should enable 1.8V signaling and select one of UHS modes. Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
-rw-r--r--drivers/mmc/sdhci.c40
-rw-r--r--include/mmc.h1
-rw-r--r--include/sdhci.h17
3 files changed, 58 insertions, 0 deletions
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index fc8ba00e59..c80a958ca2 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -425,6 +425,39 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
}
+static void sdhci_set_uhs_signaling(struct sdhci_host *host)
+{
+ u16 ctrl_2;
+ u32 timing = host->mmc->timing;
+
+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ /* Select Bus Speed Mode for host */
+ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+
+ if ((timing != MMC_TIMING_LEGACY) &&
+ (timing != MMC_TIMING_MMC_HS) &&
+ (timing != MMC_TIMING_SD_HS))
+ ctrl_2 |= SDHCI_CTRL_VDD_180;
+
+ if ((timing == MMC_TIMING_MMC_HS200) ||
+ (timing == MMC_TIMING_UHS_SDR104))
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_DRV_TYPE_A;
+ else if (timing == MMC_TIMING_UHS_SDR12)
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+ else if (timing == MMC_TIMING_UHS_SDR25)
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+ else if (timing == MMC_TIMING_UHS_SDR50)
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
+ 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 ||
+ timing == MMC_TIMING_MMC_HS400ES)
+ ctrl_2 |= SDHCI_CTRL_HS400 | SDHCI_CTRL_DRV_TYPE_A;
+
+ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+}
+
#ifdef CONFIG_DM_MMC_OPS
static bool sdhci_card_busy(struct udevice *dev)
{
@@ -484,6 +517,13 @@ static int sdhci_set_ios(struct mmc *mmc)
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+ if ((mmc->timing != MMC_TIMING_LEGACY) &&
+ (mmc->timing != MMC_TIMING_MMC_HS) &&
+ (mmc->timing != MMC_TIMING_SD_HS))
+ sdhci_set_power(host, MMC_VDD_165_195_SHIFT);
+
+ sdhci_set_uhs_signaling(host);
+
/* If available, call the driver specific "post" set_ios() function */
if (host->ops && host->ops->set_ios_post)
host->ops->set_ios_post(host);
diff --git a/include/mmc.h b/include/mmc.h
index becac9b2a7..f676d2e910 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -138,6 +138,7 @@
#define MMC_STATE_PRG (7 << 9)
+#define MMC_VDD_165_195_SHIFT 7
#define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */
#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */
diff --git a/include/sdhci.h b/include/sdhci.h
index 75432dbab2..449ada12b4 100644
--- a/include/sdhci.h
+++ b/include/sdhci.h
@@ -147,6 +147,23 @@
#define SDHCI_ACMD12_ERR 0x3C
/* 3E-3F reserved */
+#define SDHCI_HOST_CONTROL2 0x3E
+#define SDHCI_CTRL_UHS_MASK 0x0007
+#define SDHCI_CTRL_UHS_SDR12 0x0000
+#define SDHCI_CTRL_UHS_SDR25 0x0001
+#define SDHCI_CTRL_UHS_SDR50 0x0002
+#define SDHCI_CTRL_UHS_SDR104 0x0003
+#define SDHCI_CTRL_UHS_DDR50 0x0004
+#define SDHCI_CTRL_HS400 0x0005
+#define SDHCI_CTRL_VDD_180 0x0008
+#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030
+#define SDHCI_CTRL_DRV_TYPE_B 0x0000
+#define SDHCI_CTRL_DRV_TYPE_A 0x0010
+#define SDHCI_CTRL_DRV_TYPE_C 0x0020
+#define SDHCI_CTRL_DRV_TYPE_D 0x0030
+#define SDHCI_CTRL_EXEC_TUNING 0x0040
+#define SDHCI_CTRL_TUNED_CLK 0x0080
+#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000
#define SDHCI_CAPABILITIES 0x40
#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F