From patchwork Fri Oct 12 14:02:02 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulf Hansson X-Patchwork-Id: 1586851 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id 8FABBDFF71 for ; Fri, 12 Oct 2012 14:04:58 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TMfpP-0008Ry-RW; Fri, 12 Oct 2012 14:03:04 +0000 Received: from eu1sys200aog114.obsmtp.com ([207.126.144.137]) by merlin.infradead.org with smtps (Exim 4.76 #1 (Red Hat Linux)) id 1TMfpM-0008Qq-Ep for linux-arm-kernel@lists.infradead.org; Fri, 12 Oct 2012 14:03:01 +0000 Received: from beta.dmz-eu.st.com ([164.129.1.35]) (using TLSv1) by eu1sys200aob114.postini.com ([207.126.147.11]) with SMTP ID DSNKUHgjCK3n8psXL7tUnesyKU8oxkoX3aM+@postini.com; Fri, 12 Oct 2012 14:03:00 UTC Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 87B0789; Fri, 12 Oct 2012 14:02:26 +0000 (GMT) Received: from relay2.stm.gmessaging.net (unknown [10.230.100.18]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 28DFD45B8; Fri, 12 Oct 2012 14:02:24 +0000 (GMT) Received: from exdcvycastm022.EQ1STM.local (alteon-source-exch [10.230.100.61]) (using TLSv1 with cipher RC4-MD5 (128/128 bits)) (Client CN "exdcvycastm022", Issuer "exdcvycastm022" (not verified)) by relay2.stm.gmessaging.net (Postfix) with ESMTPS id 12583A807E; Fri, 12 Oct 2012 16:02:18 +0200 (CEST) Received: from steludxu1397.stericsson.com (10.230.100.153) by smtp.stericsson.com (10.230.100.30) with Microsoft SMTP Server (TLS) id 8.3.83.0; Fri, 12 Oct 2012 16:02:23 +0200 From: Ulf Hansson To: , Chris Ball Subject: [PATCH] mmc: mmci: Support non-power-of-two block sizes for ux500v2 variant Date: Fri, 12 Oct 2012 16:02:02 +0200 Message-ID: <1350050522-8852-1-git-send-email-ulf.hansson@stericsson.com> X-Mailer: git-send-email 1.7.10 MIME-Version: 1.0 X-Spam-Note: CRM114 invocation failed X-Spam-Score: -4.2 (----) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-4.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [207.126.144.137 listed in list.dnswl.org] -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: Per Forlin , Linus Walleij , Russell King , Ulf Hansson , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org From: Ulf Hansson For the ux500v2 variant non power of two block sizes are supported. This will make it possible to decrease data overhead for SDIO transfers. Although we need to put some constraints to the alignment of the buffers when enabling this feature. Buffers must be 4 bytes aligned due to restrictions that the PL18x FIFO accesses must be done in a 4 byte aligned manner. Moreover we need to enable DMA_REQCTL for SDIO to support write of non 32 bytes aligned sg element lengths. In PIO mode any buffer length can be handled as long as the buffer address is 4 byte aligned. Signed-off-by: Ulf Hansson Signed-off-by: Per Forlin Reviewed-by: Linus Walleij Acked-By: Johan Rudholm --- drivers/mmc/host/mmci.c | 56 +++++++++++++++++++++++++++++++++++++++++------ drivers/mmc/host/mmci.h | 7 ++++++ 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index edc3e9b..ca6d128 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -48,6 +48,7 @@ static unsigned int fmax = 515633; * struct variant_data - MMCI variant-specific quirks * @clkreg: default value for MCICLOCK register * @clkreg_enable: enable value for MMCICLOCK register + * @dma_sdio_req_ctrl: enable value for DMAREQCTL register for SDIO write * @datalength_bits: number of bits in the MMCIDATALENGTH register * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY * is asserted (likewise for RX) @@ -58,10 +59,12 @@ static unsigned int fmax = 515633; * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register * @pwrreg_powerup: power up value for MMCIPOWER register * @signal_direction: input/out direction of bus signals can be indicated + * @non_power_of_2_blksize: true if block sizes can be other than power of two */ struct variant_data { unsigned int clkreg; unsigned int clkreg_enable; + unsigned int dma_sdio_req_ctrl; unsigned int datalength_bits; unsigned int fifosize; unsigned int fifohalfsize; @@ -70,6 +73,7 @@ struct variant_data { bool blksz_datactrl16; u32 pwrreg_powerup; bool signal_direction; + bool non_power_of_2_blksize; }; static struct variant_data variant_arm = { @@ -112,6 +116,7 @@ static struct variant_data variant_ux500 = { .fifohalfsize = 8 * 4, .clkreg = MCI_CLK_ENABLE, .clkreg_enable = MCI_ST_UX500_HWFCEN, + .dma_sdio_req_ctrl = MCI_ST_DPSM_DMAREQCTL, .datalength_bits = 24, .sdio = true, .st_clkdiv = true, @@ -124,15 +129,42 @@ static struct variant_data variant_ux500v2 = { .fifohalfsize = 8 * 4, .clkreg = MCI_CLK_ENABLE, .clkreg_enable = MCI_ST_UX500_HWFCEN, + .dma_sdio_req_ctrl = MCI_ST_DPSM_DMAREQCTL, .datalength_bits = 24, .sdio = true, .st_clkdiv = true, .blksz_datactrl16 = true, .pwrreg_powerup = MCI_PWR_ON, .signal_direction = true, + .non_power_of_2_blksize = true, }; /* + * Validate mmc prerequisites + */ +static int mmci_validate_data(struct mmci_host *host, + struct mmc_data *data) +{ + if (!data) + return 0; + + if (!host->variant->non_power_of_2_blksize && + !is_power_of_2(data->blksz)) { + dev_err(mmc_dev(host->mmc), + "unsupported block size (%d bytes)\n", data->blksz); + return -EINVAL; + } + + if (data->sg->offset & 3) { + dev_err(mmc_dev(host->mmc), + "unsupported alginment (0x%x)\n", data->sg->offset); + return -EINVAL; + } + + return 0; +} + +/* * This must be called with host->lock held */ static void mmci_write_clkreg(struct mmci_host *host, u32 clk) @@ -446,8 +478,12 @@ static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, if (!chan) return -EINVAL; - /* If less than or equal to the fifo size, don't bother with DMA */ - if (data->blksz * data->blocks <= variant->fifosize) + /* + * If less than or equal to the fifo size, don't bother with DMA + * SDIO transfers may not be 4 bytes aligned, fall back to PIO + */ + if (data->blksz * data->blocks <= variant->fifosize || + (data->blksz * data->blocks) & 3) return -EINVAL; device = chan->device; @@ -482,6 +518,7 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) { int ret; struct mmc_data *data = host->data; + struct variant_data *variant = host->variant; ret = mmci_dma_prep_data(host, host->data, NULL); if (ret) @@ -496,6 +533,11 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) datactrl |= MCI_DPSM_DMAENABLE; + /* Some hardware versions need special flags for SDIO DMA write */ + if (variant->sdio && host->mmc->card && mmc_card_sdio(host->mmc->card) + && (data->flags & MMC_DATA_WRITE)) + datactrl |= variant->dma_sdio_req_ctrl; + /* Trigger the DMA transfer */ writel(datactrl, host->base + MMCIDATACTRL); @@ -540,6 +582,9 @@ static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq, if (!data) return; + if (mmci_validate_data(host, mrq->data)) + return; + if (data->host_cookie) { data->host_cookie = 0; return; @@ -642,7 +687,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) writel(host->size, base + MMCIDATALENGTH); blksz_bits = ffs(data->blksz) - 1; - BUG_ON(1 << blksz_bits != data->blksz); if (variant->blksz_datactrl16) datactrl = MCI_DPSM_ENABLE | (data->blksz << 16); @@ -1048,10 +1092,8 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) WARN_ON(host->mrq != NULL); - if (mrq->data && !is_power_of_2(mrq->data->blksz)) { - dev_err(mmc_dev(mmc), "unsupported block size (%d bytes)\n", - mrq->data->blksz); - mrq->cmd->error = -EINVAL; + mrq->cmd->error = mmci_validate_data(host, mrq->data); + if (mrq->cmd->error) { mmc_request_done(mmc, mrq); return; } diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index d437ccf..c2b3332 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -60,6 +60,13 @@ #define MCI_ST_DPSM_RWMOD (1 << 10) #define MCI_ST_DPSM_SDIOEN (1 << 11) /* Control register extensions in the ST Micro Ux500 versions */ +/* + * DMA request control is required for write + * if transfer size is not 32 byte aligned. + * DMA request control is also needed if the total + * transfer size is 32 byte aligned but any of the + * sg element lengths are not aligned with 32 byte. + */ #define MCI_ST_DPSM_DMAREQCTL (1 << 12) #define MCI_ST_DPSM_DBOOTMODEEN (1 << 13) #define MCI_ST_DPSM_BUSYMODE (1 << 14)