From patchwork Mon Jul 9 07:39:33 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yinbo Zhu X-Patchwork-Id: 10513775 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 2178560318 for ; Mon, 9 Jul 2018 07:41:49 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 11D0E1FF41 for ; Mon, 9 Jul 2018 07:41:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 05A8B289B2; Mon, 9 Jul 2018 07:41:49 +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=-7.9 required=2.0 tests=BAYES_00, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham 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 64D401FF41 for ; Mon, 9 Jul 2018 07:41:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932231AbeGIHlq (ORCPT ); Mon, 9 Jul 2018 03:41:46 -0400 Received: from inva021.nxp.com ([92.121.34.21]:57662 "EHLO inva021.nxp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753933AbeGIHln (ORCPT ); Mon, 9 Jul 2018 03:41:43 -0400 Received: from inva021.nxp.com (localhost [127.0.0.1]) by inva021.eu-rdc02.nxp.com (Postfix) with ESMTP id E98D2200091; Mon, 9 Jul 2018 09:41:41 +0200 (CEST) Received: from smtp.na-rdc02.nxp.com (inv1260.us-phx01.nxp.com [134.27.49.11]) by inva021.eu-rdc02.nxp.com (Postfix) with ESMTP id 934BB200097; Mon, 9 Jul 2018 09:41:41 +0200 (CEST) Received: from az84smr01.freescale.net (az84smr01.freescale.net [10.64.34.197]) by inv1260.na-rdc02.nxp.com (Postfix) with ESMTP id 10C3B40A70; Mon, 9 Jul 2018 00:41:41 -0700 (MST) Received: from titan.ap.freescale.net ([10.192.208.233]) by az84smr01.freescale.net (8.14.3/8.14.0) with ESMTP id w697fc0L032488; Mon, 9 Jul 2018 00:41:39 -0700 From: Yinbo Zhu To: yinbo.zhu@nxp.com, linux-mmc@vger.kernel.org, Adrian Hunter Cc: yangbo.lu@nxp.com, xiaobo.xie@nxp.com Subject: [PATCH v1] mmc: sdhci-of-esdhc: add erratum A008171 support Date: Mon, 9 Jul 2018 15:39:33 +0800 Message-Id: <20180709073933.38841-1-yinbo.zhu@nxp.com> X-Mailer: git-send-email 2.14.1 X-Virus-Scanned: ClamAV using ClamSMTP 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 In tuning mode of operation, when TBCTL[TB_EN] is set, eSDHC may report one of the following errors : 1)Tuning error while running tuning operation where SYSCTL2[SAMPCLKSEL] will not get set even when SYSCTL2[EXTN] is reset. OR 2)Data transaction error (e.g. IRQSTAT[DCE], IRQSTAT[DEBE]) during data transaction errors. This issue occurs when the data window sampled within eSDHC is in full cycle. So, in that case, eSDHC is not able to find out the start and end points of the data window and sets the sampling pointer at default location (which is middle of the internal SD clock). If this sampling point coincides with the data eye boundary, then it can result in the above mentioned errors. Impact: Tuning mode of operation for SDR50, SDR104 or HS200 speed modes may not work properly Workaround: In case eSDHC reports tuning error or data errors in tuning mode of operation, by add the erratum A008171 support to fix the issue. Signed-off-by: Yinbo Zhu --- drivers/mmc/host/sdhci-esdhc.h | 1 + drivers/mmc/host/sdhci-of-esdhc.c | 40 ++++++++++++++++++++++++++++++++++++- drivers/mmc/host/sdhci.c | 1 + drivers/mmc/host/sdhci.h | 1 + 4 files changed, 42 insertions(+), 1 deletions(-) diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index dfa58f8..3f16d9c 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h @@ -60,6 +60,7 @@ /* Tuning Block Control Register */ #define ESDHC_TBCTL 0x120 #define ESDHC_TB_EN 0x00000004 +#define ESDHC_TBPTR 0x128 /* Control Register for DMA transfer */ #define ESDHC_DMA_SYSCTL 0x40c diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 1f42437..6510b9a 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -26,6 +26,8 @@ #include "sdhci-pltfm.h" #include "sdhci-esdhc.h" +#define DRIVER_NAME "sdhci-esdhc" + #define VENDOR_V_22 0x12 #define VENDOR_V_23 0x13 @@ -34,6 +36,7 @@ struct sdhci_esdhc { u8 spec_ver; bool quirk_incorrect_hostver; unsigned int peripheral_clock; + u32 div_ratio; }; /** @@ -541,6 +544,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n", clock, host->max_clk / pre_div / div); host->mmc->actual_clock = host->max_clk / pre_div / div; + esdhc->div_ratio = pre_div * div; pre_div >>= 1; div--; @@ -665,9 +669,24 @@ static int esdhc_signal_voltage_switch(struct mmc_host *mmc, } } +static struct soc_device_attribute soc_fixup_tuning[] = { + { .family = "QorIQ T1040", .revision = "1.0", }, + { .family = "QorIQ T2080", .revision = "1.0", }, + { .family = "QorIQ T1023", .revision = "1.0", }, + { .family = "QorIQ LS1021A", .revision = "1.0", }, + { .family = "QorIQ LS1080A", .revision = "1.0", }, + { .family = "QorIQ LS2080A", .revision = "1.0", }, + { .family = "QorIQ LS1012A", .revision = "1.0", }, + { .family = "QorIQ LS1043A", .revision = "1.*", }, + { .family = "QorIQ LS1046A", .revision = "1.0", }, + { }, +}; + static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); u32 val; /* Use tuning block for tuning procedure */ @@ -681,7 +700,26 @@ static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) sdhci_writel(host, val, ESDHC_TBCTL); esdhc_clock_enable(host, true); - return sdhci_execute_tuning(mmc, opcode); + sdhci_execute_tuning(mmc, opcode); + if (host->tuning_flag && soc_device_match(soc_fixup_tuning)) { + + /* program TBPTR[TB_WNDW_END_PTR] = 3*DIV_RATIO and + * program TBPTR[TB_WNDW_START_PTR] = 5*DIV_RATIO + */ + val = sdhci_readl(host, ESDHC_TBPTR); + val = (val & ~((0x7f << 8) | 0x7f)) | + (3 * esdhc->div_ratio) | ((5 * esdhc->div_ratio) << 8); + sdhci_writel(host, val, ESDHC_TBPTR); + + /* program the software tuning mode by setting + * TBCTL[TB_MODE]=2'h3 + */ + val = sdhci_readl(host, ESDHC_TBCTL); + val |= 0x3; + sdhci_writel(host, val, ESDHC_TBCTL); + sdhci_execute_tuning(mmc, opcode); + } + return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 2f14334..7bb0204 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2117,6 +2117,7 @@ static void __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) { if (ctrl & SDHCI_CTRL_TUNED_CLK) return; /* Success! */ + host->tuning_flag = 1; break; } diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 54bc444..22cc3ef 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -537,6 +537,7 @@ struct sdhci_host { unsigned int tuning_count; /* Timer count for re-tuning */ unsigned int tuning_mode; /* Re-tuning mode supported by host */ + unsigned int tuning_flag; /* Re-tuning flag */ #define SDHCI_TUNING_MODE_1 0 #define SDHCI_TUNING_MODE_2 1 #define SDHCI_TUNING_MODE_3 2