diff mbox

[V2,2/2] sdhci: Support for SD/MMC Dual Data Rate

Message ID 35CD48DB-A420-4319-968D-400D45EE9C0D@marvell.com (mailing list archive)
State New, archived
Headers show

Commit Message

Philip Rakity Jan. 2, 2011, 4:45 p.m. UTC
None
diff mbox

Patch

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index d5febe5..805f850 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -84,6 +84,8 @@  static void sdhci_dumpregs(struct sdhci_host *host)
 	printk(KERN_DEBUG DRIVER_NAME ": Cmd:      0x%08x | Max curr: 0x%08x\n",
 		sdhci_readw(host, SDHCI_COMMAND),
 		sdhci_readl(host, SDHCI_MAX_CURRENT));
+	printk(KERN_DEBUG DRIVER_NAME ": HostCtrl2:0x%08x\n",
+		sdhci_readw(host, SDHCI_HOST_CONTROL_2));
 
 	if (host->flags & SDHCI_USE_ADMA)
 		printk(KERN_DEBUG DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
@@ -986,6 +988,38 @@  static void sdhci_finish_command(struct sdhci_host *host)
 	host->cmd = NULL;
 }
 
+/*
+ * Handle 1.8V signaling for DDR. No need to check for other
+ * DDR values since driver supports ONLY 1_8V DDR.  This is
+ * set by the MMC_CAP_1_8V_DDR.  1_2V DDR is not supported.
+ */
+static void sdhci_set_ddr(struct sdhci_host *host, unsigned int ddr)
+{
+	u16 con;
+
+	if (ddr == MMC_SDR_MODE)
+		return;
+
+	con = sdhci_readw(host, SDHCI_HOST_CONTROL_2);
+	con |= SDCTRL_2_SDH_V18_EN;
+	sdhci_writew(host, con, SDHCI_HOST_CONTROL_2);
+
+	/* Change sigalling voltage and wait for it to be stable */
+	if (host->ops->set_signaling_voltage)
+		host->ops->set_signaling_voltage(host, 18);
+	else
+		mdelay(5);
+
+	/*
+	 * We can fail here but there is no higher level recovery
+	 * since the card is already past the switch to ddr
+	 */
+	con = sdhci_readw(host, SDHCI_HOST_CONTROL_2);
+	con &= ~SDCTRL_2_UHS_MODE_MASK;
+	con |= SDCTRL_2_UHS_MODE_SEL_DDR50;
+	sdhci_writew(host, con, SDHCI_HOST_CONTROL_2);
+}
+
 static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 {
 	int div;
@@ -1180,6 +1214,7 @@  static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	}
 
 	sdhci_set_clock(host, ios->clock);
+	sdhci_set_ddr(host, ios->ddr);
 
 	if (ios->power_mode == MMC_POWER_OFF)
 		sdhci_set_power(host, -1);
@@ -1744,7 +1779,7 @@  EXPORT_SYMBOL_GPL(sdhci_alloc_host);
 int sdhci_add_host(struct sdhci_host *host)
 {
 	struct mmc_host *mmc;
-	unsigned int caps, ocr_avail;
+	unsigned int caps, caps_h, ocr_avail;
 	int ret;
 
 	WARN_ON(host == NULL);
@@ -1767,8 +1802,19 @@  int sdhci_add_host(struct sdhci_host *host)
 			host->version);
 	}
 
-	caps = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
-		sdhci_readl(host, SDHCI_CAPABILITIES);
+	if (host->quirks & SDHCI_QUIRK_MISSING_CAPS) {
+		caps = host->caps;
+		caps_h = 0;
+	} else {
+		caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+		if (host->version >= SDHCI_SPEC_300) 
+			caps_h = sdhci_readl(host, SDHCI_CAPABILITIES_1);
+		else
+			caps_h = 0;
+	}
+
+	if (caps_h & SDHCI_CAN_DDR50)
+		mmc->caps |= MMC_CAP_1_8V_DDR;
 
 	if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
 		host->flags |= SDHCI_USE_SDMA;
@@ -1905,7 +1951,6 @@  int sdhci_add_host(struct sdhci_host *host)
 		ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31;
 	if (caps & SDHCI_CAN_VDD_180)
 		ocr_avail |= MMC_VDD_165_195;
-
 	mmc->ocr_avail = ocr_avail;
 	mmc->ocr_avail_sdio = ocr_avail;
 	if (host->ocr_avail_sdio)
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 36f3861..d976e4f 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -182,6 +182,9 @@ 
 #define  SDHCI_CAN_64BIT	0x10000000
 
 #define SDHCI_CAPABILITIES_1	0x44
+#define  SDHCI_CAN_SDR50	0x00000001
+#define  SDHCI_CAN_SDR104	0x00000002
+#define  SDHCI_CAN_DDR50	0x00000004
 
 #define SDHCI_MAX_CURRENT	0x48
 
@@ -237,6 +240,8 @@  struct sdhci_ops {
 	void (*platform_send_init_74_clocks)(struct sdhci_host *host,
 					     u8 power_mode);
 	unsigned int    (*get_ro)(struct sdhci_host *host);
+	unsigned int    (*set_signaling_voltage)(struct sdhci_host *host,
+				unsigned short voltage);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS