Depthcharge: Enable eMMC HS200 to enhance boot time.

BRANCH=master
BUG=chrome-os-partner:34675
TEST=Build images run on Chrome OS devices and got ~12% BIOS boot
time enhancement.
Signed-off-by: Kenji Chen <kenji.chen@intel.com>

Change-Id: Ic9b4bdf4a5f933249c394ba58f29409b60bd4b66
Reviewed-on: https://chromium-review.googlesource.com/238101
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Commit-Queue: Kenji Chen <kenji.chen@intel.com>
Tested-by: Kenji Chen <kenji.chen@intel.com>
diff --git a/src/drivers/storage/mmc.c b/src/drivers/storage/mmc.c
index 0570753..687b8dd 100644
--- a/src/drivers/storage/mmc.c
+++ b/src/drivers/storage/mmc.c
@@ -491,6 +491,12 @@
 
 }
 
+static void mmc_set_bus_width(MmcCtrlr *ctrlr, uint32_t width)
+{
+	ctrlr->bus_width = width;
+	ctrlr->set_ios(ctrlr);
+}
+
 static int mmc_change_freq(MmcMedia *media)
 {
 	char cardtype;
@@ -507,9 +513,28 @@
 	if (err)
 		return err;
 
-	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
-	err = mmc_switch(media, EXT_CSD_CMD_SET_NORMAL,
+	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x1f;
+	if (cardtype & MMC_HS_200MHZ) {
+		/* Switch to 8-bit since HS200 only support 8-bit bus width */
+		err = mmc_switch(media, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_8);
+		if (err)
+			return err;
+
+		/* Switch to HS200 */
+		err = mmc_switch(media, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_HS_TIMING, 0x2);
+		if (err)
+			return err;
+
+		/* Adjust Host Bus Wisth to 8-bit */
+		mmc_set_bus_width(media->ctrlr, 8);
+		media->caps |= EXT_CSD_BUS_WIDTH_8;
+	} else {
+		err = mmc_switch(media, EXT_CSD_CMD_SET_NORMAL,
 			 EXT_CSD_HS_TIMING, 1);
+	}
+
 	if (err)
 		return err;
 
@@ -522,8 +547,11 @@
 	if (!ext_csd[EXT_CSD_HS_TIMING])
 		return 0;
 
-	/* High Speed is set, there are two types: 52MHz and 26MHz */
-	if (cardtype & MMC_HS_52MHZ)
+	/* High Speed is set, there are types: HS200, 52MHz, 26MHz */
+	if (cardtype & MMC_HS_200MHZ)
+		media->caps |= (MMC_MODE_HS_200MHz
+			| MMC_MODE_HS_52MHz | MMC_MODE_HS);
+	else if (cardtype & MMC_HS_52MHZ)
 		media->caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
 	else
 		media->caps |= MMC_MODE_HS;
@@ -662,12 +690,6 @@
 	ctrlr->set_ios(ctrlr);
 }
 
-static void mmc_set_bus_width(MmcCtrlr *ctrlr, uint32_t width)
-{
-	ctrlr->bus_width = width;
-	ctrlr->set_ios(ctrlr);
-}
-
 static uint32_t mmc_calculate_transfer_speed(uint32_t csd0)
 {
 	uint32_t mult, freq;
@@ -875,6 +897,10 @@
 			clock = MMC_CLOCK_25MHZ;
 	} else {
 		for (width = EXT_CSD_BUS_WIDTH_8; width >= 0; width--) {
+			/* If HS200 is switched, Bus Width has been 8-bit */
+			if (media->caps & MMC_MODE_HS_200MHz)
+				break;
+
 			/* Set the card to use 4 bit*/
 			err = mmc_switch(media, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH, width);
@@ -905,7 +931,9 @@
 		}
 
 		if (media->caps & MMC_MODE_HS) {
-			if (media->caps & MMC_MODE_HS_52MHz)
+			if (media->caps & MMC_MODE_HS_200MHz)
+				clock = MMC_CLOCK_200MHZ;
+			else if (media->caps & MMC_MODE_HS_52MHz)
 				clock = MMC_CLOCK_52MHZ;
 			else
 				clock = MMC_CLOCK_26MHZ;
diff --git a/src/drivers/storage/mmc.h b/src/drivers/storage/mmc.h
index 7ef4c11..57f73a2 100644
--- a/src/drivers/storage/mmc.h
+++ b/src/drivers/storage/mmc.h
@@ -45,6 +45,7 @@
 
 #define MMC_MODE_HS		0x001
 #define MMC_MODE_HS_52MHz	0x010
+#define MMC_MODE_HS_200MHz	0x020
 #define MMC_MODE_4BIT		0x100
 #define MMC_MODE_8BIT		0x200
 #define MMC_MODE_SPI		0x400
@@ -105,6 +106,7 @@
 
 #define MMC_HS_TIMING		0x00000100
 #define MMC_HS_52MHZ		0x2
+#define MMC_HS_200MHZ		0x10
 
 #define OCR_BUSY		0x80000000
 #define OCR_HCS			0x40000000
@@ -136,6 +138,8 @@
 #define MMC_VDD_34_35		0x00400000	/* VDD voltage 3.4 ~ 3.5 */
 #define MMC_VDD_35_36		0x00800000	/* VDD voltage 3.5 ~ 3.6 */
 
+#define MMC_VDD_165_195_SHIFT   7
+
 #define MMC_SWITCH_MODE_CMD_SET		0x00 /* Change the command set */
 #define MMC_SWITCH_MODE_SET_BITS	0x01 /* Set bits in EXT_CSD byte
 						addressed by index which are
@@ -203,6 +207,7 @@
 #define MMC_CLOCK_26MHZ (26000000)
 #define MMC_CLOCK_50MHZ (50000000)
 #define MMC_CLOCK_52MHZ (52000000)
+#define MMC_CLOCK_200MHZ (200000000)
 #define MMC_CLOCK_DEFAULT_MHZ	(MMC_CLOCK_20MHZ)
 
 #define EXT_CSD_SIZE	(512)
diff --git a/src/drivers/storage/sdhci.c b/src/drivers/storage/sdhci.c
index 67b1487..d6595fd 100644
--- a/src/drivers/storage/sdhci.c
+++ b/src/drivers/storage/sdhci.c
@@ -373,6 +373,11 @@
 	if (host->set_clock)
 		host->set_clock(host, div);
 
+	if (clock == MMC_CLOCK_200MHZ) {
+		sdhci_writew(host, SDHCI_CTRL_UHS_SDR104
+			| SDHCI_CTRL_VDD_180 | SDHCI_CTRL_DRV_TYPE_A
+			, SDHCI_HOST_CONTROL2);
+	}
 	clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
 	clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
 		<< SDHCI_DIVIDER_HI_SHIFT;
@@ -471,6 +476,10 @@
 	if (mmc_ctrlr->bus_hz != host->clock)
 		sdhci_set_clock(host, mmc_ctrlr->bus_hz);
 
+	/* Switch to 1.8 volt for HS200 */
+	if (mmc_ctrlr->bus_hz == MMC_CLOCK_200MHZ)
+		sdhci_set_power(host, MMC_VDD_165_195_SHIFT);
+
 	/* Set bus width */
 	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
 	if (mmc_ctrlr->bus_width == 8) {
@@ -560,7 +569,7 @@
 		host->mmc_ctrlr.voltages |= host->voltages;
 
 	host->mmc_ctrlr.caps = MMC_MODE_HS | MMC_MODE_HS_52MHz |
-		MMC_MODE_4BIT | MMC_MODE_HC;
+		MMC_MODE_4BIT | MMC_MODE_HC | MMC_MODE_HS_200MHz;
 	if (caps & SDHCI_CAN_DO_8BIT)
 		host->mmc_ctrlr.caps |= MMC_MODE_8BIT;
 	if (host->host_caps)
diff --git a/src/drivers/storage/sdhci.h b/src/drivers/storage/sdhci.h
index 1d8816b..f5b7f46 100644
--- a/src/drivers/storage/sdhci.h
+++ b/src/drivers/storage/sdhci.h
@@ -160,7 +160,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_HS_SDR200          0x0005 /* reserved value in SDIO spec */
+#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