From patchwork Mon Aug 28 14:29:15 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerome Brunet X-Patchwork-Id: 111163 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp4918453qge; Mon, 28 Aug 2017 07:29:40 -0700 (PDT) X-Received: by 10.98.86.2 with SMTP id k2mr668536pfb.289.1503930580658; Mon, 28 Aug 2017 07:29:40 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503930580; cv=none; d=google.com; s=arc-20160816; b=HGdOstPgGXZ776cuc1h+N75rXTBFpAEnt/slupHgkumClNDXjOqqu/R5iQbJbOiraz dE2X8psrHPWp/DmOa9bpnV1K9u0djR3W4qE0Q9ax8z/dnNOi2H7XAfjoVgRFq6EZnbqZ XjZyj07DIb01IE7nqGTVZ6PmffxsfT6ly61hPo+ynZvQBIoE3s8QzCKaqtp0H3NU7Hyz 9jeP3MQHkMzHP/jSB5A4ALLI0PWueokKsCx6SVCQbDGdjj/LwVB/EP9lwlNcdbI3CeOW aDVGwzivlrocWqILBIelmAbKdCjUcrQENt/WoOan6o8hgZoZtgwRtMDGrHDxdH2EDf1r ch3A== 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=6/p7RNjyKOVhaAY7O3Thr4HF79bMnzRn5Kab+yXzW7I=; b=VYgoaz94zv8uDKUkrqSrRb4RaHK1HIvcPkVIyr4aQ3GaN6JKcKEmoB/VBr2Mh+xJgz 96OZmQAlX+mayNS4ebgEicqPnM+cirM0zEO0eCBkfguh5V+WqMUU30CelMHHcsdPAQBp SmN5Gh0Y3b4XDiRkmOaqWFkzXfJ3nxuOSH0kT7Rl086e0oZEcX19YLLfvH7JQMi9jtCH J7JbykUSeVskeYlXOjYcn08txENALHG1MiItm/tp4cma97MkyrSmEH3goQ3gq7k1r61z oB0xTrP2gT+NBi4pYZJmeg00ryEwTIrZRn7YmuU+2tOeSUKbeAfZISWVQ5/tGDdQdgZE xqIQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@baylibre-com.20150623.gappssmtp.com header.s=20150623 header.b=qdBuZoLi; 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 q2si442313plh.318.2017.08.28.07.29.40; Mon, 28 Aug 2017 07:29: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=qdBuZoLi; 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 S1751707AbdH1O3g (ORCPT + 26 others); Mon, 28 Aug 2017 10:29:36 -0400 Received: from mail-wm0-f48.google.com ([74.125.82.48]:34575 "EHLO mail-wm0-f48.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751550AbdH1O3e (ORCPT ); Mon, 28 Aug 2017 10:29:34 -0400 Received: by mail-wm0-f48.google.com with SMTP id f13so13392323wme.1 for ; Mon, 28 Aug 2017 07:29:33 -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=6/p7RNjyKOVhaAY7O3Thr4HF79bMnzRn5Kab+yXzW7I=; b=qdBuZoLi06F4BdZ6RpRhkcxDDJgbp7U9cxUIhwpWuMPPj/qz+YBPVXupJZ86MsJCTU uuFP4kxjI7WUWZTvTKhMqB+1RLGbl/p68rsdrXcnppSkaNb0RPpP4BSmFn4Gbn5qCjvo PIabLZNkE1wI7oxZDZ5OFxN9HC+AWVwNbOzTdp3X+T6wDi9bymZtYBR+CeytOwOVsM0F A5C9Uoj3bKRKhTkpQHHt4IR2WJSk/26C3KvVK1v1gZfwLs2CjF3H2rjIDA9Y8mvv1GnY DmS2gvM3qxEldcf2aXAHzKoNgzrnuObcn3FJwUjpmE8PCydjTzrVYqg9KuGDDKEBzlBD ZxRQ== 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=6/p7RNjyKOVhaAY7O3Thr4HF79bMnzRn5Kab+yXzW7I=; b=JrXCe7rmBxZXqKxbNdoOndgkrsOyOOx904q1xm5BptWTQRJgAZ+Q7fr5V06M/ogbfo 9UKZS3ThMYWfSBqkvgOv/VW019dIB1xPPvrl6g5AND1HAeOvzwOXvGGydLR6gwk1t62v sengTO5tK/O2yr0r5kucLPSOYePFsZZCsIZxN+QM+Du5T4cy/M3pWoOaFI06JVT/kShN myMT22CJGYkByaEAhEeLvQNzn19c5wFDBkqwZUa7IEhqo76pxhEwGEGsetdmOeapDGke a92hm4rC2j5dfM1FSymC4peVyFIKIyp4M2LANvhM8BULMyAinHEDE5KJDYyTz7Y/SYIn EqZQ== X-Gm-Message-State: AHYfb5i5PlfTeFzx6042htMnRxDwzHM4BT25ipE2icuFcQPynlosgvcc Hh2grDG0eVudBzYx X-Received: by 10.28.13.130 with SMTP id 124mr486495wmn.13.1503930572535; Mon, 28 Aug 2017 07:29:32 -0700 (PDT) Received: from localhost.localdomain (uluru.liltaz.com. [163.172.81.188]) by smtp.googlemail.com with ESMTPSA id z39sm604792wrz.61.2017.08.28.07.29.31 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 28 Aug 2017 07:29:31 -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 v3 13/13] mmc: meson-gx: rework tuning function Date: Mon, 28 Aug 2017 16:29:15 +0200 Message-Id: <20170828142915.27020-14-jbrunet@baylibre.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20170828142915.27020-1-jbrunet@baylibre.com> References: <20170828142915.27020-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 efffd36c8d77..987bae98c61f 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; } @@ -989,29 +1083,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. @@ -1156,16 +1227,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;