From patchwork Mon Aug 21 16:03:01 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerome Brunet X-Patchwork-Id: 110565 Delivered-To: patch@linaro.org Received: by 10.182.109.195 with SMTP id hu3csp4242884obb; Mon, 21 Aug 2017 09:03:40 -0700 (PDT) X-Received: by 10.99.126.80 with SMTP id o16mr7134227pgn.378.1503331420841; Mon, 21 Aug 2017 09:03:40 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503331420; cv=none; d=google.com; s=arc-20160816; b=Eji3Ee6czSBcmnh6zEvcGirQgGmINu54/YZ/rShLwAthntZmbky5899Y/QelMJsZY/ NhkXgbxQou1xidXHS2cZDFe8gcabJZe6aEIQrdgT5ptxdt30Iq69lFJYhtqe1UWH/v6g EWvvd12jHgNXZ+GG/CoGq4N94HSf3e4EDX/fWTT6d8NAuucM4t/WLY8oLyznm8cSv2HO NsPVW+AhZ3uNuXerRS9P7pee/7OazARgzvTsXGPn5PILKDT6iXL8uIKd0UR/sST5XJSd 3OpDrnLXv35tsG3E2AopXYX9rZ0iQiPMtFJaKss4iekr5+ylRuCslHEHVcQQ8stJAmNh 6LKg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=FWSza7nhxFmVrAqzMRATkKe+54E1gYR3WI8OGLT7VxQ=; b=IRQzw6iLaaU2TxrGaASnx0UWwB156Uhw4mkVkjB8rrda6oCRdUQ33lu+Sxe1GOT4uT v/NdS5uuvORbtQ2FVNt+nml4SGfr5461f2QGNJxwfNt1Kp0abicIIUx9IHW/yv+BC3VD iu2k5e1g8JMp0PtCYcKg/hogg3xD0RvvIxh29qPwCe0XJG5FoG2HhAOpYK3VP/G+Wi9s TtGM2SXAPEvaH+SM/C1F1JeQ/KtcAqC4nlXBmL/rIm21xRvtCZDpy7Ud+7vPpKWDxZlm 0tKg27oUbRrKPVCKBp+74+EyBlb33sOanxcJ1Hkd7K9BdGhLiYCcqibfh2/77hZ9vcZx p+DA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@baylibre-com.20150623.gappssmtp.com header.s=20150623 header.b=PMnzi2Mq; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id q67si7423553pgq.557.2017.08.21.09.03.40; Mon, 21 Aug 2017 09:03:40 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@baylibre-com.20150623.gappssmtp.com header.s=20150623 header.b=PMnzi2Mq; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754507AbdHUQDi (ORCPT + 26 others); Mon, 21 Aug 2017 12:03:38 -0400 Received: from mail-wr0-f170.google.com ([209.85.128.170]:36760 "EHLO mail-wr0-f170.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754483AbdHUQDY (ORCPT ); Mon, 21 Aug 2017 12:03:24 -0400 Received: by mail-wr0-f170.google.com with SMTP id f8so67003508wrf.3 for ; Mon, 21 Aug 2017 09:03:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=FWSza7nhxFmVrAqzMRATkKe+54E1gYR3WI8OGLT7VxQ=; b=PMnzi2MqCiK+E8STsUOZeHRCziCVyZHgSCbVEiAVpeYGTo/c+F+kZkx6JJTtrCHtQt FaQoHLX28wL6/wQ+hXss7Izk98UUFIGFc0dC1rDd0K5L7BAw2VEFWctp/N0d/x164BrO +ZBYMTiJRxlgBDtAY7aSrRgCYL/fhypOzsVcjyPhML52W2WJZcLX3af3TlapmKM+2GEk laFZDH1jgC1/PwuBGsh0/eL8fk6TLzrVTQXqdKYWQFqiH+qFh9cJBGdD63CNwka/X75E hcftaRPYB44Ir8GdTbEBM4g2S2bRHS0ZrZqecICW1gBAI7C73MtiY9l7fifKAKO6rV7V dblg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=FWSza7nhxFmVrAqzMRATkKe+54E1gYR3WI8OGLT7VxQ=; b=DOnM4LRn98GaPBe5Cv3Z7zd38XntsZDf4tA3q9VTHZl8P6PbaEzWaE4ouGMVPlcJct C2b3e4/ExW3G4Pc6nGRWVNVpa/dIDqQuDIMSTKKCUd3nvL5G34gk2iwR1uEgzQNKxcu0 1/IE/xx6FT0U2FmW7yH/EAD0SV+Q70iUYWIQ0ZfBIRK7P0wJK2O5r3LMHGxHdt0n8uSq dtSC1xm227l/d6qnHmu9mLxPN3rB4WEITWx+MpifGnMeebmZ2w4xQBkYL66io+iVB8xD 8YPOWEEzveXdIWDIOh4yWjPIYEHBgAeNbdk8pcJ2q/0DhQ1ys2hdJdgrSVzKb6f20uxt tOtA== X-Gm-Message-State: AHYfb5jmHMGjRbxn+BpzroscXnr6mDcXd8eIF9B88WnTceESy1OyF+SM iqi3Ikyu5ee6aVrX X-Received: by 10.28.193.203 with SMTP id r194mr6401039wmf.85.1503331402733; Mon, 21 Aug 2017 09:03:22 -0700 (PDT) Received: from localhost.localdomain ([90.63.244.31]) by smtp.googlemail.com with ESMTPSA id 63sm8120063wra.30.2017.08.21.09.03.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 21 Aug 2017 09:03:22 -0700 (PDT) From: Jerome Brunet To: Ulf Hansson , Kevin Hilman , Carlo Caione Cc: Jerome Brunet , linux-mmc@vger.kernel.org, linux-amlogic@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 16/16] mmc: meson-gx: rework tuning function Date: Mon, 21 Aug 2017 18:03:01 +0200 Message-Id: <20170821160301.21899-17-jbrunet@baylibre.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20170821160301.21899-1-jbrunet@baylibre.com> References: <20170821160301.21899-1-jbrunet@baylibre.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Rework tuning function of the rx phase. Now that the phase can be more precisely set using CCF, test more phase setting and find the largest working window. Then the tuning selected is the one at the center of the window. This rework allows to use new modes, such as UHS SDR50 Reviewed-by: Kevin Hilman Signed-off-by: Jerome Brunet --- drivers/mmc/host/meson-gx-mmc.c | 161 +++++++++++++++++++++++++++------------- 1 file changed, 111 insertions(+), 50 deletions(-) -- 2.9.5 diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 290631d46a4b..137b93227629 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -49,6 +49,8 @@ #define CLK_TX_DELAY_MASK GENMASK(19, 16) #define CLK_RX_DELAY_MASK GENMASK(23, 20) #define CLK_DELAY_STEP_PS 200 +#define CLK_PHASE_STEP 30 +#define CLK_PHASE_POINT_NUM (360 / CLK_PHASE_STEP) #define CLK_ALWAYS_ON BIT(24) #define SD_EMMC_DELAY 0x4 @@ -119,12 +121,6 @@ #define MUX_CLK_NUM_PARENTS 2 -struct meson_tuning_params { - unsigned int core_phase; - unsigned int tx_phase; - unsigned int rx_phase; -}; - struct sd_emmc_desc { u32 cmd_cfg; u32 cmd_arg; @@ -155,7 +151,6 @@ struct meson_host { struct sd_emmc_desc *descs; dma_addr_t descs_dma_addr; - struct meson_tuning_params tp; bool vqmmc_enabled; }; @@ -458,13 +453,6 @@ static int meson_mmc_clk_set(struct meson_host *host, struct mmc_ios *ios) return 0; } -static void meson_mmc_set_phase_params(struct meson_host *host) -{ - clk_set_phase(host->mmc_clk, host->tp.core_phase); - clk_set_phase(host->tx_clk, host->tp.tx_phase); - clk_set_phase(host->rx_clk, host->tp.rx_phase); -} - /* * The SD/eMMC IP block has an internal mux and divider used for * generating the MMC clock. Use the clock framework to create and @@ -617,18 +605,122 @@ static int meson_mmc_clk_init(struct meson_host *host) if (WARN_ON(PTR_ERR_OR_ZERO(host->rx_clk))) return PTR_ERR(host->rx_clk); - /* Set the initial phase parameters */ - meson_mmc_set_phase_params(host); - /* init SD_EMMC_CLOCK to sane defaults w/min clock rate */ host->mmc->f_min = clk_round_rate(host->mmc_clk, 400000); ret = clk_set_rate(host->mmc_clk, host->mmc->f_min); if (ret) return ret; + /* + * Set phases : These values are mostly the datasheet recommended ones + * except for the Tx phase. Datasheet recommends 180 but some cards + * fail at initialisation with it. 270 works just fine, it fixes these + * initialisation issues and enable eMMC DDR52 mode. + */ + clk_set_phase(host->mmc_clk, 180); + clk_set_phase(host->tx_clk, 270); + clk_set_phase(host->rx_clk, 0); + return clk_prepare_enable(host->mmc_clk); } +static void meson_mmc_shift_map(unsigned long *map, unsigned long shift) +{ + DECLARE_BITMAP(left, CLK_PHASE_POINT_NUM); + DECLARE_BITMAP(right, CLK_PHASE_POINT_NUM); + + /* + * shift the bitmap right and reintroduce the dropped bits on the left + * of the bitmap + */ + bitmap_shift_right(right, map, shift, CLK_PHASE_POINT_NUM); + bitmap_shift_left(left, map, CLK_PHASE_POINT_NUM - shift, + CLK_PHASE_POINT_NUM); + bitmap_or(map, left, right, CLK_PHASE_POINT_NUM); +} + +static void meson_mmc_find_next_region(unsigned long *map, + unsigned long *start, + unsigned long *stop) +{ + *start = find_next_bit(map, CLK_PHASE_POINT_NUM, *start); + *stop = find_next_zero_bit(map, CLK_PHASE_POINT_NUM, *start); +} + +static int meson_mmc_find_tuning_point(unsigned long *test) +{ + unsigned long shift, stop, offset = 0, start = 0, size = 0; + + /* Get the all good/all bad situation out the way */ + if (bitmap_full(test, CLK_PHASE_POINT_NUM)) + return 0; /* All points are good so point 0 will do */ + else if (bitmap_empty(test, CLK_PHASE_POINT_NUM)) + return -EIO; /* No successful tuning point */ + + /* + * Now we know there is a least one region find. Make sure it does + * not wrap by the shifting the bitmap if necessary + */ + shift = find_first_zero_bit(test, CLK_PHASE_POINT_NUM); + if (shift != 0) + meson_mmc_shift_map(test, shift); + + while (start < CLK_PHASE_POINT_NUM) { + meson_mmc_find_next_region(test, &start, &stop); + + if ((stop - start) > size) { + offset = start; + size = stop - start; + } + + start = stop; + } + + /* Get the center point of the region */ + offset += (size / 2); + + /* Shift the result back */ + offset = (offset + shift) % CLK_PHASE_POINT_NUM; + + return offset; +} + +static int meson_mmc_clk_phase_tuning(struct mmc_host *mmc, u32 opcode, + struct clk *clk) +{ + int point, ret; + DECLARE_BITMAP(test, CLK_PHASE_POINT_NUM); + + dev_dbg(mmc_dev(mmc), "%s phase/delay tunning...\n", + __clk_get_name(clk)); + bitmap_zero(test, CLK_PHASE_POINT_NUM); + + /* Explore tuning points */ + for (point = 0; point < CLK_PHASE_POINT_NUM; point++) { + clk_set_phase(clk, point * CLK_PHASE_STEP); + ret = mmc_send_tuning(mmc, opcode, NULL); + if (!ret) + set_bit(point, test); + } + + /* Find the optimal tuning point and apply it */ + point = meson_mmc_find_tuning_point(test); + if (point < 0) + return point; /* tuning failed */ + + clk_set_phase(clk, point * CLK_PHASE_STEP); + dev_dbg(mmc_dev(mmc), "success with phase: %d\n", + clk_get_phase(clk)); + return 0; +} + +static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + struct meson_host *host = mmc_priv(mmc); + + return meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk); +} + static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct meson_host *host = mmc_priv(mmc); @@ -667,6 +759,8 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->vqmmc_enabled = true; } + /* Reset rx phase */ + clk_set_phase(host->rx_clk, 0); break; } @@ -990,29 +1084,6 @@ static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id) return IRQ_HANDLED; } -static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode) -{ - struct meson_host *host = mmc_priv(mmc); - struct meson_tuning_params tp_old = host->tp; - int ret = -EINVAL, i, cmd_error; - - dev_info(mmc_dev(mmc), "(re)tuning...\n"); - - for (i = 0; i < 360; i += 90) { - host->tp.rx_phase = i; - /* exclude the active parameter set if retuning */ - if (!memcmp(&tp_old, &host->tp, sizeof(tp_old)) && - mmc->doing_retune) - continue; - meson_mmc_set_phase_params(host); - ret = mmc_send_tuning(mmc, opcode, &cmd_error); - if (!ret) - break; - } - - return ret; -} - /* * NOTE: we only need this until the GPIO/pinctrl driver can handle * interrupts. For now, the MMC core will use this for polling. @@ -1158,16 +1229,6 @@ static int meson_mmc_probe(struct platform_device *pdev) if (ret) goto free_host; - /* - * Set phases : These values are mostly the datasheet recommended ones - * except for the Tx phase. Datasheet recommends 180 but some cards - * fail at initialisation with it. 270 works just fine, it fixes these - * initialisation issues and enable eMMC DDR52 mode. - */ - host->tp.core_phase = 180; - host->tp.tx_phase = 270; - host->tp.rx_phase = 0; - ret = meson_mmc_clk_init(host); if (ret) goto err_core_clk;