From patchwork Mon Nov 1 14:21:56 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhangfei Gao X-Patchwork-Id: 294512 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 oA1ELwU0012928 for ; Mon, 1 Nov 2010 14:22:00 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758041Ab0KAOV6 (ORCPT ); Mon, 1 Nov 2010 10:21:58 -0400 Received: from mail-yw0-f46.google.com ([209.85.213.46]:44703 "EHLO mail-yw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756461Ab0KAOV5 (ORCPT ); Mon, 1 Nov 2010 10:21:57 -0400 Received: by ywc21 with SMTP id 21so807333ywc.19 for ; Mon, 01 Nov 2010 07:21:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:received:date:message-id :subject:from:to:cc:content-type; bh=6FxNiBNnN2C5NDr6wBdtYI0u+nr4uQTZ4G2axJ3BSbU=; b=wjccEDsHhvR+sZYmbH51ll3VF1OZA7NnKtP1trMQECokpEGaJ1D1ijflFANzS/U/JR LEezN1PPcE9MV0Riu2XJEx4lUYrPCrBsEnBHL3adlwYlaQQ9ZDdigdMhdCL8z88R+rI0 ceUDzcGo8+dpBmWr+ZQ/yaPIyAoB+ndipulZU= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:date:message-id:subject:from:to:cc:content-type; b=ZFq3PDTrBOKLUf+YteUHwclDUwF7zbnErYT/5dGj43iefE6LGwel3ak7CN9hMo/QOi FzEecvV/axmdG3zBBtm6xj/dwFvFqbNgE14OqWjkKW9dQuM8JQevRWCgfK8wJyJiBGpb JKHjl+ypoHcZx6dU8dvORCvOQqI8ZeNH9EEHk= MIME-Version: 1.0 Received: by 10.204.67.68 with SMTP id q4mr2345238bki.146.1288621316386; Mon, 01 Nov 2010 07:21:56 -0700 (PDT) Received: by 10.223.1.80 with HTTP; Mon, 1 Nov 2010 07:21:56 -0700 (PDT) Date: Mon, 1 Nov 2010 10:21:56 -0400 Message-ID: Subject: [Patch 1/1]sdhci: verify ddr50 mode From: zhangfei gao To: linux-mmc@vger.kernel.org Cc: Adrian Hunter , Hanumath Prasad , Chris Ball , Matt Fleming , eric.y.miao@gmail.com, Haojian Zhuang 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]); Mon, 01 Nov 2010 14:22:00 +0000 (UTC) From 59072fa8fea50634f01009e51c4b5e16308ab466 Mon Sep 17 00:00:00 2001 From: Zhangfei Gao Date: Mon, 1 Nov 2010 07:43:57 -0400 Subject: [PATCH] sdhci: support DDR50 mode Verified DDR50 mode on sdhci-pxa and HYNIX and toshiba eMMC Signed-off-by: Zhangfei Gao --- drivers/mmc/host/sdhci.c | 48 +++++++++++++++++++++++++++++++++++++++++++++- drivers/mmc/host/sdhci.h | 15 ++++++++++++- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 782c0ee..d9e4ab8 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -982,6 +982,44 @@ static void sdhci_finish_command(struct sdhci_host *host) host->cmd = NULL; } +static void sdhci_set_ddr(struct sdhci_host *host, unsigned int ddr) +{ + u16 con; + unsigned long timeout; + + if (ddr == MMC_SDR_MODE) + return; + + if (host->ops->set_ddr) + host->ops->set_ddr(host, ddr); + + /* Fixme, how to support 1.2v Mode */ + if (ddr & MMC_1_8V_DDR_MODE) { + con = sdhci_readw(host, SDHCI_HOST_CONTROL2); + con |= SDHCI_CTRL2_1_8V; + sdhci_writew(host, con, SDHCI_HOST_CONTROL2); + + /* Wait max 5 ms */ + timeout = 5; + while (!((con = sdhci_readw(host, SDHCI_HOST_CONTROL2)) + & SDHCI_CTRL2_1_8V)) { + if (timeout == 0) { + printk(KERN_ERR "%s: HOST CONTROL fail switch to 1.8v\n", + mmc_hostname(host->mmc)); + sdhci_dumpregs(host); + return; + } + timeout--; + mdelay(1); + } + con = sdhci_readw(host, SDHCI_HOST_CONTROL2); + con &= ~SDHCI_CTRL2_UHS_MASK; + /* only support DDR50 */ + con |= SDHCI_CTRL2_DDR50; + sdhci_writew(host, con, SDHCI_HOST_CONTROL2); + } +} + static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) { int div; @@ -1176,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); @@ -1712,7 +1751,7 @@ EXPORT_SYMBOL_GPL(sdhci_alloc_host); int sdhci_add_host(struct sdhci_host *host) { struct mmc_host *mmc; - unsigned int caps; + unsigned int caps, caps_h; int ret; WARN_ON(host == NULL); @@ -1737,6 +1776,13 @@ int sdhci_add_host(struct sdhci_host *host) caps = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps : sdhci_readl(host, SDHCI_CAPABILITIES); + caps_h = sdhci_readl(host, SDHCI_CAPABILITIES_H); + + if ((caps & SDHCI_CAN_VDD_180) && + ((caps_h & SDHCI_CAN_SDR50) || + (caps_h & SDHCI_CAN_SDR104) || + (caps_h & SDHCI_CAN_DDR50))) + mmc->caps |= (MMC_CAP_1_8V_DDR); if (host->quirks & SDHCI_QUIRK_FORCE_DMA) host->flags |= SDHCI_USE_SDMA; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index b7b8a3b..fe87c5f 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -141,7 +141,14 @@ #define SDHCI_ACMD12_ERR 0x3C -/* 3E-3F reserved */ +#define SDHCI_HOST_CONTROL2 0x3E +#define SDHCI_CTRL2_UHS_MASK 0x07 +#define SDHCI_CTRL2_SDR12 0x00 +#define SDHCI_CTRL2_SDR25 0x01 +#define SDHCI_CTRL2_SDR50 0x02 +#define SDHCI_CTRL2_SDR104 0x03 +#define SDHCI_CTRL2_DDR50 0x04 +#define SDHCI_CTRL2_1_8V 0x08 #define SDHCI_CAPABILITIES 0x40 #define SDHCI_TIMEOUT_CLK_MASK 0x0000003F @@ -161,7 +168,10 @@ #define SDHCI_CAN_VDD_180 0x04000000 #define SDHCI_CAN_64BIT 0x10000000 -/* 44-47 reserved for more caps */ +#define SDHCI_CAPABILITIES_H 0x44 +#define SDHCI_CAN_SDR50 0x00000001 +#define SDHCI_CAN_SDR104 0x00000002 +#define SDHCI_CAN_DDR50 0x00000004 #define SDHCI_MAX_CURRENT 0x48 @@ -207,6 +217,7 @@ struct sdhci_ops { #endif void (*set_clock)(struct sdhci_host *host, unsigned int clock); + void (*set_ddr)(struct sdhci_host *host, unsigned int ddr); int (*enable_dma)(struct sdhci_host *host); unsigned int (*get_max_clock)(struct sdhci_host *host); -- 1.7.0.4