From patchwork Fri Dec 3 12:08:37 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhangfei Gao X-Patchwork-Id: 377701 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 oB3C8fu5010428 for ; Fri, 3 Dec 2010 12:08:41 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758478Ab0LCMIk (ORCPT ); Fri, 3 Dec 2010 07:08:40 -0500 Received: from mail-fx0-f46.google.com ([209.85.161.46]:48589 "EHLO mail-fx0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1758451Ab0LCMIj (ORCPT ); Fri, 3 Dec 2010 07:08:39 -0500 Received: by fxm20 with SMTP id 20so2109897fxm.19 for ; Fri, 03 Dec 2010 04:08:38 -0800 (PST) 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=bJgXUNN/kHnaz56ytBpsVtxWt0HqEMtyjWnMcBAZn5U=; b=RnXFq5JHJaVEuz2iz86U2y/Px4xLYiF8jokWpe6Bl0cHtOVOC7rLU/IlZO7Asg6hVG v32htXstkKJ1d8SedlLRGmmLRc+aW1QwvocVDHQrOkklHGzFzJyVwmxyeI64AXVYDC51 R90VhAa7BvVKGhGU9Ijokuk+rudGIvg+LvWKk= 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=fr+W96ielOMZZKxIzfa9wJ9KieOXCB7mKLLDYERpd/hn0lBw2tJ0pUj1mYcYmx6Ybk KZuEqQqVR6q4yozTRH3OHuOzAkMws1yghgVV5nN0ZrVhX6xreq9i8eNw2liKBN9WV3Q2 8zhOhSUGvMhJRvOSvox3XoA1lgWU4EB14vUdE= MIME-Version: 1.0 Received: by 10.223.86.4 with SMTP id q4mr2016076fal.20.1291378117876; Fri, 03 Dec 2010 04:08:37 -0800 (PST) Received: by 10.223.86.196 with HTTP; Fri, 3 Dec 2010 04:08:37 -0800 (PST) Date: Fri, 3 Dec 2010 07:08:37 -0500 Message-ID: Subject: [PATCH v2 1/1] sdhci support emmc ddr50 mode From: zhangfei gao To: linux-mmc@vger.kernel.org Cc: Chris Ball , Adrian Hunter , Hanumath Prasad , Eric Miao , 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]); Fri, 03 Dec 2010 12:08:42 +0000 (UTC) From 5e4d3011401c3a248851c22b6aa92ee3b2397dfc Mon Sep 17 00:00:00 2001 From: Zhangfei Gao Date: Fri, 3 Dec 2010 07:21:15 -0500 Subject: [PATCH] mmc: sdhci support emmc ddr50 mode 1. spec 3.0 does not claim support 1.2v ddr mode 2. Call back function set_power is added, since some controller count on external pmic to provide power Signed-off-by: Zhangfei Gao --- drivers/mmc/core/core.c | 6 ++++++ drivers/mmc/host/sdhci.c | 36 +++++++++++++++++++++++++++++++++++- drivers/mmc/host/sdhci.h | 14 ++++++++++++-- include/linux/mmc/mmc.h | 1 + include/linux/mmc/sdhci.h | 2 ++ 5 files changed, 56 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 8bf542c..512e15d 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1573,6 +1573,12 @@ void mmc_rescan(struct work_struct *work) */ err = mmc_send_op_cond(host, 0, &ocr); if (!err) { + if (ocr & MMC_CARD_1_8V) { + mmc_power_off(host); + host->ocr = ocr & host->ocr_avail; + mmc_power_up(host); + } + if (mmc_attach_mmc(host, ocr)) mmc_power_off(host); goto out; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index a25db42..b7ad2f6 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -982,6 +982,22 @@ 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; + + if (ddr == MMC_SDR_MODE) + return; + + con = sdhci_readw(host, SDHCI_HOST_CONTROL2); + if (con & SDHCI_CTRL2_1_8V) { + con &= ~SDHCI_CTRL2_UHS_MASK; + if (ddr & MMC_1_8V_DDR_MODE) + 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; @@ -1080,6 +1096,17 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) return; } + if (pwr == SDHCI_POWER_180) { + u16 con; + + con = sdhci_readw(host, SDHCI_HOST_CONTROL2); + con |= SDHCI_CTRL2_1_8V; + sdhci_writew(host, con, SDHCI_HOST_CONTROL2); + + if (host->ops->set_power) + host->ops->set_power(host, pwr); + } + /* * Spec says that we should clear the power reg before setting * a new value. Some controllers don't seem to like this though. @@ -1176,6 +1203,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); @@ -1736,7 +1764,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); @@ -1761,6 +1789,12 @@ 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) { + if (caps_h & SDHCI_CAN_SDR50) + 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 b689cc6..28c460a 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -144,7 +144,14 @@ #define SDHCI_ACMD12_ERR 0x3C -/* 3E-3F reserved */ +#define SDHCI_HOST_CONTROL2 0x3E +#define SDHCI_CTRL2_UHS_MASK 0x0007 +#define SDHCI_CTRL2_SDR12 0x0000 +#define SDHCI_CTRL2_SDR25 0x0001 +#define SDHCI_CTRL2_SDR50 0x0002 +#define SDHCI_CTRL2_SDR104 0x0003 +#define SDHCI_CTRL2_DDR50 0x0004 +#define SDHCI_CTRL2_1_8V 0x0008 #define SDHCI_CAPABILITIES 0x40 #define SDHCI_TIMEOUT_CLK_MASK 0x0000003F @@ -165,7 +172,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 diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 956fbd8..bd09b19 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -202,6 +202,7 @@ struct _mmc_csd { * OCR bits are mostly in host.h */ #define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */ +#define MMC_CARD_1_8V 0x00000080 /* Card 1.70-1.95V support bit */ /* * Card Command Classes (CCC) diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 86e8380..57bcda9 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -163,6 +163,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_power)(struct sdhci_host *host, + unsigned short power); }; -- 1.7.0.4