From patchwork Sun Jan 2 16:45:10 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philip Rakity X-Patchwork-Id: 446331 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p02GhXjP025290 for ; Sun, 2 Jan 2011 16:45:15 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751823Ab1ABQpO (ORCPT ); Sun, 2 Jan 2011 11:45:14 -0500 Received: from na3sys009aog108.obsmtp.com ([74.125.149.199]:52874 "HELO na3sys009aog108.obsmtp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1753894Ab1ABQpN convert rfc822-to-8bit (ORCPT ); Sun, 2 Jan 2011 11:45:13 -0500 Received: from source ([65.219.4.129]) (using TLSv1) by na3sys009aob108.postini.com ([74.125.148.12]) with SMTP ID DSNKTSCrmbm6yH3I5/LeEaYN6VPe5ryo+bQL@postini.com; Sun, 02 Jan 2011 08:45:13 PST Received: from SC-vEXCH3.marvell.com ([10.93.76.133]) by SC-OWA01.marvell.com ([10.93.76.21]) with mapi; Sun, 2 Jan 2011 08:45:12 -0800 From: Philip Rakity To: "linux-mmc@vger.kernel.org" CC: Mark Brown Date: Sun, 2 Jan 2011 08:45:10 -0800 Subject: [PATCH V2 2/2] sdhci: Support for SD/MMC Dual Data Rate Thread-Topic: [PATCH V2 2/2] sdhci: Support for SD/MMC Dual Data Rate Thread-Index: AcuqnGxN/2YBmPPoST2bC7zbCFFGXA== Message-ID: <35CD48DB-A420-4319-968D-400D45EE9C0D@marvell.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: acceptlanguage: en-US MIME-Version: 1.0 Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Sun, 02 Jan 2011 16:45:15 +0000 (UTC) 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