From patchwork Fri Jul 31 03:55:11 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: yangbo lu X-Patchwork-Id: 6908071 Return-Path: X-Original-To: patchwork-linux-mmc@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 45FCDC05AC for ; Fri, 31 Jul 2015 04:00:26 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 108DA20495 for ; Fri, 31 Jul 2015 04:00:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C7B7320494 for ; Fri, 31 Jul 2015 04:00:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750777AbbGaEAX (ORCPT ); Fri, 31 Jul 2015 00:00:23 -0400 Received: from mail-bl2on0144.outbound.protection.outlook.com ([65.55.169.144]:16672 "EHLO na01-bl2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1750724AbbGaEAW (ORCPT ); Fri, 31 Jul 2015 00:00:22 -0400 Received: from DM2PR03CA0002.namprd03.prod.outlook.com (10.141.96.12) by BN3PR0301MB1188.namprd03.prod.outlook.com (10.160.156.15) with Microsoft SMTP Server (TLS) id 15.1.225.19; Fri, 31 Jul 2015 04:00:20 +0000 Received: from BY2FFO11FD014.protection.gbl (2a01:111:f400:7c0c::180) by DM2PR03CA0002.outlook.office365.com (2a01:111:e400:2428::12) with Microsoft SMTP Server (TLS) id 15.1.225.19 via Frontend Transport; Fri, 31 Jul 2015 04:00:19 +0000 Authentication-Results: spf=fail (sender IP is 192.88.158.2) smtp.mailfrom=freescale.com; freescale.mail.onmicrosoft.com; dkim=none (message not signed) header.d=none; Received-SPF: Fail (protection.outlook.com: domain of freescale.com does not designate 192.88.158.2 as permitted sender) receiver=protection.outlook.com; client-ip=192.88.158.2; helo=az84smr01.freescale.net; Received: from az84smr01.freescale.net (192.88.158.2) by BY2FFO11FD014.mail.protection.outlook.com (10.1.14.76) with Microsoft SMTP Server (TLS) id 15.1.231.11 via Frontend Transport; Fri, 31 Jul 2015 04:00:18 +0000 Received: from titan.ap.freescale.net ([10.192.208.233]) by az84smr01.freescale.net (8.14.3/8.14.0) with ESMTP id t6V40H2M029249; Thu, 30 Jul 2015 21:00:17 -0700 From: Yangbo Lu To: , CC: Yangbo Lu Subject: [v4, 6/6] mmc: esdhc: add eMMC DDR mode support Date: Fri, 31 Jul 2015 11:55:11 +0800 Message-ID: <1438314911-47902-1-git-send-email-yangbo.lu@freescale.com> X-Mailer: git-send-email 2.1.0.27.g96db324 X-EOPAttributedMessage: 0 X-Microsoft-Exchange-Diagnostics: 1; BY2FFO11FD014; 1:dRPCwJ1Gyd5oopCkho36mTlmutuVCxpM9LTYF8TGgMYZH3GnpH+VGlDCvMFu1ar/Tm64MRKwHmZJ4tvQVcDQIj1pHUtoakLUIcv7Wcd4SJZ1XhrKPx48cmMFUea9Bi2fCR808sXUvPv6aqCjSSzwCCnSJt2bnY+8Q1FUC/kCIYmqJ2bL2uk89P0uGbBarmIERchV/el0xBbdEu78oR5UezbBAzl+8av5oOOWzpZIR9gy09xb3vNNJQzEFFmfbjLh3XRl3uV3lyszlhlH12dqV1y76hV/VlorxyzXwP7Imp7/bcFMLkbEqmWOcZ6j5XM6DULzFzUJ8Wj/umBcl05xCA== X-Forefront-Antispam-Report: CIP:192.88.158.2; CTRY:US; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(10019020)(6009001)(2980300002)(339900001)(199003)(189002)(77096005)(86362001)(50986999)(50226001)(106466001)(105606002)(77156002)(85426001)(229853001)(33646002)(46102003)(19580405001)(19580395003)(189998001)(87936001)(6806004)(47776003)(50466002)(104016003)(107886002)(92566002)(5001960100002)(48376002)(36756003)(62966003)(5001770100001)(4001430100001); DIR:OUT; SFP:1102; SCL:1; SRVR:BN3PR0301MB1188; H:az84smr01.freescale.net; FPR:; SPF:Fail; MLV:sfv; A:1; MX:1; LANG:en; MIME-Version: 1.0 X-Microsoft-Exchange-Diagnostics: 1; BN3PR0301MB1188; 2:DIX88KBtrG8ASSVPUS1pyiciqgeiZTOL4R56tztucQeAOMKpsM6lUVYKiH3kzwYMGb5yh/W2MOiFlJjwPXop4xz9ZkvdRvrcOvyytw2IVEsvRdR1Ssnk3odumYmewQGjY8B+Y+7C2ZkcaspVseQz7z+aXsOGSj46xo684us5U80=; 3:n9LEAMAdE1ZFYCAo3oaH6/PEpmx0dQ3g6hjrVItAnpTsLJZ1yXYdTrUmLjrakYN+OM9gwrXNewEZMYgmj9dZ4ZfvPuuhmkMq0Z1AJp8ZbPi1z2qtv+qX8kTpQE8LmWehomqWKGqm39rYA5RtVJq/mTqr3ibCPv6JCv6TdUZmx5EoZh2wkYuFuYqRx6j61KpZH04N7hkll+d6smzfoc6XUWgV3dKRH3q+yu4iXu4Jug4=; 25:MiZQWlz47yvnqQeWKSAhquMoFmVidGqgM7KWY9W6asAqTX9JOOLo1iLeY1+EHpo2LMTMuow8xehiojLHaKb572DMOLiPbsMVO8B4VD5vhCpOegppBQjGIFw7p8u/orY6pzPgONDOzg68BTVicKQwYyaCOTShVVs/ydMIC/WHyWQC9qUaMzlRVymyQERIg5kd4M2OyvLJmy/Xb2lJyWVqyqcBARElXMYzjEg/eWFujouB1n6ZDZGeSiriVBmrzYoa X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BN3PR0301MB1188; X-Microsoft-Exchange-Diagnostics: 1; BN3PR0301MB1188; 20:Rw+cGHZSFGHvcMVWrJGFJJc5Ky2uvEHm/v0oyfCGXOtoDDJIre2+yk5LpyxDewg8L24XjX5Qi1ES7c3ToC6e18wSo/fJECVCEgkNbqb6sO4ziDhgxgq4WOmXovEe56VggDjXY50uvFMCKDJcIWHhCChtPCkM5BzKPLlav2/f/2KCsHz87ymUI2AVwRvAQ4twylo3BmwOBoZn+m+BGPjXTGIv1yxNwNXm05YTTrG0vCCnfw3X7vySdkKrgraUnhrg+ODlHAdg1YEKJBZzL1OeHYNG+1V7PtXiilTanOpo+Nc2KifZqhzsFYMowZttsnDu8iAYlRE2XDkSKvttvdStWUNRp5Wdl2IzmYTyDeqWaj8=; 4:D6Ly2eRHDFOfkp8fjtqre84Za0hUarE5SKGic9lxcCYwqH+iH9yMgYPS4GoegTCcJNNtF8Hx1FTE608PlIqOwm2/RHNGhocZ3Z9mjTnw4Ksjgk1h/+vvUrrV6+jahvhaq1uPPYMZy4e9B/HXKTcKGZGgnny+2aZGBsIVfMb6yoALwNgysm7xMy5TrW51jOL/bJpqpme7dXayk1UGHVmBr2xj5fwX7iRGPgsHkg4o/5+nUrtnHAr3fs1gKPtVqvk8g/BaLT9NfrduXX0t5GC4uk8Yef0hN/psNDtkLoIZlOg= BN3PR0301MB1188: X-MS-Exchange-Organization-RulesExecuted X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(5005006)(3002001); SRVR:BN3PR0301MB1188; BCL:0; PCL:0; RULEID:; SRVR:BN3PR0301MB1188; X-Forefront-PRVS: 0654257CF5 X-Microsoft-Exchange-Diagnostics: 1; BN3PR0301MB1188; 23:yK8QORjII1bO4jejyfW2HAjHoqifbud2CSNNCv+BzTy+2pEfE563ZaBv/EhVXpNm4J00svsX9kdCABlmGRl2rIB1IyROT7mI0p8hrTTVgFsfNpUl/K+AK1/VmXPd1FJH1GjY8iZMTzhoYaJK9CrHko3YWMbG+akkPSgYMxAAk312NYDkL4+bb4WAcGf7MVXkrN+DG7GFTEIn5+UIFeXntHIC8ztms4JGWeJbPR+9tkGHJ7GpaqbF5hpAVi4HhbwQKRkQVPVj0a8hMIQ76uneyWEEahG/RLsd9ZVB72aVKjDyzYFzceUW/cq5uKvo9T+FCqgAWr9d1+y9Or6nzcEXAFtp1IVXfykRfC8PPqjy/TolnpzErzqQXUq4Cm1ZOws5EnnjOnC8xCROK+NoZGkYI+qpfy9ttK+o/30PrXCZ73cqxOcq2fCDZnNciTel0n8qS1eWcbxCvG93+cBchAULVQ0AV3ol+ZdIkZ2a+LFwFCwUjQjUonn9OEQizwepvP0JxSlTNXbChiClR/+mF/FEr6welGp6EbcUeKOZnm94JlKjQzZ6pwigjcjlv907q/2D5ccVdBt7XRohx2cU47dx7Zwsh2f0agMorGo0eXcNdFrcnwguxmaCA37O33XH6LjWZS2g+r8yS7zoSuM02RaxLCWNilZkhLiuBsTy7DOZ2BljwAvDAk/kJmkihgbfxnOD0w29Q9uhlI+cLhDk5Ru7i4g3KZeBfnJChzB9U7Sx0dMoU6wORhtLYr+4NzvHCmUrEDelvX3jKBNJzK+GTRRtPdJ63Vsj9swPKEUj3Nvav4Hq5YGB+N0GwwKP6Y95umklalSnjUz/LXj7l0rOF8V4mwvW57gOO2QoQr/us5w5t1mEXAXhMHMM88BI2vgESpru X-Microsoft-Exchange-Diagnostics: 1; BN3PR0301MB1188; 5:uubrEGxmH929SMtdG0tuGUxYGVgeJRXxuLl9DBrps02iSgt6FE8SIjdjsS781F8pwhh7n7sWXZ2TCeA086GoIAeaOlNuOxXeK9F5KzGfm1lv2jDTyUkWduwv/ZoRNRX2ZtzJAIfSvSRd007iGVELDg==; 24:bSfcvTsVETFO4eXZO/Wn9KcpMOOqlDfdWHxcqJnjw9aGA6eygKG8Pw5u8XSPbjnOM2OkTEMm/cYp6iPySHulLfkmqJwZJZ45GZt6ABnxN6Q=; 20:6TApDuTF2xgbs4tLol9t5kOA52SSxOoXUrJ//sZovG22XV5elFig1WdL66nct5YsG04GqdeMu7kRw7GSd5SCTw== X-OriginatorOrg: freescale.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 31 Jul 2015 04:00:18.9753 (UTC) X-MS-Exchange-CrossTenant-Id: 710a03f5-10f6-4d38-9ff4-a80b81da590d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=710a03f5-10f6-4d38-9ff4-a80b81da590d; Ip=[192.88.158.2]; Helo=[az84smr01.freescale.net] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN3PR0301MB1188 Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Spam-Status: No, score=-8.3 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add eMMC DDR mode support for Freescale SDHC adapter card. The u-boot should provide device tree properties 'adapter-type' and 'periperal-frequency' for this feature, if not, the card would not use DDR mode. Signed-off-by: Yangbo Lu --- drivers/mmc/host/sdhci-esdhc.h | 24 +++++++ drivers/mmc/host/sdhci-of-esdhc.c | 132 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 152 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index 163ac99..015ec01 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h @@ -28,10 +28,32 @@ #define ESDHC_CLOCK_MASK 0x0000fff0 #define ESDHC_PREDIV_SHIFT 8 #define ESDHC_DIVIDER_SHIFT 4 +#define ESDHC_CLOCK_CRDEN 0x00000008 #define ESDHC_CLOCK_PEREN 0x00000004 #define ESDHC_CLOCK_HCKEN 0x00000002 #define ESDHC_CLOCK_IPGEN 0x00000001 +#define ESDHCI_PRESENT_STATE 0x24 +#define ESDHC_CLK_STABLE 0x00000008 + +#define ESDHC_CAPABILITIES_1 0x114 +#define ESDHC_MODE_MASK 0x00000007 +#define ESDHC_MODE_DDR50_SEL 0xfffffffc +#define ESDHC_MODE_DDR50 0x00000004 + +#define ESDHC_CLOCK_CONTROL 0x144 +#define ESDHC_CLKLPBK_EXTPIN 0x80000000 +#define ESDHC_CMDCLK_SHIFTED 0x00008000 + +/* SDHC Adapter Card Type */ +#define ESDHC_ADAPTER_TYPE_EMMC45 0x1 /* eMMC Card Rev4.5 */ +#define ESDHC_ADAPTER_TYPE_SDMMC_LEGACY 0x2 /* SD/MMC Legacy Card */ +#define ESDHC_ADAPTER_TYPE_EMMC44 0x3 /* eMMC Card Rev4.4 */ +#define ESDHC_ADAPTER_TYPE_RSV 0x4 /* Reserved */ +#define ESDHC_ADAPTER_TYPE_MMC 0x5 /* MMC Card */ +#define ESDHC_ADAPTER_TYPE_SD 0x6 /* SD Card Rev2.0 Rev3.0 */ +#define ESDHC_NO_ADAPTER 0x7 /* No Card is Present*/ + /* pltfm-specific */ #define ESDHC_HOST_CONTROL_LE 0x20 @@ -45,6 +67,8 @@ /* OF-specific */ #define ESDHC_DMA_SYSCTL 0x40c #define ESDHC_DMA_SNOOP 0x00000040 +#define ESDHC_FLUSH_ASYNC_FIFO 0x00040000 +#define ESDHC_USE_PERIPHERAL_CLK 0x00080000 #define ESDHC_HOST_CONTROL_RES 0x01 diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index f1021d8..6d7e3f9 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -24,11 +24,30 @@ #define VENDOR_V_22 0x12 #define VENDOR_V_23 0x13 + +static u32 adapter_type; +static bool peripheral_clk_available; + static u32 esdhc_readl(struct sdhci_host *host, int reg) { u32 ret; - ret = sdhci_32bs_readl(host, reg); + if (reg == SDHCI_CAPABILITIES_1) { + ret = sdhci_32bs_readl(host, ESDHC_CAPABILITIES_1); + switch (adapter_type) { + case ESDHC_ADAPTER_TYPE_EMMC44: + if (ret & ESDHC_MODE_DDR50) { + ret &= ESDHC_MODE_DDR50_SEL; + /* enable 1/8V DDR capable */ + host->mmc->caps |= MMC_CAP_1_8V_DDR; + } else + ret &= ~ESDHC_MODE_MASK; + break; + default: + ret &= ~ESDHC_MODE_MASK; + } + } else + ret = sdhci_32bs_readl(host, reg); /* * The bit of ADMA flag in eSDHC is not compatible with standard * SDHC register, so set fake flag SDHCI_CAN_DO_ADMA2 when ADMA is @@ -159,8 +178,11 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg) } /* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */ - if (reg == SDHCI_HOST_CONTROL) + if (reg == SDHCI_HOST_CONTROL) { val &= ~ESDHC_HOST_CONTROL_RES; + val &= ~SDHCI_CTRL_HISPD; + val |= (sdhci_32bs_readl(host, reg) & SDHCI_CTRL_HISPD); + } sdhci_clrsetbits(host, 0xff, val, reg); } @@ -307,6 +329,84 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask) sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); } +static void esdhc_clock_control(struct sdhci_host *host, bool enable) +{ + u32 value; + u32 time_out; + + value = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); + + if (enable) + value |= ESDHC_CLOCK_CRDEN; + else + value &= ~ESDHC_CLOCK_CRDEN; + + sdhci_writel(host, value, ESDHC_SYSTEM_CONTROL); + + time_out = 20; + value = ESDHC_CLK_STABLE; + while (!(sdhci_readl(host, ESDHCI_PRESENT_STATE) & value)) { + if (time_out == 0) { + pr_err("%s: Internal clock never stabilised.\n", + mmc_hostname(host->mmc)); + break; + } + time_out--; + mdelay(1); + } +} + +static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) +{ + u16 ctrl_2; + u32 time_out; + u32 value; + + ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + /* Select Bus Speed Mode for host */ + ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; + if ((uhs == MMC_TIMING_MMC_HS200) || + (uhs == MMC_TIMING_UHS_SDR104)) + ctrl_2 |= SDHCI_CTRL_UHS_SDR104; + else if (uhs == MMC_TIMING_UHS_SDR12) + ctrl_2 |= SDHCI_CTRL_UHS_SDR12; + else if (uhs == MMC_TIMING_UHS_SDR25) + ctrl_2 |= SDHCI_CTRL_UHS_SDR25; + else if (uhs == MMC_TIMING_UHS_SDR50) + ctrl_2 |= SDHCI_CTRL_UHS_SDR50; + else if (uhs == MMC_TIMING_UHS_DDR50) + ctrl_2 |= SDHCI_CTRL_UHS_DDR50; + + if (uhs == MMC_TIMING_UHS_DDR50) { + esdhc_clock_control(host, false); + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); + value = sdhci_readl(host, ESDHC_CLOCK_CONTROL); + value |= (ESDHC_CLKLPBK_EXTPIN | ESDHC_CMDCLK_SHIFTED); + sdhci_writel(host, value, ESDHC_CLOCK_CONTROL); + esdhc_clock_control(host, true); + + esdhc_clock_control(host, false); + value = sdhci_readl(host, ESDHC_DMA_SYSCTL); + value |= ESDHC_FLUSH_ASYNC_FIFO; + sdhci_writel(host, value, ESDHC_DMA_SYSCTL); + /* Wait max 20 ms */ + time_out = 20; + value = ESDHC_FLUSH_ASYNC_FIFO; + while (sdhci_readl(host, ESDHC_DMA_SYSCTL) & value) { + if (time_out == 0) { + pr_err("%s: FAF bit is auto cleaned failed.\n", + mmc_hostname(host->mmc)); + + break; + } + time_out--; + mdelay(1); + } + esdhc_clock_control(host, true); + } else + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); +} + static const struct sdhci_ops sdhci_esdhc_ops = { .read_l = esdhc_readl, .read_w = esdhc_readw, @@ -322,7 +422,7 @@ static const struct sdhci_ops sdhci_esdhc_ops = { .adma_workaround = esdhci_of_adma_workaround, .set_bus_width = esdhc_pltfm_set_bus_width, .reset = esdhc_reset, - .set_uhs_signaling = sdhci_set_uhs_signaling, + .set_uhs_signaling = esdhc_set_uhs_signaling, }; #ifdef CONFIG_PM @@ -376,6 +476,8 @@ static void esdhc_get_property(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + const __be32 *value; + int size; sdhci_get_of_property(pdev); @@ -383,6 +485,18 @@ static void esdhc_get_property(struct platform_device *pdev) mmc_of_parse(host->mmc); mmc_of_parse_voltage(np, &host->ocr_mask); + value = of_get_property(np, "adapter-type", &size); + if (value && size == sizeof(*value) && *value) + adapter_type = be32_to_cpup(value); + + /* If getting a peripheral-frequency, use it instead */ + value = of_get_property(np, "peripheral-frequency", &size); + if (value && size == sizeof(*value) && *value) { + pltfm_host->clock = be32_to_cpup(value); + peripheral_clk_available = true; + } else + peripheral_clk_available = false; + if (of_device_is_compatible(np, "fsl,p5040-esdhc") || of_device_is_compatible(np, "fsl,p5020-esdhc") || of_device_is_compatible(np, "fsl,p4080-esdhc") || @@ -409,13 +523,23 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) { struct sdhci_host *host; int ret; - + u32 value; host = sdhci_pltfm_init(pdev, &sdhci_esdhc_pdata, 0); if (IS_ERR(host)) return PTR_ERR(host); esdhc_get_property(pdev); + + /* Select peripheral clock as the eSDHC clock */ + if (peripheral_clk_available) { + esdhc_clock_control(host, false); + value = sdhci_readl(host, ESDHC_DMA_SYSCTL); + value |= ESDHC_USE_PERIPHERAL_CLK; + sdhci_writel(host, value, ESDHC_DMA_SYSCTL); + esdhc_clock_control(host, true); + } + ret = sdhci_add_host(host); if (ret) goto err;