From patchwork Thu Dec 15 13:50:14 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?J=C3=B6rg_Krause?= X-Patchwork-Id: 9476147 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 26A1D60825 for ; Thu, 15 Dec 2016 13:53:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 022B62876D for ; Thu, 15 Dec 2016 13:53:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EA3CE2877C; Thu, 15 Dec 2016 13:53:22 +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=-4.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 00C3F2876D for ; Thu, 15 Dec 2016 13:53:21 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1cHWR0-0004Mt-So; Thu, 15 Dec 2016 13:50:58 +0000 Received: from mout02.posteo.de ([185.67.36.142]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1cHWQr-0003uC-Gb for linux-arm-kernel@lists.infradead.org; Thu, 15 Dec 2016 13:50:51 +0000 Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 3tfZZd30Zpz106P; Thu, 15 Dec 2016 14:50:16 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embedded.rocks; h=mime-version:x-mailer:content-type:content-type:organization :references:in-reply-to:date:date:from:from:subject:subject :message-id:received:received; s=default; t=1481809815; x= 1482414616; bh=/bmbOhf+ExEuTyzbdNlcTaf5TEVxxVIUkUnwdP4UtII=; b=K +rDyAjlTlZsLQQu/H/8s97wrfb+u8ZarALPGx4Ou3o1q7SQrpcgLzYE4eLcfvfFq +t1bMYp92CxvWB/clx1gUQGenu7slMzRqs9t2YgYSYe8QFd0pzmJLwOroUC4uNaP S3afoFvquJLP0XZfZMR5qNQd2WQma/r/Gi9Lq4Mazzd1g4lDRGoMzGgNyk+Bm9D3 Ux1srjtiDjISaBpkxytCIVmpZUr7vBeF83jrhvk0qlUXSsPg4WrRaX33istV8jgR nY0/H9OsdGgrsX+s4NQlg2LjCngz05bhKqT9udRlEGoNjiSon3Sl8ZRLAOmqxayt nhU6t9uqDUzQbDCbCgXSg== Received: from mail.embedded.rocks ([127.0.0.1]) by localhost (mail.embedded.rocks [127.0.0.1]) (amavisd-new, port 10025) with ESMTP id vRZi2yXG2BN2; Thu, 15 Dec 2016 14:50:15 +0100 (CET) Received: from nzxt.fritz.box (xd9ba22a6.dyn.telefonica.de [217.186.34.166]) (Authenticated sender: joerg.krause@embedded.rocks) by mail.embedded.rocks (Postfix) with ESMTPSA; Thu, 15 Dec 2016 14:50:15 +0100 (CET) Message-ID: <1481809814.29241.2.camel@embedded.rocks> Subject: Re: mmc: core: complete/wait_for_completion performance From: =?ISO-8859-1?Q?J=F6rg?= Krause To: Stefan Wahren Date: Thu, 15 Dec 2016 14:50:14 +0100 In-Reply-To: <962480933.163666.1481741832090@email.1und1.de> References: <1479644869.2653.3.camel@embedded.rocks> <585759233.283839.1cb53b4d-2805-48ea-aef1-dd282306d108.open-xchange@email.1und1.de> <1479652929.2841.1.camel@embedded.rocks> <187975187.249177.bccdc17e-e9c6-48c2-aeaf-3b81f1b61ec7.open-xchange@email.1und1.de> <1479669034.1975.1.camel@embedded.rocks> <1198138554.59982.63209ba1-8fb4-4a13-9ee0-f746a192f4c7.open-xchange@email.1und1.de> <1481095953.17027.0.camel@embedded.rocks> <123257138.400786.e58aee3b-9fc2-4b39-a030-c2409c5b92fc.open-xchange@email.1und1.de> <1481706204.3994.4.camel@embedded.rocks> <962480933.163666.1481741832090@email.1und1.de> Organization: Embedded Rocks X-Mailer: Evolution 3.22.2 Mime-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20161215_055049_928198_6A2273C3 X-CRM114-Status: GOOD ( 27.23 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Russell King , Ulf Hansson , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Hi Stefan, On Wed, 2016-12-14 at 19:57 +0100, Stefan Wahren wrote: > Hi Jörg, > [snip] > > > > > > did you try cyclictest [1]? > > > > Not yet. Not sure what to measure and which values to compare here. > > i tought you have the vendor kernel and the mainline kernel available > for your platform. > > So you could compare the both kernels. Yes, that's right. I will have a look at this tool. > > > > > > > > Beside the time for a request the amount of requests for the > > > complete > > > iperf test > > > would we interesting. Maybe there are retries. > > > > > > I'm still interested in your PIO mode patches for mxs-mmc even > > > without clean up. > > > > Actually, the patch does not implement a PIO mode, but drops DMA > > and > > uses polling instead. I've attached the patch. > > Thanks. I applied it, but unfortunately this breaks SD card support > for my Duckbill and the kernel isn't able to mount the rootfs: > > [    2.267073] mxs-mmc 80010000.ssp: initialized > [    2.272624] mxs-mmc 80010000.ssp: AC command error 0xffffff92 Sorry, I messed up the branches. I attached the correct patch which is working for me on Linux v4.9. Jörg From c321c217836fb08e31b026035a71b8ddad513a52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Krause?= Date: Tue, 1 Nov 2016 18:02:46 +0100 Subject: [PATCH] mmc: mxs-mmc: use PIO mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jörg Krause --- drivers/mmc/host/mxs-mmc.c | 365 ++++++++++++++++++++++++++++++++++---------- include/linux/spi/mxs-spi.h | 12 ++ 2 files changed, 300 insertions(+), 77 deletions(-) diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index d839147..958c073 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -47,14 +47,22 @@ #define DRIVER_NAME "mxs-mmc" -#define MXS_MMC_IRQ_BITS (BM_SSP_CTRL1_SDIO_IRQ | \ - BM_SSP_CTRL1_RESP_ERR_IRQ | \ - BM_SSP_CTRL1_RESP_TIMEOUT_IRQ | \ - BM_SSP_CTRL1_DATA_TIMEOUT_IRQ | \ - BM_SSP_CTRL1_DATA_CRC_IRQ | \ - BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ | \ - BM_SSP_CTRL1_RECV_TIMEOUT_IRQ | \ - BM_SSP_CTRL1_FIFO_OVERRUN_IRQ) +#define MXS_MMC_ERR_IRQ_BITS (BM_SSP_CTRL1_RESP_ERR_IRQ | \ + BM_SSP_CTRL1_RESP_TIMEOUT_IRQ | \ + BM_SSP_CTRL1_DATA_TIMEOUT_IRQ | \ + BM_SSP_CTRL1_DATA_CRC_IRQ | \ + BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ | \ + BM_SSP_CTRL1_RECV_TIMEOUT_IRQ | \ + BM_SSP_CTRL1_FIFO_OVERRUN_IRQ) + +#define MXS_MMC_IRQ_BITS (BM_SSP_CTRL1_SDIO_IRQ | \ + MXS_MMC_ERR_IRQ_BITS) + +#define MXS_MMC_ERR_BITS (BM_SSP_CTRL1_RESP_ERR_IRQ | \ + BM_SSP_CTRL1_RESP_TIMEOUT_IRQ | \ + BM_SSP_CTRL1_DATA_TIMEOUT_IRQ | \ + BM_SSP_CTRL1_DATA_CRC_IRQ | \ + BM_SSP_CTRL1_RECV_TIMEOUT_IRQ) /* card detect polling timeout */ #define MXS_MMC_DETECT_TIMEOUT (HZ/2) @@ -71,6 +79,10 @@ struct mxs_mmc_host { spinlock_t lock; int sdio_irq_en; bool broken_cd; + + u32 status; + int pio_size; + struct completion dma_done; }; static int mxs_mmc_get_cd(struct mmc_host *mmc) @@ -256,38 +268,81 @@ static struct dma_async_tx_descriptor *mxs_mmc_prep_dma( return desc; } +/* + * Check for MMC command errors + * Returns error code or zero if no errors + */ +static inline int mxs_mmc_cmd_error(u32 status) +{ + int err = 0; + + if (status & BM_SSP_STATUS_TIMEOUT) + err = -ETIMEDOUT; + else if (status & BM_SSP_STATUS_RESP_TIMEOUT) + err = -ETIMEDOUT; + else if (status & BM_SSP_STATUS_RESP_CRC_ERR) + err = -EILSEQ; + else if (status & BM_SSP_STATUS_RESP_ERR) + err = -EIO; + + return err; +} + static void mxs_mmc_bc(struct mxs_mmc_host *host) { struct mxs_ssp *ssp = &host->ssp; struct mmc_command *cmd = host->cmd; struct dma_async_tx_descriptor *desc; - u32 ctrl0, cmd0, cmd1; + u32 ctrl0, ctrl1, cmd0, cmd1, c1; ctrl0 = BM_SSP_CTRL0_ENABLE | BM_SSP_CTRL0_IGNORE_CRC; + ctrl1 = BM_SSP_CTRL1_DMA_ENABLE | + BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN | + BM_SSP_CTRL1_DATA_CRC_IRQ_EN | + BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN | + BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN | + BM_SSP_CTRL1_RESP_ERR_IRQ_EN; cmd0 = BF_SSP(cmd->opcode, CMD0_CMD) | BM_SSP_CMD0_APPEND_8CYC; - cmd1 = cmd->arg; + cmd1 = BF_SSP(cmd->arg, CMD1_CMD); if (host->sdio_irq_en) { ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN; } - ssp->ssp_pio_words[0] = ctrl0; - ssp->ssp_pio_words[1] = cmd0; - ssp->ssp_pio_words[2] = cmd1; - ssp->dma_dir = DMA_NONE; - ssp->slave_dirn = DMA_TRANS_NONE; - desc = mxs_mmc_prep_dma(host, DMA_CTRL_ACK); - if (!desc) - goto out; - - dmaengine_submit(desc); - dma_async_issue_pending(ssp->dmach); - return; - -out: - dev_warn(mmc_dev(host->mmc), - "%s: failed to prep dma\n", __func__); + /* following IO operations */ + writel(ctrl0, ssp->base + HW_SSP_CTRL0); + writel(cmd0, ssp->base + HW_SSP_CMD0); + writel(cmd1, ssp->base + HW_SSP_CMD1); + + /* clear these bits */ + writel(ctrl1, ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_CLR); + init_completion(&host->dma_done); + writel(BM_SSP_CTRL0_RUN, + ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); + + /* wait here as long as SSP is running and busy */ + while (readl(ssp->base + HW_SSP_CTRL0) & BM_SSP_CTRL0_RUN) + continue; + while (readl(ssp->base + HW_SSP_STATUS(ssp)) & BM_SSP_STATUS_BUSY) + continue; + + host->status = readl(ssp->base + HW_SSP_STATUS(ssp)); + c1 = readl(ssp->base + HW_SSP_CTRL1(ssp)); + + /* reset interrupt request status bits */ + writel(c1 & MXS_MMC_ERR_IRQ_BITS, + ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_CLR); + + /* reenable these bits */ + writel(ctrl1, ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_SET); + /* end IO operations */ + + cmd->error = mxs_mmc_cmd_error(host->status); + + if (cmd->error) { + dev_warn(mmc_dev(host->mmc), "BC command error %d\n", cmd->error); + } } static void mxs_mmc_ac(struct mxs_mmc_host *host) @@ -296,7 +351,7 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host) struct mmc_command *cmd = host->cmd; struct dma_async_tx_descriptor *desc; u32 ignore_crc, get_resp, long_resp; - u32 ctrl0, cmd0, cmd1; + u32 ctrl0, ctrl1, cmd0, cmd1, c1; ignore_crc = (mmc_resp_type(cmd) & MMC_RSP_CRC) ? 0 : BM_SSP_CTRL0_IGNORE_CRC; @@ -306,30 +361,76 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host) BM_SSP_CTRL0_LONG_RESP : 0; ctrl0 = BM_SSP_CTRL0_ENABLE | ignore_crc | get_resp | long_resp; + ctrl1 = BM_SSP_CTRL1_DMA_ENABLE | + BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN | + BM_SSP_CTRL1_DATA_CRC_IRQ_EN | + BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN | + BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN | + BM_SSP_CTRL1_RESP_ERR_IRQ_EN; cmd0 = BF_SSP(cmd->opcode, CMD0_CMD); - cmd1 = cmd->arg; + cmd1 = BF_SSP(cmd->arg, CMD1_CMD); if (host->sdio_irq_en) { ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN; } - ssp->ssp_pio_words[0] = ctrl0; - ssp->ssp_pio_words[1] = cmd0; - ssp->ssp_pio_words[2] = cmd1; - ssp->dma_dir = DMA_NONE; - ssp->slave_dirn = DMA_TRANS_NONE; - desc = mxs_mmc_prep_dma(host, DMA_CTRL_ACK); - if (!desc) - goto out; - - dmaengine_submit(desc); - dma_async_issue_pending(ssp->dmach); - return; - -out: - dev_warn(mmc_dev(host->mmc), - "%s: failed to prep dma\n", __func__); + /* following IO operations */ + writel(ctrl0, ssp->base + HW_SSP_CTRL0); + writel(cmd0, ssp->base + HW_SSP_CMD0); + writel(cmd1, ssp->base + HW_SSP_CMD1); + + /* clear these bits */ + writel(ctrl1, ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_CLR); + init_completion(&host->dma_done); + writel(BM_SSP_CTRL0_RUN, + ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); + + /* wait here as long as SSP is running and busy */ + while (readl(ssp->base + HW_SSP_CTRL0) & BM_SSP_CTRL0_RUN) + continue; + while (readl(ssp->base + HW_SSP_STATUS(ssp)) & BM_SSP_STATUS_BUSY) + continue; + + host->status = readl(ssp->base + HW_SSP_STATUS(ssp)); + c1 = readl(ssp->base + HW_SSP_CTRL1(ssp)); + + /* reset interrupt request status bits */ + writel(c1 & MXS_MMC_ERR_IRQ_BITS, + ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_CLR); + + /* reenable these bits */ + writel(ctrl1, ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_SET); + /* end IO operations */ + + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: + while (readl(ssp->base + HW_SSP_CTRL0) & BM_SSP_CTRL0_RUN) + continue; + break; + case MMC_RSP_R1: + case MMC_RSP_R1B: + case MMC_RSP_R3: + cmd->resp[0] = readl(ssp->base + HW_SSP_SDRESP0(ssp)); + break; + case MMC_RSP_R2: + cmd->resp[3] = readl(ssp->base + HW_SSP_SDRESP0(ssp)); + cmd->resp[2] = readl(ssp->base + HW_SSP_SDRESP1(ssp)); + cmd->resp[1] = readl(ssp->base + HW_SSP_SDRESP2(ssp)); + cmd->resp[0] = readl(ssp->base + HW_SSP_SDRESP3(ssp)); + break; + default: + dev_warn(mmc_dev(host->mmc), "Unsupported response type 0x%x\n", + mmc_resp_type(cmd)); + BUG(); + break; + } + + cmd->error = mxs_mmc_cmd_error(host->status); + + if (cmd->error) { + dev_warn(mmc_dev(host->mmc), "AC command error %d\n", cmd->error); + } } static unsigned short mxs_ns_to_ssp_ticks(unsigned clock_rate, unsigned ns) @@ -357,6 +458,15 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) unsigned int sg_len = data->sg_len; unsigned int i; + int is_reading = 0; + int index = 0; + int len; + struct scatterlist *_sg; + int size; + char *sgbuf; + u8 *p; + u32 _data, status; + unsigned short dma_data_dir, timeout; enum dma_transfer_direction slave_dirn; unsigned int data_size = 0, log2_blksz; @@ -365,7 +475,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) struct mxs_ssp *ssp = &host->ssp; u32 ignore_crc, get_resp, long_resp, read; - u32 ctrl0, cmd0, cmd1, val; + u32 ctrl0, ctrl1, cmd0, cmd1, val, c1; ignore_crc = (mmc_resp_type(cmd) & MMC_RSP_CRC) ? 0 : BM_SSP_CTRL0_IGNORE_CRC; @@ -378,10 +488,12 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) dma_data_dir = DMA_TO_DEVICE; slave_dirn = DMA_MEM_TO_DEV; read = 0; + is_reading = 0; } else { dma_data_dir = DMA_FROM_DEVICE; slave_dirn = DMA_DEV_TO_MEM; read = BM_SSP_CTRL0_READ; + is_reading = 1; } ctrl0 = BF_SSP(host->bus_width, CTRL0_BUS_WIDTH) | @@ -428,38 +540,129 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN; } - /* set the timeout count */ - timeout = mxs_ns_to_ssp_ticks(ssp->clk_rate, data->timeout_ns); - val = readl(ssp->base + HW_SSP_TIMING(ssp)); - val &= ~(BM_SSP_TIMING_TIMEOUT); - val |= BF_SSP(timeout, TIMING_TIMEOUT); - writel(val, ssp->base + HW_SSP_TIMING(ssp)); - - /* pio */ - ssp->ssp_pio_words[0] = ctrl0; - ssp->ssp_pio_words[1] = cmd0; - ssp->ssp_pio_words[2] = cmd1; - ssp->dma_dir = DMA_NONE; - ssp->slave_dirn = DMA_TRANS_NONE; - desc = mxs_mmc_prep_dma(host, 0); - if (!desc) - goto out; - - /* append data sg */ - WARN_ON(host->data != NULL); - host->data = data; - ssp->dma_dir = dma_data_dir; - ssp->slave_dirn = slave_dirn; - desc = mxs_mmc_prep_dma(host, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) - goto out; - - dmaengine_submit(desc); - dma_async_issue_pending(ssp->dmach); - return; -out: - dev_warn(mmc_dev(host->mmc), - "%s: failed to prep dma\n", __func__); + data_size = cmd->data->blksz * cmd->data->blocks; + u32 transfer_size = data_size; + + _sg = host->cmd->data->sg; + len = host->cmd->data->sg_len; + + ctrl1 = BM_SSP_CTRL1_DMA_ENABLE | + BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN | + BM_SSP_CTRL1_DATA_CRC_IRQ_EN | + BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN | + BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN | + BM_SSP_CTRL1_RESP_ERR_IRQ_EN; + + writel(ctrl0, ssp->base + HW_SSP_CTRL0); + writel(cmd0, ssp->base + HW_SSP_CMD0); + writel(cmd1, ssp->base + HW_SSP_CMD1); + /* clear these bits */ + writel(ctrl1, ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_CLR); + init_completion(&host->dma_done); + writel(BM_SSP_CTRL0_RUN, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); + + while (readl(ssp->base + HW_SSP_CTRL0) & BM_SSP_STATUS_CMD_BUSY) + continue; + + while (transfer_size) { + sgbuf = kmap_atomic(sg_page(&_sg[index])) + _sg[index].offset; + + p = (u8 *)sgbuf; + size = transfer_size < _sg[index].length ? transfer_size : _sg[index].length; + + if (is_reading) { + while (size) { + status = readl(ssp->base + HW_SSP_STATUS(ssp)); + if (status & BM_SSP_STATUS_FIFO_EMPTY) + continue; + _data = readl(ssp->base + HW_SSP_DATA(ssp)); + if ((u32)p & 0x3) { + *p++ = _data & 0xff; + *p++ = (_data >> 8) & 0xff; + *p++ = (_data >> 16) & 0xff; + *p++ = (_data >> 24) & 0xff; + } else { + *(u32 *)p = _data; + p += 4; + } + transfer_size -= 4; + size -= 4; + } + } else { + while (size) { + status = readl(ssp->base + HW_SSP_STATUS(ssp)); + if (status & BM_SSP_STATUS_FIFO_FULL) + continue; + if ((u32)p & 0x3) + _data = p[0] | \ + (p[1] << 8) | \ + (p[2] << 16) | \ + (p[3] << 24); + else + _data = *(u32 *)p; + + writel(_data, ssp->base + HW_SSP_DATA(ssp)); + transfer_size -= 4; + size -= 4; + p += 4; + } + } + kunmap_atomic(sgbuf); + index++; + } + + while (readl(ssp->base + HW_SSP_STATUS(ssp)) & (BM_SSP_STATUS_BUSY | + BM_SSP_STATUS_DATA_BUSY | + BM_SSP_STATUS_CMD_BUSY)) + continue; + + cmd->data->bytes_xfered = data_size; + + host->status = readl(ssp->base + HW_SSP_STATUS(ssp)); + + c1 = readl(ssp->base + HW_SSP_CTRL1(ssp)); + + /* reset interrupt request status bits */ + writel(c1 & MXS_MMC_ERR_IRQ_BITS, + ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_CLR); + + /* reenable these bits */ + writel(ctrl1, ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_SET); + /* end IO operations */ + + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: + break; + case MMC_RSP_R1: + case MMC_RSP_R3: + cmd->resp[0] = + readl(ssp->base + HW_SSP_SDRESP0(ssp)); + break; + case MMC_RSP_R2: + cmd->resp[3] = + readl(ssp->base + HW_SSP_SDRESP0(ssp)); + cmd->resp[2] = + readl(ssp->base + HW_SSP_SDRESP1(ssp)); + cmd->resp[1] = + readl(ssp->base + HW_SSP_SDRESP2(ssp)); + cmd->resp[0] = + readl(ssp->base + HW_SSP_SDRESP3(ssp)); + break; + default: + dev_warn(mmc_dev(host->mmc), "Unsupported response type 0x%x\n", + mmc_resp_type(cmd)); + BUG(); + break; + } + + cmd->error = mxs_mmc_cmd_error(host->status); + + if (cmd->error) { + dev_warn(mmc_dev(host->mmc), "ADTC command error %d\n", cmd->error); + } else { + dev_dbg(mmc_dev(host->mmc), "Transferred %u bytes\n", + cmd->data->bytes_xfered); + } } static void mxs_mmc_start_cmd(struct mxs_mmc_host *host, @@ -489,11 +692,18 @@ static void mxs_mmc_start_cmd(struct mxs_mmc_host *host, static void mxs_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) { + int done; struct mxs_mmc_host *host = mmc_priv(mmc); WARN_ON(host->mrq != NULL); host->mrq = mrq; mxs_mmc_start_cmd(host, mrq->cmd); + + if (mrq->data && mrq->data->stop) + mxs_mmc_start_cmd(host, mrq->data->stop); + + host->mrq = NULL; + mmc_request_done(mmc, mrq); } static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) @@ -603,6 +813,7 @@ static int mxs_mmc_probe(struct platform_device *pdev) host->mmc = mmc; host->sdio_irq_en = 0; + host->pio_size = 0; reg_vmmc = devm_regulator_get(&pdev->dev, "vmmc"); if (!IS_ERR(reg_vmmc)) { diff --git a/include/linux/spi/mxs-spi.h b/include/linux/spi/mxs-spi.h index 381d368..903c1c7 100644 --- a/include/linux/spi/mxs-spi.h +++ b/include/linux/spi/mxs-spi.h @@ -53,6 +53,8 @@ #define BP_SSP_CMD0_CMD 0 #define BM_SSP_CMD0_CMD 0xff #define HW_SSP_CMD1 0x020 +#define BP_SSP_CMD1_CMD 0 +#define BM_SSP_CMD1_CMD 0xFFFFFFFF #define HW_SSP_XFER_SIZE 0x030 #define HW_SSP_BLOCK_SIZE 0x040 #define BP_SSP_BLOCK_SIZE_BLOCK_COUNT 4 @@ -116,6 +118,16 @@ #define BM_SSP_STATUS_CARD_DETECT (1 << 28) #define BM_SSP_STATUS_SDIO_IRQ (1 << 17) #define BM_SSP_STATUS_FIFO_EMPTY (1 << 5) +#define BM_SSP_STATUS_RESP_CRC_ERR 0x00010000 +#define BM_SSP_STATUS_RESP_ERR 0x00008000 +#define BM_SSP_STATUS_RESP_TIMEOUT 0x00004000 +#define BM_SSP_STATUS_DATA_CRC_ERR 0x00002000 +#define BM_SSP_STATUS_TIMEOUT 0x00001000 +#define BM_SSP_STATUS_FIFO_FULL 0x00000100 +#define BM_SSP_STATUS_CMD_BUSY 0x00000008 +#define BM_SSP_STATUS_DATA_BUSY 0x00000004 +#define BM_SSP_STATUS_RSVD0 0x00000002 +#define BM_SSP_STATUS_BUSY 0x00000001 #define BF_SSP(value, field) (((value) << BP_SSP_##field) & BM_SSP_##field) -- 2.10.2