From patchwork Mon Jan 2 23:03:42 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 9494285 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 639EA606A9 for ; Tue, 3 Jan 2017 00:06:01 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4C88924560 for ; Tue, 3 Jan 2017 00:06:01 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 40A83269A3; Tue, 3 Jan 2017 00:06:01 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AF51F24560 for ; Tue, 3 Jan 2017 00:06:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756586AbdABXFl (ORCPT ); Mon, 2 Jan 2017 18:05:41 -0500 Received: from foss.arm.com ([217.140.101.70]:45664 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752963AbdABXED (ORCPT ); Mon, 2 Jan 2017 18:04:03 -0500 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 9806413D5; Mon, 2 Jan 2017 15:04:02 -0800 (PST) Received: from slackpad.lan (usa-sjc-mx-foss1.foss.arm.com [217.140.101.70]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 1B22D3F318; Mon, 2 Jan 2017 15:03:59 -0800 (PST) From: Andre Przywara To: Maxime Ripard , Ulf Hansson Cc: Chen-Yu Tsai , Hans De Goede , Icenowy Zheng , Mark Rutland , Rob Herring , devicetree@vger.kernel.org, linux-mmc@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@googlegroups.com, linux-kernel@vger.kernel.org Subject: [PATCH 1/5] drivers: mmc: sunxi: fix A64 calibration routine Date: Mon, 2 Jan 2017 23:03:42 +0000 Message-Id: <1483398226-29321-2-git-send-email-andre.przywara@arm.com> X-Mailer: git-send-email 2.8.2 In-Reply-To: <1483398226-29321-1-git-send-email-andre.przywara@arm.com> References: <1483398226-29321-1-git-send-email-andre.przywara@arm.com> Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The calibration facility in the A64 MMC block seems to have been misunderstood: the result value is not the value to program into the delay bits, but is the number of delay cells that result in a full clock cycle delay. So this value has to be scaled by the desired phase, which we still have to know and program. Change the calibration routine to take a phase parameter and scale the calibration value accordingly. Also introduce sun50i-a64 delay parameters to store the required phase. Looking at the BSP kernel the sample delay for anything below HS200 is 0, so we go with that value. Once the driver supports HS200 and faster modes, we can enter confirmed working values in there. Signed-off-by: Andre Przywara --- drivers/mmc/host/sunxi-mmc.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index b1d1303..1e156e8 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -681,15 +681,13 @@ static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en) return 0; } -static int sunxi_mmc_calibrate(struct sunxi_mmc_host *host, int reg_off) +static int sunxi_mmc_calibrate(struct sunxi_mmc_host *host, int reg_off, + int degrees) { u32 reg = readl(host->reg_base + reg_off); u32 delay; unsigned long timeout; - if (!host->cfg->can_calibrate) - return 0; - reg &= ~(SDXC_CAL_DL_MASK << SDXC_CAL_DL_SW_SHIFT); reg &= ~SDXC_CAL_DL_SW_EN; @@ -711,6 +709,7 @@ static int sunxi_mmc_calibrate(struct sunxi_mmc_host *host, int reg_off) } delay = (reg >> SDXC_CAL_DL_SHIFT) & SDXC_CAL_DL_MASK; + delay = degrees * delay / 360; reg &= ~SDXC_CAL_START; reg |= (delay << SDXC_CAL_DL_SW_SHIFT) | SDXC_CAL_DL_SW_EN; @@ -748,6 +747,11 @@ static int sunxi_mmc_clk_set_phase(struct sunxi_mmc_host *host, return -EINVAL; } + if (host->cfg->can_calibrate) + return sunxi_mmc_calibrate(host, SDXC_REG_SAMP_DL_REG, + host->cfg->clk_delays[index].sample); + /* TODO: calibrate data strobe delay once HS-400 is supported. */ + clk_set_phase(host->clk_sample, host->cfg->clk_delays[index].sample); clk_set_phase(host->clk_output, host->cfg->clk_delays[index].output); @@ -802,12 +806,6 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, if (ret) return ret; - ret = sunxi_mmc_calibrate(host, SDXC_REG_SAMP_DL_REG); - if (ret) - return ret; - - /* TODO: enable calibrate on sdc2 SDXC_REG_DS_DL_REG of A64 */ - return sunxi_mmc_oclk_onoff(host, 1); } @@ -1061,6 +1059,14 @@ static const struct sunxi_mmc_clk_delay sun9i_mmc_clk_delays[] = { [SDXC_CLK_50M_DDR_8BIT] = { .output = 72, .sample = 72 }, }; +static const struct sunxi_mmc_clk_delay sun50i_mmc_clk_delays[] = { + [SDXC_CLK_400K] = { .output = 90, .sample = 0 }, + [SDXC_CLK_25M] = { .output = 90, .sample = 0 }, + [SDXC_CLK_50M] = { .output = 90, .sample = 0 }, + [SDXC_CLK_50M_DDR] = { .output = 90, .sample = 0 }, + [SDXC_CLK_50M_DDR_8BIT] = { .output = 90, .sample = 0 }, +}; + static const struct sunxi_mmc_cfg sun4i_a10_cfg = { .idma_des_size_bits = 13, .clk_delays = NULL, @@ -1087,7 +1093,7 @@ static const struct sunxi_mmc_cfg sun9i_a80_cfg = { static const struct sunxi_mmc_cfg sun50i_a64_cfg = { .idma_des_size_bits = 16, - .clk_delays = NULL, + .clk_delays = sun50i_mmc_clk_delays, .can_calibrate = true, }; @@ -1134,7 +1140,7 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host, return PTR_ERR(host->clk_mmc); } - if (host->cfg->clk_delays) { + if (host->cfg->clk_delays && !host->cfg->can_calibrate) { host->clk_output = devm_clk_get(&pdev->dev, "output"); if (IS_ERR(host->clk_output)) { dev_err(&pdev->dev, "Could not get output clock\n");