[U-Boot] [PATCH 02/12] mmc: sdhci: Add support for SD3.0

Siva Durga Prasad Paladugu siva.durga.paladugu at xilinx.com
Wed Jan 18 10:04:21 CET 2017


Add support for all UHS modes of SD3.0.
The SD3.0 needs voltage switching to 1.8V
based on host and cards capabilities and also
needs to switch to one of the uhs modes based
on cards capability. This supports frequencies
till 200MHz.

Signed-off-by: Siva Durga Prasad Paladugu <sivadur at xilinx.com>
---
 drivers/mmc/mmc-uclass.c |  52 ++++++++++++++++
 drivers/mmc/mmc.c        | 138 +++++++++++++++++++++++++++++++++++++++--
 drivers/mmc/sdhci.c      | 157 ++++++++++++++++++++++++++++++++++++++++++++++-
 include/mmc.h            |  55 ++++++++++++++++-
 include/sdhci.h          |   8 +++
 5 files changed, 401 insertions(+), 9 deletions(-)

diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
index 2fe5d61..3ca3e49 100644
--- a/drivers/mmc/mmc-uclass.c
+++ b/drivers/mmc/mmc-uclass.c
@@ -77,6 +77,58 @@ int mmc_getcd(struct mmc *mmc)
 {
 	return dm_mmc_get_cd(mmc->dev);
 }
+
+int dm_mmc_set_voltage(struct udevice *dev)
+{
+	struct dm_mmc_ops *ops = mmc_get_ops(dev);
+
+	if (!ops->set_voltage)
+		return -ENOSYS;
+
+	return ops->set_voltage(dev);
+}
+
+int mmc_set_voltage(struct mmc *mmc)
+{
+	return dm_mmc_set_voltage(mmc->dev);
+}
+
+int dm_mmc_set_uhs(struct udevice *dev)
+{
+	struct dm_mmc_ops *ops = mmc_get_ops(dev);
+
+	if (!ops->set_uhs)
+		return -ENOSYS;
+
+	return ops->set_uhs(dev);
+}
+
+int mmc_switch_uhs(struct mmc *mmc)
+{
+	return dm_mmc_set_uhs(mmc->dev);
+}
+
+int dm_mmc_execute_tuning(struct udevice *dev)
+{
+	struct mmc *mmc = mmc_get_mmc_dev(dev);
+	struct dm_mmc_ops *ops = mmc_get_ops(dev);
+	u8 opcode;
+
+	if (!ops->execute_tuning)
+		return -ENOSYS;
+
+	if (IS_SD(mmc))
+		opcode = MMC_CMD_SEND_TUNING_BLOCK;
+	else
+		opcode = MMC_CMD_SEND_TUNING_BLOCK_HS200;
+
+	return ops->execute_tuning(dev, opcode);
+}
+
+int mmc_execute_tuning(struct mmc *mmc)
+{
+	return dm_mmc_execute_tuning(mmc->dev);
+}
 #endif
 
 struct mmc *mmc_get_mmc_dev(struct udevice *dev)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 9f8368a..d4ea0c2 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -339,6 +339,47 @@ static int mmc_go_idle(struct mmc *mmc)
 	return 0;
 }
 
+#ifndef CONFIG_DM_MMC_OPS
+static int mmc_set_voltage(struct mmc *mmc)
+{
+	int err = 0;
+
+	if (mmc->cfg->ops->set_voltage) {
+		err = mmc->cfg->ops->set_voltage(mmc);
+		if (err)
+			return err;
+	}
+
+	return err;
+}
+#endif
+
+static int mmc_switch_voltage(struct mmc *mmc)
+{
+	struct mmc_cmd cmd;
+	int err = 0;
+
+	cmd.cmdidx = SD_CMD_SWITCH_UHS18V;
+	cmd.cmdarg = 0;
+	cmd.resp_type = MMC_RSP_NONE;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+	if (err)
+		return err;
+
+	err = mmc_set_voltage(mmc);
+
+	return err;
+}
+
+static int mmc_host_uhs(struct mmc *mmc)
+{
+	return mmc->cfg->host_caps &
+		(MMC_MODE_UHS_SDR12 | MMC_MODE_UHS_SDR25 |
+		 MMC_MODE_UHS_SDR50 | MMC_MODE_UHS_SDR104 |
+		 MMC_MODE_UHS_DDR50);
+}
+
 static int sd_send_op_cond(struct mmc *mmc)
 {
 	int timeout = 1000;
@@ -371,6 +412,9 @@ static int sd_send_op_cond(struct mmc *mmc)
 		if (mmc->version == SD_VERSION_2)
 			cmd.cmdarg |= OCR_HCS;
 
+		if (mmc_host_uhs(mmc))
+			cmd.cmdarg |= SD_OCR_S18R;
+
 		err = mmc_send_cmd(mmc, &cmd, NULL);
 
 		if (err)
@@ -401,6 +445,13 @@ static int sd_send_op_cond(struct mmc *mmc)
 
 	mmc->ocr = cmd.response[0];
 
+	if (mmc->ocr & SD_OCR_S18R) {
+		err = mmc_switch_voltage(mmc);
+		if (err)
+			return err;
+		mmc->is_uhs = 1;
+	}
+
 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
 	mmc->rca = 0;
 
@@ -886,6 +937,7 @@ static int sd_change_freq(struct mmc *mmc)
 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
 	struct mmc_data data;
 	int timeout;
+	u8 mode;
 
 	mmc->card_caps = 0;
 
@@ -963,6 +1015,40 @@ retry_scr:
 			break;
 	}
 
+	mode = MMC_TIMING_HS;
+
+	if (mmc->is_uhs && mmc->version >= SD_VERSION_3) {
+		if (!(mmc_host_uhs(mmc)))
+			return 0;
+
+		if (__be32_to_cpu(switch_status[3]) &
+		    SD_UHS_SPEED_SDR104) {
+			mode = MMC_TIMING_UHS_SDR104;
+			mmc->card_caps |= MMC_MODE_UHS_SDR104;
+			mmc->tran_speed = 208000000;
+		} else if (__be32_to_cpu(switch_status[3]) &
+			   SD_UHS_SPEED_SDR50) {
+			mode = MMC_TIMING_UHS_SDR50;
+			mmc->card_caps |= MMC_MODE_UHS_SDR50;
+			mmc->tran_speed = 100000000;
+		} else if (__be32_to_cpu(switch_status[3]) &
+			   SD_UHS_SPEED_DDR50) {
+			mode = MMC_TIMING_UHS_DDR50;
+			mmc->card_caps |= MMC_MODE_UHS_DDR50;
+			mmc->tran_speed = 50000000;
+		} else if (__be32_to_cpu(switch_status[3]) &
+			   SD_UHS_SPEED_SDR25) {
+			mode = MMC_TIMING_UHS_SDR25;
+			mmc->card_caps |= MMC_MODE_UHS_SDR25;
+			mmc->tran_speed = 50000000;
+		} else {
+			mode = MMC_TIMING_UHS_SDR12;
+			mmc->card_caps |= MMC_MODE_UHS_SDR12;
+			mmc->tran_speed = 25000000;
+		}
+		mmc->uhsmode = mode;
+	}
+
 	/* If high-speed isn't supported, we return */
 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
 		return 0;
@@ -977,7 +1063,7 @@ retry_scr:
 		(mmc->cfg->host_caps & MMC_MODE_HS)))
 		return 0;
 
-	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
+	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, mode, (u8 *)switch_status);
 
 	if (err)
 		return err;
@@ -1102,6 +1188,33 @@ static void mmc_set_bus_width(struct mmc *mmc, uint width)
 
 	mmc_set_ios(mmc);
 }
+#ifndef CONFIG_DM_MMC_OPS
+static int mmc_switch_uhs(struct mmc *mmc)
+{
+	int err = 0;
+
+	if (mmc->cfg->ops->set_uhs)
+		err = mmc->cfg->ops->set_uhs(mmc);
+
+	return err;
+}
+
+static int mmc_execute_tuning(struct mmc *mmc)
+{
+	int err = 0;
+	u8 cmd;
+
+	if (mmc->cfg->ops->execute_tuning) {
+		if (IS_SD(mmc))
+			cmd = MMC_CMD_SEND_TUNING_BLOCK;
+		else
+			cmd = MMC_CMD_SEND_TUNING_BLOCK_HS200;
+		err = mmc->cfg->ops->execute_tuning(mmc, cmd);
+	}
+
+	return err;
+}
+#endif
 
 static int mmc_startup(struct mmc *mmc)
 {
@@ -1452,11 +1565,16 @@ static int mmc_startup(struct mmc *mmc)
 		err = sd_read_ssr(mmc);
 		if (err)
 			return err;
-
-		if (mmc->card_caps & MMC_MODE_HS)
-			mmc->tran_speed = 50000000;
-		else
-			mmc->tran_speed = 25000000;
+		if (mmc->card_caps & MMC_MODE_UHS) {
+			err = mmc_switch_uhs(mmc);
+			if (err)
+				return err;
+		} else  {
+			if (mmc->card_caps & MMC_MODE_HS)
+				mmc->tran_speed = 50000000;
+			else
+				mmc->tran_speed = 25000000;
+		}
 	} else if (mmc->version >= MMC_VERSION_4) {
 		/* Only version 4 of MMC supports wider bus widths */
 		int idx;
@@ -1551,6 +1669,14 @@ static int mmc_startup(struct mmc *mmc)
 
 	mmc_set_clock(mmc, mmc->tran_speed);
 
+	if ((mmc->card_caps & (MMC_MODE_UHS_SDR50 |
+			       MMC_MODE_UHS_SDR104)) &&
+	    (mmc->cfg->host_caps & MMC_MODE_NEEDS_TUNING)) {
+		err = mmc_execute_tuning(mmc);
+		if (err)
+			return err;
+	}
+
 	/* Fix the block length for DDR mode */
 	if (mmc->ddr_mode) {
 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 95aae4d..5ae56e0 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -13,6 +13,7 @@
 #include <malloc.h>
 #include <mmc.h>
 #include <sdhci.h>
+#include <wait_bit.h>
 
 #if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER)
 void *aligned_buffer = (void *)CONFIG_FIXED_SDHCI_ALIGNED_BUFFER;
@@ -155,7 +156,8 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
 
 	/* We shouldn't wait for data inihibit for stop commands, even
 	   though they might use busy signaling */
-	if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
+	if ((cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) ||
+	    (cmd->cmdidx ==  MMC_CMD_SEND_TUNING_BLOCK))
 		mask &= ~SDHCI_DATA_INHIBIT;
 
 	while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
@@ -175,6 +177,11 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
 	}
 
 	mask = SDHCI_INT_RESPONSE;
+
+	/* only buffer read ready interrupt whil tuning */
+	if (cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK)
+		mask = SDHCI_INT_DATA_AVAIL;
+
 	if (!(cmd->resp_type & MMC_RSP_PRESENT))
 		flags = SDHCI_CMD_RESP_NONE;
 	else if (cmd->resp_type & MMC_RSP_136)
@@ -190,7 +197,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
 		flags |= SDHCI_CMD_CRC;
 	if (cmd->resp_type & MMC_RSP_OPCODE)
 		flags |= SDHCI_CMD_INDEX;
-	if (data)
+	if (data || (cmd->cmdidx ==  MMC_CMD_SEND_TUNING_BLOCK))
 		flags |= SDHCI_CMD_DATA;
 
 	/* Set Transfer mode regarding to data flag */
@@ -291,6 +298,80 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
 	else
 		return -ECOMM;
 }
+#ifdef CONFIG_DM_MMC_OPS
+static int sdhci_execute_tuning(struct udevice *dev, u8 opcode)
+{
+	struct mmc *mmc = mmc_get_mmc_dev(dev);
+#else
+static int sdhci_execute_tuning(struct mmc *mmc, u8 opcode)
+{
+#endif
+	struct mmc_cmd cmd;
+	struct mmc_data data;
+	u32 ctrl;
+	u8 tuning_loop_counter = 40;
+	struct sdhci_host *host = mmc->priv;
+
+	debug("%s\n", __func__);
+
+	ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2);
+	ctrl |= SDHCI_CTRL_EXEC_TUNING;
+	sdhci_writew(host, ctrl, SDHCI_HOST_CTRL2);
+
+	sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE);
+	sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE);
+
+	do {
+		cmd.cmdidx = opcode;
+		cmd.resp_type = MMC_RSP_R1;
+		cmd.cmdarg = 0;
+
+		data.blocksize = 64;
+		data.blocks = 1;
+		data.flags = MMC_DATA_READ;
+
+		if (tuning_loop_counter == 0)
+			break;
+
+		tuning_loop_counter--;
+
+		if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200 &&
+		    mmc->bus_width == 8) {
+			data.blocksize = 128;
+		}
+
+		sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
+						    data.blocksize),
+			     SDHCI_BLOCK_SIZE);
+		sdhci_writew(host, data.blocks, SDHCI_BLOCK_COUNT);
+		sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
+
+		sdhci_send_command(dev, &cmd, &data);
+		ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2);
+
+		if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK)
+			udelay(1);
+
+	} while (ctrl & SDHCI_CTRL_EXEC_TUNING);
+
+	if (tuning_loop_counter < 0) {
+		ctrl &= ~SDHCI_CTRL_TUNED_CLK;
+		sdhci_writel(host, ctrl, SDHCI_HOST_CTRL2);
+	}
+
+	if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
+		debug("%s:Tuning failed\n", __func__);
+		return -1;
+	}
+
+	/* Enable only interrupts served by the SD controller */
+	sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK,
+		     SDHCI_INT_ENABLE);
+	/* Mask all sdhci interrupt sources */
+	sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE);
+
+	return 0;
+}
 
 static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
 {
@@ -386,6 +467,72 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
 	return 0;
 }
 
+#ifdef CONFIG_DM_MMC_OPS
+static int sdhci_set_voltage(struct udevice *dev)
+{
+	struct mmc *mmc = mmc_get_mmc_dev(dev);
+#else
+static int sdhci_set_voltage(struct mmc *mmc)
+{
+#endif
+	struct sdhci_host *host = mmc->priv;
+	u32 reg;
+	int err;
+
+	debug("%s\n", __func__);
+
+	reg = (unsigned long)host->ioaddr + SDHCI_PRESENT_STATE;
+	/* Wait max 20ms for the bits to clear*/
+	err = wait_for_bit(__func__, (const u32 *)(uintptr_t)reg,
+			   (SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT),
+			   false, 20, false);
+	if (err < 0)
+		return err;
+
+	reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+	reg &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN);
+	sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL);
+
+	/* keep clock gated for 5 msec as per spec */
+	udelay(5000);
+
+	reg = sdhci_readw(host, SDHCI_HOST_CTRL2);
+	reg |= SDHCI_18V_SIGNAL;
+	sdhci_writew(host, reg, SDHCI_HOST_CTRL2);
+
+	sdhci_set_clock(mmc, mmc->cfg->f_min);
+
+	reg = (unsigned long)host->ioaddr + SDHCI_PRESENT_STATE;
+	/* Wait max 20ms for bits to be clear */
+	err = wait_for_bit(__func__, (const u32 *)(uintptr_t)reg,
+			   (SDHCI_CMD_BUSY | SDHCI_DATA_BUSY),
+			   true, 20, false);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+#ifdef CONFIG_DM_MMC_OPS
+static int sdhci_set_uhs(struct udevice *dev)
+{
+	struct mmc *mmc = mmc_get_mmc_dev(dev);
+#else
+static int sdhci_set_uhs(struct mmc *mmc)
+{
+#endif
+	struct sdhci_host *host = mmc->priv;
+	u32 reg;
+
+	debug("%s\n", __func__);
+	reg = sdhci_readw(host, SDHCI_HOST_CTRL2);
+	reg &= ~SDHCI_CTRL2_MODE_MASK;
+	reg |= mmc->uhsmode;
+	sdhci_writew(host, reg, SDHCI_HOST_CTRL2);
+
+	return 0;
+}
+
 static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
 {
 	u8 pwr = 0;
@@ -503,12 +650,18 @@ int sdhci_probe(struct udevice *dev)
 const struct dm_mmc_ops sdhci_ops = {
 	.send_cmd	= sdhci_send_command,
 	.set_ios	= sdhci_set_ios,
+	.set_voltage	= sdhci_set_voltage,
+	.set_uhs	= sdhci_set_uhs,
+	.execute_tuning	= sdhci_execute_tuning,
 };
 #else
 static const struct mmc_ops sdhci_ops = {
 	.send_cmd	= sdhci_send_command,
 	.set_ios	= sdhci_set_ios,
 	.init		= sdhci_init,
+	.set_voltage	= sdhci_set_voltage,
+	.set_uhs	= sdhci_set_uhs,
+	.execute_tuning	= sdhci_execute_tuning,
 };
 #endif
 
diff --git a/include/mmc.h b/include/mmc.h
index 5c94eae..56395ee 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -66,6 +66,9 @@
 #define MMC_MODE_NEEDS_TUNING	(1 << 11)
 #define MMC_MODE_HS200		(1 << 12)
 
+#define MMC_MODE_UHS	(MMC_MODE_UHS_SDR12 | MMC_MODE_UHS_SDR25 |	\
+			 MMC_MODE_UHS_SDR50 | MMC_MODE_UHS_SDR104 |	\
+			 MMC_MODE_UHS_DDR50)
 #define SD_DATA_4BIT	0x00040000
 
 #define IS_SD(x)	((x)->version & SD_VERSION_SD)
@@ -89,6 +92,8 @@
 #define MMC_CMD_SET_BLOCKLEN		16
 #define MMC_CMD_READ_SINGLE_BLOCK	17
 #define MMC_CMD_READ_MULTIPLE_BLOCK	18
+#define MMC_CMD_SEND_TUNING_BLOCK	19
+#define MMC_CMD_SEND_TUNING_BLOCK_HS200	21
 #define MMC_CMD_SET_BLOCK_COUNT         23
 #define MMC_CMD_WRITE_SINGLE_BLOCK	24
 #define MMC_CMD_WRITE_MULTIPLE_BLOCK	25
@@ -119,12 +124,18 @@
 /* SCR definitions in different words */
 #define SD_HIGHSPEED_BUSY	0x00020000
 #define SD_HIGHSPEED_SUPPORTED	0x00020000
+#define SD_UHS_SPEED_SDR104	0x00080000
+#define SD_UHS_SPEED_SDR50	0x00040000
+#define SD_UHS_SPEED_DDR50	0x00100000
+#define SD_UHS_SPEED_SDR25	0x00020000
 
 #define OCR_BUSY		0x80000000
 #define OCR_HCS			0x40000000
 #define OCR_VOLTAGE_MASK	0x007FFF80
 #define OCR_ACCESS_MODE		0x60000000
 
+#define SD_OCR_S18R		(1 << 24)
+
 #define MMC_ERASE_ARG		0x00000000
 #define MMC_SECURE_ERASE_ARG	0x80000000
 #define MMC_TRIM_ARG		0x00000001
@@ -277,6 +288,13 @@
 #define MMC_NUM_BOOT_PARTITION	2
 #define MMC_PART_RPMB           3       /* RPMB partition number */
 
+#define MMC_TIMING_UHS_SDR12	0
+#define MMC_TIMING_UHS_SDR25	1
+#define MMC_TIMING_UHS_SDR50	2
+#define MMC_TIMING_UHS_SDR104	3
+#define MMC_TIMING_UHS_DDR50	4
+#define MMC_TIMING_HS		1
+
 /* Driver model support */
 
 /**
@@ -364,6 +382,31 @@ struct dm_mmc_ops {
 	 * @return 0 if write-enabled, 1 if write-protected, -ve on error
 	 */
 	int (*get_wp)(struct udevice *dev);
+
+	/**
+	* set_volatge() - Switches host for new voltage
+	* @dev:>-------Device to check
+	*
+	* @return 0 on success otherwise error value
+	*/
+	int (*set_voltage)(struct udevice *dev);
+
+	/**
+	 * set_uhs() - Sets the controller for specific uhs mode
+	 * @dev:>-------Device to check
+	 *
+	 * @return 0 after setting uhs mode
+	 */
+	int (*set_uhs)(struct udevice *dev);
+
+	/**
+	* execute_tuning() - Executes the required tuning sequence
+	* @dev:>-------Device to check
+	* @opcode:>----Command to be sent for tuning
+	*
+	* @return 0 on success otherwise error value
+	*/
+	int (*execute_tuning)(struct udevice *dev, u8 opcode);
 };
 
 #define mmc_get_ops(dev)        ((struct dm_mmc_ops *)(dev)->driver->ops)
@@ -373,12 +416,17 @@ int dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
 int dm_mmc_set_ios(struct udevice *dev);
 int dm_mmc_get_cd(struct udevice *dev);
 int dm_mmc_get_wp(struct udevice *dev);
+int dm_mmc_set_voltage(struct udevice *dev);
+int dm_mmc_set_uhs(struct udevice *dev);
+int dm_mmc_execute_tuning(struct udevice *dev);
 
 /* Transition functions for compatibility */
 int mmc_set_ios(struct mmc *mmc);
 int mmc_getcd(struct mmc *mmc);
 int mmc_getwp(struct mmc *mmc);
-
+int mmc_set_voltage(struct mmc *mmc);
+int mmc_switch_uhs(struct mmc *mmc);
+int mmc_execute_tuning(struct mmc *mmc);
 #else
 struct mmc_ops {
 	int (*send_cmd)(struct mmc *mmc,
@@ -387,6 +435,9 @@ struct mmc_ops {
 	int (*init)(struct mmc *mmc);
 	int (*getcd)(struct mmc *mmc);
 	int (*getwp)(struct mmc *mmc);
+	int (*set_voltage)(struct mmc *mmc);
+	int (*set_uhs)(struct mmc *mmc);
+	int (*execute_tuning)(struct mmc *mmc, u8 opcode);
 };
 #endif
 
@@ -461,6 +512,8 @@ struct mmc {
 #ifdef CONFIG_DM_MMC
 	struct udevice *dev;	/* Device for this MMC controller */
 #endif
+	u8 is_uhs;
+	u8 uhsmode;
 };
 
 struct mmc_hwpart_conf {
diff --git a/include/sdhci.h b/include/sdhci.h
index 873bd98..4d877eb 100644
--- a/include/sdhci.h
+++ b/include/sdhci.h
@@ -64,6 +64,8 @@
 #define  SDHCI_CARD_STATE_STABLE	BIT(17)
 #define  SDHCI_CARD_DETECT_PIN_LEVEL	BIT(18)
 #define  SDHCI_WRITE_PROTECT	BIT(19)
+#define  SDHCI_DATA_BUSY	0xF00000
+#define  SDHCI_CMD_BUSY		0x1000000
 
 #define SDHCI_HOST_CONTROL	0x28
 #define  SDHCI_CTRL_LED		BIT(0)
@@ -146,6 +148,12 @@
 #define SDHCI_ACMD12_ERR	0x3C
 
 /* 3E-3F reserved */
+#define SDHCI_HOST_CTRL2	0x3E
+#define SDHCI_CTRL2_MODE_MASK	0x7
+
+#define SDHCI_18V_SIGNAL	0x8
+#define SDHCI_CTRL_EXEC_TUNING	0x0040
+#define SDHCI_CTRL_TUNED_CLK	0x80
 
 #define SDHCI_CAPABILITIES	0x40
 #define  SDHCI_TIMEOUT_CLK_MASK	0x0000003F
-- 
2.7.4



More information about the U-Boot mailing list