From patchwork Tue Oct 8 09:56:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ludovic BARRE X-Patchwork-Id: 11179263 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B8BF71709 for ; Tue, 8 Oct 2019 09:56:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8FD212070B for ; Tue, 8 Oct 2019 09:56:51 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=st.com header.i=@st.com header.b="bVnGzIF/" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730415AbfJHJ4a (ORCPT ); Tue, 8 Oct 2019 05:56:30 -0400 Received: from mx08-00178001.pphosted.com ([91.207.212.93]:32948 "EHLO mx07-00178001.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730409AbfJHJ4a (ORCPT ); Tue, 8 Oct 2019 05:56:30 -0400 Received: from pps.filterd (m0046661.ppops.net [127.0.0.1]) by mx08-00178001.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id x989pXUL018224; Tue, 8 Oct 2019 11:56:20 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=st.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=STMicroelectronics; bh=CAE+x4ROHtH2W/0IjwRDmEfAmHj2rmaoB6ZpgHgK3XI=; b=bVnGzIF/uQfIYTK+en4KOARWeqsejRM9mD8B5+Du7GU3cW1MxLIdf22c+OOE5BB8ygxw JJtvwi13zSOCwb/4/wy+NlFYbAY+KFSeJ0kRymv3cg7eyOaQiJho/x1vlnRs49phuPi5 twIacmsq6VlLHhRHnTWC31TYe9nwMiaJobqxmoXUY2SoQHlbTTkV6/9eZC34uQ9dp12G k+mAN2jtnBfqug/kb7J55zkwYfIjcnfvoendZIUiQSVeOrCkxI8hLF05amkJx2XnRop8 H702YjTxo0on2bwqSrkHZu8L15sXqEkqmIIyDn+GQnlj/F4R6lrX4C+kE/F336/blBX+ Aw== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx08-00178001.pphosted.com with ESMTP id 2vej2p7k5h-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 08 Oct 2019 11:56:20 +0200 Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 25A15100039; Tue, 8 Oct 2019 11:56:20 +0200 (CEST) Received: from Webmail-eu.st.com (Safex1hubcas21.st.com [10.75.90.44]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id 169FB2B40AD; Tue, 8 Oct 2019 11:56:20 +0200 (CEST) Received: from SAFEX1HUBCAS23.st.com (10.75.90.46) by SAFEX1HUBCAS21.st.com (10.75.90.44) with Microsoft SMTP Server (TLS) id 14.3.439.0; Tue, 8 Oct 2019 11:56:20 +0200 Received: from lmecxl0923.lme.st.com (10.48.0.237) by webmail-ga.st.com (10.75.90.48) with Microsoft SMTP Server (TLS) id 14.3.439.0; Tue, 8 Oct 2019 11:56:19 +0200 From: Ludovic Barre To: Ulf Hansson , Rob Herring CC: , Maxime Coquelin , Alexandre Torgue , , , , , , Ludovic Barre Subject: [PATCH V7 1/3] mmc: mmci: add hardware busy timeout feature Date: Tue, 8 Oct 2019 11:56:02 +0200 Message-ID: <20191008095604.20675-2-ludovic.Barre@st.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191008095604.20675-1-ludovic.Barre@st.com> References: <20191008095604.20675-1-ludovic.Barre@st.com> MIME-Version: 1.0 X-Originating-IP: [10.48.0.237] X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.95,1.0.8 definitions=2019-10-08_03:2019-10-07,2019-10-08 signatures=0 Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org From: Ludovic Barre In the stm32_sdmmc variant, the datatimer is active not only during data transfers with the DPSM, but also while waiting for the busyend IRQs from commands having the MMC_RSP_BUSY flag set. This leads to an incorrect IRQ being raised to signal MCI_DATATIMEOUT error, which simply breaks the behaviour. Address this by updating the datatimer value before sending a command having the MMC_RSP_BUSY flag set. To inform the mmc core about the maximum supported busy timeout, which also depends on the current clock rate, set ->max_busy_timeout (in ms). Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 42 ++++++++++++++++++++++++++++++++++++----- drivers/mmc/host/mmci.h | 3 +++ 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index e14003e52058..ed0b40287dea 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1075,6 +1075,7 @@ static void mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) { void __iomem *base = host->base; + unsigned long long clks; dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n", cmd->opcode, cmd->arg, cmd->flags); @@ -1097,6 +1098,16 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) else c |= host->variant->cmdreg_srsp; } + + if (host->variant->busy_timeout && cmd->flags & MMC_RSP_BUSY) { + if (!cmd->busy_timeout) + cmd->busy_timeout = 10 * MSEC_PER_SEC; + + clks = (unsigned long long)cmd->busy_timeout * host->cclk; + do_div(clks, MSEC_PER_SEC); + writel_relaxed(clks, host->base + MMCIDATATIMER); + } + if (/*interrupt*/0) c |= MCI_CPSM_INTERRUPT; @@ -1201,6 +1212,7 @@ static void mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, unsigned int status) { + u32 err_msk = MCI_CMDCRCFAIL | MCI_CMDTIMEOUT; void __iomem *base = host->base; bool sbc, busy_resp; @@ -1215,8 +1227,11 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, * handling. Note that we tag on any latent IRQs postponed * due to waiting for busy status. */ - if (!((status|host->busy_status) & - (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND))) + if (host->variant->busy_timeout && busy_resp) + err_msk |= MCI_DATATIMEOUT; + + if (!((status | host->busy_status) & + (err_msk | MCI_CMDSENT | MCI_CMDRESPEND))) return; /* Handle busy detection on DAT0 if the variant supports it. */ @@ -1235,8 +1250,7 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, * while, to allow it to be set, but tests indicates that it * isn't needed. */ - if (!host->busy_status && - !(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) && + if (!host->busy_status && !(status & err_msk) && (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) { writel(readl(base + MMCIMASK0) | @@ -1290,6 +1304,9 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, cmd->error = -ETIMEDOUT; } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { cmd->error = -EILSEQ; + } else if (host->variant->busy_timeout && busy_resp && + status & MCI_DATATIMEOUT) { + cmd->error = -ETIMEDOUT; } else { cmd->resp[0] = readl(base + MMCIRESPONSE0); cmd->resp[1] = readl(base + MMCIRESPONSE1); @@ -1583,6 +1600,20 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) spin_unlock_irqrestore(&host->lock, flags); } +static void mmci_set_max_busy_timeout(struct mmc_host *mmc) +{ + struct mmci_host *host = mmc_priv(mmc); + u32 max_busy_timeout = 0; + + if (!host->variant->busy_detect) + return; + + if (host->variant->busy_timeout && mmc->actual_clock) + max_busy_timeout = ~0UL / (mmc->actual_clock / MSEC_PER_SEC); + + mmc->max_busy_timeout = max_busy_timeout; +} + static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct mmci_host *host = mmc_priv(mmc); @@ -1687,6 +1718,8 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) else mmci_set_clkreg(host, ios->clock); + mmci_set_max_busy_timeout(mmc); + if (host->ops && host->ops->set_pwrreg) host->ops->set_pwrreg(host, pwr); else @@ -1957,7 +1990,6 @@ static int mmci_probe(struct amba_device *dev, mmci_write_datactrlreg(host, host->variant->busy_dpsm_flag); mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; - mmc->max_busy_timeout = 0; } /* Prepare a CMD12 - needed to clear the DPSM on some variants. */ diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 833236ecb31e..d8b7f6774e8f 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -287,6 +287,8 @@ struct mmci_host; * @signal_direction: input/out direction of bus signals can be indicated * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock * @busy_detect: true if the variant supports busy detection on DAT0. + * @busy_timeout: true if the variant starts data timer when the DPSM + * enter in Wait_R or Busy state. * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register * indicating that the card is busy @@ -333,6 +335,7 @@ struct variant_data { u8 signal_direction:1; u8 pwrreg_clkgate:1; u8 busy_detect:1; + u8 busy_timeout:1; u32 busy_dpsm_flag; u32 busy_detect_flag; u32 busy_detect_mask; From patchwork Tue Oct 8 09:56:03 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ludovic BARRE X-Patchwork-Id: 11179259 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 76FCC1747 for ; Tue, 8 Oct 2019 09:56:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 4F972206C2 for ; Tue, 8 Oct 2019 09:56:43 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=st.com header.i=@st.com header.b="pEFTw1bp" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730495AbfJHJ4g (ORCPT ); Tue, 8 Oct 2019 05:56:36 -0400 Received: from mx07-00178001.pphosted.com ([62.209.51.94]:58105 "EHLO mx07-00178001.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730460AbfJHJ4f (ORCPT ); Tue, 8 Oct 2019 05:56:35 -0400 Received: from pps.filterd (m0046037.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id x989pbJd007847; Tue, 8 Oct 2019 11:56:21 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=st.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=STMicroelectronics; bh=+WKocQi+fVCxqzWsFLYGJL7udht10qEyhti+mMSoK38=; b=pEFTw1bpl0PaZnmFW25tB5LfSMtmfv2CAtArRTPHp6h3iRkMiJwoTYo1JoRlcqTjkcmY O0tkKTnXVKqmXSO8WViX7Dr8K67qIkTnyrALRVct1vi1m3q0SwGkKzLYXpSJhTlIcfhj rrR2uC5r2u4uhl290I048GdaFbdlFuIN//iwzRhJJqNkeKjSc86crVkp3IjUIpN+rFhr 4iamTgdEPJNjy4x5NzzxiXiyIuNvEFnBf4+WI0ntMAXPV5JqmQVTRjIPQzTs3QicrUVI zsghJQ9ZjTrT7HasAl97eDx/conjixw9qlYTb43LOW/be4ahHE/ZDHiMU/L/+NCs4Otm OQ== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com with ESMTP id 2vegxvqdq3-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 08 Oct 2019 11:56:21 +0200 Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 273CA100038; Tue, 8 Oct 2019 11:56:21 +0200 (CEST) Received: from Webmail-eu.st.com (Safex1hubcas24.st.com [10.75.90.94]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id 1AC742B40AD; Tue, 8 Oct 2019 11:56:21 +0200 (CEST) Received: from SAFEX1HUBCAS23.st.com (10.75.90.46) by Safex1hubcas24.st.com (10.75.90.94) with Microsoft SMTP Server (TLS) id 14.3.439.0; Tue, 8 Oct 2019 11:56:21 +0200 Received: from lmecxl0923.lme.st.com (10.48.0.237) by webmail-ga.st.com (10.75.90.48) with Microsoft SMTP Server (TLS) id 14.3.439.0; Tue, 8 Oct 2019 11:56:20 +0200 From: Ludovic Barre To: Ulf Hansson , Rob Herring CC: , Maxime Coquelin , Alexandre Torgue , , , , , , Ludovic Barre Subject: [PATCH V7 2/3] mmc: mmci: add busy_complete callback Date: Tue, 8 Oct 2019 11:56:03 +0200 Message-ID: <20191008095604.20675-3-ludovic.Barre@st.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191008095604.20675-1-ludovic.Barre@st.com> References: <20191008095604.20675-1-ludovic.Barre@st.com> MIME-Version: 1.0 X-Originating-IP: [10.48.0.237] X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.95,1.0.8 definitions=2019-10-08_03:2019-10-07,2019-10-08 signatures=0 Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org From: Ludovic Barre This patch adds busy_completion callback at mmci_host_ops to allow to define a specific busy completion by variant. The legacy code corresponding to busy completion used by ux500 variants is moved to ux500_busy_complete function. Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 134 +++++++++++++++++++++------------------- drivers/mmc/host/mmci.h | 1 + 2 files changed, 73 insertions(+), 62 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index ed0b40287dea..5e53f9b6d82a 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -44,6 +44,7 @@ #define DRIVER_NAME "mmci-pl18x" static void mmci_variant_init(struct mmci_host *host); +static void ux500_variant_init(struct mmci_host *host); static void ux500v2_variant_init(struct mmci_host *host); static unsigned int fmax = 515633; @@ -184,7 +185,7 @@ static struct variant_data variant_ux500 = { .irq_pio_mask = MCI_IRQ_PIO_MASK, .start_err = MCI_STARTBITERR, .opendrain = MCI_OD, - .init = mmci_variant_init, + .init = ux500_variant_init, }; static struct variant_data variant_ux500v2 = { @@ -610,6 +611,67 @@ static u32 ux500v2_get_dctrl_cfg(struct mmci_host *host) return MCI_DPSM_ENABLE | (host->data->blksz << 16); } +static bool ux500_busy_complete(struct mmci_host *host, u32 status, u32 err_msk) +{ + void __iomem *base = host->base; + + /* + * Before unmasking for the busy end IRQ, confirm that the + * command was sent successfully. To keep track of having a + * command in-progress, waiting for busy signaling to end, + * store the status in host->busy_status. + * + * Note that, the card may need a couple of clock cycles before + * it starts signaling busy on DAT0, hence re-read the + * MMCISTATUS register here, to allow the busy bit to be set. + * Potentially we may even need to poll the register for a + * while, to allow it to be set, but tests indicates that it + * isn't needed. + */ + if (!host->busy_status && !(status & err_msk) && + (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) { + writel(readl(base + MMCIMASK0) | + host->variant->busy_detect_mask, + base + MMCIMASK0); + + host->busy_status = status & (MCI_CMDSENT | MCI_CMDRESPEND); + return false; + } + + /* + * If there is a command in-progress that has been successfully + * sent, then bail out if busy status is set and wait for the + * busy end IRQ. + * + * Note that, the HW triggers an IRQ on both edges while + * monitoring DAT0 for busy completion, but there is only one + * status bit in MMCISTATUS for the busy state. Therefore + * both the start and the end interrupts needs to be cleared, + * one after the other. So, clear the busy start IRQ here. + */ + if (host->busy_status && + (status & host->variant->busy_detect_flag)) { + writel(host->variant->busy_detect_mask, base + MMCICLEAR); + return false; + } + + /* + * If there is a command in-progress that has been successfully + * sent and the busy bit isn't set, it means we have received + * the busy end IRQ. Clear and mask the IRQ, then continue to + * process the command. + */ + if (host->busy_status) { + writel(host->variant->busy_detect_mask, base + MMCICLEAR); + + writel(readl(base + MMCIMASK0) & + ~host->variant->busy_detect_mask, base + MMCIMASK0); + host->busy_status = 0; + } + + return true; +} + /* * All the DMA operation mode stuff goes inside this ifdef. * This assumes that you have a generic DMA device interface, @@ -953,9 +1015,16 @@ static void mmci_variant_init(struct mmci_host *host) host->ops = &mmci_variant_ops; } +static void ux500_variant_init(struct mmci_host *host) +{ + host->ops = &mmci_variant_ops; + host->ops->busy_complete = ux500_busy_complete; +} + static void ux500v2_variant_init(struct mmci_host *host) { host->ops = &mmci_variant_ops; + host->ops->busy_complete = ux500_busy_complete; host->ops->get_datactrl_cfg = ux500v2_get_dctrl_cfg; } @@ -1235,68 +1304,9 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, return; /* Handle busy detection on DAT0 if the variant supports it. */ - if (busy_resp && host->variant->busy_detect) { - - /* - * Before unmasking for the busy end IRQ, confirm that the - * command was sent successfully. To keep track of having a - * command in-progress, waiting for busy signaling to end, - * store the status in host->busy_status. - * - * Note that, the card may need a couple of clock cycles before - * it starts signaling busy on DAT0, hence re-read the - * MMCISTATUS register here, to allow the busy bit to be set. - * Potentially we may even need to poll the register for a - * while, to allow it to be set, but tests indicates that it - * isn't needed. - */ - if (!host->busy_status && !(status & err_msk) && - (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) { - - writel(readl(base + MMCIMASK0) | - host->variant->busy_detect_mask, - base + MMCIMASK0); - - host->busy_status = - status & (MCI_CMDSENT|MCI_CMDRESPEND); - return; - } - - /* - * If there is a command in-progress that has been successfully - * sent, then bail out if busy status is set and wait for the - * busy end IRQ. - * - * Note that, the HW triggers an IRQ on both edges while - * monitoring DAT0 for busy completion, but there is only one - * status bit in MMCISTATUS for the busy state. Therefore - * both the start and the end interrupts needs to be cleared, - * one after the other. So, clear the busy start IRQ here. - */ - if (host->busy_status && - (status & host->variant->busy_detect_flag)) { - writel(host->variant->busy_detect_mask, - host->base + MMCICLEAR); + if (busy_resp && host->variant->busy_detect) + if (!host->ops->busy_complete(host, status, err_msk)) return; - } - - /* - * If there is a command in-progress that has been successfully - * sent and the busy bit isn't set, it means we have received - * the busy end IRQ. Clear and mask the IRQ, then continue to - * process the command. - */ - if (host->busy_status) { - - writel(host->variant->busy_detect_mask, - host->base + MMCICLEAR); - - writel(readl(base + MMCIMASK0) & - ~host->variant->busy_detect_mask, - base + MMCIMASK0); - host->busy_status = 0; - } - } host->cmd = NULL; diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index d8b7f6774e8f..2a0b98f98c36 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -369,6 +369,7 @@ struct mmci_host_ops { void (*dma_error)(struct mmci_host *host); void (*set_clkreg)(struct mmci_host *host, unsigned int desired); void (*set_pwrreg)(struct mmci_host *host, unsigned int pwr); + bool (*busy_complete)(struct mmci_host *host, u32 status, u32 err_msk); }; struct mmci_host { From patchwork Tue Oct 8 09:56:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ludovic BARRE X-Patchwork-Id: 11179261 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4D3291747 for ; Tue, 8 Oct 2019 09:56:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2E002206C2 for ; Tue, 8 Oct 2019 09:56:44 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=st.com header.i=@st.com header.b="wWOV9dln" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730480AbfJHJ4f (ORCPT ); Tue, 8 Oct 2019 05:56:35 -0400 Received: from mx07-00178001.pphosted.com ([62.209.51.94]:20524 "EHLO mx07-00178001.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730471AbfJHJ4e (ORCPT ); Tue, 8 Oct 2019 05:56:34 -0400 Received: from pps.filterd (m0046668.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id x989oqB2017657; Tue, 8 Oct 2019 11:56:23 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=st.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=STMicroelectronics; bh=D1YTtXGlnn9n+wzMgmKua3M6JR/Hf72FY8yVMBQwtWI=; b=wWOV9dlnI7b6wCn4MtpVrTkngtTOGrtkV+7uI304jlygQIo0HZnhy2bmoAAC+rDCaAOi RnoFi1Z75OPIfdl+J8qwKHXWSMnZHf8SqCECwbDvUITf/bKCNqd+FbnegDoUij9cu4B6 mf6CJGoLaAA+NqUenNV4QQ/ej5Rd7kkFKW28/ii4HX8tXKcGeBVOiAe1A3UPxT8TjUip VwqaGi56ABUH2z47yR/yB+efUHuIo4B/x5iHd5tH9ImE0rBKhbu3pDIywgE/KquKomIk 1EYE4wuVA1MK4iOKRGcFxngbXaM6sGAdE8K7L9+SKbm2Ewf5EDLYNtZKM6pjqy7n/IBh Ag== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com with ESMTP id 2vegn0qfsd-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 08 Oct 2019 11:56:23 +0200 Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 992D310002A; Tue, 8 Oct 2019 11:56:22 +0200 (CEST) Received: from Webmail-eu.st.com (Safex1hubcas22.st.com [10.75.90.92]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id 8E79A2B40AF; Tue, 8 Oct 2019 11:56:22 +0200 (CEST) Received: from SAFEX1HUBCAS23.st.com (10.75.90.46) by Safex1hubcas22.st.com (10.75.90.92) with Microsoft SMTP Server (TLS) id 14.3.439.0; Tue, 8 Oct 2019 11:56:22 +0200 Received: from lmecxl0923.lme.st.com (10.48.0.237) by webmail-ga.st.com (10.75.90.48) with Microsoft SMTP Server (TLS) id 14.3.439.0; Tue, 8 Oct 2019 11:56:21 +0200 From: Ludovic Barre To: Ulf Hansson , Rob Herring CC: , Maxime Coquelin , Alexandre Torgue , , , , , , Ludovic Barre Subject: [PATCH V7 3/3] mmc: mmci: sdmmc: add busy_complete callback Date: Tue, 8 Oct 2019 11:56:04 +0200 Message-ID: <20191008095604.20675-4-ludovic.Barre@st.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191008095604.20675-1-ludovic.Barre@st.com> References: <20191008095604.20675-1-ludovic.Barre@st.com> MIME-Version: 1.0 X-Originating-IP: [10.48.0.237] X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.95,1.0.8 definitions=2019-10-08_03:2019-10-07,2019-10-08 signatures=0 Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org From: Ludovic Barre This patch adds a specific busy_complete callback for sdmmc variant. sdmmc has 2 status flags: -busyd0: This is a hardware status flag (inverted value of d0 line). it does not generate an interrupt. -busyd0end: This indicates only end of busy following a CMD response. On busy to Not busy changes, an interrupt is generated (if unmask) and BUSYD0END status flag is set. Status flag is cleared by writing corresponding interrupt clear bit in MMCICLEAR. The legacy busy completion has no dedicated interrupt for the end of busy, so it's must monitor step by step the busy progression. On sdmmc variant, this procedure is not needed, it's just need to wait the busyd0end interrupt. Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 4 +++ drivers/mmc/host/mmci.h | 1 + drivers/mmc/host/mmci_stm32_sdmmc.c | 42 +++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 5e53f9b6d82a..40e72c30ea84 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -262,6 +262,10 @@ static struct variant_data variant_stm32_sdmmc = { .datalength_bits = 25, .datactrl_blocksz = 14, .stm32_idmabsize_mask = GENMASK(12, 5), + .busy_timeout = true, + .busy_detect = true, + .busy_detect_flag = MCI_STM32_BUSYD0, + .busy_detect_mask = MCI_STM32_BUSYD0ENDMASK, .init = sdmmc_variant_init, }; diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 2a0b98f98c36..158e1231aa23 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -164,6 +164,7 @@ #define MCI_ST_CARDBUSY (1 << 24) /* Extended status bits for the STM32 variants */ #define MCI_STM32_BUSYD0 BIT(20) +#define MCI_STM32_BUSYD0END BIT(21) #define MMCICLEAR 0x038 #define MCI_CMDCRCFAILCLR (1 << 0) diff --git a/drivers/mmc/host/mmci_stm32_sdmmc.c b/drivers/mmc/host/mmci_stm32_sdmmc.c index 8e83ae6920ae..1de855d29ad4 100644 --- a/drivers/mmc/host/mmci_stm32_sdmmc.c +++ b/drivers/mmc/host/mmci_stm32_sdmmc.c @@ -282,6 +282,47 @@ static u32 sdmmc_get_dctrl_cfg(struct mmci_host *host) return datactrl; } +static bool sdmmc_busy_complete(struct mmci_host *host, u32 status, u32 err_msk) +{ + void __iomem *base = host->base; + u32 busy_d0, busy_d0end, mask, sdmmc_status; + + mask = readl_relaxed(base + MMCIMASK0); + sdmmc_status = readl_relaxed(base + MMCISTATUS); + busy_d0end = sdmmc_status & MCI_STM32_BUSYD0END; + busy_d0 = sdmmc_status & MCI_STM32_BUSYD0; + + /* complete if there is an error or busy_d0end */ + if ((status & err_msk) || busy_d0end) + goto complete; + + /* + * On response the busy signaling is reflected in the BUSYD0 flag. + * if busy_d0 is in-progress we must activate busyd0end interrupt + * to wait this completion. Else this request has no busy step. + */ + if (busy_d0) { + if (!host->busy_status) { + writel_relaxed(mask | host->variant->busy_detect_mask, + base + MMCIMASK0); + host->busy_status = status & + (MCI_CMDSENT | MCI_CMDRESPEND); + } + return false; + } + +complete: + if (host->busy_status) { + writel_relaxed(mask & ~host->variant->busy_detect_mask, + base + MMCIMASK0); + writel_relaxed(host->variant->busy_detect_mask, + base + MMCICLEAR); + host->busy_status = 0; + } + + return true; +} + static struct mmci_host_ops sdmmc_variant_ops = { .validate_data = sdmmc_idma_validate_data, .prep_data = sdmmc_idma_prep_data, @@ -292,6 +333,7 @@ static struct mmci_host_ops sdmmc_variant_ops = { .dma_finalize = sdmmc_idma_finalize, .set_clkreg = mmci_sdmmc_set_clkreg, .set_pwrreg = mmci_sdmmc_set_pwrreg, + .busy_complete = sdmmc_busy_complete, }; void sdmmc_variant_init(struct mmci_host *host)