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/239331
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 59befb1..18aeddf 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 477da1e..5ea48ba 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
@@ -104,6 +105,7 @@
#define MMC_HS_TIMING 0x00000100
#define MMC_HS_52MHZ 0x2
+#define MMC_HS_200MHZ 0x10
#define OCR_BUSY 0x80000000
#define OCR_HCS 0x40000000
@@ -135,6 +137,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
@@ -202,6 +206,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 a676c5f..e120745 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