From patchwork Mon Aug 28 14:29:09 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerome Brunet X-Patchwork-Id: 111164 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp4918971qge; Mon, 28 Aug 2017 07:30:01 -0700 (PDT) X-Received: by 10.99.2.141 with SMTP id 135mr795976pgc.208.1503930601817; Mon, 28 Aug 2017 07:30:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503930601; cv=none; d=google.com; s=arc-20160816; b=0OD4O5s+p7kZSsbhPpDXLAuGKqCT06OL4gFNVdOAxDeZ86oxNHQ87Pbfs36j5Aa7Al zHhaD9KZyEbt3aGd7qVRsbk+e3OreH2AWAVi6v756L3Q5tarrNxrH+pPNjd71N79x7/C 6iOwBZTpKc6ZiNQF3IHxPbygziFIXQLNNS60QqlmmsHiYOc8w8gf8089rpnq4pvs7VvU J32C40w903rD4q2neGEw46W79ZV6mljFHZVZ3Cz8k4ZbXNKyELpkADgk+qZXJZHznHbM VxNC12pFo/nkQnMKhPbhPIEuwSqUBl/XS7OgoSNRTD0p/IWZMuWfRG4LMaHkA4EyZ95B GjJw== 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=1jT9wGDnUBouhfMeoEutvwVzMwo6xYQd8a+2ocB0s5I=; b=bW+7DTNHej+rMh2r8zy9ZI+92WOFoC0kdWKQdO8Yq5AtViXeWy1kT7ZVw5ceFKD342 jtjlFI4BqO4tQ8mO9mjkWwXltgCnb8P9uPrr7jg2ze0NlkhndH+xJZsZYRZwsaqRblgk sCtLgeak3lX+HztKJXuMONWl46m0mwuy/yxnhsv6yNlv0tMGVCoPHg+k2Lyr6bJ/fQ60 4HhYoOzQx+1bG94pxeQwTjmTFs9ISb8LPh9XS6r8JOBghoqhl1Vm54znURsRgPqNC6E4 FOMEPdji+1CDck4cd1QmsOxnxyREDiuNr04o3XRhSimwGZqQzFJVs2YfDKRsR6cLJqZ9 FE9w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@baylibre-com.20150623.gappssmtp.com header.s=20150623 header.b=IUjf4gXY; 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.30.01; Mon, 28 Aug 2017 07:30:01 -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=IUjf4gXY; 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 S1751610AbdH1O3e (ORCPT + 26 others); Mon, 28 Aug 2017 10:29:34 -0400 Received: from mail-wr0-f169.google.com ([209.85.128.169]:35358 "EHLO mail-wr0-f169.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751391AbdH1O31 (ORCPT ); Mon, 28 Aug 2017 10:29:27 -0400 Received: by mail-wr0-f169.google.com with SMTP id j29so1308854wre.2 for ; Mon, 28 Aug 2017 07:29:27 -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=1jT9wGDnUBouhfMeoEutvwVzMwo6xYQd8a+2ocB0s5I=; b=IUjf4gXY6yXOWKt28v5nU/gtjROa6P9ofBSuNmBKzXdf5VO+jK4spLzK87JMiOna+N tjf/IMsqT9Tj9SVuigRXBNQIldGoUNbAmy333i1ML7OjSs4NS/GgJGeiagAJ3Jvjkb+r 4fCTPbuCaDTWZ+rqGTMwb6kS/+n5nR+LhR7NPEOzhdHuiePnZXeWRC0T4YLNLBBK0UPV Lb0kPkmv7NHGJZOO9JE1F3+b0WWNew09Fcohx+65cPfXsI60/HSW+9GhtBVu5IcEL4Fx KfS/Gs2ScxpCa03jbrSB34BmVt3z5ubz3waqr/oL2cortZy+D2iTcJCH1c9s2qT1nbAp XSxQ== 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=1jT9wGDnUBouhfMeoEutvwVzMwo6xYQd8a+2ocB0s5I=; b=J1KTKXLgL3ZTppnvRHJpEYh0d4Aehm6787Kra/OsXkQlVJm4G+nqagGucXsi1EE//p N9nY3RjU+ktNZyJjA5/v6s2oEM4gInmw6JIVvw007lu5O5FHPkTJfN0sqjMuDjU8GGgJ W/66YPyVWB11tdM7KvoWcClsZjkQpDfM9fGRSShRq1TJy7ym96v0cwgRRZvHDd72UTMM iMU9x7RCGNU58qaflVR3yEOjrTd9UmWvCoY3G8BCPEavVa4Y2w99zuKrEZewSbP46SeY QtKDiFJgBvthIl5eW60hhyGcw2nhNvU6IBbf6xphnofkMZIpRELS6aSQ1I3vJk4njeH/ JEAQ== X-Gm-Message-State: AHYfb5gv/hhe40OnXcRKg/M6d+U8ixSUgc1UCGuqwGbGcyfDD7XfcRFu sbLHeee2gescTrKw X-Received: by 10.223.195.140 with SMTP id p12mr577628wrf.299.1503930566356; Mon, 28 Aug 2017 07:29:26 -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.25 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 28 Aug 2017 07:29:25 -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 07/13] mmc: meson-gx: work around clk-stop issue Date: Mon, 28 Aug 2017 16:29:09 +0200 Message-Id: <20170828142915.27020-8-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 It seems that the mmc clock is also used and required, somehow, by the controller itself. It is shown during init, when writing to CFG while the divider is set to 0 will crash the SoC. During a voltage switch, the controller may crash and the card may then fail to exit busy state if the clock is stopped. To avoid this, it is best to keep the clock running for the controller, except during rate change. However, we still need to be able to gate the clock out of the SoC. Let's use the pinmux for this, and fallback to gpio mode (pulled-down) when we need to gate the clock Reviewed-by: Kevin Hilman Signed-off-by: Jerome Brunet --- drivers/mmc/host/meson-gx-mmc.c | 74 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 6 deletions(-) -- 2.9.5 diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 341e5a1b32cc..43aabb793121 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -137,6 +137,10 @@ struct meson_host { struct clk *mmc_clk; unsigned long req_rate; + struct pinctrl *pinctrl; + struct pinctrl_state *pins_default; + struct pinctrl_state *pins_clk_gate; + unsigned int bounce_buf_size; void *bounce_buf; dma_addr_t bounce_dma_addr; @@ -272,6 +276,42 @@ static bool meson_mmc_timing_is_ddr(struct mmc_ios *ios) return false; } +/* + * Gating the clock on this controller is tricky. It seems the mmc clock + * is also used by the controller. It may crash during some operation if the + * clock is stopped. The safest thing to do, whenever possible, is to keep + * clock running at stop it at the pad using the pinmux. + */ +static void meson_mmc_clk_gate(struct meson_host *host) +{ + u32 cfg; + + if (host->pins_clk_gate) { + pinctrl_select_state(host->pinctrl, host->pins_clk_gate); + } else { + /* + * If the pinmux is not provided - default to the classic and + * unsafe method + */ + cfg = readl(host->regs + SD_EMMC_CFG); + cfg |= CFG_STOP_CLOCK; + writel(cfg, host->regs + SD_EMMC_CFG); + } +} + +static void meson_mmc_clk_ungate(struct meson_host *host) +{ + u32 cfg; + + if (host->pins_clk_gate) + pinctrl_select_state(host->pinctrl, host->pins_default); + + /* Make sure the clock is not stopped in the controller */ + cfg = readl(host->regs + SD_EMMC_CFG); + cfg &= ~CFG_STOP_CLOCK; + writel(cfg, host->regs + SD_EMMC_CFG); +} + static int meson_mmc_clk_set(struct meson_host *host, struct mmc_ios *ios) { struct mmc_host *mmc = host->mmc; @@ -288,9 +328,7 @@ static int meson_mmc_clk_set(struct meson_host *host, struct mmc_ios *ios) return 0; /* stop clock */ - cfg = readl(host->regs + SD_EMMC_CFG); - cfg |= CFG_STOP_CLOCK; - writel(cfg, host->regs + SD_EMMC_CFG); + meson_mmc_clk_gate(host); host->req_rate = 0; if (!rate) { @@ -299,6 +337,11 @@ static int meson_mmc_clk_set(struct meson_host *host, struct mmc_ios *ios) return 0; } + /* Stop the clock during rate change to avoid glitches */ + cfg = readl(host->regs + SD_EMMC_CFG); + cfg |= CFG_STOP_CLOCK; + writel(cfg, host->regs + SD_EMMC_CFG); + ret = clk_set_rate(host->mmc_clk, rate); if (ret) { dev_err(host->dev, "Unable to set cfg_div_clk to %lu. ret=%d\n", @@ -318,9 +361,7 @@ static int meson_mmc_clk_set(struct meson_host *host, struct mmc_ios *ios) dev_dbg(host->dev, "requested rate was %u\n", ios->clock); /* (re)start clock */ - cfg = readl(host->regs + SD_EMMC_CFG); - cfg &= ~CFG_STOP_CLOCK; - writel(cfg, host->regs + SD_EMMC_CFG); + meson_mmc_clk_ungate(host); return 0; } @@ -931,6 +972,27 @@ static int meson_mmc_probe(struct platform_device *pdev) goto free_host; } + host->pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(host->pinctrl)) { + ret = PTR_ERR(host->pinctrl); + goto free_host; + } + + host->pins_default = pinctrl_lookup_state(host->pinctrl, + PINCTRL_STATE_DEFAULT); + if (IS_ERR(host->pins_default)) { + ret = PTR_ERR(host->pins_default); + goto free_host; + } + + host->pins_clk_gate = pinctrl_lookup_state(host->pinctrl, + "clk-gate"); + if (IS_ERR(host->pins_clk_gate)) { + dev_warn(&pdev->dev, + "can't get clk-gate pinctrl, using clk_stop bit\n"); + host->pins_clk_gate = NULL; + } + host->core_clk = devm_clk_get(&pdev->dev, "core"); if (IS_ERR(host->core_clk)) { ret = PTR_ERR(host->core_clk);