From patchwork Wed May 11 21:40:48 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 9075171 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id F1EC59F30C for ; Wed, 11 May 2016 21:43:15 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id EEF38201B9 for ; Wed, 11 May 2016 21:43:14 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E9FAF20155 for ; Wed, 11 May 2016 21:43:13 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1b0bt1-0006vf-8B; Wed, 11 May 2016 21:41:43 +0000 Received: from mail-pf0-x231.google.com ([2607:f8b0:400e:c00::231]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1b0bsy-0006pv-Mz for linux-arm-kernel@lists.infradead.org; Wed, 11 May 2016 21:41:41 +0000 Received: by mail-pf0-x231.google.com with SMTP id 77so22624765pfv.2 for ; Wed, 11 May 2016 14:41:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id; bh=5d9f7CVll0jmPzWJgvjeSjl7Z+EL2CzJ0z6jt3mLVR0=; b=WPaXUWbntPoS5ZgJOOIyQOUoJyNVZSR2MUhVBMm7Sj45mubjLYeJBXOP7ZGstIbGO4 IeZpdbZQok+HEjp/zrrkilFN7FF0xlWmqoyPZ5tDm1Ite/LwETj3p+UdOsrI0Pe1+rqc lY7r6BK5bRCg0YpN2LkSVjBlVXiRonEl7454o= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=5d9f7CVll0jmPzWJgvjeSjl7Z+EL2CzJ0z6jt3mLVR0=; b=hTRTeWU+XyV82FmeyJMMlHYxwQsrsCWdK+kz7T8zw8FtyXoP+8kdlamV2J2228E6Us XXJCmx8Y7VW/NCS8uBHXRbeaqGd7m8e8bXVLfO446QGSr3SJ3ga3iUC114Dg6tLniviO cxu/Sm00+OK1LU823pj3vrc0pMIIXhYEHrUzAtz2JUOkJI6Q3ydMJt2kS1Brm5s7Xzg5 S8yomzKK09WhzpFfcGSvQajnHU/IQcN77mChB18EMwGCJO0FGMk2XKynm+FlxluGm1st heeD8HZ11Vv0xOZfreoYR1M7V0kJKnIL2Va/0C6/7Kpw6+IFvkj2wSWbqG5/H02RihlZ p3wA== X-Gm-Message-State: AOPr4FUockI7F/YkwZ0TIkzpnOsNfyQH8iLvhbxGOMUfVXDHZXdwgdnDncOCZlj93zqEHg== X-Received: by 10.98.54.194 with SMTP id d185mr8411286pfa.34.1463002879995; Wed, 11 May 2016 14:41:19 -0700 (PDT) Received: from tictac.mtv.corp.google.com ([172.22.65.76]) by smtp.gmail.com with ESMTPSA id w15sm14477656pfa.34.2016.05.11.14.41.18 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 11 May 2016 14:41:19 -0700 (PDT) From: Douglas Anderson To: jh80.chung@samsung.com, Ulf Hansson , Heiko Stuebner , shawn.lin@rock-chips.com Subject: [PATCH v2] mmc: dw_mmc: rockchip: Set the drive phase properly Date: Wed, 11 May 2016 14:40:48 -0700 Message-Id: <1463002848-580-1-git-send-email-dianders@chromium.org> X-Mailer: git-send-email 2.8.0.rc3.226.g39d4020 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160511_144140_798137_F4337136 X-CRM114-Status: GOOD ( 21.92 ) X-Spam-Score: -2.7 (--) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: briannorris@chromium.org, linux-mmc@vger.kernel.org, Douglas Anderson , linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-5.5 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=unavailable 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 Historically for Rockchip devices we've relied on the power-on default (or perhaps the firmware setting) to get the correct drive phase for dw_mmc devices. This worked OK for the most part, but: * Relying on the setting just "being right" is a bit fragile. * As soon as there is an instance where the power on default is wrong or where the firmware didn't configure this properly then we'll get a mysterious failure. Let's explicitly set this phase in the kernel. The comments inside this patch try to explain the situation quite throughly, but the high level overview of this is: Before this patch on rk3288 devices tested: * eMMC: 180 degrees * SDMMC/SDIO0/SDIO1: 90 degrees After this patch: * Use 90 degree phase offset usually. * Use 180 degree phase offset for MMC_DDR52, SDR104, HS200. That means we are _changing_ behavior for those devices in this way: * If we have HS200 eMMC or DDR52 eMMC, we'll run ID mode at 90 degrees (vs 180) but otherwise have no change. * For any non-HS200 / non-DDR52 eMMC devices we'll now _always_ run at 90 degrees (vs 180). It seems fairly unlikely that building modern hardware is using an eMMC that isn't using DDR52 or HS200, of course. * For SDR104 cards we'll now run with 180 degree phase offset (vs 90). It's expected that 90 degree phase offset would have worked OK, but this gives us extra margin. I have tested this by inserting my collection of uSD cards (mostly UHS, though a few not) into a veyron_minnie and confirmed that they still seem to enumerate properly. For a subset of them I tried putting a filesystem on them and also tried running mmc_test. Signed-off-by: Douglas Anderson Reviewed-by: Shawn Lin --- Changes in v2: - Now use 90 degrees for some modes; updated comments to say why. drivers/mmc/host/dw_mmc-rockchip.c | 64 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index 8c20b81cafd8..8068fa887db8 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -66,6 +66,70 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios) /* Make sure we use phases which we can enumerate with */ if (!IS_ERR(priv->sample_clk)) clk_set_phase(priv->sample_clk, priv->default_sample_phase); + + /* + * Set the drive phase offset based on speed mode to achieve hold times. + * + * That this is _not_ a value that is dynamically tuned and is also + * _not_ a value that will vary from board to board. It is a value + * that could vary between different SoC models if they had massively + * different output clock delays inside their dw_mmc IP block (delay_o), + * but since it's OK to overshoot a little we don't need to do complex + * calculations and can pick values that will just work for everyone. + * + * When picking values we'll stick with picking 0/90/180/270 since + * those can be made very accurately on all known Rockchip SoCs. + * + * Note that these values match values from the DesignWare Databook + * tables for the most part except for SDR12 and "ID mode". For those + * two modes the databook calculations assume a clock in of 50MHz. As + * seen above, we always use a clock in rate that is exactly the + * card's input clock (times RK3288_CLKGEN_DIV, but that gets divided + * back out before the controller sees it). + * + * From measurement of a single device, it appears that delay_o is + * about .5 ns. Since we try to leave a bit of margin, it's expected + * that numbers here will be fine even with much larger delay_o + * (the 1.4 ns assumed by the DesignWare Databook would result in the + * same results, for instance). + */ + if (!IS_ERR(priv->drv_clk)) { + int phase; + + /* + * In almost all cases a 90 degree phase offset will provide + * sufficient hold times across all valid input clock rates + * assuming delay_o is not absurd for a given SoC. We'll use + * that as a default. + */ + phase = 90; + + switch (ios->timing) { + case MMC_TIMING_MMC_DDR52: + /* + * Since clock in rate with MMC_DDR52 is doubled when + * bus width is 8 we need to double the phase offset + * to get the same timings. + */ + if (ios->bus_width == MMC_BUS_WIDTH_8) + phase = 180; + break; + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_MMC_HS200: + /* + * In the case of 150 MHz clock (typical max for + * Rockchip SoCs), 90 degree offset will add a delay + * of 1.67 ns. That will meet min hold time of .8 ns + * as long as clock output delay is < .87 ns. On + * SoCs measured this seems to be OK, but it doesn't + * hurt to give margin here, so we use 180. + */ + phase = 180; + break; + } + + clk_set_phase(priv->drv_clk, phase); + } } #define NUM_PHASES 360